From d6925abd728036f076c8fba036a4a6c76d0509d7 Mon Sep 17 00:00:00 2001 From: Marc Aymerich Date: Mon, 21 Sep 2015 13:57:15 +0000 Subject: [PATCH] Improved VPS backend --- TODO.md | 6 --- orchestra/admin/options.py | 45 +++++++++------- orchestra/contrib/saas/services/wordpress.py | 1 + orchestra/contrib/vps/admin.py | 12 ++--- orchestra/contrib/vps/backends.py | 53 +++++++++++++------ orchestra/contrib/vps/settings.py | 5 ++ .../admin/orchestra/change_password.html | 2 +- 7 files changed, 74 insertions(+), 50 deletions(-) diff --git a/TODO.md b/TODO.md index 2d72feaf..f0854829 100644 --- a/TODO.md +++ b/TODO.md @@ -124,16 +124,12 @@ require_once(‘/etc/moodles/’.$moodle_host.‘config.php’);``` moodle/drupl * make account available on all admin forms -# WPMU blog traffic - * more robust backend error handling, continue executing but exit code > 0 if failure: failing_cmd || exit_code=1 and don't forget to call super.commit()!! * website directives uniquenes validation on serializers + is_Active custom filter with support for instance.account.is_Active annotate with F() needed (django 1.8) -# delete apache logs and php logs - * document service help things: discount/refound/compensation effect and metric table * Document metric interpretation help_text * document plugin serialization, data_serializer? @@ -385,8 +381,6 @@ Case # Mailer: mark as sent -# Implement wordpressmu change password or remove password from the form - # Deprecate orchestra start/stop/restart services management commands? # Enable/disable ignore period orders list filter diff --git a/orchestra/admin/options.py b/orchestra/admin/options.py index 273e6915..1006b657 100644 --- a/orchestra/admin/options.py +++ b/orchestra/admin/options.py @@ -236,45 +236,50 @@ class ChangePasswordAdminMixin(object): name='%s_%s_change_password' % info) ] + super(ChangePasswordAdminMixin, self).get_urls() + def get_change_password_username(self, obj): + return str(obj) + @sensitive_post_parameters_m def change_password(self, request, id, form_url=''): if not self.has_change_permission(request): raise PermissionDenied # TODO use this insetad of self.get_object(), in other places - user = get_object_or_404(self.get_queryset(request), pk=id) + obj = get_object_or_404(self.get_queryset(request), pk=id) related = [] - try: - # don't know why getattr(user, 'username', user.name) doesn't work - username = user.username - except AttributeError: - username = user.name - if hasattr(user, 'account'): - account = user.account - if user.account.username == username: - related.append(user.account) + for obj_name_attr in ('username', 'name', 'hostname'): + try: + obj_name = getattr(obj, obj_name_attr) + except AttributeError: + pass + else: + break + if hasattr(obj, 'account'): + account = obj.account + if obj.account.username == obj_name: + related.append(obj.account) else: - account = user - if account.username == username: + account = obj + if account.username == obj_name: for rel in account.get_related_passwords(): - if not isinstance(user, type(rel)): + if not isinstance(obj, type(rel)): related.append(rel) if request.method == 'POST': - form = self.change_password_form(user, request.POST, related=related) + form = self.change_password_form(obj, request.POST, related=related) if form.is_valid(): form.save() change_message = self.construct_change_message(request, form, None) - self.log_change(request, user, change_message) + self.log_change(request, obj, change_message) msg = _('Password changed successfully.') messages.success(request, msg) update_session_auth_hash(request, form.user) # This is safe return HttpResponseRedirect('..') else: - form = self.change_password_form(user, related=related) + form = self.change_password_form(obj, related=related) fieldsets = [ - (user._meta.verbose_name.capitalize(), { + (obj._meta.verbose_name.capitalize(), { 'classes': ('wide',), 'fields': ('password1', 'password2') }), @@ -285,9 +290,10 @@ class ChangePasswordAdminMixin(object): 'fields': ('password1_%i' % ix, 'password2_%i' % ix) })) + obj_username = self.get_change_password_username(obj) adminForm = admin.helpers.AdminForm(form, fieldsets, {}) context = { - 'title': _('Change password: %s') % escape(username), + 'title': _('Change password: %s') % obj_username, 'adminform': adminForm, 'errors': admin.helpers.AdminErrorList(form, []), 'form_url': form_url, @@ -299,7 +305,8 @@ class ChangePasswordAdminMixin(object): 'has_change_permission': True, 'has_absolute_url': False, 'opts': self.model._meta, - 'original': user, + 'original': obj, + 'obj_username': obj_username, 'save_as': False, 'show_save': True, 'password': random_ascii(10), diff --git a/orchestra/contrib/saas/services/wordpress.py b/orchestra/contrib/saas/services/wordpress.py index 021ec464..b2dd0ff5 100644 --- a/orchestra/contrib/saas/services/wordpress.py +++ b/orchestra/contrib/saas/services/wordpress.py @@ -19,6 +19,7 @@ class WordPressForm(SaaSBaseForm): help_text = 'Admin URL: {0}'.format(admin_url) self.fields['site_url'].help_text = mark_safe(help_text) + class WordPressDataSerializer(serializers.Serializer): email = serializers.EmailField(label=_("Email")) diff --git a/orchestra/contrib/vps/admin.py b/orchestra/contrib/vps/admin.py index 14624ba0..eca1ca35 100644 --- a/orchestra/contrib/vps/admin.py +++ b/orchestra/contrib/vps/admin.py @@ -3,7 +3,7 @@ from django.contrib import admin from django.contrib.auth.admin import UserAdmin from django.utils.translation import ugettext_lazy as _ -from orchestra.admin import ExtendedModelAdmin +from orchestra.admin import ExtendedModelAdmin, ChangePasswordAdminMixin from orchestra.contrib.accounts.actions import list_accounts from orchestra.contrib.accounts.admin import AccountAdminMixin from orchestra.forms import UserCreationForm, NonStoredUserChangeForm @@ -11,7 +11,7 @@ from orchestra.forms import UserCreationForm, NonStoredUserChangeForm from .models import VPS -class VPSAdmin(AccountAdminMixin, ExtendedModelAdmin): +class VPSAdmin(ChangePasswordAdminMixin, AccountAdminMixin, ExtendedModelAdmin): list_display = ('hostname', 'type', 'template', 'account_link') list_filter = ('type', 'template') form = NonStoredUserChangeForm @@ -40,12 +40,8 @@ class VPSAdmin(AccountAdminMixin, ExtendedModelAdmin): ) actions = (list_accounts,) - def get_urls(self): - useradmin = UserAdmin(VPS, self.admin_site) - return [ - url(r'^(\d+)/password/$', - self.admin_site.admin_view(useradmin.user_change_password)) - ] + super(VPSAdmin, self).get_urls() + def get_change_password_username(self, obj): + return 'root@%s' % obj.hostname admin.site.register(VPS, VPSAdmin) diff --git a/orchestra/contrib/vps/backends.py b/orchestra/contrib/vps/backends.py index f4fed982..ed8a1c2c 100644 --- a/orchestra/contrib/vps/backends.py +++ b/orchestra/contrib/vps/backends.py @@ -4,6 +4,8 @@ import textwrap from orchestra.contrib.orchestration import ServiceController from orchestra.contrib.resources import ServiceMonitor +from . import settings + class ProxmoxOVZ(ServiceController): model = 'vps.VPS' @@ -34,39 +36,58 @@ class ProxmoxOVZ(ServiceController): super(ProxmoxOVZ, self).prepare() self.append(self.GET_PROXMOX_INFO) - def get_vzset_args(self, vps): - args = [] + def get_vzset_args(self, context): + args = list(settings.VPS_DEFAULT_VZSET_ARGS) for resource, arg_name in self.RESOURCES: try: - allocation = getattr(vps.resources, resource).allocated - except AttributeError: + allocation = context[resource] + except KeyError: pass else: args.append('--%s %i' % (arg_name, allocation)) return ' '.join(args) + def run_ssh_commands(self, ssh_commands): + commands = '\n '.join(ssh_commands) + self.append(textwrap.dedent("""\ + cat << EOF | ssh root@${info[1]} + %s + EOF""") % commands + ) + def save(self, vps): + # TODO create the container context = self.get_context(vps) - self.append('info=( $(get_vz_info %(hostname)s) )' % context) - vzset_args = self.get_vzset_args(vps) + self.append(textwrap.dedent(""" + info=( $(get_vz_info %(hostname)s) ) + echo "Managing ${info[@]}"\ + """) % context + ) + ssh_commands = [] + vzset_args = self.get_vzset_args(context) if vzset_args: context['vzset_args'] = vzset_args - self.append(textwrap.dedent("""\ - cat << EOF | ssh root@${info[1]} - pvectl vzset ${info[0]} %(vzset_args)s - EOF""") % context - ) + ssh_commands.append("pvectl vzset ${info[0]} %(vzset_args)s" % context) if hasattr(vps, 'password'): context['password'] = vps.password.replace('$', '\\$') - self.append(textwrap.dedent("""\ - cat << EOF | ssh root@${info[1]} - echo 'root:%(password)s' | vzctl exec ${info[0]} chpasswd -e - EOF""") % context + ssh_commands.append(textwrap.dedent("""\ + echo 'root:%(password)s' \\ + | chroot /var/lib/vz/private/${info[0]} chpasswd -e""") % context ) + self.run_ssh_commands(ssh_commands) + def get_context(self, vps): - return { + context = { 'hostname': vps.hostname, } + for resource, __ in self.RESOURCES: + try: + allocation = getattr(vps.resources, resource).allocated + except AttributeError: + pass + else: + context[resource] = allocation + return context # TODO rename to proxmox diff --git a/orchestra/contrib/vps/settings.py b/orchestra/contrib/vps/settings.py index 2466ff0d..5e65fe34 100644 --- a/orchestra/contrib/vps/settings.py +++ b/orchestra/contrib/vps/settings.py @@ -27,3 +27,8 @@ VPS_DEFAULT_TEMPLATE = Setting('VPS_DEFAULT_TEMPLATE', 'debian7', choices=VPS_TEMPLATES ) + + +VPS_DEFAULT_VZSET_ARGS = Setting('VPS_DEFAULT_VZSET_ARGS', + ('--onboot yes',), +) diff --git a/orchestra/templates/admin/orchestra/change_password.html b/orchestra/templates/admin/orchestra/change_password.html index b35c8f9a..58e3618f 100644 --- a/orchestra/templates/admin/orchestra/change_password.html +++ b/orchestra/templates/admin/orchestra/change_password.html @@ -8,7 +8,7 @@
{% if is_popup %}{% endif %} {% if to_field %}{% endif %} -

{% blocktrans with username=original %}Enter a new password for the user {{ username }}, suggestion '{{ password }}'.{% endblocktrans %}

+

{% blocktrans with username=obj_username %}Enter a new password for the user {{ username }}, suggestion '{{ password }}'.{% endblocktrans %}

{% if errors %}