From 37bd353fa4e4bc76b13d2682ed99585938eaed31 Mon Sep 17 00:00:00 2001 From: VirtuBox Date: Sun, 14 Jul 2019 22:50:34 +0200 Subject: [PATCH] Add upgrade script for phpmyadmin --- config/bash_completion.d/wo_auto.rc | 4 +- docs/wo.8 | 628 ++--- wo/cli/plugins/info.py | 586 ++--- wo/cli/plugins/maintenance.py | 104 +- wo/cli/plugins/site_functions.py | 3560 +++++++++++++-------------- wo/cli/plugins/stack.py | 3 +- wo/cli/plugins/stack_upgrade.py | 36 +- wo/core/variables.py | 373 +-- 8 files changed, 2665 insertions(+), 2629 deletions(-) diff --git a/config/bash_completion.d/wo_auto.rc b/config/bash_completion.d/wo_auto.rc index ede18c6..c8f4d45 100644 --- a/config/bash_completion.d/wo_auto.rc +++ b/config/bash_completion.d/wo_auto.rc @@ -79,7 +79,7 @@ _wo_complete() ;; "upgrade" ) COMPREPLY=( $(compgen \ - -W "--web --nginx --php --php73 --mysql --all --netdata --no-prompt --wpcli" \ + -W "--web --nginx --php --php73 --mysql --all --netdata --composer --phpmyadmin --no-prompt --wpcli" \ -- $cur) ) ;; "start" | "stop" | "reload" | "restart" | "status") @@ -310,7 +310,7 @@ _wo_complete() "--all") if [ ${COMP_WORDS[1]} == "clean" ]; then - retlist="--memcache --opcache --fastcgi --redis" + retlist="--opcache --fastcgi --redis" elif [ ${COMP_WORDS[2]} == "delete" ]; then retlist="--db --files --force" elif [ ${COMP_WORDS[2]} == "update" ]; then diff --git a/docs/wo.8 b/docs/wo.8 index f0d2891..6c168b2 100644 --- a/docs/wo.8 +++ b/docs/wo.8 @@ -1,314 +1,314 @@ -.TH wo 8 "WordOps (wo) version: 3.3.8" "Sep 10,2015" "WordOps" -.SH NAME -.B WordOps (wo) -\- Manage Nginx Based Websites. -.SH SYNOPSIS -wo [ --version | --help | info | stack | site | debug | update | clean | import_slow_log | log | secure | sync | maintenance] -.TP -wo stack [ install | remove | purge | migrate | upgrade] [ --web | --all | --nginx | --php | --php73 | --mysql | --admin | --adminer | --redis | --phpmyadmin | --phpredisadmin | --wpcli | --utils | --dashboard | --netdata ] -.TP -wo stack [ status | start | stop | reload | restart ] [--all | --nginx | --php | --php73 |--mysql | --web | --memcached | --redis] -.TP -wo site [ list | info | show | enable | disable | edit | cd | show ] [ example.com ] -.TP -wo site create example.com [ --html | --php | --php73 | --mysql] [[--wp | --wpsubdir | --wpsubdomain ] [--wpsc | --wpfc | --wpredis | --letsencrypt/-le/--letsencrypt=subdomain]] -.TP -wo site update example.com [ --php | --php73 |--mysql] [[--wp | --wpsubdir | --wpsubdomain ] [--wpsc | --wpfc | --wpredis ] [--password] [--letsencrypt=on/off/subdomain/renew]] -.TP -wo site delete example.com [--db | --files | --all | --no-prompt | --force/-f ] -.TP -wo debug [ -i | --all=on/off |--nginx=on/off | --rewrite=on/off | --php=on/off | --fpm=on/off | --mysql=on/off ] -.TP -wo debug example.com [ -i | --all=on/off | --nginx=on/off | --rewrite=on/off | --wp=on/off ] -.TP -wo secure [ --auth | --port | --ip ] -.SH DESCRIPTION -WordOps aka wo is the opensource project developed with the purpose to automate web-server configuration. -.br -WordOps is the collection of python script that provides automation for the web-server -.br -installation, site creation, services debugging & monitoring. -.SH OPTIONS -.TP -.B --version -.br -Display WordOps (wo) version information. -.TP -.B info -.br -wo info - Display Nginx, PHP, MySQL and wo common location information -.br -wo site info - Diplay given website details like enable, disable. weboot and log files. -.TP -.B --help -.br -Display WordOps (wo) help. -.TP -.B stack -.TP -.B install [ --all | --web | --nginx | --php | --php73 |--mysql | --redis | --adminer | --phpmyadmin | --phpredismyadmin | --wpcli | --utils ] -.br -Install Nginx PHP5 MySQL Postfix stack Packages if not used with -.br -any options.Installs specific package if used with option. -.TP -.B remove [ --all | --web | --nginx | --php | --php73 |--mysql | --redis | --adminer | --phpmyadmin | --phpredismyadmin | --wpcli | --utils ] -.br -Remove Nginx PHP5 MySQL Postfix stack Packages if not used with -.br -any options. Remove specific package if used with option. -.TP -.B purge [ --all | --web | --nginx | --php | --php73 |--mysql | --redis | --adminer | --phpmyadmin | --phpredismyadmin | --wpcli | --utils ] -.br -Purge Nginx PHP5 MySQL Postfix stack Packages if not used with any -.br -options.Purge specific package if used with option. -.TP -.B status -.br -Display status of NGINX, PHP7.2-FPM, MySQL, Redis-Server services. -.TP -.B start -.br -Start services NGINX, PHP7.2-FPM, MySQL, Redis-Server. -.TP -.B stop -.br -Stop services NGINX, PHP7.2-FPM, MySQL, Redis-Server. -.TP -.B reload -.br -Reload services NGINX, PHP7.2-FPM, MySQL, Redis-Server. -.TP -.B restart -.br -Restart services NGINX, PHP7.2-FPM, MySQL, Redis-Server. -.TP -.B site -.br -.TP -.B cd [ example.com ] -.br -Change directory to webroot of specified site in subshell. -.TP -.B log [ example.com ] -.br -monitor access and error logs for site specified. -.TP -.B list [ --enabled | --disabled ] -.br -Lists all available sites from /etc/nginx/sites-enabled/ -.br -by default & enable argument. Display sites list from -.br -/etc/nginx/sites-available/ if used with available option. -.TP -.B info [ example.com ] -.br -prints information about site such as access log, error log -.br -location and type of site. -.TP -.B show [ example.com ] -.br -Display NGINX configuration of site. -.TP -.B enable [ example.com ] -.br -Enable site by creating softlink with site file in -.br -/etc/nginx/sites-available to /etc/nginx/sites-enabled/. -.TP -.B disable [ example.com ] -.br -Disable site by Destroying softlink with site file in -.br -/etc/nginx/sites-available to /etc/nginx/sites-enabled/. -.TP -.B edit [ example.com ] -.br -Edit NGINX configuration of site. -.TP -.B create [ example.com ] [ --html | --php | --php73 |--mysql] [[--wp | --wpsubdir | --wpsubdomain ] [--wpsc | --wpfc | --wpredis ]] -.br -Create new site according to given options. If no options provided -.br -create static site with html only. -.TP -.B update [ example.com ] [ --html | --php | --php73 |--mysql] [[--wp | --wpsubdir | --wpsubdomain ] [ --wpsc | --wpfc | --wpredis ] [--password]] -.br -Update site configuration according to specified options. -.TP -.B delete [ example.com ] [--no-prompt ] [--force/-f] [ --db | --files | --all ] -.br -Delete site i.e webroot, database, ad configuration permanently. -.TP -.B debug [ -i | --nginx=on/off | --php=on/off | --php73=on/off | --mysql=on/off | --rewrite=on/off | --fpm=on/off | --fpm7=on/off ] -.br -Starts server level debugging. If this is used without arguments it will start debugging -.br -all services.Else it will debug only service provided with argument.This will Stop -.br -Debugging if used with --all=off argument. -.TP -.B debug example.com [ -i | --nginx=on/off | --rewrite=on/off | --wp=on/off | --all=on/off ] -.br -Starts site level debugging. If this is used without arguments it will start debugging all -.br -services.Else it will debug only service provided with argument.This will Stop Debugging -.br -if used with --all=off argument. -.TP -.B secure [ --auth | --port | --ip ] -.br -Update security settings. -.TP -.B clean [ --fastcgi | --opcache | --memcached | --redis | --all ] -.br -Clean NGINX fastCGI cache, Opcache, memcached, Redis cache. -.br -Clean NGINX fastCGI cache if no option specified. -.SH ARGUMENTS -.TP -.B -i -.br -setup intractive mode while used with debug. -.TP -.B --nginx=on/off -.br -used with wo debug command. used to start or stop nginx debugging. -.TP -.B --php=on/off -.br -used with wo debug command. used to start or stop php debugging. -.TP -.B --php73=on/off -.br -used with wo debug command. used to start or stop php72 debugging. -.TP -.B --mysql=on/off -.br -used with wo debug command. used to start or stop mysql debugging. -.TP -.B --rewrite=on/off -.br -used with wo debug command. used to start or stop nginx rewrite rules debugging. -.TP -.B --fpm=on/off -.br -used with wo debug command. used to start or stop fpm debugging. -.TP -.B --wp=on/off -.br -used with wo debug command. used to start or stop wordpress site debugging. -.TP -.B --all=on/off -.br -used with wo debug command. used to stop debugging. -.TP -.B --all=off -.br -used with wo debug command. used to stop debugging. -.TP -.B --html -.br -Create a HTML website. -.TP -.B --php -.br -Create a PHP website. -.TP -.B --mysql -.br -Create a PHP+MySQL website. -.TP -.B --wp -.br -Create a WordPress Website. -.TP -.B --wpsubdir -.br -Create a Wordpress Multisite with Sub Directories Setup. -.TP -.B --wpsubdomain -.br -Create a Wordpress Multisite with Sub Domains Setup. -.br -.TP -.B --db -.br -Delete website database. -.br -.TP -.B --files -.br -Delete website webroot. -.br -.TP -.B --no-prompt -.br -Does not prompt for confirmation when delete command used. -.br -.TP -.B --force/-f -.br -Delete website webroot and database forcefully.Remove nginx configuration for site. -.br -.TP -.B --auth -.br -used with wo secure command. Update credential of HTTP authentication -.TP -.B --port -.br -used with wo secure command. Change WordOps admin port 22222. -.TP -.B --ip -.br -used with wo secure command. Update whitelist IP address -.SH WORDPRESS CACHING OPTIONS -.TP -.B --wpsc -.br -Install and activate Nginx-helper and WP Super Cache plugin. -.TP -.B --wpfc -.br -Install and activate Nginx-helper plugin with -.br -Nginx FastCGI cache. -.TP -.B --wpredis -.br -Install, activate, configure Nginx-helper and Redis Object Cache Plugin, Configure NGINX for Redis Page Caching. -.SH FILES -.br -/etc/wo/wo.conf -.SH BUGS -Report bugs at -.SH AUTHOR -.br -.B rtCamp Team -.I \ -.br -.B Mitesh Shah -.I \ -.br -.B Manish -.I \ -.br -.B Gaurav -.I \ -.br -.B Harshad -.I \ -.br -.B Prabuddha -.I \ -.br -.B Shital -.I \ -.br -.B Rajdeep Sharma -.I \ -.br +.TH wo 8 "WordOps (wo) version: 3.3.8" "Sep 10,2015" "WordOps" +.SH NAME +.B WordOps (wo) +\- Manage Nginx Based Websites. +.SH SYNOPSIS +wo [ --version | --help | info | stack | site | debug | update | clean | import_slow_log | log | secure | sync | maintenance ] +.TP +wo stack [ install | remove | purge | migrate | upgrade] [ --web | --all | --nginx | --php | --php73 | --mysql | --admin | --adminer | --redis | --phpmyadmin | --phpredisadmin | --wpcli | --utils | --dashboard | --netdata ] +.TP +wo stack [ status | start | stop | reload | restart ] [--all | --nginx | --php | --php73 |--mysql | --web | --redis] +.TP +wo site [ list | info | show | enable | disable | edit | cd | show ] [ example.com ] +.TP +wo site create example.com [ --html | --php | --php73 | --mysql] [[--wp | --wpsubdir | --wpsubdomain ] [--wpsc | --wpfc | --wpredis | --letsencrypt/--le/--letsencrypt=subdomain/wildcard]] +.TP +wo site update example.com [ --php | --php73 |--mysql] [[--wp | --wpsubdir | --wpsubdomain ] [--wpsc | --wpfc | --wpredis ] [--password] [--le/--letsencrypt=on/off/subdomain/renew]] +.TP +wo site delete example.com [--db | --files | --all | --no-prompt | --force/-f ] +.TP +wo debug [ -i | --all=on/off |--nginx=on/off | --rewrite=on/off | --php=on/off | --fpm=on/off | --mysql=on/off ] +.TP +wo debug example.com [ -i | --all=on/off | --nginx=on/off | --rewrite=on/off | --wp=on/off ] +.TP +wo secure [ --auth | --port | --ip ] +.SH DESCRIPTION +WordOps aka wo is the opensource project developed with the purpose to automate web-server configuration. +.br +WordOps is the collection of python script that provides automation for the web-server +.br +installation, site creation, services debugging & monitoring. +.SH OPTIONS +.TP +.B --version +.br +Display WordOps (wo) version information. +.TP +.B info +.br +wo info - Display Nginx, PHP, MySQL and wo common location information +.br +wo site info - Diplay given website details like enable, disable. weboot and log files. +.TP +.B --help +.br +Display WordOps (wo) help. +.TP +.B stack +.TP +.B install [ --all | --web | --nginx | --php | --php73 |--mysql | --redis | --adminer | --phpmyadmin | --phpredismyadmin | --wpcli | --utils | --netdata | --dashboard ] +.br +Install Nginx PHP5 MySQL Postfix stack Packages if not used with +.br +any options.Installs specific package if used with option. +.TP +.B remove [ --all | --web | --nginx | --php | --php73 |--mysql | --redis | --adminer | --phpmyadmin | --phpredismyadmin | --wpcli | --utils | --netdata | --dashboard ] +.br +Remove Nginx PHP5 MySQL Postfix stack Packages if not used with +.br +any options. Remove specific package if used with option. +.TP +.B purge [ --all | --web | --nginx | --php | --php73 |--mysql | --redis | --adminer | --phpmyadmin | --phpredismyadmin | --wpcli | --utils | --netdata | --dashboard ] +.br +Purge Nginx PHP5 MySQL Postfix stack Packages if not used with any +.br +options.Purge specific package if used with option. +.TP +.B status +.br +Display status of NGINX, PHP7.2-FPM, MySQL, Redis-Server services. +.TP +.B start +.br +Start services NGINX, PHP7.2-FPM, MySQL, Redis-Server. +.TP +.B stop +.br +Stop services NGINX, PHP7.2-FPM, MySQL, Redis-Server. +.TP +.B reload +.br +Reload services NGINX, PHP7.2-FPM, MySQL, Redis-Server. +.TP +.B restart +.br +Restart services NGINX, PHP7.2-FPM, MySQL, Redis-Server. +.TP +.B site +.br +.TP +.B cd [ example.com ] +.br +Change directory to webroot of specified site in subshell. +.TP +.B log [ example.com ] +.br +monitor access and error logs for site specified. +.TP +.B list [ --enabled | --disabled ] +.br +Lists all available sites from /etc/nginx/sites-enabled/ +.br +by default & enable argument. Display sites list from +.br +/etc/nginx/sites-available/ if used with available option. +.TP +.B info [ example.com ] +.br +prints information about site such as access log, error log +.br +location and type of site. +.TP +.B show [ example.com ] +.br +Display NGINX configuration of site. +.TP +.B enable [ example.com ] +.br +Enable site by creating softlink with site file in +.br +/etc/nginx/sites-available to /etc/nginx/sites-enabled/. +.TP +.B disable [ example.com ] +.br +Disable site by Destroying softlink with site file in +.br +/etc/nginx/sites-available to /etc/nginx/sites-enabled/. +.TP +.B edit [ example.com ] +.br +Edit NGINX configuration of site. +.TP +.B create [ example.com ] [ --html | --php | --php73 |--mysql] [[--wp | --wpsubdir | --wpsubdomain ] [--wpsc | --wpfc | --wpredis ]] +.br +Create new site according to given options. If no options provided +.br +create static site with html only. +.TP +.B update [ example.com ] [ --html | --php | --php73 |--mysql] [[--wp | --wpsubdir | --wpsubdomain ] [ --wpsc | --wpfc | --wpredis ] [--password]] +.br +Update site configuration according to specified options. +.TP +.B delete [ example.com ] [--no-prompt ] [--force/-f] [ --db | --files | --all ] +.br +Delete site i.e webroot, database, ad configuration permanently. +.TP +.B debug [ -i | --nginx=on/off | --php=on/off | --php73=on/off | --mysql=on/off | --rewrite=on/off | --fpm=on/off | --fpm7=on/off ] +.br +Starts server level debugging. If this is used without arguments it will start debugging +.br +all services.Else it will debug only service provided with argument.This will Stop +.br +Debugging if used with --all=off argument. +.TP +.B debug example.com [ -i | --nginx=on/off | --rewrite=on/off | --wp=on/off | --all=on/off ] +.br +Starts site level debugging. If this is used without arguments it will start debugging all +.br +services.Else it will debug only service provided with argument.This will Stop Debugging +.br +if used with --all=off argument. +.TP +.B secure [ --auth | --port | --ip ] +.br +Update security settings. +.TP +.B clean [ --fastcgi | --opcache | --redis | --all ] +.br +Clean NGINX fastCGI cache, Opcache, memcached, Redis cache. +.br +Clean NGINX fastCGI cache if no option specified. +.SH ARGUMENTS +.TP +.B -i +.br +setup intractive mode while used with debug. +.TP +.B --nginx=on/off +.br +used with wo debug command. used to start or stop nginx debugging. +.TP +.B --php=on/off +.br +used with wo debug command. used to start or stop php debugging. +.TP +.B --php73=on/off +.br +used with wo debug command. used to start or stop php72 debugging. +.TP +.B --mysql=on/off +.br +used with wo debug command. used to start or stop mysql debugging. +.TP +.B --rewrite=on/off +.br +used with wo debug command. used to start or stop nginx rewrite rules debugging. +.TP +.B --fpm=on/off +.br +used with wo debug command. used to start or stop fpm debugging. +.TP +.B --wp=on/off +.br +used with wo debug command. used to start or stop wordpress site debugging. +.TP +.B --all=on/off +.br +used with wo debug command. used to stop debugging. +.TP +.B --all=off +.br +used with wo debug command. used to stop debugging. +.TP +.B --html +.br +Create a HTML website. +.TP +.B --php +.br +Create a PHP website. +.TP +.B --mysql +.br +Create a PHP+MySQL website. +.TP +.B --wp +.br +Create a WordPress Website. +.TP +.B --wpsubdir +.br +Create a Wordpress Multisite with Sub Directories Setup. +.TP +.B --wpsubdomain +.br +Create a Wordpress Multisite with Sub Domains Setup. +.br +.TP +.B --db +.br +Delete website database. +.br +.TP +.B --files +.br +Delete website webroot. +.br +.TP +.B --no-prompt +.br +Does not prompt for confirmation when delete command used. +.br +.TP +.B --force/-f +.br +Delete website webroot and database forcefully.Remove nginx configuration for site. +.br +.TP +.B --auth +.br +used with wo secure command. Update credential of HTTP authentication +.TP +.B --port +.br +used with wo secure command. Change WordOps admin port 22222. +.TP +.B --ip +.br +used with wo secure command. Update whitelist IP address +.SH WORDPRESS CACHING OPTIONS +.TP +.B --wpsc +.br +Install and activate Nginx-helper and WP Super Cache plugin. +.TP +.B --wpfc +.br +Install and activate Nginx-helper plugin with +.br +Nginx FastCGI cache. +.TP +.B --wpredis +.br +Install, activate, configure Nginx-helper and Redis Object Cache Plugin, Configure NGINX for Redis Page Caching. +.SH FILES +.br +/etc/wo/wo.conf +.SH BUGS +Report bugs at +.SH AUTHOR +.br +.B rtCamp Team +.I \ +.br +.B Mitesh Shah +.I \ +.br +.B Manish +.I \ +.br +.B Gaurav +.I \ +.br +.B Harshad +.I \ +.br +.B Prabuddha +.I \ +.br +.B Shital +.I \ +.br +.B Rajdeep Sharma +.I \ +.br diff --git a/wo/cli/plugins/info.py b/wo/cli/plugins/info.py index 9e071d7..f478ccb 100644 --- a/wo/cli/plugins/info.py +++ b/wo/cli/plugins/info.py @@ -1,293 +1,293 @@ -"""WOInfo Plugin for WordOps""" - -from cement.core.controller import CementBaseController, expose -from cement.core import handler, hook -from wo.core.variables import WOVariables -from pynginxconfig import NginxConfig -from wo.core.aptget import WOAptGet -from wo.core.shellexec import WOShellExec -from wo.core.logging import Log -import os -import configparser - - -def wo_info_hook(app): - pass - - -class WOInfoController(CementBaseController): - class Meta: - label = 'info' - stacked_on = 'base' - stacked_type = 'nested' - description = ('Display configuration information related to Nginx,' - ' PHP and MySQL') - arguments = [ - (['--mysql'], - dict(help='Get MySQL configuration information', - action='store_true')), - (['--php'], - dict(help='Get PHP 7.2 configuration information', - action='store_true')), - (['--php73'], - dict(help='Get PHP 7.3 configuration information', - action='store_true')), - (['--nginx'], - dict(help='Get Nginx configuration information', - action='store_true')), - ] - usage = "wo info [options]" - - @expose(hide=True) - def info_nginx(self): - """Display Nginx information""" - version = os.popen("/usr/sbin/nginx -v 2>&1 | " - "awk -F '/' '{print $2}' | " - "awk -F ' ' '{print $1}' | tr '\n' ' '").read() - allow = os.popen("grep ^allow /etc/nginx/common/acl.conf | " - "cut -d' ' -f2 | cut -d';' -f1 | tr '\n' ' '").read() - nc = NginxConfig() - nc.loadf('/etc/nginx/nginx.conf') - user = nc.get('user')[1] - worker_processes = nc.get('worker_processes')[1] - worker_connections = nc.get([('events',), 'worker_connections'])[1] - keepalive_timeout = nc.get([('http',), 'keepalive_timeout'])[1] - fastcgi_read_timeout = nc.get([('http',), - 'fastcgi_read_timeout'])[1] - client_max_body_size = nc.get([('http',), - 'client_max_body_size'])[1] - data = dict(version=version, allow=allow, user=user, - worker_processes=worker_processes, - keepalive_timeout=keepalive_timeout, - worker_connections=worker_connections, - fastcgi_read_timeout=fastcgi_read_timeout, - client_max_body_size=client_max_body_size) - self.app.render((data), 'info_nginx.mustache') - - @expose(hide=True) - def info_php(self): - """Display PHP information""" - version = os.popen("/usr/bin/php7.2 -v 2>/dev/null | " - "head -n1 | cut -d' ' -f2 |" - " cut -d'+' -f1 | tr -d '\n'").read - config = configparser.ConfigParser() - config.read('/etc/{0}/fpm/php.ini'.format("php/7.2")) - expose_php = config['PHP']['expose_php'] - memory_limit = config['PHP']['memory_limit'] - post_max_size = config['PHP']['post_max_size'] - upload_max_filesize = config['PHP']['upload_max_filesize'] - max_execution_time = config['PHP']['max_execution_time'] - - config.read('/etc/{0}/fpm/pool.d/www.conf'.format("php/7.2")) - www_listen = config['www']['listen'] - www_ping_path = config['www']['ping.path'] - www_pm_status_path = config['www']['pm.status_path'] - www_pm = config['www']['pm'] - www_pm_max_requests = config['www']['pm.max_requests'] - www_pm_max_children = config['www']['pm.max_children'] - www_pm_start_servers = config['www']['pm.start_servers'] - www_pm_min_spare_servers = config['www']['pm.min_spare_servers'] - www_pm_max_spare_servers = config['www']['pm.max_spare_servers'] - www_request_terminate_time = (config['www'] - ['request_terminate_timeout']) - try: - www_xdebug = (config['www']['php_admin_flag[xdebug.profiler_enable' - '_trigger]']) - except Exception as e: - www_xdebug = 'off' - - config.read('/etc/{0}/fpm/pool.d/debug.conf'.format("php/7.2")) - debug_listen = config['debug']['listen'] - debug_ping_path = config['debug']['ping.path'] - debug_pm_status_path = config['debug']['pm.status_path'] - debug_pm = config['debug']['pm'] - debug_pm_max_requests = config['debug']['pm.max_requests'] - debug_pm_max_children = config['debug']['pm.max_children'] - debug_pm_start_servers = config['debug']['pm.start_servers'] - debug_pm_min_spare_servers = config['debug']['pm.min_spare_servers'] - debug_pm_max_spare_servers = config['debug']['pm.max_spare_servers'] - debug_request_terminate = (config['debug'] - ['request_terminate_timeout']) - try: - debug_xdebug = (config['debug']['php_admin_flag[xdebug.profiler_' - 'enable_trigger]']) - except Exception as e: - debug_xdebug = 'off' - - data = dict(version=version, expose_php=expose_php, - memory_limit=memory_limit, post_max_size=post_max_size, - upload_max_filesize=upload_max_filesize, - max_execution_time=max_execution_time, - www_listen=www_listen, www_ping_path=www_ping_path, - www_pm_status_path=www_pm_status_path, www_pm=www_pm, - www_pm_max_requests=www_pm_max_requests, - www_pm_max_children=www_pm_max_children, - www_pm_start_servers=www_pm_start_servers, - www_pm_min_spare_servers=www_pm_min_spare_servers, - www_pm_max_spare_servers=www_pm_max_spare_servers, - www_request_terminate_timeout=www_request_terminate_time, - www_xdebug_profiler_enable_trigger=www_xdebug, - debug_listen=debug_listen, debug_ping_path=debug_ping_path, - debug_pm_status_path=debug_pm_status_path, - debug_pm=debug_pm, - debug_pm_max_requests=debug_pm_max_requests, - debug_pm_max_children=debug_pm_max_children, - debug_pm_start_servers=debug_pm_start_servers, - debug_pm_min_spare_servers=debug_pm_min_spare_servers, - debug_pm_max_spare_servers=debug_pm_max_spare_servers, - debug_request_terminate_timeout=debug_request_terminate, - debug_xdebug_profiler_enable_trigger=debug_xdebug) - self.app.render((data), 'info_php.mustache') - - @expose(hide=True) - def info_php73(self): - """Display PHP information""" - version = os.popen("/usr/bin/php7.3 -v 2>/dev/null | " - "head -n1 | cut -d' ' -f2 |" - " cut -d'+' -f1 | tr -d '\n'").read - config = configparser.ConfigParser() - config.read('/etc/php/7.3/fpm/php.ini') - expose_php = config['PHP']['expose_php'] - memory_limit = config['PHP']['memory_limit'] - post_max_size = config['PHP']['post_max_size'] - upload_max_filesize = config['PHP']['upload_max_filesize'] - max_execution_time = config['PHP']['max_execution_time'] - - config.read('/etc/php/7.3/fpm/pool.d/www.conf') - www_listen = config['www']['listen'] - www_ping_path = config['www']['ping.path'] - www_pm_status_path = config['www']['pm.status_path'] - www_pm = config['www']['pm'] - www_pm_max_requests = config['www']['pm.max_requests'] - www_pm_max_children = config['www']['pm.max_children'] - www_pm_start_servers = config['www']['pm.start_servers'] - www_pm_min_spare_servers = config['www']['pm.min_spare_servers'] - www_pm_max_spare_servers = config['www']['pm.max_spare_servers'] - www_request_terminate_time = (config['www'] - ['request_terminate_timeout']) - try: - www_xdebug = (config['www']['php_admin_flag[xdebug.profiler_enable' - '_trigger]']) - except Exception as e: - www_xdebug = 'off' - - config.read('/etc/php/7.3/fpm/pool.d/debug.conf') - debug_listen = config['debug']['listen'] - debug_ping_path = config['debug']['ping.path'] - debug_pm_status_path = config['debug']['pm.status_path'] - debug_pm = config['debug']['pm'] - debug_pm_max_requests = config['debug']['pm.max_requests'] - debug_pm_max_children = config['debug']['pm.max_children'] - debug_pm_start_servers = config['debug']['pm.start_servers'] - debug_pm_min_spare_servers = config['debug']['pm.min_spare_servers'] - debug_pm_max_spare_servers = config['debug']['pm.max_spare_servers'] - debug_request_terminate = (config['debug'] - ['request_terminate_timeout']) - try: - debug_xdebug = (config['debug']['php_admin_flag[xdebug.profiler_' - 'enable_trigger]']) - except Exception as e: - debug_xdebug = 'off' - - data = dict(version=version, expose_php=expose_php, - memory_limit=memory_limit, post_max_size=post_max_size, - upload_max_filesize=upload_max_filesize, - max_execution_time=max_execution_time, - www_listen=www_listen, www_ping_path=www_ping_path, - www_pm_status_path=www_pm_status_path, www_pm=www_pm, - www_pm_max_requests=www_pm_max_requests, - www_pm_max_children=www_pm_max_children, - www_pm_start_servers=www_pm_start_servers, - www_pm_min_spare_servers=www_pm_min_spare_servers, - www_pm_max_spare_servers=www_pm_max_spare_servers, - www_request_terminate_timeout=www_request_terminate_time, - www_xdebug_profiler_enable_trigger=www_xdebug, - debug_listen=debug_listen, debug_ping_path=debug_ping_path, - debug_pm_status_path=debug_pm_status_path, - debug_pm=debug_pm, - debug_pm_max_requests=debug_pm_max_requests, - debug_pm_max_children=debug_pm_max_children, - debug_pm_start_servers=debug_pm_start_servers, - debug_pm_min_spare_servers=debug_pm_min_spare_servers, - debug_pm_max_spare_servers=debug_pm_max_spare_servers, - debug_request_terminate_timeout=debug_request_terminate, - debug_xdebug_profiler_enable_trigger=debug_xdebug) - self.app.render((data), 'info_php.mustache') - - @expose(hide=True) - def info_mysql(self): - """Display MySQL information""" - version = os.popen("/usr/bin/mysql -V | awk '{print($5)}' | " - "cut -d ',' " - "-f1 | tr -d '\n'").read() - host = "localhost" - port = os.popen("/usr/bin/mysql -e \"show variables\" | " - "grep ^port | awk " - "'{print($2)}' | tr -d '\n'").read() - wait_timeout = os.popen("/usr/bin/mysql -e \"show variables\" | grep " - "^wait_timeout | awk '{print($2)}' | " - "tr -d '\n'").read() - interactive_timeout = os.popen("/usr/bin/mysql -e " - "\"show variables\" | grep " - "^interactive_timeout | awk " - "'{print($2)}' | tr -d '\n'").read() - max_used_connections = os.popen("/usr/bin/mysql -e " - "\"show global status\" | " - "grep Max_used_connections | awk " - "'{print($2)}' | tr -d '\n'").read() - datadir = os.popen("/usr/bin/mysql -e \"show variables\" | " - "grep datadir | awk" - " '{print($2)}' | tr -d '\n'").read() - socket = os.popen("/usr/bin/mysql -e \"show variables\" | " - "grep \"^socket\" | " - "awk '{print($2)}' | tr -d '\n'").read() - data = dict(version=version, host=host, port=port, - wait_timeout=wait_timeout, - interactive_timeout=interactive_timeout, - max_used_connections=max_used_connections, - datadir=datadir, socket=socket) - self.app.render((data), 'info_mysql.mustache') - - @expose(hide=True) - def default(self): - """default function for info""" - if (not self.app.pargs.nginx and not self.app.pargs.php and - not self.app.pargs.mysql and not self.app.pargs.php73): - self.app.pargs.nginx = True - self.app.pargs.php = True - self.app.pargs.mysql = True - if WOAptGet.is_installed(self, 'php7.3-fpm'): - self.app.pargs.php73 = True - - if self.app.pargs.nginx: - if (WOAptGet.is_installed(self, 'nginx-custom') or - WOAptGet.is_installed(self, 'nginx-wo')): - self.info_nginx() - else: - Log.error(self, "Nginx is not installed") - - if self.app.pargs.php: - if WOAptGet.is_installed(self, 'php7.2-fpm'): - self.info_php() - else: - Log.error(self, "PHP 7.2 is not installed") - - if self.app.pargs.php73: - if WOAptGet.is_installed(self, 'php7.3-fpm'): - self.info_php73() - else: - Log.error(self, "PHP 7.3 is not installed") - - if self.app.pargs.mysql: - if WOShellExec.cmd_exec(self, "mysqladmin ping"): - self.info_mysql() - else: - Log.error(self, "MySQL is not installed") - - -def load(app): - # register the plugin class.. this only happens if the plugin is enabled - handler.register(WOInfoController) - - # register a hook (function) to run after arguments are parsed. - hook.register('post_argument_parsing', wo_info_hook) +"""WOInfo Plugin for WordOps""" + +from cement.core.controller import CementBaseController, expose +from cement.core import handler, hook +from wo.core.variables import WOVariables +from pynginxconfig import NginxConfig +from wo.core.aptget import WOAptGet +from wo.core.shellexec import WOShellExec +from wo.core.logging import Log +import os +import configparser + + +def wo_info_hook(app): + pass + + +class WOInfoController(CementBaseController): + class Meta: + label = 'info' + stacked_on = 'base' + stacked_type = 'nested' + description = ('Display configuration information related to Nginx,' + ' PHP and MySQL') + arguments = [ + (['--mysql'], + dict(help='Get MySQL configuration information', + action='store_true')), + (['--php'], + dict(help='Get PHP 7.2 configuration information', + action='store_true')), + (['--php73'], + dict(help='Get PHP 7.3 configuration information', + action='store_true')), + (['--nginx'], + dict(help='Get Nginx configuration information', + action='store_true')), + ] + usage = "wo info [options]" + + @expose(hide=True) + def info_nginx(self): + """Display Nginx information""" + version = os.popen("/usr/sbin/nginx -v 2>&1 | " + "awk -F '/' '{print $2}' | " + "awk -F ' ' '{print $1}' | tr '\n' ' '").read() + allow = os.popen("grep ^allow /etc/nginx/common/acl.conf | " + "cut -d' ' -f2 | cut -d';' -f1 | tr '\n' ' '").read() + nc = NginxConfig() + nc.loadf('/etc/nginx/nginx.conf') + user = nc.get('user')[1] + worker_processes = nc.get('worker_processes')[1] + worker_connections = nc.get([('events',), 'worker_connections'])[1] + keepalive_timeout = nc.get([('http',), 'keepalive_timeout'])[1] + fastcgi_read_timeout = nc.get([('http',), + 'fastcgi_read_timeout'])[1] + client_max_body_size = nc.get([('http',), + 'client_max_body_size'])[1] + data = dict(version=version, allow=allow, user=user, + worker_processes=worker_processes, + keepalive_timeout=keepalive_timeout, + worker_connections=worker_connections, + fastcgi_read_timeout=fastcgi_read_timeout, + client_max_body_size=client_max_body_size) + self.app.render((data), 'info_nginx.mustache') + + @expose(hide=True) + def info_php(self): + """Display PHP information""" + version = os.popen("/usr/bin/php7.2 -v 2>/dev/null | " + "head -n1 | cut -d' ' -f2 |" + " cut -d'+' -f1 | tr -d '\n'").read + config = configparser.ConfigParser() + config.read('/etc/{0}/fpm/php.ini'.format("php/7.2")) + expose_php = config['PHP']['expose_php'] + memory_limit = config['PHP']['memory_limit'] + post_max_size = config['PHP']['post_max_size'] + upload_max_filesize = config['PHP']['upload_max_filesize'] + max_execution_time = config['PHP']['max_execution_time'] + + config.read('/etc/{0}/fpm/pool.d/www.conf'.format("php/7.2")) + www_listen = config['www']['listen'] + www_ping_path = config['www']['ping.path'] + www_pm_status_path = config['www']['pm.status_path'] + www_pm = config['www']['pm'] + www_pm_max_requests = config['www']['pm.max_requests'] + www_pm_max_children = config['www']['pm.max_children'] + www_pm_start_servers = config['www']['pm.start_servers'] + www_pm_min_spare_servers = config['www']['pm.min_spare_servers'] + www_pm_max_spare_servers = config['www']['pm.max_spare_servers'] + www_request_terminate_time = (config['www'] + ['request_terminate_timeout']) + try: + www_xdebug = (config['www']['php_admin_flag[xdebug.profiler_enable' + '_trigger]']) + except Exception as e: + www_xdebug = 'off' + + config.read('/etc/{0}/fpm/pool.d/debug.conf'.format("php/7.2")) + debug_listen = config['debug']['listen'] + debug_ping_path = config['debug']['ping.path'] + debug_pm_status_path = config['debug']['pm.status_path'] + debug_pm = config['debug']['pm'] + debug_pm_max_requests = config['debug']['pm.max_requests'] + debug_pm_max_children = config['debug']['pm.max_children'] + debug_pm_start_servers = config['debug']['pm.start_servers'] + debug_pm_min_spare_servers = config['debug']['pm.min_spare_servers'] + debug_pm_max_spare_servers = config['debug']['pm.max_spare_servers'] + debug_request_terminate = (config['debug'] + ['request_terminate_timeout']) + try: + debug_xdebug = (config['debug']['php_admin_flag[xdebug.profiler_' + 'enable_trigger]']) + except Exception as e: + debug_xdebug = 'off' + + data = dict(version=version, expose_php=expose_php, + memory_limit=memory_limit, post_max_size=post_max_size, + upload_max_filesize=upload_max_filesize, + max_execution_time=max_execution_time, + www_listen=www_listen, www_ping_path=www_ping_path, + www_pm_status_path=www_pm_status_path, www_pm=www_pm, + www_pm_max_requests=www_pm_max_requests, + www_pm_max_children=www_pm_max_children, + www_pm_start_servers=www_pm_start_servers, + www_pm_min_spare_servers=www_pm_min_spare_servers, + www_pm_max_spare_servers=www_pm_max_spare_servers, + www_request_terminate_timeout=www_request_terminate_time, + www_xdebug_profiler_enable_trigger=www_xdebug, + debug_listen=debug_listen, debug_ping_path=debug_ping_path, + debug_pm_status_path=debug_pm_status_path, + debug_pm=debug_pm, + debug_pm_max_requests=debug_pm_max_requests, + debug_pm_max_children=debug_pm_max_children, + debug_pm_start_servers=debug_pm_start_servers, + debug_pm_min_spare_servers=debug_pm_min_spare_servers, + debug_pm_max_spare_servers=debug_pm_max_spare_servers, + debug_request_terminate_timeout=debug_request_terminate, + debug_xdebug_profiler_enable_trigger=debug_xdebug) + self.app.render((data), 'info_php.mustache') + + @expose(hide=True) + def info_php73(self): + """Display PHP information""" + version = os.popen("/usr/bin/php7.3 -v 2>/dev/null | " + "head -n1 | cut -d' ' -f2 |" + " cut -d'+' -f1 | tr -d '\n'").read + config = configparser.ConfigParser() + config.read('/etc/php/7.3/fpm/php.ini') + expose_php = config['PHP']['expose_php'] + memory_limit = config['PHP']['memory_limit'] + post_max_size = config['PHP']['post_max_size'] + upload_max_filesize = config['PHP']['upload_max_filesize'] + max_execution_time = config['PHP']['max_execution_time'] + + config.read('/etc/php/7.3/fpm/pool.d/www.conf') + www_listen = config['www']['listen'] + www_ping_path = config['www']['ping.path'] + www_pm_status_path = config['www']['pm.status_path'] + www_pm = config['www']['pm'] + www_pm_max_requests = config['www']['pm.max_requests'] + www_pm_max_children = config['www']['pm.max_children'] + www_pm_start_servers = config['www']['pm.start_servers'] + www_pm_min_spare_servers = config['www']['pm.min_spare_servers'] + www_pm_max_spare_servers = config['www']['pm.max_spare_servers'] + www_request_terminate_time = (config['www'] + ['request_terminate_timeout']) + try: + www_xdebug = (config['www']['php_admin_flag[xdebug.profiler_enable' + '_trigger]']) + except Exception as e: + www_xdebug = 'off' + + config.read('/etc/php/7.3/fpm/pool.d/debug.conf') + debug_listen = config['debug']['listen'] + debug_ping_path = config['debug']['ping.path'] + debug_pm_status_path = config['debug']['pm.status_path'] + debug_pm = config['debug']['pm'] + debug_pm_max_requests = config['debug']['pm.max_requests'] + debug_pm_max_children = config['debug']['pm.max_children'] + debug_pm_start_servers = config['debug']['pm.start_servers'] + debug_pm_min_spare_servers = config['debug']['pm.min_spare_servers'] + debug_pm_max_spare_servers = config['debug']['pm.max_spare_servers'] + debug_request_terminate = (config['debug'] + ['request_terminate_timeout']) + try: + debug_xdebug = (config['debug']['php_admin_flag[xdebug.profiler_' + 'enable_trigger]']) + except Exception as e: + debug_xdebug = 'off' + + data = dict(version=version, expose_php=expose_php, + memory_limit=memory_limit, post_max_size=post_max_size, + upload_max_filesize=upload_max_filesize, + max_execution_time=max_execution_time, + www_listen=www_listen, www_ping_path=www_ping_path, + www_pm_status_path=www_pm_status_path, www_pm=www_pm, + www_pm_max_requests=www_pm_max_requests, + www_pm_max_children=www_pm_max_children, + www_pm_start_servers=www_pm_start_servers, + www_pm_min_spare_servers=www_pm_min_spare_servers, + www_pm_max_spare_servers=www_pm_max_spare_servers, + www_request_terminate_timeout=www_request_terminate_time, + www_xdebug_profiler_enable_trigger=www_xdebug, + debug_listen=debug_listen, debug_ping_path=debug_ping_path, + debug_pm_status_path=debug_pm_status_path, + debug_pm=debug_pm, + debug_pm_max_requests=debug_pm_max_requests, + debug_pm_max_children=debug_pm_max_children, + debug_pm_start_servers=debug_pm_start_servers, + debug_pm_min_spare_servers=debug_pm_min_spare_servers, + debug_pm_max_spare_servers=debug_pm_max_spare_servers, + debug_request_terminate_timeout=debug_request_terminate, + debug_xdebug_profiler_enable_trigger=debug_xdebug) + self.app.render((data), 'info_php.mustache') + + @expose(hide=True) + def info_mysql(self): + """Display MySQL information""" + version = os.popen("/usr/bin/mysql -V | awk '{print($5)}' | " + "cut -d ',' " + "-f1 | tr -d '\n'").read() + host = "localhost" + port = os.popen("/usr/bin/mysql -e \"show variables\" | " + "grep ^port | awk " + "'{print($2)}' | tr -d '\n'").read() + wait_timeout = os.popen("/usr/bin/mysql -e \"show variables\" | grep " + "^wait_timeout | awk '{print($2)}' | " + "tr -d '\n'").read() + interactive_timeout = os.popen("/usr/bin/mysql -e " + "\"show variables\" | grep " + "^interactive_timeout | awk " + "'{print($2)}' | tr -d '\n'").read() + max_used_connections = os.popen("/usr/bin/mysql -e " + "\"show global status\" | " + "grep Max_used_connections | awk " + "'{print($2)}' | tr -d '\n'").read() + datadir = os.popen("/usr/bin/mysql -e \"show variables\" | " + "grep datadir | awk" + " '{print($2)}' | tr -d '\n'").read() + socket = os.popen("/usr/bin/mysql -e \"show variables\" | " + "grep \"^socket\" | " + "awk '{print($2)}' | tr -d '\n'").read() + data = dict(version=version, host=host, port=port, + wait_timeout=wait_timeout, + interactive_timeout=interactive_timeout, + max_used_connections=max_used_connections, + datadir=datadir, socket=socket) + self.app.render((data), 'info_mysql.mustache') + + @expose(hide=True) + def default(self): + """default function for info""" + if (not self.app.pargs.nginx and not self.app.pargs.php and + not self.app.pargs.mysql and not self.app.pargs.php73): + self.app.pargs.nginx = True + self.app.pargs.php = True + self.app.pargs.mysql = True + if WOAptGet.is_installed(self, 'php7.3-fpm'): + self.app.pargs.php73 = True + + if self.app.pargs.nginx: + if (WOAptGet.is_installed(self, 'nginx-custom') or + WOAptGet.is_installed(self, 'nginx-wo')): + self.info_nginx() + else: + Log.error(self, "Nginx is not installed") + + if self.app.pargs.php: + if WOAptGet.is_installed(self, 'php7.2-fpm'): + self.info_php() + else: + Log.error(self, "PHP 7.2 is not installed") + + if self.app.pargs.php73: + if WOAptGet.is_installed(self, 'php7.3-fpm'): + self.info_php73() + else: + Log.error(self, "PHP 7.3 is not installed") + + if self.app.pargs.mysql: + if WOShellExec.cmd_exec(self, "mysqladmin ping"): + self.info_mysql() + else: + Log.error(self, "MySQL is not installed") + + +def load(app): + # register the plugin class.. this only happens if the plugin is enabled + handler.register(WOInfoController) + + # register a hook (function) to run after arguments are parsed. + hook.register('post_argument_parsing', wo_info_hook) diff --git a/wo/cli/plugins/maintenance.py b/wo/cli/plugins/maintenance.py index cdbbd14..c787ef2 100644 --- a/wo/cli/plugins/maintenance.py +++ b/wo/cli/plugins/maintenance.py @@ -1,52 +1,52 @@ -"""Maintenance Plugin for WordOps""" - -from cement.core.controller import CementBaseController, expose -from cement.core import handler, hook -from wo.core.logging import Log -from wo.core.variables import WOVariables -from wo.core.aptget import WOAptGet -from wo.core.apt_repo import WORepo -from wo.core.services import WOService -from wo.core.shellexec import WOShellExec - - -def wo_maintenance_hook(app): - pass - - -class WOMaintenanceController(CementBaseController): - class Meta: - label = 'maintenance' - stacked_on = 'base' - stacked_type = 'nested' - description = ('update server packages to latest version') - usage = "wo maintenance" - - @expose(hide=True) - def default(self): - - try: - Log.info(self, "updating apt-cache, please wait...") - WOShellExec.cmd_exec(self, "apt-get update") - Log.info(self, "updating packages, please wait...") - WOShellExec.cmd_exec(self, "DEBIAN_FRONTEND=noninteractive " - "apt-get -o " - "Dpkg::Options::='--force-confmiss' " - "-o Dpkg::Options::='--force-confold' " - "-y dist-upgrade") - Log.info(self, "cleaning-up packages, please wait...") - WOShellExec.cmd_exec(self, "apt-get -y --purge autoremove") - WOShellExec.cmd_exec(self, "apt-get -y autoclean") - except OSError as e: - Log.debug(self, str(e)) - Log.error(self, "Package updates failed !") - except Exception as e: - Log.debug(self, str(e)) - Log.error(self, "Packages updates failed !") - - -def load(app): - # register the plugin class.. this only happens if the plugin is enabled - handler.register(WOMaintenanceController) - # register a hook (function) to run after arguments are parsed. - hook.register('post_argument_parsing', wo_maintenance_hook) +"""Maintenance Plugin for WordOps""" + +from cement.core.controller import CementBaseController, expose +from cement.core import handler, hook +from wo.core.logging import Log +from wo.core.variables import WOVariables +from wo.core.aptget import WOAptGet +from wo.core.apt_repo import WORepo +from wo.core.services import WOService +from wo.core.shellexec import WOShellExec + + +def wo_maintenance_hook(app): + pass + + +class WOMaintenanceController(CementBaseController): + class Meta: + label = 'maintenance' + stacked_on = 'base' + stacked_type = 'nested' + description = ('update server packages to latest version') + usage = "wo maintenance" + + @expose(hide=True) + def default(self): + + try: + Log.info(self, "updating apt-cache, please wait...") + WOShellExec.cmd_exec(self, "apt-get update") + Log.info(self, "updating packages, please wait...") + WOShellExec.cmd_exec(self, "DEBIAN_FRONTEND=noninteractive " + "apt-get -o " + "Dpkg::Options::='--force-confmiss' " + "-o Dpkg::Options::='--force-confold' " + "-y dist-upgrade") + Log.info(self, "cleaning-up packages, please wait...") + WOShellExec.cmd_exec(self, "apt-get -y --purge autoremove") + WOShellExec.cmd_exec(self, "apt-get -y autoclean") + except OSError as e: + Log.debug(self, str(e)) + Log.error(self, "Package updates failed !") + except Exception as e: + Log.debug(self, str(e)) + Log.error(self, "Packages updates failed !") + + +def load(app): + # register the plugin class.. this only happens if the plugin is enabled + handler.register(WOMaintenanceController) + # register a hook (function) to run after arguments are parsed. + hook.register('post_argument_parsing', wo_maintenance_hook) diff --git a/wo/cli/plugins/site_functions.py b/wo/cli/plugins/site_functions.py index f89b5ac..8697692 100644 --- a/wo/cli/plugins/site_functions.py +++ b/wo/cli/plugins/site_functions.py @@ -1,1780 +1,1780 @@ -from wo.cli.plugins.stack import WOStackController -from wo.core.fileutils import WOFileUtils -from wo.core.mysql import * -from wo.core.shellexec import * -from wo.core.sslutils import SSL -from wo.core.variables import WOVariables -from wo.cli.plugins.sitedb import * -from wo.core.aptget import WOAptGet -from wo.core.git import WOGit -from wo.core.logging import Log -from wo.core.sendmail import WOSendMail -from wo.core.services import WOService -import subprocess -from subprocess import CalledProcessError -import os -import random -import string -import sys -import getpass -import glob -import re -import platform - - -class SiteError(Exception): - """Custom Exception Occured when setting up site""" - - def __init__(self, message): - self.message = message - - def __str__(self): - return repr(self.message) - - -def pre_run_checks(self): - - # Check nginx configuration - Log.info(self, "Running pre-update checks, please wait...") - try: - Log.debug(self, "checking NGINX configuration ...") - FNULL = open('/dev/null', 'w') - ret = subprocess.check_call(["nginx", "-t"], stdout=FNULL, - stderr=subprocess.STDOUT) - except CalledProcessError as e: - Log.debug(self, "{0}".format(str(e))) - raise SiteError("nginx configuration check failed.") - - -def check_domain_exists(self, domain): - if getSiteInfo(self, domain): - return True - return False - - -def setupdomain(self, data): - - # for debug purpose - # for key, value in data.items() : - # print (key, value) - - wo_domain_name = data['site_name'] - wo_site_webroot = data['webroot'] - - # Check if nginx configuration already exists - # if os.path.isfile('/etc/nginx/sites-available/{0}' - # .format(wo_domain_name)): - # raise SiteError("nginx configuration already exists for site") - - Log.info(self, "Setting up NGINX configuration \t", end='') - # write nginx config for file - try: - wo_site_nginx_conf = open('/etc/nginx/sites-available/{0}' - .format(wo_domain_name), encoding='utf-8', - mode='w') - if not data['php73']: - self.app.render((data), 'virtualconf.mustache', - out=wo_site_nginx_conf) - else: - self.app.render((data), 'virtualconf-php7.mustache', - out=wo_site_nginx_conf) - wo_site_nginx_conf.close() - except IOError as e: - Log.debug(self, "{0}".format(e)) - raise SiteError("create nginx configuration failed for site") - except Exception as e: - Log.debug(self, "{0}".format(e)) - raise SiteError("create nginx configuration failed for site") - finally: - # Check nginx -t and return status over it - try: - Log.debug(self, "Checking generated nginx conf, please wait...") - FNULL = open('/dev/null', 'w') - ret = subprocess.check_call(["nginx", "-t"], stdout=FNULL, - stderr=subprocess.STDOUT) - Log.info(self, "[" + Log.ENDC + "Done" + Log.OKBLUE + "]") - except CalledProcessError as e: - Log.debug(self, "{0}".format(str(e))) - Log.info(self, "[" + Log.ENDC + Log.FAIL + "Fail" + - Log.OKBLUE + "]") - raise SiteError("created nginx configuration failed for site." - " check with `nginx -t`") - - # create symbolic link for - WOFileUtils.create_symlink(self, ['/etc/nginx/sites-available/{0}' - .format(wo_domain_name), - '/etc/nginx/sites-enabled/{0}' - .format(wo_domain_name)]) - - # Creating htdocs & logs directory - Log.info(self, "Setting up webroot \t\t", end='') - try: - if not os.path.exists('{0}/htdocs'.format(wo_site_webroot)): - os.makedirs('{0}/htdocs'.format(wo_site_webroot)) - if not os.path.exists('{0}/logs'.format(wo_site_webroot)): - os.makedirs('{0}/logs'.format(wo_site_webroot)) - if not os.path.exists('{0}/conf/nginx'.format(wo_site_webroot)): - os.makedirs('{0}/conf/nginx'.format(wo_site_webroot)) - - WOFileUtils.create_symlink(self, ['/var/log/nginx/{0}.access.log' - .format(wo_domain_name), - '{0}/logs/access.log' - .format(wo_site_webroot)]) - WOFileUtils.create_symlink(self, ['/var/log/nginx/{0}.error.log' - .format(wo_domain_name), - '{0}/logs/error.log' - .format(wo_site_webroot)]) - except Exception as e: - Log.debug(self, "{0}".format(e)) - raise SiteError("setup webroot failed for site") - finally: - # TODO Check if directories are setup - if (os.path.exists('{0}/htdocs'.format(wo_site_webroot)) and - os.path.exists('{0}/logs'.format(wo_site_webroot))): - Log.info(self, "[" + Log.ENDC + "Done" + Log.OKBLUE + "]") - else: - Log.info(self, "[" + Log.ENDC + "Fail" + Log.OKBLUE + "]") - raise SiteError("setup webroot failed for site") - - -def setupdatabase(self, data): - wo_domain_name = data['site_name'] - wo_random = (''.join(random.sample(string.ascii_uppercase + - string.ascii_lowercase + - string.digits, 24))) - wo_replace_dot = wo_domain_name.replace('.', '_') - prompt_dbname = self.app.config.get('mysql', 'db-name') - prompt_dbuser = self.app.config.get('mysql', 'db-user') - wo_mysql_grant_host = self.app.config.get('mysql', 'grant-host') - wo_db_name = '' - wo_db_username = '' - wo_db_password = '' - - if prompt_dbname == 'True' or prompt_dbname == 'true': - try: - wo_db_name = input('Enter the MySQL database name [{0}]: ' - .format(wo_replace_dot)) - except EOFError as e: - Log.debug(self, "{0}".format(e)) - raise SiteError("Unable to input database name") - - if not wo_db_name: - wo_db_name = wo_replace_dot - - if prompt_dbuser == 'True' or prompt_dbuser == 'true': - try: - wo_db_username = input('Enter the MySQL database user name [{0}]: ' - .format(wo_replace_dot)) - wo_db_password = getpass.getpass(prompt='Enter the MySQL database' - ' password [{0}]: ' - .format(wo_random)) - except EOFError as e: - Log.debug(self, "{0}".format(e)) - raise SiteError("Unable to input database credentials") - - if not wo_db_username: - wo_db_username = wo_replace_dot - if not wo_db_password: - wo_db_password = wo_random - - if len(wo_db_username) > 16: - Log.debug(self, 'Autofix MySQL username (ERROR 1470 (HY000)),' - ' please wait') - wo_db_username = (wo_db_name[0:6] + generate_random()) - - # create MySQL database - Log.info(self, "Setting up database\t\t", end='') - Log.debug(self, "Creating database {0}".format(wo_db_name)) - try: - if WOMysql.check_db_exists(self, wo_db_name): - Log.debug(self, "Database already exists, Updating DB_NAME .. ") - wo_db_name = (wo_db_name[0:6] + generate_random()) - wo_db_username = (wo_db_name[0:6] + generate_random()) - except MySQLConnectionError as e: - raise SiteError("MySQL Connectivity problem occured") - - try: - WOMysql.execute(self, "create database `{0}`" - .format(wo_db_name)) - except StatementExcecutionError as e: - Log.info(self, "[" + Log.ENDC + Log.FAIL + "Failed" + Log.OKBLUE + "]") - raise SiteError("create database execution failed") - # Create MySQL User - Log.debug(self, "Creating user {0}".format(wo_db_username)) - Log.debug(self, "create user `{0}`@`{1}` identified by ''" - .format(wo_db_username, wo_mysql_grant_host)) - try: - WOMysql.execute(self, - "create user `{0}`@`{1}` identified by '{2}'" - .format(wo_db_username, wo_mysql_grant_host, - wo_db_password), log=False) - except StatementExcecutionError as e: - Log.info(self, "[" + Log.ENDC + Log.FAIL + "Failed" + Log.OKBLUE + "]") - raise SiteError("creating user failed for database") - - # Grant permission - Log.debug(self, "Setting up user privileges") - try: - WOMysql.execute(self, - "grant all privileges on `{0}`.* to `{1}`@`{2}`" - .format(wo_db_name, - wo_db_username, wo_mysql_grant_host)) - except StatementExcecutionError as e: - Log.info(self, "[" + Log.ENDC + Log.FAIL + "Failed" + Log.OKBLUE + "]") - SiteError("grant privileges to user failed for database ") - - Log.info(self, "[" + Log.ENDC + "Done" + Log.OKBLUE + "]") - - 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_mysql_grant_host'] = wo_mysql_grant_host - return(data) - - -def setupwordpress(self, data): - wo_domain_name = data['site_name'] - wo_site_webroot = data['webroot'] - prompt_wpprefix = self.app.config.get('wordpress', 'prefix') - wo_wp_user = self.app.config.get('wordpress', 'user') - wo_wp_pass = self.app.config.get('wordpress', 'password') - wo_wp_email = self.app.config.get('wordpress', 'email') - # Random characters - wo_random = (''.join(random.sample(string.ascii_uppercase + - string.ascii_lowercase + - string.digits, 15))) - wo_wp_prefix = '' - # wo_wp_user = '' - # wo_wp_pass = '' - - if 'wp-user' in data.keys() and data['wp-user']: - wo_wp_user = data['wp-user'] - if 'wp-email' in data.keys() and data['wp-email']: - wo_wp_email = data['wp-email'] - if 'wp-pass' in data.keys() and data['wp-pass']: - wo_wp_pass = data['wp-pass'] - - Log.info(self, "Downloading WordPress \t\t", end='') - WOFileUtils.chdir(self, '{0}/htdocs/'.format(wo_site_webroot)) - try: - if WOShellExec.cmd_exec(self, "wp --allow-root core" - " download"): - pass - else: - Log.info(self, "[" + Log.ENDC + Log.FAIL + - "Fail" + Log.OKBLUE + "]") - raise SiteError("download WordPress core failed") - except CommandExecutionError as e: - Log.info(self, "[" + Log.ENDC + Log.FAIL + "Fail" + Log.OKBLUE + "]") - raise SiteError(self, "download WordPress core failed") - - Log.info(self, "[" + Log.ENDC + "Done" + Log.OKBLUE + "]") - - if not (data['wo_db_name'] and data['wo_db_user'] and data['wo_db_pass']): - data = setupdatabase(self, data) - if prompt_wpprefix == 'True' or prompt_wpprefix == 'true': - try: - wo_wp_prefix = input('Enter the WordPress table prefix [wp_]: ') - while not re.match('^[A-Za-z0-9_]*$', wo_wp_prefix): - Log.warn(self, "table prefix can only " - "contain numbers, letters, and underscores") - wo_wp_prefix = input('Enter the WordPress table prefix [wp_]: ' - ) - except EOFError as e: - Log.debug(self, "{0}".format(e)) - raise SiteError("input table prefix failed") - - if not wo_wp_prefix: - wo_wp_prefix = 'wp_' - - # Modify wp-config.php & move outside the webroot - - WOFileUtils.chdir(self, '{0}/htdocs/'.format(wo_site_webroot)) - Log.debug(self, "Setting up wp-config file") - if not data['multisite']: - Log.debug(self, "Generating wp-config for WordPress Single site") - Log.debug(self, "bash -c \"php {0} --allow-root " - .format(WOVariables.wo_wpcli_path) + - "config create " + - "--dbname=\'{0}\' --dbprefix=\'{1}\' --dbuser=\'{2}\' " - "--dbhost=\'{3}\' " - .format(data['wo_db_name'], wo_wp_prefix, - data['wo_db_user'], data['wo_db_host']) + - "--dbpass=\'{0}\' " - "--extra-php< {1}/{0}.gz" - .format(data['wo_db_name'], - backup_path)): - Log.info(self, - "[" + Log.ENDC + Log.FAIL + "Fail" + Log.OKBLUE + "]") - raise SiteError("mysqldump failed to backup database") - except CommandExecutionError as e: - Log.info(self, "[" + Log.ENDC + "Fail" + Log.OKBLUE + "]") - raise SiteError("mysqldump failed to backup database") - Log.info(self, "[" + Log.ENDC + "Done" + Log.OKBLUE + "]") - # move wp-config.php/wo-config.php to backup - if data['currsitetype'] in ['mysql', 'proxy']: - if data['php73'] is True and not data['wp']: - WOFileUtils.copyfile(self, configfiles[0], backup_path) - else: - WOFileUtils.mvfile(self, configfiles[0], backup_path) - else: - WOFileUtils.copyfile(self, configfiles[0], backup_path) - - -def site_package_check(self, stype): - apt_packages = [] - packages = [] - stack = WOStackController() - stack.app = self.app - if stype in ['html', 'proxy', 'php', 'mysql', 'wp', 'wpsubdir', - 'wpsubdomain', 'php73']: - Log.debug(self, "Setting apt_packages variable for Nginx") - - # Check if server has nginx-custom package - if not (WOAptGet.is_installed(self, 'nginx-custom') or - WOAptGet.is_installed(self, 'nginx-mainline')): - # check if Server has nginx-plus installed - if WOAptGet.is_installed(self, 'nginx-plus'): - # 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 - stack.post_pref(apt, packages) - elif WOAptGet.is_installed(self, 'nginx'): - Log.info(self, "WordOps detected a previously" - "installed Nginx package. " - "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 - stack.post_pref(apt, packages) - else: - apt_packages = apt_packages + WOVariables.wo_nginx - else: - # Fix for Nginx white screen death - if not WOFileUtils.grep(self, '/etc/nginx/fastcgi_params', - 'SCRIPT_FILENAME'): - with open('/etc/nginx/fastcgi_params', encoding='utf-8', - mode='a') as wo_nginx: - wo_nginx.write('fastcgi_param \tSCRIPT_FILENAME ' - '\t$request_filename;\n') - - if self.app.pargs.php and self.app.pargs.php73: - Log.error( - self, "Error: two different PHP versions cannot be " - "combined within the same WordOps site") - - if not self.app.pargs.php73 and stype in ['php', 'mysql', 'wp', 'wpsubdir', - 'wpsubdomain']: - 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 - else: - apt_packages = apt_packages + WOVariables.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 - else: - apt_packages = apt_packages + WOVariables.wo_php73 - - if stype in ['mysql', 'wp', 'wpsubdir', 'wpsubdomain']: - Log.debug(self, "Setting apt_packages variable for MySQL") - if not WOShellExec.cmd_exec(self, "mysqladmin ping"): - apt_packages = apt_packages + WOVariables.wo_mysql - packages = packages + [["https://raw.githubusercontent.com/" - "major/MySQLTuner-perl/master/" - "mysqltuner.pl", "/usr/bin/mysqltuner", - "MySQLTuner"]] - - if stype in ['wp', 'wpsubdir', 'wpsubdomain']: - Log.debug(self, "Setting packages variable for WP-CLI") - if not WOShellExec.cmd_exec(self, "command -v wp"): - packages = packages + [["https://github.com/wp-cli/wp-cli/" - "releases/download/v{0}/" - "wp-cli-{0}.phar" - .format(WOVariables.wo_wp_cli), - "/usr/local/bin/wp", "WP-CLI"]] - if self.app.pargs.wpredis: - Log.debug(self, "Setting apt_packages variable for redis") - if not WOAptGet.is_installed(self, 'redis-server'): - apt_packages = apt_packages + WOVariables.wo_redis - - if (os.path.isfile("/etc/nginx/nginx.conf") and - not os.path.isfile("/etc/nginx/common/redis-php72.conf")): - - data = dict() - Log.debug(self, 'Writting the nginx configuration to ' - 'file /etc/nginx/common/redis-php72.conf') - wo_nginx = open('/etc/nginx/common/redis-php72.conf', - encoding='utf-8', mode='w') - self.app.render((data), 'redis.mustache', - out=wo_nginx) - wo_nginx.close() - - if os.path.isfile("/etc/nginx/conf.d/upstream.conf"): - if not WOFileUtils.grep(self, "/etc/nginx/conf.d/" - "upstream.conf", - "redis"): - with open("/etc/nginx/conf.d/upstream.conf", - "a") as redis_file: - redis_file.write("upstream redis {\n" - " server 127.0.0.1:6379;\n" - " keepalive 10;\n}") - - if (os.path.isfile("/etc/nginx/nginx.conf") and - not os.path.isfile("/etc/nginx/conf.d/redis.conf")): - with open("/etc/nginx/conf.d/redis.conf", "a") as redis_file: - redis_file.write("# Log format Settings\n" - "log_format rt_cache_redis '$remote_addr" - " $upstream_response_time " - "$srcache_fetch_status [$time_local] '\n" - "'$http_host \"$request\" $status" - " $body_bytes_sent '\n" - "'\"$http_referer\" \"$http_user_agent\"';\n") - - if self.app.pargs.php73: - 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 - else: - apt_packages = apt_packages + WOVariables.wo_php73 - - if (os.path.isdir("/etc/nginx/common") and - not os.path.isfile("/etc/nginx/common/php73.conf")): - data = dict() - Log.debug(self, 'Writting the nginx configuration to ' - 'file /etc/nginx/common/locations-wo.conf') - wo_nginx = open('/etc/nginx/common/locations-wo.conf', - encoding='utf-8', mode='w') - self.app.render((data), 'locations-php7.mustache', - out=wo_nginx) - wo_nginx.close() - - Log.debug(self, 'Writting the nginx configuration to ' - 'file /etc/nginx/common/php73.conf') - wo_nginx = open('/etc/nginx/common/php73.conf', - encoding='utf-8', mode='w') - self.app.render((data), 'php7.mustache', - out=wo_nginx) - wo_nginx.close() - - Log.debug(self, 'Writting the nginx configuration to ' - 'file /etc/nginx/common/wpcommon-php73.conf') - wo_nginx = open('/etc/nginx/common/wpcommon-php73.conf', - encoding='utf-8', mode='w') - self.app.render((data), 'wpcommon-php7.mustache', - out=wo_nginx) - wo_nginx.close() - - Log.debug(self, 'Writting the nginx configuration to ' - 'file /etc/nginx/common/wpfc-php73.conf') - wo_nginx = open('/etc/nginx/common/wpfc-php73.conf', - encoding='utf-8', mode='w') - self.app.render((data), 'wpfc-php7.mustache', - out=wo_nginx) - wo_nginx.close() - - Log.debug(self, 'Writting the nginx configuration to ' - 'file /etc/nginx/common/wpsc-php73.conf') - wo_nginx = open('/etc/nginx/common/wpsc-php73.conf', - encoding='utf-8', mode='w') - self.app.render((data), 'wpsc-php7.mustache', - out=wo_nginx) - wo_nginx.close() - - if (os.path.isfile("/etc/nginx/nginx.conf") and - not os.path.isfile("/etc/nginx/common/redis-php73.conf")): - data = dict() - Log.debug(self, 'Writting the nginx configuration to ' - 'file /etc/nginx/common/redis-php73.conf') - wo_nginx = open('/etc/nginx/common/redis-php73.conf', - encoding='utf-8', mode='w') - self.app.render((data), 'redis-php7.mustache', - out=wo_nginx) - wo_nginx.close() - - if os.path.isfile("/etc/nginx/conf.d/upstream.conf"): - if not WOFileUtils.grep(self, "/etc/nginx/conf.d/upstream.conf", - "php73"): - with open("/etc/nginx/conf.d/upstream.conf", "a") as php_file: - php_file.write("upstream php73 {\nserver" - "unix:/var/run/php/php73-fpm.sock;\n}\n" - "upstream debug73" - " {\nserver 127.0.0.1:9173;\n}\n") - - return(stack.install(apt_packages=apt_packages, packages=packages, - disp_msg=False)) - - -def updatewpuserpassword(self, wo_domain, wo_site_webroot): - - wo_wp_user = '' - wo_wp_pass = '' - WOFileUtils.chdir(self, '{0}/htdocs/'.format(wo_site_webroot)) - - # Check if wo_domain is wordpress install - try: - is_wp = WOShellExec.cmd_exec(self, "wp --allow-root core" - " version") - except CommandExecutionError as e: - raise SiteError("is WordPress site? check command failed ") - - # Exit if wo_domain is not wordpress install - if not is_wp: - Log.error(self, "{0} does not seem to be a WordPress site" - .format(wo_domain)) - - try: - wo_wp_user = input("Provide WordPress user name [admin]: ") - except Exception as e: - Log.debug(self, "{0}".format(e)) - Log.error(self, "\nCould not update password") - - if wo_wp_user == "?": - Log.info(self, "Fetching WordPress user list") - try: - WOShellExec.cmd_exec(self, "wp --allow-root user list " - "--fields=user_login | grep -v user_login") - except CommandExecutionError as e: - raise SiteError("fetch wp userlist command failed") - - if not wo_wp_user: - wo_wp_user = 'admin' - - try: - is_user_exist = WOShellExec.cmd_exec(self, "wp --allow-root user list " - "--fields=user_login | grep {0}$ " - .format(wo_wp_user)) - except CommandExecutionError as e: - raise SiteError("if wp user exists check command failed") - - if is_user_exist: - try: - wo_wp_pass = getpass.getpass(prompt="Provide password for " - "{0} user: " - .format(wo_wp_user)) - - while not wo_wp_pass: - wo_wp_pass = getpass.getpass(prompt="Provide password for " - "{0} user: " - .format(wo_wp_user)) - except Exception as e: - Log.debug(self, "{0}".format(e)) - raise SiteError("failed to read password input ") - - try: - WOShellExec.cmd_exec(self, "wp --allow-root user update {0}" - " --user_pass={1}" - .format(wo_wp_user, wo_wp_pass)) - except CommandExecutionError as e: - raise SiteError("wp user password update command failed") - Log.info(self, "Password updated successfully") - - else: - Log.error(self, "Invalid WordPress user {0} for {1}." - .format(wo_wp_user, wo_domain)) - - -def display_cache_settings(self, data): - if data['wpsc']: - if data['multisite']: - Log.info(self, "Configure WPSC:" - "\t\thttp://{0}/wp-admin/network/settings.php?" - "page=wpsupercache" - .format(data['site_name'])) - else: - Log.info(self, "Configure WPSC:" - "\t\thttp://{0}/wp-admin/options-general.php?" - "page=wpsupercache" - .format(data['site_name'])) - - if data['wpredis']: - if data['multisite']: - Log.info(self, "Configure redis-cache:" - "\thttp://{0}/wp-admin/network/settings.php?" - "page=redis-cache".format(data['site_name'])) - else: - Log.info(self, "Configure redis-cache:" - "\thttp://{0}/wp-admin/options-general.php?" - "page=redis-cache".format(data['site_name'])) - Log.info(self, "Object Cache:\t\tEnable") - - -def logwatch(self, logfiles): - import zlib - import base64 - import time - from wo.core import logwatch - - def callback(filename, lines): - for line in lines: - if line.find(':::') == -1: - print(line) - else: - data = line.split(':::') - try: - print(data[0], data[1], - zlib.decompress(base64.decodestring(data[2]))) - except Exception as e: - Log.info(time.time(), - 'caught exception rendering a new log line in %s' - % filename) - - l = logwatch.LogWatcher(logfiles, callback) - l.loop() - - -def detSitePar(opts): - """ - Takes dictionary of parsed arguments - 1.returns sitetype and cachetype - 2. raises RuntimeError when wrong combination is used like - "--wp --wpsubdir" or "--html --wp" - """ - sitetype, cachetype = '', '' - typelist = list() - cachelist = list() - for key, val in opts.items(): - if val and key in ['html', 'php', 'mysql', 'wp', - 'wpsubdir', 'wpsubdomain', 'php73']: - typelist.append(key) - elif val and key in ['wpfc', 'wpsc', 'wpredis']: - cachelist.append(key) - - if len(typelist) > 1 or len(cachelist) > 1: - if len(cachelist) > 1: - raise RuntimeError( - "Could not determine cache type." - "Multiple cache parameter entered") - elif False not in [x in ('php', 'mysql', 'html') for x in typelist]: - sitetype = 'mysql' - if not cachelist: - cachetype = 'basic' - else: - cachetype = cachelist[0] - elif False not in [x in ('php73', 'mysql', 'html') for x in typelist]: - sitetype = 'mysql' - if not cachelist: - cachetype = 'basic' - else: - cachetype = cachelist[0] - elif False not in [x in ('php', 'mysql') for x in typelist]: - sitetype = 'mysql' - if not cachelist: - cachetype = 'basic' - else: - cachetype = cachelist[0] - elif False not in [x in ('php73', 'mysql') for x in typelist]: - sitetype = 'mysql' - if not cachelist: - cachetype = 'basic' - else: - cachetype = cachelist[0] - elif False not in [x in ('html', 'mysql') for x in typelist]: - sitetype = 'mysql' - if not cachelist: - cachetype = 'basic' - else: - cachetype = cachelist[0] - elif False not in [x in ('php', 'html') for x in typelist]: - sitetype = 'php' - if not cachelist: - cachetype = 'basic' - else: - cachetype = cachelist[0] - elif False not in [x in ('php73', 'html') for x in typelist]: - sitetype = 'php73' - if not cachelist: - cachetype = 'basic' - else: - cachetype = cachelist[0] - elif False not in [x in ('wp', 'wpsubdir') for x in typelist]: - sitetype = 'wpsubdir' - if not cachelist: - cachetype = 'basic' - else: - cachetype = cachelist[0] - elif False not in [x in ('wp', 'wpsubdomain') for x in typelist]: - sitetype = 'wpsubdomain' - if not cachelist: - cachetype = 'basic' - else: - cachetype = cachelist[0] - elif False not in [x in ('wp', 'php73') for x in typelist]: - sitetype = 'wp' - if not cachelist: - cachetype = 'basic' - else: - cachetype = cachelist[0] - elif False not in [x in ('wpsubdir', 'php73') for x in typelist]: - sitetype = 'wpsubdir' - if not cachelist: - cachetype = 'basic' - else: - cachetype = cachelist[0] - elif False not in [x in ('wpsubdomain', 'php73') for x in typelist]: - sitetype = 'wpsubdomain' - if not cachelist: - cachetype = 'basic' - else: - cachetype = cachelist[0] - else: - raise RuntimeError("could not determine site and cache type") - else: - if not typelist and not cachelist: - sitetype = None - cachetype = None - elif (not typelist or "php73" in typelist) and cachelist: - sitetype = 'wp' - cachetype = cachelist[0] - elif typelist and (not cachelist): - sitetype = typelist[0] - cachetype = 'basic' - else: - sitetype = typelist[0] - cachetype = cachelist[0] - - return (sitetype, cachetype) - - -def generate_random(): - wo_random10 = (''.join(random.sample(string.ascii_uppercase + - string.ascii_lowercase + - string.digits, 24))) - return wo_random10 - - -def deleteDB(self, dbname, dbuser, dbhost, exit=True): - try: - # Check if Database exists - try: - if WOMysql.check_db_exists(self, dbname): - # Drop database if exists - Log.debug(self, "dropping database `{0}`".format(dbname)) - WOMysql.execute(self, - "drop database `{0}`".format(dbname), - errormsg='Unable to drop database {0}' - .format(dbname)) - except StatementExcecutionError as e: - Log.debug(self, "drop database failed") - Log.info(self, "Database {0} not dropped".format(dbname)) - - except MySQLConnectionError as e: - Log.debug(self, "Mysql Connection problem occured") - - if dbuser != 'root': - Log.debug(self, "dropping user `{0}`".format(dbuser)) - try: - WOMysql.execute(self, - "drop user `{0}`@`{1}`" - .format(dbuser, dbhost)) - except StatementExcecutionError as e: - Log.debug(self, "drop database user failed") - Log.info(self, "Database {0} not dropped".format(dbuser)) - try: - WOMysql.execute(self, "flush privileges") - except StatementExcecutionError as e: - Log.debug(self, "drop database failed") - Log.info(self, "Database {0} not dropped".format(dbname)) - except Exception as e: - Log.error(self, "Error occured while deleting database", exit) - - -def deleteWebRoot(self, webroot): - # do some preprocessing before proceeding - webroot = webroot.strip() - if (webroot == "/var/www/" or webroot == "/var/www" or - webroot == "/var/www/.." or webroot == "/var/www/."): - Log.debug(self, "Tried to remove {0}, but didn't remove it" - .format(webroot)) - return False - - if os.path.isdir(webroot): - Log.debug(self, "Removing {0}".format(webroot)) - WOFileUtils.rm(self, webroot) - return True - Log.debug(self, "{0} does not exist".format(webroot)) - return False - - -def removeNginxConf(self, domain): - if os.path.isfile('/etc/nginx/sites-available/{0}' - .format(domain)): - Log.debug(self, "Removing Nginx configuration") - WOFileUtils.rm(self, '/etc/nginx/sites-enabled/{0}' - .format(domain)) - WOFileUtils.rm(self, '/etc/nginx/sites-available/{0}' - .format(domain)) - WOService.reload_service(self, 'nginx') - WOGit.add(self, ["/etc/nginx"], - msg="Deleted {0} " - .format(domain)) - - -def removeAcmeConf(self, domain): - if os.path.isdir('/etc/letsencrypt/renewal/{0}_ecc' - .format(domain)): - Log.debug(self, "Removing Acme configuration") - WOFileUtils.rm(self, '/etc/letsencrypt/renewal/{0}_ecc' - .format(domain)) - WOFileUtils.rm(self, '/etc/letsencrypt/live/{0}' - .format(domain)) - WOGit.add(self, ["/etc/letsencrypt"], - msg="Deleted {0} " - .format(domain)) - - -def doCleanupAction(self, domain='', webroot='', dbname='', dbuser='', - dbhost=''): - """ - Removes the nginx configuration and database for the domain provided. - doCleanupAction(self, domain='sitename', webroot='', - dbname='', dbuser='', dbhost='') - """ - if domain: - if os.path.isfile('/etc/nginx/sites-available/{0}' - .format(domain)): - removeNginxConf(self, domain) - if os.path.isdir('/etc/letsencrypt/renewal/{0}_ecc' - .format(domain)): - removeAcmeConf(self, domain) - - if webroot: - deleteWebRoot(self, webroot) - - if dbname: - if not dbuser: - raise SiteError("dbuser not provided") - if not dbhost: - raise SiteError("dbhost not provided") - deleteDB(self, dbname, dbuser, dbhost) - - -# setup letsencrypt for domain + www.domain -def setupLetsEncrypt(self, wo_domain_name): - - if os.path.isfile("/etc/letsencrypt/renewal/{0}_ecc/{0}.conf" - .format(wo_domain_name)): - if os.path.isfile("/etc/letsencrypt/" - "renewal/{0}_ecc/" - "fullchain.cer".format(wo_domain_name)): - Log.debug(self, "Let's Encrypt certificate " - "found for the domain: {0}" - .format(wo_domain_name)) - ssl = archivedCertificateHandle(self, wo_domain_name) - else: - Log.info(self, "Issuing SSL cert with acme.sh") - ssl = WOShellExec.cmd_exec(self, "/etc/letsencrypt/acme.sh " - "--config-home " - "'/etc/letsencrypt/config' " - "--issue " - "-d {0} -d www.{0} -w /var/www/html " - "-k ec-384 -f" - .format(wo_domain_name)) - else: - Log.info(self, "Issuing SSL cert with acme.sh") - ssl = WOShellExec.cmd_exec(self, "/etc/letsencrypt/acme.sh " - "--config-home " - "'/etc/letsencrypt/config' " - "--issue " - "-d {0} -d www.{0} -w /var/www/html " - "-k ec-384 -f" - .format(wo_domain_name)) - - if ssl: - - try: - Log.info(self, "Deploying SSL cert with acme.sh") - Log.debug(self, "Cert deployment for domain: {0}" - .format(wo_domain_name)) - sslsetup = WOShellExec.cmd_exec(self, "mkdir -p {0}/{1} && " - "/etc/letsencrypt/acme.sh " - "--config-home " - "'/etc/letsencrypt/config' " - "--install-cert -d {1} --ecc " - "--cert-file {0}/{1}/cert.pem " - "--key-file {0}/{1}/key.pem " - "--fullchain-file " - "{0}/{1}/fullchain.pem " - "--ca-file {0}/{1}/ca.pem " - "--reloadcmd " - "\"nginx -t && " - "service nginx restart\" " - .format(WOVariables.wo_ssl_live, - wo_domain_name)) - Log.info( - self, "Adding /var/www/{0}/conf/nginx/ssl.conf" - .format(wo_domain_name)) - - sslconf = open("/var/www/{0}/conf/nginx/ssl.conf" - .format(wo_domain_name), - encoding='utf-8', mode='w') - sslconf.write("listen 443 ssl http2;\n" - "listen [::]:443 ssl http2;\n" - "ssl_certificate {0}/{1}/fullchain.pem;\n" - "ssl_certificate_key {0}/{1}/key.pem;\n" - "ssl_trusted_certificate {0}/{1}/ca.pem;\n" - "ssl_stapling_verify on;\n" - .format(WOVariables.wo_ssl_live, wo_domain_name)) - sslconf.close() - updateSiteInfo(self, wo_domain_name, ssl=True) - - WOGit.add(self, ["/etc/letsencrypt"], - msg="Adding letsencrypt folder") - - except IOError as e: - Log.debug(self, str(e)) - Log.debug(self, "Error occured while generating " - "ssl.conf") - else: - Log.error(self, "Unable to install certificate", False) - Log.error(self, "Please make sure that your site is pointed to \n" - "same server on which " - "you are running Let\'s Encrypt Client " - "\n to allow it to verify the site automatically.") - -# setup letsencrypt for a subdomain - - -def setupLetsEncryptSubdomain(self, wo_domain_name): - - if os.path.isfile("/etc/letsencrypt/renewal/{0}_ecc/{0}.conf" - .format(wo_domain_name)): - if os.path.isfile("/etc/letsencrypt/" - "renewal/{0}_ecc/" - "fullchain.cer".format(wo_domain_name)): - Log.debug(self, "Let's Encrypt certificate " - "found for the domain: {0}" - .format(wo_domain_name)) - ssl = archivedCertificateHandle(self, wo_domain_name) - else: - Log.info(self, "Issuing SSL cert with acme.sh") - ssl = WOShellExec.cmd_exec(self, "/etc/letsencrypt/acme.sh " - "--config-home " - "'/etc/letsencrypt/config' " - "--issue " - "-d {0} -w /var/www/html " - "-k ec-384 -f" - .format(wo_domain_name)) - else: - Log.info(self, "Issuing SSL cert with acme.sh") - ssl = WOShellExec.cmd_exec(self, "/etc/letsencrypt/acme.sh " - "--config-home " - "'/etc/letsencrypt/config' " - "--issue " - "-d {0} -w /var/www/html " - "-k ec-384 -f" - .format(wo_domain_name)) - if ssl: - - try: - Log.info(self, "Deploying SSL cert with acme.sh") - Log.debug(self, "Deploying cert for domain: {0}" - .format(wo_domain_name)) - sslsetup = WOShellExec.cmd_exec(self, "mkdir -p {0}/{1} && " - "/etc/letsencrypt/acme.sh " - "--config-home " - "'/etc/letsencrypt/config' " - "--install-cert -d {1} --ecc " - "--cert-file {0}/{1}/cert.pem " - "--key-file {0}/{1}/key.pem " - "--fullchain-file " - "{0}/{1}/fullchain.pem " - "--ca-file {0}/{1}/ca.pem " - "--reloadcmd " - "\"nginx -t && service nginx restart\" " - .format(WOVariables.wo_ssl_live, - wo_domain_name)) - - Log.info( - self, "Adding /var/www/{0}/conf/nginx/ssl.conf" - .format(wo_domain_name)) - - sslconf = open("/var/www/{0}/conf/nginx/ssl.conf" - .format(wo_domain_name), - encoding='utf-8', mode='w') - sslconf.write("listen 443 ssl http2;\n" - "listen [::]:443 ssl http2;\n" - "ssl_certificate {0}/{1}/fullchain.pem;\n" - "ssl_certificate_key {0}/{1}/key.pem;\n" - "ssl_trusted_certificate {0}/{1}/ca.pem;\n" - "ssl_stapling_verify on;\n" - .format(WOVariables.wo_ssl_live, wo_domain_name)) - sslconf.close() - updateSiteInfo(self, wo_domain_name, ssl=True) - - WOGit.add(self, ["/etc/letsencrypt"], - msg="Adding letsencrypt folder") - - except IOError as e: - Log.debug(self, str(e)) - Log.debug(self, "Error occured while generating " - "ssl.conf") - else: - Log.error(self, "Unable to create ssl.conf", False) - Log.error(self, "Please make sure that your site is pointed to \n" - "same server on which " - "you are running Let\'s Encrypt Client " - "\n to allow it to verify the site automatically.") - -# setup letsencrypt for domain + www.domain - - -def setupLetsEncryptWildcard(self, wo_domain_name, wo_acme_dns='dns_cf'): - - if os.path.isfile("/etc/letsencrypt/renewal/{0}_ecc/{0}.conf" - .format(wo_domain_name)): - if os.path.isfile("/etc/letsencrypt/" - "renewal/{0}_ecc/" - "fullchain.cer".format(wo_domain_name)): - Log.debug(self, "Let's Encrypt certificate " - "found for the domain: {0}" - .format(wo_domain_name)) - ssl = archivedCertificateHandle(self, wo_domain_name) - else: - Log.info(self, "Issuing SSL cert with acme.sh") - ssl = WOShellExec.cmd_exec(self, "/etc/letsencrypt/acme.sh " - "--config-home " - "'/etc/letsencrypt/config' " - "--issue " - "-d {0} -d *.{0} --dns {1} " - "-k ec-384 -f" - .format(wo_domain_name, wo_acme_dns)) - else: - Log.info(self, "Issuing SSL cert with acme.sh") - ssl = WOShellExec.cmd_exec(self, "/etc/letsencrypt/acme.sh " - "--config-home " - "'/etc/letsencrypt/config' " - "--issue " - "-d {0} -d *.{0} --dns {1} " - "-k ec-384 -f" - .format(wo_domain_name, wo_acme_dns)) - - if ssl: - - try: - Log.info(self, "Deploying SSL cert with acme.sh") - Log.debug(self, "Cert deployment for domain: {0}" - .format(wo_domain_name)) - sslsetup = WOShellExec.cmd_exec(self, "mkdir -p {0}/{1} && " - "/etc/letsencrypt/acme.sh " - "--config-home " - "'/etc/letsencrypt/config' " - "--install-cert -d {1} --ecc " - "--cert-file {0}/{1}/cert.pem " - "--key-file {0}/{1}/key.pem " - "--fullchain-file " - "{0}/{1}/fullchain.pem " - "--ca-file {0}/{1}/ca.pem " - "--reloadcmd " - "\"nginx -t && " - "service nginx restart\" " - .format(WOVariables.wo_ssl_live, - wo_domain_name)) - Log.info( - self, "Adding /var/www/{0}/conf/nginx/ssl.conf" - .format(wo_domain_name)) - - sslconf = open("/var/www/{0}/conf/nginx/ssl.conf" - .format(wo_domain_name), - encoding='utf-8', mode='w') - sslconf.write("listen 443 ssl http2;\n" - "listen [::]:443 ssl http2;\n" - "ssl_certificate {0}/{1}/fullchain.pem;\n" - "ssl_certificate_key {0}/{1}/key.pem;\n" - "ssl_trusted_certificate {0}/{1}/ca.pem;\n" - "ssl_stapling_verify on;\n" - .format(WOVariables.wo_ssl_live, wo_domain_name)) - sslconf.close() - updateSiteInfo(self, wo_domain_name, ssl=True) - - WOGit.add(self, ["/etc/letsencrypt"], - msg="Adding letsencrypt folder") - - except IOError as e: - Log.debug(self, str(e)) - Log.debug(self, "Error occured while generating " - "ssl.conf") - else: - Log.error(self, "Unable to install certificate", False) - Log.error(self, "Please make sure that your site is pointed to \n" - "same server on which " - "you are running Let\'s Encrypt Client " - "\n to allow it to verify the site automatically.") - - -# letsencrypt cert renewal - - -def renewLetsEncrypt(self, wo_domain_name): - - ssl = WOShellExec.cmd_exec( - self, "/etc/letsencrypt/acme.sh " - "--config-home " - "'/etc/letsencrypt/config' " - "--renew -d {0} --ecc --force" - .format(wo_domain_name)) - - mail_list = '' - if not ssl: - Log.error(self, "ERROR : Let's Encrypt certificate renewal FAILED!", - False) - if (SSL.getExpirationDays(self, wo_domain_name) > 0): - Log.error(self, "Your current certificate will expire within " + - str(SSL.getExpirationDays(self, wo_domain_name)) + - " days.", False) - else: - Log.error(self, "Your current certificate already expired!", False) - - # WOSendMail("wordops@{0}".format(wo_domain_name), wo_wp_email, - # "[FAIL] HTTPS cert renewal {0}".format(wo_domain_name), - # "Hi,\n\nHTTPS certificate renewal for https://{0} - # was unsuccessful.".format(wo_domain_name) + - # "\nPlease check the WordOps log for reason - # The current expiry date is : " + - # str(SSL.getExpirationDate(self, wo_domain_name)) + - # "\n\nFor support visit https://wordops.net/support . - # \n\nBest regards,\nYour WordOps Worker", files=mail_list, - # port=25, isTls=False) - Log.error(self, "Check the WO log for more details " - "`tail /var/log/wo/wordops.log`") - - WOGit.add(self, ["/etc/letsencrypt"], - msg="Adding letsencrypt folder") - # WOSendMail("wordops@{0}".format(wo_domain_name), wo_wp_email, - # "[SUCCESS] Let's Encrypt certificate renewal {0}".format(wo_domain_name), - # "Hi,\n\nYour Let's Encrypt certificate has been renewed for - # https://{0} .".format(wo_domain_name) + - # "\nYour new certificate will expire on : " + - # str(SSL.getExpirationDate(self, wo_domain_name)) + - # "\n\nBest regards,\nYour WordOps Worker", files=mail_list, - # port=25, isTls=False) - -# redirect= False to disable https redirection - - -def setupHsts(self, wo_domain_name): - Log.info( - self, "Adding /var/www/{0}/conf/nginx/hsts.conf" - .format(wo_domain_name)) - - hstsconf = open("/var/www/{0}/conf/nginx/hsts.conf" - .format(wo_domain_name), - encoding='utf-8', mode='w') - hstsconf.write("more_set_headers " - "\"Strict-Transport-Security: " - "max-age=31536000; " - "'includeSubDomains; " - "preload\";") - hstsconf.close() - return 0 - - -def httpsRedirect(self, wo_domain_name, redirect=True, wildcard=False): - if redirect: - if os.path.isfile("/etc/nginx/conf.d/force-ssl-{0}.conf.disabled" - .format(wo_domain_name)): - WOFileUtils.mvfile(self, - "/etc/nginx/conf.d/force-ssl-{0}.conf.disabled" - .format(wo_domain_name), - "/etc/nginx/conf.d/force-ssl-{0}.conf" - .format(wo_domain_name)) - else: - if wildcard: - try: - Log.info( - self, "Adding /etc/nginx/conf.d/force-ssl-{0}.conf" - .format(wo_domain_name)) - sslconf = open("/etc/nginx/conf.d/force-ssl-{0}.conf" - .format(wo_domain_name), - encoding='utf-8', mode='w') - sslconf.write("server {\n" - "\tlisten 80;\n" + - "\tlisten [::]:80;\n" + - "\tserver_name *.{0} {0};\n" - .format(wo_domain_name) + - "\treturn 301 https://$host" - "$request_uri;\n}") - sslconf.close() - except IOError as e: - Log.debug(self, str(e)) - Log.debug(self, "Error occured while generating " - "/etc/nginx/conf.d/force-ssl-{0}.conf" - .format(wo_domain_name)) - else: - try: - Log.info( - self, "Adding /etc/nginx/conf.d/force-ssl-{0}.conf" - .format(wo_domain_name)) - - sslconf = open("/etc/nginx/conf.d/force-ssl-{0}.conf" - .format(wo_domain_name), - encoding='utf-8', mode='w') - sslconf.write("server {\n" - "\tlisten 80;\n" + - "\tlisten [::]:80;\n" + - "\tserver_name www.{0} {0};\n" - .format(wo_domain_name) + - "\treturn 301 https://{0}" - .format(wo_domain_name)+"$request_uri;\n}") - sslconf.close() - - except IOError as e: - Log.debug(self, str(e)) - Log.debug(self, "Error occured while generating " - "/etc/nginx/conf.d/force-ssl-{0}.conf" - .format(wo_domain_name)) - - Log.info(self, "Added HTTPS Force Redirection for Site " - " http://{0}".format(wo_domain_name)) - # Nginx Configation into GIT - WOGit.add(self, - ["/etc/nginx"], msg="Adding /etc/nginx/conf.d/" - "force-ssl-{0}.conf".format(wo_domain_name)) - else: - if os.path.isfile("/etc/nginx/conf.d/force-ssl-{0}.conf" - .format(wo_domain_name)): - WOFileUtils.mvfile(self, "/etc/nginx/conf.d/force-ssl-{0}.conf" - .format(wo_domain_name), - "/etc/nginx/conf.d/force-ssl-{0}.conf.disabled" - .format(wo_domain_name)) - Log.info(self, "Disabled HTTPS Force Redirection for Site " - " http://{0}".format(wo_domain_name)) - - -def archivedCertificateHandle(self, domain): - Log.warn(self, "You already have an existing certificate " - "for the domain requested.\n" - "(ref: {0}/" - "{1}_ecc/{1}.conf)".format(WOVariables.wo_ssl_archive, domain) + - "\nPlease select an option from below?" - "\n\t1: Reinstall existing certificate" - "\n\t2: Keep the existing certificate for now" - "\n\t3: Renew & replace the certificate (limit ~5 per 7 days)" - "") - check_prompt = input( - "\nType the appropriate number [1-3] or any other key to cancel: ") - if not os.path.isfile("{0}/{1}/fullchain.pem" - .format(WOVariables.wo_ssl_live, domain)): - Log.error( - self, "{0}/{1}/fullchain.pem file is missing." - .format(WOVariables.wo_ssl_live, domain)) - - if check_prompt == "1": - Log.info(self, "Issuing SSL cert with acme.sh") - ssl = WOShellExec.cmd_exec(self, "mkdir -p {0}/{1} && " - "/etc/letsencrypt/acme.sh " - "--config-home " - "'/etc/letsencrypt/config' " - "--install-cert -d {1} --ecc " - "--cert-file {0}/{1}/cert.pem " - "--key-file {0}/{1}/key.pem " - "--fullchain-file " - "{0}/{1}/fullchain.pem " - "--ca-file {0}/{1}/ca.pem " - "--reloadcmd " - "\"service nginx restart\" " - .format(WOVariables.wo_ssl_live, - domain)) - if ssl: - - try: - - if not os.path.isfile("/var/www/{0}/conf/nginx/ssl.conf" - .format(domain)): - Log.info( - self, "Adding /var/www/{0}/conf/nginx/ssl.conf" - .format(domain)) - - sslconf = open("/var/www/{0}/conf/nginx/ssl.conf" - .format(domain), - encoding='utf-8', mode='w') - sslconf.write("listen 443 ssl http2;\n" - "listen [::]:443 ssl http2;\n" - "ssl_certificate " - "{0}/{1}/fullchain.pem;\n" - "ssl_certificate_key {0}/{1}/key.pem;\n" - "ssl_trusted_certificate {0}/{1}/ca.pem;\n" - "ssl_stapling_verify on;\n" - .format(WOVariables.wo_ssl_live, domain)) - sslconf.close() - - updateSiteInfo(self, domain, ssl=True) - - except IOError as e: - Log.debug(self, str(e)) - Log.debug(self, "Error occured while generating " - "ssl.conf") - - elif (check_prompt == "2"): - Log.info(self, "Using Existing Certificate files") - if not os.path.isfile("{0}/{1}/fullchain.pem" - .format(WOVariables.wo_ssl_live, domain)): - Log.error(self, "Certificate files not found. Skipping.\n" - "Please check if following file exist" - "\n\t/etc/letsencrypt/live/{0}/fullchain.pem\n\t" - "/etc/letsencrypt/live/{0}/key.pem".format(domain)) - - updateSiteInfo(self, domain, ssl=True) - - elif (check_prompt == "3"): - Log.info(self, "Issuing SSL cert with acme.sh") - ssl = WOShellExec.cmd_exec(self, "/etc/letsencrypt/acme.sh " - "--config-home " - "'/etc/letsencrypt/config' " - "--renew -d {0} --ecc " - "--force" - .format(domain)) - - if ssl: - - try: - - WOShellExec.cmd_exec(self, "mkdir -p {0}/{1} && " - "/etc/letsencrypt/acme.sh " - "--config-home " - "'/etc/letsencrypt/config' " - "--install-cert -d {1} --ecc " - "--cert-file {0}/{1}/cert.pem " - "--key-file {0}/{1}/key.pem " - "--fullchain-file " - "{0}/{1}/fullchain.pem " - "ssl_trusted_certificate " - "{0}/{1}/ca.pem;\n" - "--reloadcmd " - "\"service nginx restart\" " - .format(WOVariables.wo_ssl_live, domain)) - - except IOError as e: - Log.debug(self, str(e)) - Log.debug(self, "Error occured while installing " - "the certificate") - - else: - Log.error(self, "Operation cancelled by user.") - - if os.path.isfile("{0}/conf/nginx/ssl.conf" - .format(domain)): - Log.info(self, "Existing ssl.conf . Backing it up ..") - WOFileUtils.mvfile(self, "/var/www/{0}/conf/nginx/ssl.conf" - .format(domain), - '/var/www/{0}/conf/nginx/ssl.conf.bak' - .format(domain)) - - return ssl +from wo.cli.plugins.stack import WOStackController +from wo.core.fileutils import WOFileUtils +from wo.core.mysql import * +from wo.core.shellexec import * +from wo.core.sslutils import SSL +from wo.core.variables import WOVariables +from wo.cli.plugins.sitedb import * +from wo.core.aptget import WOAptGet +from wo.core.git import WOGit +from wo.core.logging import Log +from wo.core.sendmail import WOSendMail +from wo.core.services import WOService +import subprocess +from subprocess import CalledProcessError +import os +import random +import string +import sys +import getpass +import glob +import re +import platform + + +class SiteError(Exception): + """Custom Exception Occured when setting up site""" + + def __init__(self, message): + self.message = message + + def __str__(self): + return repr(self.message) + + +def pre_run_checks(self): + + # Check nginx configuration + Log.info(self, "Running pre-update checks, please wait...") + try: + Log.debug(self, "checking NGINX configuration ...") + FNULL = open('/dev/null', 'w') + ret = subprocess.check_call(["nginx", "-t"], stdout=FNULL, + stderr=subprocess.STDOUT) + except CalledProcessError as e: + Log.debug(self, "{0}".format(str(e))) + raise SiteError("nginx configuration check failed.") + + +def check_domain_exists(self, domain): + if getSiteInfo(self, domain): + return True + return False + + +def setupdomain(self, data): + + # for debug purpose + # for key, value in data.items() : + # print (key, value) + + wo_domain_name = data['site_name'] + wo_site_webroot = data['webroot'] + + # Check if nginx configuration already exists + # if os.path.isfile('/etc/nginx/sites-available/{0}' + # .format(wo_domain_name)): + # raise SiteError("nginx configuration already exists for site") + + Log.info(self, "Setting up NGINX configuration \t", end='') + # write nginx config for file + try: + wo_site_nginx_conf = open('/etc/nginx/sites-available/{0}' + .format(wo_domain_name), encoding='utf-8', + mode='w') + if not data['php73']: + self.app.render((data), 'virtualconf.mustache', + out=wo_site_nginx_conf) + else: + self.app.render((data), 'virtualconf-php7.mustache', + out=wo_site_nginx_conf) + wo_site_nginx_conf.close() + except IOError as e: + Log.debug(self, "{0}".format(e)) + raise SiteError("create nginx configuration failed for site") + except Exception as e: + Log.debug(self, "{0}".format(e)) + raise SiteError("create nginx configuration failed for site") + finally: + # Check nginx -t and return status over it + try: + Log.debug(self, "Checking generated nginx conf, please wait...") + FNULL = open('/dev/null', 'w') + ret = subprocess.check_call(["nginx", "-t"], stdout=FNULL, + stderr=subprocess.STDOUT) + Log.info(self, "[" + Log.ENDC + "Done" + Log.OKBLUE + "]") + except CalledProcessError as e: + Log.debug(self, "{0}".format(str(e))) + Log.info(self, "[" + Log.ENDC + Log.FAIL + "Fail" + + Log.OKBLUE + "]") + raise SiteError("created nginx configuration failed for site." + " check with `nginx -t`") + + # create symbolic link for + WOFileUtils.create_symlink(self, ['/etc/nginx/sites-available/{0}' + .format(wo_domain_name), + '/etc/nginx/sites-enabled/{0}' + .format(wo_domain_name)]) + + # Creating htdocs & logs directory + Log.info(self, "Setting up webroot \t\t", end='') + try: + if not os.path.exists('{0}/htdocs'.format(wo_site_webroot)): + os.makedirs('{0}/htdocs'.format(wo_site_webroot)) + if not os.path.exists('{0}/logs'.format(wo_site_webroot)): + os.makedirs('{0}/logs'.format(wo_site_webroot)) + if not os.path.exists('{0}/conf/nginx'.format(wo_site_webroot)): + os.makedirs('{0}/conf/nginx'.format(wo_site_webroot)) + + WOFileUtils.create_symlink(self, ['/var/log/nginx/{0}.access.log' + .format(wo_domain_name), + '{0}/logs/access.log' + .format(wo_site_webroot)]) + WOFileUtils.create_symlink(self, ['/var/log/nginx/{0}.error.log' + .format(wo_domain_name), + '{0}/logs/error.log' + .format(wo_site_webroot)]) + except Exception as e: + Log.debug(self, "{0}".format(e)) + raise SiteError("setup webroot failed for site") + finally: + # TODO Check if directories are setup + if (os.path.exists('{0}/htdocs'.format(wo_site_webroot)) and + os.path.exists('{0}/logs'.format(wo_site_webroot))): + Log.info(self, "[" + Log.ENDC + "Done" + Log.OKBLUE + "]") + else: + Log.info(self, "[" + Log.ENDC + "Fail" + Log.OKBLUE + "]") + raise SiteError("setup webroot failed for site") + + +def setupdatabase(self, data): + wo_domain_name = data['site_name'] + wo_random = (''.join(random.sample(string.ascii_uppercase + + string.ascii_lowercase + + string.digits, 24))) + wo_replace_dot = wo_domain_name.replace('.', '_') + prompt_dbname = self.app.config.get('mysql', 'db-name') + prompt_dbuser = self.app.config.get('mysql', 'db-user') + wo_mysql_grant_host = self.app.config.get('mysql', 'grant-host') + wo_db_name = '' + wo_db_username = '' + wo_db_password = '' + + if prompt_dbname == 'True' or prompt_dbname == 'true': + try: + wo_db_name = input('Enter the MySQL database name [{0}]: ' + .format(wo_replace_dot)) + except EOFError as e: + Log.debug(self, "{0}".format(e)) + raise SiteError("Unable to input database name") + + if not wo_db_name: + wo_db_name = wo_replace_dot + + if prompt_dbuser == 'True' or prompt_dbuser == 'true': + try: + wo_db_username = input('Enter the MySQL database user name [{0}]: ' + .format(wo_replace_dot)) + wo_db_password = getpass.getpass(prompt='Enter the MySQL database' + ' password [{0}]: ' + .format(wo_random)) + except EOFError as e: + Log.debug(self, "{0}".format(e)) + raise SiteError("Unable to input database credentials") + + if not wo_db_username: + wo_db_username = wo_replace_dot + if not wo_db_password: + wo_db_password = wo_random + + if len(wo_db_username) > 16: + Log.debug(self, 'Autofix MySQL username (ERROR 1470 (HY000)),' + ' please wait') + wo_db_username = (wo_db_name[0:6] + generate_random()) + + # create MySQL database + Log.info(self, "Setting up database\t\t", end='') + Log.debug(self, "Creating database {0}".format(wo_db_name)) + try: + if WOMysql.check_db_exists(self, wo_db_name): + Log.debug(self, "Database already exists, Updating DB_NAME .. ") + wo_db_name = (wo_db_name[0:6] + generate_random()) + wo_db_username = (wo_db_name[0:6] + generate_random()) + except MySQLConnectionError as e: + raise SiteError("MySQL Connectivity problem occured") + + try: + WOMysql.execute(self, "create database `{0}`" + .format(wo_db_name)) + except StatementExcecutionError as e: + Log.info(self, "[" + Log.ENDC + Log.FAIL + "Failed" + Log.OKBLUE + "]") + raise SiteError("create database execution failed") + # Create MySQL User + Log.debug(self, "Creating user {0}".format(wo_db_username)) + Log.debug(self, "create user `{0}`@`{1}` identified by ''" + .format(wo_db_username, wo_mysql_grant_host)) + try: + WOMysql.execute(self, + "create user `{0}`@`{1}` identified by '{2}'" + .format(wo_db_username, wo_mysql_grant_host, + wo_db_password), log=False) + except StatementExcecutionError as e: + Log.info(self, "[" + Log.ENDC + Log.FAIL + "Failed" + Log.OKBLUE + "]") + raise SiteError("creating user failed for database") + + # Grant permission + Log.debug(self, "Setting up user privileges") + try: + WOMysql.execute(self, + "grant all privileges on `{0}`.* to `{1}`@`{2}`" + .format(wo_db_name, + wo_db_username, wo_mysql_grant_host)) + except StatementExcecutionError as e: + Log.info(self, "[" + Log.ENDC + Log.FAIL + "Failed" + Log.OKBLUE + "]") + SiteError("grant privileges to user failed for database ") + + Log.info(self, "[" + Log.ENDC + "Done" + Log.OKBLUE + "]") + + 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_mysql_grant_host'] = wo_mysql_grant_host + return(data) + + +def setupwordpress(self, data): + wo_domain_name = data['site_name'] + wo_site_webroot = data['webroot'] + prompt_wpprefix = self.app.config.get('wordpress', 'prefix') + wo_wp_user = self.app.config.get('wordpress', 'user') + wo_wp_pass = self.app.config.get('wordpress', 'password') + wo_wp_email = self.app.config.get('wordpress', 'email') + # Random characters + wo_random = (''.join(random.sample(string.ascii_uppercase + + string.ascii_lowercase + + string.digits, 15))) + wo_wp_prefix = '' + # wo_wp_user = '' + # wo_wp_pass = '' + + if 'wp-user' in data.keys() and data['wp-user']: + wo_wp_user = data['wp-user'] + if 'wp-email' in data.keys() and data['wp-email']: + wo_wp_email = data['wp-email'] + if 'wp-pass' in data.keys() and data['wp-pass']: + wo_wp_pass = data['wp-pass'] + + Log.info(self, "Downloading WordPress \t\t", end='') + WOFileUtils.chdir(self, '{0}/htdocs/'.format(wo_site_webroot)) + try: + if WOShellExec.cmd_exec(self, "wp --allow-root core" + " download"): + pass + else: + Log.info(self, "[" + Log.ENDC + Log.FAIL + + "Fail" + Log.OKBLUE + "]") + raise SiteError("download WordPress core failed") + except CommandExecutionError as e: + Log.info(self, "[" + Log.ENDC + Log.FAIL + "Fail" + Log.OKBLUE + "]") + raise SiteError(self, "download WordPress core failed") + + Log.info(self, "[" + Log.ENDC + "Done" + Log.OKBLUE + "]") + + if not (data['wo_db_name'] and data['wo_db_user'] and data['wo_db_pass']): + data = setupdatabase(self, data) + if prompt_wpprefix == 'True' or prompt_wpprefix == 'true': + try: + wo_wp_prefix = input('Enter the WordPress table prefix [wp_]: ') + while not re.match('^[A-Za-z0-9_]*$', wo_wp_prefix): + Log.warn(self, "table prefix can only " + "contain numbers, letters, and underscores") + wo_wp_prefix = input('Enter the WordPress table prefix [wp_]: ' + ) + except EOFError as e: + Log.debug(self, "{0}".format(e)) + raise SiteError("input table prefix failed") + + if not wo_wp_prefix: + wo_wp_prefix = 'wp_' + + # Modify wp-config.php & move outside the webroot + + WOFileUtils.chdir(self, '{0}/htdocs/'.format(wo_site_webroot)) + Log.debug(self, "Setting up wp-config file") + if not data['multisite']: + Log.debug(self, "Generating wp-config for WordPress Single site") + Log.debug(self, "bash -c \"php {0} --allow-root " + .format(WOVariables.wo_wpcli_path) + + "config create " + + "--dbname=\'{0}\' --dbprefix=\'{1}\' --dbuser=\'{2}\' " + "--dbhost=\'{3}\' " + .format(data['wo_db_name'], wo_wp_prefix, + data['wo_db_user'], data['wo_db_host']) + + "--dbpass=\'{0}\' " + "--extra-php< {1}/{0}.gz" + .format(data['wo_db_name'], + backup_path)): + Log.info(self, + "[" + Log.ENDC + Log.FAIL + "Fail" + Log.OKBLUE + "]") + raise SiteError("mysqldump failed to backup database") + except CommandExecutionError as e: + Log.info(self, "[" + Log.ENDC + "Fail" + Log.OKBLUE + "]") + raise SiteError("mysqldump failed to backup database") + Log.info(self, "[" + Log.ENDC + "Done" + Log.OKBLUE + "]") + # move wp-config.php/wo-config.php to backup + if data['currsitetype'] in ['mysql', 'proxy']: + if data['php73'] is True and not data['wp']: + WOFileUtils.copyfile(self, configfiles[0], backup_path) + else: + WOFileUtils.mvfile(self, configfiles[0], backup_path) + else: + WOFileUtils.copyfile(self, configfiles[0], backup_path) + + +def site_package_check(self, stype): + apt_packages = [] + packages = [] + stack = WOStackController() + stack.app = self.app + if stype in ['html', 'proxy', 'php', 'mysql', 'wp', 'wpsubdir', + 'wpsubdomain', 'php73']: + Log.debug(self, "Setting apt_packages variable for Nginx") + + # Check if server has nginx-custom package + if not (WOAptGet.is_installed(self, 'nginx-custom') or + WOAptGet.is_installed(self, 'nginx-mainline')): + # check if Server has nginx-plus installed + if WOAptGet.is_installed(self, 'nginx-plus'): + # 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 + stack.post_pref(apt, packages) + elif WOAptGet.is_installed(self, 'nginx'): + Log.info(self, "WordOps detected a previously" + "installed Nginx package. " + "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 + stack.post_pref(apt, packages) + else: + apt_packages = apt_packages + WOVariables.wo_nginx + else: + # Fix for Nginx white screen death + if not WOFileUtils.grep(self, '/etc/nginx/fastcgi_params', + 'SCRIPT_FILENAME'): + with open('/etc/nginx/fastcgi_params', encoding='utf-8', + mode='a') as wo_nginx: + wo_nginx.write('fastcgi_param \tSCRIPT_FILENAME ' + '\t$request_filename;\n') + + if self.app.pargs.php and self.app.pargs.php73: + Log.error( + self, "Error: two different PHP versions cannot be " + "combined within the same WordOps site") + + if not self.app.pargs.php73 and stype in ['php', 'mysql', 'wp', 'wpsubdir', + 'wpsubdomain']: + 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 + else: + apt_packages = apt_packages + WOVariables.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 + else: + apt_packages = apt_packages + WOVariables.wo_php73 + + if stype in ['mysql', 'wp', 'wpsubdir', 'wpsubdomain']: + Log.debug(self, "Setting apt_packages variable for MySQL") + if not WOShellExec.cmd_exec(self, "mysqladmin ping"): + apt_packages = apt_packages + WOVariables.wo_mysql + packages = packages + [["https://raw.githubusercontent.com/" + "major/MySQLTuner-perl/master/" + "mysqltuner.pl", "/usr/bin/mysqltuner", + "MySQLTuner"]] + + if stype in ['wp', 'wpsubdir', 'wpsubdomain']: + Log.debug(self, "Setting packages variable for WP-CLI") + if not WOShellExec.cmd_exec(self, "command -v wp"): + packages = packages + [["https://github.com/wp-cli/wp-cli/" + "releases/download/v{0}/" + "wp-cli-{0}.phar" + .format(WOVariables.wo_wp_cli), + "/usr/local/bin/wp", "WP-CLI"]] + if self.app.pargs.wpredis: + Log.debug(self, "Setting apt_packages variable for redis") + if not WOAptGet.is_installed(self, 'redis-server'): + apt_packages = apt_packages + WOVariables.wo_redis + + if (os.path.isfile("/etc/nginx/nginx.conf") and + not os.path.isfile("/etc/nginx/common/redis-php72.conf")): + + data = dict() + Log.debug(self, 'Writting the nginx configuration to ' + 'file /etc/nginx/common/redis-php72.conf') + wo_nginx = open('/etc/nginx/common/redis-php72.conf', + encoding='utf-8', mode='w') + self.app.render((data), 'redis.mustache', + out=wo_nginx) + wo_nginx.close() + + if os.path.isfile("/etc/nginx/conf.d/upstream.conf"): + if not WOFileUtils.grep(self, "/etc/nginx/conf.d/" + "upstream.conf", + "redis"): + with open("/etc/nginx/conf.d/upstream.conf", + "a") as redis_file: + redis_file.write("upstream redis {\n" + " server 127.0.0.1:6379;\n" + " keepalive 10;\n}") + + if (os.path.isfile("/etc/nginx/nginx.conf") and + not os.path.isfile("/etc/nginx/conf.d/redis.conf")): + with open("/etc/nginx/conf.d/redis.conf", "a") as redis_file: + redis_file.write("# Log format Settings\n" + "log_format rt_cache_redis '$remote_addr" + " $upstream_response_time " + "$srcache_fetch_status [$time_local] '\n" + "'$http_host \"$request\" $status" + " $body_bytes_sent '\n" + "'\"$http_referer\" \"$http_user_agent\"';\n") + + if self.app.pargs.php73: + 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 + else: + apt_packages = apt_packages + WOVariables.wo_php73 + + if (os.path.isdir("/etc/nginx/common") and + not os.path.isfile("/etc/nginx/common/php73.conf")): + data = dict() + Log.debug(self, 'Writting the nginx configuration to ' + 'file /etc/nginx/common/locations-wo.conf') + wo_nginx = open('/etc/nginx/common/locations-wo.conf', + encoding='utf-8', mode='w') + self.app.render((data), 'locations-php7.mustache', + out=wo_nginx) + wo_nginx.close() + + Log.debug(self, 'Writting the nginx configuration to ' + 'file /etc/nginx/common/php73.conf') + wo_nginx = open('/etc/nginx/common/php73.conf', + encoding='utf-8', mode='w') + self.app.render((data), 'php7.mustache', + out=wo_nginx) + wo_nginx.close() + + Log.debug(self, 'Writting the nginx configuration to ' + 'file /etc/nginx/common/wpcommon-php73.conf') + wo_nginx = open('/etc/nginx/common/wpcommon-php73.conf', + encoding='utf-8', mode='w') + self.app.render((data), 'wpcommon-php7.mustache', + out=wo_nginx) + wo_nginx.close() + + Log.debug(self, 'Writting the nginx configuration to ' + 'file /etc/nginx/common/wpfc-php73.conf') + wo_nginx = open('/etc/nginx/common/wpfc-php73.conf', + encoding='utf-8', mode='w') + self.app.render((data), 'wpfc-php7.mustache', + out=wo_nginx) + wo_nginx.close() + + Log.debug(self, 'Writting the nginx configuration to ' + 'file /etc/nginx/common/wpsc-php73.conf') + wo_nginx = open('/etc/nginx/common/wpsc-php73.conf', + encoding='utf-8', mode='w') + self.app.render((data), 'wpsc-php7.mustache', + out=wo_nginx) + wo_nginx.close() + + if (os.path.isfile("/etc/nginx/nginx.conf") and + not os.path.isfile("/etc/nginx/common/redis-php73.conf")): + data = dict() + Log.debug(self, 'Writting the nginx configuration to ' + 'file /etc/nginx/common/redis-php73.conf') + wo_nginx = open('/etc/nginx/common/redis-php73.conf', + encoding='utf-8', mode='w') + self.app.render((data), 'redis-php7.mustache', + out=wo_nginx) + wo_nginx.close() + + if os.path.isfile("/etc/nginx/conf.d/upstream.conf"): + if not WOFileUtils.grep(self, "/etc/nginx/conf.d/upstream.conf", + "php73"): + with open("/etc/nginx/conf.d/upstream.conf", "a") as php_file: + php_file.write("upstream php73 {\nserver" + "unix:/var/run/php/php73-fpm.sock;\n}\n" + "upstream debug73" + " {\nserver 127.0.0.1:9173;\n}\n") + + return(stack.install(apt_packages=apt_packages, packages=packages, + disp_msg=False)) + + +def updatewpuserpassword(self, wo_domain, wo_site_webroot): + + wo_wp_user = '' + wo_wp_pass = '' + WOFileUtils.chdir(self, '{0}/htdocs/'.format(wo_site_webroot)) + + # Check if wo_domain is wordpress install + try: + is_wp = WOShellExec.cmd_exec(self, "wp --allow-root core" + " version") + except CommandExecutionError as e: + raise SiteError("is WordPress site? check command failed ") + + # Exit if wo_domain is not wordpress install + if not is_wp: + Log.error(self, "{0} does not seem to be a WordPress site" + .format(wo_domain)) + + try: + wo_wp_user = input("Provide WordPress user name [admin]: ") + except Exception as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "\nCould not update password") + + if wo_wp_user == "?": + Log.info(self, "Fetching WordPress user list") + try: + WOShellExec.cmd_exec(self, "wp --allow-root user list " + "--fields=user_login | grep -v user_login") + except CommandExecutionError as e: + raise SiteError("fetch wp userlist command failed") + + if not wo_wp_user: + wo_wp_user = 'admin' + + try: + is_user_exist = WOShellExec.cmd_exec(self, "wp --allow-root user list " + "--fields=user_login | grep {0}$ " + .format(wo_wp_user)) + except CommandExecutionError as e: + raise SiteError("if wp user exists check command failed") + + if is_user_exist: + try: + wo_wp_pass = getpass.getpass(prompt="Provide password for " + "{0} user: " + .format(wo_wp_user)) + + while not wo_wp_pass: + wo_wp_pass = getpass.getpass(prompt="Provide password for " + "{0} user: " + .format(wo_wp_user)) + except Exception as e: + Log.debug(self, "{0}".format(e)) + raise SiteError("failed to read password input ") + + try: + WOShellExec.cmd_exec(self, "wp --allow-root user update {0}" + " --user_pass={1}" + .format(wo_wp_user, wo_wp_pass)) + except CommandExecutionError as e: + raise SiteError("wp user password update command failed") + Log.info(self, "Password updated successfully") + + else: + Log.error(self, "Invalid WordPress user {0} for {1}." + .format(wo_wp_user, wo_domain)) + + +def display_cache_settings(self, data): + if data['wpsc']: + if data['multisite']: + Log.info(self, "Configure WPSC:" + "\t\thttp://{0}/wp-admin/network/settings.php?" + "page=wpsupercache" + .format(data['site_name'])) + else: + Log.info(self, "Configure WPSC:" + "\t\thttp://{0}/wp-admin/options-general.php?" + "page=wpsupercache" + .format(data['site_name'])) + + if data['wpredis']: + if data['multisite']: + Log.info(self, "Configure redis-cache:" + "\thttp://{0}/wp-admin/network/settings.php?" + "page=redis-cache".format(data['site_name'])) + else: + Log.info(self, "Configure redis-cache:" + "\thttp://{0}/wp-admin/options-general.php?" + "page=redis-cache".format(data['site_name'])) + Log.info(self, "Object Cache:\t\tEnable") + + +def logwatch(self, logfiles): + import zlib + import base64 + import time + from wo.core import logwatch + + def callback(filename, lines): + for line in lines: + if line.find(':::') == -1: + print(line) + else: + data = line.split(':::') + try: + print(data[0], data[1], + zlib.decompress(base64.decodestring(data[2]))) + except Exception as e: + Log.info(time.time(), + 'caught exception rendering a new log line in %s' + % filename) + + l = logwatch.LogWatcher(logfiles, callback) + l.loop() + + +def detSitePar(opts): + """ + Takes dictionary of parsed arguments + 1.returns sitetype and cachetype + 2. raises RuntimeError when wrong combination is used like + "--wp --wpsubdir" or "--html --wp" + """ + sitetype, cachetype = '', '' + typelist = list() + cachelist = list() + for key, val in opts.items(): + if val and key in ['html', 'php', 'mysql', 'wp', + 'wpsubdir', 'wpsubdomain', 'php73']: + typelist.append(key) + elif val and key in ['wpfc', 'wpsc', 'wpredis']: + cachelist.append(key) + + if len(typelist) > 1 or len(cachelist) > 1: + if len(cachelist) > 1: + raise RuntimeError( + "Could not determine cache type." + "Multiple cache parameter entered") + elif False not in [x in ('php', 'mysql', 'html') for x in typelist]: + sitetype = 'mysql' + if not cachelist: + cachetype = 'basic' + else: + cachetype = cachelist[0] + elif False not in [x in ('php73', 'mysql', 'html') for x in typelist]: + sitetype = 'mysql' + if not cachelist: + cachetype = 'basic' + else: + cachetype = cachelist[0] + elif False not in [x in ('php', 'mysql') for x in typelist]: + sitetype = 'mysql' + if not cachelist: + cachetype = 'basic' + else: + cachetype = cachelist[0] + elif False not in [x in ('php73', 'mysql') for x in typelist]: + sitetype = 'mysql' + if not cachelist: + cachetype = 'basic' + else: + cachetype = cachelist[0] + elif False not in [x in ('html', 'mysql') for x in typelist]: + sitetype = 'mysql' + if not cachelist: + cachetype = 'basic' + else: + cachetype = cachelist[0] + elif False not in [x in ('php', 'html') for x in typelist]: + sitetype = 'php' + if not cachelist: + cachetype = 'basic' + else: + cachetype = cachelist[0] + elif False not in [x in ('php73', 'html') for x in typelist]: + sitetype = 'php73' + if not cachelist: + cachetype = 'basic' + else: + cachetype = cachelist[0] + elif False not in [x in ('wp', 'wpsubdir') for x in typelist]: + sitetype = 'wpsubdir' + if not cachelist: + cachetype = 'basic' + else: + cachetype = cachelist[0] + elif False not in [x in ('wp', 'wpsubdomain') for x in typelist]: + sitetype = 'wpsubdomain' + if not cachelist: + cachetype = 'basic' + else: + cachetype = cachelist[0] + elif False not in [x in ('wp', 'php73') for x in typelist]: + sitetype = 'wp' + if not cachelist: + cachetype = 'basic' + else: + cachetype = cachelist[0] + elif False not in [x in ('wpsubdir', 'php73') for x in typelist]: + sitetype = 'wpsubdir' + if not cachelist: + cachetype = 'basic' + else: + cachetype = cachelist[0] + elif False not in [x in ('wpsubdomain', 'php73') for x in typelist]: + sitetype = 'wpsubdomain' + if not cachelist: + cachetype = 'basic' + else: + cachetype = cachelist[0] + else: + raise RuntimeError("could not determine site and cache type") + else: + if not typelist and not cachelist: + sitetype = None + cachetype = None + elif (not typelist or "php73" in typelist) and cachelist: + sitetype = 'wp' + cachetype = cachelist[0] + elif typelist and (not cachelist): + sitetype = typelist[0] + cachetype = 'basic' + else: + sitetype = typelist[0] + cachetype = cachelist[0] + + return (sitetype, cachetype) + + +def generate_random(): + wo_random10 = (''.join(random.sample(string.ascii_uppercase + + string.ascii_lowercase + + string.digits, 24))) + return wo_random10 + + +def deleteDB(self, dbname, dbuser, dbhost, exit=True): + try: + # Check if Database exists + try: + if WOMysql.check_db_exists(self, dbname): + # Drop database if exists + Log.debug(self, "dropping database `{0}`".format(dbname)) + WOMysql.execute(self, + "drop database `{0}`".format(dbname), + errormsg='Unable to drop database {0}' + .format(dbname)) + except StatementExcecutionError as e: + Log.debug(self, "drop database failed") + Log.info(self, "Database {0} not dropped".format(dbname)) + + except MySQLConnectionError as e: + Log.debug(self, "Mysql Connection problem occured") + + if dbuser != 'root': + Log.debug(self, "dropping user `{0}`".format(dbuser)) + try: + WOMysql.execute(self, + "drop user `{0}`@`{1}`" + .format(dbuser, dbhost)) + except StatementExcecutionError as e: + Log.debug(self, "drop database user failed") + Log.info(self, "Database {0} not dropped".format(dbuser)) + try: + WOMysql.execute(self, "flush privileges") + except StatementExcecutionError as e: + Log.debug(self, "drop database failed") + Log.info(self, "Database {0} not dropped".format(dbname)) + except Exception as e: + Log.error(self, "Error occured while deleting database", exit) + + +def deleteWebRoot(self, webroot): + # do some preprocessing before proceeding + webroot = webroot.strip() + if (webroot == "/var/www/" or webroot == "/var/www" or + webroot == "/var/www/.." or webroot == "/var/www/."): + Log.debug(self, "Tried to remove {0}, but didn't remove it" + .format(webroot)) + return False + + if os.path.isdir(webroot): + Log.debug(self, "Removing {0}".format(webroot)) + WOFileUtils.rm(self, webroot) + return True + Log.debug(self, "{0} does not exist".format(webroot)) + return False + + +def removeNginxConf(self, domain): + if os.path.isfile('/etc/nginx/sites-available/{0}' + .format(domain)): + Log.debug(self, "Removing Nginx configuration") + WOFileUtils.rm(self, '/etc/nginx/sites-enabled/{0}' + .format(domain)) + WOFileUtils.rm(self, '/etc/nginx/sites-available/{0}' + .format(domain)) + WOService.reload_service(self, 'nginx') + WOGit.add(self, ["/etc/nginx"], + msg="Deleted {0} " + .format(domain)) + + +def removeAcmeConf(self, domain): + if os.path.isdir('/etc/letsencrypt/renewal/{0}_ecc' + .format(domain)): + Log.debug(self, "Removing Acme configuration") + WOFileUtils.rm(self, '/etc/letsencrypt/renewal/{0}_ecc' + .format(domain)) + WOFileUtils.rm(self, '/etc/letsencrypt/live/{0}' + .format(domain)) + WOGit.add(self, ["/etc/letsencrypt"], + msg="Deleted {0} " + .format(domain)) + + +def doCleanupAction(self, domain='', webroot='', dbname='', dbuser='', + dbhost=''): + """ + Removes the nginx configuration and database for the domain provided. + doCleanupAction(self, domain='sitename', webroot='', + dbname='', dbuser='', dbhost='') + """ + if domain: + if os.path.isfile('/etc/nginx/sites-available/{0}' + .format(domain)): + removeNginxConf(self, domain) + if os.path.isdir('/etc/letsencrypt/renewal/{0}_ecc' + .format(domain)): + removeAcmeConf(self, domain) + + if webroot: + deleteWebRoot(self, webroot) + + if dbname: + if not dbuser: + raise SiteError("dbuser not provided") + if not dbhost: + raise SiteError("dbhost not provided") + deleteDB(self, dbname, dbuser, dbhost) + + +# setup letsencrypt for domain + www.domain +def setupLetsEncrypt(self, wo_domain_name): + + if os.path.isfile("/etc/letsencrypt/renewal/{0}_ecc/{0}.conf" + .format(wo_domain_name)): + if os.path.isfile("/etc/letsencrypt/" + "renewal/{0}_ecc/" + "fullchain.cer".format(wo_domain_name)): + Log.debug(self, "Let's Encrypt certificate " + "found for the domain: {0}" + .format(wo_domain_name)) + ssl = archivedCertificateHandle(self, wo_domain_name) + else: + Log.info(self, "Issuing SSL cert with acme.sh") + ssl = WOShellExec.cmd_exec(self, "/etc/letsencrypt/acme.sh " + "--config-home " + "'/etc/letsencrypt/config' " + "--issue " + "-d {0} -d www.{0} -w /var/www/html " + "-k ec-384 -f" + .format(wo_domain_name)) + else: + Log.info(self, "Issuing SSL cert with acme.sh") + ssl = WOShellExec.cmd_exec(self, "/etc/letsencrypt/acme.sh " + "--config-home " + "'/etc/letsencrypt/config' " + "--issue " + "-d {0} -d www.{0} -w /var/www/html " + "-k ec-384 -f" + .format(wo_domain_name)) + + if ssl: + + try: + Log.info(self, "Deploying SSL cert with acme.sh") + Log.debug(self, "Cert deployment for domain: {0}" + .format(wo_domain_name)) + sslsetup = WOShellExec.cmd_exec(self, "mkdir -p {0}/{1} && " + "/etc/letsencrypt/acme.sh " + "--config-home " + "'/etc/letsencrypt/config' " + "--install-cert -d {1} --ecc " + "--cert-file {0}/{1}/cert.pem " + "--key-file {0}/{1}/key.pem " + "--fullchain-file " + "{0}/{1}/fullchain.pem " + "--ca-file {0}/{1}/ca.pem " + "--reloadcmd " + "\"nginx -t && " + "service nginx restart\" " + .format(WOVariables.wo_ssl_live, + wo_domain_name)) + Log.info( + self, "Adding /var/www/{0}/conf/nginx/ssl.conf" + .format(wo_domain_name)) + + sslconf = open("/var/www/{0}/conf/nginx/ssl.conf" + .format(wo_domain_name), + encoding='utf-8', mode='w') + sslconf.write("listen 443 ssl http2;\n" + "listen [::]:443 ssl http2;\n" + "ssl_certificate {0}/{1}/fullchain.pem;\n" + "ssl_certificate_key {0}/{1}/key.pem;\n" + "ssl_trusted_certificate {0}/{1}/ca.pem;\n" + "ssl_stapling_verify on;\n" + .format(WOVariables.wo_ssl_live, wo_domain_name)) + sslconf.close() + updateSiteInfo(self, wo_domain_name, ssl=True) + + WOGit.add(self, ["/etc/letsencrypt"], + msg="Adding letsencrypt folder") + + except IOError as e: + Log.debug(self, str(e)) + Log.debug(self, "Error occured while generating " + "ssl.conf") + else: + Log.error(self, "Unable to install certificate", False) + Log.error(self, "Please make sure that your site is pointed to \n" + "same server on which " + "you are running Let\'s Encrypt Client " + "\n to allow it to verify the site automatically.") + +# setup letsencrypt for a subdomain + + +def setupLetsEncryptSubdomain(self, wo_domain_name): + + if os.path.isfile("/etc/letsencrypt/renewal/{0}_ecc/{0}.conf" + .format(wo_domain_name)): + if os.path.isfile("/etc/letsencrypt/" + "renewal/{0}_ecc/" + "fullchain.cer".format(wo_domain_name)): + Log.debug(self, "Let's Encrypt certificate " + "found for the domain: {0}" + .format(wo_domain_name)) + ssl = archivedCertificateHandle(self, wo_domain_name) + else: + Log.info(self, "Issuing SSL cert with acme.sh") + ssl = WOShellExec.cmd_exec(self, "/etc/letsencrypt/acme.sh " + "--config-home " + "'/etc/letsencrypt/config' " + "--issue " + "-d {0} -w /var/www/html " + "-k ec-384 -f" + .format(wo_domain_name)) + else: + Log.info(self, "Issuing SSL cert with acme.sh") + ssl = WOShellExec.cmd_exec(self, "/etc/letsencrypt/acme.sh " + "--config-home " + "'/etc/letsencrypt/config' " + "--issue " + "-d {0} -w /var/www/html " + "-k ec-384 -f" + .format(wo_domain_name)) + if ssl: + + try: + Log.info(self, "Deploying SSL cert with acme.sh") + Log.debug(self, "Deploying cert for domain: {0}" + .format(wo_domain_name)) + sslsetup = WOShellExec.cmd_exec(self, "mkdir -p {0}/{1} && " + "/etc/letsencrypt/acme.sh " + "--config-home " + "'/etc/letsencrypt/config' " + "--install-cert -d {1} --ecc " + "--cert-file {0}/{1}/cert.pem " + "--key-file {0}/{1}/key.pem " + "--fullchain-file " + "{0}/{1}/fullchain.pem " + "--ca-file {0}/{1}/ca.pem " + "--reloadcmd " + "\"nginx -t && service nginx restart\" " + .format(WOVariables.wo_ssl_live, + wo_domain_name)) + + Log.info( + self, "Adding /var/www/{0}/conf/nginx/ssl.conf" + .format(wo_domain_name)) + + sslconf = open("/var/www/{0}/conf/nginx/ssl.conf" + .format(wo_domain_name), + encoding='utf-8', mode='w') + sslconf.write("listen 443 ssl http2;\n" + "listen [::]:443 ssl http2;\n" + "ssl_certificate {0}/{1}/fullchain.pem;\n" + "ssl_certificate_key {0}/{1}/key.pem;\n" + "ssl_trusted_certificate {0}/{1}/ca.pem;\n" + "ssl_stapling_verify on;\n" + .format(WOVariables.wo_ssl_live, wo_domain_name)) + sslconf.close() + updateSiteInfo(self, wo_domain_name, ssl=True) + + WOGit.add(self, ["/etc/letsencrypt"], + msg="Adding letsencrypt folder") + + except IOError as e: + Log.debug(self, str(e)) + Log.debug(self, "Error occured while generating " + "ssl.conf") + else: + Log.error(self, "Unable to create ssl.conf", False) + Log.error(self, "Please make sure that your site is pointed to \n" + "same server on which " + "you are running Let\'s Encrypt Client " + "\n to allow it to verify the site automatically.") + +# setup letsencrypt for domain + www.domain + + +def setupLetsEncryptWildcard(self, wo_domain_name, wo_acme_dns='dns_cf'): + + if os.path.isfile("/etc/letsencrypt/renewal/{0}_ecc/{0}.conf" + .format(wo_domain_name)): + if os.path.isfile("/etc/letsencrypt/" + "renewal/{0}_ecc/" + "fullchain.cer".format(wo_domain_name)): + Log.debug(self, "Let's Encrypt certificate " + "found for the domain: {0}" + .format(wo_domain_name)) + ssl = archivedCertificateHandle(self, wo_domain_name) + else: + Log.info(self, "Issuing SSL cert with acme.sh") + ssl = WOShellExec.cmd_exec(self, "/etc/letsencrypt/acme.sh " + "--config-home " + "'/etc/letsencrypt/config' " + "--issue " + "-d {0} -d *.{0} --dns {1} " + "-k ec-384 -f" + .format(wo_domain_name, wo_acme_dns)) + else: + Log.info(self, "Issuing SSL cert with acme.sh") + ssl = WOShellExec.cmd_exec(self, "/etc/letsencrypt/acme.sh " + "--config-home " + "'/etc/letsencrypt/config' " + "--issue " + "-d {0} -d *.{0} --dns {1} " + "-k ec-384 -f" + .format(wo_domain_name, wo_acme_dns)) + + if ssl: + + try: + Log.info(self, "Deploying SSL cert with acme.sh") + Log.debug(self, "Cert deployment for domain: {0}" + .format(wo_domain_name)) + sslsetup = WOShellExec.cmd_exec(self, "mkdir -p {0}/{1} && " + "/etc/letsencrypt/acme.sh " + "--config-home " + "'/etc/letsencrypt/config' " + "--install-cert -d {1} --ecc " + "--cert-file {0}/{1}/cert.pem " + "--key-file {0}/{1}/key.pem " + "--fullchain-file " + "{0}/{1}/fullchain.pem " + "--ca-file {0}/{1}/ca.pem " + "--reloadcmd " + "\"nginx -t && " + "service nginx restart\" " + .format(WOVariables.wo_ssl_live, + wo_domain_name)) + Log.info( + self, "Adding /var/www/{0}/conf/nginx/ssl.conf" + .format(wo_domain_name)) + + sslconf = open("/var/www/{0}/conf/nginx/ssl.conf" + .format(wo_domain_name), + encoding='utf-8', mode='w') + sslconf.write("listen 443 ssl http2;\n" + "listen [::]:443 ssl http2;\n" + "ssl_certificate {0}/{1}/fullchain.pem;\n" + "ssl_certificate_key {0}/{1}/key.pem;\n" + "ssl_trusted_certificate {0}/{1}/ca.pem;\n" + "ssl_stapling_verify on;\n" + .format(WOVariables.wo_ssl_live, wo_domain_name)) + sslconf.close() + updateSiteInfo(self, wo_domain_name, ssl=True) + + WOGit.add(self, ["/etc/letsencrypt"], + msg="Adding letsencrypt folder") + + except IOError as e: + Log.debug(self, str(e)) + Log.debug(self, "Error occured while generating " + "ssl.conf") + else: + Log.error(self, "Unable to install certificate", False) + Log.error(self, "Please make sure that your site is pointed to \n" + "same server on which " + "you are running Let\'s Encrypt Client " + "\n to allow it to verify the site automatically.") + + +# letsencrypt cert renewal + + +def renewLetsEncrypt(self, wo_domain_name): + + ssl = WOShellExec.cmd_exec( + self, "/etc/letsencrypt/acme.sh " + "--config-home " + "'/etc/letsencrypt/config' " + "--renew -d {0} --ecc --force" + .format(wo_domain_name)) + + mail_list = '' + if not ssl: + Log.error(self, "ERROR : Let's Encrypt certificate renewal FAILED!", + False) + if (SSL.getExpirationDays(self, wo_domain_name) > 0): + Log.error(self, "Your current certificate will expire within " + + str(SSL.getExpirationDays(self, wo_domain_name)) + + " days.", False) + else: + Log.error(self, "Your current certificate already expired!", False) + + # WOSendMail("wordops@{0}".format(wo_domain_name), wo_wp_email, + # "[FAIL] HTTPS cert renewal {0}".format(wo_domain_name), + # "Hi,\n\nHTTPS certificate renewal for https://{0} + # was unsuccessful.".format(wo_domain_name) + + # "\nPlease check the WordOps log for reason + # The current expiry date is : " + + # str(SSL.getExpirationDate(self, wo_domain_name)) + + # "\n\nFor support visit https://wordops.net/support . + # \n\nBest regards,\nYour WordOps Worker", files=mail_list, + # port=25, isTls=False) + Log.error(self, "Check the WO log for more details " + "`tail /var/log/wo/wordops.log`") + + WOGit.add(self, ["/etc/letsencrypt"], + msg="Adding letsencrypt folder") + # WOSendMail("wordops@{0}".format(wo_domain_name), wo_wp_email, + # "[SUCCESS] Let's Encrypt certificate renewal {0}".format(wo_domain_name), + # "Hi,\n\nYour Let's Encrypt certificate has been renewed for + # https://{0} .".format(wo_domain_name) + + # "\nYour new certificate will expire on : " + + # str(SSL.getExpirationDate(self, wo_domain_name)) + + # "\n\nBest regards,\nYour WordOps Worker", files=mail_list, + # port=25, isTls=False) + +# redirect= False to disable https redirection + + +def setupHsts(self, wo_domain_name): + Log.info( + self, "Adding /var/www/{0}/conf/nginx/hsts.conf" + .format(wo_domain_name)) + + hstsconf = open("/var/www/{0}/conf/nginx/hsts.conf" + .format(wo_domain_name), + encoding='utf-8', mode='w') + hstsconf.write("more_set_headers " + "\"Strict-Transport-Security: " + "max-age=31536000; " + "'includeSubDomains; " + "preload\";") + hstsconf.close() + return 0 + + +def httpsRedirect(self, wo_domain_name, redirect=True, wildcard=False): + if redirect: + if os.path.isfile("/etc/nginx/conf.d/force-ssl-{0}.conf.disabled" + .format(wo_domain_name)): + WOFileUtils.mvfile(self, + "/etc/nginx/conf.d/force-ssl-{0}.conf.disabled" + .format(wo_domain_name), + "/etc/nginx/conf.d/force-ssl-{0}.conf" + .format(wo_domain_name)) + else: + if wildcard: + try: + Log.info( + self, "Adding /etc/nginx/conf.d/force-ssl-{0}.conf" + .format(wo_domain_name)) + sslconf = open("/etc/nginx/conf.d/force-ssl-{0}.conf" + .format(wo_domain_name), + encoding='utf-8', mode='w') + sslconf.write("server {\n" + "\tlisten 80;\n" + + "\tlisten [::]:80;\n" + + "\tserver_name *.{0} {0};\n" + .format(wo_domain_name) + + "\treturn 301 https://$host" + "$request_uri;\n}") + sslconf.close() + except IOError as e: + Log.debug(self, str(e)) + Log.debug(self, "Error occured while generating " + "/etc/nginx/conf.d/force-ssl-{0}.conf" + .format(wo_domain_name)) + else: + try: + Log.info( + self, "Adding /etc/nginx/conf.d/force-ssl-{0}.conf" + .format(wo_domain_name)) + + sslconf = open("/etc/nginx/conf.d/force-ssl-{0}.conf" + .format(wo_domain_name), + encoding='utf-8', mode='w') + sslconf.write("server {\n" + "\tlisten 80;\n" + + "\tlisten [::]:80;\n" + + "\tserver_name www.{0} {0};\n" + .format(wo_domain_name) + + "\treturn 301 https://{0}" + .format(wo_domain_name)+"$request_uri;\n}") + sslconf.close() + + except IOError as e: + Log.debug(self, str(e)) + Log.debug(self, "Error occured while generating " + "/etc/nginx/conf.d/force-ssl-{0}.conf" + .format(wo_domain_name)) + + Log.info(self, "Added HTTPS Force Redirection for Site " + " http://{0}".format(wo_domain_name)) + # Nginx Configation into GIT + WOGit.add(self, + ["/etc/nginx"], msg="Adding /etc/nginx/conf.d/" + "force-ssl-{0}.conf".format(wo_domain_name)) + else: + if os.path.isfile("/etc/nginx/conf.d/force-ssl-{0}.conf" + .format(wo_domain_name)): + WOFileUtils.mvfile(self, "/etc/nginx/conf.d/force-ssl-{0}.conf" + .format(wo_domain_name), + "/etc/nginx/conf.d/force-ssl-{0}.conf.disabled" + .format(wo_domain_name)) + Log.info(self, "Disabled HTTPS Force Redirection for Site " + " http://{0}".format(wo_domain_name)) + + +def archivedCertificateHandle(self, domain): + Log.warn(self, "You already have an existing certificate " + "for the domain requested.\n" + "(ref: {0}/" + "{1}_ecc/{1}.conf)".format(WOVariables.wo_ssl_archive, domain) + + "\nPlease select an option from below?" + "\n\t1: Reinstall existing certificate" + "\n\t2: Keep the existing certificate for now" + "\n\t3: Renew & replace the certificate (limit ~5 per 7 days)" + "") + check_prompt = input( + "\nType the appropriate number [1-3] or any other key to cancel: ") + if not os.path.isfile("{0}/{1}/fullchain.pem" + .format(WOVariables.wo_ssl_live, domain)): + Log.error( + self, "{0}/{1}/fullchain.pem file is missing." + .format(WOVariables.wo_ssl_live, domain)) + + if check_prompt == "1": + Log.info(self, "Issuing SSL cert with acme.sh") + ssl = WOShellExec.cmd_exec(self, "mkdir -p {0}/{1} && " + "/etc/letsencrypt/acme.sh " + "--config-home " + "'/etc/letsencrypt/config' " + "--install-cert -d {1} --ecc " + "--cert-file {0}/{1}/cert.pem " + "--key-file {0}/{1}/key.pem " + "--fullchain-file " + "{0}/{1}/fullchain.pem " + "--ca-file {0}/{1}/ca.pem " + "--reloadcmd " + "\"service nginx restart\" " + .format(WOVariables.wo_ssl_live, + domain)) + if ssl: + + try: + + if not os.path.isfile("/var/www/{0}/conf/nginx/ssl.conf" + .format(domain)): + Log.info( + self, "Adding /var/www/{0}/conf/nginx/ssl.conf" + .format(domain)) + + sslconf = open("/var/www/{0}/conf/nginx/ssl.conf" + .format(domain), + encoding='utf-8', mode='w') + sslconf.write("listen 443 ssl http2;\n" + "listen [::]:443 ssl http2;\n" + "ssl_certificate " + "{0}/{1}/fullchain.pem;\n" + "ssl_certificate_key {0}/{1}/key.pem;\n" + "ssl_trusted_certificate {0}/{1}/ca.pem;\n" + "ssl_stapling_verify on;\n" + .format(WOVariables.wo_ssl_live, domain)) + sslconf.close() + + updateSiteInfo(self, domain, ssl=True) + + except IOError as e: + Log.debug(self, str(e)) + Log.debug(self, "Error occured while generating " + "ssl.conf") + + elif (check_prompt == "2"): + Log.info(self, "Using Existing Certificate files") + if not os.path.isfile("{0}/{1}/fullchain.pem" + .format(WOVariables.wo_ssl_live, domain)): + Log.error(self, "Certificate files not found. Skipping.\n" + "Please check if following file exist" + "\n\t/etc/letsencrypt/live/{0}/fullchain.pem\n\t" + "/etc/letsencrypt/live/{0}/key.pem".format(domain)) + + updateSiteInfo(self, domain, ssl=True) + + elif (check_prompt == "3"): + Log.info(self, "Issuing SSL cert with acme.sh") + ssl = WOShellExec.cmd_exec(self, "/etc/letsencrypt/acme.sh " + "--config-home " + "'/etc/letsencrypt/config' " + "--renew -d {0} --ecc " + "--force" + .format(domain)) + + if ssl: + + try: + + WOShellExec.cmd_exec(self, "mkdir -p {0}/{1} && " + "/etc/letsencrypt/acme.sh " + "--config-home " + "'/etc/letsencrypt/config' " + "--install-cert -d {1} --ecc " + "--cert-file {0}/{1}/cert.pem " + "--key-file {0}/{1}/key.pem " + "--fullchain-file " + "{0}/{1}/fullchain.pem " + "ssl_trusted_certificate " + "{0}/{1}/ca.pem;\n" + "--reloadcmd " + "\"service nginx restart\" " + .format(WOVariables.wo_ssl_live, domain)) + + except IOError as e: + Log.debug(self, str(e)) + Log.debug(self, "Error occured while installing " + "the certificate") + + else: + Log.error(self, "Operation cancelled by user.") + + if os.path.isfile("{0}/conf/nginx/ssl.conf" + .format(domain)): + Log.info(self, "Existing ssl.conf . Backing it up ..") + WOFileUtils.mvfile(self, "/var/www/{0}/conf/nginx/ssl.conf" + .format(domain), + '/var/www/{0}/conf/nginx/ssl.conf.bak' + .format(domain)) + + return ssl diff --git a/wo/cli/plugins/stack.py b/wo/cli/plugins/stack.py index 4ea0cd4..c0c623e 100644 --- a/wo/cli/plugins/stack.py +++ b/wo/cli/plugins/stack.py @@ -370,7 +370,7 @@ class WOStackController(CementBaseController): # php73 conf if not os.path.isfile("/etc/nginx/common/php73.conf"): - # data = dict() + # data = dict() Log.debug(self, 'Writting the nginx configuration to ' 'file /etc/nginx/common/php73.conf') wo_nginx = open('/etc/nginx/common/php73.conf', @@ -1418,6 +1418,7 @@ class WOStackController(CementBaseController): self.app.pargs.web = True self.app.pargs.admin = True self.app.pargs.php73 = True + self.app.pargs.redis = True if self.app.pargs.web: self.app.pargs.nginx = True diff --git a/wo/cli/plugins/stack_upgrade.py b/wo/cli/plugins/stack_upgrade.py index c8f1446..8eb0343 100644 --- a/wo/cli/plugins/stack_upgrade.py +++ b/wo/cli/plugins/stack_upgrade.py @@ -38,6 +38,8 @@ class WOStackUpgradeController(CementBaseController): dict(help='Upgrade Redis', action='store_true')), (['--netdata'], dict(help='Upgrade Netdata', action='store_true')), + (['--phpmyadmin'], + dict(help='Upgrade phpMyAdmin', action='store_true')), (['--no-prompt'], dict(help="Upgrade Packages without any prompt", action='store_true')), @@ -83,7 +85,9 @@ class WOStackUpgradeController(CementBaseController): if ((not self.app.pargs.web) and (not self.app.pargs.nginx) and (not self.app.pargs.php) and (not self.app.pargs.mysql) and (not self.app.pargs.all) and (not self.app.pargs.wpcli) and - (not self.app.pargs.netdata) and (not self.app.pargs.redis)): + (not self.app.pargs.netdata) and + (not self.app.pargs.phpmyadmin) and + (not self.app.pargs.redis)): self.app.pargs.web = True if self.app.pargs.all: @@ -144,6 +148,18 @@ class WOStackUpgradeController(CementBaseController): 'kickstart-static64.sh', '/var/lib/wo/tmp/kickstart.sh', 'Netdata']] + if self.app.pargs.phpmyadmin: + if os.path.isdir('/var/www/22222/htdocs/db/pma'): + packages = packages + \ + [["https://files.phpmyadmin.net" + "/phpMyAdmin/{0}/" + "phpMyAdmin-{0}-" + "all-languages" + ".zip".format(WOVariables.wo_phpmyadmin), + "/var/lib/wo/tmp/pma.tar.gz", + "PHPMyAdmin"]] + else: + Log.error(self, "phpMyAdmin isn't installed") if len(packages) or len(apt_packages): @@ -190,6 +206,24 @@ class WOStackUpgradeController(CementBaseController): WOShellExec.cmd_exec(self, "/bin/bash /var/lib/wo/tmp/" "kickstart.sh " "--dont-wait") + if self.app.pargs.phpmyadmin: + Log.info(self, "Upgrading phpMyAdmin, please wait...") + WOExtract.extract( + self, '/var/lib/wo/tmp/pma.tar.gz', '/var/lib/wo/tmp/') + shutil.copyfile('{0}22222/htdocs/db/pma' + '/config.inc.php' + .format(WOVariables.wo_webroot), + '/var/lib/wo/tmp/phpMyAdmin-{0}' + '-all-languages/config.inc.php' + .format(WOVariables.wo_phpmyadmin) + ) + WOFileUtils.remove('{0}22222/htdocs/db/pma' + .format(WOVariables.wo_webroot)) + shutil.move('/var/lib/wo/tmp/phpMyAdmin-{0}' + '-all-languages/' + .format(WOVariables.wo_phpmyadmin), + '{0}22222/htdocs/db/pma/' + .format(WOVariables.wo_webroot)) Log.info(self, "Successfully updated packages") else: diff --git a/wo/core/variables.py b/wo/core/variables.py index 2e1b43f..6df473c 100644 --- a/wo/core/variables.py +++ b/wo/core/variables.py @@ -1,186 +1,187 @@ -"""WordOps core variable module""" -import platform -import socket -import configparser -import os -import psutil -import datetime - - -class WOVariables(): - """Intialization of core variables""" - - # WordOps version - wo_version = "3.9.5.4" - # WordOps packages versions - wo_wp_cli = "2.2.0" - wo_adminer = "4.7.1" - - # Get WPCLI path - wo_wpcli_path = os.popen('command -v wp | tr "\n" " "').read() - if wo_wpcli_path == '': - wo_wpcli_path = '/usr/local/bin/wp ' - - # get wan network interface name - 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 == '': - wo_wan = 'eth0' - - # Current date and time of System - wo_date = datetime.datetime.now().strftime('%d%b%Y%H%M%S') - - # WordOps core variables - wo_platform_distro = os.popen("lsb_release -si " - "| tr -d \'\\n\'").read().lower() - wo_platform_version = platform.linux_distribution()[1] - wo_platform_codename = os.popen("lsb_release -sc | tr -d \'\\n\'").read() - - # Get timezone of system - if os.path.isfile('/etc/timezone'): - with open("/etc/timezone", "r") as tzfile: - wo_timezone = tzfile.read().replace('\n', '') - if wo_timezone == "Etc/UTC": - wo_timezone = "UTC" - else: - wo_timezone = "Europe/Amsterdam" - - # Get FQDN of system - wo_fqdn = socket.getfqdn() - - # WordOps default webroot path - wo_webroot = '/var/www/' - - # WordOps default renewal SSL certificates path - wo_ssl_archive = '/etc/letsencrypt/renewal' - - # WordOps default live SSL certificates path - wo_ssl_live = '/etc/letsencrypt/live' - - # PHP user - wo_php_user = 'www-data' - - # Get git user name and EMail - config = configparser.ConfigParser() - config.read(os.path.expanduser("~")+'/.gitconfig') - try: - wo_user = config['user']['name'] - wo_email = config['user']['email'] - except Exception as e: - 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)) - - # MySQL hostname - wo_mysql_host = "" - config = configparser.RawConfigParser() - if os.path.exists('/etc/mysql/conf.d/my.cnf'): - cnfpath = "/etc/mysql/conf.d/my.cnf" - else: - cnfpath = os.path.expanduser("~")+"/.my.cnf" - if [cnfpath] == config.read(cnfpath): - try: - wo_mysql_host = config.get('client', 'host') - except configparser.NoOptionError as e: - wo_mysql_host = "localhost" - else: - wo_mysql_host = "localhost" - - # WordOps stack installation variables - # Nginx repo and packages - if wo_platform_distro == 'ubuntu': - if wo_platform_codename == 'trusty': - wo_nginx_repo = ("deb http://download.opensuse.org" - "/repositories/home:" - "/virtubox:/WordOps/xUbuntu_14.04/ /") - else: - wo_nginx_repo = "ppa:wordops/nginx-wo" - elif wo_platform_distro == 'debian': - if wo_platform_codename == 'jessie': - wo_nginx_repo = ("deb http://download.opensuse.org" - "/repositories/home:" - "/virtubox:/WordOps/Debian_8.0/ /") - elif wo_platform_codename == 'stretch': - wo_nginx_repo = ("deb http://download.opensuse.org" - "/repositories/home:" - "/virtubox:/WordOps/Debian_9.0/ /") - else: - wo_nginx_repo = ("deb http://download.opensuse.org/repositories/home:" - "/virtubox:/WordOps/Raspbian_9.0/ /") - - wo_nginx = ["nginx-custom", "nginx-wo"] - wo_nginx_key = '188C9FB063F0247A' - - # PHP repo and packages - if wo_platform_distro == 'ubuntu': - wo_php_repo = "ppa:ondrej/php" - wo_php = ["php7.2-fpm", "php7.2-curl", "php7.2-gd", "php7.2-imap", - "php7.2-readline", "php7.2-common", "php7.2-recode", - "php7.2-cli", "php7.2-mbstring", - "php7.2-bcmath", "php7.2-mysql", "php7.2-opcache", - "php7.2-zip", "php7.2-xml", "php7.2-soap"] - wo_php73 = ["php7.3-fpm", "php7.3-curl", "php7.3-gd", "php7.3-imap", - "php7.3-readline", "php7.3-common", "php7.3-recode", - "php7.3-cli", "php7.3-mbstring", - "php7.3-bcmath", "php7.3-mysql", "php7.3-opcache", - "php7.3-zip", "php7.3-xml", "php7.3-soap"] - wo_php_extra = ["php-memcached", "php-imagick", - "graphviz", "php-xdebug", "php-msgpack", "php-redis"] - wo_php_key = '' - else: - wo_php_repo = ( - "deb https://packages.sury.org/php/ {codename} main" - .format(codename=wo_platform_codename)) - wo_php = ["php7.2-fpm", "php7.2-curl", "php7.2-gd", "php7.2-imap", - "php7.2-readline", "php7.2-common", "php7.2-recode", - "php7.2-cli", "php7.2-mbstring", - "php7.2-bcmath", "php7.2-mysql", "php7.2-opcache", - "php7.2-zip", "php7.2-xml", "php7.2-soap"] - wo_php73 = ["php7.3-fpm", "php7.3-curl", "php7.3-gd", "php7.3-imap", - "php7.3-readline", "php7.3-common", "php7.3-recode", - "php7.3-cli", "php7.3-mbstring", - "php7.3-bcmath", "php7.3-mysql", "php7.3-opcache", - "php7.3-zip", "php7.3-xml", "php7.3-soap"] - wo_php_extra = ["php-memcached", "php-imagick", - "graphviz", "php-xdebug", "php-msgpack", "php-redis"] - - wo_php_key = 'AC0E47584A7A714D' - - # MySQL repo and packages - if wo_platform_distro == 'ubuntu': - wo_mysql_repo = ("deb [arch=amd64,ppc64el] " - "http://sfo1.mirrors.digitalocean.com/mariadb/repo/" - "10.3/ubuntu {codename} main" - .format(codename=wo_platform_codename)) - else: - wo_mysql_repo = ("deb [arch=amd64,ppc64el] " - "http://sfo1.mirrors.digitalocean.com/mariadb/repo/" - "10.3/debian {codename} main" - .format(codename=wo_platform_codename)) - wo_mysql = ["mariadb-server", "percona-toolkit", "python3-mysqldb"] - - wo_fail2ban = "fail2ban" - - # Redis repo details - if wo_platform_distro == 'ubuntu': - wo_redis_repo = ("ppa:chris-lea/redis-server") - - else: - wo_redis_repo = ("deb https://packages.sury.org/php/ {codename} all" - .format(codename=wo_platform_codename)) - - wo_redis = ['redis-server', 'php-redis'] - - # Repo path - wo_repo_file = "wo-repo.list" - wo_repo_file_path = ("/etc/apt/sources.list.d/" + wo_repo_file) - - # Application dabase file path - basedir = os.path.abspath(os.path.dirname('/var/lib/wo/')) - wo_db_uri = 'sqlite:///' + os.path.join(basedir, 'dbase.db') - - def __init__(self): - pass +"""WordOps core variable module""" +import platform +import socket +import configparser +import os +import psutil +import datetime + + +class WOVariables(): + """Intialization of core variables""" + + # WordOps version + wo_version = "3.9.5.4" + # WordOps packages versions + wo_wp_cli = "2.2.0" + wo_adminer = "4.7.1" + wo_phpmyadmin = "4.9.0.1" + + # Get WPCLI path + wo_wpcli_path = os.popen('command -v wp | tr "\n" " "').read() + if wo_wpcli_path == '': + wo_wpcli_path = '/usr/local/bin/wp ' + + # get wan network interface name + 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 == '': + wo_wan = 'eth0' + + # Current date and time of System + wo_date = datetime.datetime.now().strftime('%d%b%Y%H%M%S') + + # WordOps core variables + wo_platform_distro = os.popen("lsb_release -si " + "| tr -d \'\\n\'").read().lower() + wo_platform_version = platform.linux_distribution()[1] + wo_platform_codename = os.popen("lsb_release -sc | tr -d \'\\n\'").read() + + # Get timezone of system + if os.path.isfile('/etc/timezone'): + with open("/etc/timezone", "r") as tzfile: + wo_timezone = tzfile.read().replace('\n', '') + if wo_timezone == "Etc/UTC": + wo_timezone = "UTC" + else: + wo_timezone = "Europe/Amsterdam" + + # Get FQDN of system + wo_fqdn = socket.getfqdn() + + # WordOps default webroot path + wo_webroot = '/var/www/' + + # WordOps default renewal SSL certificates path + wo_ssl_archive = '/etc/letsencrypt/renewal' + + # WordOps default live SSL certificates path + wo_ssl_live = '/etc/letsencrypt/live' + + # PHP user + wo_php_user = 'www-data' + + # Get git user name and EMail + config = configparser.ConfigParser() + config.read(os.path.expanduser("~")+'/.gitconfig') + try: + wo_user = config['user']['name'] + wo_email = config['user']['email'] + except Exception as e: + 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)) + + # MySQL hostname + wo_mysql_host = "" + config = configparser.RawConfigParser() + if os.path.exists('/etc/mysql/conf.d/my.cnf'): + cnfpath = "/etc/mysql/conf.d/my.cnf" + else: + cnfpath = os.path.expanduser("~")+"/.my.cnf" + if [cnfpath] == config.read(cnfpath): + try: + wo_mysql_host = config.get('client', 'host') + except configparser.NoOptionError as e: + wo_mysql_host = "localhost" + else: + wo_mysql_host = "localhost" + + # WordOps stack installation variables + # Nginx repo and packages + if wo_platform_distro == 'ubuntu': + if wo_platform_codename == 'trusty': + wo_nginx_repo = ("deb http://download.opensuse.org" + "/repositories/home:" + "/virtubox:/WordOps/xUbuntu_14.04/ /") + else: + wo_nginx_repo = "ppa:wordops/nginx-wo" + elif wo_platform_distro == 'debian': + if wo_platform_codename == 'jessie': + wo_nginx_repo = ("deb http://download.opensuse.org" + "/repositories/home:" + "/virtubox:/WordOps/Debian_8.0/ /") + elif wo_platform_codename == 'stretch': + wo_nginx_repo = ("deb http://download.opensuse.org" + "/repositories/home:" + "/virtubox:/WordOps/Debian_9.0/ /") + else: + wo_nginx_repo = ("deb http://download.opensuse.org/repositories/home:" + "/virtubox:/WordOps/Raspbian_9.0/ /") + + wo_nginx = ["nginx-custom", "nginx-wo"] + wo_nginx_key = '188C9FB063F0247A' + + # PHP repo and packages + if wo_platform_distro == 'ubuntu': + wo_php_repo = "ppa:ondrej/php" + wo_php = ["php7.2-fpm", "php7.2-curl", "php7.2-gd", "php7.2-imap", + "php7.2-readline", "php7.2-common", "php7.2-recode", + "php7.2-cli", "php7.2-mbstring", + "php7.2-bcmath", "php7.2-mysql", "php7.2-opcache", + "php7.2-zip", "php7.2-xml", "php7.2-soap"] + wo_php73 = ["php7.3-fpm", "php7.3-curl", "php7.3-gd", "php7.3-imap", + "php7.3-readline", "php7.3-common", "php7.3-recode", + "php7.3-cli", "php7.3-mbstring", + "php7.3-bcmath", "php7.3-mysql", "php7.3-opcache", + "php7.3-zip", "php7.3-xml", "php7.3-soap"] + wo_php_extra = ["php-memcached", "php-imagick", + "graphviz", "php-xdebug", "php-msgpack", "php-redis"] + wo_php_key = '' + else: + wo_php_repo = ( + "deb https://packages.sury.org/php/ {codename} main" + .format(codename=wo_platform_codename)) + wo_php = ["php7.2-fpm", "php7.2-curl", "php7.2-gd", "php7.2-imap", + "php7.2-readline", "php7.2-common", "php7.2-recode", + "php7.2-cli", "php7.2-mbstring", + "php7.2-bcmath", "php7.2-mysql", "php7.2-opcache", + "php7.2-zip", "php7.2-xml", "php7.2-soap"] + wo_php73 = ["php7.3-fpm", "php7.3-curl", "php7.3-gd", "php7.3-imap", + "php7.3-readline", "php7.3-common", "php7.3-recode", + "php7.3-cli", "php7.3-mbstring", + "php7.3-bcmath", "php7.3-mysql", "php7.3-opcache", + "php7.3-zip", "php7.3-xml", "php7.3-soap"] + wo_php_extra = ["php-memcached", "php-imagick", + "graphviz", "php-xdebug", "php-msgpack", "php-redis"] + + wo_php_key = 'AC0E47584A7A714D' + + # MySQL repo and packages + if wo_platform_distro == 'ubuntu': + wo_mysql_repo = ("deb [arch=amd64,ppc64el] " + "http://sfo1.mirrors.digitalocean.com/mariadb/repo/" + "10.3/ubuntu {codename} main" + .format(codename=wo_platform_codename)) + else: + wo_mysql_repo = ("deb [arch=amd64,ppc64el] " + "http://sfo1.mirrors.digitalocean.com/mariadb/repo/" + "10.3/debian {codename} main" + .format(codename=wo_platform_codename)) + wo_mysql = ["mariadb-server", "percona-toolkit", "python3-mysqldb"] + + wo_fail2ban = "fail2ban" + + # Redis repo details + if wo_platform_distro == 'ubuntu': + wo_redis_repo = ("ppa:chris-lea/redis-server") + + else: + wo_redis_repo = ("deb https://packages.sury.org/php/ {codename} all" + .format(codename=wo_platform_codename)) + + wo_redis = ['redis-server', 'php-redis'] + + # Repo path + wo_repo_file = "wo-repo.list" + wo_repo_file_path = ("/etc/apt/sources.list.d/" + wo_repo_file) + + # Application dabase file path + basedir = os.path.abspath(os.path.dirname('/var/lib/wo/')) + wo_db_uri = 'sqlite:///' + os.path.join(basedir, 'dbase.db') + + def __init__(self): + pass