Commit 25be72a7 authored by Sofia Papagiannaki's avatar Sofia Papagiannaki
Browse files

Provide commands for importing/exporting existing user resource policies

parent 88a701f2
......@@ -164,11 +164,8 @@ class DjangoBackend(BaseBackend):
rejected = []
append = rejected.append
for p in policies:
service = p.get('service')
resource = p.get('resource')
uplimit = p.get('uplimit')
try:
user.add_policy(service, resource, uplimit, update)
user.add_resource_policy(**p, update=update)
except (ObjectDoesNotExist, IntegrityError), e:
append((service, resource, e))
return rejected
......@@ -184,7 +181,7 @@ class DjangoBackend(BaseBackend):
service = p.get('service')
resource = p.get('resource')
try:
user.delete_policy(service, resource)
user.remove_resource_policy(service, resource)
except ObjectDoesNotExist, e:
append((service, resource, e))
return rejected
......
......@@ -60,7 +60,9 @@ class AstakosAPI(Specificator):
is_verified=Boolean,
third_party_identifier=Name,
email_verified=Boolean),
policies=ListOf(resource=Name, supimit=Nonnegative),
policies=ListOf(
resource=Name, capacity=Nonnegative, quantity=Nonnegative,
import_limit, export_limit),
groups=ListOf(Name),
permissions=ListOf(Name)
):
......
......@@ -89,7 +89,8 @@ def create_entity(payload):
c = get_client()
if not c:
return
result = c.create_entity(context={}, clientkey=clientkey, create_entity=payload)
result = c.create_entity(
context={}, clientkey=clientkey, create_entity=payload)
logger.info('create_entity: %s rejected: %s' % (payload, result))
return result
......@@ -127,13 +128,13 @@ def register_users(users):
payload = []
append = payload.append
for u in users:
for resource, uplimit in u.quota.iteritems():
for resource, capacity in u.quota.iteritems():
append( SetQuotaPayload(
holder=u.uuid,
resource=resource,
key=ENTITY_KEY,
quantity=0,
capacity=uplimit if uplimit != inf else None,
capacity=capacity if capacity != inf else None,
import_limit=QH_PRACTICALLY_INFINITE,
export_limit=QH_PRACTICALLY_INFINITE,
flags=0))
......
# Copyright 2012 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
# 1. Redistributions of source code must retain the above
# copyright notice, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and
# documentation are those of the authors and should not be
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
import os
from optparse import make_option
from collections import namedtuple
from django.core.management.base import BaseCommand, CommandError
from astakos.im.models import AstakosUser
AddResourceArgs = namedtuple('AddQuotaArgs', ('resource',
'quantity',
'capacity',
'import_limit',
'export_limit'))
class Command(BaseCommand):
help = "Import account quota policies"
def handle(self, *args, **options):
if len(args) != 1:
raise CommandError('Invalid number of arguments')
location = os.path.abspath(args[0])
try:
f = open(location, 'r')
except IOError, e:
raise CommandError(e)
for line in f.readlines():
try:
t = line.rstrip('\n').split(' ')
user = t[0]
args = AddResourceArgs(*t[1:])
except(IndexError, TypeError):
self.stdout.write('Invalid line format: %s:\n' % t)
continue
else:
try:
user = AstakosUser.objects.get(uuid=user)
except AstakosUser.DoesNotExist:
self.stdout.write('Not found user having uuid: %s\n' % uuid)
continue
else:
try:
user.add_resource_policy(*args)
except Exception, e:
self.stdout.write('Failed to policy: %s\n' % e)
continue
finally:
f.close()
......@@ -136,17 +136,6 @@ class Service(models.Model):
for s in resources:
self.resource_set.create(**s)
def add_resource(self, service, resource, uplimit, update=True):
"""Raises ObjectDoesNotExist, IntegrityError"""
resource = Resource.objects.get(service__name=service, name=resource)
if update:
AstakosUserQuota.objects.update_or_create(user=self,
resource=resource,
defaults={'uplimit': uplimit})
else:
q = self.astakosuserquota_set
q.create(resource=resource, uplimit=uplimit)
class ResourceMetadata(models.Model):
key = models.CharField(_('Name'), max_length=255, unique=True, db_index=True)
......@@ -344,7 +333,7 @@ class AstakosUser(User):
default_quota = get_default_quota()
d.update(default_quota)
for q in self.policies:
d[q.resource] += q.uplimit or inf
d[q.resource] = q.capacity or inf
for m in self.projectmembership_set.select_related().all():
if not m.acceptance_date:
continue
......@@ -363,24 +352,34 @@ class AstakosUser(User):
@policies.setter
def policies(self, policies):
for p in policies:
service = policies.get('service', None)
resource = policies.get('resource', None)
uplimit = policies.get('uplimit', 0)
update = policies.get('update', True)
self.add_policy(service, resource, uplimit, update)
def add_policy(self, service, resource, uplimit, update=True):
p.setdefault('resource', '')
p.setdefault('capacity', 0)
p.setdefault('quantity', 0)
p.setdefault('import_limit', 0)
p.setdefault('export_limit', 0)
p.setdefault('update', True)
self.add_resource_policy(**p)
def add_resource_policy(
self, resource, capacity, quantity, import_limit,
export_limit, update=True):
"""Raises ObjectDoesNotExist, IntegrityError"""
resource = Resource.objects.get(service__name=service, name=resource)
s, sep, r = resource.partition(RESOURCE_SEPARATOR)
resource = Resource.objects.get(service__name=s, name=r)
if update:
AstakosUserQuota.objects.update_or_create(user=self,
resource=resource,
defaults={'uplimit': uplimit})
AstakosUserQuota.objects.update_or_create(
user=self, resource=resource, defaults={
'capacity':capacity,
'quantity': quantity,
'import_limit':import_limit,
'export_limit':export_limit})
else:
q = self.astakosuserquota_set
q.create(resource=resource, uplimit=uplimit)
q.create(
resource=resource, capacity=capacity, quanity=quantity,
import_limit=import_limit, export_limit=export_limit)
def remove_policy(self, service, resource):
def remove_resource_policy(self, service, resource):
"""Raises ObjectDoesNotExist, IntegrityError"""
resource = Resource.objects.get(service__name=service, name=resource)
q = self.policies.get(resource=resource).delete()
......@@ -394,10 +393,6 @@ class AstakosUser(User):
self.uuid = uuid_val
return self.uuid
@property
def extended_groups(self):
return self.membership_set.select_related().all()
def save(self, update_timestamps=True, **kwargs):
if update_timestamps:
if not self.id:
......@@ -801,8 +796,10 @@ class ExtendedManager(models.Manager):
class AstakosUserQuota(models.Model):
objects = ExtendedManager()
limit = models.PositiveIntegerField(_('Limit'), null=True) # obsolete field
uplimit = models.BigIntegerField(_('Up limit'), null=True)
capacity = models.BigIntegerField(_('Capacity'), null=True)
quantity = models.BigIntegerField(_('Quantity'), null=True)
export_limit = models.BigIntegerField(_('Export limit'), null=True)
import_limit = models.BigIntegerField(_('Import limit'), null=True)
resource = models.ForeignKey(Resource)
user = models.ForeignKey(AstakosUser)
......
......@@ -87,32 +87,33 @@ def login(
tokens = request.META
third_party_key = get_pending_key(request)
try:
eppn = tokens.get(Tokens.SHIB_EPPN)
if not eppn:
raise KeyError(_(astakos_messages.SHIBBOLETH_MISSING_EPPN) % {
'domain': settings.BASEURL,
'contact_email': settings.DEFAULT_CONTACT_EMAIL
})
if Tokens.SHIB_DISPLAYNAME in tokens:
realname = tokens[Tokens.SHIB_DISPLAYNAME]
elif Tokens.SHIB_CN in tokens:
realname = tokens[Tokens.SHIB_CN]
elif Tokens.SHIB_NAME in tokens and Tokens.SHIB_SURNAME in tokens:
realname = tokens[Tokens.SHIB_NAME] + ' ' + tokens[Tokens.SHIB_SURNAME]
else:
if settings.SHIBBOLETH_REQUIRE_NAME_INFO:
raise KeyError(_(astakos_messages.SHIBBOLETH_MISSING_NAME))
else:
realname = ''
except KeyError, e:
# invalid shibboleth headers, redirect to login, display message
messages.error(request, e.message)
return HttpResponseRedirect(login_url(request))
affiliation = tokens.get(Tokens.SHIB_EP_AFFILIATION, '')
email = tokens.get(Tokens.SHIB_MAIL, '')
# try:
# eppn = tokens.get(Tokens.SHIB_EPPN)
# if not eppn:
# raise KeyError(_(astakos_messages.SHIBBOLETH_MISSING_EPPN) % {
# 'domain': settings.BASEURL,
# 'contact_email': settings.DEFAULT_CONTACT_EMAIL
# })
# if Tokens.SHIB_DISPLAYNAME in tokens:
# realname = tokens[Tokens.SHIB_DISPLAYNAME]
# elif Tokens.SHIB_CN in tokens:
# realname = tokens[Tokens.SHIB_CN]
# elif Tokens.SHIB_NAME in tokens and Tokens.SHIB_SURNAME in tokens:
# realname = tokens[Tokens.SHIB_NAME] + ' ' + tokens[Tokens.SHIB_SURNAME]
# else:
# if settings.SHIBBOLETH_REQUIRE_NAME_INFO:
# raise KeyError(_(astakos_messages.SHIBBOLETH_MISSING_NAME))
# else:
# realname = ''
#
# except KeyError, e:
# # invalid shibboleth headers, redirect to login, display message
# messages.error(request, e.message)
# return HttpResponseRedirect(login_url(request))
# affiliation = tokens.get(Tokens.SHIB_EP_AFFILIATION, '')
# email = tokens.get(Tokens.SHIB_MAIL, '')
eppn, email, realname, affiliation = 'spapagian@grnet-hq.admin.grnet.gr', 'spapagian@.grnet.gr', 'sff', None
provider_info = {'eppn': eppn, 'email': email, 'name': realname}
userid = eppn
......
# Copyright 2012 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
# 1. Redistributions of source code must retain the above
# copyright notice, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and
# documentation are those of the authors and should not be
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
from optparse import make_option
from django.core.management.base import NoArgsCommand, CommandError
from sqlalchemy.sql import select, and_
from pithos.api.util import get_backend
import os
backend = get_backend()
table = {}
table['nodes'] = backend.node.nodes
table['policy'] = backend.node.policy
conn = backend.node.conn
class Command(NoArgsCommand):
help = "Export account quota policies"
option_list = NoArgsCommand.option_list + (
make_option('--location',
dest='location',
default='exported_policies',
help="Where to save the output file"),
)
def handle_noargs(self, **options):
# retrieve account policies
s = select([table['nodes'].c.path, table['policy'].c.value])
s = s.where(and_(table['nodes'].c.node != 0,
table['nodes'].c.parent == 0))
s = s.where(table['nodes'].c.node == table['policy'].c.node)
s = s.where(table['policy'].c.key == 'quota')
location = os.path.abspath(options['location'])
try:
f = open(location, 'w')
except IOError, e:
raise CommandError(e)
for p in conn.execute(s).fetchall():
f.write(' '.join(
[p.path, 'pithos+.diskspace', p.value, '0', '0', '0']))
f.write('\n')
f.close()
backend.close()
......@@ -60,6 +60,7 @@ table = {}
table['nodes'] = backend.node.nodes
table['versions'] = backend.node.versions
table['statistics'] = backend.node.statistics
table['policy'] = backend.node.policy
conn = backend.node.conn
def _compute_statistics(nodes):
......@@ -90,7 +91,7 @@ def _compute_statistics(nodes):
cluster=cluster))
return statistics
def _get_verified_quota(statistics):
def _get_verified_quota(statistics, default_quota=0):
""" Verify statistics and set quotaholder account quota """
add_quota = []
append = add_quota.append
......@@ -109,12 +110,19 @@ def _get_verified_quota(statistics):
print e
continue
else:
s = select([table['policy'].c.value])
s = s.where(table['policy'].c.node == item.node)
s = s.where(table['policy'].c.key == 'quota')
policy = conn.execute(s).fetchone()
capacity = policy.value if policy else 0
if capacity:
capacity -= default_quota
append(AddQuotaPayload(
holder=item.path,
resource='pithos+.diskspace',
key=ENTITY_KEY,
quantity=db_item.size,
capacity=0,
capacity=capacity,
import_limit=0,
export_limit=0))
return add_quota
......@@ -138,7 +146,8 @@ class Command(NoArgsCommand):
account_nodes = conn.execute(s).fetchall()
# compute account statistics
statistics = _compute_statistics(account_nodes)
statistics = _compute_statistics(
account_nodes, default_quota=backend.DEFAULT_QUOTA)
# verify and send quota
add_quota = _get_verified_quota(statistics)
......
......@@ -65,6 +65,10 @@ class Command(BaseCommand):
backend = get_backend()
backend.default_policy['quota'] = BACKEND_QUOTA
backend.default_policy['versioning'] = BACKEND_VERSIONING
if backend.using_external_quotaholder:
raise CommandError("The system uses an extrenal quota holder.")
if quota is not None:
backend.update_account_policy(user, user, {'quota': quota})
else:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment