diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..53ae6b1 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,25 @@ +name: CI + +on: [push] + +jobs: + build: + + runs-on: ubuntu-18.04 + + steps: + - uses: actions/checkout@v1 + - name: Prepare VM + run: | + unset LANG + sudo apt update -qq + sudo LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php -y + sudo apt-get -qq purge graphviz* redis* + sudo apt-get install -qq git python3-setuptools python3-dev python3-apt ccze tree + sudo apt-get -qq autoremove --purge + sudo mkdir -p /etc/mysql/conf.d + echo -e '[client]\nuser = root\npassword = root\n' | sudo tee /etc/mysql/conf.d/my.cnf + - name: Install WordOps + run: sudo timeout 1800 bash install --travis + - name: Run tests + run: sudo timeout 1800 bash tests/travis.sh --actions diff --git a/.travis.yml b/.travis.yml index 3694e4d..64c9c5f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,8 +28,7 @@ before_script: after_script: - - sudo cat /etc/nginx/nginx.conf | ccze -A - - sudo cat /etc/mysql/my.cnf | ccze -A + - sudo cat /var/log/wo/test.log | ccze -A -p syslog - sudo bash install --purge - sudo curl --progress-bar --upload-file /var/log/wo/wordops.log https://transfer.vtbox.net/"$(basename wordops.log)" && echo "" | sudo tee -a $HOME/.transfer.log && echo "" @@ -40,5 +39,4 @@ script: - sudo echo "Travis Banch = $TRAVIS_BRANCH" - sudo time bash install --travis -b "$TRAVIS_BRANCH" - sudo time bash tests/travis.sh - - sudo wo update --travis - - sudo wo stack status + - sudo wo update --travis \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 4491648..852f9c7 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.9.2 - 2019-10-04 + +#### Added + +- [STACK] Nginx server_names_hash_bucket_size automated fix +- [STACK] Nginx configuration rollback in case of failure after `wo stack upgrade --nginx` +- [STACK] Nginx ultimate bad bots blocker with `wo stack install --ngxblocker` +- [STACK] Added support for custom Nginx compiled from source +- [STACK] Rollback configuration with Git in case of failure during service reload/restart +- [SITE] Enable or disable Nginx ultimate bad bots blocker with `wo site update site.tld --ngxblocker/--ngxblocker=off` + +#### Changed + +- [CORE] Query acme.sh database directly to check if a certificate exist +- [SITE] `--letsencrypt=renew` is deprecated because not it's not required with acme.sh + +#### Fixed + +- [SITE] Issues with root_domain variable with `wo site update` +- [SECURE] Wrong sftp-server path in sshd_config +- [SITE] Git error when using flag `--vhostonly` +- [SITE] Wrong plugin name displayed when installing Cache-Enabler + ### v3.9.9.1 - 2019-09-26 #### Added diff --git a/config/bash_completion.d/wo_auto.rc b/config/bash_completion.d/wo_auto.rc index 53d6856..d5dacc0 100644 --- a/config/bash_completion.d/wo_auto.rc +++ b/config/bash_completion.d/wo_auto.rc @@ -74,7 +74,7 @@ _wo_complete() # HANDLE EVERYTHING AFTER THE THIRD LEVEL NAMESPACE "install" | "purge" | "remove" ) COMPREPLY=( $(compgen \ - -W "--web --admin --security --nginx --php --php73 --mysql --wpcli --phpmyadmin --adminer --utils --redis --phpredisadmin --composer --netdata --fail2ban --ufw --dashboard --proftpd --clamav --mysqlclient --mysqltuner --extplorer --all --force" \ + -W "--web --admin --security --nginx --php --php73 --mysql --wpcli --phpmyadmin --adminer --utils --redis --phpredisadmin --composer --netdata --fail2ban --ufw --dashboard --proftpd --clamav --ngxblocker --mysqlclient --mysqltuner --extplorer --all --force" \ -- $cur) ) ;; "upgrade" ) @@ -154,13 +154,13 @@ _wo_complete() "create") COMPREPLY=( $(compgen \ - -W "--user --pass --email --html --php --php73 --mysql --wp --wpsubdir --wpsubdomain --wpfc --wpsc --proxy= --wpredis --wprocket --wpce -le --letsencrypt --letsencrypt=wildcard -le=wildcard --dns --dns=dns_cf --dns=dns_do" \ + -W "--user --pass --email --html --php --php73 --mysql --wp --wpsubdir --wpsubdomain --wpfc --wpsc --proxy= --wpredis --wprocket --wpce -le --letsencrypt --letsencrypt=wildcard -le=wildcard --dns --dns=dns_cf --dns=dns_dgon" \ -- $cur) ) ;; "update") COMPREPLY=( $(compgen \ - -W "--password --php --php73 --mysql --wp --wpsubdir --wpsubdomain --wpfc --wpsc --wpredis --wprocket --wpce -le -le=off --letsencrypt --letsencrypt=off --letsencrypt=clean -le=wildcard -le=clean --dns --dns=dns_cf --dns=dns_do" \ + -W "--password --php --php73 --mysql --wp --wpsubdir --wpsubdomain --wpfc --wpsc --wpredis --wprocket --wpce -le -le=off --letsencrypt --letsencrypt=off --letsencrypt=clean -le=wildcard -le=clean --dns --dns=dns_cf --dns=dns_dgon --ngxblocker --ngxblocker=off" \ -- $cur) ) ;; "delete") @@ -206,9 +206,9 @@ _wo_complete() "--wp") if [ "${COMP_WORDS[1]}" != "debug" ]; then if [ "${COMP_WORDS[2]}" == "create" ]; then - retlist="--wp --wpsc --wpfc --user --email --pass --wpredis --wprocket --wpce --letsencrypt -le --letsencrypt=wildcard --dns --dns=dns_cf --dns=dns_do --php73" + retlist="--wp --wpsc --wpfc --user --email --pass --wpredis --wprocket --wpce --letsencrypt -le --letsencrypt=wildcard --dns --dns=dns_cf --dns=dns_dgon --php73" elif [ "${COMP_WORDS[2]}" == "update" ]; then - retlist="--wp --wpfc --wpsc --php73 --php73=off --wpredis --wprocket --wpce -le --letsencrypt --letsencrypt=wildcard -le=wildcard --dns --dns=dns_cf --dns=dns_do" + retlist="--wp --wpfc --wpsc --php73 --php73=off --wpredis --wprocket --wpce -le --letsencrypt --letsencrypt=wildcard -le=wildcard --dns --dns=dns_cf --dns=dns_dgon" else retlist="" fi @@ -225,9 +225,9 @@ _wo_complete() "--wpsubdir" | "--wpsubdomain") if [ "${COMP_WORDS[1]}" != "debug" ]; then if [ "${COMP_WORDS[2]}" == "create" ]; then - retlist="--wpsc --wpfc --user --email --pass --wpredis --wprocket --wpce -le -le=wildcard --letsencrypt --letsencrypt=wildcard --php73 --dns --dns=dns_cf --dns=dns_do" + retlist="--wpsc --wpfc --user --email --pass --wpredis --wprocket --wpce -le -le=wildcard --letsencrypt --letsencrypt=wildcard --php73 --dns --dns=dns_cf --dns=dns_dgon" elif [ "${COMP_WORDS[2]}" == "update" ]; then - retlist="--wpfc --wpsc --php73 --php73=off --wpredis --wprocket --wpce -le -le=wildcard --letsencrypt --letsencrypt=wildcard --dns --dns=dns_cf --dns=dns_do" + retlist="--wpfc --wpsc --php73 --php73=off --wpredis --wprocket --wpce -le -le=wildcard --letsencrypt --letsencrypt=wildcard --dns --dns=dns_cf --dns=dns_dgon" else retlist="" fi @@ -243,7 +243,7 @@ _wo_complete() "--wpredis" | "--wprocket" | "--wpce" | "--wpfc" | "--wpsc" | "--wpsubdir" | "--wpsubdomain" | "--user" | "--pass" | "--email" | "--wp") if [ "${COMP_WORDS[2]}" == "create" ]; then - retlist="--user --pass --email --wp --wpsubdir --wpsubdomain --wpfc --wpsc --wpredis --wprocket --wpce --php73 -le -le=wildcard --letsencrypt --letsencrypt=wildcard --dns --dns=dns_cf --dns=dns_do" + retlist="--user --pass --email --wp --wpsubdir --wpsubdomain --wpfc --wpsc --wpredis --wprocket --wpce --php73 -le -le=wildcard --letsencrypt --letsencrypt=wildcard --dns --dns=dns_cf --dns=dns_dgon" else retlist="" fi @@ -256,7 +256,7 @@ _wo_complete() "--wpredis" | "--wprocket" | "--wpce" | "--wpfc") if [ "${COMP_WORDS[2]}" == "update" ]; then - retlist="--password --php --php73 --mysql --wp --wpsubdir --wpsubdomain -le --letsencrypt --dns --dns=dns_cf --dns=dns_do" + retlist="--password --php --php73 --mysql --wp --wpsubdir --wpsubdomain -le --letsencrypt --dns --dns=dns_cf --dns=dns_dgon" else retlist="" fi @@ -358,7 +358,7 @@ _wo_complete() case "$mprev" in "--user" | "--email" | "--pass") if [ "${COMP_WORDS[2]}" == "create" ]; then - retlist="--user --pass --email --html --php --php73 --mysql --wp --wpsubdir --wpsubdomain --wpfc --wpsc --wpredis --wprocket --wpce -le -le=wildcard --letsencrypt --letsencrypt=wildcard --dns --dns=dns_cf --dns=dns_do" + retlist="--user --pass --email --html --php --php73 --mysql --wp --wpsubdir --wpsubdomain --wpfc --wpsc --wpredis --wprocket --wpce -le -le=wildcard --letsencrypt --letsencrypt=wildcard --dns --dns=dns_cf --dns=dns_dgon" fi ret="${retlist[@]/$prev}" COMPREPLY=( $(compgen \ diff --git a/install b/install index a380e30..4378362 100755 --- a/install +++ b/install @@ -9,7 +9,7 @@ # ------------------------------------------------------------------------- # wget -qO wo wops.cc && sudo bash wo # ------------------------------------------------------------------------- -# Version 3.9.8.12 - 2019-09-20 +# Version 3.9.9.1 - 2019-09-27 # ------------------------------------------------------------------------- # CONTENTS @@ -70,6 +70,7 @@ while [ "$#" -gt 0 ]; do ;; --travis) wo_travis="y" + wo_force_install="y" ;; -s | --silent) wo_force_install="y" @@ -77,9 +78,6 @@ while [ "$#" -gt 0 ]; do --purge | --uninstall) wo_purge="y" ;; - -w | --wufw | --without-ufw) - ufw="n" - ;; -v | --version) wo_version="$2" shift @@ -234,7 +232,7 @@ wo_install_dep() { if [ "$wo_linux_distro" == "Ubuntu" ]; then # install dependencies apt-get -option=Dpkg::options::=--force-confmiss --option=Dpkg::options::=--force-confold --assume-yes install \ - build-essential curl gzip python3 python3-apt python3-setuptools python3-requests python3-dev sqlite3 git tar software-properties-common pigz \ + build-essential curl gzip python3 python3-apt python3-setuptools python3-dev sqlite3 git tar software-properties-common pigz \ gnupg2 cron ccze rsync tree haveged ufw unattended-upgrades tzdata ntp > /dev/null 2>&1 add-apt-repository ppa:wordops/nginx-wo -yn else @@ -455,6 +453,7 @@ wo_install_acme_sh() { chown -R www-data:www-data /var/www/html /var/www/html/.well-known chmod 750 /var/www/html /var/www/html/.well-known else + chown -R www-data:www-data /var/www/html /var/www/html/.well-known chmod 750 /var/www/html /var/www/html/.well-known fi } @@ -495,6 +494,10 @@ wo_install() { # Clone Github repository if it doesn't exist wo_install_travis() { + if [ "$wo_force_install" = "y" ]; then + [ ! -f "$HOME/.gitconfig" ] && { bash -c 'echo -e "[user]\n\tname = $USER\n\temail = root@$HOSTNAME.local" > $HOME/.gitconfig'; } + fi + if [ -f "$HOME/.gitconfig" ]; then # install and redirect log to not print python package install python3 setup.py install diff --git a/requirements-dev-py3.txt b/requirements-dev-py3.txt deleted file mode 100644 index 38fec85..0000000 --- a/requirements-dev-py3.txt +++ /dev/null @@ -1,21 +0,0 @@ -# The following are only required in development, not production -nose -coverage -sphinx -pep8 -autopep8 -mock -pyinotify - -# Required for optional extensions (only the ones supported on py3) -argcomplete -pystache -pyYaml -colorlog -configobj -tabulate -pylibmc -redis -jinja2 -watchdog -pybars3 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 2df9c0a..c396386 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,10 @@ -cement>=2.8.2 +cement==2.8.2 +pystache>=0.5.4 +pynginxconfig>=0.3.4 +PyMySQL>=0.9.3 +psutil>=5.6.3 +sh>=1.12.14 +SQLAlchemy>=1.3.8 +requests>=2.22.0 +distro>=1.4.0 +apt-mirror-updater>=6.1 \ No newline at end of file diff --git a/setup.py b/setup.py index 0bf7c71..be28dd0 100644 --- a/setup.py +++ b/setup.py @@ -4,13 +4,14 @@ import os from setuptools import find_packages, setup +with open("README.md", "r") as fh: + long_description = fh.read() + conf = [] templates = [] -long_description = '''WordOps An essential toolset that eases WordPress - site and server administration. It provide the ability - to install a high performance WordPress stack - with a few keystrokes''' +short_description = """An essential toolset that eases WordPress + site and server administration""" for name in glob.glob('config/plugins.d/*.conf'): conf.insert(1, name) @@ -21,43 +22,52 @@ for name in glob.glob('wo/cli/templates/*.mustache'): if not os.path.exists('/var/log/wo/'): os.makedirs('/var/log/wo/') -if not os.path.exists('/var/lib/wo/'): - os.makedirs('/var/lib/wo/') +if not os.path.exists('/var/lib/wo/tmp/'): + os.makedirs('/var/lib/wo/tmp/') -setup(name='wo', - version='3.9.9.1', - description=long_description, +setup(name='wordops', + version='3.9.9.2', + description=short_description, long_description=long_description, - classifiers=[], + long_description_content_type="text/markdown", + classifiers=[ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "Natural Language :: English", + "Topic :: System :: Systems Administration", + ], keywords='', author='WordOps', author_email='contact@wordops.io', - url='https://wordops.net', + url='https://github.com/WordOps/WordOps', license='MIT', packages=find_packages(exclude=['ez_setup', 'examples', 'tests', 'templates']), include_package_data=True, zip_safe=False, test_suite='nose.collector', + python_requires='>=3.5', install_requires=[ # Required to build documentation # "Sphinx >= 1.0", - # Required for testing - # "nose", - # "coverage", # Required to function 'cement == 2.8.2', - 'pystache', - 'python-apt', - 'pynginxconfig', - 'PyMySQL', - 'psutil', - 'sh', - 'SQLAlchemy', - 'requests', - 'distro', - 'apt-mirror-updater', + 'pystache >= 0.5.4', + 'pynginxconfig >= 0.3.4', + 'PyMySQL >= 0.9.3', + 'psutil >= 5.6.3', + 'sh >= 1.12.14', + 'SQLAlchemy >= 1.3.8', + 'requests >= 2.22.0', + 'distro >= 1.4.0', + 'apt-mirror-updater >= 6.1', ], + extras_require={ # Optional + 'testing': ['nose', 'coverage'], + }, data_files=[('/etc/wo', ['config/wo.conf']), ('/etc/wo/plugins.d', conf), ('/usr/lib/wo/templates', templates), diff --git a/snapcraft.yaml b/snapcraft.yaml new file mode 100644 index 0000000..eb46364 --- /dev/null +++ b/snapcraft.yaml @@ -0,0 +1,23 @@ +name: test-wordops +version: git +summary: WordOps +description: | + WordOps is an essential toolset that eases WordPress + site and server administration. It provide the ability + to install a high performance WordPress stack + with a few keystrokes. +confinement: devmode +base: core18 + +parts: + test-wordops: + plugin: python + python-version: python3 + source: . + stage-packages: + - cement + - python-apt + +apps: + test-wordops: + command: wo diff --git a/tests/travis.sh b/tests/travis.sh index 882ebe9..be1e8a3 100644 --- a/tests/travis.sh +++ b/tests/travis.sh @@ -9,9 +9,16 @@ CRED="${CSI}1;31m" CGREEN="${CSI}1;32m" CEND="${CSI}0m" -apt-get -qq purge mysql* graphviz* redis* -apt-get install -qq git python3-setuptools python3-dev python3-apt ccze tree -sudo apt-get -qq autoremove --purge +export DEBIAN_FRONTEND=noninteractive +unset LANG +export LANG='en_US.UTF-8' +export LC_ALL='C.UTF-8' + +if [ -z "$1" ]; then + apt-get -qq purge mysql* graphviz* redis* + apt-get install -qq git python3-setuptools python3-dev python3-apt ccze tree + sudo apt-get -qq autoremove --purge +fi exit_script() { curl --progress-bar --upload-file /var/log/wo/wordops.log https://transfer.vtbox.net/"$(basename wordops.log)" && echo "" @@ -21,7 +28,7 @@ exit_script() { echo -e "${CGREEN}#############################################${CEND}" echo -e ' stack install ' echo -e "${CGREEN}#############################################${CEND}" -stack_list='nginx php php73 mysql redis fail2ban clamav proftpd netdata phpmyadmin composer dashboard extplorer adminer redis phpredisadmin mysqltuner utils ufw' +stack_list='nginx php php73 mysql redis fail2ban clamav proftpd netdata phpmyadmin composer dashboard extplorer adminer redis phpredisadmin mysqltuner utils ufw ngxblocker' for stack in $stack_list; do echo -ne " Installing $stack [..]\r" if { @@ -134,26 +141,26 @@ for site in $wp_site_types; do fi done +if [ -z "$1" ]; then + echo -e "${CGREEN}#############################################${CEND}" + echo -e ' wo stack upgrade ' + echo -e "${CGREEN}#############################################${CEND}" + stack_upgrade='nginx php mysql redis netdata dashboard phpmyadmin' + for stack in $stack_upgrade; do + echo -ne " Upgrading $stack [..]\r" + if { + wo stack upgrade --${stack} --force + } >> /var/log/wo/test.log; then + echo -ne " Upgrading $stack [${CGREEN}OK${CEND}]\\r" + echo -ne '\n' + else + echo -e " Upgrading $stack [${CRED}FAIL${CEND}]" + echo -ne '\n' + exit_script -echo -e "${CGREEN}#############################################${CEND}" -echo -e ' wo stack upgrade ' -echo -e "${CGREEN}#############################################${CEND}" -stack_upgrade='nginx php mysql redis netdata dashboard phpmyadmin' -for stack in $stack_upgrade; do - echo -ne " Upgrading $stack [..]\r" - if { - wo stack upgrade --${stack} --force - } >> /var/log/wo/test.log; then - echo -ne " Upgrading $stack [${CGREEN}OK${CEND}]\\r" - echo -ne '\n' - else - echo -e " Upgrading $stack [${CRED}FAIL${CEND}]" - echo -ne '\n' - exit_script - - fi -done - + fi + done +fi echo -e "${CGREEN}#############################################${CEND}" echo -e ' wo clean ' echo -e "${CGREEN}#############################################${CEND}" @@ -197,3 +204,6 @@ for stack in $stack_purge; do fi done +if [ -n "$1" ]; then + cat /var/log/wo/test.log | ccze -A -p syslog +fi diff --git a/wo/cli/controllers/base.py b/wo/cli/controllers/base.py index 62c9587..9558442 100644 --- a/wo/cli/controllers/base.py +++ b/wo/cli/controllers/base.py @@ -2,9 +2,9 @@ from cement.core.controller import CementBaseController, expose -from wo.core.variables import WOVariables +from wo.core.variables import WOVar -VERSION = WOVariables.wo_version +VERSION = WOVar.wo_version BANNER = """ WordOps v%s diff --git a/wo/cli/main.py b/wo/cli/main.py index 00ddd6a..dad8f1c 100644 --- a/wo/cli/main.py +++ b/wo/cli/main.py @@ -106,14 +106,14 @@ def main(): # Catch our application errors and exit 1 (error) code = 1 print(e) - except FrameworkError as e: - # Catch framework errors and exit 1 (error) - code = 1 - print(e) except CaughtSignal as e: # Default Cement signals are SIGINT and SIGTERM, exit 0 (non-error) code = 0 print(e) + except FrameworkError as e: + # Catch framework errors and exit 1 (error) + code = 1 + print(e) except Exception as e: code = 1 print(e) diff --git a/wo/cli/plugins/debug.py b/wo/cli/plugins/debug.py index 51744ee..c54dccb 100644 --- a/wo/cli/plugins/debug.py +++ b/wo/cli/plugins/debug.py @@ -16,7 +16,7 @@ from wo.core.logging import Log from wo.core.mysql import WOMysql from wo.core.services import WOService from wo.core.shellexec import WOShellExec -from wo.core.variables import WOVariables +from wo.core.variables import WOVar def wo_debug_hook(app): @@ -146,7 +146,7 @@ class WODebugController(CementBaseController): Log.info(self, "Nginx debug for site already enabled") self.msg = self.msg + ['{0}{1}/logs/error.log' - .format(WOVariables.wo_webroot, + .format(WOVar.wo_webroot, self.app.pargs.site_name)] else: @@ -446,14 +446,14 @@ class WODebugController(CementBaseController): """Start/Stop WordPress debug""" if (self.app.pargs.wp == 'on' and self.app.pargs.site_name): wp_config = ("{0}/{1}/wp-config.php" - .format(WOVariables.wo_webroot, + .format(WOVar.wo_webroot, self.app.pargs.site_name)) - webroot = "{0}{1}".format(WOVariables.wo_webroot, + webroot = "{0}{1}".format(WOVar.wo_webroot, self.app.pargs.site_name) # Check wp-config.php file into htdocs folder if not os.path.isfile(wp_config): wp_config = ("{0}/{1}/htdocs/wp-config.php" - .format(WOVariables.wo_webroot, + .format(WOVar.wo_webroot, self.app.pargs.site_name)) if os.path.isfile(wp_config): if not WOShellExec.cmd_exec(self, "grep \"\'WP_DEBUG\'\" {0} |" @@ -464,7 +464,7 @@ class WODebugController(CementBaseController): WOShellExec.cmd_exec(self, "chown {1}: {0}/htdocs/wp-" "content/debug.log" "".format(webroot, - WOVariables.wo_php_user)) + WOVar.wo_php_user)) WOShellExec.cmd_exec(self, "sed -i \"s/define(\'WP_DEBUG\'" ".*/define(\'WP_DEBUG\', true);\\n" "define(\'WP_DEBUG_DISPLAY\', false);" @@ -478,11 +478,11 @@ class WODebugController(CementBaseController): WOShellExec.cmd_exec(self, "chown -R {1}: {0}/htdocs/" "wp-content/plugins" .format(webroot, - WOVariables.wo_php_user)) + WOVar.wo_php_user)) self.msg = self.msg + ['{0}{1}/htdocs/wp-content' '/debug.log' - .format(WOVariables.wo_webroot, + .format(WOVar.wo_webroot, self.app.pargs.site_name)] else: @@ -491,14 +491,14 @@ class WODebugController(CementBaseController): elif (self.app.pargs.wp == 'off' and self.app.pargs.site_name): wp_config = ("{0}{1}/wp-config.php" - .format(WOVariables.wo_webroot, + .format(WOVar.wo_webroot, self.app.pargs.site_name)) - webroot = "{0}{1}".format(WOVariables.wo_webroot, + webroot = "{0}{1}".format(WOVar.wo_webroot, self.app.pargs.site_name) # Check wp-config.php file into htdocs folder if not os.path.isfile(wp_config): wp_config = ("{0}/{1}/htdocs/wp-config.php" - .format(WOVariables.wo_webroot, + .format(WOVar.wo_webroot, self.app.pargs.site_name)) if os.path.isfile(wp_config): if WOShellExec.cmd_exec(self, "grep \"\'WP_DEBUG\'\" {0} | " @@ -565,11 +565,11 @@ class WODebugController(CementBaseController): Log.info(self, "Nginx rewrite logs for {0} already setup" .format(self.app.pargs.site_name)) - if ('{0}{1}/logs/error.log'.format(WOVariables.wo_webroot, + if ('{0}{1}/logs/error.log'.format(WOVar.wo_webroot, self.app.pargs.site_name) not in self.msg): self.msg = self.msg + ['{0}{1}/logs/error.log' - .format(WOVariables.wo_webroot, + .format(WOVar.wo_webroot, self.app.pargs.site_name)] # Stop Nginx rewrite for site @@ -608,7 +608,7 @@ class WODebugController(CementBaseController): self.debug_fpm73() if self.app.pargs.mysql: # MySQL debug will not work for remote MySQL - if WOVariables.wo_mysql_host is "localhost": + if WOVar.wo_mysql_host is "localhost": self.app.pargs.mysql = 'off' self.debug_mysql() else: @@ -756,7 +756,7 @@ class WODebugController(CementBaseController): self.debug_fpm73() if self.app.pargs.mysql: # MySQL debug will not work for remote MySQL - if WOVariables.wo_mysql_host == "localhost": + if WOVar.wo_mysql_host == "localhost": self.debug_mysql() else: Log.warn(self, "Remote MySQL found, WordOps does not support " @@ -796,22 +796,22 @@ class WODebugController(CementBaseController): def import_slow_log(self): """Default function for import slow log""" if os.path.isdir("{0}22222/htdocs/db/anemometer" - .format(WOVariables.wo_webroot)): + .format(WOVar.wo_webroot)): if os.path.isfile("/var/log/mysql/mysql-slow.log"): # Get Anemometer user name and password Log.info(self, "Importing MySQL slow log to Anemometer") host = os.popen("grep -e \"\'host\'\" {0}22222/htdocs/" - .format(WOVariables.wo_webroot) + + .format(WOVar.wo_webroot) + "db/anemometer/conf/config.inc.php " "| head -1 | cut -d\\\' -f4 | " "tr -d '\n'").read() user = os.popen("grep -e \"\'user\'\" {0}22222/htdocs/" - .format(WOVariables.wo_webroot) + + .format(WOVar.wo_webroot) + "db/anemometer/conf/config.inc.php " "| head -1 | cut -d\\\' -f4 | " "tr -d '\n'").read() password = os.popen("grep -e \"\'password\'\" {0}22222/" - .format(WOVariables.wo_webroot) + + .format(WOVar.wo_webroot) + "htdocs/db/anemometer/conf" "/config.inc.php " "| head -1 | cut -d\\\' -f4 | " diff --git a/wo/cli/plugins/log.py b/wo/cli/plugins/log.py index 8c6ee23..838f5cb 100644 --- a/wo/cli/plugins/log.py +++ b/wo/cli/plugins/log.py @@ -13,7 +13,7 @@ from wo.core.logging import Log from wo.core.mysql import WOMysql from wo.core.sendmail import WOSendMail from wo.core.shellexec import WOShellExec -from wo.core.variables import WOVariables +from wo.core.variables import WOVar def wo_log_hook(app): @@ -99,7 +99,7 @@ class WOLogShowController(CementBaseController): '/var/log/php5/fpm.log'] if self.app.pargs.mysql: # MySQL debug will not work for remote MySQL - if WOVariables.wo_mysql_host == "localhost": + if WOVar.wo_mysql_host == "localhost": if os.path.isfile('/var/log/mysql/mysql-slow.log'): self.msg = self.msg + ['/var/log/mysql/mysql-slow.log'] else: @@ -109,18 +109,18 @@ class WOLogShowController(CementBaseController): "remote MySQL servers or log files") if self.app.pargs.site_name: - webroot = "{0}{1}".format(WOVariables.wo_webroot, + webroot = "{0}{1}".format(WOVar.wo_webroot, self.app.pargs.site_name) if not os.path.isdir(webroot): Log.error(self, "Site not present, quitting") if self.app.pargs.access: self.msg = self.msg + ["{0}/{1}/logs/access.log" - .format(WOVariables.wo_webroot, + .format(WOVar.wo_webroot, self.app.pargs.site_name)] if self.app.pargs.nginx: self.msg = self.msg + ["{0}/{1}/logs/error.log" - .format(WOVariables.wo_webroot, + .format(WOVar.wo_webroot, self.app.pargs.site_name)] if self.app.pargs.wp: if os.path.isdir('{0}/htdocs/wp-content'.format(webroot)): @@ -134,7 +134,7 @@ class WOLogShowController(CementBaseController): WOShellExec.cmd_exec(self, "chown {1}: {0}/htdocs/" "wp-content/debug.log" "".format(webroot, - WOVariables + WOVar .wo_php_user) ) # create symbolic link for debug log @@ -145,7 +145,7 @@ class WOLogShowController(CementBaseController): .format(webroot)]) self.msg = self.msg + ["{0}/{1}/logs/debug.log" - .format(WOVariables.wo_webroot, + .format(WOVar.wo_webroot, self.app.pargs.site_name)] else: Log.info(self, "Site is not WordPress site, skipping " @@ -238,7 +238,7 @@ class WOLogResetController(CementBaseController): '/var/log/php5/fpm.log'] if self.app.pargs.mysql: # MySQL debug will not work for remote MySQL - if WOVariables.wo_mysql_host == "localhost": + if WOVar.wo_mysql_host == "localhost": if os.path.isfile('/var/log/mysql/mysql-slow.log'): self.msg = self.msg + ['/var/log/mysql/mysql-slow.log'] else: @@ -248,18 +248,18 @@ class WOLogResetController(CementBaseController): "remote MySQL servers or log files") if self.app.pargs.site_name: - webroot = "{0}{1}".format(WOVariables.wo_webroot, + webroot = "{0}{1}".format(WOVar.wo_webroot, self.app.pargs.site_name) if not os.path.isdir(webroot): Log.error(self, "Site not present, quitting") if self.app.pargs.access: self.msg = self.msg + ["{0}/{1}/logs/access.log" - .format(WOVariables.wo_webroot, + .format(WOVar.wo_webroot, self.app.pargs.site_name)] if self.app.pargs.nginx: self.msg = self.msg + ["{0}/{1}/logs/error.log" - .format(WOVariables.wo_webroot, + .format(WOVar.wo_webroot, self.app.pargs.site_name)] if self.app.pargs.wp: if os.path.isdir('{0}/htdocs/wp-content'.format(webroot)): @@ -273,7 +273,7 @@ class WOLogResetController(CementBaseController): WOShellExec.cmd_exec(self, "chown {1}: {0}/htdocs/" "wp-content/debug.log" "".format(webroot, - WOVariables + WOVar .wo_php_user) ) # create symbolic link for debug log @@ -284,7 +284,7 @@ class WOLogResetController(CementBaseController): .format(webroot)]) self.msg = self.msg + ["{0}/{1}/logs/debug.log" - .format(WOVariables.wo_webroot, + .format(WOVar.wo_webroot, self.app.pargs.site_name)] else: Log.info(self, "Site is not WordPress site, skipping " @@ -366,7 +366,7 @@ class WOLogGzipController(CementBaseController): '/var/log/php5/fpm.log'] if self.app.pargs.mysql: # MySQL debug will not work for remote MySQL - if WOVariables.wo_mysql_host == "localhost": + if WOVar.wo_mysql_host == "localhost": if os.path.isfile('/var/log/mysql/mysql-slow.log'): self.msg = self.msg + ['/var/log/mysql/mysql-slow.log'] else: @@ -377,18 +377,18 @@ class WOLogGzipController(CementBaseController): "remote MySQL servers or log files") if self.app.pargs.site_name: - webroot = "{0}{1}".format(WOVariables.wo_webroot, + webroot = "{0}{1}".format(WOVar.wo_webroot, self.app.pargs.site_name) if not os.path.isdir(webroot): Log.error(self, "Site not present, quitting") if self.app.pargs.access: self.msg = self.msg + ["{0}/{1}/logs/access.log" - .format(WOVariables.wo_webroot, + .format(WOVar.wo_webroot, self.app.pargs.site_name)] if self.app.pargs.nginx: self.msg = self.msg + ["{0}/{1}/logs/error.log" - .format(WOVariables.wo_webroot, + .format(WOVar.wo_webroot, self.app.pargs.site_name)] if self.app.pargs.wp: if os.path.isdir('{0}/htdocs/wp-content'.format(webroot)): @@ -402,7 +402,7 @@ class WOLogGzipController(CementBaseController): WOShellExec.cmd_exec(self, "chown {1}: {0}/htdocs/" "wp-content/debug.log" "".format(webroot, - WOVariables + WOVar .wo_php_user) ) # create symbolic link for debug log @@ -413,7 +413,7 @@ class WOLogGzipController(CementBaseController): .format(webroot)]) self.msg = self.msg + ["{0}/{1}/logs/debug.log" - .format(WOVariables.wo_webroot, + .format(WOVar.wo_webroot, self.app.pargs.site_name)] else: Log.info(self, "Site is not WordPress site, skipping " @@ -504,7 +504,7 @@ class WOLogMailController(CementBaseController): '/var/log/php5/fpm.log'] if self.app.pargs.mysql: # MySQL debug will not work for remote MySQL - if WOVariables.wo_mysql_host == "localhost": + if WOVar.wo_mysql_host == "localhost": if os.path.isfile('/var/log/mysql/mysql-slow.log'): self.msg = self.msg + ['/var/log/mysql/mysql-slow.log'] else: @@ -514,18 +514,18 @@ class WOLogMailController(CementBaseController): "remote MySQL servers or log files") if self.app.pargs.site_name: - webroot = "{0}{1}".format(WOVariables.wo_webroot, + webroot = "{0}{1}".format(WOVar.wo_webroot, self.app.pargs.site_name) if not os.path.isdir(webroot): Log.error(self, "Site not present, quitting") if self.app.pargs.access: self.msg = self.msg + ["{0}/{1}/logs/access.log" - .format(WOVariables.wo_webroot, + .format(WOVar.wo_webroot, self.app.pargs.site_name)] if self.app.pargs.nginx: self.msg = self.msg + ["{0}/{1}/logs/error.log" - .format(WOVariables.wo_webroot, + .format(WOVar.wo_webroot, self.app.pargs.site_name)] if self.app.pargs.wp: if os.path.isdir('{0}/htdocs/wp-content'.format(webroot)): @@ -539,7 +539,7 @@ class WOLogMailController(CementBaseController): WOShellExec.cmd_exec(self, "chown {1}: {0}/htdocs/" "wp-content/debug.log" "".format(webroot, - WOVariables + WOVar .wo_php_user) ) # create symbolic link for debug log @@ -550,7 +550,7 @@ class WOLogMailController(CementBaseController): .format(webroot)]) self.msg = self.msg + ["{0}/{1}/logs/debug.log" - .format(WOVariables.wo_webroot, + .format(WOVar.wo_webroot, self.app.pargs.site_name)] else: Log.info(self, "Site is not WordPress site, skipping " @@ -563,7 +563,7 @@ class WOLogMailController(CementBaseController): for tomail in self.app.pargs.to: Log.info(self, "Sending mail to {0}".format(tomail[0])) WOSendMail("wordops", tomail[0], "{0} Log Files" - .format(WOVariables.wo_fqdn), + .format(WOVar.wo_fqdn), "Hi,\n The requested logfiles are attached." "\n\nBest regards,\nYour WordOps worker", files=mail_list, port=25, isTls=False) diff --git a/wo/cli/plugins/secure.py b/wo/cli/plugins/secure.py index 0c8a968..889f765 100644 --- a/wo/cli/plugins/secure.py +++ b/wo/cli/plugins/secure.py @@ -11,7 +11,7 @@ from wo.core.random import RANDOM from wo.core.services import WOService from wo.core.shellexec import WOShellExec from wo.core.template import WOTemplate -from wo.core.variables import WOVariables +from wo.core.variables import WOVar def wo_secure_hook(app): @@ -70,13 +70,13 @@ class WOSecureController(CementBaseController): WOGit.add(self, ["/etc/nginx"], msg="Add Nginx to into Git") pargs = self.app.pargs - passwd = RANDOM.long(self) + passwd = RANDOM.gen(self, length='24') if not pargs.user_input: username = input("Provide HTTP authentication user " - "name [{0}] :".format(WOVariables.wo_user)) + "name [{0}] :".format(WOVar.wo_user)) pargs.user_input = username if username == "": - pargs.user_input = WOVariables.wo_user + pargs.user_input = WOVar.wo_user if not pargs.user_pass: password = getpass.getpass("Provide HTTP authentication " "password [{0}] :".format(passwd)) diff --git a/wo/cli/plugins/site.py b/wo/cli/plugins/site.py index 5c1fe78..f61b928 100644 --- a/wo/cli/plugins/site.py +++ b/wo/cli/plugins/site.py @@ -5,7 +5,6 @@ import subprocess from cement.core import handler, hook from cement.core.controller import CementBaseController, expose - from wo.cli.plugins.site_functions import * from wo.cli.plugins.sitedb import (addNewSite, deleteSiteInfo, getAllsites, getSiteInfo, updateSiteInfo) @@ -18,7 +17,7 @@ from wo.core.nginxhashbucket import hashbucket from wo.core.services import WOService from wo.core.shellexec import WOShellExec from wo.core.sslutils import SSL -from wo.core.variables import WOVariables +from wo.core.variables import WOVar def wo_site_hook(app): @@ -57,8 +56,8 @@ class WOSiteController(CementBaseController): pargs.site_name = pargs.site_name.strip() # validate domain name - (wo_domain, - wo_www_domain) = WODomain.validatedomain(self, pargs.site_name) + wo_domain = WODomain.validate(self, pargs.site_name) + wo_www_domain = "www.{0}".format(wo_domain) # check if site exists if not check_domain_exists(self, wo_domain): @@ -95,8 +94,8 @@ class WOSiteController(CementBaseController): Log.debug(self, str(e)) Log.error(self, 'could not input site name') pargs.site_name = pargs.site_name.strip() - (wo_domain, wo_www_domain) = WODomain.validatedomain(self, - pargs.site_name) + wo_domain = WODomain.validate(self, pargs.site_name) + wo_www_domain = "www.{0}".format(wo_domain) # check if site exists if not check_domain_exists(self, wo_domain): Log.error(self, "site {0} does not exist".format(wo_domain)) @@ -136,10 +135,10 @@ class WOSiteController(CementBaseController): Log.debug(self, str(e)) Log.error(self, 'could not input site name') pargs.site_name = pargs.site_name.strip() - (wo_domain, - wo_www_domain) = WODomain.validatedomain(self, pargs.site_name) - (wo_domain_type, - wo_root_domain) = WODomain.getdomainlevel(self, wo_domain) + wo_domain = WODomain.validate(self, pargs.site_name) + wo_www_domain = "www.{0}".format(wo_domain) + (wo_domain_type, wo_root_domain) = WODomain.getlevel( + self, wo_domain) wo_db_name = '' wo_db_user = '' wo_db_pass = '' @@ -190,8 +189,8 @@ class WOSiteController(CementBaseController): def log(self): pargs = self.app.pargs pargs.site_name = pargs.site_name.strip() - (wo_domain, - wo_www_domain) = WODomain.validatedomain(self, pargs.site_name) + wo_domain = WODomain.validate(self, pargs.site_name) + wo_www_domain = "www.{0}".format(wo_domain) wo_site_webroot = getSiteInfo(self, wo_domain).site_path if not check_domain_exists(self, wo_domain): @@ -213,8 +212,8 @@ class WOSiteController(CementBaseController): Log.error(self, 'could not input site name') # TODO Write code for wo site edit command here pargs.site_name = pargs.site_name.strip() - (wo_domain, - wo_www_domain) = WODomain.validatedomain(self, pargs.site_name) + wo_domain = WODomain.validate(self, pargs.site_name) + wo_www_domain = "www.{0}".format(wo_domain) if not check_domain_exists(self, wo_domain): Log.error(self, "site {0} does not exist".format(wo_domain)) @@ -245,8 +244,8 @@ class WOSiteController(CementBaseController): Log.error(self, 'Unable to read input, please try again') pargs.site_name = pargs.site_name.strip() - (wo_domain, - wo_www_domain) = WODomain.validatedomain(self, pargs.site_name) + wo_domain = WODomain.validate(self, pargs.site_name) + wo_www_domain = "www.{0}".format(wo_domain) if not check_domain_exists(self, wo_domain): Log.error(self, "site {0} does not exist".format(wo_domain)) @@ -286,13 +285,12 @@ class WOSiteEditController(CementBaseController): Log.error(self, 'Unable to read input, Please try again') pargs.site_name = pargs.site_name.strip() - (wo_domain, - wo_www_domain) = WODomain.validatedomain(self, pargs.site_name) - + wo_domain = WODomain.validate(self, pargs.site_name) + wo_www_domain = "www.{0}".format(wo_domain) if not check_domain_exists(self, wo_domain): Log.error(self, "site {0} does not exist".format(wo_domain)) - wo_site_webroot = WOVariables.wo_webroot + wo_domain + wo_site_webroot = WOVar.wo_webroot + wo_domain if os.path.isfile('/etc/nginx/sites-available/{0}' .format(wo_domain)): @@ -381,6 +379,9 @@ class WOSiteCreateController(CementBaseController): (['--hsts'], dict(help="enable HSTS for site secured with letsencrypt", action='store_true')), + (['--ngxblocker'], + dict(help="enable HSTS for site secured with letsencrypt", + action='store_true')), (['--user'], dict(help="provide user for WordPress site")), (['--email'], @@ -434,13 +435,15 @@ class WOSiteCreateController(CementBaseController): Log.error(self, "Unable to input site name, Please try again!") pargs.site_name = pargs.site_name.strip() - (wo_domain, - wo_www_domain) = WODomain.validatedomain(self, pargs.site_name) + wo_domain = WODomain.validate(self, pargs.site_name) + wo_www_domain = "www.{0}".format(wo_domain) + (wo_domain_type, wo_root_domain) = WODomain.getlevel( + self, wo_domain) if not wo_domain.strip(): Log.error(self, "Invalid domain name, " "Provide valid domain name") - wo_site_webroot = WOVariables.wo_webroot + wo_domain + wo_site_webroot = WOVar.wo_webroot + wo_domain if check_domain_exists(self, wo_domain): Log.error(self, "site {0} already exists".format(wo_domain)) @@ -729,15 +732,16 @@ class WOSiteCreateController(CementBaseController): if pargs.letsencrypt: acme_domains = [] - (wo_domain_type, - wo_root_domain) = WODomain.getdomainlevel(self, - wo_domain) data['letsencrypt'] = True letsencrypt = True - if data['letsencrypt'] is True: + if WOAcme.cert_check(self, wo_domain): + archivedCertificateHandle(self, wo_domain) + else: Log.debug(self, "Going to issue Let's Encrypt certificate") acmedata = dict(acme_domains, dns=False, acme_dns='dns_cf', - dnsalias=False, acme_alias='') + dnsalias=False, acme_alias='', keylength='') + acmedata['keylength'] = self.app.config.get('letsencrypt', + 'keylength') if pargs.dns: Log.debug(self, "DNS validation enabled") acmedata['dns'] = True @@ -785,9 +789,7 @@ class WOSiteCreateController(CementBaseController): # check if a wildcard cert for the root domain exist Log.debug(self, "checkWildcardExist on *.{0}" .format(wo_root_domain)) - iswildcard = SSL.checkwildcardexist(self, wo_root_domain) - Log.debug(self, "iswildcard = {0}".format(iswildcard)) - if iswildcard: + if SSL.checkwildcardexist(self, wo_root_domain): Log.info(self, "Using existing Wildcard SSL " "certificate from {0} to secure {1}" .format(wo_root_domain, wo_domain)) @@ -836,9 +838,6 @@ class WOSiteCreateController(CementBaseController): msg="Adding letsencrypts config of site: {0}" .format(wo_domain)) updateSiteInfo(self, wo_domain, ssl=letsencrypt) - elif data['letsencrypt'] is False: - Log.info(self, "Not using Let\'s encrypt for Site " - " http://{0}".format(wo_domain)) class WOSiteUpdateController(CementBaseController): @@ -906,6 +905,10 @@ class WOSiteUpdateController(CementBaseController): action='store' or 'store_const', choices=('on', 'off'), const='on', nargs='?')), + (['--ngxblocker'], + dict(help="enable HSTS for site secured with letsencrypt", + action='store' or 'store_const', + const='on', nargs='?')), (['--proxy'], dict(help="update to proxy site", nargs='+')), (['--all'], @@ -987,9 +990,11 @@ class WOSiteUpdateController(CementBaseController): Log.error(self, 'Unable to input site name, Please try again!') pargs.site_name = pargs.site_name.strip() - (wo_domain, - wo_www_domain) = WODomain.validatedomain(self, pargs.site_name) - wo_site_webroot = WOVariables.wo_webroot + wo_domain + wo_domain = WODomain.validate(self, pargs.site_name) + wo_www_domain = "www.{0}".format(wo_domain) + (wo_domain_type, wo_root_domain) = WODomain.getlevel( + self, wo_domain) + wo_site_webroot = WOVar.wo_webroot + wo_domain check_site = getSiteInfo(self, wo_domain) if check_site is None: @@ -1010,7 +1015,7 @@ class WOSiteUpdateController(CementBaseController): pargs.wp or pargs.wpfc or pargs.wpsc or pargs.wprocket or pargs.wpce or pargs.wpsubdir or pargs.wpsubdomain or - pargs.hsts)): + pargs.hsts or pargs.ngxblocker)): try: updatewpuserpassword(self, wo_domain, wo_site_webroot) except SiteError as e: @@ -1023,17 +1028,64 @@ class WOSiteUpdateController(CementBaseController): pargs.wp or pargs.wpfc or pargs.wpsc or pargs.wprocket or pargs.wpce or pargs.wpsubdir or pargs.wpsubdomain or - pargs.password)): - try: - SSL.setuphsts(self, wo_domain) - except SiteError as e: - Log.debug(self, str(e)) - Log.info(self, "\nFail to enable HSTS") + pargs.ngxblocker)): + if pargs.hsts == "on": + try: + SSL.setuphsts(self, wo_domain) + except SiteError as e: + Log.debug(self, str(e)) + Log.info(self, "\nHSTS not enabled.") + elif pargs.hsts == "off": + if os.path.isfile( + '/var/www/{0}/conf/nginx/hsts.conf' + .format(wo_domain)): + WOFileUtils.mvfile(self, '/var/www/{0}/conf/' + 'nginx/hsts.conf' + .format(wo_domain), + '/var/www/{0}/conf/' + 'nginx/hsts.conf.disabled' + .format(wo_domain)) + else: + Log.error(self, "HSTS isn't enabled") + # Service Nginx Reload + if not WOService.reload_service(self, 'nginx'): + Log.error(self, "service nginx reload failed. " + "check issues with `nginx -t` command") + return 0 + + if (pargs.ngxblocker and not (pargs.html or + pargs.php or pargs.php73 or + pargs.mysql or + pargs.wp or pargs.wpfc or pargs.wpsc or + pargs.wprocket or pargs.wpce or + pargs.wpsubdir or pargs.wpsubdomain or + pargs.hsts)): + if pargs.ngxblocker == "on": + if os.path.isdir('/etc/nginx/bots.d'): + try: + setupngxblocker(self, wo_domain) + except SiteError as e: + Log.debug(self, str(e)) + Log.info(self, "\nngxblocker not enabled.") + else: + Log.error(self, 'ngxblocker stack is not installed') + elif pargs.ngxblocker == "off": + if os.path.isfile( + '/var/www/{0}/conf/nginx/ngxblocker.conf' + .format(wo_domain)): + WOFileUtils.mvfile(self, '/var/www/{0}/conf/' + 'nginx/ngxblocker.conf' + .format(wo_domain), + '/var/www/{0}/conf/' + 'nginx/ngxblocker.conf.disabled' + .format(wo_domain)) + else: + Log.error(self, "ngxblocker isn't enabled") + + # Service Nginx Reload if not WOService.reload_service(self, 'nginx'): Log.error(self, "service nginx reload failed. " "check issues with `nginx -t` command") - Log.info(self, "HSTS is enabled for " - "https://{0}".format(wo_domain)) return 0 if ((stype == 'php' and @@ -1091,7 +1143,8 @@ class WOSiteUpdateController(CementBaseController): if pargs.php73: if not data: data = dict( - site_name=wo_domain, www_domain=wo_www_domain, + site_name=wo_domain, + www_domain=wo_www_domain, currsitetype=oldsitetype, currcachetype=oldcachetype, webroot=wo_site_webroot) @@ -1188,10 +1241,9 @@ class WOSiteUpdateController(CementBaseController): if pargs.letsencrypt: acme_domains = [] acmedata = dict(acme_domains, dns=False, acme_dns='dns_cf', - dnsalias=False, acme_alias='') - (wo_domain_type, - wo_root_domain) = WODomain.getdomainlevel(self, wo_domain) - + dnsalias=False, acme_alias='', keylength='') + acmedata['keylength'] = self.app.config.get('letsencrypt', + 'keylength') if pargs.letsencrypt == 'on': data['letsencrypt'] = True letsencrypt = True @@ -1237,86 +1289,6 @@ class WOSiteUpdateController(CementBaseController): "site") pargs.letsencrypt = False - # --letsencrypt=renew code goes here - if pargs.letsencrypt == "renew" and not pargs.all: - expiry_days = SSL.getexpirationdays(self, wo_domain) - min_expiry_days = 45 - if check_ssl: - if (expiry_days <= min_expiry_days): - renewLetsEncrypt(self, wo_domain) - elif pargs.force: - renewLetsEncrypt(self, wo_domain) - else: - Log.error( - self, "You have more than 30 days with the current " - "certificate - refusing to run.") - - else: - Log.error( - self, "Cannot renew - HTTPS is not configured for " - "the given site. Install LE first...") - - if not WOService.reload_service(self, 'nginx'): - Log.error(self, "service nginx reload failed. " - "check issues with `nginx -t` command") - Log.info(self, "SUCCESS: Certificate was successfully renewed For" - " https://{0}".format(wo_domain)) - if (SSL.getexpirationdays(self, wo_domain) > 0): - Log.info(self, "Your cert will expire within " + - str(SSL.getexpirationdays(self, wo_domain)) + - " days.") - Log.info(self, "Expiration date: " + - str(SSL.getexpirationdate(self, wo_domain))) - - else: - Log.warn( - self, "The certificate seems to be already expired. " - "Please renew it as soon as possible...") - return 0 - - if pargs.all and pargs.letsencrypt == "renew": - - if check_ssl: - expiry_days = SSL.getExpirationDays(self, wo_domain, True) - if expiry_days < 0: - return 0 - min_expiry_days = 45 - if (expiry_days <= min_expiry_days): - renewLetsEncrypt(self, wo_domain) - if not WOService.reload_service(self, 'nginx'): - Log.error(self, "service nginx reload failed. " - "check issues with `nginx -t` command") - Log.info(self, "SUCCESS: Certificate was successfully " - "renewed For https://{0}".format(wo_domain)) - elif pargs.force: - renewLetsEncrypt(self, wo_domain) - Log.info(self, "Certificate was successfully renewed") - if not WOService.reload_service(self, 'nginx'): - Log.error(self, "service nginx reload failed. " - "check issues with `nginx -t` command") - Log.info(self, "SUCCESS: Certificate was successfully " - "renewed For https://{0}".format(wo_domain)) - else: - Log.info( - self, "You have more than 45 days with the current " - "certificate - refusing to run.\n") - - if (SSL.getexpirationdays(self, wo_domain) > 0): - Log.info(self, "Your cert will expire within " + - str(SSL.getexpirationdays(self, wo_domain)) + - " days.") - Log.info(self, "Expiration date: \n\n" + - str(SSL.getexpirationdate(self, wo_domain))) - return 0 - # else: - # Log.warn(self, "Your cert already EXPIRED ! - # .PLEASE renew soon . ") - else: - Log.info( - self, "SSL not configured for " - "site http://{0}".format(wo_domain)) - return 0 - if pargs.all and pargs.letsencrypt == "off": if letsencrypt is check_ssl: if letsencrypt is False: @@ -1364,6 +1336,12 @@ class WOSiteUpdateController(CementBaseController): elif pargs.hsts == "off": data['hsts'] = False + if pargs.ngxblocker: + if pargs.ngxblocker == 'on': + ngxblocker = True + elif pargs.ngxblocker == 'off': + ngxblocker = False + if not data: Log.error(self, "Cannot update {0}, Invalid Options" .format(wo_domain)) @@ -1374,7 +1352,7 @@ class WOSiteUpdateController(CementBaseController): data['wo_db_pass'] = check_site.db_password data['wo_db_host'] = check_site.db_host - if not (pargs.letsencrypt or pargs.hsts): + if not (pargs.letsencrypt or pargs.hsts or pargs.ngxblocker): try: pre_run_checks(self) except SiteError as e: @@ -1408,47 +1386,68 @@ class WOSiteUpdateController(CementBaseController): if pargs.letsencrypt: if data['letsencrypt'] is True: - # DNS API configuration - if pargs.dns: - Log.debug(self, "DNS validation enabled") - acmedata['dns'] = True - if not pargs.dns == 'dns_cf': - Log.debug(self, "DNS API : {0}".format(pargs.dns)) - acmedata['acme_dns'] = pargs.dns - if pargs.dnsalias: - Log.debug(self, "DNS Alias enabled") - acmedata['dnsalias'] = True - acmedata['acme_alias'] = pargs.dnsalias - # Set list of domains to secure - if acme_subdomain is True: - Log.info(self, "Certificate type : subdomain") - acme_domains = acme_domains + ['{0}'.format(wo_domain)] - elif acme_wildcard is True: - Log.info(self, "Certificate type : wildcard") - acme_domains = acme_domains + ['{0}'.format(wo_domain), - '*.{0}'.format(wo_domain)] + if WOAcme.cert_check(self, wo_domain): + archivedCertificateHandle(self, wo_domain) else: - Log.info(self, "Certificate type : domain") - acme_domains = acme_domains + ['{0}'.format(wo_domain), - 'www.{0}'.format(wo_domain)] + # DNS API configuration + if pargs.dns: + Log.debug(self, "DNS validation enabled") + acmedata['dns'] = True + if not pargs.dns == 'dns_cf': + Log.debug(self, "DNS API : {0}".format(pargs.dns)) + acmedata['acme_dns'] = pargs.dns + if pargs.dnsalias: + Log.debug(self, "DNS Alias enabled") + acmedata['dnsalias'] = True + acmedata['acme_alias'] = pargs.dnsalias + # Set list of domains to secure + if acme_subdomain is True: + Log.info(self, "Certificate type : subdomain") + acme_domains = acme_domains + ['{0}'.format(wo_domain)] + elif acme_wildcard is True: + Log.info(self, "Certificate type : wildcard") + acme_domains = \ + acme_domains + ['{0}'.format(wo_domain), + '*.{0}'.format(wo_domain)] + else: + Log.info(self, "Certificate type : domain") + acme_domains = \ + acme_domains + ['{0}'.format(wo_domain), + 'www.{0}'.format(wo_domain)] - if acme_subdomain: - # check if a wildcard cert for the root domain exist - Log.debug(self, "checkWildcardExist on *.{0}" - .format(wo_root_domain)) - iswildcard = SSL.checkwildcardexist(self, wo_root_domain) - Log.debug(self, "iswildcard = {0}".format(iswildcard)) - if not os.path.isfile("{0}/conf/nginx/ssl.conf.disabled"): - if acme_subdomain: - if iswildcard: - Log.info(self, "Using existing Wildcard SSL " - "certificate from {0} to secure {1}" - .format(wo_root_domain, wo_domain)) - Log.debug(self, "symlink wildcard " - "cert between {0} & {1}" - .format(wo_domain, wo_root_domain)) - # copy the cert from the root domain - copyWildcardCert(self, wo_domain, wo_root_domain) + if not os.path.isfile("{0}/conf/nginx/ssl.conf.disabled"): + if acme_subdomain: + Log.debug(self, "checkWildcardExist on *.{0}" + .format(wo_root_domain)) + if SSL.checkwildcardexist(self, wo_root_domain): + Log.info( + self, "Using existing Wildcard SSL " + "certificate from {0} to secure {1}" + .format(wo_root_domain, wo_domain)) + Log.debug( + self, "symlink wildcard " + "cert between {0} & {1}" + .format(wo_domain, wo_root_domain)) + # copy the cert from the root domain + copyWildcardCert(self, wo_domain, + wo_root_domain) + else: + # check DNS records before issuing cert + if not acmedata['dns'] is True: + if not pargs.force: + if not WOAcme.check_dns(self, + acme_domains): + Log.error( + self, + "Aborting SSL certificate " + "issuance") + Log.debug(self, "Setup Cert with acme.sh for {0}" + .format(wo_domain)) + if WOAcme.setupletsencrypt( + self, acme_domains, acmedata): + WOAcme.deploycert(self, wo_domain) + else: + Log.error(self, "Unable to issue certificate") else: # check DNS records before issuing cert if not acmedata['dns'] is True: @@ -1457,41 +1456,28 @@ class WOSiteUpdateController(CementBaseController): acme_domains): Log.error( self, - "Aborting SSL certificate " - "issuance") - Log.debug(self, "Setup Cert with acme.sh for {0}" - .format(wo_domain)) + "Aborting SSL " + "certificate issuance") if WOAcme.setupletsencrypt( self, acme_domains, acmedata): WOAcme.deploycert(self, wo_domain) else: Log.error(self, "Unable to issue certificate") else: - # check DNS records before issuing cert - if not acmedata['dns'] is True: - if not pargs.force: - if not WOAcme.check_dns(self, acme_domains): - Log.error( - self, - "Aborting SSL certificate issuance") - if WOAcme.setupletsencrypt( - self, acme_domains, acmedata): - WOAcme.deploycert(self, wo_domain) - else: - Log.error(self, "Unable to issue certificate") - 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)) + 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, acme_wildcard) - SSL.siteurlhttps(self, wo_domain) + httpsRedirect(self, wo_domain, True, acme_wildcard) + SSL.siteurlhttps(self, wo_domain) if not WOService.reload_service(self, 'nginx'): Log.error(self, "service nginx reload failed. " @@ -1499,25 +1485,14 @@ class WOSiteUpdateController(CementBaseController): Log.info(self, "Congratulations! Successfully " "Configured SSL for Site " " https://{0}".format(wo_domain)) - if acme_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)) + - " days.") - else: - Log.warn( - self, "Your cert already EXPIRED ! " - ".PLEASE renew soon . ") + if (SSL.getexpirationdays(self, wo_domain) > 0): + Log.info(self, "Your cert will expire within " + + str(SSL.getexpirationdays(self, wo_domain)) + + " days.") else: - if (SSL.getexpirationdays(self, wo_domain) > 0): - Log.info(self, "Your cert will expire within " + - str(SSL.getexpirationdays(self, wo_domain)) + - " days.") - else: - Log.warn( - self, "Your cert already EXPIRED ! " - ".PLEASE renew soon . ") + Log.warn( + self, "Your cert already EXPIRED ! " + ".PLEASE renew soon . ") elif data['letsencrypt'] is False: if pargs.letsencrypt == "off": @@ -1598,6 +1573,22 @@ class WOSiteUpdateController(CementBaseController): else: Log.error(self, "HSTS is not configured for given " "site") + if pargs.ngxblocker: + if ngxblocker is True: + setupngxblocker(self, wo_domain) + elif ngxblocker is False: + if os.path.isfile("{0}/conf/nginx/ngxblocker.conf" + .format(wo_site_webroot)): + WOFileUtils.mvfile( + self, + "{0}/conf/nginx/ngxblocker.conf" + .format(wo_site_webroot), + "{0}/conf/nginx/ngxblocker.conf.disabled" + .format(wo_site_webroot)) + # Service Nginx Reload + if not WOService.reload_service(self, 'nginx'): + Log.error(self, "service nginx reload failed. " + "check issues with `nginx -t` command") if stype == oldsitetype and cache == oldcachetype: @@ -1958,7 +1949,8 @@ class WOSiteDeleteController(CementBaseController): Log.error(self, 'could not input site name') pargs.site_name = pargs.site_name.strip() - (wo_domain, wo_www_domain) = WODomain.validatedomain(self, pargs.site_name) + wo_domain = WODomain.validate(self, pargs.site_name) + wo_www_domain = "www.{0}".format(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 9f2d641..e9b0454 100644 --- a/wo/cli/plugins/site_functions.py +++ b/wo/cli/plugins/site_functions.py @@ -4,6 +4,7 @@ import json import os import random import re +import shutil import string import subprocess from subprocess import CalledProcessError @@ -16,11 +17,12 @@ from wo.core.aptget import WOAptGet from wo.core.fileutils import WOFileUtils from wo.core.git import WOGit from wo.core.logging import Log -from wo.core.mysql import WOMysql +from wo.core.mysql import (MySQLConnectionError, StatementExcecutionError, + WOMysql) from wo.core.services import WOService from wo.core.shellexec import CommandExecutionError, WOShellExec from wo.core.sslutils import SSL -from wo.core.variables import WOVariables +from wo.core.variables import WOVar class SiteError(Exception): @@ -93,8 +95,8 @@ def setupdomain(self, data): # Check nginx -t and return status over it try: Log.debug(self, "Checking generated nginx conf, please wait...") - FNULL = open('/dev/null', 'w') - subprocess.check_call(["/usr/sbin/nginx", "-t"], stdout=FNULL, + fnull = open('/dev/null', 'w') + subprocess.check_call(["/usr/sbin/nginx", "-t"], stdout=fnull, stderr=subprocess.STDOUT) Log.info(self, "[" + Log.ENDC + "Done" + Log.OKBLUE + "]") except CalledProcessError as e: @@ -227,7 +229,7 @@ def setupdatabase(self, data): data['wo_db_name'] = wo_db_name data['wo_db_user'] = wo_db_username data['wo_db_pass'] = wo_db_password - data['wo_db_host'] = WOVariables.wo_mysql_host + data['wo_db_host'] = WOVar.wo_mysql_host data['wo_mysql_grant_host'] = wo_mysql_grant_host return(data) @@ -293,7 +295,7 @@ def setupwordpress(self, data, vhostonly=False): if not data['multisite']: Log.debug(self, "Generating wp-config for WordPress Single site") Log.debug(self, "/bin/bash -c \"{0} --allow-root " - .format(WOVariables.wo_wpcli_path) + + .format(WOVar.wo_wpcli_path) + "config create " + "--dbname=\'{0}\' --dbprefix=\'{1}\' --dbuser=\'{2}\' " "--dbhost=\'{3}\' " @@ -305,7 +307,7 @@ def setupwordpress(self, data, vhostonly=False): "\n\ndefine(\'WP_DEBUG\', false);")) try: if WOShellExec.cmd_exec(self, "/bin/bash -c \"{0} --allow-root" - .format(WOVariables.wo_wpcli_path) + + .format(WOVar.wo_wpcli_path) + " config create " + "--dbname=\'{0}\' --dbprefix=\'{1}\' " "--dbuser=\'{2}\' --dbhost=\'{3}\' " @@ -328,7 +330,7 @@ def setupwordpress(self, data, vhostonly=False): else: Log.debug(self, "Generating wp-config for WordPress multisite") Log.debug(self, "/bin/bash -c \"{0} --allow-root " - .format(WOVariables.wo_wpcli_path) + + .format(WOVar.wo_wpcli_path) + "config create " + "--dbname=\'{0}\' --dbprefix=\'{1}\' --dbhost=\'{2}\' " .format(data['wo_db_name'], @@ -343,7 +345,7 @@ def setupwordpress(self, data, vhostonly=False): "\n\ndefine(\'WP_DEBUG\', false);")) try: if WOShellExec.cmd_exec(self, "/bin/bash -c \"{0} --allow-root" - .format(WOVariables.wo_wpcli_path) + + .format(WOVar.wo_wpcli_path) + " config create " + "--dbname=\'{0}\' --dbprefix=\'{1}\' " "--dbhost=\'{2}\' " @@ -368,36 +370,36 @@ def setupwordpress(self, data, vhostonly=False): try: WOShellExec.cmd_exec(self, "/bin/bash -c \"{0} --allow-root " - .format(WOVariables.wo_wpcli_path) + + .format(WOVar.wo_wpcli_path) + "config set WP_CACHE_KEY_SALT " "\'{0}:\'\"".format(wo_domain_name)) WOShellExec.cmd_exec(self, "/bin/bash -c \"{0} --allow-root " - .format(WOVariables.wo_wpcli_path) + + .format(WOVar.wo_wpcli_path) + "config set WP_MEMORY_LIMIT " "\'128M\'\"") WOShellExec.cmd_exec(self, "/bin/bash -c \"{0} --allow-root " - .format(WOVariables.wo_wpcli_path) + + .format(WOVar.wo_wpcli_path) + "config set WP_MAX_MEMORY_LIMIT " "\'256M\'\"") WOShellExec.cmd_exec(self, "/bin/bash -c \"{0} --allow-root " - .format(WOVariables.wo_wpcli_path) + + .format(WOVar.wo_wpcli_path) + "config set CONCATENATE_SCRIPTS " "false --raw\"") WOShellExec.cmd_exec(self, "/bin/bash -c \"{0} --allow-root " - .format(WOVariables.wo_wpcli_path) + + .format(WOVar.wo_wpcli_path) + "config set WP_POST_REVISIONS " "\'10\'\"") WOShellExec.cmd_exec(self, "/bin/bash -c \"{0} --allow-root " - .format(WOVariables.wo_wpcli_path) + + .format(WOVar.wo_wpcli_path) + "config set MEDIA_TRASH " "true --raw\"") WOShellExec.cmd_exec(self, "/bin/bash -c \"{0} --allow-root " - .format(WOVariables.wo_wpcli_path) + + .format(WOVar.wo_wpcli_path) + "config set EMPTY_TRASH_DAYS " "\'15\'\"") WOShellExec.cmd_exec(self, "/bin/bash -c \"{0} --allow-root " - .format(WOVariables.wo_wpcli_path) + + .format(WOVar.wo_wpcli_path) + "config set WP_AUTO_UPDATE_CORE " "minor\"") @@ -409,7 +411,6 @@ def setupwordpress(self, data, vhostonly=False): # os.path.abspath(os.path.join(os.getcwd(), os.pardir))) try: - import shutil Log.debug(self, "Moving file from {0} to {1}".format(os.getcwd( )+'/wp-config.php', os.path.abspath(os.path.join(os.getcwd(), @@ -425,7 +426,7 @@ def setupwordpress(self, data, vhostonly=False): raise SiteError("Unable to move wp-config.php") if not wo_wp_user: - wo_wp_user = WOVariables.wo_user + wo_wp_user = WOVar.wo_user while not wo_wp_user: Log.warn(self, "Username can have only alphanumeric" "characters, spaces, underscores, hyphens," @@ -438,7 +439,7 @@ def setupwordpress(self, data, vhostonly=False): wo_wp_pass = wo_random_pass if not wo_wp_email: - wo_wp_email = WOVariables.wo_email + wo_wp_email = WOVar.wo_email while not wo_wp_email: try: wo_wp_email = input('Enter WordPress email: ') @@ -459,14 +460,14 @@ def setupwordpress(self, data, vhostonly=False): if not data['multisite']: Log.debug(self, "Creating tables for WordPress Single site") Log.debug(self, "{0} --allow-root core install " - .format(WOVariables.wo_wpcli_path) + + .format(WOVar.wo_wpcli_path) + "--url=\'{0}\' --title=\'{0}\' --admin_name=\'{1}\' " .format(data['www_domain'], wo_wp_user) + "--admin_password= --admin_email=\'{1}\'" .format(wo_wp_pass, wo_wp_email)) try: if WOShellExec.cmd_exec(self, "{0} --allow-root core " - .format(WOVariables.wo_wpcli_path) + + .format(WOVar.wo_wpcli_path) + "install --url=\'{0}\' --title=\'{0}\' " "--admin_name=\'{1}\' " .format(data['www_domain'], wo_wp_user) + @@ -483,7 +484,7 @@ def setupwordpress(self, data, vhostonly=False): else: Log.debug(self, "Creating tables for WordPress multisite") Log.debug(self, "{0} --allow-root " - .format(WOVariables.wo_wpcli_path) + + .format(WOVar.wo_wpcli_path) + "core multisite-install " "--url=\'{0}\' --title=\'{0}\' --admin_name=\'{1}\' " .format(data['www_domain'], wo_wp_user) + @@ -494,7 +495,7 @@ def setupwordpress(self, data, vhostonly=False): if not data['wpsubdir'] else '')) try: if WOShellExec.cmd_exec(self, "{0} --allow-root " - .format(WOVariables.wo_wpcli_path) + + .format(WOVar.wo_wpcli_path) + "core multisite-install " "--url=\'{0}\' --title=\'{0}\' " "--admin_name=\'{1}\' " @@ -516,7 +517,7 @@ def setupwordpress(self, data, vhostonly=False): Log.debug(self, "Updating WordPress permalink") try: WOShellExec.cmd_exec(self, " {0} --allow-root " - .format(WOVariables.wo_wpcli_path) + + .format(WOVar.wo_wpcli_path) + "rewrite structure " "/%postname%/") except CommandExecutionError as e: @@ -607,8 +608,9 @@ def setupwordpress(self, data, vhostonly=False): if vhostonly: try: WOShellExec.cmd_exec(self, "/bin/bash -c \"{0} --allow-root " - .format(WOVariables.wo_wpcli_path) + + .format(WOVar.wo_wpcli_path) + "db clean --yes\"") + WOFileUtils.chdir(self, '{0}'.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), @@ -652,7 +654,7 @@ def installwp_plugin(self, plugin_name, data): WOFileUtils.chdir(self, '{0}/htdocs/'.format(wo_site_webroot)) try: WOShellExec.cmd_exec(self, "{0} plugin " - .format(WOVariables.wo_wpcli_path) + + .format(WOVar.wo_wpcli_path) + "--allow-root install " "{0}".format(plugin_name)) except CommandExecutionError as e: @@ -661,7 +663,7 @@ def installwp_plugin(self, plugin_name, data): try: WOShellExec.cmd_exec(self, "{0} plugin " - .format(WOVariables.wo_wpcli_path) + + .format(WOVar.wo_wpcli_path) + "--allow-root activate " "{0} {na}" .format(plugin_name, @@ -688,12 +690,12 @@ def uninstallwp_plugin(self, plugin_name, data): .format(plugin_name)) try: WOShellExec.cmd_exec(self, "{0} plugin " - .format(WOVariables.wo_wpcli_path) + + .format(WOVar.wo_wpcli_path) + "--allow-root deactivate " "{0}".format(plugin_name)) WOShellExec.cmd_exec(self, "{0} plugin " - .format(WOVariables.wo_wpcli_path) + + .format(WOVar.wo_wpcli_path) + "--allow-root uninstall " "{0}".format(plugin_name)) except CommandExecutionError as e: @@ -715,7 +717,7 @@ def setupwp_plugin(self, plugin_name, plugin_option, plugin_data, data): if not data['multisite']: try: WOShellExec.cmd_exec(self, "{0} " - .format(WOVariables.wo_wpcli_path) + + .format(WOVar.wo_wpcli_path) + "--allow-root option update " "{0} \'{1}\' --format=json" .format(plugin_option, plugin_data)) @@ -730,7 +732,7 @@ def setupwp_plugin(self, plugin_name, plugin_option, plugin_data, data): else: try: WOShellExec.cmd_exec(self, "{0} " - .format(WOVariables.wo_wpcli_path) + + .format(WOVar.wo_wpcli_path) + "--allow-root network meta update 1 " "{0} \'{1}\' --format=json" .format(plugin_option, plugin_data @@ -749,8 +751,8 @@ def setwebrootpermissions(self, webroot): Log.debug(self, "Setting up permissions") try: WOFileUtils.findBrokenSymlink(self, '/var/www/') - WOFileUtils.chown(self, webroot, WOVariables.wo_php_user, - WOVariables.wo_php_user, recursive=True) + WOFileUtils.chown(self, webroot, WOVar.wo_php_user, + WOVar.wo_php_user, recursive=True) except Exception as e: Log.debug(self, str(e)) raise SiteError("problem occured while setting up webroot permissions") @@ -758,7 +760,7 @@ def setwebrootpermissions(self, webroot): def sitebackup(self, data): wo_site_webroot = data['webroot'] - backup_path = wo_site_webroot + '/backup/{0}'.format(WOVariables.wo_date) + backup_path = wo_site_webroot + '/backup/{0}'.format(WOVar.wo_date) if not WOFileUtils.isexist(self, backup_path): WOFileUtils.mkdir(self, backup_path) Log.info(self, "Backup location : {0}".format(backup_path)) @@ -835,8 +837,8 @@ def site_package_check(self, stype): # do something # do post nginx installation configuration Log.info(self, "NGINX PLUS Detected ...") - apt = ["nginx-plus"] + WOVariables.wo_nginx - # apt_packages = apt_packages + WOVariables.wo_nginx + apt = ["nginx-plus"] + WOVar.wo_nginx + # apt_packages = apt_packages + WOVar.wo_nginx stack.post_pref(self, apt, packages) elif WOAptGet.is_installed(self, 'nginx'): Log.info(self, "WordOps detected a previously" @@ -844,11 +846,13 @@ def site_package_check(self, stype): "It may or may not have required modules. " "\nIf you need help, please create an issue at " "https://github.com/WordOps/WordOps/issues/ \n") - apt = ["nginx"] + WOVariables.wo_nginx - # apt_packages = apt_packages + WOVariables.wo_nginx + apt = ["nginx"] + WOVar.wo_nginx + # apt_packages = apt_packages + WOVar.wo_nginx post_pref(self, apt, packages) + elif os.path.isfile('/usr/sbin/nginx'): + post_pref(self, WOVar.wo_nginx, []) else: - apt_packages = apt_packages + WOVariables.wo_nginx + apt_packages = apt_packages + WOVar.wo_nginx else: # Fix for Nginx white screen death if not WOFileUtils.grep(self, '/etc/nginx/fastcgi_params', @@ -868,26 +872,26 @@ def site_package_check(self, stype): Log.debug(self, "Setting apt_packages variable for PHP 7.2") if not WOAptGet.is_installed(self, 'php7.2-fpm'): if not WOAptGet.is_installed(self, 'php7.3-fpm'): - apt_packages = apt_packages + WOVariables.wo_php + \ - WOVariables.wo_php_extra + apt_packages = apt_packages + WOVar.wo_php + \ + WOVar.wo_php_extra else: - apt_packages = apt_packages + WOVariables.wo_php + apt_packages = apt_packages + WOVar.wo_php if self.app.pargs.php73 and stype in ['mysql', 'wp', 'wpsubdir', 'wpsubdomain']: Log.debug(self, "Setting apt_packages variable for PHP 7.3") if not WOAptGet.is_installed(self, 'php7.3-fpm'): if not WOAptGet.is_installed(self, 'php7.2-fpm'): - apt_packages = apt_packages + WOVariables.wo_php + \ - WOVariables.wo_php73 + WOVariables.wo_php_extra + apt_packages = apt_packages + WOVar.wo_php + \ + WOVar.wo_php73 + WOVar.wo_php_extra else: - apt_packages = apt_packages + WOVariables.wo_php73 + apt_packages = apt_packages + WOVar.wo_php73 if stype in ['mysql', 'wp', 'wpsubdir', 'wpsubdomain']: Log.debug(self, "Setting apt_packages variable for MySQL") if not WOShellExec.cmd_exec(self, "/usr/bin/mysqladmin ping"): - if not WOVariables.wo_distro == 'raspbian': - if (not WOVariables.wo_platform_codename == 'jessie'): + if not WOVar.wo_distro == 'raspbian': + if (not WOVar.wo_platform_codename == 'jessie'): wo_mysql = ["mariadb-server", "percona-toolkit", "python3-mysqldb", "mariadb-backup"] else: @@ -904,7 +908,7 @@ def site_package_check(self, stype): packages = packages + [["https://github.com/wp-cli/wp-cli/" "releases/download/v{0}/" "wp-cli-{0}.phar" - .format(WOVariables.wo_wp_cli), + .format(WOVar.wo_wp_cli), "/usr/local/bin/wp", "WP-CLI"]] if self.app.pargs.wpredis: Log.debug(self, "Setting apt_packages variable for redis") @@ -915,10 +919,20 @@ def site_package_check(self, stype): Log.debug(self, "Setting apt_packages variable for PHP 7.3") if not WOAptGet.is_installed(self, 'php7.3-fpm'): if not WOAptGet.is_installed(self, 'php7.2-fpm'): - apt_packages = apt_packages + WOVariables.wo_php + \ - WOVariables.wo_php73 + WOVariables.wo_php_extra + apt_packages = apt_packages + WOVar.wo_php + \ + WOVar.wo_php73 + WOVar.wo_php_extra else: - apt_packages = apt_packages + WOVariables.wo_php73 + apt_packages = apt_packages + WOVar.wo_php73 + + if self.app.pargs.ngxblocker: + if not os.path.isdir('/etc/nginx/bots.d'): + Log.debug(self, "Setting packages variable for ngxblocker") + packages = packages + \ + [["https://raw.githubusercontent.com/" + "mitchellkrogza/nginx-ultimate-bad-bot-blocker" + "/master/install-ngxblocker", + "/usr/local/sbin/install-ngxblocker", + "ngxblocker"]] return(stack.install(apt_packages=apt_packages, packages=packages, disp_msg=False)) @@ -1026,11 +1040,11 @@ def display_cache_settings(self, data): if data['wpce']: if data['multisite']: - Log.info(self, "Nginx-Helper configuration :" + Log.info(self, "Cache-Enabler configuration :" "\thttp://{0}/wp-admin/network/settings.php?" "page=cache-enabler".format(data['site_name'])) else: - Log.info(self, "Nginx-Helper configuration :" + Log.info(self, "Cache-Enabler configuration :" "\thttp://{0}/wp-admin/options-general.php?" "page=cache-enabler".format(data['site_name'])) @@ -1280,9 +1294,9 @@ def removeAcmeConf(self, domain): Log.error(self, "Cert removal failed") WOFileUtils.rm(self, '{0}/{1}_ecc' - .format(WOVariables.wo_ssl_archive, domain)) + .format(WOVar.wo_ssl_archive, domain)) WOFileUtils.rm(self, '{0}/{1}' - .format(WOVariables.wo_ssl_live, domain)) + .format(WOVar.wo_ssl_live, domain)) WOFileUtils.rm(self, '{0}'.format(sslconf)) WOFileUtils.rm(self, '{0}.disabled'.format(sslconf)) WOFileUtils.rm(self, '{0}'.format(sslforce)) @@ -1489,7 +1503,7 @@ def archivedCertificateHandle(self, domain): self, "You already have an existing certificate " "for the domain requested.\n" "(ref: {0}/" - "{1}_ecc/{1}.conf)".format(WOVariables.wo_ssl_archive, domain) + + "{1}_ecc/{1}.conf)".format(WOVar.wo_ssl_archive, domain) + "\nPlease select an option from below?" "\n\t1: Reinstall existing certificate" "\n\t2: Issue a new certificate to replace " @@ -1498,10 +1512,10 @@ def archivedCertificateHandle(self, domain): check_prompt = input( "\nType the appropriate number [1-2] or any other key to cancel: ") if not os.path.isfile("{0}/{1}/fullchain.pem" - .format(WOVariables.wo_ssl_live, domain)): + .format(WOVar.wo_ssl_live, domain)): Log.error( self, "{0}/{1}/fullchain.pem file is missing." - .format(WOVariables.wo_ssl_live, domain)) + .format(WOVar.wo_ssl_live, domain)) if check_prompt == "1": Log.info(self, "Reinstalling SSL cert with acme.sh") @@ -1526,7 +1540,7 @@ def archivedCertificateHandle(self, domain): "ssl_certificate_key {0}/{1}/key.pem;\n" "ssl_trusted_certificate {0}/{1}/ca.pem;\n" "ssl_stapling_verify on;\n" - .format(WOVariables.wo_ssl_live, domain)) + .format(WOVar.wo_ssl_live, domain)) sslconf.close() except IOError as e: @@ -1560,7 +1574,7 @@ def archivedCertificateHandle(self, domain): "{0}/{1}/ca.pem;\n" "--reloadcmd " "\"nginx -t && service nginx restart\" " - .format(WOVariables.wo_ssl_live, domain)) + .format(WOVar.wo_ssl_live, domain)) except IOError as e: Log.debug(self, str(e)) @@ -1582,8 +1596,8 @@ def archivedCertificateHandle(self, domain): def setuprocketchat(self): - if ((not WOVariables.wo_platform_codename == 'bionic') and - (not WOVariables.wo_platform_codename == 'xenial')): + if ((not WOVar.wo_platform_codename == 'bionic') and + (not WOVar.wo_platform_codename == 'xenial')): Log.info(self, "Rocket.chat is only available on Ubuntu 16.04 " "& 18.04 LTS") return False @@ -1592,3 +1606,22 @@ def setuprocketchat(self): WOAptGet.install(self, ["snapd"]) if WOShellExec.cmd_exec(self, "snap install rocketchat-server"): return True + + +def setupngxblocker(self, domain, block=True): + if os.path.isdir('/var/www/{0}/conf/nginx'.format(domain)): + if not os.path.isfile('/var/www/{0}/conf/nginx/ngxblocker.disabled' + .format(domain)): + ngxconf = open("/var/www/{0}/conf/nginx/ngxblocker.conf" + .format(domain), + encoding='utf-8', mode='w') + ngxconf.write("# Bad Bot Blocker\n" + "include /etc/nginx/bots.d/ddos.conf;\n" + "include /etc/nginx/bots.d/blockbots.conf;\n") + ngxconf.close() + else: + WOFileUtils.mvfile( + self, '/var/www/{0}/conf/nginx/ngxblocker.disabled' + .format(domain), '/var/www/{0}/conf/nginx/ngxblocker' + .format(domain)) + return 0 diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index 9a2e3ea..ab75744 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -18,7 +18,7 @@ from wo.core.logging import Log from wo.core.mysql import WOMysql from wo.core.services import WOService from wo.core.shellexec import WOShellExec -from wo.core.variables import WOVariables +from wo.core.variables import WOVar def wo_stack_hook(app): @@ -85,6 +85,9 @@ class WOStackController(CementBaseController): dict(help='Install phpRedisAdmin', action='store_true')), (['--proftpd'], dict(help='Install ProFTPd', action='store_true')), + (['--ngxblocker'], + dict(help='Install Nginx Ultimate Bad Bot Blocker', + action='store_true')), (['--force'], dict(help='Force install/remove/purge without prompt', action='store_true')), @@ -116,7 +119,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.ufw) and + (not pargs.ufw) and (not pargs.ngxblocker) and (not pargs.phpredisadmin) and (not pargs.sendmail) and (not pargs.php73)): pargs.web = True @@ -151,34 +154,35 @@ class WOStackController(CementBaseController): if pargs.security: pargs.fail2ban = True pargs.clamav = True + pargs.ngxblocker = True # Nginx if pargs.nginx: Log.debug(self, "Setting apt_packages variable for Nginx") - if not (WOAptGet.is_installed(self, 'nginx-custom')): if not (WOAptGet.is_installed(self, 'nginx-plus') or WOAptGet.is_installed(self, 'nginx')): - apt_packages = apt_packages + WOVariables.wo_nginx + if not os.path.isfile('/usr/sbin/nginx'): + apt_packages = apt_packages + WOVar.wo_nginx else: if WOAptGet.is_installed(self, 'nginx-plus'): Log.info(self, "NGINX PLUS Detected ...") - apt = ["nginx-plus"] + WOVariables.wo_nginx + apt = ["nginx-plus"] + WOVar.wo_nginx 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 + apt = ["nginx"] + WOVar.wo_nginx self.post_pref(apt, empty_packages) else: - Log.debug(self, "Nginx Stable already installed") + Log.debug(self, "Nginx already installed") # Redis if pargs.redis: if not WOAptGet.is_installed(self, 'redis-server'): - apt_packages = apt_packages + WOVariables.wo_redis + apt_packages = apt_packages + WOVar.wo_redis else: Log.info(self, "Redis already installed") @@ -187,8 +191,8 @@ class WOStackController(CementBaseController): if pargs.php: Log.debug(self, "Setting apt_packages variable for PHP 7.2") if not (WOAptGet.is_installed(self, 'php7.2-fpm')): - apt_packages = (apt_packages + WOVariables.wo_php + - WOVariables.wo_php_extra) + apt_packages = (apt_packages + WOVar.wo_php + + WOVar.wo_php_extra) else: Log.debug(self, "PHP 7.2 already installed") Log.info(self, "PHP 7.2 already installed") @@ -197,9 +201,9 @@ class WOStackController(CementBaseController): if pargs.php73: Log.debug(self, "Setting apt_packages variable for PHP 7.3") if not WOAptGet.is_installed(self, 'php7.3-fpm'): - apt_packages = (apt_packages + WOVariables.wo_php + - WOVariables.wo_php73 + - WOVariables.wo_php_extra) + apt_packages = (apt_packages + WOVar.wo_php + + WOVar.wo_php73 + + WOVar.wo_php_extra) else: Log.debug(self, "PHP 7.3 already installed") Log.info(self, "PHP 7.3 already installed") @@ -209,7 +213,7 @@ class WOStackController(CementBaseController): 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 + apt_packages = apt_packages + WOVar.wo_mysql else: Log.debug(self, "MySQL already installed and alive") Log.info(self, "MySQL already installed and alive") @@ -219,7 +223,7 @@ class WOStackController(CementBaseController): Log.debug(self, "Setting apt_packages variable " "for MySQL Client") if not WOShellExec.cmd_exec(self, "mysqladmin ping"): - apt_packages = apt_packages + WOVariables.wo_mysql_client + apt_packages = apt_packages + WOVar.wo_mysql_client else: Log.debug(self, "MySQL already installed and alive") Log.info(self, "MySQL already installed and alive") @@ -232,7 +236,7 @@ class WOStackController(CementBaseController): packages = packages + [["https://github.com/wp-cli/wp-cli/" "releases/download/v{0}/" "wp-cli-{0}.phar" - "".format(WOVariables.wo_wp_cli), + "".format(WOVar.wo_wp_cli), "/usr/local/bin/wp", "WP-CLI"]] else: @@ -243,7 +247,7 @@ class WOStackController(CementBaseController): if pargs.fail2ban: Log.debug(self, "Setting apt_packages variable for Fail2ban") if not WOAptGet.is_installed(self, 'fail2ban'): - apt_packages = apt_packages + WOVariables.wo_fail2ban + apt_packages = apt_packages + WOVar.wo_fail2ban else: Log.debug(self, "Fail2ban already installed") Log.info(self, "Fail2ban already installed") @@ -252,7 +256,7 @@ class WOStackController(CementBaseController): if pargs.clamav: Log.debug(self, "Setting apt_packages variable for ClamAV") if not WOAptGet.is_installed(self, 'clamav'): - apt_packages = apt_packages + WOVariables.wo_clamav + apt_packages = apt_packages + WOVar.wo_clamav else: Log.debug(self, "ClamAV already installed") Log.info(self, "ClamAV already installed") @@ -342,17 +346,17 @@ class WOStackController(CementBaseController): packages = packages + [["https://github.com/vrana/adminer/" "releases/download/v{0}" "/adminer-{0}.php" - .format(WOVariables.wo_adminer), + .format(WOVar.wo_adminer), "{0}22222/" "htdocs/db/adminer/index.php" - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), "Adminer"], ["https://raw.githubusercontent.com" "/vrana/adminer/master/designs/" "pepa-linha/adminer.css", "{0}22222/" "htdocs/db/adminer/adminer.css" - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), "Adminer theme"]] else: Log.debug(self, "Adminer already installed") @@ -379,7 +383,7 @@ class WOStackController(CementBaseController): os.path.isdir("/etc/netdata")): Log.debug( self, "Setting packages variable for Netdata") - if WOVariables.wo_distro == 'raspbian': + if WOVar.wo_distro == 'raspbian': packages = packages + [['https://my-netdata.io/' 'kickstart.sh', '/var/lib/wo/tmp/kickstart.sh', @@ -403,7 +407,7 @@ class WOStackController(CementBaseController): "/wordops-dashboard/" "releases/download/v{0}/" "wordops-dashboard.tar.gz" - .format(WOVariables.wo_dashboard), + .format(WOVar.wo_dashboard), "/var/lib/wo/tmp/wo-dashboard.tar.gz", "WordOps Dashboard"]] else: @@ -417,13 +421,26 @@ class WOStackController(CementBaseController): packages = packages + \ [["https://github.com/soerennb/" "extplorer/archive/v{0}.tar.gz" - .format(WOVariables.wo_extplorer), + .format(WOVar.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") + if pargs.ngxblocker: + if not os.path.isdir('/etc/nginx/bots.d'): + Log.debug(self, "Setting packages variable for ngxblocker") + packages = packages + \ + [["https://raw.githubusercontent.com/" + "mitchellkrogza/nginx-ultimate-bad-bot-blocker" + "/master/install-ngxblocker", + "/usr/local/sbin/install-ngxblocker", + "ngxblocker"]] + else: + Log.debug(self, "ngxblocker is already installed") + Log.info(self, "ngxblocker is already installed") + # UTILS if pargs.utils: Log.debug(self, "Setting packages variable for utils") @@ -432,25 +449,25 @@ class WOStackController(CementBaseController): "clean.php", "{0}22222/htdocs/cache/" "nginx/clean.php" - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), "clean.php"], ["https://raw.github.com/rlerdorf/" "opcache-status/master/opcache.php", "{0}22222/htdocs/cache/" "opcache/opcache.php" - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), "opcache.php"], ["https://raw.github.com/amnuts/" "opcache-gui/master/index.php", "{0}22222/htdocs/" "cache/opcache/opgui.php" - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), "Opgui"], ["https://raw.githubusercontent.com/" "mlazarov/ocp/master/ocp.php", "{0}22222/htdocs/cache/" "opcache/ocp.php" - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), "OCP.php"], ["https://github.com/jokkedk/webgrind/" "archive/master.tar.gz", @@ -558,27 +575,27 @@ class WOStackController(CementBaseController): if pargs.nginx: if WOAptGet.is_installed(self, 'nginx-custom'): Log.debug(self, "Removing apt_packages variable of Nginx") - apt_packages = apt_packages + WOVariables.wo_nginx + apt_packages = apt_packages + WOVar.wo_nginx # PHP 7.2 if pargs.php: Log.debug(self, "Removing apt_packages variable of PHP") if WOAptGet.is_installed(self, 'php7.2-fpm'): if not WOAptGet.is_installed(self, 'php7.3-fpm'): - apt_packages = apt_packages + WOVariables.wo_php + \ - WOVariables.wo_php_extra + apt_packages = apt_packages + WOVar.wo_php + \ + WOVar.wo_php_extra else: - apt_packages = apt_packages + WOVariables.wo_php + apt_packages = apt_packages + WOVar.wo_php # PHP7.3 if pargs.php73: Log.debug(self, "Removing apt_packages variable of PHP 7.3") if WOAptGet.is_installed(self, 'php7.3-fpm'): if not (WOAptGet.is_installed(self, 'php7.2-fpm')): - apt_packages = apt_packages + WOVariables.wo_php73 + \ - WOVariables.wo_php_extra + apt_packages = apt_packages + WOVar.wo_php73 + \ + WOVar.wo_php_extra else: - apt_packages = apt_packages + WOVariables.wo_php73 + apt_packages = apt_packages + WOVar.wo_php73 # REDIS if pargs.redis: @@ -599,19 +616,19 @@ class WOStackController(CementBaseController): Log.debug(self, "Removing apt_packages variable " "for MySQL Client") if WOShellExec.cmd_exec(self, "mysqladmin ping"): - apt_packages = apt_packages + WOVariables.wo_mysql_client + apt_packages = apt_packages + WOVar.wo_mysql_client # fail2ban if pargs.fail2ban: if WOAptGet.is_installed(self, 'fail2ban'): Log.debug(self, "Remove apt_packages variable of Fail2ban") - apt_packages = apt_packages + WOVariables.wo_fail2ban + apt_packages = apt_packages + WOVar.wo_fail2ban # ClamAV if pargs.clamav: Log.debug(self, "Setting apt_packages variable for ClamAV") if WOAptGet.is_installed(self, 'clamav'): - apt_packages = apt_packages + WOVariables.wo_clamav + apt_packages = apt_packages + WOVar.wo_clamav # sendmail if pargs.sendmail: @@ -640,10 +657,10 @@ class WOStackController(CementBaseController): # PHPMYADMIN if pargs.phpmyadmin: if os.path.isdir('{0}22222/htdocs/db/pma' - .format(WOVariables.wo_webroot)): + .format(WOVar.wo_webroot)): Log.debug(self, "Removing package of phpMyAdmin ") packages = packages + ['{0}22222/htdocs/db/pma' - .format(WOVariables.wo_webroot)] + .format(WOVar.wo_webroot)] # Composer if pargs.composer: Log.debug(self, "Removing package of Composer ") @@ -660,28 +677,28 @@ class WOStackController(CementBaseController): if pargs.phpredisadmin: Log.debug(self, "Removing package variable of phpRedisAdmin ") if os.path.isdir('{0}22222/htdocs/cache/redis' - .format(WOVariables.wo_webroot)): + .format(WOVar.wo_webroot)): packages = packages + ['{0}22222/htdocs/' 'cache/redis' - .format(WOVariables.wo_webroot)] + .format(WOVar.wo_webroot)] # ADMINER if pargs.adminer: if os.path.isdir('{0}22222/htdocs/db/adminer' - .format(WOVariables.wo_webroot)): + .format(WOVar.wo_webroot)): Log.debug(self, "Removing package variable of Adminer ") packages = packages + ['{0}22222/htdocs/db/adminer' - .format(WOVariables.wo_webroot)] + .format(WOVar.wo_webroot)] if pargs.utils: Log.debug(self, "Removing package variable of utils ") packages = packages + ['{0}22222/htdocs/php/webgrind/' - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), '{0}22222/htdocs/cache/opcache' - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), '{0}22222/htdocs/cache/nginx/' - 'clean.php'.format(WOVariables.wo_webroot), + 'clean.php'.format(WOVar.wo_webroot), '/usr/bin/pt-query-advisor', '{0}22222/htdocs/db/anemometer' - .format(WOVariables.wo_webroot)] + .format(WOVar.wo_webroot)] if pargs.netdata: Log.debug(self, "Removing Netdata") @@ -691,16 +708,16 @@ class WOStackController(CementBaseController): if pargs.dashboard: if (os.path.isfile('{0}22222/htdocs/index.php' - .format(WOVariables.wo_webroot)) or + .format(WOVar.wo_webroot)) or os.path.isfile('{0}22222/htdocs/index.html' - .format(WOVariables.wo_webroot))): + .format(WOVar.wo_webroot))): Log.debug(self, "Removing Wo-Dashboard") packages = packages + ['{0}22222/htdocs/assets' - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), '{0}22222/htdocs/index.php' - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), '{0}22222/htdocs/index.html' - .format(WOVariables.wo_webroot)] + .format(WOVar.wo_webroot)] if (packages) or (apt_packages): if (not pargs.force): @@ -722,7 +739,7 @@ class WOStackController(CementBaseController): # Netdata uninstaller if (set(['/var/lib/wo/tmp/' 'kickstart.sh']).issubset(set(packages))): - if WOVariables.wo_distro == 'Raspbian': + if WOVar.wo_distro == 'Raspbian': WOShellExec.cmd_exec(self, "bash /usr/" "libexec/netdata/" "netdata-uninstaller.sh -y -f") @@ -801,7 +818,7 @@ class WOStackController(CementBaseController): if pargs.nginx: if WOAptGet.is_installed(self, 'nginx-custom'): Log.debug(self, "Add Nginx to apt_packages list") - apt_packages = apt_packages + WOVariables.wo_nginx + apt_packages = apt_packages + WOVar.wo_nginx else: Log.info(self, "Nginx is not installed") @@ -810,20 +827,20 @@ class WOStackController(CementBaseController): Log.debug(self, "Add PHP to apt_packages list") if WOAptGet.is_installed(self, 'php7.2-fpm'): if not (WOAptGet.is_installed(self, 'php7.3-fpm')): - apt_packages = apt_packages + WOVariables.wo_php + \ - WOVariables.wo_php_extra + apt_packages = apt_packages + WOVar.wo_php + \ + WOVar.wo_php_extra else: - apt_packages = apt_packages + WOVariables.wo_php + apt_packages = apt_packages + WOVar.wo_php # PHP 7.3 if pargs.php73: Log.debug(self, "Removing apt_packages variable of PHP 7.3") if WOAptGet.is_installed(self, 'php7.3-fpm'): if not (WOAptGet.is_installed(self, 'php7.2-fpm')): - apt_packages = apt_packages + WOVariables.wo_php73 + \ - WOVariables.wo_php_extra + apt_packages = apt_packages + WOVar.wo_php73 + \ + WOVar.wo_php_extra else: - apt_packages = apt_packages + WOVariables.wo_php73 + apt_packages = apt_packages + WOVar.wo_php73 # REDIS if pargs.redis: @@ -848,19 +865,19 @@ class WOStackController(CementBaseController): if pargs.mysqlclient: if WOShellExec.cmd_exec(self, "mysqladmin ping"): Log.debug(self, "Add MySQL client to apt_packages list") - apt_packages = apt_packages + WOVariables.wo_mysql_client + apt_packages = apt_packages + WOVar.wo_mysql_client # fail2ban if pargs.fail2ban: if WOAptGet.is_installed(self, 'fail2ban'): Log.debug(self, "Add Fail2ban to apt_packages list") - apt_packages = apt_packages + WOVariables.wo_fail2ban + apt_packages = apt_packages + WOVar.wo_fail2ban # ClamAV if pargs.clamav: if WOAptGet.is_installed(self, 'clamav'): Log.debug(self, "Add ClamAV to apt_packages list") - apt_packages = apt_packages + WOVariables.wo_clamav + apt_packages = apt_packages + WOVar.wo_clamav # UFW if pargs.ufw: @@ -889,10 +906,10 @@ class WOStackController(CementBaseController): # PHPMYADMIN if pargs.phpmyadmin: if os.path.isdir('{0}22222/htdocs/db/pma' - .format(WOVariables.wo_webroot)): + .format(WOVar.wo_webroot)): Log.debug(self, "Removing package of phpMyAdmin ") packages = packages + ['{0}22222/htdocs/db/pma' - .format(WOVariables.wo_webroot)] + .format(WOVar.wo_webroot)] # Composer if pargs.composer: @@ -910,29 +927,29 @@ class WOStackController(CementBaseController): if pargs.phpredisadmin: Log.debug(self, "Removing package variable of phpRedisAdmin ") if os.path.isdir('{0}22222/htdocs/cache/redis' - .format(WOVariables.wo_webroot)): + .format(WOVar.wo_webroot)): packages = packages + ['{0}22222/htdocs/' 'cache/redis' - .format(WOVariables.wo_webroot)] + .format(WOVar.wo_webroot)] # ADMINER if pargs.adminer: if os.path.isdir('{0}22222/htdocs/db/adminer' - .format(WOVariables.wo_webroot)): + .format(WOVar.wo_webroot)): Log.debug(self, "Removing package variable of Adminer ") packages = packages + ['{0}22222/htdocs/db/adminer' - .format(WOVariables.wo_webroot)] + .format(WOVar.wo_webroot)] # utils if pargs.utils: Log.debug(self, "Purge package variable utils") packages = packages + ['{0}22222/htdocs/php/webgrind/' - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), '{0}22222/htdocs/cache/opcache' - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), '{0}22222/htdocs/cache/nginx/' - 'clean.php'.format(WOVariables.wo_webroot), + 'clean.php'.format(WOVar.wo_webroot), '/usr/bin/pt-query-advisor', '{0}22222/htdocs/db/anemometer' - .format(WOVariables.wo_webroot) + .format(WOVar.wo_webroot) ] if pargs.netdata: @@ -944,9 +961,9 @@ class WOStackController(CementBaseController): if pargs.dashboard: Log.debug(self, "Removing Wo-Dashboard") packages = packages + ['{0}22222/htdocs/assets/' - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), '{0}22222/htdocs/index.php' - .format(WOVariables.wo_webroot)] + .format(WOVar.wo_webroot)] if (packages) or (apt_packages): if (not pargs.force): @@ -974,7 +991,7 @@ class WOStackController(CementBaseController): # Netdata uninstaller if (set(['/var/lib/wo/tmp/' 'kickstart.sh']).issubset(set(packages))): - if WOVariables.wo_distro == 'Raspbian': + if WOVar.wo_distro == 'Raspbian': WOShellExec.cmd_exec(self, "bash /usr/" "libexec/netdata/netdata-" "uninstaller.sh -y -f", diff --git a/wo/cli/plugins/stack_migrate.py b/wo/cli/plugins/stack_migrate.py index 7b64b37..20bf585 100644 --- a/wo/cli/plugins/stack_migrate.py +++ b/wo/cli/plugins/stack_migrate.py @@ -9,7 +9,7 @@ from wo.core.aptget import WOAptGet from wo.core.logging import Log from wo.core.mysql import WOMysql from wo.core.shellexec import WOShellExec -from wo.core.variables import WOVariables +from wo.core.variables import WOVar class WOStackMigrateController(CementBaseController): @@ -29,8 +29,8 @@ class WOStackMigrateController(CementBaseController): # Backup all database WOMysql.backupAll(self) - if not WOVariables.wo_distro == 'raspbian': - if (not WOVariables.wo_platform_codename == 'jessie'): + if not WOVar.wo_distro == 'raspbian': + if (not WOVar.wo_platform_codename == 'jessie'): wo_mysql = ["mariadb-server", "percona-toolkit", "python3-mysqldb", "mariadb-backup"] else: @@ -49,9 +49,9 @@ class WOStackMigrateController(CementBaseController): 'MariaDB.pref', 'w') as mysql_pref_file: mysql_pref_file.write(mysql_pref) - WORepo.add(self, repo_url=WOVariables.wo_mysql_repo) + WORepo.add(self, repo_url=WOVar.wo_mysql_repo) Log.debug(self, 'Adding key for {0}' - .format(WOVariables.wo_mysql_repo)) + .format(WOVar.wo_mysql_repo)) WORepo.add_key(self, '0xcbcb082a1bb943db', keyserver="keyserver.ubuntu.com") @@ -104,7 +104,7 @@ class WOStackMigrateController(CementBaseController): if ((not self.app.pargs.mariadb)): self.app.args.print_help() if self.app.pargs.mariadb: - if WOVariables.wo_mysql_host != "localhost": + if WOVar.wo_mysql_host != "localhost": Log.error( self, "Remote MySQL server in use, skipping local install") diff --git a/wo/cli/plugins/stack_pref.py b/wo/cli/plugins/stack_pref.py index 521e2d3..2bcce47 100644 --- a/wo/cli/plugins/stack_pref.py +++ b/wo/cli/plugins/stack_pref.py @@ -7,7 +7,6 @@ import string import psutil import requests - from wo.cli.plugins.site_functions import * from wo.cli.plugins.stack_services import WOStackStatusController from wo.core.apt_repo import WORepo @@ -19,11 +18,12 @@ from wo.core.fileutils import WOFileUtils from wo.core.git import WOGit from wo.core.logging import Log from wo.core.mysql import WOMysql +from wo.core.nginxhashbucket import hashbucket from wo.core.services import WOService from wo.core.shellexec import CommandExecutionError, WOShellExec from wo.core.sslutils import SSL from wo.core.template import WOTemplate -from wo.core.variables import WOVariables +from wo.core.variables import WOVar def pre_pref(self, apt_packages): @@ -31,7 +31,7 @@ def pre_pref(self, apt_packages): if ("mariadb-server" in apt_packages or "mariadb-client" in apt_packages): # add mariadb repository excepted on raspbian and ubuntu 19.04 - if (not WOVariables.wo_distro == 'raspbian'): + if (not WOVar.wo_distro == 'raspbian'): Log.info(self, "Adding repository for MySQL, please wait...") mysql_pref = ("Package: *\nPin: origin " "sfo1.mirrors.digitalocean.com" @@ -39,7 +39,7 @@ def pre_pref(self, apt_packages): with open('/etc/apt/preferences.d/' 'MariaDB.pref', 'w') as mysql_pref_file: mysql_pref_file.write(mysql_pref) - WORepo.add(self, repo_url=WOVariables.wo_mysql_repo) + WORepo.add(self, repo_url=WOVar.wo_mysql_repo) WORepo.add_key(self, '0xcbcb082a1bb943db', keyserver='keys.gnupg.net') WORepo.add_key(self, '0xF1656F24C74CD1D8', @@ -49,8 +49,8 @@ def pre_pref(self, apt_packages): chars = ''.join(random.sample(string.ascii_letters, 24)) # configure MySQL non-interactive install - if ((WOVariables.wo_distro == 'raspbian') and - (WOVariables.wo_platform_codename == 'stretch')): + if ((WOVar.wo_distro == 'raspbian') and + (WOVar.wo_platform_codename == 'stretch')): mariadb_ver = '10.1' else: mariadb_ver = '10.3' @@ -105,26 +105,26 @@ def pre_pref(self, apt_packages): WOFileUtils.chmod(self, "/etc/mysql/conf.d/my.cnf", 0o600) # add nginx repository - if set(WOVariables.wo_nginx).issubset(set(apt_packages)): + if set(WOVar.wo_nginx).issubset(set(apt_packages)): Log.info(self, "Adding repository for NGINX, please wait...") - if (WOVariables.wo_distro == 'ubuntu'): - WORepo.add(self, ppa=WOVariables.wo_nginx_repo) + if (WOVar.wo_distro == 'ubuntu'): + WORepo.add(self, ppa=WOVar.wo_nginx_repo) Log.debug(self, 'Adding ppa for Nginx') else: - WORepo.add(self, repo_url=WOVariables.wo_nginx_repo) + WORepo.add(self, repo_url=WOVar.wo_nginx_repo) Log.debug(self, 'Adding repository for Nginx') - WORepo.add_key(self, WOVariables.wo_nginx_key) + WORepo.add_key(self, WOVar.wo_nginx_key) # add php repository - if (set(WOVariables.wo_php73).issubset(set(apt_packages)) or - set(WOVariables.wo_php).issubset(set(apt_packages))): + if (set(WOVar.wo_php73).issubset(set(apt_packages)) or + set(WOVar.wo_php).issubset(set(apt_packages))): Log.info(self, "Adding repository for PHP, please wait...") - if (WOVariables.wo_distro == 'ubuntu'): + if (WOVar.wo_distro == 'ubuntu'): Log.debug(self, 'Adding ppa for PHP') - WORepo.add(self, ppa=WOVariables.wo_php_repo) + WORepo.add(self, ppa=WOVar.wo_php_repo) else: # Add repository for php - if (WOVariables.wo_platform_codename == 'buster'): + if (WOVar.wo_platform_codename == 'buster'): php_pref = ("Package: *\nPin: origin " "packages.sury.org" "\nPin-Priority: 1000\n") @@ -132,22 +132,22 @@ def pre_pref(self, apt_packages): 'PHP.pref', 'w') as php_pref_file: php_pref_file.write(php_pref) Log.debug(self, 'Adding repo_url of php for debian') - WORepo.add(self, repo_url=WOVariables.wo_php_repo) + WORepo.add(self, repo_url=WOVar.wo_php_repo) Log.debug(self, 'Adding deb.sury GPG key') - WORepo.add_key(self, WOVariables.wo_php_key) + WORepo.add_key(self, WOVar.wo_php_key) # add redis repository - if set(WOVariables.wo_redis).issubset(set(apt_packages)): + if set(WOVar.wo_redis).issubset(set(apt_packages)): Log.info(self, "Adding repository for Redis, please wait...") - if WOVariables.wo_distro == 'ubuntu': + if WOVar.wo_distro == 'ubuntu': Log.debug(self, 'Adding ppa for redis') - WORepo.add(self, ppa=WOVariables.wo_redis_repo) + WORepo.add(self, ppa=WOVar.wo_redis_repo) def post_pref(self, apt_packages, packages, upgrade=False): """Post activity after installation of packages""" if (apt_packages): # Nginx configuration - if set(WOVariables.wo_nginx).issubset(set(apt_packages)): + if set(WOVar.wo_nginx).issubset(set(apt_packages)): Log.info(self, "Applying Nginx configuration templates") # Nginx main configuration ngxcnf = '/etc/nginx/conf.d' @@ -305,7 +305,7 @@ def post_pref(self, apt_packages, packages, upgrade=False): with open("/etc/nginx/common/release", "w") as release_file: release_file.write("v{0}" - .format(WOVariables.wo_version)) + .format(WOVar.wo_version)) release_file.close() # Following files should not be overwrited @@ -458,7 +458,7 @@ def post_pref(self, apt_packages, packages, upgrade=False): "on https://{0}:22222 " "or https://{1}:22222" .format(server_ip.text, - WOVariables.wo_fqdn)]) + WOVar.wo_fqdn)]) if not os.path.isfile("/opt/cf-update.sh"): data = dict() @@ -471,21 +471,26 @@ def post_pref(self, apt_packages, packages, upgrade=False): comment='Cloudflare IP refresh cronjob ' 'added by WordOps') - if upgrade: - try: - 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 - WOGit.add(self, - ["/etc/nginx"], msg="Adding Nginx into Git") - WOService.restart_service(self, 'nginx') + if not WOService.restart_service(self, 'nginx'): + try: + hashbucket(self) + WOService.restart_service(self, 'nginx') + except Exception: + Log.warn( + self, "increasing nginx server_names_hash_bucket_size " + "do not fix the issue") + Log.info(self, "Rolling back to previous configuration") + WOGit.rollback(self, ["/etc/nginx"]) + if not WOService.restart_service(self, 'nginx'): + Log.error( + self, "There is an error in Nginx configuration.\n" + "Use the command nginx -t to identify " + "the cause of this issue", False) + else: + WOGit.add(self, ["/etc/nginx"], msg="Adding Nginx into Git") - if set(WOVariables.wo_php).issubset(set(apt_packages)): + if set(WOVar.wo_php).issubset(set(apt_packages)): WOGit.add(self, ["/etc/php"], msg="Adding PHP into Git") Log.info(self, "Configuring php7.2-fpm") ngxroot = '/var/www/' @@ -509,7 +514,7 @@ def post_pref(self, apt_packages, packages, upgrade=False): config['PHP']['max_execution_time'] = '300' config['PHP']['max_input_time'] = '300' config['PHP']['max_input_vars'] = '20000' - config['Date']['date.timezone'] = WOVariables.wo_timezone + config['Date']['date.timezone'] = WOVar.wo_timezone config['opcache']['opcache.enable'] = '1' config['opcache']['opcache.interned_strings_buffer'] = '8' config['opcache']['opcache.max_accelerated_files'] = '10000' @@ -615,11 +620,14 @@ def post_pref(self, apt_packages, packages, upgrade=False): 'www-data', 'www-data', recursive=True) - WOGit.add(self, ["/etc/php"], msg="Adding PHP into Git") - WOService.restart_service(self, 'php7.2-fpm') + # check service restart or rollback configuration + if not WOService.restart_service(self, 'php7.2-fpm'): + WOGit.rollback(self, ["/etc/php"], msg="Rollback PHP") + else: + WOGit.add(self, ["/etc/php"], msg="Adding PHP into Git") # PHP7.3 configuration - if set(WOVariables.wo_php73).issubset(set(apt_packages)): + if set(WOVar.wo_php73).issubset(set(apt_packages)): WOGit.add(self, ["/etc/php"], msg="Adding PHP into Git") Log.info(self, "Configuring php7.3-fpm") ngxroot = '/var/www/' @@ -643,7 +651,7 @@ def post_pref(self, apt_packages, packages, upgrade=False): config['PHP']['max_execution_time'] = '300' config['PHP']['max_input_time'] = '300' config['PHP']['max_input_vars'] = '20000' - config['Date']['date.timezone'] = WOVariables.wo_timezone + config['Date']['date.timezone'] = WOVar.wo_timezone config['opcache']['opcache.enable'] = '1' config['opcache']['opcache.interned_strings_buffer'] = '8' config['opcache']['opcache.max_accelerated_files'] = '10000' @@ -748,9 +756,11 @@ def post_pref(self, apt_packages, packages, upgrade=False): .format(ngxroot), 'www-data', 'www-data', recursive=True) - - WOGit.add(self, ["/etc/php"], msg="Adding PHP into Git") - WOService.restart_service(self, 'php7.3-fpm') + # check service restart or rollback configuration + if not WOService.restart_service(self, 'php7.3-fpm'): + WOGit.rollback(self, ["/etc/php"], msg="Rollback PHP") + else: + WOGit.add(self, ["/etc/php"], msg="Adding PHP into Git") # create mysql config if it doesn't exist if "mariadb-server" in apt_packages: @@ -807,7 +817,7 @@ def post_pref(self, apt_packages, packages, upgrade=False): WOGit.add(self, ["/etc/mysql"], msg="Adding MySQL into Git") # create fail2ban configuration files - if set(WOVariables.wo_fail2ban).issubset(set(apt_packages)): + if set(WOVar.wo_fail2ban).issubset(set(apt_packages)): WOGit.add(self, ["/etc/fail2ban"], msg="Adding Fail2ban into Git") if not os.path.isfile("/etc/fail2ban/jail.d/custom.conf"): @@ -829,9 +839,12 @@ def post_pref(self, apt_packages, packages, upgrade=False): 'fail2ban-forbidden.mustache', data, overwrite=False) - WOGit.add(self, ["/etc/fail2ban"], - msg="Adding Fail2ban into Git") - WOService.reload_service(self, 'fail2ban') + if not WOService.reload_service(self, 'fail2ban'): + WOGit.rollback( + self, ['/etc/fail2ban'], msg="Rollback f2b config") + else: + WOGit.add(self, ["/etc/fail2ban"], + msg="Adding Fail2ban into Git") # Proftpd configuration if "proftpd-basic" in apt_packages: @@ -891,9 +904,12 @@ def post_pref(self, apt_packages, packages, upgrade=False): f2bproftpd.write("\n\n[proftpd]\nenabled = true\n") WOService.reload_service(self, 'fail2ban') - WOGit.add(self, ["/etc/proftpd"], - msg="Adding ProFTPd into Git") - WOService.reload_service(self, 'proftpd') + if not WOService.reload_service(self, 'proftpd'): + WOGit.rollback(self, ["/etc/proftpd"], + msg="Rollback ProFTPd") + else: + WOGit.add(self, ["/etc/proftpd"], + msg="Adding ProFTPd into Git") if "ufw" in apt_packages: # check if ufw is already enabled @@ -991,12 +1007,13 @@ def post_pref(self, apt_packages, packages, upgrade=False): WOFileUtils.chown(self, '/etc/redis/redis.conf', 'redis', 'redis', recursive=False) Log.valide(self, "Tuning Redis configuration") - WOGit.add(self, ["/etc/redis"], - msg="Adding Redis into Git") - WOService.restart_service(self, 'redis-server') + if not WOService.restart_service(self, 'redis-server'): + WOGit.rollback(self, ["/etc/redis"], msg="Rollback Redis") + else: + WOGit.add(self, ["/etc/redis"], msg="Adding Redis into Git") # ClamAV configuration - if set(WOVariables.wo_clamav).issubset(set(apt_packages)): + if set(WOVar.wo_clamav).issubset(set(apt_packages)): Log.debug(self, "Setting up freshclam cronjob") if not os.path.isfile("/opt/freshclam.sh"): data = dict() @@ -1024,26 +1041,26 @@ def post_pref(self, apt_packages, packages, upgrade=False): Log.debug(self, 'Extracting file /var/lib/wo/tmp/pma.tar.gz to ' 'location /var/lib/wo/tmp/') if not os.path.exists('{0}22222/htdocs/db' - .format(WOVariables.wo_webroot)): + .format(WOVar.wo_webroot)): Log.debug(self, "Creating new directory " "{0}22222/htdocs/db" - .format(WOVariables.wo_webroot)) + .format(WOVar.wo_webroot)) os.makedirs('{0}22222/htdocs/db' - .format(WOVariables.wo_webroot)) + .format(WOVar.wo_webroot)) if not os.path.exists('{0}22222/htdocs/db/pma/' - .format(WOVariables.wo_webroot)): + .format(WOVar.wo_webroot)): shutil.move('/var/lib/wo/tmp/phpmyadmin-STABLE/', '{0}22222/htdocs/db/pma/' - .format(WOVariables.wo_webroot)) + .format(WOVar.wo_webroot)) shutil.copyfile('{0}22222/htdocs/db/pma' '/config.sample.inc.php' - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), '{0}22222/htdocs/db/pma/config.inc.php' - .format(WOVariables.wo_webroot)) + .format(WOVar.wo_webroot)) Log.debug(self, 'Setting Blowfish Secret Key ' 'FOR COOKIE AUTH to ' '{0}22222/htdocs/db/pma/config.inc.php file ' - .format(WOVariables.wo_webroot)) + .format(WOVar.wo_webroot)) blowfish_key = ''.join([random.choice (string.ascii_letters + string.digits) @@ -1051,7 +1068,7 @@ def post_pref(self, apt_packages, packages, upgrade=False): WOFileUtils.searchreplace(self, '{0}22222/htdocs/db/pma' '/config.inc.php' - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), "$cfg[\'blowfish_secret\']" " = \'\';", "$cfg[\'blowfish_secret\']" @@ -1059,21 +1076,21 @@ def post_pref(self, apt_packages, packages, upgrade=False): .format(blowfish_key)) Log.debug(self, 'Setting HOST Server For Mysql to ' '{0}22222/htdocs/db/pma/config.inc.php file ' - .format(WOVariables.wo_webroot)) + .format(WOVar.wo_webroot)) WOFileUtils.searchreplace(self, '{0}22222/htdocs/db/pma' '/config.inc.php' - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), "$cfg[\'Servers\'][$i][\'host\']" " = \'localhost\';", "$cfg" "[\'Servers\'][$i][\'host\'] " "= \'{0}\';" - .format(WOVariables.wo_mysql_host)) + .format(WOVar.wo_mysql_host)) Log.debug(self, 'Setting Privileges of webroot permission to ' '{0}22222/htdocs/db/pma file ' - .format(WOVariables.wo_webroot)) + .format(WOVar.wo_webroot)) WOFileUtils.chown(self, '{0}22222/htdocs' - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), 'www-data', 'www-data', recursive=True) @@ -1099,19 +1116,19 @@ def post_pref(self, apt_packages, packages, upgrade=False): "/var/www/22222/htdocs/db/pma/") WOFileUtils.chown( self, '{0}22222/htdocs/db/pma' - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), 'www-data', 'www-data', recursive=True) Log.valide(self, "Updating phpMyAdmin") if not os.path.exists('{0}22222/htdocs/cache/' 'redis/phpRedisAdmin' - .format(WOVariables.wo_webroot)): + .format(WOVar.wo_webroot)): Log.debug(self, "Creating new directory " "{0}22222/htdocs/cache/redis" - .format(WOVariables.wo_webroot)) + .format(WOVar.wo_webroot)) os.makedirs('{0}22222/htdocs/cache/redis/phpRedisAdmin' - .format(WOVariables.wo_webroot)) + .format(WOVar.wo_webroot)) if not os.path.isfile('/var/www/22222/htdocs/cache/redis/' 'phpRedisAdmin/composer.lock'): WOShellExec.cmd_exec( @@ -1120,7 +1137,7 @@ def post_pref(self, apt_packages, packages, upgrade=False): "erik-dubbelboer/php-redis-admin " "/var/www/22222/htdocs/cache/redis/phpRedisAdmin") WOFileUtils.chown(self, '{0}22222/htdocs' - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), 'www-data', 'www-data', recursive=True) @@ -1186,25 +1203,25 @@ def post_pref(self, apt_packages, packages, upgrade=False): for x in packages): Log.debug(self, "Extracting wo-dashboard.tar.gz " "to location {0}22222/htdocs/" - .format(WOVariables.wo_webroot)) + .format(WOVar.wo_webroot)) WOExtract.extract(self, '/var/lib/wo/tmp/' 'wo-dashboard.tar.gz', '{0}22222/htdocs' - .format(WOVariables.wo_webroot)) + .format(WOVar.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.html" - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), "eth0", "{0}".format(wo_wan)) Log.debug(self, "Setting Privileges to " "{0}22222/htdocs" - .format(WOVariables.wo_webroot)) + .format(WOVar.wo_webroot)) WOFileUtils.chown(self, '{0}22222/htdocs' - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), 'www-data', 'www-data', recursive=True) @@ -1214,18 +1231,18 @@ def post_pref(self, apt_packages, packages, upgrade=False): for x in packages): Log.debug(self, "Extracting extplorer.tar.gz " "to location {0}22222/htdocs/files" - .format(WOVariables.wo_webroot)) + .format(WOVar.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), + .format(WOVar.wo_extplorer), '{0}22222/htdocs/files' - .format(WOVariables.wo_webroot)) + .format(WOVar.wo_webroot)) Log.debug(self, "Setting Privileges to " "{0}22222/htdocs/files" - .format(WOVariables.wo_webroot)) + .format(WOVar.wo_webroot)) WOFileUtils.chown(self, '{0}22222/htdocs' - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), 'www-data', 'www-data', recursive=True) @@ -1239,41 +1256,41 @@ def post_pref(self, apt_packages, packages, upgrade=False): self, '/var/lib/wo/tmp/webgrind.tar.gz', '/var/lib/wo/tmp/') if not os.path.exists('{0}22222/htdocs/php' - .format(WOVariables.wo_webroot)): + .format(WOVar.wo_webroot)): Log.debug(self, "Creating directroy " "{0}22222/htdocs/php" - .format(WOVariables.wo_webroot)) + .format(WOVar.wo_webroot)) os.makedirs('{0}22222/htdocs/php' - .format(WOVariables.wo_webroot)) + .format(WOVar.wo_webroot)) if not os.path.exists('{0}22222/htdocs/php/webgrind' - .format(WOVariables.wo_webroot)): + .format(WOVar.wo_webroot)): shutil.move('/var/lib/wo/tmp/webgrind-master/', '{0}22222/htdocs/php/webgrind' - .format(WOVariables.wo_webroot)) + .format(WOVar.wo_webroot)) WOFileUtils.searchreplace( self, "{0}22222/htdocs/php/webgrind/" "config.php" - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), "/usr/local/bin/dot", "/usr/bin/dot") WOFileUtils.searchreplace( self, "{0}22222/htdocs/php/webgrind/" "config.php" - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), "Europe/Copenhagen", - WOVariables.wo_timezone) + WOVar.wo_timezone) WOFileUtils.searchreplace( self, "{0}22222/htdocs/php/webgrind/" "config.php" - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), "90", "100") Log.debug(self, "Setting Privileges of webroot permission to " "{0}22222/htdocs/php/webgrind/ file " - .format(WOVariables.wo_webroot)) + .format(WOVar.wo_webroot)) WOFileUtils.chown(self, '{0}22222/htdocs' - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), 'www-data', 'www-data', recursive=True) @@ -1286,20 +1303,20 @@ def post_pref(self, apt_packages, packages, upgrade=False): self, '/var/lib/wo/tmp/anemometer.tar.gz', '/var/lib/wo/tmp/') if not os.path.exists('{0}22222/htdocs/db/' - .format(WOVariables.wo_webroot)): + .format(WOVar.wo_webroot)): Log.debug(self, "Creating directory") os.makedirs('{0}22222/htdocs/db/' - .format(WOVariables.wo_webroot)) + .format(WOVar.wo_webroot)) if not os.path.exists('{0}22222/htdocs/db/anemometer' - .format(WOVariables.wo_webroot)): + .format(WOVar.wo_webroot)): shutil.move('/var/lib/wo/tmp/Anemometer-master', '{0}22222/htdocs/db/anemometer' - .format(WOVariables.wo_webroot)) + .format(WOVar.wo_webroot)) chars = ''.join(random.sample(string.ascii_letters, 8)) try: WOShellExec.cmd_exec(self, 'mysql < {0}22222/htdocs/db' '/anemometer/install.sql' - .format(WOVariables.wo_webroot)) + .format(WOVar.wo_webroot)) except Exception as e: Log.debug(self, "{0}".format(e)) Log.error(self, "failed to configure Anemometer", @@ -1326,14 +1343,23 @@ def post_pref(self, apt_packages, packages, upgrade=False): # Custom Anemometer configuration Log.debug(self, "configration Anemometer") - data = dict(host=WOVariables.wo_mysql_host, port='3306', + data = dict(host=WOVar.wo_mysql_host, port='3306', user='anemometer', password=chars) WOTemplate.deploy(self, '{0}22222/htdocs/db/anemometer' '/conf/config.inc.php' - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), 'anemometer.mustache', data) # 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) + + # ngxblocker + if any('/usr/local/sbin/install-ngxblocker' == x[1] + for x in packages): + WOFileUtils.chmod( + self, "/usr/local/sbin/install-ngxblocker", 0o700) + WOShellExec.cmd_exec(self, '/usr/local/sbin/install-ngxblocker -x') + WOFileUtils.chmod( + self, "/usr/local/sbin/update-ngxblocker", 0o700) diff --git a/wo/cli/plugins/stack_services.py b/wo/cli/plugins/stack_services.py index 26408f6..84598e4 100644 --- a/wo/cli/plugins/stack_services.py +++ b/wo/cli/plugins/stack_services.py @@ -6,7 +6,7 @@ from cement.core.controller import CementBaseController, expose from wo.core.aptget import WOAptGet from wo.core.logging import Log from wo.core.services import WOService -from wo.core.variables import WOVariables +from wo.core.variables import WOVar class WOStackStatusController(CementBaseController): @@ -57,8 +57,8 @@ class WOStackStatusController(CementBaseController): Log.info(self, "PHP7.3-FPM is not installed") if pargs.mysql: - if ((WOVariables.wo_mysql_host == "localhost") or - (WOVariables.wo_mysql_host == "127.0.0.1")): + if ((WOVar.wo_mysql_host == "localhost") or + (WOVar.wo_mysql_host == "127.0.0.1")): if (WOAptGet.is_installed(self, 'mysql-server') or WOAptGet.is_installed(self, 'percona-server-server-5.6') or WOAptGet.is_installed(self, 'mariadb-server')): @@ -144,8 +144,8 @@ class WOStackStatusController(CementBaseController): # mysql if pargs.mysql: - if ((WOVariables.wo_mysql_host == "localhost") or - (WOVariables.wo_mysql_host == "127.0.0.1")): + if ((WOVar.wo_mysql_host == "localhost") or + (WOVar.wo_mysql_host == "127.0.0.1")): if (WOAptGet.is_installed(self, 'mysql-server') or WOAptGet.is_installed(self, 'percona-server-server-5.6') or WOAptGet.is_installed(self, 'mariadb-server')): @@ -230,8 +230,8 @@ class WOStackStatusController(CementBaseController): Log.info(self, "PHP7.3-FPM is not installed") if pargs.mysql: - if ((WOVariables.wo_mysql_host == "localhost") or - (WOVariables.wo_mysql_host == "127.0.0.1")): + if ((WOVar.wo_mysql_host == "localhost") or + (WOVar.wo_mysql_host == "127.0.0.1")): if ((WOAptGet.is_installed(self, 'mysql-server') or WOAptGet.is_installed(self, 'percona-server-server-5.6') or @@ -316,8 +316,8 @@ class WOStackStatusController(CementBaseController): Log.info(self, "PHP7.3-FPM is not installed") if pargs.mysql: - if ((WOVariables.wo_mysql_host == "localhost") or - (WOVariables.wo_mysql_host == "127.0.0.1")): + if ((WOVar.wo_mysql_host == "localhost") or + (WOVar.wo_mysql_host == "127.0.0.1")): if (WOAptGet.is_installed(self, 'mysql-server') or WOAptGet.is_installed(self, 'percona-server-server-5.6') or WOAptGet.is_installed(self, 'mariadb-server')): @@ -401,8 +401,8 @@ class WOStackStatusController(CementBaseController): Log.info(self, "PHP7.3-FPM is not installed") if pargs.mysql: - if ((WOVariables.wo_mysql_host == "localhost") or - (WOVariables.wo_mysql_host == "127.0.0.1")): + if ((WOVar.wo_mysql_host == "localhost") or + (WOVar.wo_mysql_host == "127.0.0.1")): if (WOAptGet.is_installed(self, 'mysql-server') or WOAptGet.is_installed(self, 'percona-server-server-5.6') or WOAptGet.is_installed(self, 'mariadb-server')): diff --git a/wo/cli/plugins/stack_upgrade.py b/wo/cli/plugins/stack_upgrade.py index fe4eeca..136aeaf 100644 --- a/wo/cli/plugins/stack_upgrade.py +++ b/wo/cli/plugins/stack_upgrade.py @@ -12,7 +12,7 @@ from wo.core.fileutils import WOFileUtils from wo.core.logging import Log from wo.core.services import WOService from wo.core.shellexec import WOShellExec -from wo.core.variables import WOVariables +from wo.core.variables import WOVar class WOStackUpgradeController(CementBaseController): @@ -92,27 +92,31 @@ class WOStackUpgradeController(CementBaseController): if pargs.nginx: if WOAptGet.is_installed(self, 'nginx-custom'): - apt_packages = apt_packages + WOVariables.wo_nginx + apt_packages = apt_packages + WOVar.wo_nginx else: - Log.info(self, "Nginx Stable is not already installed") + if os.path.isfile(self, '/usr/sbin/nginx'): + Log.info(self, "Updating Nginx templates") + post_pref(self, WOVar.wo_nginx, []) + else: + Log.info(self, "Nginx Stable is not already installed") if pargs.php: if WOAptGet.is_installed(self, 'php7.2-fpm'): if not WOAptGet.is_installed(self, 'php7.3-fpm'): - apt_packages = apt_packages + WOVariables.wo_php + \ - WOVariables.wo_php_extra + apt_packages = apt_packages + WOVar.wo_php + \ + WOVar.wo_php_extra else: - apt_packages = apt_packages + WOVariables.wo_php + apt_packages = apt_packages + WOVar.wo_php else: Log.info(self, "PHP 7.2 is not installed") if pargs.php73: if WOAptGet.is_installed(self, 'php7.3-fpm'): if not WOAptGet.is_installed(self, 'php7.2-fpm'): - apt_packages = apt_packages + WOVariables.wo_php73 + \ - WOVariables.wo_php_extra + apt_packages = apt_packages + WOVar.wo_php73 + \ + WOVar.wo_php_extra else: - apt_packages = apt_packages + WOVariables.wo_php73 + apt_packages = apt_packages + WOVar.wo_php73 else: Log.info(self, "PHP 7.3 is not installed") @@ -133,7 +137,7 @@ class WOStackUpgradeController(CementBaseController): packages = packages + [["https://github.com/wp-cli/wp-cli/" "releases/download/v{0}/" "wp-cli-{0}.phar" - "".format(WOVariables.wo_wp_cli), + "".format(WOVar.wo_wp_cli), "/usr/local/bin/wp", "WP-CLI"]] else: @@ -153,7 +157,7 @@ class WOStackUpgradeController(CementBaseController): packages = packages + \ [["https://github.com/WordOps/wordops-dashboard/" "releases/download/v{0}/wordops-dashboard.tar.gz" - .format(WOVariables.wo_dashboard), + .format(WOVar.wo_dashboard), "/var/lib/wo/tmp/wo-dashboard.tar.gz", "WordOps Dashboard"]] @@ -164,7 +168,7 @@ class WOStackUpgradeController(CementBaseController): "/phpMyAdmin/{0}/" "phpMyAdmin-{0}-" "all-languages" - ".tar.gz".format(WOVariables.wo_phpmyadmin), + ".tar.gz".format(WOVar.wo_phpmyadmin), "/var/lib/wo/tmp/pma.tar.gz", "PHPMyAdmin"]] else: @@ -205,7 +209,7 @@ class WOStackUpgradeController(CementBaseController): # additional pre_pref if ["nginx-custom"] in apt_packages: - pre_pref(self, WOVariables.wo_nginx) + pre_pref(self, WOVar.wo_nginx) if ["php7.2-fpm"] in apt_packages: WOAptGet.remove(self, ['php7.2-fpm'], auto=False, purge=True) @@ -215,8 +219,8 @@ class WOStackUpgradeController(CementBaseController): # check if nginx upgrade is blocked if os.path.isfile( '/etc/apt/preferences.d/nginx-block'): - apt_packages.remove(WOVariables.wo_nginx) - post_pref(self, WOVariables.wo_nginx, [], True) + apt_packages.remove(WOVar.wo_nginx) + post_pref(self, WOVar.wo_nginx, [], True) # upgrade packages WOAptGet.install(self, apt_packages) Log.valide(self, "Upgrading APT Packages") @@ -265,7 +269,7 @@ class WOStackUpgradeController(CementBaseController): "/wordops-dashboard/" "releases/download/v{0}/" "wordops-dashboard.tar.gz" - .format(WOVariables.wo_dashboard), + .format(WOVar.wo_dashboard), "/var/lib/wo/tmp/wo-dashboard.tar.gz", "WordOps Dashboard"]]) @@ -286,20 +290,20 @@ class WOStackUpgradeController(CementBaseController): '/var/lib/wo/tmp/') shutil.copyfile(('{0}22222/htdocs/db/pma' '/config.inc.php' - .format(WOVariables.wo_webroot)), + .format(WOVar.wo_webroot)), ('/var/lib/wo/tmp/phpMyAdmin-{0}' '-all-languages/config.inc.php' - .format(WOVariables.wo_phpmyadmin)) + .format(WOVar.wo_phpmyadmin)) ) WOFileUtils.rm(self, '{0}22222/htdocs/db/pma' - .format(WOVariables.wo_webroot)) + .format(WOVar.wo_webroot)) shutil.move('/var/lib/wo/tmp/phpMyAdmin-{0}' '-all-languages/' - .format(WOVariables.wo_phpmyadmin), + .format(WOVar.wo_phpmyadmin), '{0}22222/htdocs/db/pma/' - .format(WOVariables.wo_webroot)) + .format(WOVar.wo_webroot)) WOFileUtils.chown(self, "{0}22222/htdocs" - .format(WOVariables.wo_webroot), + .format(WOVar.wo_webroot), 'www-data', 'www-data', recursive=True) Log.valide(self, "Upgrading phpMyAdmin") diff --git a/wo/cli/templates/cf-update.mustache b/wo/cli/templates/cf-update.mustache index 562b451..60739a1 100644 --- a/wo/cli/templates/cf-update.mustache +++ b/wo/cli/templates/cf-update.mustache @@ -5,19 +5,21 @@ 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 +if [ -d /etc/nginx/conf.d ]; then + 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 + nginx -t && service nginx reload +fi diff --git a/wo/cli/templates/sshd.mustache b/wo/cli/templates/sshd.mustache index f05b6c8..5c5383b 100644 --- a/wo/cli/templates/sshd.mustache +++ b/wo/cli/templates/sshd.mustache @@ -37,7 +37,7 @@ AcceptEnv LANG LC_* LogLevel VERBOSE # Log sftp level file access (read/write/etc.) that would not be easily logged otherwise. -Subsystem sftp /usr/lib/ssh/sftp-server -f AUTHPRIV -l INFO +Subsystem sftp /usr/lib/openssh/sftp-server -f AUTHPRIV -l INFO # Host keys the client accepts - order here is honored by OpenSSH HostKeyAlgorithms ssh-ed25519-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ssh-ed25519,ssh-rsa,ecdsa-sha2-nistp521-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp521,ecdsa-sha2-nistp384,ecdsa-sha2-nistp256 diff --git a/wo/core/acme.py b/wo/core/acme.py index d640eed..b2c514b 100644 --- a/wo/core/acme.py +++ b/wo/core/acme.py @@ -1,3 +1,4 @@ +import csv import os import requests @@ -6,20 +7,27 @@ from wo.core.fileutils import WOFileUtils from wo.core.git import WOGit from wo.core.logging import Log from wo.core.shellexec import WOShellExec -from wo.core.variables import WOVariables +from wo.core.variables import WOVar class WOAcme: """Acme.sh utilities for WordOps""" + wo_acme_exec = ("/etc/letsencrypt/acme.sh --config-home " + "'/etc/letsencrypt/config'") + + def export_cert(self): + """Export acme.sh csv certificate list""" + if not WOShellExec.cmd_exec( + self, "{0} ".format(WOAcme.wo_acme_exec) + + "--list --listraw > /var/lib/wo/cert.csv"): + Log.error(self, "Unable to export certs list") + def setupletsencrypt(self, acme_domains, acmedata): - """issue SSL certificates with acme.sh""" + """Issue SSL certificates with acme.sh""" all_domains = '\' -d \''.join(acme_domains) wo_acme_dns = acmedata['acme_dns'] - keylenght = "{0}".format(self.app.config.get('letsencrypt', - 'keylength')) - wo_acme_exec = ("/etc/letsencrypt/acme.sh --config-home " - "'/etc/letsencrypt/config'") + keylenght = acmedata['keylength'] if acmedata['dns'] is True: acme_mode = "--dns {0}".format(wo_acme_dns) validation_mode = "DNS mode with {0}".format(wo_acme_dns) @@ -34,7 +42,7 @@ class WOAcme: Log.info(self, "Validation mode : {0}".format(validation_mode)) Log.wait(self, "Issuing SSL cert with acme.sh") if not WOShellExec.cmd_exec( - self, "{0} ".format(wo_acme_exec) + + self, "{0} ".format(WOAcme.wo_acme_exec) + "--issue -d '{0}' {1} -k {2} -f" .format(all_domains, acme_mode, keylenght)): Log.failed(self, "Issuing SSL cert with acme.sh") @@ -54,8 +62,6 @@ class WOAcme: return True def deploycert(self, wo_domain_name): - wo_acme_exec = ("/etc/letsencrypt/acme.sh --config-home " - "'/etc/letsencrypt/config'") if not os.path.isfile('/etc/letsencrypt/renewal/{0}_ecc/fullchain.cer' .format(wo_domain_name)): Log.error(self, 'Certificate not found. Deployment canceled') @@ -71,8 +77,8 @@ class WOAcme: "--fullchain-file {0}/{1}/fullchain.pem " "--ca-file {0}/{1}/ca.pem --reloadcmd \"nginx -t && " "service nginx restart\" " - .format(WOVariables.wo_ssl_live, - wo_domain_name, wo_acme_exec)): + .format(WOVar.wo_ssl_live, + wo_domain_name, WOAcme.wo_acme_exec)): Log.valide(self, "Deploying SSL cert") else: Log.failed(self, "Deploying SSL cert") @@ -91,20 +97,19 @@ class WOAcme: "ssl_certificate_key {0}/{1}/key.pem;\n" "ssl_trusted_certificate {0}/{1}/ca.pem;\n" "ssl_stapling_verify on;\n" - .format(WOVariables.wo_ssl_live, wo_domain_name)) + .format(WOVar.wo_ssl_live, wo_domain_name)) sslconf.close() if not WOFileUtils.grep(self, '/var/www/22222/conf/nginx/ssl.conf', '/etc/letsencrypt'): - Log.info(self, "Securing WordOps backend with current cert" - .format(wo_domain_name)) + Log.info(self, "Securing WordOps backend with current cert") sslconf = open("/var/www/22222/conf/nginx/ssl.conf", encoding='utf-8', mode='w') sslconf.write("ssl_certificate {0}/{1}/fullchain.pem;\n" "ssl_certificate_key {0}/{1}/key.pem;\n" "ssl_trusted_certificate {0}/{1}/ca.pem;\n" "ssl_stapling_verify on;\n" - .format(WOVariables.wo_ssl_live, wo_domain_name)) + .format(WOVar.wo_ssl_live, wo_domain_name)) sslconf.close() WOGit.add(self, ["/etc/letsencrypt"], @@ -114,6 +119,7 @@ class WOAcme: Log.debug(self, str(e)) Log.debug(self, "Error occured while generating " "ssl.conf") + return 0 def check_dns(self, acme_domains): """Check if a list of domains point to the server IP""" @@ -129,7 +135,26 @@ class WOAcme: self, "You have to add the " "proper DNS record", False) return False - break else: Log.debug(self, "DNS record are properly set") return True + + def cert_check(self, wo_domain_name): + """Check certificate existance with acme.sh and return Boolean""" + WOAcme.export_cert(self) + # define new csv dialect + csv.register_dialect('acmeconf', delimiter='|') + # open file + certfile = open('/var/lib/wo/cert.csv', mode='r', encoding='utf-8') + reader = csv.reader(certfile, 'acmeconf') + for row in reader: + # check if domain exist + if wo_domain_name in row[0]: + # check if cert expiration exist + if not row[3] == '': + cert_exist = True + break + else: + cert_exist = False + certfile.close() + return cert_exist diff --git a/wo/core/apt_repo.py b/wo/core/apt_repo.py index 1684b6e..f7ba7b6 100644 --- a/wo/core/apt_repo.py +++ b/wo/core/apt_repo.py @@ -3,7 +3,7 @@ import os from wo.core.logging import Log from wo.core.shellexec import WOShellExec -from wo.core.variables import WOVariables +from wo.core.variables import WOVar class WORepo(): @@ -25,7 +25,7 @@ class WORepo(): if repo_url is not None: repo_file_path = ("/etc/apt/sources.list.d/" + - WOVariables().wo_repo_file) + WOVar().wo_repo_file) try: if not os.path.isfile(repo_file_path): with open(repo_file_path, @@ -65,7 +65,7 @@ class WORepo(): .format(ppa_name=ppa)) elif repo_url: repo_file_path = ("/etc/apt/sources.list.d/" + - WOVariables().wo_repo_file) + WOVar().wo_repo_file) try: repofile = open(repo_file_path, "w+") diff --git a/wo/core/checkfqdn.py b/wo/core/checkfqdn.py index 8b240f8..55f93d5 100644 --- a/wo/core/checkfqdn.py +++ b/wo/core/checkfqdn.py @@ -1,20 +1,20 @@ import requests from wo.core.shellexec import WOShellExec -from wo.core.variables import WOVariables +from wo.core.variables import WOVar def check_fqdn(self, wo_host): """FQDN check with WordOps, for mail server hostname must be FQDN""" # wo_host=os.popen("hostname -f | tr -d '\n'").read() if '.' in wo_host: - WOVariables.wo_fqdn = wo_host + WOVar.wo_fqdn = wo_host with open('/etc/hostname', encoding='utf-8', mode='w') as hostfile: hostfile.write(wo_host) WOShellExec.cmd_exec(self, "sed -i \"1i\\127.0.0.1 {0}\" /etc/hosts" .format(wo_host)) - if WOVariables.wo_distro == 'debian': + if WOVar.wo_distro == 'debian': WOShellExec.cmd_exec(self, "/etc/init.d/hostname.sh start") else: WOShellExec.cmd_exec(self, "service hostname restart") @@ -29,7 +29,7 @@ def check_fqdn_ip(self): x = requests.get('http://v4.wordops.eu') ip = (x.text).strip() - wo_fqdn = WOVariables.wo_fqdn + wo_fqdn = WOVar.wo_fqdn y = requests.get('http://v4.wordops.eu/dns/{0}/'.format(wo_fqdn)) ip_fqdn = (y.text).strip() diff --git a/wo/core/database.py b/wo/core/database.py index c7fbff9..5be0dd7 100644 --- a/wo/core/database.py +++ b/wo/core/database.py @@ -3,10 +3,10 @@ from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import scoped_session, sessionmaker -from wo.core.variables import WOVariables +from wo.core.variables import WOVar # db_path = self.app.config.get('site', 'db_path') -engine = create_engine(WOVariables.wo_db_uri, convert_unicode=True) +engine = create_engine(WOVar.wo_db_uri, convert_unicode=True) db_session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine)) diff --git a/wo/core/domainvalidate.py b/wo/core/domainvalidate.py index de74fce..50ab1dc 100644 --- a/wo/core/domainvalidate.py +++ b/wo/core/domainvalidate.py @@ -1,12 +1,11 @@ """WordOps domain validation module.""" import os -from urllib.parse import urlparse class WODomain(): """WordOps domain validation utilities""" - def validatedomain(self, url): + def validate(self, url): """ This function returns domain name removing http:// and https:// returns domain name only with or without www as user provided. @@ -25,11 +24,11 @@ class WODomain(): else: final_domain = domain_name - return (final_domain, domain_name) + return final_domain - def getdomainlevel(self, domain): + def getlevel(self, domain): """ - This function returns the domain type : domain, subdomain, + Returns the domain type : domain, subdomain and the root domain """ domain_name = domain.lower().strip().split('.') if domain_name[0] == 'www': @@ -49,5 +48,5 @@ class WODomain(): domain_type = 'subdomain' root_domain = ('.'.join(domain_name[1:])) suffix_file.close() - - return (domain_type, root_domain) + return (domain_type, root_domain) + return ('other', domain) diff --git a/wo/core/fileutils.py b/wo/core/fileutils.py index ca3ae00..6a9b505 100644 --- a/wo/core/fileutils.py +++ b/wo/core/fileutils.py @@ -43,7 +43,7 @@ class WOFileUtils(): Log.debug(self, "Creating Symbolic link, Source:{0}, Dest:{1}" .format(src, dst)) os.symlink(src, dst) - except Exception as e: + except OSError as e: Log.debug(self, "{0}{1}".format(e.errno, e.strerror)) Log.error(self, "Unable to create symbolic link ...\n ") else: diff --git a/wo/core/git.py b/wo/core/git.py index 72a86f6..a157282 100644 --- a/wo/core/git.py +++ b/wo/core/git.py @@ -2,7 +2,6 @@ import os from sh import ErrorReturnCode, git - from wo.core.logging import Log @@ -72,9 +71,10 @@ class WOGit: Log.error(self, "Unable to find a git repository at {0}" .format(path)) try: - Log.debug(self, "WOGit: git reset HEAD~ at {0}" + Log.debug(self, "WOGit: git stash --include-untracked at {0}" .format(path)) - git.reset("HEAD~", "--hard") + git.stash("push", "--include-untracked", "-m {0}" + .format(msg)) except ErrorReturnCode as e: Log.debug(self, "{0}".format(e)) Log.error(self, "Unable to git reset at {0} " diff --git a/wo/core/mysql.py b/wo/core/mysql.py index 2e962b6..cd9de53 100644 --- a/wo/core/mysql.py +++ b/wo/core/mysql.py @@ -6,7 +6,7 @@ import pymysql from pymysql import DatabaseError, Error, connections from wo.core.logging import Log -from wo.core.variables import WOVariables +from wo.core.variables import WOVar class MySQLConnectionError(Exception): @@ -54,14 +54,14 @@ class WOMysql(): db=db_name, read_default_file='~/.my.cnf') return connection + except pymysql.err.InternalError as e: + Log.debug(self, str(e)) + raise MySQLConnectionError except DatabaseError as e: if e.args[1] == '#42000Unknown database \'{0}\''.format(db_name): raise DatabaseNotExistsError else: raise MySQLConnectionError - except pymysql.err.InternalError as e: - Log.debug(self, str(e)) - raise MySQLConnectionError except Exception as e: Log.debug(self, "[Error]Setting up database: \'" + str(e) + "\'") raise MySQLConnectionError @@ -115,7 +115,7 @@ class WOMysql(): stderr=subprocess.PIPE, shell=True) p2 = subprocess.Popen("/usr/bin/pigz -c > " "/var/wo-mysqlbackup/{0}{1}.sql.gz" - .format(dbs, WOVariables.wo_date), + .format(dbs, WOVar.wo_date), stdin=p1.stdout, shell=True) diff --git a/wo/core/nginxhashbucket.py b/wo/core/nginxhashbucket.py index 9145812..6424c5e 100644 --- a/wo/core/nginxhashbucket.py +++ b/wo/core/nginxhashbucket.py @@ -28,8 +28,14 @@ def hashbucket(self): ngx_hash = math.trunc(math.pow(2, ngx_calc)) # Replace hashbucket in Nginx.conf file - if WOFileUtils.grep(self, "/etc/nginx/nginx.conf", - "server_names_hash_bucket_size"): + if WOFileUtils.grepcheck(self, "/etc/nginx/nginx.conf", + "# server_names_hash_bucket_size 64;"): + ngxconf = open("/etc/nginx/conf.d/hashbucket.conf", + encoding='utf-8', mode='w') + ngxconf.write("\tserver_names_hash_bucket_size {0};".format(ngx_hash)) + ngxconf.close() + elif WOFileUtils.grepcheck(self, "/etc/nginx/nginx/conf", + "server_names_hash_bucket_size"): for line in fileinput.FileInput("/etc/nginx/nginx.conf", inplace=1): if "server_names_hash_bucket_size" in line: print("\tserver_names_hash_bucket_size {0};".format(ngx_hash)) @@ -37,8 +43,7 @@ def hashbucket(self): print(line, end='') else: - WOFileUtils.searchreplace(self, '/etc/nginx/nginx.conf', - "gzip_disable \"msie6\";", - "gzip_disable \"msie6\";\n" - "\tserver_names_hash_bucket_size {0};\n" - .format(ngx_hash)) + ngxconf = open("/etc/nginx/conf.d/hashbucket.conf", + encoding='utf-8', mode='w') + ngxconf.write("\tserver_names_hash_bucket_size {0};".format(ngx_hash)) + ngxconf.close() diff --git a/wo/core/random.py b/wo/core/random.py index cb7482d..f6ff3b0 100644 --- a/wo/core/random.py +++ b/wo/core/random.py @@ -3,15 +3,10 @@ import string class RANDOM: + """Random strings generator""" - def short(self): + def gen(self, length='24'): short_random = ''.join([random.choice (string.ascii_letters + string.digits) - for n in range(8)]) + for n in range(length)]) return short_random - - def long(self): - long_random = ''.join([random.choice - (string.ascii_letters + string.digits) - for n in range(24)]) - return long_random diff --git a/wo/core/services.py b/wo/core/services.py index dc874b2..7b4d748 100644 --- a/wo/core/services.py +++ b/wo/core/services.py @@ -145,6 +145,7 @@ class WOService(): if retcode[0] == 0: Log.valide(self, "Reloading {0:10}".format( service_name)) + return True else: Log.debug(self, "{0}".format(retcode[1])) Log.failed(self, "Reloading {0:10}".format( diff --git a/wo/core/sslutils.py b/wo/core/sslutils.py index 9bb620d..1202c18 100644 --- a/wo/core/sslutils.py +++ b/wo/core/sslutils.py @@ -5,7 +5,7 @@ import re from wo.core.fileutils import WOFileUtils from wo.core.logging import Log from wo.core.shellexec import WOShellExec -from wo.core.variables import WOVariables +from wo.core.variables import WOVar class SSL: @@ -63,11 +63,11 @@ class SSL: self, '{0}/htdocs/'.format(wo_site_webroot)) if WOShellExec.cmd_exec( self, "{0} --allow-root core is-installed" - .format(WOVariables.wo_wp_cli)): + .format(WOVar.wo_wp_cli)): wo_siteurl = ( WOShellExec.cmd_exec_stdout( self, "{0} option get siteurl " - .format(WOVariables.wo_wpcli_path) + + .format(WOVar.wo_wpcli_path) + "--allow-root --quiet")) test_url = re.split(":", wo_siteurl) if not (test_url[0] == 'https'): @@ -76,11 +76,11 @@ class SSL: WOShellExec.cmd_exec( self, "{0} option update siteurl " "\'https://{1}\' --allow-root".format( - WOVariables.wo_wpcli_path, domain)) + WOVar.wo_wpcli_path, domain)) WOShellExec.cmd_exec( self, "{0} option update home " "\'https://{1}\' --allow-root".format( - WOVariables.wo_wpcli_path, domain)) + WOVar.wo_wpcli_path, domain)) WOShellExec.cmd_exec( self, "{0} search-replace \'http://{0}\'" "\'https://{0}\' --skip-columns=guid " @@ -111,8 +111,9 @@ class SSL: wo_wildcard_domain = ("*.{0}".format(wo_domain_name)) for row in reader: if wo_wildcard_domain in row[2]: - iswildcard = True - break + if not row[2] == "": + iswildcard = True + break else: iswildcard = False certfile.close() diff --git a/wo/core/template.py b/wo/core/template.py index e827149..93ee44c 100644 --- a/wo/core/template.py +++ b/wo/core/template.py @@ -9,6 +9,8 @@ Render Templates class WOTemplate(): + """WordOps template utilities""" + def deploy(self, fileconf, template, data, overwrite=True): """Deploy template with render()""" data = dict(data) diff --git a/wo/core/variables.py b/wo/core/variables.py index d0154c0..67c86dd 100644 --- a/wo/core/variables.py +++ b/wo/core/variables.py @@ -1,17 +1,19 @@ """WordOps core variable module""" import configparser -import datetime import os -import socket +from datetime import datetime +from re import match +from socket import getfqdn -import distro +from distro import linux_distribution +from sh import git -class WOVariables(): +class WOVar(): """Intialization of core variables""" # WordOps version - wo_version = "3.9.9.1" + wo_version = "3.9.9.2" # WordOps packages versions wo_wp_cli = "2.3.0" wo_adminer = "4.7.3" @@ -23,14 +25,14 @@ class WOVariables(): wo_wpcli_path = '/usr/local/bin/wp' # Current date and time of System - wo_date = datetime.datetime.now().strftime('%d%b%Y-%H-%M-%S') + wo_date = datetime.now().strftime('%d%b%Y-%H-%M-%S') # WordOps core variables - wo_distro = distro.linux_distribution( + wo_distro = linux_distribution( full_distribution_name=False)[0].lower() - wo_platform_version = distro.linux_distribution( + wo_platform_version = linux_distribution( full_distribution_name=False)[1].lower() - wo_platform_codename = distro.linux_distribution( + wo_platform_codename = linux_distribution( full_distribution_name=False)[2].lower() # Get timezone of system @@ -43,7 +45,7 @@ class WOVariables(): wo_timezone = "Europe/Amsterdam" # Get FQDN of system - wo_fqdn = socket.getfqdn() + wo_fqdn = getfqdn() # WordOps default webroot path wo_webroot = '/var/www/' @@ -64,11 +66,25 @@ class WOVariables(): wo_user = config['user']['name'] wo_email = config['user']['email'] except Exception: + print("WordOps (wo) require an username & and an email " + "address to configure Git (used to save server configurations)") + print("Your informations will ONLY be stored locally") + wo_user = input("Enter your name: ") + while wo_user == "": + print("Unfortunately, this can't be left blank") + wo_user = input("Enter your name: ") + wo_email = input("Enter your email: ") - os.system("/usr/bin/git config --global user.name {0}".format(wo_user)) - os.system( - "/usr/bin/git config --global user.email {0}".format(wo_email)) + + while not match(r"^[A-Za-z0-9\.\+_-]+@[A-Za-z0-9\._-]+\.[a-zA-Z]*$", + wo_email): + print("Whoops, seems like you made a typo - " + "the e-mailaddress is invalid...") + wo_email = input("Enter your email: ") + + git.config("--global", "user.name", "{0}".format(wo_user)) + git.config("--global", "user.email", "{0}".format(wo_email)) # MySQL hostname wo_mysql_host = ""