diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..d30a7b1f --- /dev/null +++ b/.gitignore @@ -0,0 +1,65 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.cache +nosetests.xml +coverage.xml + +# Translations +*.mo +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + + +# Vim .swp file +*.swp + +# Folder created for Nose testing +bin/ +coverage_report/ +include/ +local/ +man/ diff --git a/.travis.yml b/.travis.yml index f20bb3fe..4c1e15aa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ notifications: + slack: rtcamp:MGteQ7CA6kFIsNbMIarkeWxa webhooks: urls: - https://webhooks.gitter.im/e/bd77a26eab56de803949 @@ -9,152 +10,86 @@ notifications: language: bash before_install: -- rm -rf ~/.gnupg + - rm -rf ~/.gnupg before_script: -- sudo apt-get -qq purge mysql* graphviz* -- sudo apt-get -qq autoremove + - sudo bash -c 'echo example.com > /etc/hostname' + - sudo service hostname restart + - sudo apt-get -qq purge mysql* graphviz* + - sudo apt-get -qq autoremove + - sudo apt-get update script: -- sudo echo -e "[user]\n\tname = Mitesh Shah\n\temail = root@localhost.com" > ~/.gitconfig -- sudo echo "Travis Banch = $TRAVIS_BRANCH" -- sudo bash bin/install $TRAVIS_BRANCH - -- sudo ee stack install - -- sudo bash ee site create html.com -- sudo bash ee site create html.net --html - -- sudo bash ee site create php.com --php - -- sudo bash ee site create mysql.com --mysql - -- sudo bash ee site create site1.com --wp -- sudo bash ee site create site1.net --basic -- sudo bash ee site create site1.org --wp --basic -- sudo bash ee site create site1.in --basic --wp -- sudo bash ee site create subdomain.site1.in --basic --wp - -- sudo bash ee site create site2.com --wpsc -- sudo bash ee site create site2.net --wp --wpsc -- sudo bash ee site create site2.org --wpsc --wp - -- sudo bash ee site create site3.com --w3tc -- sudo bash ee site create site3.net --wp --w3tc -- sudo bash ee site create site3.org --w3tc --wp - -- sudo bash ee site create site4.com --wpfc -- sudo bash ee site create site4.net --wp --wpfc -- sudo bash ee site create site4.org --wpfc --wp - -- sudo bash ee site create site5.com --wpsubdir -- sudo bash ee site create site5.net --wpsubdir --basic -- sudo bash ee site create site5.org --basic --wpsubdir -- sudo bash ee site create site5.in --wpsubdirectory -- sudo bash ee site create site5.co --wpsubdirectory --basic -- sudo bash ee site create site5.co.in --basic --wpsubdirector - -- sudo bash ee site create site6.com --wpsubdir --wpsc -- sudo bash ee site create site6.net --wpsc --wpsubdir -- sudo bash ee site create site6.org --wpsubdirectory --wpsc -- sudo bash ee site create site6.in --wpsc --wpsubdirectory - -- sudo bash ee site create site7.com --wpsubdir --w3tc -- sudo bash ee site create site7.net --w3tc --wpsubdir -- sudo bash ee site create site7.org --wpsubdirectory --w3tc -- sudo bash ee site create site7.in --w3tc --wpsubdirectory - -- sudo bash ee site create site8.com --wpsubdir --wpfc -- sudo bash ee site create site8.net --wpfc --wpsubdir -- sudo bash ee site create site8.org --wpsubdirectory --wpfc -- sudo bash ee site create site8.in --wpfc --wpsubdirectory - - -- sudo bash ee site create site9.com --wpsubdom -- sudo bash ee site create site9.net --wpsubdom --basic -- sudo bash ee site create site9.org --basic --wpsubdom -- sudo bash ee site create site9.in --wpsubdomain -- sudo bash ee site create site9.co --wpsubdomain --basic -- sudo bash ee site create site9.co.in --basic --wpsubdomain - -- sudo bash ee site create site10.com --wpsubdom --wpsc -- sudo bash ee site create site10.net --wpsc --wpsubdom -- sudo bash ee site create site10.org --wpsubdomain --wpsc -- sudo bash ee site create site10.in --wpsc --wpsubdomain - -- sudo bash ee site create site11.com --wpsubdom --w3tc -- sudo bash ee site create site11.net --w3tc --wpsubdom -- sudo bash ee site create site11.org --wpsubdomain --w3tc -- sudo bash ee site create site11.in --w3tc --wpsubdomain - -- sudo bash ee site create site12.com --wpsubdom --wpfc -- sudo bash ee site create site12.net --wpfc --wpsubdom -- sudo bash ee site create site12.org --wpsubdomain --wpfc -- sudo bash ee site create site12.in --wpfc --wpsubdomain - -- sudo bash ee debug --nginx -- sudo bash ee debug --nginx stop -- sudo bash ee debug --nginx site1.com -- sudo bash ee debug --nginx site1.com --stop - -- sudo bash ee debug -rewrite -- sudo bash ee debug -rewrite --stop -- sudo bash ee debug -rewrite site1.com -- sudo bash ee debug -rewrite site1.com --stop - -- sudo bash ee debug --php -- sudo bash ee debug --php --stop -- sudo bash ee debug --php site1.com -- sudo bash ee debug --php site1.com --stop - -- sudo bash ee debug --fpm -- sudo bash ee debug --fpm --stop -- sudo bash ee debug --fpm site1.com -- sudo bash ee debug --fpm site1.com --stop - -- sudo bash ee debug --mysql -- sudo bash ee debug --mysql --stop -- sudo bash ee debug --mysql site1.com -- sudo bash ee debug --mysql site1.com --smysql - - -- sudo bash ee debug --wp site1.com -- sudo bash ee debug --wp site1.com --stop - -- sudo bash ee debug -- sudo bash ee debug --stop - -- sudo bash ee site create 1.com --html -- sudo bash ee site create 2.com --php -- sudo bash ee site create 3.com --mysql - -- sudo bash ee site update 1.com --wp -- sudo bash ee site update 2.com --wpsubdir - -- sudo bash ee site update 3.com --wpsubdomain -- sudo bash ee site update site1.com --wp --wpfc -- sudo bash ee site update site1.com --wp --w3tc -- sudo bash ee site update site1.com --wp --wpsc - -- sudo bash ee site update site5.com --wpsubdir --wpfc -- sudo bash ee site update site5.com --wpsubdir --w3tc -- sudo bash ee site update site5.com --wpsubdir --wpsc - -- sudo bash ee site update site9.com --wpsubdom --wpfc -- sudo bash ee site update site9.com --wpsubdom --w3tc -- sudo bash ee site update site9.com --wpsubdom --wpsc - -- sudo ee site delete site12.com --no-prompt -- sudo ee site delete site12.net --no-prompt -- sudo ee site delete site12.org --no-prompt - -- sudo bash ee stack install mail - -- sudo bash -c 'cat /var/log/easyengine/*' - - -- sudo ls /var/www/ -- sudo mysql -e "show databases"; - - -- sudo wp --allow-root --info + - sudo echo -e "[user]\n\tname = abc\n\temail = root@localhost.com" > ~/.gitconfig + - sudo echo "Travis Banch = $TRAVIS_BRANCH" + - sudo apt-get install -y --force-yes git python3-setuptools python3-dev python3-apt + - sudo python3 setup.py install + - sudo ee --help + - sudo ee stack install + - sudo ee stack install --web + - sudo ee stack install --admin + + - sudo ee site create html.net --html + - sudo ee site create php.com --php + - sudo ee site create mysql.com --mysql + - sudo ee site create site1.com --wp + + - sudo ee site create site2.com --wpsc + - sudo ee site create site2.net --wp --wpsc + - sudo ee site create site2.org --wpsc --wp + - sudo ee site create site3.com --w3tc + - sudo ee site create site3.net --wp --w3tc + - sudo ee site create site3.org --w3tc --wp + - sudo ee site create site4.com --wpfc + - sudo ee site create site4.net --wp --wpfc + - sudo ee site create site4.org --wpfc --wp + - sudo ee site create site5.com --wpsubdir + - sudo ee site create site5.net --wpsubdir + + - sudo ee site create site6.com --wpsubdir --wpsc + - sudo ee site create site6.net --wpsc --wpsubdir + - sudo ee site create site7.com --wpsubdir --w3tc + - sudo ee site create site7.net --w3tc --wpsubdir + - sudo ee site create site8.com --wpsubdir --wpfc + - sudo ee site create site8.net --wpfc --wpsubdir + - sudo ee site create site9.com --wpsubdomain + + - sudo ee site create site10.org --wpsubdomain --wpsc + - sudo ee site create site10.in --wpsc --wpsubdomain + - sudo ee site create site11.org --wpsubdomain --w3tc + - sudo ee site create site11.in --w3tc --wpsubdomain + - sudo ee site create site12.org --wpsubdomain --wpfc + - sudo ee site create site12.in --wpfc --wpsubdomain + - sudo ee site create site12.net --wpfc --wpsubdomain + + - sudo ee debug + - sudo ee debug --stop + - sudo ee debug site12.net + - sudo ee debug site12.net --stop + - sudo ee site create 1.com --html + - sudo ee site create 2.com --php + - sudo ee site create 3.com --mysql + + - sudo ee site update 1.com --wp + - sudo ee site update 2.com --wpsubdir + - sudo ee site update 3.com --wpsubdomain + + - sudo ee site update site1.com --wp --wpfc + - sudo ee site update site1.com --wp --w3tc + - sudo ee site update site1.com --wp --wpsc + + - sudo ee site update site5.com --wpsubdir --wpfc + - sudo ee site update site5.com --wpsubdir --w3tc + - sudo ee site update site5.com --wpsubdir --wpsc + + - sudo ee site update site9.com --wpsubdomain --wpfc + - sudo ee site update site9.com --wpsubdomain --w3tc + - sudo ee site update site9.com --wpsubdomain --wpsc + + - sudo ee site delete site12.in --all --no-prompt + - sudo ee site delete site12.net --no-prompt + - sudo ee site delete site12.org --no-prompt + + - sudo ee stack install --mail + - sudo ls /var/www/ + - sudo wp --allow-root --info diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..f43e98ae --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 rtCamp Solutions Private Limited + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 00000000..5883aaaa --- /dev/null +++ b/README.md @@ -0,0 +1,96 @@ +IMPORTANT +============================================ + +#### We are looking for [Python Developers] (https://rtcamp.com/careers/python-developer/) to join our team. We offer work from home, so you can join EasyEngine team anywhere! _[Why Python?] (https://rtcamp.com/blog/easyengine-3-roadmap/#whypython)_ + +--- + +[![Stories in Ready](https://badge.waffle.io/rtcamp/easyengine.png?label=ready&title=Ready)](https://waffle.io/rtcamp/easyengine) +[![Stories in Progress](https://badge.waffle.io/rtcamp/easyengine.png?label=in%20progress&title=In%20Progress)](https://waffle.io/rtcamp/easyengine) + +EasyEngine Logo + +[![Travis Build Status](https://travis-ci.org/rtCamp/easyengine.svg "Travis Build Status")] (https://travis-ci.org/rtCamp/easyengine) + +EasyEngine (ee) is a python tool, which makes it easy to manage your wordpress sites running on nginx web-server. + +**EasyEngine currently supports:** + +- Ubuntu 12.04 & 14.04 +- Debian 7 + + +## Quick Start + +```bash +wget -q http://rt.cx/ee && sudo bash ee # install easyengine 3.0.0-beta +sudo ee site create example.com --wp # Install required packages & setup WordPress on example.com +``` + +## Update EasyEngine + + +Update Procedure For EasyEngine to version 3.0 + +```bash +wget -q http://rt.cx/ee && sudo bash ee +``` + +## More Site Creation Commands + +### Standard WordPress Sites + +```bash +ee site create example.com --wp # install wordpress without any page caching +ee site create example.com --w3tc # install wordpress with w3-total-cache plugin +ee site create example.com --wpsc # install wordpress with wp-super-cache plugin +ee site create example.com --wpfc # install wordpress + nginx fastcgi_cache +``` + +### WordPress Multsite with subdirectory + +```bash +ee site create example.com --wpsubdir # install wpmu-subdirectory without any page caching +ee site create example.com --wpsubdir --w3tc # install wpmu-subdirectory with w3-total-cache plugin +ee site create example.com --wpsubdir --wpsc # install wpmu-subdirectory with wp-super-cache plugin +ee site create example.com --wpsubdir --wpfc # install wpmu-subdirectory + nginx fastcgi_cache +``` + +### WordPress Multsite with subdomain + +```bash +ee site create example.com --wpsubdomin # install wpmu-subdomain without any page caching +ee site create example.com --wpsubdomain --w3tc # install wpmu-subdomain with w3-total-cache plugin +ee site create example.com --wpsubdomain --wpsc # install wpmu-subdomain with wp-super-cache plugin +ee site create example.com --wpsubdomain --wpfc # install wpmu-subdomain + nginx fastcgi_cache +``` + +### Non-WordPress Sites +```bash +ee site create example.com --html # create example.com for static/html sites +ee site create example.com --php # create example.com with php support +ee site create example.com --mysql # create example.com with php & mysql support +``` + +## Cheatsheet - Site creation + + +| | Single Site | Multisite w/ Subdir | Multisite w/ Subdom | +|--------------------|---------------|-----------------------|-----------------------| +| **NO Cache** | --wp | --wpsubdir | --wpsubdomain | +| **WP Super Cache** | --wpsc | --wpsubdir --wpsc | --wpsubdomain --wpsc | +| **W3 Total Cache** | --w3tc | --wpsubdir --w3tc | --wpsubdomain --w3tc | +| **Nginx cache** | --wpfc | --wpsubdir --wpfc | --wpsubdomain --wpfc | + + +## Useful Links +- [Documentation] (http://docs.rtcamp.com/easyengine/docs/) +- [FAQ] (http://docs.rtcamp.com/easyengine/faq/) +- [Conventions used] (http://rtcamp.com/wordpress-nginx/tutorials/conventions/) + +## Donations + +[![Donate](https://cloud.githubusercontent.com/assets/4115/5297691/c7b50292-7bd7-11e4-987b-2dc21069e756.png)] (https://rtcamp.com/donate/?project=easyengine) + +## License +[MIT] (http://opensource.org/licenses/MIT) diff --git a/config/bash_completion.d/ee_auto.rc b/config/bash_completion.d/ee_auto.rc new file mode 100644 index 00000000..2e936e1c --- /dev/null +++ b/config/bash_completion.d/ee_auto.rc @@ -0,0 +1,176 @@ +_ee_complete() +{ + local cur prev BASE_LEVEL + + COMPREPLY=() + cur=${COMP_WORDS[COMP_CWORD]} + prev=${COMP_WORDS[COMP_CWORD-1]} + mprev=${COMP_WORDS[COMP_CWORD-2]} + + + # SETUP THE BASE LEVEL (everything after "ee") + if [ $COMP_CWORD -eq 1 ]; then + COMPREPLY=( $(compgen \ + -W "stack site debug clean secure" \ + -- $cur) ) + + + # SETUP THE SECOND LEVEL (EVERYTHING AFTER "ee second") + elif [ $COMP_CWORD -eq 2 ]; then + case "$prev" in + + # HANDLE EVERYTHING AFTER THE SECOND LEVEL NAMESPACE + "clean") + COMPREPLY=( $(compgen \ + -W "--memcache --opcache --fastcgi --all" \ + -- $cur) ) + ;; + + # IF YOU HAD ANOTHER CONTROLLER, YOU'D HANDLE THAT HERE + "debug") + COMPREPLY=( $(compgen \ + -W "--start --nginx --php --fpm --mysql -i --interactive --stop " \ + -- $cur) ) + ;; + + "stack") + COMPREPLY=( $(compgen \ + -W "install purge reload remove restart start status stop" \ + -- $cur) ) + ;; + + "site") + COMPREPLY=( $(compgen \ + -W "cd create delete disable edit enable info list log show update" \ + -- $cur) ) + ;; + + "secure") + COMPREPLY=( $(compgen \ + -W "--auth --port --ip" \ + -- $cur) ) + ;; + + "info") + COMPREPLY=( $(compgen \ + -W "--mysql --php --nginx" \ + -- $cur) ) + ;; + + # EVERYTHING ELSE + *) + ;; + esac + + # SETUP THE THIRD LEVEL (EVERYTHING AFTER "ee second third") + elif [ $COMP_CWORD -eq 3 ]; then + case "$prev" in + # HANDLE EVERYTHING AFTER THE THIRD LEVEL NAMESPACE + "install" | "purge" | "remove" | "start" | "stop" | "reload") + COMPREPLY=( $(compgen \ + -W "--web --admin --mail --nginx --php --mysql --postfix --wpcli --phpmyadmin --adminer --utils --memcache --dovecot" \ + -- $cur) ) + ;; + + "list") + COMPREPLY=( $(compgen \ + -W "--enabled --disabled" \ + -- $cur) ) + ;; + + "edit" | "enable" | "info" | "log" | "show" | "cd" | "update" | "delete") + COMPREPLY=( $(compgen \ + -W "$(find /etc/nginx/sites-available/ -type f -printf "%P " 2> /dev/null)" \ + -- $cur) ) + ;; + + "disable") + COMPREPLY=( $(compgen \ + -W "$(command find /etc/nginx/sites-enabled/ -type l -printf "%P " 2> /dev/null)" \ + -- $cur) ) + ;; + + *) + ;; + esac + + if [ ${COMP_WORDS[1]} == "debug" ] && ([ "$prev" != "--start" ] || [ "$prev" != "--nginx" ] || [ "$prev" != "--php" ] || [ "$prev" != "--fpm" ] || [ "$prev" != "--mysql" ] || [ "$prev" != "-i" ] || ["$prev" != "--interactive" ] || ["$prev" != "--stop" ]); then + retlist="--start --stop --wp --rewrite -i" + ret="${retlist[@]/$prev}" + COMPREPLY=( $(compgen \ + -W "$(echo $ret)" \ + -- $cur) ) + fi + + elif [ $COMP_CWORD -eq 4 ]; then + case "$mprev" in + # HANDLE EVERYTHING AFTER THE THIRD LEVEL NAMESPACE + + "create") + COMPREPLY=( $(compgen \ + -W "--html --php --mysql --wp --wpsubdir --wpsubdomain --w3tc --wpfc --wpsc" \ + -- $cur) ) + ;; + + "update") + COMPREPLY=( $(compgen \ + -W "--password --php --mysql --wp --wpsubdir --wpsubdomain --w3tc --wpfc --wpsc" \ + -- $cur) ) + ;; + "delete") + COMPREPLY=( $(compgen \ + -W "--db --files --all" \ + -- $cur) ) + + esac + fi + + case "$prev" in + "--wpsubdir" | "--wpsubdomain") + COMPREPLY=( $(compgen \ + -W "--w3tc --wpfc --wpsc" \ + -- $cur) ) + ;; + + "--web" | "--admin" | "--mail" | "--nginx" | "--php" | "--mysql" | "--postfix" | "--wpcli" | "--phpmyadmin" | "--adminer" | "--utils" | "--memcache" | "--dovecot") + if [[ ${COMP_WORDS[1]} == "stack" ]]; then + retlist="--web --admin --mail --nginx --php --mysql --postfix --wpcli --phpmyadmin --adminer --utils --memcache --dovecot" + elif [[ ${COMP_WORDS[1]} == "debug" ]]; then + retlist="--start --nginx --php --fpm --mysql -i --interactive --stop" + fi + ret="${retlist[@]/$prev}" + COMPREPLY=( $(compgen \ + -W "$(echo $ret)" \ + -- $cur) ) + ;; + + "--db" | "--files" | "--all") + retlist="--db --files --all" + ret="${retlist[@]/$prev}" + COMPREPLY=( $(compgen \ + -W "$(echo $ret)" \ + -- $cur) ) + ;; + + "--memcache" | "--opcache" | "--fastcgi" | "--all") + retlist="--memcache --opcache --fastcgi --all" + ret="${retlist[@]/$prev}" + COMPREPLY=( $(compgen \ + -W "$(echo $ret)" \ + -- $cur) ) + ;; + "--auth" | "--port" | "--ip") + retlist="--auth --port --ip" + ret="${retlist[@]/$prev}" + COMPREPLY=( $(compgen \ + -W "$(echo $ret)" \ + -- $cur) ) + ;; + *) + ;; + esac + + return 0 + +} && +complete -F _ee_complete ee diff --git a/config/ee.conf b/config/ee.conf new file mode 100644 index 00000000..7472f571 --- /dev/null +++ b/config/ee.conf @@ -0,0 +1,69 @@ +# EasyEngine Configuration +# +# All commented values are the application default +# + +[ee] + +### Toggle application level debug (does not toggle framework debugging) +# debug = false + +### Where external (third-party) plugins are loaded from +# plugin_dir = /var/lib/ee/plugins/ + +### Where all plugin configurations are loaded from +# plugin_config_dir = /etc/ee/plugins.d/ + +### Where external templates are loaded from +# template_dir = /var/lib/ee/templates/ + + +[log.logging] + +### Where the log file lives (no log file by default) +file = /var/log/ee/ee.log + +### The level for which to log. One of: info, warn, error, fatal, debug +level = debug + +### Whether or not to log to console +to_console = false + +### Whether or not to rotate the log file when it reaches `max_bytes` +rotate = true + +### Max size in bytes that a log file can grow until it is rotated. +max_bytes = 512000 + +### The maximun number of log files to maintain when rotating +max_files = 7 + +[stack] + +### IP address that will be used in Nginx configurations while installing +ip-address = 127.0.0.1 + +[mysql] + +### MySQL database grant host name +grant-host = localhost + +### Ask for MySQL db name while site creation +db-name = False + +### Ask for MySQL user name while site creation +db-user = False + +[wordpress] + +### Ask for WordPress prefix while site creation +prefix = False + +### User name for WordPress sites +user = + +### Password for WordPress sites +password = + +### EMail for WordPress sites +email = diff --git a/config/plugins.d/clean.conf b/config/plugins.d/clean.conf new file mode 100644 index 00000000..be834348 --- /dev/null +++ b/config/plugins.d/clean.conf @@ -0,0 +1,8 @@ +### Example Plugin Configuration for EasyEngine + +[clean] + +### If enabled, load a plugin named `example` either from the Python module +### `ee.cli.plugins.example` or from the file path +### `/var/lib/ee/plugins/example.py` +enable_plugin = true diff --git a/config/plugins.d/debug.conf b/config/plugins.d/debug.conf new file mode 100644 index 00000000..9ccdf106 --- /dev/null +++ b/config/plugins.d/debug.conf @@ -0,0 +1,8 @@ +### Example Plugin Configuration for EasyEngine + +[debug] + +### If enabled, load a plugin named `example` either from the Python module +### `ee.cli.plugins.example` or from the file path +### `/var/lib/ee/plugins/example.py` +enable_plugin = true diff --git a/config/plugins.d/import_slow_log.conf b/config/plugins.d/import_slow_log.conf new file mode 100644 index 00000000..d7841dbe --- /dev/null +++ b/config/plugins.d/import_slow_log.conf @@ -0,0 +1,8 @@ +### Example Plugin Configuration for EasyEngine + +[import_slow_log] + +### If enabled, load a plugin named `example` either from the Python module +### `ee.cli.plugins.example` or from the file path +### `/var/lib/ee/plugins/example.py` +enable_plugin = true diff --git a/config/plugins.d/info.conf b/config/plugins.d/info.conf new file mode 100644 index 00000000..59f51a03 --- /dev/null +++ b/config/plugins.d/info.conf @@ -0,0 +1,11 @@ +### Example Plugin Configuration for EasyEngine + +[info] + +### If enabled, load a plugin named `example` either from the Python module +### `ee.cli.plugins.example` or from the file path +### `/var/lib/ee/plugins/example.py` +enable_plugin = true + +### Additional plugin configuration settings +foo = bar diff --git a/config/plugins.d/secure.conf b/config/plugins.d/secure.conf new file mode 100644 index 00000000..b70f167b --- /dev/null +++ b/config/plugins.d/secure.conf @@ -0,0 +1,8 @@ +### Example Plugin Configuration for EasyEngine + +[secure] + +### If enabled, load a plugin named `example` either from the Python module +### `ee.cli.plugins.example` or from the file path +### `/var/lib/ee/plugins/example.py` +enable_plugin = true diff --git a/config/plugins.d/site.conf b/config/plugins.d/site.conf new file mode 100644 index 00000000..2fb468fe --- /dev/null +++ b/config/plugins.d/site.conf @@ -0,0 +1,8 @@ +### Example Plugin Configuration for EasyEngine + +[site] + +### If enabled, load a plugin named `example` either from the Python module +### `ee.cli.plugins.example` or from the file path +### `/var/lib/ee/plugins/example.py` +enable_plugin = true diff --git a/config/plugins.d/stack.conf b/config/plugins.d/stack.conf new file mode 100644 index 00000000..f7bf9b80 --- /dev/null +++ b/config/plugins.d/stack.conf @@ -0,0 +1,8 @@ +### Example Plugin Configuration for EasyEngine + +[stack] + +### If enabled, load a plugin named `example` either from the Python module +### `ee.cli.plugins.example` or from the file path +### `/var/lib/ee/plugins/example.py` +enable_plugin = true diff --git a/docs/ee.8 b/docs/ee.8 new file mode 100644 index 00000000..68252f27 --- /dev/null +++ b/docs/ee.8 @@ -0,0 +1,312 @@ +.TH ee 8 "EasyEngine (ee) version: 3.0" "Feb 2,2014" "EasyEngine" +.SH NAME +.B EasyEngine (ee) +\- Manage Nginx Based Websites. +.SH SYNOPSIS +ee [ --version | --help | info | stack | site | debug | update ] +.TP +ee stack [ install | remove | purge ] [ --web | --mail | --all | --nginx | --php | --mysql | --postfix | --adminer | --phpmyadmin | --wpcli | --utils ] +.TP +ee stack [ status | start | stop | reload | restart ] +.TP +ee site [ list | info | show | enable | disable | edit ] [ example.com ] +.TP +ee site create example.com [ --html | --php | --mysql] [[--wp | --wpsubdir | --wpsubdomain ] [--basic | --wpsc | --w3tc | --wpfc]] +.TP +ee site update example.com [ --php | --mysql] [[--wp | --wpsubdir | --wpsubdomain ] [--basic | --wpsc | --w3tc | --wpfc]] +.TP +ee site delete example.com [--db | --files | --all | --no-prompt ] +.TP +ee debug [ -i | --nginx | --rewrite | --php | --fpm | --mysql ] [--stop ] +.TP +ee debug example.com [ -i | --nginx | --rewrite | --wp ] [--stop ] +.TP +ee secure [ --auth | --port | --ip ] +.SH DESCRIPTION +EasyEngine aka ee is the opensource project developed with the purpose to automate web-server configuration. +.br +EasyEngine is the collection of shell scripts that provides automation for the web-server +.br +installation, site creation, services debugging & monitoring. +.SH OPTIONS +.TP +.B --version +.br +Display easyengine (ee) version information. +.TP +.B info +.br +ee info - Display Nginx, PHP, MySQL and ee common location information +.br +ee site info - Diplay given website details like enable, disable. weboot and log files. +.TP +.B --help +.br +Display easyengine (ee) help. +.TP +.B stack +.TP +.B install [ --all | --web | --mail | --nginx | --php | --mysql | --postfix | --adminer | --phpmyadmin | --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 | --mail | --nginx | --php | --mysql | --postfix | --adminer | --phpmyadmin | --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 | --mail | --nginx | --php | --mysql | --postfix | --adminer | --phpmyadmin | --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, PHP5-FPM, MySQL, Postfix services. +.TP +.B start +.br +Start services NGINX, PHP5-FPM, MySQL, Postfix. +.TP +.B stop +.br +Stop services NGINX, PHP5-FPM, MySQL, Postfix. +.TP +.B reload +.br +Reload services NGINX, PHP5-FPM, MySQL, Postfix. +.TP +.B restart +.br +Restart services NGINX, PHP5-FPM, MySQL, Postfix. +.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 [ enable | available ] +.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 | --mysql] [[--wp | --wpsubdir | --wpsubdomain ] [--basic | --wpsc | --w3tc | --wpfc]] +.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 | --mysql] [[--wp | --wpsubdir | --wpsubdomain ] [--basic | --wpsc | --w3tc | --wpfc]] +.br +Update site configuration according to specified options. +.TP +.B delete [ example.com ] [--no-prompt ] [ --db | --files ] +.br +Delete site i.e webroot, database, ad configuration permenantly. +.TP +.B debug [ -i | --nginx | --php | --mysql | --rewrite | --fpm ] [ --start | --stop ] +.br +Starts server level debugging. If used without arguments starts debugging +.br +all services, else debug only service provided with argument. Stop +.br +Debugging if used with --stop argument. +.TP +.B debug example.com [ -i | --nginx | --rewrite | --wp ] [ --start | --stop ] +.br +Starts site level debugging. If used without arguments starts debugging all +.br +services, else debug only service provided with argument. Stop Debugging +.br +if used with --stop argument. +.TP +.B secure [ --auth | --port ] +.br +Update security settings. +.TP +.B clean [ --fastcgi | --opcache | --memcache | --all ] +.br +Clean NGINX fastCGI cache, Opcache, Memcache. +.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 +.br +used with ee debug command. used to start or stop nginx debugging. +.TP +.B --php +.br +used with ee debug command. used to start or stop php debugging. +.TP +.B --mysql +.br +used with ee debug command. used to start or stop mysql debugging. +.TP +.B --rewrite +.br +used with ee debug command. used to start or stop nginx rewrite rules debugging. +.TP +.B --fpm +.br +used with ee debug command. used to start or stop fpm debugging. +.TP +.B --wp +.br +used with ee debug command. used to start or stop wordpress site debugging. +.TP +.B --start +.br +used with ee debug command. used to stop debugging. +.TP +.B --stop +.br +used with ee 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. +.TP +.B --auth +.br +used with ee secure command. Update credential of HTTP authentication +.TP +.B --port +.br +used with ee secure command. Change EasyEngine admin port 22222. +.TP +.B --ip +.br +used with ee secure command. Update whitelist IP address +.SH WORDPRESS CACHING OPTIONS +.TP +.B --basic +.br +Create WordPress website without cache. +.TP +.B --w3tc +.br +Install and activate Nginx-helper and W3 Total Cache plugin. +.TP +.B --wpsc +.br +Install and activate Nginx-helper and WP Super Cache plugin. +.TP +.B --wpfc +.br +Install and activate Nginx-helper and W3 Total Cache plugin with +.br +Nginx FastCGI cache. +.SH FILES +.br +/etc/easyengine/ee.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 Shital +.I \ +.br +.SH "SEE ALSO" +.br +EE: +.I https://rtcamp.com/easyengine/ +.br +FAQ: +.I https://rtcamp.com/easyengine/faq/ +.br +DOCS: +.I https://rtcamp.com/easyengine/docs/ diff --git a/ee/__init__.py b/ee/__init__.py new file mode 100644 index 00000000..de40ea7c --- /dev/null +++ b/ee/__init__.py @@ -0,0 +1 @@ +__import__('pkg_resources').declare_namespace(__name__) diff --git a/ee/cli/__init__.py b/ee/cli/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ee/cli/bootstrap.py b/ee/cli/bootstrap.py new file mode 100644 index 00000000..a5ce6d75 --- /dev/null +++ b/ee/cli/bootstrap.py @@ -0,0 +1,11 @@ +"""EasyEngine bootstrapping.""" + +# All built-in application controllers should be imported, and registered +# in this file in the same way as EEBaseController. + +from cement.core import handler +from ee.cli.controllers.base import EEBaseController + + +def load(app): + handler.register(EEBaseController) diff --git a/ee/cli/controllers/__init__.py b/ee/cli/controllers/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ee/cli/controllers/base.py b/ee/cli/controllers/base.py new file mode 100644 index 00000000..3c2354ab --- /dev/null +++ b/ee/cli/controllers/base.py @@ -0,0 +1,25 @@ +"""EasyEngine base controller.""" + +from cement.core.controller import CementBaseController, expose +from ee.core.variables import EEVariables +VERSION = EEVariables.ee_version + +BANNER = """ +EasyEngine v%s +Copyright (c) 2015 rtCamp Solutions Pvt. Ltd. +""" % VERSION + + +class EEBaseController(CementBaseController): + class Meta: + label = 'base' + description = ("EasyEngine is the commandline tool to manage your" + " websites based on WordPress and Nginx with easy to" + " use commands") + arguments = [ + (['-v', '--version'], dict(action='version', version=BANNER)), + ] + + @expose(hide=True) + def default(self): + self.app.args.print_help() diff --git a/ee/cli/ext/__init__.py b/ee/cli/ext/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ee/cli/main.py b/ee/cli/main.py new file mode 100644 index 00000000..8f6019dd --- /dev/null +++ b/ee/cli/main.py @@ -0,0 +1,116 @@ +"""EasyEngine main application entry point.""" +import sys +import os + +# this has to happen after you import sys, but before you import anything +# from Cement "source: https://github.com/datafolklabs/cement/issues/290" +if '--debug' in sys.argv: + sys.argv.remove('--debug') + TOGGLE_DEBUG = True +else: + TOGGLE_DEBUG = False + +from cement.core import foundation +from cement.utils.misc import init_defaults +from cement.core.exc import FrameworkError, CaughtSignal +from ee.core import exc + +# Application default. Should update config/ee.conf to reflect any +# changes, or additions here. +defaults = init_defaults('ee') + +# All internal/external plugin configurations are loaded from here +defaults['ee']['plugin_config_dir'] = '/etc/ee/plugins.d' + +# External plugins (generally, do not ship with application code) +defaults['ee']['plugin_dir'] = '/var/lib/ee/plugins' + +# External templates (generally, do not ship with application code) +defaults['ee']['template_dir'] = '/var/lib/ee/templates' + + +class EEApp(foundation.CementApp): + class Meta: + label = 'ee' + + config_defaults = defaults + + # All built-in application bootstrapping (always run) + bootstrap = 'ee.cli.bootstrap' + + # Optional plugin bootstrapping (only run if plugin is enabled) + plugin_bootstrap = 'ee.cli.plugins' + + # Internal templates (ship with application code) + template_module = 'ee.cli.templates' + + # Internal plugins (ship with application code) + plugin_bootstrap = 'ee.cli.plugins' + + extensions = ['mustache'] + + # default output handler + output_handler = 'mustache' + + debug = TOGGLE_DEBUG + + +class EETestApp(EEApp): + """A test app that is better suited for testing.""" + class Meta: + argv = [] + config_files = [] + + +# Define the applicaiton object outside of main, as some libraries might wish +# to import it as a global (rather than passing it into another class/func) +app = EEApp() + + +def main(): + try: + # Default our exit status to 0 (non-error) + code = 0 + + # if not root...kick out + if not os.geteuid() == 0: + print("\nOnly root or sudo user can run this EasyEngine\n") + app.close(1) + + # Setup the application + app.setup() + + # Run the application + app.run() + except exc.EEError as e: + # Catch our application errors and exit 1 (error) + code = 1 + print(e) + except FrameworkError as e: + # Catch framework errors and exit 1 (error) + code = 1 + print(e) + except CaughtSignal as e: + # Default Cement signals are SIGINT and SIGTERM, exit 0 (non-error) + code = 0 + print(e) + finally: + # Print an exception (if it occurred) and --debug was passed + if app.debug: + import sys + import traceback + + exc_type, exc_value, exc_traceback = sys.exc_info() + if exc_traceback is not None: + traceback.print_exc() + + # # Close the application + app.close(code) + + +def get_test_app(**kw): + app = EEApp(**kw) + return app + +if __name__ == '__main__': + main() diff --git a/ee/cli/plugins/__init__.py b/ee/cli/plugins/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ee/cli/plugins/clean.py b/ee/cli/plugins/clean.py new file mode 100644 index 00000000..9718fc3b --- /dev/null +++ b/ee/cli/plugins/clean.py @@ -0,0 +1,89 @@ +"""Clean Plugin for EasyEngine.""" + +from ee.core.shellexec import EEShellExec +from ee.core.aptget import EEAptGet +from ee.core.services import EEService +from ee.core.logging import Log +from cement.core.controller import CementBaseController, expose +from cement.core import handler, hook +import os +import urllib.request + + +def clean_plugin_hook(app): + # do something with the ``app`` object here. + pass + + +class EECleanController(CementBaseController): + class Meta: + label = 'clean' + stacked_on = 'base' + stacked_type = 'nested' + description = ('Clean NGINX FastCGI cache, Opcacache, Memcache') + arguments = [ + (['--all'], + dict(help='Clean all cache', action='store_true')), + (['--fastcgi'], + dict(help='Clean FastCGI cache', action='store_true')), + (['--memcache'], + dict(help='Clean MemCache', action='store_true')), + (['--opcache'], + dict(help='Clean OpCache', action='store_true')) + ] + + @expose(hide=True) + def default(self): + if (not (self.app.pargs.all or self.app.pargs.fastcgi or + self.app.pargs.memcache or self.app.pargs.opcache)): + self.clean_fastcgi() + if self.app.pargs.all: + self.clean_memcache() + self.clean_fastcgi() + self.clean_opcache() + if self.app.pargs.fastcgi: + self.clean_fastcgi() + if self.app.pargs.memcache: + self.clean_memcache() + if self.app.pargs.opcache: + self.clean_opcache() + + @expose(hide=True) + def clean_memcache(self): + """This function Clears memcache""" + try: + if(EEAptGet.is_installed(self, "memcached")): + EEService.restart_service(self, "memcached") + Log.info(self, "Cleaning MemCache") + else: + Log.error(self, "Memcache not installed") + except Exception as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "Unable to restart Memcached") + + @expose(hide=True) + def clean_fastcgi(self): + """This function clears Fastcgi cache""" + if(os.path.isdir("/var/run/nginx-cache")): + Log.info(self, "Cleaning NGINX FastCGI cache") + EEShellExec.cmd_exec(self, "rm -rf /var/run/nginx-cache/*") + else: + Log.error(self, "Unable to clean FastCGI cache") + + @expose(hide=True) + def clean_opcache(self): + """This function clears opcache""" + try: + Log.info(self, "Cleaning opcache") + wp = urllib.request.urlopen(" https://127.0.0.1:22222/cache" + "/opcache/opgui.php?page=reset").read() + except Exception as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "Unable to clean OpCache") + + +def load(app): + # register the plugin class.. this only happens if the plugin is enabled + handler.register(EECleanController) + # register a hook (function) to run after arguments are parsed. + hook.register('post_argument_parsing', clean_plugin_hook) diff --git a/ee/cli/plugins/debug.py b/ee/cli/plugins/debug.py new file mode 100644 index 00000000..0e384246 --- /dev/null +++ b/ee/cli/plugins/debug.py @@ -0,0 +1,503 @@ +"""Debug Plugin for EasyEngine""" + +from cement.core.controller import CementBaseController, expose +from cement.core import handler, hook +from ee.core.shellexec import EEShellExec +from ee.core.mysql import EEMysql +from ee.core.services import EEService +from ee.core.logging import Log +from ee.cli.plugins.site_functions import logwatch +from ee.core.variables import EEVariables +import os +import configparser +import glob +import signal + + +def debug_plugin_hook(app): + # do something with the ``app`` object here. + pass + + +class EEDebugController(CementBaseController): + class Meta: + label = 'debug' + description = 'Used for server level debugging' + stacked_on = 'base' + stacked_type = 'nested' + arguments = [ + (['--stop'], + dict(help='Stop debug', action='store_true')), + (['--start'], + dict(help='Start debug', action='store_true')), + (['--nginx'], + dict(help='Debug Nginx', action='store_true')), + (['--php'], + dict(help='Debug PHP', action='store_true')), + (['--fpm'], + dict(help='Debug FastCGI', action='store_true')), + (['--mysql'], + dict(help='Debug MySQL', action='store_true')), + (['--wp'], + dict(help='Debug WordPress sites', action='store_true')), + (['--rewrite'], + dict(help='Debug Nginx rewrite rules', action='store_true')), + (['-i', '--interactive'], + dict(help='Interactive debug', action='store_true')), + (['--import-slow-log-interval'], + dict(help='Import MySQL slow log to Anemometer', + action='store', dest='interval')), + (['site_name'], + dict(help='Website Name', nargs='?', default=None)) + ] + + @expose(hide=True) + def debug_nginx(self): + """Start/Stop Nginx debug""" + # start global debug + if self.start and not self.app.pargs.site_name: + try: + debug_address = (self.app.config.get('stack', 'ip-address') + .split()) + except Exception as e: + debug_address = ['0.0.0.0/0'] + for ip_addr in debug_address: + if not ("debug_connection "+ip_addr in open('/etc/nginx/' + 'nginx.conf').read()): + Log.info(self, "Setting up Nginx debug connection" + " for "+ip_addr) + EEShellExec.cmd_exec(self, "sed -i \"/events {{/a\\ \\ \\ " + "\\ $(echo debug_connection " + "{ip}\;)\" /etc/nginx/" + "nginx.conf".format(ip=ip_addr)) + self.trigger_nginx = True + + if not self.trigger_nginx: + Log.info(self, "Nginx debug connection already enabled") + + self.msg = self.msg + ["/var/log/nginx/*.error.log"] + + # stop global debug + elif not self.start and not self.app.pargs.site_name: + if "debug_connection " in open('/etc/nginx/nginx.conf').read(): + Log.info(self, "Disabling Nginx debug connections") + EEShellExec.cmd_exec(self, "sed -i \"/debug_connection.*/d\"" + " /etc/nginx/nginx.conf") + self.trigger_nginx = True + else: + Log.info(self, "Nginx debug connection already disabled") + + # start site specific debug + elif self.start and self.app.pargs.site_name: + config_path = ("/etc/nginx/sites-available/{0}" + .format(self.app.pargs.site_name)) + if os.path.isfile(config_path): + if not EEShellExec.cmd_exec(self, "grep \"error.log debug\" " + "{0}".format(config_path)): + Log.info(self, "Starting NGINX debug connection for " + "{0}".format(self.app.pargs.site_name)) + EEShellExec.cmd_exec(self, "sed -i \"s/error.log;/" + "error.log " + "debug;/\" {0}".format(config_path)) + self.trigger_nginx = True + + else: + Log.info(self, "Debug for site allready enabled") + + self.msg = self.msg + ['{0}{1}/logs/error.log' + .format(EEVariables.ee_webroot, + self.app.pargs.site_name)] + + else: + Log.info(self, "{0} domain not valid" + .format(self.app.pargs.site_name)) + + # stop site specific debug + elif not self.start and self.app.pargs.site_name: + config_path = ("/etc/nginx/sites-available/{0}" + .format(self.app.pargs.site_name)) + if os.path.isfile(config_path): + if EEShellExec.cmd_exec(self, "grep \"error.log debug\" {0}" + .format(config_path)): + Log.info(self, "Stoping NGINX debug connection for {0}" + .format(self.app.pargs.site_name)) + EEShellExec.cmd_exec(self, "sed -i \"s/error.log debug;/" + "error.log;/\" {0}" + .format(config_path)) + self.trigger_nginx = True + + else: + + Log.info(self, "Debug for site allready disabled") + else: + Log.info(self, "{0} domain not valid" + .format(self.app.pargs.site_name)) + + @expose(hide=True) + def debug_php(self): + """Start/Stop PHP debug""" + # PHP global debug start + if self.start: + if not (EEShellExec.cmd_exec(self, "sed -n \"/upstream php" + "{/,/}/p \" /etc/nginx/" + "conf.d/upstream.conf " + "| grep 9001")): + Log.info(self, "Enabling PHP debug") + data = dict(php="9001", debug="9001") + Log.info(self, 'Writting the Nginx debug configration to file ' + '/etc/nginx/conf.d/upstream.conf ') + ee_nginx = open('/etc/nginx/conf.d/upstream.conf', 'w') + self.app.render((data), 'upstream.mustache', out=ee_nginx) + ee_nginx.close() + self.trigger_php = True + self.trigger_nginx = True + else: + Log.info(self, "PHP debug is allready enabled") + + self.msg = self.msg + ['/var/log/php5/slow.log'] + + # PHP global debug stop + else: + if EEShellExec.cmd_exec(self, "sed -n \"/upstream php {/,/}/p\" " + "/etc/nginx/conf.d/upstream.conf " + "| grep 9001"): + Log.info(self, "Disabling PHP debug") + data = dict(php="9000", debug="9001") + Log.debug(self, 'Writting the Nginx debug configration to file' + ' /etc/nginx/conf.d/upstream.conf ') + ee_nginx = open('/etc/nginx/conf.d/upstream.conf', 'w') + self.app.render((data), 'upstream.mustache', out=ee_nginx) + ee_nginx.close() + self.trigger_php = True + self.trigger_nginx = True + else: + Log.info(self, "PHP debug is allready disabled") + + @expose(hide=True) + def debug_fpm(self): + """Start/Stop PHP5-FPM debug""" + # PHP5-FPM start global debug + if self.start: + if not EEShellExec.cmd_exec(self, "grep \"log_level = debug\" " + "/etc/php5/fpm/php-fpm.conf"): + Log.info(self, "Setting up PHP5-FPM log_level = debug") + config = configparser.ConfigParser() + config.read('/etc/php5/fpm/php-fpm.conf') + config.remove_option('global', 'include') + config['global']['log_level'] = 'debug' + config['global']['include'] = '/etc/php5/fpm/pool.d/*.conf' + with open('/etc/php5/fpm/php-fpm.conf', 'w') as configfile: + Log.debug(self, "Writting php5-FPM configuration into " + "/etc/php5/fpm/php-fpm.conf") + config.write(configfile) + self.trigger_php = True + else: + Log.info(self, "PHP5-FPM log_level = debug already setup") + + self.msg = self.msg + ['/var/log/php5/fpm.log'] + + # PHP5-FPM stop global debug + else: + if EEShellExec.cmd_exec(self, "grep \"log_level = debug\" " + "/etc/php5/fpm/php-fpm.conf"): + Log.info(self, "Disabling PHP5-FPM log_level = debug") + config = configparser.ConfigParser() + config.read('/etc/php5/fpm/php-fpm.conf') + config.remove_option('global', 'include') + config['global']['log_level'] = 'notice' + config['global']['include'] = '/etc/php5/fpm/pool.d/*.conf' + with open('/etc/php5/fpm/php-fpm.conf', 'w') as configfile: + Log.debug(self, "writting php5 configuration into " + "/etc/php5/fpm/php-fpm.conf") + config.write(configfile) + + self.trigger_php = True + else: + Log.info(self, "PHP5-FPM log_level = debug already disabled") + + @expose(hide=True) + def debug_mysql(self): + """Start/Stop MySQL debug""" + # MySQL start global debug + if self.start: + if not EEShellExec.cmd_exec(self, "mysql -e \"show variables like" + " \'slow_query_log\';\" | " + "grep ON"): + Log.info(self, "Setting up MySQL slow log") + EEMysql.execute(self, "set global slow_query_log = " + "\'ON\';") + EEMysql.execute(self, "set global slow_query_log_file = " + "\'/var/log/mysql/mysql-slow.log\';") + EEMysql.execute(self, "set global long_query_time = 2;") + EEMysql.execute(self, "set global log_queries_not_using" + "_indexes = \'ON\';") + if self.app.pargs.interval: + try: + cron_time = int(self.app.pargs.interval) + except Exception as e: + cron_time = 5 + EEShellExec.cmd_exec(self, "/bin/bash -c \"crontab -l 2> " + "/dev/null | {{ cat; echo -e" + " \\\"#EasyEngine start MySQL slow" + " log \\n*/{0} * * * * " + "/usr/local/sbin/ee import-slow-log\\" + "n#EasyEngine end MySQL slow log\\\";" + " }} | crontab -\"".format(cron_time)) + else: + Log.info(self, "MySQL slow log is allready enabled") + + self.msg = self.msg + ['/var/log/mysql/mysql-slow.log'] + + # MySQL stop global debug + else: + if EEShellExec.cmd_exec(self, "mysql -e \"show variables like \'" + "slow_query_log\';\" | grep ON"): + Log.info(self, "Disabling MySQL slow log") + EEMysql.execute(self, "set global slow_query_log = \'OFF\';") + EEMysql.execute(self, "set global slow_query_log_file = \'" + "/var/log/mysql/mysql-slow.log\';") + EEMysql.execute(self, "set global long_query_time = 10;") + EEMysql.execute(self, "set global log_queries_not_using_index" + "es = \'OFF\';") + EEShellExec.cmd_exec(self, "crontab -l | sed \'/#EasyEngine " + "start/,/#EasyEngine end/d\' | crontab -") + else: + Log.info(self, "MySQL slow log already disabled") + + @expose(hide=True) + def debug_wp(self): + """Start/Stop WordPress debug""" + if self.start and self.app.pargs.site_name: + wp_config = ("{0}{1}/wp-config.php" + .format(EEVariables.ee_webroot, + self.app.pargs.site_name)) + webroot = "{0}{1}".format(EEVariables.ee_webroot, + self.app.pargs.site_name) + if os.path.isfile(wp_config): + if not EEShellExec.cmd_exec(self, "grep \"\'WP_DEBUG\'\" {0} |" + " grep true".format(wp_config)): + Log.info(self, "Starting WordPress debug") + open("{0}/htdocs/wp-content/debug.log".format(webroot), + 'a').close() + EEShellExec.cmd_exec(self, "chown {1}: {0}/htdocs/wp-" + "content/debug.log" + "".format(webroot, + EEVariables.ee_php_user)) + EEShellExec.cmd_exec(self, "sed -i \"s/define(\'WP_DEBUG\'" + ".*/define(\'WP_DEBUG\', true);\\n" + "define(\'WP_DEBUG_DISPLAY\', false);" + "\\ndefine(\'WP_DEBUG_LOG\', true);" + "\\ndefine(\'SAVEQUERIES\', true);/\"" + " {0}".format(wp_config)) + EEShellExec.cmd_exec(self, "cd {0}/htdocs/ && wp" + " plugin --allow-root install " + "developer".format(webroot)) + EEShellExec.cmd_exec(self, "chown -R {1}: {0}/htdocs/" + "wp-content/plugins" + .format(webroot, + EEVariables.ee_php_user)) + else: + Log.info(self, "WordPress debug log already enabled") + + self.msg = self.msg + ['{0}{1}/htdocs/wp-content' + '/debug.log' + .format(EEVariables.ee_webroot, + self.app.pargs.site_name)] + + else: + Log.info(self, "{0} domain not valid" + .format(self.app.pargs.site_name)) + + elif not self.start and self.app.pargs.site_name: + wp_config = ("{0}{1}/wp-config.php" + .format(EEVariables.ee_webroot, + self.app.pargs.site_name)) + webroot = "{0}{1}".format(EEVariables.ee_webroot, + self.app.pargs.site_name) + if os.path.isfile(wp_config): + if EEShellExec.cmd_exec(self, "grep \"\'WP_DEBUG\'\" {0} | " + "grep true".format(wp_config)): + Log.info(self, "Disabling WordPress debug") + EEShellExec.cmd_exec(self, "sed -i \"s/define(\'WP_DEBUG\'" + ", true);/define(\'WP_DEBUG\', " + "false);/\" {0}".format(wp_config)) + EEShellExec.cmd_exec(self, "sed -i \"/define(\'" + "WP_DEBUG_DISPLAY\', false);/d\" {0}" + .format(wp_config)) + EEShellExec.cmd_exec(self, "sed -i \"/define(\'" + "WP_DEBUG_LOG\', true);/d\" {0}" + .format(wp_config)) + EEShellExec.cmd_exec(self, "sed -i \"/define(\'" + "SAVEQUERIES\', " + "true);/d\" {0}".format(wp_config)) + else: + Log.info(self, "WordPress debug all already disabled") + else: + Log.error(self, "{0} domain not valid" + .format(self.app.pargs.site_name)) + else: + Log.error(self, "Missing argument site name") + + @expose(hide=True) + def debug_rewrite(self): + """Start/Stop Nginx rewrite rules debug""" + # Start Nginx rewrite debug globally + if self.start and not self.app.pargs.site_name: + if not EEShellExec.cmd_exec(self, "grep \"rewrite_log on;\" " + "/etc/nginx/nginx.conf"): + Log.info(self, "Setting up Nginx rewrite logs") + EEShellExec.cmd_exec(self, "sed -i \'/http {/a \\\\t" + "rewrite_log on;\' /etc/nginx/nginx.conf") + self.trigger_nginx = True + else: + Log.info(self, "Nginx rewrite logs already enabled") + + if '/var/log/nginx/*.error.log' not in self.msg: + self.msg = self.msg + ['/var/log/nginx/*.error.log'] + + # Stop Nginx rewrite debug globally + elif not self.start and not self.app.pargs.site_name: + if EEShellExec.cmd_exec(self, "grep \"rewrite_log on;\" " + "/etc/nginx/nginx.conf"): + Log.info(self, "Disabling Nginx rewrite logs") + EEShellExec.cmd_exec(self, "sed -i \"/rewrite_log.*/d\"" + " /etc/nginx/nginx.conf") + self.trigger_nginx = True + else: + Log.info(self, "Nginx rewrite logs already disabled") + # Start Nginx rewrite for site + elif self.start and self.app.pargs.site_name: + config_path = ("/etc/nginx/sites-available/{0}" + .format(self.app.pargs.site_name)) + if not EEShellExec.cmd_exec(self, "grep \"rewrite_log on;\" {0}" + .format(config_path)): + Log.info(self, "Setting up Nginx rewrite logs for {0}" + .format(self.app.pargs.site_name)) + EEShellExec.cmd_exec(self, "sed -i \"/access_log/i \\\\\\t" + "rewrite_log on;\" {0}" + .format(config_path)) + self.trigger_nginx = True + else: + Log.info(self, "Nginx rewrite logs for {0} allready setup" + .format(self.app.pargs.site_name)) + + if ('{0}{1}/logs/error.log'.format(EEVariables.ee_webroot, + self.app.pargs.site_name) + not in self.msg): + self.msg = self.msg + ['{0}{1}/logs/error.log' + .format(EEVariables.ee_webroot, + self.app.pargs.site_name)] + + # Stop Nginx rewrite for site + elif not self.start and self.app.pargs.site_name: + config_path = ("/etc/nginx/sites-available/{0}" + .format(self.app.pargs.site_name)) + if EEShellExec.cmd_exec(self, "grep \"rewrite_log on;\" {0}" + .format(config_path)): + Log.info(self, "Disabling Nginx rewrite logs for {0}" + .format(self.app.pargs.site_name)) + EEShellExec.cmd_exec(self, "sed -i \"/rewrite_log.*/d\" {0}" + .format(config_path)) + self.trigger_nginx = True + else: + Log.info(self, "Nginx rewrite logs for {0} allready " + " disabled".format(self.app.pargs.site_name)) + + @expose(hide=True) + def signal_handler(self, signal, frame): + """Handle Ctrl+c hevent for -i option of debug""" + self.start = False + if self.app.pargs.nginx: + self.debug_nginx() + if self.app.pargs.php: + self.debug_php() + if self.app.pargs.fpm: + self.debug_fpm() + if self.app.pargs.mysql: + self.debug_mysql() + if self.app.pargs.wp: + self.debug_wp() + if self.app.pargs.rewrite: + self.debug_rewrite() + + # Reload Nginx + if self.trigger_nginx: + EEService.reload_service(self, 'nginx') + + # Reload PHP + if self.trigger_php: + EEService.reload_service(self, 'php5-fpm') + self.app.close(0) + + @expose(hide=True) + def default(self): + """Default function of debug""" + self.start = True + self.interactive = False + self.msg = [] + self.trigger_nginx = False + self.trigger_php = False + + if self.app.pargs.stop: + self.start = False + + if ((not self.app.pargs.nginx) and (not self.app.pargs.php) + and (not self.app.pargs.fpm) and (not self.app.pargs.mysql) + and (not self.app.pargs.wp) and (not self.app.pargs.rewrite) + and (not self.app.pargs.site_name)): + self.debug_nginx() + self.debug_php() + self.debug_fpm() + self.debug_mysql() + self.debug_rewrite() + + if ((not self.app.pargs.nginx) and (not self.app.pargs.php) + and (not self.app.pargs.fpm) and (not self.app.pargs.mysql) + and (not self.app.pargs.wp) and (not self.app.pargs.rewrite) + and self.app.pargs.site_name): + self.debug_nginx() + self.debug_wp() + self.debug_rewrite() + + if self.app.pargs.nginx: + self.debug_nginx() + if self.app.pargs.php: + self.debug_php() + if self.app.pargs.fpm: + self.debug_fpm() + if self.app.pargs.mysql: + self.debug_mysql() + if self.app.pargs.wp: + self.debug_wp() + if self.app.pargs.rewrite: + self.debug_rewrite() + + if self.app.pargs.interactive: + self.interactive = True + + # Reload Nginx + if self.trigger_nginx: + EEService.reload_service(self, 'nginx') + # Reload PHP + if self.trigger_php: + EEService.reload_service(self, 'php5-fpm') + + if len(self.msg) > 0: + if not self.app.pargs.interactive: + disp_msg = ' '.join(self.msg) + Log.info(self, "Use following command to check debug logs:\n" + + Log.ENDC + "tail -f {0}".format(disp_msg)) + else: + signal.signal(signal.SIGINT, self.signal_handler) + watch_list = [] + for w_list in self.msg: + watch_list = watch_list + glob.glob(w_list) + + logwatch(self, watch_list) + + +def load(app): + # register the plugin class.. this only happens if the plugin is enabled + handler.register(EEDebugController) + # register a hook (function) to run after arguments are parsed. + hook.register('post_argument_parsing', debug_plugin_hook) diff --git a/ee/cli/plugins/import_slow_log.py b/ee/cli/plugins/import_slow_log.py new file mode 100644 index 00000000..b52bf72b --- /dev/null +++ b/ee/cli/plugins/import_slow_log.py @@ -0,0 +1,70 @@ +from cement.core.controller import CementBaseController, expose +from cement.core import handler, hook +from ee.core.shellexec import EEShellExec +from ee.core.logging import Log +from ee.core.variables import EEVariables +import os + + +def import_slow_log_plugin_hook(app): + pass + + +class EEImportslowlogController(CementBaseController): + class Meta: + label = 'import_slow_log' + stacked_on = 'base' + stacked_type = 'nested' + description = 'Import MySQL slow log to Anemometer database' + + @expose(hide=True) + def default(self): + """Default function for import slow log""" + if os.path.isdir("{0}22222/htdocs/db/anemometer" + .format(EEVariables.ee_webroot)): + if os.path.isfile("/var/log/mysql/mysql-slow.log"): + # Get Anemometer user name and password + Log.info(self, "Importing MySQL slow log to Anemometer") + host = os.popen("grep -e \"\'host\'\" {0}22222/htdocs/" + .format(EEVariables.ee_webroot) + + "db/anemometer/conf/config.inc.php " + "| head -1 | cut -d\\\' -f4 | " + "tr -d '\n'").read() + user = os.popen("grep -e \"\'user\'\" {0}22222/htdocs/" + .format(EEVariables.ee_webroot) + + "db/anemometer/conf/config.inc.php " + "| head -1 | cut -d\\\' -f4 | " + "tr -d '\n'").read() + password = os.popen("grep -e \"\'password\'\" {0}22222/" + .format(EEVariables.ee_webroot) + + "htdocs/db/anemometer/conf" + "/config.inc.php " + "| head -1 | cut -d\\\' -f4 | " + "tr -d '\n'").read() + + # Import slow log Anemometer using pt-query-digest + EEShellExec.cmd_exec(self, "pt-query-digest --user={0} " + "--password={1} " + "--review D=slow_query_log," + "t=global_query_review " + "--history D=slow_query_log,t=" + "global_query_review_history " + "--no-report --limit=0% " + "--filter=\" \\$event->{{Bytes}} = " + "length(\\$event->{{arg}}) " + "and \\$event->{{hostname}}=\\\"" + "{2}\\\"\" " + "/var/log/mysql/mysql-slow.log" + .format(user, password, host)) + else: + Log.error(self, "Unable to find MySQL slow log file") + else: + Log.error(self, "Anemometer is not installed") + + +def load(app): + # register the plugin class.. this only happens if the plugin is enabled + handler.register(EEImportslowlogController) + + # register a hook (function) to run after arguments are parsed. + hook.register('post_argument_parsing', import_slow_log_plugin_hook) diff --git a/ee/cli/plugins/info.py b/ee/cli/plugins/info.py new file mode 100644 index 00000000..4ec74db2 --- /dev/null +++ b/ee/cli/plugins/info.py @@ -0,0 +1,202 @@ +"""EEInfo Plugin for EasyEngine.""" + +from cement.core.controller import CementBaseController, expose +from cement.core import handler, hook +from pynginxconfig import NginxConfig +from ee.core.aptget import EEAptGet +from ee.core.shellexec import EEShellExec +from ee.core.logging import Log +import os +import configparser + + +def info_plugin_hook(app): + # do something with the ``app`` object here. + pass + + +class EEInfoController(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 configuration information', + action='store_true')), + (['--nginx'], + dict(help='Get Nginx configuration information', + action='store_true')), + ] + + @expose(hide=True) + def info_nginx(self): + """Display Nginx information""" + version = os.popen("nginx -v 2>&1 | cut -d':' -f2 | cut -d' ' -f2 | " + "cut -d'/' -f2 | tr -d '\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] + if os.path.isfile('/etc/nginx/conf.d/ee-nginx.conf'): + nc.loadf('/etc/nginx/conf.d/ee-nginx.conf') + fastcgi_read_timeout = nc.get('fastcgi_read_timeout')[1] + client_max_body_size = nc.get('client_max_body_size')[1] + else: + 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("php -v | head -n1 | cut -d' ' -f2 |" + " cut -d'+' -f1 | tr -d '\n'").read + config = configparser.ConfigParser() + config.read('/etc/php5/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/php5/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/php5/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("mysql -V | awk '{print($5)}' | cut -d ',' " + "-f1 | tr -d '\n'").read() + host = "localhost" + port = os.popen("mysql -e \"show variables\" | grep ^port | awk " + "'{print($2)}' | tr -d '\n'").read() + wait_timeout = os.popen("mysql -e \"show variables\" | grep " + "^wait_timeout | awk '{print($2)}' | " + "tr -d '\n'").read() + interactive_timeout = os.popen("mysql -e \"show variables\" | grep " + "^interactive_timeout | awk " + "'{print($2)}' | tr -d '\n'").read() + max_used_connections = os.popen("mysql -e \"show global status\" | " + "grep Max_used_connections | awk " + "'{print($2)}' | tr -d '\n'").read() + datadir = os.popen("mysql -e \"show variables\" | grep datadir | awk" + " '{print($2)}' | tr -d '\n'").read() + socket = os.popen("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): + self.app.pargs.nginx = True + self.app.pargs.php = True + self.app.pargs.mysql = True + + if self.app.pargs.nginx: + if EEAptGet.is_installed(self, 'nginx-common'): + self.info_nginx() + else: + Log.error(self, "Nginx is not installed") + + if self.app.pargs.php: + if EEAptGet.is_installed(self, 'php5-fpm'): + self.info_php() + else: + Log.error(self, "PHP5 is not installed") + + if self.app.pargs.mysql: + if EEShellExec.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(EEInfoController) + + # register a hook (function) to run after arguments are parsed. + hook.register('post_argument_parsing', info_plugin_hook) diff --git a/ee/cli/plugins/secure.py b/ee/cli/plugins/secure.py new file mode 100644 index 00000000..359d8513 --- /dev/null +++ b/ee/cli/plugins/secure.py @@ -0,0 +1,132 @@ +from cement.core.controller import CementBaseController, expose +from cement.core import handler, hook +from ee.core.shellexec import EEShellExec +from ee.core.variables import EEVariables +from ee.core.logging import Log +import string +import random +import sys +import hashlib +import getpass + + +def secure_plugin_hook(app): + # do something with the ``app`` object here. + pass + + +class EESecureController(CementBaseController): + class Meta: + label = 'secure' + stacked_on = 'base' + stacked_type = 'nested' + description = ('Secure command secure auth, ip and port') + arguments = [ + (['--auth'], + dict(help='secure auth', action='store_true')), + (['--port'], + dict(help='secure port', action='store_true')), + (['--ip'], + dict(help='secure ip', action='store_true')), + (['user_input'], + dict(help='user input', nargs='?', default=None)), + (['user_pass'], + dict(help='user pass', nargs='?', default=None))] + + @expose(hide=True) + def default(self): + if self.app.pargs.auth: + self.secure_auth() + if self.app.pargs.port: + self.secure_port() + if self.app.pargs.ip: + self.secure_ip() + + @expose(hide=True) + def secure_auth(self): + """This function Secures authentication""" + passwd = ''.join([random.choice + (string.ascii_letters + string.digits) + for n in range(6)]) + if not self.app.pargs.user_input: + username = input("Provide HTTP authentication user " + "name [{0}] :".format(EEVariables.ee_user)) + self.app.pargs.user_input = username + if username == "": + self.app.pargs.user_input = EEVariables.ee_user + if not self.app.pargs.user_pass: + password = input("Provide HTTP authentication " + "password [{0}] :".format(passwd)) + self.app.pargs.user_pass = password + if password == "": + self.app.pargs.user_pass = passwd + EEShellExec.cmd_exec(self, "printf \"{username}:" + "$(openssl passwd -crypt " + "{password} 2> /dev/null)\n\"" + "> /etc/nginx/htpasswd-ee 2>/dev/null" + .format(username=self.app.pargs.user_input, + password=self.app.pargs.user_pass)) + Log.info(self, "Successfully changed HTTP authentication" + " username to : {username}" + .format(username=self.app.pargs.user_input)) + Log.info(self, "Successfully changed HTTP authentication" + " password to : {password}" + .format(password=self.app.pargs.user_pass)) + + @expose(hide=True) + def secure_port(self): + """This function Secures port""" + if self.app.pargs.user_input: + while not self.app.pargs.user_input.isdigit(): + Log.info(self, "Please Enter valid port number ") + self.app.pargs.user_input = input("EasyEngine " + "admin port [22222]:") + if not self.app.pargs.user_input: + port = input("EasyEngine admin port [22222]:") + if port == "": + self.app.pargs.user_input = 22222 + while not port.isdigit() and port != "": + Log.info(self, "Please Enter valid port number :") + port = input("EasyEngine admin port [22222]:") + self.app.pargs.user_input = port + if EEVariables.ee_platform_distro == 'Ubuntu': + EEShellExec.cmd_exec(self, "sed -i \"s/listen.*/listen " + "{port} default_server ssl spdy;/\" " + "/etc/nginx/sites-available/22222.conf" + .format(port=self.app.pargs.user_input)) + if EEVariables.ee_platform_distro == 'debian': + EEShellExec.cmd_exec(self, "sed -i \"s/listen.*/listen " + "{port} default_server ssl;/\" " + "/etc/nginx/sites-available/22222.conf" + .format(port=self.app.pargs.user_input)) + Log.info(self, "Successfully port changed {port}" + .format(port=self.app.pargs.user_input)) + + @expose(hide=True) + def secure_ip(self): + """This function Secures IP""" + # TODO:remaining with ee.conf updation in file + newlist = [] + if not self.app.pargs.user_input: + ip = input("Enter the comma separated IP addresses " + "to white list [127.0.0.1]:") + self.app.pargs.user_input = ip + try: + user_ip = self.app.pargs.user_input.split(',') + except Exception as e: + user_ip = ['127.0.0.1'] + for ip_addr in user_ip: + if not ("exist_ip_address "+ip_addr in open('/etc/nginx/common/' + 'acl.conf').read()): + EEShellExec.cmd_exec(self, "sed -i " + "\"/deny/i allow {whitelist_adre}\;\"" + " /etc/nginx/common/acl.conf" + .format(whitelist_adre=ip_addr)) + Log.info(self, "Successfully added IP address in acl.conf file") + + +def load(app): + # register the plugin class.. this only happens if the plugin is enabled + handler.register(EESecureController) + # register a hook (function) to run after arguments are parsed. + hook.register('post_argument_parsing', secure_plugin_hook) diff --git a/ee/cli/plugins/site.py b/ee/cli/plugins/site.py new file mode 100644 index 00000000..f73ea40c --- /dev/null +++ b/ee/cli/plugins/site.py @@ -0,0 +1,1097 @@ +# """EasyEngine site controller.""" +from cement.core.controller import CementBaseController, expose +from cement.core import handler, hook +from ee.core.variables import EEVariables +from ee.core.domainvalidate import ValidateDomain +from ee.core.fileutils import EEFileUtils +from ee.cli.plugins.site_functions import * +from ee.core.services import EEService +from ee.cli.plugins.sitedb import * +from ee.core.git import EEGit +from subprocess import Popen +import sys +import os +import glob +import subprocess + + +def ee_site_hook(app): + # do something with the ``app`` object here. + from ee.core.database import init_db + init_db() + + +class EESiteController(CementBaseController): + class Meta: + label = 'site' + stacked_on = 'base' + stacked_type = 'nested' + description = ('Performs website specific operations') + arguments = [ + (['site_name'], + dict(help='Website name')), + ] + + @expose(hide=True) + def default(self): + self.app.args.print_help() + + @expose(help="Enable site example.com") + def enable(self): + (ee_domain, ee_www_domain) = ValidateDomain(self.app.pargs.site_name) + Log.info(self, "Enable domain {0:10} \t".format(ee_domain), end='') + if os.path.isfile('/etc/nginx/sites-available/{0}' + .format(ee_domain)): + EEFileUtils.create_symlink(self, + ['/etc/nginx/sites-available/{0}' + .format(ee_domain), + '/etc/nginx/sites-enabled/{0}' + .format(ee_domain)]) + + updateSiteInfo(self, ee_domain, enabled=True) + Log.info(self, "[" + Log.ENDC + "OK" + Log.OKBLUE + "]") + EEService.reload_service(self, 'nginx') + else: + Log.error(self, " site {0} does not exists".format(ee_domain)) + + @expose(help="Disable site example.com") + def disable(self): + (ee_domain, ee_www_domain) = ValidateDomain(self.app.pargs.site_name) + Log.info(self, "Disable domain {0:10} \t".format(ee_domain), end='') + if os.path.isfile('/etc/nginx/sites-available/{0}' + .format(ee_domain)): + if not os.path.isfile('/etc/nginx/sites-enabled/{0}' + .format(ee_domain)): + Log.debug(self, "Site {0} already disabled" + ee_domain) + Log.info(self, "[" + Log.FAIL + "Failed" + Log.OKBLUE+"]") + else: + EEFileUtils.remove_symlink(self, + '/etc/nginx/sites-enabled/{0}' + .format(ee_domain)) + updateSiteInfo(self, ee_domain, enabled=False) + Log.info(self, "[" + Log.ENDC + "OK" + Log.OKBLUE + "]") + EEService.reload_service(self, 'nginx') + else: + Log.error(self, " site {0} does not exists".format(ee_domain)) + + @expose(help="Get example.com information") + def info(self): + (ee_domain, ee_www_domain) = ValidateDomain(self.app.pargs.site_name) + ee_db_name = '' + ee_db_user = '' + ee_db_pass = '' + if os.path.isfile('/etc/nginx/sites-available/{0}' + .format(ee_domain)): + check_site = getSiteInfo(self, ee_domain) + if check_site is None: + Log.error(self, " Site {0} does not exist.".format(ee_domain)) + else: + sitetype = check_site.site_type + cachetype = check_site.cache_type + + ee_site_webroot = EEVariables.ee_webroot + ee_domain + access_log = (ee_site_webroot + '/logs/access.log') + error_log = (ee_site_webroot + '/logs/error.log') + configfiles = glob.glob(ee_site_webroot + '/*-config.php') + if configfiles: + if EEFileUtils.isexist(self, configfiles[0]): + ee_db_name = (EEFileUtils.grep(self, configfiles[0], + 'DB_NAME').split(',')[1] + .split(')')[0].strip().replace('\'', '')) + ee_db_user = (EEFileUtils.grep(self, configfiles[0], + 'DB_USER').split(',')[1] + .split(')')[0].strip().replace('\'', '')) + ee_db_pass = (EEFileUtils.grep(self, configfiles[0], + 'DB_PASSWORD').split(',')[1] + .split(')')[0].strip().replace('\'', '')) + + data = dict(domain=ee_domain, webroot=ee_site_webroot, + accesslog=access_log, errorlog=error_log, + dbname=ee_db_name, dbuser=ee_db_user, + dbpass=ee_db_pass, type=sitetype + " " + cachetype + + " ({0})".format("enabled" + if check_site.is_enabled else + "disabled")) + self.app.render((data), 'siteinfo.mustache') + else: + Log.error(self, " site {0} does not exists".format(ee_domain)) + + @expose(help="Monitor example.com logs") + def log(self): + (ee_domain, ee_www_domain) = ValidateDomain(self.app.pargs.site_name) + ee_site_webroot = EEVariables.ee_webroot + ee_domain + + if os.path.isfile('/etc/nginx/sites-available/{0}' + .format(ee_domain)): + logfiles = glob.glob(ee_site_webroot + '/logs/*.log') + logwatch(self, logfiles) + else: + Log.error(self, " site {0} does not exists".format(ee_domain)) + + @expose(help="Edit Nginx configuration of example.com") + def edit(self): + (ee_domain, ee_www_domain) = ValidateDomain(self.app.pargs.site_name) + if os.path.isfile('/etc/nginx/sites-available/{0}' + .format(ee_domain)): + EEShellExec.invoke_editor(self, '/etc/nginx/sites-available/{0}' + .format(ee_domain)) + if (EEGit.checkfilestatus(self, "/etc/nginx", + '/etc/nginx/sites-available/{0}'.format(ee_domain))): + EEGit.add(self, ["/etc/nginx"], msg="Edit website: {0}" + .format(ee_domain)) + # Reload NGINX + EEService.reload_service(self, 'nginx') + else: + Log.error(self, " site {0} does not exists".format(ee_domain)) + + @expose(help="Display Nginx configuration of example.com") + def show(self): + # TODO Write code for ee site edit command here + (ee_domain, ee_www_domain) = ValidateDomain(self.app.pargs.site_name) + if os.path.isfile('/etc/nginx/sites-available/{0}' + .format(ee_domain)): + Log.info(self, "Display NGINX configuration for {0}" + .format(ee_domain)) + f = open('/etc/nginx/sites-available/{0}'.format(ee_domain), "r") + text = f.read() + Log.info(self, Log.ENDC + text) + f.close() + else: + Log.error(self, " site {0} does not exists".format(ee_domain)) + + @expose(help="Change directory to site webroot") + def cd(self): + + (ee_domain, ee_www_domain) = ValidateDomain(self.app.pargs.site_name) + if os.path.isfile('/etc/nginx/sites-available/{0}' + .format(ee_domain)): + ee_site_webroot = EEVariables.ee_webroot + ee_domain + EEFileUtils.chdir(self, ee_site_webroot) + try: + subprocess.call(['bash']) + except OSError as e: + Log.debug(self, "{0}{1}".format(e.errno, e.strerror)) + Log.error(self, " cannot change directory") + + +class EESiteCreateController(CementBaseController): + class Meta: + label = 'create' + stacked_on = 'site' + stacked_type = 'nested' + description = ('this commands set up configuration and installs ' + 'required files as options are provided') + arguments = [ + (['site_name'], + dict(help='domain name for the site to be created.')), + (['--html'], + dict(help="create html site", action='store_true')), + (['--php'], + dict(help="create php site", action='store_true')), + (['--mysql'], + dict(help="create mysql site", action='store_true')), + (['--wp'], + dict(help="create wordpress single site", + action='store_true')), + (['--wpsubdir'], + dict(help="create wordpress multisite with subdirectory setup", + action='store_true')), + (['--wpsubdomain'], + dict(help="create wordpress multisite with subdomain setup", + action='store_true')), + (['--w3tc'], + dict(help="create wordpress single/multi site with w3tc cache", + action='store_true')), + (['--wpfc'], + dict(help="create wordpress single/multi site with wpfc cache", + action='store_true')), + (['--wpsc'], + dict(help="create wordpress single/multi site with wpsc cache", + action='store_true')), + ] + + @expose(hide=True) + def default(self): + # self.app.render((data), 'default.mustache') + # Check domain name validation + data = '' + (ee_domain, ee_www_domain) = ValidateDomain(self.app.pargs.site_name) + ee_site_webroot = EEVariables.ee_webroot + ee_domain + + # Check if doain previously exists or not + if os.path.isfile('/etc/nginx/sites-available/{0}' + .format(ee_domain)): + Log.error(self, " site {0} already exists" + .format(ee_domain)) + + # setup nginx configuration for site + # HTML + if (self.app.pargs.html and not (self.app.pargs.php or + self.app.pargs.mysql or self.app.pargs.wp or self.app.pargs.w3tc + or self.app.pargs.wpfc or self.app.pargs.wpsc or + self.app.pargs.wpsubdir or self.app.pargs.wpsubdomain)): + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=True, basic=False, wp=False, w3tc=False, + wpfc=False, wpsc=False, multisite=False, + wpsubdir=False, webroot=ee_site_webroot) + stype = 'html' + cache = 'basic' + + # PHP + if (self.app.pargs.php and not (self.app.pargs.html or + self.app.pargs.mysql or self.app.pargs.wp or self.app.pargs.w3tc + or self.app.pargs.wpfc or self.app.pargs.wpsc or + self.app.pargs.wpsubdir or self.app.pargs.wpsubdomain)): + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=True, wp=False, w3tc=False, + wpfc=False, wpsc=False, multisite=False, + wpsubdir=False, webroot=ee_site_webroot) + stype = 'php' + cache = 'basic' + # MySQL + if (self.app.pargs.mysql and not (self.app.pargs.html or + self.app.pargs.php or self.app.pargs.wp or self.app.pargs.w3tc + or self.app.pargs.wpfc or self.app.pargs.wpsc or + self.app.pargs.wpsubdir or self.app.pargs.wpsubdomain)): + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=True, wp=False, w3tc=False, + wpfc=False, wpsc=False, multisite=False, + wpsubdir=False, webroot=ee_site_webroot, + ee_db_name='', ee_db_user='', ee_db_pass='', + ee_db_host='') + stype = 'mysql' + cache = 'basic' + # WP + if ((self.app.pargs.wp or self.app.pargs.w3tc or self.app.pargs.wpfc or + self.app.pargs.wpsc) and not (self.app.pargs.html or + self.app.pargs.php or self.app.pargs.mysql or + self.app.pargs.wpsubdir or self.app.pargs.wpsubdomain)): + + if (self.app.pargs.wp and not (self.app.pargs.w3tc + or self.app.pargs.wpfc or self.app.pargs.wpsc)): + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=True, wp=True, w3tc=False, + wpfc=False, wpsc=False, multisite=False, + wpsubdir=False, webroot=ee_site_webroot, + ee_db_name='', ee_db_user='', ee_db_pass='', + ee_db_host='') + stype = 'wp' + cache = 'basic' + + if (self.app.pargs.w3tc and not + (self.app.pargs.wpfc or self.app.pargs.wpsc)): + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=False, wp=True, w3tc=True, + wpfc=False, wpsc=False, multisite=False, + wpsubdir=False, webroot=ee_site_webroot, + ee_db_name='', ee_db_user='', ee_db_pass='', + ee_db_host='') + stype = 'wp' + cache = 'w3tc' + + if (self.app.pargs.wpfc and not + (self.app.pargs.wpsc or self.app.pargs.w3tc)): + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=False, wp=True, w3tc=False, + wpfc=True, wpsc=False, multisite=False, + wpsubdir=False, webroot=ee_site_webroot, + ee_db_name='', ee_db_user='', ee_db_pass='', + ee_db_host='') + stype = 'wp' + cache = 'wpfc' + + if (self.app.pargs.wpsc and not + (self.app.pargs.w3tc or self.app.pargs.wpfc)): + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=False, wp=True, w3tc=False, + wpfc=False, wpsc=True, multisite=False, + wpsubdir=False, webroot=ee_site_webroot, + ee_db_name='', ee_db_user='', ee_db_pass='', + ee_db_host='') + stype = 'wp' + cache = 'wpsc' + + # WPSUBDIR + if (self.app.pargs.wpsubdir and not (self.app.pargs.html or + self.app.pargs.php or self.app.pargs.mysql or + self.app.pargs.wpsubdomain or self.app.pargs.wp)): + + if (self.app.pargs.wpsubdir and not (self.app.pargs.w3tc + or self.app.pargs.wpfc or self.app.pargs.wpsc)): + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=True, wp=True, w3tc=False, + wpfc=False, wpsc=False, multisite=True, + wpsubdir=True, webroot=ee_site_webroot, + ee_db_name='', ee_db_user='', ee_db_pass='', + ee_db_host='') + stype = 'wpsubdir' + cache = 'basic' + + if (self.app.pargs.w3tc and not + (self.app.pargs.wpfc or self.app.pargs.wpsc)): + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=False, wp=True, w3tc=True, + wpfc=False, wpsc=False, multisite=True, + wpsubdir=True, webroot=ee_site_webroot, + ee_db_name='', ee_db_user='', ee_db_pass='', + ee_db_host='') + stype = 'wpsubdir' + cache = 'w3tc' + + if (self.app.pargs.wpfc and not + (self.app.pargs.wpsc or self.app.pargs.w3tc)): + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=False, wp=True, w3tc=False, + wpfc=True, wpsc=False, multisite=True, + wpsubdir=True, webroot=ee_site_webroot, + ee_db_name='', ee_db_user='', ee_db_pass='', + ee_db_host='') + stype = 'wpsubdir' + cache = 'wpfc' + + if (self.app.pargs.wpsc and not + (self.app.pargs.w3tc or self.app.pargs.wpfc)): + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=False, wp=True, w3tc=False, + wpfc=False, wpsc=True, multisite=True, + wpsubdir=True, webroot=ee_site_webroot, + ee_db_name='', ee_db_user='', ee_db_pass='', + ee_db_host='') + stype = 'wpsubdir' + cache = 'wpsc' + + # WPSUBDOAIN + if (self.app.pargs.wpsubdomain and not (self.app.pargs.html or + self.app.pargs.php or self.app.pargs.mysql or + self.app.pargs.wpsubdir or self.app.pargs.wp)): + + if (self.app.pargs.wpsubdomain and not (self.app.pargs.w3tc + or self.app.pargs.wpfc or self.app.pargs.wpsc)): + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=True, wp=True, w3tc=False, + wpfc=False, wpsc=False, multisite=True, + wpsubdir=False, webroot=ee_site_webroot, + ee_db_name='', ee_db_user='', ee_db_pass='', + ee_db_host='') + stype = 'wpsubdomain' + cache = 'basic' + + if (self.app.pargs.w3tc and not + (self.app.pargs.wpfc or self.app.pargs.wpsc)): + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=False, wp=True, w3tc=True, + wpfc=False, wpsc=False, multisite=True, + wpsubdir=False, webroot=ee_site_webroot, + ee_db_name='', ee_db_user='', ee_db_pass='', + ee_db_host='') + stype = 'wpsubdomain' + cache = 'w3tc' + + if (self.app.pargs.wpfc and not + (self.app.pargs.wpsc or self.app.pargs.w3tc)): + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=False, wp=True, w3tc=False, + wpfc=True, wpsc=False, multisite=True, + wpsubdir=False, webroot=ee_site_webroot, + ee_db_name='', ee_db_user='', ee_db_pass='', + ee_db_host='') + stype = 'wpsubdomain' + cache = 'wpfc' + + if (self.app.pargs.wpsc and not + (self.app.pargs.w3tc or self.app.pargs.wpfc)): + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=False, wp=True, w3tc=False, + wpfc=False, wpsc=True, multisite=True, + wpsubdir=False, webroot=ee_site_webroot, + ee_db_name='', ee_db_user='', ee_db_pass='', + ee_db_host='') + stype = 'wpsubdomain' + cache = 'wpsc' + + if not data: + self.app.args.print_help() + self.app.close(1) + + # Check rerequired packages are installed or not + ee_auth = site_package_check(self, stype) + # setup NGINX configuration, and webroot + setupdomain(self, data) + # Setup database for MySQL site + if 'ee_db_name' in data.keys() and not data['wp']: + data = setupdatabase(self, data) + try: + eedbconfig = open("{0}/ee-config.php".format(ee_site_webroot), + 'w') + eedbconfig.write("" + .format(data['ee_db_name'], + data['ee_db_user'], + data['ee_db_pass'], + data['ee_db_host'])) + eedbconfig.close() + stype = 'mysql' + except IOError as e: + Log.debug(self, "{2} ({0}): {1}" + .format(e.errno, e.strerror, ee_domain)) + Log.error(self, " Unable to create ee-config.php for ") + + # Setup WordPress if Wordpress site + if data['wp']: + ee_wp_creds = setupwordpress(self, data) + # Service Nginx Reload + EEService.reload_service(self, 'nginx') + + EEGit.add(self, ["/etc/nginx"], + msg="{0} created with {1} {2}" + .format(ee_www_domain, stype, cache)) + # Setup Permissions for webroot + setwebrootpermissions(self, data['webroot']) + if ee_auth and len(ee_auth): + for msg in ee_auth: + Log.info(self, Log.ENDC + msg) + + if data['wp']: + Log.info(self, Log.ENDC + "WordPress admin user :" + " {0}".format(ee_wp_creds['wp_user'])) + Log.info(self, Log.ENDC + "WordPress admin user password : {0}" + .format(ee_wp_creds['wp_pass'])) + + display_cache_settings(self, data) + addNewSite(self, ee_www_domain, stype, cache, ee_site_webroot) + Log.info(self, "Successfully created site" + " http://{0}".format(ee_domain)) + + +class EESiteUpdateController(CementBaseController): + class Meta: + label = 'update' + stacked_on = 'site' + stacked_type = 'nested' + description = ('This command updates websites configuration to ' + 'another as per the options are provided') + arguments = [ + (['site_name'], + dict(help='domain name for the site to be updated')), + (['--password'], + dict(help="update to password for wordpress site user", + action='store_true')), + (['--html'], + dict(help="update to html site", action='store_true')), + (['--php'], + dict(help="update to php site", action='store_true')), + (['--mysql'], + dict(help="update to mysql site", action='store_true')), + (['--wp'], + dict(help="update to wordpress single site", + action='store_true')), + (['--wpsubdir'], + dict(help="update to wpsubdir site", action='store_true')), + (['--wpsubdomain'], + dict(help="update to wpsubdomain site", action='store_true')), + (['--w3tc'], + dict(help="update to w3tc cache", action='store_true')), + (['--wpfc'], + dict(help="update to wpfc cache", action='store_true')), + (['--wpsc'], + dict(help="update to wpsc cache", action='store_true')), + ] + + @expose(help="Update site type or cache") + def default(self): + data = '' + (ee_domain, + ee_www_domain, ) = ValidateDomain(self.app.pargs.site_name) + ee_site_webroot = EEVariables.ee_webroot + ee_domain + + check_site = getSiteInfo(self, ee_domain) + + if check_site is None: + Log.error(self, " Site {0} does not exist.".format(ee_domain)) + else: + oldsitetype = check_site.site_type + oldcachetype = check_site.cache_type + + if (self.app.pargs.password and not (self.app.pargs.html or + self.app.pargs.php or self.app.pargs.mysql or self.app.pargs.wp or + self.app.pargs.w3tc or self.app.pargs.wpfc or self.app.pargs.wpsc + or self.app.pargs.wpsubdir or self.app.pargs.wpsubdomain)): + + updatewpuserpassword(self, ee_domain, ee_site_webroot) + self.app.close(0) + + if (self.app.pargs.html and not (self.app.pargs.php or + self.app.pargs.mysql or self.app.pargs.wp or self.app.pargs.w3tc + or self.app.pargs.wpfc or self.app.pargs.wpsc or + self.app.pargs.wpsubdir or self.app.pargs.wpsubdomain)): + Log.error(self, " Cannot update {0} {1} to html" + .format(ee_domain, oldsitetype)) + + # PHP + if (self.app.pargs.php and not (self.app.pargs.html or + self.app.pargs.mysql or self.app.pargs.wp or self.app.pargs.w3tc + or self.app.pargs.wpfc or self.app.pargs.wpsc or + self.app.pargs.wpsubdir or self.app.pargs.wpsubdomain)): + + if oldsitetype != 'html': + + Log.error(self, " Cannot update {0} {1} to php" + .format(ee_domain, oldsitetype)) + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=True, wp=False, w3tc=False, + wpfc=False, wpsc=False, multisite=False, + wpsubdir=False, webroot=ee_site_webroot, + currsitetype=oldsitetype, currcachetype=oldcachetype) + stype = 'php' + cache = 'basic' + + # MySQL + if (self.app.pargs.mysql and not (self.app.pargs.html or + self.app.pargs.php or self.app.pargs.wp or self.app.pargs.w3tc + or self.app.pargs.wpfc or self.app.pargs.wpsc or + self.app.pargs.wpsubdir or self.app.pargs.wpsubdomain)): + + if oldsitetype not in ['html', 'php']: + Log.error(self, " Cannot update {0}, {1} to mysql" + .format(ee_domain, oldsitetype)) + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=True, wp=False, w3tc=False, + wpfc=False, wpsc=False, multisite=False, + wpsubdir=False, webroot=ee_site_webroot, + ee_db_name='', ee_db_user='', ee_db_pass='', + ee_db_host='', currsitetype=oldsitetype, + currcachetype=oldcachetype) + stype = 'mysql' + cache = 'basic' + + # WP + if ((self.app.pargs.wp or self.app.pargs.w3tc or self.app.pargs.wpfc or + self.app.pargs.wpsc) and not (self.app.pargs.html or + self.app.pargs.php or self.app.pargs.mysql or + self.app.pargs.wpsubdir or self.app.pargs.wpsubdomain)): + if (self.app.pargs.wp and not (self.app.pargs.w3tc + or self.app.pargs.wpfc or self.app.pargs.wpsc)): + + if ((oldsitetype not in ['html', 'php', 'mysql', 'wp']) + or (oldsitetype == 'wp' and oldcachetype == 'basic')): + + Log.error(self, "Cannot update {0} {1} {2} to wp basic" + .format(ee_domain, oldsitetype, oldcachetype)) + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=True, wp=True, w3tc=False, + wpfc=False, wpsc=False, multisite=False, + wpsubdir=False, webroot=ee_site_webroot, + ee_db_name='', ee_db_user='', ee_db_pass='', + ee_db_host='', currsitetype=oldsitetype, + currcachetype=oldcachetype) + stype = 'wp' + cache = 'basic' + + if (self.app.pargs.w3tc and not + (self.app.pargs.wpfc or self.app.pargs.wpsc)): + + if (oldsitetype not in ['html', 'php', 'mysql', 'wp'] + or (oldsitetype == 'wp' and oldcachetype == 'w3tc')): + Log.error(self, "Cannot update {0}, {1} {2} to wp w3tc" + .format(ee_domain, oldsitetype, oldcachetype)) + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=False, wp=True, w3tc=True, + wpfc=False, wpsc=False, multisite=False, + wpsubdir=False, webroot=ee_site_webroot, + ee_db_name='', ee_db_user='', ee_db_pass='', + ee_db_host='', currsitetype=oldsitetype, + currcachetype=oldcachetype) + + stype = 'wp' + cache = 'w3tc' + + if (self.app.pargs.wpfc and not + (self.app.pargs.wpsc or self.app.pargs.w3tc)): + + if (oldsitetype not in ['html', 'php', 'mysql', 'wp'] + or (oldsitetype == 'wp' and oldcachetype == 'wpfc')): + Log.error(self, "Cannot update {0}, {1} {2} to wp wpfc" + .format(ee_domain, oldsitetype, oldcachetype)) + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=False, wp=True, w3tc=False, + wpfc=True, wpsc=False, multisite=False, + wpsubdir=False, webroot=ee_site_webroot, + ee_db_name='', ee_db_user='', ee_db_pass='', + ee_db_host='', currsitetype=oldsitetype, + currcachetype=oldcachetype) + stype = 'wp' + cache = 'wpfc' + + if (self.app.pargs.wpsc and not + (self.app.pargs.w3tc or self.app.pargs.wpfc)): + + if (oldsitetype not in ['html', 'php', 'mysql', 'wp'] + or (oldsitetype == 'wp' and oldcachetype == 'wpsc')): + Log.error(self, "Cannot update {0}, {1} {2} to wp wpsc" + .format(ee_domain, oldsitetype, oldcachetype)) + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=False, wp=True, w3tc=False, + wpfc=False, wpsc=True, multisite=False, + wpsubdir=False, webroot=ee_site_webroot, + ee_db_name='', ee_db_user='', ee_db_pass='', + ee_db_host='', currsitetype=oldsitetype, + currcachetype=oldcachetype) + stype = 'wp' + cache = 'wpsc' + + # WPSUBDIR + if (self.app.pargs.wpsubdir and not (self.app.pargs.html or + self.app.pargs.php or self.app.pargs.mysql or + self.app.pargs.wpsubdomain or self.app.pargs.wp)): + if (self.app.pargs.wpsubdir and not (self.app.pargs.w3tc + or self.app.pargs.wpfc or self.app.pargs.wpsc)): + + if (oldsitetype not in ['html', 'php', 'mysql', 'wp', + 'wpsubdir'] + or (oldsitetype == 'wpsubdir' and oldcachetype == 'basic')): + Log.error(self, " Cannot update {0}, {1} {2} " + "to wpsubdir basic" + .format(ee_domain, oldsitetype, oldcachetype)) + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=True, wp=True, w3tc=False, + wpfc=False, wpsc=False, multisite=True, + wpsubdir=True, webroot=ee_site_webroot, + ee_db_name='', ee_db_user='', ee_db_pass='', + ee_db_host='', currsitetype=oldsitetype, + currcachetype=oldcachetype) + stype = 'wpsubdir' + cache = 'basic' + + if (self.app.pargs.w3tc and not + (self.app.pargs.wpfc or self.app.pargs.wpsc)): + + if (oldsitetype not in ['html', 'php', 'mysql', 'wp', + 'wpsubdir'] + or (oldsitetype == 'wpsubdir' and oldcachetype == 'w3tc')): + Log.error(self, " Cannot update {0} {1} {2}" + "to wpsubdir w3tc" + .format(ee_domain, oldsitetype, oldcachetype)) + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=False, wp=True, w3tc=True, + wpfc=False, wpsc=False, multisite=True, + wpsubdir=True, webroot=ee_site_webroot, + ee_db_name='', ee_db_user='', ee_db_pass='', + ee_db_host='', currsitetype=oldsitetype, + currcachetype=oldcachetype) + + stype = 'wpsubdir' + cache = 'w3tc' + + if (self.app.pargs.wpfc and not + (self.app.pargs.wpsc or self.app.pargs.w3tc)): + + if (oldsitetype not in ['html', 'php', 'mysql', 'wp', + 'wpsubdir'] + or (oldsitetype == 'wpsubdir' and oldcachetype == 'wpfc')): + Log.error(self, "Cannot update {0} {1} {2}" + " to wpsubdir wpfc" + .format(ee_domain, oldsitetype, oldcachetype)) + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=False, wp=True, w3tc=False, + wpfc=True, wpsc=False, multisite=True, + wpsubdir=True, webroot=ee_site_webroot, + ee_db_name='', ee_db_user='', ee_db_pass='', + ee_db_host='', currsitetype=oldsitetype, + currcachetype=oldcachetype) + stype = 'wpsubdir' + cache = 'wpfc' + + if (self.app.pargs.wpsc and not + (self.app.pargs.w3tc or self.app.pargs.wpfc)): + + if (oldsitetype not in ['html', 'php', 'mysql', 'wp', + 'wpsubdir'] + or (oldsitetype == 'wpsubdir' and oldcachetype == 'wpsc')): + Log.error(self, " Cannot update {0} {1} {2}" + " to wpsubdir wpsc" + .format(ee_domain, oldsitetype, oldcachetype)) + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=False, wp=True, w3tc=False, + wpfc=False, wpsc=True, multisite=True, + wpsubdir=True, webroot=ee_site_webroot, + ee_db_name='', ee_db_user='', ee_db_pass='', + ee_db_host='', currsitetype=oldsitetype, + currcachetype=oldcachetype) + stype = 'wpsubdir' + cache = 'wpsc' + + if (self.app.pargs.wpsubdomain and not (self.app.pargs.html or + self.app.pargs.php or self.app.pargs.mysql or + self.app.pargs.wpsubdir or self.app.pargs.wp)): + if (self.app.pargs.wpsubdomain and not (self.app.pargs.w3tc + or self.app.pargs.wpfc or self.app.pargs.wpsc)): + if (oldsitetype not in ['html', 'php', 'mysql', 'wp', + 'wpsubdomain'] + or (oldsitetype == 'wpsubdomain' and + oldcachetype == 'basic')): + + Log.error(self, " Cannot update {0} {1} {2}" + " to wpsubdomain basic" + .format(ee_domain, oldsitetype, oldcachetype)) + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=True, wp=True, w3tc=False, + wpfc=False, wpsc=False, multisite=True, + wpsubdir=False, webroot=ee_site_webroot, + ee_db_name='', ee_db_user='', ee_db_pass='', + ee_db_host='', currsitetype=oldsitetype, + currcachetype=oldcachetype) + + stype = 'wpsubdomain' + cache = 'basic' + + if (self.app.pargs.w3tc and not + (self.app.pargs.wpfc or self.app.pargs.wpsc)): + + if (oldsitetype not in ['html', 'php', 'mysql', 'wp', + 'wpsubdomain'] or + (oldsitetype == 'wpsubdomain' and oldcachetype == 'w3tc')): + print(oldsitetype, oldcachetype) + Log.error(self, " Cannot update {0}, {1} {2}" + " to wpsubdomain w3tc" + .format(ee_domain, oldsitetype, oldcachetype)) + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=False, wp=True, w3tc=True, + wpfc=False, wpsc=False, multisite=True, + wpsubdir=False, webroot=ee_site_webroot, + ee_db_name='', ee_db_user='', ee_db_pass='', + ee_db_host='', currsitetype=oldsitetype, + currcachetype=oldcachetype) + + stype = 'wpsubdomain' + cache = 'w3tc' + + if (self.app.pargs.wpfc and not + (self.app.pargs.wpsc or self.app.pargs.w3tc)): + + if (oldsitetype not in ['html', 'php', 'mysql', 'wp', + 'wpsubdomain'] or + (oldsitetype == 'wpsubdomain' and oldcachetype == 'wpfc')): + print(oldsitetype, oldcachetype) + Log.error(self, " Cannot update {0}, {1} {2} " + "to wpsubdomain wpfc" + .format(ee_domain, oldsitetype, oldcachetype)) + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=False, wp=True, w3tc=False, + wpfc=True, wpsc=False, multisite=True, + wpsubdir=False, webroot=ee_site_webroot, + ee_db_name='', ee_db_user='', ee_db_pass='', + ee_db_host='', currsitetype=oldsitetype, + currcachetype=oldcachetype) + + stype = 'wpsubdomain' + cache = 'wpfc' + + if (self.app.pargs.wpsc and not + (self.app.pargs.w3tc or self.app.pargs.wpfc)): + + if (oldsitetype not in ['html', 'php', 'mysql', 'wp', + 'wpsubdomain'] or + (oldsitetype == 'wpsubdomain' and oldcachetype == 'wpsc')): + print(oldsitetype, oldcachetype) + Log.error(self, " Cannot update {0}, {1} {2}" + " to wpsubdomain wpsc" + .format(ee_domain, oldsitetype, oldcachetype)) + + data = dict(site_name=ee_domain, www_domain=ee_www_domain, + static=False, basic=False, wp=True, w3tc=False, + wpfc=False, wpsc=True, multisite=True, + wpsubdir=False, webroot=ee_site_webroot, + ee_db_name='', ee_db_user='', ee_db_pass='', + ee_db_host='', currsitetype=oldsitetype, + currcachetype=oldcachetype) + + stype = 'wpsubdomain' + cache = 'wpsc' + + if not data: + Log.error(self, " Cannot update {0}, Invalid Options" + .format(ee_domain)) + + ee_auth = site_package_check(self, stype) + sitebackup(self, data) + + # setup NGINX configuration, and webroot + setupdomain(self, data) + + if 'ee_db_name' in data.keys() and not data['wp']: + data = setupdatabase(self, data) + try: + eedbconfig = open("{0}/ee-config.php".format(ee_site_webroot), + 'w') + eedbconfig.write("" + .format(data['ee_db_name'], + data['ee_db_user'], + data['ee_db_pass'], + data['ee_db_host'])) + eedbconfig.close() + except IOError as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, " Unable to create ee-config.php.") + + if oldsitetype == 'mysql': + config_file = (ee_site_webroot + '/backup/{0}/ee-config.php' + .format(EEVariables.ee_date)) + data['ee_db_name'] = (EEFileUtils.grep(self, config_file, + 'DB_NAME') + .split(',')[1] + .split(')')[0].strip()) + data['ee_db_user'] = (EEFileUtils.grep(self, config_file, + 'DB_USER') + .split(',')[1] + .split(')')[0].strip()) + data['ee_db_pass'] = (EEFileUtils.grep(self, config_file, + 'DB_PASSWORD') + .split(',')[1] + .split(')')[0].strip()) + + # Setup WordPress if old sites are html/php/mysql sites + if data['wp'] and oldsitetype in ['html', 'php', 'mysql']: + ee_wp_creds = setupwordpress(self, data) + + # Uninstall unnecessary plugins + if oldsitetype in ['wp', 'wpsubdir', 'wpsubdomain']: + # Setup WordPress Network if update option is multisite + # and oldsite is WordPress single site + if data['multisite'] and oldsitetype == 'wp': + setupwordpressnetwork(self, data) + + if (oldcachetype == 'w3tc' or oldcachetype == 'wpfc' and + not (data['w3tc'] or data['wpfc'])): + uninstallwp_plugin(self, 'w3-total-cache', data) + + if oldcachetype == 'wpsc' and not data['wpsc']: + uninstallwp_plugin(self, 'wp-super-cache', data) + + if (oldcachetype != 'w3tc' or oldcachetype != 'wpfc') and (data['w3tc'] + or data['wpfc']): + installwp_plugin(self, 'w3-total-cache', data) + + if oldcachetype != 'wpsc' and data['wpsc']: + installwp_plugin(self, 'wp-super-cache', data) + + # Service Nginx Reload + EEService.reload_service(self, 'nginx') + + EEGit.add(self, ["/etc/nginx"], + msg="{0} updated with {1} {2}" + .format(ee_www_domain, stype, cache)) + # Setup Permissions for webroot + setwebrootpermissions(self, data['webroot']) + if ee_auth and len(ee_auth): + for msg in ee_auth: + Log.info(self, Log.ENDC + msg) + + if data['wp'] and oldsitetype in ['html', 'php', 'mysql']: + Log.info(self, "\n\n" + Log.ENDC + "WordPress admin user :" + " {0}".format(ee_wp_creds['wp_user'])) + Log.info(self, Log.ENDC + "WordPress admin password : {0}" + .format(ee_wp_creds['wp_pass']) + "\n\n") + display_cache_settings(self, data) + updateSiteInfo(self, ee_www_domain, stype=stype, cache=cache) + Log.info(self, "Successfully updated site" + " http://{0}".format(ee_domain)) + + +class EESiteDeleteController(CementBaseController): + class Meta: + label = 'delete' + stacked_on = 'site' + stacked_type = 'nested' + description = 'To delete website' + arguments = [ + (['site_name'], + dict(help='domain name to be deleted')), + (['--no-prompt'], + dict(help="doesnt ask permission for delete", + action='store_true')), + (['--all'], + dict(help="delete all", action='store_true')), + (['--db'], + dict(help="delete db only", action='store_true')), + (['--files'], + dict(help="delete webroot only", action='store_true')), + ] + + @expose(help="Delete website configuration and files") + def default(self): + # TODO Write code for ee site update here + (ee_domain, ee_www_domain) = ValidateDomain(self.app.pargs.site_name) + ee_db_name = '' + ee_prompt = '' + ee_nginx_prompt = '' + + if ((not self.app.pargs.db) and (not self.app.pargs.files) and + (not self.app.pargs.all)): + self.app.pargs.all = True + + if os.path.isfile('/etc/nginx/sites-available/{0}' + .format(ee_domain)): + ee_site_webroot = EEVariables.ee_webroot + ee_domain + + if self.app.pargs.no_prompt: + ee_prompt = 'Y' + + if self.app.pargs.db: + if not ee_prompt: + ee_db_prompt = input('Do you want to delete database' + '[Y/N]: ') + else: + ee_db_prompt = 'Y' + + if ee_db_prompt == 'Y' or ee_db_prompt == 'y': + self.deleteDB(ee_site_webroot) + + if self.app.pargs.files: + if not ee_prompt: + ee_web_prompt = input('Do you want to delete webroot' + '[Y/N]: ') + else: + ee_web_prompt = 'Y' + + if ee_web_prompt == 'Y' or ee_web_prompt == 'y': + self.deleteWebRoot(ee_site_webroot) + + if self.app.pargs.all: + if not ee_prompt: + ee_db_prompt = input('Do you want to delete database' + '[Y/N]: ' + ) + ee_web_prompt = input('Do you want to delete webroot' + '[Y/N]: ') + ee_nginx_prompt = input('Do you want to delete NGINX' + ' configuration [Y/N]: ') + else: + ee_db_prompt = 'Y' + ee_web_prompt = 'Y' + ee_nginx_prompt = 'Y' + + if ee_db_prompt == 'Y' or ee_db_prompt == 'y': + self.deleteDB(ee_site_webroot) + if ee_web_prompt == 'Y' or ee_web_prompt == 'y': + self.deleteWebRoot(ee_site_webroot) + + if (ee_nginx_prompt == 'Y' or ee_nginx_prompt == 'y'): + Log.debug(self, "Removing Nginx configuration") + EEFileUtils.rm(self, '/etc/nginx/sites-available/{0}' + .format(ee_domain)) + deleteSiteInfo(self, ee_domain) + Log.info(self, "Deleted site {0}".format(ee_domain)) + else: + Log.error(self, " site {0} does not exists".format(ee_domain)) + + @expose(hide=True) + def deleteDB(self, webroot): + configfiles = glob.glob(webroot + '/*-config.php') + if configfiles: + if EEFileUtils.isexist(self, configfiles[0]): + ee_db_name = (EEFileUtils.grep(self, configfiles[0], + 'DB_NAME').split(',')[1] + .split(')')[0].strip().replace('\'', '')) + ee_db_user = (EEFileUtils.grep(self, configfiles[0], + 'DB_USER').split(',')[1] + .split(')')[0].strip().replace('\'', '')) + ee_db_pass = (EEFileUtils.grep(self, configfiles[0], + 'DB_PASSWORD').split(',')[1] + .split(')')[0].strip().replace('\'', '')) + ee_db_host = (EEFileUtils.grep(self, configfiles[0], + 'DB_HOST').split(',')[1] + .split(')')[0].strip().replace('\'', '')) + try: + Log.debug(self, "dropping database {0}".format(ee_db_name)) + EEMysql.execute(self, + "drop database {0}".format(ee_db_name), + errormsg='Unable to drop database {0}' + .format(ee_db_name)) + if ee_db_user != 'root': + Log.debug(self, "dropping user {0}".format(ee_db_user)) + EEMysql.execute(self, + "drop user {0}@{1}" + .format(ee_db_user, ee_db_host)) + EEMysql.execute(self, + "flush privileges") + except Exception as e: + Log.error(self, "Error occured while deleting database") + + @expose(hide=True) + def deleteWebRoot(self, webroot): + EEFileUtils.rm(self, webroot) + + +class EESiteListController(CementBaseController): + class Meta: + label = 'list' + stacked_on = 'site' + stacked_type = 'nested' + description = 'List websites' + arguments = [ + (['--enabled'], + dict(help='List enabled websites', action='store_true')), + (['--disabled'], + dict(help="List disabled websites", action='store_true')), + ] + + @expose(help="Lists websites") + def default(self): + sites = getAllsites(self) + if not sites: + pass + + if self.app.pargs.enabled: + for site in sites: + if site.is_enabled: + Log.info(self, "{0}".format(site.sitename)) + elif self.app.pargs.disabled: + for site in sites: + if not site.is_enabled: + Log.info(self, "{0}".format(site.sitename)) + else: + for site in sites: + Log.info(self, "{0}".format(site.sitename)) + + +def load(app): + # register the plugin class.. this only happens if the plugin is enabled + handler.register(EESiteController) + handler.register(EESiteCreateController) + handler.register(EESiteUpdateController) + handler.register(EESiteDeleteController) + handler.register(EESiteListController) + # register a hook (function) to run after arguments are parsed. + hook.register('post_argument_parsing', ee_site_hook) diff --git a/ee/cli/plugins/site_functions.py b/ee/cli/plugins/site_functions.py new file mode 100644 index 00000000..b12d3673 --- /dev/null +++ b/ee/cli/plugins/site_functions.py @@ -0,0 +1,538 @@ +from ee.cli.plugins.stack import EEStackController +from ee.core.fileutils import EEFileUtils +from ee.core.mysql import EEMysql +from ee.core.shellexec import EEShellExec +from ee.core.variables import EEVariables +from ee.core.aptget import EEAptGet +from ee.core.logging import Log +import os +import random +import string +import sys +import getpass +import glob +import re + + +def setupdomain(self, data): + + ee_domain_name = data['site_name'] + ee_site_webroot = data['webroot'] + Log.info(self, "Setting up NGINX configuration \t", end='') + # write nginx config for file + try: + ee_site_nginx_conf = open('/etc/nginx/sites-available/{0}' + .format(ee_domain_name), 'w') + + self.app.render((data), 'virtualconf.mustache', + out=ee_site_nginx_conf) + ee_site_nginx_conf.close() + except IOError as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "\nUnable to create NGINX configuration") + except Exception as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "\nUnable to create NGINX configuration") + Log.info(self, "[" + Log.ENDC + "Done" + Log.OKBLUE + "]") + + # create symbolic link for + EEFileUtils.create_symlink(self, ['/etc/nginx/sites-available/{0}' + .format(ee_domain_name), + '/etc/nginx/sites-enabled/{0}' + .format(ee_domain_name)]) + + # Creating htdocs & logs directory + Log.info(self, "Setting up webroot \t\t", end='') + try: + if not os.path.exists('{0}/htdocs'.format(ee_site_webroot)): + os.makedirs('{0}/htdocs'.format(ee_site_webroot)) + if not os.path.exists('{0}/logs'.format(ee_site_webroot)): + os.makedirs('{0}/logs'.format(ee_site_webroot)) + except Exception as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "\nUnable to setup webroot") + + EEFileUtils.create_symlink(self, ['/var/log/nginx/{0}.access.log' + .format(ee_domain_name), + '{0}/logs/access.log' + .format(ee_site_webroot)]) + EEFileUtils.create_symlink(self, ['/var/log/nginx/{0}.error.log' + .format(ee_domain_name), + '{0}/logs/error.log' + .format(ee_site_webroot)]) + Log.info(self, "[" + Log.ENDC + "Done" + Log.OKBLUE + "]") + + +def setupdatabase(self, data): + ee_domain_name = data['site_name'] + ee_random = (''.join(random.sample(string.ascii_uppercase + + string.ascii_lowercase + string.digits, 15))) + ee_replace_dot = ee_domain_name.replace('.', '_') + prompt_dbname = self.app.config.get('mysql', 'db-name') + prompt_dbuser = self.app.config.get('mysql', 'db-user') + ee_mysql_grant_host = self.app.config.get('mysql', 'grant-host') + ee_db_name = '' + ee_db_username = '' + ee_db_password = '' + + if prompt_dbname == 'True' or prompt_dbname == 'true': + try: + ee_db_name = input('Enter the MySQL database name [{0}]: ' + .format(ee_replace_dot)) + except EOFError as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "Unable to input database name") + + if not ee_db_name: + ee_db_name = ee_replace_dot + + if prompt_dbuser == 'True' or prompt_dbuser == 'true': + try: + ee_db_username = input('Enter the MySQL database user name [{0}]: ' + .format(ee_replace_dot)) + ee_db_password = getpass.getpass(prompt='Enter the MySQL database' + ' password [{0}]: ' + .format(ee_random)) + except EOFError as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "Unable to input database credentials") + + if not ee_db_username: + ee_db_username = ee_replace_dot + if not ee_db_password: + ee_db_password = ee_random + + if len(ee_db_username) > 16: + Log.debug(self, 'Autofix MySQL username (ERROR 1470 (HY000)),' + ' please wait') + ee_random10 = (''.join(random.sample(string.ascii_uppercase + + string.ascii_lowercase + string.digits, 10))) + ee_db_username = (ee_db_name[0:6] + ee_random10) + # create MySQL database + Log.info(self, "Setting up database\t\t", end='') + Log.debug(self, "Creating databse {0}".format(ee_db_name)) + EEMysql.execute(self, "create database {0}" + .format(ee_db_name)) + + # Create MySQL User + Log.debug(self, "Creating user {0}".format(ee_db_username)) + EEMysql.execute(self, + "create user {0}@{1} identified by '{2}'" + .format(ee_db_username, ee_mysql_grant_host, + ee_db_password)) + + # Grant permission + Log.debug(self, "Setting up user privileges") + EEMysql.execute(self, + "grant all privileges on {0}.* to {1}@{2}" + .format(ee_db_name, ee_db_username, ee_mysql_grant_host)) + Log.info(self, "[" + Log.ENDC + "Done" + Log.OKBLUE + "]") + + data['ee_db_name'] = ee_db_name + data['ee_db_user'] = ee_db_username + data['ee_db_pass'] = ee_db_password + data['ee_db_host'] = EEVariables.ee_mysql_host + return(data) + + +def setupwordpress(self, data): + ee_domain_name = data['site_name'] + ee_site_webroot = data['webroot'] + prompt_wpprefix = self.app.config.get('wordpress', 'prefix') + ee_wp_user = self.app.config.get('wordpress', 'user') + ee_wp_pass = self.app.config.get('wordpress', 'password') + ee_wp_email = self.app.config.get('wordpress', 'email') + # Random characters + ee_random = (''.join(random.sample(string.ascii_uppercase + + string.ascii_lowercase + string.digits, 15))) + ee_wp_prefix = '' + # ee_wp_user = '' + # ee_wp_pass = '' + + Log.info(self, "Downloading Wordpress \t\t", end='') + EEFileUtils.chdir(self, '{0}/htdocs/'.format(ee_site_webroot)) + EEShellExec.cmd_exec(self, "wp --allow-root core download") + Log.info(self, "[" + Log.ENDC + "Done" + Log.OKBLUE + "]") + + if not (data['ee_db_name'] and data['ee_db_user'] and data['ee_db_pass']): + data = setupdatabase(self, data) + if prompt_wpprefix == 'True' or prompt_wpprefix == 'true': + try: + ee_wp_prefix = input('Enter the WordPress table prefix [wp_]: ') + while not re.match('^[A-Za-z0-9_]*$', ee_wp_prefix): + Log.warn(self, "table prefix can only " + "contain numbers, letters, and underscores") + ee_wp_prefix = input('Enter the WordPress table prefix [wp_]: ' + ) + except EOFError as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "Unable to input table prefix") + + if not ee_wp_prefix: + ee_wp_prefix = 'wp_' + + # Modify wp-config.php & move outside the webroot + + EEFileUtils.chdir(self, '{0}/htdocs/'.format(ee_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 /usr/bin/wp --allow-root " + + "core config " + + "--dbname={0} --dbprefix={1} --dbuser={2} " + .format(data['ee_db_name'], ee_wp_prefix, + data['ee_db_user']) + + "--dbpass= " + "--extra-php< {1}/{0}.sql" + .format(ee_db_name, backup_path), + errormsg="\nFailed: Backup Database") + Log.info(self, "[" + Log.ENDC + "Done" + Log.OKBLUE + "]") + # move wp-config.php/ee-config.php to backup + if data['currsitetype'] in ['mysql']: + EEFileUtils.mvfile(self, configfiles[0], backup_path) + else: + EEFileUtils.copyfile(self, configfiles[0], backup_path) + + +def site_package_check(self, stype): + apt_packages = [] + packages = [] + stack = EEStackController() + stack.app = self.app + if stype in ['html', 'php', 'mysql', 'wp', 'wpsubdir', 'wpsubdomain']: + Log.debug(self, "Setting apt_packages variable for Nginx") + if not EEAptGet.is_installed(self, 'nginx-common'): + apt_packages = apt_packages + EEVariables.ee_nginx + + if stype in ['php', 'mysql', 'wp', 'wpsubdir', 'wpsubdomain']: + Log.debug(self, "Setting apt_packages variable for PHP") + if not EEAptGet.is_installed(self, 'php5-fpm'): + apt_packages = apt_packages + EEVariables.ee_php + + if stype in ['mysql', 'wp', 'wpsubdir', 'wpsubdomain']: + Log.debug(self, "Setting apt_packages variable for MySQL") + if not EEShellExec.cmd_exec(self, "mysqladmin ping"): + apt_packages = apt_packages + EEVariables.ee_mysql + + if stype in ['php', 'mysql', 'wp', 'wpsubdir', 'wpsubdomain']: + Log.debug(self, "Setting apt_packages variable for Postfix") + if not EEAptGet.is_installed(self, 'postfix'): + apt_packages = apt_packages + EEVariables.ee_postfix + + if stype in ['wp', 'wpsubdir', 'wpsubdomain']: + Log.debug(self, "Setting packages variable for WP-CLI") + if not EEShellExec.cmd_exec(self, "which wp"): + packages = packages + [["https://github.com/wp-cli/wp-cli/" + "releases/download/v0.17.1/" + "wp-cli.phar", "/usr/bin/wp", + "WP-CLI"]] + return(stack.install(apt_packages=apt_packages, packages=packages, + disp_msg=False)) + + +def updatewpuserpassword(self, ee_domain, ee_site_webroot): + + ee_wp_user = '' + ee_wp_pass = '' + EEFileUtils.chdir(self, '{0}/htdocs/'.format(ee_site_webroot)) + + # Check if ee_domain is wordpress install + is_wp = EEShellExec.cmd_exec(self, "wp --allow-root core" + " version", + errormsg="{0} : Unable to check if wp install" + .format(ee_domain)) + + # Exit if ee_domain is not wordpress install + if not is_wp: + Log.error(self, "{0} does not seem to be a WordPress site" + .format(ee_domain)) + + ee_wp_user = input("Provide WordPress user name [admin]: ") + if ee_wp_user == "?": + Log.info(self, "Fetching WordPress user list") + EEShellExec.cmd_exec(self, "wp --allow-root user list " + "--fields=user_login | grep -v user_login", + errormsg="Unable to Fetch users list") + + if not ee_wp_user: + ee_wp_user = 'admin' + + is_user_exist = EEShellExec.cmd_exec(self, "wp --allow-root user list " + "--fields=user_login | grep {0}$ " + .format(ee_wp_user)) + + if is_user_exist: + ee_wp_pass = input("Provide password for {0} user: " + .format(ee_wp_user)) + if len(ee_wp_pass) > 8: + EEShellExec.cmd_exec(self, "wp --allow-root user update {0}" + " --user_pass={1}" + .format(ee_wp_user, ee_wp_pass)) + Log.info(self, "Password updated successfully") + else: + Log.error(self, "Password Unchanged. Hint : Your password must be " + "8 characters long") + else: + Log.error(self, "Invalid WordPress user {0} for {1}." + .format(ee_wp_user, ee_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['wpfc']: + if data['multisite']: + Log.info(self, "Configure nginx-helper:" + "\thttp://{0}/wp-admin/network/settings.php?" + "page=nginx".format(data['site_name'])) + else: + Log.info(self, "Configure nginx-helper:" + "\thttp://{0}/wp-admin/options-general.php?" + "page=nginx".format(data['site_name'])) + + if data['wpfc'] or data['w3tc']: + if data['multisite']: + Log.info(self, "Configure W3TC:" + "\t\thttp://{0}/wp-admin/network/admin.php?" + "page=w3tc_general".format(data['site_name'])) + else: + Log.info(self, "Configure W3TC:" + "\t\thttp://{0}/wp-admin/admin.php?" + "page=w3tc_general".format(data['site_name'])) + + if data['wpfc']: + Log.info(self, "Page Cache:\t\tDisable") + elif data['w3tc']: + Log.info(self, "Page Cache:\t\tDisk Enhanced") + Log.info(self, "Database Cache:\t\tMemcached") + Log.info(self, "Object Cache:\t\tMemcached") + Log.info(self, "Browser Cache:\t\tDisable") + + +def logwatch(self, logfiles): + import zlib + import base64 + import time + from ee.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() diff --git a/ee/cli/plugins/sitedb.py b/ee/cli/plugins/sitedb.py new file mode 100644 index 00000000..805b72bc --- /dev/null +++ b/ee/cli/plugins/sitedb.py @@ -0,0 +1,96 @@ +from sqlalchemy import Column, DateTime, String, Integer, Boolean +from sqlalchemy import ForeignKey, func +from sqlalchemy.orm import relationship, backref +from sqlalchemy.ext.declarative import declarative_base +from ee.core.logging import Log +from ee.core.database import db_session +from ee.core.models import SiteDB +import sys + + +def addNewSite(self, site, stype, cache, path, + enabled=True, ssl=False, fs='ext4', db='mysql'): + """ + Add New Site record information into ee database. + """ + try: + newRec = SiteDB(site, stype, cache, path, enabled, ssl, fs, db) + db_session.add(newRec) + db_session.commit() + except Exception as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "Unable to add site to database") + + +def getSiteInfo(self, site): + """ + Retrieves site record from ee databse + """ + try: + q = SiteDB.query.filter(SiteDB.sitename == site).first() + return q + except Exception as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "Unable to query database for site info") + + +def updateSiteInfo(self, site, stype='', cache='', + enabled=True, ssl=False, fs='', db=''): + """updates site record in database""" + try: + q = SiteDB.query.filter(SiteDB.sitename == site).first() + except Exception as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "Unable to query database for site info") + + if not q: + Log.error(self, "{0} does not exist in database".format(site)) + + # Check if new record matches old if not then only update database + if stype and q.site_type != stype: + q.site_type = stype + + if cache and q.cache_type != cache: + q.cache_type = cache + + if q.is_enabled != enabled: + q.is_enabled = enabled + + if ssl and q.is_ssl != ssl: + q.is_ssl = ssl + + try: + q.created_on = func.now() + db_session.commit() + except Exception as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "Unable to update site info in application database.") + + +def deleteSiteInfo(self, site): + """Delete site record in database""" + try: + q = SiteDB.query.filter(SiteDB.sitename == site).first() + except Exception as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "Unable to query database") + + if not q: + Log.error(self, "{0} does not exist in database".format(site)) + + try: + db_session.delete(q) + db_session.commit() + except Exception as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "Unable to delete site from application database.") + + +def getAllsites(self): + + try: + q = SiteDB.query.all() + return q + except Exception as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "Unable to query database") diff --git a/ee/cli/plugins/stack.py b/ee/cli/plugins/stack.py new file mode 100644 index 00000000..8c27ba82 --- /dev/null +++ b/ee/cli/plugins/stack.py @@ -0,0 +1,1466 @@ +"""Stack Plugin for EasyEngine.""" + +from cement.core.controller import CementBaseController, expose +from cement.core import handler, hook +from ee.core.variables import EEVariables +from ee.core.aptget import EEAptGet +from ee.core.download import EEDownload +from ee.core.shellexec import EEShellExec +from ee.core.fileutils import EEFileUtils +from ee.core.apt_repo import EERepo +from ee.core.extract import EEExtract +from ee.core.mysql import EEMysql +from ee.core.addswap import EESwap +from ee.core.git import EEGit +from ee.core.checkfqdn import check_fqdn +from pynginxconfig import NginxConfig +from ee.core.services import EEService +from ee.core.variables import EEVariables +import random +import string +import configparser +import time +import shutil +import os +import pwd +import grp +from ee.cli.plugins.stack_services import EEStackStatusController +from ee.core.logging import Log + + +def ee_stack_hook(app): + # do something with the ``app`` object here. + pass + + +class EEStackController(CementBaseController): + class Meta: + label = 'stack' + stacked_on = 'base' + stacked_type = 'nested' + description = 'Stack command manages stack operations' + arguments = [ + (['--all'], + dict(help='Install all stack', action='store_true')), + (['--web'], + dict(help='Install web stack', action='store_true')), + (['--admin'], + dict(help='Install admin tools stack', action='store_true')), + (['--mail'], + dict(help='Install mail server stack', action='store_true')), + (['--mailscanner'], + dict(help='Install mail scanner stack', action='store_true')), + (['--nginx'], + dict(help='Install Nginx stack', action='store_true')), + (['--php'], + dict(help='Install PHP stack', action='store_true')), + (['--mysql'], + dict(help='Install MySQL stack', action='store_true')), + (['--postfix'], + dict(help='Install Postfix stack', action='store_true')), + (['--wpcli'], + dict(help='Install WPCLI stack', action='store_true')), + (['--phpmyadmin'], + dict(help='Install PHPMyAdmin stack', action='store_true')), + (['--adminer'], + dict(help='Install Adminer stack', action='store_true')), + (['--utils'], + dict(help='Install Utils stack', action='store_true')), + ] + + @expose(hide=True) + def default(self): + """default action of ee stack command""" + self.app.args.print_help() + + @expose(hide=True) + def pre_pref(self, apt_packages): + """Pre settings to do before installation packages""" + if set(EEVariables.ee_postfix).issubset(set(apt_packages)): + Log.debug(self, "Pre-seeding Postfix") + EEShellExec.cmd_exec(self, "echo \"postfix postfix" + "/main_mailer_type string \'Internet Site\'\"" + " | debconf-set-selections") + EEShellExec.cmd_exec(self, "echo \"postfix postfix/mailname string" + " $(hostname -f)\" | debconf-set-selections") + + if set(EEVariables.ee_mysql).issubset(set(apt_packages)): + Log.info(self, "Adding repository for MySQL") + EERepo.add(self, repo_url=EEVariables.ee_mysql_repo) + Log.debug(self, 'Adding key for {0}' + .format(EEVariables.ee_mysql_repo)) + EERepo.add_key(self, '1C4CBDCDCD2EFD2A', + keyserver="subkeys.pgp.net") + chars = ''.join(random.sample(string.ascii_letters, 8)) + Log.debug(self, "Pre-seeding MySQL") + EEShellExec.cmd_exec(self, "echo \"percona-server-server-5.6 " + "percona-server-server/root_password " + "password {chars}\" | " + "debconf-set-selections".format(chars=chars)) + EEShellExec.cmd_exec(self, "echo \"percona-server-server-5.6 " + "percona-server-server/root_password_again " + "password {chars}\" | " + "debconf-set-selections".format(chars=chars)) + mysql_config = """ + [client] + user = root + password = {chars} + """.format(chars=chars) + config = configparser.ConfigParser() + config.read_string(mysql_config) + Log.debug(self, 'Writting configuration into MySQL file') + with open(os.path.expanduser("~")+'/.my.cnf', 'w') as configfile: + config.write(configfile) + + if set(EEVariables.ee_nginx).issubset(set(apt_packages)): + Log.info(self, "Adding repository for Nginx") + if EEVariables.ee_platform_distro == 'debian': + Log.debug(self, 'Adding Dotdeb/nginx GPG key') + EERepo.add(self, repo_url=EEVariables.ee_nginx_repo) + else: + EERepo.add(self, ppa=EEVariables.ee_nginx_repo) + Log.debug(self, 'Adding ppa of Nginx') + + if set(EEVariables.ee_php).issubset(set(apt_packages)): + Log.info(self, "Adding repository for PHP") + if EEVariables.ee_platform_distro == 'debian': + Log.debug(self, 'Adding repo_url of php for debian') + EERepo.add(self, repo_url=EEVariables.ee_php_repo) + Log.debug(self, 'Adding Dotdeb/php GPG key') + EERepo.add_key(self, '89DF5277') + else: + Log.debug(self, 'Adding ppa for PHP') + EERepo.add(self, ppa=EEVariables.ee_php_repo) + + if set(EEVariables.ee_mail).issubset(set(apt_packages)): + if EEVariables.ee_platform_codename == 'squeeze': + Log.info(self, "Adding repository for dovecot ") + EERepo.add(self, repo_url=EEVariables.ee_dovecot_repo) + Log.debug(self, 'Executing the command debconf-set-selections.') + EEShellExec.cmd_exec(self, "echo \"dovecot-core dovecot-core/" + "create-ssl-cert boolean yes\" " + "| debconf-set-selections") + EEShellExec.cmd_exec(self, "echo \"dovecot-core dovecot-core" + "/ssl-cert-name string $(hostname -f)\"" + " | debconf-set-selections") + + @expose(hide=True) + def post_pref(self, apt_packages, packages): + """Post activity after installation of packages""" + if len(apt_packages): + if set(EEVariables.ee_postfix).issubset(set(apt_packages)): + EEGit.add(self, ["/etc/postfix"], + msg="Adding Postfix into Git") + EEService.reload_service(self, 'postfix') + + if set(EEVariables.ee_nginx).issubset(set(apt_packages)): + if ((not os.path.isfile('/etc/nginx/conf.d/ee-nginx.conf')) and + os.path.isfile('/etc/nginx/nginx.conf')): + nc = NginxConfig() + Log.debug(self, 'Loading file /etc/nginx/nginx.conf ') + nc.loadf('/etc/nginx/nginx.conf') + nc.set('worker_processes', 'auto') + nc.append(('worker_rlimit_nofile', '100000'), position=2) + nc.remove(('events', '')) + nc.append({'name': 'events', 'param': '', 'value': + [('worker_connections', '4096'), + ('multi_accept', 'on')]}, position=4) + nc.set([('http',), 'keepalive_timeout'], '30') + Log.debug(self, "Writting nginx configuration to " + "file /etc/nginx/nginx.conf ") + nc.savef('/etc/nginx/nginx.conf') + + # Custom Nginx configuration by EasyEngine + data = dict(version=EEVariables.ee_version) + Log.debug(self, 'Writting the nginx configuration to ' + 'file /etc/nginx/conf.d/ee-nginx.conf ') + ee_nginx = open('/etc/nginx/conf.d/ee-nginx.conf', 'w') + self.app.render((data), 'nginx-core.mustache', + out=ee_nginx) + ee_nginx.close() + + data = dict() + Log.debug(self, 'Writting the nginx configuration to ' + 'file /etc/nginx/conf.d/blockips.conf') + ee_nginx = open('/etc/nginx/conf.d/blockips.conf', 'w') + self.app.render((data), 'blockips.mustache', out=ee_nginx) + ee_nginx.close() + + Log.debug(self, 'Writting the nginx configuration to ' + 'file /etc/nginx/conf.d/fastcgi.conf') + ee_nginx = open('/etc/nginx/conf.d/fastcgi.conf', 'w') + self.app.render((data), 'fastcgi.mustache', out=ee_nginx) + ee_nginx.close() + + data = dict(php="9000", debug="9001") + Log.debug(self, 'Writting the nginx configuration to ' + 'file /etc/nginx/conf.d/upstream.conf ') + ee_nginx = open('/etc/nginx/conf.d/upstream.conf', 'w') + self.app.render((data), 'upstream.mustache', out=ee_nginx) + ee_nginx.close() + + # Setup Nginx common directory + if not os.path.exists('/etc/nginx/common'): + Log.debug(self, 'Creating directory' + '/etc/nginx/common') + os.makedirs('/etc/nginx/common') + + data = dict(webroot=EEVariables.ee_webroot) + Log.debug(self, 'Writting the nginx configuration to ' + 'file /etc/nginx/common/acl.conf') + ee_nginx = open('/etc/nginx/common/acl.conf', 'w') + self.app.render((data), 'acl.mustache', + out=ee_nginx) + ee_nginx.close() + + Log.debug(self, 'Writting the nginx configuration to ' + 'file /etc/nginx/common/locations.conf') + ee_nginx = open('/etc/nginx/common/locations.conf', 'w') + self.app.render((data), 'locations.mustache', + out=ee_nginx) + ee_nginx.close() + + Log.debug(self, 'Writting the nginx configuration to ' + 'file /etc/nginx/common/ php.conf') + ee_nginx = open('/etc/nginx/common/php.conf', 'w') + self.app.render((data), 'php.mustache', + out=ee_nginx) + ee_nginx.close() + + Log.debug(self, 'Writting the nginx configuration to ' + 'file /etc/nginx/common/w3tc.conf') + ee_nginx = open('/etc/nginx/common/w3tc.conf', 'w') + self.app.render((data), 'w3tc.mustache', + out=ee_nginx) + ee_nginx.close() + + Log.debug(self, 'Writting the nginx configuration to ' + 'file /etc/nginx/common/wpcommon.conf') + ee_nginx = open('/etc/nginx/common/wpcommon.conf', 'w') + self.app.render((data), 'wpcommon.mustache', + out=ee_nginx) + ee_nginx.close() + + Log.debug(self, 'Writting the nginx configuration to ' + 'file /etc/nginx/common/wpfc.conf') + ee_nginx = open('/etc/nginx/common/wpfc.conf', 'w') + self.app.render((data), 'wpfc.mustache', + out=ee_nginx) + ee_nginx.close() + + Log.debug(self, 'Writting the nginx configuration to ' + 'file /etc/nginx/common/wpsc.conf') + ee_nginx = open('/etc/nginx/common/wpsc.conf', 'w') + self.app.render((data), 'wpsc.mustache', + out=ee_nginx) + ee_nginx.close() + + Log.debug(self, 'Writting the nginx configuration to ' + 'file /etc/nginx/common/wpsubdir.conf') + ee_nginx = open('/etc/nginx/common/wpsubdir.conf', 'w') + self.app.render((data), 'wpsubdir.mustache', + out=ee_nginx) + ee_nginx.close() + + # 22222 port settings + Log.debug(self, 'Writting the nginx configuration to ' + 'file /etc/nginx/sites-available/' + '22222.conf') + ee_nginx = open('/etc/nginx/sites-available/22222.conf', + 'w') + self.app.render((data), '22222.mustache', + out=ee_nginx) + ee_nginx.close() + + passwd = ''.join([random.choice + (string.ascii_letters + string.digits) + for n in range(6)]) + EEShellExec.cmd_exec(self, "printf \"easyengine:" + "$(openssl passwd -crypt " + "{password} 2> /dev/null)\n\"" + "> /etc/nginx/htpasswd-ee 2>/dev/null" + .format(password=passwd)) + + # Create Symbolic link for 22222 + EEFileUtils.create_symlink(self, ['/etc/nginx/' + 'sites-available/' + '22222.conf', + '/etc/nginx/' + 'sites-enabled/' + '22222.conf']) + # Create log and cert folder and softlinks + if not os.path.exists('{0}22222/logs' + .format(EEVariables.ee_webroot)): + Log.debug(self, "Creating directory " + "{0}22222/logs " + .format(EEVariables.ee_webroot)) + os.makedirs('{0}22222/logs' + .format(EEVariables.ee_webroot)) + + if not os.path.exists('{0}22222/cert' + .format(EEVariables.ee_webroot)): + Log.debug(self, "Creating directory " + "{0}22222/cert" + .format(EEVariables.ee_webroot)) + os.makedirs('{0}22222/cert' + .format(EEVariables.ee_webroot)) + + EEFileUtils.create_symlink(self, ['/var/log/nginx/' + '22222.access.log', + '{0}22222/' + 'logs/access.log' + .format(EEVariables.ee_webroot)] + ) + + EEFileUtils.create_symlink(self, ['/var/log/nginx/' + '22222.error.log', + '{0}22222/' + 'logs/error.log' + .format(EEVariables.ee_webroot)] + ) + + EEShellExec.cmd_exec(self, "openssl genrsa -out " + "{0}22222/cert/22222.key 2048" + .format(EEVariables.ee_webroot)) + EEShellExec.cmd_exec(self, "openssl req -new -batch -subj " + "/commonName=127.0.0.1/ -key " + "{0}22222/cert/22222.key " + "-out {0}22222/cert/" + "22222.csr" + .format(EEVariables.ee_webroot)) + + EEFileUtils.mvfile(self, "{0}22222/cert/22222.key" + .format(EEVariables.ee_webroot), + "{0}22222/cert/" + "22222.key.org" + .format(EEVariables.ee_webroot)) + + EEShellExec.cmd_exec(self, "openssl rsa -in " + "{0}22222/cert/" + "22222.key.org -out " + "{0}22222/cert/22222.key" + .format(EEVariables.ee_webroot)) + + EEShellExec.cmd_exec(self, "openssl x509 -req -days 3652 " + "-in {0}22222/cert/" + "22222.csr -signkey {0}" + "22222/cert/22222.key -out " + "{0}22222/cert/22222.crt" + .format(EEVariables.ee_webroot)) + # Nginx Configation into GIT + EEGit.add(self, + ["/etc/nginx"], msg="Adding Nginx into Git") + EEService.reload_service(self, 'nginx') + self.msg = (self.msg + ["HTTP Auth User Name: easyengine"] + + ["HTTP Auth Password : {0}".format(passwd)]) + + if set(EEVariables.ee_php).issubset(set(apt_packages)): + # Create log directories + if not os.path.exists('/var/log/php5/'): + Log.debug(self, 'Creating directory /var/log/php5/') + os.makedirs('/var/log/php5/') + + # Parse etc/php5/fpm/php.ini + config = configparser.ConfigParser() + Log.debug(self, "configuring php file /etc/php5/fpm/php.ini") + config.read('/etc/php5/fpm/php.ini') + config['PHP']['expose_php'] = 'Off' + config['PHP']['post_max_size'] = '100M' + config['PHP']['upload_max_filesize'] = '100M' + config['PHP']['max_execution_time'] = '300' + config['PHP']['date.timezone'] = time.tzname[time.daylight] + with open('/etc/php5/fpm/php.ini', 'w') as configfile: + Log.debug(self, "Writting php configuration into " + "/etc/php5/fpm/php.ini") + config.write(configfile) + + # Prase /etc/php5/fpm/php-fpm.conf + config = configparser.ConfigParser() + config.read('/etc/php5/fpm/php-fpm.conf') + config['global']['error_log'] = '/var/log/php5/fpm.log' + config.remove_option('global', 'include') + config['global']['log_level'] = 'notice' + config['global']['include'] = '/etc/php5/fpm/pool.d/*.conf' + with open('/etc/php5/fpm/php-fpm.conf', 'w') as configfile: + Log.debug(self, "writting php5 configuration into " + "/etc/php5/fpm/php-fpm.conf") + config.write(configfile) + + # Parse /etc/php5/fpm/pool.d/www.conf + config = configparser.ConfigParser() + config.read('/etc/php5/fpm/pool.d/www.conf') + config['www']['ping.path'] = '/ping' + config['www']['pm.status_path'] = '/status' + config['www']['pm.max_requests'] = '500' + config['www']['pm.max_children'] = '100' + config['www']['pm.start_servers'] = '20' + config['www']['pm.min_spare_servers'] = '10' + config['www']['pm.max_spare_servers'] = '30' + config['www']['request_terminate_timeout'] = '300' + config['www']['pm'] = 'ondemand' + config['www']['listen'] = '127.0.0.1:9000' + with open('/etc/php5/fpm/pool.d/www.conf', 'w') as configfile: + Log.debug(self, "writting PHP5 configuration into " + "/etc/php5/fpm/pool.d/www.conf") + config.write(configfile) + + # Generate /etc/php5/fpm/pool.d/debug.conf + EEFileUtils.copyfile(self, "/etc/php5/fpm/pool.d/www.conf", + "/etc/php5/fpm/pool.d/debug.conf") + EEFileUtils.searchreplace(self, "/etc/php5/fpm/pool.d/" + "debug.conf", "[www]", "[debug]") + config = configparser.ConfigParser() + config.read('/etc/php5/fpm/pool.d/debug.conf') + config['debug']['listen'] = '127.0.0.1:9001' + with open('/etc/php5/fpm/pool.d/debug.conf', 'w') as confifile: + Log.debug(self, "writting PHP5 configuration into " + "/etc/php5/fpm/pool.d/debug.conf") + config.write(confifile) + + with open("/etc/php5/fpm/pool.d/debug.conf", "a") as myfile: + myfile.write("php_admin_value[xdebug.profiler_output_dir] " + "= /tmp/ \nphp_admin_value[xdebug.profiler_" + "output_name] = cachegrind.out.%p-%H-%R " + "\nphp_admin_flag[xdebug.profiler_enable" + "_trigger] = on \nphp_admin_flag[xdebug." + "profiler_enable] = off\n") + + # PHP and Debug pull configuration + if not os.path.exists('{0}22222/htdocs/fpm/status/' + .format(EEVariables.ee_webroot)): + Log.debug(self, 'Creating directory ' + '{0}22222/htdocs/fpm/status/ ' + .format(EEVariables.ee_webroot)) + os.makedirs('{0}22222/htdocs/fpm/status/' + .format(EEVariables.ee_webroot)) + open('{0}22222/htdocs/fpm/status/debug' + .format(EEVariables.ee_webroot), 'a').close() + open('{0}22222/htdocs/fpm/status/php' + .format(EEVariables.ee_webroot), 'a').close() + + # Write info.php + if not os.path.exists('{0}22222/htdocs/php/' + .format(EEVariables.ee_webroot)): + Log.debug(self, 'Creating directory ' + '{0}22222/htdocs/php/ ' + .format(EEVariables.ee_webroot)) + os.makedirs('{0}22222/htdocs/php' + .format(EEVariables.ee_webroot)) + + with open("{0}22222/htdocs/php/info.php" + .format(EEVariables.ee_webroot), "w") as myfile: + myfile.write("") + + EEFileUtils.chown(self, "{0}22222" + .format(EEVariables.ee_webroot), + EEVariables.ee_php_user, + EEVariables.ee_php_user, recursive=True) + + EEGit.add(self, ["/etc/php5"], msg="Adding PHP into Git") + EEService.reload_service(self, 'php5-fpm') + + if set(EEVariables.ee_mysql).issubset(set(apt_packages)): + # TODO: Currently we are using, we need to remove it in future + # config = configparser.ConfigParser() + # config.read('/etc/mysql/my.cnf') + # config['mysqld']['wait_timeout'] = 30 + # config['mysqld']['interactive_timeout'] = 60 + # config['mysqld']['performance_schema'] = 0 + # with open('/etc/mysql/my.cnf', 'w') as configfile: + # config.write(configfile) + if not os.path.isfile("/etc/mysql/my.cnf"): + config = ("[mysqld]\nwait_timeout = 30\n" + "interactive_timeout=60\nperformance_schema = 0") + config_file = open("/etc/mysql/my.cnf", "w") + config_file.write(config) + config_file.close() + else: + EEShellExec.cmd_exec(self, "sed -i \"/#max_connections/a " + "wait_timeout = 30 \\n" + "interactive_timeout = 60 \\n" + "performance_schema = 0\" " + "/etc/mysql/my.cnf") + + EEGit.add(self, ["/etc/mysql"], msg="Adding Nginx into Git") + EEService.reload_service(self, 'mysql') + + if set(EEVariables.ee_mail).issubset(set(apt_packages)): + Log.debug(self, "Adding user") + EEShellExec.cmd_exec(self, "adduser --uid 5000 --home /var" + "/vmail --disabled-password --gecos ''" + " vmail") + EEShellExec.cmd_exec(self, "openssl req -new -x509 -days 3650 " + "-nodes -subj /commonName={HOSTNAME}" + "/emailAddress={EMAIL} -out /etc/ssl" + "/certs/dovecot." + "pem -keyout /etc/ssl/private/dovecot.pem" + .format(HOSTNAME=EEVariables.ee_fqdn, + EMAIL=EEVariables.ee_email)) + Log.debug(self, "Setting Privileges to " + "/etc/ssl/private/dovecot.pem file ") + EEShellExec.cmd_exec(self, "chmod 0600 /etc/ssl/private" + "/dovecot.pem") + + # Custom Dovecot configuration by EasyEngine + data = dict(email=EEVariables.ee_email) + Log.debug(self, "Writting configuration into file" + "/etc/dovecot/conf.d/99-ee.conf ") + ee_dovecot = open('/etc/dovecot/conf.d/99-ee.conf', 'w') + self.app.render((data), 'dovecot.mustache', out=ee_dovecot) + ee_dovecot.close() + + EEShellExec.cmd_exec(self, "sed -i \"s/\\!include " + "auth-system.conf.ext/#\\!include " + "auth-system.conf.ext/\" " + "/etc/dovecot/conf.d/10-auth.conf") + + EEShellExec.cmd_exec(self, "sed -i \"s\'/etc/dovecot/" + "dovecot.pem\'/etc/ssl/certs/dovecot.pem" + "\'\" /etc/dovecot/conf.d/10-ssl.conf") + EEShellExec.cmd_exec(self, "sed -i \"s\'/etc/dovecot/" + "private/dovecot.pem\'/etc/ssl/private" + "/dovecot.pem\'\" /etc/dovecot/conf.d/" + "10-ssl.conf") + + # Custom Postfix configuration needed with Dovecot + # Changes in master.cf + # TODO: Find alternative for sed in Python + EEShellExec.cmd_exec(self, "sed -i \'s/#submission/submission" + "/\'" + " /etc/postfix/master.cf") + EEShellExec.cmd_exec(self, "sed -i \'s/#smtps/smtps/\'" + " /etc/postfix/master.cf") + + EEShellExec.cmd_exec(self, "postconf -e \"smtpd_sasl_type = " + "dovecot\"") + EEShellExec.cmd_exec(self, "postconf -e \"smtpd_sasl_path = " + "private/auth\"") + EEShellExec.cmd_exec(self, "postconf -e \"" + "smtpd_sasl_auth_enable = " + "yes\"") + EEShellExec.cmd_exec(self, "postconf -e \"" + " smtpd_relay_restrictions =" + " permit_sasl_authenticated, " + " permit_mynetworks, " + " reject_unauth_destination\"") + + EEShellExec.cmd_exec(self, "postconf -e \"" + "smtpd_tls_mandatory_" + "protocols = !SSLv2,!SSLv3\"") + EEShellExec.cmd_exec(self, "postconf -e \"smtp_tls_mandatory_" + "protocols = !SSLv2,!SSLv3\"") + EEShellExec.cmd_exec(self, "postconf -e \"smtpd_tls_protocols " + " = !SSLv2,!SSLv3\"") + EEShellExec.cmd_exec(self, "postconf -e \"smtp_tls_protocols " + "= !SSLv2,!SSLv3\"") + EEShellExec.cmd_exec(self, "postconf -e \"mydestination " + "= localhost\"") + EEShellExec.cmd_exec(self, "postconf -e \"virtual_transport " + "= lmtp:unix:private/dovecot-lmtp\"") + EEShellExec.cmd_exec(self, "postconf -e \"virtual_uid_maps " + "= static:5000\"") + EEShellExec.cmd_exec(self, "postconf -e \"virtual_gid_maps " + "= static:5000\"") + EEShellExec.cmd_exec(self, "postconf -e \"" + " virtual_mailbox_domains = " + "mysql:/etc/postfix/mysql/virtual_" + "domains_maps.cf\"") + EEShellExec.cmd_exec(self, "postconf -e \"virtual_mailbox_maps" + " = mysql:/etc/postfix/mysql/virtual_" + "mailbox_maps.cf\"") + EEShellExec.cmd_exec(self, "postconf -e \"virtual_alias_maps " + "= mysql:/etc/postfix/mysql/virtual_" + "alias_maps.cf\"") + EEShellExec.cmd_exec(self, "openssl req -new -x509 -days " + " 3650 -nodes -subj /commonName=" + "{HOSTNAME}/emailAddress={EMAIL}" + " -out /etc/ssl/certs/postfix.pem" + " -keyout /etc/ssl/private/postfix.pem" + .format(HOSTNAME=EEVariables.ee_fqdn, + EMAIL=EEVariables.ee_email)) + EEShellExec.cmd_exec(self, "chmod 0600 /etc/ssl/private" + "/postfix.pem") + EEShellExec.cmd_exec(self, "postconf -e \"smtpd_tls_cert_file " + "= /etc/ssl/certs/postfix.pem\"") + EEShellExec.cmd_exec(self, "postconf -e \"smtpd_tls_key_file " + "= /etc/ssl/private/postfix.pem\"") + + # Sieve configuration + if not os.path.exists('/var/lib/dovecot/sieve/'): + Log.debug(self, 'Creating directory ' + '/var/lib/dovecot/sieve/ ') + os.makedirs('/var/lib/dovecot/sieve/') + + # Custom sieve configuration by EasyEngine + data = dict() + Log.debug(self, "Writting configuration of EasyEngine into " + "file /var/lib/dovecot/sieve/default.sieve") + ee_sieve = open('/var/lib/dovecot/sieve/default.sieve', 'w') + self.app.render((data), 'default-sieve.mustache', + out=ee_sieve) + ee_sieve.close() + + # Compile sieve rules + Log.debug(self, "Setting Privileges to dovecot ") + # EEShellExec.cmd_exec(self, "chown -R vmail:vmail /var/lib" + # "/dovecot") + EEFileUtils.chown(self, "/var/lig/dovecot", 'vmail', 'vmail', + recursive=True) + EEShellExec.cmd_exec(self, "sievec /var/lib/dovecot/sieve/" + "default.sieve") + EEGit.add(self, ["/etc/postfix", "/etc/dovecot"], + msg="Installed mail server") + EEService.restart_service(self, 'dovecot') + EEService.reload_service(self, 'postfix') + + if set(EEVariables.ee_mailscanner).issubset(set(apt_packages)): + # Set up Custom amavis configuration + data = dict() + Log.debug(self, "Configuring file /etc/amavis/conf.d" + "/15-content_filter_mode") + ee_amavis = open('/etc/amavis/conf.d/15-content_filter_mode', + 'w') + self.app.render((data), '15-content_filter_mode.mustache', + out=ee_amavis) + ee_amavis.close() + + # Amavis ViMbadmin configuration + if os.path.isfile("/etc/postfix/mysql/virtual_alias_maps.cf"): + vm_host = os.popen("grep hosts /etc/postfix/mysql/virtual_" + "alias_maps.cf | awk \'{ print $3 }\' |" + " tr -d '\\n'").read() + vm_pass = os.popen("grep password /etc/postfix/mysql/" + "virtual_alias_maps.cf | awk \'{ print " + "$3 }\' | tr -d '\\n'").read() + + data = dict(host=vm_host, password=vm_pass) + vm_config = open('/etc/amavis/conf.d/50-user', 'w') + self.app.render((data), '50-user.mustache', out=vm_config) + vm_config.close() + + # Amavis postfix configuration + EEShellExec.cmd_exec(self, "postconf -e \"content_filter = " + "smtp-amavis:[127.0.0.1]:10024\"") + EEShellExec.cmd_exec(self, "sed -i \"s/1 pickup/1 " + "pickup" + "\\n -o content_filter=\\n -o" + " receive_override_options=no_header_body" + "_checks/\" /etc/postfix/master.cf") + + amavis_master = ("""smtp-amavis unix - - n - 2 smtp + -o smtp_data_done_timeout=1200 + -o smtp_send_xforward_command=yes + -o disable_dns_lookups=yes + -o max_use=20 +127.0.0.1:10025 inet n - n - - smtpd + -o content_filter= + -o smtpd_delay_reject=no + -o smtpd_client_restrictions=permit_mynetworks,reject + -o smtpd_helo_restrictions= + -o smtpd_sender_restrictions= + -o smtpd_recipient_restrictions=permit_mynetworks,reject + -o smtpd_data_restrictions=reject_unauth_pipelining + -o smtpd_end_of_data_restrictions= + -o smtpd_restriction_classes= + -o mynetworks=127.0.0.0/8 + -o smtpd_error_sleep_time=0 + -o smtpd_soft_error_limit=1001 + -o smtpd_hard_error_limit=1000 + -o smtpd_client_connection_count_limit=0 + -o smtpd_client_connection_rate_limit=0 + -o local_header_rewrite_clients=""") + + with open("/etc/postfix/master.cf", "a") as am_config: + am_config.write(amavis_master) + + # Amavis ClamAV configuration + Log.debug(self, "Adding new user clamav amavis") + EEShellExec.cmd_exec(self, "adduser clamav amavis") + Log.debug(self, "Adding new user amavis clamav") + EEShellExec.cmd_exec(self, "adduser amavis clamav") + Log.debug(self, "Setting Privileges to /var/lib/amavis/tmp ") + EEShellExec.cmd_exec(self, "chmod -R 775 /var/lib/amavis/tmp") + + # Update ClamAV database + Log.debug(self, "Updating database") + EEShellExec.cmd_exec(self, "freshclam") + Log.debug(self, "Restarting clamav-daemon service") + EEShellExec.cmd_exec(self, "service clamav-daemon restart") + EEGit.add(self, ["/etc/amavis"], msg="Adding Amavis into Git") + EEService.restart_service(self, 'dovecot') + EEService.reload_service(self, 'postfix') + EEService.restart_service(self, 'amavis') + + if len(packages): + if any('/usr/bin/wp' == x[1] for x in packages): + Log.debug(self, "Setting Privileges to /usr/bin/wp file ") + EEShellExec.cmd_exec(self, "chmod +x /usr/bin/wp") + if any('/tmp/pma.tar.gz' == x[1] + for x in packages): + EEExtract.extract(self, '/tmp/pma.tar.gz', '/tmp/') + Log.debug(self, 'Extracting file /tmp/pma.tar.gz to ' + 'loaction /tmp/') + if not os.path.exists('{0}22222/htdocs/db' + .format(EEVariables.ee_webroot)): + Log.debug(self, "Creating new directory " + "{0}22222/htdocs/db" + .format(EEVariables.ee_webroot)) + os.makedirs('{0}22222/htdocs/db' + .format(EEVariables.ee_webroot)) + shutil.move('/tmp/phpmyadmin-STABLE/', + '{0}22222/htdocs/db/pma/' + .format(EEVariables.ee_webroot)) + Log.debug(self, 'Setting Privileges of webroot permission to ' + '{0}22222/htdocs/db/pma file ' + .format(EEVariables.ee_webroot)) + EEFileUtils.chown(self, '{0}22222' + .format(EEVariables.ee_webroot), + EEVariables.ee_php_user, + EEVariables.ee_php_user, + recursive=True) + if any('/tmp/memcache.tar.gz' == x[1] + for x in packages): + Log.debug(self, "Extracting memcache.tar.gz to location" + " {0}22222/htdocs/cache/memcache " + .format(EEVariables.ee_webroot)) + EEExtract.extract(self, '/tmp/memcache.tar.gz', + '{0}22222/htdocs/cache/memcache' + .format(EEVariables.ee_webroot)) + Log.debug(self, "Setting Privileges to " + "{0}22222/htdocs/cache/memcache file" + .format(EEVariables.ee_webroot)) + EEFileUtils.chown(self, '{0}22222' + .format(EEVariables.ee_webroot), + EEVariables.ee_php_user, + EEVariables.ee_php_user, + recursive=True) + + if any('/tmp/webgrind.tar.gz' == x[1] + for x in packages): + Log.debug(self, "Extracting file webgrind.tar.gz to " + "location /tmp/ ") + EEExtract.extract(self, '/tmp/webgrind.tar.gz', '/tmp/') + if not os.path.exists('{0}22222/htdocs/php' + .format(EEVariables.ee_webroot)): + Log.debug(self, "Creating directroy " + "{0}22222/htdocs/php" + .format(EEVariables.ee_webroot)) + os.makedirs('{0}22222/htdocs/php' + .format(EEVariables.ee_webroot)) + shutil.move('/tmp/webgrind-master/', + '{0}22222/htdocs/php/webgrind' + .format(EEVariables.ee_webroot)) + EEShellExec.cmd_exec(self, "sed -i \"s\'/usr/local/bin/dot\'" + "/usr/bin/dot\'\" {0}22222/htdocs/" + "php/webgrind/config.php" + .format(EEVariables.ee_webroot)) + Log.debug(self, "Setting Privileges of webroot permission to " + "{0}22222/htdocs/php/webgrind/ file " + .format(EEVariables.ee_webroot)) + EEFileUtils.chown(self, '{0}22222' + .format(EEVariables.ee_webroot), + EEVariables.ee_php_user, + EEVariables.ee_php_user, + recursive=True) + + if any('/tmp/anemometer.tar.gz' == x[1] + for x in packages): + Log.debug(self, "Extracting file anemometer.tar.gz to " + "location /tmp/ ") + EEExtract.extract(self, '/tmp/anemometer.tar.gz', '/tmp/') + if not os.path.exists('{0}22222/htdocs/db/' + .format(EEVariables.ee_webroot)): + Log.debug(self, "Creating directory") + os.makedirs('{0}22222/htdocs/db/' + .format(EEVariables.ee_webroot)) + shutil.move('/tmp/Anemometer-master', + '{0}22222/htdocs/db/anemometer' + .format(EEVariables.ee_webroot)) + chars = ''.join(random.sample(string.ascii_letters, 8)) + EEShellExec.cmd_exec(self, 'mysql < {0}22222/htdocs/db' + '/anemometer/install.sql' + .format(EEVariables.ee_webroot)) + EEMysql.execute(self, 'grant select on *.* to \'anemometer\'' + '@\'{0}\''.format(self.app.config.get('mysql', + 'grant-host'))) + EEMysql.execute(self, 'grant all on slow_query_log.* to' + '\'anemometer\'@\'{0}\' IDENTIFIED' + ' BY \'{1}\''.format(self.app.config.get( + 'mysql', 'grant-host'), + chars)) + + # Custom Anemometer configuration + Log.debug(self, "configration Anemometer") + data = dict(host=EEVariables.ee_mysql_host, port='3306', + user='anemometer', password=chars) + ee_anemometer = open('{0}22222/htdocs/db/anemometer' + '/conf/config.inc.php' + .format(EEVariables.ee_webroot), 'w') + self.app.render((data), 'anemometer.mustache', + out=ee_anemometer) + ee_anemometer.close() + + if any('/usr/bin/pt-query-advisor' == x[1] + for x in packages): + EEShellExec.cmd_exec(self, "chmod +x /usr/bin/pt-query" + "-advisor") + + if any('/tmp/vimbadmin.tar.gz' == x[1] for x in packages): + # Extract ViMbAdmin + Log.debug(self, "Extracting ViMbAdmin.tar.gz to " + "location /tmp/") + EEExtract.extract(self, '/tmp/vimbadmin.tar.gz', '/tmp/') + if not os.path.exists('{0}22222/htdocs/' + .format(EEVariables.ee_webroot)): + Log.debug(self, "Creating directory " + "{0}22222/htdocs/" + .format(EEVariables.ee_webroot)) + os.makedirs('{0}22222/htdocs/' + .format(EEVariables.ee_webroot)) + shutil.move('/tmp/ViMbAdmin-{0}/' + .format(EEVariables.ee_vimbadmin), + '{0}22222/htdocs/vimbadmin/' + .format(EEVariables.ee_webroot)) + + # Donwload composer and install ViMbAdmin + Log.debug(self, "Downloading composer " + "https://getcomposer.org/installer | php ") + EEShellExec.cmd_exec(self, "cd {0}22222/htdocs" + "/vimbadmin; curl" + " -sS https://getcomposer.org/installer |" + " php".format(EEVariables.ee_webroot)) + Log.debug(self, "installation of composer") + EEShellExec.cmd_exec(self, "cd {0}22222/htdocs" + "/vimbadmin && " + "php composer.phar install --prefer-dist" + " --no-dev && rm -f {1}22222/htdocs" + "/vimbadmin/composer.phar" + .format(EEVariables.ee_webroot, + EEVariables.ee_webroot)) + + # Configure vimbadmin database + vm_passwd = ''.join(random.sample(string.ascii_letters, 8)) + Log.debug(self, "Creating vimbadmin database if not exist") + EEMysql.execute(self, "create database if not exists" + " vimbadmin") + Log.debug(self, "Granting all privileges on vimbadmin ") + EEMysql.execute(self, "grant all privileges on vimbadmin.* to" + " vimbadmin@{0} IDENTIFIED BY" + " '{1}'".format(self.app.config.get('mysql', + 'grant-host'), vm_passwd)) + vm_salt = (''.join(random.sample(string.ascii_letters + + string.ascii_letters, 64))) + + # Custom Vimbadmin configuration by EasyEngine + data = dict(salt=vm_salt, host=EEVariables.ee_mysql_host, + password=vm_passwd, + php_user=EEVariables.ee_php_user) + Log.debug(self, 'Writting the ViMbAdmin configuration to ' + 'file {0}22222/htdocs/vimbadmin/application/' + 'configs/application.ini' + .format(EEVariables.ee_webroot)) + ee_vmb = open('{0}22222/htdocs/vimbadmin/application/' + 'configs/application.ini' + .format(EEVariables.ee_webroot), 'w') + self.app.render((data), 'vimbadmin.mustache', + out=ee_vmb) + ee_vmb.close() + + shutil.copyfile("{0}22222/htdocs/vimbadmin/public/" + ".htaccess.dist" + .format(EEVariables.ee_webroot), + "{0}22222/htdocs/vimbadmin/public/" + ".htaccess".format(EEVariables.ee_webroot)) + Log.debug(self, "Executing command " + "{0}22222/htdocs/vimbadmin/bin" + "/doctrine2-cli.php orm:schema-tool:" + "create".format(EEVariables.ee_webroot)) + EEShellExec.cmd_exec(self, "{0}22222/htdocs/vimbadmin" + "/bin/doctrine2-cli.php orm:schema-tool:" + "create".format(EEVariables.ee_webroot)) + + EEFileUtils.chown(self, '{0}22222' + .format(EEVariables.ee_webroot), + EEVariables.ee_php_user, + EEVariables.ee_php_user, + recursive=True) + + # Copy Dovecot and Postfix templates which are depednet on + # Vimbadmin + + if not os.path.exists('/etc/postfix/mysql/'): + Log.debug(self, "Creating directory " + "/etc/postfix/mysql/") + os.makedirs('/etc/postfix/mysql/') + + if EEVariables.ee_mysql_host is "localhost": + data = dict(password=vm_passwd, host="127.0.0.1") + else: + data = dict(password=vm_passwd, + host=EEVariables.ee_mysql_host) + + vm_config = open('/etc/postfix/mysql/virtual_alias_maps.cf', + 'w') + self.app.render((data), 'virtual_alias_maps.mustache', + out=vm_config) + vm_config.close() + + Log.debug(self, "Writting configuration to " + "/etc/postfix/mysql" + "/virtual_domains_maps.cf file") + vm_config = open('/etc/postfix/mysql/virtual_domains_maps.cf', + 'w') + self.app.render((data), 'virtual_domains_maps.mustache', + out=vm_config) + vm_config.close() + + Log.debug(self, "Writting configuration to " + "/etc/postfix/mysql" + "/virtual_mailbox_maps.cf file") + vm_config = open('/etc/postfix/mysql/virtual_mailbox_maps.cf', + 'w') + self.app.render((data), 'virtual_mailbox_maps.mustache', + out=vm_config) + vm_config.close() + + Log.debug(self, "Writting configration" + " to /etc/dovecot/dovecot-sql.conf.ext file ") + vm_config = open('/etc/dovecot/dovecot-sql.conf.ext', + 'w') + self.app.render((data), 'dovecot-sql-conf.mustache', + out=vm_config) + vm_config.close() + + # If Amavis is going to be installed then configure Vimabadmin + # Amvis settings + if set(EEVariables.ee_mailscanner).issubset(set(apt_packages)): + vm_config = open('/etc/amavis/conf.d/50-user', + 'w') + self.app.render((data), '50-user.mustache', + out=vm_config) + vm_config.close() + EEService.restart_service(self, 'dovecot') + EEService.reload_service(self, 'nginx') + EEService.reload_service(self, 'php5-fpm') + self.msg = (self.msg + ["Configure ViMbAdmin:\thttps://{0}:" + "22222/vimbadmin".format(EEVariables.ee_fqdn)] + + ["Security Salt: {0}".format(vm_salt)]) + + if any('/tmp/roundcube.tar.gz' == x[1] for x in packages): + # Extract RoundCubemail + Log.debug(self, "Extracting file /tmp/roundcube.tar.gz " + "to location /tmp/ ") + EEExtract.extract(self, '/tmp/roundcube.tar.gz', '/tmp/') + if not os.path.exists('{0}roundcubemail' + .format(EEVariables.ee_webroot)): + Log.debug(self, "Creating new directory " + " {0}roundcubemail/" + .format(EEVariables.ee_webroot)) + os.makedirs('{0}roundcubemail/' + .format(EEVariables.ee_webroot)) + shutil.move('/tmp/roundcubemail-{0}/' + .format(EEVariables.ee_roundcube), + '{0}roundcubemail/htdocs' + .format(EEVariables.ee_webroot)) + + # Install Roundcube depednet pear packages + EEShellExec.cmd_exec(self, "pear install Mail_Mime Net_SMTP" + " Mail_mimeDecode Net_IDNA2-beta " + "Auth_SASL Net_Sieve Crypt_GPG") + + # Configure roundcube database + rc_passwd = ''.join(random.sample(string.ascii_letters, 8)) + Log.debug(self, "Creating Database roundcubemail") + EEMysql.execute(self, "create database if not exists " + " roundcubemail") + Log.debug(self, "Grant all privileges on roundcubemail") + EEMysql.execute(self, "grant all privileges" + " on roundcubemail.* to " + " roundcube@{0} IDENTIFIED BY " + "'{1}'".format(self.app.config.get( + 'mysql', 'grant-host'), + rc_passwd)) + EEShellExec.cmd_exec(self, "mysql roundcubemail < {0}" + "roundcubemail/htdocs/SQL/mysql" + ".initial.sql" + .format(EEVariables.ee_webroot)) + + shutil.copyfile("{0}roundcubemail/htdocs/config/" + "config.inc.php.sample" + .format(EEVariables.ee_webroot), + "{0}roundcubemail/htdocs/config/" + "config.inc.php" + .format(EEVariables.ee_webroot)) + EEShellExec.cmd_exec(self, "sed -i \"s\'mysql://roundcube:" + "pass@localhost/roundcubemail\'mysql://" + "roundcube:{0}@{1}/" + "roundcubemail\'\" {2}roundcubemail" + "/htdocs/config/config." + "inc.php" + .format(rc_passwd, + EEVariables.ee_mysql_host, + EEVariables.ee_webroot)) + + # Sieve plugin configuration in roundcube + EEShellExec.cmd_exec(self, "bash -c \"sed -i \\\"s:\$config\[" + "\'plugins\'\] " + "= array(:\$config\['plugins'\] = " + "array(\\n \'sieverules\',:\\\" " + "{0}roundcubemail/htdocs/config" + .format(EEVariables.ee_webroot) + + "/config.inc.php\"") + EEShellExec.cmd_exec(self, "echo \"\$config['sieverules_port']" + "=4190;\" >> {0}roundcubemail" + .format(EEVariables.ee_webroot) + + "/htdocs/config/config.inc.php") + + data = dict(site_name='webmail', www_domain='webmail', + static=False, + basic=True, wp=False, w3tc=False, wpfc=False, + wpsc=False, multisite=False, wpsubdir=False, + webroot=EEVariables.ee_webroot, ee_db_name='', + ee_db_user='', ee_db_pass='', ee_db_host='', + rc=True) + + Log.debug(self, 'Writting the nginx configuration for ' + 'RoundCubemail') + ee_rc = open('/etc/nginx/sites-available/webmail.conf', 'w') + self.app.render((data), 'virtualconf.mustache', + out=ee_rc) + ee_rc.close() + + # Create Symbolic link for webmail.conf + EEFileUtils.create_symlink(self, ['/etc/nginx/sites-available' + '/webmail.conf', + '/etc/nginx/sites-enabled/' + 'webmail.conf']) + # Create log folder and softlinks + if not os.path.exists('{0}roundcubemail/logs' + .format(EEVariables.ee_webroot)): + os.makedirs('{0}roundcubemail/logs' + .format(EEVariables.ee_webroot)) + + EEFileUtils.create_symlink(self, ['/var/log/nginx/' + 'webmail.access.log', + '{0}roundcubemail/' + 'logs/access.log' + .format(EEVariables.ee_webroot)]) + + EEFileUtils.create_symlink(self, ['/var/log/nginx/' + 'webmail.error.log', + '{0}roundcubemail/' + 'logs/error.log' + .format(EEVariables.ee_webroot)]) + # Remove roundcube installer + EEService.reload_service(self, 'nginx') + EEFileUtils.remove(self, ["{0}roundcubemail" + "/htdocs/installer" + .format(EEVariables.ee_webroot)]) + EEFileUtils.chown(self, '{0}roundcubemail' + .format(EEVariables.ee_webroot), + EEVariables.ee_php_user, + EEVariables.ee_php_user, + recursive=True) + + @expose(help="Install packages") + def install(self, packages=[], apt_packages=[], disp_msg=True): + """Start installation of packages""" + self.msg = [] + try: + # Default action for stack installation + if ((not self.app.pargs.web) and (not self.app.pargs.admin) and + (not self.app.pargs.mail) and (not self.app.pargs.nginx) and + (not self.app.pargs.php) and (not self.app.pargs.mysql) and + (not self.app.pargs.postfix) and (not self.app.pargs.wpcli) and + (not self.app.pargs.phpmyadmin) and + (not self.app.pargs.adminer) and (not self.app.pargs.utils) and + (not self.app.pargs.mailscanner)): + self.app.pargs.web = True + + if self.app.pargs.all: + self.app.pargs.web = True + self.app.pargs.admin = True + self.app.pargs.mail = True + + if self.app.pargs.web: + Log.debug(self, "Setting apt_packages variable for Nginx ,PHP" + " ,MySQL ") + self.app.pargs.nginx = True + self.app.pargs.php = True + self.app.pargs.mysql = True + self.app.pargs.wpcli = True + self.app.pargs.postfix = True + + if self.app.pargs.admin: + self.app.pargs.nginx = True + self.app.pargs.php = True + self.app.pargs.mysql = True + self.app.pargs.adminer = True + self.app.pargs.phpmyadmin = True + self.app.pargs.utils = True + + if self.app.pargs.mail: + self.app.pargs.nginx = True + self.app.pargs.php = True + self.app.pargs.mysql = True + self.app.pargs.postfix = True + + if not EEAptGet.is_installed(self, 'dovecot-core'): + check_fqdn(self, + os.popen("hostname -f | tr -d '\n'").read()) + Log.debug(self, "Setting apt_packages variable for mail") + apt_packages = apt_packages + EEVariables.ee_mail + packages = packages + [["https://github.com/opensolutions/" + "ViMbAdmin/archive/{0}.tar.gz" + .format(EEVariables.ee_vimbadmin), + "/tmp/vimbadmin.tar.gz", + "ViMbAdmin"], + ["https://github.com/roundcube/" + "roundcubemail/releases/download/" + "{0}/roundcubemail-{0}.tar.gz" + .format(EEVariables.ee_roundcube), + "/tmp/roundcube.tar.gz", + "Roundcube"]] + + if EEVariables.ee_ram > 1024: + self.app.pargs.mailscanner = True + else: + Log.info(self, "System RAM is less than 1GB\nMail " + "scanner packages are not going to install" + " automatically") + else: + Log.info(self, "Mail server is already installed") + + if self.app.pargs.nginx: + Log.debug(self, "Setting apt_packages variable for Nginx") + if not EEAptGet.is_installed(self, 'nginx-common'): + apt_packages = apt_packages + EEVariables.ee_nginx + else: + Log.debug(self, "Nginx already installed") + Log.info(self, "Nginx already installed") + if self.app.pargs.php: + Log.debug(self, "Setting apt_packages variable for PHP") + if not EEAptGet.is_installed(self, 'php5-fpm'): + apt_packages = apt_packages + EEVariables.ee_php + else: + Log.debug(self, "PHP already installed") + Log.info(self, "PHP already installed") + if self.app.pargs.mysql: + Log.debug(self, "Setting apt_packages variable for MySQL") + if not EEShellExec.cmd_exec(self, "mysqladmin ping"): + apt_packages = apt_packages + EEVariables.ee_mysql + else: + Log.debug(self, "MySQL connection is already alive") + Log.info(self, "MySQL connection is already alive") + if self.app.pargs.postfix: + Log.debug(self, "Setting apt_packages variable for Postfix") + if not EEAptGet.is_installed(self, 'postfix'): + apt_packages = apt_packages + EEVariables.ee_postfix + else: + Log.debug(self, "Postfix is already installed") + Log.info(self, "Postfix is already installed") + if self.app.pargs.wpcli: + Log.debug(self, "Setting packages variable for WP-CLI") + if not EEShellExec.cmd_exec(self, "which wp"): + packages = packages + [["https://github.com/wp-cli/wp-cli/" + "releases/download/v{0}/" + "wp-cli-{0}.phar" + "".format(EEVariables.ee_wp_cli), + "/usr/bin/wp", + "WP-CLI"]] + else: + Log.debug(self, "WP-CLI is already installed") + Log.info(self, "WP-CLI is already installed") + if self.app.pargs.phpmyadmin: + Log.debug(self, "Setting packages varible for phpMyAdmin ") + packages = packages + [["https://github.com/phpmyadmin/" + "phpmyadmin/archive/STABLE.tar.gz", + "/tmp/pma.tar.gz", "phpMyAdmin"]] + + if self.app.pargs.adminer: + Log.debug(self, "Setting packages variable for Adminer ") + packages = packages + [["http://downloads.sourceforge.net/" + "adminer/adminer-{0}.php" + "".format(EEVariables.ee_adminer), + "{0}22222/" + "htdocs/db/adminer/index.php" + .format(EEVariables.ee_webroot), + "Adminer"]] + + if self.app.pargs.mailscanner: + if not EEAptGet.is_installed(self, 'amavisd-new'): + if (EEAptGet.is_installed(self, 'dovecot-core') or + self.app.pargs.mail): + apt_packages = (apt_packages + + EEVariables.ee_mailscanner) + else: + Log.error(self, "Failed to find installed Dovecot") + else: + Log.error(self, "Mail scanner allready installed") + + if self.app.pargs.utils: + Log.debug(self, "Setting packages variable for utils") + packages = packages + [["http://phpmemcacheadmin.googlecode" + ".com/files/phpMemcachedAdmin-1.2.2" + "-r262.tar.gz", '/tmp/memcache.tar.gz', + 'phpMemcachedAdmin'], + ["https://raw.githubusercontent.com" + "/rtCamp/eeadmin/master/cache/nginx/" + "clean.php", + "{0}22222/htdocs/cache/" + "nginx/clean.php" + .format(EEVariables.ee_webroot), + "clean.php"], + ["https://raw.github.com/rlerdorf/" + "opcache-status/master/opcache.php", + "{0}22222/htdocs/cache/" + "opcache/opcache.php" + .format(EEVariables.ee_webroot), + "opcache.php"], + ["https://raw.github.com/amnuts/" + "opcache-gui/master/index.php", + "{0}22222/htdocs/" + "cache/opcache/opgui.php" + .format(EEVariables.ee_webroot), + "Opgui"], + ["https://gist.github.com/ck-on/4959032" + "/raw/0b871b345fd6cfcd6d2be030c1f33d1" + "ad6a475cb/ocp.php", + "{0}22222/htdocs/cache/" + "opcache/ocp.php" + .format(EEVariables.ee_webroot), + "OCP.php"], + ["https://github.com/jokkedk/webgrind/" + "archive/master.tar.gz", + '/tmp/webgrind.tar.gz', 'Webgrind'], + ["http://bazaar.launchpad.net/~" + "percona-toolkit-dev/percona-toolkit/" + "2.1/download/head:/ptquerydigest-" + "20110624220137-or26tn4" + "expb9ul2a-16/pt-query-digest", + "/usr/bin/pt-query-advisor", + "pt-query-advisor"], + ["https://github.com/box/Anemometer/" + "archive/master.tar.gz", + '/tmp/anemometer.tar.gz', 'Anemometer'] + ] + except Exception as e: + pass + + if len(apt_packages) or len(packages): + Log.debug(self, "Calling pre_pref") + self.pre_pref(apt_packages) + if len(apt_packages): + EESwap.add(self) + Log.debug(self, "Updating apt-cache") + EEAptGet.update(self) + EEAptGet.install(self, apt_packages) + if len(packages): + Log.debug(self, "Downloading following: {0}".format(packages)) + EEDownload.download(self, packages) + Log.debug(self, "Calling post_pref") + self.post_pref(apt_packages, packages) + if disp_msg: + if len(self.msg): + for msg in self.msg: + Log.info(self, Log.ENDC + msg) + Log.info(self, "Successfully installed packages") + else: + return self.msg + + @expose(help="Remove packages") + def remove(self): + """Start removal of packages""" + apt_packages = [] + packages = [] + + # Default action for stack remove + if ((not self.app.pargs.web) and (not self.app.pargs.admin) and + (not self.app.pargs.mail) and (not self.app.pargs.nginx) and + (not self.app.pargs.php) and (not self.app.pargs.mysql) and + (not self.app.pargs.postfix) and (not self.app.pargs.wpcli) and + (not self.app.pargs.phpmyadmin) and + (not self.app.pargs.adminer) and (not self.app.pargs.utils) and + (not self.app.pargs.mailscanner)): + self.app.pargs.web = True + + if self.app.pargs.all: + self.app.pargs.web = True + self.app.pargs.admin = True + self.app.pargs.mail = True + + if self.app.pargs.web: + self.app.pargs.nginx = True + self.app.pargs.php = True + self.app.pargs.mysql = True + self.app.pargs.wpcli = True + self.app.pargs.postfix = True + + if self.app.pargs.admin: + self.app.pargs.adminer = True + self.app.pargs.phpmyadmin = True + self.app.pargs.utils = True + + if self.app.pargs.mail: + Log.debug(self, "Removing mail server packages") + apt_packages = apt_packages + EEVariables.ee_mail + apt_packages = apt_packages + EEVariables.ee_mailscanner + packages = packages + ["{0}22222/htdocs/vimbadmin" + .format(EEVariables.ee_webroot), + "{0}roundcubemail" + .format(EEVariables.ee_webroot)] + if EEShellExec.cmd_exec(self, "mysqladmin ping"): + EEMysql.execute(self, "drop database IF EXISTS vimbadmin") + EEMysql.execute(self, "drop database IF EXISTS roundcubemail") + + if self.app.pargs.mailscanner: + apt_packages = (apt_packages + EEVariables.ee_mailscanner) + + if self.app.pargs.nginx: + Log.debug(self, "Removing apt_packages variable of Nginx") + apt_packages = apt_packages + EEVariables.ee_nginx + if self.app.pargs.php: + Log.debug(self, "Removing apt_packages variable of PHP") + apt_packages = apt_packages + EEVariables.ee_php + if self.app.pargs.mysql: + Log.debug(self, "Removing apt_packages variable of MySQL") + apt_packages = apt_packages + EEVariables.ee_mysql + if self.app.pargs.postfix: + Log.debug(self, "Removing apt_packages variable of Postfix") + apt_packages = apt_packages + EEVariables.ee_postfix + if self.app.pargs.wpcli: + Log.debug(self, "Removing package variable of WPCLI ") + packages = packages + ['/usr/bin/wp'] + if self.app.pargs.phpmyadmin: + Log.debug(self, "Removing package variable of phpMyAdmin ") + packages = packages + ['{0}22222/htdocs/db/pma' + .format(EEVariables.ee_webroot)] + if self.app.pargs.adminer: + Log.debug(self, "Removing package variable of Adminer ") + packages = packages + ['{0}22222/htdocs/db/Adminer' + .format(EEVariables.ee_webroot)] + if self.app.pargs.utils: + Log.debug(self, "Removing package variable of utils ") + packages = packages + ['{0}22222/htdocs/php/webgrind/' + .format(EEVariables.ee_webroot), + '{0}22222/htdocs/cache/opcache' + .format(EEVariables.ee_webroot), + '{0}22222/htdocs/cache/Nginx/' + 'clean.php'.format(EEVariables.ee_webroot), + '{0}22222/htdocs/cache/Memcache' + .format(EEVariables.ee_webroot), + '/usr/bin/pt-query-advisor', + '{0}22222/htdocs/db/Anemometer' + .format(EEVariables.ee_webroot)] + + if len(apt_packages): + Log.debug(self, "Removing apt_packages") + EEAptGet.remove(self, apt_packages) + EEAptGet.auto_remove(self) + if len(packages): + EEFileUtils.remove(self, packages) + EEAptGet.auto_remove(self) + Log.info(self, "Successfully removed packages") + + @expose(help="Purge packages") + def purge(self): + """Start purging of packages""" + apt_packages = [] + packages = [] + + # Default action for stack purge + if ((not self.app.pargs.web) and (not self.app.pargs.admin) and + (not self.app.pargs.mail) and (not self.app.pargs.nginx) and + (not self.app.pargs.php) and (not self.app.pargs.mysql) and + (not self.app.pargs.postfix) and (not self.app.pargs.wpcli) and + (not self.app.pargs.phpmyadmin) and + (not self.app.pargs.adminer) and (not self.app.pargs.utils) and + (not self.app.pargs.mailscanner)): + self.app.pargs.web = True + + if self.app.pargs.all: + self.app.pargs.web = True + self.app.pargs.admin = True + self.app.pargs.mail = True + + if self.app.pargs.web: + self.app.pargs.nginx = True + self.app.pargs.php = True + self.app.pargs.mysql = True + self.app.pargs.wpcli = True + self.app.pargs.postfix = True + + if self.app.pargs.admin: + self.app.pargs.adminer = True + self.app.pargs.phpmyadmin = True + self.app.pargs.utils = True + + if self.app.pargs.mail: + Log.debug(self, "Removing mail server packages") + apt_packages = apt_packages + EEVariables.ee_mail + apt_packages = apt_packages + EEVariables.ee_mailscanner + packages = packages + ["{0}22222/htdocs/vimbadmin" + .format(EEVariables.ee_webroot), + "{0}roundcubemail" + .format(EEVariables.ee_webroot)] + if EEShellExec.cmd_exec(self, "mysqladmin ping"): + EEMysql.execute(self, "drop database IF EXISTS vimbadmin") + EEMysql.execute(self, "drop database IF EXISTS roundcubemail") + + if self.app.pargs.mailscanner: + apt_packages = (apt_packages + EEVariables.ee_mailscanner) + + if self.app.pargs.nginx: + Log.debug(self, "Purge apt_packages variable of Nginx") + apt_packages = apt_packages + EEVariables.ee_nginx + if self.app.pargs.php: + Log.debug(self, "Purge apt_packages variable PHP") + apt_packages = apt_packages + EEVariables.ee_php + if self.app.pargs.mysql: + Log.debug(self, "Purge apt_packages variable MySQL") + apt_packages = apt_packages + EEVariables.ee_mysql + if self.app.pargs.postfix: + Log.debug(self, "Purge apt_packages variable PostFix") + apt_packages = apt_packages + EEVariables.ee_postfix + if self.app.pargs.wpcli: + Log.debug(self, "Purge package variable WPCLI") + packages = packages + ['/usr/bin/wp'] + if self.app.pargs.phpmyadmin: + packages = packages + ['{0}22222/htdocs/db/pma'. + format(EEVariables.ee_webroot)] + Log.debug(self, "Purge package variable phpMyAdmin") + if self.app.pargs.adminer: + Log.debug(self, "Purge package variable Adminer") + packages = packages + ['{0}22222/htdocs/db/adminer' + .format(EEVariables.ee_webroot)] + if self.app.pargs.utils: + Log.debug(self, "Purge package variable utils") + packages = packages + ['{0}22222/htdocs/php/webgrind/' + .format(EEVariables.ee_webroot), + '{0}22222/htdocs/cache/opcache' + .format(EEVariables.ee_webroot), + '{0}22222/htdocs/cache/nginx/' + 'clean.php'.format(EEVariables.ee_webroot), + '{0}22222/htdocs/cache/memcache' + .format(EEVariables.ee_webroot), + '/usr/bin/pt-query-advisor', + '{0}22222/htdocs/db/anemometer' + .format(EEVariables.ee_webroot) + ] + + if len(apt_packages): + EEAptGet.remove(self, apt_packages, purge=True) + EEAptGet.auto_remove(self) + if len(packages): + EEFileUtils.remove(self, packages) + EEAptGet.auto_remove(self) + Log.info(self, "Successfully purged packages") + + +def load(app): + # register the plugin class.. this only happens if the plugin is enabled + handler.register(EEStackController) + handler.register(EEStackStatusController) + + # register a hook (function) to run after arguments are parsed. + hook.register('post_argument_parsing', ee_stack_hook) diff --git a/ee/cli/plugins/stack_services.py b/ee/cli/plugins/stack_services.py new file mode 100644 index 00000000..37943dd0 --- /dev/null +++ b/ee/cli/plugins/stack_services.py @@ -0,0 +1,159 @@ +from cement.core.controller import CementBaseController, expose +from cement.core import handler, hook +from ee.core.services import EEService +from ee.core.logging import Log + + +class EEStackStatusController(CementBaseController): + class Meta: + label = 'stack_services' + stacked_on = 'stack' + stacked_type = 'embedded' + description = 'Get status of stack' + arguments = [ + (['--memcache'], + dict(help='start/stop/restart memcache', action='store_true')), + (['--dovecot'], + dict(help='start/stop/restart dovecot', action='store_true')), + ] + + @expose(help="Start stack services") + def start(self): + """Start services""" + services = [] + if self.app.pargs.nginx: + Log.debug(self, "nginx service start") + services = services + ['nginx'] + elif self.app.pargs.php: + Log.debug(self, "php5-fpm service start") + services = services + ['php5-fpm'] + elif self.app.pargs.mysql: + Log.debug(self, "mysql service start") + services = services + ['mysql'] + elif self.app.pargs.postfix: + Log.debug(self, "postfix service start") + services = services + ['postfix'] + elif self.app.pargs.memcache: + Log.debug(self, "memcached service start") + services = services + ['memcached'] + elif self.app.pargs.dovecot: + Log.debug(self, "dovecot service start") + services = services + ['dovecot'] + else: + Log.debug(self, "nginx,php5-fpm,mysql,postfix services start") + services = services + ['nginx', 'php5-fpm', 'mysql', 'postfix'] + for service in services: + EEService.start_service(self, service) + + @expose(help="Stop stack services") + def stop(self): + """Stop services""" + services = [] + if self.app.pargs.nginx: + Log.debug(self, "nginx service stop") + services = services + ['nginx'] + elif self.app.pargs.php: + Log.debug(self, "php5-fpm service stop") + services = services + ['php5-fpm'] + elif self.app.pargs.mysql: + Log.debug(self, "mysql service stop") + services = services + ['mysql'] + elif self.app.pargs.postfix: + Log.debug(self, "postfix service stop") + services = services + ['postfix'] + elif self.app.pargs.memcache: + Log.debug(self, "memcached service stop") + services = services + ['memcached'] + elif self.app.pargs.dovecot: + Log.debug(self, "dovecot service stop") + services = services + ['dovecot'] + else: + services = services + ['nginx', 'php5-fpm', 'mysql', 'postfix'] + Log.debug(self, "nginx,php5-fpm,mysql,postfix services stop") + for service in services: + EEService.stop_service(self, service) + + @expose(help="Restart stack services") + def restart(self): + """Restart services""" + services = [] + if self.app.pargs.nginx: + Log.debug(self, "nginx service restart") + services = services + ['nginx'] + elif self.app.pargs.php: + Log.debug(self, "php5-fpm service restart") + services = services + ['php5-fpm'] + elif self.app.pargs.mysql: + Log.debug(self, "mysql service restart") + services = services + ['mysql'] + elif self.app.pargs.postfix: + Log.debug(self, "postfix service restart") + services = services + ['postfix'] + elif self.app.pargs.memcache: + Log.debug(self, "memcached service restart") + services = services + ['memcached'] + elif self.app.pargs.dovecot: + Log.debug(self, "dovecot service restart") + services = services + ['dovecot'] + else: + services = services + ['nginx', 'php5-fpm', 'mysql', 'postfix'] + for service in services: + Log.debug(self, "nginx,php5-fpm,mysql,postfix services restart") + EEService.restart_service(self, service) + + @expose(help="Get stack status") + def status(self): + """Status of services""" + services = [] + if self.app.pargs.nginx: + Log.debug(self, "nginx service status") + services = services + ['nginx'] + elif self.app.pargs.php: + Log.debug(self, "php5-fpm service status") + services = services + ['php5-fpm'] + elif self.app.pargs.mysql: + Log.debug(self, "mysql service status") + services = services + ['mysql'] + elif self.app.pargs.postfix: + services = services + ['postfix'] + Log.debug(self, "postfix service status") + elif self.app.pargs.memcache: + Log.debug(self, "memcached service status") + services = services + ['memcached'] + elif self.app.pargs.dovecot: + Log.debug(self, "dovecot service status") + services = services + ['dovecot'] + else: + Log.debug(self, "nginx,php5-fpm,mysql,postfix services status") + services = services + ['nginx', 'php5-fpm', 'mysql', 'postfix'] + for service in services: + if EEService.get_service_status(self, service): + Log.info(self, "{0:10}: {1}".format(service, "Running")) + + @expose(help="Reload stack services") + def reload(self): + """Reload service""" + services = [] + if self.app.pargs.nginx: + Log.debug(self, "nginx service reload") + services = services + ['nginx'] + elif self.app.pargs.php: + Log.debug(self, "php5-fpm service reload") + services = services + ['php5-fpm'] + elif self.app.pargs.mysql: + Log.debug(self, "mysql service reload") + services = services + ['mysql'] + elif self.app.pargs.postfix: + Log.debug(self, "postfix service reload") + services = services + ['postfix'] + elif self.app.pargs.memcache: + Log.debug(self, "memcached service reload") + services = services + ['memcached'] + elif self.app.pargs.dovecot: + Log.debug(self, "dovecot service reload") + services = services + ['dovecot'] + else: + services = services + ['nginx', 'php5-fpm', 'mysql', 'postfix'] + for service in services: + Log.debug(self, "nginx,php5-fpm,mysql,postfix services reload") + EEService.reload_service(self, service) diff --git a/ee/cli/templates/15-content_filter_mode.mustache b/ee/cli/templates/15-content_filter_mode.mustache new file mode 100644 index 00000000..6fd8f218 --- /dev/null +++ b/ee/cli/templates/15-content_filter_mode.mustache @@ -0,0 +1,27 @@ +use strict; + +# You can modify this file to re-enable SPAM checking through spamassassin +# and to re-enable antivirus checking. + +# +# Default antivirus checking mode +# Please note, that anti-virus checking is DISABLED by +# default. +# If You wish to enable it, please uncomment the following lines: + + +@bypass_virus_checks_maps = ( + \%bypass_virus_checks, \@bypass_virus_checks_acl, \$bypass_virus_checks_re); + + +# +# Default SPAM checking mode +# Please note, that anti-spam checking is DISABLED by +# default. +# If You wish to enable it, please uncomment the following lines: + + +@bypass_spam_checks_maps = ( + \%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re); + +1; # ensure a defined return diff --git a/ee/cli/templates/22222.mustache b/ee/cli/templates/22222.mustache new file mode 100644 index 00000000..c0897d54 --- /dev/null +++ b/ee/cli/templates/22222.mustache @@ -0,0 +1,61 @@ +# EasyEngine admin NGINX CONFIGURATION + +server { + + listen 22222 default_server ssl spdy; + + access_log /var/log/nginx/22222.access.log rt_cache; + error_log /var/log/nginx/22222.error.log; + + ssl_certificate {{webroot}}22222/cert/22222.crt; + ssl_certificate_key {{webroot}}22222/cert/22222.key; + + # Force HTTP to HTTPS + error_page 497 =200 https://$host:22222$request_uri; + + root {{webroot}}22222/htdocs; + index index.php index.htm index.html; + + # Turn on directory listing + autoindex on; + + location / { + include common/acl.conf; + try_files $uri $uri/ /index.php?$args; + } + + location = /fpm/status/ {} + + location ~ /fpm/status/(.*) { + include fastcgi_params; + fastcgi_param SCRIPT_NAME /status; + fastcgi_pass $1; + } + + location ~ \.php$ { + include common/acl.conf; + try_files $uri =404; + include fastcgi_params; + fastcgi_pass php; + } + + # ViMbAdmin Rules + location = /vimbadmin/ { + return 301 $scheme://$host:22222/vimbadmin/public/; + } + + location ~* \.(js|css|jpg|gif|png)$ { + root {{webroot}}22222/htdocs/; + } + + location ~* /vimbadmin/public/(.*)/(.*) { + root {{webroot}}22222/htdocs/vimbadmin/public; + try_files $uri $uri/ /vimbadmin/public/index.php?$args; + } + + location ~* /vimbadmin/public/(.*) { + root {{webroot}}22222/htdocs/vimbadmin/public; + try_files $uri $uri/ /vimbadmin/public/index.php?$args; + } + +} diff --git a/ee/cli/templates/50-user.mustache b/ee/cli/templates/50-user.mustache new file mode 100644 index 00000000..0cee70fb --- /dev/null +++ b/ee/cli/templates/50-user.mustache @@ -0,0 +1,17 @@ +use strict; +$sa_spam_subject_tag = undef; +$spam_quarantine_to = undef; +$sa_tag_level_deflt = undef; + +# Prevent spams from automatically rejected by mail-server +$final_spam_destiny = D_PASS; + +# We need to provide list of domains for which filtering need to be done +@lookup_sql_dsn = ( +['DBI:mysql:database=vimbadmin;host={{host}};port=3306', +'vimbadmin', +'{{password}}']); + +$sql_select_policy = 'SELECT domain FROM domain WHERE CONCAT("@",domain) IN (%k)'; + +1; # ensure a defined return diff --git a/ee/cli/templates/__init__.py b/ee/cli/templates/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ee/cli/templates/acl.mustache b/ee/cli/templates/acl.mustache new file mode 100644 index 00000000..122675f9 --- /dev/null +++ b/ee/cli/templates/acl.mustache @@ -0,0 +1,8 @@ +# EasyEngine (ee) protect locations using +# HTTP authentication || IP address +satisfy any; +auth_basic "Restricted Area"; +auth_basic_user_file htpasswd-ee; +# Allowed IP Address List +allow 127.0.0.1; +deny all; diff --git a/ee/cli/templates/anemometer.mustache b/ee/cli/templates/anemometer.mustache new file mode 100644 index 00000000..7b85a6a7 --- /dev/null +++ b/ee/cli/templates/anemometer.mustache @@ -0,0 +1,255 @@ + '{{host}}', + 'port' => '{{port}}', + 'db' => 'slow_query_log', + 'user' => '{{user}}', + 'password' => '{{password}}', + 'tables' => array( + 'global_query_review' => 'fact', + 'global_query_review_history' => 'dimension' + ), + 'source_type' => 'slow_query_log' +); + +$conf['default_report_action'] = 'report'; + +$conf['reviewers'] = array( 'dba1','dba2'); +$conf['review_types'] = array( 'good', 'bad', 'ticket-created', 'needs-fix', 'fixed', 'needs-analysis', 'review-again'); + +$conf['history_defaults'] = array( + 'output' => 'table', + 'fact-group' => 'date', + 'fact-order' => 'date DESC', + 'fact-limit' => '90', + 'dimension-ts_min_start' => date("Y-m-d H:i:s", strtotime( '-90 day')), + 'dimension-ts_min_end' => date("Y-m-d H:i:s"), + 'table_fields' => array('date', 'index_ratio','query_time_avg','rows_sent_avg','ts_cnt','Query_time_sum','Lock_time_sum','Rows_sent_sum','Rows_examined_sum','Tmp_table_sum','Filesort_sum','Full_scan_sum') +); + +$conf['report_defaults'] = array( + 'fact-group' => 'checksum', + 'fact-order' => 'Query_time_sum DESC', + 'fact-limit' => '20', + 'dimension-ts_min_start' => date("Y-m-d H:i:s", strtotime( '-1 day')), + 'dimension-ts_min_end' => date("Y-m-d H:i:s"), + 'table_fields' => array('checksum','snippet', 'index_ratio','query_time_avg','rows_sent_avg','ts_cnt','Query_time_sum','Lock_time_sum','Rows_sent_sum','Rows_examined_sum','Tmp_table_sum','Filesort_sum','Full_scan_sum'), + 'dimension-pivot-hostname_max' => null +); + +$conf['graph_defaults'] = array( + 'fact-group' => 'minute_ts', + 'fact-order' => 'minute_ts', + 'fact-limit' => '', + 'dimension-ts_min_start' => date("Y-m-d H:i:s", strtotime( '-7 day')), + 'dimension-ts_min_end' => date("Y-m-d H:i:s"), + 'table_fields' => array('minute_ts'), + 'plot_field' => 'Query_time_sum', +); + +$conf['report_defaults']['performance_schema'] = array( + 'fact-order' => 'SUM_TIMER_WAIT DESC', + 'fact-limit' => '20', + 'fact-group' => 'DIGEST', + 'table_fields' => array( 'DIGEST', 'snippet', 'index_ratio', 'COUNT_STAR', 'SUM_TIMER_WAIT', 'SUM_LOCK_TIME','SUM_ROWS_AFFECTED','SUM_ROWS_SENT','SUM_ROWS_EXAMINED','SUM_CREATED_TMP_TABLES','SUM_SORT_SCAN','SUM_NO_INDEX_USED' ) +); + +$conf['history_defaults']['performance_schema'] = array( + 'fact-order' => 'SUM_TIMER_WAIT DESC', + 'fact-limit' => '20', + 'fact-group' => 'DIGEST', + 'table_fields' => array( 'DIGEST', 'index_ratio', 'COUNT_STAR', 'SUM_LOCK_TIME','SUM_ROWS_AFFECTED','SUM_ROWS_SENT','SUM_ROWS_EXAMINED','SUM_CREATED_TMP_TABLES','SUM_SORT_SCAN','SUM_NO_INDEX_USED' ) +); + +$conf['report_defaults']['performance_schema_history'] = array( + 'fact-group' => 'DIGEST', + 'fact-order' => 'SUM_TIMER_WAIT DESC', + 'fact-limit' => '20', + 'dimension-FIRST_SEEN_start' => date("Y-m-d H:i:s", strtotime( '-1 day')), + 'dimension-FIRST_SEEN_end' => date("Y-m-d H:i:s"), + 'table_fields' => array( 'DIGEST', 'snippet', 'index_ratio', 'COUNT_STAR', 'SUM_LOCK_TIME','SUM_ROWS_AFFECTED','SUM_ROWS_SENT','SUM_ROWS_EXAMINED','SUM_CREATED_TMP_TABLES','SUM_SORT_SCAN','SUM_NO_INDEX_USED' ) +); + +$conf['graph_defaults']['performance_schema_history'] = array( + 'fact-group' => 'minute_ts', + 'fact-order' => 'minute_ts', + 'fact-limit' => '', + 'dimension-FIRST_SEEN_start' => date("Y-m-d H:i:s", strtotime( '-7 day')), + 'dimension-FIRST_SEEN_end' => date("Y-m-d H:i:s"), + 'table_fields' => array('minute_ts'), + 'plot_field' => 'SUM_TIMER_WAIT', + 'dimension-pivot-hostname_max' => null +); + +$conf['history_defaults']['performance_schema_history'] = array( + 'output' => 'table', + 'fact-group' => 'date', + 'fact-order' => 'date DESC', + 'fact-limit' => '90', + 'dimension-FIRST_SEEN_start' => date("Y-m-d H:i:s", strtotime( '-90 day')), + 'dimension-FIRST_SEEN_end' => date("Y-m-d H:i:s"), + 'table_fields' => array( 'date', 'snippet', 'index_ratio', 'COUNT_STAR', 'SUM_LOCK_TIME','SUM_ROWS_AFFECTED','SUM_ROWS_SENT','SUM_ROWS_EXAMINED','SUM_CREATED_TMP_TABLES','SUM_SORT_SCAN','SUM_NO_INDEX_USED' ) +); +$conf['plugins'] = array( + + 'visual_explain' => '/usr/bin/pt-visual-explain', + 'query_advisor' => '/usr/bin/pt-query-advisor', + + 'show_create' => true, + 'show_status' => true, + + 'explain' => function ($sample) { + $conn = array(); + + if (!array_key_exists('hostname_max',$sample) or strlen($sample['hostname_max']) < 5) + { + return; + } + + $pos = strpos($sample['hostname_max'], ':'); + if ($pos === false) + { + $conn['port'] = 3306; + $conn['host'] = $sample['hostname_max']; + } + else + { + $parts = preg_split("/:/", $sample['hostname_max']); + $conn['host'] = $parts[0]; + $conn['port'] = $parts[1]; + } + + $conn['db'] = 'mysql'; + if ($sample['db_max'] != '') + { + $conn['db'] = $sample['db_max']; + } + + $conn['user'] = '{{user}}'; + $conn['password'] = '{{password}}'; + + return $conn; + }, +); + +$conf['reports']['slow_query_log'] = array( + 'join' => array ( + 'dimension' => 'USING (`checksum`)' + ), + 'fields' => array( + 'fact' => array( + 'group' => 'group', + 'order' => 'order', + 'having' => 'having', + 'limit' => 'limit', + 'first_seen'=> 'clear|reldate|ge|where', + 'where' => 'raw_where', + 'sample' => 'clear|like|where', + 'checksum' => 'clear|where', + 'reviewed_status' => 'clear|where', + + ), + + 'dimension' => array( + 'extra_fields' => 'where', + 'hostname_max' => 'clear|where', + 'ts_min' => 'date_range|reldate|clear|where', + 'pivot-hostname_max' => 'clear|pivot|select', + 'pivot-checksum' => 'clear|pivot|select', + ), + ), + 'custom_fields' => array( + 'checksum' => 'checksum', + 'date' => 'DATE(ts_min)', + 'hour' => 'substring(ts_min,1,13)', + 'hour_ts' => 'round(unix_timestamp(substring(ts_min,1,13)))', + 'minute_ts' => 'round(unix_timestamp(substring(ts_min,1,16)))', + 'minute' => 'substring(ts_min,1,16)', + 'snippet' => 'LEFT(dimension.sample,20)', + 'index_ratio' =>'ROUND(SUM(Rows_examined_sum)/SUM(rows_sent_sum),2)', + 'query_time_avg' => 'SUM(Query_time_sum) / SUM(ts_cnt)', + 'rows_sent_avg' => 'ROUND(SUM(Rows_sent_sum)/SUM(ts_cnt),0)', + ), + + 'callbacks' => array( + 'table' => array( + 'date' => function ($x) { $type=''; if ( date('N',strtotime($x)) >= 6) { $type = 'weekend'; } return array($x,$type); }, + 'checksum' => function ($x) { return array(dec2hex($x), ''); } + ) + ) + +); + +$conf['reports']['performance_schema'] = array( + 'fields' => array( + 'fact' => array( + 'order' => 'order', + 'having' => 'having', + 'limit' => 'limit', + 'first_seen' => 'date_range|reldate|clear|where', + 'where' => 'raw_where', + 'DIGEST' => 'clear|where', + 'DIGEST_TEXT' => 'clear|like|where', + 'group' => 'group', + ), + ), + 'custom_fields' => array( + 'snippet' => 'LEFT(fact.DIGEST_TEXT,20)', + 'index_ratio' =>'ROUND(SUM_ROWS_EXAMINED/SUM_ROWS_SENT,2)', + 'rows_sent_avg' => 'ROUND(SUM_ROWS_SENT/COUNT_STAR,0)', + + ), + + 'special_field_names' => array( + 'time' => 'FIRST_SEEN', + 'checksum' => 'DIGEST', + 'sample' => 'DIGEST_TEXT', + 'fingerprint' => 'DIGEST_TEXT', + ), +); + +$conf['reports']['performance_schema_history'] = array( + 'join' => array ( + 'dimension' => 'USING (`DIGEST`)' + ), + 'fields' => array( + 'fact' => array( + 'group' => 'group', + 'order' => 'order', + 'having' => 'having', + 'limit' => 'limit', + 'first_seen'=> 'clear|reldate|ge|where', + 'where' => 'raw_where', + 'DIGEST_TEXT' => 'clear|like|where', + 'DIGEST' => 'clear|where', + 'reviewed_status' => 'clear|where', + + ), + + 'dimension' => array( + 'extra_fields' => 'where', + 'hostname' => 'clear|where', + 'FIRST_SEEN' => 'date_range|reldate|clear|where', + 'pivot-hostname' => 'clear|pivot|select', + ), + ), + 'custom_fields' => array( + 'date' => 'DATE(fact.FIRST_SEEN)', + 'snippet' => 'LEFT(fact.DIGEST_TEXT,20)', + 'index_ratio' =>'ROUND(SUM_ROWS_EXAMINED/SUM_ROWS_SENT,2)', + 'rows_sent_avg' => 'ROUND(SUM_ROWS_SENT/COUNT_STAR,0)', + 'hour' => 'substring(dimension.FIRST_SEEN,1,13)', + 'hour_ts' => 'round(unix_timestamp(substring(dimension.FIRST_SEEN,1,13)))', + 'minute_ts' => 'round(unix_timestamp(substring(dimension.FIRST_SEEN,1,16)))', + 'minute' => 'substring(dimension.FIRST_SEEN,1,16)', + ), + + 'special_field_names' => array( + 'time' => 'FIRST_SEEN', + 'checksum' => 'DIGEST', + 'hostname' => 'hostname', + 'sample' => 'DIGEST_TEXT' + ), +); + +?> diff --git a/ee/cli/templates/auth-sql-conf.mustache b/ee/cli/templates/auth-sql-conf.mustache new file mode 100644 index 00000000..8854747b --- /dev/null +++ b/ee/cli/templates/auth-sql-conf.mustache @@ -0,0 +1,11 @@ +passdb { + driver = sql + args = /etc/dovecot/dovecot-sql.conf.ext +} +userdb { + driver = prefetch +} +userdb { + driver = sql + args = /etc/dovecot/dovecot-sql.conf.ext +} diff --git a/ee/cli/templates/blockips.mustache b/ee/cli/templates/blockips.mustache new file mode 100644 index 00000000..8228bedb --- /dev/null +++ b/ee/cli/templates/blockips.mustache @@ -0,0 +1,2 @@ +# Block IP Address +# deny 1.1.1.1; diff --git a/ee/cli/templates/default-sieve.mustache b/ee/cli/templates/default-sieve.mustache new file mode 100644 index 00000000..62532322 --- /dev/null +++ b/ee/cli/templates/default-sieve.mustache @@ -0,0 +1,4 @@ +require "fileinto"; +if header :contains "X-Spam-Flag" "YES" { + fileinto "Junk"; +} diff --git a/ee/cli/templates/dovecot-sql-conf.mustache b/ee/cli/templates/dovecot-sql-conf.mustache new file mode 100644 index 00000000..0ec50c11 --- /dev/null +++ b/ee/cli/templates/dovecot-sql-conf.mustache @@ -0,0 +1,12 @@ +driver = mysql +connect = host={{host}} user=vimbadmin password={{password}} dbname=vimbadmin +default_pass_scheme = MD5 +password_query = SELECT username as user, password as password, \ +homedir AS home, maildir AS mail, \ +concat('*:bytes=', quota) as quota_rule, uid, gid \ +FROM mailbox \ +WHERE username = '%Lu' AND active = '1' \ +AND ( access_restriction = 'ALL' OR LOCATE( access_restriction, '%Us' ) > 0 ) +user_query = SELECT homedir AS home, maildir AS mail, \ +concat('*:bytes=', quota) as quota_rule, uid, gid \ +FROM mailbox WHERE username = '%u' diff --git a/ee/cli/templates/dovecot.mustache b/ee/cli/templates/dovecot.mustache new file mode 100644 index 00000000..f7370da8 --- /dev/null +++ b/ee/cli/templates/dovecot.mustache @@ -0,0 +1,60 @@ +protocols = imap pop3 lmtp sieve + +mail_location = maildir:/var/vmail/%d/%n + +disable_plaintext_auth = no +auth_mechanisms = plain login +#!include auth-system.conf.ext +!include auth-sql.conf.ext + +ssl_protocols = !SSLv2 !SSLv3 + +service lmtp { + unix_listener /var/spool/postfix/private/dovecot-lmtp { + mode = 0600 + user = postfix + group = postfix + } +} +service auth { + unix_listener /var/spool/postfix/private/auth { + mode = 0666 + user = postfix + group = postfix + } + unix_listener auth-userdb { + mode = 0600 + user = vmail + } + user = dovecot +} +service auth-worker { + user = vmail +} + +log_path = /var/log/dovecot.log + +mail_plugins = $mail_plugins autocreate + +plugin { + autocreate = Trash + autocreate2 = Junk + autocreate3 = Drafts + autocreate4 = Sent + autosubscribe = Trash + autosubscribe2 = Junk + autosubscribe3 = Drafts + autosubscribe4 = Sent +} + +protocol lmtp { + postmaster_address = {{email}} + mail_plugins = $mail_plugins sieve +} + +plugin { + sieve = ~/.dovecot.sieve + sieve_global_path = /var/lib/dovecot/sieve/default.sieve + sieve_global_dir = /var/lib/dovecot/sieve/ + sieve_dir = ~/sieve +} diff --git a/ee/cli/templates/fastcgi.mustache b/ee/cli/templates/fastcgi.mustache new file mode 100644 index 00000000..db82c459 --- /dev/null +++ b/ee/cli/templates/fastcgi.mustache @@ -0,0 +1,9 @@ +# FastCGI cache settings +fastcgi_cache_path /var/run/nginx-cache levels=1:2 keys_zone=WORDPRESS:50m inactive=60m; +fastcgi_cache_key "$scheme$request_method$host$request_uri"; +fastcgi_cache_use_stale error timeout invalid_header updating http_500 http_503; +fastcgi_cache_valid 200 301 302 404 1h; +fastcgi_buffers 16 16k; +fastcgi_buffer_size 32k; +fastcgi_param SERVER_NAME $http_host; +fastcgi_ignore_headers Cache-Control Expires Set-Cookie; diff --git a/ee/cli/templates/info_mysql.mustache b/ee/cli/templates/info_mysql.mustache new file mode 100644 index 00000000..29a5d81e --- /dev/null +++ b/ee/cli/templates/info_mysql.mustache @@ -0,0 +1,9 @@ + +MySQL ({{version}}) on {{host}}: + +port {{port}} +wait_timeout {{wait_timeout}} +interactive_timeout {{interactive_timeout}} +max_used_connections {{max_used_connections}} +datadir {{datadir}} +socket {{socket}} diff --git a/ee/cli/templates/info_nginx.mustache b/ee/cli/templates/info_nginx.mustache new file mode 100644 index 00000000..6420405b --- /dev/null +++ b/ee/cli/templates/info_nginx.mustache @@ -0,0 +1,10 @@ + +NGINX ({{version}}): + +user {{user}} +worker_processes {{worker_processes}} +worker_connections {{worker_connections}} +keepalive_timeout {{keepalive_timeout}} +fastcgi_read_timeout {{fastcgi_read_timeout}} +client_max_body_size {{client_max_body_size}} +allow {{allow}} diff --git a/ee/cli/templates/info_php.mustache b/ee/cli/templates/info_php.mustache new file mode 100644 index 00000000..1638cf8a --- /dev/null +++ b/ee/cli/templates/info_php.mustache @@ -0,0 +1,35 @@ + +PHP ({{version}}): + +user {{user}} +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}} + +Information about www.conf +ping.path {{www_ping_path}} +pm.status_path {{www_pm_status_path}} +process_manager {{www_pm}} +pm.max_requests {{www_pm_max_requests}} +pm.max_children {{www_pm_max_children}} +pm.start_servers {{www_pm_start_servers}} +pm.min_spare_servers {{www_pm_min_spare_servers}} +pm.max_spare_servers {{www_pm_max_spare_servers}} +request_terminate_timeout {{www_request_terminate_timeout}} +xdebug.profiler_enable_trigger {{www_xdebug_profiler_enable_trigger}} +listen {{www_listen}} + +Information about debug.conf +ping.path {{debug_ping_path}} +pm.status_path {{debug_pm_status_path}} +process_manager {{debug_pm}} +pm.max_requests {{debug_pm_max_requests}} +pm.max_children {{debug_pm_max_children}} +pm.start_servers {{debug_pm_start_servers}} +pm.min_spare_servers {{debug_pm_min_spare_servers}} +pm.max_spare_servers {{debug_pm_max_spare_servers}} +request_terminate_timeout {{debug_request_terminate_timeout}} +xdebug.profiler_enable_trigger {{debug_xdebug_profiler_enable_trigger}} +listen {{debug_listen}} diff --git a/ee/cli/templates/locations.mustache b/ee/cli/templates/locations.mustache new file mode 100644 index 00000000..c8414fb2 --- /dev/null +++ b/ee/cli/templates/locations.mustache @@ -0,0 +1,65 @@ +# NGINX CONFIGURATION FOR COMMON LOCATION +# DO NOT MODIFY, ALL CHNAGES LOST AFTER UPDATE EasyEngine (ee) +# Basic locations files +location = /favicon.ico { + access_log off; + log_not_found off; + expires max; +} +location = /robots.txt { + # Some WordPress plugin gererate robots.txt file + # Refer #340 issue + try_files $uri $uri/ /index.php?$args; + access_log off; + log_not_found off; +} +# Cache static files +location ~* \.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|css|rss|atom|js|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf|swf)$ { + add_header "Access-Control-Allow-Origin" "*"; + access_log off; + log_not_found off; + expires max; +} +# Security settings for better privacy +# Deny hidden files +location ~ /\. { + deny all; + access_log off; + log_not_found off; +} +# Deny backup extensions & log files +location ~* ^.+\.(bak|log|old|orig|original|php#|php~|php_bak|save|swo|swp|sql)$ { + deny all; + access_log off; + log_not_found off; +} +# Return 403 forbidden for readme.(txt|html) or license.(txt|html) +if ($request_uri ~* "^.+(readme|license)\.(txt|html)$") { + return 403; +} +# Status pages +location /nginx_status { + stub_status on; + access_log off; + include common/acl.conf; +} +location ~ ^/(status|ping) { + include fastcgi_params; + fastcgi_pass php; + include common/acl.conf; +} +# EasyEngine (ee) utilities +# phpMyAdmin settings +location /pma { + return 301 https://$host:22222/db/pma; +} +location /phpMyAdmin { + return 301 https://$host:22222/db/pma; +} +location /phpmyadmin { + return 301 https://$host:22222/db/pma; +} +# Adminer settings +location /adminer { + return 301 https://$host:22222/db/adminer; +} diff --git a/ee/cli/templates/nginx-core.mustache b/ee/cli/templates/nginx-core.mustache new file mode 100644 index 00000000..6c90e51b --- /dev/null +++ b/ee/cli/templates/nginx-core.mustache @@ -0,0 +1,39 @@ +## +# EasyEngine Settings +## + +server_tokens off; +reset_timedout_connection on; +add_header X-Powered-By "EasyEngine {{version}}"; +add_header rt-Fastcgi-Cache $upstream_cache_status; + +# Limit Request +limit_req_status 403; +limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s; + +# Proxy Settings +# set_real_ip_from proxy-server-ip; +# real_ip_header X-Forwarded-For; + +fastcgi_read_timeout 300; +client_max_body_size 100m; + +# SSL Settings +ssl_session_cache shared:SSL:20m; +ssl_session_timeout 10m; +ssl_prefer_server_ciphers on; +ssl_ciphers HIGH:!aNULL:!MD5:!kEDH; + +# Log format Settings +log_format rt_cache '$remote_addr $upstream_response_time $upstream_cache_status [$time_local] ' +'$http_host "$request" $status $body_bytes_sent ' +'"$http_referer" "$http_user_agent"'; + + +# GZip settings +gzip_vary on; +gzip_proxied any; +gzip_comp_level 6; +gzip_buffers 16 8k; +gzip_http_version 1.1; +gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; diff --git a/ee/cli/templates/php.mustache b/ee/cli/templates/php.mustache new file mode 100644 index 00000000..3546f571 --- /dev/null +++ b/ee/cli/templates/php.mustache @@ -0,0 +1,10 @@ +# PHP NGINX CONFIGURATION +# DO NOT MODIFY, ALL CHNAGES LOST AFTER UPDATE EasyEngine (ee) +location / { + try_files $uri $uri/ /index.php?$args; +} +location ~ \.php$ { + try_files $uri =404; + include fastcgi_params; + fastcgi_pass php; +} diff --git a/ee/cli/templates/siteinfo.mustache b/ee/cli/templates/siteinfo.mustache new file mode 100644 index 00000000..dfe7d917 --- /dev/null +++ b/ee/cli/templates/siteinfo.mustache @@ -0,0 +1,10 @@ +Information about {{domain}}: + +Nginx configuration {{type}} {{enable}} +access_log {{accesslog}} +error_log {{errorlog}} +Webroot {{webroot}} +{{#dbname}}DB_NAME {{dbname}}{{/dbname}} +{{#dbname}}DB_USER {{dbuser}}{{/dbname}} +{{#dbname}}DB_PASS {{dbpass}}{{/dbname}} +{{#tablepref}}table_prefix {{tableprefix}}{{/tablepref}} diff --git a/ee/cli/templates/upstream.mustache b/ee/cli/templates/upstream.mustache new file mode 100644 index 00000000..8a265179 --- /dev/null +++ b/ee/cli/templates/upstream.mustache @@ -0,0 +1,9 @@ +# Common upstream settings +upstream php { +# server unix:/run/php5-fpm.sock; +server 127.0.0.1:{{php}}; +} +upstream debug { +# Debug Pool +server 127.0.0.1:{{debug}}; +} diff --git a/ee/cli/templates/vimbadmin.mustache b/ee/cli/templates/vimbadmin.mustache new file mode 100644 index 00000000..808d57ce --- /dev/null +++ b/ee/cli/templates/vimbadmin.mustache @@ -0,0 +1,662 @@ +;; This file is licenesed Under GNU GENERAL PUBLIC LICENSE Version 3 +;; © Copyright 2011 - 2014 Open Source Solutions Limited, Dublin, Ireland. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; ViMbAdmin :: Virtual Mailbox Admin +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; IMPORTANT: Review and change all options in [user] +;; +;; ** This is for ViMbAdmin V3 and later ** +;; +;; See: https://github.com/opensolutions/ViMbAdmin/wiki/Configuration + +[user] + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Installation Keys and Salts +; +; During installation, you will be prompted to enter strings here. This +; is to verify that you are in fact the person authorised to complete the +; installation as well as provide security for cookies and passwords. + +securitysalt = "{{salt}}" +resources.auth.oss.rememberme.salt = "{{salt}}" +defaults.mailbox.password_salt = "{{salt}}" + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; When installing for the first time, it may be useful to set the following +; to 1 BUT ensure you set it to zero again in a production system + +phpSettings.display_startup_errors = 0 +phpSettings.display_errors = 0 +resources.frontController.params.displayExceptions = 0 + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; You database and caching connection. +;; + +resources.doctrine2.connection.options.driver = 'mysqli' +resources.doctrine2.connection.options.dbname = 'vimbadmin' +resources.doctrine2.connection.options.user = 'vimbadmin' +resources.doctrine2.connection.options.password = '{{password}}' +resources.doctrine2.connection.options.host = '{{host}}' +resources.doctrine2.connection.options.charset = 'utf8' + +;; Doctrine2 requires Memcache for maximum efficency. Without Memcache +;; it can be highly inefficient and will slow page requests down. +;; +;; You are strongly advised to install memcache and comment ArrayCache +;; here and uncomment MemcacheCache. +;; + +resources.doctrine2cache.type = 'ArrayCache' +;resources.doctrine2cache.type = 'MemcacheCache' +;resources.doctrine2cache.memcache.servers.0.host = '127.0.0.1' +resources.doctrine2cache.namespace = 'ViMbAdmin3' + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Default values used when creating domains +; +; See: https://github.com/opensolutions/ViMbAdmin/wiki/Configuration +; See: https://github.com/opensolutions/ViMbAdmin/wiki/Quotas + +defaults.domain.quota = 0 +defaults.domain.maxquota = 0 +defaults.domain.transport = "virtual" +defaults.domain.aliases = 0 +defaults.domain.mailboxes = 0 + +defaults.quota.multiplier = 'MB' + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Use server side filtering to reduce pagination time on client side +;; Defaults to off / false +defaults.server_side.pagination.enable = false +defaults.server_side.pagination.min_search_str = 3 +defaults.server_side.pagination.max_result_cnt = 500 + +;; Separate configuration for domain list +defaults.server_side.pagination.domain.enable = false +defaults.server_side.pagination.domain.min_search_str = 3 +defaults.server_side.pagination.domain.max_result_cnt = 500 + +; The number of rows displayed in the tables +; must be one of these: 10, 25, 50, 100 +defaults.table.entries = 50 + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Options for the display of domain and mailbox sizes +;; +;; See: https://github.com/opensolutions/ViMbAdmin/wiki/Mailbox-Sizes +;; +;; Enable or disable display of sizes. Default: disabled + +defaults.list_size.disabled = true + +;; Maildir size units. By default: KB. One of B, KB, MB or GB. +defaults.list_size.multiplier = 'GB' + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Default values for creating mailboxes + +; This sets the uid and gid columns in the mailbox table to the below values +defaults.mailbox.uid = 5000 +defaults.mailbox.gid = 5000 + + +; Set the homedir and maildir values in the mailbox table where the +; following substitutions apply: +; +; %d -> domain part of email address +; %u -> user part of email address +; $m -> full email address +; +; +; http://wiki2.dovecot.org/VirtualUsers/Home + +defaults.mailbox.maildir = "maildir:/var/vmail/%d/%u" +defaults.mailbox.homedir = "/var/vmail/" + +;minimum mailbox password length +defaults.mailbox.min_password_length = 8 + +; The password hashing function to use. Set to one of: +; +; "plain" - password stored as clear text +; "md5" - password hashed using MD5 without salt (PHP md5()) +; "md5.salted" - password hashed using MD5 with salt (see below) +; "sha1" - password hashed using sha1 without salt +; "sha1.salted" - password hashed using sha1 with salt defined below +; "crypt:XXX" - call the PHP crypt function (with random salt) where XXX is one of: md5, blowfish, sha256, sha512 +; "dovecot:XXX" - call the Dovecot password generator (see next option below) and use the +; scheme specified by XXX. To see available schemes, use 'dovecotpw -l' +; or 'doveadm pw -l' + +defaults.mailbox.password_scheme = "md5" + +; The path to (and initial option(s) if necessary) the Dovecot password generator. Typical +; values may be something like: +; +; "/usr/bin/doveadm pw" +; "/usr/bin/dovecotpw" + +defaults.mailbox.dovecot_pw_binary = "/usr/bin/doveadm pw" + + + +;; A "mailbox alias" will, for example add the following entry to +;; the alias table for a mailbox: name@example.com +;; +;; name@example.com -> name@example.com +;; +;; This is required for aliasing an entire domain. If in doubt, leave it enabled. +mailboxAliases = 1 + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; See: https://github.com/opensolutions/ViMbAdmin/wiki/Archiving-Mailboxes + +server_id = 1 + +;;Archive options +binary.path.chown_R = "/bin/chown -R" +binary.path.tar_cf = "/bin/tar -cf" +binary.path.tar_xf = "/bin/tar -xf" +binary.path.bzip2_q = "/bin/bzip2 -q" +binary.path.bunzip2_q = "/bin/bunzip2 -q" +binary.path.rm_rf = "/bin/rm -rf" + +archive.path = "/srv/archives" + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Enable mailbox deletion on the file system +; +; See: https://github.com/opensolutions/ViMbAdmin/wiki/Deleting-Mailboxes +; + +mailbox_deletion_fs_enabled = false + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Export Mailbox Settings +; +; See: https://github.com/opensolutions/ViMbAdmin/wiki/Export-Settings +; +defaults.export_settings.disabled = true + + +;; Export settings alowed subnets +defaults.export_settings.allowed_subnet[] = "10." +defaults.export_settings.allowed_subnet[] = "192.168." + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Settings email default values. +;; +;; Substituions are as follows: +;; +;; %d -> domain part of email address +;; %u -> user part of email address +;; $m -> full email address +;; +;; See (and skin) the following file to see how the below are used: +;; +;; views/mailbox/email/settings.phtml +;; + +server.smtp.enabled = 1 +server.smtp.host = "mail.%d" +server.smtp.user = "%m" +server.smtp.port = "465" +server.smtp.crypt = "SSL" + +server.pop3.enabled = 1 +server.pop3.host = "gpo.%d" +server.pop3.user = "%m" +server.pop3.port = "995" +server.pop3.crypt = "SSL" + +server.imap.enabled = 1 +server.imap.host = "gpo.%d" +server.imap.user = "%m" +server.imap.port = "993" +server.imap.crypt = "SSL" + +server.webmail.enabled = 1 +server.webmail.host = "https://webmail.%d" +server.webmail.user = "%m" + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Identity + +identity.orgname = "Example Limited" +identity.name = "Example Support Team" +identity.email = "support@example.com" +identity.autobot.name = "ViMbAdmin Autobot" +identity.autobot.email = "autobot@example.com" +identity.mailer.name = "ViMbAdmin Autobot" +identity.mailer.email = "do-not-reply@example.com" + +identity.sitename = "ViMbAdmin" +identity.siteurl = "https://www.example.com/vimbadmin/" + + +;; +;; All mail and correspondence will come from the following;; + +server.email.name = "ViMbAdmin Administrator" +server.email.address = "support@example.com" + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Skinning +;; +;; You can skin ViMbAdmin pages if you wish. +;; +;; See: https://github.com/opensolutions/ViMbAdmin/wiki/Skinning + +; resources.smarty.skin = "myskin" + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; See: http://framework.zend.com/manual/en/zend.mail.smtp-authentication.html +;; +;; Ensure you have a working mail server configuration so the system can +;; send emails: +;; +resources.mailer.smtphost = "localhost" +;resources.mailer.username = "" +;resources.mailer.password = "" +;resources.mailer.auth = "" +;resources.mailer.ssl = "" +;resources.mailer.port = "25" + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Local filesystem logging. +;; +;; We log various things to var/log/YYYY/MM/ if you enable the logger here. +;; +;; It is useful to use the email logger to be alerted of serious errors. +;; + +ondemand_resources.logger.enabled = 1 + +;ondemand_resources.logger.writers.email.from = "admin@example.com" +;ondemand_resources.logger.writers.email.to = "admin@example.com" +;ondemand_resources.logger.writers.email.prefix = "ViMbAdmin_Error" +;ondemand_resources.logger.writers.email.level = 3 + +ondemand_resources.logger.writers.stream.level = 7 + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; ViMbAdmin performs a version check on administrator login and alerts the +;; user if there is a newer version available. +;; +;; This can be disabled by setting the below to 1 +;; + +skipVersionCheck = 0 + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; ViMbAdmin 'pings' the developers as part of the set up process to let +;; them know there is a new installation. +;; +;; All we are interested in is knowing whether people are using the software +;; or not and whether continued support and development is worth the time +;; and effort. +;; +;; Unless you're very shy, PLEASE LET US KNOW YOU'RE USING IT! +;; +;; This can be disabled by setting the below to 1 +;; + +skipInstallPingback = 0 + + + + + + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Allow admins to dictate whether a user can use BOTH, IMAP ONLY, +; POP3 ONLY when creating mailboxes. +; +; Must be supported by your POP3/IMAP server. +; +; See https://github.com/opensolutions/ViMbAdmin/wiki/POP3-IMAP-Access-Permissions +; for documentation. +; +; This is handled via a plugin +; + +vimbadmin_plugins.AccessPermissions.disabled = false + +; specify the options which should be allowed for access restrictions +vimbadmin_plugins.AccessPermissions.type.SMTP = "SMTP" +vimbadmin_plugins.AccessPermissions.type.IMAP = "IMAP" +vimbadmin_plugins.AccessPermissions.type.POP3 = "POP3" +vimbadmin_plugins.AccessPermissions.type.SIEVE = "SIEVE" + + + + + + + + + + + + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Proceed onwards with caution. +;; +;; The above [user] params are the may ones of consequence. +;; + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Allows to add additional information. +; +; This is handled via a plugin +; + +vimbadmin_plugins.AccessPermissions.disabled = false +vimbadmin_plugins.Jabber.disabled = true +vimbadmin_plugins.DirectoryEntry.disabled = true +vimbadmin_plugins.SharedMailbox.disabled = true +vimbadmin_plugins.SOGo.disabled = true + + +vimbadmin_plugins.AdditionalInfo.disabled = true +vimbadmin_plugins.Addressbook.disabled = true +vimbadmin_plugins.Calendar.disabled = true +vimbadmin_plugins.RoundCube.disabled = true + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Disabling directory entry subform element +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +vimbadmin_plugins.DirectoryEntry.disabled_elements.JpegPhoto = true +vimbadmin_plugins.DirectoryEntry.disabled_elements.Mail = true +vimbadmin_plugins.DirectoryEntry.disabled_elements.PreferredLanguage = true +vimbadmin_plugins.DirectoryEntry.disabled_elements.Secretary = true + +vimbadmin_plugins.DirectoryEntry.disabled_elements.PersonalTitle = false +vimbadmin_plugins.DirectoryEntry.disabled_elements.GivenName = false +vimbadmin_plugins.DirectoryEntry.disabled_elements.Sn = false +vimbadmin_plugins.DirectoryEntry.disabled_elements.DisplayName = false +vimbadmin_plugins.DirectoryEntry.disabled_elements.Initials = false +vimbadmin_plugins.DirectoryEntry.disabled_elements.BusinesCategory = false +vimbadmin_plugins.DirectoryEntry.disabled_elements.EmployeeType = false +vimbadmin_plugins.DirectoryEntry.disabled_elements.Title = false +vimbadmin_plugins.DirectoryEntry.disabled_elements.DepartmentNumber = false +vimbadmin_plugins.DirectoryEntry.disabled_elements.Ou = false +vimbadmin_plugins.DirectoryEntry.disabled_elements.RoomNumber = false +vimbadmin_plugins.DirectoryEntry.disabled_elements.O = false +vimbadmin_plugins.DirectoryEntry.disabled_elements.CarLicense = false +vimbadmin_plugins.DirectoryEntry.disabled_elements.EmployeeNumber = false +vimbadmin_plugins.DirectoryEntry.disabled_elements.HomePhone = false +vimbadmin_plugins.DirectoryEntry.disabled_elements.TelephoneNumber = false +vimbadmin_plugins.DirectoryEntry.disabled_elements.Mobile = false +vimbadmin_plugins.DirectoryEntry.disabled_elements.Pager = false +vimbadmin_plugins.DirectoryEntry.disabled_elements.FacsimileTelephoneNumber = false +vimbadmin_plugins.DirectoryEntry.disabled_elements.HomePostalAddress = false +vimbadmin_plugins.DirectoryEntry.disabled_elements.LabeledUri = false +vimbadmin_plugins.DirectoryEntry.disabled_elements.Manager = false + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Mailbox AdditionalInfo plugin elements +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +;;Additional text messages for plugin. +AdditionalInfo.mailbox.formPreBlurb = "

NB: Do not edit the following. It is sync'd on a nightly basis ..." + +; First Name +vimbadmin_plugins.AdditionalInfo.elements.id.type = "Zend_Form_Element_Text" +vimbadmin_plugins.AdditionalInfo.elements.id.options.required = false +vimbadmin_plugins.AdditionalInfo.elements.id.options.label = "LDAP Id" + +; First Name +vimbadmin_plugins.AdditionalInfo.elements.first_name.type = "Zend_Form_Element_Text" +vimbadmin_plugins.AdditionalInfo.elements.first_name.options.required = false +vimbadmin_plugins.AdditionalInfo.elements.first_name.options.label = "First Name" + +; Last Name +vimbadmin_plugins.AdditionalInfo.elements.second_name.type = "Zend_Form_Element_Text" +vimbadmin_plugins.AdditionalInfo.elements.second_name.options.required = false +vimbadmin_plugins.AdditionalInfo.elements.second_name.options.label = "Last Name" + +; Grade +vimbadmin_plugins.AdditionalInfo.elements.grade.type = "Zend_Form_Element_Text" +vimbadmin_plugins.AdditionalInfo.elements.grade.options.required = false +vimbadmin_plugins.AdditionalInfo.elements.grade.options.label = "Grade" + +; Grade Id +vimbadmin_plugins.AdditionalInfo.elements.grade_id.type = "Zend_Form_Element_Text" +vimbadmin_plugins.AdditionalInfo.elements.grade_id.options.required = false +vimbadmin_plugins.AdditionalInfo.elements.grade_id.options.label = "Grade Id" +vimbadmin_plugins.AdditionalInfo.elements.grade_id.options.validators.digits[] = 'Digits' +vimbadmin_plugins.AdditionalInfo.elements.grade_id.options.validators.digits[] = true + +; Department +vimbadmin_plugins.AdditionalInfo.elements.department.type = "Zend_Form_Element_Text" +vimbadmin_plugins.AdditionalInfo.elements.department.options.required = false +vimbadmin_plugins.AdditionalInfo.elements.department.options.label = "Department" + +; Department Id +vimbadmin_plugins.AdditionalInfo.elements.department_id.type = "Zend_Form_Element_Text" +vimbadmin_plugins.AdditionalInfo.elements.department_id.options.required = false +vimbadmin_plugins.AdditionalInfo.elements.department_id.options.label = "Department Id" +vimbadmin_plugins.AdditionalInfo.elements.department_id.options.validators.digits[] = 'Digits' +vimbadmin_plugins.AdditionalInfo.elements.department_id.options.validators.digits[] = true + +; Section +vimbadmin_plugins.AdditionalInfo.elements.section.type = "Zend_Form_Element_Text" +vimbadmin_plugins.AdditionalInfo.elements.section.options.required = false +vimbadmin_plugins.AdditionalInfo.elements.section.options.label = "Section" + +; Extension Number +vimbadmin_plugins.AdditionalInfo.elements.ext_no.type = "Zend_Form_Element_Text" +vimbadmin_plugins.AdditionalInfo.elements.ext_no.options.required = false +vimbadmin_plugins.AdditionalInfo.elements.ext_no.options.label = "Extension Number" +vimbadmin_plugins.AdditionalInfo.elements.ext_no.options.validators.digits[] = 'Digits' +vimbadmin_plugins.AdditionalInfo.elements.ext_no.options.validators.digits[] = true +vimbadmin_plugins.AdditionalInfo.elements.ext_no.options.validators.length[] = 'StringLength' +vimbadmin_plugins.AdditionalInfo.elements.ext_no.options.validators.length[] = false +vimbadmin_plugins.AdditionalInfo.elements.ext_no.options.validators.length.range[] = 4 +vimbadmin_plugins.AdditionalInfo.elements.ext_no.options.validators.length.range[] = 4 +;;to disable autocomplete functionality +vimbadmin_plugins.AdditionalInfo.elements.ext_no.options.autocomplete = 'off' + +; Direct Dial +vimbadmin_plugins.AdditionalInfo.elements.d_dial.type = "Zend_Form_Element_Text" +vimbadmin_plugins.AdditionalInfo.elements.d_dial.options.required = false +vimbadmin_plugins.AdditionalInfo.elements.d_dial.options.label = "Direct Dial" +vimbadmin_plugins.AdditionalInfo.elements.d_dial.options.autocomplete = 'off' + +; Mobile +vimbadmin_plugins.AdditionalInfo.elements.mobile.type = "Zend_Form_Element_Text" +vimbadmin_plugins.AdditionalInfo.elements.mobile.options.required = false +vimbadmin_plugins.AdditionalInfo.elements.mobile.options.label = "Mobile" +vimbadmin_plugins.AdditionalInfo.elements.mobile.options.autocomplete = 'off' + +;;;;;;; +;; Aliases additional information +;; +; First Name +vimbadmin_plugins.AdditionalInfo.alias.elements.name.type = "Zend_Form_Element_Text" +vimbadmin_plugins.AdditionalInfo.alias.elements.name.options.required = false +vimbadmin_plugins.AdditionalInfo.alias.elements.name.options.label = "Name" + +; Extension Number +vimbadmin_plugins.AdditionalInfo.alias.elements.ext_no.type = "Zend_Form_Element_Text" +vimbadmin_plugins.AdditionalInfo.alias.elements.ext_no.options.required = false +vimbadmin_plugins.AdditionalInfo.alias.elements.ext_no.options.label = "Extension Number" +vimbadmin_plugins.AdditionalInfo.alias.elements.ext_no.options.validators.digits[] = 'Digits' +vimbadmin_plugins.AdditionalInfo.alias.elements.ext_no.options.validators.digits[] = true +vimbadmin_plugins.AdditionalInfo.alias.elements.ext_no.options.validators.length[] = 'StringLength' +vimbadmin_plugins.AdditionalInfo.alias.elements.ext_no.options.validators.length[] = false +vimbadmin_plugins.AdditionalInfo.alias.elements.ext_no.options.validators.length.range[] = 4 +vimbadmin_plugins.AdditionalInfo.alias.elements.ext_no.options.validators.length.range[] = 4 +vimbadmin_plugins.AdditionalInfo.alias.elements.ext_no.options.autocomplete = 'off' + +; Direct Dial +vimbadmin_plugins.AdditionalInfo.alias.elements.d_dial.type = "Zend_Form_Element_Text" +vimbadmin_plugins.AdditionalInfo.alias.elements.d_dial.options.required = false +vimbadmin_plugins.AdditionalInfo.alias.elements.d_dial.options.label = "Direct Dial" +vimbadmin_plugins.AdditionalInfo.alias.elements.d_dial.options.autocomplete = 'off' + + +[production : user] + +includePaths.library = APPLICATION_PATH "/../library" +includePaths.osslibrary = APPLICATION_PATH "/../vendor/opensolutions/oss-framework/src/" + +bootstrap.path = APPLICATION_PATH "/Bootstrap.php" +bootstrap.class = "Bootstrap" +appnamespace = "ViMbAdmin" + +temporary_directory = APPLICATION_PATH "/../var/tmp" + +pluginPaths.OSS_Resource = APPLICATION_PATH "/../vendor/opensolutions/oss-framework/src/OSS/Resource" +pluginPaths.ViMbAdmin_Resource = APPLICATION_PATH "/../library/ViMbAdmin/Resource" + +mini_js = 1 +mini_css = 1 + +alias_autocomplete_min_length = 2 + + + +resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers" +resources.frontController.moduleDirectory = APPLICATION_PATH "/modules" +resources.modules[] = + + +; doctrine2 +resources.doctrine2.models_path = APPLICATION_PATH +resources.doctrine2.proxies_path = APPLICATION_PATH "/Proxies" +resources.doctrine2.repositories_path = APPLICATION_PATH +resources.doctrine2.xml_schema_path = APPLICATION_PATH "/../doctrine2/xml" +resources.doctrine2.autogen_proxies = 0 +resources.doctrine2.logger = 1 +resources.doctrine2.models_namespace = "Entities" +resources.doctrine2.proxies_namespace = "Proxies" +resources.doctrine2.repositories_namespace = "Repositories" + + +resources.doctrine2cache.autoload_method = "composer" +;resources.doctrine2cache.type = 'ArrayCache' +;resources.doctrine2cache.type = 'MemcacheCache' +;resources.doctrine2cache.memcache.servers.0.host = '127.0.0.1' +;resources.doctrine2cache.memcache.servers.0.port = '11211' +;resources.doctrine2cache.memcache.servers.0.persistent = false +;resources.doctrine2cache.memcache.servers.0.weight = 1 +;resources.doctrine2cache.memcache.servers.0.timeout = 1 +;resources.doctrine2cache.memcache.servers.0.retry_int = 15 + +; resources.doctrine2cache.memcache.servers.1.host = 'xxx' +; resources.doctrine2cache.memcache.servers.2.host = 'yyy' + +resources.namespace.checkip = 0 + +resources.auth.enabled = 1 +resources.auth.oss.adapter = "OSS_Auth_Doctrine2Adapter" +resources.auth.oss.pwhash = "bcrypt" +resources.auth.oss.hash_cost = 9 +resources.auth.oss.entity = "\\Entities\\Admin" +resources.auth.oss.disabled.lost-username = 1 +resources.auth.oss.disabled.lost-password = 0 + +resources.auth.oss.rememberme.enabled = 1 +resources.auth.oss.rememberme.timeout = 2592000 +resources.auth.oss.rememberme.secure = true + +resources.auth.oss.lost_password.use_captcha = true + +resources.session.save_path = APPLICATION_PATH "/../var/session" +resources.session.use_only_cookies = true +resources.session.remember_me_seconds = 3600 +resources.session.name = 'VIMBADMIN3' + +ondemand_resources.logger.writers.stream.path = APPLICATION_PATH "/../var/log" +ondemand_resources.logger.writers.stream.owner = {{php_user}} +ondemand_resources.logger.writers.stream.group = {{php_user}} +ondemand_resources.logger.writers.stream.mode = single +ondemand_resources.logger.writers.stream.logname = vimbadmin.log + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Smarty View +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +resources.smarty.enabled = 1 +resources.smarty.templates = APPLICATION_PATH "/views" +; resources.smarty.skin = "myskin" +resources.smarty.compiled = APPLICATION_PATH "/../var/templates_c" +resources.smarty.cache = APPLICATION_PATH "/../var/cache" +resources.smarty.config = APPLICATION_PATH "/configs/smarty" +resources.smarty.plugins[] = APPLICATION_PATH "/../library/ViMbAdmin/Smarty/functions" +resources.smarty.plugins[] = APPLICATION_PATH "/../vendor/opensolutions/oss-framework/src/OSS/Smarty/functions" +resources.smarty.plugins[] = APPLICATION_PATH "/../vendor/smarty/smarty/libs/plugins" +resources.smarty.plugins[] = APPLICATION_PATH "/../vendor/smarty/smarty/libs/sysplugins" +resources.smarty.debugging = 0 + + + + +[development : production] + +mini_js = 0 +mini_css = 0 + +phpSettings.display_startup_errors = 1 +phpSettings.display_errors = 1 +resources.frontController.params.displayExceptions = 1 diff --git a/ee/cli/templates/virtual_alias_maps.mustache b/ee/cli/templates/virtual_alias_maps.mustache new file mode 100644 index 00000000..b7919c74 --- /dev/null +++ b/ee/cli/templates/virtual_alias_maps.mustache @@ -0,0 +1,5 @@ +user = vimbadmin +password = {{password}} +hosts = {{host}} +dbname = vimbadmin +query = SELECT goto FROM alias WHERE address = '%s' AND active = '1' diff --git a/ee/cli/templates/virtual_domains_maps.mustache b/ee/cli/templates/virtual_domains_maps.mustache new file mode 100644 index 00000000..2dce79a0 --- /dev/null +++ b/ee/cli/templates/virtual_domains_maps.mustache @@ -0,0 +1,5 @@ +user = vimbadmin +password = {{password}} +hosts = {{host}} +dbname = vimbadmin +query = SELECT domain FROM domain WHERE domain = '%s' AND backupmx = '0' AND active = '1' diff --git a/ee/cli/templates/virtual_mailbox_maps.mustache b/ee/cli/templates/virtual_mailbox_maps.mustache new file mode 100644 index 00000000..f8aafdaf --- /dev/null +++ b/ee/cli/templates/virtual_mailbox_maps.mustache @@ -0,0 +1,7 @@ +user = vimbadmin +password = {{password}} +hosts = {{host}} +dbname = vimbadmin +table = mailbox +select_field = maildir +where_field = username diff --git a/ee/cli/templates/virtualconf.mustache b/ee/cli/templates/virtualconf.mustache new file mode 100644 index 00000000..cadb946b --- /dev/null +++ b/ee/cli/templates/virtualconf.mustache @@ -0,0 +1,34 @@ + +server { + + {{#multisite}} + # Uncomment the following line for domain mapping + # listen 80 default_server; + {{/multisite}} + + server_name {{^vma}}{{^rc}}{{site_name}}{{/rc}}{{/vma}} {{#vma}}vma.*{{/vma}} {{#rc}}webmail.*{{/rc}} {{^vma}}{{^rc}}{{#multisite}}*{{/multisite}}{{^multisite}}www{{/multisite}}.{{site_name}}{{/rc}}{{/vma}}; + + {{#multisite}} + # Uncomment the following line for domain mapping + #server_name_in_redirect off; + {{/multisite}} + + access_log /var/log/nginx/{{site_name}}.access.log {{^static}}rt_cache{{/static}}; + error_log /var/log/nginx/{{site_name}}.error.log; + {{^vma}}{{^rc}}root {{webroot}}/htdocs;{{/rc}}{{/vma}} + {{#vma}}root /var/www/22222/htdocs/vimbadmin/public;{{/vma}} + {{#rc}}root /var/www/roundcubemail/htdocs/;{{/rc}} + + index {{^static}}index.php{{/static}} index.html index.htm; + + {{#static}} + location / { + try_files $uri $uri/ /index.html; + } + {{/static}} + + {{^static}}include{{/static}} {{#basic}}common/php.conf;{{/basic}}{{#w3tc}}common/w3tc.conf;{{/w3tc}}{{#wpfc}}common/wpfc.conf;{{/wpfc}} {{#wpsc}}common/wpsc.conf;{{/wpsc}} + {{#wpsubdir}}include common/wpsubdir.conf;{{/wpsubdir}} + {{#wp}}include common/wpcommon.conf;{{/wp}} + include common/locations.conf; +} diff --git a/ee/cli/templates/w3tc.mustache b/ee/cli/templates/w3tc.mustache new file mode 100644 index 00000000..5b162822 --- /dev/null +++ b/ee/cli/templates/w3tc.mustache @@ -0,0 +1,31 @@ + +# W3TC NGINX CONFIGURATION +# DO NOT MODIFY, ALL CHNAGES LOST AFTER UPDATE EasyEngine (ee) +set $cache_uri $request_uri; +# POST requests and URL with a query string should always go to php +if ($request_method = POST) { + set $cache_uri 'null cache'; +} +if ($query_string != "") { + set $cache_uri 'null cache'; +} +# Don't cache URL containing the following segments +if ($request_uri ~* "(/wp-admin/|/xmlrpc.php|wp-.*.php|index.php|/feed/|sitemap(_index)?.xml|[a-z0-9_-]+-sitemap([0-9]+)?.xml)") { + set $cache_uri 'null cache'; +} +# Don't use the cache for logged in users or recent commenter +if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_logged_in") { + set $cache_uri 'null cache'; +} +# Use cached or actual file if they exists, Otherwise pass request to WordPress +location / { + try_files /wp-content/cache/page_enhanced/${host}${cache_uri}_index.html $uri $uri/ /index.php?$args; +} +location ~ ^/wp-content/cache/minify/(.+\.(css|js))$ { + try_files $uri /wp-content/plugins/w3-total-cache/pub/minify.php?file=$1; +} +location ~ \.php$ { + try_files $uri =404; + include fastcgi_params; + fastcgi_pass php; +} diff --git a/ee/cli/templates/wpcommon.mustache b/ee/cli/templates/wpcommon.mustache new file mode 100644 index 00000000..e6b34782 --- /dev/null +++ b/ee/cli/templates/wpcommon.mustache @@ -0,0 +1,35 @@ +# WordPress COMMON SETTINGS +# DO NOT MODIFY, ALL CHNAGES LOST AFTER UPDATE EasyEngine (ee) +# Limit access to avoid brute force attack +location = /wp-login.php { + limit_req zone=one burst=1 nodelay; + include fastcgi_params; + fastcgi_pass php; +} +# Disable wp-config.txt +location = /wp-config.txt { + deny all; + access_log off; + log_not_found off; +} +# Disallow php in upload folder +location /wp-content/uploads/ { + location ~ \.php$ { + #Prevent Direct Access Of PHP Files From Web Browsers + deny all; + } +} +# Yoast sitemap +location ~ ([^/]*)sitemap(.*)\.x(m|s)l$ { + rewrite ^/sitemap\.xml$ /sitemap_index.xml permanent; + rewrite ^/([a-z]+)?-?sitemap\.xsl$ /index.php?xsl=$1 last; + # Rules for yoast sitemap with wp|wpsubdir|wpsubdomain + rewrite ^.*/sitemap_index\.xml$ /index.php?sitemap=1 last; + rewrite ^.*/([^/]+?)-sitemap([0-9]+)?\.xml$ /index.php?sitemap=$1&sitemap_n=$2 last; + # Following lines are options. Needed for WordPress seo addons + rewrite ^/news_sitemap\.xml$ /index.php?sitemap=wpseo_news last; + rewrite ^/locations\.kml$ /index.php?sitemap=wpseo_local_kml last; + rewrite ^/geo_sitemap\.xml$ /index.php?sitemap=wpseo_local last; + rewrite ^/video-sitemap\.xsl$ /index.php?xsl=video last; + access_log off; +} diff --git a/ee/cli/templates/wpfc.mustache b/ee/cli/templates/wpfc.mustache new file mode 100644 index 00000000..ff5240c7 --- /dev/null +++ b/ee/cli/templates/wpfc.mustache @@ -0,0 +1,36 @@ +# WPFC NGINX CONFIGURATION +# DO NOT MODIFY, ALL CHNAGES LOST AFTER UPDATE EasyEngine (ee) +set $skip_cache 0; +# POST requests and URL with a query string should always go to php +if ($request_method = POST) { + set $skip_cache 1; +} +if ($query_string != "") { + set $skip_cache 1; +} +# Don't cache URL containing the following segments +if ($request_uri ~* "(/wp-admin/|/xmlrpc.php|wp-.*.php|index.php|/feed/|sitemap(_index)?.xml|[a-z0-9_-]+-sitemap([0-9]+)?.xml)") { + set $skip_cache 1; +} +# Don't use the cache for logged in users or recent commenter +if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") { + set $skip_cache 1; +} +# Use cached or actual file if they exists, Otherwise pass request to WordPress +location / { + try_files $uri $uri/ /index.php?$args; +} +location ~ ^/wp-content/cache/minify/(.+\.(css|js))$ { + try_files $uri /wp-content/plugins/w3-total-cache/pub/minify.php?file=$1; +} +location ~ \.php$ { + try_files $uri =404; + include fastcgi_params; + fastcgi_pass php; + fastcgi_cache_bypass $skip_cache; + fastcgi_no_cache $skip_cache; + fastcgi_cache WORDPRESS; +} +location ~ /purge(/.*) { + fastcgi_cache_purge WORDPRESS "$scheme$request_method$host$1"; +} diff --git a/ee/cli/templates/wpsc.mustache b/ee/cli/templates/wpsc.mustache new file mode 100644 index 00000000..2600a795 --- /dev/null +++ b/ee/cli/templates/wpsc.mustache @@ -0,0 +1,31 @@ +# WPSC NGINX CONFIGURATION +# DO NOT MODIFY, ALL CHNAGES LOST AFTER UPDATE EasyEngine (ee) +set $cache_uri $request_uri; +# POST requests and URL with a query string should always go to php +if ($request_method = POST) { + set $cache_uri 'null cache'; +} +if ($query_string != "") { + set $cache_uri 'null cache'; +} +# Don't cache URL containing the following segments +if ($request_uri ~* "(/wp-admin/|/xmlrpc.php|wp-.*.php|index.php|/feed/|sitemap(_index)?.xml|[a-z0-9_-]+-sitemap([0-9]+)?.xml)") { + set $cache_uri 'null cache'; +} +# Don't use the cache for logged in users or recent commenter +if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_logged_in") { + set $cache_uri 'null cache'; +} +# Use cached or actual file if they exists, Otherwise pass request to WordPress +location / { + # If we add index.php?$args its break WooCommerce like plugins + # Ref: #330 + try_files /wp-content/cache/supercache/$http_host/$cache_uri/index.html $uri $uri/ /index.php; +} +location ~ \.php$ { + try_files $uri =404; + include fastcgi_params; + fastcgi_pass php; + # Following line is needed by WP Super Cache plugin + fastcgi_param SERVER_NAME $http_host; +} diff --git a/ee/cli/templates/wpsubdir.mustache b/ee/cli/templates/wpsubdir.mustache new file mode 100644 index 00000000..7b65841f --- /dev/null +++ b/ee/cli/templates/wpsubdir.mustache @@ -0,0 +1,10 @@ +# WPSUBDIRECTORY NGINX CONFIGURATION +# DO NOT MODIFY, ALL CHNAGES LOST AFTER UPDATE EasyEngine (ee) +if (!-e $request_filename) { + # Redirect wp-admin to wp-admin/ + rewrite /wp-admin$ $scheme://$host$uri/ permanent; + # Redirect wp-* files/folders + rewrite ^(/[^/]+)?(/wp-.*) $2 last; + # Redirect other php files + rewrite ^(/[^/]+)?(/.*\.php) $2 last; +} diff --git a/ee/core/__init__.py b/ee/core/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ee/core/addswap.py b/ee/core/addswap.py new file mode 100644 index 00000000..717d67a1 --- /dev/null +++ b/ee/core/addswap.py @@ -0,0 +1,27 @@ +"""EasyEngine SWAP creation""" +from ee.core.variables import EEVariables +from ee.core.shellexec import EEShellExec +from ee.core.fileutils import EEFileUtils +from ee.core.logging import Log + + +class EESwap(): + """Manage Swap""" + + def __init__(): + """Initialize """ + pass + + def add(self): + """Swap addition with EasyEngine""" + if EEVariables.ee_ram < 512: + if EEVariables.ee_swap < 1000: + Log.info(self, "Adding SWAP") + EEShellExec.cmd_exec(self, "dd if=/dev/zero of=/ee-swapfile " + "bs=1024 count=1048k") + EEShellExec.cmd_exec(self, "mkswap /ee-swapfile") + EEFileUtils.chown(self, "/ee-swapfile", "root", "root") + EEFileUtils.chmod(self, "/ee-swapfile", 0o600) + EEShellExec.cmd_exec(self, "swapon /ee-swapfile") + with open("/etc/fstab", "a") as swap_file: + swap_file.write("/ee-swapfile\tnone\tswap\tsw\t0 0") diff --git a/ee/core/apt_repo.py b/ee/core/apt_repo.py new file mode 100644 index 00000000..d3e82ed9 --- /dev/null +++ b/ee/core/apt_repo.py @@ -0,0 +1,78 @@ +"""EasyEngine packages repository operations""" +from ee.core.shellexec import EEShellExec +from ee.core.variables import EEVariables +import os + + +class EERepo(): + """Manage Repositories""" + + def __init__(self): + """Initialize """ + pass + + def add(self, repo_url=None, ppa=None): + """ + This function used to add apt repositories and or ppa's + If repo_url is provided adds repo file to + /etc/apt/sources.list.d/ + If ppa is provided add apt-repository using + add-apt-repository + command. + """ + + if repo_url is not None: + repo_file_path = ("/etc/apt/sources.list.d/" + + EEVariables().ee_repo_file) + try: + if not os.path.isfile(repo_file_path): + with open(repo_file_path, "a") as repofile: + repofile.write(repo_url) + repofile.write('\n') + repofile.close() + elif repo_url not in open(repo_file_path).read(): + with open(repo_file_path, "a") as repofile: + repofile.write(repo_url) + repofile.write('\n') + repofile.close() + return True + except IOError as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "File I/O error.") + except Exception as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "Unable to add repo") + if ppa is not None: + if EEVariables.ee_platform_distro == 'squeeze': + print("Cannot add repo for {distro}" + .format(distro=EEVariables.ee_platform_distro)) + else: + EEShellExec.cmd_exec(self, "add-apt-repository -y " + "'{ppa_name}'" + .format(ppa_name=ppa)) + + def remove(self, ppa=None): + """ + This function used to remove ppa's + If ppa is provided adds repo file to + /etc/apt/sources.list.d/ + command. + """ + EEShellExec.cmd_exec(self, "add-apt-repository -y " + "--remove '{ppa_name}'" + .format(ppa_name=repo_url)) + + def add_key(self, keyids, keyserver=None): + """ + This function adds imports repository keys from keyserver. + default keyserver is hkp://keys.gnupg.net + user can provide other keyserver with keyserver="hkp://xyz" + """ + if keyserver is None: + EEShellExec.cmd_exec(self, "gpg --keyserver {serv}" + .format(serv=(keyserver or + "hkp://keys.gnupg.net")) + + " --recv-keys {key}".format(key=keyids)) + EEShellExec.cmd_exec(self, "gpg -a --export --armor {0}" + .format(keyids) + + " | apt-key add - ") diff --git a/ee/core/aptget.py b/ee/core/aptget.py new file mode 100644 index 00000000..b33b3d1d --- /dev/null +++ b/ee/core/aptget.py @@ -0,0 +1,198 @@ +"""EasyEngine package installation using apt-get module.""" +import apt +import apt_pkg +import sys +from ee.core.logging import Log +from sh import apt_get + + +class EEAptGet(): + """Generic apt-get intialisation""" + + def update(self): + """ + Similar to `apt-get upgrade` + """ + try: + apt_cache = apt.cache.Cache() + import sys + orig_out = sys.stdout + sys.stdout = open(self.app.config.get('log.logging', 'file'), 'a') + apt_cache.update(apt.progress.text.AcquireProgress()) + sys.stdout = orig_out + # success = (apt_cache.commit( + # apt.progress.text.AcquireProgress(), + # apt.progress.base.InstallProgress())) + # #apt_cache.close() + # return success + except AttributeError as e: + Log.error(self, 'AttributeError: ' + str(e)) + except Exception as e: + Log.debug(self, 'SystemError: ' + str(e)) + Log.error(self, 'Unable to Fetch update') + + def dist_upgrade(): + """ + Similar to `apt-get upgrade` + """ + try: + apt_cache = apt.cache.Cache() + apt_cache.update() + apt_cache.open(None) + apt_cache.upgrade(True) + success = (apt_cache.commit( + apt.progress.text.AcquireProgress(), + apt.progress.base.InstallProgress())) + #apt_cache.close() + return success + except AttributeError as e: + Log.error(self, 'AttributeError: ' + str(e)) + except FetchFailedException as e: + Log.debug(self, 'SystemError: ' + str(e)) + Log.error(self, 'Unable to Fetch update') + + def install(self, packages): + """ + Similar to `apt-get install` + """ + apt_pkg.init() + # #apt_pkg.PkgSystemLock() + global apt_cache + apt_cache = apt.cache.Cache() + + def install_package(self, package_name): + pkg = apt_cache[package_name.strip()] + if package_name.strip() in apt_cache: + if pkg.is_installed: + #apt_pkg.PkgSystemUnLock() + Log.debug(self, 'Trying to install a package that ' + 'is already installed (' + + package_name.strip() + ')') + #apt_cache.close() + return False + else: + try: + # print(pkg.name) + pkg.mark_install() + except Exception as e: + Log.debug(self, str(e)) + Log.error(self, str(e)) + else: + #apt_cache.close() + Log.error(self, 'Unknown package selected (' + + package_name.strip() + ')') + + for package in packages: + if not install_package(self, package): + continue + + if apt_cache.install_count > 0: + try: + #apt_pkg.PkgSystemUnLock() + orig_out = sys.stdout + sys.stdout = open(self.app.config.get('log.logging', 'file'), + 'a') + result = apt_cache.commit(apt.progress.text.AcquireProgress(), + apt.progress.base.InstallProgress()) + sys.stdout = orig_out + #apt_cache.close() + return result + except SystemError as e: + Log.debug(self, 'SystemError: ' + str(e)) + Log.error(self, 'SystemError: ' + str(e)) + #apt_cache.close() + except Exception as e: + Log.debug(self, str(e)) + Log.error(self, str(e)) + + def remove(self, packages, auto=False, purge=False): + """ + Similar to `apt-get remove/purge` + purge packages if purge=True + """ + apt_pkg.init() + # apt_pkg.PkgSystemLock() + global apt_cache + apt_cache = apt.cache.Cache() + + def remove_package(self, package_name, purge=False): + pkg = apt_cache[package_name.strip()] + if package_name.strip() in apt_cache: + if not pkg.is_installed: + # apt_pkg.PkgSystemUnLock() + Log.debug(self, 'Trying to uninstall a package ' + 'that is not installed (' + + package_name.strip() + ')') + return False + else: + try: + # print(pkg.name) + pkg.mark_delete(purge) + except SystemError as e: + Log.debug(self, 'SystemError: ' + str(e)) + return False + else: + # apt_cache.close() + Log.error(self, 'Unknown package selected (' + + package_name.strip() + ')') + + for package in packages: + if not remove_package(self, package, purge=purge): + continue + + if apt_cache.delete_count > 0: + try: + # apt_pkg.PkgSystemUnLock() + orig_out = sys.stdout + sys.stdout = open(self.app.config.get('log.logging', 'file'), + 'a') + result = apt_cache.commit(apt.progress.text.AcquireProgress(), + apt.progress.base.InstallProgress()) + sys.stdout = orig_out + # apt_cache.close() + return result + except SystemError as e: + Log.debug(self, 'SystemError: ' + str(e)) + return False + except Exception as e: + Log.debug(self, str(e)) + Log.error(self, str(e)) + # apt_cache.close() + + def auto_clean(self): + """ + Similar to `apt-get autoclean` + """ + try: + orig_out = sys.stdout + sys.stdout = open(self.app.config.get('log.logging', 'file'), 'a') + apt_get.autoclean("-y") + sys.stdout = orig_out + except ErrorReturnCode as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "Unable to apt-get autoclean") + + def auto_remove(self): + """ + Similar to `apt-get autoremove` + """ + try: + Log.debug(self, "Running apt-get autoremove") + apt_get.autoremove("-y") + except ErrorReturnCode as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "Unable to apt-get autoremove") + + def is_installed(self, package_name): + """ + Checks if package is available in cache and is installed or not + returns True if installed otherwise returns False + """ + apt_cache = apt.cache.Cache() + apt_cache.open() + if (package_name.strip() in apt_cache and + apt_cache[package_name.strip()].is_installed): + # apt_cache.close() + return True + # apt_cache.close() + return False diff --git a/ee/core/checkfqdn.py b/ee/core/checkfqdn.py new file mode 100644 index 00000000..915b2e24 --- /dev/null +++ b/ee/core/checkfqdn.py @@ -0,0 +1,23 @@ +from ee.core.shellexec import EEShellExec +from ee.core.variables import EEVariables +import os + + +def check_fqdn(self, ee_host): + """FQDN check with EasyEngine, for mail server hostname must be FQDN""" + #ee_host=os.popen("hostname -f | tr -d '\n'").read() + if '.' in ee_host: + EEVariables.ee_fqdn = ee_host + with open('/etc/hostname', 'w') as hostfile: + hostfile.write(ee_host) + + EEShellExec.cmd_exec(self, "sed -i \"1i\\127.0.0.1 {0}\" /etc/hosts" + .format(ee_host)) + if EEVariables.ee_platform_distro == 'debian': + EEShellExec.cmd_exec(self, "/etc/init.d/hostname.sh start") + else: + EEShellExec.cmd_exec(self, "service hostname restart") + + else: + ee_host = input("Enter hostname [fqdn]:") + check_fqdn(self, ee_host) diff --git a/ee/core/database.py b/ee/core/database.py new file mode 100644 index 00000000..573ee099 --- /dev/null +++ b/ee/core/database.py @@ -0,0 +1,24 @@ +"""EasyEngine generic database creation module""" +from sqlalchemy import create_engine +from sqlalchemy.orm import scoped_session, sessionmaker +from sqlalchemy.ext.declarative import declarative_base +from ee.core.variables import EEVariables + +# db_path = self.app.config.get('site', 'db_path') +engine = create_engine(EEVariables.ee_db_uri, convert_unicode=True) +db_session = scoped_session(sessionmaker(autocommit=False, + autoflush=False, + bind=engine)) +Base = declarative_base() +Base.query = db_session.query_property() + + +def init_db(): + """ + Initializes and creates all tables from models into the database + """ + # import all modules here that might define models so that + # they will be registered properly on the metadata. Otherwise + # you will have to import them first before calling init_db() + import ee.core.models + Base.metadata.create_all(bind=engine) diff --git a/ee/core/domainvalidate.py b/ee/core/domainvalidate.py new file mode 100644 index 00000000..a9400c9a --- /dev/null +++ b/ee/core/domainvalidate.py @@ -0,0 +1,24 @@ +"""EasyEngine domain validation module.""" +from urllib.parse import urlparse + + +def ValidateDomain(url): + """ + This function returns domain name removing http:// and https:// + returns domain name only with or without www as user provided. + """ + + # Check if http:// or https:// present remove it if present + domain_name = url.split('/') + if 'http:' in domain_name or 'https:' in domain_name: + domain_name = domain_name[2] + else: + domain_name = domain_name[0] + www_domain_name = domain_name.split('.') + final_domain = '' + if www_domain_name[0] == 'www': + final_domain = '.'.join(www_domain_name[1:]) + return final_domain + else: + final_domain = domain_name + return (final_domain, domain_name) diff --git a/ee/core/download.py b/ee/core/download.py new file mode 100644 index 00000000..c0796658 --- /dev/null +++ b/ee/core/download.py @@ -0,0 +1,43 @@ +"""EasyEngine download core classes.""" +import urllib.request +import urllib.error +import os +from ee.core.logging import Log + + +class EEDownload(): + """Method to download using urllib""" + def __init__(): + pass + + def download(self, packages): + """Download packages, packges must be list in format of + [url, path, package name]""" + for package in packages: + url = package[0] + filename = package[1] + pkg_name = package[2] + try: + directory = os.path.dirname(filename) + if not os.path.exists(directory): + os.makedirs(directory) + Log.info(self, "Downloading {0:20}".format(pkg_name), end=' ') + urllib.request.urlretrieve(url, filename) + Log.info(self, "{0}".format("[" + Log.ENDC + "Done" + + Log.OKBLUE + "]")) + except urllib.error.URLError as e: + Log.debug(self, "[{err}]".format(err=str(e.reason))) + Log.error(self, "Unable to donwload file, {0}" + .format(filename)) + return False + except urllib.error.HTTPError as e: + Log.error(self, "Package download failed. {0}" + .format(pkg_name)) + Log.debug(self, "[{err}]".format(err=str(e.reason))) + return False + except urllib.error.ContentTooShortError as e: + Log.debug(self, "{0}{1}".format(e.errno, e.strerror)) + Log.error(self, "Package download failed. The amount of the" + " downloaded data is less than " + "the expected amount \{0} ".format(pkg_name)) + return False diff --git a/ee/core/exc.py b/ee/core/exc.py new file mode 100644 index 00000000..06579f41 --- /dev/null +++ b/ee/core/exc.py @@ -0,0 +1,26 @@ +"""EasyEngine exception classes.""" + + +class EEError(Exception): + """Generic errors.""" + def __init__(self, msg): + Exception.__init__(self) + self.msg = msg + + def __str__(self): + return self.msg + + +class EEConfigError(EEError): + """Config related errors.""" + pass + + +class EERuntimeError(EEError): + """Generic runtime errors.""" + pass + + +class EEArgumentError(EEError): + """Argument related errors.""" + pass diff --git a/ee/core/extract.py b/ee/core/extract.py new file mode 100644 index 00000000..d8db19c5 --- /dev/null +++ b/ee/core/extract.py @@ -0,0 +1,21 @@ +"""EasyEngine extarct core classes.""" +import tarfile +import os +from ee.core.logging import Log + + +class EEExtract(): + """Method to extract from tar.gz file""" + + def extract(self, file, path): + """Function to extract tar.gz file""" + try: + tar = tarfile.open(file) + tar.extractall(path=path) + tar.close() + os.remove(file) + return True + except tarfile.TarError as e: + Log.debug(self, "{0}{1}".format(e.errno, e.strerror)) + Log.error(self, 'Unable to extract file \{0}'.format(file)) + return False diff --git a/ee/core/fileutils.py b/ee/core/fileutils.py new file mode 100644 index 00000000..5e8a4b68 --- /dev/null +++ b/ee/core/fileutils.py @@ -0,0 +1,224 @@ +"""EasyEngine file utils core classes.""" +import shutil +import os +import sys +import glob +import shutil +import pwd +import fileinput +from ee.core.logging import Log + + +class EEFileUtils(): + """Utilities to operate on files""" + def __init__(): + pass + + def remove(self, filelist): + """remove files from given path""" + for file in filelist: + if os.path.isfile(file): + Log.info(self, "Removing {0:65}".format(file), end=' ') + os.remove(file) + Log.info(self, "{0}".format("[" + Log.ENDC + "Done" + + Log.OKBLUE + "]")) + Log.debug(self, 'file Removed') + if os.path.isdir(file): + try: + Log.info(self, "Removing {0:65}".format(file), end=' ') + shutil.rmtree(file) + Log.info(self, "{0}".format("[" + Log.ENDC + "Done" + + Log.OKBLUE + "]")) + except shutil.Error as e: + Log.debug(self, "{err}".format(err=str(e.reason))) + Log.error(self, 'Unable to Remove file ') + + def create_symlink(self, paths, errormsg=''): + """ + Create symbolic links provided in list with first as source + and second as destination + """ + src = paths[0] + dst = paths[1] + if not os.path.islink(dst): + try: + os.symlink(src, dst) + except Exception as e: + Log.debug(self, "{0}{1}".format(e.errno, e.strerror)) + Log.error(self, "Unable to create symbolic link ...\n ") + else: + Log.debug(self, "Destination: {0} exists".format(dst)) + + def remove_symlink(self, filepath): + """ + Removes symbolic link for the path provided with filepath + """ + try: + os.unlink(filepath) + except Exception as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "Unable to reomove symbolic link ...\n") + + def copyfile(self, src, dest): + """ + Copies files: + src : source path + dest : destination path + """ + try: + shutil.copy2(src, dest) + except shutil.Error as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, 'Unable to copy file from {0} to {1}' + .format(src, dest)) + except IOError as e: + Log.debug(self, "{e}".format(e.strerror)) + Log.error(self, "Unable to copy file from {0} to {1}" + .fromat(src, dest)) + + def searchreplace(self, fnm, sstr, rstr): + """ + Search replace strings in file + fnm : filename + sstr: search string + rstr: replace string + """ + try: + for line in fileinput.input(fnm, inplace=True): + print(line.replace(sstr, rstr), end='') + fileinput.close() + except Exception as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "Unable to search {0} and replace {1} {2}" + .format(fnm, sstr, rstr)) + + def mvfile(self, src, dst): + """ + Moves file from source path to destination path + src : source path + dst : Destination path + """ + try: + Log.debug(self, "Moving file from {0} to {1}".format(src, dst)) + shutil.move(src, dst) + except Exception as e: + Log.debug(self, "{err}".format(err=e)) + Log.error(self, 'Unable to move file from {0} to {1}' + .format(src, dst)) + + def chdir(self, path): + """ + Change Directory to path specified + Path : path for destination directory + """ + try: + os.chdir(path) + except OSError as e: + Log.debug(self, "{err}".format(err=e.strerror)) + Log.error(self, 'Unable to Change Directory {0}'.format(path)) + + def chown(self, path, user, group, recursive=False): + """ + Change Owner for files + change owner for file with path specified + user: username of owner + group: group of owner + recursive: if recursive is True change owner for all + files in directory + """ + userid = pwd.getpwnam(user)[2] + groupid = pwd.getpwnam(user)[3] + try: + if recursive: + for root, dirs, files in os.walk(path): + for d in dirs: + os.chown(os.path.join(root, d), userid, + groupid) + for f in files: + os.chown(os.path.join(root, f), userid, + groupid) + else: + os.chown(path, userid, groupid) + except shutil.Error as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "Unable to change owner : {0}".format(path)) + except Exception as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "Unable to change owner : {0} ".format(path)) + + def chmod(self, path, perm, recursive=False): + """ + Changes Permission for files + path : file path permission to be changed + perm : permissions to be given + recursive: change permission recursively for all files + """ + try: + if recursive: + for root, dirs, files in os.walk(path): + for d in dirs: + os.chmod(os.path.join(root, d), perm) + for f in files: + os.chmod(os.path.join(root, f), perm) + else: + os.chmod(path, perm) + except OSError as e: + Log.debug(self, "{0}".format(e.strerror)) + Log.error(self, "Unable to change owner : {0}".format(path)) + + def mkdir(self, path): + """ + create directories. + path : path for directory to be created + Similar to `mkdir -p` + """ + try: + os.makedirs(path) + except OSError as e: + Log.debug(self, "{0}".format(e.strerror)) + Log.error(self, "Unable to create directory {0} ".format(path)) + + def isexist(self, path): + """ + Check if file exist on given path + """ + try: + if os.path.exists(path): + return (True) + else: + return (False) + except OSError as e: + Log.debug(self, "{0}".format(e.strerror)) + Log.error(self, "Unable to check path {0}".format(path)) + + def grep(self, fnm, sstr): + """ + Searches for string in file and returns the matched line. + """ + try: + for line in open(fnm): + if sstr in line: + return line + except OSError as e: + Log.debug(self, "{0}".format(e.strerror)) + Log.error(self, "Unable to Search string {0} in {1}" + .format(sstr, fnm)) + + def rm(self, path): + """ + Remove files + """ + if EEFileUtils.isexist(self, path): + try: + if os.path.isdir(path): + shutil.rmtree(path) + else: + os.remove(path) + except shutil.Error as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "Unable to remove directory : {0} " + .format(path)) + except OSError as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "Unable to remove file : {0} " + .format(path)) diff --git a/ee/core/git.py b/ee/core/git.py new file mode 100644 index 00000000..5d587c81 --- /dev/null +++ b/ee/core/git.py @@ -0,0 +1,57 @@ +"""EasyEngine GIT module""" +from sh import git, ErrorReturnCode +from ee.core.logging import Log +import os + + +class EEGit: + """Intialization of core variables""" + def ___init__(): + # TODO method for core variables + pass + + def add(self, paths, msg="Intializating"): + """ + Initializes Directory as repository if not already git repo. + and adds uncommited changes automatically + """ + for path in paths: + global git + git = git.bake("--git-dir={0}/.git".format(path), + "--work-tree={0}".format(path)) + if os.path.isdir(path): + if not os.path.isdir(path+"/.git"): + try: + Log.debug(self, "EEGit: git init at {0}" + .format(path)) + git.init(path) + except ErrorReturnCode as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "Unable to git init at {0}" + .format(path)) + status = git.status("-s") + if len(status.splitlines()) > 0: + try: + Log.debug(self, "EEGit: git commit at {0}" + .format(path)) + git.add("--all") + git.commit("-am {0}".format(msg)) + except ErrorReturnCode as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "Unable to git commit at {0} " + .format(path)) + else: + Log.debug(self, "EEGit: Path {0} not present".format(path)) + + def checkfilestatus(self, repo, filepath): + """ + Checks status of file, If its tracked or untracked. + """ + global git + git = git.bake("--git-dir={0}/.git".format(repo), + "--work-tree={0}".format(repo)) + status = git.status("-s", "{0}".format(filepath)) + if len(status.splitlines()) > 0: + return True + else: + return False diff --git a/ee/core/logging.py b/ee/core/logging.py new file mode 100644 index 00000000..a02d47c6 --- /dev/null +++ b/ee/core/logging.py @@ -0,0 +1,43 @@ +"""EasyEngine log module""" + + +class Log: + """ + Logs messages with colors for different messages + according to functions + """ + HEADER = '\033[95m' + OKBLUE = '\033[94m' + OKGREEN = '\033[92m' + WARNING = '\033[93m' + FAIL = '\033[91m' + ENDC = '\033[0m' + BOLD = '\033[1m' + UNDERLINE = '\033[4m' + + def error(self, msg): + """ + Logs error into log file + """ + print(Log.FAIL + msg + Log.ENDC) + self.app.log.error(Log.FAIL + msg + Log.ENDC) + self.app.close(1) + + def info(self, msg, end='\n'): + """ + Logs info messages into log file + """ + print(Log.OKBLUE + msg + Log.ENDC, end=end) + self.app.log.info(Log.OKBLUE + msg + Log.ENDC) + + def warn(self, msg): + """ + Logs warning into log file + """ + self.app.log.warn(Log.BOLD + msg + Log.ENDC) + + def debug(self, msg): + """ + Logs debug messages into log file + """ + self.app.log.debug(Log.HEADER + msg + Log.ENDC) diff --git a/ee/core/logwatch.py b/ee/core/logwatch.py new file mode 100644 index 00000000..818f50d3 --- /dev/null +++ b/ee/core/logwatch.py @@ -0,0 +1,195 @@ + +""" +Real time log files watcher supporting log rotation. +""" + +import os +import time +import errno +import stat +from ee.core.logging import Log + + +class LogWatcher(object): + """Looks for changes in all files of a directory. + This is useful for watching log file changes in real-time. + It also supports files rotation. + + Example: + + >>> def callback(filename, lines): + ... print filename, lines + ... + >>> l = LogWatcher("/var/www/example.com/logs", callback) + >>> l.loop() + """ + + def __init__(self, filelist, callback, extensions=["log"], tail_lines=0): + """Arguments: + + (str) @folder: + the folder to watch + + (callable) @callback: + a function which is called every time a new line in a + file being watched is found; + this is called with "filename" and "lines" arguments. + + (list) @extensions: + only watch files with these extensions + + (int) @tail_lines: + read last N lines from files being watched before starting + """ + self.files_map = {} + self.filelist = filelist + self.callback = callback + # self.folder = os.path.realpath(folder) + self.extensions = extensions + # assert (os.path.isdir(self.folder), "%s does not exists" + # % self.folder) + for file in self.filelist: + assert (os.path.isfile(file)) + assert callable(callback) + self.update_files() + # The first time we run the script we move all file markers at EOF. + # In case of files created afterwards we don't do this. + for id, file in list(iter(self.files_map.items())): + file.seek(os.path.getsize(file.name)) # EOF + if tail_lines: + lines = self.tail(file.name, tail_lines) + if lines: + self.callback(file.name, lines) + + def __del__(self): + self.close() + + def loop(self, interval=0.1, async=False): + """Start the loop. + If async is True make one loop then return. + """ + while 1: + self.update_files() + for fid, file in list(iter(self.files_map.items())): + self.readfile(file) + if async: + return + time.sleep(interval) + + def log(self, line): + """Log when a file is un/watched""" + print(line) + + # def listdir(self): + # """List directory and filter files by extension. + # You may want to override this to add extra logic or + # globbling support. + # """ + # ls = os.listdir(self.folder) + # if self.extensions: + # return ([x for x in ls if os.path.splitext(x)[1][1:] + # in self.extensions]) + # else: + # return ls + + @staticmethod + def tail(fname, window): + """Read last N lines from file fname.""" + try: + f = open(fname, 'r') + except IOError as err: + if err.errno == errno.ENOENT: + return [] + else: + raise + else: + BUFSIZ = 1024 + f.seek(0, os.SEEK_END) + fsize = f.tell() + block = -1 + data = "" + exit = False + while not exit: + step = (block * BUFSIZ) + if abs(step) >= fsize: + f.seek(0) + exit = True + else: + f.seek(step, os.SEEK_END) + data = f.read().strip() + if data.count('\n') >= window: + break + else: + block -= 1 + return data.splitlines()[-window:] + + def update_files(self): + ls = [] + for name in self.filelist: + absname = os.path.realpath(os.path.join(name)) + try: + st = os.stat(absname) + except EnvironmentError as err: + if err.errno != errno.ENOENT: + raise + else: + if not stat.S_ISREG(st.st_mode): + continue + fid = self.get_file_id(st) + ls.append((fid, absname)) + + # check existent files + for fid, file in list(iter(self.files_map.items())): + # next(iter(graph.items())) + try: + st = os.stat(file.name) + except EnvironmentError as err: + if err.errno == errno.ENOENT: + self.unwatch(file, fid) + else: + raise + else: + if fid != self.get_file_id(st): + # same name but different file (rotation); reload it. + self.unwatch(file, fid) + self.watch(file.name) + + # add new ones + for fid, fname in ls: + if fid not in self.files_map: + self.watch(fname) + + def readfile(self, file): + lines = file.readlines() + if lines: + self.callback(file.name, lines) + + def watch(self, fname): + try: + file = open(fname, "r") + fid = self.get_file_id(os.stat(fname)) + except EnvironmentError as err: + if err.errno != errno.ENOENT: + raise + else: + self.log("watching logfile %s" % fname) + self.files_map[fid] = file + + def unwatch(self, file, fid): + # file no longer exists; if it has been renamed + # try to read it for the last time in case the + # log rotator has written something in it. + lines = self.readfile(file) + self.log("un-watching logfile %s" % file.name) + del self.files_map[fid] + if lines: + self.callback(file.name, lines) + + @staticmethod + def get_file_id(st): + return "%xg%x" % (st.st_dev, st.st_ino) + + def close(self): + for id, file in list(iter(self.files_map.items())): + file.close() + self.files_map.clear() diff --git a/ee/core/models.py b/ee/core/models.py new file mode 100644 index 00000000..2592a26c --- /dev/null +++ b/ee/core/models.py @@ -0,0 +1,43 @@ +from sqlalchemy import Column, DateTime, String, Integer, Boolean, func +from ee.core.database import Base + + +class SiteDB(Base): + """ + Databse model for site table + """ + __tablename__ = 'sites' + id = Column(Integer, primary_key=True) + sitename = Column(String, unique=True) + + site_type = Column(String) + cache_type = Column(String) + site_path = Column(String) + + # Use default=func.now() to set the default created time + # of a site to be the current time when a + # Site record was created + + created_on = Column(DateTime, default=func.now()) + is_enabled = Column(Boolean, unique=False, default=True, nullable=False) + is_ssl = Column(Boolean, unique=False, default=False) + storage_fs = Column(String) + storage_db = Column(String) + + def __init__(self, sitename=None, site_type=None, cache_type=None, + site_path=None, site_enabled=None, + is_ssl=None, storage_fs=None, storage_db=None): + self.sitename = sitename + self.site_type = site_type + self.cache_type = cache_type + self.site_path = site_path + self.is_enabled = site_enabled + self.is_ssl = is_ssl + self.storage_fs = storage_fs + self.storage_db = storage_db + + # def __repr__(self): + # return '' % (self.site_type) + # + # def getType(self): + # return '%r>' % (self.site_type) diff --git a/ee/core/mysql.py b/ee/core/mysql.py new file mode 100644 index 00000000..d288dab8 --- /dev/null +++ b/ee/core/mysql.py @@ -0,0 +1,62 @@ +"""EasyEngine MySQL core classes.""" +import pymysql +import configparser +from os.path import expanduser +import sys +from ee.core.logging import Log + + +class EEMysql(): + """Method for MySQL connection""" + + def execute(self, statement, errormsg=''): + """Get login details from ~/.my.cnf & Execute MySQL query""" + config = configparser.RawConfigParser() + cnfpath = expanduser("~")+"/.my.cnf" + if [cnfpath] == config.read(cnfpath): + user = config.get('client', 'user') + passwd = config.get('client', 'password') + try: + host = config.get('client', 'host') + except configparser.NoOptionError as e: + host = 'localhost' + + try: + port = config.get('client', 'port') + except configparser.NoOptionError as e: + port = '3306' + + try: + conn = pymysql.connect(host=host, port=int(port), + user=user, passwd=passwd) + cur = conn.cursor() + except Exception as e: + if errormsg: + Log.debug(self, '{0}' + .format(e)) + Log.error(self, '{0}' + .format(errormsg)) + else: + Log.debug(self, '{0}' + .format(e)) + Log.error(self, 'Unable to connect to database: {0}' + .format(e)) + + try: + Log.debug(self, "Executing MySQL statement: {0}".format(statement)) + cur.execute(statement) + except Exception as e: + cur.close() + conn.close() + Log.debug(self, "{0}".format(e)) + if not errormsg: + Log.error(self, 'Unable to execute statement') + else: + Log.error(self, '{0}'.format(errormsg)) + + cur.close() + conn.close() + +# def __del__(self): +# self.cur.close() +# self.conn.close() diff --git a/ee/core/services.py b/ee/core/services.py new file mode 100644 index 00000000..a32a7ecf --- /dev/null +++ b/ee/core/services.py @@ -0,0 +1,135 @@ +"""EasyEngine service start/stop/restart module.""" +import os +import sys +import subprocess +from subprocess import Popen +from ee.core.logging import Log +import pystache + + +class EEService(): + """Intialization for service""" + def ___init__(): + pass + + def start_service(self, service_name): + """ + start service + Similar to `service xyz start` + """ + try: + Log.info(self, "Start : {0:10}" .format(service_name), end='') + retcode = subprocess.getstatusoutput('service {0} start' + .format(service_name)) + if retcode[0] == 0: + Log.info(self, "[" + Log.ENDC + "OK" + Log.OKBLUE + "]") + return True + else: + Log.debug(self, "{0}".format(retcode[1])) + Log.info(self, "[" + Log.FAIL + "Failed" + Log.OKBLUE+"]") + return False + except OSError as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "\nFailed to start service {0}" + .format(service_name)) + + def stop_service(self, service_name): + """ + Stop service + Similar to `service xyz stop` + """ + try: + Log.info(self, "Stop : {0:10}" .format(service_name), end='') + retcode = subprocess.getstatusoutput('service {0} stop' + .format(service_name)) + if retcode[0] == 0: + Log.info(self, "[" + Log.ENDC + "OK" + Log.OKBLUE + "]") + return True + else: + Log.debug(self, "{0}".format(retcode[1])) + Log.info(self, "[" + Log.FAIL + "Failed" + Log.OKBLUE+"]") + return False + except OSError as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "\nFailed to stop service : {0}" + .format(service_name)) + + def restart_service(self, service_name): + """ + Restart service + Similar to `service xyz restart` + """ + try: + Log.info(self, "Restart : {0:10}".format(service_name), end='') + retcode = subprocess.getstatusoutput('service {0} restart' + .format(service_name)) + if retcode[0] == 0: + Log.info(self, "[" + Log.ENDC + "OK" + Log.OKBLUE + "]") + return True + else: + Log.debug(self, "{0}".format(retcode[1])) + Log.info(self, "[" + Log.FAIL + "Failed" + Log.OKBLUE+"]") + return False + except OSError as e: + Log.debug(self, "{0} {1}".format(e.errno, e.strerror)) + Log.error(self, "\nFailed to restart service : {0}" + .format(service_name)) + + def reload_service(self, service_name): + """ + Stop service + Similar to `service xyz stop` + """ + try: + if service_name in ['nginx', 'php5-fpm']: + Log.info(self, "Reload : {0:10}".format(service_name), + end='') + retcode = subprocess.getstatusoutput('{0} -t &&' + ' service {0} reload' + .format(service_name)) + if retcode[0] == 0: + # print(retcode[0]) + # subprocess.getstatusoutput('service {0} reload' + # .format(service_name)) + Log.info(self, "[" + Log.ENDC + "OK" + Log.OKBLUE + + "]") + return True + else: + Log.debug(self, "{0}".format(retcode[1])) + Log.info(self, "[" + Log.FAIL + "Failed" + + Log.OKBLUE+"]") + return False + Log.info(self, "Reload : {0:10}".format(service_name), end='') + retcode = subprocess.getstatusoutput('service {0} reload' + .format(service_name)) + if retcode[0] == 0: + Log.info(self, "[" + Log.ENDC + "OK" + Log.OKBLUE + "]") + return True + else: + Log.debug(self, "{0}".format(retcode[1])) + Log.info(self, "[" + Log.FAIL + "Failed" + Log.OKBLUE+"]") + return False + except OSError as e: + Log.debug(self, "{0}".format(e)) + Log.error(self, "\nFailed to reload service {0}" + .format(service_name)) + + def get_service_status(self, service_name): + try: + is_exist = subprocess.getstatusoutput('which {0}' + .format(service_name)) + if is_exist[0] == 0: + retcode = subprocess.getstatusoutput('service {0} status' + .format(service_name)) + if retcode[0] == 0: + return True + else: + Log.debug(self, "{0}".format(retcode[1])) + return False + else: + return False + except OSError as e: + Log.debug(self, "{0}{1}".format(e.errno, e.strerror)) + Log.error(self, "Unable to get services status of {0}" + .format(service_name)) + return False diff --git a/ee/core/shellexec.py b/ee/core/shellexec.py new file mode 100644 index 00000000..112fed9a --- /dev/null +++ b/ee/core/shellexec.py @@ -0,0 +1,51 @@ +"""EasyEngine shell executaion functions.""" +from subprocess import Popen +from ee.core.logging import Log +import os +import sys +import subprocess + + +class EEShellExec(): + """Method to run shell commands""" + def __init__(): + pass + + def cmd_exec(self, command, errormsg='', log=True): + """Run shell command from Python""" + try: + if log: + Log.debug(self, "Running command: {0}".format(command)) + retcode = subprocess.getstatusoutput(command) + if retcode[0] == 0: + return True + else: + Log.debug(self, retcode[1]) + return False + except OSError as e: + if errormsg: + Log.error(self, errormsg) + else: + Log.debug(self, "{0}".format(e)) + Log.error(self, "Unable to execute command {0}" + .format(command)) + except Exception as e: + if errormsg: + Log.error(self, errormsg) + else: + Log.debug(self, "{0}".format(e)) + Log.error(self, "Unable to execute command {0}" + .format(command)) + + def invoke_editor(self, filepath, errormsg=''): + """ + Open files using sensible editor + """ + try: + subprocess.call(['sensible-editor', filepath]) + except OSError as e: + if errormsg: + Log.error(self, errormsg) + else: + Log.debug(self, "{0}{1}".format(e.errno, e.strerror)) + Log.error(self, "Unable to edit file {0}".format(filepath)) diff --git a/ee/core/variables.py b/ee/core/variables.py new file mode 100644 index 00000000..dfd820a2 --- /dev/null +++ b/ee/core/variables.py @@ -0,0 +1,125 @@ +"""EasyEngine core variable module""" +import platform +import socket +import configparser +import os +import sys +import psutil +import datetime + + +class EEVariables(): + """Intialization of core variables""" + + # EasyEngine version + ee_version = "3.0.0" + + # EasyEngine packages versions + ee_wp_cli = "0.18.0" + ee_adminer = "4.1.0" + ee_roundcube = "1.1.0" + ee_vimbadmin = "3.0.11" + + # Current date and time of System + ee_date = datetime.datetime.now().strftime('%d%b%Y%H%M%S') + + # EasyEngine core variables + ee_platform_distro = platform.linux_distribution()[0] + ee_platform_version = platform.linux_distribution()[1] + ee_platform_codename = os.popen("lsb_release -sc | tr -d \'\\n\'").read() + + # Get FQDN of system + ee_fqdn = socket.getfqdn() + + # EasyEngien default webroot path + ee_webroot = '/var/www/' + + # PHP5 user + ee_php_user = 'www-data' + + # Get git user name and EMail + config = configparser.ConfigParser() + config.read(os.path.expanduser("~")+'/.gitconfig') + try: + ee_user = config['user']['name'] + ee_email = config['user']['email'] + except Exception as e: + ee_user = input("Enter your name: ") + ee_email = input("Enter your email: ") + os.system("git config --global user.name {0}".format(ee_user)) + os.system("git config --global user.email {0}".format(ee_email)) + + # Get System RAM and SWAP details + ee_ram = psutil.virtual_memory().total / (1024 * 1024) + ee_swap = psutil.swap_memory().total / (1024 * 1024) + + # MySQL hostname + ee_mysql_host = "" + config = configparser.RawConfigParser() + cnfpath = os.path.expanduser("~")+"/.my.cnf" + if [cnfpath] == config.read(cnfpath): + try: + ee_mysql_host = config.get('client', 'host') + except configparser.NoOptionError as e: + ee_mysql_host = "localhost" + else: + ee_mysql_host = "localhost" + + # EasyEngine stack installation varibales + # Nginx repo and packages + if ee_platform_distro == 'Ubuntu': + ee_nginx_repo = "ppa:rtcamp/nginx" + ee_nginx = ["nginx-custom", "nginx-common"] + elif ee_platform_distro == 'debian': + ee_nginx_repo = ("deb http://packages.dotdeb.org {codename} all" + .format(codename=ee_platform_codename)) + ee_nginx = ["nginx-full", "nginx-common"] + + # PHP repo and packages + if ee_platform_distro == 'Ubuntu': + ee_php_repo = "ppa:ondrej/php5" + elif ee_platform_codename == 'squeeze': + ee_php_repo = ("deb http://packages.dotdeb.org {codename}-php54 all" + .format(codename=ee_platform_codename)) + elif ee_platform_codename == 'wheezy': + ee_php_repo = ("deb http://packages.dotdeb.org {codename}-php55 all" + .format(codename=ee_platform_codename)) + ee_php = ["php5-fpm", "php5-curl", "php5-gd", "php5-imap", + "php5-mcrypt", "php5-xdebug", "php5-common", "php5-readline", + "php5-mysql", "php5-cli", "php5-memcache", "memcached", + "graphviz"] + + # MySQL repo and packages + ee_mysql_repo = ("deb http://repo.percona.com/apt {codename} main" + .format(codename=ee_platform_codename)) + ee_mysql = ["percona-server-server-5.6", "mysqltuner", "percona-toolkit"] + + # Postfix repo and packages + ee_postfix_repo = "" + ee_postfix = ["postfix"] + + # Mail repo and packages + ee_mail_repo = ("deb http://http.debian.net/debian-backports {codename}" + "-backports main".format(codename=ee_platform_codename)) + + ee_mail = ["dovecot-core", "dovecot-imapd", "dovecot-pop3d", + "dovecot-lmtpd", "dovecot-mysql", "dovecot-sieve", + "dovecot-managesieved", "postfix-mysql", "php5-cgi", + "php-gettext", "php-pear"] + + # Mailscanner repo and packages + ee_mailscanner_repo = () + ee_mailscanner = ["amavisd-new", "spamassassin", "clamav", "clamav-daemon", + "arj", "zoo", "nomarch", "lzop", "cabextract", "p7zip", + "rpm", "unrar-free"] + + # Repo path + ee_repo_file = "ee-repo.list" + ee_repo_file_path = ("/etc/apt/sources.list.d/" + ee_repo_file) + + # Application dabase file path + basedir = os.path.abspath(os.path.dirname('/var/lib/ee/')) + ee_db_uri = 'sqlite:///' + os.path.join(basedir, 'ee.db') + + def __init__(self): + pass diff --git a/ee/utils/__init__.py b/ee/utils/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ee/utils/test.py b/ee/utils/test.py new file mode 100644 index 00000000..1d3371ed --- /dev/null +++ b/ee/utils/test.py @@ -0,0 +1,15 @@ +"""Testing utilities for EasyEngine.""" +from ee.cli.main import EETestApp +from cement.utils.test import * + + +class EETestCase(CementTestCase): + app_class = EETestApp + + def setUp(self): + """Override setup actions (for every test).""" + super(EETestCase, self).setUp() + + def tearDown(self): + """Override teardown actions (for every test).""" + super(EETestCase, self).tearDown() diff --git a/install b/install new file mode 100644 index 00000000..bb2cb291 --- /dev/null +++ b/install @@ -0,0 +1,244 @@ +#!/bin/bash + +# EasyEngine update script. +# This script is designed to install latest EasyEngine or +# to update current EasyEngine from 2.x to 3.x + +old_ee_version="2.2.3" +branch=$1 + +# Define echo function +# Blue color + +function ee_lib_echo() +{ + echo $(tput setaf 4)$@$(tput sgr0) +} +# White color +function ee_lib_echo_info() +{ + echo $(tput setaf 7)$@$(tput sgr0) +} +# Red color +function ee_lib_echo_fail() +{ + echo $(tput setaf 1)$@$(tput sgr0) +} + +# Capture errors +function ee_lib_error() +{ + echo "[ `date` ] $(tput setaf 1)$@$(tput sgr0)" + exit $2 +} + +function install_dep() +{ + # Execute: apt-get update + ee_lib_echo "Executing apt-get update" + apt-get update &>> /dev/null + + # Install Python3 on users system + ee_lib_echo "Installing pre depedencies" + apt-get -y install python3 python3-apt python3-setuptools python3-dev sqlite3 git + if [[ $? -ne 0 ]]; then + ee_lib_echo_fail "Unable to install pre depedencies" + exit 1 + fi +} + +function sync_db() +{ + mkdir /var/lib/ee + + # Sqlite query to create table `sites` into ee.db which will be used by ee.3.0 + echo "CREATE TABLE sites ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + sitename UNIQUE, + site_type CHAR, + cache_type CHAR, + site_path CHAR, + created_on TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + is_enabled INT, + is_ssl INT, + storage_fs CHAR, + storage_db CHAR + );" | sqlite3 /var/lib/ee/ee.db + + for site in $(ls /etc/nginx/sites-available/ | grep -v default); + do + if [ -f /etc/nginx/sites-available/$site ]; then + ENABLE_STATUS='1' + else + ENABLE_STATUS='0' + fi + # Find out information about current NGINX configuration + EE_SITE_CURRENT_TYPE=$(head -n1 /etc/nginx/sites-available/$site | grep "NGINX CONFIGURATION" | rev | cut -d' ' -f3,4,5,6,7 | rev | cut -d ' ' -f2,3,4,5) + # Detect current website type and cache + if [ "$EE_SITE_CURRENT_TYPE" = "HTML" ]; then + EE_SITE_CURRENT="html" + EE_SITE_CURRENT_CACHE="basic" + elif [ "$EE_SITE_CURRENT_TYPE" = "PHP" ]; then + EE_SITE_CURRENT="php" + EE_SITE_CURRENT_CACHE="basic" + elif [ "$EE_SITE_CURRENT_TYPE" = "MYSQL" ]; then + EE_SITE_CURRENT="mysql" + EE_SITE_CURRENT_CACHE="basic" + # Single WordPress + elif [ "$EE_SITE_CURRENT_TYPE" = "WPSINGLE BASIC" ]; then + EE_SITE_CURRENT="wp" + EE_SITE_CURRENT_CACHE="basic" + + elif [ "$EE_SITE_CURRENT_TYPE" = "WPSINGLE WP SUPER CACHE" ]; then + EE_SITE_CURRENT="wp" + EE_SITE_CURRENT_CACHE="wpsc" + + elif [ "$EE_SITE_CURRENT_TYPE" = "WPSINGLE W3 TOTAL CACHE" ]; then + EE_SITE_CURRENT="wp" + EE_SITE_CURRENT_CACHE="w3tc" + + elif [ "$EE_SITE_CURRENT_TYPE" = "WPSINGLE FAST CGI" ] || [ "$EE_SITE_CURRENT_TYPE" = "WPSINGLE FASTCGI" ]; then + EE_SITE_CURRENT="wp" + EE_SITE_CURRENT_CACHE="wpfc" + + # WordPress subdirectory + elif [ "$EE_SITE_CURRENT_TYPE" = "WPSUBDIR BASIC" ]; then + EE_SITE_CURRENT="wpsubdir" + EE_SITE_CURRENT_CACHE="basic" + + elif [ "$EE_SITE_CURRENT_TYPE" = "WPSUBDIR WP SUPER CACHE" ]; then + EE_SITE_CURRENT="wpsubdir" + EE_SITE_CURRENT_CACHE="wpsc" + + elif [ "$EE_SITE_CURRENT_TYPE" = "WPSUBDIR W3 TOTAL CACHE" ]; then + EE_SITE_CURRENT="wpsubdir" + EE_SITE_CURRENT_CACHE="w3tc" + + elif [ "$EE_SITE_CURRENT_TYPE" = "WPSUBDIR FAST CGI" ] || [ "$EE_SITE_CURRENT_TYPE" = "WPSUBDIR FASTCGI" ]; then + EE_SITE_CURRENT="wpsubdir" + EE_SITE_CURRENT_CACHE="wpfc" + + # WordPress subdomain + elif [ "$EE_SITE_CURRENT_TYPE" = "WPSUBDOMAIN BASIC" ]; then + EE_SITE_CURRENT="wpsubdomain" + EE_SITE_CURRENT_CACHE="basic" + + elif [ "$EE_SITE_CURRENT_TYPE" = "WPSUBDOMAIN WP SUPER CACHE" ]; then + EE_SITE_CURRENT="wpsubdomain" + EE_SITE_CURRENT_CACHE="wpsc" + + elif [ "$EE_SITE_CURRENT_TYPE" = "WPSUBDOMAIN W3 TOTAL CACHE" ]; then + EE_SITE_CURRENT="wpsubdomain" + EE_SITE_CURRENT_CACHE="w3tc" + + elif [ "$EE_SITE_CURRENT_TYPE" = "WPSUBDOMAIN FAST CGI" ] || [ "$EE_SITE_CURRENT_TYPE" = "WPSUBDOMAIN FASTCGI" ]; then + EE_SITE_CURRENT="wpsubdomain" + EE_SITE_CURRENT_CACHE="wpfc" + fi + + WEBROOT="/var/www/$site" + + # Insert query to insert old site information into ee.db + echo "INSERT INTO sites (sitename, site_type, cache_type, site_path, is_enabled, is_ssl, storage_fs, storage_db) + VALUES (\"$site\", \"$EE_SITE_CURRENT\", \"$EE_SITE_CURRENT_CACHE\", \"$WEBROOT\", \"$ENABLE_STATUS\", 0, 'ext4', 'mysql');" | sqlite3 /var/lib/ee/ee.db + + done +} + + +function install_ee3() +{ + # Remove old clone of EasyEngine (ee) if any + rm -rf /tmp/easyengine &>> /dev/null + + # Clone EE 3.0 Python branch + ee_lib_echo "Cloning EasyEngine 3.0" + if [ "$branch" = "" ]; then + branch=stable + fi + + git clone -b $branch https://github.com/rtCamp/easyengine.git /tmp/easyengine --quiet > /dev/null || ee_lib_error "Unable to clone EasyEngine, exit status" 1 + + cd /tmp/easyengine + ee_lib_echo "Installing EasyEngine 3.0" + python3 setup.py install || ee_lib_error "Unable to install EasyEngine 3.0, exit status " 1 + +} + +function update_to_ee3() +{ + # Preserve old configuration + ee_lib_echo "Updating EasyEngine 3.0 configuration" + + grant_host=$(grep grant-host /etc/easyengine/ee.conf | awk '{ print $3 }') + db_name=$(grep db-name /etc/easyengine/ee.conf | awk '{ print $3 }') + db_user=$(grep db-name /etc/easyengine/ee.conf | awk '{ print $3 }') + wp_prefix=$(grep prefix /etc/easyengine/ee.conf | awk '{ print $3 }') + wp_user=$(grep 'user ' /etc/easyengine/ee.conf | grep -v db-user |awk '{ print $3 }') + wp_pass=$(grep password /etc/easyengine/ee.conf | awk '{ print $3 }') + wp_email=$(grep email /etc/easyengine/ee.conf | awk '{ print $3 }') + ip_addr=$(grep ip-address /etc/easyengine/ee.conf |awk -F'=' '{ print $2 }') + + sed -i "s/ip-address.*/ip-address = ${ip_addr}/" /etc/ee/ee.conf && \ + sed -i "s/grant-host.*/grant-host = ${grant_host}/" /etc/ee/ee.conf && \ + sed -i "s/db-name.*/db-name = ${db-name}/" /etc/ee/ee.conf && \ + sed -i "s/db-user.*/db-user = ${db_user}/" /etc/ee/ee.conf && \ + sed -i "s/prefix.*/prefix = ${wp_prefix}/" /etc/ee/ee.conf && \ + sed -i "s/^user.*/user = ${wp_user}/" /etc/ee/ee.conf && \ + sed -i "s/password.*/password = ${wp_password}/" /etc/ee/ee.conf && \ + sed -i "s/email.*/email = ${wp_email}/" /etc/ee/ee.conf || ee_lib_error "Unable to update configuration, exit status " 1 + + + # Remove old EasyEngine + ee_lib_echo "Removing EasyEngine 2" + rm -rf /etc/bash_completion.d/ee /etc/easyengine/ /usr/share/easyengine/ /usr/local/lib/easyengine /usr/local/sbin/easyengine /usr/local/sbin/ee /var/log/easyengine + + # Softlink to fix command not found error + ln -s /usr/local/bin/ee /usr/local/sbin/ee + +} + +function git_init() +{ + # Do git intialisation on EasyEngine configuration + cd /etc/ee + if [ ! -d /etc/ee/.git ]; then + git init > /dev/null + fi + git add . + git commit -am "Installed/Updated to EasyEngine 3" > /dev/null + +} + +# Checking permissions +if [[ $EUID -ne 0 ]]; then + ee_lib_echo_fail "Sudo privilege required..." + ee_lib_echo_fail "Uses: wget -qO ee rt.cx/ee && sudo bash ee" + exit 1 +fi + +if [ -f /usr/local/sbin/easyengine ]; then + # Check old EasyEngine version + ee version | grep ${old_ee_version} &>> /dev/null + if [[ $? -ne 0 ]]; then + ee_lib_echo "EasyEngine $old_ee_version not found on your system" + ee_lib_echo "Updating your EasyEngine to $old_ee_version for compability" + wget -q https://raw.githubusercontent.com/rtCamp/easyengine/old-stable/bin/update && bash update + if [[ $? -ne 0 ]]; then + ee_lib_echo_info "Unbale to update EasyEngine2 to $old_ee_version" + exit 1 + fi + fi + install_dep + sync_db + install_ee3 + update_to_ee3 + git_init +elif [ ! -f /usr/local/bin/ee ]; then + install_dep + install_ee3 + git_init +else + ee_lib_echo_fail "EasyEngine 3 allready installed on your system" + exit 1 +fi diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..24fb2218 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +cement>=2.4.0 diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 00000000..a273d468 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,9 @@ +[nosetests] +verbosity=3 +debug=0 +detailed-errors=1 +with-coverage=1 +cover-package=ee +cover-erase=1 +cover-html=1 +cover-html-dir=coverage_report/ diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..a7f5a3f3 --- /dev/null +++ b/setup.py @@ -0,0 +1,109 @@ + +from setuptools import setup, find_packages +import sys +import os +import glob +import configparser +import re + +conf = [] +templates = [] + +long_description = '''EasyEngine is the commandline tool to manage your + Websites based on WordPress and Nginx with easy to use + commands''' + +for name in glob.glob('config/plugins.d/*.conf'): + conf.insert(1, name) + +for name in glob.glob('ee/cli/templates/*.mustache'): + templates.insert(1, name) + +if not os.path.exists('/var/log/ee/'): + os.makedirs('/var/log/ee/') + +if not os.path.exists('/var/lib/ee/'): + os.makedirs('/var/lib/ee/') + +# EasyEngine git function +config = configparser.ConfigParser() +config.read(os.path.expanduser("~")+'/.gitconfig') +try: + ee_user = config['user']['name'] + ee_email = config['user']['email'] +except Exception as e: + print("EasyEngine (ee) required your name & email address to track" + " changes you made under the Git version control") + print("EasyEngine (ee) will be able to send you daily reports & alerts in " + "upcoming version") + print("EasyEngine (ee) will NEVER send your information across") + + ee_user = input("Enter your name: ") + while ee_user is "": + print("Name not Valid, Please enter again") + ee_user = input("Enter your name: ") + + ee_email = input("Enter your email: ") + + while not re.match(r"^[A-Za-z0-9\.\+_-]+@[A-Za-z0-9\._-]+\.[a-zA-Z]*$", + ee_email): + print("EMail not Valid, Please enter again") + ee_email = input("Enter your email: ") + + os.system("git config --global user.name {0}".format(ee_user)) + os.system("git config --global user.email {0}".format(ee_email)) + +setup(name='ee', + version='3.0', + description=long_description, + long_description=long_description, + classifiers=[], + keywords='', + author='rtCamp Soultions Pvt. LTD', + author_email='sys@rtcamp.com', + url='http://rtcamp.com/easyengine', + license='GPL', + packages=find_packages(exclude=['ez_setup', 'examples', 'tests', + 'templates']), + include_package_data=True, + zip_safe=False, + test_suite='nose.collector', + install_requires=[ + # Required to build documentation + # "Sphinx >= 1.0", + # Required for testing + # "nose", + # "coverage", + # Required to function + 'cement == 2.4', + 'pystache', + 'python-apt', + 'pynginxconfig', + 'pymysql3 == 0.4', + 'psutil', + 'sh', + 'sqlalchemy', + ], + data_files=[('/etc/ee', ['config/ee.conf']), + ('/etc/ee/plugins.d', conf), + ('/usr/lib/ee/templates', templates), + ('/etc/bash_completion.d/', + ['config/bash_completion.d/ee_auto.rc']), + ('/usr/share/man/man8/', ['docs/ee.8'])], + setup_requires=[], + entry_points=""" + [console_scripts] + ee = ee.cli.main:main + """, + namespace_packages=[], + ) + +print("""\033[94m +For EasyEngine (ee) auto completion, run the following command +\033[92m +source /etc/bash_completion.d/ee_auto.rc +\033[94m +EasyEngine (ee) installed successfully +EasyEngine (ee) help: https://rtcamp.com/easyengine/docs/ +\033[0m +""") diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/cli/13_test_stack.py b/tests/cli/13_test_stack.py new file mode 100644 index 00000000..a108e594 --- /dev/null +++ b/tests/cli/13_test_stack.py @@ -0,0 +1,76 @@ +from ee.utils import test +from ee.cli.main import get_test_app + + +class CliTestCaseStack(test.EETestCase): + + def test_ee_cli(self): + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_install_web(self): + self.app = get_test_app(argv=['stack', 'install', '--web']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_install_admin(self): + self.app = get_test_app(argv=['stack', 'install', '--admin']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_install_mail(self): + self.app = get_test_app(argv=['stack', 'install', '--mail']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_install_nginx(self): + self.app = get_test_app(argv=['stack', 'install', '--nginx']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_install_php(self): + self.app = get_test_app(argv=['stack', 'install', '--php']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_install_mysql(self): + self.app = get_test_app(argv=['stack', 'install', '--mysql']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_install_postfix(self): + self.app = get_test_app(argv=['stack', 'install', '--postfix']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_install_wpcli(self): + self.app = get_test_app(argv=['stack', 'install', '--wpcli']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_install_phpmyadmin(self): + self.app = get_test_app(argv=['stack', 'install', '--phpmyadmin']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_install_adminer(self): + self.app = get_test_app(argv=['stack', 'install', '--adminer']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_install_utils(self): + self.app = get_test_app(argv=['stack', 'install', '--utils']) + self.app.setup() + self.app.run() + self.app.close() diff --git a/tests/cli/2_test_stack_services_start.py b/tests/cli/2_test_stack_services_start.py new file mode 100644 index 00000000..de874afe --- /dev/null +++ b/tests/cli/2_test_stack_services_start.py @@ -0,0 +1,52 @@ +from ee.utils import test +from ee.cli.main import get_test_app + + +class CliTestCaseStack(test.EETestCase): + + def test_ee_cli(self): + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_start_nginx(self): + self.app = get_test_app(argv=['stack', 'start', '--nginx']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_start_php5_fpm(self): + self.app = get_test_app(argv=['stack', 'start', '--php']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_start_mysql(self): + self.app = get_test_app(argv=['stack', 'start', '--mysql']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_start_postfix(self): + self.app = get_test_app(argv=['stack', 'start', '--postfix']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_start_memcached(self): + self.app = get_test_app(argv=['stack', 'start', '--memcache']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_start_dovecot(self): + self.app = get_test_app(argv=['stack', 'start', '--dovecot']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_start_all(self): + self.app = get_test_app(argv=['stack', 'start']) + self.app.setup() + self.app.run() + self.app.close() diff --git a/tests/cli/3_test_stack_services_status.py b/tests/cli/3_test_stack_services_status.py new file mode 100644 index 00000000..42bd65a8 --- /dev/null +++ b/tests/cli/3_test_stack_services_status.py @@ -0,0 +1,52 @@ +from ee.utils import test +from ee.cli.main import get_test_app + + +class CliTestCaseStack(test.EETestCase): + + def test_ee_cli(self): + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_status_nginx(self): + self.app = get_test_app(argv=['stack', 'status', '--nginx']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_status_php5_fpm(self): + self.app = get_test_app(argv=['stack', 'status', '--php']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_status_mysql(self): + self.app = get_test_app(argv=['stack', 'status', '--mysql']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_status_postfix(self): + self.app = get_test_app(argv=['stack', 'status', '--postfix']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_status_memcached(self): + self.app = get_test_app(argv=['stack', 'status', '--memcache']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_status_dovecot(self): + self.app = get_test_app(argv=['stack', 'status', '--dovecot']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_status_all(self): + self.app = get_test_app(argv=['stack', 'status']) + self.app.setup() + self.app.run() + self.app.close() diff --git a/tests/cli/4_test_stack_services_stop.py b/tests/cli/4_test_stack_services_stop.py new file mode 100644 index 00000000..9b6ece4b --- /dev/null +++ b/tests/cli/4_test_stack_services_stop.py @@ -0,0 +1,52 @@ +from ee.utils import test +from ee.cli.main import get_test_app + + +class CliTestCaseStack(test.EETestCase): + + def test_ee_cli(self): + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_stop_nginx(self): + self.app = get_test_app(argv=['stack', 'stop', '--nginx']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_stop_php5_fpm(self): + self.app = get_test_app(argv=['stack', 'stop', '--php']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_stop_mysql(self): + self.app = get_test_app(argv=['stack', 'stop', '--mysql']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_stop_postfix(self): + self.app = get_test_app(argv=['stack', 'stop', '--postfix']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_stop_memcached(self): + self.app = get_test_app(argv=['stack', 'stop', '--memcache']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_stop_dovecot(self): + self.app = get_test_app(argv=['stack', 'stop', '--dovecot']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_stop_all(self): + self.app = get_test_app(argv=['stack', 'stop']) + self.app.setup() + self.app.run() + self.app.close() diff --git a/tests/cli/5_test_stack_services_restart.py b/tests/cli/5_test_stack_services_restart.py new file mode 100644 index 00000000..39d8825c --- /dev/null +++ b/tests/cli/5_test_stack_services_restart.py @@ -0,0 +1,52 @@ +from ee.utils import test +from ee.cli.main import get_test_app + + +class CliTestCaseStack(test.EETestCase): + + def test_ee_cli(self): + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_restart_nginx(self): + self.app = get_test_app(argv=['stack', 'restart', '--nginx']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_restart_php5_fpm(self): + self.app = get_test_app(argv=['stack', 'restart', '--php']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_restart_mysql(self): + self.app = get_test_app(argv=['stack', 'restart', '--mysql']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_restart_postfix(self): + self.app = get_test_app(argv=['stack', 'restart', '--postfix']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_restart_memcached(self): + self.app = get_test_app(argv=['stack', 'restart', '--memcache']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_restart_dovecot(self): + self.app = get_test_app(argv=['stack', 'restart', '--dovecot']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_services_restart_all(self): + self.app = get_test_app(argv=['stack', 'restart']) + self.app.setup() + self.app.run() + self.app.close() diff --git a/tests/cli/8_test_site_create.py b/tests/cli/8_test_site_create.py new file mode 100644 index 00000000..3b3a2554 --- /dev/null +++ b/tests/cli/8_test_site_create.py @@ -0,0 +1,73 @@ +from ee.utils import test +from ee.cli.main import get_test_app + + +class CliTestCaseSite(test.EETestCase): + + def test_ee_cli(self): + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_site_create_html(self): + self.app = get_test_app(argv=['site', 'create', 'example1.com', + '--html']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_site_create_php(self): + self.app = get_test_app(argv=['site', 'create', 'example2.com', + '--php']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_site_create_mysql(self): + self.app = get_test_app(argv=['site', 'create', 'example3.com', + '--mysql']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_site_create_wp(self): + self.app = get_test_app(argv=['site', 'create', 'example4.com', + '--wp']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_site_create_wpsubdir(self): + self.app = get_test_app(argv=['site', 'create', 'example5.com', + '--wpsubdir']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_site_create_wpsubdomain(self): + self.app = get_test_app(argv=['site', 'create', 'example6.com', + '--wpsubdomain']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_site_create_w3tc(self): + self.app = get_test_app(argv=['site', 'create', 'example7.com', + '--w3tc']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_site_create_wpfc(self): + self.app = get_test_app(argv=['site', 'create', 'example8.com', + '--wpfc']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_site_create_wpsc(self): + self.app = get_test_app(argv=['site', 'create', 'example9.com', + '--wpsc']) + self.app.setup() + self.app.run() + self.app.close() diff --git a/tests/cli/91_test_site_info.py b/tests/cli/91_test_site_info.py new file mode 100644 index 00000000..1ecc2062 --- /dev/null +++ b/tests/cli/91_test_site_info.py @@ -0,0 +1,16 @@ +from ee.utils import test +from ee.cli.main import get_test_app + + +class CliTestCaseSite(test.EETestCase): + + def test_ee_cli(self): + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_site_info(self): + self.app = get_test_app(argv=['site', 'info', 'example1.com']) + self.app.setup() + self.app.run() + self.app.close() diff --git a/tests/cli/93_test_site_list.py b/tests/cli/93_test_site_list.py new file mode 100644 index 00000000..477e6915 --- /dev/null +++ b/tests/cli/93_test_site_list.py @@ -0,0 +1,22 @@ +from ee.utils import test +from ee.cli.main import get_test_app + + +class CliTestCaseSite(test.EETestCase): + + def test_ee_cli(self): + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_site_list_enable(self): + self.app = get_test_app(argv=['site', 'list', '--enabled']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_site_list_disable(self): + self.app = get_test_app(argv=['site', 'list', '--disabled']) + self.app.setup() + self.app.run() + self.app.close() diff --git a/tests/cli/95_test_site_show.py b/tests/cli/95_test_site_show.py new file mode 100644 index 00000000..606578a6 --- /dev/null +++ b/tests/cli/95_test_site_show.py @@ -0,0 +1,16 @@ +from ee.utils import test +from ee.cli.main import get_test_app + + +class CliTestCaseSite(test.EETestCase): + + def test_ee_cli(self): + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_show_edit(self): + self.app = get_test_app(argv=['site', 'show', 'example1.com']) + self.app.setup() + self.app.run() + self.app.close() diff --git a/tests/cli/97_test_site_update.py b/tests/cli/97_test_site_update.py new file mode 100644 index 00000000..38b0c0ab --- /dev/null +++ b/tests/cli/97_test_site_update.py @@ -0,0 +1,73 @@ +from ee.utils import test +from ee.cli.main import get_test_app + + +class CliTestCaseSite(test.EETestCase): + + def test_ee_cli(self): + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_site_update_html(self): + self.app = get_test_app(argv=['site', 'update', 'example2.com', + '--html']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_site_update_php(self): + self.app = get_test_app(argv=['site', 'update', 'example1.com', + '--php']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_site_update_mysql(self): + self.app = get_test_app(argv=['site', 'update', 'example1.com', + '--html']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_site_update_wp(self): + self.app = get_test_app(argv=['site', 'update', 'example5.com', + '--wp']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_site_update_wpsubdir(self): + self.app = get_test_app(argv=['site', 'update', 'example4.com', + '--wpsubdir']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_site_update_wpsubdomain(self): + self.app = get_test_app(argv=['site', 'update', 'example7.com', + '--wpsubdomain']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_site_update_w3tc(self): + self.app = get_test_app(argv=['site', 'update', 'example8.com', + '--w3tc']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_site_update_wpfc(self): + self.app = get_test_app(argv=['site', 'update', 'example9.com', + '--wpfc']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_site_update_wpsc(self): + self.app = get_test_app(argv=['site', 'update', 'example6.com', + '--wpsc']) + self.app.setup() + self.app.run() + self.app.close() diff --git a/tests/cli/9_test_site_enable.py b/tests/cli/9_test_site_enable.py new file mode 100644 index 00000000..87cc4f85 --- /dev/null +++ b/tests/cli/9_test_site_enable.py @@ -0,0 +1,16 @@ +from ee.utils import test +from ee.cli.main import get_test_app + + +class CliTestCaseSite(test.EETestCase): + + def test_ee_cli(self): + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_site_enable(self): + self.app = get_test_app(argv=['site', 'enable', 'example2.com']) + self.app.setup() + self.app.run() + self.app.close() diff --git a/tests/cli/__init__.py b/tests/cli/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/cli/a_test_site_disable.py b/tests/cli/a_test_site_disable.py new file mode 100644 index 00000000..3d948f77 --- /dev/null +++ b/tests/cli/a_test_site_disable.py @@ -0,0 +1,16 @@ +from ee.utils import test +from ee.cli.main import get_test_app + + +class CliTestCaseSite(test.EETestCase): + + def test_ee_cli(self): + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_site_disable(self): + self.app = get_test_app(argv=['site', 'disable', 'example2.com']) + self.app.setup() + self.app.run() + self.app.close() diff --git a/tests/cli/ext/__init__.py b/tests/cli/ext/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/cli/plugins/__init__.py b/tests/cli/plugins/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/cli/plugins/test_example.py b/tests/cli/plugins/test_example.py new file mode 100644 index 00000000..860a5485 --- /dev/null +++ b/tests/cli/plugins/test_example.py @@ -0,0 +1,8 @@ +"""Tests for Example Plugin.""" + +from ee.utils import test + +class ExamplePluginTestCase(test.EETestCase): + def test_load_example_plugin(self): + self.app.setup() + self.app.plugin.load_plugin('example') diff --git a/tests/cli/test_clean.py b/tests/cli/test_clean.py new file mode 100644 index 00000000..39254bff --- /dev/null +++ b/tests/cli/test_clean.py @@ -0,0 +1,40 @@ +from ee.utils import test +from ee.cli.main import get_test_app + + +class CliTestCaseClean(test.EETestCase): + + def test_ee_cli(self): + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_clean(self): + self.app = get_test_app(argv=['clean']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_clean_fastcgi(self): + self.app = get_test_app(argv=['clean', '--fastcgi']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_clean_all(self): + self.app = get_test_app(argv=['clean', '--all']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_clean_memcache(self): + self.app = get_test_app(argv=['clean', '--memcache']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_clean_opcache(self): + self.app = get_test_app(argv=['clean', '--opcache']) + self.app.setup() + self.app.run() + self.app.close() diff --git a/tests/cli/test_debug.py b/tests/cli/test_debug.py new file mode 100644 index 00000000..ba071001 --- /dev/null +++ b/tests/cli/test_debug.py @@ -0,0 +1,95 @@ +from ee.utils import test +from ee.cli.main import get_test_app + + +class CliTestCaseDebug(test.EETestCase): + + def test_ee_cli(self): + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_debug_stop(self): + self.app = get_test_app(argv=['debug', '--stop']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_debug_start(self): + self.app = get_test_app(argv=['debug', '--start']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_debug_php(self): + self.app = get_test_app(argv=['debug', '--php']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_debug_nginx(self): + self.app = get_test_app(argv=['debug', '--nginx']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_debug_rewrite(self): + self.app = get_test_app(argv=['debug', '--rewrite']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_debug_fpm(self): + self.app = get_test_app(argv=['debug', '--fpm']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_debug_mysql(self): + self.app = get_test_app(argv=['debug', '--mysql']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_debug_import_slow_log_interval(self): + self.app = get_test_app(argv=['debug', '--mysql', + '--import-slow-log-interval']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_debug_site_name_mysql(self): + self.app = get_test_app(argv=['debug', 'example3.com', '--mysql']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_debug_site_name_wp(self): + self.app = get_test_app(argv=['debug', 'example4.com', '--wp']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_debug_site_name_nginx(self): + self.app = get_test_app(argv=['debug', 'example4.com', '--nginx']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_debug_site_name_start(self): + self.app = get_test_app(argv=['debug', 'example1.com', '--start']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_debug_site_name_stop(self): + self.app = get_test_app(argv=['debug', 'example1.com', '--stop']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_debug_site_name_rewrite(self): + self.app = get_test_app(argv=['debug', 'example1.com', '--rewrite']) + self.app.setup() + self.app.run() + self.app.close() diff --git a/tests/cli/test_info.py b/tests/cli/test_info.py new file mode 100644 index 00000000..0c36edb4 --- /dev/null +++ b/tests/cli/test_info.py @@ -0,0 +1,28 @@ +from ee.utils import test +from ee.cli.main import get_test_app + + +class CliTestCaseInfo(test.EETestCase): + + def test_ee_cli(self): + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_info_mysql(self): + self.app = get_test_app(argv=['info', '--mysql']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_info_php(self): + self.app = get_test_app(argv=['info', '--php']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_info_nginx(self): + self.app = get_test_app(argv=['info', '--nginx']) + self.app.setup() + self.app.run() + self.app.close() diff --git a/tests/cli/test_secure.py b/tests/cli/test_secure.py new file mode 100644 index 00000000..d867a2e8 --- /dev/null +++ b/tests/cli/test_secure.py @@ -0,0 +1,28 @@ +from ee.utils import test +from ee.cli.main import get_test_app + + +class CliTestCaseSecure(test.EETestCase): + + def test_ee_cli(self): + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_secure_auth(self): + self.app = get_test_app(argv=['secure', '--auth']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_secure_port(self): + self.app = get_test_app(argv=['secure', '--port']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_secure_ip(self): + self.app = get_test_app(argv=['secure', '--ip']) + self.app.setup() + self.app.run() + self.app.close() diff --git a/tests/cli/test_site_delete.py b/tests/cli/test_site_delete.py new file mode 100644 index 00000000..b9f204ea --- /dev/null +++ b/tests/cli/test_site_delete.py @@ -0,0 +1,38 @@ +from ee.utils import test +from ee.cli.main import get_test_app + + +class CliTestCaseSite(test.EETestCase): + + def test_ee_cli(self): + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_site_detele(self): + self.app = get_test_app(argv=['site', 'delete', 'example1.com', + '--no-prompt']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_site_detele_all(self): + self.app = get_test_app(argv=['site', 'delete', 'example2.com', + '--all', '--no-prompt']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_site_detele_db(self): + self.app = get_test_app(argv=['site', 'delete', 'example3.com', + '--db', '--no-prompt']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_site_detele_files(self): + self.app = get_test_app(argv=['site', 'delete', 'example4.com', + '--files', '--no-prompt']) + self.app.setup() + self.app.run() + self.app.close() diff --git a/tests/cli/test_stack_purge.py b/tests/cli/test_stack_purge.py new file mode 100644 index 00000000..433b23d4 --- /dev/null +++ b/tests/cli/test_stack_purge.py @@ -0,0 +1,76 @@ +from ee.utils import test +from ee.cli.main import get_test_app + + +class CliTestCaseStack(test.EETestCase): + + def test_ee_cli(self): + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_purge_web(self): + self.app = get_test_app(argv=['stack', 'purge', '--web']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_purge_admin(self): + self.app = get_test_app(argv=['stack', 'purge', '--admin']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_purge_mail(self): + self.app = get_test_app(argv=['stack', 'purge', '--mail']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_purge_nginx(self): + self.app = get_test_app(argv=['stack', 'purge', '--nginx']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_purge_php(self): + self.app = get_test_app(argv=['stack', 'purge', '--php']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_purge_mysql(self): + self.app = get_test_app(argv=['stack', 'purge', '--mysql']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_purge_postfix(self): + self.app = get_test_app(argv=['stack', 'purge', '--postfix']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_purge_wpcli(self): + self.app = get_test_app(argv=['stack', 'purge', '--wpcli']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_purge_phpmyadmin(self): + self.app = get_test_app(argv=['stack', 'purge', '--phpmyadmin']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_purge_adminer(self): + self.app = get_test_app(argv=['stack', 'purge', '--adminer']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_purge_utils(self): + self.app = get_test_app(argv=['stack', 'purge', '--utils']) + self.app.setup() + self.app.run() + self.app.close() diff --git a/tests/cli/test_stack_remove.py b/tests/cli/test_stack_remove.py new file mode 100644 index 00000000..54338373 --- /dev/null +++ b/tests/cli/test_stack_remove.py @@ -0,0 +1,76 @@ +from ee.utils import test +from ee.cli.main import get_test_app + + +class CliTestCaseStack(test.EETestCase): + + def test_ee_cli(self): + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_remove_web(self): + self.app = get_test_app(argv=['stack', 'remove', '--web']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_install_admin(self): + self.app = get_test_app(argv=['stack', 'remove', '--admin']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_install_mail(self): + self.app = get_test_app(argv=['stack', 'remove', '--mail']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_install_nginx(self): + self.app = get_test_app(argv=['stack', 'remove', '--nginx']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_install_php(self): + self.app = get_test_app(argv=['stack', 'remove', '--php']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_install_mysql(self): + self.app = get_test_app(argv=['stack', 'remove', '--mysql']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_install_postfix(self): + self.app = get_test_app(argv=['stack', 'remove', '--postfix']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_install_wpcli(self): + self.app = get_test_app(argv=['stack', 'remove', '--wpcli']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_install_phpmyadmin(self): + self.app = get_test_app(argv=['stack', 'remove', '--phpmyadmin']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_install_adminer(self): + self.app = get_test_app(argv=['stack', 'remove', '--adminer']) + self.app.setup() + self.app.run() + self.app.close() + + def test_ee_cli_stack_install_utils(self): + self.app = get_test_app(argv=['stack', 'remove', '--utils']) + self.app.setup() + self.app.run() + self.app.close() diff --git a/tests/core/__init__.py b/tests/core/__init__.py new file mode 100644 index 00000000..e69de29b