diff --git a/.travis.yml b/.travis.yml index a78e956..5445688 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,6 +24,13 @@ before_script: - unset LANG - sudo apt-get install --assume-yes --quiet git python3-setuptools python3-dev python3-apt ccze tree +after_script: + - sudo cat /etc/nginx/nginx.conf | ccze -A + - sudo cat /var/log/wo/wordops.log | ccze -A + - sudo cat /etc/mysql/my.cnf | ccze -A + - sudo bash install --purge + + script: - lsb_release -a - sudo bash -c 'echo -e "[user]\n\tname = abc\n\temail = root@localhost.com" > /home/travis/.gitconfig' @@ -36,5 +43,3 @@ script: - sudo wo update --travis - sudo wo stack status - - sudo wo stack purge --all --force - - sudo bash install --purge diff --git a/CHANGELOG.md b/CHANGELOG.md index 99250b1..3c64539 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,29 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### v3.9.x - [Unreleased] +### v3.9.8.8 - 2019-09-02 + +#### Added + +- Sendmail stack to send WordPress welcome email properly +- Backup all MySQL databases before removing/purging MySQL stack + +#### Changed + +- do not terminate stack install process on errors +- WordOps internal log rotation limit increased to 1MB + +#### Fixed + +- ufw rules for proftpd not applied +- phpredisadmin install +- netdata configuration +- extplorer installation +- add LANG='en_US.UTF-8' in install script +- Read public_suffix list with utf8 encoding. Issue [#128](https://github.com/WordOps/WordOps/issues/128) +- Netdata uninstall script path. PR [#135](https://github.com/WordOps/WordOps/pull/135) +- SSL Certificates expiration for subdomains + ### v3.9.8.7 - 2019-08-31 #### Changed diff --git a/README.md b/README.md index a167a62..faca027 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,14 @@ Apps & Tools shipped with WordOps : - [cheat.sh](https://github.com/chubin/cheat.sh) - [ProFTPd](https://github.com/proftpd/proftpd) +Cache Plugins supported by WordOps : + +- [Nginx-helper](https://github.com/rtCamp/nginx-helper) +- [Cache-Enabler](https://github.com/keycdn/cache-enabler) +- [Redis-object-cache](https://github.com/tillkruss/redis-cache) +- [WP-Super-Cache](https://github.com/Automattic/wp-super-cache) +- [WP-Rocket](https://github.com/wp-media/wp-rocket) + ## License - [MIT](http://opensource.org/licenses/MIT) © [WordOps](https://wordops.net) diff --git a/config/wo.conf b/config/wo.conf index 8d4a3ad..f0d077c 100644 --- a/config/wo.conf +++ b/config/wo.conf @@ -33,7 +33,7 @@ to_console = false rotate = true ### Max size in bytes that a log file can grow until it is rotated. -max_bytes = 512000 +max_bytes = 1000000 ### The maximun number of log files to maintain when rotating max_files = 7 diff --git a/install b/install index 438411d..d10db07 100755 --- a/install +++ b/install @@ -103,6 +103,10 @@ fi # 1- Update the apt sewers with fresh info ### export DEBIAN_FRONTEND=noninteractive +unset LANG +export LANG='en_US.UTF-8' +export LC_ALL='C.UTF-8' + [ -z "$wo_travis" ] && { apt-get update -qq } @@ -151,7 +155,8 @@ readonly TIME=$(date +"$TIME_FORMAT") readonly NGINX_BACKUP_FILE="/var/lib/wo-backup/nginx-backup.$TIME.tar.gz" readonly EE_BACKUP_FILE="/var/lib/wo-backup/ee-backup.$TIME.tar.gz" readonly WO_BACKUP_FILE="/var/lib/wo-backup/wo-backup.$TIME.tar.gz" -readonly wo_env=$(grep "container=lxc" /proc/1/environ) +readonly wo_lxc=$(grep "container=lxc" /proc/1/environ) +readonly wo_wsl=$(grep "wsl" /proc/1/environ) WO_ARCH="$(uname -m)" if [ -x /usr/local/bin/ee ]; then @@ -653,7 +658,7 @@ wo_remove_ee_cron() { wo_tweak_kernel() { - if [ "$WO_ARCH" = "x86_64" ] && [ -z "$wo_env" ]; then + if [ "$WO_ARCH" = "x86_64" ] && [ -z "$wo_lxc" ] && [ -z "$wo_wsl" ]; then rm -f /etc/sysctl.d/60-ubuntu-nginx-web-server.conf wget -qO /etc/sysctl.d/60-wo-tweaks.conf https://raw.githubusercontent.com/WordOps/WordOps/"$wo_branch"/wo/cli/templates/sysctl.mustache if [ "$wo_distro_version" = "bionic" ] || [ "$wo_distro_version" = "disco" ] || [ "$wo_distro_version" = "buster" ]; then @@ -813,8 +818,7 @@ else if [ -x /usr/local/bin/wo ]; then if [ -z "$wo_force_install" ]; then if { wo -v 2>&1 | grep -q "$wo_version_new"; }; then - wo_lib_error "You already have WordOps $wo_version_new" - exit 1 + wo_lib_error "You already have WordOps $wo_version_new" 1 fi fi wo_lib_echo "Installing wo dependencies " | tee -ai $wo_install_log @@ -861,8 +865,7 @@ else if [ -z "$wo_force_install" ]; then echo -e "Migrate from EasyEngine to WordOps (y/n): " && read -r WO_ANSWER if [ "$WO_ANSWER" != "y" ] && [ "$WO_ANSWER" != "Y" ]; then - wo_lib_error "Not installing WordOps, exit status = " 1 - exit 1 + wo_lib_error "Not installing WordOps" 1 fi fi wo_lib_echo "Installing wo dependencies " | tee -ai $wo_install_log diff --git a/setup.py b/setup.py index 30aeadf..2989001 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.7', + version='3.9.8.8', description=long_description, long_description=long_description, classifiers=[], diff --git a/tests/travis.sh b/tests/travis.sh index 74806d1..d4b74b3 100644 --- a/tests/travis.sh +++ b/tests/travis.sh @@ -131,6 +131,5 @@ 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 -cat /etc/mysql/my.cnf +wo stack purge --all --force \ No newline at end of file diff --git a/wo/cli/plugins/site.py b/wo/cli/plugins/site.py index 9096a94..2a1ec33 100644 --- a/wo/cli/plugins/site.py +++ b/wo/cli/plugins/site.py @@ -429,7 +429,6 @@ class WOSiteCreateController(CementBaseController): pargs.site_name = pargs.site_name.strip() (wo_domain, wo_www_domain) = ValidateDomain(pargs.site_name) - (wo_domain_type, wo_root_domain) = GetDomainlevel(wo_domain) if not wo_domain.strip(): Log.error("Invalid domain name, " "Provide valid domain name") @@ -499,10 +498,8 @@ class WOSiteCreateController(CementBaseController): if data and pargs.php73: data['php73'] = True - php73 = 1 elif data: data['php73'] = False - php73 = 0 if ((not pargs.wpfc) and (not pargs.wpsc) and @@ -568,8 +565,10 @@ class WOSiteCreateController(CementBaseController): if data['php73']: php_version = "7.3" + php73 = 1 else: php_version = "7.2" + php73 = 0 addNewSite(self, wo_domain, stype, cache, wo_site_webroot, php_version=php_version) @@ -744,6 +743,7 @@ class WOSiteCreateController(CementBaseController): "`tail /var/log/wo/wordops.log` and please try again") if pargs.letsencrypt: + (wo_domain_type, wo_root_domain) = GetDomainlevel(wo_domain) data['letsencrypt'] = True letsencrypt = True if data['letsencrypt'] is True: @@ -958,7 +958,6 @@ class WOSiteUpdateController(CementBaseController): pargs.site_name = pargs.site_name.strip() (wo_domain, wo_www_domain) = ValidateDomain(pargs.site_name) wo_site_webroot = WOVariables.wo_webroot + wo_domain - (wo_domain_type, wo_root_domain) = GetDomainlevel(wo_domain) check_site = getSiteInfo(self, wo_domain) if check_site is None: @@ -1151,6 +1150,53 @@ class WOSiteUpdateController(CementBaseController): "site") pargs.php73 = False + if pargs.letsencrypt: + (wo_domain_type, wo_root_domain) = GetDomainlevel(wo_domain) + 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 + 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 not wo_subdomain: + if letsencrypt is check_ssl: + if letsencrypt is False: + Log.error(self, "SSl is not configured for given " + "site") + elif letsencrypt is True: + Log.error(self, "SSl is already configured for given " + "site") + pargs.letsencrypt = False + # --letsencrypt=renew code goes here if pargs.letsencrypt == "renew" and not pargs.all: expiry_days = SSL.getExpirationDays(self, wo_domain) @@ -1238,52 +1284,6 @@ class WOSiteUpdateController(CementBaseController): "site", False) return 0 - if pargs.letsencrypt: - 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 - 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 not wo_subdomain: - if letsencrypt is check_ssl: - if letsencrypt is False: - Log.error(self, "SSl is not configured for given " - "site") - elif letsencrypt is True: - Log.error(self, "SSl is already configured for given " - "site") - pargs.letsencrypt = False - if data and (not pargs.php73): if old_php73 is True: data['php73'] = True @@ -1375,13 +1375,14 @@ class WOSiteUpdateController(CementBaseController): else: wo_acme_dns = '' wo_dns = False + if wo_subdomain: + # check if a wildcard cert for the root domain exist + Log.debug(self, "checkWildcardExist on *.{0}" + .format(wo_root_domain)) + isWildcard = checkWildcardExist(self, wo_root_domain) + Log.debug(self, "isWildcard = {0}".format(isWildcard)) if not os.path.isfile("{0}/conf/nginx/ssl.conf.disabled"): if wo_subdomain: - # check if a wildcard cert for the root domain exist - Log.debug(self, "checkWildcardExist on *.{0}" - .format(wo_root_domain)) - isWildcard = checkWildcardExist(self, wo_root_domain) - Log.debug(self, "isWildcard = {0}".format(isWildcard)) if isWildcard: Log.info(self, "Using existing Wildcard SSL " "certificate from {0} to secure {1}" @@ -1422,7 +1423,7 @@ class WOSiteUpdateController(CementBaseController): Log.info(self, "Congratulations! Successfully " "Configured SSL for Site " " https://{0}".format(wo_domain)) - if wo_subdomain: + if wo_subdomain and isWildcard: if (SSL.getExpirationDays(self, wo_root_domain) > 0): Log.info(self, "Your cert will expire within " + str(SSL.getExpirationDays(self, wo_root_domain)) + @@ -1470,6 +1471,9 @@ class WOSiteUpdateController(CementBaseController): elif (pargs.letsencrypt == "clean" or pargs.letsencrypt == "purge"): removeAcmeConf(self, wo_domain) + # find all broken symlinks + sympath = "/var/www" + WOFileUtils.findBrokenSymlink(self, sympath) if not WOService.reload_service(self, 'nginx'): Log.error(self, "service nginx reload failed. " "check issues with `nginx -t` command") @@ -1874,7 +1878,6 @@ class WOSiteDeleteController(CementBaseController): pargs.site_name = pargs.site_name.strip() (wo_domain, wo_www_domain) = ValidateDomain(pargs.site_name) - wo_domain_type, wo_root_domain = GetDomainlevel(wo_domain) wo_db_name = '' wo_prompt = '' wo_nginx_prompt = '' diff --git a/wo/cli/plugins/site_functions.py b/wo/cli/plugins/site_functions.py index 201d37e..ccf7575 100644 --- a/wo/cli/plugins/site_functions.py +++ b/wo/cli/plugins/site_functions.py @@ -610,7 +610,10 @@ def setupwordpress(self, data, vhostonly=False): WOShellExec.cmd_exec(self, "/bin/bash -c \"{0} --allow-root " .format(WOVariables.wo_wpcli_path) + "db clean --yes\"") - WOFileUtils.rm(self, "{0}/htdocs/*".format(wo_site_webroot)) + WOFileUtils.rm(self, "{0}/htdocs".format(wo_site_webroot)) + WOFileUtils.mkdir(self, "{0}/htdocs".format(wo_site_webroot)) + WOFileUtils.chown(self, "{0}/htdocs".format(wo_site_webroot), + 'www-data', 'www-data') except CommandExecutionError: raise SiteError("Cleaning WordPress install failed") @@ -1332,10 +1335,8 @@ 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)) or - os.path.isdir('/etc/letsencrypt/live/{0}' - .format(domain))): + if os.path.isdir('/etc/letsencrypt/renewal/{0}_ecc' + .format(domain)): removeAcmeConf(self, domain) if webroot: @@ -1483,7 +1484,7 @@ def checkWildcardExist(self, wo_domain_name): # define new csv dialect csv.register_dialect('acmeconf', delimiter='|') # open file - certfile = open('/var/lib/wo/cert.csv', 'rt') + certfile = open('/var/lib/wo/cert.csv', mode='r', encoding='utf-8') reader = csv.reader(certfile, 'acmeconf') wo_wildcard_domain = ("*.{0}".format(wo_domain_name)) for row in reader: diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index b11de59..833750e 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -34,6 +34,7 @@ from wo.core.mysql import WOMysql from wo.core.services import WOService from wo.core.shellexec import CommandExecutionError, WOShellExec from wo.core.variables import WOVariables +from wo.core.template import WOTemplate def wo_stack_hook(app): @@ -88,6 +89,8 @@ class WOStackController(CementBaseController): dict(help='Install Fail2ban stack', action='store_true')), (['--clamav'], dict(help='Install ClamAV stack', action='store_true')), + (['--sendmail'], + dict(help='Install Sendmail stack', action='store_true')), (['--utils'], dict(help='Install Utils stack', action='store_true')), (['--redis'], @@ -126,7 +129,7 @@ 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.clamav) and - (not pargs.phpredisadmin) and + (not pargs.phpredisadmin) and (not pargs.sendmail) and (not pargs.php73)): pargs.web = True pargs.admin = True @@ -145,8 +148,10 @@ class WOStackController(CementBaseController): pargs.php = True pargs.mysql = True pargs.wpcli = True + pargs.sendmail = True if pargs.admin: + pargs.web = True pargs.adminer = True pargs.phpmyadmin = True pargs.composer = True @@ -185,9 +190,10 @@ class WOStackController(CementBaseController): # Redis if pargs.redis: + pargs.php = True if not WOAptGet.is_installed(self, 'redis-server'): apt_packages = apt_packages + WOVariables.wo_redis - pargs.php = True + else: Log.info(self, "Redis already installed") @@ -240,8 +246,8 @@ class WOStackController(CementBaseController): # WP-CLI if pargs.wpcli: Log.debug(self, "Setting packages variable for WP-CLI") - if (not os.path.isfile("/usr/local/bin/wp") and not - os.path.isfile("/usr/bin/wp")): + if ((not os.path.isfile("/usr/local/bin/wp")) and + (not os.path.isfile("/usr/bin/wp"))): packages = packages + [["https://github.com/wp-cli/wp-cli/" "releases/download/v{0}/" "wp-cli-{0}.phar" @@ -270,6 +276,15 @@ class WOStackController(CementBaseController): Log.debug(self, "ClamAV already installed") Log.info(self, "ClamAV already installed") + # sendmail + if pargs.sendmail: + Log.debug(self, "Setting apt_packages variable for Sendmail") + if not WOAptGet.is_installed(self, 'sendmail'): + apt_packages = apt_packages + ["sendmail"] + else: + Log.debug(self, "Sendmail already installed") + Log.info(self, "Sendmail already installed") + # proftpd if pargs.proftpd: Log.debug(self, "Setting apt_packages variable for ProFTPd") @@ -312,6 +327,9 @@ class WOStackController(CementBaseController): # Composer if pargs.composer: + if ((not WOAptGet.is_installed(self, 'php7.2-fpm')) and + (not WOAptGet.is_installed(self, 'php7.3-fpm'))): + pargs.php = True if not os.path.isfile('/usr/local/bin/composer'): Log.debug(self, "Setting packages variable for Composer ") packages = packages + [["https://getcomposer.org/" @@ -400,7 +418,7 @@ class WOStackController(CementBaseController): Log.info(self, "WordOps dashboard already installed") # eXtplorer - if pargs.explorer: + if pargs.extplorer: if not os.path.isdir('/var/www/22222/htdocs/files'): Log.debug(self, "Setting packages variable for eXtplorer") packages = packages + \ @@ -502,7 +520,7 @@ 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.clamav) and - (not pargs.phpredisadmin) and + (not pargs.phpredisadmin) and (not pargs.sendmail) and (not pargs.php73)): pargs.web = True pargs.admin = True @@ -523,6 +541,7 @@ class WOStackController(CementBaseController): pargs.php = True pargs.mysql = True pargs.wpcli = True + pargs.sendmail = True if pargs.admin: pargs.composer = True @@ -589,6 +608,12 @@ class WOStackController(CementBaseController): if WOAptGet.is_installed(self, 'clamav'): apt_packages = apt_packages + WOVariables.wo_clamav + # sendmail + if pargs.sendmail: + Log.debug(self, "Setting apt_packages variable for Sendmail") + if WOAptGet.is_installed(self, 'sendmail'): + apt_packages = apt_packages + ["sendmail"] + # proftpd if pargs.proftpd: if WOAptGet.is_installed(self, 'proftpd-basic'): @@ -667,6 +692,10 @@ class WOStackController(CementBaseController): if (set(["nginx-custom"]).issubset(set(apt_packages))): WOService.stop_service(self, 'nginx') + if (set(WOVariables.wo_mysql).issubset(set(apt_packages))): + WOMysql.backupAll(self) + WOService.stop_service(self, 'mysql') + # Netdata uninstaller if (set(['/var/lib/wo/tmp/' 'kickstart.sh']).issubset(set(packages))): @@ -708,7 +737,7 @@ 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.clamav) and - (not pargs.phpredisadmin) and + (not pargs.phpredisadmin) and (not pargs.sendmail) and (not pargs.php73)): pargs.web = True pargs.admin = True @@ -729,6 +758,7 @@ class WOStackController(CementBaseController): pargs.php = True pargs.mysql = True pargs.wpcli = True + pargs.sendmail = True if pargs.admin: pargs.utils = True @@ -795,6 +825,12 @@ class WOStackController(CementBaseController): if WOAptGet.is_installed(self, 'clamav'): apt_packages = apt_packages + WOVariables.wo_clamav + # sendmail + if pargs.sendmail: + Log.debug(self, "Setting apt_packages variable for Sendmail") + if WOAptGet.is_installed(self, 'sendmail'): + apt_packages = apt_packages + ["sendmail"] + # proftpd if pargs.proftpd: if WOAptGet.is_installed(self, 'proftpd-basic'): @@ -880,16 +916,20 @@ class WOStackController(CementBaseController): if (set(["fail2ban"]).issubset(set(apt_packages))): WOService.stop_service(self, 'fail2ban') + if (set(WOVariables.wo_mysql).issubset(set(apt_packages))): + WOMysql.backupAll(self) + WOService.stop_service(self, 'mysql') + # Netdata uninstaller if (set(['/var/lib/wo/tmp/' 'kickstart.sh']).issubset(set(packages))): if WOVariables.wo_distro == 'Raspbian': WOShellExec.cmd_exec(self, "bash /usr/" - "libexec/netdata-" + "libexec/netdata/netdata-" "uninstaller.sh -y -f") else: WOShellExec.cmd_exec(self, "bash /opt/netdata/usr/" - "libexec/netdata-" + "libexec/netdata/netdata-" "uninstaller.sh -y -f") if (apt_packages): diff --git a/wo/cli/plugins/stack_pref.py b/wo/cli/plugins/stack_pref.py index 375c44d..e3fab80 100644 --- a/wo/cli/plugins/stack_pref.py +++ b/wo/cli/plugins/stack_pref.py @@ -47,11 +47,13 @@ def pre_pref(self, apt_packages): if set(WOVariables.wo_mysql).issubset(set(apt_packages)): # generate random 24 characters root password chars = ''.join(random.sample(string.ascii_letters, 24)) + # configure MySQL non-interactive install - if (not WOVariables.wo_distro == 'raspbian'): - mariadb_ver = '10.3' - else: + if ((WOVariables.wo_distro == 'raspbian') and + (WOVariables.wo_platform_codename == 'stretch')): mariadb_ver = '10.1' + else: + mariadb_ver = '10.3' Log.debug(self, "Pre-seeding MySQL") Log.debug(self, "echo \"mariadb-server-{0} " @@ -182,32 +184,34 @@ def post_pref(self, apt_packages, packages, upgrade=False): encoding='utf-8', mode='a') as wo_nginx: wo_nginx.write('fastcgi_param \tSCRIPT_FILENAME ' '\t$request_filename;\n') + try: + data = dict(php="9000", debug="9001", + php7="9070", debug7="9170") + WOTemplate.render( + self, '{0}/upstream.conf'.format(ngxcnf), + 'upstream.mustache', data, overwrite=True) - data = dict(php="9000", debug="9001", - php7="9070", debug7="9170") - 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.render(self, + '{0}/stub_status.conf'.format(ngxcnf), + 'stub_status.mustache', data) + data = dict() + WOTemplate.render(self, + '{0}/webp.conf'.format(ngxcnf), + 'webp.mustache', data, overwrite=False) - data = dict(phpconf=True if - WOAptGet.is_installed(self, 'php7.2-fpm') - else False) - WOTemplate.render(self, - '{0}/stub_status.conf'.format(ngxcnf), - 'stub_status.mustache', data) - data = dict() - WOTemplate.render(self, - '{0}/webp.conf'.format(ngxcnf), - 'webp.mustache', data) + WOTemplate.render(self, + '{0}/cloudflare.conf'.format(ngxcnf), + 'cloudflare.mustache', data) - WOTemplate.render(self, - '{0}/cloudflare.conf'.format(ngxcnf), - 'cloudflare.mustache', data) - - WOTemplate.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) + except CommandExecutionError as e: + Log.debug(self, "{0}".format(e)) # Setup Nginx common directory if not os.path.exists('{0}'.format(ngxcom)): @@ -215,7 +219,7 @@ def post_pref(self, apt_packages, packages, upgrade=False): '/etc/nginx/common') os.makedirs('/etc/nginx/common') - if os.path.exists('/etc/nginx/common'): + try: data = dict() # Common Configuration @@ -263,9 +267,7 @@ def post_pref(self, apt_packages, packages, upgrade=False): '{0}/wpce-php72.conf' .format(ngxcom), 'wpce.mustache', data) - - # PHP 7.3 conf - if os.path.isdir("/etc/nginx/common"): + # PHP 7.3 conf data = dict(upstream="php73") WOTemplate.render(self, @@ -301,12 +303,14 @@ def post_pref(self, apt_packages, packages, upgrade=False): '{0}/wpce-php73.conf' .format(ngxcom), 'wpce.mustache', data) + except CommandExecutionError as e: + Log.debug(self, "{0}".format(e)) - with open("/etc/nginx/common/release", - "w") as release_file: - release_file.write("v{0}" - .format(WOVariables.wo_version)) - release_file.close() + with open("/etc/nginx/common/release", + "w") as release_file: + release_file.write("v{0}" + .format(WOVariables.wo_version)) + release_file.close() # Following files should not be overwrited @@ -322,7 +326,7 @@ def post_pref(self, apt_packages, packages, upgrade=False): WOTemplate.render(self, '{0}/fastcgi.conf' .format(ngxcnf), - 'fastcgi.mustache', data, overwrite=False) + 'fastcgi.mustache', data, overwrite=True) # add redis cache format if not already done if (os.path.isfile("/etc/nginx/nginx.conf") and @@ -477,6 +481,7 @@ def post_pref(self, apt_packages, packages, upgrade=False): "/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') if set(["nginx"]).issubset(set(apt_packages)): @@ -665,12 +670,12 @@ def post_pref(self, apt_packages, packages, upgrade=False): .format(ngxroot)) os.makedirs('{0}22222/htdocs/fpm/status/' .format(ngxroot)) - open('{0}22222/htdocs/fpm/status/debug72' - .format(ngxroot), - encoding='utf-8', mode='a').close() - open('{0}22222/htdocs/fpm/status/php72' - .format(ngxroot), - encoding='utf-8', mode='a').close() + open('{0}22222/htdocs/fpm/status/debug72' + .format(ngxroot), + encoding='utf-8', mode='a').close() + open('{0}22222/htdocs/fpm/status/php72' + .format(ngxroot), + encoding='utf-8', mode='a').close() # Write info.php if not os.path.exists('{0}22222/htdocs/php/' @@ -681,10 +686,10 @@ def post_pref(self, apt_packages, packages, upgrade=False): os.makedirs('{0}22222/htdocs/php' .format(ngxroot)) - with open("{0}22222/htdocs/php/info.php" - .format(ngxroot), - encoding='utf-8', mode='w') as myfile: - myfile.write("") + with open("{0}22222/htdocs/php/info.php" + .format(ngxroot), + encoding='utf-8', mode='w') as myfile: + myfile.write("") WOFileUtils.chown(self, "{0}22222/htdocs" .format(ngxroot), @@ -1072,17 +1077,22 @@ def post_pref(self, apt_packages, packages, upgrade=False): WOService.restart_service(self, 'proftpd') # add rule for proftpd with UFW - if WOAptGet.is_installed(self, 'ufw'): + if os.path.isdir('/etc/ufw'): try: - WOShellExec.cmd_exec(self, "/usr/bin/ufw allow " - "49000:50000/tcp") + WOShellExec.cmd_exec( + self, "ufw allow 21") + WOShellExec.cmd_exec( + self, "ufw allow 49000:50000/tcp") + WOShellExec.cmd_exec( + self, "ufw reload") except CommandExecutionError as e: Log.debug(self, "{0}".format(e)) Log.error(self, "Unable to add UFW rule") if ((os.path.isfile("/etc/fail2ban/jail.d/custom.conf")) and - (not WOFileUtils.grep(self, "/etc/fail2ban/jail.d/custom.conf", - "proftpd"))): + (not WOFileUtils.grep( + self, "/etc/fail2ban/jail.d/custom.conf", + "proftpd"))): with open("/etc/fail2ban/jail.d/custom.conf", encoding='utf-8', mode='a') as f2bproftpd: f2bproftpd.write("\n\n[proftpd]\nenabled = true\n") @@ -1108,17 +1118,13 @@ def post_pref(self, apt_packages, packages, upgrade=False): if not os.path.isfile("/etc/nginx/conf.d/redis.conf"): with open("/etc/nginx/conf.d/redis.conf", "a") as redis_file: - redis_file.write("# Log format Settings\n" - "log_format rt_cache_redis " - "'$remote_addr " - "$upstream_response_time " - "$srcache_fetch_status " - "[$time_local]" - " '\n '$http_host" - " \"$request\" " - "$status $body_bytes_sent '\n" - "'\"$http_referer\" " - "\"$http_user_agent\"';\n") + redis_file.write( + "# Log format Settings\n" + "log_format rt_cache_redis '$remote_addr " + "$upstream_response_time $srcache_fetch_status " + "[$time_local] '\n '$http_host \"$request\" " + "$status $body_bytes_sent '\n'\"$http_referer\" " + "\"$http_user_agent\"';\n") # set redis.conf parameter # set maxmemory 10% for ram below 512MB and 20% for others # set maxmemory-policy allkeys-lru @@ -1158,12 +1164,10 @@ def post_pref(self, apt_packages, packages, upgrade=False): Log.debug( self, "Setting maxmemory-policy variable to " "allkeys-lru in redis.conf") - WOFileUtils.searchreplace(self, - "/etc/redis/redis.conf", - "# maxmemory-policy " - "noeviction", - "maxmemory-policy " - "allkeys-lru") + WOFileUtils.searchreplace( + self, "/etc/redis/redis.conf", + "# maxmemory-policy noeviction", + "maxmemory-policy allkeys-lru") Log.debug( self, "Setting tcp-backlog variable to " "in redis.conf") @@ -1268,7 +1272,9 @@ def post_pref(self, apt_packages, packages, upgrade=False): shutil.copyfile('/var/lib/wo/tmp/composer.phar', '/usr/local/bin/composer') WOFileUtils.chmod(self, "/usr/local/bin/composer", 0o775) - if os.path.isdir("/var/www/22222/htdocs/db/pma"): + if ((os.path.isdir("/var/www/22222/htdocs/db/pma")) and + (not os.path.isfile('/var/www/22222/htdocs/db/' + 'pma/composer.lock'))): Log.info(self, "Updating phpMyAdmin, please wait...") WOShellExec.cmd_exec( self, "/usr/local/bin/composer update " @@ -1289,11 +1295,19 @@ def post_pref(self, apt_packages, packages, upgrade=False): .format(WOVariables.wo_webroot)) os.makedirs('{0}22222/htdocs/cache/redis/phpRedisAdmin' .format(WOVariables.wo_webroot)) - WOFileUtils.chown(self, '{0}22222/htdocs' - .format(WOVariables.wo_webroot), - 'www-data', - 'www-data', - recursive=True) + if not os.path.isfile('/var/www/22222/htdocs/cache/redis/' + 'phpRedisAdmin/composer.lock'): + 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 ") + WOFileUtils.chown(self, '{0}22222/htdocs' + .format(WOVariables.wo_webroot), + 'www-data', + 'www-data', + recursive=True) # MySQLtuner if any('/usr/bin/mysqltuner' == x[1] @@ -1304,101 +1318,73 @@ def post_pref(self, apt_packages, packages, upgrade=False): # netdata install if any('/var/lib/wo/tmp/kickstart.sh' == x[1] for x in packages): - if ((not os.path.exists('/opt/netdata')) and - (not os.path.exists('/etc/netdata'))): - Log.info(self, "Installing Netdata, please wait...") - WOShellExec.cmd_exec(self, "bash /var/lib/wo/tmp/" - "kickstart.sh " - "--dont-wait") - if WOVariables.wo_distro == 'raspbian': - wo_netdata = "/" - else: - wo_netdata = "/opt/netdata/" - # disable mail notifications - WOFileUtils.searchreplace( - self, "{0}usr/" - "lib/netdata/conf.d/health_alarm_notify.conf" - .format(wo_netdata), - 'SEND_EMAIL="YES"', - 'SEND_EMAIL="NO"') - # make changes persistant - WOFileUtils.copyfile( - self, "{0}usr/lib/netdata/conf.d/" - "health_alarm_notify.conf" - .format(wo_netdata), - "{0}etc/netdata/health_alarm_notify.conf" - .format(wo_netdata)) - # check if mysql credentials are available - if os.path.isfile('/etc/mysql/conf.d/my.cnf'): - try: - WOMysql.execute( - self, - "create user 'netdata'@'localhost';", - log=False) - WOMysql.execute( - self, - "grant usage on *.* to 'netdata'@'localhost';", - log=False) - WOMysql.execute( - self, "flush privileges;", - log=False) - except CommandExecutionError as e: - Log.debug(self, "{0}".format(e)) - Log.info( - self, "fail to setup mysql user for netdata") - WOFileUtils.chown(self, '{0}etc/netdata' - .format(wo_netdata), - 'netdata', - 'netdata', - recursive=True) - WOService.restart_service(self, 'netdata') + Log.info(self, "Installing Netdata, please wait...") + WOShellExec.cmd_exec(self, "bash /var/lib/wo/tmp/" + "kickstart.sh " + "--dont-wait") + if os.path.isdir('/etc/netdata'): + wo_netdata = "/" + elif os.path.isdir('/opt/netdata'): + wo_netdata = "/opt/netdata/" + # disable mail notifications + WOFileUtils.searchreplace( + self, "{0}etc/netdata/orig/health_alarm_notify.conf" + .format(wo_netdata), + 'SEND_EMAIL="YES"', + 'SEND_EMAIL="NO"') + # make changes persistant + WOFileUtils.copyfile( + self, "{0}etc/netdata/orig/" + "health_alarm_notify.conf" + .format(wo_netdata), + "{0}etc/netdata/health_alarm_notify.conf" + .format(wo_netdata)) + # check if mysql credentials are available + if WOShellExec.cmd_exec(self, "mysqladmin ping"): + try: + WOMysql.execute( + self, + "create user 'netdata'@'localhost';", + log=False) + WOMysql.execute( + self, + "grant usage on *.* to 'netdata'@'localhost';", + log=False) + WOMysql.execute( + self, "flush privileges;", + log=False) + except CommandExecutionError as e: + Log.debug(self, "{0}".format(e)) + Log.info( + self, "fail to setup mysql user for netdata") + WOFileUtils.chown(self, '{0}etc/netdata' + .format(wo_netdata), + 'netdata', + 'netdata', + recursive=True) + WOService.restart_service(self, 'netdata') # WordOps Dashboard if any('/var/lib/wo/tmp/wo-dashboard.tar.gz' == x[1] for x in packages): - if not os.path.isfile('{0}22222/htdocs/index.php' - .format(WOVariables.wo_webroot)): - Log.debug(self, "Extracting wo-dashboard.tar.gz " - "to location {0}22222/htdocs/" - .format(WOVariables.wo_webroot)) - WOExtract.extract(self, '/var/lib/wo/tmp/' - 'wo-dashboard.tar.gz', - '{0}22222/htdocs' - .format(WOVariables.wo_webroot)) - wo_wan = os.popen("/sbin/ip -4 route get 8.8.8.8 | " - "grep -oP \"dev [^[:space:]]+ \" " - "| cut -d ' ' -f 2").read() - if (wo_wan != 'eth0' and wo_wan != ''): - WOFileUtils.searchreplace(self, - "{0}22222/htdocs/index.php" - .format(WOVariables.wo_webroot), - "eth0", - "{0}".format(wo_wan)) - Log.debug(self, "Setting Privileges to " - "{0}22222/htdocs" + Log.debug(self, "Extracting wo-dashboard.tar.gz " + "to location {0}22222/htdocs/" + .format(WOVariables.wo_webroot)) + WOExtract.extract(self, '/var/lib/wo/tmp/' + 'wo-dashboard.tar.gz', + '{0}22222/htdocs' .format(WOVariables.wo_webroot)) - WOFileUtils.chown(self, '{0}22222/htdocs' - .format(WOVariables.wo_webroot), - 'www-data', - 'www-data', - recursive=True) - - # Extplorer FileManager - if any('/var/lib/wo/tmp/extplorer.tar.gz' == x[1] - for x in packages): - if not os.path.exists('{0}22222/htdocs/files' - .format(WOVariables.wo_webroot)): - Log.debug(self, "Extracting explorer.tar.gz " - "to location {0}22222/htdocs/files" - .format(WOVariables.wo_webroot)) - WOExtract.extract(self, '/var/lib/wo/tmp/extplorer.tar.gz', - '/var/lib/wo/tmp/') - shutil.move('/var/lib/wo/tmp/extplorer-{0}' - .format(WOVariables.wo_extplorer), - '{0}22222/htdocs/files' - .format(WOVariables.wo_webroot)) + wo_wan = os.popen("/sbin/ip -4 route get 8.8.8.8 | " + "grep -oP \"dev [^[:space:]]+ \" " + "| cut -d ' ' -f 2").read() + if (wo_wan != 'eth0' and wo_wan != ''): + WOFileUtils.searchreplace(self, + "{0}22222/htdocs/index.php" + .format(WOVariables.wo_webroot), + "eth0", + "{0}".format(wo_wan)) Log.debug(self, "Setting Privileges to " - "{0}22222/htdocs/files" + "{0}22222/htdocs" .format(WOVariables.wo_webroot)) WOFileUtils.chown(self, '{0}22222/htdocs' .format(WOVariables.wo_webroot), @@ -1406,6 +1392,27 @@ def post_pref(self, apt_packages, packages, upgrade=False): 'www-data', recursive=True) + # Extplorer FileManager + if any('/var/lib/wo/tmp/extplorer.tar.gz' == x[1] + for x in packages): + Log.debug(self, "Extracting extplorer.tar.gz " + "to location {0}22222/htdocs/files" + .format(WOVariables.wo_webroot)) + WOExtract.extract(self, '/var/lib/wo/tmp/extplorer.tar.gz', + '/var/lib/wo/tmp/') + shutil.move('/var/lib/wo/tmp/extplorer-{0}' + .format(WOVariables.wo_extplorer), + '{0}22222/htdocs/files' + .format(WOVariables.wo_webroot)) + Log.debug(self, "Setting Privileges to " + "{0}22222/htdocs/files" + .format(WOVariables.wo_webroot)) + WOFileUtils.chown(self, '{0}22222/htdocs' + .format(WOVariables.wo_webroot), + 'www-data', + 'www-data', + recursive=True) + # webgrind if any('/var/lib/wo/tmp/webgrind.tar.gz' == x[1] for x in packages): diff --git a/wo/cli/plugins/stack_upgrade.py b/wo/cli/plugins/stack_upgrade.py index 3809d6f..606998f 100644 --- a/wo/cli/plugins/stack_upgrade.py +++ b/wo/cli/plugins/stack_upgrade.py @@ -145,7 +145,8 @@ class WOStackUpgradeController(CementBaseController): Log.info(self, "WPCLI is not installed with WordOps") if pargs.netdata: - if os.path.isdir('/opt/netdata'): + if (os.path.isdir('/opt/netdata') or + os.path.isdir('/etc/netdata')): packages = packages + [['https://my-netdata.io/' 'kickstart-static64.sh', '/var/lib/wo/tmp/kickstart.sh', @@ -223,9 +224,16 @@ class WOStackUpgradeController(CementBaseController): if pargs.netdata: Log.info(self, "Upgrading Netdata, please wait...") - WOShellExec.cmd_exec(self, "/bin/bash /var/lib/wo/tmp/" - "kickstart.sh " - "--dont-wait") + if os.path.isdir('/opt/netdata'): + WOShellExec.cmd_exec( + self, "bash /opt/netdata/usr/" + "libexec/netdata/netdata-" + "updater.sh") + elif os.path.isdir('/etc/netdata'): + WOShellExec.cmd_exec( + self, "bash /usr/" + "libexec/netdata/netdata-" + "updater.sh") if pargs.dashboard: Log.debug(self, "Extracting wo-dashboard.tar.gz " diff --git a/wo/cli/templates/wo-ufw.mustache b/wo/cli/templates/wo-ufw.mustache new file mode 100644 index 0000000..2ffc453 --- /dev/null +++ b/wo/cli/templates/wo-ufw.mustache @@ -0,0 +1,4 @@ +[WordOps] +title=WordOps(WO) +description=Command-line tool that ease WordPress site and server management +ports=22222/tcp \ No newline at end of file diff --git a/wo/core/apt_repo.py b/wo/core/apt_repo.py index e5610e7..44f53df 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 -yu '{ppa_name}'" + WOShellExec.cmd_exec(self, "LC_ALL=C.UTF-8 add-apt-repository -yu '{ppa_name}'" .format(ppa_name=ppa)) def remove(self, ppa=None, repo_url=None): diff --git a/wo/core/domainvalidate.py b/wo/core/domainvalidate.py index 574f6bc..5d1d65d 100644 --- a/wo/core/domainvalidate.py +++ b/wo/core/domainvalidate.py @@ -29,13 +29,14 @@ def GetDomainlevel(domain): """ This function returns the domain type : domain, subdomain, """ - domain_name = domain.split('.') + domain_name = domain.lower().split('.') if domain_name[0] == 'www': domain_name = domain_name[1:] + domain_type = '' 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") + "/var/lib/wo/public_suffix_list.dat", encoding='utf-8', ) # Read all the lines into a list. for domain_suffix in Suffix_file: if (str(domain_suffix).strip()) == ('.'.join(domain_name[1:])): diff --git a/wo/core/fileutils.py b/wo/core/fileutils.py index cc6678f..cf44ab3 100644 --- a/wo/core/fileutils.py +++ b/wo/core/fileutils.py @@ -80,7 +80,7 @@ class WOFileUtils(): except IOError as e: Log.debug(self, "{0}".format(e.strerror)) Log.error(self, "Unable to copy files from {0} to {1}" - .format(src, dest)) + .format(src, dest), exit=False) def copyfile(self, src, dest): """ @@ -99,7 +99,7 @@ class WOFileUtils(): except IOError as e: Log.debug(self, "{0}".format(e.strerror)) Log.error(self, "Unable to copy file from {0} to {1}" - .format(src, dest)) + .format(src, dest), exit=False) def searchreplace(self, fnm, sstr, rstr): """ @@ -109,7 +109,7 @@ class WOFileUtils(): rstr: replace string """ try: - Log.debug(self, "Doning search and replace, File:{0}," + Log.debug(self, "Doing search and replace, File:{0}," "Source string:{1}, Dest String:{2}" .format(fnm, sstr, rstr)) for line in fileinput.input(fnm, inplace=True): @@ -118,7 +118,7 @@ class WOFileUtils(): except Exception as e: Log.debug(self, "{0}".format(e)) Log.error(self, "Unable to search {0} and replace {1} {2}" - .format(fnm, sstr, rstr)) + .format(fnm, sstr, rstr), exit=False) def mvfile(self, src, dst): """ diff --git a/wo/core/variables.py b/wo/core/variables.py index 11547bb..a06fb2e 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.7" + wo_version = "3.9.8.8" # WordOps packages versions wo_wp_cli = "2.2.0" wo_adminer = "4.7.2"