Commit 70a71ce7 authored by Giorgos Korfiatis's avatar Giorgos Korfiatis
Browse files

Make side-effecting quotaholder API calls fail completely,

if part of the request is rejected.

If such a call returns a non-empty list, this means that
the entire call failed due to the actions mentioned in the list.
parent 5888e742
......@@ -34,6 +34,7 @@
# Import general commission framework
from .exception import (CallError, CorruptedError, InvalidDataError,
ReturnButFail,
register_exception, register_exceptions)
from .callpoint import Callpoint, mkcallargs
......
......@@ -33,7 +33,7 @@
from .specificator import CanonifyException
from .exception import CorruptedError, InvalidDataError
from .exception import CorruptedError, InvalidDataError, ReturnButFail
from .importing import imp_module
from re import compile as re_compile, sub as re_sub
......@@ -165,11 +165,13 @@ class Callpoint(object):
data = self.do_make_call(call_name, data)
else:
data = call_func(**data)
self.commit()
except ReturnButFail, e:
self.rollback()
data = e.data
except Exception, e:
self.rollback()
raise
else:
self.commit()
try:
data = canonifier.canonify_output(call_name, data)
......
......@@ -108,3 +108,7 @@ class CorruptedError(CallError):
@register_exception
class InvalidDataError(CallError):
pass
class ReturnButFail(Exception):
def __init__(self, retval=None):
self.data = retval
......@@ -39,7 +39,7 @@ from synnefo.lib.quotaholder.api import (
DuplicateError)
from synnefo.lib.commissioning import \
Callpoint, CorruptedError, InvalidDataError
Callpoint, CorruptedError, InvalidDataError, ReturnButFail
from synnefo.lib.commissioning.utils.newname import newname
from django.db.models import Q
......@@ -101,6 +101,9 @@ class QuotaholderDjangoDBCallpoint(Callpoint):
e = Entity.objects.create(entity=entity,
owner=owner,
key=key)
if rejected:
raise ReturnButFail(rejected)
return rejected
def set_entity_key(self, context={}, set_entity_key=()):
......@@ -117,6 +120,8 @@ class QuotaholderDjangoDBCallpoint(Callpoint):
e.key = newkey
e.save()
if rejected:
raise ReturnButFail(rejected)
return rejected
def list_entities(self, context={}, entity=None, key=None):
......@@ -243,6 +248,8 @@ class QuotaholderDjangoDBCallpoint(Callpoint):
h = Holding.objects.create( entity=e, resource=resource,
policy=p, flags=flags )
if rejected:
raise ReturnButFail(rejected)
return rejected
def _init_holding(self, entity, resource, policy,
......@@ -294,6 +301,8 @@ class QuotaholderDjangoDBCallpoint(Callpoint):
imported, exported,
returned, released,
flags)
if rejected:
raise ReturnButFail(rejected)
return rejected
def reset_holding(self, context={}, reset_holding=()):
......@@ -325,6 +334,8 @@ class QuotaholderDjangoDBCallpoint(Callpoint):
append(idx)
continue
if rejected:
raise ReturnButFail(rejected)
return rejected
def _check_pending(self, entity, resource):
......@@ -384,6 +395,8 @@ class QuotaholderDjangoDBCallpoint(Callpoint):
h.delete()
if rejected:
raise ReturnButFail(rejected)
return rejected
def list_resources(self, context={}, entity=None, key=None):
......@@ -489,6 +502,8 @@ class QuotaholderDjangoDBCallpoint(Callpoint):
if p is not None and p.holding_set.count() == 0:
p.delete()
if rejected:
raise ReturnButFail(rejected)
return rejected
def issue_commission(self, context = {},
......@@ -770,6 +785,8 @@ class QuotaholderDjangoDBCallpoint(Callpoint):
e.delete()
if rejected:
raise ReturnButFail(rejected)
return rejected
def get_timeline(self, context={}, after="", before="Z", get_timeline=()):
......
......@@ -180,11 +180,20 @@ class QHAPITest(QHTestCase):
f1 = self.rand_flags()
p2, _ = self.new_policy()
f2 = self.rand_flags()
# none is committed
r = self.qh.set_holding(set_holding=[(e, resource, k, p0, f0),
(e, resource, k, p1, f1),
(e, resource, k, p2, f2)])
self.assertEqual(r, [(e, resource, p0)])
r = self.qh.get_holding(get_holding=[(e, resource, k)])
self.assertEqual(r, [])
r = self.qh.set_holding(set_holding=[(e, resource, k, p1, f1),
(e, resource, k, p2, f2)])
self.assertEqual(r, [])
resource1 = self.rand_resource()
r = self.qh.get_holding(get_holding=[(e, resource, k),
(e, resource1, k)])
......@@ -277,19 +286,35 @@ class QHAPITest(QHTestCase):
def test_011_release_empty(self):
e, k = self.new_entity()
e0, k0 = self.rand_entity(), Key.random()
# none is committed
r = self.qh.release_entity(release_entity=[(e, k), (e0, k0)])
self.assertEqual(r, [e0])
r = self.qh.get_entity(get_entity=[(e, k)])
self.assertEqual(r, [(e, 'system')])
r = self.qh.release_entity(release_entity=[(e, k)])
self.assertEqual(r, [])
r = self.qh.get_entity(get_entity=[(e, k)])
self.assertEqual(r, [])
def test_012_release_nonempty(self):
e, k = self.new_entity()
e1, k1 = self.new_entity(e, k)
# none is committed
r = self.qh.release_entity(release_entity=[(e, k), (e1, k1)])
self.assertEqual(r, [e])
r = self.qh.get_entity(get_entity=[(e1, k1)])
self.assertEqual(r, [(e1, e)])
r = self.qh.release_entity(release_entity=[(e1, k1), (e, k)])
self.assertEqual(r, [])
r = self.qh.release_entity(release_entity=[(e, k)])
r = self.qh.get_entity(get_entity=[(e1, k1)])
self.assertEqual(r, [])
def test_013_release_nonempty(self):
......@@ -312,10 +337,20 @@ class QHAPITest(QHTestCase):
r = self.qh.set_holding(set_holding=[(e1, resource, k1, p, f)])
counters = self.rand_counters()
# none is committed
r = self.qh.reset_holding(
reset_holding=[(e0, resource, k0) + counters,
(e1, resource, k1) + counters])
self.assertEqual(r, [0])
r = self.qh.get_holding(get_holding=[(e1, resource, k1)])
self.assertEqual(r, [(e1, resource, p) + DEFAULT_HOLDING + (f,)])
r = self.qh.reset_holding(
reset_holding=[(e1, resource, k1) + counters])
self.assertEqual(r, [])
r = self.qh.get_holding(get_holding=[(e1, resource, k1)])
self.assertEqual(r, [(e1, resource, p) + counters + (f,)])
......
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