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): 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): interactive = options.get('interactive') context = { 'project_name': get_project_name(), 'project_root': get_project_root(), 'site_root': get_site_root(), 'static_root': settings.STATIC_ROOT, 'user': options.get('user'), 'group': options.get('group') or options.get('user'), 'home': expanduser("~%s" % options.get('user')), 'processes': int(options.get('processes')),} nginx_conf = ( 'server {\n' ' listen 80;\n' ' listen [::]:80 ipv6only=on;\n' ' rewrite ^/$ /admin;\n' ' client_max_body_size 500m;\n' ' location / {\n' ' uwsgi_pass unix:///var/run/uwsgi/app/%(project_name)s/socket;\n' ' include uwsgi_params;\n' ' }\n' ' location /static {\n' ' alias %(static_root)s;\n' ' expires 30d;\n' ' }\n' '}\n') % context uwsgi_conf = ( '[uwsgi]\n' 'plugins = python\n' 'chdir = %(site_root)s\n' 'module = %(project_name)s.wsgi\n' 'master = true\n' 'processes = %(processes)d\n' 'chmod-socket = 664\n' 'stats = /run/uwsgi/%%(deb-confnamespace)/%%(deb-confname)/statsocket\n' 'vacuum = true\n' 'uid = %(user)s\n' 'gid = %(group)s\n' 'env = HOME=%(home)s\n') % context nginx = { 'file': '/etc/nginx/conf.d/%(project_name)s.conf' % context, 'conf': nginx_conf } uwsgi = { 'file': '/etc/uwsgi/apps-available/%(project_name)s.ini' % context, 'conf': uwsgi_conf } for extra_context in (nginx, uwsgi): context.update(extra_context) diff = run("echo '%(conf)s'|diff - %(file)s" % context, error_codes=[0,1,2]) if diff.return_code == 2: # File does not exist run("echo '%(conf)s' > %(file)s" % context) elif diff.return_code == 1: # File is different, save the old one if interactive: msg = ("\n\nFile %(file)s be updated, do you like to overide " "it? (yes/no): " % context) confirm = input(msg) while 1: if confirm not in ('yes', 'no'): confirm = input('Please enter either "yes" or "no": ') continue if confirm == 'no': return break run("cp %(file)s %(file)s.save" % context) run("echo '%(conf)s' > %(file)s" % context) 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) run('ln -s /etc/uwsgi/apps-available/%(project_name)s.ini /etc/uwsgi/apps-enabled/' % context, error_codes=[0,1]) # nginx should start after tincd current = "\$local_fs \$remote_fs \$network \$syslog" run('sed -i "s/ %s$/ %s \$named/g" /etc/init.d/nginx' % (current, current)) rotate = ( '/var/log/nginx/*.log {\n' ' daily\n' ' missingok\n' ' rotate 30\n' ' compress\n' ' delaycompress\n' ' notifempty\n' ' create 640 root adm\n' ' sharedscripts\n' ' postrotate\n' ' [ ! -f /var/run/nginx.pid ] || kill -USR1 `cat /var/run/nginx.pid`\n' ' endscript\n' '}\n') run("echo '%s' > /etc/logrotate.d/nginx" % rotate) # Allow nginx to write to uwsgi socket run('adduser www-data %(group)s' % context)