diff --git a/snf-cyclades-app/synnefo/quotas/__init__.py b/snf-cyclades-app/synnefo/quotas/__init__.py
index 4451d4b1cddf2b61f319f55d2ed3e89d18bda969..747c8d28a6478df5d76838af8751034aba322713 100644
--- a/snf-cyclades-app/synnefo/quotas/__init__.py
+++ b/snf-cyclades-app/synnefo/quotas/__init__.py
@@ -148,7 +148,7 @@ def issue_commission(user, source, provisions,
try:
serial = qh.issue_one_commission(ASTAKOS_TOKEN,
user, source, provisions,
- force, auto_accept)
+ force=force, auto_accept=auto_accept)
except QuotaLimit as e:
msg, details = render_overlimit_exception(e)
raise faults.OverLimit(msg, details=details)
diff --git a/snf-cyclades-app/synnefo/quotas/management/commands/cyclades-reset-usage.py b/snf-cyclades-app/synnefo/quotas/management/commands/cyclades-reset-usage.py
deleted file mode 100644
index e9bafd8c3e1b7f09038a584c5bdb3de815dc00cf..0000000000000000000000000000000000000000
--- a/snf-cyclades-app/synnefo/quotas/management/commands/cyclades-reset-usage.py
+++ /dev/null
@@ -1,76 +0,0 @@
-# Copyright 2012, 2013 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 django.core.management.base import BaseCommand
-from optparse import make_option
-
-from synnefo.quotas import Quotaholder
-from synnefo.quotas.util import get_db_holdings
-
-
-class Command(BaseCommand):
- help = """Reset cyclades.* usage values in Quotaholder"""
- output_transaction = True
- option_list = BaseCommand.option_list + (
- make_option("--userid", dest="userid",
- default=None,
- help="Verify quotas only for this user"),
- make_option("--dry-run", dest="dry_run",
- action='store_true',
- default=False),
- )
-
- def handle(self, *args, **options):
- userid = options['userid']
-
- users = [userid] if userid else None
- # Get info from DB
- db_holdings = get_db_holdings(users)
-
- # Create commissions
- qh = Quotaholder.get()
- for user, resources in db_holdings.items():
- if not user:
- continue
- reset_holding = []
- for res, val in resources.items():
- reset_holding.append((user, "cyclades." + res, "1", val, 0,
- 0, 0))
- if not options['dry_run']:
- try:
- qh.reset_holding(context={},
- reset_holding=reset_holding)
- except Exception as e:
- self.stderr.write("Can not set up holding:%s" % e)
- else:
- self.stdout.write("Reseting holding: %s\n" % reset_holding)
diff --git a/snf-cyclades-app/synnefo/quotas/management/commands/cyclades-usage-verify.py b/snf-cyclades-app/synnefo/quotas/management/commands/cyclades-usage-verify.py
index 61cdf100133a790df2a072b7975aedb0d551cfde..55aa82871e6ed6d95aeeea577a97cc52be18fd4c 100644
--- a/snf-cyclades-app/synnefo/quotas/management/commands/cyclades-usage-verify.py
+++ b/snf-cyclades-app/synnefo/quotas/management/commands/cyclades-usage-verify.py
@@ -34,68 +34,85 @@
from django.core.management.base import BaseCommand
from optparse import make_option
-from synnefo.quotas import DEFAULT_SOURCE
+
+from synnefo import quotas
from synnefo.quotas.util import (get_db_holdings, get_quotaholder_holdings,
transform_quotas)
from synnefo.webproject.management.utils import pprint_table
+from synnefo.settings import CYCLADES_ASTAKOS_SERVICE_TOKEN as ASTAKOS_TOKEN
class Command(BaseCommand):
- help = """
- Verify that cyclades.* resource usage.
+ help = """Reconcile quotas of Astakos with Cyclades DB.
- Verify that usage calculated from Cyclades DB agrees with the usage
- recorded in the effective quota database (Quotaholder)
+ Detect unsynchronized quotas between Astakos and Cyclades DB and
+ synchronize them if specified so.
"""
- output_transaction = True
option_list = BaseCommand.option_list + (
make_option("--userid", dest="userid",
default=None,
- help="Verify usage only for this user"),
+ help="Reconcile resources only for this user"),
+ make_option("--fix", dest="fix",
+ default=False,
+ action="store_true",
+ help="Synchronize Astakos quotas with Cyclades DB."),
+ make_option("--force",
+ default=False,
+ action="store_true",
+ help="Override Astakos quotas. Force Astakos to impose"
+ " the Cyclades quota, independently of their value.")
)
def handle(self, *args, **options):
write = self.stdout.write
userid = options['userid']
- users = [userid] if userid else None
- # Get info from DB
- db_holdings = get_db_holdings(users)
- users = db_holdings.keys()
+ # Get holdings from Cyclades DB
+ db_holdings = get_db_holdings(userid)
+ # Get holdings from QuotaHolder
qh_holdings = get_quotaholder_holdings(userid)
- qh_users = qh_holdings.keys()
- if len(qh_users) < len(users):
- for u in set(users) - set(qh_users):
- write("Unknown entity: %s\n" % u)
- users = qh_users
+ users = set(db_holdings.keys())
+ users.update(qh_holdings.keys())
+ # Remove 'None' user
+ users.discard(None)
- headers = ("User", "Resource", "Database", "Quotaholder")
unsynced = []
for user in users:
- db = db_holdings[user]
- qh_all = qh_holdings[user]
+ db = db_holdings.get(user, {})
+ qh_all = qh_holdings.get(user, {})
# Assuming only one source
- qh = qh_all[DEFAULT_SOURCE]
+ qh = qh_all.get(quotas.DEFAULT_SOURCE, {})
qh = transform_quotas(qh)
-
- for resource, (value, value1) in qh.iteritems:
- db_value = db.pop(resource, None)
- if value != value1:
- write("Commission pending for %s"
- % str((user, resource)))
+ for resource in quotas.RESOURCES:
+ db_value = db.pop(resource, 0)
+ qh_value, _, qh_pending = qh.pop(resource, (0, 0))
+ if qh_pending:
+ write("Pending commission. User '%s', resource '%s'.\n" %
+ (user, resource))
continue
- if db_value is None:
- write("Resource %s exists in QH for %s but not in DB\n"
- % (resource, user))
- elif db_value != value:
- data = (user, resource, str(db_value), str(value))
+ if db_value != qh_value:
+ data = (user, resource, db_value, qh_value)
unsynced.append(data)
- for resource, db_value in db.iteritems():
- write("Resource %s exists in DB for %s but not in QH\n"
- % (resource, user))
-
+ headers = ("User", "Resource", "Database", "Quotaholder")
if unsynced:
pprint_table(self.stderr, unsynced, headers)
+ if options["fix"]:
+ qh = quotas.Quotaholder.get()
+ request = {}
+ request["force"] = options["force"]
+ request["auto_accept"] = True
+ request["provisions"] = map(create_provision, unsynced)
+ qh.issue_commission(ASTAKOS_TOKEN, request)
+ else:
+ write("Everything in sync.\n")
+
+
+def create_provision(provision_info):
+ user, resource, db_value, qh_value = provision_info
+ return {"holder": user,
+ "source": quotas.DEFAULT_SOURCE,
+ "resource": resource,
+ "quantity": db_value - qh_value}