예제 #1
0
 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)))
예제 #2
0
 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)))
예제 #3
0
 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)
예제 #4
0
 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)
예제 #5
0
 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)
예제 #6
0
 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)))