From 9cc8e0c432c0bfb0b91ec3b1cf5ae1c4302840ab Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Wed, 22 Oct 2014 11:29:30 +0530 Subject: [PATCH 01/23] new install script --- install_scripts/setup_frappe.sh | 361 ++++++++++++++++++++------------ 1 file changed, 223 insertions(+), 138 deletions(-) diff --git a/install_scripts/setup_frappe.sh b/install_scripts/setup_frappe.sh index ad44508b..251423de 100644 --- a/install_scripts/setup_frappe.sh +++ b/install_scripts/setup_frappe.sh @@ -1,5 +1,34 @@ +#!/bin/bash + set -e + +## Utils + +set_opts () { + OPTS=`getopt -o v --long verbose,mysql-root-password:,frappe-user:,setup-production,help -n 'parse-options' -- "$@"` + + if [ $? != 0 ] ; then echo "Failed parsing options." >&2 ; exit 1 ; fi + + eval set -- "$OPTS" + + VERBOSE=false + HELP=false + FRAPPE_USER=false + + while true; do + case "$1" in + -v | --verbose ) VERBOSE=true; shift ;; + -h | --help ) HELP=true; shift ;; + --mysql-root-password ) MSQ_PASS="$2"; shift; shift ;; + --frappe-user ) FRAPPE_USER="$2"; shift; shift ;; + --setup-production ) SETUP_PROD=true; shift;; + -- ) shift; break ;; + * ) break ;; + esac + done +} + get_distro() { ARCH=$(uname -m | sed 's/x86_/amd/;s/i[3-6]86/x86/') if [ -f /etc/redhat-release ]; then @@ -23,7 +52,18 @@ get_distro() { echo DEBUG $OS $OS_VER $ARCH } -add_centos_mariadb_repo() { +run_cmd() { + if $VERBOSE; then + "$@" + else + # $@ + "$@" > /tmp/cmdoutput.txt 2>&1 || (cat /tmp/cmdoutput.txt && exit 1) + fi +} + +## add repos + +add_centos6_mariadb_repo() { echo " [mariadb] name = MariaDB @@ -32,12 +72,13 @@ gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB gpgcheck=1 " > /etc/yum.repos.d/mariadb.repo } + add_ubuntu_mariadb_repo() { - sudo apt-get update - sudo apt-get install -y python-software-properties - sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xcbcb082a1bb943db - sudo add-apt-repository "deb http://ams2.mirrors.digitalocean.com/mariadb/repo/5.5/ubuntu $OS_VER main" + run_cmd sudo apt-get update + run_cmd sudo apt-get install -y python-software-properties + run_cmd sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xcbcb082a1bb943db + run_cmd sudo add-apt-repository "deb http://ams2.mirrors.digitalocean.com/mariadb/repo/5.5/ubuntu $OS_VER main" } add_debian_mariadb_repo() { @@ -51,129 +92,12 @@ add_debian_mariadb_repo() { exit 1 fi - sudo apt-get update - sudo apt-get install -y python-software-properties - sudo apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 0xcbcb082a1bb943db - sudo add-apt-repository "deb http://ams2.mirrors.digitalocean.com/mariadb/repo/5.5/debian $CODENAME main" + run_cmd sudo apt-get update + run_cmd sudo apt-get install -y python-software-properties + run_cmd sudo apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 0xcbcb082a1bb943db + run_cmd sudo add-apt-repository "deb http://ams2.mirrors.digitalocean.com/mariadb/repo/5.5/debian $CODENAME main" } -add_maria_db_repo() { - if [ "$OS" == "centos" ]; then - echo DEBUG adding centos mariadb repo - add_centos_mariadb_repo - - elif [ "$OS" == "debian" ]; then - echo DEBUG adding debian mariadb repo - add_debian_mariadb_repo - - elif [ "$OS" == "Ubuntu" ]; then - echo DEBUG adding debian mariadb repo - add_ubuntu_mariadb_repo - else - echo Unsupported Distribution - exit 1 - fi -} - -install_packages() { - if [ $OS == "centos" ] && [ $OS_VER == "6" ]; then - sudo yum install wget -y - add_ius_repo - sudo yum groupinstall -y "Development tools" - sudo yum install -y git MariaDB-server MariaDB-client MariaDB-compat python-setuptools nginx zlib-devel bzip2-devel openssl-devel memcached postfix python27-devel python27 libxml2 libxml2-devel libxslt libxslt-devel redis MariaDB-devel libXrender libXext python27-setuptools - wget http://downloads.sourceforge.net/project/wkhtmltopdf/0.12.1/wkhtmltox-0.12.1_linux-centos6-amd64.rpm - sudo rpm -Uvh wkhtmltox-0.12.1_linux-centos6-amd64.rpm - easy_install-2.7 -U pip - - elif [ $OS == "centos" ] && [ $OS_VER == "7" ]; then - sudo yum install wget -y - add_epel_centos7 - sudo yum groupinstall -y "Development tools" - sudo yum install -y git mariadb-server mariadb-server mariadb-devel python-setuptools nginx zlib-devel bzip2-devel openssl-devel memcached postfix python-devel libxml2 libxml2-devel libxslt libxslt-devel redis libXrender libXext supervisor - wget http://downloads.sourceforge.net/project/wkhtmltopdf/0.12.1/wkhtmltox-0.12.1_linux-centos6-amd64.rpm - sudo rpm -Uvh wkhtmltox-0.12.1_linux-centos6-amd64.rpm - easy_install-2.7 -U pip - - elif [ $OS == "debian" ]; then - sudo apt-get update - sudo apt-get install python-dev python-setuptools build-essential python-mysqldb git memcached ntp vim screen htop mariadb-server mariadb-common libmariadbclient-dev libxslt1.1 libxslt1-dev redis-server libssl-dev libcrypto++-dev postfix nginx supervisor python-pip fontconfig libxrender1 -y - - elif [ $OS == "Ubuntu" ]; then - sudo apt-get update - sudo apt-get install python-dev python-setuptools build-essential python-mysqldb git memcached ntp vim screen htop mariadb-server mariadb-common libmariadbclient-dev libxslt1.1 libxslt1-dev redis-server libssl-dev libcrypto++-dev postfix nginx supervisor python-pip fontconfig libxrender1 -y - else - echo Unsupported Distribution - exit 1 - fi -} - -add_user() { -# Check if script is running as root and is not running as sudo. We want to skip -# this step if the user is already running this script with sudo as a non root -# user - if [ $SUDO_UID -eq 0 ] && [ $EUID -eq 0 ]; then - useradd -m -d /home/frappe -s $SHELL frappe - chmod o+x /home/frappe - chmod o+r /home/frappe - export FRAPPE_USER="frappe" - else - export FRAPPE_USER="$SUDO_USER" - fi -} - -configure_mariadb_centos() { - # Required only for CentOS, Ubuntu and Debian will show dpkg configure screen to set the password - if [ $OS == "centos" ]; then - echo Enter mysql root password to set: - read -t 1 -n 10000 discard || true - read -p "Enter mysql root password to set:" -s MSQ_PASS - mysqladmin -u root password $MSQ_PASS - fi -} - -install_supervisor_centos() { - # Required only for CentOS, Ubuntu and Debian have them in repositories - easy_install supervisor - curl https://raw.githubusercontent.com/pdvyas/supervisor-initscripts/master/redhat-init-jkoppe > /etc/init.d/supervisord - curl https://raw.githubusercontent.com/pdvyas/supervisor-initscripts/master/redhat-sysconfig-jkoppe > /etc/sysconfig/supervisord - curl https://raw.githubusercontent.com/pdvyas/supervisor-initscripts/master/supervisord.conf > /etc/supervisord.conf - mkdir /etc/supervisor.d - chmod +x /etc/init.d/supervisord - bash -c "service supervisord start || true" -} - - -start_services_centos() { - service mysql start - service redis start - service postfix start - service nginx start - service memcached start -} - -start_services_centos7() { - systemctl start nginx - systemctl start mariadb - systemctl start redis - systemctl start supervisord -} - -configure_services_centos() { - chkconfig --add supervisord - chkconfig redis on - chkconfig mysql on - chkconfig nginx on - chkconfig supervisord on -} - -configure_services_centos7() { - systemctl enable nginx - systemctl enable mariadb - systemctl enable redis - systemctl enable supervisord -} - - add_ius_repo() { if [ $ARCH == "amd64" ]; then T_ARCH="x86_64" @@ -192,6 +116,128 @@ add_epel_centos7() { yum install -y epel-release } +add_maria_db_repo() { + if [ "$OS" == "centos" ]; then + echo DEBUG adding centos mariadb repo + add_centos6_mariadb_repo + + elif [ "$OS" == "debian" ]; then + echo DEBUG adding debian mariadb repo + add_debian_mariadb_repo + + elif [ "$OS" == "Ubuntu" ]; then + echo DEBUG adding debian mariadb repo + add_ubuntu_mariadb_repo + else + echo Unsupported Distribution + exit 1 + fi +} + +## install + +install_packages() { + if [ $OS == "centos" ]; then + run_cmd sudo yum install wget -y + run_cmd sudo yum groupinstall -y "Development tools" + if [ $OS_VER == "6" ]; then + run_cmd add_ius_repo + run_cmd sudo yum install -y git MariaDB-server MariaDB-client MariaDB-compat python-setuptools nginx zlib-devel bzip2-devel openssl-devel memcached postfix python27-devel python27 libxml2 libxml2-devel libxslt libxslt-devel redis MariaDB-devel libXrender libXext python27-setuptools + elif [ $OS_VER == "7" ]; then + run_cmd add_epel_centos7 + run_cmd sudo yum install -y git mariadb-server mariadb-server mariadb-devel python-setuptools nginx zlib-devel bzip2-devel openssl-devel memcached postfix python-devel libxml2 libxml2-devel libxslt libxslt-devel redis libXrender libXext supervisor + fi + run_cmd wget http://downloads.sourceforge.net/project/wkhtmltopdf/0.12.1/wkhtmltox-0.12.1_linux-centos6-amd64.rpm + run_cmd sudo rpm -Uvh wkhtmltox-0.12.1_linux-centos6-amd64.rpm + run_cmd easy_install-2.7 -U pip + + + elif [ $OS == "debian" ] || [ $OS == "Ubuntu" ]; then + export DEBIAN_FRONTEND=noninteractive + get_mariadb_password + setup_debconf + run_cmd sudo apt-get update + run_cmd sudo apt-get install python-dev python-setuptools build-essential python-mysqldb git memcached ntp vim screen htop mariadb-server mariadb-common libmariadbclient-dev libxslt1.1 libxslt1-dev redis-server libssl-dev libcrypto++-dev postfix nginx supervisor python-pip fontconfig libxrender1 -y + + else + echo Unsupported Distribution + exit 1 + fi +} + + +install_supervisor_centos6() { + run_cmd easy_install supervisor + run_cmd curl https://raw.githubusercontent.com/pdvyas/supervisor-initscripts/master/redhat-init-jkoppe > /etc/init.d/supervisord + run_cmd curl https://raw.githubusercontent.com/pdvyas/supervisor-initscripts/master/redhat-sysconfig-jkoppe > /etc/sysconfig/supervisord + run_cmd curl https://raw.githubusercontent.com/pdvyas/supervisor-initscripts/master/supervisord.conf > /etc/supervisord.conf + run_cmd mkdir /etc/supervisor.d + run_cmd chmod +x /etc/init.d/supervisord + bash -c "service supervisord start || true" +} + +### config + +get_mariadb_password() { + if [ -z "$MSQ_PASS" ]; then + read -t 1 -n 10000 discard || true + echo + read -p "Enter mysql root password to set:" -s MSQ_PASS1 + echo + read -p "Re enter mysql root password to set:" -s MSQ_PASS2 + echo + if [ $MSQ_PASS1 == $MSQ_PASS2 ]; then + export MSQ_PASS=$MSQ_PASS1 + else + echo Passwords do not match + get_mariadb_password + fi + fi +} + +configure_mariadb_centos() { + # Required only for CentOS, Ubuntu and Debian will show dpkg configure screen to set the password + if [ $OS == "centos" ]; then + mysqladmin -u root password $MSQ_PASS + fi +} + +start_services_centos() { + run_cmd systemctl start nginx + run_cmd systemctl start mariadb + run_cmd systemctl start redis + run_cmd systemctl start supervisord +} + +configure_services_centos6() { + run_cmd chkconfig --add supervisord + run_cmd chkconfig redis on + run_cmd chkconfig mysql on + run_cmd chkconfig nginx on + run_cmd chkconfig supervisord on +} + +configure_services_centos7() { + run_cmd systemctl enable nginx + run_cmd systemctl enable mariadb + run_cmd systemctl enable redis + run_cmd systemctl enable supervisord +} + +start_services_centos7() { + run_cmd systemctl start nginx + run_cmd systemctl start mariadb + run_cmd systemctl start redis + run_cmd systemctl start supervisord +} + +setup_debconf() { + debconf-set-selections <<< "postfix postfix/mailname string `hostname`" + debconf-set-selections <<< "postfix postfix/main_mailer_type string 'Internet Site'" + debconf-set-selections <<< "mariadb-server-5.5 mysql-server/root_password password $MSQ_PASS" + debconf-set-selections <<< "mariadb-server-5.5 mysql-server/root_password_again password $MSQ_PASS" +} + install_bench() { sudo su $FRAPPE_USER -c "cd /home/$FRAPPE_USER && git clone https://github.com/frappe/bench bench-repo" if hash pip-2.7; then @@ -206,24 +252,63 @@ install_bench() { echo PIP not installed exit 1 fi - sudo $PIP install -e /home/$FRAPPE_USER/bench-repo + run_cmd sudo $PIP install -e /home/$FRAPPE_USER/bench-repo # temp MariaDB fix sudo bench patch mariadb-config } +setup_bench() { + echo Installing frappe-bench + run_cmd sudo su $FRAPPE_USER -c "cd /home/$FRAPPE_USER && bench init frappe-bench --apps_path https://raw.githubusercontent.com/frappe/bench/master/install_scripts/erpnext-apps.json" + sudo su $FRAPPE_USER -c "cd /home/$FRAPPE_USER/frappe-bench && bench new-site site1.local" + sudo su $FRAPPE_USER -c "cd /home/$FRAPPE_USER/frappe-bench && bench frappe --install_app erpnext" + sudo su $FRAPPE_USER -c "cd /home/$FRAPPE_USER/frappe-bench && bench frappe --install_app shopping_cart" +} + +add_user() { +# Check if script is running as root and is not running as sudo. We want to skip +# this step if the user is already running this script with sudo as a non root +# user + if [ "$FRAPPE_USER" == "false" ]; then + if [ $SUDO_UID -eq 0 ] && [ $EUID -eq 0 ]; then + export FRAPPE_USER="frappe" + else + export FRAPPE_USER="$SUDO_USER" + fi + fi + + USER_EXISTS=`bash -c "id $FRAPPE_USER > /dev/null 2>&1 && echo true || (echo false && exit 0)"` + + if [ $USER_EXISTS == "false" ]; then + useradd -m -d /home/$FRAPPE_USER -s $SHELL $FRAPPE_USER + chmod o+x /home/$FRAPPE_USER + chmod o+r /home/$FRAPPE_USER + fi +} + +set_opts $@ get_distro add_maria_db_repo +echo Installing packages for $OS\. This might take time... install_packages +if [ $OS == "centos" ]; then + if [ $OS_VER == "6" ]; then + echo "Installing supervisor" + install_supervisor_centos6 + echo "Configuring CentOS services" + configure_services_centos6 + echo "Starting services" + start_services_centos6 + elif [ $OS_VER == "7" ]; then + echo "Configuring CentOS services" + configure_services_centos7 + echo "Starting services" + start_services_centos7 + fi +fi +echo "Adding frappe user" +get_mariadb_password +configure_mariadb_centos add_user -if [ $OS == "centos" ] && [ $OS_VER == "6"]; then - install_supervisor_centos - configure_services_centos - start_services_centos - configure_mariadb_centos -fi -if [ $OS == "centos" ] && [ $OS_VER == "7"]; then - configure_services_centos7 - start_services_centos7 - configure_mariadb_centos -fi install_bench +setup_bench From 736d14f9889bcbee1785d576c54b3dc50c920919 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Wed, 22 Oct 2014 12:15:41 +0530 Subject: [PATCH 02/23] pass admin-password and root password to new-site --- bench/cli.py | 6 ++++-- bench/utils.py | 11 +++++++++-- install_scripts/setup_frappe.sh | 26 ++++++++++++++++++-------- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/bench/cli.py b/bench/cli.py index 412d1b1c..548c2af8 100644 --- a/bench/cli.py +++ b/bench/cli.py @@ -83,10 +83,12 @@ def new_app(app_name): _new_app(app_name) @click.command('new-site') +@click.option('--mariadb-root-password', help="MariaDB root password") +@click.option('--admin-password', help="admin password to set for site") @click.argument('site') -def new_site(site): +def new_site(site, mariadb_root_password=None, admin_password=None): "Create a new site in the bench" - _new_site(site) + _new_site(site, mariadb_root_password=mariadb_root_password, admin_password=admin_password) #TODO: Not DRY @click.command('update') diff --git a/bench/utils.py b/bench/utils.py index 72534cbf..43c8f09d 100644 --- a/bench/utils.py +++ b/bench/utils.py @@ -71,9 +71,16 @@ def setup_procfile(bench='.'): worker: sh -c 'cd sites && exec ../env/bin/python -m frappe.celery_app worker' workerbeat: sh -c 'cd sites && exec ../env/bin/python -m frappe.celery_app beat -s scheduler.schedule'""") -def new_site(site, bench='.'): +def new_site(site, mariadb_root_password=None, admin_password=None, bench='.'): logger.info('creating new site {}'.format(site)) - exec_cmd("{frappe} --install {site} {site}".format(frappe=get_frappe(bench=bench), site=site), cwd=os.path.join(bench, 'sites')) + mariadb_root_password_fragment = '--root_password {}'.format(mariadb_root_password) if mariadb_root_password else '' + admin_password_fragment = '--admin_password {}'.format(admin_password) if admin_password else '' + exec_cmd("{frappe} --install {site} {site} {mariadb_root_password_fragment} {admin_password_fragment}".format( + frappe=get_frappe(bench=bench), + site=site, + mariadb_root_password_fragment=mariadb_root_password_fragment, + admin_password_fragment=admin_password_fragment + ), cwd=os.path.join(bench, 'sites')) if len(get_sites(bench=bench)) == 1: exec_cmd("{frappe} --use {site}".format(frappe=get_frappe(bench=bench), site=site), cwd=os.path.join(bench, 'sites')) diff --git a/install_scripts/setup_frappe.sh b/install_scripts/setup_frappe.sh index 251423de..a0084832 100644 --- a/install_scripts/setup_frappe.sh +++ b/install_scripts/setup_frappe.sh @@ -179,18 +179,26 @@ install_supervisor_centos6() { ### config get_mariadb_password() { + get_password "MariaDB root" MSQ_PASS +} + +get_site_admin_password() { + get_password "Admin password" ADMIN_PASS +} + +get_password() { if [ -z "$MSQ_PASS" ]; then read -t 1 -n 10000 discard || true echo - read -p "Enter mysql root password to set:" -s MSQ_PASS1 + read -p "Enter $1 password to set:" -s TMP_PASS1 echo - read -p "Re enter mysql root password to set:" -s MSQ_PASS2 + read -p "Re enter $1 password to set:" -s TMP_PASS2 echo - if [ $MSQ_PASS1 == $MSQ_PASS2 ]; then - export MSQ_PASS=$MSQ_PASS1 + if [ $TMP_PASS1 == $TMP_PASS2 ]; then + export $2=$TMp_PASS1 else echo Passwords do not match - get_mariadb_password + get_password $1 $2 fi fi } @@ -260,9 +268,11 @@ install_bench() { setup_bench() { echo Installing frappe-bench run_cmd sudo su $FRAPPE_USER -c "cd /home/$FRAPPE_USER && bench init frappe-bench --apps_path https://raw.githubusercontent.com/frappe/bench/master/install_scripts/erpnext-apps.json" - sudo su $FRAPPE_USER -c "cd /home/$FRAPPE_USER/frappe-bench && bench new-site site1.local" - sudo su $FRAPPE_USER -c "cd /home/$FRAPPE_USER/frappe-bench && bench frappe --install_app erpnext" - sudo su $FRAPPE_USER -c "cd /home/$FRAPPE_USER/frappe-bench && bench frappe --install_app shopping_cart" + echo Setting up first site + get_site_admin_password + run_cmd sudo su $FRAPPE_USER -c "cd /home/$FRAPPE_USER/frappe-bench && bench new-site site1.local --root-password $MSQ_PASS --admin_password $ADMIN_PASS" + run_cmd sudo su $FRAPPE_USER -c "cd /home/$FRAPPE_USER/frappe-bench && bench frappe --install_app erpnext" + run_cmd sudo su $FRAPPE_USER -c "cd /home/$FRAPPE_USER/frappe-bench && bench frappe --install_app shopping_cart" } add_user() { From 0206dfb7b5504ebded097ef1268300a4cacfea09 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Tue, 4 Nov 2014 16:23:50 +0530 Subject: [PATCH 03/23] add setup production --- bench/cli.py | 7 ++++++- bench/config.py | 3 ++- bench/production_setup.py | 40 +++++++++++++++++++++++++++++++++++++++ bench/utils.py | 13 ++++++++++--- 4 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 bench/production_setup.py diff --git a/bench/cli.py b/bench/cli.py index 548c2af8..db5f586a 100644 --- a/bench/cli.py +++ b/bench/cli.py @@ -16,6 +16,7 @@ from .app import get_app as _get_app from .app import new_app as _new_app from .app import pull_all_apps from .config import generate_nginx_config, generate_supervisor_config +from .production_setup import setup_production as _setup_production import os import sys import logging @@ -225,7 +226,11 @@ def setup_nginx(): def setup_supervisor(): "generate config for supervisor" generate_supervisor_config() - update_config({'restart_supervisor_on_update': True}) + +@click.command('production') +def setup_production(): + "setup bench for production" + _setup_production @click.command('auto-update') def setup_auto_update(): diff --git a/bench/config.py b/bench/config.py index 7d89076a..abb0bf96 100644 --- a/bench/config.py +++ b/bench/config.py @@ -2,7 +2,7 @@ import os import getpass import json from jinja2 import Environment, PackageLoader -from .utils import get_sites, get_config +from .utils import get_sites, get_config, update_config env = Environment(loader=PackageLoader('bench', 'templates'), trim_blocks=True) @@ -22,6 +22,7 @@ def generate_supervisor_config(bench='.'): }) with open("config/supervisor.conf", 'w') as f: f.write(config) + update_config({'restart_supervisor_on_update': True}) def get_site_config(site, bench='.'): with open(os.path.join(bench, 'sites', site, 'site_config.json')) as f: diff --git a/bench/production_setup.py b/bench/production_setup.py new file mode 100644 index 00000000..6aaf4e6d --- /dev/null +++ b/bench/production_setup.py @@ -0,0 +1,40 @@ +from .utils import get_program, exec_cmd, get_cmd_output +from .config import generate_nginx_config, generate_supervisor_config +import os + +def restart_service(service): + program = get_program(['systemctl', 'service']) + if not program: + raise Exception, 'No service manager found' + elif program == 'systemctl': + exec_cmd("{prog} restart {service}".format(prog=program, service=service)) + elif program == 'service': + exec_cmd("{prog} {service} restart ".format(prog=program, service=service)) + +def get_supervisor_confdir(): + possiblities = ('/etc/supervisor/conf.d', '/etc/supervisor.d/', '/etc/supervisord/conf.d') + for possiblity in possiblities: + if os.path.exists(possiblity): + return possiblity + +def remove_default_nginx_configs(): + default_nginx_configs = ['/etc/nginx/conf.d/default.conf', '/etc/nginx/sites-available/default.conf'] + + for conf_file in default_nginx_configs: + if os.path.exists(conf_file): + os.unlink(conf_file) + +def setup_production(bench='.'): + generate_supervisor_config(bench=bench) + generate_nginx_config(bench=bench) + remove_default_nginx_configs() + + if os.path.exists('/etc/redhat-release') and get_cmd_output("cat /etc/redhat-release | sed 's/Linux\ //g' | cut -d" " -f3 | cut -d. -f1") == '7': + supervisor_conf_filename = 'frappe.ini' + else: + supervisor_conf_filename = 'frappe.conf' + + os.symlink(os.path.abspath(os.path.join(bench, 'config', 'supervisor.conf')), os.path.join(get_supervisor_confdir(), supervisor_conf_filename)) + os.symlink(os.path.abspath(os.path.join(bench, 'config', 'supervisor.conf')), '/etc/nginx/conf.d/frappe.conf') + exec_cmd('supervisorctl reload') + restart_service('nginx') diff --git a/bench/utils.py b/bench/utils.py index 43c8f09d..8508243f 100644 --- a/bench/utils.py +++ b/bench/utils.py @@ -136,10 +136,12 @@ def update_bench(): exec_cmd("git pull", cwd=cwd) def setup_sudoers(user): - with open('/etc/sudoers.d/frappe', 'w') as f: + sudoers_file = '/etc/sudoers.d/frappe' + with open(sudoers_file, 'w') as f: f.write("{user} ALL=(ALL) NOPASSWD: {supervisorctl} restart frappe\:\n".format( user=user, supervisorctl=subprocess.check_output('which supervisorctl', shell=True).strip())) + os.chmod(sudoers_file, 0440) def setup_logging(bench='.'): if os.path.exists(os.path.join(bench, 'logs')): @@ -167,8 +169,7 @@ def update_config(new_config, bench='.'): config.update(new_config) put_config(config, bench=bench) -def get_process_manager(): - programs = ['foreman', 'forego', 'honcho'] +def get_program(programs): program = None for p in programs: program = find_executable(p) @@ -176,6 +177,9 @@ def get_process_manager(): break return program +def get_process_manager(): + return get_program(['foreman', 'forego', 'honcho']) + def start(): program = get_process_manager() if not program: @@ -269,3 +273,6 @@ def prime_wheel_cache(bench='.'): wheelhouse=wheel_cache_dir, requirements=requirements) exec_cmd(cmd) + +def is_root(): + pass From c2d58a2789a72f4ef405088b8b9918b8d9fa3520 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Tue, 4 Nov 2014 16:27:56 +0530 Subject: [PATCH 04/23] fix setup production --- bench/cli.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bench/cli.py b/bench/cli.py index db5f586a..96d6b7bf 100644 --- a/bench/cli.py +++ b/bench/cli.py @@ -270,6 +270,7 @@ setup.add_command(setup_backups) setup.add_command(setup_env) setup.add_command(setup_procfile) setup.add_command(setup_config) +setup.add_command(setup_production) ## Config ## Not DRY From 2509347b4de110894dbec08518a62ed9c4e40693 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Tue, 4 Nov 2014 18:13:18 +0530 Subject: [PATCH 05/23] fix setup production --- bench/cli.py | 2 +- bench/production_setup.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bench/cli.py b/bench/cli.py index 96d6b7bf..2daea818 100644 --- a/bench/cli.py +++ b/bench/cli.py @@ -230,7 +230,7 @@ def setup_supervisor(): @click.command('production') def setup_production(): "setup bench for production" - _setup_production + _setup_production() @click.command('auto-update') def setup_auto_update(): diff --git a/bench/production_setup.py b/bench/production_setup.py index 6aaf4e6d..4c03a63c 100644 --- a/bench/production_setup.py +++ b/bench/production_setup.py @@ -12,7 +12,7 @@ def restart_service(service): exec_cmd("{prog} {service} restart ".format(prog=program, service=service)) def get_supervisor_confdir(): - possiblities = ('/etc/supervisor/conf.d', '/etc/supervisor.d/', '/etc/supervisord/conf.d') + possiblities = ('/etc/supervisor/conf.d', '/etc/supervisor.d/', '/etc/supervisord/conf.d', '/etc/supervisord.d') for possiblity in possiblities: if os.path.exists(possiblity): return possiblity @@ -35,6 +35,6 @@ def setup_production(bench='.'): supervisor_conf_filename = 'frappe.conf' os.symlink(os.path.abspath(os.path.join(bench, 'config', 'supervisor.conf')), os.path.join(get_supervisor_confdir(), supervisor_conf_filename)) - os.symlink(os.path.abspath(os.path.join(bench, 'config', 'supervisor.conf')), '/etc/nginx/conf.d/frappe.conf') + os.symlink(os.path.abspath(os.path.join(bench, 'config', 'nginx.conf')), '/etc/nginx/conf.d/frappe.conf') exec_cmd('supervisorctl reload') restart_service('nginx') From 3c8de42f516bae7ef74e7ad454279d0909ab2c9f Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Tue, 4 Nov 2014 18:14:23 +0530 Subject: [PATCH 06/23] fix setup production --- bench/production_setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench/production_setup.py b/bench/production_setup.py index 4c03a63c..3848446d 100644 --- a/bench/production_setup.py +++ b/bench/production_setup.py @@ -29,7 +29,7 @@ def setup_production(bench='.'): generate_nginx_config(bench=bench) remove_default_nginx_configs() - if os.path.exists('/etc/redhat-release') and get_cmd_output("cat /etc/redhat-release | sed 's/Linux\ //g' | cut -d" " -f3 | cut -d. -f1") == '7': + if os.path.exists('/etc/redhat-release') and get_cmd_output("cat /etc/redhat-release | sed 's/Linux\ //g' | cut -d' ' -f3 | cut -d. -f1") == '7': supervisor_conf_filename = 'frappe.ini' else: supervisor_conf_filename = 'frappe.conf' From bbcc8d1745e0dbe498e083c898dd1f90f8fdc45f Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Tue, 4 Nov 2014 18:16:34 +0530 Subject: [PATCH 07/23] fix setup production --- bench/production_setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench/production_setup.py b/bench/production_setup.py index 3848446d..a3223568 100644 --- a/bench/production_setup.py +++ b/bench/production_setup.py @@ -29,7 +29,7 @@ def setup_production(bench='.'): generate_nginx_config(bench=bench) remove_default_nginx_configs() - if os.path.exists('/etc/redhat-release') and get_cmd_output("cat /etc/redhat-release | sed 's/Linux\ //g' | cut -d' ' -f3 | cut -d. -f1") == '7': + if os.path.exists('/etc/redhat-release') and get_cmd_output("cat /etc/redhat-release | sed 's/Linux\ //g' | cut -d' ' -f3 | cut -d. -f1").strip() == '7': supervisor_conf_filename = 'frappe.ini' else: supervisor_conf_filename = 'frappe.conf' From 80bf4feeed298f01cdb0253a0dd5e8f219b2131b Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Tue, 4 Nov 2014 18:21:09 +0530 Subject: [PATCH 08/23] fix setup production --- bench/production_setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bench/production_setup.py b/bench/production_setup.py index a3223568..ee0a1b11 100644 --- a/bench/production_setup.py +++ b/bench/production_setup.py @@ -6,9 +6,9 @@ def restart_service(service): program = get_program(['systemctl', 'service']) if not program: raise Exception, 'No service manager found' - elif program == 'systemctl': + elif os.path.basename(program) == 'systemctl': exec_cmd("{prog} restart {service}".format(prog=program, service=service)) - elif program == 'service': + elif os.path.basename(program) == 'service': exec_cmd("{prog} {service} restart ".format(prog=program, service=service)) def get_supervisor_confdir(): From 7363c9d2b9714630ef73d08ea9900a122ee9872c Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Wed, 5 Nov 2014 11:44:03 +0530 Subject: [PATCH 09/23] fix nginx config list to remove --- bench/production_setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench/production_setup.py b/bench/production_setup.py index ee0a1b11..1b7aa05a 100644 --- a/bench/production_setup.py +++ b/bench/production_setup.py @@ -18,7 +18,7 @@ def get_supervisor_confdir(): return possiblity def remove_default_nginx_configs(): - default_nginx_configs = ['/etc/nginx/conf.d/default.conf', '/etc/nginx/sites-available/default.conf'] + default_nginx_configs = ['/etc/nginx/conf.d/default.conf', '/etc/nginx/sites-enabled/default'] for conf_file in default_nginx_configs: if os.path.exists(conf_file): From eb8778f0845b6d391dd3b9c557cfce6c6f9d4426 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Wed, 5 Nov 2014 11:45:00 +0530 Subject: [PATCH 10/23] fixes to new script --- install_scripts/setup_frappe.sh | 88 +++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 32 deletions(-) diff --git a/install_scripts/setup_frappe.sh b/install_scripts/setup_frappe.sh index a0084832..ef5bcd83 100644 --- a/install_scripts/setup_frappe.sh +++ b/install_scripts/setup_frappe.sh @@ -5,6 +5,17 @@ set -e ## Utils +print_msg() { + echo "Frappe/ERPNext is installed successfully." + echo "Frappe password: $FRAPPE_USER_PASS" + echo "MariaDB root password: $MSQ_PASS" + echo "Administrator password: $ADMIN_PASS" +} + +get_passwd() { + echo `cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1` +} + set_opts () { OPTS=`getopt -o v --long verbose,mysql-root-password:,frappe-user:,setup-production,help -n 'parse-options' -- "$@"` @@ -15,6 +26,10 @@ set_opts () { VERBOSE=false HELP=false FRAPPE_USER=false + FRAPPE_USER_PASS=`get_passwd` + MSQ_PASS=`get_passwd` + ADMIN_PASS=`get_passwd` + SETUP_PROD=false while true; do case "$1" in @@ -145,7 +160,7 @@ install_packages() { run_cmd sudo yum install -y git MariaDB-server MariaDB-client MariaDB-compat python-setuptools nginx zlib-devel bzip2-devel openssl-devel memcached postfix python27-devel python27 libxml2 libxml2-devel libxslt libxslt-devel redis MariaDB-devel libXrender libXext python27-setuptools elif [ $OS_VER == "7" ]; then run_cmd add_epel_centos7 - run_cmd sudo yum install -y git mariadb-server mariadb-server mariadb-devel python-setuptools nginx zlib-devel bzip2-devel openssl-devel memcached postfix python-devel libxml2 libxml2-devel libxslt libxslt-devel redis libXrender libXext supervisor + run_cmd sudo yum install -y git mariadb-server mariadb-devel python-setuptools nginx zlib-devel bzip2-devel openssl-devel memcached postfix python-devel libxml2 libxml2-devel libxslt libxslt-devel redis libXrender libXext supervisor fi run_cmd wget http://downloads.sourceforge.net/project/wkhtmltopdf/0.12.1/wkhtmltox-0.12.1_linux-centos6-amd64.rpm run_cmd sudo rpm -Uvh wkhtmltox-0.12.1_linux-centos6-amd64.rpm @@ -154,7 +169,6 @@ install_packages() { elif [ $OS == "debian" ] || [ $OS == "Ubuntu" ]; then export DEBIAN_FRONTEND=noninteractive - get_mariadb_password setup_debconf run_cmd sudo apt-get update run_cmd sudo apt-get install python-dev python-setuptools build-essential python-mysqldb git memcached ntp vim screen htop mariadb-server mariadb-common libmariadbclient-dev libxslt1.1 libxslt1-dev redis-server libssl-dev libcrypto++-dev postfix nginx supervisor python-pip fontconfig libxrender1 -y @@ -187,7 +201,7 @@ get_site_admin_password() { } get_password() { - if [ -z "$MSQ_PASS" ]; then + if [ -z "$2" ]; then read -t 1 -n 10000 discard || true echo read -p "Enter $1 password to set:" -s TMP_PASS1 @@ -230,6 +244,7 @@ configure_services_centos7() { run_cmd systemctl enable mariadb run_cmd systemctl enable redis run_cmd systemctl enable supervisord + run_cmd systemctl enable memcached } start_services_centos7() { @@ -237,6 +252,7 @@ start_services_centos7() { run_cmd systemctl start mariadb run_cmd systemctl start redis run_cmd systemctl start supervisord + run_cmd systemctl start memcached } setup_debconf() { @@ -247,7 +263,8 @@ setup_debconf() { } install_bench() { - sudo su $FRAPPE_USER -c "cd /home/$FRAPPE_USER && git clone https://github.com/frappe/bench bench-repo" + echo WARNING BENCH INSTALLING FROM ANOTHER BRANCH + run_cmd sudo su $FRAPPE_USER -c "cd /home/$FRAPPE_USER && git clone https://github.com/frappe/bench --branch v0.9wip bench-repo" if hash pip-2.7; then PIP="pip-2.7" elif hash pip2.7; then @@ -269,10 +286,13 @@ setup_bench() { echo Installing frappe-bench run_cmd sudo su $FRAPPE_USER -c "cd /home/$FRAPPE_USER && bench init frappe-bench --apps_path https://raw.githubusercontent.com/frappe/bench/master/install_scripts/erpnext-apps.json" echo Setting up first site - get_site_admin_password - run_cmd sudo su $FRAPPE_USER -c "cd /home/$FRAPPE_USER/frappe-bench && bench new-site site1.local --root-password $MSQ_PASS --admin_password $ADMIN_PASS" + run_cmd sudo su $FRAPPE_USER -c "cd /home/$FRAPPE_USER/frappe-bench && bench new-site site1.local --mariadb-root-password $MSQ_PASS --admin-password $ADMIN_PASS" run_cmd sudo su $FRAPPE_USER -c "cd /home/$FRAPPE_USER/frappe-bench && bench frappe --install_app erpnext" run_cmd sudo su $FRAPPE_USER -c "cd /home/$FRAPPE_USER/frappe-bench && bench frappe --install_app shopping_cart" + run_cmd bash -c "cd /home/$FRAPPE_USER/frappe-bench && bench setup sudoers $FRAPPE_USER" + if $SETUP_PROD; then + run_cmd bash -c "cd /home/$FRAPPE_USER/frappe-bench && bench setup production" + fi } add_user() { @@ -280,7 +300,7 @@ add_user() { # this step if the user is already running this script with sudo as a non root # user if [ "$FRAPPE_USER" == "false" ]; then - if [ $SUDO_UID -eq 0 ] && [ $EUID -eq 0 ]; then + if [[ $SUDO_UID -eq 0 ]] && [[ $EUID -eq 0 ]]; then export FRAPPE_USER="frappe" else export FRAPPE_USER="$SUDO_USER" @@ -291,34 +311,38 @@ add_user() { if [ $USER_EXISTS == "false" ]; then useradd -m -d /home/$FRAPPE_USER -s $SHELL $FRAPPE_USER + echo $FRAPPE_USER:$FRAPPE_USER_PASS | chpasswd chmod o+x /home/$FRAPPE_USER chmod o+r /home/$FRAPPE_USER fi } -set_opts $@ -get_distro -add_maria_db_repo -echo Installing packages for $OS\. This might take time... -install_packages -if [ $OS == "centos" ]; then - if [ $OS_VER == "6" ]; then - echo "Installing supervisor" - install_supervisor_centos6 - echo "Configuring CentOS services" - configure_services_centos6 - echo "Starting services" - start_services_centos6 - elif [ $OS_VER == "7" ]; then - echo "Configuring CentOS services" - configure_services_centos7 - echo "Starting services" - start_services_centos7 +main() { + set_opts $@ + get_distro + add_maria_db_repo + echo Installing packages for $OS\. This might take time... + install_packages + if [ $OS == "centos" ]; then + if [ $OS_VER == "6" ]; then + echo "Installing supervisor" + install_supervisor_centos6 + echo "Configuring CentOS services" + configure_services_centos6 + echo "Starting services" + start_services_centos6 + elif [ $OS_VER == "7" ]; then + echo "Configuring CentOS services" + configure_services_centos7 + echo "Starting services" + start_services_centos7 + fi fi -fi -echo "Adding frappe user" -get_mariadb_password -configure_mariadb_centos -add_user -install_bench -setup_bench + echo "Adding frappe user" + add_user + install_bench + setup_bench + print_msg +} + +main From 6476c7eb72a53fc502b7476f46c9e92a2995286e Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Fri, 7 Nov 2014 16:16:26 +0530 Subject: [PATCH 11/23] raise error if not root for setup production and sudoers command --- bench/cli.py | 8 +++++++- bench/utils.py | 4 +++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/bench/cli.py b/bench/cli.py index 2daea818..3661ade8 100644 --- a/bench/cli.py +++ b/bench/cli.py @@ -11,7 +11,7 @@ from .utils import set_nginx_port as _set_nginx_port from .utils import set_default_site as _set_default_site from .utils import (build_assets, patch_sites, exec_cmd, update_bench, get_frappe, setup_logging, get_config, update_config, restart_supervisor_processes, put_config, default_config, update_requirements, - backup_all_sites, backup_site, get_sites, prime_wheel_cache) + backup_all_sites, backup_site, get_sites, prime_wheel_cache, is_root) from .app import get_app as _get_app from .app import new_app as _new_app from .app import pull_all_apps @@ -215,6 +215,9 @@ def setup(): @click.argument('user') def setup_sudoers(user): "Add commands to sudoers list for execution without password" + if not is_root(): + print 'superuser privileges required for this command' + sys.exit(1) _setup_sudoers(user) @click.command('nginx') @@ -230,6 +233,9 @@ def setup_supervisor(): @click.command('production') def setup_production(): "setup bench for production" + if not is_root(): + print 'superuser privileges required for this command' + sys.exit(1) _setup_production() @click.command('auto-update') diff --git a/bench/utils.py b/bench/utils.py index 8508243f..b42e6baf 100644 --- a/bench/utils.py +++ b/bench/utils.py @@ -275,4 +275,6 @@ def prime_wheel_cache(bench='.'): exec_cmd(cmd) def is_root(): - pass + if os.getuid() == 0: + return True + return False From 585d041b19fa1ec7f7247cab529ba0b88476dac5 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Fri, 7 Nov 2014 20:12:42 +0530 Subject: [PATCH 12/23] check for roor, change dir and change user on init --- bench/cli.py | 31 +++++++++++++++++++++++++------ bench/utils.py | 1 + 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/bench/cli.py b/bench/cli.py index 3661ade8..61fd246b 100644 --- a/bench/cli.py +++ b/bench/cli.py @@ -21,14 +21,39 @@ import os import sys import logging import copy +import pwd logger = logging.getLogger('bench') def cli(): + check_uid() + change_dir() + change_uid() if len(sys.argv) > 2 and sys.argv[1] == "frappe": return frappe() return bench() +def check_uid(): + if len(sys.argv) > 3 and sys.argv[2] in ('production', 'sudoers') and not is_root(): + print 'superuser privileges required for this command' + sys.exit(1) + +def change_uid(): + if is_root(): + frappe_user = get_config().get('frappe_user') + if frappe_user: + os.setuid(pwd.getpwnam(frappe_user).pw_uid) + else: + print 'You should not run this command as root' + sys.exit(1) + +def change_dir(): + dir_path_file = '/etc/frappe_bench_dir' + if os.path.exists(dir_path_file): + with open(dir_path_file) as f: + dir_path = f.read().strip() + os.chdir(dir_path) + def frappe(bench='.'): f = get_frappe(bench=bench) os.chdir(os.path.join(bench, 'sites')) @@ -215,9 +240,6 @@ def setup(): @click.argument('user') def setup_sudoers(user): "Add commands to sudoers list for execution without password" - if not is_root(): - print 'superuser privileges required for this command' - sys.exit(1) _setup_sudoers(user) @click.command('nginx') @@ -233,9 +255,6 @@ def setup_supervisor(): @click.command('production') def setup_production(): "setup bench for production" - if not is_root(): - print 'superuser privileges required for this command' - sys.exit(1) _setup_production() @click.command('auto-update') diff --git a/bench/utils.py b/bench/utils.py index b42e6baf..7cd121a2 100644 --- a/bench/utils.py +++ b/bench/utils.py @@ -14,6 +14,7 @@ default_config = { 'serve_default_site': True, 'rebase_on_pull': False, 'update_bench_on_update': True, + 'frappe_user': getpass.getuser(), 'shallow_clone': True } From 9cc3c4492b32a3bd58c6d6e51b1dee32767f13b4 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Fri, 7 Nov 2014 20:19:13 +0530 Subject: [PATCH 13/23] add set-mariadb-host --- bench/cli.py | 10 +++++++++- bench/utils.py | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/bench/cli.py b/bench/cli.py index 61fd246b..5d894d2c 100644 --- a/bench/cli.py +++ b/bench/cli.py @@ -8,10 +8,11 @@ from .utils import setup_sudoers as _setup_sudoers from .utils import start as _start from .utils import setup_procfile as _setup_procfile from .utils import set_nginx_port as _set_nginx_port +from .utils import set_nginx_port as _set_nginx_port from .utils import set_default_site as _set_default_site from .utils import (build_assets, patch_sites, exec_cmd, update_bench, get_frappe, setup_logging, get_config, update_config, restart_supervisor_processes, put_config, default_config, update_requirements, - backup_all_sites, backup_site, get_sites, prime_wheel_cache, is_root) + backup_all_sites, backup_site, get_sites, prime_wheel_cache, is_root, set_mariadb_host) from .app import get_app as _get_app from .app import new_app as _new_app from .app import pull_all_apps @@ -196,6 +197,12 @@ def set_nginx_port(site, port): "Set nginx port for site" _set_nginx_port(site, port) +@click.command('set-mariadb-host') +@click.argument('host') +def _set_mariadb_host(host): + "Set MariaDB host for bench" + set_mariadb_host(host) + @click.command('set-default-site') @click.argument('site') def set_default_site(site): @@ -384,6 +391,7 @@ bench.add_command(restart) bench.add_command(config) bench.add_command(start) bench.add_command(set_nginx_port) +bench.add_command(_set_mariadb_host) bench.add_command(set_default_site) bench.add_command(migrate_3to4) bench.add_command(shell) diff --git a/bench/utils.py b/bench/utils.py index 7cd121a2..6c68ebf5 100644 --- a/bench/utils.py +++ b/bench/utils.py @@ -279,3 +279,17 @@ def is_root(): if os.getuid() == 0: return True return False + +def set_mariadb_host(host, bench='.'): + update_common_site_config({'db_host': host}, bench=bench) + +def update_common_site_config(ddict, bench='.'): + update_json_file(os.path.join(bench, 'sites', 'common_site_config.json'), ddict) + +def update_json_file(filename, ddict): + with open(filename, 'r') as f: + content = json.load(f) + content.update(ddict) + with open(filename, 'w') as f: + content = json.dump(content, f, indent=1) + From 6a100e22ba212db6905807d6be49ae2995401599 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Mon, 10 Nov 2014 14:56:09 +0530 Subject: [PATCH 14/23] fix cmd_requires_root logic --- bench/cli.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/bench/cli.py b/bench/cli.py index 5d894d2c..a87eca09 100644 --- a/bench/cli.py +++ b/bench/cli.py @@ -34,13 +34,20 @@ def cli(): return frappe() return bench() +def cmd_requires_root(): + print sys.argv + if len(sys.argv) > 3 and sys.argv[2] in ('production', 'sudoers'): + return True + if len(sys.argv) > 2 and sys.argv[1] in ('patch',): + return True + def check_uid(): - if len(sys.argv) > 3 and sys.argv[2] in ('production', 'sudoers') and not is_root(): + if cmd_requires_root() and not is_root(): print 'superuser privileges required for this command' sys.exit(1) def change_uid(): - if is_root(): + if is_root() and not cmd_requires_root(): frappe_user = get_config().get('frappe_user') if frappe_user: os.setuid(pwd.getpwnam(frappe_user).pw_uid) From 2e38e0ee379454b9e31d0afc24c4efa978246a05 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Mon, 10 Nov 2014 16:03:23 +0530 Subject: [PATCH 15/23] use seteuid instead of setuid --- bench/cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bench/cli.py b/bench/cli.py index a87eca09..50dd1c83 100644 --- a/bench/cli.py +++ b/bench/cli.py @@ -35,7 +35,6 @@ def cli(): return bench() def cmd_requires_root(): - print sys.argv if len(sys.argv) > 3 and sys.argv[2] in ('production', 'sudoers'): return True if len(sys.argv) > 2 and sys.argv[1] in ('patch',): @@ -50,7 +49,8 @@ def change_uid(): if is_root() and not cmd_requires_root(): frappe_user = get_config().get('frappe_user') if frappe_user: - os.setuid(pwd.getpwnam(frappe_user).pw_uid) + os.seteuid(pwd.getpwnam(frappe_user).pw_uid) + os.environ['HOME'] = pwd.getpwnam(frappe_user).pw_dir else: print 'You should not run this command as root' sys.exit(1) From af1da4acf24a0474f6a8b258707134d6dd2d3e91 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Mon, 10 Nov 2014 17:09:05 +0530 Subject: [PATCH 16/23] fix cmd_requires_root logic --- bench/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench/cli.py b/bench/cli.py index 50dd1c83..2c6caf58 100644 --- a/bench/cli.py +++ b/bench/cli.py @@ -35,7 +35,7 @@ def cli(): return bench() def cmd_requires_root(): - if len(sys.argv) > 3 and sys.argv[2] in ('production', 'sudoers'): + if len(sys.argv) > 2 and sys.argv[2] in ('production', 'sudoers'): return True if len(sys.argv) > 2 and sys.argv[1] in ('patch',): return True From 3cfdf6972c46f2dc86e12e0c258a217676a11b59 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Mon, 10 Nov 2014 21:21:45 +0530 Subject: [PATCH 17/23] better drop_privileges --- bench/cli.py | 6 +++--- bench/utils.py | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/bench/cli.py b/bench/cli.py index 2c6caf58..28cb458e 100644 --- a/bench/cli.py +++ b/bench/cli.py @@ -11,8 +11,8 @@ from .utils import set_nginx_port as _set_nginx_port from .utils import set_nginx_port as _set_nginx_port from .utils import set_default_site as _set_default_site from .utils import (build_assets, patch_sites, exec_cmd, update_bench, get_frappe, setup_logging, - get_config, update_config, restart_supervisor_processes, put_config, default_config, update_requirements, - backup_all_sites, backup_site, get_sites, prime_wheel_cache, is_root, set_mariadb_host) + get_config, update_config, restart_supervisor_processes, put_config, default_config, update_requirements, + backup_all_sites, backup_site, get_sites, prime_wheel_cache, is_root, set_mariadb_host, drop_privileges) from .app import get_app as _get_app from .app import new_app as _new_app from .app import pull_all_apps @@ -49,7 +49,7 @@ def change_uid(): if is_root() and not cmd_requires_root(): frappe_user = get_config().get('frappe_user') if frappe_user: - os.seteuid(pwd.getpwnam(frappe_user).pw_uid) + drop_privileges(uid_name=frappe_user, gid_name=frappe_user) os.environ['HOME'] = pwd.getpwnam(frappe_user).pw_dir else: print 'You should not run this command as root' diff --git a/bench/utils.py b/bench/utils.py index 6c68ebf5..b1812438 100644 --- a/bench/utils.py +++ b/bench/utils.py @@ -293,3 +293,22 @@ def update_json_file(filename, ddict): with open(filename, 'w') as f: content = json.dump(content, f, indent=1) +def drop_privileges(uid_name='nobody', gid_name='nogroup'): + # from http://stackoverflow.com/a/2699996 + if os.getuid() != 0: + # We're not root so, like, whatever dude + return + + # Get the uid/gid from the name + running_uid = pwd.getpwnam(uid_name).pw_uid + running_gid = grp.getgrnam(gid_name).gr_gid + + # Remove group privileges + os.setgroups([]) + + # Try setting the new uid/gid + os.setgid(running_gid) + os.setuid(running_uid) + + # Ensure a very conservative umask + old_umask = os.umask(077) From 0608f04d7ead45a23bb9515d2d2bccbd97ec08bc Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Tue, 11 Nov 2014 09:42:17 +0530 Subject: [PATCH 18/23] replace default nginx config in case of centos7 --- bench/production_setup.py | 12 +++++++- bench/templates/nginx_default.conf | 44 ++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 bench/templates/nginx_default.conf diff --git a/bench/production_setup.py b/bench/production_setup.py index 1b7aa05a..164b649a 100644 --- a/bench/production_setup.py +++ b/bench/production_setup.py @@ -1,6 +1,8 @@ from .utils import get_program, exec_cmd, get_cmd_output from .config import generate_nginx_config, generate_supervisor_config +from jinja2 import Environment, PackageLoader import os +import shutil def restart_service(service): program = get_program(['systemctl', 'service']) @@ -24,12 +26,20 @@ def remove_default_nginx_configs(): if os.path.exists(conf_file): os.unlink(conf_file) + +def is_centos7(): + return os.path.exists('/etc/redhat-release') and get_cmd_output("cat /etc/redhat-release | sed 's/Linux\ //g' | cut -d' ' -f3 | cut -d. -f1").strip() == '7' + + +def copy_default_nginx_config(): + shutil.copy(os.path.join(os.path.dirname(__file__), 'templates', 'nginx_default.conf'), '/etc/nginx/nginx.conf') + def setup_production(bench='.'): generate_supervisor_config(bench=bench) generate_nginx_config(bench=bench) remove_default_nginx_configs() - if os.path.exists('/etc/redhat-release') and get_cmd_output("cat /etc/redhat-release | sed 's/Linux\ //g' | cut -d' ' -f3 | cut -d. -f1").strip() == '7': + if is_centos7(): supervisor_conf_filename = 'frappe.ini' else: supervisor_conf_filename = 'frappe.conf' diff --git a/bench/templates/nginx_default.conf b/bench/templates/nginx_default.conf new file mode 100644 index 00000000..a7604841 --- /dev/null +++ b/bench/templates/nginx_default.conf @@ -0,0 +1,44 @@ +# For more information on configuration, see: +# * Official English Documentation: http://nginx.org/en/docs/ +# * Official Russian Documentation: http://nginx.org/ru/docs/ + +user nginx; +worker_processes 1; + +error_log /var/log/nginx/error.log; +#error_log /var/log/nginx/error.log notice; +#error_log /var/log/nginx/error.log info; + +pid /run/nginx.pid; + + +events { + worker_connections 1024; +} + + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + #tcp_nopush on; + + #keepalive_timeout 0; + keepalive_timeout 65; + + #gzip on; + + index index.html index.htm; + + # Load modular configuration files from the /etc/nginx/conf.d directory. + # See http://nginx.org/en/docs/ngx_core_module.html#include + # for more information. + include /etc/nginx/conf.d/*.conf; +} \ No newline at end of file From 07f770486c55e7d01f31e5035ae0dd670d2f8322 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Tue, 11 Nov 2014 09:43:37 +0530 Subject: [PATCH 19/23] ad missing imports --- bench/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bench/utils.py b/bench/utils.py index b1812438..e199669f 100644 --- a/bench/utils.py +++ b/bench/utils.py @@ -5,6 +5,7 @@ import getpass import logging import json from distutils.spawn import find_executable +import pwd, grp logger = logging.getLogger(__name__) From 5319ee50d2d7f2d98df35be0b46687cdc2275601 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Tue, 11 Nov 2014 10:09:34 +0530 Subject: [PATCH 20/23] missing function call --- bench/production_setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bench/production_setup.py b/bench/production_setup.py index 164b649a..9719b8fa 100644 --- a/bench/production_setup.py +++ b/bench/production_setup.py @@ -41,6 +41,7 @@ def setup_production(bench='.'): if is_centos7(): supervisor_conf_filename = 'frappe.ini' + copy_default_nginx_config() else: supervisor_conf_filename = 'frappe.conf' From 388a3958030581cb9b19dd709bbef917677419cf Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Tue, 11 Nov 2014 10:46:55 +0530 Subject: [PATCH 21/23] fix install script --- install_scripts/setup_frappe.sh | 95 ++++++++++++++++++++++++--------- 1 file changed, 71 insertions(+), 24 deletions(-) diff --git a/install_scripts/setup_frappe.sh b/install_scripts/setup_frappe.sh index ef5bcd83..6c6fdada 100644 --- a/install_scripts/setup_frappe.sh +++ b/install_scripts/setup_frappe.sh @@ -6,7 +6,6 @@ set -e ## Utils print_msg() { - echo "Frappe/ERPNext is installed successfully." echo "Frappe password: $FRAPPE_USER_PASS" echo "MariaDB root password: $MSQ_PASS" echo "Administrator password: $ADMIN_PASS" @@ -46,6 +45,15 @@ set_opts () { get_distro() { ARCH=$(uname -m | sed 's/x86_/amd/;s/i[3-6]86/x86/') + + if [ $ARCH == "amd64" ]; then + T_ARCH="x86_64" + WK_ARCH="amd64" + else + T_ARCH="i386" + WK_ARCH="i386" + fi + if [ -f /etc/redhat-release ]; then OS="centos" OS_VER=`cat /etc/redhat-release | sed 's/Linux\ //g' | cut -d" " -f3 | cut -d. -f1` @@ -64,7 +72,9 @@ get_distro() { export OS=$OS export OS_VER=$OS_VER export ARCH=$ARCH - echo DEBUG $OS $OS_VER $ARCH + export T_ARCH=$T_ARCH + export WK_ARCH=$WK_ARCH + echo DEBUG $OS $OS_VER $ARCH $WK_ARCH } run_cmd() { @@ -114,16 +124,11 @@ add_debian_mariadb_repo() { } add_ius_repo() { - if [ $ARCH == "amd64" ]; then - T_ARCH="x86_64" - else - T_ARCH="i386" - fi if [ $OS_VER -eq "6" ]; then wget http://dl.iuscommunity.org/pub/ius/stable/CentOS/$OS_VER/$T_ARCH/epel-release-6-5.noarch.rpm wget http://dl.iuscommunity.org/pub/ius/stable/CentOS/$OS_VER/$T_ARCH/ius-release-1.0-13.ius.centos6.noarch.rpm - rpm -Uvh epel-release-6-5.noarch.rpm - rpm -Uvh ius-release-1.0-13.ius.centos6.noarch.rpm + rpm --quiet -q epel-release || rpm -Uvh epel-release-6-5.noarch.rpm + rpm --quiet -q ius-release || rpm -Uvh ius-release-1.0-13.ius.centos6.noarch.rpm fi } @@ -133,15 +138,15 @@ add_epel_centos7() { add_maria_db_repo() { if [ "$OS" == "centos" ]; then - echo DEBUG adding centos mariadb repo + echo Adding centos mariadb repo add_centos6_mariadb_repo elif [ "$OS" == "debian" ]; then - echo DEBUG adding debian mariadb repo + echo Adding debian mariadb repo add_debian_mariadb_repo elif [ "$OS" == "Ubuntu" ]; then - echo DEBUG adding debian mariadb repo + echo Adding debian mariadb repo add_ubuntu_mariadb_repo else echo Unsupported Distribution @@ -162,8 +167,8 @@ install_packages() { run_cmd add_epel_centos7 run_cmd sudo yum install -y git mariadb-server mariadb-devel python-setuptools nginx zlib-devel bzip2-devel openssl-devel memcached postfix python-devel libxml2 libxml2-devel libxslt libxslt-devel redis libXrender libXext supervisor fi - run_cmd wget http://downloads.sourceforge.net/project/wkhtmltopdf/0.12.1/wkhtmltox-0.12.1_linux-centos6-amd64.rpm - run_cmd sudo rpm -Uvh wkhtmltox-0.12.1_linux-centos6-amd64.rpm + echo "Installing wkhtmltopdf" + install_wkhtmltopdf_centos run_cmd easy_install-2.7 -U pip @@ -172,6 +177,8 @@ install_packages() { setup_debconf run_cmd sudo apt-get update run_cmd sudo apt-get install python-dev python-setuptools build-essential python-mysqldb git memcached ntp vim screen htop mariadb-server mariadb-common libmariadbclient-dev libxslt1.1 libxslt1-dev redis-server libssl-dev libcrypto++-dev postfix nginx supervisor python-pip fontconfig libxrender1 -y + echo "Installing wkhtmltopdf" + install_wkhtmltopdf_deb else echo Unsupported Distribution @@ -179,12 +186,37 @@ install_packages() { fi } +install_wkhtmltopdf_centos () { + + if [[ $OS == "centos" && $OS_VER == "7" && $T_ARCH="i386" ]]; then + echo "Cannot install wkhtmltodpdf. Skipping..." + return 0 + fi + RPM="wkhtmltox-0.12.1_linux-$OS$OS_VER-$WK_ARCH.rpm" + run_cmd wget http://downloads.sourceforge.net/project/wkhtmltopdf/0.12.1/$RPM + rpm --quiet -q wkhtmltox || run_cmd rpm -Uvh $RPM +} + +install_wkhtmltopdf_deb () { + if [[ $OS_VER == "utopic" ]]; then + echo "Cannot install wkhtmltodpdf. Skipping..." + return 0 + fi + if [[ $OS == "debian" && $OS_VER == "7" ]]; then + WK_VER="wheezy" + else + WK_VER=$OS_VER + fi + run_cmd wget http://downloads.sourceforge.net/project/wkhtmltopdf/0.12.1/wkhtmltox-0.12.1_linux-$WK_VER-$WK_ARCH.deb + run_cmd dpkg -i wkhtmltox-0.12.1_linux-$WK_VER-$WK_ARCH.deb +} + install_supervisor_centos6() { run_cmd easy_install supervisor - run_cmd curl https://raw.githubusercontent.com/pdvyas/supervisor-initscripts/master/redhat-init-jkoppe > /etc/init.d/supervisord - run_cmd curl https://raw.githubusercontent.com/pdvyas/supervisor-initscripts/master/redhat-sysconfig-jkoppe > /etc/sysconfig/supervisord - run_cmd curl https://raw.githubusercontent.com/pdvyas/supervisor-initscripts/master/supervisord.conf > /etc/supervisord.conf + curl -Ss https://raw.githubusercontent.com/pdvyas/supervisor-initscripts/master/redhat-init-jkoppe > /etc/init.d/supervisord + curl -Ss https://raw.githubusercontent.com/pdvyas/supervisor-initscripts/master/redhat-sysconfig-jkoppe > /etc/sysconfig/supervisord + curl -Ss https://raw.githubusercontent.com/pdvyas/supervisor-initscripts/master/supervisord.conf > /etc/supervisord.conf run_cmd mkdir /etc/supervisor.d run_cmd chmod +x /etc/init.d/supervisord bash -c "service supervisord start || true" @@ -224,11 +256,10 @@ configure_mariadb_centos() { fi } -start_services_centos() { - run_cmd systemctl start nginx - run_cmd systemctl start mariadb - run_cmd systemctl start redis - run_cmd systemctl start supervisord +start_services_centos6() { + run_cmd service nginx start + run_cmd service mysql start + run_cmd service redis start } configure_services_centos6() { @@ -284,8 +315,16 @@ install_bench() { setup_bench() { echo Installing frappe-bench - run_cmd sudo su $FRAPPE_USER -c "cd /home/$FRAPPE_USER && bench init frappe-bench --apps_path https://raw.githubusercontent.com/frappe/bench/master/install_scripts/erpnext-apps.json" + FRAPPE_BRANCH="develop" + ERPNEXT_APPS_JSON="https://raw.githubusercontent.com/frappe/bench/master/install_scripts/erpnext-apps.json" + if $SETUP_PROD; then + FRAPPE_BRANCH="master" + ERPNEXT_APPS_JSON="https://raw.githubusercontent.com/frappe/bench/master/install_scripts/erpnext-apps-master.json" + fi + + run_cmd sudo su $FRAPPE_USER -c "cd /home/$FRAPPE_USER && bench init frappe-bench --frappe-branch $FRAPPE_BRANCH --apps_path $ERPNEXT_APPS_JSON" echo Setting up first site + echo /home/$FRAPPE_USER/frappe-bench > /etc/frappe_bench_dir run_cmd sudo su $FRAPPE_USER -c "cd /home/$FRAPPE_USER/frappe-bench && bench new-site site1.local --mariadb-root-password $MSQ_PASS --admin-password $ADMIN_PASS" run_cmd sudo su $FRAPPE_USER -c "cd /home/$FRAPPE_USER/frappe-bench && bench frappe --install_app erpnext" run_cmd sudo su $FRAPPE_USER -c "cd /home/$FRAPPE_USER/frappe-bench && bench frappe --install_app shopping_cart" @@ -337,12 +376,20 @@ main() { echo "Starting services" start_services_centos7 fi + configure_mariadb_centos fi echo "Adding frappe user" add_user install_bench setup_bench + + echo + echo "Frappe/ERPNext is installed successfully." + print_msg > ~/frappe_passwords.txt print_msg + echo + echo "The passwords are also stored at ~/frappe_passwords.txt" + echo "You can remove this file after making a note of the passwords." } -main +main $@ From 0fb4b76aee98797b5975b53b947df32248fb5af8 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Tue, 11 Nov 2014 10:51:57 +0530 Subject: [PATCH 22/23] update readme --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 300f4961..40231215 100644 --- a/README.md +++ b/README.md @@ -19,10 +19,12 @@ Open your Terminal and enter: ``` wget https://raw.githubusercontent.com/frappe/bench/master/install_scripts/setup_frappe.sh -sudo bash setup_frappe.sh +sudo bash setup_frappe.sh --setup-production ``` -This script should install the pre-requisites and add a bench command. +This script should install the pre-requisites, install bench and setup an ERPNext site. + +If you want to develop ERPNext or any Frappe App, you can omit the "--setup-production" part from the command. Manual Install @@ -181,8 +183,10 @@ Production Deployment ===================== -You can setup the bench for production use by configuring two programs, -Supervisor and nginx. +You can setup the bench for production use by configuring two programs +, Supervisor and nginx. These steps are automated if you pass +`--setup-production` to the easy install script or run `sudo bench +setup production` Supervisor ---------- From a65980a78d697c6edf295d0b24fc62da1094bf18 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Tue, 11 Nov 2014 10:53:29 +0530 Subject: [PATCH 23/23] install bench from master --- install_scripts/setup_frappe.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/install_scripts/setup_frappe.sh b/install_scripts/setup_frappe.sh index 6c6fdada..06fc3454 100644 --- a/install_scripts/setup_frappe.sh +++ b/install_scripts/setup_frappe.sh @@ -294,8 +294,7 @@ setup_debconf() { } install_bench() { - echo WARNING BENCH INSTALLING FROM ANOTHER BRANCH - run_cmd sudo su $FRAPPE_USER -c "cd /home/$FRAPPE_USER && git clone https://github.com/frappe/bench --branch v0.9wip bench-repo" + run_cmd sudo su $FRAPPE_USER -c "cd /home/$FRAPPE_USER && git clone https://github.com/frappe/bench bench-repo" if hash pip-2.7; then PIP="pip-2.7" elif hash pip2.7; then