Improved ACL support
This commit is contained in:
parent
b8c815edf2
commit
b5ede03858
2
TODO.md
2
TODO.md
|
@ -354,3 +354,5 @@ make django admin taskstate uncollapse fucking traceback, ( if exists ?)
|
||||||
resorce monitoring more efficient, less mem an better queries for calc current data
|
resorce monitoring more efficient, less mem an better queries for calc current data
|
||||||
|
|
||||||
# best_price rating method
|
# best_price rating method
|
||||||
|
|
||||||
|
# select contact with one result: redirect
|
||||||
|
|
|
@ -58,7 +58,7 @@ class AccountAdmin(ChangePasswordAdminMixin, auth.UserAdmin, ExtendedModelAdmin)
|
||||||
add_form = AccountCreationForm
|
add_form = AccountCreationForm
|
||||||
form = UserChangeForm
|
form = UserChangeForm
|
||||||
filter_horizontal = ()
|
filter_horizontal = ()
|
||||||
change_readonly_fields = ('username', 'main_systemuser_link')
|
change_readonly_fields = ('username', 'main_systemuser_link', 'is_active')
|
||||||
change_form_template = 'admin/accounts/account/change_form.html'
|
change_form_template = 'admin/accounts/account/change_form.html'
|
||||||
actions = [disable, list_contacts, service_report, SendEmail(), delete_related_services]
|
actions = [disable, list_contacts, service_report, SendEmail(), delete_related_services]
|
||||||
change_view_actions = [disable, service_report]
|
change_view_actions = [disable, service_report]
|
||||||
|
@ -139,8 +139,14 @@ class AccountListAdmin(AccountAdmin):
|
||||||
'original_model': original_model,
|
'original_model': original_model,
|
||||||
}
|
}
|
||||||
context.update(extra_context or {})
|
context.update(extra_context or {})
|
||||||
return super(AccountListAdmin, self).changelist_view(request,
|
response = super(AccountListAdmin, self).changelist_view(request, extra_context=context)
|
||||||
extra_context=context)
|
if hasattr(response, 'context_data'):
|
||||||
|
# user has submitted a change list change, we redirect directly to the add view
|
||||||
|
# if there is only one result
|
||||||
|
queryset = response.context_data['cl'].queryset
|
||||||
|
if len(queryset) == 1:
|
||||||
|
return HttpResponseRedirect('../?account=%i' % queryset[0].pk)
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
class AccountAdminMixin(object):
|
class AccountAdminMixin(object):
|
||||||
|
@ -283,8 +289,7 @@ class AccountAdminMixin(object):
|
||||||
request_copy.pop('account')
|
request_copy.pop('account')
|
||||||
request.GET = request_copy
|
request.GET = request_copy
|
||||||
context.update(extra_context or {})
|
context.update(extra_context or {})
|
||||||
return super(AccountAdminMixin, self).changelist_view(request,
|
return super(AccountAdminMixin, self).changelist_view(request, extra_context=context)
|
||||||
extra_context=context)
|
|
||||||
|
|
||||||
|
|
||||||
class SelectAccountAdminMixin(AccountAdminMixin):
|
class SelectAccountAdminMixin(AccountAdminMixin):
|
||||||
|
|
|
@ -177,7 +177,12 @@ class Bind9SlaveDomainBackend(Bind9MasterDomainBackend):
|
||||||
|
|
||||||
def commit(self):
|
def commit(self):
|
||||||
""" ideally slave should be restarted after master """
|
""" ideally slave should be restarted after master """
|
||||||
self.append('if [[ $UPDATED == 1 ]]; then { sleep 1 && service bind9 reload; } & fi')
|
self.append(textwrap.dedent("""\
|
||||||
|
if [[ $UPDATED == 1 ]]; then
|
||||||
|
nohup bash -c 'sleep 1 && service bind9 reload' &> /dev/null &
|
||||||
|
fi
|
||||||
|
""")
|
||||||
|
)
|
||||||
|
|
||||||
def get_context(self, domain):
|
def get_context(self, domain):
|
||||||
context = {
|
context = {
|
||||||
|
|
|
@ -252,6 +252,7 @@ class Record(models.Model):
|
||||||
def clean(self):
|
def clean(self):
|
||||||
""" validates record value based on its type """
|
""" validates record value based on its type """
|
||||||
# validate value
|
# validate value
|
||||||
|
if self.type != self.TXT:
|
||||||
self.value = self.value.lower().strip()
|
self.value = self.value.lower().strip()
|
||||||
choices = {
|
choices = {
|
||||||
self.MX: validators.validate_mx_record,
|
self.MX: validators.validate_mx_record,
|
||||||
|
|
|
@ -124,5 +124,5 @@ def validate_zone(zone):
|
||||||
if check.exit_code == 127:
|
if check.exit_code == 127:
|
||||||
logger.error("Cannot validate domain zone: %s not installed." % checkzone)
|
logger.error("Cannot validate domain zone: %s not installed." % checkzone)
|
||||||
elif check.exit_code == 1:
|
elif check.exit_code == 1:
|
||||||
errors = re.compile(r'zone.*: (.*)').findall(check.stdout)[:-1]
|
errors = re.compile(r'zone.*: (.*)').findall(check.stdout.decode('utf8'))[:-1]
|
||||||
raise ValidationError(', '.join(errors))
|
raise ValidationError(', '.join(errors))
|
||||||
|
|
|
@ -78,7 +78,7 @@ class MailmanBackend(MailmanVirtualDomainBackend):
|
||||||
Includes <tt>MailmanVirtualDomainBackend</tt>
|
Includes <tt>MailmanVirtualDomainBackend</tt>
|
||||||
"""
|
"""
|
||||||
verbose_name = "Mailman"
|
verbose_name = "Mailman"
|
||||||
addresses = [
|
address_suffixes = [
|
||||||
'',
|
'',
|
||||||
'-admin',
|
'-admin',
|
||||||
'-bounces',
|
'-bounces',
|
||||||
|
@ -99,9 +99,12 @@ class MailmanBackend(MailmanVirtualDomainBackend):
|
||||||
|
|
||||||
def get_virtual_aliases(self, context):
|
def get_virtual_aliases(self, context):
|
||||||
aliases = ['# %(banner)s' % context]
|
aliases = ['# %(banner)s' % context]
|
||||||
for address in self.addresses:
|
for suffix in self.address_suffixes:
|
||||||
context['address'] = address
|
context['suffix'] = suffix
|
||||||
aliases.append("%(address_name)s%(address)s@%(domain)s\t%(name)s%(address)s" % context)
|
# Because mailman doesn't properly handle lists aliases we need two virtual aliases
|
||||||
|
aliases.append("%(address_name)s%(suffix)s@%(domain)s\t%(name)s%(suffix)s" % context)
|
||||||
|
# And another with the original list name; Mailman generates links with it
|
||||||
|
aliases.append("%(name)s%(suffix)s@%(domain)s\t%(name)s%(suffix)s" % context)
|
||||||
return '\n'.join(aliases)
|
return '\n'.join(aliases)
|
||||||
|
|
||||||
def save(self, mail_list):
|
def save(self, mail_list):
|
||||||
|
@ -122,7 +125,7 @@ class MailmanBackend(MailmanVirtualDomainBackend):
|
||||||
UPDATED_VIRTUAL_ALIAS=1
|
UPDATED_VIRTUAL_ALIAS=1
|
||||||
else
|
else
|
||||||
if [[ ! $(grep '^\s*%(address_name)s@%(address_domain)s\s\s*%(name)s\s*$' %(virtual_alias)s) ]]; then
|
if [[ ! $(grep '^\s*%(address_name)s@%(address_domain)s\s\s*%(name)s\s*$' %(virtual_alias)s) ]]; then
|
||||||
sed -i -e '/^.*\s%(name)s\(%(address_regex)s\)\s*$/d' \\
|
sed -i -e '/^.*\s%(name)s\(%(suffixes_regex)s\)\s*$/d' \\
|
||||||
-e 'N; /^\s*\\n\s*$/d; P; D' %(virtual_alias)s
|
-e 'N; /^\s*\\n\s*$/d; P; D' %(virtual_alias)s
|
||||||
echo "${aliases}" >> %(virtual_alias)s
|
echo "${aliases}" >> %(virtual_alias)s
|
||||||
UPDATED_VIRTUAL_ALIAS=1
|
UPDATED_VIRTUAL_ALIAS=1
|
||||||
|
@ -159,7 +162,7 @@ class MailmanBackend(MailmanVirtualDomainBackend):
|
||||||
context = self.get_context(mail_list)
|
context = self.get_context(mail_list)
|
||||||
self.exclude_virtual_alias_domain(context)
|
self.exclude_virtual_alias_domain(context)
|
||||||
self.append(textwrap.dedent("""
|
self.append(textwrap.dedent("""
|
||||||
sed -i -e '/^.*\s%(name)s\(%(address_regex)s\)\s*$/d' \\
|
sed -i -e '/^.*\s%(name)s\(%(suffixes_regex)s\)\s*$/d' \\
|
||||||
-e 'N; /^\s*\\n\s*$/d; P; D' %(virtual_alias)s""") % context
|
-e 'N; /^\s*\\n\s*$/d; P; D' %(virtual_alias)s""") % context
|
||||||
)
|
)
|
||||||
self.append(textwrap.dedent("""
|
self.append(textwrap.dedent("""
|
||||||
|
@ -201,7 +204,7 @@ class MailmanBackend(MailmanVirtualDomainBackend):
|
||||||
'domain': mail_list.address_domain or settings.LISTS_DEFAULT_DOMAIN,
|
'domain': mail_list.address_domain or settings.LISTS_DEFAULT_DOMAIN,
|
||||||
'address_name': mail_list.get_address_name(),
|
'address_name': mail_list.get_address_name(),
|
||||||
'address_domain': mail_list.address_domain,
|
'address_domain': mail_list.address_domain,
|
||||||
'address_regex': '\|'.join(self.addresses),
|
'suffixes_regex': '\|'.join(self.address_suffixes),
|
||||||
'admin': mail_list.admin_email,
|
'admin': mail_list.admin_email,
|
||||||
'mailman_root': settings.LISTS_MAILMAN_ROOT_DIR,
|
'mailman_root': settings.LISTS_MAILMAN_ROOT_DIR,
|
||||||
})
|
})
|
||||||
|
|
|
@ -48,12 +48,16 @@ class SieveFilteringMixin(object):
|
||||||
class UNIXUserMaildirBackend(SieveFilteringMixin, ServiceController):
|
class UNIXUserMaildirBackend(SieveFilteringMixin, ServiceController):
|
||||||
"""
|
"""
|
||||||
Assumes that all system users on this servers all mail accounts.
|
Assumes that all system users on this servers all mail accounts.
|
||||||
If you want to have system users AND mailboxes on the same server you should consider using virtual mailboxes
|
If you want to have system users AND mailboxes on the same server you should consider using virtual mailboxes.
|
||||||
|
Supports quota allocation via <tt>resources.disk.allocated</tt>.
|
||||||
"""
|
"""
|
||||||
SHELL = '/dev/null'
|
SHELL = '/dev/null'
|
||||||
|
|
||||||
verbose_name = _("UNIX maildir user")
|
verbose_name = _("UNIX maildir user")
|
||||||
model = 'mailboxes.Mailbox'
|
model = 'mailboxes.Mailbox'
|
||||||
|
doc_settings = (settings,
|
||||||
|
('MAILBOXES_USE_ACCOUNT_AS_GROUP',)
|
||||||
|
)
|
||||||
|
|
||||||
def save(self, mailbox):
|
def save(self, mailbox):
|
||||||
context = self.get_context(mailbox)
|
context = self.get_context(mailbox)
|
||||||
|
@ -89,7 +93,7 @@ class UNIXUserMaildirBackend(SieveFilteringMixin, ServiceController):
|
||||||
context = self.get_context(mailbox)
|
context = self.get_context(mailbox)
|
||||||
self.append('mv %(home)s %(home)s.deleted || exit_code=$?' % context)
|
self.append('mv %(home)s %(home)s.deleted || exit_code=$?' % context)
|
||||||
self.append(textwrap.dedent("""
|
self.append(textwrap.dedent("""
|
||||||
{ sleep 2 && killall -u %(user)s -s KILL; } &
|
nohup bash -c '{ sleep 2 && killall -u %(user)s -s KILL; }' &> /dev/null &
|
||||||
killall -u %(user)s || true
|
killall -u %(user)s || true
|
||||||
userdel %(user)s || true
|
userdel %(user)s || true
|
||||||
groupdel %(user)s || true""") % context
|
groupdel %(user)s || true""") % context
|
||||||
|
@ -98,7 +102,7 @@ class UNIXUserMaildirBackend(SieveFilteringMixin, ServiceController):
|
||||||
def get_context(self, mailbox):
|
def get_context(self, mailbox):
|
||||||
context = {
|
context = {
|
||||||
'user': mailbox.name,
|
'user': mailbox.name,
|
||||||
'group': mailbox.name,
|
'group': mailbox.account.username if settings.MAILBOXES_USE_ACCOUNT_AS_GROUP else mailbox.name,
|
||||||
'name': mailbox.name,
|
'name': mailbox.name,
|
||||||
'password': mailbox.password if mailbox.active else '*%s' % mailbox.password,
|
'password': mailbox.password if mailbox.active else '*%s' % mailbox.password,
|
||||||
'home': mailbox.get_home(),
|
'home': mailbox.get_home(),
|
||||||
|
@ -147,7 +151,7 @@ class DovecotPostfixPasswdVirtualUserBackend(SieveFilteringMixin, ServiceControl
|
||||||
def delete(self, mailbox):
|
def delete(self, mailbox):
|
||||||
context = self.get_context(mailbox)
|
context = self.get_context(mailbox)
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
{ sleep 2 && killall -u %(uid)s -s KILL; } &
|
nohup bash -c 'sleep 2 && killall -u %(uid)s -s KILL' &> /dev/null &
|
||||||
killall -u %(uid)s || true
|
killall -u %(uid)s || true
|
||||||
sed -i '/^%(user)s:.*/d' %(passwd_path)s
|
sed -i '/^%(user)s:.*/d' %(passwd_path)s
|
||||||
sed -i '/^%(user)s@%(mailbox_domain)s\s.*/d' %(virtual_mailbox_maps)s
|
sed -i '/^%(user)s@%(mailbox_domain)s\s.*/d' %(virtual_mailbox_maps)s
|
||||||
|
@ -224,10 +228,10 @@ class PostfixAddressVirtualDomainBackend(ServiceController):
|
||||||
domain = context['domain']
|
domain = context['domain']
|
||||||
if domain.name != context['local_domain'] and self.is_local_domain(domain):
|
if domain.name != context['local_domain'] and self.is_local_domain(domain):
|
||||||
self.append(textwrap.dedent("""
|
self.append(textwrap.dedent("""
|
||||||
[[ $(grep '^\s*%(domain)s\s*$' %(virtual_alias_domains)s) ]] || {
|
if [[ ! $(grep '^\s*%(domain)s\s*$' %(virtual_alias_domains)s) ]]; then
|
||||||
echo '%(domain)s' >> %(virtual_alias_domains)s
|
echo '%(domain)s' >> %(virtual_alias_domains)s
|
||||||
UPDATED_VIRTUAL_ALIAS_DOMAINS=1
|
UPDATED_VIRTUAL_ALIAS_DOMAINS=1
|
||||||
}""") % context
|
fi""") % context
|
||||||
)
|
)
|
||||||
|
|
||||||
def is_last_domain(self, domain):
|
def is_last_domain(self, domain):
|
||||||
|
@ -237,9 +241,10 @@ class PostfixAddressVirtualDomainBackend(ServiceController):
|
||||||
domain = context['domain']
|
domain = context['domain']
|
||||||
if self.is_last_domain(domain):
|
if self.is_last_domain(domain):
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
sed -i '/^%(domain)s\s*/d;{!q0;q1}' %(virtual_alias_domains)s && \\
|
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
|
UPDATED_VIRTUAL_ALIAS_DOMAINS=1
|
||||||
""") % context
|
fi""") % context
|
||||||
)
|
)
|
||||||
|
|
||||||
def save(self, address):
|
def save(self, address):
|
||||||
|
@ -307,9 +312,10 @@ class PostfixAddressBackend(PostfixAddressVirtualDomainBackend):
|
||||||
else:
|
else:
|
||||||
logger.warning("Address %i is empty" % address.pk)
|
logger.warning("Address %i is empty" % address.pk)
|
||||||
self.append(textwrap.dedent("""
|
self.append(textwrap.dedent("""
|
||||||
sed -i '/^%(email)s\s/d;{!q0;q1}' %(virtual_alias_maps)s && \\
|
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
|
UPDATED_VIRTUAL_ALIAS_MAPS=1
|
||||||
""") % context
|
fi""") % context
|
||||||
)
|
)
|
||||||
# Virtual mailbox stuff
|
# Virtual mailbox stuff
|
||||||
# destination = []
|
# destination = []
|
||||||
|
|
|
@ -45,6 +45,12 @@ MAILBOXES_SIEVETEST_BIN_PATH = Setting('MAILBOXES_SIEVETEST_BIN_PATH',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
MAILBOXES_USE_ACCOUNT_AS_GROUP = Setting('MAILBOXES_USE_ACCOUNT_AS_GROUP',
|
||||||
|
False,
|
||||||
|
help_text="Group used for system user based mailboxes. If <tt>False</tt> mailbox.name will be used as group."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
MAILBOXES_VIRTUAL_MAILBOX_MAPS_PATH = Setting('MAILBOXES_VIRTUAL_MAILBOX_MAPS_PATH',
|
MAILBOXES_VIRTUAL_MAILBOX_MAPS_PATH = Setting('MAILBOXES_VIRTUAL_MAILBOX_MAPS_PATH',
|
||||||
'/etc/postfix/virtual_mailboxes'
|
'/etc/postfix/virtual_mailboxes'
|
||||||
)
|
)
|
||||||
|
|
|
@ -87,9 +87,9 @@ def message_user(request, logs):
|
||||||
if log.state != log.EXCEPTION:
|
if log.state != log.EXCEPTION:
|
||||||
# EXCEPTION logs are not stored on the database
|
# EXCEPTION logs are not stored on the database
|
||||||
ids.append(log.pk)
|
ids.append(log.pk)
|
||||||
if log.state in (log.SUCCESS, log.NOTHING):
|
if log.is_success:
|
||||||
successes += 1
|
successes += 1
|
||||||
elif log.state in (log.RECEIVED, log.STARTED):
|
elif not log.has_finished:
|
||||||
async += 1
|
async += 1
|
||||||
async_ids.append(log.id)
|
async_ids.append(log.id)
|
||||||
errors = total-successes-async
|
errors = total-successes-async
|
||||||
|
|
|
@ -79,7 +79,7 @@ class Command(BaseCommand):
|
||||||
route, __ = key
|
route, __ = key
|
||||||
backend, operations = value
|
backend, operations = value
|
||||||
servers.append(str(route.host))
|
servers.append(str(route.host))
|
||||||
self.stdout.write('# Execute on %s' % server.name)
|
self.stdout.write('# Execute on %s' % route.host)
|
||||||
for method, commands in backend.scripts:
|
for method, commands in backend.scripts:
|
||||||
script = '\n'.join(commands)
|
script = '\n'.join(commands)
|
||||||
self.stdout.write(script)
|
self.stdout.write(script)
|
||||||
|
|
|
@ -28,7 +28,7 @@ def keep_log(execute, log, operations):
|
||||||
log = kwargs['log']
|
log = kwargs['log']
|
||||||
try:
|
try:
|
||||||
log = execute(*args, **kwargs)
|
log = execute(*args, **kwargs)
|
||||||
if log.state != log.SUCCESS:
|
if not log.is_success:
|
||||||
send_report(execute, args, log)
|
send_report(execute, args, log)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
trace = traceback.format_exc()
|
trace = traceback.format_exc()
|
||||||
|
|
|
@ -96,6 +96,10 @@ class BackendLog(models.Model):
|
||||||
def has_finished(self):
|
def has_finished(self):
|
||||||
return self.state not in (self.STARTED, self.RECEIVED)
|
return self.state not in (self.STARTED, self.RECEIVED)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_success(self):
|
||||||
|
return self.state in (self.SUCCESS, self.NOTHING)
|
||||||
|
|
||||||
def backend_class(self):
|
def backend_class(self):
|
||||||
return ServiceBackend.get_backend(self.backend)
|
return ServiceBackend.get_backend(self.backend)
|
||||||
|
|
||||||
|
|
|
@ -12,13 +12,16 @@ from . import settings
|
||||||
class UNIXUserBackend(ServiceController):
|
class UNIXUserBackend(ServiceController):
|
||||||
"""
|
"""
|
||||||
Basic UNIX system user/group support based on <tt>useradd</tt>, <tt>usermod</tt>, <tt>userdel</tt> and <tt>groupdel</tt>.
|
Basic UNIX system user/group support based on <tt>useradd</tt>, <tt>usermod</tt>, <tt>userdel</tt> and <tt>groupdel</tt>.
|
||||||
|
Autodetects and uses ACL if available, for better permission management.
|
||||||
"""
|
"""
|
||||||
verbose_name = _("UNIX user")
|
verbose_name = _("UNIX user")
|
||||||
model = 'systemusers.SystemUser'
|
model = 'systemusers.SystemUser'
|
||||||
actions = ('save', 'delete', 'set_permission', 'validate_path')
|
actions = ('save', 'delete', 'set_permission', 'validate_path_exists')
|
||||||
doc_settings = (settings,
|
doc_settings = (settings, (
|
||||||
('SYSTEMUSERS_DEFAULT_GROUP_MEMBERS', 'SYSTEMUSERS_MOVE_ON_DELETE_PATH')
|
'SYSTEMUSERS_DEFAULT_GROUP_MEMBERS',
|
||||||
)
|
'SYSTEMUSERS_MOVE_ON_DELETE_PATH',
|
||||||
|
'SYSTEMUSERS_FORBIDDEN_PATHS'
|
||||||
|
))
|
||||||
|
|
||||||
def save(self, user):
|
def save(self, user):
|
||||||
context = self.get_context(user)
|
context = self.get_context(user)
|
||||||
|
@ -33,16 +36,25 @@ class UNIXUserBackend(ServiceController):
|
||||||
else
|
else
|
||||||
useradd %(user)s --home %(home)s --password '%(password)s' --shell %(shell)s %(groups_arg)s
|
useradd %(user)s --home %(home)s --password '%(password)s' --shell %(shell)s %(groups_arg)s
|
||||||
fi
|
fi
|
||||||
mkdir -p %(home)s
|
|
||||||
chmod 750 %(home)s
|
|
||||||
chown %(user)s:%(user)s %(home)s""") % context
|
|
||||||
)
|
|
||||||
if context['home'] != context['base_home']:
|
|
||||||
self.append(textwrap.dedent("""
|
|
||||||
mkdir -p %(base_home)s
|
mkdir -p %(base_home)s
|
||||||
chmod 750 %(base_home)s
|
chmod 750 %(base_home)s
|
||||||
chown %(user)s:%(user)s %(base_home)s""") % context
|
chown %(user)s:%(user)s %(base_home)s""") % context
|
||||||
)
|
)
|
||||||
|
if context['home'] != context['base_home']:
|
||||||
|
self.append(textwrap.dedent("""
|
||||||
|
if [[ $(mount | grep "^$(df %(home)s|grep '^/')\s" | grep acl) ]]; then
|
||||||
|
chown %(mainuser)s:%(mainuser)s %(home)s
|
||||||
|
# Home access
|
||||||
|
setfacl -m u:%(user)s:--x '%(mainuser_home)s'
|
||||||
|
# Grant perms to future files within the directory
|
||||||
|
setfacl -m d:u:%(user)s:rwx %(home)s
|
||||||
|
# Grant access to main user
|
||||||
|
setfacl -m d:u:%(mainuser)s:rwx %(home)s
|
||||||
|
else
|
||||||
|
chmod g+rxw %(home)s
|
||||||
|
chown %(user)s:%(user)s %(home)s
|
||||||
|
fi""") % context
|
||||||
|
)
|
||||||
for member in settings.SYSTEMUSERS_DEFAULT_GROUP_MEMBERS:
|
for member in settings.SYSTEMUSERS_DEFAULT_GROUP_MEMBERS:
|
||||||
context['member'] = member
|
context['member'] = member
|
||||||
self.append('usermod -a -G %(user)s %(member)s || exit_code=$?' % context)
|
self.append('usermod -a -G %(user)s %(member)s || exit_code=$?' % context)
|
||||||
|
@ -54,7 +66,7 @@ class UNIXUserBackend(ServiceController):
|
||||||
if not context['user']:
|
if not context['user']:
|
||||||
return
|
return
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
{ sleep 2 && killall -u %(user)s -s KILL; } &
|
nohup bash -c 'sleep 2 && killall -u %(user)s -s KILL' &> /dev/null &
|
||||||
killall -u %(user)s || true
|
killall -u %(user)s || true
|
||||||
userdel %(user)s || exit_code=$?
|
userdel %(user)s || exit_code=$?
|
||||||
groupdel %(group)s || exit_code=$?
|
groupdel %(group)s || exit_code=$?
|
||||||
|
@ -71,15 +83,12 @@ class UNIXUserBackend(ServiceController):
|
||||||
'perm_action': user.set_perm_action,
|
'perm_action': user.set_perm_action,
|
||||||
'perm_home': user.set_perm_base_home,
|
'perm_home': user.set_perm_base_home,
|
||||||
'perm_to': os.path.join(user.set_perm_base_home, user.set_perm_home_extension),
|
'perm_to': os.path.join(user.set_perm_base_home, user.set_perm_home_extension),
|
||||||
'exclude': '',
|
|
||||||
})
|
})
|
||||||
|
|
||||||
exclude_acl = []
|
exclude_acl = []
|
||||||
for exclude in settings.SYSTEMUSERS_EXLUDE_ACL_PATHS:
|
for exclude in settings.SYSTEMUSERS_FORBIDDEN_PATHS:
|
||||||
context['exclude'] = exclude
|
context['exclude_acl'] = exclude
|
||||||
exclude_acl.append('-not -path "%(perm_home)s/%(exclude)s"' % context)
|
exclude_acl.append('-not -path "%(perm_to)s/%(exclude_acl)s"' % context)
|
||||||
if exclude_acl:
|
context['exclude_acl'] = ' \\\n -a '.join(exclude_acl) if exclude_acl else ''
|
||||||
context['exclude'] = ' \\\n -a '.join(exclude_acl)
|
|
||||||
if user.set_perm_perms == 'read-write':
|
if user.set_perm_perms == 'read-write':
|
||||||
context['perm_perms'] = 'rwx' if user.set_perm_action == 'grant' else '---'
|
context['perm_perms'] = 'rwx' if user.set_perm_action == 'grant' else '---'
|
||||||
elif user.set_perm_perms == 'read-only':
|
elif user.set_perm_perms == 'read-only':
|
||||||
|
@ -91,9 +100,9 @@ class UNIXUserBackend(ServiceController):
|
||||||
# Home access
|
# Home access
|
||||||
setfacl -m u:%(user)s:--x '%(perm_home)s'
|
setfacl -m u:%(user)s:--x '%(perm_home)s'
|
||||||
# Grant perms to existing and future files
|
# Grant perms to existing and future files
|
||||||
find '%(perm_to)s' %(exclude)s \\
|
find '%(perm_to)s' %(exclude_acl)s \\
|
||||||
-exec setfacl -m u:%(user)s:%(perm_perms)s {} \\;
|
-exec setfacl -m u:%(user)s:%(perm_perms)s {} \\;
|
||||||
find '%(perm_to)s' -type d %(exclude)s \\
|
find '%(perm_to)s' -type d %(exclude_acl)s \\
|
||||||
-exec setfacl -m d:u:%(user)s:%(perm_perms)s {} \\;
|
-exec setfacl -m d:u:%(user)s:%(perm_perms)s {} \\;
|
||||||
# Account group as the owner of new files
|
# Account group as the owner of new files
|
||||||
chmod g+s '%(perm_to)s'
|
chmod g+s '%(perm_to)s'
|
||||||
|
@ -102,28 +111,27 @@ class UNIXUserBackend(ServiceController):
|
||||||
if not user.is_main:
|
if not user.is_main:
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
# Grant access to main user
|
# Grant access to main user
|
||||||
find '%(perm_to)s' -type d %(exclude)s \\
|
find '%(perm_to)s' -type d %(exclude_acl)s \\
|
||||||
-exec setfacl -m d:u:%(mainuser)s:rwx {} \\;
|
-exec setfacl -m d:u:%(mainuser)s:rwx {} \\;
|
||||||
""") % context
|
""") % context
|
||||||
)
|
)
|
||||||
elif user.set_perm_action == 'revoke':
|
elif user.set_perm_action == 'revoke':
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
# Revoke permissions
|
# Revoke permissions
|
||||||
find '%(perm_to)s' %(exclude)s \\
|
find '%(perm_to)s' %(exclude_acl)s \\
|
||||||
-exec setfacl -m u:%(user)s:%(perm_perms)s {} \\;
|
-exec setfacl -m u:%(user)s:%(perm_perms)s {} \\;
|
||||||
""") % context
|
""") % context
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def validate_path(self, user):
|
def validate_path_exists(self, user):
|
||||||
context = {
|
context = {
|
||||||
'perm_to': os.path.join(user.set_perm_base_home, user.set_perm_home_extension)
|
'path': user.path_to_validate,
|
||||||
}
|
}
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
if [[ ! -e '%(perm_to)s' ]]; then
|
if [[ ! -e '%(path)s' ]]; then
|
||||||
echo "%(perm_to)s path does not exists." >&2
|
echo "%(path)s path does not exists." >&2
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
""") % context
|
""") % context
|
||||||
)
|
)
|
||||||
|
@ -143,6 +151,7 @@ class UNIXUserBackend(ServiceController):
|
||||||
'mainuser': user.username if user.is_main else user.account.username,
|
'mainuser': user.username if user.is_main else user.account.username,
|
||||||
'home': user.get_home(),
|
'home': user.get_home(),
|
||||||
'base_home': user.get_base_home(),
|
'base_home': user.get_base_home(),
|
||||||
|
'mainuser_home': user.main.get_home(),
|
||||||
}
|
}
|
||||||
context['deleted_home'] = settings.SYSTEMUSERS_MOVE_ON_DELETE_PATH % context
|
context['deleted_home'] = settings.SYSTEMUSERS_MOVE_ON_DELETE_PATH % context
|
||||||
return replace(context, "'", '"')
|
return replace(context, "'", '"')
|
||||||
|
|
|
@ -4,12 +4,11 @@ from django import forms
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.utils.translation import ngettext, ugettext_lazy as _
|
from django.utils.translation import ngettext, ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.contrib.orchestration import Operation
|
|
||||||
from orchestra.forms import UserCreationForm, UserChangeForm
|
from orchestra.forms import UserCreationForm, UserChangeForm
|
||||||
|
|
||||||
from . import settings
|
from . import settings
|
||||||
from .models import SystemUser
|
from .models import SystemUser
|
||||||
from .validators import validate_home
|
from .validators import validate_home, validate_path_exists
|
||||||
|
|
||||||
|
|
||||||
class SystemUserFormMixin(object):
|
class SystemUserFormMixin(object):
|
||||||
|
@ -66,11 +65,13 @@ class SystemUserFormMixin(object):
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
super(SystemUserFormMixin, self).clean()
|
super(SystemUserFormMixin, self).clean()
|
||||||
home = self.cleaned_data.get('home')
|
cleaned_data = self.cleaned_data
|
||||||
|
home = cleaned_data.get('home')
|
||||||
if home and self.MOCK_USERNAME in home:
|
if home and self.MOCK_USERNAME in home:
|
||||||
username = self.cleaned_data.get('username', '')
|
username = cleaned_data.get('username', '')
|
||||||
self.cleaned_data['home'] = home.replace(self.MOCK_USERNAME, username)
|
cleaned_data['home'] = home.replace(self.MOCK_USERNAME, username)
|
||||||
validate_home(self.instance, self.cleaned_data, self.account)
|
validate_home(self.instance, cleaned_data, self.account)
|
||||||
|
return cleaned_data
|
||||||
|
|
||||||
|
|
||||||
class SystemUserCreationForm(SystemUserFormMixin, UserCreationForm):
|
class SystemUserCreationForm(SystemUserFormMixin, UserCreationForm):
|
||||||
|
@ -111,14 +112,11 @@ class PermissionForm(forms.Form):
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
cleaned_data = super(PermissionForm, self).clean()
|
cleaned_data = super(PermissionForm, self).clean()
|
||||||
user = self.instance
|
path = os.path.join(cleaned_data['base_home'], cleaned_data['home_extension'])
|
||||||
user.set_perm_action = cleaned_data['set_action']
|
try:
|
||||||
user.set_perm_base_home = cleaned_data['base_home']
|
validate_path_exists(self.instance, path)
|
||||||
user.set_perm_home_extension = cleaned_data['home_extension']
|
except ValidationError as err:
|
||||||
user.set_perm_perms = cleaned_data['permissions']
|
|
||||||
log = Operation.execute_action(user, 'validate_path')[0]
|
|
||||||
if 'path does not exists' in log.stderr:
|
|
||||||
raise ValidationError({
|
raise ValidationError({
|
||||||
'home_extension': log.stderr,
|
'home_extension': err,
|
||||||
})
|
})
|
||||||
return cleaned_data
|
return cleaned_data
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import fnmatch
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from django.contrib.auth.hashers import make_password
|
from django.contrib.auth.hashers import make_password
|
||||||
|
@ -64,6 +65,10 @@ class SystemUser(models.Model):
|
||||||
return self.account.main_systemuser_id == self.pk
|
return self.account.main_systemuser_id == self.pk
|
||||||
return self.account.username == self.username
|
return self.account.username == self.username
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def main(self):
|
||||||
|
return self.account.main_systemuser
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def has_shell(self):
|
def has_shell(self):
|
||||||
return self.shell not in settings.SYSTEMUSERS_DISABLED_SHELLS
|
return self.shell not in settings.SYSTEMUSERS_DISABLED_SHELLS
|
||||||
|
@ -84,16 +89,20 @@ class SystemUser(models.Model):
|
||||||
if self.home:
|
if self.home:
|
||||||
self.home = os.path.normpath(self.home)
|
self.home = os.path.normpath(self.home)
|
||||||
if self.directory:
|
if self.directory:
|
||||||
directory_error = None
|
self.directory = os.path.normpath(self.directory)
|
||||||
|
dir_errors = []
|
||||||
if self.has_shell:
|
if self.has_shell:
|
||||||
directory_error = _("Directory with shell users can not be specified.")
|
dir_errors.append(_("Directory with shell users can not be specified."))
|
||||||
elif self.account_id and self.is_main:
|
elif self.account_id and self.is_main:
|
||||||
directory_error = _("Directory with main system users can not be specified.")
|
dir_errors.append(_("Directory with main system users can not be specified."))
|
||||||
elif self.home == self.get_base_home():
|
elif self.home == self.get_base_home():
|
||||||
directory_error = _("Directory on the user's base home is not allowed.")
|
dir_errors.append(_("Directory on the user's base home is not allowed."))
|
||||||
if directory_error:
|
for pattern in settings.SYSTEMUSERS_FORBIDDEN_PATHS:
|
||||||
|
if fnmatch.fnmatch(self.directory, pattern):
|
||||||
|
dir_errors.append(_("Provided directory is forbidden."))
|
||||||
|
if dir_errors:
|
||||||
raise ValidationError({
|
raise ValidationError({
|
||||||
'directory': directory_error,
|
'directory': [ValidationError(error) for error in dir_errors]
|
||||||
})
|
})
|
||||||
if self.has_shell and self.home and self.home != self.get_base_home():
|
if self.has_shell and self.home and self.home != self.get_base_home():
|
||||||
raise ValidationError({
|
raise ValidationError({
|
||||||
|
|
|
@ -60,8 +60,8 @@ SYSTEMUSERS_MOVE_ON_DELETE_PATH = Setting('SYSTEMUSERS_MOVE_ON_DELETE_PATH',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
SYSTEMUSERS_EXLUDE_ACL_PATHS = Setting('SYSTEMUSERS_EXLUDE_ACL_PATHS',
|
SYSTEMUSERS_FORBIDDEN_PATHS = Setting('SYSTEMUSERS_FORBIDDEN_PATHS',
|
||||||
(),
|
(),
|
||||||
help_text=("Exlude ACL operations on provided globs, relative to user's home.<br>"
|
help_text=("Exlude ACL operations or home locations on provided globs, relative to user's home.<br>"
|
||||||
"e.g. ('logs', 'logs/apache*', 'webapps')"),
|
"e.g. ('logs', 'logs/apache*', 'webapps')"),
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
{% extends "admin/base_site.html" %}
|
||||||
|
{% load i18n l10n %}
|
||||||
|
{% load url from future %}
|
||||||
|
{% load admin_urls static utils %}
|
||||||
|
|
||||||
|
{% block extrastyle %}
|
||||||
|
{{ block.super }}
|
||||||
|
<link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="{% static "orchestra/css/hide-inline-id.css" %}" />
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block breadcrumbs %}
|
||||||
|
<div class="breadcrumbs">
|
||||||
|
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
|
||||||
|
› <a href="{% url 'admin:app_list' app_label=app_label %}">{{ app_label|capfirst|escape }}</a>
|
||||||
|
› <a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a>
|
||||||
|
{% if obj %}
|
||||||
|
› <a href="{% url opts|admin_urlname:'change' obj.pk %}">{{ obj }}</a>
|
||||||
|
› {{ action_name }}
|
||||||
|
{% elif add %}
|
||||||
|
› <a href="../">{% trans "Add" %} {{ opts.verbose_name }}</a>
|
||||||
|
› {{ action_name }}
|
||||||
|
{% else %}
|
||||||
|
› {{ action_name }} multiple objects
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div>
|
||||||
|
<div style="margin:20px;">
|
||||||
|
Set permissions for {% for user in queryset %}{{ user.username }}{% if not forloop.last %}, {% endif %}{% endfor %} system user(s).
|
||||||
|
<ul>{{ display_objects | unordered_list }}</ul>
|
||||||
|
<form action="" method="post">{% csrf_token %}
|
||||||
|
<fieldset class="module aligned wide">
|
||||||
|
{{ form.non_field_errors }}
|
||||||
|
<div class="form-row ">
|
||||||
|
{{ form.set_action.errors }}
|
||||||
|
<label for="{{ form.set_action.id_for_label }}">{{ form.set_action.label }}:</label>
|
||||||
|
{{ form.set_action }}{% for x in ""|ljust:"50" %} {% endfor %}
|
||||||
|
<p class="help">{{ form.set_action.help_text|safe }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-row ">
|
||||||
|
<div class="field-box field-base_home">
|
||||||
|
{{ form.base_home.errors }}
|
||||||
|
<label for="{{ form.base_home.id_for_label }}">{{ form.base_home.label }}:</label>
|
||||||
|
{{ form.base_home }}{% for x in ""|ljust:"50" %} {% endfor %}
|
||||||
|
<p class="help">{{ form.base_home.help_text|safe }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="field-box field-user_extension">
|
||||||
|
{{ form.home_extension.errors }}
|
||||||
|
<label for="{{ form.home_extension.id_for_label }}"></label>
|
||||||
|
{{ form.home_extension }}
|
||||||
|
<p class="help">{{ form.home_extension.help_text|safe }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row ">
|
||||||
|
{{ form.permissions.errors }}
|
||||||
|
<label for="{{ form.base_path.id_for_label }}">{{ form.permissions.label }}:</label>
|
||||||
|
{{ form.permissions }}{% for x in ""|ljust:"50" %} {% endfor %}
|
||||||
|
<p class="help">{{ form.permissions.help_text|safe }}</p>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
<div>
|
||||||
|
{% for obj in queryset %}
|
||||||
|
<input type="hidden" name="{{ action_checkbox_name }}" value="{{ obj.pk|unlocalize }}" />
|
||||||
|
{% endfor %}
|
||||||
|
<input type="hidden" name="action" value="{{ action_value }}" />
|
||||||
|
<input type="hidden" name="post" value="{{ post_value|default:'generic_confirmation' }}" />
|
||||||
|
<input type="submit" value="{{ submit_value|default:_("Save") }}" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -2,6 +2,15 @@ import os
|
||||||
|
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
|
||||||
|
from orchestra.contrib.orchestration import Operation
|
||||||
|
|
||||||
|
|
||||||
|
def validate_path_exists(user, path, ):
|
||||||
|
user.path_to_validate = path
|
||||||
|
log = Operation.execute_action(user, 'validate_path_exists')[0]
|
||||||
|
if 'path does not exists' in log.stderr:
|
||||||
|
raise ValidationError(log.stderr)
|
||||||
|
|
||||||
|
|
||||||
def validate_home(user, data, account):
|
def validate_home(user, data, account):
|
||||||
""" validates home based on account and data['shell'] """
|
""" validates home based on account and data['shell'] """
|
||||||
|
@ -25,3 +34,11 @@ def validate_home(user, data, account):
|
||||||
raise ValidationError({
|
raise ValidationError({
|
||||||
'home': _("Not a valid home directory.")
|
'home': _("Not a valid home directory.")
|
||||||
})
|
})
|
||||||
|
if 'directory' in data and data['directory']:
|
||||||
|
path = os.path.join(data['home'], data['directory'])
|
||||||
|
try:
|
||||||
|
validate_path_exists(user, path)
|
||||||
|
except ValidationError as err:
|
||||||
|
raise ValidationError({
|
||||||
|
'directory': err,
|
||||||
|
})
|
||||||
|
|
|
@ -29,14 +29,13 @@ class WebAppServiceMixin(object):
|
||||||
if context['under_construction_path']:
|
if context['under_construction_path']:
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
if [[ $CREATED == 1 && ! $(ls -A %(app_path)s) ]]; then
|
if [[ $CREATED == 1 && ! $(ls -A %(app_path)s) ]]; then
|
||||||
{
|
# Async wait for other backends to do their thing or cp under construction
|
||||||
# Wait for other backends to do their thing or cp under construction
|
nohup bash -c '
|
||||||
sleep 10
|
sleep 10
|
||||||
if [[ ! $(ls -A %(app_path)s) ]]; then
|
if [[ ! $(ls -A %(app_path)s) ]]; then
|
||||||
cp -r %(under_construction_path)s %(app_path)s
|
cp -r %(under_construction_path)s %(app_path)s
|
||||||
chown -R %(user)s:%(group)s %(app_path)s
|
chown -R %(user)s:%(group)s %(app_path)s
|
||||||
fi
|
fi' &> /dev/null &
|
||||||
} &
|
|
||||||
fi""") % context
|
fi""") % context
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -127,6 +127,9 @@ class PHPBackend(WebAppServiceMixin, ServiceController):
|
||||||
mv /dev/shm/restart.apache2 /dev/shm/restart.apache2.locked
|
mv /dev/shm/restart.apache2 /dev/shm/restart.apache2.locked
|
||||||
}
|
}
|
||||||
state="$(grep -v "$backend" /dev/shm/restart.apache2.locked)" || is_last=1
|
state="$(grep -v "$backend" /dev/shm/restart.apache2.locked)" || is_last=1
|
||||||
|
[[ $is_last -eq 0 ]] && {
|
||||||
|
echo "$state" | grep -v ' RESTART$' || is_last=1
|
||||||
|
}
|
||||||
if [[ $is_last -eq 1 ]]; then
|
if [[ $is_last -eq 1 ]]; then
|
||||||
if [[ $UPDATED_APACHE -eq 1 || "$state" =~ .*RESTART$ ]]; then
|
if [[ $UPDATED_APACHE -eq 1 || "$state" =~ .*RESTART$ ]]; then
|
||||||
service apache2 status && service apache2 reload || service apache2 start
|
service apache2 status && service apache2 reload || service apache2 start
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import os
|
||||||
import textwrap
|
import textwrap
|
||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
@ -41,11 +42,19 @@ class WordPressBackend(WebAppServiceMixin, ServiceController):
|
||||||
if (count(glob("%(app_path)s/*")) > 1) {
|
if (count(glob("%(app_path)s/*")) > 1) {
|
||||||
die("App directory not empty.");
|
die("App directory not empty.");
|
||||||
}
|
}
|
||||||
exc('mkdir -p %(app_path)s');
|
shell_exec("mkdir -p %(app_path)s
|
||||||
exc('rm -f %(app_path)s/index.html');
|
rm -f %(app_path)s/index.html
|
||||||
exc('wget http://wordpress.org/latest.tar.gz -O - --no-check-certificate | tar -xzvf - -C %(app_path)s --strip-components=1');
|
filename=\\$(wget https://wordpress.org/latest.tar.gz --server-response --spider --no-check-certificate 2>&1 | grep filename | cut -d'=' -f2)
|
||||||
exc('mkdir %(app_path)s/wp-content/uploads');
|
mkdir -p %(cms_cache_dir)s
|
||||||
exc('chmod 750 %(app_path)s/wp-content/uploads');
|
if [ \\$(basename \\$(readlink %(cms_cache_dir)s/wordpress) 2> /dev/null ) != \\$filename ]; then
|
||||||
|
wget https://wordpress.org/latest.tar.gz -O - --no-check-certificate | tee %(cms_cache_dir)s/\\$filename | tar -xzvf - -C %(app_path)s --strip-components=1
|
||||||
|
rm -f %(cms_cache_dir)s/wordpress
|
||||||
|
ln -s %(cms_cache_dir)s/\\$filename %(cms_cache_dir)s/wordpress
|
||||||
|
else
|
||||||
|
tar -xzvf %(cms_cache_dir)s/wordpress -C %(app_path)s --strip-components=1
|
||||||
|
fi
|
||||||
|
mkdir %(app_path)s/wp-content/uploads
|
||||||
|
chmod 750 %(app_path)s/wp-content/uploads");
|
||||||
|
|
||||||
$config_file = file('%(app_path)s/' . 'wp-config-sample.php');
|
$config_file = file('%(app_path)s/' . 'wp-config-sample.php');
|
||||||
$secret_keys = file_get_contents('https://api.wordpress.org/secret-key/1.1/salt/');
|
$secret_keys = file_get_contents('https://api.wordpress.org/secret-key/1.1/salt/');
|
||||||
|
@ -124,5 +133,6 @@ class WordPressBackend(WebAppServiceMixin, ServiceController):
|
||||||
'db_host': settings.WEBAPPS_DEFAULT_MYSQL_DATABASE_HOST,
|
'db_host': settings.WEBAPPS_DEFAULT_MYSQL_DATABASE_HOST,
|
||||||
'email': webapp.account.email,
|
'email': webapp.account.email,
|
||||||
'title': "%s blog's" % webapp.account.get_full_name(),
|
'title': "%s blog's" % webapp.account.get_full_name(),
|
||||||
|
'cms_cache_dir': os.path.normpath(settings.WEBAPPS_CMS_CACHE_DIR)
|
||||||
})
|
})
|
||||||
return replace(context, '"', "'")
|
return replace(context, '"', "'")
|
||||||
|
|
|
@ -261,3 +261,10 @@ WEBAPPS_DEFAULT_MYSQL_DATABASE_HOST = Setting('WEBAPPS_DEFAULT_MYSQL_DATABASE_HO
|
||||||
WEBAPPS_MOVE_ON_DELETE_PATH = Setting('WEBAPPS_MOVE_ON_DELETE_PATH',
|
WEBAPPS_MOVE_ON_DELETE_PATH = Setting('WEBAPPS_MOVE_ON_DELETE_PATH',
|
||||||
''
|
''
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
WEBAPPS_CMS_CACHE_DIR = Setting('WEBAPPS_CMS_CACHE_DIR',
|
||||||
|
'/tmp/orchestra_cms_cache',
|
||||||
|
help_text="Server-side cache directori for CMS tarballs.",
|
||||||
|
)
|
||||||
|
|
|
@ -148,6 +148,9 @@ class Apache2Backend(ServiceController):
|
||||||
mv /dev/shm/restart.apache2 /dev/shm/restart.apache2.locked
|
mv /dev/shm/restart.apache2 /dev/shm/restart.apache2.locked
|
||||||
}
|
}
|
||||||
state="$(grep -v "$backend" /dev/shm/restart.apache2.locked)" || is_last=1
|
state="$(grep -v "$backend" /dev/shm/restart.apache2.locked)" || is_last=1
|
||||||
|
[[ $is_last -eq 0 ]] && {
|
||||||
|
echo "$state" | grep -v ' RESTART$' || is_last=1
|
||||||
|
}
|
||||||
if [[ $is_last -eq 1 ]]; then
|
if [[ $is_last -eq 1 ]]; then
|
||||||
if [[ $UPDATED_APACHE -eq 1 || "$state" =~ .*RESTART$ ]]; then
|
if [[ $UPDATED_APACHE -eq 1 || "$state" =~ .*RESTART$ ]]; then
|
||||||
service apache2 status && service apache2 reload || service apache2 start
|
service apache2 status && service apache2 reload || service apache2 start
|
||||||
|
|
Loading…
Reference in New Issue