From 2defb346e3907dc08a4506ff06dcab75180344dd Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Fri, 23 Aug 2019 17:11:43 +0200 Subject: [PATCH 01/27] Fix migration from EE with custom nginx-ee --- install | 2 ++ wo/cli/plugins/stack.py | 19 ++++++++++++++----- wo/cli/plugins/stack_pref.py | 6 ++++-- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/install b/install index d40a208..6ae2bd7 100755 --- a/install +++ b/install @@ -494,6 +494,7 @@ wo_upgrade_nginx() { # install new nginx package if [ -n "$CHECK_NGINX_EE" ]; then if [ -x /usr/local/bin/wo ]; then + [ -f /etc/apt/preferences.d/nginx-block ] && { mv /etc/apt/preferences.d/nginx-block .;} # stop nginx service nginx stop # remove previous package @@ -544,6 +545,7 @@ wo_upgrade_nginx() { systemctl stop nginx systemctl start nginx fi + [ -f ./nginx-block ] && { mv nginx-block /etc/apt/preferences.d/nginx-block ;} } \ >> "$wo_install_log" 2>&1 diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index 12732cd..3ddc4ee 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -63,6 +63,8 @@ class WOStackController(CementBaseController): dict(help='Install PHP 7.3 stack', action='store_true')), (['--mysql'], dict(help='Install MySQL stack', action='store_true')), + (['--mariabackup'], + dict(help='Install MariaBackup stack', action='store_true')), (['--mysqlclient'], dict(help='Install MySQL client for remote MySQL server', action='store_true')), @@ -79,6 +81,8 @@ class WOStackController(CementBaseController): action='store_true')), (['--dashboard'], dict(help='Install WordOps dashboard', action='store_true')), + (['--extplorer'], + dict(help='Install eXtplorer file manager', action='store_true')), (['--adminer'], dict(help='Install Adminer stack', action='store_true')), (['--fail2ban'], @@ -119,6 +123,7 @@ class WOStackController(CementBaseController): and (not pargs.mysqlclient) and (not pargs.mysqltuner) and (not pargs.adminer) and (not pargs.utils) and (not pargs.redis) and (not pargs.proftpd) and + (not pargs.extplorer) and (not pargs.mariabackup) and (not pargs.phpredisadmin) and (not pargs.php73)): pargs.web = True @@ -139,17 +144,13 @@ class WOStackController(CementBaseController): pargs.wpcli = True if pargs.admin: - pargs.nginx = True - pargs.php = True - pargs.mysql = True + pargs.web = True pargs.adminer = True pargs.phpmyadmin = True - pargs.composer = True pargs.utils = True pargs.netdata = True pargs.dashboard = True pargs.phpredisadmin = True - pargs.mysqltuner = True if pargs.security: pargs.fail2ban = True @@ -213,6 +214,8 @@ class WOStackController(CementBaseController): # MariaDB 10.3 if pargs.mysql: + pargs.mariabackup = True + pargs.mysqltuner = True Log.debug(self, "Setting apt_packages variable for MySQL") if not WOShellExec.cmd_exec(self, "mysqladmin ping"): apt_packages = apt_packages + WOVariables.wo_mysql @@ -222,6 +225,12 @@ class WOStackController(CementBaseController): "for MySQL Client") apt_packages = apt_packages + WOVariables.wo_mysql_client + if pargs.mariabackup: + if not WOAptGet.is_installed(self, 'mariadb-backup'): + Log.debug(self, "Setting apt_packages variable " + "for MariaBackup") + apt_packages = apt_packages + ["mariadb-backup"] + # WP-CLI if pargs.wpcli: Log.debug(self, "Setting packages variable for WP-CLI") diff --git a/wo/cli/plugins/stack_pref.py b/wo/cli/plugins/stack_pref.py index 65ba0e3..8d1eca4 100644 --- a/wo/cli/plugins/stack_pref.py +++ b/wo/cli/plugins/stack_pref.py @@ -27,7 +27,8 @@ def pre_pref(self, apt_packages): """Pre settings to do before installation packages""" if (set(WOVariables.wo_mysql).issubset(set(apt_packages)) or - set(WOVariables.wo_mysql_client).issubset(set(apt_packages))): + set(WOVariables.wo_mysql_client).issubset(set(apt_packages)) or + set(['mariadb-backup']).issubset(set(apt_packages))): # add mariadb repository excepted on raspbian and ubuntu 19.04 if (not WOVariables.wo_distro == 'raspbian'): Log.info(self, "Adding repository for MySQL, please wait...") @@ -1182,7 +1183,8 @@ def post_pref(self, apt_packages, packages): .format(WOVariables.wo_webroot), "$cfg[\'Servers\'][$i][\'host\']" " = \'localhost\';", "$cfg" - "[\'Servers\'][$i][\'host\'] = \'{0}\';" + "[\'Servers\'][$i][\'host\'] " + "= \'{0}\';" .format(WOVariables.wo_mysql_host)) Log.debug(self, 'Setting Privileges of webroot permission to ' '{0}22222/htdocs/db/pma file ' From 1f342da054ecf2d82a849b3e04f82ea5398e71bb Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Sun, 25 Aug 2019 23:30:05 +0200 Subject: [PATCH 02/27] Detect .custom files by default --- wo/core/template.py | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/wo/core/template.py b/wo/core/template.py index a39200b..da1f6e9 100644 --- a/wo/core/template.py +++ b/wo/core/template.py @@ -9,8 +9,18 @@ Render Templates class WOTemplate(): def tmpl_render(self, fileconf, template, data, overwrite=True): data = dict(data) - if (not overwrite): - if not os.path.isfile('{0}'.format(fileconf)): + if (not os.path.isfile('{0}.custom' + .format(fileconf))): + if (not overwrite): + if not os.path.isfile('{0}'.format(fileconf)): + Log.debug(self, 'Writting the configuration to ' + 'file {0}'.format(fileconf)) + wo_template = open('{0}'.format(fileconf), + encoding='utf-8', mode='w') + self.app.render((data), '{0}'.format(template), + out=wo_template) + wo_template.close() + else: Log.debug(self, 'Writting the configuration to ' 'file {0}'.format(fileconf)) wo_template = open('{0}'.format(fileconf), @@ -19,20 +29,10 @@ class WOTemplate(): out=wo_template) wo_template.close() else: - if (not os.path.isfile('{0}.custom' - .format(fileconf))): - Log.debug(self, 'Writting the configuration to ' - 'file {0}'.format(fileconf)) - wo_template = open('{0}'.format(fileconf), - encoding='utf-8', mode='w') - self.app.render((data), '{0}'.format(template), - out=wo_template) - wo_template.close() - else: - Log.debug(self, 'Writting the configuration to ' - 'file {0}.orig'.format(fileconf)) - wo_template = open('{0}.orig'.format(fileconf), - encoding='utf-8', mode='w') - self.app.render((data), '{0}'.format(template), - out=wo_template) - wo_template.close() + Log.debug(self, 'Writting the configuration to ' + 'file {0}.orig'.format(fileconf)) + wo_template = open('{0}.orig'.format(fileconf), + encoding='utf-8', mode='w') + self.app.render((data), '{0}'.format(template), + out=wo_template) + wo_template.close() From 1eae7665a70db4eaaf1191b12dc412b8a0a139f8 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Mon, 26 Aug 2019 00:09:15 +0200 Subject: [PATCH 03/27] Add color steps to travis --- tests/travis.sh | 23 ++++++++++++++++--- wo/cli/plugins/stack_pref.py | 43 ++++++++++++++++++------------------ 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/tests/travis.sh b/tests/travis.sh index c41565f..3fd6685 100644 --- a/tests/travis.sh +++ b/tests/travis.sh @@ -3,6 +3,9 @@ # WordOps travis testing script # # +CSI='\033[' +CEND="${CSI}0m" +CGREEN="${CSI}1;32m" exit_script() { tar -I pigz -cf wordops.tar.gz /var/log/wo @@ -16,26 +19,38 @@ if ! { exit_script fi if ! { + echo -e "${CGREEN}#############################################${CEND}" + echo -e ' Simple site create ' + echo -e "${CGREEN}#############################################${CEND}" wo site create html.net --html && wo site create php.com --php && wo site create mysql.com --mysql && wo site create proxy.com --proxy=127.0.0.1:3000 wo site create wp1.com --wp && wo site create wpsc1.net --wpsc && wo site create wpfc1.com --wpfc wo site create wpsc-php73.net --wpsc --php73 && wo site create wpfc-php73.net --wpfc --php73 wo site create wprocket.net --wprocket && wo site create wprocket-php73.net --wprocket --php73 wo site create wpce.net --wpce && wo site create wpce-php73.net --wpce --php73 wo site create wpredis.net --wpredis && wo site create wpredis-php73.net --wpredis --php73 - wo site create wpsubdir1.com --wpsubdir && wo site create wpsubdir-php73.com --wpsubdir --php73 + }; then exit_script fi if ! { + echo -e "${CGREEN}#############################################${CEND}" + echo -e ' Multi-site create ' + echo -e "${CGREEN}#############################################${CEND}" + wo site create wpsubdir1.com --wpsubdir && wo site create wpsubdir-php73.com --wpsubdir --php73 wo site create wpsubdirwpsc1.com --wpsubdir --wpsc && wo site create wpsubdirwpsc2.com --wpsubdir --wpfc && wo site create wpsubdirwpsc1-php73.com --wpsubdir --wpsc --php73 && wo site create wpsubdirwpsc2-php73.com --wpsubdir --wpfc --php73 wo site create wpsubdomain1.com --wpsubdomain && wo site create wpsubdomain1-php73.com --wpsubdomain --php73 && wo site create wpsubdomainwpsc.org --wpsubdomain --wpsc && wo site create wpsubdomainwpfc.org --wpsubdomain --wpfc && wo site create wpsubdomainwpfc2.in --wpfc --wpsubdomain - + echo -e "${CGREEN}#############################################${CEND}" + echo -e ' wo site update ' + echo -e "${CGREEN}#############################################${CEND}" wo site create 1.com --html && wo site create 2.com --php && wo site create 3.com --mysql wo site update 1.com --wp && wo site update 2.com --php73 && wo site update 3.com --php73 && wo site update 1.com --wpfc && wo site update 1.com --wpsc && wo site update 1.com --wpredis }; then exit_script fi if ! { + echo -e "${CGREEN}#############################################${CEND}" + echo -e ' wo stack upgrade ' + echo -e "${CGREEN}#############################################${CEND}" wo stack upgrade --force wo stack upgrade --php --force wo stack upgrade --netdata --force @@ -45,7 +60,9 @@ if ! { }; then exit_script fi - + echo -e "${CGREEN}#############################################${CEND}" + echo -e ' various informations ' + echo -e "${CGREEN}#############################################${CEND}" wp --allow-root --info cat /etc/nginx/nginx.conf wo site info wp1.com diff --git a/wo/cli/plugins/stack_pref.py b/wo/cli/plugins/stack_pref.py index 8d1eca4..cc2899e 100644 --- a/wo/cli/plugins/stack_pref.py +++ b/wo/cli/plugins/stack_pref.py @@ -182,32 +182,31 @@ def post_pref(self, apt_packages, packages): wo_nginx.write('fastcgi_param \tSCRIPT_FILENAME ' '\t$request_filename;\n') - if os.path.isfile('/etc/nginx/nginx.conf'): - data = dict(php="9000", debug="9001", + data = dict(php="9000", debug="9001", php7="9070", debug7="9170") - WOTemplate.tmpl_render( - self, '{0}/upstream.conf'.format(ngxcnf), - 'upstream.mustache', data, overwrite=True) + WOTemplate.tmpl_render( + self, '{0}/upstream.conf'.format(ngxcnf), + 'upstream.mustache', data, overwrite=True) - data = dict(phpconf=True if - WOAptGet.is_installed(self, 'php7.2-fpm') - else False) - WOTemplate.tmpl_render(self, - '{0}/stub_status.conf'.format(ngxcnf), - 'stub_status.mustache', data) - data = dict() - WOTemplate.tmpl_render(self, - '{0}/webp.conf'.format(ngxcnf), - 'webp.mustache', data) + data = dict(phpconf=True if + WOAptGet.is_installed(self, 'php7.2-fpm') + else False) + WOTemplate.tmpl_render(self, + '{0}/stub_status.conf'.format(ngxcnf), + 'stub_status.mustache', data) + data = dict() + WOTemplate.tmpl_render(self, + '{0}/webp.conf'.format(ngxcnf), + 'webp.mustache', data) - WOTemplate.tmpl_render(self, - '{0}/cloudflare.conf'.format(ngxcnf), - 'cloudflare.mustache', data) + WOTemplate.tmpl_render(self, + '{0}/cloudflare.conf'.format(ngxcnf), + 'cloudflare.mustache', data) - WOTemplate.tmpl_render(self, - '{0}/map-wp-fastcgi-cache.conf'.format( - ngxcnf), - 'map-wp.mustache', data) + WOTemplate.tmpl_render(self, + '{0}/map-wp-fastcgi-cache.conf'.format( + ngxcnf), + 'map-wp.mustache', data) # Setup Nginx common directory if not os.path.exists('{0}'.format(ngxcom)): From d9bd7868470ae6541e2bcc325efddc5d307ebbb3 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Mon, 26 Aug 2019 03:08:33 +0200 Subject: [PATCH 04/27] Remove extra line --- wo/core/logging.py | 1 - 1 file changed, 1 deletion(-) diff --git a/wo/core/logging.py b/wo/core/logging.py index 89a53da..84a3508 100644 --- a/wo/core/logging.py +++ b/wo/core/logging.py @@ -24,7 +24,6 @@ class Log: if exit: self.app.close(1) - def info(self, msg, end='\n', log=True): """ Logs info messages into log file From 42e856173f7e7213287e8be5a372ba39a2c995ca Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Mon, 26 Aug 2019 18:05:26 +0200 Subject: [PATCH 05/27] Several new features - cht.sh stack : linux online cheatsheet. Usage : `cheat `. Example for tar : `cheat tar` - ClamAV anti-virus with weekly cronjob to update signatures database - Internal function to add daily cronjobs - Additional comment to detect previous configuration tuning (MariaDB & Redis) - Domain/Subdomain detection based on public domain suffixes list - Increase Nginx & MariaDB systemd open_files limits - Cronjob to update Cloudflare IPs list --- CHANGELOG.md | 16 ++ install | 40 ++++- wo/cli/plugins/site.py | 226 +++++++++++++++------------- wo/cli/plugins/site_functions.py | 6 +- wo/cli/plugins/stack.py | 53 ++++++- wo/cli/plugins/stack_pref.py | 122 ++++++++++----- wo/cli/plugins/stack_upgrade.py | 2 +- wo/cli/templates/cf-update.sh | 23 +++ wo/cli/templates/freshclam.mustache | 11 ++ wo/core/cron.py | 14 ++ wo/core/domainvalidate.py | 27 ++++ wo/core/services.py | 24 ++- 12 files changed, 397 insertions(+), 167 deletions(-) create mode 100644 wo/cli/templates/cf-update.sh create mode 100644 wo/cli/templates/freshclam.mustache diff --git a/CHANGELOG.md b/CHANGELOG.md index a4c5a67..d610049 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### v3.9.x - [Unreleased] +#### Added + +- cht.sh stack : linux online cheatsheet. Usage : `cheat `. Example for tar : `cheat tar` +- ClamAV anti-virus with weekly cronjob to update signatures database +- Internal function to add daily cronjobs +- Additional comment to detect previous configuration tuning (MariaDB & Redis) +- Domain/Subdomain detection based on public domain suffixes list +- Increase Nginx & MariaDB systemd open_files limits +- Cronjob to update Cloudflare IPs list + +#### Changed + +- eXplorer filemanager isn't installed with WordOps dashboard anymore, and a flag `--extplorer` is available. But it's still installed when running the command `wo stack install` +- Template rendering function now check for a .custom file before overwriting a configuration by default. +- flag `--letsencrypt=subdomain` is not required anymore, you can use `--letsencrypt` or `-le` + ### v3.9.8.3 - 2019-08-21 #### Changed diff --git a/install b/install index 6ae2bd7..a13716b 100755 --- a/install +++ b/install @@ -494,7 +494,7 @@ wo_upgrade_nginx() { # install new nginx package if [ -n "$CHECK_NGINX_EE" ]; then if [ -x /usr/local/bin/wo ]; then - [ -f /etc/apt/preferences.d/nginx-block ] && { mv /etc/apt/preferences.d/nginx-block .;} + [ -f /etc/apt/preferences.d/nginx-block ] && { mv /etc/apt/preferences.d/nginx-block /var/lib/wo/tmp/nginx-block; } # stop nginx service nginx stop # remove previous package @@ -545,7 +545,7 @@ wo_upgrade_nginx() { systemctl stop nginx systemctl start nginx fi - [ -f ./nginx-block ] && { mv nginx-block /etc/apt/preferences.d/nginx-block ;} + [ -f /var/lib/wo/tmp/nginx-block ] && { mv /var/lib/wo/tmp/nginx-block /etc/apt/preferences.d/nginx-block; } } \ >> "$wo_install_log" 2>&1 @@ -655,7 +655,6 @@ wo_tweak_kernel() { # apply sysctl tweaks sysctl -eq -p /etc/sysctl.d/60-wo-tweaks.conf fi - } wo_systemd_tweak() { @@ -678,6 +677,37 @@ wo_systemd_tweak() { } +wo_domain_suffix() { + curl -sL https://raw.githubusercontent.com/publicsuffix/list/master/public_suffix_list.dat | sed '/^\/\//d' | sed '/^$/d' | sed 's/^\s+//g' > /var/lib/wo/public_suffix_list.dat +} + +wo_mariadb_tweak() { + # increase mariadb open_files_limit + { + if [ -d /etc/systemd/system/mariadb.service.d ] && [ ! -f /etc/systemd/system/mariadb.service.d/limits.conf ]; then + echo -e '[Service]\nLimitNOFILE=500000' > /etc/systemd/system/mariadb.service.d/limits.conf + systemctl daemon-reload + service mysql restart + fi + } >> /var/log/wo/install.log 2>&1 +} + +wo_nginx_tweak() { + # increase nginx open_files_limit + { + if [ -x /usr/sbin/nginx ]; then + if [ ! -d /etc/systemd/system/nginx.service.d ]; then + mkdir -p /etc/systemd/system/nginx.service.d + if [ ! -f /etc/systemd/system/nginx.service.d/limits.conf ]; then + echo -e '[Service]\nLimitNOFILE=500000' > /etc/systemd/system/nginx.service.d/limits.conf + systemctl daemon-reload + nginx -t && service nginx restart + fi + fi + fi + } >> /var/log/wo/install.log 2>&1 +} + wo_clean() { rm -rf /usr/local/lib/python3.*/dist-packages/wo-* } @@ -794,6 +824,8 @@ else wo_lib_echo "Adding systemd service tweak" | tee -ai $wo_install_log wo_systemd_tweak | tee -ai $wo_install_log fi + wo_nginx_tweak | tee -ai $wo_install_log + wo_mysql_tweak | tee -ai $wo_install_log wo_lib_echo "Running post-install steps " | tee -ai $wo_install_log wo_update_wp_cli | tee -ai $wo_install_log else @@ -836,6 +868,8 @@ else wo_lib_echo "Adding systemd service tweak" | tee -ai $wo_install_log wo_systemd_tweak | tee -ai $wo_install_log fi + wo_nginx_tweak | tee -ai $wo_install_log + wo_mysql_tweak | tee -ai $wo_install_log wo_lib_echo "Running post-install steps " | tee -ai $wo_install_log wo_git_init | tee -ai $wo_install_log wo_update_wp_cli | tee -ai $wo_install_log diff --git a/wo/cli/plugins/site.py b/wo/cli/plugins/site.py index 8455856..52188c3 100644 --- a/wo/cli/plugins/site.py +++ b/wo/cli/plugins/site.py @@ -4,7 +4,7 @@ from cement.core import handler, hook from wo.core.sslutils import SSL from wo.core.variables import WOVariables from wo.core.shellexec import WOShellExec -from wo.core.domainvalidate import ValidateDomain +from wo.core.domainvalidate import ValidateDomain, GetDomainlevel from wo.core.fileutils import WOFileUtils from wo.cli.plugins.site_functions import * from wo.core.services import WOService @@ -45,18 +45,19 @@ class WOSiteController(CementBaseController): @expose(help="Enable site example.com") def enable(self): - if not self.app.pargs.site_name: + pargs = self.app.pargs + if not pargs.site_name: try: - while not self.app.pargs.site_name: - self.app.pargs.site_name = (input('Enter site name : ') - .strip()) + 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') - self.app.pargs.site_name = self.app.pargs.site_name.strip() + pargs.site_name = pargs.site_name.strip() # validate domain name - (wo_domain, wo_www_domain) = ValidateDomain(self.app.pargs.site_name) + (wo_domain, wo_www_domain) = ValidateDomain(pargs.site_name) # check if site exists if not check_domain_exists(self, wo_domain): @@ -83,17 +84,18 @@ class WOSiteController(CementBaseController): @expose(help="Disable site example.com") def disable(self): - if not self.app.pargs.site_name: + pargs = self.app.pargs + if not pargs.site_name: try: - while not self.app.pargs.site_name: - self.app.pargs.site_name = (input('Enter site name : ') - .strip()) + 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') - self.app.pargs.site_name = self.app.pargs.site_name.strip() - (wo_domain, wo_www_domain) = ValidateDomain(self.app.pargs.site_name) + pargs.site_name = pargs.site_name.strip() + (wo_domain, wo_www_domain) = ValidateDomain(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)) @@ -124,16 +126,18 @@ class WOSiteController(CementBaseController): @expose(help="Get example.com information") def info(self): - if not self.app.pargs.site_name: + pargs = self.app.pargs + if not pargs.site_name: try: - while not self.app.pargs.site_name: - self.app.pargs.site_name = (input('Enter site name : ') - .strip()) + 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') - self.app.pargs.site_name = self.app.pargs.site_name.strip() - (wo_domain, wo_www_domain) = ValidateDomain(self.app.pargs.site_name) + pargs.site_name = pargs.site_name.strip() + (wo_domain, wo_www_domain) = ValidateDomain(pargs.site_name) + wo_domain_type = GetDomainlevel(wo_domain) wo_db_name = '' wo_db_user = '' wo_db_pass = '' @@ -143,7 +147,6 @@ class WOSiteController(CementBaseController): if os.path.isfile('/etc/nginx/sites-available/{0}' .format(wo_domain)): siteinfo = getSiteInfo(self, wo_domain) - sitetype = siteinfo.site_type cachetype = siteinfo.cache_type wo_site_webroot = siteinfo.site_path @@ -179,8 +182,9 @@ class WOSiteController(CementBaseController): @expose(help="Monitor example.com logs") def log(self): - self.app.pargs.site_name = self.app.pargs.site_name.strip() - (wo_domain, wo_www_domain) = ValidateDomain(self.app.pargs.site_name) + pargs = self.app.pargs + pargs.site_name = pargs.site_name.strip() + (wo_domain, wo_www_domain) = ValidateDomain(pargs.site_name) wo_site_webroot = getSiteInfo(self, wo_domain).site_path if not check_domain_exists(self, wo_domain): @@ -191,17 +195,18 @@ class WOSiteController(CementBaseController): @expose(help="Display Nginx configuration of example.com") def show(self): - if not self.app.pargs.site_name: + pargs = self.app.pargs + if not pargs.site_name: try: - while not self.app.pargs.site_name: - self.app.pargs.site_name = (input('Enter site name : ') - .strip()) + 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 - self.app.pargs.site_name = self.app.pargs.site_name.strip() - (wo_domain, wo_www_domain) = ValidateDomain(self.app.pargs.site_name) + pargs.site_name = pargs.site_name.strip() + (wo_domain, wo_www_domain) = ValidateDomain(pargs.site_name) if not check_domain_exists(self, wo_domain): Log.error(self, "site {0} does not exist".format(wo_domain)) @@ -221,17 +226,18 @@ class WOSiteController(CementBaseController): @expose(help="Change directory to site webroot") def cd(self): - if not self.app.pargs.site_name: + pargs = self.app.pargs + if not pargs.site_name: try: - while not self.app.pargs.site_name: - self.app.pargs.site_name = (input('Enter site name : ') - .strip()) + 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, 'Unable to read input, please try again') - self.app.pargs.site_name = self.app.pargs.site_name.strip() - (wo_domain, wo_www_domain) = ValidateDomain(self.app.pargs.site_name) + pargs.site_name = pargs.site_name.strip() + (wo_domain, wo_www_domain) = ValidateDomain(pargs.site_name) if not check_domain_exists(self, wo_domain): Log.error(self, "site {0} does not exist".format(wo_domain)) @@ -261,17 +267,18 @@ class WOSiteEditController(CementBaseController): @expose(hide=True) def default(self): - if not self.app.pargs.site_name: + pargs = self.app.pargs + if not pargs.site_name: try: - while not self.app.pargs.site_name: - self.app.pargs.site_name = (input('Enter site name : ') - .strip()) + 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, 'Unable to read input, Please try again') - self.app.pargs.site_name = self.app.pargs.site_name.strip() - (wo_domain, wo_www_domain) = ValidateDomain(self.app.pargs.site_name) + pargs.site_name = pargs.site_name.strip() + (wo_domain, wo_www_domain) = ValidateDomain(pargs.site_name) if not check_domain_exists(self, wo_domain): Log.error(self, "site {0} does not exist".format(wo_domain)) @@ -381,43 +388,43 @@ class WOSiteCreateController(CementBaseController): def default(self): pargs = self.app.pargs if pargs.php72: - self.app.pargs.php = True + pargs.php = True # self.app.render((data), 'default.mustache') # Check domain name validation data = dict() host, port = None, None try: - stype, cache = detSitePar(vars(self.app.pargs)) + stype, cache = detSitePar(vars(pargs)) except RuntimeError as e: Log.debug(self, str(e)) Log.error(self, "Please provide valid options to creating site") - if stype is None and self.app.pargs.proxy: + if stype is None and pargs.proxy: stype, cache = 'proxy', '' - proxyinfo = self.app.pargs.proxy[0].strip() + proxyinfo = pargs.proxy[0].strip() if not proxyinfo: Log.error(self, "Please provide proxy server host information") proxyinfo = proxyinfo.split(':') host = proxyinfo[0].strip() port = '80' if len(proxyinfo) < 2 else proxyinfo[1].strip() - elif stype is None and not self.app.pargs.proxy: + elif stype is None and not pargs.proxy: stype, cache = 'html', 'basic' - elif stype and self.app.pargs.proxy: + elif stype and pargs.proxy: Log.error(self, "proxy should not be used with other site types") - if not self.app.pargs.site_name: + if not pargs.site_name: try: - while not self.app.pargs.site_name: + while not pargs.site_name: # preprocessing before finalize site name - self.app.pargs.site_name = (input('Enter site name : ') - .strip()) + pargs.site_name = (input('Enter site name : ') + .strip()) except IOError as e: Log.debug(self, str(e)) Log.error(self, "Unable to input site name, Please try again!") - self.app.pargs.site_name = self.app.pargs.site_name.strip() - (wo_domain, wo_www_domain) = ValidateDomain(self.app.pargs.site_name) - + pargs.site_name = pargs.site_name.strip() + (wo_domain, wo_www_domain) = ValidateDomain(pargs.site_name) + wo_domain_type = GetDomainlevel(wo_domain) if not wo_domain.strip(): Log.error("Invalid domain name, " "Provide valid domain name") @@ -442,7 +449,7 @@ class WOSiteCreateController(CementBaseController): data['port'] = port data['basic'] = True - if self.app.pargs.php73: + if pargs.php73: data = dict(site_name=wo_domain, www_domain=wo_www_domain, static=False, basic=False, php73=True, wp=False, wpfc=False, wpsc=False, wprocket=False, wpce=False, @@ -475,9 +482,9 @@ class WOSiteCreateController(CementBaseController): data['wp'] = True data['basic'] = False data[cache] = True - data['wp-user'] = self.app.pargs.user - data['wp-email'] = self.app.pargs.email - data['wp-pass'] = self.app.pargs.wppass + data['wp-user'] = pargs.user + data['wp-email'] = pargs.email + data['wp-pass'] = pargs.wppass if stype in ['wpsubdir', 'wpsubdomain']: data['multisite'] = True if stype == 'wpsubdir': @@ -485,25 +492,25 @@ class WOSiteCreateController(CementBaseController): else: pass - if data and self.app.pargs.php73: + if data and pargs.php73: data['php73'] = True php73 = 1 elif data: data['php73'] = False php73 = 0 - if ((not self.app.pargs.wpfc) and - (not self.app.pargs.wpsc) and - (not self.app.pargs.wprocket) and - (not self.app.pargs.wpce) and - (not self.app.pargs.wpredis)): + if ((not pargs.wpfc) and + (not pargs.wpsc) and + (not pargs.wprocket) and + (not pargs.wpce) and + (not pargs.wpredis)): data['basic'] = True if (cache == 'wpredis'): cache = 'wpredis' data['wpredis'] = True data['basic'] = False - self.app.pargs.wpredis = True + pargs.wpredis = True # Check rerequired packages are installed or not wo_auth = site_package_check(self, stype) @@ -619,7 +626,7 @@ class WOSiteCreateController(CementBaseController): "and please try again") # Setup WordPress if Wordpress site - if (data['wp'] and (not self.app.pargs.vhostonly)): + if (data['wp'] and (not pargs.vhostonly)): try: wo_wp_creds = setupwordpress(self, data) # Add database information for site into database @@ -644,7 +651,7 @@ class WOSiteCreateController(CementBaseController): "`tail /var/log/wo/wordops.log` " "and please try again") - if (data['wp'] and (self.app.pargs.vhostonly)): + if (data['wp'] and (pargs.vhostonly)): try: wo_wp_creds = setupwordpress(self, data) # Add database information for site into database @@ -745,7 +752,7 @@ class WOSiteCreateController(CementBaseController): for msg in wo_auth: Log.info(self, Log.ENDC + msg, log=False) - if data['wp'] and (not self.app.pargs.vhostonly): + if data['wp'] and (not pargs.vhostonly): Log.info(self, Log.ENDC + "WordPress admin user :" " {0}".format(wo_wp_creds['wp_user']), log=False) Log.info(self, Log.ENDC + "WordPress admin user password : {0}" @@ -759,32 +766,32 @@ class WOSiteCreateController(CementBaseController): Log.error(self, "Check the log for details: " "`tail /var/log/wo/wordops.log` and please try again") - if self.app.pargs.letsencrypt: + if pargs.letsencrypt: data['letsencrypt'] = True letsencrypt = True - if self.app.pargs.dns: + if pargs.dns: wo_acme_dns = pargs.dns if data['letsencrypt'] is True: - if self.app.pargs.letsencrypt == "subdomain": - if self.app.pargs.dns: + if pargs.letsencrypt == "subdomain": + if pargs.dns: setupLetsEncrypt(self, wo_domain, True, False, True, wo_acme_dns) else: setupLetsEncrypt(self, wo_domain, True) httpsRedirect(self, wo_domain) - elif self.app.pargs.letsencrypt == "wildcard": + elif pargs.letsencrypt == "wildcard": setupLetsEncrypt(self, wo_domain, False, True, True, wo_acme_dns) httpsRedirect(self, wo_domain, True, True) else: - if self.app.pargs.dns: + if pargs.dns: setupLetsEncrypt(self, wo_domain, False, False, True, wo_acme_dns) else: setupLetsEncrypt(self, wo_domain) httpsRedirect(self, wo_domain) - if self.app.pargs.hsts: + if pargs.hsts: setupHsts(self, wo_domain) site_url_https(self, wo_domain) @@ -915,6 +922,7 @@ class WOSiteUpdateController(CementBaseController): self.doupdatesite(pargs) def doupdatesite(self, pargs): + pargs = self.app.pargs letsencrypt = False php73 = None @@ -950,7 +958,7 @@ class WOSiteUpdateController(CementBaseController): (wo_domain, wo_www_domain, ) = ValidateDomain(pargs.site_name) wo_site_webroot = WOVariables.wo_webroot + wo_domain - + wo_domain_type = GetDomainlevel(wo_domain) check_site = getSiteInfo(self, wo_domain) if check_site is None: @@ -1342,27 +1350,30 @@ class WOSiteUpdateController(CementBaseController): " http://{0}".format(wo_domain)) return 0 - if self.app.pargs.letsencrypt: - if self.app.pargs.dns: + if pargs.letsencrypt: + if pargs.dns: wo_acme_dns = pargs.dns if data['letsencrypt'] is True: + if (wo_domain_type == 'subdomain' and + pargs.letsencrypt != 'wildcard'): + pargs.letsencrypt == 'subdomain' if not os.path.isfile("{0}/conf/nginx/ssl.conf.disabled" .format(wo_site_webroot)): - if self.app.pargs.letsencrypt == "on": - if self.app.pargs.dns: + if pargs.letsencrypt == "on": + if pargs.dns: setupLetsEncrypt(self, wo_domain, False, False, True, wo_acme_dns) else: setupLetsEncrypt(self, wo_domain) httpsRedirect(self, wo_domain) - elif self.app.pargs.letsencrypt == "subdomain": - if self.app.pargs.dns: + elif pargs.letsencrypt == "subdomain": + if pargs.dns: setupLetsEncrypt(self, wo_domain, True, False, True, wo_acme_dns) else: setupLetsEncrypt(self, wo_domain, True) httpsRedirect(self, wo_domain) - elif self.app.pargs.letsencrypt == "wildcard": + elif pargs.letsencrypt == "wildcard": setupLetsEncrypt(self, wo_domain, False, True, True, wo_acme_dns) httpsRedirect(self, wo_domain, True, True) @@ -1391,7 +1402,7 @@ class WOSiteUpdateController(CementBaseController): ".PLEASE renew soon . ") elif data['letsencrypt'] is False: - if self.app.pargs.letsencrypt == "off": + if pargs.letsencrypt == "off": if os.path.isfile("{0}/conf/nginx/ssl.conf" .format(wo_site_webroot)): Log.info(self, 'Setting Nginx configuration') @@ -1407,8 +1418,8 @@ class WOSiteUpdateController(CementBaseController): '{0}/conf/nginx/' 'hsts.conf.disabled' .format(wo_site_webroot)) - elif (self.app.pargs.letsencrypt == "clean" or - self.app.pargs.letsencrypt == "purge"): + elif (pargs.letsencrypt == "clean" or + pargs.letsencrypt == "purge"): removeAcmeConf(self, wo_domain) if not WOService.reload_service(self, 'nginx'): Log.error(self, "service nginx reload failed. " @@ -1798,16 +1809,18 @@ class WOSiteDeleteController(CementBaseController): @expose(help="Delete website configuration and files") @expose(hide=True) def default(self): - if not self.app.pargs.site_name: + pargs = self.app.pargs + if not pargs.site_name: try: - while not self.app.pargs.site_name: - self.app.pargs.site_name = (input('Enter site name : ') - .strip()) + while not pargs.site_name: + pargs.site_name = (input('Enter site name : ') + .strip()) except IOError as e: Log.error(self, 'could not input site name') - self.app.pargs.site_name = self.app.pargs.site_name.strip() - (wo_domain, wo_www_domain) = ValidateDomain(self.app.pargs.site_name) + pargs.site_name = pargs.site_name.strip() + (wo_domain, wo_www_domain) = ValidateDomain(pargs.site_name) + wo_domain_type = GetDomainlevel(wo_domain) wo_db_name = '' wo_prompt = '' wo_nginx_prompt = '' @@ -1818,9 +1831,9 @@ class WOSiteDeleteController(CementBaseController): if not check_domain_exists(self, wo_domain): Log.error(self, "site {0} does not exist".format(wo_domain)) - if ((not self.app.pargs.db) and (not self.app.pargs.files) and - (not self.app.pargs.all)): - self.app.pargs.all = True + if ((not pargs.db) and (not pargs.files) and + (not pargs.all)): + pargs.all = True # Gather information from wo-db for wo_domain check_site = getSiteInfo(self, wo_domain) @@ -1834,18 +1847,18 @@ class WOSiteDeleteController(CementBaseController): wo_mysql_grant_host = self.app.config.get('mysql', 'grant-host') if wo_db_name == 'deleted': mark_db_deleted = True - if self.app.pargs.all: - self.app.pargs.db = True - self.app.pargs.files = True + if pargs.all: + pargs.db = True + pargs.files = True else: - if self.app.pargs.all: + if pargs.all: mark_db_deleted = True - self.app.pargs.files = True + pargs.files = True # Delete website database - if self.app.pargs.db: + if pargs.db: if wo_db_name != 'deleted' and wo_db_name != '': - if not self.app.pargs.no_prompt: + if not pargs.no_prompt: wo_db_prompt = input('Are you sure, you want to delete' ' database [y/N]: ') else: @@ -1870,9 +1883,9 @@ class WOSiteDeleteController(CementBaseController): ) # Delete webroot - if self.app.pargs.files: + if pargs.files: if wo_site_webroot != 'deleted': - if not self.app.pargs.no_prompt: + if not pargs.no_prompt: wo_web_prompt = input('Are you sure, you want to delete ' 'webroot [y/N]: ') else: @@ -1891,7 +1904,7 @@ class WOSiteDeleteController(CementBaseController): mark_webroot_deleted = True Log.info(self, "Webroot seems to be already deleted") - if not self.app.pargs.force: + if not pargs.force: if (mark_webroot_deleted and mark_db_deleted): # TODO Delete nginx conf removeNginxConf(self, wo_domain) @@ -1925,15 +1938,16 @@ class WOSiteListController(CementBaseController): @expose(help="Lists websites") def default(self): + pargs = self.app.pargs sites = getAllsites(self) if not sites: pass - if self.app.pargs.enabled: + if pargs.enabled: for site in sites: if site.is_enabled: Log.info(self, "{0}".format(site.sitename)) - elif self.app.pargs.disabled: + elif pargs.disabled: for site in sites: if not site.is_enabled: Log.info(self, "{0}".format(site.sitename)) diff --git a/wo/cli/plugins/site_functions.py b/wo/cli/plugins/site_functions.py index 7b30f21..54774f6 100644 --- a/wo/cli/plugins/site_functions.py +++ b/wo/cli/plugins/site_functions.py @@ -1279,8 +1279,10 @@ def doCleanupAction(self, domain='', webroot='', dbname='', dbuser='', if os.path.isfile('/etc/nginx/sites-available/{0}' .format(domain)): removeNginxConf(self, domain) - if os.path.isdir('/etc/letsencrypt/renewal/{0}_ecc' - .format(domain)): + if (os.path.isdir('/etc/letsencrypt/renewal/{0}_ecc' + .format(domain)) or + os.path.isdir('/etc/letsencrypt/live/{0}' + .format(domain))): removeAcmeConf(self, domain) if webroot: diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index 3ddc4ee..07b5a1c 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -87,8 +87,12 @@ class WOStackController(CementBaseController): dict(help='Install Adminer stack', action='store_true')), (['--fail2ban'], dict(help='Install Fail2ban stack', action='store_true')), + (['--clamav'], + dict(help='Install ClamAV stack', action='store_true')), (['--utils'], dict(help='Install Utils stack', action='store_true')), + (['--cheat'], + dict(help='Install cht.sh stack', action='store_true')), (['--redis'], dict(help='Install Redis', action='store_true')), (['--phpredisadmin'], @@ -124,11 +128,12 @@ class WOStackController(CementBaseController): (not pargs.adminer) and (not pargs.utils) and (not pargs.redis) and (not pargs.proftpd) and (not pargs.extplorer) and (not pargs.mariabackup) and + (not pargs.cheat) and (not pargs.clamav) and (not pargs.phpredisadmin) and (not pargs.php73)): pargs.web = True pargs.admin = True - pargs.security = True + pargs.fail2ban = True if pargs.all: pargs.web = True @@ -151,9 +156,11 @@ class WOStackController(CementBaseController): pargs.netdata = True pargs.dashboard = True pargs.phpredisadmin = True + pargs.cheat = True if pargs.security: pargs.fail2ban = True + pargs.clamav = True # Redis if pargs.redis: @@ -220,11 +227,13 @@ class WOStackController(CementBaseController): if not WOShellExec.cmd_exec(self, "mysqladmin ping"): apt_packages = apt_packages + WOVariables.wo_mysql + # mysqlclient if pargs.mysqlclient: Log.debug(self, "Setting apt_packages variable " "for MySQL Client") apt_packages = apt_packages + WOVariables.wo_mysql_client + # mariabackup if pargs.mariabackup: if not WOAptGet.is_installed(self, 'mariadb-backup'): Log.debug(self, "Setting apt_packages variable " @@ -254,6 +263,15 @@ class WOStackController(CementBaseController): Log.debug(self, "Fail2ban already installed") Log.info(self, "Fail2ban already installed") + # ClamAV + if pargs.clamav: + Log.debug(self, "Setting apt_packages variable for ClamAV") + if not WOAptGet.is_installed(self, 'fail2ban'): + apt_packages = apt_packages + ["clamav"] + else: + Log.debug(self, "Fail2ban already installed") + Log.info(self, "Fail2ban already installed") + # proftpd if pargs.proftpd: Log.debug(self, "Setting apt_packages variable for ProFTPd") @@ -324,7 +342,7 @@ class WOStackController(CementBaseController): "htdocs/db/adminer/adminer.css" .format(WOVariables.wo_webroot), "Adminer theme"]] - + # mysqltuner if pargs.mysqltuner: Log.debug(self, "Setting packages variable for MySQLTuner ") packages = packages + [["https://raw." @@ -356,16 +374,24 @@ class WOStackController(CementBaseController): "releases/download/v{0}/wordops-dashboard.tar.gz" .format(WOVariables.wo_dashboard), "/var/lib/wo/tmp/wo-dashboard.tar.gz", - "WordOps Dashboard"], - ["https://github.com/soerennb/" - "extplorer/archive/v{0}.tar.gz" - .format(WOVariables.wo_extplorer), - "/var/lib/wo/tmp/extplorer.tar.gz", - "eXtplorer"]] + "WordOps Dashboard"]] else: Log.debug(self, "WordOps dashboard already installed") Log.info(self, "WordOps dashboard already installed") + if pargs.dashboard: + if not os.path.isdir('/var/www/22222/htdocs/files'): + Log.debug(self, "Setting packages variable for eXtplorer") + packages = packages + \ + [["https://github.com/soerennb/" + "extplorer/archive/v{0}.tar.gz" + .format(WOVariables.wo_extplorer), + "/var/lib/wo/tmp/extplorer.tar.gz", + "eXtplorer"]] + else: + Log.debug(self, "eXtplorer is already installed") + Log.info(self, "eXtplorer is already installed") + # UTILS if pargs.utils: Log.debug(self, "Setting packages variable for utils") @@ -408,6 +434,17 @@ class WOStackController(CementBaseController): '/var/lib/wo/tmp/anemometer.tar.gz', 'Anemometer'] ] + if pargs.cheat: + if (not os.path.isfile('/usr/local/bin/cht.sh') and + not os.path.isfile('/usr/bin/cht.sh')): + Log.debug(self, "Setting packages variable for cht.sh") + [["https://cht.sh/:cht.sh", + "/usr/local/bin/cht.sh", + "Cht.sh"]] + else: + Log.debug(self, "cht.sh is already installed") + Log.info(self, "cht.sh is already installed") + except Exception as e: Log.debug(self, "{0}".format(e)) diff --git a/wo/cli/plugins/stack_pref.py b/wo/cli/plugins/stack_pref.py index cc2899e..f4d48b0 100644 --- a/wo/cli/plugins/stack_pref.py +++ b/wo/cli/plugins/stack_pref.py @@ -202,6 +202,15 @@ def post_pref(self, apt_packages, packages): WOTemplate.tmpl_render(self, '{0}/cloudflare.conf'.format(ngxcnf), 'cloudflare.mustache', data) + Log.debug("Setting up freshclam cronjob") + WOTemplate.tmpl_render(self, '/opt/cf-update.sh', + 'cf-update.mustache', + data, overwrite=False) + WOFileUtils.chmod(self, "/opt/cf-update.sh", 0o775) + WOCron.setcron_weekly(self, '/opt/cf-update.sh ' + '> /dev/null 2>&1', + comment='Cloudflare IP refresh cronjob ' + 'added by WordOps') WOTemplate.tmpl_render(self, '{0}/map-wp-fastcgi-cache.conf'.format( @@ -471,7 +480,7 @@ def post_pref(self, apt_packages, packages): WOGit.add(self, ["/etc/nginx"], msg="Adding Nginx into Git") WOService.reload_service(self, 'nginx') - server_ip = requests.get('http://v4.wordops.eu') + if set(["nginx"]).issubset(set(apt_packages)): print("WordOps backend configuration was successful\n" "You can access it on : https://{0}:22222" @@ -657,8 +666,8 @@ def post_pref(self, apt_packages, packages): WOFileUtils.chown(self, "{0}22222/htdocs" .format(ngxroot), - WOVariables.wo_php_user, - WOVariables.wo_php_user, recursive=True) + 'www-data', + 'www-data', recursive=True) WOGit.add(self, ["/etc/php"], msg="Adding PHP into Git") WOService.restart_service(self, 'php7.2-fpm') @@ -829,8 +838,8 @@ def post_pref(self, apt_packages, packages): WOFileUtils.chown(self, "{0}22222/htdocs" .format(ngxroot), - WOVariables.wo_php_user, - WOVariables.wo_php_user, recursive=True) + 'www-data', + 'www-data', recursive=True) WOGit.add(self, ["/etc/php"], msg="Adding PHP into Git") WOService.restart_service(self, 'php7.3-fpm') @@ -845,17 +854,34 @@ def post_pref(self, apt_packages, packages): encoding='utf-8', mode='w') config_file.write(config) config_file.close() - else: + elif (not WOFileUtils.grep(self, "/etc/mysql/my.cnf", "WordOps")): + with open("/etc/mysql/my.cnf", + "a") as mysql_file: + mysql_file.write("\n# WordOps v3.9.8\n") wo_ram = psutil.virtual_memory().total / (1024 * 1024) + # set InnoDB variable depending on the RAM available wo_ram_innodb = int(wo_ram*0.3) wo_ram_log_buffer = int(wo_ram_innodb*0.25) wo_ram_log_size = int(wo_ram_log_buffer*0.5) # replacing default values Log.debug(self, "Tuning MySQL configuration") + # set innodb_buffer_pool_instances depending + # on the amount of RAM + if (wo_ram_innodb > 1000) and (wo_ram_innodb < 64000): + wo_innodb_instance = int( + wo_ram_innodb/1000) + elif (wo_ram_innodb < 1000): + wo_innodb_instance = int(1) + elif (wo_ram_innodb > 64000): + wo_innodb_instance = int(64) WOFileUtils.searchreplace(self, "/etc/mysql/my.cnf", "innodb_buffer_pool_size = 256M", - "innodb_buffer_pool_size = {0}M" - .format(wo_ram_innodb)) + "innodb_buffer_pool_size " + "= {0}M\n" + "innodb_buffer_pool_instances " + "= {1}\n" + .format(wo_ram_innodb, + wo_innodb_instance)) WOFileUtils.searchreplace(self, "/etc/mysql/my.cnf", "innodb_log_buffer_size = 8M", "innodb_log_buffer_size = {0}M" @@ -870,11 +896,6 @@ def post_pref(self, apt_packages, packages): "= 600", "wait_timeout " "= 120") - WOFileUtils.searchreplace(self, "/etc/mysql/my.cnf", - "skip-external-locking", - "skip-external-locking\n" - "skip-name-resolve = 1\n") - # disabling mariadb binlog WOFileUtils.searchreplace(self, "/etc/mysql/my.cnf", @@ -924,15 +945,8 @@ def post_pref(self, apt_packages, packages): "table_open_cache = 16000") WOFileUtils.searchreplace(self, "/etc/mysql/my.cnf", "max_allowed_packet = 16M", - "max_allowed_packet = 64M") - if (wo_ram_innodb > 1000) and (wo_ram_innodb < 64000): - wo_innodb_instance = int(wo_ram_innodb/1000) - WOFileUtils.searchreplace(self, "/etc/mysql/my.cnf", - "# * Security Features", - "innodb_buffer_pool_instances " - "= {0}\n" - .format(wo_innodb_instance) + - "# * Security Features") + "max_allowed_packet = 64M\n" + "skip-name-resolve=1\n") WOService.stop_service(self, 'mysql') WOFileUtils.mvfile(self, '/var/lib/mysql/ib_logfile0', @@ -1083,7 +1097,11 @@ def post_pref(self, apt_packages, packages): # enable systemd service Log.debug(self, "Enabling redis systemd service") WOShellExec.cmd_exec(self, "systemctl enable redis-server") - if os.path.isfile("/etc/redis/redis.conf"): + if (os.path.isfile("/etc/redis/redis.conf") and + not WOFileUtils.grep(self, "/etc/mysql/my.cnf", "WordOps")): + with open("/etc/redis/redis.conf", + "a") as redis_file: + redis_file.write("\n# WordOps v3.9.8\n") wo_ram = psutil.virtual_memory().total / (1024 * 1024) if wo_ram < 1024: Log.debug(self, "Setting maxmemory variable to " @@ -1127,6 +1145,18 @@ def post_pref(self, apt_packages, packages): 'redis', 'redis', recursive=False) WOService.restart_service(self, 'redis-server') + # Redis configuration + if set(["clamav"]).issubset(set(apt_packages)): + Log.debug("Setting up freshclam cronjob") + WOTemplate.tmpl_render(self, '/opt/freshclam.sh', + 'freshclam.mustache', + data, overwrite=False) + WOFileUtils.chmod(self, "/opt/freshclam.sh", 0o775) + WOCron.setcron_weekly(self, '/opt/freshclam.sh ' + '> /dev/null 2>&1', + comment='ClamAV freshclam cronjob ' + 'added by WordOps') + if (packages): if any('/usr/local/bin/wp' == x[1] for x in packages): Log.debug(self, "Setting Privileges" @@ -1190,8 +1220,8 @@ def post_pref(self, apt_packages, packages): .format(WOVariables.wo_webroot)) WOFileUtils.chown(self, '{0}22222/htdocs' .format(WOVariables.wo_webroot), - WOVariables.wo_php_user, - WOVariables.wo_php_user, + 'www-data', + 'www-data', recursive=True) # composer install and phpmyadmin update @@ -1211,8 +1241,8 @@ def post_pref(self, apt_packages, packages): "/var/www/22222/htdocs/db/pma/") WOFileUtils.chown(self, '{0}22222/htdocs/db/pma' .format(WOVariables.wo_webroot), - WOVariables.wo_php_user, - WOVariables.wo_php_user, + 'www-data', + 'www-data', recursive=True) if any('/usr/bin/mysqltuner' == x[1] @@ -1291,8 +1321,8 @@ def post_pref(self, apt_packages, packages): .format(WOVariables.wo_webroot)) WOFileUtils.chown(self, '{0}22222/htdocs' .format(WOVariables.wo_webroot), - WOVariables.wo_php_user, - WOVariables.wo_php_user, + 'www-data', + 'www-data', recursive=True) # Extplorer FileManager @@ -1314,8 +1344,8 @@ def post_pref(self, apt_packages, packages): .format(WOVariables.wo_webroot)) WOFileUtils.chown(self, '{0}22222/htdocs' .format(WOVariables.wo_webroot), - WOVariables.wo_php_user, - WOVariables.wo_php_user, + 'www-data', + 'www-data', recursive=True) # webgrind @@ -1359,8 +1389,8 @@ def post_pref(self, apt_packages, packages): .format(WOVariables.wo_webroot)) WOFileUtils.chown(self, '{0}22222/htdocs' .format(WOVariables.wo_webroot), - WOVariables.wo_php_user, - WOVariables.wo_php_user, + 'www-data', + 'www-data', recursive=True) # anemometer if any('/var/lib/wo/tmp/anemometer.tar.gz' == x[1] @@ -1419,10 +1449,20 @@ def post_pref(self, apt_packages, packages): out=wo_anemometer) wo_anemometer.close() + # pt-query-advisor if any('/usr/bin/pt-query-advisor' == x[1] for x in packages): WOFileUtils.chmod(self, "/usr/bin/pt-query-advisor", 0o775) + # cht.sh + if any('/usr/local/bin/cht.sh' == x[1] + for x in packages): + WOFileUtils.chmod(self, "/usr/local/bin/cht.sh", 0o775) + if not WOFileUtils.grep(self, "~/.bashrc", "cheat"): + with open("~/.bashrc", + "a") as wo_bashrc: + wo_bashrc.write("\nalias cheat='cht.sh'\n") + # phpredisadmin if any('/var/lib/wo/tmp/pra.tar.gz' == x[1] for x in packages): @@ -1436,21 +1476,21 @@ def post_pref(self, apt_packages, packages): .format(WOVariables.wo_webroot)) WOFileUtils.chown(self, '{0}22222/htdocs' .format(WOVariables.wo_webroot), - WOVariables.wo_php_user, - WOVariables.wo_php_user, + 'www-data', + 'www-data', recursive=True) if os.path.isfile("/usr/local/bin/composer"): - WOShellExec.cmd_exec(self, "sudo -u www-data -H " - "composer " - "create-project -n -s dev " + WOShellExec.cmd_exec(self, "/usr/local/bin/composer" + "create-project --no-plugins " + "--no-scripts -n -s dev " "erik-dubbelboer/php-redis-admin " "/var/www/22222/htdocs/cache" "/redis/phpRedisAdmin ") Log.debug(self, 'Setting Privileges of webroot permission to ' - '{0}22222/htdocs/cache/file ' + '{0}22222/htdocs/cache/redis' .format(WOVariables.wo_webroot)) WOFileUtils.chown(self, '{0}22222/htdocs' .format(WOVariables.wo_webroot), - WOVariables.wo_php_user, - WOVariables.wo_php_user, + 'www-data', + 'www-data', recursive=True) diff --git a/wo/cli/plugins/stack_upgrade.py b/wo/cli/plugins/stack_upgrade.py index b46858c..7a2566a 100644 --- a/wo/cli/plugins/stack_upgrade.py +++ b/wo/cli/plugins/stack_upgrade.py @@ -64,7 +64,7 @@ class WOStackUpgradeController(CementBaseController): packages = [] nginx_packages = [] empty_packages = [] - pargs = pargs = self.app.pargs + pargs = self.app.pargs if ((not pargs.web) and (not pargs.nginx) and (not pargs.php) and (not pargs.php73) and diff --git a/wo/cli/templates/cf-update.sh b/wo/cli/templates/cf-update.sh new file mode 100644 index 0000000..562b451 --- /dev/null +++ b/wo/cli/templates/cf-update.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# WordOps bash script to update cloudflare IP + +CURL_BIN=$(command -v curl) +CF_IPV4=$($CURL_BIN -sL https://www.cloudflare.com/ips-v4) +CF_IPV6=$($CURL_BIN -sL https://www.cloudflare.com/ips-v6) + +echo -e '# WordOps (wo) set visitors real ip with Cloudflare\n' > /etc/nginx/conf.d/cloudflare.conf +echo "####################################" +echo "Adding Cloudflare IPv4" +echo "####################################" +for cf_ip4 in $CF_IPV4; do + echo "set_real_ip_from $cf_ip4;" >> /etc/nginx/conf.d/cloudflare.conf +done +echo "####################################" +echo "Adding Cloudflare IPv6" +echo "####################################" +for cf_ip6 in $CF_IPV6; do + echo "set_real_ip_from $cf_ip6;" >> /etc/nginx/conf.d/cloudflare.conf +done +echo 'real_ip_header CF-Connecting-IP;' >> /etc/nginx/conf.d/cloudflare.conf + +nginx -t && service nginx reload \ No newline at end of file diff --git a/wo/cli/templates/freshclam.mustache b/wo/cli/templates/freshclam.mustache new file mode 100644 index 0000000..e8bbd34 --- /dev/null +++ b/wo/cli/templates/freshclam.mustache @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# WordOps ClamAV freshclam script +# script path after installation /opt/freshcham.sh + +if [ -x /etc/init.d/clamav-freshclam ]; then +{ + /etc/init.d/clamav-freshclam stop + freshclam + /etc/init.d/clamav-freshclam start +} >> /var/log/wo/clamav.log 2>&1 +fi diff --git a/wo/core/cron.py b/wo/core/cron.py index 02e9e81..fd4ec70 100644 --- a/wo/core/cron.py +++ b/wo/core/cron.py @@ -21,6 +21,20 @@ class WOCron(): "\\\"; } | crontab -\"") Log.debug(self, "Cron set") + def setcron_daily(self, cmd, comment='Cron set by WordOps', user='root', + min=0, hour=12): + if not WOShellExec.cmd_exec(self, "crontab -l " + "| grep -q \'{0}\'".format(cmd)): + + WOShellExec.cmd_exec(self, "/bin/bash -c \"crontab -l " + "2> /dev/null | {{ cat; echo -e" + " \\\"" + "\\n@daily" + "{0}".format(cmd) + + " # {0}".format(comment) + + "\\\"; } | crontab -\"") + Log.debug(self, "Cron set") + def remove_cron(self, cmd): if WOShellExec.cmd_exec(self, "crontab -l " "| grep -q \'{0}\'".format(cmd)): diff --git a/wo/core/domainvalidate.py b/wo/core/domainvalidate.py index f0c5985..750622e 100644 --- a/wo/core/domainvalidate.py +++ b/wo/core/domainvalidate.py @@ -1,5 +1,6 @@ """WordOps domain validation module.""" from urllib.parse import urlparse +import os def ValidateDomain(url): @@ -22,3 +23,29 @@ def ValidateDomain(url): final_domain = domain_name return (final_domain, domain_name) + + +def GetDomainlevel(domain): + """ + This function returns the domain type : domain, subdomain, + """ + domain_name = domain.split('.') + if domain_name[0] == 'www': + domain_name = domain_name[1:] + if os.path.isfile("/var/lib/wo/public_suffix_list.dat"): + # Read mode opens a file for reading only. + Suffix_file = open( + "/var/lib/wo/public_suffix_list.dat", "r") + # Read all the lines into a list. + for domain_suffix in Suffix_file: + if (str(domain_suffix).strip()) == ('.'.join(testing_domain[1:])): + domain_type = 'domain' + break + elif (str(domain_suffix).strip()) == ('.'.join(testing_domain[2:]): + domain_type='subdomain' + break + else: + domain_type='other' + Suffix_file.close() + + return (domain_type) diff --git a/wo/core/services.py b/wo/core/services.py index e47aca1..bd545ea 100644 --- a/wo/core/services.py +++ b/wo/core/services.py @@ -17,8 +17,12 @@ class WOService(): """ try: if service_name in ['nginx', 'php5-fpm']: - service_cmd = ('{0} -t && service {0} start' - .format(service_name)) + # 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)) else: service_cmd = ('service {0} start'.format(service_name)) @@ -64,8 +68,12 @@ class WOService(): """ try: if service_name in ['nginx', 'php5-fpm']: - service_cmd = ('{0} -t && service {0} restart' - .format(service_name)) + # 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} restart'.format(service_name)) else: service_cmd = ('service {0} restart'.format(service_name)) @@ -90,8 +98,12 @@ class WOService(): """ try: if service_name in ['nginx', 'php5-fpm']: - service_cmd = ('{0} -t && service {0} reload' - .format(service_name)) + # 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} restart'.format(service_name)) else: service_cmd = ('service {0} reload'.format(service_name)) From ee1985cc0b96feb1254a6611993aa8cfae0de652 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Mon, 26 Aug 2019 18:15:54 +0200 Subject: [PATCH 06/27] Fix typo --- wo/core/domainvalidate.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wo/core/domainvalidate.py b/wo/core/domainvalidate.py index 750622e..97f6003 100644 --- a/wo/core/domainvalidate.py +++ b/wo/core/domainvalidate.py @@ -38,14 +38,14 @@ def GetDomainlevel(domain): "/var/lib/wo/public_suffix_list.dat", "r") # Read all the lines into a list. for domain_suffix in Suffix_file: - if (str(domain_suffix).strip()) == ('.'.join(testing_domain[1:])): + if (str(domain_suffix).strip()) == ('.'.join(domain_name[1:])): domain_type = 'domain' break - elif (str(domain_suffix).strip()) == ('.'.join(testing_domain[2:]): - domain_type='subdomain' + elif (str(domain_suffix).strip()) == ('.'.join(domain_name[2:])): + domain_type = 'subdomain' break else: - domain_type='other' + domain_type = 'other' Suffix_file.close() return (domain_type) From a4c48c10bd4ac0d71408f7a29f165c61593c9d03 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Mon, 26 Aug 2019 18:33:27 +0200 Subject: [PATCH 07/27] Fix missing variable --- wo/cli/plugins/stack.py | 6 +++++- wo/cli/plugins/stack_pref.py | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index 07b5a1c..e72b8c5 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -82,7 +82,8 @@ class WOStackController(CementBaseController): (['--dashboard'], dict(help='Install WordOps dashboard', action='store_true')), (['--extplorer'], - dict(help='Install eXtplorer file manager', action='store_true')), + dict(help='Install eXtplorer file manager', + action='store_true')), (['--adminer'], dict(help='Install Adminer stack', action='store_true')), (['--fail2ban'], @@ -141,12 +142,14 @@ class WOStackController(CementBaseController): pargs.php73 = True pargs.redis = True pargs.proftpd = True + pargs.clamav = True if pargs.web: pargs.nginx = True pargs.php = True pargs.mysql = True pargs.wpcli = True + pargs.mariabackup = True if pargs.admin: pargs.web = True @@ -156,6 +159,7 @@ class WOStackController(CementBaseController): pargs.netdata = True pargs.dashboard = True pargs.phpredisadmin = True + pargs.extplorer = True pargs.cheat = True if pargs.security: diff --git a/wo/cli/plugins/stack_pref.py b/wo/cli/plugins/stack_pref.py index f4d48b0..2267d6e 100644 --- a/wo/cli/plugins/stack_pref.py +++ b/wo/cli/plugins/stack_pref.py @@ -4,8 +4,8 @@ import os import random import shutil import string -import requests import psutil +import requests from wo.cli.plugins.site_functions import * from wo.cli.plugins.stack_services import WOStackStatusController @@ -475,7 +475,7 @@ def post_pref(self, apt_packages, packages): "/var/www/22222/cert/22222.crt;\n" "ssl_certificate_key " "/var/www/22222/cert/22222.key;\n") - + server_ip = requests.get('http://v4.wordops.eu') # Nginx Configation into GIT WOGit.add(self, ["/etc/nginx"], msg="Adding Nginx into Git") From b703388b30693f190c9b492f67a719b6d739c29c Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Mon, 26 Aug 2019 18:59:06 +0200 Subject: [PATCH 08/27] Fix package install --- install | 21 +++++++++++++++------ wo/cli/plugins/stack.py | 30 +++++++++++------------------- wo/core/variables.py | 5 +++-- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/install b/install index a13716b..d5132ba 100755 --- a/install +++ b/install @@ -695,7 +695,6 @@ wo_mariadb_tweak() { wo_nginx_tweak() { # increase nginx open_files_limit { - if [ -x /usr/sbin/nginx ]; then if [ ! -d /etc/systemd/system/nginx.service.d ]; then mkdir -p /etc/systemd/system/nginx.service.d if [ ! -f /etc/systemd/system/nginx.service.d/limits.conf ]; then @@ -704,7 +703,6 @@ wo_nginx_tweak() { nginx -t && service nginx restart fi fi - fi } >> /var/log/wo/install.log 2>&1 } @@ -824,8 +822,13 @@ else wo_lib_echo "Adding systemd service tweak" | tee -ai $wo_install_log wo_systemd_tweak | tee -ai $wo_install_log fi - wo_nginx_tweak | tee -ai $wo_install_log - wo_mysql_tweak | tee -ai $wo_install_log + if [ -x /usr/sbin/nginx ]; then + wo_nginx_tweak | tee -ai $wo_install_log + fi + if [ -d /etc/systemd/system/mariadb.service.d ]; then + wo_mariadb_tweak | tee -ai $wo_install_log + fi + wo_domain_suffix | tee -ai $wo_install_log wo_lib_echo "Running post-install steps " | tee -ai $wo_install_log wo_update_wp_cli | tee -ai $wo_install_log else @@ -868,8 +871,13 @@ else wo_lib_echo "Adding systemd service tweak" | tee -ai $wo_install_log wo_systemd_tweak | tee -ai $wo_install_log fi - wo_nginx_tweak | tee -ai $wo_install_log - wo_mysql_tweak | tee -ai $wo_install_log + if [ -x /usr/sbin/nginx ]; then + wo_nginx_tweak | tee -ai $wo_install_log + fi + if [ -d /etc/systemd/system/mariadb.service.d ]; then + wo_mariadb_tweak | tee -ai $wo_install_log + fi + wo_domain_suffix | tee -ai $wo_install_log wo_lib_echo "Running post-install steps " | tee -ai $wo_install_log wo_git_init | tee -ai $wo_install_log wo_update_wp_cli | tee -ai $wo_install_log @@ -907,6 +915,7 @@ else wo_install_acme_sh | tee -ai $wo_install_log wo_lib_echo "Running post-install steps " | tee -ai $wo_install_log secure_wo_db | tee -ai $wo_install_log + wo_domain_suffix | tee -ai $wo_install_log wo_git_init | tee -ai $wo_install_log wo_update_wp_cli | tee -ai $wo_install_log fi diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index e72b8c5..d82a63f 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -128,7 +128,7 @@ class WOStackController(CementBaseController): and (not pargs.mysqlclient) and (not pargs.mysqltuner) and (not pargs.adminer) and (not pargs.utils) and (not pargs.redis) and (not pargs.proftpd) and - (not pargs.extplorer) and (not pargs.mariabackup) and + (not pargs.extplorer) and (not pargs.cheat) and (not pargs.clamav) and (not pargs.phpredisadmin) and (not pargs.php73)): @@ -149,7 +149,6 @@ class WOStackController(CementBaseController): pargs.php = True pargs.mysql = True pargs.wpcli = True - pargs.mariabackup = True if pargs.admin: pargs.web = True @@ -186,14 +185,14 @@ class WOStackController(CementBaseController): if WOAptGet.is_installed(self, 'nginx-plus'): Log.info(self, "NGINX PLUS Detected ...") apt = ["nginx-plus"] + WOVariables.wo_nginx - self.post_pref(apt, packages) + self.post_pref(apt, empty_packages) elif WOAptGet.is_installed(self, 'nginx'): Log.info(self, "WordOps detected an already " "installed nginx package." "It may or may not have " "required modules.\n") apt = ["nginx"] + WOVariables.wo_nginx - self.post_pref(apt, packages) + self.post_pref(apt, empty_packages) else: Log.debug(self, "Nginx Stable already installed") @@ -225,7 +224,6 @@ class WOStackController(CementBaseController): # MariaDB 10.3 if pargs.mysql: - pargs.mariabackup = True pargs.mysqltuner = True Log.debug(self, "Setting apt_packages variable for MySQL") if not WOShellExec.cmd_exec(self, "mysqladmin ping"): @@ -237,13 +235,6 @@ class WOStackController(CementBaseController): "for MySQL Client") apt_packages = apt_packages + WOVariables.wo_mysql_client - # mariabackup - if pargs.mariabackup: - if not WOAptGet.is_installed(self, 'mariadb-backup'): - Log.debug(self, "Setting apt_packages variable " - "for MariaBackup") - apt_packages = apt_packages + ["mariadb-backup"] - # WP-CLI if pargs.wpcli: Log.debug(self, "Setting packages variable for WP-CLI") @@ -270,11 +261,11 @@ class WOStackController(CementBaseController): # ClamAV if pargs.clamav: Log.debug(self, "Setting apt_packages variable for ClamAV") - if not WOAptGet.is_installed(self, 'fail2ban'): + if not WOAptGet.is_installed(self, 'clamav'): apt_packages = apt_packages + ["clamav"] else: - Log.debug(self, "Fail2ban already installed") - Log.info(self, "Fail2ban already installed") + Log.debug(self, "ClamAV already installed") + Log.info(self, "ClamAV already installed") # proftpd if pargs.proftpd: @@ -383,7 +374,8 @@ class WOStackController(CementBaseController): Log.debug(self, "WordOps dashboard already installed") Log.info(self, "WordOps dashboard already installed") - if pargs.dashboard: + # eXtplorer + if pargs.explorer: if not os.path.isdir('/var/www/22222/htdocs/files'): Log.debug(self, "Setting packages variable for eXtplorer") packages = packages + \ @@ -442,9 +434,9 @@ class WOStackController(CementBaseController): if (not os.path.isfile('/usr/local/bin/cht.sh') and not os.path.isfile('/usr/bin/cht.sh')): Log.debug(self, "Setting packages variable for cht.sh") - [["https://cht.sh/:cht.sh", - "/usr/local/bin/cht.sh", - "Cht.sh"]] + packages = packages + [["https://cht.sh/:cht.sh", + "/usr/local/bin/cht.sh", + "cht.sh"]] else: Log.debug(self, "cht.sh is already installed") Log.info(self, "cht.sh is already installed") diff --git a/wo/core/variables.py b/wo/core/variables.py index d5997f8..f73e6dd 100644 --- a/wo/core/variables.py +++ b/wo/core/variables.py @@ -10,7 +10,7 @@ class WOVariables(): """Intialization of core variables""" # WordOps version - wo_version = "3.9.8.3" + wo_version = "3.9.8.4" # WordOps packages versions wo_wp_cli = "2.2.0" wo_adminer = "4.7.2" @@ -143,7 +143,8 @@ class WOVariables(): "10.3/debian {codename} main" .format(codename=wo_platform_codename)) - wo_mysql = ["mariadb-server", "percona-toolkit", "python3-mysqldb"] + wo_mysql = ["mariadb-server", "percona-toolkit", + "python3-mysqldb", "mariadb-backup"] wo_mysql_client = ["mariadb-client", "python3-mysqldb"] From b156fd00b84ba6cbcd9f6f8d0bc0bc140025d955 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Mon, 26 Aug 2019 19:12:06 +0200 Subject: [PATCH 09/27] Fix wrong template extension --- wo/cli/templates/{cf-update.sh => cf-update.mustache} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename wo/cli/templates/{cf-update.sh => cf-update.mustache} (100%) diff --git a/wo/cli/templates/cf-update.sh b/wo/cli/templates/cf-update.mustache similarity index 100% rename from wo/cli/templates/cf-update.sh rename to wo/cli/templates/cf-update.mustache From b9d9969093d28351422e44c806df812844b896be Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Mon, 26 Aug 2019 19:43:21 +0200 Subject: [PATCH 10/27] Fix cloudflare conf --- CHANGELOG.md | 1 + setup.py | 2 +- wo/cli/plugins/stack_pref.py | 17 ++++++++--------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d610049..a98b188 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Domain/Subdomain detection based on public domain suffixes list - Increase Nginx & MariaDB systemd open_files limits - Cronjob to update Cloudflare IPs list +- mariadb-backup to perform full and non-blocking databases backup #### Changed diff --git a/setup.py b/setup.py index 684f3a9..361c02d 100644 --- a/setup.py +++ b/setup.py @@ -57,7 +57,7 @@ if not os.path.isfile('/root/.gitconfig'): shutil.copy2(os.path.expanduser("~")+'/.gitconfig', '/root/.gitconfig') setup(name='wo', - version='3.9.8.3', + version='3.9.8.4', description=long_description, long_description=long_description, classifiers=[], diff --git a/wo/cli/plugins/stack_pref.py b/wo/cli/plugins/stack_pref.py index 2267d6e..c83c410 100644 --- a/wo/cli/plugins/stack_pref.py +++ b/wo/cli/plugins/stack_pref.py @@ -202,15 +202,6 @@ def post_pref(self, apt_packages, packages): WOTemplate.tmpl_render(self, '{0}/cloudflare.conf'.format(ngxcnf), 'cloudflare.mustache', data) - Log.debug("Setting up freshclam cronjob") - WOTemplate.tmpl_render(self, '/opt/cf-update.sh', - 'cf-update.mustache', - data, overwrite=False) - WOFileUtils.chmod(self, "/opt/cf-update.sh", 0o775) - WOCron.setcron_weekly(self, '/opt/cf-update.sh ' - '> /dev/null 2>&1', - comment='Cloudflare IP refresh cronjob ' - 'added by WordOps') WOTemplate.tmpl_render(self, '{0}/map-wp-fastcgi-cache.conf'.format( @@ -476,6 +467,14 @@ def post_pref(self, apt_packages, packages): "ssl_certificate_key " "/var/www/22222/cert/22222.key;\n") server_ip = requests.get('http://v4.wordops.eu') + WOTemplate.tmpl_render(self, '/opt/cf-update.sh', + 'cf-update.mustache', + data, overwrite=False) + WOFileUtils.chmod(self, "/opt/cf-update.sh", 0o775) + WOCron.setcron_weekly(self, '/opt/cf-update.sh ' + '> /dev/null 2>&1', + comment='Cloudflare IP refresh cronjob ' + 'added by WordOps') # Nginx Configation into GIT WOGit.add(self, ["/etc/nginx"], msg="Adding Nginx into Git") From 378c9a4820d987338e396f47c81d44c6ae970377 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Tue, 27 Aug 2019 10:20:25 +0200 Subject: [PATCH 11/27] Fix nginx restart service --- wo/core/services.py | 83 +++++++++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 33 deletions(-) diff --git a/wo/core/services.py b/wo/core/services.py index bd545ea..6fcf220 100644 --- a/wo/core/services.py +++ b/wo/core/services.py @@ -1,10 +1,9 @@ """WordOps Service Manager""" +import os import subprocess -from subprocess import Popen from wo.core.logging import Log - class WOService(): """Intialization for service""" def ___init__(): @@ -16,25 +15,31 @@ class WOService(): Similar to `service xyz start` """ try: - if service_name in ['nginx', 'php5-fpm']: + 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) + Log.info(self, "[" + Log.ENDC + "OK" + Log.OKBLUE + "]") + return True + else: + Log.info(self, "[" + 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 + 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}" @@ -67,25 +72,30 @@ class WOService(): Similar to `service xyz restart` """ try: - if service_name in ['nginx', 'php5-fpm']: + 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): + Log.info(self, "[" + Log.ENDC + "OK" + Log.OKBLUE + "]") service_cmd = ('service {0} restart'.format(service_name)) + retcode = subprocess.getstatusoutput(service_cmd) + return True + else: + Log.info(self, "[" + Log.FAIL + "Failed" + Log.OKBLUE+"]") + return False else: service_cmd = ('service {0} restart'.format(service_name)) - - Log.info(self, "Restart : {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 + Log.info(self, "Restart : {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} {1}".format(e.errno, e.strerror)) Log.error(self, "\nFailed to restart service : {0}" @@ -97,25 +107,32 @@ class WOService(): Similar to `service xyz stop` """ try: - if service_name in ['nginx', 'php5-fpm']: + 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} restart'.format(service_name)) + retcode = subprocess.getstatusoutput(service_cmd) + Log.info(self, "[" + Log.ENDC + "OK" + Log.OKBLUE + "]") + return True + else: + Log.info(self, "[" + Log.FAIL + "Failed" + Log.OKBLUE+"]") + return False + else: service_cmd = ('service {0} reload'.format(service_name)) - Log.info(self, "Reload : {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 + Log.info(self, "Reload : {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 reload service {0}" From c60d4e306a3f38eb1860ea2e7446ea88b9991a6c Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Tue, 27 Aug 2019 12:32:48 +0200 Subject: [PATCH 12/27] Improve Nginx service management --- CHANGELOG.md | 2 ++ wo/cli/plugins/site.py | 8 ++++---- wo/cli/templates/map-wp.mustache | 11 ++++++++-- wo/core/domainvalidate.py | 4 +++- wo/core/services.py | 35 ++++++++++++++++++++------------ 5 files changed, 40 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a98b188..6ae9030 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Increase Nginx & MariaDB systemd open_files limits - Cronjob to update Cloudflare IPs list - mariadb-backup to perform full and non-blocking databases backup +- Nginx configuration check before performing reload/restart +- Nginx mapping to proxy web-socket connections #### Changed diff --git a/wo/cli/plugins/site.py b/wo/cli/plugins/site.py index 52188c3..9ebe3e4 100644 --- a/wo/cli/plugins/site.py +++ b/wo/cli/plugins/site.py @@ -137,7 +137,7 @@ class WOSiteController(CementBaseController): Log.error(self, 'could not input site name') pargs.site_name = pargs.site_name.strip() (wo_domain, wo_www_domain) = ValidateDomain(pargs.site_name) - wo_domain_type = GetDomainlevel(wo_domain) + wo_domain_type, wo_root_domain = GetDomainlevel(wo_domain) wo_db_name = '' wo_db_user = '' wo_db_pass = '' @@ -424,7 +424,7 @@ class WOSiteCreateController(CementBaseController): pargs.site_name = pargs.site_name.strip() (wo_domain, wo_www_domain) = ValidateDomain(pargs.site_name) - wo_domain_type = GetDomainlevel(wo_domain) + wo_domain_type, wo_root_domain = GetDomainlevel(wo_domain) if not wo_domain.strip(): Log.error("Invalid domain name, " "Provide valid domain name") @@ -958,7 +958,7 @@ class WOSiteUpdateController(CementBaseController): (wo_domain, wo_www_domain, ) = ValidateDomain(pargs.site_name) wo_site_webroot = WOVariables.wo_webroot + wo_domain - wo_domain_type = GetDomainlevel(wo_domain) + wo_domain_type, wo_root_domain = GetDomainlevel(wo_domain) check_site = getSiteInfo(self, wo_domain) if check_site is None: @@ -1820,7 +1820,7 @@ class WOSiteDeleteController(CementBaseController): pargs.site_name = pargs.site_name.strip() (wo_domain, wo_www_domain) = ValidateDomain(pargs.site_name) - wo_domain_type = GetDomainlevel(wo_domain) + wo_domain_type, wo_root_domain = GetDomainlevel(wo_domain) wo_db_name = '' wo_prompt = '' wo_nginx_prompt = '' diff --git a/wo/cli/templates/map-wp.mustache b/wo/cli/templates/map-wp.mustache index 22e62cb..cd5f4b9 100644 --- a/wo/cli/templates/map-wp.mustache +++ b/wo/cli/templates/map-wp.mustache @@ -1,4 +1,4 @@ -# NGINX CONFIGURATION FOR FASTCGI_CACHE EXCEPTION - WO v3.9.7 +# NGINX CONFIGURATION FOR FASTCGI_CACHE EXCEPTION - WO v3.9.8 # DO NOT MODIFY, ALL CHANGES WILL BE LOST AFTER AN WordOps (wo) UPDATE # do not cache xhtml request @@ -53,7 +53,7 @@ map $request_uri $uri_no_cache { "~*/commande/" 1; "~*/resetpass/" 1; } - +# mobile_prefix needed for WP-Rocket map $http_user_agent $mobile_prefix { default ""; "~*iphone" -mobile; @@ -78,7 +78,14 @@ map $skip_cache $cache_uri { default 'null cache'; } +# http_prefix needed for WP-Rocket map $https $https_prefix { default ""; on "-https"; } + +# needed to proxy web-socket connections +map $http_upgrade $connection_upgrade { + default upgrade; + '' close; +} \ No newline at end of file diff --git a/wo/core/domainvalidate.py b/wo/core/domainvalidate.py index 97f6003..9008f82 100644 --- a/wo/core/domainvalidate.py +++ b/wo/core/domainvalidate.py @@ -40,12 +40,14 @@ def GetDomainlevel(domain): for domain_suffix in Suffix_file: if (str(domain_suffix).strip()) == ('.'.join(domain_name[1:])): domain_type = 'domain' + root_domain = domain_name[0:] break elif (str(domain_suffix).strip()) == ('.'.join(domain_name[2:])): domain_type = 'subdomain' + root_domain = domain_name[1:] break else: domain_type = 'other' Suffix_file.close() - return (domain_type) + return (domain_type, root_domain) diff --git a/wo/core/services.py b/wo/core/services.py index 6fcf220..67ce261 100644 --- a/wo/core/services.py +++ b/wo/core/services.py @@ -1,5 +1,4 @@ """WordOps Service Manager""" -import os import subprocess from wo.core.logging import Log @@ -23,10 +22,14 @@ class WOService(): if 'emerg' not in str(error_output): service_cmd = ('service {0} start'.format(service_name)) retcode = subprocess.getstatusoutput(service_cmd) - Log.info(self, "[" + Log.ENDC + "OK" + Log.OKBLUE + "]") - return True + if retcode[0] == 0: + Log.info(self, "Starting Nginx" + + "[" + Log.ENDC + "OK" + Log.OKBLUE + "]") + return True else: - Log.info(self, "[" + Log.FAIL + "Failed" + Log.OKBLUE+"]") + Log.info( + self, "Starting Nginx" + "[" + Log.FAIL + + "Failed" + Log.OKBLUE+"]") return False else: service_cmd = ('service {0} start'.format(service_name)) @@ -78,12 +81,16 @@ class WOService(): stderr=subprocess.PIPE, shell=True) output, error_output = sub.communicate() if 'emerg' not in str(error_output): - Log.info(self, "[" + Log.ENDC + "OK" + Log.OKBLUE + "]") service_cmd = ('service {0} restart'.format(service_name)) retcode = subprocess.getstatusoutput(service_cmd) - return True + if retcode[0] == 0: + Log.info(self, "Restarting Nginx" + + "[" + Log.ENDC + "OK" + Log.OKBLUE + "]") + return True else: - Log.info(self, "[" + Log.FAIL + "Failed" + Log.OKBLUE+"]") + Log.info( + self, "Restarting Nginx" + "[" + Log.FAIL + + "Failed" + Log.OKBLUE+"]") return False else: service_cmd = ('service {0} restart'.format(service_name)) @@ -113,17 +120,19 @@ class WOService(): stderr=subprocess.PIPE, shell=True) output, error_output = sub.communicate() if 'emerg' not in str(error_output): - service_cmd = ('service {0} restart'.format(service_name)) + service_cmd = ('service {0} reload'.format(service_name)) retcode = subprocess.getstatusoutput(service_cmd) - Log.info(self, "[" + Log.ENDC + "OK" + Log.OKBLUE + "]") - return True + if retcode[0] == 0: + Log.info(self, "Reloading Nginx" + + "[" + Log.ENDC + "OK" + Log.OKBLUE + "]") + return True else: - Log.info(self, "[" + Log.FAIL + "Failed" + Log.OKBLUE+"]") + Log.info( + self, "Restarting Nginx" + "[" + Log.FAIL + + "Failed" + Log.OKBLUE+"]") return False - else: service_cmd = ('service {0} reload'.format(service_name)) - Log.info(self, "Reload : {0:10}".format(service_name), end='') retcode = subprocess.getstatusoutput(service_cmd) if retcode[0] == 0: From 5cc1c06e880f53c8587d30c0d0606d37da714894 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Tue, 27 Aug 2019 13:40:43 +0200 Subject: [PATCH 13/27] Changes services messages --- wo/core/services.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/wo/core/services.py b/wo/core/services.py index 67ce261..e217040 100644 --- a/wo/core/services.py +++ b/wo/core/services.py @@ -23,12 +23,12 @@ class WOService(): service_cmd = ('service {0} start'.format(service_name)) retcode = subprocess.getstatusoutput(service_cmd) if retcode[0] == 0: - Log.info(self, "Starting Nginx" + + Log.info(self, "Starting Nginx " + "[" + Log.ENDC + "OK" + Log.OKBLUE + "]") return True else: - Log.info( - self, "Starting Nginx" + "[" + Log.FAIL + + Log.error( + self, "Starting Nginx " + "[" + Log.FAIL + "Failed" + Log.OKBLUE+"]") return False else: @@ -84,12 +84,12 @@ class WOService(): service_cmd = ('service {0} restart'.format(service_name)) retcode = subprocess.getstatusoutput(service_cmd) if retcode[0] == 0: - Log.info(self, "Restarting Nginx" + + Log.info(self, "Restarting Nginx " + "[" + Log.ENDC + "OK" + Log.OKBLUE + "]") return True else: - Log.info( - self, "Restarting Nginx" + "[" + Log.FAIL + + Log.error( + self, "Restarting Nginx " + "[" + Log.FAIL + "Failed" + Log.OKBLUE+"]") return False else: @@ -110,8 +110,8 @@ class WOService(): def reload_service(self, service_name): """ - Stop service - Similar to `service xyz stop` + Reload service + Similar to `service xyz reload` """ try: if service_name in ['nginx']: @@ -123,12 +123,12 @@ class WOService(): service_cmd = ('service {0} reload'.format(service_name)) retcode = subprocess.getstatusoutput(service_cmd) if retcode[0] == 0: - Log.info(self, "Reloading Nginx" + + Log.info(self, "Reloading Nginx " + "[" + Log.ENDC + "OK" + Log.OKBLUE + "]") return True else: - Log.info( - self, "Restarting Nginx" + "[" + Log.FAIL + + Log.error( + self, "Reloading Nginx " + "[" + Log.FAIL + "Failed" + Log.OKBLUE+"]") return False else: From d24ae7e8d2563a9dd04d9de79ed5d7809d914103 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Tue, 27 Aug 2019 15:12:01 +0200 Subject: [PATCH 14/27] Add Nginx configuration Rollback --- CHANGELOG.md | 3 +- wo/cli/plugins/site_functions.py | 12 ++ wo/cli/plugins/stack_pref.py | 305 +++++++++++++++---------------- wo/cli/plugins/stack_upgrade.py | 4 +- wo/core/git.py | 25 +++ wo/core/services.py | 10 +- wo/core/template.py | 2 +- 7 files changed, 199 insertions(+), 162 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ae9030..888dc24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,8 +18,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Increase Nginx & MariaDB systemd open_files limits - Cronjob to update Cloudflare IPs list - mariadb-backup to perform full and non-blocking databases backup -- Nginx configuration check before performing reload/restart +- Nginx configuration check before performing start/reload/restart - Nginx mapping to proxy web-socket connections +- Nginx configuration rollback in case of failure with `wo stack upgrade --nginx` #### Changed diff --git a/wo/cli/plugins/site_functions.py b/wo/cli/plugins/site_functions.py index 54774f6..775afb5 100644 --- a/wo/cli/plugins/site_functions.py +++ b/wo/cli/plugins/site_functions.py @@ -978,6 +978,18 @@ def display_cache_settings(self, data): "page=redis-cache".format(data['site_name'])) Log.info(self, "Object Cache:\t\tEnable") + if data['wpfc']: + if data['multisite']: + Log.info(self, "Nginx-Helper configuration :" + "\thttp://{0}/wp-admin/network/settings.php?" + "page=nginx".format(data['site_name'])) + else: + Log.info(self, "Nginx-Helper configuration :" + "\thttp://{0}/wp-admin/options-general.php?" + "page=nginx".format(data['site_name'])) + + + def logwatch(self, logfiles): import zlib diff --git a/wo/cli/plugins/stack_pref.py b/wo/cli/plugins/stack_pref.py index c83c410..f821b49 100644 --- a/wo/cli/plugins/stack_pref.py +++ b/wo/cli/plugins/stack_pref.py @@ -142,7 +142,7 @@ def pre_pref(self, apt_packages): WORepo.add(self, ppa=WOVariables.wo_redis_repo) -def post_pref(self, apt_packages, packages): +def post_pref(self, apt_packages, packages, upgrade=False): """Post activity after installation of packages""" if (apt_packages): # Nginx configuration @@ -151,28 +151,29 @@ def post_pref(self, apt_packages, packages): ngxcnf = '/etc/nginx/conf.d' ngxcom = '/etc/nginx/common' ngxroot = '/var/www/' - if (WOVariables.wo_distro == 'ubuntu' or - WOVariables.wo_platform_codename == 'buster'): - data = dict(tls13=True) - else: - data = dict(tls13=False) - WOTemplate.tmpl_render(self, - '/etc/nginx/nginx.conf', - 'nginx-core.mustache', data) + if upgrade: + if os.path.isdir('/etc/nginx'): + WOGit.add(self, + ["/etc/nginx"], + msg="Adding Nginx into Git") + data = dict(tls13=True) + WOTemplate.render(self, + '/etc/nginx/nginx.conf', + 'nginx-core.mustache', data) if not os.path.isfile('{0}/gzip.conf.disabled'.format(ngxcnf)): data = dict() - WOTemplate.tmpl_render(self, '{0}/gzip.conf'.format(ngxcnf), - 'gzip.mustache', data) + WOTemplate.render(self, '{0}/gzip.conf'.format(ngxcnf), + 'gzip.mustache', data) if not os.path.isfile('{0}/brotli.conf'.format(ngxcnf)): - WOTemplate.tmpl_render(self, - '{0}/brotli.conf.disabled' - .format(ngxcnf), - 'brotli.mustache', data) + WOTemplate.render(self, + '{0}/brotli.conf.disabled' + .format(ngxcnf), + 'brotli.mustache', data) - WOTemplate.tmpl_render(self, '{0}/tweaks.conf'.format(ngxcnf), - 'tweaks.mustache', data) + WOTemplate.render(self, '{0}/tweaks.conf'.format(ngxcnf), + 'tweaks.mustache', data) # Fix for white screen death with NGINX PLUS if not WOFileUtils.grep(self, '/etc/nginx/fastcgi_params', @@ -184,29 +185,29 @@ def post_pref(self, apt_packages, packages): data = dict(php="9000", debug="9001", php7="9070", debug7="9170") - WOTemplate.tmpl_render( + WOTemplate.render( self, '{0}/upstream.conf'.format(ngxcnf), 'upstream.mustache', data, overwrite=True) data = dict(phpconf=True if WOAptGet.is_installed(self, 'php7.2-fpm') else False) - WOTemplate.tmpl_render(self, - '{0}/stub_status.conf'.format(ngxcnf), - 'stub_status.mustache', data) + WOTemplate.render(self, + '{0}/stub_status.conf'.format(ngxcnf), + 'stub_status.mustache', data) data = dict() - WOTemplate.tmpl_render(self, - '{0}/webp.conf'.format(ngxcnf), - 'webp.mustache', data) + WOTemplate.render(self, + '{0}/webp.conf'.format(ngxcnf), + 'webp.mustache', data) - WOTemplate.tmpl_render(self, - '{0}/cloudflare.conf'.format(ngxcnf), - 'cloudflare.mustache', data) + WOTemplate.render(self, + '{0}/cloudflare.conf'.format(ngxcnf), + 'cloudflare.mustache', data) - WOTemplate.tmpl_render(self, - '{0}/map-wp-fastcgi-cache.conf'.format( - ngxcnf), - 'map-wp.mustache', data) + WOTemplate.render(self, + '{0}/map-wp-fastcgi-cache.conf'.format( + ngxcnf), + 'map-wp.mustache', data) # Setup Nginx common directory if not os.path.exists('{0}'.format(ngxcom)): @@ -218,88 +219,88 @@ def post_pref(self, apt_packages, packages): data = dict() # Common Configuration - WOTemplate.tmpl_render(self, - '{0}/locations-wo.conf' - .format(ngxcom), - 'locations.mustache', data) + WOTemplate.render(self, + '{0}/locations-wo.conf' + .format(ngxcom), + 'locations.mustache', data) - WOTemplate.tmpl_render(self, - '{0}/wpsubdir.conf' - .format(ngxcom), - 'wpsubdir.mustache', data) + WOTemplate.render(self, + '{0}/wpsubdir.conf' + .format(ngxcom), + 'wpsubdir.mustache', data) data = dict(upstream="php72") # PHP 7.2 conf - WOTemplate.tmpl_render(self, - '{0}/php72.conf' - .format(ngxcom), - 'php.mustache', data) + WOTemplate.render(self, + '{0}/php72.conf' + .format(ngxcom), + 'php.mustache', data) - WOTemplate.tmpl_render(self, - '{0}/redis-php72.conf' - .format(ngxcom), - 'redis.mustache', data) + WOTemplate.render(self, + '{0}/redis-php72.conf' + .format(ngxcom), + 'redis.mustache', data) - WOTemplate.tmpl_render(self, - '{0}/wpcommon-php72.conf' - .format(ngxcom), - 'wpcommon.mustache', data) + WOTemplate.render(self, + '{0}/wpcommon-php72.conf' + .format(ngxcom), + 'wpcommon.mustache', data) - WOTemplate.tmpl_render(self, - '{0}/wpfc-php72.conf' - .format(ngxcom), - 'wpfc.mustache', data) - WOTemplate.tmpl_render(self, - '{0}/wpsc-php72.conf' - .format(ngxcom), - 'wpsc.mustache', data) + WOTemplate.render(self, + '{0}/wpfc-php72.conf' + .format(ngxcom), + 'wpfc.mustache', data) + WOTemplate.render(self, + '{0}/wpsc-php72.conf' + .format(ngxcom), + 'wpsc.mustache', data) - WOTemplate.tmpl_render(self, - '{0}/wprocket-php72.conf' - .format(ngxcom), - 'wprocket.mustache', data) + WOTemplate.render(self, + '{0}/wprocket-php72.conf' + .format(ngxcom), + 'wprocket.mustache', data) - WOTemplate.tmpl_render(self, - '{0}/wpce-php72.conf' - .format(ngxcom), - 'wpce.mustache', data) + WOTemplate.render(self, + '{0}/wpce-php72.conf' + .format(ngxcom), + 'wpce.mustache', data) # PHP 7.3 conf if os.path.isdir("/etc/nginx/common"): data = dict(upstream="php73") - WOTemplate.tmpl_render(self, - '{0}/php73.conf' - .format(ngxcom), - 'php.mustache', data) + WOTemplate.render(self, + '{0}/php73.conf' + .format(ngxcom), + 'php.mustache', data) - WOTemplate.tmpl_render(self, - '{0}/redis-php73.conf' - .format(ngxcom), - 'redis.mustache', data) + WOTemplate.render(self, + '{0}/redis-php73.conf' + .format(ngxcom), + 'redis.mustache', data) - WOTemplate.tmpl_render(self, - '{0}/wpcommon-php73.conf' - .format(ngxcom), - 'wpcommon.mustache', data) + WOTemplate.render(self, + '{0}/wpcommon-php73.conf' + .format(ngxcom), + 'wpcommon.mustache', data) - WOTemplate.tmpl_render(self, - '{0}/wpfc-php73.conf' - .format(ngxcom), - 'wpfc.mustache', data) - WOTemplate.tmpl_render(self, - '{0}/wpsc-php73.conf' - .format(ngxcom), - 'wpsc.mustache', data) + WOTemplate.render(self, + '{0}/wpfc-php73.conf' + .format(ngxcom), + 'wpfc.mustache', data) + WOTemplate.render(self, + '{0}/wpsc-php73.conf' + .format(ngxcom), + 'wpsc.mustache', data) - WOTemplate.tmpl_render(self, - '{0}/wprocket-php73.conf' - .format(ngxcom), - 'wprocket.mustache', data) + WOTemplate.render(self, + '{0}/wprocket-php73.conf' + .format(ngxcom), + 'wprocket.mustache', data) - WOTemplate.tmpl_render(self, - '{0}/wpce-php73.conf' - .format(ngxcom), - 'wpce.mustache', data) + WOTemplate.render(self, + '{0}/wpce-php73.conf' + .format(ngxcom), + 'wpce.mustache', data) with open("/etc/nginx/common/release", "w") as release_file: @@ -310,18 +311,18 @@ def post_pref(self, apt_packages, packages): # Following files should not be overwrited data = dict(webroot=ngxroot) - WOTemplate.tmpl_render(self, - '{0}/acl.conf' - .format(ngxcom), - 'acl.mustache', data, overwrite=False) - WOTemplate.tmpl_render(self, - '{0}/blockips.conf' - .format(ngxcnf), - 'blockips.mustache', data, overwrite=False) - WOTemplate.tmpl_render(self, - '{0}/fastcgi.conf' - .format(ngxcnf), - 'fastcgi.mustache', data, overwrite=False) + WOTemplate.render(self, + '{0}/acl.conf' + .format(ngxcom), + 'acl.mustache', data, overwrite=False) + WOTemplate.render(self, + '{0}/blockips.conf' + .format(ngxcnf), + 'blockips.mustache', data, overwrite=False) + WOTemplate.render(self, + '{0}/fastcgi.conf' + .format(ngxcnf), + 'fastcgi.mustache', data, overwrite=False) # add redis cache format if not already done if (os.path.isfile("/etc/nginx/nginx.conf") and @@ -355,9 +356,9 @@ def post_pref(self, apt_packages, packages): # 22222 port settings if not os.path.isfile('/etc/nginx/sites-available/22222'): - WOTemplate.tmpl_render(self, - '/etc/nginx/sites-available/22222', - '22222.mustache', data, overwrite=False) + WOTemplate.render(self, + '/etc/nginx/sites-available/22222', + '22222.mustache', data, overwrite=False) passwd = ''.join([random.choice (string.ascii_letters + string.digits) @@ -455,7 +456,7 @@ def post_pref(self, apt_packages, packages): Log.debug(self, "{0}".format(e)) Log.error( self, "Failed to generate HTTPS " - "certificate for 22222") + "certificate for 22222", False) if not os.path.isfile('{0}22222/conf/nginx/ssl.conf' .format(ngxroot)): @@ -467,38 +468,36 @@ def post_pref(self, apt_packages, packages): "ssl_certificate_key " "/var/www/22222/cert/22222.key;\n") server_ip = requests.get('http://v4.wordops.eu') - WOTemplate.tmpl_render(self, '/opt/cf-update.sh', - 'cf-update.mustache', - data, overwrite=False) + + WOTemplate.render(self, '/opt/cf-update.sh', + 'cf-update.mustache', + data, overwrite=False) WOFileUtils.chmod(self, "/opt/cf-update.sh", 0o775) WOCron.setcron_weekly(self, '/opt/cf-update.sh ' '> /dev/null 2>&1', comment='Cloudflare IP refresh cronjob ' 'added by WordOps') - # Nginx Configation into GIT - WOGit.add(self, - ["/etc/nginx"], msg="Adding Nginx into Git") - WOService.reload_service(self, 'nginx') + self.msg = (self.msg + ["HTTP Auth User " + "Name: WordOps"] + + ["HTTP Auth Password : {0}" + .format(passwd)]) + self.msg = (self.msg + ["WordOps backend is available " + "on https://{0}:22222 " + "or https://{1}:22222" + .format(server_ip.text, + WOVariables.wo_fqdn)]) - if set(["nginx"]).issubset(set(apt_packages)): - print("WordOps backend configuration was successful\n" - "You can access it on : https://{0}:22222" - .format(server_ip)) - print("HTTP Auth User Name: WordOps" + - "\nHTTP Auth Password : {0}".format(passwd)) + if upgrade: + try: WOService.reload_service(self, 'nginx') - else: - self.msg = (self.msg + ["HTTP Auth User " - "Name: WordOps"] + - ["HTTP Auth Password : {0}" - .format(passwd)]) - self.msg = (self.msg + ["WordOps backend is available " - "on https://{0}:22222 " - "or https://{1}:22222" - .format(server_ip.text, - WOVariables.wo_fqdn)]) - else: - WOService.restart_service(self, 'nginx') + except CommandExecutionError as e: + Log.debug(self, "{0}".format(e)) + WOGit.rollback(self, ["/etc/nginx"]) + + # Nginx Configation into GIT + WOGit.add(self, + ["/etc/nginx"], msg="Adding Nginx into Git") + WOService.restart_service(self, 'nginx') if set(WOVariables.wo_php).issubset(set(apt_packages)): ngxroot = '/var/www/' @@ -964,20 +963,20 @@ def post_pref(self, apt_packages, packages): if set(WOVariables.wo_fail2ban).issubset(set(apt_packages)): if not os.path.isfile("/etc/fail2ban/jail.d/custom.conf"): data = dict() - WOTemplate.tmpl_render(self, - '/etc/fail2ban/jail.d/custom.conf', - 'fail2ban.mustache', - data, overwrite=False) - WOTemplate.tmpl_render(self, - '/etc/fail2ban/filter.d/' - 'wo-wordpress.conf', - 'fail2ban-wp.mustache', - data, overwrite=False) - WOTemplate.tmpl_render(self, - '/etc/fail2ban/filter.d/' - 'nginx-forbidden.conf', - 'fail2ban-forbidden.mustache', - data, overwrite=False) + WOTemplate.render(self, + '/etc/fail2ban/jail.d/custom.conf', + 'fail2ban.mustache', + data, overwrite=False) + WOTemplate.render(self, + '/etc/fail2ban/filter.d/' + 'wo-wordpress.conf', + 'fail2ban-wp.mustache', + data, overwrite=False) + WOTemplate.render(self, + '/etc/fail2ban/filter.d/' + 'nginx-forbidden.conf', + 'fail2ban-forbidden.mustache', + data, overwrite=False) WOGit.add(self, ["/etc/fail2ban"], msg="Adding Fail2ban into Git") @@ -1147,9 +1146,9 @@ def post_pref(self, apt_packages, packages): # Redis configuration if set(["clamav"]).issubset(set(apt_packages)): Log.debug("Setting up freshclam cronjob") - WOTemplate.tmpl_render(self, '/opt/freshclam.sh', - 'freshclam.mustache', - data, overwrite=False) + WOTemplate.render(self, '/opt/freshclam.sh', + 'freshclam.mustache', + data, overwrite=False) WOFileUtils.chmod(self, "/opt/freshclam.sh", 0o775) WOCron.setcron_weekly(self, '/opt/freshclam.sh ' '> /dev/null 2>&1', diff --git a/wo/cli/plugins/stack_upgrade.py b/wo/cli/plugins/stack_upgrade.py index 7a2566a..efe4855 100644 --- a/wo/cli/plugins/stack_upgrade.py +++ b/wo/cli/plugins/stack_upgrade.py @@ -184,7 +184,7 @@ class WOStackUpgradeController(CementBaseController): Log.error(self, "Not starting package update") Log.info(self, "Updating APT packages, please wait...") if set(WOVariables.wo_nginx).issubset(set(apt_packages)): - pre_pref(self, nginx_packages) + pre_pref(self, ["nginx-custom", "nginx-wo"]) # apt-get update WOAptGet.update(self) if set(WOVariables.wo_php).issubset(set(apt_packages)): @@ -195,7 +195,7 @@ class WOStackUpgradeController(CementBaseController): auto=False, purge=True) # Update packages WOAptGet.install(self, apt_packages) - post_pref(self, apt_packages, empty_packages) + post_pref(self, apt_packages, empty_packages, True) # Post Actions after package updates if len(packages): diff --git a/wo/core/git.py b/wo/core/git.py index d01eee6..3a3531b 100644 --- a/wo/core/git.py +++ b/wo/core/git.py @@ -55,3 +55,28 @@ class WOGit: return True else: return False + + def rollback(self, paths, msg="Rolling-Back"): + """ + Rollback last commit to restore previous. + configuration and commit changes automatically + """ + for path in paths: + global git + git = git.bake("--git-dir={0}/.git".format(path), + "--work-tree={0}".format(path)) + if os.path.isdir(path): + if not os.path.isdir(path+"/.git"): + Log.error(self, "Unable to find a git repository at {0}" + .format(path)) + try: + Log.debug(self, "WOGit: git reset HEAD~ at {0}" + .format(path)) + git.reset("HEAD~ --soft") + git.stash("save \"Rollback\"") + except ErrorReturnCode as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "Unable to git reset at {0} " + .format(path)) + else: + Log.debug(self, "WOGit: Path {0} not present".format(path)) diff --git a/wo/core/services.py b/wo/core/services.py index e217040..cd12a6b 100644 --- a/wo/core/services.py +++ b/wo/core/services.py @@ -27,7 +27,7 @@ class WOService(): "[" + Log.ENDC + "OK" + Log.OKBLUE + "]") return True else: - Log.error( + Log.info( self, "Starting Nginx " + "[" + Log.FAIL + "Failed" + Log.OKBLUE+"]") return False @@ -88,13 +88,13 @@ class WOService(): "[" + Log.ENDC + "OK" + Log.OKBLUE + "]") return True else: - Log.error( - self, "Restarting Nginx " + "[" + Log.FAIL + - "Failed" + Log.OKBLUE+"]") + Log.info(self, "Restarting Nginx " + "[" + Log.FAIL + + "Failed" + Log.OKBLUE+"]") return False else: service_cmd = ('service {0} restart'.format(service_name)) - Log.info(self, "Restart : {0:10}".format(service_name), end='') + Log.info(self, "Restart : {0:10}".format( + service_name), end='') retcode = subprocess.getstatusoutput(service_cmd) if retcode[0] == 0: Log.info(self, "[" + Log.ENDC + "OK" + Log.OKBLUE + "]") diff --git a/wo/core/template.py b/wo/core/template.py index da1f6e9..a4057d9 100644 --- a/wo/core/template.py +++ b/wo/core/template.py @@ -7,7 +7,7 @@ Render Templates class WOTemplate(): - def tmpl_render(self, fileconf, template, data, overwrite=True): + def render(self, fileconf, template, data, overwrite=True): data = dict(data) if (not os.path.isfile('{0}.custom' .format(fileconf))): From 1650d2093ed90f1eaebfe48a3187f50d057fcf5c Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Tue, 27 Aug 2019 15:50:23 +0200 Subject: [PATCH 15/27] Log.info instead of error --- wo/core/services.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wo/core/services.py b/wo/core/services.py index cd12a6b..7b73c04 100644 --- a/wo/core/services.py +++ b/wo/core/services.py @@ -127,7 +127,7 @@ class WOService(): "[" + Log.ENDC + "OK" + Log.OKBLUE + "]") return True else: - Log.error( + Log.info( self, "Reloading Nginx " + "[" + Log.FAIL + "Failed" + Log.OKBLUE+"]") return False From 890e81119a57a5a88526529cc1c4de968284d6e3 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Tue, 27 Aug 2019 16:10:21 +0200 Subject: [PATCH 16/27] Fix rollback --- wo/cli/plugins/stack_pref.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wo/cli/plugins/stack_pref.py b/wo/cli/plugins/stack_pref.py index f821b49..82a5c62 100644 --- a/wo/cli/plugins/stack_pref.py +++ b/wo/cli/plugins/stack_pref.py @@ -489,9 +489,11 @@ def post_pref(self, apt_packages, packages, upgrade=False): if upgrade: try: - WOService.reload_service(self, 'nginx') + WOShellExec.cmd_exec(self, 'nginx -t') except CommandExecutionError as e: Log.debug(self, "{0}".format(e)) + Log.info(self, "Rolling-Back Nginx" + "configuration") WOGit.rollback(self, ["/etc/nginx"]) # Nginx Configation into GIT From 0728c94e6e753961e978678fca1f9069d02bc1c2 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Tue, 27 Aug 2019 16:13:23 +0200 Subject: [PATCH 17/27] edit git --- wo/core/git.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/wo/core/git.py b/wo/core/git.py index 3a3531b..32f919e 100644 --- a/wo/core/git.py +++ b/wo/core/git.py @@ -72,8 +72,7 @@ class WOGit: try: Log.debug(self, "WOGit: git reset HEAD~ at {0}" .format(path)) - git.reset("HEAD~ --soft") - git.stash("save \"Rollback\"") + git.reset("--hard HEAD~") except ErrorReturnCode as e: Log.debug(self, "{0}".format(e)) Log.error(self, "Unable to git reset at {0} " From 6ec91412c0084570223a6a61980be6f252364871 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Tue, 27 Aug 2019 20:20:25 +0200 Subject: [PATCH 18/27] Improve repo gpg keys handling --- CHANGELOG.md | 7 +++++++ README.md | 1 + wo/cli/plugins/stack_pref.py | 2 +- wo/core/apt_repo.py | 5 +---- wo/core/variables.py | 19 ++++++++++++++----- 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 888dc24..d58d8c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### v3.9.x - [Unreleased] +### v3.9.8.4 - 2019-08-27 + #### Added - cht.sh stack : linux online cheatsheet. Usage : `cheat `. Example for tar : `cheat tar` @@ -27,6 +29,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - eXplorer filemanager isn't installed with WordOps dashboard anymore, and a flag `--extplorer` is available. But it's still installed when running the command `wo stack install` - Template rendering function now check for a .custom file before overwriting a configuration by default. - flag `--letsencrypt=subdomain` is not required anymore, you can use `--letsencrypt` or `-le` +- Simplify APT GPG Keys import + +#### Fixed + +- typo error in `wo site update` : [PR #126](https://github.com/WordOps/WordOps/pull/126) ### v3.9.8.3 - 2019-08-21 diff --git a/README.md b/README.md index aaff823..11642d9 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,7 @@ - Debian 9 (Stretch) - Debian 10 (Buster) - Not ready for production - Raspbian 9 (Stretch) +- Raspbian 10 (Buster) - Testing ## Getting Started diff --git a/wo/cli/plugins/stack_pref.py b/wo/cli/plugins/stack_pref.py index 82a5c62..5ec4fce 100644 --- a/wo/cli/plugins/stack_pref.py +++ b/wo/cli/plugins/stack_pref.py @@ -27,7 +27,7 @@ def pre_pref(self, apt_packages): """Pre settings to do before installation packages""" if (set(WOVariables.wo_mysql).issubset(set(apt_packages)) or - set(WOVariables.wo_mysql_client).issubset(set(apt_packages)) or + set(WOVariables.wo_mysql_client).issubset(set(apt_packages))): set(['mariadb-backup']).issubset(set(apt_packages))): # add mariadb repository excepted on raspbian and ubuntu 19.04 if (not WOVariables.wo_distro == 'raspbian'): diff --git a/wo/core/apt_repo.py b/wo/core/apt_repo.py index cfd1f22..2ff2862 100644 --- a/wo/core/apt_repo.py +++ b/wo/core/apt_repo.py @@ -82,10 +82,7 @@ class WORepo(): default keyserver is hkp://keyserver.ubuntu.com user can provide other keyserver with keyserver="hkp://xyz" """ - WOShellExec.cmd_exec(self, "gpg --keyserver {serv}" + WOShellExec.cmd_exec(self, "apt-key adv --keyserver {serv}" .format(serv=(keyserver or "hkp://keyserver.ubuntu.com")) + " --recv-keys {key}".format(key=keyids)) - WOShellExec.cmd_exec(self, "gpg -a --export --armor {0}" - .format(keyids) + - " | apt-key add - ") diff --git a/wo/core/variables.py b/wo/core/variables.py index f73e6dd..aa4d4f8 100644 --- a/wo/core/variables.py +++ b/wo/core/variables.py @@ -101,9 +101,15 @@ class WOVariables(): wo_nginx_repo = ("deb http://download.opensuse.org" "/repositories/home:" "/virtubox:/WordOps/Debian_10/ /") - else: - wo_nginx_repo = ("deb http://download.opensuse.org/repositories/home:" - "/virtubox:/WordOps/Raspbian_9.0/ /") + elif wo_distro == 'raspbian': + if wo_platform_codename == 'stretch': + wo_nginx_repo = ("deb http://download.opensuse.org/" + "repositories/home:" + "/virtubox:/WordOps/Raspbian_9.0/ /") + if wo_platform_codename == 'buster': + wo_nginx_repo = ("deb http://download.opensuse.org/" + "repositories/home:" + "/virtubox:/WordOps/Raspbian_10/ /") wo_nginx = ["nginx-custom", "nginx-wo"] wo_nginx_key = '188C9FB063F0247A' @@ -137,14 +143,17 @@ class WOVariables(): "http://sfo1.mirrors.digitalocean.com/mariadb/repo/" "10.3/ubuntu {codename} main" .format(codename=wo_platform_codename)) + if wo_distro == 'raspbian': + wo_mysql = ["mariadb-server", "percona-toolkit", + "python3-mysqldb"] else: wo_mysql_repo = ("deb [arch=amd64,ppc64el] " "http://sfo1.mirrors.digitalocean.com/mariadb/repo/" "10.3/debian {codename} main" .format(codename=wo_platform_codename)) - wo_mysql = ["mariadb-server", "percona-toolkit", - "python3-mysqldb", "mariadb-backup"] + wo_mysql = ["mariadb-server", "percona-toolkit", + "python3-mysqldb", "mariadb-backup"] wo_mysql_client = ["mariadb-client", "python3-mysqldb"] From 1c3b303ee4f22a798fd3a2d70830d6466af02c03 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Tue, 27 Aug 2019 20:53:03 +0200 Subject: [PATCH 19/27] Fix syntax --- wo/cli/plugins/stack_pref.py | 1 - 1 file changed, 1 deletion(-) diff --git a/wo/cli/plugins/stack_pref.py b/wo/cli/plugins/stack_pref.py index 5ec4fce..16add4b 100644 --- a/wo/cli/plugins/stack_pref.py +++ b/wo/cli/plugins/stack_pref.py @@ -28,7 +28,6 @@ def pre_pref(self, apt_packages): if (set(WOVariables.wo_mysql).issubset(set(apt_packages)) or set(WOVariables.wo_mysql_client).issubset(set(apt_packages))): - set(['mariadb-backup']).issubset(set(apt_packages))): # add mariadb repository excepted on raspbian and ubuntu 19.04 if (not WOVariables.wo_distro == 'raspbian'): Log.info(self, "Adding repository for MySQL, please wait...") From 8db9521a9a9170c9ad3d88404157a76d45285fbe Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Tue, 27 Aug 2019 22:21:22 +0200 Subject: [PATCH 20/27] Fix variables --- wo/cli/plugins/stack.py | 2 -- wo/core/apt_repo.py | 2 +- wo/core/variables.py | 48 +++++++++++++++++++---------------------- 3 files changed, 23 insertions(+), 29 deletions(-) diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index d82a63f..fcf9387 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -63,8 +63,6 @@ class WOStackController(CementBaseController): dict(help='Install PHP 7.3 stack', action='store_true')), (['--mysql'], dict(help='Install MySQL stack', action='store_true')), - (['--mariabackup'], - dict(help='Install MariaBackup stack', action='store_true')), (['--mysqlclient'], dict(help='Install MySQL client for remote MySQL server', action='store_true')), diff --git a/wo/core/apt_repo.py b/wo/core/apt_repo.py index 2ff2862..e5610e7 100644 --- a/wo/core/apt_repo.py +++ b/wo/core/apt_repo.py @@ -47,7 +47,7 @@ class WORepo(): Log.debug(self, "{0}".format(e)) Log.error(self, "Unable to add repo") if ppa is not None: - WOShellExec.cmd_exec(self, "add-apt-repository -y '{ppa_name}'" + WOShellExec.cmd_exec(self, "add-apt-repository -yu '{ppa_name}'" .format(ppa_name=ppa)) def remove(self, ppa=None, repo_url=None): diff --git a/wo/core/variables.py b/wo/core/variables.py index aa4d4f8..4fff892 100644 --- a/wo/core/variables.py +++ b/wo/core/variables.py @@ -88,28 +88,24 @@ class WOVariables(): # Nginx repo and packages if wo_distro == 'ubuntu': wo_nginx_repo = "ppa:wordops/nginx-wo" - elif wo_distro == 'debian': - if wo_platform_codename == 'jessie': - wo_nginx_repo = ("deb http://download.opensuse.org" - "/repositories/home:" - "/virtubox:/WordOps/Debian_8.0/ /") - elif wo_platform_codename == 'stretch': - wo_nginx_repo = ("deb http://download.opensuse.org" - "/repositories/home:" - "/virtubox:/WordOps/Debian_9.0/ /") - elif wo_platform_codename == 'buster': - wo_nginx_repo = ("deb http://download.opensuse.org" - "/repositories/home:" - "/virtubox:/WordOps/Debian_10/ /") - elif wo_distro == 'raspbian': - if wo_platform_codename == 'stretch': - wo_nginx_repo = ("deb http://download.opensuse.org/" - "repositories/home:" - "/virtubox:/WordOps/Raspbian_9.0/ /") - if wo_platform_codename == 'buster': - wo_nginx_repo = ("deb http://download.opensuse.org/" - "repositories/home:" - "/virtubox:/WordOps/Raspbian_10/ /") + else: + if wo_distro == 'debian': + if wo_platform_codename == 'jessie': + wo_deb_repo = "Debian_8.0" + elif wo_platform_codename == 'stretch': + wo_deb_repo = "Debian_9.0" + elif wo_platform_codename == 'buster': + wo_deb_repo = "Debian_10" + elif wo_distro == 'raspbian': + if wo_platform_codename == 'stretch': + wo_deb_repo = "Raspbian_9.0" + elif wo_platform_codename == 'buster': + wo_deb_repo = "Raspbian_10" + # debian/raspbian nginx repository + wo_nginx_repo = ("deb http://download.opensuse.org" + "/repositories/home:" + "/virtubox:/WordOps/{0}/ /" + .format(wo_deb_repo)) wo_nginx = ["nginx-custom", "nginx-wo"] wo_nginx_key = '188C9FB063F0247A' @@ -117,7 +113,6 @@ class WOVariables(): # PHP repo and packages if wo_distro == 'ubuntu': wo_php_repo = "ppa:ondrej/php" - wo_php_key = '' else: wo_php_repo = ( "deb https://packages.sury.org/php/ {codename} main" @@ -143,15 +138,16 @@ class WOVariables(): "http://sfo1.mirrors.digitalocean.com/mariadb/repo/" "10.3/ubuntu {codename} main" .format(codename=wo_platform_codename)) - if wo_distro == 'raspbian': - wo_mysql = ["mariadb-server", "percona-toolkit", - "python3-mysqldb"] else: wo_mysql_repo = ("deb [arch=amd64,ppc64el] " "http://sfo1.mirrors.digitalocean.com/mariadb/repo/" "10.3/debian {codename} main" .format(codename=wo_platform_codename)) + if wo_distro == 'raspbian': + wo_mysql = ["mariadb-server", "percona-toolkit", + "python3-mysqldb"] + else: wo_mysql = ["mariadb-server", "percona-toolkit", "python3-mysqldb", "mariadb-backup"] From 446ab8d7c77e429885b1c275f112a13c299e4636 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Tue, 27 Aug 2019 22:25:18 +0200 Subject: [PATCH 21/27] Fix typo --- wo/cli/plugins/stack.py | 4 ++++ wo/cli/plugins/stack_services.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index fcf9387..bafb182 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -499,6 +499,8 @@ class WOStackController(CementBaseController): pargs.proftpd = True pargs.utils = True pargs.redis = True + packages = \ + packages + ['/var/www/22222/htdocs/*'] if pargs.web: pargs.nginx = True @@ -686,6 +688,8 @@ class WOStackController(CementBaseController): pargs.proftpd = True pargs.utils = True pargs.redis = True + packages = \ + packages + ['/var/www/22222/htdocs/*'] if pargs.web: pargs.nginx = True diff --git a/wo/cli/plugins/stack_services.py b/wo/cli/plugins/stack_services.py index a9b7550..e4585b4 100644 --- a/wo/cli/plugins/stack_services.py +++ b/wo/cli/plugins/stack_services.py @@ -19,7 +19,7 @@ class WOStackStatusController(CementBaseController): def start(self): """Start services""" services = [] - pargs = pargs = self.app.pargs + pargs = self.app.pargs if not (pargs.nginx or pargs.php or pargs.php73 or pargs.mysql or From b5048425509ac88f5ab314b8e43c9d01ac8a7f54 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Tue, 27 Aug 2019 22:49:54 +0200 Subject: [PATCH 22/27] Add issue script --- tests/issue.sh | 26 ++++++++++++++++++++++++++ wo/cli/plugins/site.py | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 tests/issue.sh diff --git a/tests/issue.sh b/tests/issue.sh new file mode 100644 index 0000000..6a0408b --- /dev/null +++ b/tests/issue.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# ------------------------------------------------------------------------- +# WordOps support script +# ------------------------------------------------------------------------- +# Website: https://wordops.net +# GitHub: https://github.com/WordOps/WordOps +# Copyright (c) 2019 - WordOps +# This script is licensed under M.I.T +# ------------------------------------------------------------------------- +# wget -qO wo wops.cc && sudo bash wo +# ------------------------------------------------------------------------- +# Version 3.9.8.4 - 2019-08-28 +# ------------------------------------------------------------------------- + +if [ -f /var/log/wo/wordops.log ]; then + cd /var/log/wo/ || exit 1 + if { + tar -I pigz -cf wordops.tar.gz wordops.log + }; then + wo_link=$(curl -sL --upload-file wordops.tar.gz https://transfer.sh/wordops.tar.gz) + echo + echo "Here the link to provide in your github issue : $wo_link" + echo + fi + cd || exit 1 +fi diff --git a/wo/cli/plugins/site.py b/wo/cli/plugins/site.py index 880ad9e..cb1e075 100644 --- a/wo/cli/plugins/site.py +++ b/wo/cli/plugins/site.py @@ -755,7 +755,7 @@ class WOSiteCreateController(CementBaseController): if data['wp'] and (not pargs.vhostonly): Log.info(self, Log.ENDC + "WordPress admin user :" " {0}".format(wo_wp_creds['wp_user']), log=False) - Log.info(self, Log.ENDC + "WordPress admin user password : {0}" + Log.info(self, Log.ENDC + "WordPress admin password : {0}" .format(wo_wp_creds['wp_pass']), log=False) display_cache_settings(self, data) From 54a17e796f2cbcbc16cb0f24ac35a1b068af81e8 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Tue, 27 Aug 2019 23:25:39 +0200 Subject: [PATCH 23/27] Refactor letsencrypt stack --- wo/cli/plugins/site.py | 103 +++++++++++++++++++++++------------------ 1 file changed, 58 insertions(+), 45 deletions(-) diff --git a/wo/cli/plugins/site.py b/wo/cli/plugins/site.py index cb1e075..13ec710 100644 --- a/wo/cli/plugins/site.py +++ b/wo/cli/plugins/site.py @@ -769,27 +769,29 @@ class WOSiteCreateController(CementBaseController): if pargs.letsencrypt: data['letsencrypt'] = True letsencrypt = True - if pargs.dns: - wo_acme_dns = pargs.dns if data['letsencrypt'] is True: - if pargs.letsencrypt == "subdomain": - if pargs.dns: - setupLetsEncrypt(self, wo_domain, True, False, - True, wo_acme_dns) - else: - setupLetsEncrypt(self, wo_domain, True) - httpsRedirect(self, wo_domain) - elif pargs.letsencrypt == "wildcard": - setupLetsEncrypt(self, wo_domain, False, True, - True, wo_acme_dns) - httpsRedirect(self, wo_domain, True, True) + if (wo_domain_type == 'subdomain' and + (not pargs.letsencrypt == 'wildcard')): + pargs.letsencrypt == 'subdomain' + if pargs.dns: + wo_acme_dns = pargs.dns + wo_dns = True else: - if pargs.dns: - setupLetsEncrypt(self, wo_domain, False, - False, True, wo_acme_dns) - else: - setupLetsEncrypt(self, wo_domain) - httpsRedirect(self, wo_domain) + wo_acme_dns = '' + wo_dns = False + if pargs.letsencrypt == "subdomain": + wo_subdomain = True + wo_wildcard = False + elif pargs.letsencrypt == "wildcard": + wo_wildcard = True + wo_subdomain = False + else: + wo_wildcard = False + wo_subdomain = False + + setupLetsEncrypt(self, wo_domain, wo_subdomain, wo_wildcard, + wo_dns, wo_acme_dns) + httpsRedirect(self, wo_domain, True, wo_wildcard) if pargs.hsts: setupHsts(self, wo_domain) @@ -951,7 +953,7 @@ class WOSiteUpdateController(CementBaseController): try: while not pargs.site_name: pargs.site_name = (input('Enter site name : ').strip()) - except IOError as e: + except IOError: Log.error(self, 'Unable to input site name, Please try again!') pargs.site_name = pargs.site_name.strip() @@ -1239,24 +1241,42 @@ class WOSiteUpdateController(CementBaseController): return 0 if pargs.letsencrypt: + if ((wo_domain_type == 'subdomain') and + (not pargs.letsencrypt == 'wildcard') and + (not pargs.letsencrypt == 'off') and + (not pargs.letsencrypt == 'clean') and + (not pargs.letsencrypt == 'purge')): + pargs.letsencrypt == 'subdomain' if pargs.letsencrypt == 'on': data['letsencrypt'] = True letsencrypt = True + wo_wildcard = False + wo_subdomain = False elif pargs.letsencrypt == 'subdomain': data['letsencrypt'] = True letsencrypt = True + wo_subdomain = True + wo_wildcard = False elif pargs.letsencrypt == 'wildcard': data['letsencrypt'] = True letsencrypt = True + wo_wildcard = True + wo_subdomain = False elif pargs.letsencrypt == 'off': data['letsencrypt'] = False letsencrypt = False + wo_subdomain = False + wo_wildcard = False elif pargs.letsencrypt == 'clean': data['letsencrypt'] = False letsencrypt = False + wo_subdomain = False + wo_wildcard = False elif pargs.letsencrypt == 'purge': data['letsencrypt'] = False letsencrypt = False + wo_subdomain = False + wo_wildcard = False if letsencrypt is check_ssl: if letsencrypt is False: @@ -1351,38 +1371,31 @@ class WOSiteUpdateController(CementBaseController): return 0 if pargs.letsencrypt: - if pargs.dns: - wo_acme_dns = pargs.dns if data['letsencrypt'] is True: - if (wo_domain_type == 'subdomain' and - pargs.letsencrypt != 'wildcard'): - pargs.letsencrypt == 'subdomain' - if not os.path.isfile("{0}/conf/nginx/ssl.conf.disabled" - .format(wo_site_webroot)): - if pargs.letsencrypt == "on": - if pargs.dns: - setupLetsEncrypt(self, wo_domain, False, - False, True, wo_acme_dns) - else: - setupLetsEncrypt(self, wo_domain) - httpsRedirect(self, wo_domain) - elif pargs.letsencrypt == "subdomain": - if pargs.dns: - setupLetsEncrypt(self, wo_domain, True, False, - True, wo_acme_dns) - else: - setupLetsEncrypt(self, wo_domain, True) - httpsRedirect(self, wo_domain) - elif pargs.letsencrypt == "wildcard": - setupLetsEncrypt(self, wo_domain, False, True, - True, wo_acme_dns) - httpsRedirect(self, wo_domain, True, True) + if pargs.dns: + wo_acme_dns = pargs.dns + wo_dns = True + else: + wo_acme_dns = '' + wo_dns = False + if not os.path.isfile("{0}/conf/nginx/ssl.conf.disabled"): + setupLetsEncrypt(self, wo_domain, wo_subdomain, + wo_wildcard, + wo_dns, wo_acme_dns) + httpsRedirect(self, wo_domain, True, wo_wildcard) site_url_https(self, wo_domain) else: WOFileUtils.mvfile(self, "{0}/conf/nginx/ssl.conf.disabled" .format(wo_site_webroot), '{0}/conf/nginx/ssl.conf' .format(wo_site_webroot)) + WOFileUtils.mvfile(self, "/etc/nginx/conf.d/" + "force-ssl-{0}.conf.disabled" + .format(wo_domain), + '/etc/nginx/conf.d/force-ssl-{0}.conf' + .format(wo_domain)) + + httpsRedirect(self, wo_domain, True, wo_wildcard) site_url_https(self, wo_domain) if not WOService.reload_service(self, 'nginx'): From 3308df3adc083fc589f10598232b55cfae6adca5 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Tue, 27 Aug 2019 23:41:53 +0200 Subject: [PATCH 24/27] update changelog & issues --- .github/ISSUE_TEMPLATE.md | 13 +++++++------ CHANGELOG.md | 7 +++---- tests/issue.sh | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 77ccba4..212c00c 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,13 +1,14 @@ -This issue tracker is only for issues related to WordOps. +This issue tracker is only for issues directly related to WordOps. Please use for support questions. If you feel the issue is a WordOps specific issue, please attach the output of the following commands. System Information -- [ ] lsb_release -a -- [ ] wo info -- [ ] nginx -V -- [ ] wo -v -- [ ] wp cli info --allow-root +- [ ] `lsb_release -a` +- [ ] `wo info` +- [ ] `nginx -V` +- [ ] `wo -v` +- [ ] `wp cli info --allow-root` +- [ ] `curl -sL git.io/fjAp3 | sudo -E bash -` diff --git a/CHANGELOG.md b/CHANGELOG.md index d58d8c0..fa968e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### v3.9.x - [Unreleased] -### v3.9.8.4 - 2019-08-27 +### v3.9.8.4 - 2019-08-28 #### Added @@ -19,17 +19,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Domain/Subdomain detection based on public domain suffixes list - Increase Nginx & MariaDB systemd open_files limits - Cronjob to update Cloudflare IPs list -- mariadb-backup to perform full and non-blocking databases backup +- mariadb-backup to perform full and non-blocking databases backup (only installation) - Nginx configuration check before performing start/reload/restart - Nginx mapping to proxy web-socket connections -- Nginx configuration rollback in case of failure with `wo stack upgrade --nginx` #### Changed - eXplorer filemanager isn't installed with WordOps dashboard anymore, and a flag `--extplorer` is available. But it's still installed when running the command `wo stack install` - Template rendering function now check for a .custom file before overwriting a configuration by default. - flag `--letsencrypt=subdomain` is not required anymore, you can use `--letsencrypt` or `-le` -- Simplify APT GPG Keys import +- Simplifiy and decrease duration of `apt-key` GPG keys import #### Fixed diff --git a/tests/issue.sh b/tests/issue.sh index 6a0408b..61bf57e 100644 --- a/tests/issue.sh +++ b/tests/issue.sh @@ -7,7 +7,7 @@ # Copyright (c) 2019 - WordOps # This script is licensed under M.I.T # ------------------------------------------------------------------------- -# wget -qO wo wops.cc && sudo bash wo +# curl -sL git.io/fjAp3 | sudo -E bash - # ------------------------------------------------------------------------- # Version 3.9.8.4 - 2019-08-28 # ------------------------------------------------------------------------- From b2eb5ea10144596299bc0a1dfbc4ff789d77eb46 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Tue, 27 Aug 2019 23:49:06 +0200 Subject: [PATCH 25/27] Fix wo_subdomain --- wo/cli/plugins/site.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wo/cli/plugins/site.py b/wo/cli/plugins/site.py index 13ec710..381f2c4 100644 --- a/wo/cli/plugins/site.py +++ b/wo/cli/plugins/site.py @@ -770,9 +770,6 @@ class WOSiteCreateController(CementBaseController): data['letsencrypt'] = True letsencrypt = True if data['letsencrypt'] is True: - if (wo_domain_type == 'subdomain' and - (not pargs.letsencrypt == 'wildcard')): - pargs.letsencrypt == 'subdomain' if pargs.dns: wo_acme_dns = pargs.dns wo_dns = True @@ -788,6 +785,9 @@ class WOSiteCreateController(CementBaseController): else: wo_wildcard = False wo_subdomain = False + if ((wo_domain_type == 'subdomain') and + (not pargs.letsencrypt == 'wildcard')): + wo_subdomain = True setupLetsEncrypt(self, wo_domain, wo_subdomain, wo_wildcard, wo_dns, wo_acme_dns) From 1f407aaa4891d5f63a9eef1a9913bc6e9fdc0790 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Wed, 28 Aug 2019 00:26:52 +0200 Subject: [PATCH 26/27] Fix wo update --- wo/cli/plugins/site.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/wo/cli/plugins/site.py b/wo/cli/plugins/site.py index 381f2c4..6ec5dfc 100644 --- a/wo/cli/plugins/site.py +++ b/wo/cli/plugins/site.py @@ -1250,8 +1250,12 @@ class WOSiteUpdateController(CementBaseController): if pargs.letsencrypt == 'on': data['letsencrypt'] = True letsencrypt = True + if ((wo_domain_type == 'subdomain') and + (not pargs.letsencrypt == 'wildcard')): + wo_subdomain = True + else: + wo_subdomain = False wo_wildcard = False - wo_subdomain = False elif pargs.letsencrypt == 'subdomain': data['letsencrypt'] = True letsencrypt = True From a83fd9bfda4a09a0792ef52be32f43e94a084ee2 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Wed, 28 Aug 2019 00:36:39 +0200 Subject: [PATCH 27/27] Update changelog before release --- CHANGELOG.md | 6 +++--- install | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa968e1..c6074c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,11 +16,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - ClamAV anti-virus with weekly cronjob to update signatures database - Internal function to add daily cronjobs - Additional comment to detect previous configuration tuning (MariaDB & Redis) -- Domain/Subdomain detection based on public domain suffixes list +- Domain/Subdomain detection based on public domain suffixes list for letsencrypt - Increase Nginx & MariaDB systemd open_files limits - Cronjob to update Cloudflare IPs list -- mariadb-backup to perform full and non-blocking databases backup (only installation) -- Nginx configuration check before performing start/reload/restart +- mariadb-backup to perform full and non-blocking databases backup (installation only. Backup feature will be available soon) +- Nginx configuration check before performing start/reload/restart (If configuration check fail, WordOps will not reload/restart Nginx anymore) - Nginx mapping to proxy web-socket connections #### Changed diff --git a/install b/install index d5132ba..d4da65f 100755 --- a/install +++ b/install @@ -9,7 +9,7 @@ # ------------------------------------------------------------------------- # wget -qO wo wops.cc && sudo bash wo # ------------------------------------------------------------------------- -# Version 3.9.8.3 - 2019-08-20 +# Version 3.9.8.4 - 2019-08-28 # ------------------------------------------------------------------------- # CONTENTS