Implement basic Enforcer context manager

This commit builds the foundation for a context manager that can be
used for usage enforcement.

Subsequent patches will incorporate keystoneauth and perform calls
to keystone to verify project limits and registered limits,
incorporating them into the usage check.

Change-Id: I7c78c1979444a2a83189e2035a4ab72890abc5ab
This commit is contained in:
Lance Bragstad 2018-07-02 20:53:13 +00:00
parent 9f7fd57753
commit 9359e9c1c7
2 changed files with 102 additions and 0 deletions

View File

@ -44,3 +44,42 @@ class ProjectClaim(object):
self.resource_name = resource_name
self.project_id = project_id
self.quantity = quantity
class Enforcer(object):
def __init__(self, claim, callback=None, verify=True):
"""Context manager for checking usage against resource claims.
:param claim: An object containing information about the claim.
:type claim: ``oslo_limit.limit.ProjectClaim``
:param callback: A callable function that accepts a project_id string
as a parameter and calculates the current usage of a
resource.
:type callable function:
:param verify: Boolean denoting whether or not to verify the new usage
after executing a claim. This can be useful for handling
race conditions between clients claiming resources.
:type verify: boolean
"""
if not isinstance(claim, ProjectClaim):
msg = 'claim must be an instance of oslo_limit.limit.ProjectClaim.'
raise ValueError(msg)
if callback and not callable(callback):
msg = 'callback must be a callable function.'
raise ValueError(msg)
if verify and not isinstance(verify, bool):
msg = 'verify must be a boolean value.'
raise ValueError(msg)
self.claim = claim
self.callback = callback
self.verify = verify
def __enter__(self):
pass
def __exit__(self, *args):
pass

View File

@ -91,3 +91,66 @@ class TestProjectClaim(base.BaseTestCase):
invalid_quantity,
quantity=invalid_quantity
)
class TestEnforcer(base.BaseTestCase):
def setUp(self):
super(TestEnforcer, self).setUp()
self.resource_name = uuid.uuid4().hex
self.project_id = uuid.uuid4().hex
self.quantity = 10
self.claim = limit.ProjectClaim(
self.resource_name, self.project_id, quantity=self.quantity
)
def _get_usage_for_project(self, project_id):
return 8
def test_required_parameters(self):
enforcer = limit.Enforcer(self.claim)
self.assertEqual(self.claim, enforcer.claim)
self.assertIsNone(enforcer.callback)
self.assertTrue(enforcer.verify)
def test_optional_parameters(self):
callback = self._get_usage_for_project
enforcer = limit.Enforcer(self.claim, callback=callback, verify=True)
self.assertEqual(self.claim, enforcer.claim)
self.assertEqual(self._get_usage_for_project, enforcer.callback)
self.assertTrue(enforcer.verify)
def test_callback_must_be_callable(self):
invalid_callback_types = [uuid.uuid4().hex, 5, 5.1]
for invalid_callback in invalid_callback_types:
self.assertRaises(
ValueError,
limit.Enforcer,
self.claim,
callback=invalid_callback
)
def test_verify_must_be_boolean(self):
invalid_verify_types = [uuid.uuid4().hex, 5, 5.1]
for invalid_verify in invalid_verify_types:
self.assertRaises(
ValueError,
limit.Enforcer,
self.claim,
callback=self._get_usage_for_project,
verify=invalid_verify
)
def test_claim_must_be_an_instance_of_project_claim(self):
invalid_claim_types = [uuid.uuid4().hex, 5, 5.1, True, False, [], {}]
for invalid_claim in invalid_claim_types:
self.assertRaises(
ValueError,
limit.Enforcer,
invalid_claim,
)