callpoint.py 28.3 KB
Newer Older
Giorgos Korfiatis's avatar
Giorgos Korfiatis committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
# Copyright 2012 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
#   1. Redistributions of source code must retain the above
#      copyright notice, this list of conditions and the following
#      disclaimer.
#
#   2. Redistributions in binary form must reproduce the above
#      copyright notice, this list of conditions and the following
#      disclaimer in the documentation and/or other materials
#      provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and
# documentation are those of the authors and should not be
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.

34 35
from synnefo.lib.quotaholder.api import (
                            QuotaholderAPI,
36
                            InvalidKeyError, NoEntityError,
37
                            NoQuantityError, NoCapacityError,
38 39
                            ExportLimitError, ImportLimitError,
                            DuplicateError)
40

41 42 43 44
from synnefo.lib.commissioning import \
    Callpoint, CorruptedError, InvalidDataError
from synnefo.lib.commissioning.utils.newname import newname

Giorgos Korfiatis's avatar
Giorgos Korfiatis committed
45
from django.db.models import Q
46
from django.db import transaction, IntegrityError
Georgios D. Tsoukalas's avatar
Georgios D. Tsoukalas committed
47
from .models import (Holder, Entity, Policy, Holding,
48
                     Commission, Provision, ProvisionLog, now)
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87


class QuotaholderDjangoDBCallpoint(Callpoint):

    api_spec = QuotaholderAPI()

    http_exc_lookup = {
        CorruptedError:   550,
        InvalidDataError: 400,
        InvalidKeyError:  401,
        NoEntityError:    404,
        NoQuantityError:  413,
        NoCapacityError:  413,
    }

    def init_connection(self, connection):
        if connection is not None:
            raise ValueError("Cannot specify connection args with %s" %
                             type(self).__name__)
        pass

    def commit(self):
        transaction.commit()

    def rollback(self):
        transaction.rollback()

    def do_make_call(self, call_name, data):
        call_fn = getattr(self, call_name, None)
        if not call_fn:
            m = "cannot find call '%s'" % (call_name,)
            raise CorruptedError(m)

        return call_fn(**data)

    def create_entity(self, context={}, create_entity=()):
        rejected = []
        append = rejected.append

88
        for idx, (entity, owner, key, ownerkey) in enumerate(create_entity):
89 90 91
            try:
                owner = Entity.objects.get(entity=owner, key=ownerkey)
            except Entity.DoesNotExist:
92
                append(idx)
93
                continue
94

95
            try:
96 97
                e = Entity.objects.get(entity=entity)
                append(idx)
98
            except Entity.DoesNotExist:
99 100 101
                e = Entity.objects.create(entity=entity,
                                          owner=owner,
                                          key=key)
102 103
        return rejected

104 105 106 107 108 109 110 111 112
    def set_entity_key(self, context={}, set_entity_key=()):
        rejected = []
        append = rejected.append

        for entity, key, newkey in set_entity_key:
            try:
                e = Entity.objects.get(entity=entity, key=key)
            except Entity.DoesNotExist:
                append(entity)
113
                continue
114 115 116 117 118 119

            e.key = newkey
            e.save()

        return rejected

120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
    def list_entities(self, context={}, entity=None, key=None):
        try:
            e = Entity.objects.get(entity=entity, key=key)
        except Entity.DoesNotExist:
            m = "Entity '%s' does not exist" % (entity,)
            raise NoEntityError(m)

        children = e.entities.all()
        entities = [e.entity for e in children]
        return entities

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

        for entity, key in get_entity:
            try:
137
                e = Entity.objects.get(entity=entity, key=key)
138 139 140
            except Entity.DoesNotExist:
                continue

141
            append((entity, e.owner.entity))
142 143 144 145 146 147 148

        return entities

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

149
        for policy in get_limits:
150
            try:
151
                p = Policy.objects.get(policy=policy)
152 153 154
            except Policy.DoesNotExist:
                continue

155 156
            append((policy, p.quantity, p.capacity,
                    p.import_limit, p.export_limit))
157 158 159 160 161 162 163 164

        return limits

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

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

165 166 167 168 169 170 171 172 173 174 175 176 177 178
                try:
                    policy = Policy.objects.get(policy=policy)
                except Policy.DoesNotExist:
                    Policy.objects.create(  policy=policy,
                                            quantity=quantity,
                                            capacity=capacity,
                                            import_limit=import_limit,
                                            export_limit=export_limit   )
                else:
                    policy.quantity = quantity
                    policy.capacity = capacity
                    policy.export_limit = export_limit
                    policy.import_limit = import_limit
                    policy.save()
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194

        return ()

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

        for entity, resource, key in get_holding:
            try:
                h = Holding.objects.get(entity=entity, resource=resource)
            except Holding.DoesNotExist:
                continue

            if h.entity.key != key:
                continue

195
            append((h.entity.entity, h.resource, h.policy.policy,
196
                    h.imported, h.exported,
197
                    h.returned, h.released, h.flags))
198 199 200

        return holdings

Giorgos Korfiatis's avatar
Giorgos Korfiatis committed
201 202 203 204 205 206 207 208 209 210 211
    def _set_holding(self, entity, resource, policy, flags):
        try:
            h = Holding.objects.get(entity=entity, resource=resource)
            h.policy = p
            h.flags = flags
            h.save()
        except Holding.DoesNotExist:
            h = Holding.objects.create( entity=e, resource=resource,
                                        policy=p, flags=flags      )
        return h

212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
    def set_holding(self, context={}, set_holding=()):
        rejected = []
        append = rejected.append

        for entity, resource, key, policy, flags in set_holding:
            try:
                e = Entity.objects.get(entity=entity, key=key)
            except Entity.DoesNotExist:
                append((entity, resource, policy))
                continue

            if e.key != key:
                append((entity, resource, policy))
                continue

            try:
                p = Policy.objects.get(policy=policy)
            except Policy.DoesNotExist:
                append((entity, resource, policy))
                continue

            try:
                h = Holding.objects.get(entity=entity, resource=resource)
                h.policy = p
                h.flags = flags
                h.save()
            except Holding.DoesNotExist:
239 240
                h = Holding.objects.create( entity=e, resource=resource,
                                            policy=p, flags=flags      )
241 242 243

        return rejected

244
    def _init_holding(self, entity, resource, policy,
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
                          imported, exported, returned, released,
                          flags):
        try:
            h = Holding.objects.get(entity=entity, resource=resource)
        except Holding.DoesNotExist:
            h = Holding(entity=entity, resource=resource)

        h.policy = policy
        h.flags = flags
        h.imported=imported
        h.importing=imported
        h.exported=exported
        h.exporting=exported
        h.returned=returned
        h.returning=returned
        h.released=released
        h.releasing=released
        h.save()

264
    def init_holding(self, context={}, init_holding=()):
265 266 267
        rejected = []
        append = rejected.append

268
        for idx, sfh in enumerate(init_holding):
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
            (entity, resource, key, policy,
             imported, exported, returned, released,
             flags) = sfh
            try:
                e = Entity.objects.get(entity=entity, key=key)
            except Entity.DoesNotExist:
                append(idx)
                continue

            if e.key != key:
                append(idx)
                continue

            try:
                p = Policy.objects.get(policy=policy)
            except Policy.DoesNotExist:
                append(idx)
                continue

288
            self._init_holding(e, resource, p,
289 290 291 292 293
                                   imported, exported,
                                   returned, released,
                                   flags)
        return rejected

294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
    def reset_holding(self, context={}, reset_holding=()):
        rejected = []
        append = rejected.append

        for idx, tpl in enumerate(reset_holding):
            (entity, resource, key,
             imported, exported, returned, released) = tpl
            try:
                e = Entity.objects.get(entity=entity, key=key)
            except Entity.DoesNotExist:
                append(idx)
                continue

            try:
                h = Holding.objects.get(entity=entity, resource=resource)
                h.imported=imported
                h.importing=imported
                h.exported=exported
                h.exporting=exported
                h.returned=returned
                h.returning=returned
                h.released=released
                h.releasing=released
                h.save()
            except Holding.DoesNotExist:
                append(idx)
                continue

        return rejected

324 325 326 327
    def _check_pending(self, entity, resource):
        cs = Commission.objects.filter(entity=entity)
        cs = [c for c in cs if c.provisions.filter(resource=resource)]
        as_target = [c.serial for c in cs]
Giorgos Korfiatis's avatar
Giorgos Korfiatis committed
328

329 330 331 332
        ps = Provision.objects.filter(entity=entity, resource=resource)
        as_source = [p.serial.serial for p in ps]

        return as_target + as_source
Giorgos Korfiatis's avatar
Giorgos Korfiatis committed
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367

    def _actual_quantity(self, holding):
        hp = holding.policy
        return hp.quantity + (holding.imported + holding.returned -
                              holding.exported - holding.released)

    def _new_policy_name(self):
        return newname('policy_')

    def _increase_resource(self, entity, resource, amount):
        try:
            h = Holding.objects.get(entity=entity, resource=resource)
        except Holding.DoesNotExist:
            h = Holding(entity=entity, resource=resource)
            p = Policy.objects.create(policy=self._new_policy_name(),
                                      quantity=0)
            h.policy = p
        h.imported += amount
        h.save()

    def release_holding(self, context={}, release_holding=()):
        rejected = []
        append = rejected.append

        for idx, (entity, resource, key) in enumerate(release_holding):
            try:
                h = Holding.objects.get(entity=entity, resource=resource)
            except Holding.DoesNotExist:
                append(idx)
                continue

            if h.entity.key != key:
                append(idx)
                continue

368
            if self._check_pending(entity, resource):
Giorgos Korfiatis's avatar
Giorgos Korfiatis committed
369 370 371 372
                append(idx)
                continue

            q = self._actual_quantity(h)
Giorgos Korfiatis's avatar
Giorgos Korfiatis committed
373 374 375 376
            if q > 0:
                owner = h.entity.owner
                self._increase_resource(owner, resource, q)

Giorgos Korfiatis's avatar
Giorgos Korfiatis committed
377 378 379 380
            h.delete()

        return rejected

381 382
    def list_resources(self, context={}, entity=None, key=None):
        try:
383
            e = Entity.objects.get(entity=entity)
384 385 386 387 388 389 390 391
        except Entity.DoesNotExist:
            m = "No such entity '%s'" % (entity,)
            raise NoEntityError(m)

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

392
        holdings = e.holding_set.filter(entity=entity)
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
        resources = [h.resource for h in holdings]
        return resources

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

        for entity, resource, key in get_quota:
            try:
                h = Holding.objects.get(entity=entity, resource=resource)
            except Holding.DoesNotExist:
                continue

            if h.entity.key != key:
                continue

            p = h.policy

            append((h.entity.entity, h.resource, p.quantity, p.capacity,
                    p.import_limit, p.export_limit,
413
                    h.imported, h.exported,
414
                    h.returned, h.released,
415
                    h.flags))
416 417 418 419 420 421 422 423 424 425 426

        return quotas

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

        for (   entity, resource, key,
                quantity, capacity,
                import_limit, export_limit, flags  ) in set_quota:

427 428
                p = None

429 430 431 432 433
                try:
                    h = Holding.objects.get(entity=entity, resource=resource)
                    if h.entity.key != key:
                        append((entity, resource))
                        continue
434 435
                    p = h.policy

436
                except Holding.DoesNotExist:
437 438 439 440 441
                    try:
                        e = Entity.objects.get(entity=entity)
                    except Entity.DoesNotExist:
                        append((entity, resource))
                        continue
442

443 444 445 446 447 448 449 450
                    if e.key != key:
                        append((entity, resource))
                        continue

                    h = None

                policy = newname('policy_')
                newp = Policy   (
451 452 453 454 455 456 457
                            policy=policy,
                            quantity=quantity,
                            capacity=capacity,
                            import_limit=import_limit,
                            export_limit=export_limit
                )

458
                if h is None:
459
                    h = Holding(entity=e, resource=resource,
460 461 462 463 464
                                policy=newp, flags=flags)
                else:
                    h.policy = newp
                    h.flags = flags

465
                h.save()
466
                newp.save()
467

468
                if p is not None and p.holding_set.count() == 0:
469 470 471 472
                    p.delete()

        return rejected

Georgios D. Tsoukalas's avatar
Georgios D. Tsoukalas committed
473 474 475 476
    def issue_commission(self,  context     =   {},
                                clientkey   =   None,
                                target      =   None,
                                key         =   None,
477
                                name        =   None,
Georgios D. Tsoukalas's avatar
Georgios D. Tsoukalas committed
478
                                provisions  =   ()  ):
479 480 481 482

        try:
            t = Entity.objects.get(entity=target)
        except Entity.DoesNotExist:
483 484
            m = "No target entity '%s'" % (target,)
            raise NoEntityError(m)
485 486 487 488 489
        else:
            if t.key != key:
                m = "Invalid key for target entity '%s'" % (target,)
                raise InvalidKeyError(m)

490
        create = Commission.objects.create
491
        commission = create(entity_id=target, clientkey=clientkey, name=name)
492 493
        serial = commission.serial

494
        checked = []
495
        for entity, resource, quantity in provisions:
496 497 498 499 500 501 502

            ent_res = entity, resource
            if ent_res in checked:
                m = "Duplicate provision for %s.%s" % ent_res
                raise DuplicateError(m)
            checked.append(ent_res)

503 504 505 506 507 508
            try:
                e = Entity.objects.get(entity=entity)
            except Entity.DoesNotExist:
                m = "No source entity '%s'" % (entity,)
                raise NoEntityError(m)

509 510 511 512
            release = 0
            if quantity < 0:
                release = 1

513 514 515 516 517 518 519 520 521
            try:
                h = Holding.objects.get(entity=entity, resource=resource)
            except Holding.DoesNotExist:
                m = ("There is not enough quantity "
                     "to allocate from in %s.%s" % (entity, resource))
                raise NoQuantityError(m)

            hp = h.policy

522 523 524 525 526
            if (hp.export_limit is not None and
                h.exporting + quantity > hp.export_limit):
                    m = ("Export limit reached for %s.%s" % (entity, resource))
                    raise ExportLimitError(m)

527
            if hp.quantity is not None:
528
                available = (+ hp.quantity + h.imported + h.returned
529
                             - h.exporting - h.releasing)
Georgios D. Tsoukalas's avatar
Georgios D. Tsoukalas committed
530

531 532 533 534
                if available - quantity < 0:
                    m = ("There is not enough quantity "
                         "to allocate from in %s.%s" % (entity, resource))
                    raise NoQuantityError(m)
535 536 537 538 539 540 541 542 543 544

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

            tp = th.policy

545 546 547 548 549
            if (tp.import_limit is not None and
                th.importing + quantity > tp.import_limit):
                    m = ("Import limit reached for %s.%s" % (target, resource))
                    raise ImportLimitError(m)

550 551
            if tp.capacity is not None:
                capacity = (+ tp.capacity + th.exported + th.released
552
                            - th.importing - th.returning)
553

554 555 556 557
                if capacity - quantity < 0:
                        m = ("There is not enough capacity "
                             "to allocate into in %s.%s" % (target, resource))
                        raise NoCapacityError(m)
558

559
            Provision.objects.create(   serial      =   commission,
560
                                        entity      =   e,
561 562
                                        resource    =   resource,
                                        quantity    =   quantity   )
Georgios D. Tsoukalas's avatar
Georgios D. Tsoukalas committed
563
            if release:
564
                h.returning -= quantity
Georgios D. Tsoukalas's avatar
Georgios D. Tsoukalas committed
565 566 567 568
                th.releasing -= quantity
            else:
                h.exporting += quantity
                th.importing += quantity
569 570 571 572 573 574

            h.save()
            th.save()

        return serial

575
    def _log_provision(self, commission, s_holding, t_holding,
576 577
                             provision, log_time, reason):

578 579 580 581
        s_entity = s_holding.entity
        s_policy = s_holding.policy
        t_entity = t_holding.entity
        t_policy = t_holding.policy
582 583

        ProvisionLog.objects.create(
584
                        serial              =   commission.serial,
585
                        name                =   commission.name,
586 587
                        source              =   s_entity.entity,
                        target              =   t_entity.entity,
588
                        resource            =   provision.resource,
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604
                        source_quantity     =   s_policy.quantity,
                        source_capacity     =   s_policy.capacity,
                        source_import_limit =   s_policy.import_limit,
                        source_export_limit =   s_policy.export_limit,
                        source_imported     =   s_holding.imported,
                        source_exported     =   s_holding.exported,
                        source_returned     =   s_holding.returned,
                        source_released     =   s_holding.released,
                        target_quantity     =   t_policy.quantity,
                        target_capacity     =   t_policy.capacity,
                        target_import_limit =   t_policy.import_limit,
                        target_export_limit =   t_policy.export_limit,
                        target_imported     =   t_holding.imported,
                        target_exported     =   t_holding.exported,
                        target_returned     =   t_holding.returned,
                        target_released     =   t_holding.released,
605
                        delta_quantity      =   provision.quantity,
606
                        issue_time          =   commission.issue_time,
607 608 609
                        log_time            =   log_time,
                        reason              =   reason)

Georgios D. Tsoukalas's avatar
Georgios D. Tsoukalas committed
610
    def accept_commission(self, context={}, clientkey=None,
611
                                serials=(), reason=''):
612 613
        log_time = now()

614 615 616 617 618
        for serial in serials:
            try:
                c = Commission.objects.get(clientkey=clientkey, serial=serial)
            except Commission.DoesNotExist:
                return
619

620
            t = c.entity
621

622 623 624 625 626 627 628 629 630
            provisions = Provision.objects.filter(serial=serial)
            for pv in provisions:
                try:
                    h = Holding.objects.get(entity=pv.entity.entity,
                                            resource=pv.resource    )
                    th = Holding.objects.get(entity=t, resource=pv.resource)
                except Holding.DoesNotExist:
                    m = "Corrupted provision"
                    raise CorruptedError(m)
631

632 633 634 635
                quantity = pv.quantity
                release = 0
                if quantity < 0:
                    release = 1
Georgios D. Tsoukalas's avatar
Georgios D. Tsoukalas committed
636

637
                if release:
638
                    h.returned -= quantity
639 640 641 642
                    th.released -= quantity
                else:
                    h.exported += quantity
                    th.imported += quantity
Georgios D. Tsoukalas's avatar
Georgios D. Tsoukalas committed
643

644
                reason = 'ACCEPT:' + reason[-121:]
645
                self._log_provision(c, h, th, pv, log_time, reason)
646 647 648
                h.save()
                th.save()
                pv.delete()
649
            c.delete()
650 651 652

        return

Georgios D. Tsoukalas's avatar
Georgios D. Tsoukalas committed
653
    def reject_commission(self, context={}, clientkey=None,
654
                                serials=(), reason=''):
655 656
        log_time = now()

657 658 659 660 661
        for serial in serials:
            try:
                c = Commission.objects.get(clientkey=clientkey, serial=serial)
            except Commission.DoesNotExist:
                return
662

663
            t = c.entity
664

665 666 667 668 669 670 671 672 673
            provisions = Provision.objects.filter(serial=serial)
            for pv in provisions:
                try:
                    h = Holding.objects.get(entity=pv.entity.entity,
                                            resource=pv.resource)
                    th = Holding.objects.get(entity=t, resource=pv.resource)
                except Holding.DoesNotExist:
                    m = "Corrupted provision"
                    raise CorruptedError(m)
674

675 676 677 678
                quantity = pv.quantity
                release = 0
                if quantity < 0:
                    release = 1
Georgios D. Tsoukalas's avatar
Georgios D. Tsoukalas committed
679

680
                if release:
681
                    h.returning += quantity
682 683 684 685 686 687
                    th.releasing += quantity
                else:
                    h.exporting -= quantity
                    th.importing -= quantity

                reason = 'REJECT:' + reason[-121:]
688
                self._log_provision(c, h, th, pv, log_time, reason)
689 690 691
                h.save()
                th.save()
                pv.delete()
692
            c.delete()
693 694 695 696

        return

    def get_pending_commissions(self, context={}, clientkey=None):
697 698
        pending = Commission.objects.filter(clientkey=clientkey)\
                                    .values_list('serial', flat=True)
699 700 701 702 703
        return pending

    def resolve_pending_commissions(self,   context={}, clientkey=None,
                                            max_serial=None, accept_set=()  ):
        accept_set = set(accept_set)
704
        pending = self.get_pending_commissions(context=context, clientkey=clientkey)
705 706 707 708 709 710 711 712 713 714
        pending = sorted(pending)

        accept = self.accept_commission
        reject = self.reject_commission

        for serial in pending:
            if serial > max_serial:
                break

            if serial in accept_set:
715
                accept(context=context, clientkey=clientkey, serials=[serial])
716
            else:
717
                reject(context=context, clientkey=clientkey, serials=[serial])
718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734

        return

    def release_entity(self, context={}, release_entity=()):
        rejected = []
        append = rejected.append
        for entity, key in release_entity:
            try:
                e = Entity.objects.get(entity=entity, key=key)
            except Entity.DoesNotExist:
                append(entity)
                continue

            if e.entities.count() != 0:
                append(entity)
                continue

735
            if e.holding_set.count() != 0:
736 737 738 739 740 741 742
                append(entity)
                continue

            e.delete()

        return rejected

743
    def get_timeline(self, context={}, after="", before="Z", get_timeline=()):
Georgios D. Tsoukalas's avatar
Georgios D. Tsoukalas committed
744
        entity_set = set()
745 746 747
        e_add = entity_set.add
        resource_set = set()
        r_add = resource_set.add
Georgios D. Tsoukalas's avatar
Georgios D. Tsoukalas committed
748

749 750 751 752 753 754 755 756 757
        for entity, resource, key in get_timeline:
            if entity not in entity_set:
                try:
                    e = Entity.objects.get(entity=entity, key=key)
                    e_add(entity)
                except Entity.DoesNotExist:
                    continue

            r_add((entity, resource))
Georgios D. Tsoukalas's avatar
Georgios D. Tsoukalas committed
758 759 760 761

        chunk_size = 65536
        nr = 0
        timeline = []
762
        append = timeline.append
763 764
        filterlogs = ProvisionLog.objects.filter
        if entity_set:
Georgios D. Tsoukalas's avatar
Georgios D. Tsoukalas committed
765
            q_entity = Q(source__in = entity_set) | Q(target__in = entity_set)
766 767 768 769 770 771
        else:
            q_entity = Q()

        while 1:
            logs = filterlogs(  q_entity,
                                issue_time__gt      =   after,
Georgios D. Tsoukalas's avatar
Georgios D. Tsoukalas committed
772
                                issue_time__lte     =   before,
773
                                reason__startswith  =   'ACCEPT:'   )
Georgios D. Tsoukalas's avatar
Georgios D. Tsoukalas committed
774 775

            logs = logs.order_by('issue_time')
776
            #logs = logs.values()
Georgios D. Tsoukalas's avatar
Georgios D. Tsoukalas committed
777 778 779 780
            logs = logs[:chunk_size]
            nr += len(logs)
            if not logs:
                break
781 782 783 784 785
            for g in logs:
                if ((g.source, g.resource) not in resource_set
                    or (g.target, g.resource) not in resource_set):
                        continue

786 787 788 789 790 791 792 793 794 795 796 797
                o = {
                    'serial'                    :   g.serial,
                    'source'                    :   g.source,
                    'target'                    :   g.target,
                    'resource'                  :   g.resource,
                    'name'                      :   g.name,
                    'quantity'                  :   g.delta_quantity,
                    'source_allocated'          :   g.source_allocated(),
                    'source_allocated_through'  :   g.source_allocated_through(),
                    'source_inbound'            :   g.source_inbound(),
                    'source_inbound_through'    :   g.source_inbound_through(),
                    'source_outbound'           :   g.source_outbound(),
Georgios D. Tsoukalas's avatar
Georgios D. Tsoukalas committed
798
                    'source_outbound_through'   :   g.source_outbound_through(),
799 800 801 802 803 804 805 806 807 808
                    'target_allocated'          :   g.target_allocated(),
                    'target_allocated_through'  :   g.target_allocated_through(),
                    'target_inbound'            :   g.target_inbound(),
                    'target_inbound_through'    :   g.target_inbound_through(),
                    'target_outbound'           :   g.target_outbound(),
                    'target_outbound_through'   :   g.target_outbound_through(),
                    'issue_time'                :   g.issue_time,
                    'log_time'                  :   g.log_time,
                    'reason'                    :   g.reason,
                }
809

810
                append(o)
811 812

            after = g.issue_time
Georgios D. Tsoukalas's avatar
Georgios D. Tsoukalas committed
813 814 815 816 817 818
            if after >= before:
                break

        return timeline


819
API_Callpoint = QuotaholderDjangoDBCallpoint
Georgios D. Tsoukalas's avatar
Georgios D. Tsoukalas committed
820