From 2f1813d0fdad9ec78ab167bae0636b79e253e07a Mon Sep 17 00:00:00 2001 From: glic3 Date: Mon, 4 May 2015 14:57:41 +0200 Subject: [PATCH] Added setupcronbeat command --- INSTALL.md | 22 +- TODO.md | 43 +--- orchestra/bin/orchestra-admin | 48 +---- orchestra/contrib/domains/bin/named-checkzone | Bin 0 -> 26680 bytes orchestra/contrib/domains/settings.py | 2 +- orchestra/management/commands/setupnginx.py | 191 ++++++++++++++---- requirements.txt | 49 +++-- setup.py | 1 + 8 files changed, 209 insertions(+), 147 deletions(-) create mode 100755 orchestra/contrib/domains/bin/named-checkzone diff --git a/INSTALL.md b/INSTALL.md index 01ba3a51..54f82731 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -38,22 +38,38 @@ Django-orchestra can be installed on any Linux system, however it is **strongly 5. Create and configure a Postgres database ```bash + sudo apt-get install python3-psycopg2 postgresql sudo python3 manage.py setuppostgres --db_password # admin_tools needs accounts and does not have migrations python3 manage.py migrate accounts python3 manage.py migrate ``` -7. Configure celeryd + +6. See the Django deployment checklist ```bash - sudo python3 manage.py setupcelery --username orchestra + python3 panel/manage.py check --deploy ``` + +6. Configure periodic execution of tasks (choose one) + 1. Use cron + ```bash + sudo python3 manage.py setupcronbeat + ``` + + 2. Use celeryd + ```bash + sudo apt-get install rabbitmq + sudo python3 manage.py setupcelery --username orchestra + ``` + + 8. Configure the web server: ```bash python3 manage.py collectstatic --noinput sudo apt-get install nginx-full uwsgi uwsgi-plugin-python3 - sudo python3 manage.py setupnginx + sudo python3 manage.py setupnginx --user orchestra ``` 9. Start all services: diff --git a/TODO.md b/TODO.md index a0c88898..f6ea79d3 100644 --- a/TODO.md +++ b/TODO.md @@ -361,9 +361,10 @@ Collecting lxml==3.3.5 (from -r re (line 22)) # project settings modified copy of django's default project settings -# migrate accounts break on superuser insert because of orders signals: read() + db_ready() +# migrate accounts break on superuser insert because of orders signals: ready() + db_ready() -# if backend.async: don't join +# if backend.async: don't join. +# RELATED: domains.sync to ns3 make it async # ngnix setup certificate from orchestra.contrib.tasks import task @@ -377,46 +378,18 @@ Collecting lxml==3.3.5 (from -r re (line 22)) time.sleep(1) counter.apply_async(10, '/tmp/kakas') -# standard django deployment pracices (run checks) # setup main systemuser on post_migrate SystemUser # Provide some fixtures with mocked data -# don't make hard dependencies strict dependencies, fail when needed. +don't make hard dependencies strict dependencies, fail when needed. # on project_settings add debug settings but commented # rename context processes varbailes to its original name -# TODO http://wiki2.dovecot.org/HowTo/SimpleVirtualInstall -# TODO http://wiki2.dovecot.org/HowTo/VirtualUserFlatFilesPostfix -# TODO mount the filesystem with "nosuid" option +TODO http://wiki2.dovecot.org/HowTo/SimpleVirtualInstall +TODO http://wiki2.dovecot.org/HowTo/VirtualUserFlatFilesPostfix +TODO mount the filesystem with "nosuid" option # execute Make after postfix update -# setupuwsgi + setupnginx - - -if not cert: - sudo mkdir /etc/nginx/ssl - sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt - if --noinput - openssl req \ - -new \ - -newkey rsa:4096 \ - -days 365 \ - -nodes \ - -x509 \ - -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=www.example.com" \ - -keyout www.example.com.key \ - -out www.example.com.cert - - - ssl_certificate /etc/nginx/ssl/nginx.crt; - ssl_certificate_key /etc/nginx/ssl/nginx.key; - -if server_name: - at sites-enabled - server_name your_domain.com; - -else conf-enabled - - +# wkhtmltopdf -> reportlab diff --git a/orchestra/bin/orchestra-admin b/orchestra/bin/orchestra-admin index a6eb8375..90df6bbc 100755 --- a/orchestra/bin/orchestra-admin +++ b/orchestra/bin/orchestra-admin @@ -122,56 +122,23 @@ function install_requirements () { check_root || true ORCHESTRA_PATH=$(get_orchestra_dir) || true - # TODO reduce this list to 0 - # include /usr/sbin/named-checkzone - # wkhtmltopdf -> reportlab - # remove rabbit, postgres - # uwsgi –py-autoreload for devel APT="python3 \ python3-pip \ - python3-psycopg2 \ - python3-lxml \ python3-dev \ - bind9utils \ - python3-cracklib \ - libz-dev \ + libxml2-dev \ + libxslt1-dev \ wkhtmltopdf \ xvfb \ ca-certificates \ gettext" - # TODO remove celery deps, django 1.8.1, glic3rinu fork, celery email - PIP="django==1.8.1 \ - django-celery-email==1.0.4 \ - https://github.com/glic3rinu/django-fluent-dashboard/archive/master.zip \ - https://bitbucket.org/izi/django-admin-tools/get/a0abfffd76a0.zip \ - IPy==0.81 \ - django-extensions==1.5.2 \ - django-transaction-signals==1.0.0 \ - django-celery==3.1.16 \ - celery==3.1.16 \ - kombu==3.0.23 \ - billiard==3.3.0.18 \ - Markdown==2.4 \ - djangorestframework==3.1.1 \ - paramiko==1.15.1 \ - ecdsa==0.11 \ - Pygments==1.6 \ - django-filter==0.9.2 \ - https://github.com/glic3rinu/passlib/archive/master.zip \ - jsonfield==0.9.22 \ - python-dateutil==2.4.2 \ - django-iban==0.3.0 \ - requests \ - phonenumbers \ - django-countries \ - django-localflavor \ - pip==6.0.8" + PIP=$(wget https://raw.githubusercontent.com/glic3rinu/django-orchestra/master/requirements.txt -q -O - | tr '\n' ' ') if $testing; then APT="${APT} \ iceweasel \ dnsutils" + PIP="${PIP} \ selenium \ xvfbwrapper \ @@ -205,13 +172,6 @@ function install_requirements () { fi run pip3 install $PIP - - # Patch passlib -# IMPORT="from django.contrib.auth.hashers import mask_hash, _" -# COLLECTIONS="from collections import OrderedDict" -# PASSLIB_PATH=$(python3 -c "from passlib.ext.django import utils; print(utils.__file__)") -# sed -i "s/${IMPORT}, SortedDict/${IMPORT}\n ${COLLECTIONS}/" $PASSLIB_PATH -# sed -i "s/SortedDict/OrderedDict/g" $PASSLIB_PATH } export -f install_requirements diff --git a/orchestra/contrib/domains/bin/named-checkzone b/orchestra/contrib/domains/bin/named-checkzone new file mode 100755 index 0000000000000000000000000000000000000000..3d2961c8933300d2194e02007471fdbc5a96b0d8 GIT binary patch literal 26680 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 literal 0 HcmV?d00001 diff --git a/orchestra/contrib/domains/settings.py b/orchestra/contrib/domains/settings.py index 62afd2fa..2e9c6b73 100644 --- a/orchestra/contrib/domains/settings.py +++ b/orchestra/contrib/domains/settings.py @@ -63,7 +63,7 @@ DOMAINS_SLAVES_PATH = Setting('DOMAINS_SLAVES_PATH', DOMAINS_CHECKZONE_BIN_PATH = Setting('DOMAINS_CHECKZONE_BIN_PATH', - '/usr/sbin/named-checkzone -i local -k fail -n fail', + 'named-checkzone -i local -k fail -n fail', ) diff --git a/orchestra/management/commands/setupnginx.py b/orchestra/management/commands/setupnginx.py index f6f38d70..1d3fb75c 100644 --- a/orchestra/management/commands/setupnginx.py +++ b/orchestra/management/commands/setupnginx.py @@ -1,3 +1,4 @@ +import os import textwrap from optparse import make_option from os.path import expanduser @@ -17,6 +18,29 @@ class Command(BaseCommand): help='Nginx SSL certificate, one will be created by default.'), make_option('--cert-key', dest='cert_key', default='', help='Nginx SSL certificate key.'), + + make_option('--cert-path', dest='cert_path', default='/etc/nginx/ssl/orchestra.crt', + help='Nginx SSL certificate, one will be created by default.'), + make_option('--cert-key-path', dest='cert_key_path', default='/etc/nginx/ssl/orchestra.key', + help='Nginx SSL certificate key.'), + # Cert options + make_option('--cert-override', dest='cert_override', action='store_true', + default=False, help='Force override cert and keys if exists.'), + make_option('--cert-country', dest='cert_country', default='ES', + help='Certificate Distinguished Name Country.'), + make_option('--cert-state', dest='cert_state', default='Spain', + help='Certificate Distinguished Name STATE.'), + make_option('--cert-locality', dest='cert_locality', default='Barcelona', + help='Certificate Distinguished Name Country.'), + make_option('--cert-org_name', dest='cert_org_name', default='Orchestra', + help='Certificate Distinguished Name Organization Name.'), + make_option('--cert-org_unit', dest='cert_org_unit', default='DevOps', + help='Certificate Distinguished Name Organization Unity.'), + make_option('--cert-email', dest='cert_email', default='orchestra@orchestra.lan', + help='Certificate Distinguished Name Email Address.'), + make_option('--cert-common_name', dest='cert_common_name', default=None, + help='Certificate Distinguished Name Common Name.'), + make_option('--server-name', dest='server_name', default='', help='Nginx SSL certificate key.'), make_option('--user', dest='user', default='', @@ -34,36 +58,121 @@ class Command(BaseCommand): option_list = BaseCommand.option_list help = 'Configures nginx + uwsgi to run with your Orchestra instance.' - @check_root - def handle(self, *args, **options): + def generate_certificate(self, **options): + override = options.get('cert_override') interactive = options.get('interactive') cert = options.get('cert') - cert_key = options.get('cert_key') - if bool(cert) != bool(cert_key): + key = options.get('cert_key') + if bool(cert) != bool(key): raise CommandError("--cert and --cert-key go in tandem") - if not cert: - run("mkdir -p /etc/nginx/ssl") - if interactive: - run("openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt") + cert_path = options.get('cert_path') + key_path = options.get('cert_key_path') + + run('mkdir -p %s' % os.path.basename(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, + } + self.stdout.write('writing new cert to \'%s\'' % cert_path) + self.stdout.write('writing new cert key to \'%s\'' % key_path) + run('openssl req -x509 -nodes -days 365 -newkey rsa:4096 -keyout %(key_path)s -out %(cert_path)s -subj "%(subject)s"' % context, display=True) + + return cert_path, key_path + + @check_root + 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, - 'user': options.get('user'), - 'group': options.get('group') or options.get('user'), + 'user': user, + 'group': options.get('group') or user, 'home': expanduser("~%s" % options.get('user')), - 'processes': int(options.get('processes')),} + '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 500m; + client_max_body_size 16m; location / { uwsgi_pass unix:///var/run/uwsgi/app/%(project_name)s/socket; include uwsgi_params; @@ -78,34 +187,42 @@ class Command(BaseCommand): uwsgi_conf = textwrap.dedent("""\ [uwsgi] - plugins = python - chdir = %(site_dir)s - module = %(project_name)s.wsgi - master = true - processes = %(processes)d - chmod-socket = 664 - stats = /run/uwsgi/%%(deb-confnamespace)/%%(deb-confname)/statsocket - vacuum = true - uid = %(user)s - gid = %(group)s - env = HOME=%(home)s - touch-reload = %(project_dir)s/wsgi.py + plugins = python + chdir = %(site_dir)s + module = %(project_name)s.wsgi + master = true + processes = %(processes)d + chmod-socket = 664 + stats = /run/uwsgi/%%(deb-confnamespace)/%%(deb-confname)/statsocket + vacuum = true + uid = %(user)s + gid = %(group)s + env = HOME=%(home)s + touch-reload = %(project_dir)s/wsgi.py + enable-threads = true + max-requests = 500 """ ) % context + nginx_file = '/etc/nginx/conf.d/%(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': '/etc/nginx/conf.d/%(project_name)s.conf' % context, - 'conf': nginx_conf } + 'file': nginx_file, + 'conf': nginx_conf + } uwsgi = { 'file': '/etc/uwsgi/apps-available/%(project_name)s.ini' % context, - 'conf': uwsgi_conf } + '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]) + 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) + run("echo '%(conf)s' > %(file)s" % context, display=True) elif diff.return_code == 1: # File is different, save the old one if interactive: @@ -119,16 +236,14 @@ class Command(BaseCommand): if confirm == 'no': return break - run("cp %(file)s %(file)s.save" % context) - run("echo '%(conf)s' > %(file)s" % context) + run("cp %(file)s %(file)s.save" % context, display=True) + run("echo '%(conf)s' > %(file)s" % 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) - 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)) + if server_name: + run('ln -s /etc/nginx/sites-available/%(server_name)s.conf /etc/nginx/sites-enabled/' % context, error_codes=[0,1], display=True) + run('ln -s /etc/uwsgi/apps-available/%(project_name)s.ini /etc/uwsgi/apps-enabled/' % context, error_codes=[0,1], display=True) rotate = textwrap.dedent("""\ /var/log/nginx/*.log { @@ -145,7 +260,7 @@ class Command(BaseCommand): endscript }""" ) - run("echo '%s' > /etc/logrotate.d/nginx" % rotate) + run("echo '%s' > /etc/logrotate.d/nginx" % rotate, display=True) # Allow nginx to write to uwsgi socket - run('adduser www-data %(group)s' % context) + run('adduser www-data %(group)s' % context, display=True) diff --git a/requirements.txt b/requirements.txt index 3d16a2a4..610e5292 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,30 +1,27 @@ cracklib django==1.8.1 -django-celery-email==1.0.4 -https://github.com/glic3rinu/django-fluent-dashboard/archive/master.zip -https://bitbucket.org/izi/django-admin-tools/get/a0abfffd76a0.zip -IPy==0.81 -django-extensions==1.5.2 -django-transaction-signals==1.0.0 -django-celery==3.1.16 -celery==3.1.16 -kombu==3.0.23 -billiard==3.3.0.18 -Markdown==2.4 +django-celery-email==1.0.4 +django-fluent-dashboard==0.5 +https://bitbucket.org/izi/django-admin-tools/get/a0abfffd76a0.zip +IPy==0.81 +django-extensions==1.5.2 +django-transaction-signals==1.0.0 +django-celery==3.1.16 +celery==3.1.16 +kombu==3.0.23 +billiard==3.3.0.18 +Markdown==2.4 djangorestframework==3.1.1 -paramiko==1.15.1 -ecdsa==0.11 -Pygments==1.6 -django-filter==0.7 +paramiko==1.15.1 +ecdsa==0.11 +Pygments==1.6 +django-filter==0.7 https://github.com/glic3rinu/passlib/archive/master.zip -jsonfield==0.9.22 -lxml==3.3.5 -python-dateutil==2.2 -django-iban==0.3.0 -requests -phonenumbers -django-countries -django-localflavor -###development -django-debug-toolbar -django-nose +jsonfield==0.9.22 +lxml==3.3.5 +python-dateutil==2.2 +django-iban==0.3.0 +requests +phonenumbers +django-countries +django-localflavor diff --git a/setup.py b/setup.py index 804e8337..11b34b53 100644 --- a/setup.py +++ b/setup.py @@ -30,6 +30,7 @@ setup( scripts=[ 'orchestra/bin/orchestra-admin', 'orchestra/contrib/tasks/bin/orchestra-beat', + 'orchestra/contrib/domains/bin/named-checkzone', ], packages = packages, classifiers = [