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 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): # 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)
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 get_settings_file(): return os.path.join(get_project_dir(), 'settings.py')
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 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') 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): 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): 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)