Revision a69ad12b
b/docs/admin-guide.rst | ||
---|---|---|
915 | 915 |
project-control Manage projects and applications |
916 | 916 |
project-list List projects |
917 | 917 |
project-show Show project details |
918 |
quota List and check the integrity of user quota |
|
918 |
quota-list List user quota |
|
919 |
quota-verify Check the integrity of user quota |
|
919 | 920 |
reconcile-resources-astakos Reconcile resource usage of Quotaholder with Astakos DB |
920 | 921 |
resource-list List resources |
921 | 922 |
resource-modify Modify a resource's default base quota and boolean flags |
b/snf-astakos-app/astakos/im/management/commands/_common.py | ||
---|---|---|
68 | 68 |
return None |
69 | 69 |
|
70 | 70 |
|
71 |
def get_accepted_user(user_ident): |
|
72 |
if is_uuid(user_ident): |
|
73 |
try: |
|
74 |
user = AstakosUser.objects.get(uuid=user_ident) |
|
75 |
except AstakosUser.DoesNotExist: |
|
76 |
raise CommandError('There is no user with uuid: %s' % |
|
77 |
user_ident) |
|
78 |
elif is_email(user_ident): |
|
79 |
try: |
|
80 |
user = AstakosUser.objects.get(username=user_ident) |
|
81 |
except AstakosUser.DoesNotExist: |
|
82 |
raise CommandError('There is no user with email: %s' % |
|
83 |
user_ident) |
|
84 |
else: |
|
85 |
raise CommandError('Please specify user by uuid or email') |
|
86 |
|
|
87 |
if not user.is_accepted(): |
|
88 |
raise CommandError('%s is not an accepted user.' % user.uuid) |
|
89 |
|
|
90 |
return user |
|
91 |
|
|
92 |
|
|
71 | 93 |
def get_astakosuser_content_type(): |
72 | 94 |
try: |
73 | 95 |
return ContentType.objects.get(app_label='im', |
b/snf-astakos-app/astakos/im/management/commands/quota-list.py | ||
---|---|---|
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 optparse import make_option |
|
35 |
from django.db import transaction |
|
36 |
|
|
37 |
from astakos.im.models import AstakosUser |
|
38 |
from astakos.im.quotas import list_user_quotas |
|
39 |
from snf_django.management.commands import SynnefoCommand |
|
40 |
from snf_django.management import utils |
|
41 |
from astakos.im.management.commands import _common as common |
|
42 |
|
|
43 |
import logging |
|
44 |
logger = logging.getLogger(__name__) |
|
45 |
|
|
46 |
|
|
47 |
class Command(SynnefoCommand): |
|
48 |
help = "List user quota" |
|
49 |
|
|
50 |
option_list = SynnefoCommand.option_list + ( |
|
51 |
make_option('--unit-style', |
|
52 |
default='mb', |
|
53 |
help=("Specify display unit for resource values " |
|
54 |
"(one of %s); defaults to mb") % |
|
55 |
common.style_options), |
|
56 |
make_option('--user', |
|
57 |
metavar='<uuid or email>', |
|
58 |
dest='user', |
|
59 |
help="List quota for a specified user"), |
|
60 |
) |
|
61 |
|
|
62 |
@transaction.commit_on_success |
|
63 |
def handle(self, *args, **options): |
|
64 |
output_format = options["output_format"] |
|
65 |
user_ident = options['user'] |
|
66 |
unit_style = options["unit_style"] |
|
67 |
common.check_style(unit_style) |
|
68 |
|
|
69 |
if user_ident is not None: |
|
70 |
users = [common.get_accepted_user(user_ident)] |
|
71 |
else: |
|
72 |
users = AstakosUser.objects.accepted() |
|
73 |
|
|
74 |
qh_quotas, astakos_i = list_user_quotas(users) |
|
75 |
|
|
76 |
info = {} |
|
77 |
for user in users: |
|
78 |
info[user.uuid] = user.email |
|
79 |
|
|
80 |
print_data, labels = common.show_quotas( |
|
81 |
qh_quotas, astakos_i, info, style=unit_style) |
|
82 |
utils.pprint_table(self.stdout, print_data, labels, output_format) |
b/snf-astakos-app/astakos/im/management/commands/quota-verify.py | ||
---|---|---|
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 optparse import make_option |
|
35 |
from django.db import transaction |
|
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 |
|
41 |
from snf_django.management.commands import SynnefoCommand |
|
42 |
from astakos.im.management.commands import _common as common |
|
43 |
|
|
44 |
import logging |
|
45 |
logger = logging.getLogger(__name__) |
|
46 |
|
|
47 |
|
|
48 |
class Command(SynnefoCommand): |
|
49 |
help = "Check the integrity of user quota" |
|
50 |
|
|
51 |
option_list = SynnefoCommand.option_list + ( |
|
52 |
make_option('--sync', |
|
53 |
action='store_true', |
|
54 |
dest='sync', |
|
55 |
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"), |
|
61 |
) |
|
62 |
|
|
63 |
@transaction.commit_on_success |
|
64 |
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.stdout.write("No sync needed.\n") |
|
83 |
else: |
|
84 |
self.stdout.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.stdout.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.stdout.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.stdout.write("Quota differ for %d users.\n" % (diffs)) |
/dev/null | ||
---|---|---|
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 optparse import make_option |
|
35 |
from django.core.management.base import CommandError |
|
36 |
from django.db import transaction |
|
37 |
|
|
38 |
from astakos.im.models import AstakosUser |
|
39 |
from astakos.im.quotas import ( |
|
40 |
qh_sync_users_diffs, list_user_quotas, add_base_quota) |
|
41 |
from astakos.im.functions import get_user_by_uuid |
|
42 |
from astakos.im.management.commands._common import is_uuid, is_email |
|
43 |
from snf_django.management.commands import SynnefoCommand |
|
44 |
from snf_django.management import utils |
|
45 |
from ._common import show_quotas, style_options, check_style, units |
|
46 |
|
|
47 |
import logging |
|
48 |
logger = logging.getLogger(__name__) |
|
49 |
|
|
50 |
|
|
51 |
class Command(SynnefoCommand): |
|
52 |
help = "List and check the integrity of user quota" |
|
53 |
|
|
54 |
option_list = SynnefoCommand.option_list + ( |
|
55 |
make_option('--list', |
|
56 |
action='store_true', |
|
57 |
dest='list', |
|
58 |
default=False, |
|
59 |
help="List all quota (default)"), |
|
60 |
make_option('--unit-style', |
|
61 |
default='mb', |
|
62 |
help=("Specify display unit for resource values " |
|
63 |
"(one of %s); defaults to mb") % style_options), |
|
64 |
make_option('--verify', |
|
65 |
action='store_true', |
|
66 |
dest='verify', |
|
67 |
default=False, |
|
68 |
help="Check if quotaholder is in sync with astakos"), |
|
69 |
make_option('--sync', |
|
70 |
action='store_true', |
|
71 |
dest='sync', |
|
72 |
default=False, |
|
73 |
help="Sync quotaholder"), |
|
74 |
make_option('--user', |
|
75 |
metavar='<uuid or email>', |
|
76 |
dest='user', |
|
77 |
help="List quota for a specified user"), |
|
78 |
make_option('--import-base-quota', |
|
79 |
dest='import_base_quota', |
|
80 |
metavar='<exported-quota.txt>', |
|
81 |
help=("Import base quota from file. " |
|
82 |
"The file must contain non-empty lines, and each " |
|
83 |
"line must contain a single-space-separated list " |
|
84 |
"of values: <user> <resource name> <capacity>. " |
|
85 |
"Capacity can be followed by a unit with no " |
|
86 |
"separating space (e.g 10GB).") |
|
87 |
), |
|
88 |
) |
|
89 |
|
|
90 |
@transaction.commit_on_success |
|
91 |
def handle(self, *args, **options): |
|
92 |
sync = options['sync'] |
|
93 |
verify = options['verify'] |
|
94 |
user_ident = options['user'] |
|
95 |
list_ = options['list'] |
|
96 |
import_base_quota = options['import_base_quota'] |
|
97 |
|
|
98 |
if import_base_quota: |
|
99 |
if any([sync, verify, list_]): |
|
100 |
m = "--from-file cannot be combined with other options." |
|
101 |
raise CommandError(m) |
|
102 |
self.import_from_file(import_base_quota) |
|
103 |
else: |
|
104 |
unit_style = options["unit_style"] |
|
105 |
check_style(unit_style) |
|
106 |
|
|
107 |
self.quotas(sync, verify, user_ident, options["output_format"], |
|
108 |
unit_style) |
|
109 |
|
|
110 |
def quotas(self, sync, verify, user_ident, output_format, style): |
|
111 |
list_only = not sync and not verify |
|
112 |
|
|
113 |
if user_ident is not None: |
|
114 |
users = [self.get_user(user_ident)] |
|
115 |
else: |
|
116 |
users = AstakosUser.objects.accepted() |
|
117 |
|
|
118 |
if list_only: |
|
119 |
qh_quotas, astakos_i = list_user_quotas(users) |
|
120 |
|
|
121 |
info = {} |
|
122 |
for user in users: |
|
123 |
info[user.uuid] = user.email |
|
124 |
|
|
125 |
print_data, labels = show_quotas(qh_quotas, astakos_i, info, |
|
126 |
style=style) |
|
127 |
utils.pprint_table(self.stdout, print_data, labels, |
|
128 |
output_format) |
|
129 |
|
|
130 |
elif verify or sync: |
|
131 |
qh_limits, diff_q = qh_sync_users_diffs(users, sync=sync) |
|
132 |
if verify: |
|
133 |
self.print_verify(qh_limits, diff_q) |
|
134 |
if sync: |
|
135 |
self.print_sync(diff_q) |
|
136 |
|
|
137 |
def get_user(self, user_ident): |
|
138 |
if is_uuid(user_ident): |
|
139 |
try: |
|
140 |
user = AstakosUser.objects.get(uuid=user_ident) |
|
141 |
except AstakosUser.DoesNotExist: |
|
142 |
raise CommandError('There is no user with uuid: %s' % |
|
143 |
user_ident) |
|
144 |
elif is_email(user_ident): |
|
145 |
try: |
|
146 |
user = AstakosUser.objects.get(username=user_ident) |
|
147 |
except AstakosUser.DoesNotExist: |
|
148 |
raise CommandError('There is no user with email: %s' % |
|
149 |
user_ident) |
|
150 |
else: |
|
151 |
raise CommandError('Please specify user by uuid or email') |
|
152 |
|
|
153 |
if not user.is_accepted(): |
|
154 |
raise CommandError('%s is not an accepted user.' % user.uuid) |
|
155 |
|
|
156 |
return user |
|
157 |
|
|
158 |
def print_sync(self, diff_quotas): |
|
159 |
size = len(diff_quotas) |
|
160 |
if size == 0: |
|
161 |
self.stdout.write("No sync needed.\n") |
|
162 |
else: |
|
163 |
self.stdout.write("Synced %s users:\n" % size) |
|
164 |
uuids = diff_quotas.keys() |
|
165 |
users = AstakosUser.objects.filter(uuid__in=uuids) |
|
166 |
for user in users: |
|
167 |
self.stdout.write("%s (%s)\n" % (user.uuid, user.username)) |
|
168 |
|
|
169 |
def print_verify(self, |
|
170 |
qh_limits, |
|
171 |
diff_quotas): |
|
172 |
|
|
173 |
for holder, local in diff_quotas.iteritems(): |
|
174 |
registered = qh_limits.pop(holder, None) |
|
175 |
user = get_user_by_uuid(holder) |
|
176 |
if registered is None: |
|
177 |
self.stdout.write( |
|
178 |
"No quota for %s (%s) in quotaholder.\n" % |
|
179 |
(holder, user.username)) |
|
180 |
else: |
|
181 |
self.stdout.write("Quota differ for %s (%s):\n" % |
|
182 |
(holder, user.username)) |
|
183 |
self.stdout.write("Quota according to quotaholder:\n") |
|
184 |
self.stdout.write("%s\n" % (registered)) |
|
185 |
self.stdout.write("Quota according to astakos:\n") |
|
186 |
self.stdout.write("%s\n\n" % (local)) |
|
187 |
|
|
188 |
diffs = len(diff_quotas) |
|
189 |
if diffs: |
|
190 |
self.stdout.write("Quota differ for %d users.\n" % (diffs)) |
|
191 |
|
|
192 |
def import_from_file(self, location): |
|
193 |
users = set() |
|
194 |
with open(location) as f: |
|
195 |
for line in f.readlines(): |
|
196 |
try: |
|
197 |
t = line.rstrip('\n').split(' ') |
|
198 |
user = t[0] |
|
199 |
resource = t[1] |
|
200 |
capacity = t[2] |
|
201 |
try: |
|
202 |
capacity = units.parse(capacity) |
|
203 |
except units.ParseError: |
|
204 |
m = ("Capacity should be an integer, optionally " |
|
205 |
"followed by a unit.") |
|
206 |
raise CommandError(m) |
|
207 |
except(IndexError, TypeError): |
|
208 |
self.stdout.write('Invalid line format: %s:\n' % t) |
|
209 |
continue |
|
210 |
else: |
|
211 |
try: |
|
212 |
user = self.get_user(user) |
|
213 |
users.add(user.id) |
|
214 |
except CommandError: |
|
215 |
self.stdout.write('Not found user: %s\n' % user) |
|
216 |
continue |
|
217 |
else: |
|
218 |
try: |
|
219 |
add_base_quota(user, resource, capacity) |
|
220 |
except Exception, e: |
|
221 |
self.stdout.write('Failed to add quota: %s\n' % e) |
|
222 |
continue |
Also available in: Unified diff