django-orchestra/orchestra/apps/orchestration/backends.py

132 lines
3.8 KiB
Python
Raw Normal View History

2014-05-08 16:59:35 +00:00
from functools import partial
2014-11-14 16:12:56 +00:00
from django.db.models.loading import get_model
2014-07-11 14:48:46 +00:00
from django.utils import timezone
2014-10-11 16:21:51 +00:00
from django.utils.translation import ugettext_lazy as _
2014-05-08 16:59:35 +00:00
2014-11-12 16:33:40 +00:00
from orchestra.apps import plugins
2014-05-08 16:59:35 +00:00
from . import methods
2014-07-21 12:20:04 +00:00
class ServiceBackend(plugins.Plugin):
2014-05-08 16:59:35 +00:00
"""
Service management backend base class
It uses the _unit of work_ design principle, which allows bulk operations to
be conviniently supported. Each backend generates the configuration for all
the changes of all modified objects, reloading the daemon just once.
"""
model = None
related_models = () # ((model, accessor__attribute),)
script_method = methods.BashSSH
function_method = methods.Python
type = 'task' # 'sync'
ignore_fields = []
2014-07-09 16:17:43 +00:00
actions = []
2014-05-08 16:59:35 +00:00
# TODO type: 'script', execution:'task'
__metaclass__ = plugins.PluginMount
def __unicode__(self):
return type(self).__name__
2014-07-14 14:56:48 +00:00
2014-05-08 16:59:35 +00:00
def __str__(self):
return unicode(self)
def __init__(self):
self.cmds = []
2014-07-09 16:17:43 +00:00
@classmethod
def get_actions(cls):
return [ action for action in cls.actions if action in dir(cls) ]
2014-05-08 16:59:35 +00:00
@classmethod
def get_name(cls):
return cls.__name__
@classmethod
def is_main(cls, obj):
opts = obj._meta
return cls.model == '%s.%s' % (opts.app_label, opts.object_name)
@classmethod
def get_related(cls, obj):
opts = obj._meta
model = '%s.%s' % (opts.app_label, opts.object_name)
for rel_model, field in cls.related_models:
if rel_model == model:
related = obj
for attribute in field.split('__'):
related = getattr(related, attribute)
return related
return None
@classmethod
def get_backends(cls):
2014-07-21 12:20:04 +00:00
return cls.get_plugins()
2014-05-08 16:59:35 +00:00
2014-07-10 10:03:22 +00:00
@classmethod
def get_backend(cls, name):
2014-07-21 12:20:04 +00:00
return cls.get_plugin(name)
2014-05-08 16:59:35 +00:00
2014-11-14 16:12:56 +00:00
@classmethod
def model_class(cls):
return get_model(cls.model)
2014-05-08 16:59:35 +00:00
def get_banner(self):
2014-07-11 14:48:46 +00:00
time = timezone.now().strftime("%h %d, %Y %I:%M:%S")
2014-10-04 09:29:18 +00:00
return "Generated by Orchestra at %s" % time
2014-05-08 16:59:35 +00:00
def execute(self, server):
from .models import BackendLog
state = BackendLog.STARTED if self.cmds else BackendLog.SUCCESS
log = BackendLog.objects.create(backend=self.get_name(), state=state, server=server)
for method, cmds in self.cmds:
method(log, server, cmds)
if log.state != BackendLog.SUCCESS:
break
return log
def append(self, *cmd):
# aggregate commands acording to its execution method
if isinstance(cmd[0], basestring):
method = self.script_method
cmd = cmd[0]
else:
method = self.function_method
cmd = partial(*cmd)
if not self.cmds or self.cmds[-1][0] != method:
self.cmds.append((method, [cmd]))
else:
self.cmds[-1][1].append(cmd)
2014-07-25 15:17:50 +00:00
def prepare(self):
""" hook for executing something at the beging """
pass
2014-05-08 16:59:35 +00:00
def commit(self):
"""
apply the configuration, usually reloading a service
reloading a service is done in a separated method in order to reload
the service once in bulk operations
"""
pass
2014-07-09 16:17:43 +00:00
class ServiceController(ServiceBackend):
actions = ('save', 'delete')
2014-10-11 16:21:51 +00:00
abstract = True
@classmethod
def get_verbose_name(cls):
return _("[S] %s") % super(ServiceController, cls).get_verbose_name()
2014-07-09 16:17:43 +00:00
@classmethod
def get_backends(cls):
""" filter controller classes """
2014-07-16 15:20:16 +00:00
return [
plugin for plugin in cls.plugins if ServiceController in plugin.__mro__
]