django-orchestra/orchestra/contrib/orchestration/__init__.py

91 lines
2.9 KiB
Python
Raw Permalink Normal View History

import collections
2015-04-07 15:14:49 +00:00
import copy
from orchestra.utils.python import AttrDict
2015-04-05 18:02:36 +00:00
from .backends import ServiceBackend, ServiceController, replace
2015-04-07 15:14:49 +00:00
2015-04-07 15:14:49 +00:00
class Operation():
DELETE = 'delete'
SAVE = 'save'
MONITOR = 'monitor'
EXCEEDED = 'exceeded'
RECOVERY = 'recovery'
2015-04-07 15:14:49 +00:00
def __str__(self):
return '%s.%s(%s)' % (self.backend, self.action, self.instance)
2015-06-15 11:21:33 +00:00
def __repr__(self):
return str(self)
2015-04-07 15:14:49 +00:00
def __hash__(self):
""" set() """
2015-07-08 10:21:19 +00:00
return hash((self.backend, self.instance, self.action))
2015-04-07 15:14:49 +00:00
def __eq__(self, operation):
""" set() """
return hash(self) == hash(operation)
2015-05-06 15:32:22 +00:00
def __init__(self, backend, instance, action, routes=None):
2015-04-07 15:14:49 +00:00
self.backend = backend
# instance should maintain any dynamic attribute until backend execution
# deep copy is prefered over copy otherwise objects will share same atributes (queryset cache)
self.instance = copy.deepcopy(instance)
self.action = action
2015-05-06 15:32:22 +00:00
self.routes = routes
2015-04-07 15:14:49 +00:00
@classmethod
def execute(cls, operations, serialize=False, run_async=None):
2015-04-07 15:14:49 +00:00
from . import manager
scripts, backend_serialize = manager.generate(operations)
return manager.execute(scripts, serialize=(serialize or backend_serialize), run_async=run_async)
2015-04-07 15:14:49 +00:00
@classmethod
def create_for_action(cls, instances, action):
if not isinstance(instances, collections.Iterable):
instances = [instances]
operations = []
for instance in instances:
backends = ServiceBackend.get_backends(instance=instance, action=action)
for backend_cls in backends:
operations.append(
cls(backend_cls, instance, action)
)
return operations
@classmethod
def execute_action(cls, instances, action):
""" instances can be an object or an iterable for batch processing """
operations = cls.create_for_action(instances, action)
2015-04-07 15:14:49 +00:00
return cls.execute(operations)
2015-04-07 15:14:49 +00:00
def preload_context(self):
"""
Heuristic: Running get_context will prevent most of related objects do not exist errors
2015-04-07 15:14:49 +00:00
"""
if self.action == self.DELETE:
if hasattr(self.backend, 'get_context'):
self.backend().get_context(self.instance)
2015-04-09 14:32:10 +00:00
def store(self, log):
2015-04-07 15:14:49 +00:00
from .models import BackendOperation
return BackendOperation.objects.create(
log=log,
backend=self.backend.get_name(),
instance=self.instance,
action=self.action,
)
@classmethod
def load(cls, operation, log=None):
routes = None
if log:
routes = {
(operation.backend, operation.action): AttrDict(host=log.server)
}
return cls(operation.backend_class, operation.instance, operation.action, routes=routes)