Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / quotas / management / commands / cyclades-usage-verify.py @ ccfbf77b

History | View | Annotate | Download (4.7 kB)

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

    
34
from django.core.management.base import BaseCommand
35
from optparse import make_option
36

    
37

    
38
from synnefo import quotas
39
from synnefo.quotas.util import (get_db_holdings, get_quotaholder_holdings,
40
                                 transform_quotas)
41
from synnefo.webproject.management.utils import pprint_table
42
from synnefo.settings import CYCLADES_ASTAKOS_SERVICE_TOKEN as ASTAKOS_TOKEN
43

    
44

    
45
class Command(BaseCommand):
46
    help = """Reconcile quotas of Astakos with Cyclades DB.
47

48
    Detect unsynchronized quotas between Astakos and Cyclades DB and
49
    synchronize them if specified so.
50

51
    """
52
    option_list = BaseCommand.option_list + (
53
        make_option("--userid", dest="userid",
54
                    default=None,
55
                    help="Reconcile resources only for this user"),
56
        make_option("--fix", dest="fix",
57
                    default=False,
58
                    action="store_true",
59
                    help="Synchronize Astakos quotas with Cyclades DB."),
60
        make_option("--force",
61
                    default=False,
62
                    action="store_true",
63
                    help="Override Astakos quotas. Force Astakos to impose"
64
                         " the Cyclades quota, independently of their value.")
65
    )
66

    
67
    def handle(self, *args, **options):
68
        write = self.stdout.write
69
        userid = options['userid']
70

    
71
        # Get holdings from Cyclades DB
72
        db_holdings = get_db_holdings(userid)
73
        # Get holdings from QuotaHolder
74
        qh_holdings = get_quotaholder_holdings(userid)
75

    
76
        users = set(db_holdings.keys())
77
        users.update(qh_holdings.keys())
78
        # Remove 'None' user
79
        users.discard(None)
80

    
81
        unsynced = []
82
        for user in users:
83
            db = db_holdings.get(user, {})
84
            qh_all = qh_holdings.get(user, {})
85
            # Assuming only one source
86
            qh = qh_all.get(quotas.DEFAULT_SOURCE, {})
87
            qh = transform_quotas(qh)
88
            for resource in quotas.RESOURCES:
89
                db_value = db.pop(resource, 0)
90
                qh_value, _, qh_pending = qh.pop(resource, (0, 0))
91
                if qh_pending:
92
                    write("Pending commission. User '%s', resource '%s'.\n" %
93
                          (user, resource))
94
                    continue
95
                if db_value != qh_value:
96
                    data = (user, resource, db_value, qh_value)
97
                    unsynced.append(data)
98

    
99
        headers = ("User", "Resource", "Database", "Quotaholder")
100
        if unsynced:
101
            pprint_table(self.stderr, unsynced, headers)
102
            if options["fix"]:
103
                qh = quotas.Quotaholder.get()
104
                request = {}
105
                request["force"] = options["force"]
106
                request["auto_accept"] = True
107
                request["provisions"] = map(create_provision, unsynced)
108
                qh.issue_commission(ASTAKOS_TOKEN, request)
109
        else:
110
            write("Everything in sync.\n")
111

    
112

    
113
def create_provision(provision_info):
114
    user, resource, db_value, qh_value = provision_info
115
    return {"holder": user,
116
            "source": quotas.DEFAULT_SOURCE,
117
            "resource": resource,
118
            "quantity": db_value - qh_value}