def handle(self, *args, **options): list_backends = options.get('list_backends') if list_backends: for backend in ServiceBackend.get_backends(): self.stdout.write(str(backend).split("'")[1]) return interactive = options.get('interactive') dry = options.get('dry') operations = self.collect_operations(**options) scripts, serialize = manager.generate(operations) servers = set() # Print scripts for key, value in scripts.items(): route, __, __ = key backend, operations = value servers.add(str(route.host)) self.stdout.write('# Execute %s on %s' % (backend.get_name(), route.host)) for method, commands in backend.scripts: script = '\n'.join(commands) self.stdout.write( script.encode('ascii', errors='replace').decode()) if interactive: context = { 'servers': ', '.join(servers), } if not confirm( "\n\nAre your sure to execute the previous scripts on %(servers)s (yes/no)? " % context): return if not dry: logs = manager.execute(scripts, serialize=serialize, run_async=True) running = list(logs) stdout = 0 stderr = 0 while running: for log in running: cstdout = len(log.stdout) cstderr = len(log.stderr) if cstdout > stdout: self.stdout.write(log.stdout[stdout:]) stdout = cstdout if cstderr > stderr: self.stderr.write(log.stderr[stderr:]) stderr = cstderr if log.has_finished: running.remove(log) time.sleep(0.05) for log in logs: self.stdout.write(' '.join((log.backend, log.state)))
def handle(self, *args, **options): list_backends = options.get('list_backends') if list_backends: for backend in ServiceBackend.get_backends(): self.stdout.write(str(backend).split("'")[1]) return interactive = options.get('interactive') dry = options.get('dry') operations = self.collect_operations(**options) scripts, serialize = manager.generate(operations) servers = set() # Print scripts for key, value in scripts.items(): route, __, __ = key backend, operations = value servers.add(str(route.host)) self.stdout.write('# Execute %s on %s' % (backend.get_name(), route.host)) for method, commands in backend.scripts: script = '\n'.join(commands) self.stdout.write(script.encode('ascii', errors='replace').decode()) if interactive: context = { 'servers': ', '.join(servers), } if not confirm("\n\nAre your sure to execute the previous scripts on %(servers)s (yes/no)? " % context): return if not dry: logs = manager.execute(scripts, serialize=serialize, async=True) running = list(logs) stdout = 0 stderr = 0 while running: for log in running: cstdout = len(log.stdout) cstderr = len(log.stderr) if cstdout > stdout: self.stdout.write(log.stdout[stdout:]) stdout = cstdout if cstderr > stderr: self.stderr.write(log.stderr[stderr:]) stderr = cstderr if log.has_finished: running.remove(log) time.sleep(0.05) for log in logs: self.stdout.write(' '.join((log.backend, log.state)))
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 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") 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): list_backends = options.get('list_backends') if list_backends: for backend in ServiceBackend.get_backends(): self.stdout.write(str(backend).split("'")[1]) return model = apps.get_model(*options['model'].split('.')) action = options.get('action') interactive = options.get('interactive') servers = options.get('servers') backends = options.get('backends') if (servers and not backends) or (not servers and backends): raise CommandError("--backends and --servers go in tandem.") dry = options.get('dry') kwargs = {} for comp in options.get('query', []): comps = iter(comp.split('=')) for arg in comps: kwargs[arg] = next(comps).strip().rstrip(',') operations = OrderedSet() route_cache = {} queryset = model.objects.filter(**kwargs).order_by('id') if servers: servers = servers.split(',') backends = backends.split(',') routes = [] # Get and create missing Servers for server in servers: try: server = Server.objects.get(address=server) except Server.DoesNotExist: server = Server(name=server, address=server) server.full_clean() server.save() routes.append(AttrDict( host=server, async=False, action_is_async=lambda self: False, )) # Generate operations for the given backend for instance in queryset: for backend in backends: backend = import_class(backend) operations.add(Operation(backend, instance, action, routes=routes)) else: for instance in queryset: manager.collect(instance, action, operations=operations, route_cache=route_cache) scripts, serialize = manager.generate(operations) servers = [] # Print scripts for key, value in scripts.items(): route, __, __ = key backend, operations = value servers.append(str(route.host)) self.stdout.write('# Execute %s on %s' % (backend.get_name(), route.host)) for method, commands in backend.scripts: script = '\n'.join(commands) self.stdout.write(script) if interactive: context = { 'servers': ', '.join(servers), } if not confirm("\n\nAre your sure to execute the previous scripts on %(servers)s (yes/no)? " % context): return if not dry: logs = manager.execute(scripts, serialize=serialize, async=True) running = list(logs) stdout = 0 stderr = 0 while running: for log in running: cstdout = len(log.stdout) cstderr = len(log.stderr) if cstdout > stdout: self.stdout.write(log.stdout[stdout:]) stdout = cstdout if cstderr > stderr: self.stderr.write(log.stderr[stderr:]) stderr = cstderr if log.has_finished: running.remove(log) time.sleep(0.05) for log in logs: self.stdout.write(' '.join((log.backend, log.state)))