def get_rewrite_rules(self): """ Returns rewrite rules for the default virtual host with their definitions :return: """ cmd = '/subsystem=web/virtual-server=default-host:read-children-resources(child-type=rewrite)' ret, out, err = self.cli_cmd(cmd) if ret != 0: raise errors.SetupError('Cannot get JBoss rewrite rules') out_json = util.jboss_to_json(out) if out_json is None or 'result' not in out_json: raise errors.SetupError( 'Invalid JBoss response on rewrite rules get') return out_json['result']
def ctl_refresh(self): """ supervisorctl reread supervisorctl update :return: """ ret = self.sysconfig.exec_shell('sudo %s supervisorctl reread' % self.sysconfig.epiper_path()) if ret != 0: raise errors.SetupError('Could not exec supervisorctl reread') ret = self.sysconfig.exec_shell('sudo %s supervisorctl update' % self.sysconfig.epiper_path()) if ret != 0: raise errors.SetupError('Could not exec supervisorctl update')
def _configure_env(self, env_path): """ Creates env configuration file for Laravel :param env_path: :return: """ tpl_file = self._get_env_template() tpl_file = tpl_file.replace('{{ APP_URL }}', 'https://%s:8442' % self.hostname) tpl_file = tpl_file.replace('{{ APP_PRIVATE_SPACE_NAME }}', self._cfg_str(self.hostname)) tpl_file = tpl_file.replace('{{ APP_ADMIN }}', self._cfg_str(self.admin_email)) tpl_file = tpl_file.replace('{{ APP_STATS }}', self._cfg_str(self.stats_file_path)) tpl_file = tpl_file.replace('{{ APP_VPN_NET_ADDR }}', self._cfg_str(self.vpn_net_addr)) tpl_file = tpl_file.replace('{{ APP_VPN_NET_SIZE }}', self._cfg_str(self.vpn_net_size)) tpl_file = tpl_file.replace('{{ DB_DATABASE }}', self._cfg_str(self.config.pspace_db)) tpl_file = tpl_file.replace('{{ DB_USERNAME }}', self._cfg_str(self.config.pspace_db_user)) tpl_file = tpl_file.replace('{{ DB_PASSWORD }}', self._cfg_str(self.config.pspace_db_password)) # Remove all other templates not filled in tpl_file = re.sub(r'\{\{\s*[a-zA-Z0-9_\-]+\s*\}\}', '', tpl_file) with open(env_path, mode='w') as fh: fh.write(tpl_file) cmd = 'sudo -E -H chown %s "%s"' % (self.user, env_path) ret, out, err = self.sysconfig.cli_cmd_sync(cmd, cwd=self.webroot) if ret != 0: raise errors.SetupError('Could not change .env owner')
def _find_dirs(self): """ Finds the ejabberd root dir :return: """ base = '/opt' folders = [ os.path.join(base, f) for f in os.listdir(base) if not os.path.isfile(os.path.join(base, f)) and f != '.' and f != '..' and f.startswith('ejabberd') ] if len(folders) > 1: logger.debug('Too many ejabberd folders, picking the last one') if len(folders) > 0: self._root_dir = folders[-1] self._config_dir = os.path.join(self._root_dir, 'conf') self._bin_dir = os.path.join(self._root_dir, 'bin') self._ejabberctl = os.path.join(self._bin_dir, 'ejabberdctl') self._bin_initd_script = os.path.join(self._bin_dir, 'ejabberd.init') self._bin_svc_script = os.path.join(self._bin_dir, 'ejabberd.service') self._server_cert_path = os.path.join(self._config_dir, 'server.pem') cfg_stat = os.stat(self._config_dir) self._user = cfg_stat.st_uid self._group = cfg_stat.st_gid return raise errors.SetupError('Could not find Ejabberd folders')
def ctl_stop(self, cmd): """ :return: """ ret = self.sysconfig.exec_shell( 'sudo %s supervisorctl stop %s' % (self.sysconfig.epiper_path(), util.escape_shell(cmd))) if ret != 0: raise errors.SetupError('Could not exec supervisorctl stop')
def _deploy_downloaded(self, archive_path, basedir): """ Analyzes downloaded file, deploys to the install dir :param archive_path: :param basedir: :return: """ cmd = 'sudo tar -xzvf %s' % util.escape_shell(archive_path) ret, out, err = self.sysconfig.cli_cmd_sync(cmd, write_dots=True, cwd=basedir) if ret != 0: raise errors.SetupError('Could not extract update archive') folders = [ f for f in os.listdir(basedir) if not os.path.isfile(os.path.join(basedir, f)) and f != '.' and f != '..' ] if len(folders) != 1: raise errors.SetupError( 'Invalid folder structure after update extraction') archive_dir = os.path.join(basedir, folders[0]) if not os.path.exists(archive_dir): raise errors.SetupError( 'Directory with jboss not found in the install archive: %s' % archive_dir) archive_slash = util.add_ending_slash(archive_dir) dest_slash = util.add_ending_slash(self.get_jboss_home()) # reinstall - preserve user data excludes = '' cmd = 'sudo rsync -av --delete %s %s %s' \ % (excludes, util.escape_shell(archive_slash), util.escape_shell(dest_slash)) ret, out, err = self.sysconfig.cli_cmd_sync(cmd, write_dots=True, cwd=basedir) if ret != 0: raise errors.SetupError('jboss sync failed') self.fix_privileges()
def install(self): """ Installs itself :return: installer return code """ install_package = self._install_package() if install_package == 0: return 0 raise errors.SetupError('Cannot install PHP')
def _install_package(self): """ Installs from the package. :return: status code of the installer. """ if self.sysconfig.get_packager() == osutil.PKG_APT: cmd_exec = 'sudo apt-get install -y php-fpm php-mysql php-mbstring php-gd' return self.sysconfig.exec_shell(cmd_exec, write_dots=self.write_dost) if self.sysconfig.get_packager() != osutil.PKG_YUM: raise errors.SetupError('Unsupported packager, cannot install PHP') # Check out versions available packages = [ 'php*-fpm', 'php*-mysqlnd', 'php*-mbstring', 'php*-gd', 'php*-xml' ] cmd_version = 'sudo repoquery ' + (' '.join(packages)) ret, out, err = self.sysconfig.cli_cmd_sync(cmd_version, shell=True) if ret != 0: raise errors.SetupError( 'Could not determine available PHP versions') versions = util.get_repoquery_available_versions(out) # Prefer versions 5.6 versions_to_install = util.repoquery_find_version(versions, exact_version='5.6') if len(versions_to_install) < len(packages): versions_to_install = util.repoquery_find_version( versions, min_version='5.6', max_version='5.99') versions_to_install = util.repoquery_pick_version( versions_to_install, pick_min=True) if len(versions_to_install) < len(packages): raise errors.SetupError('Could not install all packages') packages_to_install = [x[0] for x in versions_to_install] cmd_exec = 'sudo yum install -y ' + (' '.join(packages_to_install)) return self.sysconfig.exec_shell(cmd_exec, write_dots=self.write_dost)
def enable_default_root(self): """ Enables default root for JBoss - required for rewrites /subsystem=web/virtual-server=default-host:write-attribute(name="enable-welcome-root",value=true) :return: """ cmd = '/subsystem=web/virtual-server=default-host:write-attribute(name="enable-welcome-root",value=true)' ret, out, err = self.cli_cmd(cmd) if ret != 0: raise errors.SetupError('Cannot set JBoss default host') return ret
def install(self): """ Installs itself :return: installer return code """ cmd_exec = 'sudo -E -H pip install --upgrade --no-cache vpnauth' ret = self.sysconfig.exec_shell(cmd_exec, write_dots=self.write_dost) if ret != 0: raise errors.SetupError('Could not install vpnauth from the pip') return 0
def remove_rewrite_rule(self, rule): """ Removes rewrite rule from the default virtual host :param rule: :return: """ cmd = '/subsystem=web/virtual-server=default-host/rewrite=%s:remove' % rule ret, out, err = self.cli_cmd(cmd) if ret != 0: raise errors.SetupError('Cannot get JBoss rewrite rules') return ret
def install(self): """ Installs itself :return: installer return code """ ret = self._install(attempts=3) if ret != 0: raise errors.SetupError('Could not install Ejabberd') self._install_extauth() return 0
def configure(self): """ Configures supervisord after manual installation :return: """ self.config.pspace_db = self.DB_NAME self.config.pspace_db_user = self.DB_USER self.config.pspace_db_password = util.random_password(16) self.audit.add_secrets(self.config.pspace_db_password) # Create mysql database and user self.mysql.drop_database(self.config.pspace_db) self.mysql.create_database(self.config.pspace_db) self.mysql.create_user(self.DB_USER, self.config.pspace_db_password, self.config.pspace_db) # Create .env config file. env_path = os.path.join(self.webroot, '.env') if os.path.exists(env_path): util.file_backup(env_path) os.remove(env_path) # Env path config self._configure_env(env_path) # Composer install cmd = 'sudo -E -H -u %s composer install' % self.user ret, out, err = self.sysconfig.cli_cmd_sync(cmd, cwd=self.webroot) if ret != 0: raise errors.SetupError('Could not install dependencies') # Artisan - generate new fresh app key cmd = 'sudo -E -H -u %s php artisan key:generate' % self.user ret, out, err = self.sysconfig.cli_cmd_sync(cmd, cwd=self.webroot) if ret != 0: raise errors.SetupError('Could not create a new app key for privatespace') # Artisan migrate - create DB structure cmd = 'sudo -E -H -u %s php artisan migrate --force' % self.user ret, out, err = self.sysconfig.cli_cmd_sync(cmd, cwd=self.webroot) if ret != 0: raise errors.SetupError('Could not initialize DB for privatespace')
def _occ_cmd(self, cmd, require_zero_result=True): """ Calls OCC command, returns ret, out, err :param cmd: :return: """ cmd = 'sudo -u %s php occ %s ' % (self.user, cmd) ret, out, err = self.sysconfig.cli_cmd_sync(cmd, cwd=self.webroot) if require_zero_result and ret != 0: raise errors.SetupError('OCC call failed') return ret, out, err
def _ctl_cmd(self, cmd, require_zero_result=True): """ Calls ejabberctl command, returns ret, out, err :param cmd: :return: """ self._find_dirs_if_needed() cmd = '%s %s' % (self._ejabberctl, cmd) ret, out, err = self.sysconfig.cli_cmd_sync(cmd, cwd=self._root_dir) if require_zero_result and ret != 0: raise errors.SetupError('Ejabberctl call failed') return ret, out, err
def _install_ojsxc(self): """ Installs chat plugin app :return: """ url = self._file_ojsxc base_file = 'jsxc-nc.tgz' try: logger.debug('Going to download NextCloud/ojsxc') tmpdir = util.safe_new_dir('/tmp/nextcloud-jsxc-install') archive_path = os.path.join(tmpdir, base_file) app_dir = os.path.join(self.webroot, 'apps', 'ojsxc') try: self.audit.audit_evt('prov-jsxc', url=url) self._download_file(url, archive_path, attempts=3) unpacked_dir = util.untar_get_single_dir( archive_path, self.sysconfig) shutil.move(unpacked_dir, app_dir) self._fix_privileges() self._occ_cmd('app:enable ojsxc') self.config.nextcloud_jsxc_token = util.random_password(23) self._occ_set_config('ojsxc', 'apiSecret', self.config.nextcloud_jsxc_token) self._occ_set_config('ojsxc', 'boshUrl', '/http-bind/') self._occ_set_config('ojsxc', 'timeLimitedToken', 'true') self._occ_set_config('ojsxc', 'serverType', 'external') self._occ_set_config( 'ojsxc', 'externalServices', '|'.join(self.get_domains() + [self.hostname])) self._occ_set_config('ojsxc', 'xmppDomain', self.hostname) self._occ_set_config('ojsxc', 'xmppOverwrite', 'true') self._occ_set_config('ojsxc', 'xmppStartMinimized', 'false') except Exception as e: logger.debug('Exception in fetching NextCloud/ojsxc: %s' % e) self.audit.audit_exception(e, process='prov-jsxc') finally: if os.path.exists(tmpdir): shutil.rmtree(tmpdir) return 0 except Exception as e: logger.debug('Exception when fetching NextCloud/ojsxc') self.audit.audit_exception(e) raise errors.SetupError('Could not install NextCloud/ojsxc', cause=e)
def install(self): """ Installs itself :return: installer return code """ # Remove webroot if exists if os.path.exists(self.webroot): util.dir_backup(self.webroot, backup_dir='/tmp') if os.path.exists(self.webroot): shutil.rmtree(self.webroot) # Git clone cmd = 'git clone "%s" "%s"' % (self.get_git_repo(), self.webroot) ret, out, err = self.sysconfig.cli_cmd_sync(cmd) if ret != 0: raise errors.SetupError('Git clone of the private space repo failed') # Dependencies self._install_deps() # Privileges storage_dir = os.path.join(self.webroot, 'storage', 'bootstrap', 'cache') cache_sub_dir = os.path.join(storage_dir, 'bootstrap', 'cache') if not os.path.exists(cache_sub_dir): os.makedirs(cache_sub_dir, mode=0o775) cmd = 'sudo chown %s -R "%s"' % (self.user, self.webroot) ret, out, err = self.sysconfig.cli_cmd_sync(cmd) if ret != 0: raise errors.SetupError('Owner change failed for private space web') cmd = 'sudo chmod 775 -R "%s"' % storage_dir ret, out, err = self.sysconfig.cli_cmd_sync(cmd) if ret != 0: raise errors.SetupError('Permission change failed for private space web') return 0
def _install_composer(self): """ Installs PHP composer :return: """ tmpdir = os.path.join('/tmp', 'tmp-composer.%08d' % random.randint(0, 2**31)) if os.path.exists(tmpdir): shutil.rmtree(tmpdir) util.make_or_verify_dir(tmpdir) composer_installer = os.path.join(tmpdir, 'composer-setup.php') cmd = 'curl -s "%s" > "%s"' % ('https://getcomposer.org/installer', composer_installer) ret, out, err = self.sysconfig.cli_cmd_sync(cmd, cwd=tmpdir) if ret != 0: raise errors.SetupError('Could not download composer') cmd = 'sudo php "%s" --install-dir=/bin --filename=composer' % composer_installer ret, out, err = self.sysconfig.cli_cmd_sync(cmd, cwd=tmpdir) if ret != 0: raise errors.SetupError('Could not install composer') shutil.rmtree(tmpdir)
def install(self): """ Installs itself :return: installer return code """ ret = self._install(attempts=3) if ret != 0: raise errors.SetupError('Could not install NextCloud') self._occ_install() self._trusted_domains() self._install_ojsxc() self._install_vpnauth() self._fix_privileges() return 0
def _trusted_domains(self): """ Trusted domains configuration - modifies config.php and adds current domain to the trusted_domains config key :return: """ cfg_path = os.path.join(self.webroot, 'config', 'config.php') if not os.path.exists(cfg_path): logger.warning('NextCloud config file not found: %s' % cfg_path) raise errors.SetupError('NextCloud config file not found') tpl_file = self._get_php_trusted_domains_template() tpl_file = tpl_file.replace('{{ CONFIG_FILE }}', cfg_path) tpl_file = re.sub(r'\{\{\s*[a-zA-Z0-9_\-]+\s*\}\}', '', tpl_file) php_file = os.path.join(self.webroot, 'ebstall-config.php') util.safely_remove(php_file) with util.safe_open(php_file, 'w', 0o755) as fw: fw.write(tpl_file) domains_list = ' '.join(self.get_domains() + [self.hostname]) cmd = 'sudo -u %s php %s %s ' \ % (self.user, php_file, domains_list) ret, out, err = self.sysconfig.cli_cmd_sync(cmd, cwd=self.webroot) if ret != 0: raise errors.SetupError( 'Owner change failed for private space web') if isinstance(out, types.ListType): out = ''.join(out) new_cfg = '<?php\n $CONFIG = %s; \n' % out with open(cfg_path, 'w') as fw: fw.write(new_cfg) util.safely_remove(php_file)
def install(self): """ Installs itself Jboss installer is not supported yet, has to be already present on the system. :return: installer return code """ # TODO: full install on clean image: # TODO: - create jboss user # TODO: - _install to download jboss image, symlink /opt/jboss -> /opt/jboss-eap.6.4.0 # TODO: - start script for jboss home = self.get_jboss_home() if not os.path.exists(home): raise errors.SetupError('JBoss not found in %s' % home) return 0
def _install(self, attempts=3): """ Downloads JBoss installation file from provisioning server. :return: """ base_file = self.JBOSS_ARCHIVE try: logger.debug( 'Going to download JBoss from the provisioning servers') for provserver in PROVISIONING_SERVERS: url = 'https://%s/jboss/%s' % (provserver, base_file) tmpdir = util.safe_new_dir('/tmp/jboss-install') try: self.audit.audit_evt('prov-jboss', url=url) # Download archive. archive_path = os.path.join(tmpdir, base_file) self._download_file(url, archive_path, attempts=attempts) # Install self._deploy_downloaded(archive_path, tmpdir) return 0 except errors.SetupError as e: logger.debug( 'SetupException in fetching JBoss from the provisioning server: %s' % e) self.audit.audit_exception(e, process='prov-jboss') except Exception as e: logger.debug( 'Exception in fetching JBoss from the provisioning server: %s' % e) self.audit.audit_exception(e, process='prov-jboss') finally: if os.path.exists(tmpdir): shutil.rmtree(tmpdir) return 0 except Exception as e: logger.debug('Exception when fetching jBoss') self.audit.audit_exception(e) raise errors.SetupError('Could not install jBoss', cause=e)
def add_tile(self, name, icon, link): """ Adds a new tile to the page :param name: :param icon: :param link: :return: """ cmd = 'sudo -u %s php artisan tiles:add %s %s %s' \ % (self.user, util.escape_shell(name), util.escape_shell(icon), util.escape_shell(link)) ret, out, err = self.sysconfig.cli_cmd_sync(cmd, cwd=self.webroot) if ret != 0: raise errors.SetupError('Could not add an application tile')
def _fix_privileges(self): """ Fixes privileges to the files :return: """ # Privileges storage_dir = os.path.join(self.webroot, 'storage', 'bootstrap', 'cache') cache_sub_dir = os.path.join(storage_dir, 'bootstrap', 'cache') if not os.path.exists(cache_sub_dir): os.makedirs(cache_sub_dir, mode=0o775) cmd = 'sudo chown %s -R "%s"' % (self.user, self.webroot) ret, out, err = self.sysconfig.cli_cmd_sync(cmd) if ret != 0: raise errors.SetupError( 'Owner change failed for private space web')
def init_client_config(self): """ Client configuration parser :return: """ if self.client_config_path is None: logger.debug('Client configuration path not provided') return if not os.path.exists(self.client_config_path): raise errors.SetupError( 'Could not find client VPN configuration file: %s' % self.client_config_path) if self.client_config is None: self.client_config = OpenVpnConfig( config_path=self.client_config_path, audit=self.audit)
def _deploy_downloaded(self, archive_path, basedir): """ Analyzes downloaded file, deploys to the webroot :param archive_path: :param basedir: :return: """ cmd_exec = None pkg = self.sysconfig.get_packager() if pkg == osutil.PKG_YUM: cmd_exec = 'sudo yum localinstall enablerepo=epel -y %s' % util.escape_shell( archive_path) elif pkg == osutil.PKG_APT: cmd_exec = 'sudo dpkg -i %s' % util.escape_shell(archive_path) ret = self.sysconfig.exec_shell(cmd_exec, write_dots=self.write_dots) if ret != 0: raise errors.SetupError('Could not install ejabberd server')
def le_enroll(self, le_method=None): """ Enrolls to LetsEncrypt with specified domains :param le_method: :return: """ # If hostname is none/localhost, there is no point for lets encrypt here. Maybe later. if self.hostname is None or self.hostname == 'localhost': logger.info( "Hostname is none/localhost, no letsencrypt operation will be performed" ) return 1 cert_sets = self.get_domain_certificate_set() if len(cert_sets) != 1: raise errors.Error( 'Invalid certificate domain set size. Currently supported only one.' ) self.lets_encrypt = letsencrypt.LetsEncrypt(email=self.config.email, domains=cert_sets[0], staging=self.is_staging(), audit=self.audit, sysconfig=self.sysconfig) le_method = self.get_le_method(le_method=le_method) # noinspection PyUnusedLocal ret, out, err = -1, None, None if le_method == LE_VERIFY_DNS: logger.debug('Using DNS validation') mdns = self.lets_encrypt.manual_dns( expand=True, on_domain_challenge=self.le_dns) ret, out, err = mdns.start() else: ret, out, err = self.lets_encrypt.certonly(expand=True, force=True) if ret != 0: raise errors.SetupError( 'Certificate could not be created, return code: %s' % ret) return 0
def add_rewrite_rule(self, rule_id, pattern, subs, flags='L,QSA,R'): """ Adds a new rewrite rule to the jboss :param rule_id: :param pattern: :param subs: :param flags: :return: """ pattern = pattern.replace('"', '\\"') subs = subs.replace('"', '\\"') flags = flags.replace('"', '\\"') cmd = '/subsystem=web/virtual-server=default-host/rewrite=%s:add(pattern="%s", substitution="%s", flags="%s")' \ % (rule_id, pattern, subs, flags) ret, out, err = self.cli_cmd(cmd) if ret != 0: raise errors.SetupError('Cannot set JBoss rewrite rule %s' % rule_id) return ret
def _configure(self): """ Configures supervisord after manual installation :return: """ cmd_prep = '%s echo_supervisord_conf > %s' % ( self.sysconfig.epiper_path(), self.CONFIG_FILE) ret = self.sysconfig.exec_shell(cmd_prep) if ret != 0: raise errors.SetupError( 'Could not initialize supervisord config file') if not os.path.exists(self.CONFIG_FILE_DIR): util.make_or_verify_dir(self.CONFIG_FILE_DIR) with open(self.CONFIG_FILE, 'a') as fh: fh.write('\n') fh.write('[include]\n') fh.write('files = /etc/supervisord.d/*.conf\n\n')
def _install_extauth(self): """ Installs external authentication plugin :return: """ url = self._file_extauth base_file = 'extauth-nc.tgz' try: logger.debug('Going to download Ejabberd/extauth') tmpdir = util.safe_new_dir('/tmp/ejabberd-extauth-install') archive_path = os.path.join(tmpdir, base_file) try: self.audit.audit_evt('prov-extauth', url=url) self._download_file(url, archive_path, attempts=3) unpacked_dir = util.untar_get_single_dir( archive_path, self.sysconfig) if os.path.exists(self._extauth_path): shutil.rmtree(self._extauth_path) shutil.move(unpacked_dir, self._extauth_path) # Setup log dir for ext auth if not os.path.exists(self._extauth_log_dir): util.make_or_verify_dir(self._extauth_log_dir) self.sysconfig.chown_recursive(self._extauth_log_dir, self._user, self._group, throw_on_error=False) finally: if os.path.exists(tmpdir): shutil.rmtree(tmpdir) return 0 except Exception as e: logger.debug('Exception when fetching Ejabberd/extauth: %s' % e) self.audit.audit_exception(e) raise errors.SetupError('Could not install Ejabberd/extauth', cause=e)