Revision 44d950c6 snf-astakos-app/astakos/im/management/commands/quota-verify.py
b/snf-astakos-app/astakos/im/management/commands/quota-verify.py | ||
---|---|---|
34 | 34 |
from optparse import make_option |
35 | 35 |
from django.db import transaction |
36 | 36 |
|
37 |
from astakos.im.models import AstakosUser |
|
38 |
from astakos.im.quotas import ( |
|
39 |
qh_sync_users_diffs,) |
|
40 |
from astakos.im.functions import get_user_by_uuid |
|
37 |
from astakos.im.models import Project |
|
38 |
from astakos.im import quotas |
|
39 |
from snf_django.management.utils import pprint_table |
|
41 | 40 |
from snf_django.management.commands import SynnefoCommand |
42 |
from astakos.im.management.commands import _common as common |
|
43 | 41 |
|
44 | 42 |
import logging |
45 | 43 |
logger = logging.getLogger(__name__) |
46 | 44 |
|
47 | 45 |
|
46 |
def differences(local_quotas, qh_quotas): |
|
47 |
unsynced = [] |
|
48 |
unexpected = [] |
|
49 |
for holder, h_quotas in local_quotas.iteritems(): |
|
50 |
qh_h_quotas = qh_quotas.pop(holder, {}) |
|
51 |
for source, s_quotas in h_quotas.iteritems(): |
|
52 |
qh_s_quotas = qh_h_quotas.pop(source, {}) |
|
53 |
for resource, value in s_quotas.iteritems(): |
|
54 |
qh_value = qh_s_quotas.pop(resource, None) |
|
55 |
if value != qh_value: |
|
56 |
data = (holder, source, resource, value, qh_value) |
|
57 |
unsynced.append(data) |
|
58 |
unexpected += unexpected_resources(holder, source, qh_s_quotas) |
|
59 |
unexpected += unexpected_sources(holder, qh_h_quotas) |
|
60 |
unexpected += unexpected_holders(qh_quotas) |
|
61 |
return unsynced, unexpected |
|
62 |
|
|
63 |
|
|
64 |
def unexpected_holders(qh_quotas): |
|
65 |
unexpected = [] |
|
66 |
for holder, qh_h_quotas in qh_quotas.iteritems(): |
|
67 |
unexpected += unexpected_sources(holder, qh_h_quotas) |
|
68 |
return unexpected |
|
69 |
|
|
70 |
|
|
71 |
def unexpected_sources(holder, qh_h_quotas): |
|
72 |
unexpected = [] |
|
73 |
for source, qh_s_quotas in qh_h_quotas.iteritems(): |
|
74 |
unexpected += unexpected_resources(holder, source, qh_s_quotas) |
|
75 |
return unexpected |
|
76 |
|
|
77 |
|
|
78 |
def unexpected_resources(holder, source, qh_s_quotas): |
|
79 |
unexpected = [] |
|
80 |
for resource, qh_value in qh_s_quotas.iteritems(): |
|
81 |
data = (holder, source, resource, None, qh_value) |
|
82 |
unexpected.append(data) |
|
83 |
return unexpected |
|
84 |
|
|
85 |
|
|
48 | 86 |
class Command(SynnefoCommand): |
49 |
help = "Check the integrity of user quota" |
|
87 |
help = "Check the integrity of user and project quota"
|
|
50 | 88 |
|
51 | 89 |
option_list = SynnefoCommand.option_list + ( |
52 |
make_option('--sync', |
|
53 |
action='store_true', |
|
54 |
dest='sync', |
|
90 |
make_option("--include-unexpected-holdings", |
|
91 |
default=False, |
|
92 |
action="store_true", |
|
93 |
help=("Also check for holdings that do not correspond " |
|
94 |
"to Astakos projects or user. Note that fixing such " |
|
95 |
"inconsistencies will permanently delete these " |
|
96 |
"holdings.")), |
|
97 |
make_option("--fix", dest="fix", |
|
55 | 98 |
default=False, |
56 |
help="Sync quotaholder"), |
|
57 |
make_option('--user', |
|
58 |
metavar='<uuid or email>', |
|
59 |
dest='user', |
|
60 |
help="Check for a specified user"), |
|
99 |
action="store_true", |
|
100 |
help="Synchronize Quotaholder with Astakos DB."), |
|
61 | 101 |
) |
62 | 102 |
|
63 | 103 |
@transaction.commit_on_success |
64 | 104 |
def handle(self, *args, **options): |
65 |
sync = options['sync'] |
|
66 |
user_ident = options['user'] |
|
67 |
|
|
68 |
if user_ident is not None: |
|
69 |
users = [common.get_accepted_user(user_ident)] |
|
70 |
else: |
|
71 |
users = AstakosUser.objects.accepted() |
|
72 |
|
|
73 |
qh_limits, diff_q = qh_sync_users_diffs(users, sync=sync) |
|
74 |
if sync: |
|
75 |
self.print_sync(diff_q) |
|
76 |
else: |
|
77 |
self.print_verify(qh_limits, diff_q) |
|
78 |
|
|
79 |
def print_sync(self, diff_quotas): |
|
80 |
size = len(diff_quotas) |
|
81 |
if size == 0: |
|
82 |
self.stderr.write("No sync needed.\n") |
|
83 |
else: |
|
84 |
self.stderr.write("Synced %s users:\n" % size) |
|
85 |
uuids = diff_quotas.keys() |
|
86 |
users = AstakosUser.objects.filter(uuid__in=uuids) |
|
87 |
for user in users: |
|
88 |
self.stderr.write("%s (%s)\n" % (user.uuid, user.username)) |
|
89 |
|
|
90 |
def print_verify(self, qh_limits, diff_quotas): |
|
91 |
for holder, local in diff_quotas.iteritems(): |
|
92 |
registered = qh_limits.pop(holder, None) |
|
93 |
user = get_user_by_uuid(holder) |
|
94 |
if registered is None: |
|
95 |
self.stderr.write( |
|
96 |
"No quota for %s (%s) in quotaholder.\n" % |
|
97 |
(holder, user.username)) |
|
98 |
else: |
|
99 |
self.stdout.write("Quota differ for %s (%s):\n" % |
|
100 |
(holder, user.username)) |
|
101 |
self.stdout.write("Quota according to quotaholder:\n") |
|
102 |
self.stdout.write("%s\n" % (registered)) |
|
103 |
self.stdout.write("Quota according to astakos:\n") |
|
104 |
self.stdout.write("%s\n\n" % (local)) |
|
105 |
|
|
106 |
diffs = len(diff_quotas) |
|
107 |
if diffs: |
|
108 |
self.stderr.write("Quota differ for %d users.\n" % (diffs)) |
|
105 |
write = self.stderr.write |
|
106 |
fix = options['fix'] |
|
107 |
check_unexpected = options["include_unexpected_holdings"] |
|
108 |
|
|
109 |
projects = Project.objects.all() |
|
110 |
local_proj_quotas, local_user_quotas = \ |
|
111 |
quotas.astakos_project_quotas(projects) |
|
112 |
qh_proj_quotas, qh_user_quotas = \ |
|
113 |
quotas.get_projects_quota_limits() |
|
114 |
unsynced, unexpected = differences(local_proj_quotas, qh_proj_quotas) |
|
115 |
unsync_u, unexpect_u = differences(local_user_quotas, qh_user_quotas) |
|
116 |
unsynced += unsync_u |
|
117 |
unexpected += unexpect_u |
|
118 |
|
|
119 |
headers = ("Holder", "Source", "Resource", "Astakos", "Quotaholder") |
|
120 |
if not unsynced and (not check_unexpected or not unexpected): |
|
121 |
write("Everything in sync.\n") |
|
122 |
return |
|
123 |
|
|
124 |
printable = (unsynced if not check_unexpected |
|
125 |
else unsynced + unexpected) |
|
126 |
pprint_table(self.stdout, printable, headers, title="Inconsistencies") |
|
127 |
if fix: |
|
128 |
to_sync = [] |
|
129 |
for holder, source, resource, value, qh_value in unsynced: |
|
130 |
to_sync.append(((holder, source, resource), value)) |
|
131 |
quotas.qh.set_quota(to_sync) |
|
132 |
|
|
133 |
if check_unexpected: |
|
134 |
to_del = [] |
|
135 |
for holder, source, resource, value, qh_value in unexpected: |
|
136 |
to_del.append((holder, source, resource)) |
|
137 |
quotas.qh.delete_quota(to_del) |
Also available in: Unified diff