Browse Source

Merged Python into stable

bugfixes
gau1991 10 years ago
parent
commit
63dc1c4a9b
  1. 65
      .gitignore
  2. 225
      .travis.yml
  3. 21
      LICENSE
  4. 96
      README.md
  5. 176
      config/bash_completion.d/ee_auto.rc
  6. 69
      config/ee.conf
  7. 8
      config/plugins.d/clean.conf
  8. 8
      config/plugins.d/debug.conf
  9. 8
      config/plugins.d/import_slow_log.conf
  10. 11
      config/plugins.d/info.conf
  11. 8
      config/plugins.d/secure.conf
  12. 8
      config/plugins.d/site.conf
  13. 8
      config/plugins.d/stack.conf
  14. 312
      docs/ee.8
  15. 1
      ee/__init__.py
  16. 0
      ee/cli/__init__.py
  17. 11
      ee/cli/bootstrap.py
  18. 0
      ee/cli/controllers/__init__.py
  19. 25
      ee/cli/controllers/base.py
  20. 0
      ee/cli/ext/__init__.py
  21. 116
      ee/cli/main.py
  22. 0
      ee/cli/plugins/__init__.py
  23. 89
      ee/cli/plugins/clean.py
  24. 503
      ee/cli/plugins/debug.py
  25. 70
      ee/cli/plugins/import_slow_log.py
  26. 202
      ee/cli/plugins/info.py
  27. 132
      ee/cli/plugins/secure.py
  28. 1097
      ee/cli/plugins/site.py
  29. 538
      ee/cli/plugins/site_functions.py
  30. 96
      ee/cli/plugins/sitedb.py
  31. 1466
      ee/cli/plugins/stack.py
  32. 159
      ee/cli/plugins/stack_services.py
  33. 27
      ee/cli/templates/15-content_filter_mode.mustache
  34. 61
      ee/cli/templates/22222.mustache
  35. 17
      ee/cli/templates/50-user.mustache
  36. 0
      ee/cli/templates/__init__.py
  37. 8
      ee/cli/templates/acl.mustache
  38. 255
      ee/cli/templates/anemometer.mustache
  39. 11
      ee/cli/templates/auth-sql-conf.mustache
  40. 2
      ee/cli/templates/blockips.mustache
  41. 4
      ee/cli/templates/default-sieve.mustache
  42. 12
      ee/cli/templates/dovecot-sql-conf.mustache
  43. 60
      ee/cli/templates/dovecot.mustache
  44. 9
      ee/cli/templates/fastcgi.mustache
  45. 9
      ee/cli/templates/info_mysql.mustache
  46. 10
      ee/cli/templates/info_nginx.mustache
  47. 35
      ee/cli/templates/info_php.mustache
  48. 65
      ee/cli/templates/locations.mustache
  49. 39
      ee/cli/templates/nginx-core.mustache
  50. 10
      ee/cli/templates/php.mustache
  51. 10
      ee/cli/templates/siteinfo.mustache
  52. 9
      ee/cli/templates/upstream.mustache
  53. 662
      ee/cli/templates/vimbadmin.mustache
  54. 5
      ee/cli/templates/virtual_alias_maps.mustache
  55. 5
      ee/cli/templates/virtual_domains_maps.mustache
  56. 7
      ee/cli/templates/virtual_mailbox_maps.mustache
  57. 34
      ee/cli/templates/virtualconf.mustache
  58. 31
      ee/cli/templates/w3tc.mustache
  59. 35
      ee/cli/templates/wpcommon.mustache
  60. 36
      ee/cli/templates/wpfc.mustache
  61. 31
      ee/cli/templates/wpsc.mustache
  62. 10
      ee/cli/templates/wpsubdir.mustache
  63. 0
      ee/core/__init__.py
  64. 27
      ee/core/addswap.py
  65. 78
      ee/core/apt_repo.py
  66. 198
      ee/core/aptget.py
  67. 23
      ee/core/checkfqdn.py
  68. 24
      ee/core/database.py
  69. 24
      ee/core/domainvalidate.py
  70. 43
      ee/core/download.py
  71. 26
      ee/core/exc.py
  72. 21
      ee/core/extract.py
  73. 224
      ee/core/fileutils.py
  74. 57
      ee/core/git.py
  75. 43
      ee/core/logging.py
  76. 195
      ee/core/logwatch.py
  77. 43
      ee/core/models.py
  78. 62
      ee/core/mysql.py
  79. 135
      ee/core/services.py
  80. 51
      ee/core/shellexec.py
  81. 125
      ee/core/variables.py
  82. 0
      ee/utils/__init__.py
  83. 15
      ee/utils/test.py
  84. 244
      install
  85. 1
      requirements.txt
  86. 9
      setup.cfg
  87. 109
      setup.py
  88. 0
      tests/__init__.py
  89. 76
      tests/cli/13_test_stack.py
  90. 52
      tests/cli/2_test_stack_services_start.py
  91. 52
      tests/cli/3_test_stack_services_status.py
  92. 52
      tests/cli/4_test_stack_services_stop.py
  93. 52
      tests/cli/5_test_stack_services_restart.py
  94. 73
      tests/cli/8_test_site_create.py
  95. 16
      tests/cli/91_test_site_info.py
  96. 22
      tests/cli/93_test_site_list.py
  97. 16
      tests/cli/95_test_site_show.py
  98. 73
      tests/cli/97_test_site_update.py
  99. 16
      tests/cli/9_test_site_enable.py
  100. 0
      tests/cli/__init__.py

65
.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/

225
.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

21
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.

96
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)
<img src="https://d3qt5vpr7p9rgn.cloudfront.net/wp-content/uploads/2013/08/easy-engine-logo-2-RS1.png" alt="EasyEngine Logo" align="right" />
[![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)

176
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

69
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 =

8
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

8
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

8
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

11
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

8
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

8
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

8
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

312
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 <http://github.com/rtCamp/easyengine/issues/>
.SH AUTHOR
.br
.B rtCamp Team
.I \<admin@rtcamp.com\>
.br
.B Mitesh Shah
.I \<Mitesh.Shah@rtcamp.com\>
.br
.B Manish
.I \<Manish.Songirkar@rtcamp.com\>
.br
.B Gaurav
.I \<Gaurav.Astikar@rtcamp.com\>
.br
.B Harshad
.I \<harshad.yeola@rtcamp.com>
.br
.B Shital
.I \<shital.patil@rtcamp.com\>
.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/

1
ee/__init__.py

@ -0,0 +1 @@
__import__('pkg_resources').declare_namespace(__name__)

0
ee/cli/__init__.py

11
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)

0
ee/cli/controllers/__init__.py

25
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()

0
ee/cli/ext/__init__.py

116
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()

0
ee/cli/plugins/__init__.py

89
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)

503
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)

70
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)

202
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)

132
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)

1097
ee/cli/plugins/site.py

File diff suppressed because it is too large

538
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<<PHP \n {1}\nPHP\""
.format(data['ee_db_pass'],
"\n\ndefine(\'WP_DEBUG\', false);"))
EEShellExec.cmd_exec(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={0} "
"--extra-php<<PHP \n {1}\nPHP\""
.format(data['ee_db_pass'],
"\n\ndefine(\'WP_DEBUG\', false);"),
log=False
)
else:
Log.debug(self, "Generating wp-config for WordPress multisite")
Log.debug(self, "bash -c \"php /usr/bin/wp --allow-root "
+ "core config "
+ "--dbname={0} --dbprefix={1} "
.format(data['ee_db_name'], ee_wp_prefix)
+ "--dbuser={0} --dbpass= "
"--extra-php<<PHP \n {2} {3} {4}\nPHP\""
.format(data['ee_db_user'], data['ee_db_pass'],
"\ndefine(\'WP_ALLOW_MULTISITE\', "
"true);",
"\ndefine(\'WPMU_ACCEL_REDIRECT\',"
" true);",
"\n\ndefine(\'WP_DEBUG\', false);"))
EEShellExec.cmd_exec(self, "bash -c \"php /usr/bin/wp --allow-root "
+ "core config "
+ "--dbname={0} --dbprefix={1} "
.format(data['ee_db_name'], ee_wp_prefix)
+ "--dbuser={0} --dbpass={1} "
"--extra-php<<PHP \n {2} {3} {4}\nPHP\""
.format(data['ee_db_user'], data['ee_db_pass'],
"\ndefine(\'WP_ALLOW_MULTISITE\', "
"true);",
"\ndefine(\'WPMU_ACCEL_REDIRECT\',"
" true);",
"\n\ndefine(\'WP_DEBUG\', false);"),
log=False
)
EEFileUtils.mvfile(self, os.getcwd()+'/wp-config.php',
os.path.abspath(os.path.join(os.getcwd(), os.pardir)))
if not ee_wp_user:
ee_wp_user = EEVariables.ee_user
while not ee_wp_user:
Log.warn(self, "Username can have only alphanumeric"
"characters, spaces, underscores, hyphens,"
"periods and the @ symbol.")
try:
ee_wp_user = input('Enter WordPress username: ')
except EOFError as e:
Log.debug(self, "{0}".format(e))
Log.error(self, "Unable to input WordPress user name")
if not ee_wp_pass:
ee_wp_pass = ee_random
if not ee_wp_email:
ee_wp_email = EEVariables.ee_email
while not ee_wp_email:
try:
ee_wp_email = input('Enter WordPress email: ')
except EOFError as e:
Log.debug(self, "{0}".format(e))
Log.error(self, "Unable to input WordPress user email")
Log.debug(self, "Setting up WordPress tables")
if not data['multisite']:
Log.debug(self, "Creating tables for WordPress Single site")
Log.debug(self, "php /usr/bin/wp --allow-root core install "
"--url={0} --title={0} --admin_name={1} "
.format(data['www_domain'], ee_wp_user)
+ "--admin_password= --admin_email={1}"
.format(ee_wp_pass, ee_wp_email))
EEShellExec.cmd_exec(self, "php /usr/bin/wp --allow-root core install "
"--url={0} --title={0} --admin_name={1} "
.format(data['www_domain'], ee_wp_user)
+ "--admin_password={0} --admin_email={1}"
.format(ee_wp_pass, ee_wp_email),
errormsg="Unable to setup WordPress Tables",
log=False)
else:
Log.debug(self, "Creating tables for WordPress multisite")
Log.debug(self, "php /usr/bin/wp --allow-root "
"core multisite-install "
"--url={0} --title={0} --admin_name={1} "
.format(data['www_domain'], ee_wp_user)
+ "--admin_password= --admin_email={1} "
"{subdomains}"
.format(ee_wp_pass, ee_wp_email,
subdomains='--subdomains'
if not data['wpsubdir'] else ''))
EEShellExec.cmd_exec(self, "php /usr/bin/wp --allow-root "
"core multisite-install "
"--url={0} --title={0} --admin_name={1} "
.format(data['www_domain'], ee_wp_user)
+ "--admin_password={0} --admin_email={1} "
"{subdomains}"
.format(ee_wp_pass, ee_wp_email,
subdomains='--subdomains'
if not data['wpsubdir'] else ''),
errormsg="Unable to setup WordPress Tables")
Log.debug(self, "Updating WordPress permalink")
EEShellExec.cmd_exec(self, " php /usr/bin/wp --allow-root "
"rewrite structure "
"/%year%/%monthnum%/%day%/%postname%/",
errormsg="Unable to Update WordPress permalink")
"""Install nginx-helper plugin """
installwp_plugin(self, 'nginx-helper', data)
"""Install Wp Super Cache"""
if data['wpsc']:
installwp_plugin(self, 'wp-super-cache', data)
"""Install W3 Total Cache"""
if data['w3tc'] or data['wpfc']:
installwp_plugin(self, 'w3-total-cache', data)
wp_creds = dict(wp_user=ee_wp_user, wp_pass=ee_wp_pass,
wp_email=ee_wp_email)
return(wp_creds)
def setupwordpressnetwork(self, data):
ee_site_webroot = data['webroot']
EEFileUtils.chdir(self, '{0}/htdocs/'.format(ee_site_webroot))
Log.info(self, "Setting up WordPress Network \t", end='')
EEShellExec.cmd_exec(self, 'wp --allow-root core multisite-convert'
' --title={0} {subdomains}'
.format(data['www_domain'], subdomains='--subdomains'
if not data['wpsubdir'] else ''))
Log.info(self, "[" + Log.ENDC + "Done" + Log.OKBLUE + "]")
def installwp_plugin(self, plugin_name, data):
ee_site_webroot = data['webroot']
Log.debug(self, "Installing plugin {0}".format(plugin_name))
EEFileUtils.chdir(self, '{0}/htdocs/'.format(ee_site_webroot))
EEShellExec.cmd_exec(self, "php /usr/bin/wp plugin --allow-root install "
"{0}".format(plugin_name),
errormsg="Unable to Install plugin {0}"
.format(plugin_name))
EEShellExec.cmd_exec(self, "php /usr/bin/wp plugin --allow-root activate "
"{0} {na}"
.format(plugin_name,
na='--network' if data['multisite'] else ''),
errormsg="Unable to Activate plugin {0}"
.format(plugin_name))
def uninstallwp_plugin(self, plugin_name, data):
ee_site_webroot = data['webroot']
Log.debug(self, "Uninstalling plugin {0}".format(plugin_name))
EEFileUtils.chdir(self, '{0}/htdocs/'.format(ee_site_webroot))
EEShellExec.cmd_exec(self, "php /usr/bin/wp plugin --allow-root uninstall "
"{0}".format(plugin_name),
errormsg="Unable to UnInstall plugin {0}"
.format(plugin_name))
def setwebrootpermissions(self, webroot):
Log.debug(self, "Setting up permissions")
EEFileUtils.chown(self, webroot, EEVariables.ee_php_user,
EEVariables.ee_php_user, recursive=True)
def sitebackup(self, data):
ee_site_webroot = data['webroot']
backup_path = ee_site_webroot + '/backup/{0}'.format(EEVariables.ee_date)
if not EEFileUtils.isexist(self, backup_path):
EEFileUtils.mkdir(self, backup_path)
Log.info(self, "Backup location : {0}".format(backup_path))
EEFileUtils.copyfile(self, '/etc/nginx/sites-available/{0}'
.format(data['site_name']), backup_path)
if data['currsitetype'] in ['html', 'php', 'mysql']:
Log.info(self, "Backing up Webroot \t\t", end='')
EEFileUtils.mvfile(self, ee_site_webroot + '/htdocs', backup_path)
Log.info(self, "[" + Log.ENDC + "Done" + Log.OKBLUE + "]")
configfiles = glob.glob(ee_site_webroot + '/*-config.php')
if configfiles and EEFileUtils.isexist(self, configfiles[0]):
ee_db_name = (EEFileUtils.grep(self, configfiles[0],
'DB_NAME').split(',')[1]
.split(')')[0].strip().replace('\'', ''))
Log.info(self, 'Backing up database \t\t', end='')
EEShellExec.cmd_exec(self, "mysqldump {0} > {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()

96
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")

1466
ee/cli/plugins/stack.py

File diff suppressed because it is too large

159
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)

27
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

61
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;
}
}

17
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

0
ee/cli/templates/__init__.py

8
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;

255
ee/cli/templates/anemometer.mustache

@ -0,0 +1,255 @@
<?php
$conf['datasources']['localhost'] = array(
'host' => '{{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'
),
);
?>

11
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
}

2
ee/cli/templates/blockips.mustache

@ -0,0 +1,2 @@
# Block IP Address
# deny 1.1.1.1;

4
ee/cli/templates/default-sieve.mustache

@ -0,0 +1,4 @@
require "fileinto";
if header :contains "X-Spam-Flag" "YES" {
fileinto "Junk";
}

12
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'

60
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
}

9
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;

9
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}}

10
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}}

35
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}}

65
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;
}

39
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;

10
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;
}

10
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}}

9
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}};
}

662
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 = "<p><strong>NB:</strong> 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

5
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'

5
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'

7
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

34
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;
}

31
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;
}

35
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;
}

36
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";
}

31
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;
}

10
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;
}

0
ee/core/__init__.py

27
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")

78
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 - ")

198
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

23
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)

24
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)

24
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)

43
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

26
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

21
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

224
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))

57
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

43
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)

195
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()

43
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 '<Site %r>' % (self.site_type)
#
# def getType(self):
# return '%r>' % (self.site_type)

62
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()

135
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

51
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))

125
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

0
ee/utils/__init__.py

15
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()

244
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

1
requirements.txt

@ -0,0 +1 @@
cement>=2.4.0

9
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/

109
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
""")

0
tests/__init__.py

76
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()

52
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()

52
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()

52
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()

52
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()

73
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()

16
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()

22
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()

16
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()

73
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()

16
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()

0
tests/cli/__init__.py

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save