diff --git a/README.md b/README.md index 7dbf0ee2..d6cdaacc 100644 --- a/README.md +++ b/README.md @@ -31,10 +31,10 @@ However, Orchestra also provides glue, tools and patterns that you may find very Fast Deployment Setup --------------------- -To only run the Python interface follow these steps: +To only run the web interface follow these steps: ```bash -# Create a new virtualenv +# Create and activate a Python virtualenv python3 -mvenv env-django-orchestra source env-django-orchestra/bin/activate diff --git a/TODO.md b/TODO.md index 0b9bde7f..a0c88898 100644 --- a/TODO.md +++ b/TODO.md @@ -380,3 +380,43 @@ Collecting lxml==3.3.5 (from -r re (line 22)) # 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. +# 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 +# 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 + + + + + diff --git a/orchestra/contrib/domains/backends.py b/orchestra/contrib/domains/backends.py index 02b3ac6d..983bdbf7 100644 --- a/orchestra/contrib/domains/backends.py +++ b/orchestra/contrib/domains/backends.py @@ -111,8 +111,10 @@ class Bind9MasterDomainBackend(ServiceController): def get_slaves(self, domain): ips = [] masters = self.get_masters(domain) - for ns in domain.records.filter(type=Record.NS): - hostname = ns.value.rstrip('.') + ns_queryset = domain.records.filter(type=Record.NS).values_list('value', flat=True) + ns_records = ns_queryset or settings.DOMAINS_DEFAULT_NS + for ns in ns_records: + hostname = ns.rstrip('.') # First try with a DNS query, a more reliable source try: addr = socket.gethostbyname(hostname) @@ -123,7 +125,7 @@ class Bind9MasterDomainBackend(ServiceController): except Domain.DoesNotExist: continue else: - a_record = domain.records.filter(name=Record.A) or [settings.DOMAINS_DEFAULT_NS] + a_record = domain.records.filter(name=Record.A) or [settings.DOMAINS_DEFAULT_A] addr = a_record[0] if addr not in masters: ips.append(addr) diff --git a/orchestra/contrib/lists/backends.py b/orchestra/contrib/lists/backends.py index dd9416d5..763b8c6d 100644 --- a/orchestra/contrib/lists/backends.py +++ b/orchestra/contrib/lists/backends.py @@ -2,6 +2,7 @@ import textwrap from django.utils.translation import ugettext_lazy as _ +from orchestra.contrib.domains.models import Domain, Record from orchestra.contrib.orchestration import ServiceController, replace from orchestra.contrib.resources import ServiceMonitor @@ -36,12 +37,15 @@ class MailmanBackend(ServiceController): def include_virtual_alias_domain(self, context): if context['address_domain']: - self.append(textwrap.dedent(""" - [[ $(grep '^\s*%(address_domain)s\s*$' %(virtual_alias_domains)s) ]] || { - echo '%(address_domain)s' >> %(virtual_alias_domains)s - UPDATED_VIRTUAL_ALIAS_DOMAINS=1 - }""") % context - ) + # Check if the domain is hosted on this mail server + # TODO this is dependent on the domain model + if Domain.objects.filter(records__type=Record.MX, name=context['address_domain']).exists(): + self.append(textwrap.dedent(""" + [[ $(grep '^\s*%(address_domain)s\s*$' %(virtual_alias_domains)s) ]] || { + echo '%(address_domain)s' >> %(virtual_alias_domains)s + UPDATED_VIRTUAL_ALIAS_DOMAINS=1 + }""") % context + ) def exclude_virtual_alias_domain(self, context): address_domain = context['address_domain'] diff --git a/orchestra/contrib/mailboxes/backends.py b/orchestra/contrib/mailboxes/backends.py index f1fbde23..f35fba8c 100644 --- a/orchestra/contrib/mailboxes/backends.py +++ b/orchestra/contrib/mailboxes/backends.py @@ -6,6 +6,7 @@ import textwrap from django.core.exceptions import ObjectDoesNotExist from django.utils.translation import ugettext_lazy as _ +from orchestra.contrib.domains.models import Domain, Record from orchestra.contrib.orchestration import ServiceController, replace from orchestra.contrib.resources import ServiceMonitor #from orchestra.utils.humanize import unit_to_bytes @@ -13,10 +14,6 @@ from orchestra.contrib.resources import ServiceMonitor from . import settings from .models import Address -# TODO http://wiki2.dovecot.org/HowTo/SimpleVirtualInstall -# TODO http://wiki2.dovecot.org/HowTo/VirtualUserFlatFilesPostfix -# TODO mount the filesystem with "nosuid" option - logger = logging.getLogger(__name__) @@ -220,12 +217,15 @@ class PostfixAddressBackend(ServiceController): ) def include_virtual_alias_domain(self, context): if context['domain'] != context['local_domain']: - self.append(textwrap.dedent(""" - [[ $(grep '^\s*%(domain)s\s*$' %(virtual_alias_domains)s) ]] || { - echo '%(domain)s' >> %(virtual_alias_domains)s - UPDATED_VIRTUAL_ALIAS_DOMAINS=1 - }""") % context - ) + # Check if the domain is hosted on this mail server + # TODO this is dependent on the domain model + if Domain.objects.filter(records__type=Record.MX, name=context['address_domain']).exists(): + self.append(textwrap.dedent(""" + [[ $(grep '^\s*%(domain)s\s*$' %(virtual_alias_domains)s) ]] || { + echo '%(domain)s' >> %(virtual_alias_domains)s + UPDATED_VIRTUAL_ALIAS_DOMAINS=1 + }""") % context + ) def exclude_virtual_alias_domain(self, context): domain = context['domain'] diff --git a/orchestra/contrib/tasks/__init__.py b/orchestra/contrib/tasks/__init__.py index cd37bd5e..509e3837 100644 --- a/orchestra/contrib/tasks/__init__.py +++ b/orchestra/contrib/tasks/__init__.py @@ -76,16 +76,16 @@ def task(fn=None, **kwargs): from . import settings # register task if fn is None: + name = kwargs.get('name', None) if settings.TASKS_BACKEND in ('thread', 'process'): def decorator(fn): - return apply_async(celery_shared_task(fn)) + return apply_async(celery_shared_task(**kwargs)(fn), name=name) return decorator else: return celery_shared_task(**kwargs) fn = update_wraper(partial(celery_shared_task, fn)) if settings.TASKS_BACKEND in ('thread', 'process'): - name = kwargs.pop('name', None) - fn = update_wrapper(apply_async(fn, name), fn) + fn = update_wrapper(apply_async(fn), fn) return fn @@ -93,13 +93,14 @@ def periodic_task(fn=None, **kwargs): from . import settings # register task if fn is None: + name = kwargs.get('name', None) if settings.TASKS_BACKEND in ('thread', 'process'): def decorator(fn): - return apply_async(celery_periodic_task(fn)) + return apply_async(celery_periodic_task(**kwargs)(fn), name=name) return decorator else: return celery_periodic_task(**kwargs) - fn = update_wraper(partial(celery_periodic_task, fn)) + fn = update_wraper(celery_periodic_task(fn), fn) if settings.TASKS_BACKEND in ('thread', 'process'): name = kwargs.pop('name', None) fn = update_wrapper(apply_async(fn, name), fn) diff --git a/orchestra/management/commands/setupnginx.py b/orchestra/management/commands/setupnginx.py index 0c2b4876..f6f38d70 100644 --- a/orchestra/management/commands/setupnginx.py +++ b/orchestra/management/commands/setupnginx.py @@ -13,7 +13,13 @@ class Command(BaseCommand): def __init__(self, *args, **kwargs): super(Command, self).__init__(*args, **kwargs) self.option_list = BaseCommand.option_list + ( - make_option('--user', dest='user', default=get_default_celeryd_username(), + make_option('--cert', dest='cert', default='', + 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('--server-name', dest='server_name', default='', + help='Nginx SSL certificate key.'), + make_option('--user', dest='user', default='', help='uWSGI daemon user.'), make_option('--group', dest='group', default='', help='uWSGI daemon group.'), @@ -32,6 +38,16 @@ class Command(BaseCommand): def handle(self, *args, **options): interactive = options.get('interactive') + cert = options.get('cert') + cert_key = options.get('cert_key') + if bool(cert) != bool(cert_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") + context = { 'project_name': paths.get_project_name(), 'project_dir': paths.get_project_dir(),