Statistics
| Branch: | Tag: | Revision:

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