Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / management / commands / reconcile-resources-astakos.py @ f8cac8c7

History | View | Annotate | Download (6.7 kB)

1 3f5851eb Giorgos Korfiatis
# Copyright 2013 GRNET S.A. All rights reserved.
2 3f5851eb Giorgos Korfiatis
#
3 3f5851eb Giorgos Korfiatis
# Redistribution and use in source and binary forms, with or
4 3f5851eb Giorgos Korfiatis
# without modification, are permitted provided that the following
5 3f5851eb Giorgos Korfiatis
# conditions are met:
6 3f5851eb Giorgos Korfiatis
#
7 3f5851eb Giorgos Korfiatis
#   1. Redistributions of source code must retain the above
8 3f5851eb Giorgos Korfiatis
#      copyright notice, this list of conditions and the following
9 3f5851eb Giorgos Korfiatis
#      disclaimer.
10 3f5851eb Giorgos Korfiatis
#
11 3f5851eb Giorgos Korfiatis
#   2. Redistributions in binary form must reproduce the above
12 3f5851eb Giorgos Korfiatis
#      copyright notice, this list of conditions and the following
13 3f5851eb Giorgos Korfiatis
#      disclaimer in the documentation and/or other materials
14 3f5851eb Giorgos Korfiatis
#      provided with the distribution.
15 3f5851eb Giorgos Korfiatis
#
16 3f5851eb Giorgos Korfiatis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 3f5851eb Giorgos Korfiatis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 3f5851eb Giorgos Korfiatis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 3f5851eb Giorgos Korfiatis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 3f5851eb Giorgos Korfiatis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 3f5851eb Giorgos Korfiatis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 3f5851eb Giorgos Korfiatis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 3f5851eb Giorgos Korfiatis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 3f5851eb Giorgos Korfiatis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 3f5851eb Giorgos Korfiatis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 3f5851eb Giorgos Korfiatis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 3f5851eb Giorgos Korfiatis
# POSSIBILITY OF SUCH DAMAGE.
28 3f5851eb Giorgos Korfiatis
#
29 3f5851eb Giorgos Korfiatis
# The views and conclusions contained in the software and
30 3f5851eb Giorgos Korfiatis
# documentation are those of the authors and should not be
31 3f5851eb Giorgos Korfiatis
# interpreted as representing official policies, either expressed
32 3f5851eb Giorgos Korfiatis
# or implied, of GRNET S.A.
33 3f5851eb Giorgos Korfiatis
34 3f5851eb Giorgos Korfiatis
from optparse import make_option
35 f8cac8c7 Giorgos Korfiatis
from datetime import datetime
36 3f5851eb Giorgos Korfiatis
37 3f5851eb Giorgos Korfiatis
from django.core.management.base import BaseCommand, CommandError
38 a3e3917f Giorgos Korfiatis
from django.db import transaction
39 3f5851eb Giorgos Korfiatis
40 f8cac8c7 Giorgos Korfiatis
from snf_django.utils import reconcile
41 d758784b Christos Stavrakakis
from snf_django.management.utils import pprint_table
42 d9f634a2 Giorgos Korfiatis
from astakos.im.models import Component, AstakosUser
43 f8cac8c7 Giorgos Korfiatis
from astakos.im import quotas
44 3f5851eb Giorgos Korfiatis
from astakos.im.functions import count_pending_app
45 3f5851eb Giorgos Korfiatis
import astakos.quotaholder_app.callpoint as qh
46 205cc8d3 Giorgos Korfiatis
import astakos.quotaholder_app.exception as qh_exception
47 3f5851eb Giorgos Korfiatis
48 3f5851eb Giorgos Korfiatis
49 3f5851eb Giorgos Korfiatis
class Command(BaseCommand):
50 3f5851eb Giorgos Korfiatis
    help = """Reconcile resource usage of Quotaholder with Astakos DB.
51 3f5851eb Giorgos Korfiatis

52 3f5851eb Giorgos Korfiatis
    Detect unsynchronized usage between Quotaholder and Astakos DB resources
53 3f5851eb Giorgos Korfiatis
    and synchronize them if specified so.
54 3f5851eb Giorgos Korfiatis

55 3f5851eb Giorgos Korfiatis
    """
56 3f5851eb Giorgos Korfiatis
57 3f5851eb Giorgos Korfiatis
    option_list = BaseCommand.option_list + (
58 3f5851eb Giorgos Korfiatis
        make_option("--userid", dest="userid",
59 3f5851eb Giorgos Korfiatis
                    default=None,
60 3f5851eb Giorgos Korfiatis
                    help="Reconcile resources only for this user"),
61 f8cac8c7 Giorgos Korfiatis
        make_option("--project",
62 f8cac8c7 Giorgos Korfiatis
                    help="Reconcile resources only for this project"),
63 3f5851eb Giorgos Korfiatis
        make_option("--fix", dest="fix",
64 3f5851eb Giorgos Korfiatis
                    default=False,
65 3f5851eb Giorgos Korfiatis
                    action="store_true",
66 3f5851eb Giorgos Korfiatis
                    help="Synchronize Quotaholder with Astakos DB."),
67 3f5851eb Giorgos Korfiatis
        make_option("--force",
68 3f5851eb Giorgos Korfiatis
                    default=False,
69 3f5851eb Giorgos Korfiatis
                    action="store_true",
70 3f5851eb Giorgos Korfiatis
                    help="Override Quotaholder. Force Quotaholder to impose"
71 3f5851eb Giorgos Korfiatis
                         " the quota, independently of their value.")
72 3f5851eb Giorgos Korfiatis
    )
73 3f5851eb Giorgos Korfiatis
74 a3e3917f Giorgos Korfiatis
    @transaction.commit_on_success
75 3f5851eb Giorgos Korfiatis
    def handle(self, *args, **options):
76 d9a7f0bb Giorgos Korfiatis
        write = self.stderr.write
77 3f5851eb Giorgos Korfiatis
        force = options['force']
78 3f5851eb Giorgos Korfiatis
        userid = options['userid']
79 f8cac8c7 Giorgos Korfiatis
        project = options['project']
80 f8cac8c7 Giorgos Korfiatis
81 f8cac8c7 Giorgos Korfiatis
        RESOURCES = [quotas.PENDING_APP_RESOURCE]
82 3f5851eb Giorgos Korfiatis
83 3f5851eb Giorgos Korfiatis
        try:
84 d9f634a2 Giorgos Korfiatis
            astakos = Component.objects.get(name="astakos")
85 d9f634a2 Giorgos Korfiatis
        except Component.DoesNotExist:
86 d9f634a2 Giorgos Korfiatis
            raise CommandError("Component 'astakos' not found.")
87 3f5851eb Giorgos Korfiatis
88 3f5851eb Giorgos Korfiatis
        query = [userid] if userid is not None else None
89 f8cac8c7 Giorgos Korfiatis
        qh_holdings = quotas.service_get_quotas(astakos, query)
90 f8cac8c7 Giorgos Korfiatis
        query = [project] if project is not None else None
91 f8cac8c7 Giorgos Korfiatis
        qh_project_holdings = quotas.service_get_project_quotas(astakos, query)
92 3f5851eb Giorgos Korfiatis
93 3f5851eb Giorgos Korfiatis
        if userid is None:
94 f8cac8c7 Giorgos Korfiatis
            users = AstakosUser.objects.accepted().select_related(
95 f8cac8c7 Giorgos Korfiatis
                'base_project')
96 3f5851eb Giorgos Korfiatis
        else:
97 3f5851eb Giorgos Korfiatis
            try:
98 3848b521 Giorgos Korfiatis
                user = AstakosUser.objects.get(uuid=userid)
99 3f5851eb Giorgos Korfiatis
            except AstakosUser.DoesNotExist:
100 3f5851eb Giorgos Korfiatis
                raise CommandError("There is no user with uuid '%s'." % userid)
101 3848b521 Giorgos Korfiatis
            if not user.is_accepted():
102 3848b521 Giorgos Korfiatis
                raise CommandError("%s is not an accepted user." % userid)
103 3848b521 Giorgos Korfiatis
            users = [user]
104 3f5851eb Giorgos Korfiatis
105 3f5851eb Giorgos Korfiatis
        db_holdings = count_pending_app(users)
106 3f5851eb Giorgos Korfiatis
107 f8cac8c7 Giorgos Korfiatis
        db_project_holdings = {}
108 f8cac8c7 Giorgos Korfiatis
        for user, user_holdings in db_holdings.iteritems():
109 f8cac8c7 Giorgos Korfiatis
            db_project_holdings.update(user_holdings)
110 f8cac8c7 Giorgos Korfiatis
111 f8cac8c7 Giorgos Korfiatis
        unsynced_users, users_pending, users_unknown =\
112 f8cac8c7 Giorgos Korfiatis
            reconcile.check_users(self.stderr, RESOURCES,
113 f8cac8c7 Giorgos Korfiatis
                                  db_holdings, qh_holdings)
114 f8cac8c7 Giorgos Korfiatis
115 f8cac8c7 Giorgos Korfiatis
        unsynced_projects, projects_pending, projects_unknown =\
116 f8cac8c7 Giorgos Korfiatis
            reconcile.check_projects(self.stderr, RESOURCES,
117 f8cac8c7 Giorgos Korfiatis
                                     db_project_holdings, qh_project_holdings)
118 f8cac8c7 Giorgos Korfiatis
        pending_exists = users_pending or projects_pending
119 f8cac8c7 Giorgos Korfiatis
        unknown_exists = users_unknown or projects_unknown
120 f8cac8c7 Giorgos Korfiatis
121 f8cac8c7 Giorgos Korfiatis
        headers = ("Type", "Holder", "Source", "Resource",
122 f8cac8c7 Giorgos Korfiatis
                   "Astakos", "Quotaholder")
123 f8cac8c7 Giorgos Korfiatis
        unsynced = unsynced_users + unsynced_projects
124 3f5851eb Giorgos Korfiatis
        if unsynced:
125 d9a7f0bb Giorgos Korfiatis
            pprint_table(self.stdout, unsynced, headers)
126 3f5851eb Giorgos Korfiatis
            if options["fix"]:
127 f8cac8c7 Giorgos Korfiatis
                user_provisions = create_user_provisions(unsynced_users)
128 f8cac8c7 Giorgos Korfiatis
                project_provisions = create_project_provisions(
129 f8cac8c7 Giorgos Korfiatis
                    unsynced_projects)
130 f8cac8c7 Giorgos Korfiatis
                provisions = user_provisions + project_provisions
131 f8cac8c7 Giorgos Korfiatis
                name = ("client: reconcile-resources-astakos, time: %s"
132 f8cac8c7 Giorgos Korfiatis
                        % datetime.now())
133 205cc8d3 Giorgos Korfiatis
                try:
134 205cc8d3 Giorgos Korfiatis
                    s = qh.issue_commission('astakos', provisions,
135 f8cac8c7 Giorgos Korfiatis
                                            name=name, force=force)
136 205cc8d3 Giorgos Korfiatis
                except qh_exception.NoCapacityError:
137 205cc8d3 Giorgos Korfiatis
                    write("Reconciling failed because a limit has been "
138 205cc8d3 Giorgos Korfiatis
                          "reached. Use --force to ignore the check.\n")
139 205cc8d3 Giorgos Korfiatis
                    return
140 205cc8d3 Giorgos Korfiatis
141 3f5851eb Giorgos Korfiatis
                qh.resolve_pending_commission('astakos', s)
142 3f5851eb Giorgos Korfiatis
                write("Fixed unsynced resources\n")
143 3f5851eb Giorgos Korfiatis
144 3f5851eb Giorgos Korfiatis
        if pending_exists:
145 3f5851eb Giorgos Korfiatis
            write("Found pending commissions. "
146 3f5851eb Giorgos Korfiatis
                  "This is probably a bug. Please report.\n")
147 f8cac8c7 Giorgos Korfiatis
        elif not (unsynced or unknown_exists):
148 3f5851eb Giorgos Korfiatis
            write("Everything in sync.\n")
149 3f5851eb Giorgos Korfiatis
150 3f5851eb Giorgos Korfiatis
151 f8cac8c7 Giorgos Korfiatis
def create_user_provisions(provision_list):
152 f8cac8c7 Giorgos Korfiatis
    provisions = []
153 f8cac8c7 Giorgos Korfiatis
    for _, holder, source, resource, db_value, qh_value in provision_list:
154 f8cac8c7 Giorgos Korfiatis
        value = db_value - qh_value
155 f8cac8c7 Giorgos Korfiatis
        provisions.append(
156 f8cac8c7 Giorgos Korfiatis
            quotas.mk_user_provision(holder, source, resource, value))
157 f8cac8c7 Giorgos Korfiatis
    return provisions
158 f8cac8c7 Giorgos Korfiatis
159 f8cac8c7 Giorgos Korfiatis
160 f8cac8c7 Giorgos Korfiatis
def create_project_provisions(provision_list):
161 f8cac8c7 Giorgos Korfiatis
    provisions = []
162 f8cac8c7 Giorgos Korfiatis
    for _, holder, _, resource, db_value, qh_value in provision_list:
163 f8cac8c7 Giorgos Korfiatis
        value = db_value - qh_value
164 f8cac8c7 Giorgos Korfiatis
        provisions.append(
165 f8cac8c7 Giorgos Korfiatis
            quotas.mk_project_provision(holder, resource, value))
166 f8cac8c7 Giorgos Korfiatis
    return provisions