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