Resource Quota - DB layer changes
Change-Id: Ib1d4d8634eabdba76c5f7f858efc16702ebc0d2a Partially-Implements: blueprint resource-quota
This commit is contained in:
parent
73059c5c20
commit
ccc04d67fc
|
@ -383,6 +383,10 @@ class QuotaAlreadyExists(Conflict):
|
|||
"for resource %(resource)s.")
|
||||
|
||||
|
||||
class QuotaNotFound(ResourceNotFound):
|
||||
message = _("Quota could not be found: %(msg)s")
|
||||
|
||||
|
||||
class RegionsListFailed(MagnumException):
|
||||
message = _("Failed to list regions.")
|
||||
|
||||
|
|
|
@ -358,6 +358,62 @@ class Connection(object):
|
|||
:returns: A quota record.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_quota(self, project_id, values):
|
||||
"""Update quota record.
|
||||
|
||||
:param project_id: The project id.
|
||||
:param values: A dict containing several items used to identify
|
||||
and track quota for a resource in a project.
|
||||
|
||||
::
|
||||
|
||||
{
|
||||
'id': uuidutils.generate_uuid(),
|
||||
'project_id': 'fake_project',
|
||||
'resource': 'fake_resource',
|
||||
'hard_limit': 'fake_hardlimit',
|
||||
}
|
||||
:returns: A quota record.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_quota(self, project_id, resource):
|
||||
"""Delete a quota.
|
||||
|
||||
:param project_id: Project id.
|
||||
:param resource: resource name.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_quota_by_id(self, context, quota_id):
|
||||
"""Return a quota.
|
||||
|
||||
:param context: The security context
|
||||
:param quota_id: The id of a quota.
|
||||
:returns: A quota.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_quota_list(self, context, filters=None, limit=None,
|
||||
marker=None, sort_key=None, sort_dir=None):
|
||||
"""Get quota list.
|
||||
|
||||
Return a list of the specified columns for all quotas that match the
|
||||
specified filters.
|
||||
|
||||
:param context: The security context
|
||||
:param filters: Filters to apply. Defaults to None.
|
||||
|
||||
:param limit: Maximum number of clusters to return.
|
||||
:param marker: the last item of the previous page; we return the next
|
||||
result set.
|
||||
:param sort_key: Attribute by which results should be sorted.
|
||||
:param sort_dir: direction in which results should be sorted.
|
||||
(asc, desc)
|
||||
:returns: A list of tuples of the specified columns.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def quota_get_all_by_project_id(self, project_id):
|
||||
"""Gets Quota record for all the resources in a project.
|
||||
|
@ -366,3 +422,13 @@ class Connection(object):
|
|||
|
||||
:returns: Quota record for all resources in a project.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_quota_by_project_id_resource(self, project_id, resource):
|
||||
"""Gets quota record for the given quota id.
|
||||
|
||||
:param project_id: project id.
|
||||
:param resource: resource name.
|
||||
|
||||
:returns: Quota record.
|
||||
"""
|
||||
|
|
|
@ -527,8 +527,81 @@ class Connection(api.Connection):
|
|||
resource=values['resource'])
|
||||
return quotas
|
||||
|
||||
def _add_quota_filters(self, query, filters):
|
||||
if filters is None:
|
||||
filters = {}
|
||||
|
||||
possible_filters = ["resource", "project_id"]
|
||||
|
||||
filter_names = set(filters).intersection(possible_filters)
|
||||
filter_dict = {filter_name: filters[filter_name]
|
||||
for filter_name in filter_names}
|
||||
|
||||
query = query.filter_by(**filter_dict)
|
||||
return query
|
||||
|
||||
def get_quota_list(self, context, filters=None, limit=None, marker=None,
|
||||
sort_key=None, sort_dir=None):
|
||||
query = model_query(models.Quota)
|
||||
query = self._add_quota_filters(query, filters)
|
||||
return _paginate_query(models.Quota, limit, marker,
|
||||
sort_key, sort_dir, query)
|
||||
|
||||
def update_quota(self, project_id, values):
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
query = model_query(models.Quota, session=session)
|
||||
resource = values['resource']
|
||||
try:
|
||||
query = query.filter_by(project_id=project_id).filter_by(
|
||||
resource=resource)
|
||||
ref = query.with_lockmode('update').one()
|
||||
except NoResultFound:
|
||||
msg = (_('project_id %(project_id)s resource %(resource)s.') %
|
||||
{'project_id': project_id, 'resource': resource})
|
||||
raise exception.QuotaNotFound(msg=msg)
|
||||
|
||||
ref.update(values)
|
||||
return ref
|
||||
|
||||
def delete_quota(self, project_id, resource):
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
query = model_query(models.Quota, session=session)
|
||||
|
||||
try:
|
||||
query.filter_by(project_id=project_id).filter_by(
|
||||
resource=resource).one()
|
||||
except NoResultFound:
|
||||
msg = (_('project_id %(project_id)s resource %(resource)s.') %
|
||||
{'project_id': project_id, 'resource': resource})
|
||||
raise exception.QuotaNotFound(msg=msg)
|
||||
|
||||
query.delete()
|
||||
|
||||
def get_quota_by_id(self, context, quota_id):
|
||||
query = model_query(models.Quota)
|
||||
query = query.filter_by(id=quota_id)
|
||||
try:
|
||||
return query.one()
|
||||
except NoResultFound:
|
||||
msg = _('quota id %s .') % quota_id
|
||||
raise exception.QuotaNotFound(msg=msg)
|
||||
|
||||
def quota_get_all_by_project_id(self, project_id):
|
||||
query = model_query(models.Quota)
|
||||
result = query.filter_by(project_id=project_id).all()
|
||||
|
||||
return result
|
||||
|
||||
def get_quota_by_project_id_resource(self, project_id, resource):
|
||||
query = model_query(models.Quota)
|
||||
query = query.filter_by(project_id=project_id).filter_by(
|
||||
resource=resource)
|
||||
|
||||
try:
|
||||
return query.one()
|
||||
except NoResultFound:
|
||||
msg = (_('project_id %(project_id)s resource %(resource)s.') %
|
||||
{'project_id': project_id, 'resource': resource})
|
||||
raise exception.QuotaNotFound(msg=msg)
|
||||
|
|
|
@ -39,3 +39,123 @@ class DbQuotaTestCase(base.DbTestCase):
|
|||
self.assertEqual(q.hard_limit, r.hard_limit)
|
||||
self.assertEqual(q.project_id, r.project_id)
|
||||
self.assertEqual(q.resource, r.resource)
|
||||
|
||||
def test_get_quota_by_project_id_resource(self):
|
||||
q = utils.create_test_quotas(project_id='123',
|
||||
resource='test-res',
|
||||
hard_limit=5)
|
||||
res = self.dbapi.get_quota_by_project_id_resource('123', 'test-res')
|
||||
self.assertEqual(q.hard_limit, res.hard_limit)
|
||||
self.assertEqual(q.project_id, res.project_id)
|
||||
self.assertEqual(q.resource, res.resource)
|
||||
|
||||
def test_get_quota_by_project_id_resource_not_found(self):
|
||||
utils.create_test_quotas(project_id='123',
|
||||
resource='test-res',
|
||||
hard_limit=5)
|
||||
self.assertRaises(exception.QuotaNotFound,
|
||||
self.dbapi.get_quota_by_project_id_resource,
|
||||
project_id='123',
|
||||
resource='bad-res')
|
||||
|
||||
def test_get_quota_list(self):
|
||||
project_ids = []
|
||||
for i in range(1, 6):
|
||||
project_id = 'proj-'+str(i)
|
||||
utils.create_test_quotas(project_id=project_id)
|
||||
project_ids.append(project_id)
|
||||
res = self.dbapi.get_quota_list(self.context)
|
||||
res_proj_ids = [r.project_id for r in res]
|
||||
self.assertEqual(sorted(project_ids), sorted(res_proj_ids))
|
||||
|
||||
def test_get_quota_list_sorted(self):
|
||||
project_ids = []
|
||||
for i in range(1, 6):
|
||||
project_id = 'proj-'+str(i)
|
||||
utils.create_test_quotas(project_id=project_id)
|
||||
project_ids.append(project_id)
|
||||
res = self.dbapi.get_quota_list(self.context, sort_key='project_id')
|
||||
res_proj_ids = [r.project_id for r in res]
|
||||
self.assertEqual(sorted(project_ids), res_proj_ids)
|
||||
|
||||
def test_get_quota_list_invalid_sort_key(self):
|
||||
project_ids = []
|
||||
for i in range(1, 6):
|
||||
project_id = 'proj-'+str(i)
|
||||
utils.create_test_quotas(project_id=project_id)
|
||||
project_ids.append(project_id)
|
||||
|
||||
self.assertRaises(exception.InvalidParameterValue,
|
||||
self.dbapi.get_quota_list,
|
||||
self.context,
|
||||
sort_key='invalid')
|
||||
|
||||
def test_get_quota_list_with_filters(self):
|
||||
quota1 = utils.create_test_quotas(project_id='proj-1', resource='res1')
|
||||
quota2 = utils.create_test_quotas(project_id='proj-1', resource='res2')
|
||||
quota3 = utils.create_test_quotas(project_id='proj-2', resource='res1')
|
||||
|
||||
res = self.dbapi.get_quota_list(
|
||||
self.context, filters={'resource': 'res2'})
|
||||
self.assertEqual(quota2.project_id, res[0].project_id)
|
||||
|
||||
res = self.dbapi.get_quota_list(
|
||||
self.context, filters={'project_id': 'proj-2'})
|
||||
self.assertEqual(quota3.project_id, res[0].project_id)
|
||||
|
||||
res = self.dbapi.get_quota_list(
|
||||
self.context, filters={'project_id': 'proj-1'})
|
||||
self.assertEqual(sorted([quota1.project_id, quota2.project_id]),
|
||||
sorted([r.project_id for r in res]))
|
||||
|
||||
def test_update_quota(self):
|
||||
q = utils.create_test_quotas(hard_limit=5,
|
||||
project_id='1234',
|
||||
resource='Cluster')
|
||||
|
||||
res = self.dbapi.get_quota_by_project_id_resource('1234', 'Cluster')
|
||||
self.assertEqual(q.hard_limit, res.hard_limit)
|
||||
self.assertEqual(q.project_id, res.project_id)
|
||||
self.assertEqual(q.resource, res.resource)
|
||||
quota_dict = {'resource': 'Cluster', 'hard_limit': 15}
|
||||
self.dbapi.update_quota('1234', quota_dict)
|
||||
res = self.dbapi.get_quota_by_project_id_resource('1234', 'Cluster')
|
||||
self.assertEqual(quota_dict['hard_limit'], res.hard_limit)
|
||||
self.assertEqual(quota_dict['resource'], res.resource)
|
||||
|
||||
def test_update_quota_not_found(self):
|
||||
utils.create_test_quotas(hard_limit=5,
|
||||
project_id='1234',
|
||||
resource='Cluster')
|
||||
quota_dict = {'resource': 'Cluster', 'hard_limit': 15}
|
||||
self.assertRaises(exception.QuotaNotFound,
|
||||
self.dbapi.update_quota,
|
||||
'invalid_proj',
|
||||
quota_dict)
|
||||
|
||||
def test_delete_quota(self):
|
||||
q = utils.create_test_quotas(project_id='123',
|
||||
resource='test-res',
|
||||
hard_limit=5)
|
||||
res = self.dbapi.get_quota_by_project_id_resource('123', 'test-res')
|
||||
self.assertEqual(q.hard_limit, res.hard_limit)
|
||||
self.assertEqual(q.project_id, res.project_id)
|
||||
self.assertEqual(q.resource, res.resource)
|
||||
self.dbapi.delete_quota(q.project_id, q.resource)
|
||||
self.assertRaises(exception.QuotaNotFound,
|
||||
self.dbapi.get_quota_by_project_id_resource,
|
||||
project_id='123',
|
||||
resource='bad-res')
|
||||
|
||||
def test_delete_quota_that_does_not_exist(self):
|
||||
# Make sure that quota does not exist
|
||||
self.assertRaises(exception.QuotaNotFound,
|
||||
self.dbapi.get_quota_by_project_id_resource,
|
||||
project_id='123',
|
||||
resource='bad-res')
|
||||
|
||||
# Now try to delete non-existing quota
|
||||
self.assertRaises(exception.QuotaNotFound,
|
||||
self.dbapi.delete_quota,
|
||||
project_id='123',
|
||||
resource='bad-res')
|
||||
|
|
|
@ -122,6 +122,32 @@ def create_test_cluster(**kw):
|
|||
return dbapi.create_cluster(cluster)
|
||||
|
||||
|
||||
def get_test_quota(**kw):
|
||||
attrs = {
|
||||
'id': kw.get('id', 42),
|
||||
'project_id': kw.get('project_id', 'fake_project'),
|
||||
'resource': kw.get('resource', 'Cluster'),
|
||||
'hard_limit': kw.get('hard_limit', 10)
|
||||
}
|
||||
|
||||
return attrs
|
||||
|
||||
|
||||
def create_test_quota(**kw):
|
||||
"""Create test quota entry in DB and return Quota DB object.
|
||||
|
||||
Function to be used to create test Quota objects in the database.
|
||||
:param kw: kwargs with overriding values for quota's attributes.
|
||||
:returns: Test Quota DB object.
|
||||
"""
|
||||
quota = get_test_quota(**kw)
|
||||
# Let DB generate ID if it isn't specified explicitly
|
||||
if 'id' not in kw:
|
||||
del quota['id']
|
||||
dbapi = db_api.get_instance()
|
||||
return dbapi.create_quota(quota)
|
||||
|
||||
|
||||
def get_test_x509keypair(**kw):
|
||||
return {
|
||||
'id': kw.get('id', 42),
|
||||
|
@ -187,7 +213,7 @@ def get_test_quotas(**kw):
|
|||
return {
|
||||
'id': kw.get('', 18),
|
||||
'project_id': kw.get('project_id', 'fake_project'),
|
||||
'resource': kw.get('resource', 'fake_resource'),
|
||||
'resource': kw.get('resource', 'Cluster'),
|
||||
'hard_limit': kw.get('hard_limit', 10),
|
||||
'created_at': kw.get('created_at'),
|
||||
'updated_at': kw.get('updated_at'),
|
||||
|
|
Loading…
Reference in New Issue