root / commissioning / api / controller.py @ 9f1a1bd0
History | View | Annotate | Download (7 kB)
1 | 9f1a1bd0 | Georgios D. Tsoukalas | from .exception import CorruptedError |
---|---|---|---|
2 | 9f1a1bd0 | Georgios D. Tsoukalas | from .callpoint import Callpoint |
3 | 9f1a1bd0 | Georgios D. Tsoukalas | from .physical import Physical |
4 | 9f1a1bd0 | Georgios D. Tsoukalas | |
5 | 9f1a1bd0 | Georgios D. Tsoukalas | class Controller(object): |
6 | 9f1a1bd0 | Georgios D. Tsoukalas | |
7 | 9f1a1bd0 | Georgios D. Tsoukalas | def __init__(self, quotaholder, physical): |
8 | 9f1a1bd0 | Georgios D. Tsoukalas | self.quotaholder = quotaholder
|
9 | 9f1a1bd0 | Georgios D. Tsoukalas | self.physical = physical
|
10 | 9f1a1bd0 | Georgios D. Tsoukalas | self.controller_init()
|
11 | 9f1a1bd0 | Georgios D. Tsoukalas | |
12 | 9f1a1bd0 | Georgios D. Tsoukalas | def controller_init(self): |
13 | 9f1a1bd0 | Georgios D. Tsoukalas | pass
|
14 | 9f1a1bd0 | Georgios D. Tsoukalas | |
15 | 9f1a1bd0 | Georgios D. Tsoukalas | def get_commission_issue(self, commission_spec): |
16 | 9f1a1bd0 | Georgios D. Tsoukalas | """Prepare and return the arguments for the
|
17 | 9f1a1bd0 | Georgios D. Tsoukalas | quotaholder's issue_commission call,
|
18 | 9f1a1bd0 | Georgios D. Tsoukalas | containing the provisions required and
|
19 | 9f1a1bd0 | Georgios D. Tsoukalas | the target entity for their allocation.
|
20 | 9f1a1bd0 | Georgios D. Tsoukalas | """
|
21 | 9f1a1bd0 | Georgios D. Tsoukalas | raise NotImplementedError |
22 | 9f1a1bd0 | Georgios D. Tsoukalas | |
23 | 9f1a1bd0 | Georgios D. Tsoukalas | def register_commission(self, serial, |
24 | 9f1a1bd0 | Georgios D. Tsoukalas | clientkey, |
25 | 9f1a1bd0 | Georgios D. Tsoukalas | physical_description ): |
26 | 9f1a1bd0 | Georgios D. Tsoukalas | |
27 | 9f1a1bd0 | Georgios D. Tsoukalas | """Register a commission to the controller's stable storage,
|
28 | 9f1a1bd0 | Georgios D. Tsoukalas | along with the quotaholder serial and clientkey,
|
29 | 9f1a1bd0 | Georgios D. Tsoukalas | and the target physical description.
|
30 | 9f1a1bd0 | Georgios D. Tsoukalas | This information is needed to co-ordinate the commission
|
31 | 9f1a1bd0 | Georgios D. Tsoukalas | execution among the quotaholder server, the controller,
|
32 | 9f1a1bd0 | Georgios D. Tsoukalas | and the physical layer implementing the resource.
|
33 | 9f1a1bd0 | Georgios D. Tsoukalas | """
|
34 | 9f1a1bd0 | Georgios D. Tsoukalas | raise NotImplementedError |
35 | 9f1a1bd0 | Georgios D. Tsoukalas | |
36 | 9f1a1bd0 | Georgios D. Tsoukalas | def get_commission(self, serial): |
37 | 9f1a1bd0 | Georgios D. Tsoukalas | """Retrieve the commission registered with serial"""
|
38 | 9f1a1bd0 | Georgios D. Tsoukalas | raise NotImplementedError |
39 | 9f1a1bd0 | Georgios D. Tsoukalas | |
40 | 9f1a1bd0 | Georgios D. Tsoukalas | def complete_commission(self, serial): |
41 | 9f1a1bd0 | Georgios D. Tsoukalas | """Mark and commit in stable storage the commission identified by
|
42 | 9f1a1bd0 | Georgios D. Tsoukalas | a serial as to-be-completed-successfully,
|
43 | 9f1a1bd0 | Georgios D. Tsoukalas | i.e that it has succeeded in producing a physical resource
|
44 | 9f1a1bd0 | Georgios D. Tsoukalas | and is to be removed from being tracked by the holder server,
|
45 | 9f1a1bd0 | Georgios D. Tsoukalas | controller, and physical layers.
|
46 | 9f1a1bd0 | Georgios D. Tsoukalas | """
|
47 | 9f1a1bd0 | Georgios D. Tsoukalas | raise NotImplementedError |
48 | 9f1a1bd0 | Georgios D. Tsoukalas | |
49 | 9f1a1bd0 | Georgios D. Tsoukalas | def is_commission_complete(self, serial): |
50 | 9f1a1bd0 | Georgios D. Tsoukalas | """Return true if the serial is marked as
|
51 | 9f1a1bd0 | Georgios D. Tsoukalas | completed by complete_commission()
|
52 | 9f1a1bd0 | Georgios D. Tsoukalas | """
|
53 | 9f1a1bd0 | Georgios D. Tsoukalas | raise NotImplementedError |
54 | 9f1a1bd0 | Georgios D. Tsoukalas | |
55 | 9f1a1bd0 | Georgios D. Tsoukalas | def fail_commission(self, serial): |
56 | 9f1a1bd0 | Georgios D. Tsoukalas | """Mark and commit in stable storage the commission identified by
|
57 | 9f1a1bd0 | Georgios D. Tsoukalas | a serial as to-be-completed-unsuccessfully,
|
58 | 9f1a1bd0 | Georgios D. Tsoukalas | i.e. that it has failed in producing a physical resource
|
59 | 9f1a1bd0 | Georgios D. Tsoukalas | and is to be removed from being tracked by the holder server,
|
60 | 9f1a1bd0 | Georgios D. Tsoukalas | controller, and physical layers.
|
61 | 9f1a1bd0 | Georgios D. Tsoukalas | """
|
62 | 9f1a1bd0 | Georgios D. Tsoukalas | raise NotImplementedError |
63 | 9f1a1bd0 | Georgios D. Tsoukalas | |
64 | 9f1a1bd0 | Georgios D. Tsoukalas | def is_commission_failing(self, serial): |
65 | 9f1a1bd0 | Georgios D. Tsoukalas | """Return true if the serial is marked as
|
66 | 9f1a1bd0 | Georgios D. Tsoukalas | failing by fail_commission()
|
67 | 9f1a1bd0 | Georgios D. Tsoukalas | """
|
68 | 9f1a1bd0 | Georgios D. Tsoukalas | raise NotImplementedError |
69 | 9f1a1bd0 | Georgios D. Tsoukalas | |
70 | 9f1a1bd0 | Georgios D. Tsoukalas | def retire_commission(self, serial): |
71 | 9f1a1bd0 | Georgios D. Tsoukalas | """Stop tracking the commission identified by a serial"""
|
72 | 9f1a1bd0 | Georgios D. Tsoukalas | raise NotImplementedError |
73 | 9f1a1bd0 | Georgios D. Tsoukalas | |
74 | 9f1a1bd0 | Georgios D. Tsoukalas | def undertake_commission(self, commission_spec): |
75 | 9f1a1bd0 | Georgios D. Tsoukalas | """Initiate and start tracking and co-ordinating a commission
|
76 | 9f1a1bd0 | Georgios D. Tsoukalas | from a commission spec.
|
77 | 9f1a1bd0 | Georgios D. Tsoukalas | """
|
78 | 9f1a1bd0 | Georgios D. Tsoukalas | holder = self.quotaholder
|
79 | 9f1a1bd0 | Georgios D. Tsoukalas | physical = self.physical
|
80 | 9f1a1bd0 | Georgios D. Tsoukalas | |
81 | 9f1a1bd0 | Georgios D. Tsoukalas | commission_issue = self.get_commission_issue(commission_spec)
|
82 | 9f1a1bd0 | Georgios D. Tsoukalas | entity = commission_issue['entity']
|
83 | 9f1a1bd0 | Georgios D. Tsoukalas | clientkey = commission_issue['clientkey']
|
84 | 9f1a1bd0 | Georgios D. Tsoukalas | physical_description = self.derive_description(commission_spec)
|
85 | 9f1a1bd0 | Georgios D. Tsoukalas | |
86 | 9f1a1bd0 | Georgios D. Tsoukalas | serial = holder.issue_commission(entity, provisions) |
87 | 9f1a1bd0 | Georgios D. Tsoukalas | self.register_commission( serial,
|
88 | 9f1a1bd0 | Georgios D. Tsoukalas | clientkey, |
89 | 9f1a1bd0 | Georgios D. Tsoukalas | physical_description ) |
90 | 9f1a1bd0 | Georgios D. Tsoukalas | |
91 | 9f1a1bd0 | Georgios D. Tsoukalas | self.process_controller(serial)
|
92 | 9f1a1bd0 | Georgios D. Tsoukalas | return serial
|
93 | 9f1a1bd0 | Georgios D. Tsoukalas | |
94 | 9f1a1bd0 | Georgios D. Tsoukalas | def process_controller(self, serial): |
95 | 9f1a1bd0 | Georgios D. Tsoukalas | """Consider the current state of a commission in the controller layer,
|
96 | 9f1a1bd0 | Georgios D. Tsoukalas | and schedule next actions.
|
97 | 9f1a1bd0 | Georgios D. Tsoukalas | """
|
98 | 9f1a1bd0 | Georgios D. Tsoukalas | holder = self.quotaholder
|
99 | 9f1a1bd0 | Georgios D. Tsoukalas | physical = self.physical
|
100 | 9f1a1bd0 | Georgios D. Tsoukalas | controller = self
|
101 | 9f1a1bd0 | Georgios D. Tsoukalas | |
102 | 9f1a1bd0 | Georgios D. Tsoukalas | r = controller.get_commission(serial) |
103 | 9f1a1bd0 | Georgios D. Tsoukalas | if not r: |
104 | 9f1a1bd0 | Georgios D. Tsoukalas | return
|
105 | 9f1a1bd0 | Georgios D. Tsoukalas | |
106 | 9f1a1bd0 | Georgios D. Tsoukalas | serial, clientkey, physical_description, status = r |
107 | 9f1a1bd0 | Georgios D. Tsoukalas | |
108 | 9f1a1bd0 | Georgios D. Tsoukalas | if controller.is_commission_complete(serial):
|
109 | 9f1a1bd0 | Georgios D. Tsoukalas | holder.accept_commission(serial=serial, clientkey=clientkey) |
110 | 9f1a1bd0 | Georgios D. Tsoukalas | physical.end_commission(serial, physical_description) |
111 | 9f1a1bd0 | Georgios D. Tsoukalas | controller.retire_commission(serial) |
112 | 9f1a1bd0 | Georgios D. Tsoukalas | |
113 | 9f1a1bd0 | Georgios D. Tsoukalas | elif controller.is_commission_failing(serial):
|
114 | 9f1a1bd0 | Georgios D. Tsoukalas | holder.recall_commission(serial=serial, clientkey=clientkey) |
115 | 9f1a1bd0 | Georgios D. Tsoukalas | physical.end_commission(serial, physical_description) |
116 | 9f1a1bd0 | Georgios D. Tsoukalas | controller.retire_commission(serial) |
117 | 9f1a1bd0 | Georgios D. Tsoukalas | |
118 | 9f1a1bd0 | Georgios D. Tsoukalas | else:
|
119 | 9f1a1bd0 | Georgios D. Tsoukalas | controller.process_physical(serial) |
120 | 9f1a1bd0 | Georgios D. Tsoukalas | |
121 | 9f1a1bd0 | Georgios D. Tsoukalas | def process_physical(self, serial): |
122 | 9f1a1bd0 | Georgios D. Tsoukalas | """Consider the current state of a commission in the physical layer,
|
123 | 9f1a1bd0 | Georgios D. Tsoukalas | and schedule next actions.
|
124 | 9f1a1bd0 | Georgios D. Tsoukalas | """
|
125 | 9f1a1bd0 | Georgios D. Tsoukalas | physical = self.physical
|
126 | 9f1a1bd0 | Georgios D. Tsoukalas | |
127 | 9f1a1bd0 | Georgios D. Tsoukalas | r = self.get_commission(serial)
|
128 | 9f1a1bd0 | Georgios D. Tsoukalas | if not r: |
129 | 9f1a1bd0 | Georgios D. Tsoukalas | m = "Unknown serial %d in process_physical!" % (serial,)
|
130 | 9f1a1bd0 | Georgios D. Tsoukalas | raise CorruptedError(m)
|
131 | 9f1a1bd0 | Georgios D. Tsoukalas | |
132 | 9f1a1bd0 | Georgios D. Tsoukalas | target_description = r[2]
|
133 | 9f1a1bd0 | Georgios D. Tsoukalas | current_state = physical.get_current_state(serial, target_description) |
134 | 9f1a1bd0 | Georgios D. Tsoukalas | |
135 | 9f1a1bd0 | Georgios D. Tsoukalas | if not current_state: |
136 | 9f1a1bd0 | Georgios D. Tsoukalas | |
137 | 9f1a1bd0 | Georgios D. Tsoukalas | physical.initiate_commission(serial, target_description) |
138 | 9f1a1bd0 | Georgios D. Tsoukalas | |
139 | 9f1a1bd0 | Georgios D. Tsoukalas | elif physical.complies(current_state, target_description):
|
140 | 9f1a1bd0 | Georgios D. Tsoukalas | |
141 | 9f1a1bd0 | Georgios D. Tsoukalas | self.complete_commission(serial)
|
142 | 9f1a1bd0 | Georgios D. Tsoukalas | self.process_controller(serial)
|
143 | 9f1a1bd0 | Georgios D. Tsoukalas | |
144 | 9f1a1bd0 | Georgios D. Tsoukalas | elif physical.attainable(current_state, target_description):
|
145 | 9f1a1bd0 | Georgios D. Tsoukalas | |
146 | 9f1a1bd0 | Georgios D. Tsoukalas | physical.continue_commission(serial, target_description) |
147 | 9f1a1bd0 | Georgios D. Tsoukalas | |
148 | 9f1a1bd0 | Georgios D. Tsoukalas | else:
|
149 | 9f1a1bd0 | Georgios D. Tsoukalas | self.fail_commission(serial)
|
150 | 9f1a1bd0 | Georgios D. Tsoukalas | physical.end_commission(serial, target_description) |
151 | 9f1a1bd0 | Georgios D. Tsoukalas | self.process_controller(serial)
|
152 | 9f1a1bd0 | Georgios D. Tsoukalas | |
153 | 9f1a1bd0 | Georgios D. Tsoukalas | |
154 | 9f1a1bd0 | Georgios D. Tsoukalas | class ControlledCallpoint(Callpoint): |
155 | 9f1a1bd0 | Georgios D. Tsoukalas | |
156 | 9f1a1bd0 | Georgios D. Tsoukalas | controllables = set()
|
157 | 9f1a1bd0 | Georgios D. Tsoukalas | |
158 | 9f1a1bd0 | Georgios D. Tsoukalas | def __init__(self, *args): |
159 | 9f1a1bd0 | Georgios D. Tsoukalas | self.controllables = set() |
160 | 9f1a1bd0 | Georgios D. Tsoukalas | super(ControlledCallpoint, self).__init__(*args) |
161 | 9f1a1bd0 | Georgios D. Tsoukalas | |
162 | 9f1a1bd0 | Georgios D. Tsoukalas | def commission_from_call(self, call_name, call_data): |
163 | 9f1a1bd0 | Georgios D. Tsoukalas | commission_spec = {} |
164 | 9f1a1bd0 | Georgios D. Tsoukalas | commission_spec['call_name'] = call_name
|
165 | 9f1a1bd0 | Georgios D. Tsoukalas | commission_spec['call_data'] = call_data
|
166 | 9f1a1bd0 | Georgios D. Tsoukalas | commission_spec['provisions'] = ()
|
167 | 9f1a1bd0 | Georgios D. Tsoukalas | return commission_spec, True |
168 | 9f1a1bd0 | Georgios D. Tsoukalas | |
169 | 9f1a1bd0 | Georgios D. Tsoukalas | def register_controllable(self, call_name): |
170 | 9f1a1bd0 | Georgios D. Tsoukalas | controllable = self.controllables
|
171 | 9f1a1bd0 | Georgios D. Tsoukalas | if call_name in controllables: |
172 | 9f1a1bd0 | Georgios D. Tsoukalas | return
|
173 | 9f1a1bd0 | Georgios D. Tsoukalas | |
174 | 9f1a1bd0 | Georgios D. Tsoukalas | try:
|
175 | 9f1a1bd0 | Georgios D. Tsoukalas | canonify_output = self.api_spec.canonify_output
|
176 | 9f1a1bd0 | Georgios D. Tsoukalas | s = canonify_output(None) is None |
177 | 9f1a1bd0 | Georgios D. Tsoukalas | s += isinstance(canonify_output(1), int) |
178 | 9f1a1bd0 | Georgios D. Tsoukalas | s += isinstance(canonify_output(2**63), int) |
179 | 9f1a1bd0 | Georgios D. Tsoukalas | if s != 3: |
180 | 9f1a1bd0 | Georgios D. Tsoukalas | raise CanonifyException
|
181 | 9f1a1bd0 | Georgios D. Tsoukalas | except CanonifyException, e:
|
182 | 9f1a1bd0 | Georgios D. Tsoukalas | m = ("Attempt to register controllable call '%s', but"
|
183 | 9f1a1bd0 | Georgios D. Tsoukalas | "the api spec does not define a nullable int (serial) output!"
|
184 | 9f1a1bd0 | Georgios D. Tsoukalas | % (call_name,)) |
185 | 9f1a1bd0 | Georgios D. Tsoukalas | raise CanonifyException(m, e)
|
186 | 9f1a1bd0 | Georgios D. Tsoukalas | |
187 | 9f1a1bd0 | Georgios D. Tsoukalas | controllables.add(call_name) |
188 | 9f1a1bd0 | Georgios D. Tsoukalas | |
189 | 9f1a1bd0 | Georgios D. Tsoukalas | def do_make_call(self, call_name, call_data): |
190 | 9f1a1bd0 | Georgios D. Tsoukalas | r = self.commission_from_call(call_name, call_data)
|
191 | 9f1a1bd0 | Georgios D. Tsoukalas | commission_spec, controllable = r |
192 | 9f1a1bd0 | Georgios D. Tsoukalas | controller = self.controller
|
193 | 9f1a1bd0 | Georgios D. Tsoukalas | |
194 | 9f1a1bd0 | Georgios D. Tsoukalas | if not controllable: |
195 | 9f1a1bd0 | Georgios D. Tsoukalas | return controller.forward_commission(commission_spec)
|
196 | 9f1a1bd0 | Georgios D. Tsoukalas | |
197 | 9f1a1bd0 | Georgios D. Tsoukalas | if call_name not in self.controllables: |
198 | 9f1a1bd0 | Georgios D. Tsoukalas | self.register_controllable(call_name)
|
199 | 9f1a1bd0 | Georgios D. Tsoukalas | |
200 | 9f1a1bd0 | Georgios D. Tsoukalas | serial = controller.undertake_commission(commission_spec) |
201 | 9f1a1bd0 | Georgios D. Tsoukalas | return serial
|