32 |
32 |
# or implied, of GRNET S.A.
|
33 |
33 |
|
34 |
34 |
from optparse import make_option
|
|
35 |
from datetime import datetime
|
35 |
36 |
|
36 |
37 |
from django.core.management.base import BaseCommand, CommandError
|
37 |
38 |
from django.db import transaction
|
38 |
39 |
|
|
40 |
from snf_django.utils import reconcile
|
39 |
41 |
from snf_django.management.utils import pprint_table
|
40 |
42 |
from astakos.im.models import Component, AstakosUser
|
41 |
|
from astakos.im.quotas import service_get_quotas, SYSTEM
|
|
43 |
from astakos.im import quotas
|
42 |
44 |
from astakos.im.functions import count_pending_app
|
43 |
45 |
import astakos.quotaholder_app.callpoint as qh
|
44 |
46 |
import astakos.quotaholder_app.exception as qh_exception
|
... | ... | |
56 |
58 |
make_option("--userid", dest="userid",
|
57 |
59 |
default=None,
|
58 |
60 |
help="Reconcile resources only for this user"),
|
|
61 |
make_option("--project",
|
|
62 |
help="Reconcile resources only for this project"),
|
59 |
63 |
make_option("--fix", dest="fix",
|
60 |
64 |
default=False,
|
61 |
65 |
action="store_true",
|
... | ... | |
72 |
76 |
write = self.stderr.write
|
73 |
77 |
force = options['force']
|
74 |
78 |
userid = options['userid']
|
|
79 |
project = options['project']
|
|
80 |
|
|
81 |
RESOURCES = [quotas.PENDING_APP_RESOURCE]
|
75 |
82 |
|
76 |
83 |
try:
|
77 |
84 |
astakos = Component.objects.get(name="astakos")
|
... | ... | |
79 |
86 |
raise CommandError("Component 'astakos' not found.")
|
80 |
87 |
|
81 |
88 |
query = [userid] if userid is not None else None
|
82 |
|
qh_holdings = service_get_quotas(astakos, query)
|
|
89 |
qh_holdings = quotas.service_get_quotas(astakos, query)
|
|
90 |
query = [project] if project is not None else None
|
|
91 |
qh_project_holdings = quotas.service_get_project_quotas(astakos, query)
|
83 |
92 |
|
84 |
93 |
if userid is None:
|
85 |
|
users = AstakosUser.objects.accepted()
|
|
94 |
users = AstakosUser.objects.accepted().select_related(
|
|
95 |
'base_project')
|
86 |
96 |
else:
|
87 |
97 |
try:
|
88 |
98 |
user = AstakosUser.objects.get(uuid=userid)
|
... | ... | |
94 |
104 |
|
95 |
105 |
db_holdings = count_pending_app(users)
|
96 |
106 |
|
97 |
|
pending_exists = False
|
98 |
|
unknown_user_exists = False
|
99 |
|
unsynced = []
|
100 |
|
for user in users:
|
101 |
|
uuid = user.uuid
|
102 |
|
db_value = db_holdings.get(uuid, 0)
|
103 |
|
try:
|
104 |
|
qh_all = qh_holdings[uuid]
|
105 |
|
except KeyError:
|
106 |
|
write("User '%s' does not exist in Quotaholder!\n" % uuid)
|
107 |
|
unknown_user_exists = True
|
108 |
|
continue
|
109 |
|
|
110 |
|
# Assuming only one source
|
111 |
|
system_qh = qh_all.get(SYSTEM, {})
|
112 |
|
# Assuming only one resource
|
113 |
|
resource = 'astakos.pending_app'
|
114 |
|
try:
|
115 |
|
qh_values = system_qh[resource]
|
116 |
|
qh_value = qh_values['usage']
|
117 |
|
qh_pending = qh_values['pending']
|
118 |
|
except KeyError:
|
119 |
|
write("Resource '%s' does not exist in Quotaholder"
|
120 |
|
" for user '%s'!\n" % (resource, uuid))
|
121 |
|
continue
|
122 |
|
if qh_pending:
|
123 |
|
write("Pending commission. User '%s', resource '%s'.\n" %
|
124 |
|
(uuid, resource))
|
125 |
|
pending_exists = True
|
126 |
|
continue
|
127 |
|
if db_value != qh_value:
|
128 |
|
data = (uuid, resource, db_value, qh_value)
|
129 |
|
unsynced.append(data)
|
130 |
|
|
131 |
|
headers = ("User", "Resource", "Astakos", "Quotaholder")
|
|
107 |
db_project_holdings = {}
|
|
108 |
for user, user_holdings in db_holdings.iteritems():
|
|
109 |
db_project_holdings.update(user_holdings)
|
|
110 |
|
|
111 |
unsynced_users, users_pending, users_unknown =\
|
|
112 |
reconcile.check_users(self.stderr, RESOURCES,
|
|
113 |
db_holdings, qh_holdings)
|
|
114 |
|
|
115 |
unsynced_projects, projects_pending, projects_unknown =\
|
|
116 |
reconcile.check_projects(self.stderr, RESOURCES,
|
|
117 |
db_project_holdings, qh_project_holdings)
|
|
118 |
pending_exists = users_pending or projects_pending
|
|
119 |
unknown_exists = users_unknown or projects_unknown
|
|
120 |
|
|
121 |
headers = ("Type", "Holder", "Source", "Resource",
|
|
122 |
"Astakos", "Quotaholder")
|
|
123 |
unsynced = unsynced_users + unsynced_projects
|
132 |
124 |
if unsynced:
|
133 |
125 |
pprint_table(self.stdout, unsynced, headers)
|
134 |
126 |
if options["fix"]:
|
135 |
|
provisions = map(create_provision, unsynced)
|
|
127 |
user_provisions = create_user_provisions(unsynced_users)
|
|
128 |
project_provisions = create_project_provisions(
|
|
129 |
unsynced_projects)
|
|
130 |
provisions = user_provisions + project_provisions
|
|
131 |
name = ("client: reconcile-resources-astakos, time: %s"
|
|
132 |
% datetime.now())
|
136 |
133 |
try:
|
137 |
134 |
s = qh.issue_commission('astakos', provisions,
|
138 |
|
name='RECONCILE', force=force)
|
|
135 |
name=name, force=force)
|
139 |
136 |
except qh_exception.NoCapacityError:
|
140 |
137 |
write("Reconciling failed because a limit has been "
|
141 |
138 |
"reached. Use --force to ignore the check.\n")
|
... | ... | |
147 |
144 |
if pending_exists:
|
148 |
145 |
write("Found pending commissions. "
|
149 |
146 |
"This is probably a bug. Please report.\n")
|
150 |
|
elif not (unsynced or unknown_user_exists):
|
|
147 |
elif not (unsynced or unknown_exists):
|
151 |
148 |
write("Everything in sync.\n")
|
152 |
149 |
|
153 |
150 |
|
154 |
|
def create_provision(provision_info):
|
155 |
|
user, resource, db_value, qh_value = provision_info
|
156 |
|
return (user, SYSTEM, resource), (db_value - qh_value)
|
|
151 |
def create_user_provisions(provision_list):
|
|
152 |
provisions = []
|
|
153 |
for _, holder, source, resource, db_value, qh_value in provision_list:
|
|
154 |
value = db_value - qh_value
|
|
155 |
provisions.append(
|
|
156 |
quotas.mk_user_provision(holder, source, resource, value))
|
|
157 |
return provisions
|
|
158 |
|
|
159 |
|
|
160 |
def create_project_provisions(provision_list):
|
|
161 |
provisions = []
|
|
162 |
for _, holder, _, resource, db_value, qh_value in provision_list:
|
|
163 |
value = db_value - qh_value
|
|
164 |
provisions.append(
|
|
165 |
quotas.mk_project_provision(holder, resource, value))
|
|
166 |
return provisions
|