root / commissioning / servers / quotaholder / django_backend / callpoint.py @ fac1de87
History | View | Annotate | Download (13.3 kB)
1 |
|
---|---|
2 |
from commissioning import ( QuotaholderAPI, |
3 |
Callpoint, CommissionException, |
4 |
CorruptedError, InvalidDataError, |
5 |
InvalidKeyError, NoEntityError, |
6 |
NoQuantityError, NoCapacityError ) |
7 |
|
8 |
|
9 |
from django.db.models import Model, BigIntegerField, CharField, ForeignKey |
10 |
from django.db import transaction |
11 |
from .models import Holder, Entity, Policy, Holding, Commission, Provision |
12 |
|
13 |
|
14 |
class QuotaholderDjangoDBCallpoint(Callpoint): |
15 |
|
16 |
api_spec = QuotaholderAPI() |
17 |
|
18 |
http_exc_lookup = { |
19 |
CorruptedError: 550,
|
20 |
InvalidDataError: 400,
|
21 |
InvalidKeyError: 401,
|
22 |
NoEntityError: 404,
|
23 |
NoQuantityError: 413,
|
24 |
NoCapacityError: 413,
|
25 |
} |
26 |
|
27 |
def init_connection(self, connection): |
28 |
if connection is not None: |
29 |
raise ValueError("Cannot specify connection args with %s" % |
30 |
type(self).__name__) |
31 |
pass
|
32 |
|
33 |
def commit(self): |
34 |
transaction.commit() |
35 |
|
36 |
def rollback(self): |
37 |
transaction.rollback() |
38 |
|
39 |
def do_make_call(self, call_name, data): |
40 |
call_fn = getattr(self, call_name, None) |
41 |
if not call_fn: |
42 |
m = "cannot find call '%s'" % (call_name,)
|
43 |
raise CorruptedError(m)
|
44 |
|
45 |
return call_fn(**data)
|
46 |
|
47 |
@classmethod
|
48 |
def http_exception(cls, exc): |
49 |
if not isinstance(exc, CommissionException): |
50 |
raise exc
|
51 |
|
52 |
body = str(exc.args)
|
53 |
status = cls.http_exc_lookup.get(type(exc), 400) |
54 |
return status, body
|
55 |
|
56 |
def create_entity(self, context={}, create_entity=()): |
57 |
rejected = [] |
58 |
append = rejected.append |
59 |
|
60 |
for entity, owner, key, ownerkey in create_entity: |
61 |
try:
|
62 |
owner = Entity.objects.get(entity=owner, key=ownerkey) |
63 |
except Entity.DoesNotExist:
|
64 |
append(entity) |
65 |
|
66 |
Entity.objects.create(entity=entity, owner=owner, key=key) |
67 |
|
68 |
return rejected
|
69 |
|
70 |
def list_entities(self, context={}, entity=None, key=None): |
71 |
try:
|
72 |
e = Entity.objects.get(entity=entity, key=key) |
73 |
except Entity.DoesNotExist:
|
74 |
m = "Entity '%s' does not exist" % (entity,)
|
75 |
raise NoEntityError(m)
|
76 |
|
77 |
children = e.entities.all() |
78 |
entities = [e.entity for e in children] |
79 |
return entities
|
80 |
|
81 |
def get_entity(self, context={}, get_entity=()): |
82 |
entities = [] |
83 |
append = entities.append |
84 |
|
85 |
for entity, key in get_entity: |
86 |
try:
|
87 |
Entity.objects.get(entity=entity, key=key) |
88 |
except Entity.DoesNotExist:
|
89 |
continue
|
90 |
|
91 |
append((entity, key)) |
92 |
|
93 |
return entities
|
94 |
|
95 |
def get_limits(self, context={}, get_limits=()): |
96 |
limits = [] |
97 |
append = limits.append |
98 |
|
99 |
for entity, resource, key in get_limits: |
100 |
try:
|
101 |
h = Holding.objects.get(entity=entity, resource=resource) |
102 |
except Policy.DoesNotExist:
|
103 |
continue
|
104 |
|
105 |
if h.entity.key != key:
|
106 |
continue
|
107 |
p = h.policy |
108 |
append((h.entity, h.resource, p.quantity, p.capacity, |
109 |
p.import_limit, p.export_limit, h.flags)) |
110 |
|
111 |
return limits
|
112 |
|
113 |
def set_limits(self, context={}, set_limits=()): |
114 |
|
115 |
for ( policy, quantity, capacity,
|
116 |
import_limit, export_limit ) in set_limits:
|
117 |
|
118 |
#XXX: create or replace?
|
119 |
Policy.objects.create( policy=policy, |
120 |
quantity=quantity, |
121 |
capacity=capacity, |
122 |
import_limit=import_limit, |
123 |
export_limit=export_limit ) |
124 |
|
125 |
return ()
|
126 |
|
127 |
def get_holding(self, context={}, get_holding=()): |
128 |
holdings = [] |
129 |
append = holdings.append |
130 |
|
131 |
for entity, resource, key in get_holding: |
132 |
try:
|
133 |
h = Holding.objects.get(entity=entity, resource=resource) |
134 |
except Holding.DoesNotExist:
|
135 |
continue
|
136 |
|
137 |
if h.entity.key != key:
|
138 |
continue
|
139 |
|
140 |
append((h.entity, h.resource, h.policy, |
141 |
h.imported, h.exported, h.flags)) |
142 |
|
143 |
return holdings
|
144 |
|
145 |
def set_holding(self, context={}, set_holding=()): |
146 |
rejected = [] |
147 |
append = rejected.append |
148 |
|
149 |
for entity, resource, key, policy, flags in set_holding: |
150 |
try:
|
151 |
e = Entity.objects.get(entity=entity, key=key) |
152 |
except Entity.DoesNotExist:
|
153 |
append((entity, resource, policy)) |
154 |
continue
|
155 |
|
156 |
if e.key != key:
|
157 |
append((entity, resource, policy)) |
158 |
continue
|
159 |
|
160 |
try:
|
161 |
p = Policy.objects.get(policy=policy) |
162 |
except Policy.DoesNotExist:
|
163 |
append((entity, resource, policy)) |
164 |
continue
|
165 |
|
166 |
try:
|
167 |
h = Holding.objects.get(entity=entity, resource=resource) |
168 |
h.policy = p |
169 |
h.flags = flags |
170 |
h.save() |
171 |
except Holding.DoesNotExist:
|
172 |
h = Holding.objects.create( entity=entity, resource=resource, |
173 |
policy=policy, flags=flags ) |
174 |
|
175 |
return rejected
|
176 |
|
177 |
def list_resources(self, context={}, entity=None, key=None): |
178 |
try:
|
179 |
e = Entity.objects.get() |
180 |
except Entity.DoesNotExist:
|
181 |
m = "No such entity '%s'" % (entity,)
|
182 |
raise NoEntityError(m)
|
183 |
|
184 |
if e.key != key:
|
185 |
m = "Invalid key for entity '%s'" % (entity,)
|
186 |
raise InvalidKeyError(m)
|
187 |
|
188 |
holdings = e.holdings.filter(entity=entity) |
189 |
resources = [h.resource for h in holdings] |
190 |
return resources
|
191 |
|
192 |
def get_quota(self, context={}, get_quota=()): |
193 |
quotas = [] |
194 |
append = quotas.append |
195 |
|
196 |
for entity, resource, key in get_quota: |
197 |
try:
|
198 |
h = Holding.objects.get(entity=entity, resource=resource) |
199 |
except Holding.DoesNotExist:
|
200 |
continue
|
201 |
|
202 |
if h.entity.key != key:
|
203 |
continue
|
204 |
|
205 |
p = h.policy |
206 |
|
207 |
append((h.entity.entity, h.resource, p.quantity, p.capacity, |
208 |
p.import_limit, p.export_limit, |
209 |
h.imported, h.exported, h.flags)) |
210 |
|
211 |
return quotas
|
212 |
|
213 |
def set_quota(self, context={}, set_quota=()): |
214 |
rejected = [] |
215 |
append = rejected.append |
216 |
|
217 |
for ( entity, resource, key,
|
218 |
quantity, capacity, |
219 |
import_limit, export_limit, flags ) in set_quota:
|
220 |
|
221 |
try:
|
222 |
h = Holding.objects.get(entity=entity, resource=resource) |
223 |
if h.entity.key != key:
|
224 |
append((entity, resource)) |
225 |
continue
|
226 |
except Holding.DoesNotExist:
|
227 |
append(entity, resource) |
228 |
|
229 |
p = h.policy |
230 |
policy = newname() |
231 |
newp = Policy.objects.create ( |
232 |
policy=policy, |
233 |
quantity=quantity, |
234 |
capacity=capacity, |
235 |
import_limit=import_limit, |
236 |
export_limit=export_limit |
237 |
) |
238 |
|
239 |
h.policy = newp |
240 |
h.save() |
241 |
|
242 |
if p.holdings.count() == 0: |
243 |
p.delete() |
244 |
|
245 |
return rejected
|
246 |
|
247 |
def issue_commission(self, context={}, clientkey=None, |
248 |
target=None, key=None, |
249 |
owner=None, ownerkey=None, |
250 |
provisions=() ): |
251 |
|
252 |
try:
|
253 |
t = Entity.objects.get(entity=target) |
254 |
except Entity.DoesNotExist:
|
255 |
create_entity = ((entity, owner, key, ownerkey),) |
256 |
rejected = self.create_entity( context=context,
|
257 |
create_entity=create_entity ) |
258 |
if rejected:
|
259 |
raise NoEntityError("No target entity '%s'" % (target,)) |
260 |
|
261 |
t = Entity.objects.get(entity=target) |
262 |
else:
|
263 |
if t.key != key:
|
264 |
m = "Invalid key for target entity '%s'" % (target,)
|
265 |
raise InvalidKeyError(m)
|
266 |
|
267 |
commission = Commission.objects.create( entity=target, |
268 |
clientkey=clientkey ) |
269 |
serial = commission.serial |
270 |
|
271 |
for entity, resource, quantity in provisions: |
272 |
try:
|
273 |
h = Holding.objects.get(entity=entity, resource=resource) |
274 |
except Holding.DoesNotExist:
|
275 |
m = ("There is not enough quantity "
|
276 |
"to allocate from in %s.%s" % (entity, resource))
|
277 |
raise NoQuantityError(m)
|
278 |
|
279 |
hp = h.policy |
280 |
|
281 |
if h.importing - h.exported + hp.quantity - quantity < 0: |
282 |
m = ("There is not enough quantity "
|
283 |
"to allocate from in %s.%s" % (entity, resource))
|
284 |
raise NoQuantityError(m)
|
285 |
|
286 |
try:
|
287 |
th = Holding.objects.get(entity=target, resource=resource) |
288 |
except Holding.DoesNotExist:
|
289 |
m = ("There is not enough capacity "
|
290 |
"to allocate into in %s.%s" % (target, resource))
|
291 |
raise NoCapacityError(m)
|
292 |
|
293 |
tp = th.policy |
294 |
|
295 |
if ( th.exported - th.importing - tp.quantity
|
296 |
+ tp.capacity - quantity ) < 0:
|
297 |
|
298 |
m = ("There is not enough capacity "
|
299 |
"to allocate into in %s.%s" % (target, resource))
|
300 |
raise NoCapacityError(m)
|
301 |
|
302 |
Provision.objects.create( serial=serial, |
303 |
entity=entity, |
304 |
resource=resource, |
305 |
quantity=quantity ) |
306 |
|
307 |
h.exporting += quantity |
308 |
th.importing += quantity |
309 |
|
310 |
h.save() |
311 |
th.save() |
312 |
|
313 |
return serial
|
314 |
|
315 |
def accept_commission(self, context={}, clientkey=None, serial=None): |
316 |
try:
|
317 |
c = Commission.objects.get(clientkey=clientkey, serial=serial) |
318 |
except Commission.DoesNotExist:
|
319 |
return
|
320 |
|
321 |
t = c.entity |
322 |
|
323 |
provisions = Provision.objects.filter( clientkey=clientkey, |
324 |
serial=serial ) |
325 |
for pv in provisions: |
326 |
pv.entity, |
327 |
pv.resource |
328 |
try:
|
329 |
h = Holding.objects.get(entity=pv.entity.entity, |
330 |
resource=pv.resource ) |
331 |
th = Holding.objects.get(entity=t, resource=pv.resource) |
332 |
except Holding.DoesNotExist:
|
333 |
m = "Corrupted provision"
|
334 |
raise CorruptedError(m)
|
335 |
|
336 |
h.exported += pv.quantity |
337 |
th.imported += pv.quantity |
338 |
h.save() |
339 |
th.save() |
340 |
pv.delete() |
341 |
|
342 |
return
|
343 |
|
344 |
def reject_commission(self, context={}, clientkey=None, serial=None): |
345 |
try:
|
346 |
c = Commission.objects.get(clientkey=clientkey, serial=serial) |
347 |
except Commission.DoesNotExist:
|
348 |
return
|
349 |
|
350 |
t = c.entity |
351 |
|
352 |
provisions = Provision.objects.filter( clientkey=clientkey, |
353 |
serial=serial ) |
354 |
for pv in provisions: |
355 |
pv.entity, |
356 |
pv.resource |
357 |
try:
|
358 |
h = Holding.objects.get(entity=pv.entity.entity, |
359 |
resource=pv.resource ) |
360 |
th = Holding.objects.get(entity=t, resource=pv.resource) |
361 |
except Holding.DoesNotExist:
|
362 |
m = "Corrupted provision"
|
363 |
raise CorruptedError(m)
|
364 |
|
365 |
h.exporting -= pv.quantity |
366 |
th.importing -= pv.quantity |
367 |
h.save() |
368 |
th.save() |
369 |
pv.delete() |
370 |
|
371 |
return
|
372 |
|
373 |
def get_pending_commissions(self, context={}, clientkey=None): |
374 |
pending = Commission.objects.filter(clientkey=clientkey) |
375 |
return pending
|
376 |
|
377 |
def resolve_pending_commissions(self, context={}, clientkey=None, |
378 |
max_serial=None, accept_set=() ):
|
379 |
accept_set = set(accept_set)
|
380 |
pending = self.get_pending_commissions(clientkey=clientkey)
|
381 |
pending = sorted(pending)
|
382 |
|
383 |
accept = self.accept_commission
|
384 |
reject = self.reject_commission
|
385 |
|
386 |
for serial in pending: |
387 |
if serial > max_serial:
|
388 |
break
|
389 |
|
390 |
if serial in accept_set: |
391 |
accept(clientkey=clientkey, serial=serial) |
392 |
else:
|
393 |
reject(clientkey=clientkey, serial=serial) |
394 |
|
395 |
return
|
396 |
|
397 |
def release_entity(self, context={}, release_entity=()): |
398 |
rejected = [] |
399 |
append = rejected.append |
400 |
for entity, key in release_entity: |
401 |
try:
|
402 |
e = Entity.objects.get(entity=entity, key=key) |
403 |
except Entity.DoesNotExist:
|
404 |
append(entity) |
405 |
continue
|
406 |
|
407 |
if e.entities.count() != 0: |
408 |
append(entity) |
409 |
continue
|
410 |
|
411 |
if e.holdings.count() != 0: |
412 |
append(entity) |
413 |
continue
|
414 |
|
415 |
e.delete() |
416 |
|
417 |
return rejected
|
418 |
|
419 |
API_Callpoint = QuotaholderDjangoDBCallpoint |