Initial implementation of backend arbitrary action execution

This commit is contained in:
Marc Aymerich 2014-11-14 16:52:54 +00:00
parent a58ebbd40a
commit b93be150c2
6 changed files with 41 additions and 12 deletions

View file

@ -64,8 +64,24 @@ class ServiceBackend(plugins.Plugin):
return None
@classmethod
def get_backends(cls):
return cls.get_plugins()
def get_backends(cls, instance=None, action=None):
backends = cls.get_plugins()
included = []
# Filter for instance or action
if instance or action:
for backend in backends:
include = True
if instance:
opts = instance._meta
if backend.model != '.'.join((opts.app_label, opts.object_name)):
include = False
if include and action:
if action not in backend.get_actions():
include = False
if include:
included.append(backend)
backends = included
return backends
@classmethod
def get_backend(cls, name):
@ -126,6 +142,7 @@ class ServiceController(ServiceBackend):
@classmethod
def get_backends(cls):
""" filter controller classes """
backends = super(ServiceController, cls).get_backends()
return [
plugin for plugin in cls.plugins if ServiceController in plugin.__mro__
backend for backend in backends if ServiceController in backend.__mro__
]

View file

@ -19,8 +19,6 @@ transports = {}
def BashSSH(backend, log, server, cmds):
from .models import BackendLog
script = '\n'.join(['set -e', 'set -o pipefail'] + cmds + ['exit 0'])
script = script.replace('\r', '')
digest = hashlib.md5(script).hexdigest()
@ -48,7 +46,7 @@ def BashSSH(backend, log, server, cmds):
ssh.connect(addr, username='root', key_filename=settings.ORCHESTRATION_SSH_KEY_PATH, timeout=10)
except socket.error:
logger.error('%s timed out on %s' % (backend, server))
log.state = BackendLog.TIMEOUT
log.state = log.TIMEOUT
log.save(update_fields=['state'])
return
transport = ssh.get_transport()
@ -92,11 +90,11 @@ def BashSSH(backend, log, server, cmds):
if channel.exit_status_ready():
break
log.exit_code = exit_code = channel.recv_exit_status()
log.state = BackendLog.SUCCESS if exit_code == 0 else BackendLog.FAILURE
log.state = log.SUCCESS if exit_code == 0 else log.FAILURE
logger.debug('%s execution state on %s is %s' % (backend, server, log.state))
log.save()
except:
log.state = BackendLog.ERROR
log.state = log.ERROR
log.traceback = ExceptionInfo(sys.exc_info()).traceback
logger.error('Exception while executing %s on %s' % (backend, server))
logger.debug(log.traceback)
@ -109,7 +107,6 @@ def BashSSH(backend, log, server, cmds):
def Python(backend, log, server, cmds):
from .models import BackendLog
script = [ str(cmd.func.func_name) + str(cmd.args) for cmd in cmds ]
script = json.dumps(script, indent=4).replace('"', '')
log.script = '\n'.join([log.script, script])
@ -121,10 +118,10 @@ def Python(backend, log, server, cmds):
stdout += str(result)
except:
log.exit_code = 1
log.state = BackendLog.FAILURE
log.state = log.FAILURE
log.traceback = ExceptionInfo(sys.exc_info()).traceback
else:
log.exit_code = 0
log.state = BackendLog.SUCCESS
log.state = log.SUCCESS
log.stdout += stdout
log.save()

View file

@ -50,6 +50,7 @@ class OperationsMiddleware(object):
return
pending_operations = cls.get_pending_operations()
for backend in ServiceBackend.get_backends():
# Check if there exists a related instance to be executed for this backend
instance = None
if backend.is_main(kwargs['instance']):
instance = kwargs['instance']
@ -61,6 +62,7 @@ class OperationsMiddleware(object):
instance = candidate
# related objects with backend.model trigger save()
action = Operation.SAVE
# Maintain consistent state of pending_operations based on save/delete behaviour
if instance is not None:
# Prevent creating a deleted instance by deleting existing saves
if action == Operation.DELETE:

View file

@ -138,6 +138,12 @@ class BackendOperation(models.Model):
def execute(cls, operations):
return manager.execute(operations)
@classmethod
def execute_action(cls, instance, action):
backends = ServiceBackend.get_backends(instance=instance, action=action)
operations = [cls.create(backend, instance, action) for backend in backends]
return cls.execute(operations)
def backend_class(self):
return ServiceBackend.get_backend(self.backend)

View file

@ -10,6 +10,7 @@ from django.utils.translation import ungettext, ugettext_lazy as _
from orchestra.admin.decorators import action_with_confirmation
from orchestra.admin.utils import change_url
from orchestra.apps.orchestration.models import BackendOperation as Operation
class GrantPermissionForm(forms.Form):
@ -22,7 +23,8 @@ class GrantPermissionForm(forms.Form):
@action_with_confirmation(extra_context=dict(form=GrantPermissionForm()))
def grant_permission(modeladmin, request, queryset):
user = queryset.get()
log = Operation.execute_action(user, 'grant_permission')
# TODO
pass
grant_permission.url_name = 'grant-permission'
grant_permission.verbose_name = _("Grant permission")

View file

@ -12,6 +12,7 @@ from . import settings
class SystemUserBackend(ServiceController):
verbose_name = _("System user")
model = 'systemusers.SystemUser'
actions = ('save', 'delete', 'grant_permission')
def save(self, user):
context = self.get_context(user)
@ -40,6 +41,10 @@ class SystemUserBackend(ServiceController):
self.append("groupdel %(username)s || true" % context)
self.delete_home(context, user)
def grant_permission(self, user):
context = self.get_context(user)
# TODO setacl
def delete_home(self, context, user):
if user.is_main:
# TODO delete instead of this shit