mirror of
https://github.com/frappe/bench.git
synced 2024-11-12 00:06:36 +00:00
Merge pull request #955 from gavindsouza/sec-patch
fix: remove bench and supervisor from sudoers
This commit is contained in:
commit
c600c3f86b
@ -8,6 +8,7 @@ from bench.commands import bench_command
|
||||
|
||||
logger = logging.getLogger('bench')
|
||||
from_command_line = False
|
||||
change_uid_msg = "You should not run this command as root"
|
||||
|
||||
def cli():
|
||||
global from_command_line
|
||||
@ -48,7 +49,7 @@ def check_uid():
|
||||
sys.exit(1)
|
||||
|
||||
def cmd_requires_root():
|
||||
if len(sys.argv) > 2 and sys.argv[2] in ('production', 'sudoers', 'lets-encrypt', 'fonts',
|
||||
if len(sys.argv) > 2 and sys.argv[2] in ('production', 'sudoers', 'supervisor', 'lets-encrypt', 'fonts',
|
||||
'print', 'firewall', 'ssh-port', 'role', 'fail2ban', 'wildcard-ssl'):
|
||||
return True
|
||||
if len(sys.argv) >= 2 and sys.argv[1] in ('patch', 'renew-lets-encrypt', 'disable-production',
|
||||
@ -72,7 +73,7 @@ def change_uid():
|
||||
drop_privileges(uid_name=frappe_user, gid_name=frappe_user)
|
||||
os.environ['HOME'] = pwd.getpwnam(frappe_user).pw_dir
|
||||
else:
|
||||
log('You should not run this command as root', level=3)
|
||||
log(change_uid_msg, level=3)
|
||||
sys.exit(1)
|
||||
|
||||
def old_frappe_cli(bench_path='.'):
|
||||
|
@ -2,12 +2,21 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
# imports - module imports
|
||||
from bench.utils import exec_cmd
|
||||
|
||||
# imports - third party imports
|
||||
from six import PY3
|
||||
import click
|
||||
from six import PY3
|
||||
|
||||
# imports - module imports
|
||||
import bench.config.lets_encrypt
|
||||
import bench.config.nginx
|
||||
import bench.config.procfile
|
||||
import bench.config.production_setup
|
||||
import bench.config.redis
|
||||
import bench.config.site_config
|
||||
import bench.config.supervisor
|
||||
|
||||
import bench.utils
|
||||
from bench.utils import exec_cmd, run_playbook
|
||||
|
||||
|
||||
@click.group(help="Setup command group for enabling setting up a Frappe environment")
|
||||
@ -18,80 +27,59 @@ def setup():
|
||||
@click.command("sudoers", help="Add commands to sudoers list for execution without password")
|
||||
@click.argument("user")
|
||||
def setup_sudoers(user):
|
||||
from bench.utils import setup_sudoers
|
||||
setup_sudoers(user)
|
||||
bench.utils.setup_sudoers(user)
|
||||
|
||||
|
||||
@click.command("nginx", help="Generate configuration files for NGINX")
|
||||
@click.option("--yes", help="Yes to regeneration of nginx config file", default=False, is_flag=True)
|
||||
def setup_nginx(yes=False):
|
||||
from bench.config.nginx import make_nginx_conf
|
||||
make_nginx_conf(bench_path=".", yes=yes)
|
||||
bench.config.nginx.make_nginx_conf(bench_path=".", yes=yes)
|
||||
|
||||
|
||||
@click.command("reload-nginx", help="Checks NGINX config file and reloads service")
|
||||
def reload_nginx():
|
||||
from bench.config.production_setup import reload_nginx
|
||||
reload_nginx()
|
||||
bench.config.production_setup.reload_nginx()
|
||||
|
||||
|
||||
@click.command("supervisor", help="Generate configuration for supervisor")
|
||||
@click.option("--user", help="optional user argument")
|
||||
@click.option("--yes", help="Yes to regeneration of supervisor config", is_flag=True, default=False)
|
||||
def setup_supervisor(user=None, yes=False):
|
||||
from bench.config.supervisor import generate_supervisor_config
|
||||
generate_supervisor_config(bench_path=".", user=user, yes=yes)
|
||||
bench.config.supervisor.generate_supervisor_config(bench_path=".", user=user, yes=yes)
|
||||
|
||||
|
||||
@click.command("redis", help="Generates configuration for Redis")
|
||||
def setup_redis():
|
||||
from bench.config.redis import generate_config
|
||||
generate_config(".")
|
||||
bench.config.redis.generate_config(".")
|
||||
|
||||
|
||||
@click.command("fonts", help="Add Frappe fonts to system")
|
||||
def setup_fonts():
|
||||
from bench.utils import setup_fonts
|
||||
setup_fonts()
|
||||
bench.utils.setup_fonts()
|
||||
|
||||
|
||||
@click.command("production", help="Setup Frappe production environment for specific user")
|
||||
@click.argument("user")
|
||||
@click.option("--yes", help="Yes to regeneration config", is_flag=True, default=False)
|
||||
def setup_production(user, yes=False):
|
||||
from bench.config.production_setup import setup_production
|
||||
# Install prereqs for production
|
||||
from distutils.spawn import find_executable
|
||||
if not find_executable("ansible"):
|
||||
exec_cmd("sudo -H {0} -m pip install ansible".format(sys.executable))
|
||||
if not find_executable("fail2ban-client"):
|
||||
exec_cmd("bench setup role fail2ban")
|
||||
if not find_executable("nginx"):
|
||||
exec_cmd("bench setup role nginx")
|
||||
if not find_executable("supervisord"):
|
||||
exec_cmd("bench setup role supervisor")
|
||||
setup_production(user=user, yes=yes)
|
||||
bench.config.production_setup.setup_production(user=user, yes=yes)
|
||||
|
||||
|
||||
@click.command("backups", help="Add cronjob for bench backups")
|
||||
def setup_backups():
|
||||
from bench.utils import setup_backups
|
||||
setup_backups()
|
||||
bench.utils.setup_backups()
|
||||
|
||||
|
||||
@click.command("env", help="Setup virtualenv for bench")
|
||||
@click.option("--python", type = str, default = "python3", help = "Path to Python Executable.")
|
||||
def setup_env(python="python3"):
|
||||
from bench.utils import setup_env
|
||||
setup_env(python=python)
|
||||
bench.utils.setup_env(python=python)
|
||||
|
||||
|
||||
@click.command("firewall", help="Setup firewall for system")
|
||||
@click.option("--ssh_port")
|
||||
@click.option("--force")
|
||||
def setup_firewall(ssh_port=None, force=False):
|
||||
from bench.utils import run_playbook
|
||||
|
||||
if not force:
|
||||
click.confirm("Setting up the firewall will block all ports except 80, 443 and {0}\nDo you want to continue?".format(ssh_port), abort=True)
|
||||
|
||||
@ -105,8 +93,6 @@ def setup_firewall(ssh_port=None, force=False):
|
||||
@click.argument("port")
|
||||
@click.option("--force")
|
||||
def set_ssh_port(port, force=False):
|
||||
from bench.utils import run_playbook
|
||||
|
||||
if not force:
|
||||
click.confirm("This will change your SSH Port to {}\nDo you want to continue?".format(port), abort=True)
|
||||
|
||||
@ -118,8 +104,7 @@ def set_ssh_port(port, force=False):
|
||||
@click.option("--custom-domain")
|
||||
@click.option('-n', '--non-interactive', default=False, is_flag=True, help="Run command non-interactively. This flag restarts nginx and runs certbot non interactively. Shouldn't be used on 1'st attempt")
|
||||
def setup_letsencrypt(site, custom_domain, non_interactive):
|
||||
from bench.config.lets_encrypt import setup_letsencrypt
|
||||
setup_letsencrypt(site, custom_domain, bench_path=".", interactive=not non_interactive)
|
||||
bench.config.lets_encrypt.setup_letsencrypt(site, custom_domain, bench_path=".", interactive=not non_interactive)
|
||||
|
||||
|
||||
@click.command("wildcard-ssl", help="Setup wildcard SSL certificate for multi-tenant bench")
|
||||
@ -127,20 +112,17 @@ def setup_letsencrypt(site, custom_domain, non_interactive):
|
||||
@click.option("--email")
|
||||
@click.option("--exclude-base-domain", default=False, is_flag=True, help="SSL Certificate not applicable for base domain")
|
||||
def setup_wildcard_ssl(domain, email, exclude_base_domain):
|
||||
from bench.config.lets_encrypt import setup_wildcard_ssl
|
||||
setup_wildcard_ssl(domain, email, bench_path=".", exclude_base_domain=exclude_base_domain)
|
||||
bench.config.lets_encrypt.setup_wildcard_ssl(domain, email, bench_path=".", exclude_base_domain=exclude_base_domain)
|
||||
|
||||
|
||||
@click.command("procfile", help="Generate Procfile for bench start")
|
||||
def setup_procfile():
|
||||
from bench.config.procfile import setup_procfile
|
||||
setup_procfile(".")
|
||||
bench.config.procfile.setup_procfile(".")
|
||||
|
||||
|
||||
@click.command("socketio", help="Setup node dependencies for socketio server")
|
||||
def setup_socketio():
|
||||
from bench.utils import setup_socketio
|
||||
setup_socketio()
|
||||
bench.utils.setup_socketio()
|
||||
|
||||
|
||||
@click.command("requirements", help="Setup Python and Node dependencies")
|
||||
@ -213,34 +195,28 @@ def setup_config():
|
||||
@click.option("--ssl-certificate-key", help="Absolute path to SSL Certificate Key")
|
||||
def add_domain(domain, site=None, ssl_certificate=None, ssl_certificate_key=None):
|
||||
"""Add custom domain to site"""
|
||||
from bench.config.site_config import add_domain
|
||||
|
||||
if not site:
|
||||
print("Please specify site")
|
||||
sys.exit(1)
|
||||
|
||||
add_domain(site, domain, ssl_certificate, ssl_certificate_key, bench_path=".")
|
||||
bench.config.site_config.add_domain(site, domain, ssl_certificate, ssl_certificate_key, bench_path=".")
|
||||
|
||||
|
||||
@click.command("remove-domain", help="Remove custom domain from a site")
|
||||
@click.argument("domain")
|
||||
@click.option("--site", prompt=True)
|
||||
def remove_domain(domain, site=None):
|
||||
from bench.config.site_config import remove_domain
|
||||
|
||||
if not site:
|
||||
print("Please specify site")
|
||||
sys.exit(1)
|
||||
|
||||
remove_domain(site, domain, bench_path=".")
|
||||
bench.config.site_config.remove_domain(site, domain, bench_path=".")
|
||||
|
||||
|
||||
@click.command("sync-domains", help="Check if there is a change in domains. If yes, updates the domains list.")
|
||||
@click.option("--domain", multiple=True)
|
||||
@click.option("--site", prompt=True)
|
||||
def sync_domains(domain=None, site=None):
|
||||
from bench.config.site_config import sync_domains
|
||||
|
||||
if not site:
|
||||
print("Please specify site")
|
||||
sys.exit(1)
|
||||
@ -251,7 +227,7 @@ def sync_domains(domain=None, site=None):
|
||||
print("Domains should be a json list of strings or dictionaries")
|
||||
sys.exit(1)
|
||||
|
||||
changed = sync_domains(site, domains, bench_path=".")
|
||||
changed = bench.config.site_config.sync_domains(site, domains, bench_path=".")
|
||||
|
||||
# if changed, success, else failure
|
||||
sys.exit(0 if changed else 1)
|
||||
@ -263,8 +239,6 @@ def sync_domains(domain=None, site=None):
|
||||
@click.option("--mysql_root_password")
|
||||
@click.option("--container", is_flag=True, default=False)
|
||||
def setup_roles(role, **kwargs):
|
||||
from bench.utils import run_playbook
|
||||
|
||||
extra_vars = {"production": True}
|
||||
extra_vars.update(kwargs)
|
||||
|
||||
@ -279,7 +253,6 @@ def setup_roles(role, **kwargs):
|
||||
@click.option("--bantime", default=600, help="The counter is set to zero if no match is found within 'findtime' seconds. Default is 600 seconds")
|
||||
@click.option("--findtime", default=600, help="Duration (in seconds) for IP to be banned for. Negative number for 'permanent' ban. Default is 600 seconds")
|
||||
def setup_nginx_proxy_jail(**kwargs):
|
||||
from bench.utils import run_playbook
|
||||
run_playbook("roles/fail2ban/tasks/configure_nginx_jail.yml", extra_vars=kwargs)
|
||||
|
||||
|
||||
|
@ -1,11 +1,30 @@
|
||||
from bench.utils import get_program, exec_cmd, get_cmd_output, fix_prod_setup_perms, get_bench_name, find_executable, CommandFailedError
|
||||
# imports - standard imports
|
||||
import os
|
||||
import sys
|
||||
from distutils.spawn import find_executable
|
||||
|
||||
# imports - module imports
|
||||
from bench.config.common_site_config import get_config
|
||||
from bench.config.nginx import make_nginx_conf
|
||||
from bench.config.supervisor import generate_supervisor_config
|
||||
from bench.config.systemd import generate_systemd_config
|
||||
from bench.config.nginx import make_nginx_conf
|
||||
from bench.config.common_site_config import get_config
|
||||
import os, subprocess
|
||||
from bench.utils import CommandFailedError, exec_cmd, fix_prod_setup_perms, get_bench_name, get_cmd_output
|
||||
|
||||
|
||||
def setup_production_prerequisites():
|
||||
"""Installs ansible, fail2banc, NGINX and supervisor"""
|
||||
if not find_executable("ansible"):
|
||||
exec_cmd("sudo {0} -m pip install ansible".format(sys.executable))
|
||||
if not find_executable("fail2ban-client"):
|
||||
exec_cmd("bench setup role fail2ban")
|
||||
if not find_executable("nginx"):
|
||||
exec_cmd("bench setup role nginx")
|
||||
if not find_executable("supervisord"):
|
||||
exec_cmd("bench setup role supervisor")
|
||||
|
||||
|
||||
def setup_production(user, bench_path='.', yes=False):
|
||||
setup_production_prerequisites()
|
||||
if get_config(bench_path).get('restart_supervisor_on_update') and get_config(bench_path).get('restart_systemd_on_update'):
|
||||
raise Exception("You cannot use supervisor and systemd at the same time. Modify your common_site_config accordingly." )
|
||||
|
||||
@ -40,6 +59,7 @@ def setup_production(user, bench_path='.', yes=False):
|
||||
|
||||
reload_nginx()
|
||||
|
||||
|
||||
def disable_production(bench_path='.'):
|
||||
bench_name = get_bench_name(bench_path)
|
||||
|
||||
@ -62,28 +82,35 @@ def disable_production(bench_path='.'):
|
||||
|
||||
reload_nginx()
|
||||
|
||||
def service(service, option):
|
||||
if os.path.basename(get_program(['systemctl']) or '') == 'systemctl' and is_running_systemd():
|
||||
exec_cmd("sudo {service_manager} {option} {service}".format(service_manager='systemctl', option=option, service=service))
|
||||
elif os.path.basename(get_program(['service']) or '') == 'service':
|
||||
exec_cmd("sudo {service_manager} {service} {option} ".format(service_manager='service', service=service, option=option))
|
||||
|
||||
def service(service_name, service_option):
|
||||
if os.path.basename(find_executable('systemctl') or '') == 'systemctl' and is_running_systemd():
|
||||
systemctl_cmd = "sudo {service_manager} {service_option} {service_name}"
|
||||
exec_cmd(systemctl_cmd.format(service_manager='systemctl', service_option=service_option, service_name=service_name))
|
||||
|
||||
elif os.path.basename(find_executable('service') or '') == 'service':
|
||||
service_cmd = "sudo {service_manager} {service_name} {service_option}"
|
||||
exec_cmd(service_cmd.format(service_manager='service', service_name=service_name, service_option=service_option))
|
||||
|
||||
else:
|
||||
# look for 'service_manager' and 'service_manager_command' in environment
|
||||
service_manager = os.environ.get("BENCH_SERVICE_MANAGER")
|
||||
if service_manager:
|
||||
service_manager_command = (os.environ.get("BENCH_SERVICE_MANAGER_COMMAND")
|
||||
or "{service_manager} {option} {service}").format(service_manager=service_manager, service=service, option=option)
|
||||
or "{service_manager} {service_option} {service}").format(service_manager=service_manager, service=service, service_option=service_option)
|
||||
exec_cmd(service_manager_command)
|
||||
|
||||
else:
|
||||
raise Exception('No service manager found')
|
||||
|
||||
|
||||
def get_supervisor_confdir():
|
||||
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
|
||||
|
||||
|
||||
def remove_default_nginx_configs():
|
||||
default_nginx_configs = ['/etc/nginx/conf.d/default.conf', '/etc/nginx/sites-enabled/default']
|
||||
|
||||
@ -95,6 +122,7 @@ def remove_default_nginx_configs():
|
||||
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 is_running_systemd():
|
||||
with open('/proc/1/comm') as f:
|
||||
comm = f.read().strip()
|
||||
@ -104,20 +132,21 @@ def is_running_systemd():
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def reload_supervisor():
|
||||
supervisorctl = find_executable('supervisorctl')
|
||||
|
||||
try:
|
||||
# first try reread/update
|
||||
exec_cmd('sudo {0} reread'.format(supervisorctl))
|
||||
exec_cmd('sudo {0} update'.format(supervisorctl))
|
||||
exec_cmd('{0} reread'.format(supervisorctl))
|
||||
exec_cmd('{0} update'.format(supervisorctl))
|
||||
return
|
||||
except CommandFailedError:
|
||||
pass
|
||||
|
||||
try:
|
||||
# something is wrong, so try reloading
|
||||
exec_cmd('sudo {0} reload'.format(supervisorctl))
|
||||
exec_cmd('{0} reload'.format(supervisorctl))
|
||||
return
|
||||
except CommandFailedError:
|
||||
pass
|
||||
@ -138,7 +167,7 @@ def reload_supervisor():
|
||||
|
||||
def reload_nginx():
|
||||
try:
|
||||
subprocess.check_output(['sudo', find_executable('nginx'), '-t'])
|
||||
exec_cmd('sudo {0} -t'.format(find_executable('nginx')))
|
||||
except:
|
||||
raise
|
||||
|
||||
|
@ -1,17 +1,27 @@
|
||||
import os, getpass, click
|
||||
import bench
|
||||
# imports - standard imports
|
||||
import getpass
|
||||
import os
|
||||
|
||||
def generate_supervisor_config(bench_path, user=None, yes=False):
|
||||
# imports - module imports
|
||||
import bench
|
||||
from bench.app import get_current_frappe_version, use_rq
|
||||
from bench.utils import get_bench_name, find_executable
|
||||
from bench.config.common_site_config import get_config, update_config, get_gunicorn_workers
|
||||
|
||||
template = bench.env.get_template('supervisor.conf')
|
||||
# imports - third party imports
|
||||
import click
|
||||
from six.moves import configparser
|
||||
|
||||
|
||||
def generate_supervisor_config(bench_path, user=None, yes=False):
|
||||
"""Generate supervisor config for respective bench path"""
|
||||
if not user:
|
||||
user = getpass.getuser()
|
||||
|
||||
config = get_config(bench_path=bench_path)
|
||||
update_supervisord_conf(user=user)
|
||||
|
||||
template = bench.env.get_template('supervisor.conf')
|
||||
config = get_config(bench_path=bench_path)
|
||||
bench_dir = os.path.abspath(bench_path)
|
||||
|
||||
config = template.render(**{
|
||||
@ -44,3 +54,37 @@ def generate_supervisor_config(bench_path, user=None, yes=False):
|
||||
update_config({'restart_supervisor_on_update': True}, bench_path=bench_path)
|
||||
update_config({'restart_systemd_on_update': False}, bench_path=bench_path)
|
||||
|
||||
|
||||
def get_supervisord_conf():
|
||||
"""Returns path of supervisord config from possible paths"""
|
||||
possibilities = ("supervisord.conf", "etc/supervisord.conf", "/etc/supervisord.conf", "/etc/supervisor/supervisord.conf", "/etc/supervisord.conf")
|
||||
|
||||
for possibility in possibilities:
|
||||
if os.path.exists(possibility):
|
||||
return possibility
|
||||
|
||||
|
||||
def update_supervisord_conf(user):
|
||||
"""From bench v5.0, we're moving to supervisor running as user"""
|
||||
from bench.config.production_setup import service
|
||||
|
||||
supervisord_conf = get_supervisord_conf()
|
||||
section = "unix_http_server"
|
||||
|
||||
if not supervisord_conf:
|
||||
return
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
config.read(supervisord_conf)
|
||||
|
||||
if section not in config.sections():
|
||||
config.add_section(section)
|
||||
|
||||
config.set(section, "chmod", "0760")
|
||||
config.set(section, "chown", "{user}:{user}".format(user=user))
|
||||
|
||||
with open(supervisord_conf, "w") as f:
|
||||
config.write(f)
|
||||
|
||||
# restart supervisor to take new changes into effect
|
||||
service('supervisor', 'restart')
|
||||
|
@ -1,20 +1,20 @@
|
||||
# This file is auto-generated by frappe/bench
|
||||
# To re-generate this file, run "bench setup sudoers"
|
||||
|
||||
{% if service %}
|
||||
{{ user }} ALL = (root) {{ service }}
|
||||
{{ user }} ALL = (root) NOPASSWD: {{ service }} nginx *
|
||||
{{ user }} ALL = (root) NOPASSWD: {{ service }} supervisord *
|
||||
{% endif %}
|
||||
|
||||
{% if systemctl %}
|
||||
{{ user }} ALL = (root) {{ systemctl }}
|
||||
{{ user }} ALL = (root) NOPASSWD: {{ systemctl }} * nginx
|
||||
{{ user }} ALL = (root) NOPASSWD: {{ systemctl }} * supervisord
|
||||
{% endif %}
|
||||
{% if supervisorctl %}
|
||||
{{ user }} ALL = (root) NOPASSWD: {{ supervisorctl }}
|
||||
{% endif %}
|
||||
|
||||
{% if nginx %}
|
||||
{{ user }} ALL = (root) NOPASSWD: {{ nginx }}
|
||||
{% endif %}
|
||||
|
||||
{{ user }} ALL = (root) NOPASSWD: /opt/certbot-auto
|
||||
{{ user }} ALL = (root) NOPASSWD: {{ bench }}
|
||||
Defaults:{{ user }} !requiretty
|
||||
|
||||
|
@ -4,3 +4,4 @@ bench.patches.v3.redis_bind_ip
|
||||
bench.patches.v4.update_node
|
||||
bench.patches.v4.update_socketio
|
||||
bench.patches.v4.install_yarn #2
|
||||
bench.patches.v5.fix_user_permissions
|
||||
|
0
bench/patches/v5/__init__.py
Normal file
0
bench/patches/v5/__init__.py
Normal file
59
bench/patches/v5/fix_user_permissions.py
Normal file
59
bench/patches/v5/fix_user_permissions.py
Normal file
@ -0,0 +1,59 @@
|
||||
# imports - standard imports
|
||||
import getpass
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
# imports - module imports
|
||||
from bench.cli import change_uid_msg
|
||||
from bench.config.production_setup import get_supervisor_confdir, is_centos7
|
||||
from bench.config.common_site_config import get_config
|
||||
from bench.utils import exec_cmd, get_bench_name, get_cmd_output
|
||||
|
||||
|
||||
def is_sudoers_set():
|
||||
"""Check if bench sudoers is set"""
|
||||
cmd = ["sudo", "-n", "bench"]
|
||||
|
||||
with open(os.devnull, "wb") as f:
|
||||
return_code_check = not subprocess.call(cmd, stdout=f)
|
||||
|
||||
if return_code_check:
|
||||
try:
|
||||
bench_warn = change_uid_msg in get_cmd_output(cmd, _raise=False)
|
||||
except subprocess.CalledProcessError:
|
||||
bench_warn = False
|
||||
finally:
|
||||
return_code_check = return_code_check and bench_warn
|
||||
|
||||
return return_code_check
|
||||
|
||||
|
||||
def is_production_set(bench_path):
|
||||
"""Check if production is set for current bench"""
|
||||
production_setup = False
|
||||
bench_name = get_bench_name(bench_path)
|
||||
|
||||
supervisor_conf_extn = "ini" if is_centos7() else "conf"
|
||||
supervisor_conf_file_name = '{bench_name}.{extn}'.format(bench_name=bench_name, extn=supervisor_conf_extn)
|
||||
supervisor_conf = os.path.join(get_supervisor_confdir(), supervisor_conf_file_name)
|
||||
|
||||
if os.path.exists(supervisor_conf):
|
||||
production_setup = production_setup or True
|
||||
|
||||
nginx_conf = '/etc/nginx/conf.d/{bench_name}.conf'.format(bench_name=bench_name)
|
||||
|
||||
if os.path.exists(nginx_conf):
|
||||
production_setup = production_setup or True
|
||||
|
||||
return production_setup
|
||||
|
||||
|
||||
def execute(bench_path):
|
||||
"""This patch checks if bench sudoers is set and regenerate supervisor and sudoers files"""
|
||||
user = get_config('.').get("frappe_user") or getpass.getuser()
|
||||
|
||||
if is_sudoers_set():
|
||||
exec_cmd("sudo bench setup sudoers {user}".format(user=user))
|
||||
|
||||
if is_production_set(bench_path):
|
||||
exec_cmd("sudo bench setup supervisor --yes --user {user}".format(user=user))
|
@ -61,6 +61,9 @@ class TestSetupProduction(TestBenchBase):
|
||||
|
||||
def assert_sudoers(self, user):
|
||||
sudoers_file = '/etc/sudoers.d/frappe'
|
||||
service = bench.utils.which("service")
|
||||
nginx = bench.utils.which("nginx")
|
||||
|
||||
self.assertTrue(self.file_exists(sudoers_file))
|
||||
|
||||
if os.environ.get("CI"):
|
||||
@ -69,9 +72,8 @@ class TestSetupProduction(TestBenchBase):
|
||||
with open(sudoers_file, 'r') as f:
|
||||
sudoers = f.read()
|
||||
|
||||
self.assertTrue('{user} ALL = (root) NOPASSWD: /usr/sbin/service nginx *'.format(user=user) in sudoers)
|
||||
self.assertTrue('{user} ALL = (root) NOPASSWD: /usr/bin/supervisorctl'.format(user=user) in sudoers)
|
||||
self.assertTrue('{user} ALL = (root) NOPASSWD: /usr/sbin/nginx'.format(user=user) in sudoers)
|
||||
self.assertTrue('{user} ALL = (root) NOPASSWD: {service} nginx *'.format(service=service, user=user) in sudoers)
|
||||
self.assertTrue('{user} ALL = (root) NOPASSWD: {nginx}'.format(nginx=nginx, user=user) in sudoers)
|
||||
|
||||
|
||||
def assert_supervisor_config(self, bench_name, use_rq=True):
|
||||
@ -126,12 +128,12 @@ class TestSetupProduction(TestBenchBase):
|
||||
|
||||
|
||||
def assert_supervisor_process(self, bench_name, use_rq=True, disable_production=False):
|
||||
out = bench.utils.get_cmd_output("sudo supervisorctl status")
|
||||
out = bench.utils.get_cmd_output("supervisorctl status")
|
||||
|
||||
while "STARTING" in out:
|
||||
print ("Waiting for all processes to start...")
|
||||
time.sleep(10)
|
||||
out = bench.utils.get_cmd_output("sudo supervisorctl status")
|
||||
out = bench.utils.get_cmd_output("supervisorctl status")
|
||||
|
||||
tests = [
|
||||
"{bench_name}-web:{bench_name}-frappe-web[\s]+RUNNING",
|
||||
|
@ -37,6 +37,7 @@ class CommandFailedError(Exception):
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
folders_in_bench = ('apps', 'sites', 'config', 'logs', 'config/pids')
|
||||
sudoers_file = '/etc/sudoers.d/frappe'
|
||||
|
||||
|
||||
class color:
|
||||
@ -65,10 +66,10 @@ def log(message, level=0):
|
||||
2: color.red + 'ERROR', # fail
|
||||
3: color.yellow + 'WARN' # warn/suggest
|
||||
}
|
||||
start = (levels.get(level) + ': ') if level in levels else ''
|
||||
end = '\033[0m'
|
||||
start_line = (levels.get(level) + ': ') if level in levels else ''
|
||||
end_line = '\033[0m'
|
||||
|
||||
print(start + message + end)
|
||||
print(start_line + message + end_line)
|
||||
|
||||
|
||||
def safe_decode(string, encoding = 'utf-8'):
|
||||
@ -393,16 +394,12 @@ def setup_sudoers(user):
|
||||
if set_permissions:
|
||||
os.chmod('/etc/sudoers', 0o440)
|
||||
|
||||
sudoers_file = '/etc/sudoers.d/frappe'
|
||||
|
||||
template = env.get_template('frappe_sudoers')
|
||||
frappe_sudoers = template.render(**{
|
||||
'user': user,
|
||||
'service': find_executable('service'),
|
||||
'systemctl': find_executable('systemctl'),
|
||||
'supervisorctl': find_executable('supervisorctl'),
|
||||
'nginx': find_executable('nginx'),
|
||||
'bench': find_executable('bench')
|
||||
})
|
||||
frappe_sudoers = safe_decode(frappe_sudoers)
|
||||
|
||||
@ -410,6 +407,7 @@ def setup_sudoers(user):
|
||||
f.write(frappe_sudoers)
|
||||
|
||||
os.chmod(sudoers_file, 0o440)
|
||||
log("Sudoers was set up for user {}".format(user), level=1)
|
||||
|
||||
|
||||
def setup_logging(bench_path='.'):
|
||||
@ -423,17 +421,11 @@ def setup_logging(bench_path='.'):
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
|
||||
def get_program(programs):
|
||||
program = None
|
||||
for p in programs:
|
||||
program = find_executable(p)
|
||||
if program:
|
||||
break
|
||||
return program
|
||||
|
||||
|
||||
def get_process_manager():
|
||||
return get_program(['foreman', 'forego', 'honcho'])
|
||||
for proc_man in ['honcho', 'foreman', 'forego']:
|
||||
proc_man_path = find_executable(proc_man)
|
||||
if proc_man_path:
|
||||
return proc_man_path
|
||||
|
||||
|
||||
def start(no_dev=False, concurrency=None, procfile=None):
|
||||
@ -488,15 +480,16 @@ def check_git_for_shallow_clone():
|
||||
return True
|
||||
|
||||
|
||||
def get_cmd_output(cmd, cwd='.'):
|
||||
def get_cmd_output(cmd, cwd='.', _raise=True):
|
||||
output = ""
|
||||
try:
|
||||
output = subprocess.check_output(cmd, cwd=cwd, shell=True, stderr=subprocess.PIPE).strip()
|
||||
output = output.decode('utf-8')
|
||||
return output
|
||||
except subprocess.CalledProcessError as e:
|
||||
if e.output:
|
||||
print(e.output)
|
||||
output = e.output
|
||||
elif _raise:
|
||||
raise
|
||||
return safe_decode(output)
|
||||
|
||||
|
||||
def safe_encode(what, encoding = 'utf-8'):
|
||||
@ -518,7 +511,7 @@ def restart_supervisor_processes(bench_path='.', web_workers=False):
|
||||
exec_cmd(cmd, cwd=bench_path)
|
||||
|
||||
else:
|
||||
supervisor_status = subprocess.check_output(['sudo', 'supervisorctl', 'status'], cwd=bench_path)
|
||||
supervisor_status = get_cmd_output('supervisorctl status', cwd=bench_path)
|
||||
supervisor_status = safe_decode(supervisor_status)
|
||||
|
||||
if web_workers and '{bench_name}-web:'.format(bench_name=bench_name) in supervisor_status:
|
||||
@ -535,7 +528,7 @@ def restart_supervisor_processes(bench_path='.', web_workers=False):
|
||||
else:
|
||||
group = 'frappe:'
|
||||
|
||||
exec_cmd('sudo supervisorctl restart {group}'.format(group=group), cwd=bench_path)
|
||||
exec_cmd('supervisorctl restart {group}'.format(group=group), cwd=bench_path)
|
||||
|
||||
|
||||
def restart_systemd_processes(bench_path='.', web_workers=False):
|
||||
@ -1048,8 +1041,8 @@ def migrate_env(python, backup=False):
|
||||
from bench.config.common_site_config import get_config
|
||||
from bench.app import get_apps
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
log.setLevel(logging.DEBUG)
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
nvenv = 'env'
|
||||
path = os.getcwd()
|
||||
@ -1065,12 +1058,12 @@ def migrate_env(python, backup=False):
|
||||
|
||||
redis = '{redis} -p {port}'.format(redis=which('redis-cli'), port=rredis.port)
|
||||
|
||||
log.debug('Clearing Redis Cache...')
|
||||
logger.debug('Clearing Redis Cache...')
|
||||
exec_cmd('{redis} FLUSHALL'.format(redis = redis))
|
||||
log.debug('Clearing Redis DataBase...')
|
||||
logger.debug('Clearing Redis DataBase...')
|
||||
exec_cmd('{redis} FLUSHDB'.format(redis = redis))
|
||||
except:
|
||||
log.warn('Please ensure Redis Connections are running or Daemonized.')
|
||||
logger.warn('Please ensure Redis Connections are running or Daemonized.')
|
||||
|
||||
# Backup venv: restore using `virtualenv --relocatable` if needed
|
||||
if backup:
|
||||
@ -1081,7 +1074,7 @@ def migrate_env(python, backup=False):
|
||||
source = os.path.join(path, 'env')
|
||||
target = parch
|
||||
|
||||
log.debug('Backing up Virtual Environment')
|
||||
logger.debug('Backing up Virtual Environment')
|
||||
stamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||
dest = os.path.join(path, str(stamp))
|
||||
|
||||
@ -1090,15 +1083,15 @@ def migrate_env(python, backup=False):
|
||||
|
||||
# Create virtualenv using specified python
|
||||
try:
|
||||
log.debug('Setting up a New Virtual {} Environment'.format(python))
|
||||
logger.debug('Setting up a New Virtual {} Environment'.format(python))
|
||||
exec_cmd('{virtualenv} --python {python} {pvenv}'.format(virtualenv=virtualenv, python=python, pvenv=pvenv))
|
||||
|
||||
apps = ' '.join(["-e {}".format(os.path.join("apps", app)) for app in get_apps()])
|
||||
exec_cmd('{0} install -q -U {1}'.format(pip, apps))
|
||||
|
||||
log.debug('Migration Successful to {}'.format(python))
|
||||
logger.debug('Migration Successful to {}'.format(python))
|
||||
except:
|
||||
log.debug('Migration Error')
|
||||
logger.debug('Migration Error')
|
||||
raise
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user