def handle(self, *args, **options): context = { 'site_dir': get_site_dir(), 'orchestra_beat': run('which orchestra-beat').stdout.decode('utf8'), 'venv': os.environ.get('VIRTUAL_ENV', ''), } content = run('crontab -l || true').stdout.decode('utf8') if 'orchestra-beat' not in content: if context['venv']: content += "\n* * * * * . %(venv)s/bin/activate && %(orchestra_beat)s %(site_dir)s/manage.py; deactivate" % context else: content += "\n* * * * * %(orchestra_beat)s %(site_dir)s/manage.py" % context context['content'] = content run("cat << EOF | crontab\n%(content)s\nEOF" % context, display=True) # Configrue settings to use threaded task backend (default) changes = {} if Setting.settings['TASKS_BACKEND'].value == 'celery': changes['TASKS_BACKEND'] = settings_parser.Remove() if 'celeryd' in Setting.settings['ORCHESTRA_START_SERVICES'].value: changes['ORCHESTRA_START_SERVICES'] = settings_parser.Remove() if 'celeryd' in Setting.settings['ORCHESTRA_RESTART_SERVICES'].value: changes['ORCHESTRA_RESTART_SERVICES'] = settings_parser.Remove() if 'celeryd' in Setting.settings['ORCHESTRA_STOP_SERVICES'].value: changes['ORCHESTRA_STOP_SERVICES'] = settings_parser.Remove() if changes: settings_parser.apply(changes)
def save(self, *args, **kwargs): created = not self.pk super(Resource, self).save(*args, **kwargs) self.sync_periodic_task() # This only work on tests (multiprocessing used on real deployments) apps.get_app_config('resources').reload_relations() run('{ sleep 2 && touch %s/wsgi.py; } &' % get_project_dir(), async=True)
def handle(self, *args, **options): context = { "site_dir": get_site_dir(), "orchestra_beat": run("which orchestra-beat").stdout.decode("utf8"), "venv": os.environ.get("VIRTUAL_ENV", ""), } content = run("crontab -l || true").stdout.decode("utf8") if "orchestra-beat" not in content: if context["venv"]: content += ( "\n* * * * * . %(venv)s/bin/activate && %(orchestra_beat)s %(site_dir)s/manage.py; deactivate" % context ) else: content += "\n* * * * * %(orchestra_beat)s %(site_dir)s/manage.py" % context context["content"] = content run("cat << EOF | crontab\n%(content)s\nEOF" % context, display=True) # Configrue settings to use threaded task backend (default) changes = {} if Setting.settings["TASKS_BACKEND"].value == "celery": changes["TASKS_BACKEND"] = settings_parser.Remove() if "celeryd" in Setting.settings["ORCHESTRA_START_SERVICES"].value: changes["ORCHESTRA_START_SERVICES"] = settings_parser.Remove() if "celeryd" in Setting.settings["ORCHESTRA_RESTART_SERVICES"].value: changes["ORCHESTRA_RESTART_SERVICES"] = settings_parser.Remove() if "celeryd" in Setting.settings["ORCHESTRA_STOP_SERVICES"].value: changes["ORCHESTRA_STOP_SERVICES"] = settings_parser.Remove() if changes: settings_parser.apply(changes)
def form_valid(self, form): settings = Setting.settings changes = {} for data in form.cleaned_data: setting = settings[data['name']] if not isinstance(data['value'], parser.NotSupported) and setting.editable: if setting.value != data['value']: if setting.default == data['value']: changes[setting.name] = parser.Remove() else: changes[setting.name] = parser.serialize(data['value']) if changes: # Display confirmation if not self.request.POST.get('confirmation'): settings_file = parser.get_settings_file() new_content = parser.apply(changes) diff = sys.run("cat <<EOF | diff %s -\n%s\nEOF" % (settings_file, new_content), error_codes=[1, 0]).stdout context = self.get_context_data(form=form) context['diff'] = diff return self.render_to_response(context) # Save changes parser.save(changes) sys.run('{ sleep 2 && touch %s/wsgi.py; } &' % paths.get_project_dir(), async=True) n = len(changes) context = { 'message': ngettext( _("One change successfully applied, orchestra is being restarted."), _("%s changes successfully applied, orchestra is being restarted.") % n, n), } return render_to_response(self.reload_template_name, context) else: messages.success(self.request, _("No changes have been detected.")) return super(SettingView, self).form_valid(form)
def handle(self, *args, **options): context = { 'project_name': paths.get_project_name(), 'site_dir': paths.get_site_dir(), } banner = "%(project_name)s status" % context self.stdout.write(banner) self.stdout.write('-' * len(banner)) self.stdout.write(' Orchestra version: ' + get_version()) if djsettings.DEBUG: self.stdout.write(" debug enabled") else: self.stdout.write(" debug disabled") ps = run('ps aux').stdout.decode().replace('\n', ' ') for service in flatten(settings.ORCHESTRA_START_SERVICES): context['service'] = service if self.is_running(context, ps): self.stdout.write(" %(service)s online" % context) else: self.stdout.write(" %(service)s offline" % context) if service == 'nginx': try: config_path = '/etc/nginx/sites-enabled/%(project_name)s.conf' % context with open(config_path, 'r') as handler: config = handler.read().replace('\n', ' ') except FileNotFoundError: self.stdout.write(" * %s not found" % config_path) else: regex = r'location\s+([^\s]+)\s+{.*uwsgi_pass unix:///var/run/uwsgi/app/%(project_name)s/socket;.*' % context location = re.findall(regex, config) if location: ip = run( "ip a | grep 'inet ' | awk {'print $2'} | grep -v '^127.0.' | head -n 1 | cut -d'/' -f1" ).stdout.decode() if not ip: ip = '127.0.0.1' location = 'http://%s%s' % (ip, location[0]) self.stdout.write(" * location %s" % location) else: self.stdout.write(" * location not found") elif service == 'postgresql': db_conn = connections['default'] try: c = db_conn.cursor() except OperationalError: self.stdout.write(" * DB connection failed") else: self.stdout.write(" * DB connection succeeded") elif service == 'uwsgi': uwsgi_config = '/etc/uwsgi/apps-enabled/%(project_name)s.ini' % context if os.path.isfile(uwsgi_config): self.stdout.write(" * %s exists" % uwsgi_config) else: self.stdout.write(" * %s does not exist" % uwsgi_config) cronbeat = 'crontab -l | grep "^.*/orchestra-beat %(site_dir)s/manage.py"' % context if run(cronbeat, valid_codes=(0, 1)).exit_code == 0: self.stdout.write(" cronbeat installed") else: self.stdout.write(" cronbeat not installed")
def handle(self, *args, **options): context = { 'project_name': paths.get_project_name(), 'site_dir': paths.get_site_dir(), } banner = "%(project_name)s status" % context self.stdout.write(banner) self.stdout.write('-'*len(banner)) self.stdout.write(' Orchestra version: ' + get_version()) if djsettings.DEBUG: self.stdout.write(" debug enabled") else: self.stdout.write(" debug disabled") ps = run('ps aux').stdout.decode().replace('\n', ' ') for service in flatten(settings.ORCHESTRA_START_SERVICES): context['service'] = service if self.is_running(context, ps): self.stdout.write(" %(service)s online" % context) else: self.stdout.write(" %(service)s offline" % context) if service == 'nginx': try: config_path = '/etc/nginx/sites-enabled/%(project_name)s.conf' % context with open(config_path, 'r') as handler: config = handler.read().replace('\n', ' ') except FileNotFoundError: self.stdout.write(" * %s not found" % config_path) else: regex = r'location\s+([^\s]+)\s+{.*uwsgi_pass unix:///var/run/uwsgi/app/%(project_name)s/socket;.*' % context location = re.findall(regex, config) if location: ip = run("ip a | grep 'inet ' | awk {'print $2'} | grep -v '^127.0.' | head -n 1 | cut -d'/' -f1").stdout.decode() if not ip: ip = '127.0.0.1' location = 'http://%s%s' % (ip, location[0]) self.stdout.write(" * location %s" % location) else: self.stdout.write(" * location not found") elif service == 'postgresql': db_conn = connections['default'] try: c = db_conn.cursor() except OperationalError: self.stdout.write(" * DB connection failed") else: self.stdout.write(" * DB connection succeeded") elif service == 'uwsgi': uwsgi_config = '/etc/uwsgi/apps-enabled/%(project_name)s.ini' % context if os.path.isfile(uwsgi_config): self.stdout.write(" * %s exists" % uwsgi_config) else: self.stdout.write(" * %s does not exist" % uwsgi_config) cronbeat = 'crontab -l | grep "^.*/orchestra-beat %(site_dir)s/manage.py"' % context if run(cronbeat, valid_codes=(0, 1)).exit_code == 0: self.stdout.write(" cronbeat installed") else: self.stdout.write(" cronbeat not installed")
def handle(self, *args, **options): context = { 'site_dir': get_site_dir(), 'orchestra_beat': run('which orchestra-beat').stdout.decode('utf8'), 'venv': os.environ.get('VIRTUAL_ENV', ''), } content = run('crontab -l || true').stdout.decode('utf8') if 'orchestra-beat' not in content: if context['venv']: content += "\n* * * * * . %(venv)s/bin/activate && %(orchestra_beat)s %(site_dir)s/manage.py; deactivate" % context else: content += "\n* * * * * %(orchestra_beat)s %(site_dir)s/manage.py" % context context['content'] = content run("cat << EOF | crontab\n%(content)s\nEOF" % context, display=True)
def deprecate_periodic_tasks(names): from djcelery.models import PeriodicTask for name in names: PeriodicTask.objects.filter(name=name).delete() run('rabbitmqctl stop_app') run('rabbitmqctl reset') run('rabbitmqctl start_app') run('service celeryd restart')
def retrieve_state(servers): uptimes = [] pings = [] for server in servers: address = server.get_address() ping = run('ping -c 1 -w 1 %s' % address, async=True) pings.append(ping) uptime = sshrun(address, 'uptime', persist=True, async=True, options={'ConnectTimeout': 1}) uptimes.append(uptime) state = {} for server, ping, uptime in zip(servers, pings, uptimes): ping = join(ping, silent=True) ping = ping.stdout.splitlines()[-1].decode() if ping.startswith('rtt'): ping = '%s ms' % ping.split('/')[4] else: ping = '<span style="color:red">Offline</span>' uptime = join(uptime, silent=True) uptime_stderr = uptime.stderr.decode() uptime = uptime.stdout.decode().split() if uptime: uptime = 'Up %s %s load %s %s %s' % (uptime[2], uptime[3], uptime[-3], uptime[-2], uptime[-1]) else: uptime = '<span style="color:red">%s</span>' % uptime_stderr state[server.pk] = (ping, uptime) return state
def validate_zone(zone): """ Ultimate zone file validation using named-checkzone """ zone_name = zone.split()[0][:-1] zone_path = os.path.join(domains.settings.DOMAINS_ZONE_VALIDATION_TMP_DIR, zone_name) checkzone = domains.settings.DOMAINS_CHECKZONE_BIN_PATH try: with open(zone_path, 'wb') as f: f.write(zone.encode('ascii')) # Don't use /dev/stdin becuase the 'argument list is too long' error check = run(' '.join([checkzone, zone_name, zone_path]), valid_codes=(0, 1, 127), display=False) finally: try: os.unlink(zone_path) except FileNotFoundError: pass if check.exit_code == 127: logger.error("Cannot validate domain zone: %s not installed." % checkzone) elif check.exit_code == 1: errors = re.compile(r'zone.*: (.*)').findall( check.stdout.decode('utf8'))[:-1] raise ValidationError(', '.join(errors))
def get_existing_pip_installation(): """ returns current pip installation path """ if run("pip freeze|grep django-orchestra", valid_codes=(0,1)).exit_code == 0: for lib_path in get_python_lib(), get_python_lib(prefix="/usr/local"): existing_path = os.path.abspath(os.path.join(lib_path, "orchestra")) if os.path.exists(existing_path): return existing_path return None
def html_to_pdf(html): """ converts HTL to PDF using wkhtmltopdf """ return run( 'PATH=$PATH:/usr/local/bin/\n' 'xvfb-run -a -s "-screen 0 640x4800x16" ' 'wkhtmltopdf -q --footer-center "Page [page] of [topage]" ' ' --footer-font-size 9 --margin-bottom 20 --margin-top 20 - -', stdin=html.encode('utf-8') ).stdout
def run_tuple(services, action, options, optional=False): if isinstance(services, str): services = [services] for service in services: if options.get(service): valid_codes = (0,1) if optional else (0,) e = run('service %s %s' % (service, action), valid_codes=valid_codes) if e.exit_code == 1: return False return True
def validate_www_update(self, server_addr, domain_name): context = {'domain_name': domain_name, 'server_addr': server_addr} dig_cname = 'dig @%(server_addr)s www.%(domain_name)s CNAME | grep "\sCNAME\s"' cname = run(dig_cname % context).stdout.split() # testdomain.org. 3600 IN MX 10 orchestra.lan. self.assertEqual('www.%(domain_name)s.' % context, cname[0]) self.assertEqual('3600', cname[1]) self.assertEqual('IN', cname[2]) self.assertEqual('CNAME', cname[3]) self.assertEqual('external.server.org.', cname[4])
def validate_add(self, server_addr, domain_name): context = {'domain_name': domain_name, 'server_addr': server_addr} dig_soa = 'dig @%(server_addr)s %(domain_name)s SOA|grep "\sSOA\s"' soa = run(dig_soa % context).stdout.split() # testdomain.org. 3600 IN SOA ns.example.com. hostmaster.example.com. 2014021100 86400 7200 2419200 3600 self.assertEqual('%(domain_name)s.' % context, soa[0]) self.assertEqual('3600', soa[1]) self.assertEqual('IN', soa[2]) self.assertEqual('SOA', soa[3]) self.assertEqual('%s.' % settings.DOMAINS_DEFAULT_NAME_SERVER, soa[4]) hostmaster = utils.format_hostmaster( settings.DOMAINS_DEFAULT_HOSTMASTER) self.assertEqual(hostmaster, soa[5]) dig_ns = 'dig @%(server_addr)s %(domain_name)s NS|grep "\sNS\s"' name_servers = run(dig_ns % context).stdout # testdomain.org. 3600 IN NS ns1.orchestra.lan. ns_records = [ 'ns1.%s.' % self.domain_name, 'ns2.%s.' % self.domain_name ] self.assertEqual(2, len(name_servers.splitlines())) for ns in name_servers.splitlines(): ns = ns.split() # testdomain.org. 3600 IN NS ns1.orchestra.lan. self.assertEqual('%(domain_name)s.' % context, ns[0]) self.assertEqual('3600', ns[1]) self.assertEqual('IN', ns[2]) self.assertEqual('NS', ns[3]) self.assertIn(ns[4], ns_records) dig_mx = 'dig @%(server_addr)s %(domain_name)s MX|grep "\sMX\s"' mail_servers = run(dig_mx % context).stdout for mx in mail_servers.splitlines(): mx = mx.split() # testdomain.org. 3600 IN NS ns1.orchestra.lan. self.assertEqual('%(domain_name)s.' % context, mx[0]) self.assertEqual('3600', mx[1]) self.assertEqual('IN', mx[2]) self.assertEqual('MX', mx[3]) self.assertIn(mx[4], ['10', '20']) self.assertIn(mx[5], ['mail2.orchestra.lan.', 'mail.orchestra.lan.'])
def run_tuple(services, action, options, optional=False): if isinstance(services, str): services = [services] for service in services: if options.get(service): error_codes = [0,1] if optional else [0] e = run('service %s %s' % (service, action), error_codes=error_codes) if e.return_code == 1: return False return True
def validate_add(self, server_addr, domain_name): context = { 'domain_name': domain_name, 'server_addr': server_addr } dig_soa = 'dig @%(server_addr)s %(domain_name)s SOA|grep "\sSOA\s"' soa = run(dig_soa % context).stdout.split() # testdomain.org. 3600 IN SOA ns.example.com. hostmaster.example.com. 2014021100 86400 7200 2419200 3600 self.assertEqual('%(domain_name)s.' % context, soa[0]) self.assertEqual('3600', soa[1]) self.assertEqual('IN', soa[2]) self.assertEqual('SOA', soa[3]) self.assertEqual('%s.' % settings.DOMAINS_DEFAULT_NAME_SERVER, soa[4]) hostmaster = utils.format_hostmaster(settings.DOMAINS_DEFAULT_HOSTMASTER) self.assertEqual(hostmaster, soa[5]) dig_ns = 'dig @%(server_addr)s %(domain_name)s NS|grep "\sNS\s"' name_servers = run(dig_ns % context).stdout # testdomain.org. 3600 IN NS ns1.orchestra.lan. ns_records = ['ns1.%s.' % self.domain_name, 'ns2.%s.' % self.domain_name] self.assertEqual(2, len(name_servers.splitlines())) for ns in name_servers.splitlines(): ns = ns.split() # testdomain.org. 3600 IN NS ns1.orchestra.lan. self.assertEqual('%(domain_name)s.' % context, ns[0]) self.assertEqual('3600', ns[1]) self.assertEqual('IN', ns[2]) self.assertEqual('NS', ns[3]) self.assertIn(ns[4], ns_records) dig_mx = 'dig @%(server_addr)s %(domain_name)s MX|grep "\sMX\s"' mail_servers = run(dig_mx % context).stdout for mx in mail_servers.splitlines(): mx = mx.split() # testdomain.org. 3600 IN NS ns1.orchestra.lan. self.assertEqual('%(domain_name)s.' % context, mx[0]) self.assertEqual('3600', mx[1]) self.assertEqual('IN', mx[2]) self.assertEqual('MX', mx[3]) self.assertIn(mx[4], ['10', '20']) self.assertIn(mx[5], ['mail2.orchestra.lan.', 'mail.orchestra.lan.'])
def run_tuple(services, action, options, optional=False): if isinstance(services, str): services = [services] for service in services: if options.get(service): valid_codes = (0, 1) if optional else (0, ) e = run('service %s %s' % (service, action), valid_codes=valid_codes, display=True) if e.exit_code == 1: return False return True
def validate_www_update(self, server_addr, domain_name): context = { 'domain_name': domain_name, 'server_addr': server_addr } dig_cname = 'dig @%(server_addr)s www.%(domain_name)s CNAME | grep "\sCNAME\s"' cname = run(dig_cname % context).stdout.split() # testdomain.org. 3600 IN MX 10 orchestra.lan. self.assertEqual('www.%(domain_name)s.' % context, cname[0]) self.assertEqual('3600', cname[1]) self.assertEqual('IN', cname[2]) self.assertEqual('CNAME', cname[3]) self.assertEqual('external.server.org.', cname[4])
def validate_delete(self, server_addr, domain_name): context = {'domain_name': domain_name, 'server_addr': server_addr} dig_soa = 'dig @%(server_addr)s %(domain_name)s|grep "\sSOA\s"' soa = run(dig_soa % context, valid_codes=(0, 1)).stdout if soa: soa = soa.split() self.assertEqual('IN', soa[2]) self.assertEqual('SOA', soa[3]) self.assertNotEqual('%s.' % settings.DOMAINS_DEFAULT_NAME_SERVER, soa[4]) hostmaster = utils.format_hostmaster( settings.DOMAINS_DEFAULT_HOSTMASTER) self.assertNotEqual(hostmaster, soa[5])
def validate_delete(self, server_addr, domain_name): context = { 'domain_name': domain_name, 'server_addr': server_addr } dig_soa = 'dig @%(server_addr)s %(domain_name)s|grep "\sSOA\s"' soa = run(dig_soa % context, valid_codes=(0, 1)).stdout if soa: soa = soa.split() self.assertEqual('IN', soa[2]) self.assertEqual('SOA', soa[3]) self.assertNotEqual('%s.' % settings.DOMAINS_DEFAULT_NAME_SERVER, soa[4]) hostmaster = utils.format_hostmaster(settings.DOMAINS_DEFAULT_HOSTMASTER) self.assertNotEqual(hostmaster, soa[5])
def validate_zone(zone): """ Ultimate zone file validation using named-checkzone """ zone_name = zone.split()[0][:-1] zone_path = os.path.join(settings.DOMAINS_ZONE_VALIDATION_TMP_DIR, zone_name) checkzone = settings.DOMAINS_CHECKZONE_BIN_PATH try: with open(zone_path, 'wb') as f: f.write(zone.encode('ascii')) # Don't use /dev/stdin becuase the 'argument list is too long' error check = run(' '.join([checkzone, zone_name, zone_path]), error_codes=[0,1], display=False) finally: os.unlink(zone_path) if check.return_code == 1: errors = re.compile(r'zone.*: (.*)').findall(check.stdout)[:-1] raise ValidationError(', '.join(errors))
def validate_sieve(value): sieve_name = '%s.sieve' % hashlib.md5(value.encode('utf8')).hexdigest() path = os.path.join(settings.MAILBOXES_SIEVETEST_PATH, sieve_name) with open(path, 'w') as f: f.write(value) context = { 'orchestra_root': paths.get_orchestra_dir() } sievetest = settings.MAILBOXES_SIEVETEST_BIN_PATH % context test = run(' '.join([sievetest, path, '/dev/null']), silent=True) if test.return_code: errors = [] for line in test.stderr.decode('utf8').splitlines(): error = re.match(r'^.*(line\s+[0-9]+:.*)', line) if error: errors += error.groups() raise ValidationError(' '.join(errors))
def validate_sieve(value): sieve_name = '%s.sieve' % hashlib.md5(value).hexdigest() path = os.path.join(settings.MAILBOXES_SIEVETEST_PATH, sieve_name) with open(path, 'wb') as f: f.write(value) context = { 'orchestra_root': paths.get_orchestra_dir() } sievetest = settings.MAILBOXES_SIEVETEST_BIN_PATH % context try: test = run(' '.join([sievetest, path, '/dev/null']), display=False) except CommandError: errors = [] for line in test.stderr.splitlines(): error = re.match(r'^.*(line\s+[0-9]+:.*)', line) if error: errors += error.groups() raise ValidationError(' '.join(errors))
def validate_sieve(value): sieve_name = '%s.sieve' % hashlib.md5(value.encode('utf8')).hexdigest() test_path = os.path.join(settings.MAILBOXES_SIEVETEST_PATH, sieve_name) with open(test_path, 'w') as f: f.write(value) context = {'orchestra_root': paths.get_orchestra_dir()} sievetest = settings.MAILBOXES_SIEVETEST_BIN_PATH % context try: test = run(' '.join([sievetest, test_path, '/dev/null']), silent=True) finally: os.unlink(test_path) if test.exit_code: errors = [] for line in test.stderr.decode('utf8').splitlines(): error = re.match(r'^.*(line\s+[0-9]+:.*)', line) if error: errors += error.groups() raise ValidationError(' '.join(errors))
def html_to_pdf(html, pagination=False): """ converts HTL to PDF using wkhtmltopdf """ context = { 'pagination': textwrap.dedent("""\ --footer-center "Page [page] of [topage]" \\ --footer-font-name sans \\ --footer-font-size 7 \\ --footer-spacing 7""" ) if pagination else '', } cmd = textwrap.dedent("""\ PATH=$PATH:/usr/local/bin/ xvfb-run -a -s "-screen 0 2480x3508x16" wkhtmltopdf -q \\ --use-xserver \\ %(pagination)s \\ --margin-bottom 22 \\ --margin-top 20 - - \ """) % context return run(cmd, stdin=html.encode('utf-8')).stdout
def html_to_pdf(html, pagination=False): """ converts HTL to PDF using wkhtmltopdf """ context = { 'pagination': textwrap.dedent("""\ --footer-center "Page [page] of [topage]" \\ --footer-font-name sans \\ --footer-font-size 7 \\ --footer-spacing 7""") if pagination else '', } cmd = textwrap.dedent("""\ PATH=$PATH:/usr/local/bin/ xvfb-run -a -s "-screen 0 2480x3508x16" wkhtmltopdf -q \\ --use-xserver \\ %(pagination)s \\ --margin-bottom 22 \\ --margin-top 20 - - \ """) % context return run(cmd, stdin=html.encode('utf-8')).stdout
def form_valid(self, form): settings = Setting.settings changes = {} for data in form.cleaned_data: setting = settings[data['name']] if not isinstance(data['value'], parser.NotSupported) and setting.editable: if setting.value != data['value']: # Ignore differences between lists and tuples if (type(setting.value) != type(data['value']) and isinstance(data['value'], list) and tuple(data['value']) == setting.value): continue if setting.default == data['value']: changes[setting.name] = parser.Remove() else: changes[setting.name] = data['value'] if changes: # Display confirmation if not self.request.POST.get('confirmation'): settings_file = parser.get_settings_file() new_content = parser.apply(changes) cmd = "cat <<EOF | diff %s -\n%s\nEOF" % (settings_file, new_content) diff = sys.run(cmd, valid_codes=(1, 0)).stdout context = self.get_context_data(form=form) context['diff'] = diff if not diff: messages.warning(self.request, _("Changes detected but no diff %s.") % changes) return self.render_to_response(context) n = len(changes) # Save changes parser.save(changes) sys.touch_wsgi() context = { 'message': ngettext( _("One change successfully applied, orchestra is being restarted."), _("%s changes successfully applied, orchestra is being restarted.") % n, n), } return render_to_response(self.reload_template_name, context) else: messages.success(self.request, _("No changes have been detected.")) return super(SettingView, self).form_valid(form)
def validate_zone(zone): """ Ultimate zone file validation using named-checkzone """ zone_name = zone.split()[0][:-1] zone_path = os.path.join(domains.settings.DOMAINS_ZONE_VALIDATION_TMP_DIR, zone_name) checkzone = domains.settings.DOMAINS_CHECKZONE_BIN_PATH try: with open(zone_path, 'wb') as f: f.write(zone.encode('ascii')) # Don't use /dev/stdin becuase the 'argument list is too long' error check = run(' '.join([checkzone, zone_name, zone_path]), valid_codes=(0,1,127), display=False) finally: try: os.unlink(zone_path) except FileNotFoundError: pass if check.exit_code == 127: logger.error("Cannot validate domain zone: %s not installed." % checkzone) elif check.exit_code == 1: errors = re.compile(r'zone.*: (.*)').findall(check.stdout.decode('utf8'))[:-1] raise ValidationError(', '.join(errors))
def retrieve_state(servers): uptimes = [] pings = [] for server in servers: address = server.get_address() ping = run('ping -c 1 -w 1 %s' % address, run_async=True) pings.append(ping) uptime = sshrun(address, 'uptime', persist=True, run_async=True, options={'ConnectTimeout': 1}) uptimes.append(uptime) state = {} for server, ping, uptime in zip(servers, pings, uptimes): ping = join(ping, silent=True) try: ping = ping.stdout.splitlines()[-1].decode() except IndexError: ping = '' if ping.startswith('rtt'): ping = '%s ms' % ping.split('/')[4] else: ping = '<span style="color:red">Offline</span>' uptime = join(uptime, silent=True) uptime_stderr = uptime.stderr.decode() uptime = uptime.stdout.decode().split() if uptime: uptime = 'Up %s %s load %s %s %s' % ( uptime[2], uptime[3], uptime[-3], uptime[-2], uptime[-1]) else: uptime = '<span style="color:red">%s</span>' % uptime_stderr state[server.pk] = (ping, uptime) return state
def handle(self, *filenames, **options): flake = run('flake8 {%s,%s} | grep -v "W293\|E501"' % (get_orchestra_dir(), get_site_dir())) self.stdout.write(flake.stdout.decode('utf8'))
def handle(self, *args, **options): version = options.get('version') upgrade_notes = [] if version: version_re = re.compile(r'^\s*(\d+)\.(\d+)\.(\d+).*') minor_release = version_re.search(version) if minor_release is not None: major, major2, minor = version_re.search(version).groups() else: version_re = re.compile(r'^\s*(\d+)\.(\d+).*') major, major2 = version_re.search(version).groups() minor = 0 # Represent version as two digits per number: 1.2.2 -> 10202 version = int( str(major) + "%02d" % int(major2) + "%02d" % int(minor)) # Pre version specific upgrade operations if version < '001': pass if not options.get('specifics_only'): # Common stuff orchestra_admin = os.path.join(os.path.dirname(__file__), '../../bin/') orchestra_admin = os.path.join(orchestra_admin, 'orchestra-admin') run('chmod +x %s' % orchestra_admin) run("%s install_requirements" % orchestra_admin) manage_path = os.path.join(get_site_dir(), 'manage.py') run("python %s collectstatic --noinput" % manage_path) run("python %s migrate --noinput accounts" % manage_path) run("python %s migrate --noinput" % manage_path) if options.get('restart'): run("python %s restartservices" % manage_path) if not version: self.stderr.write( '\n' 'Next time you migth want to provide a --from argument in order ' 'to run version specific upgrade operations\n') return # Post version specific operations if version <= '001': pass if upgrade_notes and options.get('print_upgrade_notes'): self.stdout.write('\n\033[1m\n' ' ===================\n' ' ** UPGRADE NOTES **\n' ' ===================\n\n' + '\n'.join(upgrade_notes) + '\033[m\n')
def handle(self, *args, **options): # Configure firmware generation context = { 'db_name': options.get('db_name'), 'db_user': options.get('db_user'), 'db_password': options.get('db_password'), 'db_host': options.get('db_host'), 'vmail_username': options.get('vmail_username'), 'vmail_uid': options.get('vmail_uid'), 'vmail_groupname': options.get('vmail_groupname'), 'vmail_gid': options.get('vmail_gid'), 'vmail_home': options.get('vmail_home'), 'dovecot_dir': options.get('dovecot_dir'), 'postfix_dir': options.get('postfix_dir'), 'amavis_dir': options.get('amavis_dir'), } file_name = '%(postfix_dir)s/pgsql-email2email.cf' % context run("#Processing %s" % file_name) pgsql_email2email = """user = %(db_user)s password = %(db_password)s hosts = %(db_host)s dbname = %(db_name)s query = SELECT mails_mailbox.emailname || '@' || names_domain.name as email FROM mails_mailbox INNER JOIN names_domain ON (mails_mailbox.domain_id = names_domain.id) WHERE mails_mailbox.emailname = '%%u' AND names_domain.name = '%%d' """ f = open(file_name, 'w') f.write(pgsql_email2email % context) f.close() run("chown root:postfix %s" % file_name) run("chmod 640 %s" % file_name) file_name = '%(postfix_dir)s/pgsql-virtual-alias-maps.cf' % context run("#Processing %s" % file_name) virtual_alias_maps = """user = %(db_user)s password = %(db_password)s hosts = %(db_host)s dbname = %(db_name)s query = SELECT mails_mailalias.destination FROM mails_mailalias INNER JOIN names_domain ON (mails_mailalias.domain_id = names_domain.id) WHERE mails_mailalias.emailname = '%%u' AND names_domain.name='%%d' """ f = open(file_name, 'w') f.write(virtual_alias_maps % context) f.close() run("chown root:postfix %s" % file_name) run("chmod 640 %s" % file_name) file_name = '%(postfix_dir)s/pgsql-virtual-mailbox-domains.cf' % context run("#Processing %s" % file_name) virtual_mailbox_domains = """user = %(db_user)s password = %(db_password)s hosts = %(db_host)s dbname = %(db_name)s query = SELECT 1 FROM names_domain WHERE names_domain.name='%%s' """ f = open(file_name, 'w') f.write(virtual_mailbox_domains % context) f.close() run("chown root:postfix %s" % file_name) run("chmod 640 %s" % file_name) file_name = '%(postfix_dir)s/pgsql-virtual-mailbox-maps.cf' % context run("#Processing %s" % file_name) virtual_mailbox_maps = """user = %(db_user)s password = %(db_password)s hosts = %(db_host)s dbname = %(db_name)s query = SELECT 1 FROM mails_mailbox INNER JOIN names_domain ON (mails_mailbox.domain_id = names_domain.id) WHERE mails_mailbox.emailname='%%u' AND names_domain.name='%%d' """ f = open(file_name, 'w') f.write(virtual_mailbox_maps % context) f.close() run("chown root:postfix %s" % file_name) run("chmod 640 %s" % file_name) #Dovecot vmail_usename = run("id -u %(vmail_username)s" % context) vmail_groupname = run("id -g %(vmail_groupname)s" % context) if vmail_groupname != context["vmail_gid"]: run("groupadd -g %(vmail_gid)s %(vmail_groupname)s" % context) run("chown -R %(vmail_username)s:%(vmail_groupname)s %(vmail_home)s" % context) if vmail_usename != context["vmail_uid"]: run("useradd -g %(vmail_groupname)s -u %(vmail_uid)s %(vmail_username)s -d %(vmail_home)s -m" % context) run("chmod u+w %(vmail_home)s" % context) run("chown -R %(vmail_username)s:%(vmail_groupname)s %(vmail_home)s" % context) run("chmod u+w %(vmail_home)s" % context) file_name = "%(dovecot_dir)s/conf.d/10-auth.conf" % context run("""sed -i "s/auth_mechanisms = plain$/auth_mechanisms = plain login/g" %s """ % file_name) run("""sed -i "s/\#\!include auth-sql.conf.ext/\!include auth-sql.conf.ext/" %s """ % file_name) file_name = "%(dovecot_dir)s/conf.d/auth-sql.conf.ext" % context run("#Processing %s" % file_name) auth_sql_conf_ext = """passdb { driver = sql args = %(dovecot_dir)s/dovecot-sql.conf.ext } userdb { driver = static args = uid=%(vmail_username)s gid=%(vmail_groupname)s home=%(vmail_home)s/%%d/%%n/Maildir allow_all_users=yes } """ f = open(file_name, 'w') f.write(auth_sql_conf_ext % context) f.close() file_name = "%(dovecot_dir)s/conf.d/10-mail.conf" % context run("#Processing %s" % file_name) mail_conf = """mail_location = maildir:%(vmail_home)s/%%d/%%n/Maildir namespace inbox { separator = . inbox = yes } """ f = open(file_name, 'w') f.write(mail_conf % context) f.close() file_name = "%(dovecot_dir)s/conf.d/10-master.conf" % context run("""sed -i "s/service auth {/service auth {\\n\\tunix_listener \/var\/spool\/postfix\/private\/auth {\\n\\t\\tmode = 0660\\n\\t\\tuser = postfix\\n\\t\\tgroup = postfix\\n\\t}\\n/g" %s """ % file_name) file_name = "%(dovecot_dir)s/conf.d/10-ssl.conf" % context run("#Processing %s" % file_name) ssl_conf = """ssl_cert = </etc/ssl/certs/mailserver.pem ssl_key = </etc/ssl/private/mailserver.pem""" f = open(file_name, 'w') f.write(ssl_conf) f.close() file_name = "%(dovecot_dir)s/conf.d/15-lda.conf" % context run("#Processing %s" % file_name) lda_conf ="""protocol lda { postmaster_address = postmaster mail_plugins = $mail_plugins sieve } """ f = open(file_name, 'w') f.write(lda_conf) f.close() file_name = "%(dovecot_dir)s/dovecot-sql.conf.ext" % context run("#Processing %s" % file_name) dovecot_sql = """driver = pgsql connect = host=%(db_host)s dbname=%(db_name)s user=%(db_user)s password=%(db_password)s default_pass_scheme = SSHA password_query = \ SELECT mails_mailbox.emailname || '@' || names_domain.name as user, mails_mailbox.shadigest as password \\ FROM mails_mailbox \\ INNER JOIN names_domain ON (mails_mailbox.domain_id = names_domain.id) \\ INNER JOIN auth_user ON (mails_mailbox.user_id = auth_user.id) \\ WHERE mails_mailbox.emailname = '%%n' AND \\ names_domain.name = '%%d' """ f = open(file_name, 'w') f.write(dovecot_sql % context) f.close() run("chgrp %(vmail_groupname)s %(dovecot_dir)s/dovecot.conf" % context) run("chmod g+r %(dovecot_dir)s/dovecot.conf" % context) run("chown root:root %(dovecot_dir)s/dovecot-sql.conf.ext" % context) run("chmod go= %(dovecot_dir)s/dovecot-sql.conf.ext" % context) file_name = "%(postfix_dir)s/master.cf" % context grep_dovecot = run("grep dovecot %s" % file_name, valid_codes=(0,1)) if grep_dovecot == '': run("#Processing %s" % file_name) dovecot_master=""" dovecot unix - n n - - pipe flags=DRhu user=%(vmail_username)s:%(vmail_groupname)s argv=/usr/lib/dovecot/dovecot-lda -f ${sender} -d ${recipient} #Amavis: amavis unix - - n - 5 smtp -o smtp_data_done_timeout=1200 -o smtp_send_xforward_command=yes -o smtp_tls_note_starttls_offer=no 127.0.0.1:10025 inet n - n - - smtpd -o content_filter= -o smtpd_delay_reject=no -o smtpd_client_restrictions=permit_mynetworks,reject -o smtpd_helo_restrictions= -o smtpd_sender_restrictions= -o smtpd_recipient_restrictions=permit_mynetworks,reject -o smtpd_data_restrictions=reject_unauth_pipelining -o smtpd_end_of_data_restrictions= -o smtpd_restriction_classes= -o mynetworks=127.0.0.0/8 -o smtpd_error_sleep_time=0 -o smtpd_soft_error_limit=1001 -o smtpd_hard_error_limit=1000 -o smtpd_client_connection_count_limit=0 -o smtpd_client_connection_rate_limit=0 -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks,no_milters -o local_header_rewrite_clients= -o smtpd_milters= -o local_recipient_maps= -o relay_recipient_maps= """ f = open(file_name, 'a') f.write(dovecot_master % context) f.close() #Postfix mailname = run("cat /etc/mailname", vallid_codes=[0,1]) hostname = run("hostname", valid_codes=[0,1]) if mailname != hostname: file_name = "/etc/mailname" run("#Processing %s" % file_name) f = open(file_name, 'w') f.write(hostname % context) f.close() # Set the base address for all virtual mailboxes run("postconf -e virtual_mailbox_base=%(vmail_home)s" % context) # A list of all virtual domains serviced by this instance of postfix. run("postconf -e virtual_mailbox_domains=pgsql:%(postfix_dir)s/pgsql-virtual-mailbox-domains.cf" % context) # Look up the mailbox location based on the email address received. run("postconf -e virtual_mailbox_maps=pgsql:%(postfix_dir)s/pgsql-virtual-mailbox-maps.cf" % context) # Any aliases that are supported by this system run("postconf -e virtual_alias_maps=pgsql:%(postfix_dir)s/pgsql-virtual-alias-maps.cf" % context) #Dovecot: run("postconf -e virtual_transport=dovecot") run("postconf -e dovecot_destination_recipient_limit=1") run("postconf -e smtpd_sasl_type=dovecot") run("postconf -e smtpd_sasl_path=private/auth") run("postconf -e smtpd_sasl_auth_enable=yes") if os.path.isfile("/etc/ssl/certs/mailserver.pem"): run("postconf -e smtpd_tls_security_level=may") run("postconf -e smtpd_tls_auth_only=yes") run("postconf -e smtpd_tls_cert_file=/etc/ssl/certs/mailserver.pem") run("postconf -e smtpd_tls_key_file=/etc/ssl/private/mailserver.pem") run("""postconf -e smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject_invalid_hostname,reject_non_fqdn_recipient,reject_unknown_sender_domain,reject_unknown_recipient_domain,reject_unauth_destination,permit""") run("""postconf -e soft_bounce=no""") run("""postconf -e content_filter=amavis:[127.0.0.1]:10024""") #Amavis: file_name = "%(amavis_dir)s/conf.d/15-content_filter_mode" % context run("""sed -i "s/#@bypass_virus_checks_maps/@bypass_virus_checks_maps/g" %s""" % file_name) run("""sed -i 's/# \\\\%%bypass_virus_checks, \\\@bypass_virus_checks_acl, \\\$bypass_virus_checks_re/ \\\\%%bypass_virus_checks, \\\@bypass_virus_checks_acl, \\\$bypass_virus_checks_re/g' %s""" % file_name) run("""sed -i 's/# \\\\%%bypass_virus_checks/ \\\\%%bypass_virus_checks/g' %s""" % (file_name,) ) run("""sed -i "s/#@bypass_spam_checks_maps/@bypass_spam_checks_maps/g" %s""" % file_name) run("""sed -i 's/# \\\\%%bypass_spam_checks, \\\@bypass_spam_checks_acl, \\\$bypass_spam_checks_re/ \\\\%%bypass_spam_checks, \\\@bypass_spam_checks_acl, \\\$bypass_spam_checks_re/g' %s""" % file_name) run("adduser clamav amavis") run("service clamav-freshclam restart") run("service clamav-daemon restart") run("service spamassassin restart") run("service amavis restart") run("service dovecot restart") run("service postfix restart")
def handle(self, *args, **options): interactive = options.get('interactive') db_password = options.get('db_password') context = { 'db_name': options.get('db_name'), 'db_user': options.get('db_user'), 'db_password': db_password, 'db_host': options.get('db_host'), 'db_port': options.get('db_port'), 'default_db_password': db_password or random_ascii(10), } create_user = "******" alter_user = "******" create_database = "CREATE DATABASE %(db_name)s OWNER %(db_user)s;" # Create or update user if self.run_postgres(create_user % context, valid_codes=(0,1)).exit_code == 1: if interactive and not db_password: msg = ("Postgres user '%(db_user)s' already exists, " "please provide a password [%(default_db_password)s]: " % context) context['db_password'] = input(msg) or context['default_db_password'] self.run_postgres(alter_user % context) msg = "Updated Postgres user '%(db_user)s' password: '******'" self.stdout.write(msg % context) elif db_password: self.run_postgres(alter_user % context) msg = "Updated Postgres user '%(db_user)s' password: '******'" self.stdout.write(msg % context) else: raise CommandError("Postgres user '%(db_user)s' already exists and " "--db_pass has not been provided." % context) else: context['db_password'] = context['default_db_password'] msg = "Created new Postgres user '%(db_user)s' with password '%(db_password)s'" self.stdout.write(msg % context) self.run_postgres(create_database % context, valid_codes=(0,1)) context.update({ 'settings': os.path.join(get_project_dir(), 'settings.py') }) if run("grep '^DATABASES\s*=\s*{' %(settings)s" % context, valid_codes=(0,1)).exit_code == 0: # Update existing settings_file run(textwrap.dedent("""sed -i \\ -e "s/'ENGINE':[^#]*/'ENGINE': 'django.db.backends.postgresql_psycopg2', /" \\ -e "s/'NAME':[^#]*/'NAME': '%(db_name)s', /" \\ -e "s/'USER':[^#]*/'USER': '******', /" \\ -e "s/'PASSWORD':[^#]*/'PASSWORD': '******', /" \\ -e "s/'HOST':[^#]*/'HOST': '%(db_host)s', /" \\ -e "s/'PORT':[^#]*/'PORT': '%(db_port)s', /" %(settings)s\ """) % context ) else: db_config = textwrap.dedent("""\ DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': '%(db_name)s', 'USER': '******', 'PASSWORD': '******', 'HOST': '%(db_host)s', 'PORT': '%(db_port)s', 'ATOMIC_REQUESTS': True, } }""") % context context.update({ 'db_config': db_config }) run('echo "%(db_config)s" >> %(settings)s' % context)
def handle(self, *args, **options): user = options.get('user') if not user: raise CommandError("System user for running uwsgi must be provided.") cert_path, key_path = self.generate_certificate(**options) server_name = options.get('server_name') context = { 'cert_path': cert_path, 'key_path': key_path, 'project_name': paths.get_project_name(), 'project_dir': paths.get_project_dir(), 'site_dir': paths.get_site_dir(), 'static_root': settings.STATIC_ROOT, 'static_url': (settings.STATIC_URL or '/static').rstrip('/'), 'user': user, 'group': options.get('group') or user, 'home': expanduser("~%s" % options.get('user')), 'processes': int(options.get('processes')), 'server_name': 'server_name %s' % server_name if server_name else '' } nginx_conf = textwrap.dedent("""\ server { listen 80; listen [::]:80 ipv6only=on; return 301 https://$host$request_uri; } server { listen 443 ssl; # listen [::]:443 ssl; # add SSL support to IPv6 address %(server_name)s ssl_certificate %(cert_path)s; ssl_certificate_key %(key_path)s; rewrite ^/$ /admin/; client_max_body_size 16m; location / { uwsgi_pass unix:///var/run/uwsgi/app/%(project_name)s/socket; include uwsgi_params; } location %(static_url)s { alias %(static_root)s; expires 30d; } } """ ) % context uwsgi_conf = textwrap.dedent("""\ [uwsgi] plugins = python3 chdir = %(site_dir)s module = %(project_name)s.wsgi master = true workers = %(processes)d chmod-socket = 664 stats = /run/uwsgi/%%(deb-confnamespace)/%%(deb-confname)/statsocket uid = %(user)s gid = %(group)s env = HOME=%(home)s touch-reload = %(project_dir)s/wsgi.py vacuum = true # Remove socket stop enable-threads = true # Initializes the GIL max-requests = 500 # Mitigates memory leaks lazy-apps = true # Don't share database connections """ ) % context nginx_file = '/etc/nginx/sites-available/%(project_name)s.conf' % context if server_name: context['server_name'] = server_name nginx_file = '/etc/nginx/sites-available/%(server_name)s.conf' % context nginx = { 'file': nginx_file, 'conf': nginx_conf } uwsgi = { 'file': '/etc/uwsgi/apps-available/%(project_name)s.ini' % context, 'conf': uwsgi_conf } interactive = options.get('interactive') for extra_context in (nginx, uwsgi): context.update(extra_context) diff = run("cat << 'EOF' | diff - %(file)s\n%(conf)s\nEOF" % context, valid_codes=(0,1,2)) if diff.exit_code == 2: # File does not exist run("cat << 'EOF' > %(file)s\n%(conf)s\nEOF" % context, display=True) elif diff.exit_code == 1: # File is different, save the old one if interactive: if not confirm("\n\nFile %(file)s be updated, do you like to overide " "it? (yes/no): " % context): return run(textwrap.dedent("""\ cp %(file)s %(file)s.save cat << 'EOF' > %(file)s %(conf)s EOF""") % context, display=True ) self.stdout.write("\033[1;31mA new version of %(file)s has been installed.\n " "The old version has been placed at %(file)s.save\033[m" % context) if server_name: run('ln -s /etc/nginx/sites-available/%(server_name)s.conf /etc/nginx/sites-enabled/' % context, valid_codes=[0,1], display=True) else: run('rm -f /etc/nginx/sites-enabled/default') run('ln -s /etc/nginx/sites-available/%(project_name)s.conf /etc/nginx/sites-enabled/' % context, valid_codes=[0,1], display=True) run('ln -s /etc/uwsgi/apps-available/%(project_name)s.ini /etc/uwsgi/apps-enabled/' % context, valid_codes=[0,1], display=True) rotate = textwrap.dedent("""\ /var/log/nginx/*.log { daily missingok rotate 30 compress delaycompress notifempty create 640 root adm sharedscripts postrotate [ ! -f /var/run/nginx.pid ] || kill -USR1 `cat /var/run/nginx.pid` endscript }""" ) run("echo '%s' > /etc/logrotate.d/nginx" % rotate, display=True) # Allow nginx to write to uwsgi socket run('adduser www-data %(group)s' % context, display=True)
def run_postgres(self, cmd, *args, **kwargs): return run('su postgres -c "psql -c \\"%s\\""' % cmd, *args, **kwargs)
def handle(self, *args, **options): interactive = options.get("interactive") context = { "site_dir": get_site_dir(), "settings_path": os.path.join(get_project_dir(), "settings.py"), "project_name": get_project_name(), "log_dir": os.path.join(get_site_dir(), "log"), "log_path": os.path.join(get_site_dir(), "log", "orchestra.log"), } has_logging = not run('grep "^LOGGING\s*=" %(settings_path)s' % context, valid_codes=(0, 1)).exit_code if has_logging: if not interactive: self.stderr.write("Project settings already defines LOGGING setting, doing nothing.") return msg = ( "\n\nYour project settings file already defines a LOGGING setting.\n" "Do you want to override it? (yes/no): " ) if not confirm(msg): return settings_parser.save({"LOGGING": settings_parser.Remove()}) setuplogrotate = ( textwrap.dedent( """\ mkdir %(log_dir)s && chown --reference=%(site_dir)s %(log_dir)s touch %(log_path)s chown --reference=%(log_dir)s %(log_path)s echo '%(log_dir)s/*.log { copytruncate daily rotate 5 compress delaycompress missingok notifempty }' > /etc/logrotate.d/orchestra.%(project_name)s cat << 'EOF' >> %(settings_path)s LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'simple': { 'format': '%%(asctime)s %%(name)s %%(levelname)s %%(message)s' }, }, 'handlers': { 'file': { 'class': 'logging.FileHandler', 'filename': '%(log_path)s', 'formatter': 'simple' }, }, 'loggers': { 'orchestra': { 'handlers': ['file'], 'level': 'INFO', 'propagate': True, }, 'orm': { 'handlers': ['file'], 'level': 'INFO', 'propagate': True, }, }, } EOF""" ) % context ) run(setuplogrotate, display=True)
def handle(self, *args, **options): interactive = options.get('interactive') db_password = options.get('db_password') context = { 'db_name': options.get('db_name'), 'db_user': options.get('db_user'), 'db_password': db_password, 'db_host': options.get('db_host'), 'db_port': options.get('db_port'), 'default_db_password': db_password or random_ascii(10), } create_user = "******" alter_user = "******" create_database = "CREATE DATABASE %(db_name)s OWNER %(db_user)s;" # Create or update user if self.run_postgres(create_user % context, valid_codes=(0, 1)).exit_code == 1: if interactive and not db_password: msg = ( "Postgres user '%(db_user)s' already exists, " "please provide a password [%(default_db_password)s]: " % context) context['db_password'] = input( msg) or context['default_db_password'] self.run_postgres(alter_user % context) msg = "Updated Postgres user '%(db_user)s' password: '******'" self.stdout.write(msg % context) elif db_password: self.run_postgres(alter_user % context) msg = "Updated Postgres user '%(db_user)s' password: '******'" self.stdout.write(msg % context) else: raise CommandError( "Postgres user '%(db_user)s' already exists and " "--db_password has not been provided." % context) else: context['db_password'] = context['default_db_password'] msg = "Created new Postgres user '%(db_user)s' with password '%(db_password)s'" self.stdout.write(msg % context) self.run_postgres(create_database % context, valid_codes=(0, 1)) context.update( {'settings': os.path.join(get_project_dir(), 'settings.py')}) if run("grep '^DATABASES\s*=\s*{' %(settings)s" % context, valid_codes=(0, 1)).exit_code == 0: # Update existing settings_file run( textwrap.dedent("""sed -i \\ -e "s/'ENGINE':[^#]*/'ENGINE': 'django.db.backends.postgresql_psycopg2', /" \\ -e "s/'NAME':[^#]*/'NAME': '%(db_name)s', /" \\ -e "s/'USER':[^#]*/'USER': '******', /" \\ -e "s/'PASSWORD':[^#]*/'PASSWORD': '******', /" \\ -e "s/'HOST':[^#]*/'HOST': '%(db_host)s', /" \\ -e "s/'PORT':[^#]*/'PORT': '%(db_port)s', /" %(settings)s\ """) % context) else: db_config = textwrap.dedent("""\ DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': '%(db_name)s', 'USER': '******', 'PASSWORD': '******', 'HOST': '%(db_host)s', 'PORT': '%(db_port)s', 'ATOMIC_REQUESTS': True, } }""") % context context.update({'db_config': db_config}) run('echo "%(db_config)s" >> %(settings)s' % context)
def handle(self, *args, **options): current_version = get_version() current_path = get_existing_pip_installation() if current_path is not None: desired_version = options.get('version') if args: desired_version = args[0] if current_version == desired_version: msg = "Not upgrading, you already have version %s installed" raise CommandError(msg % desired_version) # Create a backup of current installation base_path = os.path.abspath(os.path.join(current_path, '..')) char_set = string.ascii_uppercase + string.digits rand_name = ''.join(random.sample(char_set, 6)) backup = os.path.join(base_path, 'orchestra.' + rand_name) run("mv %s %s" % (current_path, backup)) # collect existing eggs previous to the installation eggs_regex = os.path.join(base_path, 'django_orchestra-*.egg-info') eggs = run('ls -d %s' % eggs_regex) eggs = eggs.stdout.splitlines() try: if desired_version: r('pip install django-orchestra==%s' % desired_version) else: # Did I mentioned how I hate PIP? if run('pip --version|cut -d" " -f2').stdout == '1.0': r('pip install django-orchestra --upgrade') else: # (F*****g pip)^2, it returns exit code 0 even when fails # because requirement already up-to-date r('pip install django-orchestra --upgrade --force') except CommandError: # Restore backup run('rm -rf %s' % current_path) run('mv %s %s' % (backup, current_path)) raise CommandError("Problem runing pip upgrade, aborting...") else: # Some old versions of pip do not performe this cleaning ... # Remove all backups run('rm -fr %s' % os.path.join(base_path, 'orchestra\.*')) # Clean old egg files, yeah, cleaning PIP shit :P c_version = 'from orchestra import get_version; print get_version()' version = run('python -c "%s;"' % c_version).stdout for egg in eggs: # Do not remove the actual egg file when upgrading twice the same version if egg.split('/')[-1] != "django_orchestra-%s.egg-info" % version: run('rm -fr %s' % egg) else: raise CommandError("You don't seem to have any previous PIP installation") # version specific upgrade operations if not options.get('pip_only'): call_command("postupgradeorchestra", version=current_version)
def handle(self, *args, **options): version = options.get('version') upgrade_notes = [] if version: version_re = re.compile(r'^\s*(\d+)\.(\d+)\.(\d+).*') minor_release = version_re.search(version) if minor_release is not None: major, major2, minor = version_re.search(version).groups() else: version_re = re.compile(r'^\s*(\d+)\.(\d+).*') major, major2 = version_re.search(version).groups() minor = 0 # Represent version as two digits per number: 1.2.2 -> 10202 version = int(str(major) + "%02d" % int(major2) + "%02d" % int(minor)) # Pre version specific upgrade operations if version < '001': pass if not options.get('specifics_only'): # Common stuff orchestra_admin = os.path.join(os.path.dirname(__file__), '../../bin/') orchestra_admin = os.path.join(orchestra_admin, 'orchestra-admin') run('chmod +x %s' % orchestra_admin) run("%s install_requirements" % orchestra_admin) manage_path = os.path.join(get_site_dir(), 'manage.py') run("python %s collectstatic --noinput" % manage_path) run("python %s migrate --noinput accounts" % manage_path) run("python %s migrate --noinput" % manage_path) if options.get('restart'): run("python %s restartservices" % manage_path) if not version: self.stderr.write('\n' 'Next time you migth want to provide a --from argument in order ' 'to run version specific upgrade operations\n') return # Post version specific operations if version <= '001': pass if upgrade_notes and options.get('print_upgrade_notes'): self.stdout.write('\n\033[1m\n' ' ===================\n' ' ** UPGRADE NOTES **\n' ' ===================\n\n' + '\n'.join(upgrade_notes) + '\033[m\n')
def handle(self, *args, **options): context = { 'site_dir': get_site_dir(), 'username': options.get('username'), 'bin_path': path.join(get_orchestra_dir(), 'bin'), 'processes': options.get('processes'), 'settings': path.join(get_project_dir(), 'settings.py') } celery_config = textwrap.dedent("""\ # Name of nodes to start, here we have a single node CELERYD_NODES="w1" # Where to chdir at start. CELERYD_CHDIR="%(site_dir)s" # How to call "manage.py celeryd_multi" CELERYD_MULTI="python3 $CELERYD_CHDIR/manage.py celeryd_multi" # Extra arguments to celeryd CELERYD_OPTS="-P:w1 processes -c:w1 %(processes)s -Q:w1 celery" # Name of the celery config module. CELERY_CONFIG_MODULE="celeryconfig" # %%n will be replaced with the nodename. CELERYD_LOG_FILE="/var/log/celery/%%n.log" CELERYD_PID_FILE="/var/run/celery/%%n.pid" CELERY_CREATE_DIRS=1 # Full path to the celeryd logfile. CELERYEV_LOG_FILE="/var/log/celery/celeryev.log" CELERYEV_PID_FILE="/var/run/celery/celeryev.pid" # Workers should run as an unprivileged user. CELERYD_USER="******" CELERYD_GROUP="$CELERYD_USER" # Persistent revokes CELERYD_STATE_DB="$CELERYD_CHDIR/persistent_revokes" # Celeryev CELERYEV="python3 $CELERYD_CHDIR/manage.py" CELERYEV_CAM="djcelery.snapshot.Camera" CELERYEV_USER="******" CELERYEV_GROUP="$CELERYD_USER" CELERYEV_OPTS="celerycam" # Celerybeat CELERYBEAT="python3 ${CELERYD_CHDIR}/manage.py celerybeat" CELERYBEAT_USER="******" CELERYBEAT_GROUP="$CELERYD_USER" CELERYBEAT_CHDIR="$CELERYD_CHDIR" CELERYBEAT_OPTS="--schedule=/var/run/celerybeat-schedule --scheduler=djcelery.schedulers.DatabaseScheduler" """ % context) run("echo '%s' > /etc/default/celeryd" % celery_config) # https://raw.github.com/celery/celery/master/extra/generic-init.d/ for script in ['celeryevcam', 'celeryd', 'celerybeat']: context['script'] = script run('cp %(bin_path)s/%(script)s /etc/init.d/%(script)s' % context) run('chmod +x /etc/init.d/%(script)s' % context) run('update-rc.d %(script)s defaults' % context) rotate = textwrap.dedent("""\ /var/log/celery/*.log { weekly missingok rotate 10 compress delaycompress notifempty copytruncate }""") run("echo '%s' > /etc/logrotate.d/celeryd" % rotate) changes = {} if Setting.settings['TASKS_BACKEND'].value != 'celery': changes['TASKS_BACKEND'] = 'celery' if Setting.settings[ 'ORCHESTRA_START_SERVICES'].value == Setting.settings[ 'ORCHESTRA_START_SERVICES'].default: changes['ORCHESTRA_START_SERVICES'] = ( 'postgresql', 'celeryevcam', 'celeryd', 'celerybeat', ('uwsgi', 'nginx'), ) if Setting.settings[ 'ORCHESTRA_RESTART_SERVICES'].value == Setting.settings[ 'ORCHESTRA_RESTART_SERVICES'].default: changes['ORCHESTRA_RESTART_SERVICES'] = ( 'celeryd', 'celerybeat', 'uwsgi', ) if Setting.settings[ 'ORCHESTRA_STOP_SERVICES'].value == Setting.settings[ 'ORCHESTRA_STOP_SERVICES'].default: changes['ORCHESTRA_STOP_SERVICES'] = (('uwsgi', 'nginx'), 'celerybeat', 'celeryd', 'celeryevcam', 'postgresql') if changes: settings_parser.apply(changes)
def generate_certificate(self, **options): override = options.get('cert_override') interactive = options.get('interactive') cert = options.get('cert') key = options.get('cert_key') if bool(cert) != bool(key): raise CommandError("--cert and --cert-key go in tandem") cert_path = options.get('cert_path') key_path = options.get('cert_key_path') run('mkdir -p %s' % os.path.dirname(cert_path)) exists = os.path.isfile(cert_path) if not override and exists: self.stdout.write('Your cert and keys are already in place.') self.stdout.write('Use --override in order to regenerate them.') return cert_path, key_path common_name = options.get('cert_common_name') or options.get('server_name') or 'orchestra.lan' country = options.get('cert_country') state = options.get('cert_state') locality = options.get('cert_locality') org_name = options.get('cert_org_name') org_unit = options.get('cert_org_unit') email = options.get('cert_email') if interactive: msg = ('-----\n' 'You are about to be asked to enter information that\n' 'will be incorporated\n' 'into your certificate request.\n' 'What you are about to enter is what is called a\n' 'Distinguished Name or a DN.\n' 'There are quite a few fields but you can leave some blank\n' '-----\n') self.stdout.write(msg) msg = 'Country Name (2 letter code) [%s]: ' % country country = input(msg) or country msg = 'State or Province Name (full name) [%s]: ' % state state = input(msg) or state msg = 'Locality Name (eg, city) [%s]: ' % locality locality = input(msg) or locality msg = 'Organization Name (eg, company) [%s]: ' % org_name org_name = input(msg) or org_name msg = 'Organizational Unit Name (eg, section) [%s]: ' % org_unit org_unit = input(msg) or org_unit msg = 'Email Address [%s]: ' % email email = input(msg) or email self.stdout.write('Common Name: %s' % common_name) subject = { 'C': country, 'S': state, 'L': locality, 'O': org_name, 'OU': org_unit, 'Email': email, 'CN': common_name, } context = { 'subject': ''.join(('/%s=%s' % (k,v) for k,v in subject.items())), 'key_path': key_path, 'cert_path': cert_path, 'cert_root': os.path.dirname(cert_path), } self.stdout.write('writing new cert to \'%s\'' % cert_path) self.stdout.write('writing new cert key to \'%s\'' % key_path) run(textwrap.dedent("""\ openssl req -x509 -nodes -days 365 -newkey rsa:4096 -keyout %(key_path)s -out %(cert_path)s -subj "%(subject)s" chown --reference=%(cert_root)s %(cert_path)s %(key_path)s\ """) % context, display=True ) return cert_path, key_path
def handle(self, *args, **options): interactive = options.get('interactive') context = { 'site_dir': get_site_dir(), 'settings_path': os.path.join(get_project_dir(), 'settings.py'), 'project_name': get_project_name(), 'log_dir': os.path.join(get_site_dir(), 'log'), 'log_path': os.path.join(get_site_dir(), 'log', 'orchestra.log') } has_logging = not run( 'grep "^LOGGING\s*=" %(settings_path)s' % context, valid_codes=(0, 1)).exit_code if has_logging: if not interactive: self.stderr.write( "Project settings already defines LOGGING setting, doing nothing." ) return msg = ( "\n\nYour project settings file already defines a LOGGING setting.\n" "Do you want to override it? (yes/no): ") if not confirm(msg): return settings_parser.save({ 'LOGGING': settings_parser.Remove(), }) setuplogrotate = textwrap.dedent("""\ mkdir %(log_dir)s && chown --reference=%(site_dir)s %(log_dir)s touch %(log_path)s chown --reference=%(log_dir)s %(log_path)s echo '%(log_dir)s/*.log { copytruncate daily rotate 5 compress delaycompress missingok notifempty }' > /etc/logrotate.d/orchestra.%(project_name)s cat << 'EOF' >> %(settings_path)s LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'simple': { 'format': '%%(asctime)s %%(name)s %%(levelname)s %%(message)s' }, }, 'handlers': { 'file': { 'class': 'logging.FileHandler', 'filename': '%(log_path)s', 'formatter': 'simple' }, }, 'loggers': { 'orchestra': { 'handlers': ['file'], 'level': 'INFO', 'propagate': True, }, 'orm': { 'handlers': ['file'], 'level': 'INFO', 'propagate': True, }, }, } EOF""") % context run(setuplogrotate, display=True)
def handle(self, *args, **options): # Configure firmware generation context = { 'db_name': options.get('db_name'), 'db_user': options.get('db_user'), 'db_password': options.get('db_password'), 'db_host': options.get('db_host'), 'vmail_username': options.get('vmail_username'), 'vmail_uid': options.get('vmail_uid'), 'vmail_groupname': options.get('vmail_groupname'), 'vmail_gid': options.get('vmail_gid'), 'vmail_home': options.get('vmail_home'), 'dovecot_dir': options.get('dovecot_dir'), 'postfix_dir': options.get('postfix_dir'), 'amavis_dir': options.get('amavis_dir'), } file_name = '%(postfix_dir)s/pgsql-email2email.cf' % context run("#Processing %s" % file_name) pgsql_email2email = """user = %(db_user)s password = %(db_password)s hosts = %(db_host)s dbname = %(db_name)s query = SELECT mails_mailbox.emailname || '@' || names_domain.name as email FROM mails_mailbox INNER JOIN names_domain ON (mails_mailbox.domain_id = names_domain.id) WHERE mails_mailbox.emailname = '%%u' AND names_domain.name = '%%d' """ f = open(file_name, 'w') f.write(pgsql_email2email % context) f.close() run("chown root:postfix %s" % file_name) run("chmod 640 %s" % file_name) file_name = '%(postfix_dir)s/pgsql-virtual-alias-maps.cf' % context run("#Processing %s" % file_name) virtual_alias_maps = """user = %(db_user)s password = %(db_password)s hosts = %(db_host)s dbname = %(db_name)s query = SELECT mails_mailalias.destination FROM mails_mailalias INNER JOIN names_domain ON (mails_mailalias.domain_id = names_domain.id) WHERE mails_mailalias.emailname = '%%u' AND names_domain.name='%%d' """ f = open(file_name, 'w') f.write(virtual_alias_maps % context) f.close() run("chown root:postfix %s" % file_name) run("chmod 640 %s" % file_name) file_name = '%(postfix_dir)s/pgsql-virtual-mailbox-domains.cf' % context run("#Processing %s" % file_name) virtual_mailbox_domains = """user = %(db_user)s password = %(db_password)s hosts = %(db_host)s dbname = %(db_name)s query = SELECT 1 FROM names_domain WHERE names_domain.name='%%s' """ f = open(file_name, 'w') f.write(virtual_mailbox_domains % context) f.close() run("chown root:postfix %s" % file_name) run("chmod 640 %s" % file_name) file_name = '%(postfix_dir)s/pgsql-virtual-mailbox-maps.cf' % context run("#Processing %s" % file_name) virtual_mailbox_maps = """user = %(db_user)s password = %(db_password)s hosts = %(db_host)s dbname = %(db_name)s query = SELECT 1 FROM mails_mailbox INNER JOIN names_domain ON (mails_mailbox.domain_id = names_domain.id) WHERE mails_mailbox.emailname='%%u' AND names_domain.name='%%d' """ f = open(file_name, 'w') f.write(virtual_mailbox_maps % context) f.close() run("chown root:postfix %s" % file_name) run("chmod 640 %s" % file_name) #Dovecot vmail_usename = run("id -u %(vmail_username)s" % context) vmail_groupname = run("id -g %(vmail_groupname)s" % context) if vmail_groupname != context["vmail_gid"]: run("groupadd -g %(vmail_gid)s %(vmail_groupname)s" % context) run("chown -R %(vmail_username)s:%(vmail_groupname)s %(vmail_home)s" % context) if vmail_usename != context["vmail_uid"]: run("useradd -g %(vmail_groupname)s -u %(vmail_uid)s %(vmail_username)s -d %(vmail_home)s -m" % context) run("chmod u+w %(vmail_home)s" % context) run("chown -R %(vmail_username)s:%(vmail_groupname)s %(vmail_home)s" % context) run("chmod u+w %(vmail_home)s" % context) file_name = "%(dovecot_dir)s/conf.d/10-auth.conf" % context run("""sed -i "s/auth_mechanisms = plain$/auth_mechanisms = plain login/g" %s """ % file_name) run("""sed -i "s/\#\!include auth-sql.conf.ext/\!include auth-sql.conf.ext/" %s """ % file_name) file_name = "%(dovecot_dir)s/conf.d/auth-sql.conf.ext" % context run("#Processing %s" % file_name) auth_sql_conf_ext = """passdb { driver = sql args = %(dovecot_dir)s/dovecot-sql.conf.ext } userdb { driver = static args = uid=%(vmail_username)s gid=%(vmail_groupname)s home=%(vmail_home)s/%%d/%%n/Maildir allow_all_users=yes } """ f = open(file_name, 'w') f.write(auth_sql_conf_ext % context) f.close() file_name = "%(dovecot_dir)s/conf.d/10-mail.conf" % context run("#Processing %s" % file_name) mail_conf = """mail_location = maildir:%(vmail_home)s/%%d/%%n/Maildir namespace inbox { separator = . inbox = yes } """ f = open(file_name, 'w') f.write(mail_conf % context) f.close() file_name = "%(dovecot_dir)s/conf.d/10-master.conf" % context run("""sed -i "s/service auth {/service auth {\\n\\tunix_listener \/var\/spool\/postfix\/private\/auth {\\n\\t\\tmode = 0660\\n\\t\\tuser = postfix\\n\\t\\tgroup = postfix\\n\\t}\\n/g" %s """ % file_name) file_name = "%(dovecot_dir)s/conf.d/10-ssl.conf" % context run("#Processing %s" % file_name) ssl_conf = """ssl_cert = </etc/ssl/certs/mailserver.pem ssl_key = </etc/ssl/private/mailserver.pem""" f = open(file_name, 'w') f.write(ssl_conf) f.close() file_name = "%(dovecot_dir)s/conf.d/15-lda.conf" % context run("#Processing %s" % file_name) lda_conf = """protocol lda { postmaster_address = postmaster mail_plugins = $mail_plugins sieve } """ f = open(file_name, 'w') f.write(lda_conf) f.close() file_name = "%(dovecot_dir)s/dovecot-sql.conf.ext" % context run("#Processing %s" % file_name) dovecot_sql = """driver = pgsql connect = host=%(db_host)s dbname=%(db_name)s user=%(db_user)s password=%(db_password)s default_pass_scheme = SSHA password_query = \ SELECT mails_mailbox.emailname || '@' || names_domain.name as user, mails_mailbox.shadigest as password \\ FROM mails_mailbox \\ INNER JOIN names_domain ON (mails_mailbox.domain_id = names_domain.id) \\ INNER JOIN auth_user ON (mails_mailbox.user_id = auth_user.id) \\ WHERE mails_mailbox.emailname = '%%n' AND \\ names_domain.name = '%%d' """ f = open(file_name, 'w') f.write(dovecot_sql % context) f.close() run("chgrp %(vmail_groupname)s %(dovecot_dir)s/dovecot.conf" % context) run("chmod g+r %(dovecot_dir)s/dovecot.conf" % context) run("chown root:root %(dovecot_dir)s/dovecot-sql.conf.ext" % context) run("chmod go= %(dovecot_dir)s/dovecot-sql.conf.ext" % context) file_name = "%(postfix_dir)s/master.cf" % context grep_dovecot = run("grep dovecot %s" % file_name, valid_codes=(0, 1)) if grep_dovecot == '': run("#Processing %s" % file_name) dovecot_master = """ dovecot unix - n n - - pipe flags=DRhu user=%(vmail_username)s:%(vmail_groupname)s argv=/usr/lib/dovecot/dovecot-lda -f ${sender} -d ${recipient} #Amavis: amavis unix - - n - 5 smtp -o smtp_data_done_timeout=1200 -o smtp_send_xforward_command=yes -o smtp_tls_note_starttls_offer=no 127.0.0.1:10025 inet n - n - - smtpd -o content_filter= -o smtpd_delay_reject=no -o smtpd_client_restrictions=permit_mynetworks,reject -o smtpd_helo_restrictions= -o smtpd_sender_restrictions= -o smtpd_recipient_restrictions=permit_mynetworks,reject -o smtpd_data_restrictions=reject_unauth_pipelining -o smtpd_end_of_data_restrictions= -o smtpd_restriction_classes= -o mynetworks=127.0.0.0/8 -o smtpd_error_sleep_time=0 -o smtpd_soft_error_limit=1001 -o smtpd_hard_error_limit=1000 -o smtpd_client_connection_count_limit=0 -o smtpd_client_connection_rate_limit=0 -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks,no_milters -o local_header_rewrite_clients= -o smtpd_milters= -o local_recipient_maps= -o relay_recipient_maps= """ f = open(file_name, 'a') f.write(dovecot_master % context) f.close() #Postfix mailname = run("cat /etc/mailname", vallid_codes=[0, 1]) hostname = run("hostname", valid_codes=[0, 1]) if mailname != hostname: file_name = "/etc/mailname" run("#Processing %s" % file_name) f = open(file_name, 'w') f.write(hostname % context) f.close() # Set the base address for all virtual mailboxes run("postconf -e virtual_mailbox_base=%(vmail_home)s" % context) # A list of all virtual domains serviced by this instance of postfix. run("postconf -e virtual_mailbox_domains=pgsql:%(postfix_dir)s/pgsql-virtual-mailbox-domains.cf" % context) # Look up the mailbox location based on the email address received. run("postconf -e virtual_mailbox_maps=pgsql:%(postfix_dir)s/pgsql-virtual-mailbox-maps.cf" % context) # Any aliases that are supported by this system run("postconf -e virtual_alias_maps=pgsql:%(postfix_dir)s/pgsql-virtual-alias-maps.cf" % context) #Dovecot: run("postconf -e virtual_transport=dovecot") run("postconf -e dovecot_destination_recipient_limit=1") run("postconf -e smtpd_sasl_type=dovecot") run("postconf -e smtpd_sasl_path=private/auth") run("postconf -e smtpd_sasl_auth_enable=yes") if os.path.isfile("/etc/ssl/certs/mailserver.pem"): run("postconf -e smtpd_tls_security_level=may") run("postconf -e smtpd_tls_auth_only=yes") run("postconf -e smtpd_tls_cert_file=/etc/ssl/certs/mailserver.pem" ) run("postconf -e smtpd_tls_key_file=/etc/ssl/private/mailserver.pem" ) run("""postconf -e smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject_invalid_hostname,reject_non_fqdn_recipient,reject_unknown_sender_domain,reject_unknown_recipient_domain,reject_unauth_destination,permit""" ) run("""postconf -e soft_bounce=no""") run("""postconf -e content_filter=amavis:[127.0.0.1]:10024""") #Amavis: file_name = "%(amavis_dir)s/conf.d/15-content_filter_mode" % context run("""sed -i "s/#@bypass_virus_checks_maps/@bypass_virus_checks_maps/g" %s""" % file_name) run("""sed -i 's/# \\\\%%bypass_virus_checks, \\\@bypass_virus_checks_acl, \\\$bypass_virus_checks_re/ \\\\%%bypass_virus_checks, \\\@bypass_virus_checks_acl, \\\$bypass_virus_checks_re/g' %s""" % file_name) run("""sed -i 's/# \\\\%%bypass_virus_checks/ \\\\%%bypass_virus_checks/g' %s""" % (file_name, )) run("""sed -i "s/#@bypass_spam_checks_maps/@bypass_spam_checks_maps/g" %s""" % file_name) run("""sed -i 's/# \\\\%%bypass_spam_checks, \\\@bypass_spam_checks_acl, \\\$bypass_spam_checks_re/ \\\\%%bypass_spam_checks, \\\@bypass_spam_checks_acl, \\\$bypass_spam_checks_re/g' %s""" % file_name) run("adduser clamav amavis") run("service clamav-freshclam restart") run("service clamav-daemon restart") run("service spamassassin restart") run("service amavis restart") run("service dovecot restart") run("service postfix restart")
def handle(self, *args, **options): # Configure firmware generation context = { 'db_name': options.get('db_name'), 'db_user': options.get('db_user'), 'db_password': options.get('db_password'), 'db_host': options.get('db_host'), 'db_port': options.get('db_port') } run('su postgres -c "psql -c \\"CREATE USER %(db_user)s PASSWORD \'%(db_password)s\';\\""' % context, valid_codes=(0,1)) run('su postgres -c "psql -c \\"CREATE DATABASE %(db_name)s OWNER %(db_user)s;\\""' % context, valid_codes=(0,1)) context.update({'settings': os.path.join(get_project_dir(), 'settings.py')}) if run("grep 'DATABASES' %(settings)s" % context, valid_codes=(0,1)).exit_code == 0: # Update existing settings_file run("sed -i \"s/'ENGINE': '\w*',/'ENGINE': 'django.db.backends.postgresql_psycopg2',/\" %(settings)s" % context) run("sed -i \"s/'NAME': '.*',/'NAME': '%(db_name)s',/\" %(settings)s" % context) run("sed -i \"s/'USER': '******',/'USER': '******',/\" %(settings)s" % context) run("sed -i \"s/'PASSWORD': '******',/'PASSWORD': '******',/\" %(settings)s" % context) run("sed -i \"s/'HOST': '.*',/'HOST': '%(db_host)s',/\" %(settings)s" % context) run("sed -i \"s/'PORT': '.*',/'PORT': '%(db_port)s',/\" %(settings)s" % context) else: db_config = ( "DATABASES = {\n" " 'default': {\n" " 'ENGINE': 'django.db.backends.postgresql_psycopg2',\n" " 'NAME': '%(db_name)s',\n" " 'USER': '******',\n" " 'PASSWORD': '******',\n" " 'HOST': '%(db_host)s',\n" " 'PORT': '%(db_port)s',\n" " 'ATOMIC_REQUESTS': True,\n" " }\n" "}\n" % context) context.update({'db_config': db_config}) run('echo "%(db_config)s" >> %(settings)s' % context)