Revision 84a3f701
b/snf-astakos-app/astakos/im/api/backends/lib/django/__init__.py | ||
---|---|---|
231 | 231 |
@safe |
232 | 232 |
def get_resource_usage(self, user_id): |
233 | 233 |
user = self._lookup_user(user_id) |
234 |
data = get_quota(user)
|
|
234 |
data = get_quota([user])
|
|
235 | 235 |
if not data: |
236 | 236 |
return () |
237 | 237 |
resources = [] |
b/snf-astakos-app/astakos/im/endpoints/qh.py | ||
---|---|---|
73 | 73 |
logger.info('set_quota: %s rejected: %s' % (payload, result)) |
74 | 74 |
return result |
75 | 75 |
|
76 |
def qh_get_quota(user, resources): |
|
76 |
def get_entity(payload): |
|
77 |
c = get_client() |
|
78 |
if not c: |
|
79 |
return |
|
80 |
result = c.get_entity(context={}, get_entity=payload) |
|
81 |
logger.info('get_entity: %s reply: %s' % (payload, result)) |
|
82 |
return result |
|
83 |
|
|
84 |
def get_holding(payload): |
|
85 |
c = get_client() |
|
86 |
if not c: |
|
87 |
return |
|
88 |
result = c.get_holding(context={}, get_holding=payload) |
|
89 |
logger.info('get_holding: %s reply: %s' % (payload, result)) |
|
90 |
return result |
|
91 |
|
|
92 |
def qh_get_holdings(users, resources): |
|
93 |
payload = [] |
|
94 |
append = payload.append |
|
95 |
for user in users: |
|
96 |
for resource in resources: |
|
97 |
append((user.uuid, resource, ENTITY_KEY),) |
|
98 |
result = get_holding(payload) |
|
99 |
return result |
|
100 |
|
|
101 |
def qh_get_quota(users, resources): |
|
77 | 102 |
c = get_client() |
78 | 103 |
if not c: |
79 | 104 |
return |
80 | 105 |
payload = [] |
81 | 106 |
append = payload.append |
82 |
for r in resources: |
|
83 |
append((user.uuid, r, ENTITY_KEY),) |
|
107 |
for user in users: |
|
108 |
for resource in resources: |
|
109 |
append((user.uuid, resource, ENTITY_KEY),) |
|
110 |
|
|
84 | 111 |
result = c.get_quota(context={}, clientkey=clientkey, get_quota=payload) |
85 | 112 |
logger.info('get_quota: %s rejected: %s' % (payload, result)) |
86 | 113 |
return result |
87 | 114 |
|
115 |
def qh_get_quota_limits(users, resources): |
|
116 |
result = qh_get_quota(users, resources) |
|
117 |
return result |
|
118 |
|
|
88 | 119 |
def create_entity(payload): |
89 | 120 |
c = get_client() |
90 | 121 |
if not c: |
... | ... | |
129 | 160 |
import_limit = q1.import_limit + q2.import_limit, |
130 | 161 |
export_limit = q1.export_limit + q2.export_limit) |
131 | 162 |
|
132 |
def qh_register_user(user): |
|
133 |
return register_users([user]) |
|
163 |
def qh_register_user_with_quotas(user):
|
|
164 |
return register_users_with_quotas([user])
|
|
134 | 165 |
|
135 |
def register_users(users): |
|
136 |
rejected = create_users(users)
|
|
166 |
def register_users_with_quotas(users):
|
|
167 |
rejected = register_users(users)
|
|
137 | 168 |
if not rejected: |
138 | 169 |
register_quotas(users) |
139 | 170 |
|
140 |
def create_users(users): |
|
171 |
def register_users(users): |
|
172 |
if not users: |
|
173 |
return |
|
174 |
|
|
141 | 175 |
payload = list(CreateEntityPayload( |
142 | 176 |
entity=u.uuid, |
143 | 177 |
owner='system', |
... | ... | |
146 | 180 |
return create_entity(payload) |
147 | 181 |
|
148 | 182 |
def register_quotas(users): |
183 |
if not users: |
|
184 |
return |
|
185 |
|
|
149 | 186 |
payload = [] |
150 | 187 |
append = payload.append |
151 | 188 |
for u in users: |
... | ... | |
186 | 223 |
flags=0) for resource in resources) |
187 | 224 |
return set_quota(payload) |
188 | 225 |
|
226 |
def qh_check_users(users): |
|
227 |
payload = [(u.uuid, ENTITY_KEY) for u in users] |
|
228 |
result = get_entity(payload) |
|
229 |
uuids = [entity for (entity, owner) in result] |
|
230 |
|
|
231 |
existing = [] |
|
232 |
nonexisting = [] |
|
233 |
for u in users: |
|
234 |
if u.uuid in uuids: |
|
235 |
existing.append(u) |
|
236 |
else: |
|
237 |
nonexisting.append(u) |
|
238 |
return (existing, nonexisting) |
|
239 |
|
|
189 | 240 |
def qh_add_quota(serial, sub_list, add_list): |
190 | 241 |
if not QUOTAHOLDER_URL: |
191 | 242 |
return () |
b/snf-astakos-app/astakos/im/functions.py | ||
---|---|---|
66 | 66 |
from astakos.im.notifications import build_notification, NotificationError |
67 | 67 |
from astakos.im.models import ( |
68 | 68 |
AstakosUser, ProjectMembership, ProjectApplication, Project, |
69 |
trigger_sync, PendingMembershipError, get_resource_names)
|
|
69 |
sync_projects, PendingMembershipError, get_resource_names)
|
|
70 | 70 |
from astakos.im.models import submit_application as models_submit_application |
71 | 71 |
from astakos.im.project_notif import ( |
72 | 72 |
membership_change_notify, |
73 | 73 |
application_submit_notify, application_approve_notify, |
74 | 74 |
application_deny_notify, |
75 | 75 |
project_termination_notify, project_suspension_notify) |
76 |
from astakos.im.endpoints.qh import qh_register_user, qh_get_quota |
|
76 |
from astakos.im.endpoints.qh import qh_register_user_with_quotas, qh_get_quota
|
|
77 | 77 |
|
78 | 78 |
import astakos.im.messages as astakos_messages |
79 | 79 |
|
... | ... | |
299 | 299 |
if not user.activation_sent: |
300 | 300 |
user.activation_sent = datetime.now() |
301 | 301 |
user.save() |
302 |
qh_register_user(user) |
|
302 |
qh_register_user_with_quotas(user)
|
|
303 | 303 |
send_helpdesk_notification(user, helpdesk_email_template_name) |
304 | 304 |
send_greeting(user, email_template_name) |
305 | 305 |
|
... | ... | |
377 | 377 |
super(SendNotificationError, self).__init__() |
378 | 378 |
|
379 | 379 |
|
380 |
def get_quota(user): |
|
380 |
def get_quota(users):
|
|
381 | 381 |
resources = get_resource_names() |
382 |
return qh_get_quota(user, resources) |
|
382 |
return qh_get_quota(users, resources)
|
|
383 | 383 |
|
384 | 384 |
|
385 | 385 |
### PROJECT VIEWS ### |
... | ... | |
507 | 507 |
|
508 | 508 |
membership = get_membership_for_update(project, user) |
509 | 509 |
membership.accept() |
510 |
trigger_sync()
|
|
510 |
sync_projects()
|
|
511 | 511 |
|
512 | 512 |
membership_change_notify(project, membership.person, 'accepted') |
513 | 513 |
|
... | ... | |
560 | 560 |
|
561 | 561 |
membership = get_membership_for_update(project, user) |
562 | 562 |
membership.remove() |
563 |
trigger_sync()
|
|
563 |
sync_projects()
|
|
564 | 564 |
|
565 | 565 |
membership_change_notify(project, membership.person, 'removed') |
566 | 566 |
|
... | ... | |
576 | 576 |
|
577 | 577 |
membership = create_membership(project_id, user) |
578 | 578 |
membership.accept() |
579 |
trigger_sync()
|
|
579 |
sync_projects()
|
|
580 | 580 |
|
581 | 581 |
# TODO send proper notification |
582 | 582 |
return membership |
... | ... | |
606 | 606 |
leave_policy = project.application.member_leave_policy |
607 | 607 |
if leave_policy == AUTO_ACCEPT_POLICY: |
608 | 608 |
membership.remove() |
609 |
trigger_sync()
|
|
609 |
sync_projects()
|
|
610 | 610 |
else: |
611 | 611 |
membership.leave_request_date = datetime.now() |
612 | 612 |
membership.save() |
... | ... | |
638 | 638 |
if (join_policy == AUTO_ACCEPT_POLICY and |
639 | 639 |
not project.violates_members_limit(adding=1)): |
640 | 640 |
membership.accept() |
641 |
trigger_sync()
|
|
641 |
sync_projects()
|
|
642 | 642 |
return membership |
643 | 643 |
|
644 | 644 |
def submit_application(kw, request_user=None): |
... | ... | |
698 | 698 |
raise PermissionDenied() |
699 | 699 |
|
700 | 700 |
application.approve() |
701 |
trigger_sync()
|
|
701 |
sync_projects()
|
|
702 | 702 |
|
703 | 703 |
application_approve_notify(application) |
704 | 704 |
|
... | ... | |
716 | 716 |
checkAlive(project) |
717 | 717 |
|
718 | 718 |
project.terminate() |
719 |
trigger_sync()
|
|
719 |
sync_projects()
|
|
720 | 720 |
|
721 | 721 |
project_termination_notify(project) |
722 | 722 |
|
... | ... | |
725 | 725 |
checkAlive(project) |
726 | 726 |
|
727 | 727 |
project.suspend() |
728 |
trigger_sync()
|
|
728 |
sync_projects()
|
|
729 | 729 |
|
730 | 730 |
project_suspension_notify(project) |
731 | 731 |
|
... | ... | |
737 | 737 |
raise PermissionDenied(m) |
738 | 738 |
|
739 | 739 |
project.resume() |
740 |
trigger_sync() |
|
740 |
sync_projects() |
b/snf-astakos-app/astakos/im/management/commands/astakos-qh-sync.py | ||
---|---|---|
31 | 31 |
# interpreted as representing official policies, either expressed |
32 | 32 |
# or implied, of GRNET S.A. |
33 | 33 |
|
34 |
from django.core.management.base import NoArgsCommand, CommandError |
|
34 |
from optparse import make_option |
|
35 |
from django.core.management.base import BaseCommand, CommandError |
|
36 |
from django.db import transaction |
|
35 | 37 |
|
36 |
from astakos.im.models import AstakosUser, Resource |
|
37 |
from astakos.im.endpoints.qh import register_users, register_resources |
|
38 |
from astakos.im.models import sync_all_users, sync_projects |
|
38 | 39 |
|
39 | 40 |
import logging |
40 | 41 |
logger = logging.getLogger(__name__) |
41 | 42 |
|
43 |
class Command(BaseCommand): |
|
44 |
help = "Inspect quotaholder status and sync" |
|
42 | 45 |
|
43 |
class Command(NoArgsCommand): |
|
44 |
help = "Send user information and resource quota in the Quotaholder" |
|
46 |
option_list = BaseCommand.option_list + ( |
|
47 |
make_option('--users', |
|
48 |
action='store_true', |
|
49 |
dest='users', |
|
50 |
default=False, |
|
51 |
help="Check if users and their quotas are in sync with quotaholder"), |
|
52 |
make_option('--projects', |
|
53 |
action='store_true', |
|
54 |
dest='projects', |
|
55 |
default=False, |
|
56 |
help="Check if projects are in sync with quotaholder"), |
|
57 |
make_option('--execute', |
|
58 |
action='store_true', |
|
59 |
dest='execute', |
|
60 |
default=False, |
|
61 |
help="Perform the actual operation"), |
|
62 |
) |
|
63 |
|
|
64 |
@transaction.commit_on_success |
|
65 |
def handle(self, *args, **options): |
|
66 |
execute = options['execute'] |
|
45 | 67 |
|
46 |
def handle_noargs(self, **options): |
|
47 | 68 |
try: |
48 |
resources = list(Resource.objects.all()) |
|
49 |
print("Registering resources") |
|
50 |
register_resources(resources) |
|
51 |
print("Registering users") |
|
52 |
users = list(AstakosUser.objects.verified().all()) |
|
53 |
if users: |
|
54 |
register_users(users) |
|
55 |
else: |
|
56 |
print(" -> No verified users found.") |
|
69 |
if options['users']: |
|
70 |
log = sync_all_users(execute=execute) |
|
71 |
elif options['projects']: |
|
72 |
log = sync_projects(execute=execute) |
|
57 | 73 |
except BaseException, e: |
58 | 74 |
logger.exception(e) |
59 | 75 |
raise CommandError("Syncing failed.") |
60 |
|
b/snf-astakos-app/astakos/im/models.py | ||
---|---|---|
70 | 70 |
SITENAME, SERVICES, MODERATION_ENABLED, RESOURCES_PRESENTATION_DATA) |
71 | 71 |
from astakos.im import settings as astakos_settings |
72 | 72 |
from astakos.im.endpoints.qh import ( |
73 |
register_users, register_quotas, qh_check_users, qh_get_quota_limits, |
|
73 | 74 |
register_services, register_resources, qh_add_quota, QuotaLimits, |
74 | 75 |
qh_query_serials, qh_ack_serials, |
75 | 76 |
QuotaValues, add_quota_values) |
... | ... | |
2010 | 2011 |
qh_ack_serials(list(serials_to_ack)) |
2011 | 2012 |
return len(memberships) |
2012 | 2013 |
|
2013 |
def pre_sync(): |
|
2014 |
def pre_sync_projects():
|
|
2014 | 2015 |
ACCEPTED = ProjectMembership.ACCEPTED |
2015 | 2016 |
PROJECT_DEACTIVATED = ProjectMembership.PROJECT_DEACTIVATED |
2016 | 2017 |
psfu = Project.objects.select_for_update() |
... | ... | |
2044 | 2045 |
membership.state = PROJECT_DEACTIVATED |
2045 | 2046 |
membership.save() |
2046 | 2047 |
|
2047 |
def do_sync(): |
|
2048 |
def do_sync_projects():
|
|
2048 | 2049 |
|
2049 | 2050 |
ACCEPTED = ProjectMembership.ACCEPTED |
2050 | 2051 |
objects = ProjectMembership.objects.select_for_update() |
... | ... | |
2085 | 2086 |
|
2086 | 2087 |
return serial |
2087 | 2088 |
|
2088 |
def post_sync(): |
|
2089 |
def post_sync_projects():
|
|
2089 | 2090 |
ACCEPTED = ProjectMembership.ACCEPTED |
2090 | 2091 |
PROJECT_DEACTIVATED = ProjectMembership.PROJECT_DEACTIVATED |
2091 | 2092 |
psfu = Project.objects.select_for_update() |
... | ... | |
2120 | 2121 |
|
2121 | 2122 |
transaction.commit() |
2122 | 2123 |
|
2123 |
def sync_projects():
|
|
2124 |
def _sync_projects(execute):
|
|
2124 | 2125 |
sync_finish_serials() |
2125 |
pre_sync() |
|
2126 |
serial = do_sync() |
|
2126 |
if not execute: |
|
2127 |
# Do some reporting and |
|
2128 |
return |
|
2129 |
|
|
2130 |
pre_sync_projects() |
|
2131 |
serial = do_sync_projects() |
|
2127 | 2132 |
sync_finish_serials([serial]) |
2128 |
post_sync() |
|
2133 |
post_sync_projects() |
|
2134 |
|
|
2135 |
def sync_projects(execute=True, retries=3, retry_wait=1.0): |
|
2136 |
return lock_sync(_sync_projects, |
|
2137 |
args=[execute], |
|
2138 |
retries=retries, |
|
2139 |
retry_wait=retry_wait) |
|
2140 |
|
|
2141 |
def _sync_users(users, execute): |
|
2142 |
sync_finish_serials() |
|
2143 |
|
|
2144 |
existing, nonexisting = qh_check_users(users) |
|
2145 |
resources = get_resource_names() |
|
2146 |
quotas = qh_get_quota_limits(existing, resources) |
|
2129 | 2147 |
|
2130 |
def trigger_sync(retries=3, retry_wait=1.0): |
|
2148 |
if execute: |
|
2149 |
r = register_users(nonexisting) |
|
2150 |
r = register_quotas(users) |
|
2151 |
|
|
2152 |
# TODO: some proper reporting |
|
2153 |
return (existing, nonexisting, quotas) |
|
2154 |
|
|
2155 |
def sync_users(users, execute=True, retries=3, retry_wait=1.0): |
|
2156 |
return lock_sync(_sync_users, |
|
2157 |
args=[users, execute], |
|
2158 |
retries=retries, |
|
2159 |
retry_wait=retry_wait) |
|
2160 |
|
|
2161 |
def sync_all_users(execute=True, retries=3, retry_wait=1.0): |
|
2162 |
users = AstakosUser.objects.all() |
|
2163 |
return sync_users(users, execute, retries=retries, retry_wait=retry_wait) |
|
2164 |
|
|
2165 |
def lock_sync(func, args=[], kwargs={}, retries=3, retry_wait=1.0): |
|
2131 | 2166 |
transaction.commit() |
2132 | 2167 |
|
2133 | 2168 |
cursor = connection.cursor() |
... | ... | |
2148 | 2183 |
return False |
2149 | 2184 |
sleep(retry_wait) |
2150 | 2185 |
|
2151 |
sync_projects() |
|
2152 |
return True |
|
2186 |
return func(*args, **kwargs) |
|
2153 | 2187 |
|
2154 | 2188 |
finally: |
2155 | 2189 |
if locked: |
Also available in: Unified diff