def remove(self, packages, auto=False, purge=False): all_packages = ' '.join(packages) try: with open('/var/log/wo/wordops.log', 'a') as f: if purge: proc = subprocess.Popen('apt-get purge -y {0}' .format(all_packages), shell=True, stdin=None, stdout=f, stderr=f, executable="/bin/bash") else: proc = subprocess.Popen('apt-get remove -y {0}' .format(all_packages), shell=True, stdin=None, stdout=f, stderr=f, executable="/bin/bash") proc.wait() if proc.returncode == 0: return True else: Log.info(self, Log.FAIL + "Oops Something went " "wrong!!") Log.error(self, "Check the WordOps log for more details " "`tail /var/log/wo/wordops.log` and please try again...") except Exception as e: Log.error(self, "Error while installing packages, " "apt-get exited with error")
def secure_ip(self): """IP whitelisting""" WOGit.add(self, ["/etc/nginx"], msg="Add Nginx to into Git") pargs = self.app.pargs if not pargs.user_input: ip = input("Enter the comma separated IP addresses " "to white list [127.0.0.1]:") pargs.user_input = ip try: user_ip = pargs.user_input.split(',') except Exception as e: Log.debug(self, "{0}".format(e)) user_ip = ['127.0.0.1'] for ip_addr in user_ip: if not ("exist_ip_address " + ip_addr in open('/etc/nginx/common/' 'acl.conf').read()): WOShellExec.cmd_exec( self, "sed -i " "\"/deny/i allow {whitelist_address}\;\"" " /etc/nginx/common/acl.conf".format( whitelist_address=ip_addr)) WOGit.add(self, ["/etc/nginx"], msg="Adding changed secure ip into Git") Log.info(self, "Successfully added IP address in acl.conf file")
def add(self): """Swap addition with WordOps""" # Get System RAM and SWAP details wo_ram = psutil.virtual_memory().total / (1024 * 1024) wo_swap = psutil.swap_memory().total / (1024 * 1024) if wo_ram < 512: if wo_swap < 1000: Log.info(self, "Adding SWAP file, please wait...") # Install dphys-swapfile WOAptGet.update(self) WOAptGet.install(self, ["dphys-swapfile"]) # Stop service WOShellExec.cmd_exec(self, "service dphys-swapfile stop") # Remove Default swap created WOShellExec.cmd_exec(self, "/sbin/dphys-swapfile uninstall") # Modify Swap configuration if os.path.isfile("/etc/dphys-swapfile"): WOFileUtils.searchreplace(self, "/etc/dphys-swapfile", "#CONF_SWAPFILE=/var/swap", "CONF_SWAPFILE=/wo-swapfile") WOFileUtils.searchreplace(self, "/etc/dphys-swapfile", "#CONF_MAXSWAP=2048", "CONF_MAXSWAP=1024") WOFileUtils.searchreplace(self, "/etc/dphys-swapfile", "#CONF_SWAPSIZE=", "CONF_SWAPSIZE=1024") else: with open("/etc/dphys-swapfile", 'w') as conffile: conffile.write("CONF_SWAPFILE=/wo-swapfile\n" "CONF_SWAPSIZE=1024\n" "CONF_MAXSWAP=1024\n") # Create swap file WOShellExec.cmd_exec(self, "service dphys-swapfile start")
def enable(self): pargs = self.app.pargs if not pargs.site_name: try: while not pargs.site_name: pargs.site_name = (input('Enter site name : ').strip()) except IOError as e: Log.debug(self, str(e)) Log.error(self, 'could not input site name') pargs.site_name = pargs.site_name.strip() # validate domain name wo_domain = WODomain.validate(self, pargs.site_name) # check if site exists if not check_domain_exists(self, wo_domain): Log.error(self, "site {0} does not exist".format(wo_domain)) if os.path.isfile('/etc/nginx/sites-available/{0}'.format(wo_domain)): Log.info(self, "Enable domain {0:10} \t".format(wo_domain), end='') WOFileUtils.create_symlink(self, [ '/etc/nginx/sites-available/{0}'.format(wo_domain), '/etc/nginx/sites-enabled/{0}'.format(wo_domain) ]) WOGit.add(self, ["/etc/nginx"], msg="Enabled {0} ".format(wo_domain)) updateSiteInfo(self, wo_domain, enabled=True) Log.info(self, "[" + Log.ENDC + "OK" + Log.OKBLUE + "]") if not WOService.reload_service(self, 'nginx'): Log.error( self, "service nginx reload failed. " "check issues with `nginx -t` command") else: Log.error(self, 'nginx configuration file does not exist')
def install(self, packages): all_packages = ' '.join(packages) try: with open('/var/log/wo/wordops.log', 'a') as f: proc = subprocess.Popen("DEBIAN_FRONTEND=noninteractive " "apt-get install -o " "Dpkg::Options::=\"--force-confdef\"" " -o " "Dpkg::Options::=\"--force-confold\"" " -y --allow-unauthenticated {0}" .format(all_packages), shell=True, stdin=None, stdout=f, stderr=f, executable="/bin/bash") proc.wait() if proc.returncode == 0: return True else: Log.info(self, Log.FAIL + "Oops Something went " "wrong!!") Log.error(self, "Check the WordOps log for more details " "`tail /var/log/wo/wordops.log` and please try again...") except Exception as e: Log.info(self, Log.FAIL + "Oops Something went " "wrong!!") Log.error(self, "Check the WordOps log for more details " "`tail /var/log/wo/wordops.log` and please try again...")
def default(self): if ((not self.app.pargs.mariadb)): self.app.args.print_help() if self.app.pargs.mariadb: if WOVariables.wo_mysql_host is not "localhost": Log.error( self, "Remote MySQL server in use, skipping local install") if WOShellExec.cmd_exec(self, "mysqladmin ping") and ( not WOAptGet.is_installed(self, 'mariadb-server')): Log.info( self, "If your database size is big, " "migration may take some time.") Log.info( self, "During migration non nginx-cached parts of " "your site may remain down") start_migrate = input("Type \"mariadb\" to continue:") if start_migrate != "mariadb": Log.error(self, "Not starting migration") self.migrate_mariadb() else: Log.error( self, "Your current MySQL is not alive or " "you allready installed MariaDB")
def show(self): pargs = self.app.pargs if not pargs.site_name: try: while not pargs.site_name: pargs.site_name = (input('Enter site name : ').strip()) except IOError as e: Log.debug(self, str(e)) Log.error(self, 'could not input site name') # TODO Write code for wo site edit command here pargs.site_name = pargs.site_name.strip() wo_domain = WODomain.validate(self, pargs.site_name) wo_www_domain = "www.{0}".format(wo_domain) if not check_domain_exists(self, wo_domain): Log.error(self, "site {0} does not exist".format(wo_domain)) if os.path.isfile('/etc/nginx/sites-available/{0}'.format(wo_domain)): Log.info(self, "Display NGINX configuration for {0}".format(wo_domain)) f = open('/etc/nginx/sites-available/{0}'.format(wo_domain), encoding='utf-8', mode='r') text = f.read() Log.info(self, Log.ENDC + text) f.close() else: Log.error(self, "nginx configuration file does not exists")
def download(self, packages): """Download packages, packges must be list in format of [url, path, package name]""" for package in packages: url = package[0] filename = package[1] pkg_name = package[2] try: directory = os.path.dirname(filename) if not os.path.exists(directory): os.makedirs(directory) Log.info(self, "Downloading {0:20}".format(pkg_name), end=' ') req = urllib.request.Request( url, headers={'User-Agent': 'Mozilla/5.0'}) with urllib.request.urlopen(req) as response, open(filename, 'wb') as out_file: out_file.write(response.read()) Log.info(self, "{0}".format("[" + Log.ENDC + "Done" + Log.OKBLUE + "]")) except urllib.error.URLError as e: Log.debug(self, "[{err}]".format(err=str(e.reason))) Log.error(self, "Unable to download file, {0}" .format(filename)) return False except urllib.HTTPError.error as e: Log.error(self, "Package download failed. {0}" .format(pkg_name)) Log.debug(self, "[{err}]".format(err=str(e.reason))) return False except urllib.ContentTooShortError.error as e: Log.debug(self, "{0}{1}".format(e.errno, e.strerror)) Log.error(self, "Package download failed. The amount of the" " downloaded data is less than " "the expected amount \{0} ".format(pkg_name)) return False
def clean_fastcgi(self): if(os.path.isdir("/var/run/nginx-cache")): Log.info(self, "Cleaning NGINX FastCGI cache") WOShellExec.cmd_exec(self, "rm -rf /var/run/nginx-cache/*") WOService.restart_service(self, 'nginx') else: Log.error(self, "Unable to clean FastCGI cache", False)
def clean_redis(self): """This function clears Redis cache""" if (WOAptGet.is_installed(self, "redis-server")): Log.info(self, "Cleaning Redis cache") WOShellExec.cmd_exec(self, "redis-cli flushall") else: Log.info(self, "Redis is not installed")
def download(self, packages): """Download packages, packages must be list in format of [url, path, package name]""" for package in packages: url = package[0] filename = package[1] pkg_name = package[2] try: directory = os.path.dirname(filename) if not os.path.exists(directory): os.makedirs(directory) Log.info(self, "Downloading {0:20}".format(pkg_name), end=' ') with open(filename, "wb") as out_file: req = requests.get(url, timeout=(5, 30)) if req.encoding is None: req.encoding = 'utf-8' out_file.write(req.content) Log.info( self, "{0}".format("[" + Log.ENDC + "Done" + Log.OKBLUE + "]")) except requests.RequestException as e: Log.debug(self, "[{err}]".format(err=str(e.reason))) Log.error(self, "Unable to download file, {0}".format(filename)) return False return 0
def default(self): pargs = self.app.pargs if ((not pargs.mariadb)): self.app.args.print_help() if pargs.mariadb: if WOVar.wo_distro == 'raspbian': Log.error(self, "MariaDB upgrade is not available on Raspbian") if WOVar.wo_mysql_host != "localhost": Log.error( self, "Remote MySQL server in use, skipping local install") if (WOShellExec.cmd_exec(self, "mysqladmin ping")): Log.info( self, "If your database size is big, " "migration may take some time.") Log.info( self, "During migration non nginx-cached parts of " "your site may remain down") if not pargs.force: start_upgrade = input("Do you want to continue:[y/N]") if start_upgrade != "Y" and start_upgrade != "y": Log.error(self, "Not starting package update") if not pargs.ci: self.migrate_mariadb() else: self.migrate_mariadb(ci=True) else: Log.error( self, "Your current MySQL is not alive or " "you allready installed MariaDB")
def deploycert(self, wo_domain_name): """Deploy Let's Encrypt certificates with acme.sh""" if not os.path.isfile('/etc/letsencrypt/renewal/{0}_ecc/fullchain.cer'. format(wo_domain_name)): Log.error(self, 'Certificate not found. Deployment canceled') Log.debug(self, "Cert deployment for domain: {0}".format(wo_domain_name)) try: Log.wait(self, "Deploying SSL cert") if WOShellExec.cmd_exec( self, "mkdir -p {0}/{1} && {2} --install-cert -d {1} --ecc " "--cert-file {0}/{1}/cert.pem --key-file {0}/{1}/key.pem " "--fullchain-file {0}/{1}/fullchain.pem " "--ca-file {0}/{1}/ca.pem --reloadcmd \"nginx -t && " "service nginx restart\" ".format(WOVar.wo_ssl_live, wo_domain_name, WOAcme.wo_acme_exec)): Log.valide(self, "Deploying SSL cert") else: Log.failed(self, "Deploying SSL cert") Log.error(self, "Unable to deploy certificate") if os.path.isdir('/var/www/{0}/conf/nginx'.format(wo_domain_name)): sslconf = open( "/var/www/{0}/conf/nginx/ssl.conf".format(wo_domain_name), encoding='utf-8', mode='w') sslconf.write("listen 443 ssl http2;\n" "listen [::]:443 ssl http2;\n" "ssl_certificate {0}/{1}/fullchain.pem;\n" "ssl_certificate_key {0}/{1}/key.pem;\n" "ssl_trusted_certificate {0}/{1}/ca.pem;\n" "ssl_stapling_verify on;\n".format( WOVar.wo_ssl_live, wo_domain_name)) sslconf.close() if not WOFileUtils.grep(self, '/var/www/22222/conf/nginx/ssl.conf', '/etc/letsencrypt'): Log.info(self, "Securing WordOps backend with current cert") sslconf = open("/var/www/22222/conf/nginx/ssl.conf", encoding='utf-8', mode='w') sslconf.write("ssl_certificate {0}/{1}/fullchain.pem;\n" "ssl_certificate_key {0}/{1}/key.pem;\n" "ssl_trusted_certificate {0}/{1}/ca.pem;\n" "ssl_stapling_verify on;\n".format( WOVar.wo_ssl_live, wo_domain_name)) sslconf.close() WOGit.add(self, ["/etc/letsencrypt"], msg="Adding letsencrypt folder") except IOError as e: Log.debug(self, str(e)) Log.debug(self, "Error occured while generating " "ssl.conf") return 0
def dist_upgrade(self): """ Similar to `apt-get upgrade` """ try: with open('/var/log/wo/wordops.log', 'a') as f: proc = subprocess.Popen("DEBIAN_FRONTEND=noninteractive " "apt-get dist-upgrade -o " "Dpkg::Options::=\"--force-confdef\"" " -o " "Dpkg::Options::=\"--force-confold\"" " -y ", shell=True, stdin=None, stdout=f, stderr=f, executable="/bin/bash") proc.wait() if proc.returncode == 0: return True else: Log.info(self, Log.FAIL + "Oops Something went " "wrong!!") Log.error(self, "Check the WordOps log for more details " "`tail /var/log/wo/wordops.log` and please try again...") except Exception as e: Log.error(self, "Error while installing packages, " "apt-get exited with error")
def default(self): filename = "woupdate" + time.strftime("%Y%m%d-%H%M%S") if self.app.pargs.travis: wo_branch = "updating-configuration" install_args = "--travis --force " elif self.app.pargs.beta: wo_branch = "beta" install_args = "" else: wo_branch = "master" install_args = "" if self.app.pargs.force: install_args = install_args + "--force " if self.app.pargs.preserve: install_args = install_args + "--preserve " WODownload.download(self, [[ "https://raw.githubusercontent.com/" "WordOps/WordOps/{0}/install".format(wo_branch), "/var/lib/wo/tmp/{0}".format(filename), "update script" ]]) try: Log.info(self, "updating WordOps, please wait...") os.system("/bin/bash /var/lib/wo/tmp/{0} " "-b {1} {2}".format(filename, wo_branch, install_args)) except OSError as e: Log.debug(self, str(e)) Log.error(self, "WordOps update failed !")
def clean_memcache(self): try: if (WOAptGet.is_installed(self, "memcached")): WOService.restart_service(self, "memcached") Log.info(self, "Cleaning MemCache") else: Log.info(self, "Memcache not installed") except Exception as e: Log.debug(self, "{0}".format(e)) Log.error(self, "Unable to restart Memcached", False)
def setupletsencrypt(self, acme_domains, acmedata): """Issue SSL certificates with acme.sh""" # check acme.sh is installed WOAcme.check_acme(self) # define variables all_domains = '\' -d \''.join(acme_domains) wo_acme_dns = acmedata['acme_dns'] keylenght = acmedata['keylength'] if acmedata['dns'] is True: acme_mode = "--dns {0}".format(wo_acme_dns) validation_mode = "DNS mode with {0}".format(wo_acme_dns) if acmedata['dnsalias'] is True: acme_mode = acme_mode + \ " --challenge-alias {0}".format(acmedata['acme_alias']) else: acme_mode = "-w /var/www/html" validation_mode = "Webroot challenge" Log.debug(self, "Validation : Webroot mode") if not os.path.isdir('/var/www/html/.well-known/acme-challenge'): WOFileUtils.mkdir(self, '/var/www/html/.well-known/acme-challenge') WOFileUtils.chown(self, '/var/www/html/.well-known', 'www-data', 'www-data', recursive=True) WOFileUtils.chmod(self, '/var/www/html/.well-known', 0o750, recursive=True) Log.info(self, "Validation mode : {0}".format(validation_mode)) Log.wait(self, "Issuing SSL cert with acme.sh") if not WOShellExec.cmd_exec( self, "{0} ".format(WOAcme.wo_acme_exec) + "--issue -d '{0}' {1} -k {2} -f".format( all_domains, acme_mode, keylenght)): Log.failed(self, "Issuing SSL cert with acme.sh") if acmedata['dns'] is True: Log.error( self, "Please make sure your properly " "set your DNS API credentials for acme.sh\n" "If you are using sudo, use \"sudo -E wo\"") return False else: Log.error( self, "Your domain is properly configured " "but acme.sh was unable to issue certificate.\n" "You can find more informations in " "/var/log/wo/wordops.log") return False else: Log.valide(self, "Issuing SSL cert with acme.sh") return True
def import_slow_log(self): """Default function for import slow log""" if os.path.isdir("{0}22222/htdocs/db/anemometer".format( WOVariables.wo_webroot)): if os.path.isfile("/var/log/mysql/mysql-slow.log"): # Get Anemometer user name and password Log.info(self, "Importing MySQL slow log to Anemometer") host = os.popen("grep -e \"\'host\'\" {0}22222/htdocs/".format( WOVariables.wo_webroot) + "db/anemometer/conf/config.inc.php " "| head -1 | cut -d\\\' -f4 | " "tr -d '\n'").read() user = os.popen("grep -e \"\'user\'\" {0}22222/htdocs/".format( WOVariables.wo_webroot) + "db/anemometer/conf/config.inc.php " "| head -1 | cut -d\\\' -f4 | " "tr -d '\n'").read() password = os.popen("grep -e \"\'password\'\" {0}22222/". format(WOVariables.wo_webroot) + "htdocs/db/anemometer/conf" "/config.inc.php " "| head -1 | cut -d\\\' -f4 | " "tr -d '\n'").read() # Import slow log Anemometer using pt-query-digest try: WOShellExec.cmd_exec( self, "pt-query-digest --user={0} " "--password={1} " "--review D=slow_query_log," "t=global_query_review " "--history D=slow_query_log,t=" "global_query_review_history " "--no-report --limit=0% " "--filter=\" \\$event->{{Bytes}} = " "length(\\$event->{{arg}}) " "and \\$event->{{hostname}}=\\\"" "{2}\\\"\" " "/var/log/mysql/mysql-slow.log".format( user, password, host)) except CommandExecutionError as e: Log.debug(self, str(e)) Log.error(self, "MySQL slow log import failed.") else: Log.error( self, "MySQL slow log file not found," " so not imported slow logs") else: Log.error( self, "Anemometer is not installed." + Log.ENDC + "\n Install Anemometer with:" + Log.BOLD + "\n `wo stack install --utils`" + Log.ENDC)
def debug_mysql(self): """Start/Stop MySQL debug""" # MySQL start global debug if (self.app.pargs.mysql == 'on' and not self.app.pargs.site_name): if not WOShellExec.cmd_exec(self, "mysql -e \"show variables like" " \'slow_query_log\';\" | " "grep ON"): Log.info(self, "Setting up MySQL slow log") WOMysql.execute(self, "set global slow_query_log = " "\'ON\';") WOMysql.execute(self, "set global slow_query_log_file = " "\'/var/log/mysql/mysql-slow.log\';") WOMysql.execute(self, "set global long_query_time = 2;") WOMysql.execute(self, "set global log_queries_not_using" "_indexes = \'ON\';") else: Log.info(self, "MySQL slow log is already enabled") self.msg = self.msg + ['/var/log/mysql/mysql-slow.log'] # MySQL stop global debug elif (self.app.pargs.mysql == 'off' and not self.app.pargs.site_name): if WOShellExec.cmd_exec(self, "mysql -e \"show variables like \'" "slow_query_log\';\" | grep ON"): Log.info(self, "Disabling MySQL slow log") WOMysql.execute(self, "set global slow_query_log = \'OFF\';") WOMysql.execute(self, "set global slow_query_log_file = \'" "/var/log/mysql/mysql-slow.log\';") WOMysql.execute(self, "set global long_query_time = 10;") WOMysql.execute(self, "set global log_queries_not_using_index" "es = \'OFF\';") WOShellExec.cmd_exec(self, "crontab -l | sed \'/#WordOps " "start/,/#WordOps end/d\' | crontab -") else: Log.info(self, "MySQL slow log already disabled")
def default(self): filename = "woupdate" + time.strftime("%Y%m%d-%H%M%S") WODownload.download(self, [["https://raw.githubusercontent.com/WordOps/WordOps/master/install", "/tmp/{0}".format(filename), "update script"]]) try: Log.info(self, "updating WordOps, please wait...") os.system("bash /tmp/{0}".format(filename)) except OSError as e: Log.debug(self, str(e)) Log.error(self, "WordOps update failed !") except Exception as e: Log.debug(self, str(e)) Log.error(self, "WordOps update failed !")
def clean_opcache(self): try: Log.info(self, "Cleaning opcache") urllib.request.urlopen("https://127.0.0.1:22222/cache" "/opcache/opgui.php?reset=1").read() except Exception as e: Log.debug(self, "{0}".format(e)) Log.debug(self, "Unable hit url, " " https://127.0.0.1:22222/cache/opcache/" "opgui.php?reset=1," " please check you have admin tools installed") Log.debug(self, "please check you have admin tools installed," " or install them with `wo stack install --admin`") Log.error(self, "Unable to clean opcache", False)
def update(self): """ Similar to `apt-get update` """ try: with open('/var/log/wo/wordops.log', 'a') as f: proc = subprocess.Popen('apt-get update', shell=True, stdin=None, stdout=f, stderr=subprocess.PIPE, executable="/bin/bash") proc.wait() output, error_output = proc.communicate() # Check what is error in error_output if "NO_PUBKEY" in str(error_output): # Split the output Log.info(self, "Fixing missing GPG keys, please wait...") error_list = str(error_output).split("\\n") # Use a loop to add misising keys for single_error in error_list: if "NO_PUBKEY" in single_error: key = single_error.rsplit(None, 1)[-1] WORepo.add_key(self, key, keyserver="hkp://pgp.mit.edu") proc = subprocess.Popen('apt-get update', shell=True, stdin=None, stdout=f, stderr=f, executable="/bin/bash") proc.wait() if proc.returncode == 0: return True else: Log.info(self, Log.FAIL + "Whoops, something went wrong...") Log.error( self, "Check the WordOps log for more details " "`tail /var/log/wo/wordops.log` " "and please try again...") except Exception as e: Log.error(self, "apt-get update exited with error")
def httpsredirect(self, wo_domain_name, acme_domains, redirect=True): """Create Nginx redirection from http to https""" wo_acme_domains = ' '.join(acme_domains) if redirect: Log.wait(self, "Adding HTTPS redirection") if WOFileUtils.enabledisable( self, '/etc/nginx/conf.d/force-ssl-{0}.conf'.format( wo_domain_name), enable=True): Log.valide(self, "Adding HTTPS redirection") return 0 else: try: sslconf = open( "/etc/nginx/conf.d/force-ssl-{0}.conf".format( wo_domain_name), encoding='utf-8', mode='w') sslconf.write( "server {\n" "\tlisten 80;\n" + "\tlisten [::]:80;\n" + "\tserver_name {0};\n".format(wo_acme_domains) + "\treturn 301 https://$host" "$request_uri;\n}") sslconf.close() except IOError as e: Log.debug(self, str(e)) Log.debug( self, "Error occured while generating " "/etc/nginx/conf.d/force-ssl-{0}.conf".format( wo_domain_name)) return 1 Log.valide(self, "Adding HTTPS redirection") return 0 else: if WOFileUtils.enabledisable( self, "/etc/nginx/conf.d/force-ssl-{0}.conf".format( wo_domain_name), enable=False): Log.info( self, "Disabled HTTPS Force Redirection for site " "{0}".format(wo_domain_name)) else: Log.info( self, "HTTPS redirection already disabled for site" "{0}".format(wo_domain_name)) return 0
def setuphsts(self, wo_domain_name): Log.info( self, "Adding /var/www/{0}/conf/nginx/hsts.conf".format(wo_domain_name)) hstsconf = open( "/var/www/{0}/conf/nginx/hsts.conf".format(wo_domain_name), encoding='utf-8', mode='w') hstsconf.write("more_set_headers " "\"Strict-Transport-Security: " "max-age=31536000; " "includeSubDomains; " "preload\";") hstsconf.close() return 0
def removeconf(self, domain): sslconf = ("/var/www/{0}/conf/nginx/ssl.conf" .format(domain)) sslforce = ("/etc/nginx/conf.d/force-ssl-{0}.conf" .format(domain)) acmedir = [ '{0}'.format(sslforce), '{0}'.format(sslconf), '{0}/{1}_ecc'.format(WOVar.wo_ssl_archive, domain), '{0}.disabled'.format(sslconf), '{0}.disabled' .format(sslforce), '{0}/{1}' .format(WOVar.wo_ssl_live, domain), '/etc/letsencrypt/shared/{0}.conf'.format(domain)] wo_domain = domain # check acme.sh is installed WOAcme.check_acme(self) if WOAcme.cert_check(self, wo_domain): Log.info(self, "Removing Acme configuration") Log.debug(self, "Removing Acme configuration") try: WOShellExec.cmd_exec( self, "{0} ".format(WOAcme.wo_acme_exec) + "--remove -d {0} --ecc".format(domain)) except CommandExecutionError as e: Log.debug(self, "{0}".format(e)) Log.error(self, "Cert removal failed") # remove all files and directories for dir in acmedir: if os.path.exists('{0}'.format(dir)): WOFileUtils.rm(self, '{0}'.format(dir)) # find all broken symlinks WOFileUtils.findBrokenSymlink(self, "/var/www") else: if os.path.islink("{0}".format(sslconf)): WOFileUtils.remove_symlink(self, "{0}".format(sslconf)) WOFileUtils.rm(self, '{0}'.format(sslforce)) if WOFileUtils.grepcheck(self, '/var/www/22222/conf/nginx/ssl.conf', '{0}'.format(domain)): Log.info( self, "Setting back default certificate for WordOps backend") with open("/var/www/22222/conf/nginx/" "ssl.conf", "w") as ssl_conf_file: ssl_conf_file.write("ssl_certificate " "/var/www/22222/cert/22222.crt;\n" "ssl_certificate_key " "/var/www/22222/cert/22222.key;\n")
def default(self): pargs = self.app.pargs filename = "woupdate" + time.strftime("%Y%m%d-%H%M%S") install_args = "" wo_branch = "master" if pargs.mainline or pargs.beta: wo_branch = "mainline" install_args = install_args + "--mainline " elif pargs.branch: wo_branch = pargs.branch install_args = install_args + "-b {0} ".format(wo_branch) if pargs.force: install_args = install_args + "--force " if pargs.travis: install_args = install_args + "--travis " wo_branch = "updating-configuration" if ((not pargs.force) and (not pargs.travis) and (not pargs.mainline) and (not pargs.beta) and (not pargs.branch)): wo_current = ("v{0}".format(WOVar.wo_version)) wo_latest = WODownload.latest_release(self, "WordOps/WordOps") if wo_current == wo_latest: Log.info( self, "WordOps {0} is already installed" .format(wo_latest)) self.app.close(0) if not os.path.isdir('/var/lib/wo/tmp'): os.makedirs('/var/lib/wo/tmp') WODownload.download(self, [["https://raw.githubusercontent.com/" "WordOps/WordOps/{0}/install" .format(wo_branch), "/var/lib/wo/tmp/{0}".format(filename), "update script"]]) if os.path.isfile('install'): Log.info(self, "updating WordOps from local install\n") try: Log.info(self, "updating WordOps, please wait...") os.system("/bin/bash install --travis") except OSError as e: Log.debug(self, str(e)) Log.error(self, "WordOps update failed !") else: try: Log.info(self, "updating WordOps, please wait...") os.system("/bin/bash /var/lib/wo/tmp/{0} " "{1}".format(filename, install_args)) except OSError as e: Log.debug(self, str(e)) Log.error(self, "WordOps update failed !") os.remove("/var/lib/wo/tmp/{0}".format(filename))
def check_upgrade(self): """ Similar to `apt-get upgrade` """ try: check_update = subprocess.Popen(['apt-get upgrade -s | grep ' '\"^Inst\" | wc -l'], stdout=subprocess.PIPE, shell=True).communicate()[0] if check_update == b'0\n': Log.error(self, "No package updates available") Log.info(self, "Following package updates are available:") subprocess.Popen("apt-get -s dist-upgrade | grep \"^Inst\"", shell=True, executable="/bin/bash", stdout=sys.stdout).communicate() except Exception as e: Log.error(self, "Unable to check for packages upgrades")
def clean_opcache(self): try: Log.info(self, "Cleaning opcache") opgui = requests.get( "https://127.0.0.1:22222/cache/opcache/opgui.php?reset=1") if opgui.status_code != '200': Log.warn(self, 'Cleaning opcache failed') except Exception as e: Log.debug(self, "{0}".format(e)) Log.debug( self, "Unable hit url, " " https://127.0.0.1:22222/cache/opcache/" "opgui.php?reset=1," " please check you have admin tools installed") Log.debug( self, "please check you have admin tools installed," " or install them with `wo stack install --admin`") Log.error(self, "Unable to clean opcache", False)
def start_service(self, service_name): """ start service Similar to `service xyz start` """ try: if service_name in ['nginx']: # Check Nginx configuration before executing command sub = subprocess.Popen('nginx -t', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) output, error_output = sub.communicate() if 'emerg' not in str(error_output): service_cmd = ('service {0} start'.format(service_name)) retcode = subprocess.getstatusoutput(service_cmd) if retcode[0] == 0: Log.info( self, "Starting Nginx " + "[" + Log.ENDC + "OK" + Log.OKBLUE + "]") return True else: Log.info( self, "Starting Nginx " + "[" + Log.FAIL + "Failed" + Log.OKBLUE + "]") return False else: service_cmd = ('service {0} start'.format(service_name)) Log.info(self, "Start : {0:10}".format(service_name), end='') retcode = subprocess.getstatusoutput(service_cmd) if retcode[0] == 0: Log.info(self, "[" + Log.ENDC + "OK" + Log.OKBLUE + "]") return True else: Log.debug(self, "{0}".format(retcode[1])) Log.info(self, "[" + Log.FAIL + "Failed" + Log.OKBLUE + "]") return False except OSError as e: Log.debug(self, "{0}".format(e)) Log.error(self, "\nFailed to start service {0}".format(service_name))
def secure_ssh(self): """Harden ssh security""" pargs = self.app.pargs if not pargs.force and not pargs.allowpassword: start_secure = input('Are you sure you to want to' ' harden SSH security ?' '\nSSH login with password will not ' 'be possible anymore. Please make sure ' 'you are already using SSH Keys.\n' 'Harden SSH security [y/N]') if start_secure != "Y" and start_secure != "y": Log.error(self, "Not hardening SSH security") if os.path.exists('/etc/ssh'): WOGit.add(self, ["/etc/ssh"], msg="Adding SSH into Git") Log.debug(self, "check if /etc/ssh/sshd_config exist") if os.path.isfile('/etc/ssh/sshd_config'): Log.debug(self, "looking for the current ssh port") for line in open('/etc/ssh/sshd_config', encoding='utf-8'): if 'Port' in line: ssh_line = line.strip() break port = (ssh_line).split(' ') current_ssh_port = (port[1]).strip() if os.getenv('SUDO_USER'): sudo_user = os.getenv('SUDO_USER') else: sudo_user = '' if pargs.allowpassword: wo_allowpassword = '******' else: wo_allowpassword = '******' data = dict(sshport=current_ssh_port, allowpass=wo_allowpassword, user=sudo_user) WOTemplate.deploy(self, '/etc/ssh/sshd_config', 'sshd.mustache', data) WOGit.add(self, ["/etc/ssh"], msg="Adding changed SSH port into Git") if not WOService.restart_service(self, 'ssh'): Log.error(self, "service SSH restart failed.") Log.info(self, "Successfully harden SSH security") else: Log.error(self, "SSH config file not found")