34 |
34 |
from astakos.quotaholder.exception import (
|
35 |
35 |
QuotaholderError,
|
36 |
36 |
CorruptedError, InvalidDataError,
|
37 |
|
InvalidKeyError, NoEntityError,
|
38 |
37 |
NoQuantityError, NoCapacityError,
|
39 |
38 |
ExportLimitError, ImportLimitError,
|
40 |
39 |
DuplicateError)
|
... | ... | |
43 |
42 |
from astakos.quotaholder.api import QH_PRACTICALLY_INFINITE
|
44 |
43 |
|
45 |
44 |
from django.db.models import Q, Count
|
46 |
|
from .models import (Entity, Policy, Holding,
|
|
45 |
from django.db.models import Q
|
|
46 |
from .models import (Policy, Holding,
|
47 |
47 |
Commission, Provision, ProvisionLog, CallSerial,
|
48 |
48 |
now,
|
49 |
|
db_get_entity, db_get_holding, db_get_policy,
|
|
49 |
db_get_holding, db_get_policy,
|
50 |
50 |
db_get_commission, db_filter_provision, db_get_callserial)
|
51 |
51 |
|
52 |
52 |
|
53 |
53 |
class QuotaholderDjangoDBCallpoint(object):
|
54 |
54 |
|
55 |
|
def create_entity(self, context=None, create_entity=()):
|
56 |
|
rejected = []
|
57 |
|
append = rejected.append
|
58 |
|
|
59 |
|
for idx, (entity, owner, key, ownerkey) in enumerate(create_entity):
|
60 |
|
try:
|
61 |
|
owner = Entity.objects.get(entity=owner, key=ownerkey)
|
62 |
|
except Entity.DoesNotExist:
|
63 |
|
append(idx)
|
64 |
|
continue
|
65 |
|
|
66 |
|
try:
|
67 |
|
e = Entity.objects.get(entity=entity)
|
68 |
|
append(idx)
|
69 |
|
except Entity.DoesNotExist:
|
70 |
|
e = Entity.objects.create(entity=entity,
|
71 |
|
owner=owner,
|
72 |
|
key=key)
|
73 |
|
|
74 |
|
if rejected:
|
75 |
|
raise QuotaholderError(rejected)
|
76 |
|
return rejected
|
77 |
|
|
78 |
|
def set_entity_key(self, context=None, set_entity_key=()):
|
79 |
|
rejected = []
|
80 |
|
append = rejected.append
|
81 |
|
|
82 |
|
for entity, key, newkey in set_entity_key:
|
83 |
|
try:
|
84 |
|
e = db_get_entity(entity=entity, key=key, for_update=True)
|
85 |
|
except Entity.DoesNotExist:
|
86 |
|
append(entity)
|
87 |
|
continue
|
88 |
|
|
89 |
|
e.key = newkey
|
90 |
|
e.save()
|
91 |
|
|
92 |
|
if rejected:
|
93 |
|
raise QuotaholderError(rejected)
|
94 |
|
return rejected
|
95 |
|
|
96 |
|
def list_entities(self, context=None, entity=None, key=None):
|
97 |
|
try:
|
98 |
|
e = Entity.objects.get(entity=entity, key=key)
|
99 |
|
except Entity.DoesNotExist:
|
100 |
|
m = "Entity '%s' does not exist" % (entity,)
|
101 |
|
raise NoEntityError(m)
|
102 |
|
|
103 |
|
children = e.entities.all()
|
104 |
|
entities = [e.entity for e in children]
|
105 |
|
return entities
|
106 |
|
|
107 |
|
def get_entity(self, context=None, get_entity=()):
|
108 |
|
entities = []
|
109 |
|
append = entities.append
|
110 |
|
|
111 |
|
names = [entity for entity, key in get_entity]
|
112 |
|
es = Entity.objects.select_related(depth=1).filter(entity__in=names)
|
113 |
|
data = {}
|
114 |
|
for e in es:
|
115 |
|
data[e.entity] = e
|
116 |
|
|
117 |
|
for entity, key in get_entity:
|
118 |
|
e = data.get(entity, None)
|
119 |
|
if e is None or e.key != key:
|
120 |
|
continue
|
121 |
|
append((entity, e.owner.entity))
|
122 |
|
|
123 |
|
return entities
|
124 |
|
|
125 |
55 |
def get_limits(self, context=None, get_limits=()):
|
126 |
56 |
limits = []
|
127 |
57 |
append = limits.append
|
... | ... | |
163 |
93 |
holdings = []
|
164 |
94 |
append = holdings.append
|
165 |
95 |
|
166 |
|
for entity, resource, key in get_holding:
|
|
96 |
for entity, resource in get_holding:
|
167 |
97 |
try:
|
168 |
98 |
h = Holding.objects.get(entity=entity, resource=resource)
|
169 |
99 |
except Holding.DoesNotExist:
|
170 |
100 |
continue
|
171 |
101 |
|
172 |
|
if h.entity.key != key:
|
173 |
|
continue
|
174 |
|
|
175 |
|
append((h.entity.entity, h.resource, h.policy.policy,
|
|
102 |
append((h.entity, h.resource, h.policy.policy,
|
176 |
103 |
h.imported, h.exported,
|
177 |
104 |
h.returned, h.released, h.flags))
|
178 |
105 |
|
... | ... | |
182 |
109 |
rejected = []
|
183 |
110 |
append = rejected.append
|
184 |
111 |
|
185 |
|
for entity, resource, key, policy, flags in set_holding:
|
186 |
|
try:
|
187 |
|
e = Entity.objects.get(entity=entity, key=key)
|
188 |
|
except Entity.DoesNotExist:
|
189 |
|
append((entity, resource, policy))
|
190 |
|
continue
|
191 |
|
|
192 |
|
if e.key != key:
|
193 |
|
append((entity, resource, policy))
|
194 |
|
continue
|
195 |
|
|
|
112 |
for entity, resource, policy, flags in set_holding:
|
196 |
113 |
try:
|
197 |
114 |
p = Policy.objects.get(policy=policy)
|
198 |
115 |
except Policy.DoesNotExist:
|
... | ... | |
206 |
123 |
h.flags = flags
|
207 |
124 |
h.save()
|
208 |
125 |
except Holding.DoesNotExist:
|
209 |
|
h = Holding.objects.create(entity=e, resource=resource,
|
|
126 |
h = Holding.objects.create(entity=entity, resource=resource,
|
210 |
127 |
policy=p, flags=flags)
|
211 |
128 |
|
212 |
129 |
if rejected:
|
... | ... | |
240 |
157 |
append = rejected.append
|
241 |
158 |
|
242 |
159 |
for idx, sfh in enumerate(init_holding):
|
243 |
|
(entity, resource, key, policy,
|
|
160 |
(entity, resource, policy,
|
244 |
161 |
imported, exported, returned, released,
|
245 |
162 |
flags) = sfh
|
246 |
|
try:
|
247 |
|
e = Entity.objects.get(entity=entity, key=key)
|
248 |
|
except Entity.DoesNotExist:
|
249 |
|
append(idx)
|
250 |
|
continue
|
251 |
|
|
252 |
|
if e.key != key:
|
253 |
|
append(idx)
|
254 |
|
continue
|
255 |
163 |
|
256 |
164 |
try:
|
257 |
165 |
p = Policy.objects.get(policy=policy)
|
... | ... | |
259 |
167 |
append(idx)
|
260 |
168 |
continue
|
261 |
169 |
|
262 |
|
self._init_holding(e, resource, p,
|
|
170 |
self._init_holding(entity, resource, p,
|
263 |
171 |
imported, exported,
|
264 |
172 |
returned, released,
|
265 |
173 |
flags)
|
... | ... | |
272 |
180 |
append = rejected.append
|
273 |
181 |
|
274 |
182 |
for idx, tpl in enumerate(reset_holding):
|
275 |
|
(entity, resource, key,
|
|
183 |
(entity, resource,
|
276 |
184 |
imported, exported, returned, released) = tpl
|
277 |
|
try:
|
278 |
|
e = Entity.objects.get(entity=entity, key=key)
|
279 |
|
except Entity.DoesNotExist:
|
280 |
|
append(idx)
|
281 |
|
continue
|
282 |
185 |
|
283 |
186 |
try:
|
284 |
187 |
h = db_get_holding(entity=entity, resource=resource,
|
... | ... | |
315 |
218 |
return hp.quantity + (holding.imported + holding.returned -
|
316 |
219 |
holding.exported - holding.released)
|
317 |
220 |
|
318 |
|
def _new_policy_name(self):
|
319 |
|
return newname('policy_')
|
320 |
|
|
321 |
|
def _increase_resource(self, entity, resource, amount):
|
322 |
|
try:
|
323 |
|
h = db_get_holding(entity=entity, resource=resource,
|
324 |
|
for_update=True)
|
325 |
|
except Holding.DoesNotExist:
|
326 |
|
h = Holding(entity=entity, resource=resource)
|
327 |
|
p = Policy.objects.create(policy=self._new_policy_name(),
|
328 |
|
quantity=0,
|
329 |
|
capacity=QH_PRACTICALLY_INFINITE,
|
330 |
|
import_limit=QH_PRACTICALLY_INFINITE,
|
331 |
|
export_limit=QH_PRACTICALLY_INFINITE)
|
332 |
|
h.policy = p
|
333 |
|
h.imported += amount
|
334 |
|
h.save()
|
335 |
|
|
336 |
221 |
def release_holding(self, context=None, release_holding=()):
|
337 |
222 |
rejected = []
|
338 |
223 |
append = rejected.append
|
339 |
224 |
|
340 |
|
for idx, (entity, resource, key) in enumerate(release_holding):
|
|
225 |
for idx, (entity, resource) in enumerate(release_holding):
|
341 |
226 |
try:
|
342 |
227 |
h = db_get_holding(entity=entity, resource=resource,
|
343 |
228 |
for_update=True)
|
... | ... | |
345 |
230 |
append(idx)
|
346 |
231 |
continue
|
347 |
232 |
|
348 |
|
if h.entity.key != key:
|
349 |
|
append(idx)
|
350 |
|
continue
|
351 |
|
|
352 |
233 |
if self._check_pending(entity, resource):
|
353 |
234 |
append(idx)
|
354 |
235 |
continue
|
355 |
236 |
|
356 |
237 |
q = self._actual_quantity(h)
|
357 |
238 |
if q > 0:
|
358 |
|
owner = h.entity.owner
|
359 |
|
self._increase_resource(owner, resource, q)
|
|
239 |
append(idx)
|
|
240 |
continue
|
360 |
241 |
|
361 |
242 |
h.delete()
|
362 |
243 |
|
... | ... | |
364 |
245 |
raise QuotaholderError(rejected)
|
365 |
246 |
return rejected
|
366 |
247 |
|
367 |
|
def list_resources(self, context=None, entity=None, key=None):
|
368 |
|
try:
|
369 |
|
e = Entity.objects.get(entity=entity)
|
370 |
|
except Entity.DoesNotExist:
|
371 |
|
m = "No such entity '%s'" % (entity,)
|
372 |
|
raise NoEntityError(m)
|
373 |
|
|
374 |
|
if e.key != key:
|
375 |
|
m = "Invalid key for entity '%s'" % (entity,)
|
376 |
|
raise InvalidKeyError(m)
|
377 |
|
|
378 |
|
holdings = e.holding_set.filter(entity=entity)
|
|
248 |
def list_resources(self, context=None, entity=None):
|
|
249 |
holdings = Holding.objects.filter(entity=entity)
|
379 |
250 |
resources = [h.resource for h in holdings]
|
380 |
251 |
return resources
|
381 |
252 |
|
... | ... | |
385 |
256 |
holdings_list = []
|
386 |
257 |
append = holdings_list.append
|
387 |
258 |
|
388 |
|
for entity, key in list_holdings:
|
389 |
|
try:
|
390 |
|
e = Entity.objects.get(entity=entity)
|
391 |
|
if e.key != key:
|
392 |
|
raise Entity.DoesNotExist("wrong key")
|
393 |
|
except Entity.DoesNotExist:
|
|
259 |
for entity in list_holdings:
|
|
260 |
holdings = list(Holding.objects.filter(entity=entity))
|
|
261 |
if not holdings:
|
394 |
262 |
reject(entity)
|
395 |
263 |
continue
|
396 |
264 |
|
397 |
|
holdings = e.holding_set.filter(entity=entity)
|
398 |
265 |
append([[entity, h.resource,
|
399 |
266 |
h.imported, h.exported, h.returned, h.released]
|
400 |
267 |
for h in holdings])
|
... | ... | |
405 |
272 |
quotas = []
|
406 |
273 |
append = quotas.append
|
407 |
274 |
|
408 |
|
entities = set(e for e, r, k in get_quota)
|
|
275 |
entities = set(e for e, r in get_quota)
|
409 |
276 |
hs = Holding.objects.select_related().filter(entity__in=entities)
|
410 |
277 |
holdings = {}
|
411 |
278 |
for h in hs:
|
412 |
|
holdings[(h.entity_id, h.resource)] = h
|
|
279 |
holdings[(h.entity, h.resource)] = h
|
413 |
280 |
|
414 |
|
for entity, resource, key in get_quota:
|
|
281 |
for entity, resource in get_quota:
|
415 |
282 |
try:
|
416 |
283 |
h = holdings[(entity, resource)]
|
417 |
284 |
except:
|
418 |
285 |
continue
|
419 |
286 |
|
420 |
|
if h.entity.key != key:
|
421 |
|
continue
|
422 |
|
|
423 |
287 |
p = h.policy
|
424 |
288 |
|
425 |
|
append((h.entity.entity, h.resource, p.quantity, p.capacity,
|
|
289 |
append((h.entity, h.resource, p.quantity, p.capacity,
|
426 |
290 |
p.import_limit, p.export_limit,
|
427 |
291 |
h.imported, h.exported,
|
428 |
292 |
h.returned, h.released,
|
... | ... | |
436 |
300 |
|
437 |
301 |
q_holdings = Q()
|
438 |
302 |
entities = []
|
439 |
|
for (entity, resource, key, _, _, _, _, _) in set_quota:
|
|
303 |
for (entity, resource, _, _, _, _, _) in set_quota:
|
440 |
304 |
entities.append(entity)
|
441 |
305 |
|
442 |
306 |
hs = Holding.objects.filter(entity__in=entities).select_for_update()
|
443 |
307 |
holdings = {}
|
444 |
308 |
for h in hs:
|
445 |
|
holdings[(h.entity_id, h.resource)] = h
|
446 |
|
|
447 |
|
entities = Entity.objects.in_bulk(entities)
|
|
309 |
holdings[(h.entity, h.resource)] = h
|
448 |
310 |
|
449 |
311 |
old_policies = []
|
450 |
312 |
|
451 |
|
for (entity, resource, key,
|
|
313 |
for (entity, resource,
|
452 |
314 |
quantity, capacity,
|
453 |
315 |
import_limit, export_limit, flags) in set_quota:
|
454 |
316 |
|
455 |
|
e = entities.get(entity, None)
|
456 |
|
if e is None or e.key != key:
|
457 |
|
append((entity, resource))
|
458 |
|
continue
|
459 |
|
|
460 |
317 |
policy = newname('policy_')
|
461 |
318 |
newp = Policy(policy=policy,
|
462 |
319 |
quantity=quantity,
|
... | ... | |
470 |
327 |
h.policy = newp
|
471 |
328 |
h.flags = flags
|
472 |
329 |
except KeyError:
|
473 |
|
h = Holding(entity=e, resource=resource,
|
|
330 |
h = Holding(entity=entity, resource=resource,
|
474 |
331 |
policy=newp, flags=flags)
|
475 |
332 |
|
476 |
333 |
# the order is intentionally reversed so that it
|
... | ... | |
507 |
364 |
sources = sub_quota + add_quota
|
508 |
365 |
q_holdings = Q()
|
509 |
366 |
entities = []
|
510 |
|
for (entity, resource, key, _, _, _, _) in sources:
|
|
367 |
for (entity, resource, _, _, _, _) in sources:
|
511 |
368 |
entities.append(entity)
|
512 |
369 |
|
513 |
370 |
hs = Holding.objects.filter(entity__in=entities).select_for_update()
|
514 |
371 |
holdings = {}
|
515 |
372 |
for h in hs:
|
516 |
|
holdings[(h.entity_id, h.resource)] = h
|
517 |
|
|
518 |
|
entities = Entity.objects.in_bulk(entities)
|
|
373 |
holdings[(h.entity, h.resource)] = h
|
519 |
374 |
|
520 |
375 |
pids = [h.policy_id for h in hs]
|
521 |
376 |
policies = Policy.objects.in_bulk(pids)
|
... | ... | |
523 |
378 |
old_policies = []
|
524 |
379 |
|
525 |
380 |
for removing, source in [(True, sub_quota), (False, add_quota)]:
|
526 |
|
for (entity, resource, key,
|
|
381 |
for (entity, resource,
|
527 |
382 |
quantity, capacity,
|
528 |
383 |
import_limit, export_limit) in source:
|
529 |
384 |
|
530 |
|
e = entities.get(entity, None)
|
531 |
|
if e is None or e.key != key:
|
532 |
|
append((entity, resource))
|
533 |
|
continue
|
534 |
|
|
535 |
385 |
try:
|
536 |
386 |
h = holdings[(entity, resource)]
|
537 |
387 |
old_policies.append(h.policy_id)
|
... | ... | |
543 |
393 |
if removing:
|
544 |
394 |
append((entity, resource))
|
545 |
395 |
continue
|
546 |
|
h = Holding(entity=e, resource=resource, flags=0)
|
|
396 |
|
|
397 |
h = Holding(entity=entity, resource=resource, flags=0)
|
547 |
398 |
p = None
|
548 |
399 |
|
549 |
400 |
policy = newname('policy_')
|
... | ... | |
622 |
473 |
context=None,
|
623 |
474 |
clientkey=None,
|
624 |
475 |
target=None,
|
625 |
|
key=None,
|
626 |
476 |
name=None,
|
627 |
477 |
provisions=()):
|
628 |
478 |
|
629 |
|
try:
|
630 |
|
t = Entity.objects.get(entity=target)
|
631 |
|
except Entity.DoesNotExist:
|
632 |
|
m = "No target entity '%s'" % (target,)
|
633 |
|
raise NoEntityError(m)
|
634 |
|
else:
|
635 |
|
if t.key != key:
|
636 |
|
m = "Invalid key for target entity '%s'" % (target,)
|
637 |
|
raise InvalidKeyError(m)
|
638 |
|
|
639 |
479 |
create = Commission.objects.create
|
640 |
|
commission = create(entity_id=target, clientkey=clientkey, name=name)
|
|
480 |
commission = create(entity=target, clientkey=clientkey, name=name)
|
641 |
481 |
serial = commission.serial
|
642 |
482 |
|
643 |
483 |
checked = []
|
... | ... | |
654 |
494 |
raise DuplicateError(m)
|
655 |
495 |
checked.append(ent_res)
|
656 |
496 |
|
657 |
|
try:
|
658 |
|
e = Entity.objects.get(entity=entity)
|
659 |
|
except Entity.DoesNotExist:
|
660 |
|
m = "No source entity '%s'" % (entity,)
|
661 |
|
raise NoEntityError(m)
|
662 |
|
|
663 |
497 |
release = 0
|
664 |
498 |
if quantity < 0:
|
665 |
499 |
release = 1
|
... | ... | |
781 |
615 |
limit=limit)
|
782 |
616 |
|
783 |
617 |
Provision.objects.create(serial=commission,
|
784 |
|
entity=e,
|
|
618 |
entity=entity,
|
785 |
619 |
resource=resource,
|
786 |
620 |
quantity=quantity)
|
787 |
621 |
if release:
|
... | ... | |
808 |
642 |
kwargs = {
|
809 |
643 |
'serial': commission.serial,
|
810 |
644 |
'name': commission.name,
|
811 |
|
'source': s_entity.entity,
|
812 |
|
'target': t_entity.entity,
|
|
645 |
'source': s_entity,
|
|
646 |
'target': t_entity,
|
813 |
647 |
'resource': provision.resource,
|
814 |
648 |
'source_quantity': s_policy.quantity,
|
815 |
649 |
'source_capacity': s_policy.capacity,
|
... | ... | |
852 |
686 |
provisions = db_filter_provision(serial=serial, for_update=True)
|
853 |
687 |
for pv in provisions:
|
854 |
688 |
try:
|
855 |
|
h = db_get_holding(entity=pv.entity.entity,
|
|
689 |
h = db_get_holding(entity=pv.entity,
|
856 |
690 |
resource=pv.resource, for_update=True)
|
857 |
691 |
th = db_get_holding(entity=t, resource=pv.resource,
|
858 |
692 |
for_update=True)
|
... | ... | |
898 |
732 |
provisions = db_filter_provision(serial=serial, for_update=True)
|
899 |
733 |
for pv in provisions:
|
900 |
734 |
try:
|
901 |
|
h = db_get_holding(entity=pv.entity.entity,
|
|
735 |
h = db_get_holding(entity=pv.entity,
|
902 |
736 |
resource=pv.resource, for_update=True)
|
903 |
737 |
th = db_get_holding(entity=t, resource=pv.resource,
|
904 |
738 |
for_update=True)
|
... | ... | |
954 |
788 |
|
955 |
789 |
return
|
956 |
790 |
|
957 |
|
def release_entity(self, context=None, release_entity=()):
|
958 |
|
rejected = []
|
959 |
|
append = rejected.append
|
960 |
|
for entity, key in release_entity:
|
961 |
|
try:
|
962 |
|
e = db_get_entity(entity=entity, key=key, for_update=True)
|
963 |
|
except Entity.DoesNotExist:
|
964 |
|
append(entity)
|
965 |
|
continue
|
966 |
|
|
967 |
|
if e.entities.count() != 0:
|
968 |
|
append(entity)
|
969 |
|
continue
|
970 |
|
|
971 |
|
if e.holding_set.count() != 0:
|
972 |
|
append(entity)
|
973 |
|
continue
|
974 |
|
|
975 |
|
e.delete()
|
976 |
|
|
977 |
|
if rejected:
|
978 |
|
raise QuotaholderError(rejected)
|
979 |
|
return rejected
|
980 |
|
|
981 |
791 |
def get_timeline(self, context=None, after="", before="Z", get_timeline=()):
|
982 |
792 |
entity_set = set()
|
983 |
793 |
e_add = entity_set.add
|
984 |
794 |
resource_set = set()
|
985 |
795 |
r_add = resource_set.add
|
986 |
796 |
|
987 |
|
for entity, resource, key in get_timeline:
|
|
797 |
for entity, resource in get_timeline:
|
988 |
798 |
if entity not in entity_set:
|
989 |
|
try:
|
990 |
|
e = Entity.objects.get(entity=entity, key=key)
|
991 |
|
e_add(entity)
|
992 |
|
except Entity.DoesNotExist:
|
993 |
|
continue
|
|
799 |
e_add(entity)
|
994 |
800 |
|
995 |
801 |
r_add((entity, resource))
|
996 |
802 |
|