diff --git a/bench/config/templates/frappe_sudoers b/bench/config/templates/frappe_sudoers new file mode 100644 index 00000000..c002fcd4 --- /dev/null +++ b/bench/config/templates/frappe_sudoers @@ -0,0 +1,18 @@ +{% 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 %} +Defaults:{{ user }} !requiretty + diff --git a/bench/tests/test_setup_production.py b/bench/tests/test_setup_production.py index 836510f9..afe1a85b 100644 --- a/bench/tests/test_setup_production.py +++ b/bench/tests/test_setup_production.py @@ -28,6 +28,10 @@ class TestSetupProduction(test_init.TestBenchInit): self.assert_nginx_process() + # sudoers + bench.utils.setup_sudoers(user) + self.assert_sudoers(user) + def test_setup_production_v6(self): bench_name = 'test-bench-v6' self.test_init(bench_name, frappe_branch='master') @@ -67,6 +71,17 @@ class TestSetupProduction(test_init.TestBenchInit): out = bench.utils.get_cmd_output("sudo nginx -t 2>&1") self.assertTrue("nginx: configuration file /etc/nginx/nginx.conf test is successful" in out) + def assert_sudoers(self, user): + sudoers_file = '/etc/sudoers.d/frappe' + self.assertTrue(os.path.exists(sudoers_file)) + + with open(sudoers_file, 'r') as f: + sudoers = f.read().decode('utf-8') + + 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) + def assert_supervisor_config(self, bench_name, use_rq=True): conf_src = os.path.join(os.path.abspath(self.benches_path), bench_name, 'config', 'supervisor.conf') diff --git a/bench/utils.py b/bench/utils.py index 8a0b981e..84b95715 100644 --- a/bench/utils.py +++ b/bench/utils.py @@ -10,6 +10,7 @@ import select import multiprocessing from distutils.spawn import find_executable import pwd, grp +from bench import env class PatchError(Exception): pass @@ -193,11 +194,33 @@ def update_bench(): exec_cmd("git pull", cwd=cwd) def setup_sudoers(user): + if not os.path.exists('/etc/sudoers.d'): + os.makedirs('/etc/sudoers.d') + + set_permissions = False + if not os.path.exists('/etc/sudoers'): + set_permissions = True + + with open('/etc/sudoers', 'a') as f: + f.write('\n#includedir /etc/sudoers.d\n') + + if set_permissions: + os.chmod('/etc/sudoers', 0440) + 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'), + }) + with open(sudoers_file, 'w') as f: - f.write("{user} ALL=(ALL) NOPASSWD: {supervisorctl}\n".format( - user=user, - supervisorctl=subprocess.check_output('which supervisorctl', shell=True).strip())) + f.write(frappe_sudoers.encode('utf-8')) + os.chmod(sudoers_file, 0440) def setup_logging(bench='.'):