Commit 15e08fdf authored by Giorgos Korfiatis's avatar Giorgos Korfiatis
Browse files

Sync quotas efficiently when importing resources

When changing the default base quota (uplimit) for a preexisting resource,
do a bulk update of the related holdings.
When importing a new resource, create the new related holdings.

Prompt the admin for the uplimit in the management command, if a config
file is not given.
parent a125b747
......@@ -38,7 +38,7 @@ from django.db.utils import IntegrityError
from django.utils import simplejson as json
from synnefo.lib.db.transaction import commit_on_success_strict
from astakos.im.resources import add_resources
from astakos.im.resources import add_resource
class Command(BaseCommand):
......@@ -50,33 +50,66 @@ class Command(BaseCommand):
dest='json',
metavar='<json.file>',
help="Load resource info from a json file"),
make_option('--service',
dest='service_id',
metavar='<service_id>',
help=("Automatically load resource info for a given "
"service")),
make_option('--conf',
dest='conf',
metavar='<conf.json>',
help="Limit configuration file"),
)
@commit_on_success_strict()
def handle(self, *args, **options):
config = {}
conf_file = options['conf']
if not conf_file:
m = "Please provide a configuation file."
raise CommandError(m)
with open(conf_file) as file_data:
config = json.load(file_data)
if conf_file is not None:
with open(conf_file) as file_data:
config = json.load(file_data)
json_file = options['json']
service_id = options['service_id']
if bool(json_file) == bool(service_id):
m = "Please provide either --service or --json option."
raise CommandError(m)
if service_id:
raise NotImplementedError()
if json_file:
with open(json_file) as file_data:
data = json.load(file_data)
service = data.get('service')
resources = data.get('resources')
if service is None or resources is None:
m = "JSON file should contain service and resource data."
raise CommandError(m)
self.add_resources(service, resources, config)
@commit_on_success_strict()
def add_resources(self, service, resources, config):
for resource in resources:
name = resource['name']
uplimit = config.get(name)
if uplimit is None:
desc = resource['desc']
unit = resource.get('unit')
self.stdout.write(
"Provide default base quota for resource '%s' (%s)" %
(name, desc))
m = (" in %s: " % unit) if unit else ": "
self.stdout.write(m)
uplimit = raw_input()
service = data.get('service')
resources = data.get('resources')
if service is None or resources is None:
m = "JSON file should contain service and resource data."
try:
uplimit = int(uplimit)
except ValueError:
m = "Limit for resource %s is not an integer." % (name)
raise CommandError(m)
add_resources(service, resources, config)
add_resource(service, resource, uplimit)
......@@ -236,3 +236,21 @@ def sync_users(users, sync=True):
def sync_all_users(sync=True):
users = AstakosUser.objects.verified()
return sync_users(users, sync)
def qh_add_resource_limit(resource, diff):
users = AstakosUser.forupdate.all().select_for_update()
qh.add_resource_limit(SYSTEM, resource, diff)
def qh_sync_new_resource(resource, limit):
users = AstakosUser.forupdate.filter(
email_verified=True).select_for_update()
data = []
for user in users:
uuid = user.uuid
key = uuid, SYSTEM, resource
data.append((key, limit))
qh.set_quota(data)
......@@ -33,35 +33,41 @@
from astakos.im.models import Service, Resource
from astakos.im.functions import qh_sync_all_users
from astakos.im.quotas import qh_add_resource_limit, qh_sync_new_resource
import logging
logger = logging.getLogger(__name__)
def add_resources(service, resources, conf):
def add_resource(service, resource, uplimit):
try:
s = Service.objects.get(name=service)
except Service.DoesNotExist:
raise Exception("Service %s is not registered." % (service))
names = [resource['name'] for resource in resources]
rs = Resource.objects.filter(name__in=names).select_for_update()
rs = dict((r.name, r) for r in rs)
for resource in resources:
name = resource['name']
existing = rs.get(name)
r = existing if existing is not None else Resource()
name = resource['name']
try:
r = Resource.objects.get_for_update(name=name)
old_uplimit = r.uplimit
except Resource.DoesNotExist:
r = Resource()
old_uplimit = None
uplimit = conf.get(name)
if uplimit is None:
raise Exception("Limit for resource %s is missing." % (name))
r.uplimit = uplimit
r.service = s
for key, value in resource.iteritems():
setattr(r, key, value)
if not isinstance(uplimit, (int, long)):
raise Exception("Limit for resource %s is not an integer." %
(name))
r.save()
r.uplimit = uplimit
r.service = s
for key, value in resource.iteritems():
setattr(r, key, value)
if old_uplimit is not None:
logger.info("Updated resource %s with limit %s." % (name, uplimit))
else:
logger.info("Added resource %s with limit %s." % (name, uplimit))
r.save()
qh_sync_all_users()
if old_uplimit is not None:
diff = uplimit - old_uplimit
if diff != 0:
qh_add_resource_limit(name, diff)
else:
qh_sync_new_resource(name, uplimit)
......@@ -31,6 +31,7 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
from django.db.models import F
from astakos.quotaholder.exception import (
QuotaholderError,
NoCommissionError,
......@@ -131,6 +132,10 @@ class QuotaholderDjangoDBCallpoint(object):
h.save()
holdings[key] = h
def add_resource_limit(self, source, resource, diff):
objs = Holding.objects.filter(source=source, resource=resource)
objs.update(limit=F('limit')+diff)
def issue_commission(self,
context=None,
clientkey=None,
......
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