diff --git a/TODO.md b/TODO.md index f8d767e5..f31ef7ee 100644 --- a/TODO.md +++ b/TODO.md @@ -379,3 +379,6 @@ http://wiki2.dovecot.org/Pigeonhole/Sieve/Examples # orders ignorign default filter is not very effective, because of selecting all orders for billing will select ignored too + + +# mail system users group? which one is more convinient? if main group does not exists, backend will fail! diff --git a/orchestra/contrib/mailboxes/backends.py b/orchestra/contrib/mailboxes/backends.py index c42d36c0..50c2f13c 100644 --- a/orchestra/contrib/mailboxes/backends.py +++ b/orchestra/contrib/mailboxes/backends.py @@ -23,6 +23,7 @@ class SieveFilteringMixin(object): # create mailboxes if fileinfo is provided witout ':create' option context['box'] = box self.append(textwrap.dedent(""" + # Create %(box)s mailbox mkdir -p %(maildir)s/.%(box)s chown %(user)s:%(group)s %(maildir)s/.%(box)s if [[ ! $(grep '%(box)s' %(maildir)s/subscriptions) ]]; then @@ -34,13 +35,15 @@ class SieveFilteringMixin(object): context['filtering_cpath'] = re.sub(r'\.sieve$', '.svbin', context['filtering_path']) if content: context['filtering'] = ('# %(banner)s\n' + content) % context - self.append(textwrap.dedent(""" + self.append(textwrap.dedent("""\ + # Create and compile orchestra sieve filtering mkdir -p $(dirname '%(filtering_path)s') cat << 'EOF' > %(filtering_path)s %(filtering)s EOF sievec %(filtering_path)s - chown %(user)s:%(group)s {%(filtering_path)s,%(filtering_cpath)s} + chown %(user)s:%(group)s %(filtering_path)s + chown %(user)s:%(group)s %(filtering_cpath)s """) % context ) else: @@ -64,15 +67,20 @@ class UNIXUserMaildirBackend(SieveFilteringMixin, ServiceController): def save(self, mailbox): context = self.get_context(mailbox) self.append(textwrap.dedent(""" + # Update/create %(user)s user state if [[ $( id %(user)s ) ]]; then - # Fucking postfix SASL caches credentials - old_password=$(grep "^%(user)s:" /etc/shadow|cut -d':' -f2) - usermod %(user)s --password '%(password)s' --shell %(initial_shell)s - if [[ "$old_password" != "%(password)s" ]]; then + old_password=$(getent shadow %(user)s | cut -d':' -f2) + usermod %(user)s \\ + --shell %(initial_shell)s \\ + --password '%(password)s' + if [[ "$old_password" != '%(password)s' ]]; then + # Postfix SASL caches passwords RESTART_POSTFIX=1 fi else - useradd %(user)s --home %(home)s --password '%(password)s' + useradd %(user)s \\ + --home %(home)s \\ + --password '%(password)s' fi mkdir -p %(home)s chmod 751 %(home)s @@ -86,6 +94,7 @@ class UNIXUserMaildirBackend(SieveFilteringMixin, ServiceController): context['quota'] = mailbox.resources.disk.allocated * mailbox.resources.disk.resource.get_scale() #unit_to_bytes(mailbox.resources.disk.unit) self.append(textwrap.dedent(""" + # Set Maildir quota for %(user)s mkdir -p %(maildir)s chown %(user)s:%(group)s %(maildir)s if [[ ! -f %(maildir)s/maildirsize ]]; then @@ -137,7 +146,7 @@ class DovecotPostfixPasswdVirtualUserBackend(SieveFilteringMixin, ServiceControl def set_user(self, context): self.append(textwrap.dedent(""" - if [[ $( grep "^%(user)s:" %(passwd_path)s ) ]]; then + if [[ $( grep '^%(user)s:' %(passwd_path)s ) ]]; then sed -i 's#^%(user)s:.*#%(passwd)s#' %(passwd_path)s else echo '%(passwd)s' >> %(passwd_path)s @@ -148,7 +157,7 @@ class DovecotPostfixPasswdVirtualUserBackend(SieveFilteringMixin, ServiceControl def set_mailbox(self, context): self.append(textwrap.dedent(""" - if [[ ! $(grep "^%(user)s@%(mailbox_domain)s\s" %(virtual_mailbox_maps)s) ]]; then + if [[ ! $(grep '^%(user)s@%(mailbox_domain)s\s' %(virtual_mailbox_maps)s) ]]; then echo "%(user)s@%(mailbox_domain)s\tOK" >> %(virtual_mailbox_maps)s UPDATED_VIRTUAL_MAILBOX_MAPS=1 fi""") % context @@ -240,6 +249,7 @@ class PostfixAddressVirtualDomainBackend(ServiceController): domain = context['domain'] if domain.name != context['local_domain'] and self.is_local_domain(domain): self.append(textwrap.dedent(""" + # %(domain)s is a virtual domain belonging to this server if [[ ! $(grep '^\s*%(domain)s\s*$' %(virtual_alias_domains)s) ]]; then echo '%(domain)s' >> %(virtual_alias_domains)s UPDATED_VIRTUAL_ALIAS_DOMAINS=1 @@ -253,6 +263,7 @@ class PostfixAddressVirtualDomainBackend(ServiceController): domain = context['domain'] if self.is_last_domain(domain): self.append(textwrap.dedent(""" + # Delete %(domain)s virtual domain if [[ $(grep '^%(domain)s\s*$' %(virtual_alias_domains)s) ]]; then sed -i '/^%(domain)s\s*/d' %(virtual_alias_domains)s UPDATED_VIRTUAL_ALIAS_DOMAINS=1 @@ -271,7 +282,7 @@ class PostfixAddressVirtualDomainBackend(ServiceController): def commit(self): context = self.get_context_files() - self.append(textwrap.dedent("""\ + self.append(textwrap.dedent(""" [[ $UPDATED_VIRTUAL_ALIAS_DOMAINS == 1 ]] && { service postfix reload } @@ -309,6 +320,7 @@ class PostfixAddressBackend(PostfixAddressVirtualDomainBackend): if destination: context['destination'] = destination self.append(textwrap.dedent(""" + # Set virtual alias entry for %(email)s LINE='%(email)s\t%(destination)s' if [[ ! $(grep '^%(email)s\s' %(virtual_alias_maps)s) ]]; then # Add new line @@ -323,12 +335,7 @@ class PostfixAddressBackend(PostfixAddressVirtualDomainBackend): fi""") % context) else: logger.warning("Address %i is empty" % address.pk) - self.append(textwrap.dedent(""" - if [[ $(grep '^%(email)s\s' %(virtual_alias_maps)s) ]]; then - sed -i '/^%(email)s\s/d' %(virtual_alias_maps)s - UPDATED_VIRTUAL_ALIAS_MAPS=1 - fi""") % context - ) + self.exclude_virtual_alias_maps(context) # Virtual mailbox stuff # destination = [] # for mailbox in address.get_mailboxes(): @@ -340,10 +347,12 @@ class PostfixAddressBackend(PostfixAddressVirtualDomainBackend): def exclude_virtual_alias_maps(self, context): self.append(textwrap.dedent(""" - sed -i '/^%(email)s\s.*$/d;{!q0;q1}' %(virtual_alias_maps)s && \\ + # Remove %(email)s virtual alias entry + if [[ $(grep '^%(email)s\s' %(virtual_alias_maps)s) ]]; then + sed -i '/^%(email)s\s/d' %(virtual_alias_maps)s UPDATED_VIRTUAL_ALIAS_MAPS=1 - """) % context - ) + fi""") % context + ) def save(self, address): context = super(PostfixAddressBackend, self).save(address) @@ -356,6 +365,7 @@ class PostfixAddressBackend(PostfixAddressVirtualDomainBackend): def commit(self): context = self.get_context_files() self.append(textwrap.dedent("""\ + # Apply changes if needed [[ $UPDATED_VIRTUAL_ALIAS_DOMAINS == 1 ]] && { service postfix reload } diff --git a/orchestra/contrib/systemusers/backends.py b/orchestra/contrib/systemusers/backends.py index bfd9bb1f..651e6da9 100644 --- a/orchestra/contrib/systemusers/backends.py +++ b/orchestra/contrib/systemusers/backends.py @@ -31,6 +31,7 @@ class UNIXUserBackend(ServiceController): context['groups_arg'] = '--groups %s' % groups if groups else '' # TODO userd add will fail if %(user)s group already exists self.append(textwrap.dedent(""" + # Update/create %(user)s user state if [[ $( id %(user)s ) ]]; then usermod %(user)s --home %(home)s \\ --password '%(password)s' \\ @@ -58,6 +59,7 @@ class UNIXUserBackend(ServiceController): ) if context['home'] != context['base_home']: self.append(textwrap.dedent(""" + # Set extra permissions since %(user)s home is inside %(mainuser)s home if [[ $(mount | grep "^$(df %(home)s|grep '^/')\s" | grep acl) ]]; then # Accountn group as the owner chown %(mainuser)s:%(mainuser)s %(home)s @@ -83,7 +85,8 @@ class UNIXUserBackend(ServiceController): context = self.get_context(user) if not context['user']: return - self.append(textwrap.dedent("""\ + self.append(textwrap.dedent(""" + # Delete %(user)s user nohup bash -c 'sleep 2 && killall -u %(user)s -s KILL' &> /dev/null & killall -u %(user)s || true userdel %(user)s || exit_code=$? diff --git a/orchestra/contrib/webapps/backends/php.py b/orchestra/contrib/webapps/backends/php.py index 77f8cc69..b0521f72 100644 --- a/orchestra/contrib/webapps/backends/php.py +++ b/orchestra/contrib/webapps/backends/php.py @@ -126,7 +126,7 @@ class PHPBackend(WebAppServiceMixin, ServiceController): service php5-fpm reload fi - # Coordinate Apache restart with other concurrent backends (i.e. Apache2Backend) + # Coordinate Apache restart with other concurrent backends (e.g. Apache2Backend) is_last=0 mv /dev/shm/restart.apache2 /dev/shm/restart.apache2.locked || { sleep 0.2 @@ -144,6 +144,7 @@ class PHPBackend(WebAppServiceMixin, ServiceController): else echo -n "$state" > /dev/shm/restart.apache2.locked if [[ $UPDATED_APACHE -eq 1 ]]; then + echo -e "Apache will be restarted by another backend:\\n${state}" echo "$backend RESTART" >> /dev/shm/restart.apache2.locked fi mv /dev/shm/restart.apache2.locked /dev/shm/restart.apache2 diff --git a/orchestra/contrib/websites/backends/apache.py b/orchestra/contrib/websites/backends/apache.py index 3e0c8de6..b2161feb 100644 --- a/orchestra/contrib/websites/backends/apache.py +++ b/orchestra/contrib/websites/backends/apache.py @@ -67,8 +67,7 @@ class Apache2Backend(ServiceController): SuexecUserGroup {{ user }} {{ group }}\ {% for line in extra_conf.splitlines %} {{ line | safe }}{% endfor %} - - """) + """) ).render(Context(context)) def render_redirect_https(self, context): @@ -85,8 +84,7 @@ class Apache2Backend(ServiceController): RewriteEngine On RewriteCond %{HTTPS} off RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} - - """) + """) ).render(Context(context)) def save(self, site): @@ -99,8 +97,9 @@ class Apache2Backend(ServiceController): apache_conf += self.render_virtual_host(site, context, ssl=True) if site.protocol == site.HTTPS_ONLY: apache_conf += self.render_redirect_https(context) - context['apache_conf'] = apache_conf - self.append(textwrap.dedent("""\ + context['apache_conf'] = apache_conf.strip() + self.append(textwrap.dedent(""" + # Generate %(site_name)s Apache site config read -r -d '' apache_conf << 'EOF' || true %(apache_conf)s EOF @@ -113,6 +112,7 @@ class Apache2Backend(ServiceController): ) if context['server_name'] and site.active: self.append(textwrap.dedent("""\ + # Enable %(site_name)s site if [[ ! -f %(sites_enabled)s ]]; then a2ensite %(site_unique_name)s.conf UPDATED_APACHE=1 @@ -120,6 +120,7 @@ class Apache2Backend(ServiceController): ) else: self.append(textwrap.dedent("""\ + # Disable %(site_name)s site if [[ -f %(sites_enabled)s ]]; then a2dissite %(site_unique_name)s.conf; UPDATED_APACHE=1 @@ -128,22 +129,26 @@ class Apache2Backend(ServiceController): def delete(self, site): context = self.get_context(site) - self.append("a2dissite %(site_unique_name)s.conf && UPDATED_APACHE=1" % context) - self.append("rm -f %(sites_available)s" % context) + self.append(textwrap.dedent(""" + # Remove %(site_name)s site configuration + a2dissite %(site_unique_name)s.conf && UPDATED_APACHE=1 + rm -f %(sites_available)s\ + """) % context + ) def prepare(self): super(Apache2Backend, self).prepare() # Coordinate apache restart with php backend in order not to overdo it self.append(textwrap.dedent("""\ backend="Apache2Backend" - echo "$backend" >> /dev/shm/restart.apache2 + echo "$backend" >> /dev/shm/restart.apache2\ """) ) def commit(self): """ reload Apache2 if necessary """ self.append(textwrap.dedent(""" - # Coordinate Apache restart with other concurrent backends (i.e. Apache2Backend) + # Coordinate Apache restart with other concurrent backends (e.g. PHPBackend) is_last=0 mv /dev/shm/restart.apache2 /dev/shm/restart.apache2.locked || { sleep 0.2 @@ -161,6 +166,7 @@ class Apache2Backend(ServiceController): else echo -n "$state" > /dev/shm/restart.apache2.locked if [[ $UPDATED_APACHE -eq 1 ]]; then + echo -e "Apache will be restarted by another backend:\\n${state}" echo "$backend RESTART" >> /dev/shm/restart.apache2.locked fi mv /dev/shm/restart.apache2.locked /dev/shm/restart.apache2