Statistics
| Branch: | Tag: | Revision:

root / commissioning / servers / quotaholder / django_backend / callpoint.py @ eec92c03

History | View | Annotate | Download (14.5 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
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
            Entity.objects.create(entity=entity, owner=owner, key=key)
70

    
71
        return rejected
72

    
73
    def list_entities(self, context={}, entity=None, key=None):
74
        try:
75
            e = Entity.objects.get(entity=entity, key=key)
76
        except Entity.DoesNotExist:
77
            m = "Entity '%s' does not exist" % (entity,)
78
            raise NoEntityError(m)
79

    
80
        children = e.entities.all()
81
        entities = [e.entity for e in children]
82
        return entities
83

    
84
    def get_entity(self, context={}, get_entity=()):
85
        entities = []
86
        append = entities.append
87

    
88
        for entity, key in get_entity:
89
            try:
90
                Entity.objects.get(entity=entity, key=key)
91
            except Entity.DoesNotExist:
92
                continue
93

    
94
            append((entity, key))
95

    
96
        return entities
97

    
98
    def get_limits(self, context={}, get_limits=()):
99
        limits = []
100
        append = limits.append
101

    
102
        for entity, resource, key in get_limits:
103
            try:
104
                h = Holding.objects.get(entity=entity, resource=resource)
105
            except Policy.DoesNotExist:
106
                continue
107

    
108
            if h.entity.key != key:
109
                continue
110
            p = h.policy
111
            append((h.entity, h.resource, p.quantity, p.capacity,
112
                    p.import_limit, p.export_limit, h.flags))
113

    
114
        return limits
115

    
116
    def set_limits(self, context={}, set_limits=()):
117

    
118
        for (   policy, quantity, capacity,
119
                import_limit, export_limit  ) in set_limits:
120

    
121
                #XXX: create or replace?
122
                Policy.objects.create(  policy=policy,
123
                                        quantity=quantity,
124
                                        capacity=capacity,
125
                                        import_limit=import_limit,
126
                                        export_limit=export_limit   )
127

    
128
        return ()
129

    
130
    def get_holding(self, context={}, get_holding=()):
131
        holdings = []
132
        append = holdings.append
133

    
134
        for entity, resource, key in get_holding:
135
            try:
136
                h = Holding.objects.get(entity=entity, resource=resource)
137
            except Holding.DoesNotExist:
138
                continue
139

    
140
            if h.entity.key != key:
141
                continue
142

    
143
            append((h.entity, h.resource, h.policy,
144
                    h.imported, h.exported, h.flags))
145

    
146
        return holdings
147

    
148
    def set_holding(self, context={}, set_holding=()):
149
        rejected = []
150
        append = rejected.append
151

    
152
        for entity, resource, key, policy, flags in set_holding:
153
            try:
154
                e = Entity.objects.get(entity=entity, key=key)
155
            except Entity.DoesNotExist:
156
                append((entity, resource, policy))
157
                continue
158

    
159
            if e.key != key:
160
                append((entity, resource, policy))
161
                continue
162

    
163
            try:
164
                p = Policy.objects.get(policy=policy)
165
            except Policy.DoesNotExist:
166
                append((entity, resource, policy))
167
                continue
168

    
169
            try:
170
                h = Holding.objects.get(entity=entity, resource=resource)
171
                h.policy = p
172
                h.flags = flags
173
                h.save()
174
            except Holding.DoesNotExist:
175
                h = Holding.objects.create( entity=entity, resource=resource,
176
                                            policy=policy, flags=flags      )
177

    
178
        return rejected
179

    
180
    def list_resources(self, context={}, entity=None, key=None):
181
        try:
182
            e = Entity.objects.get()
183
        except Entity.DoesNotExist:
184
            m = "No such entity '%s'" % (entity,)
185
            raise NoEntityError(m)
186

    
187
        if e.key != key:
188
            m = "Invalid key for entity '%s'" % (entity,)
189
            raise InvalidKeyError(m)
190

    
191
        holdings = e.holdings.filter(entity=entity)
192
        resources = [h.resource for h in holdings]
193
        return resources
194

    
195
    def get_quota(self, context={}, get_quota=()):
196
        quotas = []
197
        append = quotas.append
198

    
199
        for entity, resource, key in get_quota:
200
            try:
201
                h = Holding.objects.get(entity=entity, resource=resource)
202
            except Holding.DoesNotExist:
203
                continue
204

    
205
            if h.entity.key != key:
206
                continue
207

    
208
            p = h.policy
209

    
210
            append((h.entity.entity, h.resource, p.quantity, p.capacity,
211
                    p.import_limit, p.export_limit,
212
                    h.imported, h.exported, h.flags))
213

    
214
        return quotas
215

    
216
    def set_quota(self, context={}, set_quota=()):
217
        rejected = []
218
        append = rejected.append
219

    
220
        for (   entity, resource, key,
221
                quantity, capacity,
222
                import_limit, export_limit, flags  ) in set_quota:
223

    
224
                p = None
225

    
226
                try:
227
                    h = Holding.objects.get(entity=entity, resource=resource)
228
                    if h.entity.key != key:
229
                        append((entity, resource))
230
                        continue
231
                    p = h.policy
232

    
233
                except Holding.DoesNotExist:
234
                    try:
235
                        e = Entity.objects.get(entity=entity)
236
                    except Entity.DoesNotExist:
237
                        append((entity, resource))
238
                        continue
239

    
240
                    if e.key != key:
241
                        append((entity, resource))
242
                        continue
243

    
244
                    h = None
245

    
246
                policy = newname('policy_')
247
                newp = Policy   (
248
                            policy=policy,
249
                            quantity=quantity,
250
                            capacity=capacity,
251
                            import_limit=import_limit,
252
                            export_limit=export_limit
253
                )
254

    
255
                if h is None:
256
                    h = Holding(entity=entity, resource=resource,
257
                                policy=newp, flags=flags)
258
                else:
259
                    h.policy = newp
260
                    h.flags = flags
261

    
262
                h.save()
263
                newp.save()
264

    
265
                if p is not None and p.holdings.count() == 0:
266
                    p.delete()
267

    
268
        return rejected
269

    
270
    def issue_commission(self,  context={}, clientkey=None,
271
                                target=None, key=None,
272
                                owner=None, ownerkey=None,
273
                                provisions=()               ):
274

    
275
        try:
276
            t = Entity.objects.get(entity=target)
277
        except Entity.DoesNotExist:
278
            create_entity = ((entity, owner, key, ownerkey),)
279
            rejected = self.create_entity(  context=context,
280
                                            create_entity=create_entity )
281
            if rejected:
282
                raise NoEntityError("No target entity '%s'" % (target,))
283

    
284
            t = Entity.objects.get(entity=target)
285
        else:
286
            if t.key != key:
287
                m = "Invalid key for target entity '%s'" % (target,)
288
                raise InvalidKeyError(m)
289

    
290
        commission = Commission.objects.create( entity=target,
291
                                                clientkey=clientkey )
292
        serial = commission.serial
293

    
294
        for entity, resource, quantity in provisions:
295
            try:
296
                h = Holding.objects.get(entity=entity, resource=resource)
297
            except Holding.DoesNotExist:
298
                m = ("There is not enough quantity "
299
                     "to allocate from in %s.%s" % (entity, resource))
300
                raise NoQuantityError(m)
301

    
302
            hp = h.policy
303

    
304
            if (hp.export_limit is not None and
305
                h.exporting + quantity > hp.export_limit):
306
                    m = ("Export limit reached for %s.%s" % (entity, resource))
307
                    raise ExportLimitError(m)
308

    
309
            if h.importing - h.exported + hp.quantity - quantity < 0:
310
                m = ("There is not enough quantity "
311
                     "to allocate from in %s.%s" % (entity, resource))
312
                raise NoQuantityError(m)
313

    
314
            try:
315
                th = Holding.objects.get(entity=target, resource=resource)
316
            except Holding.DoesNotExist:
317
                m = ("There is not enough capacity "
318
                     "to allocate into in %s.%s" % (target, resource))
319
                raise NoCapacityError(m)
320

    
321
            tp = th.policy
322

    
323
            if (tp.import_limit is not None and
324
                th.importing + quantity > tp.import_limit):
325
                    m = ("Import limit reached for %s.%s" % (target, resource))
326
                    raise ImportLimitError(m)
327

    
328
            if (    th.exported - th.importing - tp.quantity
329
                    + tp.capacity - quantity                ) < 0:
330

    
331
                    m = ("There is not enough capacity "
332
                         "to allocate into in %s.%s" % (target, resource))
333
                    raise NoCapacityError(m)
334

    
335
            Provision.objects.create(   serial=serial,
336
                                        entity=entity,
337
                                        resource=resource,
338
                                        quantity=quantity   )
339

    
340
            h.exporting += quantity
341
            th.importing += quantity
342

    
343
            h.save()
344
            th.save()
345

    
346
        return serial
347

    
348
    def accept_commission(self, context={}, clientkey=None, serial=None):
349
        try:
350
            c = Commission.objects.get(clientkey=clientkey, serial=serial)
351
        except Commission.DoesNotExist:
352
            return
353

    
354
        t = c.entity
355

    
356
        provisions = Provision.objects.filter(  clientkey=clientkey,
357
                                                serial=serial       )
358
        for pv in provisions:
359
            pv.entity,
360
            pv.resource
361
            try:
362
                h = Holding.objects.get(entity=pv.entity.entity,
363
                                        resource=pv.resource    )
364
                th = Holding.objects.get(entity=t, resource=pv.resource)
365
            except Holding.DoesNotExist:
366
                m = "Corrupted provision"
367
                raise CorruptedError(m)
368

    
369
            h.exported += pv.quantity
370
            th.imported += pv.quantity
371
            h.save()
372
            th.save()
373
            pv.delete()
374

    
375
        return
376

    
377
    def reject_commission(self, context={}, clientkey=None, serial=None):
378
        try:
379
            c = Commission.objects.get(clientkey=clientkey, serial=serial)
380
        except Commission.DoesNotExist:
381
            return
382

    
383
        t = c.entity
384

    
385
        provisions = Provision.objects.filter(  clientkey=clientkey,
386
                                                serial=serial       )
387
        for pv in provisions:
388
            pv.entity,
389
            pv.resource
390
            try:
391
                h = Holding.objects.get(entity=pv.entity.entity,
392
                                        resource=pv.resource    )
393
                th = Holding.objects.get(entity=t, resource=pv.resource)
394
            except Holding.DoesNotExist:
395
                m = "Corrupted provision"
396
                raise CorruptedError(m)
397

    
398
            h.exporting -= pv.quantity
399
            th.importing -= pv.quantity
400
            h.save()
401
            th.save()
402
            pv.delete()
403

    
404
        return
405

    
406
    def get_pending_commissions(self, context={}, clientkey=None):
407
        pending = Commission.objects.filter(clientkey=clientkey)
408
        return pending
409

    
410
    def resolve_pending_commissions(self,   context={}, clientkey=None,
411
                                            max_serial=None, accept_set=()  ):
412
        accept_set = set(accept_set)
413
        pending = self.get_pending_commissions(clientkey=clientkey)
414
        pending = sorted(pending)
415

    
416
        accept = self.accept_commission
417
        reject = self.reject_commission
418

    
419
        for serial in pending:
420
            if serial > max_serial:
421
                break
422

    
423
            if serial in accept_set:
424
                accept(clientkey=clientkey, serial=serial)
425
            else:
426
                reject(clientkey=clientkey, serial=serial)
427

    
428
        return
429

    
430
    def release_entity(self, context={}, release_entity=()):
431
        rejected = []
432
        append = rejected.append
433
        for entity, key in release_entity:
434
            try:
435
                e = Entity.objects.get(entity=entity, key=key)
436
            except Entity.DoesNotExist:
437
                append(entity)
438
                continue
439

    
440
            if e.entities.count() != 0:
441
                append(entity)
442
                continue
443

    
444
            if e.holdings.count() != 0:
445
                append(entity)
446
                continue
447

    
448
            e.delete()
449

    
450
        return rejected
451

    
452
API_Callpoint = QuotaholderDjangoDBCallpoint