Commit 5b527c67 authored by Giorgos Korfiatis's avatar Giorgos Korfiatis
Browse files

Refactoring

parent 9fe916b4
# Import general commission framework
from .api.exception import (CallError,
from .exception import (CallError,
CommissionException,
CorruptedError,
InvalidDataError,
......@@ -11,18 +11,12 @@ from .api.exception import (CallError,
ExportLimitError,
ImportLimitError)
from .api.callpoint import Callpoint, get_callpoint, mkcallargs
from .api.physical import Physical
from .api.controller import Controller, ControlledCallpoint
from .callpoint import Callpoint, get_callpoint, mkcallargs
from .api.specificator import (Specificator, SpecifyException,
from .specificator import (Specificator, SpecifyException,
Canonifier, CanonifyException,
Canonical,
Null, Nothing, Integer, Serial,
Text, Bytes, Tuple, ListOf, Dict, Args)
# Import quota holder API
from .api.quotaholder import QuotaholderAPI
# Import standard implementations?
# Don't import anything here,
# parent imports everything 'public'
from .exception import CorruptedError
from .callpoint import Callpoint
from .physical import Physical
from .specificator import CanonifyException
class Controller(object):
def __init__(self, quotaholder, physical):
self.quotaholder = quotaholder
self.physical = physical
self.controller_init()
def controller_init(self):
pass
def get_commission_issue(self, commission_spec):
"""Prepare and return the arguments for the
quotaholder's issue_commission call,
containing the provisions required and
the target entity for their allocation.
"""
raise NotImplementedError
def register_commission(self, serial,
clientkey,
physical_description ):
"""Register a commission to the controller's stable storage,
along with the quotaholder serial and clientkey,
and the target physical description.
This information is needed to co-ordinate the commission
execution among the quotaholder server, the controller,
and the physical layer implementing the resource.
"""
raise NotImplementedError
def get_commission(self, serial):
"""Retrieve the commission registered with serial"""
raise NotImplementedError
def complete_commission(self, serial):
"""Mark and commit in stable storage the commission identified by
a serial as to-be-completed-successfully,
i.e that it has succeeded in producing a physical resource
and is to be removed from being tracked by the holder server,
controller, and physical layers.
"""
raise NotImplementedError
def is_commission_complete(self, serial):
"""Return true if the serial is marked as
completed by complete_commission()
"""
raise NotImplementedError
def fail_commission(self, serial):
"""Mark and commit in stable storage the commission identified by
a serial as to-be-completed-unsuccessfully,
i.e. that it has failed in producing a physical resource
and is to be removed from being tracked by the holder server,
controller, and physical layers.
"""
raise NotImplementedError
def is_commission_failing(self, serial):
"""Return true if the serial is marked as
failing by fail_commission()
"""
raise NotImplementedError
def retire_commission(self, serial):
"""Stop tracking the commission identified by a serial"""
raise NotImplementedError
def undertake_commission(self, commission_spec):
"""Initiate and start tracking and co-ordinating a commission
from a commission spec.
"""
holder = self.quotaholder
physical = self.physical
commission_issue = self.get_commission_issue(commission_spec)
entity = commission_issue['entity']
clientkey = commission_issue['clientkey']
physical_description = physical.derive_description(commission_spec)
serial = holder.issue_commission(**commission_issue)
self.register_commission( serial,
clientkey,
physical_description )
self.process_controller(serial)
return serial
def process_controller(self, serial):
"""Consider the current state of a commission in the controller layer,
and schedule next actions.
"""
holder = self.quotaholder
physical = self.physical
controller = self
r = controller.get_commission(serial)
if not r:
return
serial, clientkey, physical_description, status = r
if controller.is_commission_complete(serial):
holder.accept_commission(serial=serial, clientkey=clientkey)
physical.end_commission(serial, physical_description)
controller.retire_commission(serial)
elif controller.is_commission_failing(serial):
holder.recall_commission(serial=serial, clientkey=clientkey)
physical.end_commission(serial, physical_description)
controller.retire_commission(serial)
else:
controller.process_physical(serial)
def process_physical(self, serial):
"""Consider the current state of a commission in the physical layer,
and schedule next actions.
"""
physical = self.physical
r = self.get_commission(serial)
if not r:
m = "Unknown serial %d in process_physical!" % (serial,)
raise CorruptedError(m)
target_description = r[2]
current_state = physical.get_current_state(serial, target_description)
if not current_state:
physical.initiate_commission(serial, target_description)
elif physical.complies(current_state, target_description):
self.complete_commission(serial)
self.process_controller(serial)
elif physical.attainable(current_state, target_description):
physical.continue_commission(serial, target_description)
else:
self.fail_commission(serial)
physical.end_commission(serial, target_description)
self.process_controller(serial)
class ControlledCallpoint(Callpoint):
controllables = set()
def __init__(self, *args):
self.controllables = set()
super(ControlledCallpoint, self).__init__(*args)
def commission_from_call(self, call_name, call_data):
commission_spec = {}
commission_spec['call_name'] = call_name
commission_spec['call_data'] = call_data
commission_spec['provisions'] = ()
return commission_spec, True
def register_controllable(self, call_name):
controllables = self.controllables
if call_name in controllables:
return
canonify_output = self.api_spec.canonify_output
if (canonify_output(call_name, None) is not None or
not isinstance(canonify_output(call_name, 1L), long)):
m = ("Attempt to register controllable call '%s', "
"but the api spec does not define a "
"nullable long (serial) output!" % (call_name,))
raise CanonifyException(m)
if not isinstance(canonify_output(call_name, 2**63), long):
m = ("Attempt to register controllable call '%s', "
"but the api spec does not define a nullable long "
"(serial) output with a range up to 2**63!" % (call_name,))
raise CanonifyException(m)
controllables.add(call_name)
def do_make_call(self, call_name, call_data):
r = self.commission_from_call(call_name, call_data)
commission_spec, controllable = r
controller = self.controller
if not controllable:
return controller.forward_commission(commission_spec)
if call_name not in self.controllables:
self.register_controllable(call_name)
serial = controller.undertake_commission(commission_spec)
return serial
class Physical(object):
def derive_description(self, commission_spec):
"""Derive a target physical description from a commission specification
which is understandable and executable by the physical layer.
"""
raise NotImplementedError
def initiate_commission(self, serial, description):
"""Start creating a resource with a physical description,
tagged by the given serial.
"""
raise NotImplementedError
def get_current_state(self, serial, description):
"""Query and return the current physical state for the
target physical description initiated by the given serial.
"""
raise NotImplementedError
def complies(self, state, description):
"""Compare current physical state and target physical description
and decide if the commission has been successfully implemented.
"""
raise NotImplementedError
def attainable(self, state, description):
"""Compare current physical state and target physical description
and decide if the commission can be implemented.
"""
raise NotImplementedError
def continue_commission(self, serial, description):
"""Continue an ongoing commission towards
the given target physical description
"""
raise NotImplementedError
def end_commission(self, serial, description):
"""Cancel and stop tracking the commission identified by serial"""
raise NotImplementedError
......@@ -163,20 +163,16 @@ def get_callpoint(pointname, version=None, automake=None, **kw):
versiontag = mk_versiontag(version)
components = pointname.split('.')
category = components[0]
if not category:
raise ValueError("invalid pointname '%s'" % (pointname,))
if category not in ['clients', 'servers']:
category = 'clients'
components = [category] + components
appname = components[0]
if len(components) < 2:
raise ValueError("invalid pointname '%s'" % (pointname,))
appname = components[1]
pointname = '.'.join(components)
modname = ('commissioning.%s.callpoint.API_Callpoint%s'
category = components[1]
if not category or category not in ['clients', 'servers']:
raise ValueError("invalid pointname '%s'" % (pointname,))
modname = ('%s.callpoint.API_Callpoint%s'
% (pointname, versiontag))
try:
......@@ -196,9 +192,9 @@ def get_callpoint(pointname, version=None, automake=None, **kw):
pointname = '.'.join(components)
if pointname == 'quotaholder':
apiname = 'commissioning.api.quotaholder.QuotaholderAPI'
apiname = 'quotaholder.api.QuotaholderAPI'
else:
apiname = 'commissioning.specs.%s.API_Spec%s' % (pointname, versiontag)
apiname = '%s.api.API_Spec%s' % (pointname, versiontag)
API_Spec = imp_module(apiname)
......
#!/usr/bin/env python
from commissioning import Callpoint
from commissioning.clients.http import main, HTTP_API_Client
from commissioning.specs.fscrud import API_Spec as FSCRUD_API
class FSCRUD_HTTP(HTTP_API_Client):
api_spec = FSCRUD_API()
class FSCRUD_Debug(Callpoint):
api_spec = FSCRUD_API()
def init_connection(self, connection):
self.connection = connection
print 'connecting to', connection
def commit(self):
pass
def abort(self):
pass
def do_make_call(self, call_name, call_data):
print call_name, str(call_data)
if __name__ == '__main__':
main()
#!/usr/bin/env python
from commissioning.clients.http import main, HTTP_API_Client
from commissioning import QuotaholderAPI
class QuotaholderHTTP(HTTP_API_Client):
api_spec = QuotaholderAPI()
from .models import DjangoController
Controller = DjangoController
from commissioning import Controller
from django.db.models import Model, BigIntegerField, CharField, IntegerField
from django.db import transaction
from json import dumps as json_dumps, loads as json_loads
class ControllerCommission(Model):
serial = BigIntegerField(primary_key=True)
clientkey = CharField(null=False, max_length=72)
physical_description = CharField(null=False, max_length=4096)
status = IntegerField(null=False)
class DjangoController(Controller):
def get_commission_issue(self, commission_spec):
"""Prepare and return the arguments for the
quotaholder's issue_commission call,
containing the provisions required and
the target entity for their allocation.
"""
raise NotImplementedError
def register_commission(self, serial,
clientkey,
physical_description ):
"""Register a commission to the controller's stable storage,
along with the quotaholder serial and clientkey,
and the target physical description.
This information is needed to co-ordinate the commission
execution among the quotaholder server, the controller,
and the physical layer implementing the resource.
"""
physical_description = json_dumps(physical_description)
create = ControllerCommission.objects.create
create( serial=serial, clientkey=clientkey,
physical_description=physical_description )
def get_commission(self, serial):
"""Retrieve the commission registered with serial"""
try:
commission = ControllerCommission.objects.get(serial=serial)
except ControllerCommission.DoesNotExist:
return None
return (commission.serial,
commission.clientkey,
commission.physical_description,
commission.status)
def complete_commission(self, serial):
"""Mark and commit in stable storage the commission identified by
a serial as to-be-completed-successfully,
i.e that it has succeeded in producing a physical resource
and is to be removed from being tracked by the holder server,
controller, and physical layers.
"""
commission = ControllerCommission.objects.get(serial=serial)
commission.status = 1
commission.save()
def is_commission_complete(self, serial):
"""Return true if the serial is marked as
completed by complete_commission()
"""
commission = ControllerCommission.objects.get(serial=serial)
return commission.status > 0
def fail_commission(self, serial):
"""Mark and commit in stable storage the commission identified by
a serial as to-be-completed-unsuccessfully,
i.e. that it has failed in producing a physical resource
and is to be removed from being tracked by the holder server,
controller, and physical layers.
"""
commission = ControllerCommission.objects.get(serial=serial)
commission.status = -1
commission.save()
def is_commission_failing(self, serial):
"""Return true if the serial is marked as
failing by fail_commission()
"""
commission = ControllerCommission.objects.get(serial=serial)
return commission.status < 0
def retire_commission(self, serial):
"""Stop tracking the commission identified by a serial"""
try:
commission = ControllerCommission.objects.get(serial=serial)
except ControllerCommission.DoesNotExist:
return
commission.delete()
......@@ -18,7 +18,7 @@ callpoints = {}
@transaction.commit_on_success
def view(request, appname=None, version=None, callname=None):
if (appname, version) not in callpoints:
pointname = 'servers.%s.django_backend' % (appname,)
pointname = '%s.servers.django_backend' % (appname,)
Callpoint = get_callpoint(pointname, version=version)
callpoint = Callpoint()
callpoints[(appname, version)] = callpoint
......
......@@ -32,7 +32,7 @@ DATABASES = {
}
}
ROOT_URLCONF = 'commissioning.servers.django_server.urls'
ROOT_URLCONF = 'commissioning.lib.django_server.urls'
from commissioning.utils.pyconf import pyconf_vars
conffile = '/etc/%s/django.conf' % (_appname,)
......@@ -90,14 +90,13 @@ TEMPLATE_DIRS = (
INSTALLED_APPS = (
'django.contrib.contenttypes',
'commissioning.controllers.django_controller',
'commissioning.servers.django_server.server_app',
'commissioning.lib.django_server.server_app',
'south',
#'django_extensions',
)
names = COMMISSIONING_APP_NAME.split(',')
names = ('commissioning.servers.%s.django_backend' % (n,) for n in names)
names = ('%s.servers.django_backend' % (n,) for n in names)
from django.utils.importlib import import_module
applist = []
......@@ -108,4 +107,4 @@ for name in names:
except ImportError:
pass
INSTALLED_APPS += tuple(applist)
\ No newline at end of file
INSTALLED_APPS += tuple(applist)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment