Merge "Add Quota SQL database models & api"
This commit is contained in:
commit
95611e8bf2
@ -681,3 +681,20 @@ class ContainerActionEventNotFound(ZunException):
|
|||||||
class ServerNotUsable(ZunException):
|
class ServerNotUsable(ZunException):
|
||||||
message = _("Zun server not usable")
|
message = _("Zun server not usable")
|
||||||
code = 404
|
code = 404
|
||||||
|
|
||||||
|
|
||||||
|
class QuotaNotFound(NotFound):
|
||||||
|
message = _("Quota could not be found.")
|
||||||
|
|
||||||
|
|
||||||
|
class ProjectQuotaNotFound(QuotaNotFound):
|
||||||
|
message = _("Quota for project %(project_id)s could not be found.")
|
||||||
|
|
||||||
|
|
||||||
|
class QuotaExists(ZunException):
|
||||||
|
message = _("Quota exists for project %(project_id)s, "
|
||||||
|
"resource %(resource)s.")
|
||||||
|
|
||||||
|
|
||||||
|
class QuotaClassNotFound(QuotaNotFound):
|
||||||
|
message = _("Quota class %(class_name)s could not be found.")
|
||||||
|
@ -890,3 +890,72 @@ def action_event_finish(context, values):
|
|||||||
def action_events_get(context, action_id):
|
def action_events_get(context, action_id):
|
||||||
"""Get the events by action id."""
|
"""Get the events by action id."""
|
||||||
return _get_dbdriver_instance().action_events_get(context, action_id)
|
return _get_dbdriver_instance().action_events_get(context, action_id)
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace("db")
|
||||||
|
def quota_create(context, project_id, resource, limit):
|
||||||
|
"""Create a quota for the given project and resource"""
|
||||||
|
return _get_dbdriver_instance().quota_create(context, project_id,
|
||||||
|
resource, limit)
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace("db")
|
||||||
|
def quota_get(context, project_id, resource):
|
||||||
|
"""Retrieve a quota or raise if it does not exist"""
|
||||||
|
return _get_dbdriver_instance().quota_get(context, project_id,
|
||||||
|
resource)
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace("db")
|
||||||
|
def quota_get_all_by_project(context, project_id):
|
||||||
|
"""Retrieve all quotas associated with a given project"""
|
||||||
|
return _get_dbdriver_instance().quota_get_all_by_project(context,
|
||||||
|
project_id)
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace("db")
|
||||||
|
def quota_update(context, project_id, resource, limit):
|
||||||
|
"""Update a quota or raise if it does not exist"""
|
||||||
|
return _get_dbdriver_instance().quota_update(context, project_id,
|
||||||
|
resource, limit)
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace("db")
|
||||||
|
def quota_destroy(context, project_id, resource):
|
||||||
|
"""Destroy resource quota associated with a given project"""
|
||||||
|
return _get_dbdriver_instance().quota_destroy(context, project_id,
|
||||||
|
resource)
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace("db")
|
||||||
|
def quota_class_create(context, class_name, resource, limit):
|
||||||
|
"""Create a quota class for the given name and resource"""
|
||||||
|
return _get_dbdriver_instance().quota_class_create(context, class_name,
|
||||||
|
resource, limit)
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace("db")
|
||||||
|
def quota_class_get(context, class_name, resource):
|
||||||
|
"""Retrieve a quota class or raise if it does not exist"""
|
||||||
|
return _get_dbdriver_instance().quota_class_get(context, class_name,
|
||||||
|
resource)
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace("db")
|
||||||
|
def quota_class_get_default(context):
|
||||||
|
"""Retrieve all default quota"""
|
||||||
|
return _get_dbdriver_instance().quota_class_get_default(context)
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace("db")
|
||||||
|
def quota_class_get_all_by_name(context, class_name):
|
||||||
|
"""Retrieve all quotas associated with a given quota class"""
|
||||||
|
return _get_dbdriver_instance().quota_class_get_all_by_name(
|
||||||
|
context, class_name)
|
||||||
|
|
||||||
|
|
||||||
|
@profiler.trace("db")
|
||||||
|
def quota_class_update(context, class_name, resource, limit):
|
||||||
|
"""Update a quota class or raise if it does not exist"""
|
||||||
|
return _get_dbdriver_instance().quota_class_update(context, class_name,
|
||||||
|
resource, limit)
|
||||||
|
@ -0,0 +1,59 @@
|
|||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
"""Create quota & quota class tables
|
||||||
|
|
||||||
|
Revision ID: 2b045cb595db
|
||||||
|
Revises: 238f94009eab
|
||||||
|
Create Date: 2018-04-09 13:33:52.522262
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '2b045cb595db'
|
||||||
|
down_revision = '238f94009eab'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_table(
|
||||||
|
'quotas',
|
||||||
|
sa.Column('created_at', sa.DateTime()),
|
||||||
|
sa.Column('updated_at', sa.DateTime()),
|
||||||
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('project_id', sa.String(length=255), index=True),
|
||||||
|
sa.Column('resource', sa.String(length=255), nullable=False),
|
||||||
|
sa.Column('hard_limit', sa.Integer()),
|
||||||
|
sa.PrimaryKeyConstraint('id'),
|
||||||
|
mysql_charset='utf8',
|
||||||
|
mysql_engine='InnoDB'
|
||||||
|
)
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
'quota_classes',
|
||||||
|
sa.Column('created_at', sa.DateTime()),
|
||||||
|
sa.Column('updated_at', sa.DateTime()),
|
||||||
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('class_name', sa.String(length=255), index=True),
|
||||||
|
sa.Column('resource', sa.String(length=255)),
|
||||||
|
sa.Column('hard_limit', sa.Integer()),
|
||||||
|
sa.Index('quota_classes_class_name_idx', 'class_name'),
|
||||||
|
sa.PrimaryKeyConstraint('id'),
|
||||||
|
mysql_charset='utf8',
|
||||||
|
mysql_engine='InnoDB'
|
||||||
|
)
|
||||||
|
# ### end Alembic commands ###
|
@ -40,6 +40,8 @@ CONF = zun.conf.CONF
|
|||||||
|
|
||||||
_FACADE = None
|
_FACADE = None
|
||||||
|
|
||||||
|
_DEFAULT_QUOTA_NAME = 'default'
|
||||||
|
|
||||||
|
|
||||||
def _create_facade_lazily():
|
def _create_facade_lazily():
|
||||||
global _FACADE
|
global _FACADE
|
||||||
@ -1043,3 +1045,117 @@ class Connection(object):
|
|||||||
events = _paginate_query(models.ContainerActionEvent, sort_dir='desc',
|
events = _paginate_query(models.ContainerActionEvent, sort_dir='desc',
|
||||||
sort_key='created_at', query=query)
|
sort_key='created_at', query=query)
|
||||||
return events
|
return events
|
||||||
|
|
||||||
|
def quota_create(self, context, project_id, resource, limit):
|
||||||
|
quota_ref = models.Quota()
|
||||||
|
quota_ref.project_id = project_id
|
||||||
|
quota_ref.resource = resource
|
||||||
|
quota_ref.hard_limit = limit
|
||||||
|
session = get_session()
|
||||||
|
try:
|
||||||
|
quota_ref.save(session=session)
|
||||||
|
except db_exc.DBDuplicateEntry:
|
||||||
|
raise exception.QuotaExists(project_id=project_id,
|
||||||
|
resource=resource)
|
||||||
|
return quota_ref
|
||||||
|
|
||||||
|
def quota_get(self, context, project_id, resource):
|
||||||
|
session = get_session()
|
||||||
|
with session.begin():
|
||||||
|
query = model_query(models.Quota, session=session).\
|
||||||
|
filter_by(project_id=project_id).\
|
||||||
|
filter_by(resource=resource)
|
||||||
|
result = query.first()
|
||||||
|
if not result:
|
||||||
|
raise exception.ProjectQuotaNotFound(project_id=project_id)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def quota_get_all_by_project(self, context, project_id):
|
||||||
|
session = get_session()
|
||||||
|
with session.begin():
|
||||||
|
rows = model_query(models.Quota, session=session).\
|
||||||
|
filter_by(project_id=project_id).\
|
||||||
|
all()
|
||||||
|
result = {'project_id': project_id}
|
||||||
|
for row in rows:
|
||||||
|
result[row.resource] = row.hard_limit
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def quota_update(self, context, project_id, resource, limit):
|
||||||
|
session = get_session()
|
||||||
|
with session.begin():
|
||||||
|
query = model_query(models.Quota, session=session).\
|
||||||
|
filter_by(project_id=project_id).\
|
||||||
|
filter_by(resource=resource)
|
||||||
|
|
||||||
|
result = query.update({'hard_limit': limit})
|
||||||
|
if not result:
|
||||||
|
raise exception.ProjectQuotaNotFound(project_id=project_id)
|
||||||
|
|
||||||
|
def quota_destroy(self, context, project_id, resource):
|
||||||
|
session = get_session()
|
||||||
|
with session.begin():
|
||||||
|
query = model_query(models.Quota, session=session).\
|
||||||
|
filter_by(project_id=project_id).\
|
||||||
|
filter_by(resource=resource)
|
||||||
|
query.delete()
|
||||||
|
|
||||||
|
def quota_class_create(self, context, class_name, resource, limit):
|
||||||
|
quota_class_ref = models.QuotaClass()
|
||||||
|
quota_class_ref.class_name = class_name
|
||||||
|
quota_class_ref.resource = resource
|
||||||
|
quota_class_ref.hard_limit = limit
|
||||||
|
session = get_session()
|
||||||
|
with session.begin():
|
||||||
|
quota_class_ref.save(session=session)
|
||||||
|
return quota_class_ref
|
||||||
|
|
||||||
|
def quota_class_get(self, context, class_name, resource):
|
||||||
|
session = get_session()
|
||||||
|
with session.begin():
|
||||||
|
result = model_query(models.QuotaClass, session=session).\
|
||||||
|
filter_by(class_name=class_name).\
|
||||||
|
filter_by(resource=resource).\
|
||||||
|
first()
|
||||||
|
|
||||||
|
if not result:
|
||||||
|
raise exception.QuotaClassNotFound(class_name=class_name)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def quota_class_get_default(self, context):
|
||||||
|
session = get_session()
|
||||||
|
with session.begin():
|
||||||
|
rows = model_query(models.QuotaClass, session=session).\
|
||||||
|
filter_by(class_name=_DEFAULT_QUOTA_NAME).\
|
||||||
|
all()
|
||||||
|
|
||||||
|
result = {'class_name': _DEFAULT_QUOTA_NAME}
|
||||||
|
for row in rows:
|
||||||
|
result[row.resource] = row.hard_limit
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def quota_class_get_all_by_name(self, context, class_name):
|
||||||
|
session = get_session()
|
||||||
|
with session.begin():
|
||||||
|
rows = model_query(models.QuotaClass, session=session).\
|
||||||
|
filter_by(class_name=class_name).\
|
||||||
|
all()
|
||||||
|
|
||||||
|
result = {'class_name': class_name}
|
||||||
|
for row in rows:
|
||||||
|
result[row.resource] = row.hard_limit
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def quota_class_update(self, context, class_name, resource, limit):
|
||||||
|
session = get_session()
|
||||||
|
with session.begin():
|
||||||
|
result = model_query(models.QuotaClass, session=session).\
|
||||||
|
filter_by(class_name=class_name).\
|
||||||
|
filter_by(resource=resource).\
|
||||||
|
update({'hard_limit': limit})
|
||||||
|
|
||||||
|
if not result:
|
||||||
|
raise exception.QuotaClassNotFound(class_name=class_name)
|
||||||
|
@ -201,7 +201,7 @@ class Image(Base):
|
|||||||
__table_args__ = (
|
__table_args__ = (
|
||||||
schema.UniqueConstraint('repo', 'tag', name='uniq_image0repotag'),
|
schema.UniqueConstraint('repo', 'tag', name='uniq_image0repotag'),
|
||||||
table_args()
|
table_args()
|
||||||
)
|
)
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
project_id = Column(String(255))
|
project_id = Column(String(255))
|
||||||
user_id = Column(String(255))
|
user_id = Column(String(255))
|
||||||
@ -460,3 +460,39 @@ class ContainerActionEvent(Base):
|
|||||||
result = Column(String(255))
|
result = Column(String(255))
|
||||||
traceback = Column(Text)
|
traceback = Column(Text)
|
||||||
details = Column(Text)
|
details = Column(Text)
|
||||||
|
|
||||||
|
|
||||||
|
class Quota(Base):
|
||||||
|
"""Represents a single quota override for a project
|
||||||
|
|
||||||
|
If there is no row for a given project id and resource, then the
|
||||||
|
default for the quota class is used. If there is no row for a
|
||||||
|
given quota class and resource, then the default for the deployment
|
||||||
|
is used. If the row is present but the hard limit is None then the
|
||||||
|
resource is unlimited.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__tablename__ = 'quotas'
|
||||||
|
__table_args__ = ()
|
||||||
|
id = Column(Integer, primary_key=True, nullable=False)
|
||||||
|
project_id = Column(String(255), index=True)
|
||||||
|
resource = Column(String(255), nullable=False)
|
||||||
|
hard_limit = Column(Integer)
|
||||||
|
|
||||||
|
|
||||||
|
class QuotaClass(Base):
|
||||||
|
"""Represents a single quota override for a quota class
|
||||||
|
|
||||||
|
If there is no row for a given quota class and resource, then the
|
||||||
|
default for the deployment is used. If the row is present but the
|
||||||
|
hard limit is None, then the resource is unlimited.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__tablename__ = 'quota_classes'
|
||||||
|
__table_args__ = (
|
||||||
|
Index('quota_classes_class_name_idx', 'class_name'),
|
||||||
|
)
|
||||||
|
id = Column(Integer, primary_key=True, nullable=False)
|
||||||
|
class_name = Column(String(255), index=True)
|
||||||
|
resource = Column(String(255))
|
||||||
|
hard_limit = Column(Integer)
|
||||||
|
107
zun/tests/unit/db/test_quota_classes.py
Normal file
107
zun/tests/unit/db/test_quota_classes.py
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
"""Tests for manipulating Quota via the DB API"""
|
||||||
|
from zun.common import context
|
||||||
|
import zun.conf
|
||||||
|
from zun.db import api as dbapi
|
||||||
|
from zun.db.sqlalchemy import api as sqlalchemy_dbapi
|
||||||
|
from zun.tests.unit.db import base
|
||||||
|
from zun.tests.unit.db import utils
|
||||||
|
|
||||||
|
CONF = zun.conf.CONF
|
||||||
|
|
||||||
|
|
||||||
|
class DBQuotaClassesTestCase(base.DbTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(DBQuotaClassesTestCase, self).setUp()
|
||||||
|
self.ctx = context.get_admin_context()
|
||||||
|
self.class_name = 'default'
|
||||||
|
self.resource = 'containers'
|
||||||
|
self.limit = 100
|
||||||
|
|
||||||
|
def test_create_quota_class(self):
|
||||||
|
quota_class = utils.create_test_quota_class(context=self.ctx,
|
||||||
|
class_name=self.class_name,
|
||||||
|
resource=self.resource,
|
||||||
|
limit=self.limit)
|
||||||
|
self.assertEqual(quota_class.class_name, self.class_name)
|
||||||
|
self.assertEqual(quota_class.resource, self.resource)
|
||||||
|
self.assertEqual(quota_class.hard_limit, self.limit)
|
||||||
|
|
||||||
|
def test_get_quota_class(self):
|
||||||
|
quota_class = utils.create_test_quota_class(context=self.ctx,
|
||||||
|
class_name=self.class_name,
|
||||||
|
resource=self.resource,
|
||||||
|
limit=self.limit)
|
||||||
|
res = dbapi.quota_class_get(context=self.ctx,
|
||||||
|
class_name=quota_class.class_name,
|
||||||
|
resource=quota_class.resource)
|
||||||
|
self.assertEqual(quota_class.class_name, res.class_name)
|
||||||
|
self.assertEqual(quota_class.resource, res.resource)
|
||||||
|
self.assertEqual(quota_class.hard_limit, res.hard_limit)
|
||||||
|
|
||||||
|
def test_get_default_quota_class(self):
|
||||||
|
default_quota_class_resource_1 = utils.create_test_quota_class(
|
||||||
|
context=self.ctx,
|
||||||
|
class_name=sqlalchemy_dbapi._DEFAULT_QUOTA_NAME,
|
||||||
|
resource='resource_1',
|
||||||
|
limit=10)
|
||||||
|
|
||||||
|
default_quota_class_resource_2 = utils.create_test_quota_class(
|
||||||
|
context=self.ctx,
|
||||||
|
class_name=sqlalchemy_dbapi._DEFAULT_QUOTA_NAME,
|
||||||
|
resource='resource_2',
|
||||||
|
limit=20)
|
||||||
|
|
||||||
|
res = dbapi.quota_class_get_default(self.ctx)
|
||||||
|
self.assertEqual(res['class_name'],
|
||||||
|
sqlalchemy_dbapi._DEFAULT_QUOTA_NAME)
|
||||||
|
self.assertEqual(res[default_quota_class_resource_1.resource],
|
||||||
|
default_quota_class_resource_1.hard_limit)
|
||||||
|
self.assertEqual(res[default_quota_class_resource_2.resource],
|
||||||
|
default_quota_class_resource_2.hard_limit)
|
||||||
|
|
||||||
|
def test_get_all_by_name_quota_class(self):
|
||||||
|
quota_class_resource_1 = utils.create_test_quota_class(
|
||||||
|
context=self.ctx,
|
||||||
|
class_name='class_1',
|
||||||
|
resource='resource_1',
|
||||||
|
limit=10)
|
||||||
|
|
||||||
|
quota_class_resource_2 = utils.create_test_quota_class(
|
||||||
|
context=self.ctx,
|
||||||
|
class_name='class_1',
|
||||||
|
resource='resource_2',
|
||||||
|
limit=20)
|
||||||
|
|
||||||
|
res = dbapi.quota_class_get_all_by_name(self.ctx, 'class_1')
|
||||||
|
self.assertEqual(res['class_name'],
|
||||||
|
'class_1')
|
||||||
|
self.assertEqual(res[quota_class_resource_1.resource],
|
||||||
|
quota_class_resource_1.hard_limit)
|
||||||
|
self.assertEqual(res[quota_class_resource_2.resource],
|
||||||
|
quota_class_resource_2.hard_limit)
|
||||||
|
|
||||||
|
def test_update_quota_class(self):
|
||||||
|
quota_class = utils.create_test_quota_class(context=self.ctx,
|
||||||
|
class_name=self.class_name,
|
||||||
|
resource=self.resource,
|
||||||
|
limit=self.limit)
|
||||||
|
dbapi.quota_class_update(
|
||||||
|
self.ctx, quota_class.class_name,
|
||||||
|
quota_class.resource, 200)
|
||||||
|
updated_quota_class = dbapi.quota_class_get(
|
||||||
|
self.ctx, quota_class.class_name,
|
||||||
|
quota_class.resource)
|
||||||
|
self.assertEqual(updated_quota_class.hard_limit, 200)
|
86
zun/tests/unit/db/test_quotas.py
Normal file
86
zun/tests/unit/db/test_quotas.py
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
"""Tests for manipulating Quota via the DB API"""
|
||||||
|
from zun.common import context
|
||||||
|
from zun.common import exception
|
||||||
|
import zun.conf
|
||||||
|
from zun.db import api as dbapi
|
||||||
|
from zun.tests.unit.db import base
|
||||||
|
from zun.tests.unit.db import utils
|
||||||
|
|
||||||
|
CONF = zun.conf.CONF
|
||||||
|
|
||||||
|
|
||||||
|
class DBQuotaTestCase(base.DbTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(DBQuotaTestCase, self).setUp()
|
||||||
|
self.ctx = context.get_admin_context()
|
||||||
|
self.project_id = 'fake_project_id'
|
||||||
|
self.resource = 'containers'
|
||||||
|
self.limit = 100
|
||||||
|
|
||||||
|
def test_create_quota(self):
|
||||||
|
quota = utils.create_test_quota(context=self.ctx,
|
||||||
|
project_id=self.project_id,
|
||||||
|
resource=self.resource,
|
||||||
|
limit=self.limit)
|
||||||
|
self.assertEqual(quota.project_id, self.project_id)
|
||||||
|
self.assertEqual(quota.resource, self.resource)
|
||||||
|
self.assertEqual(quota.hard_limit, self.limit)
|
||||||
|
|
||||||
|
def test_get_quota(self):
|
||||||
|
quota = utils.create_test_quota(context=self.ctx,
|
||||||
|
project_id=self.project_id,
|
||||||
|
resource=self.resource,
|
||||||
|
limit=self.limit)
|
||||||
|
res = dbapi.quota_get(context=self.ctx,
|
||||||
|
project_id=quota.project_id,
|
||||||
|
resource=quota.resource)
|
||||||
|
self.assertEqual(quota.project_id, res.project_id)
|
||||||
|
self.assertEqual(quota.resource, res.resource)
|
||||||
|
self.assertEqual(quota.hard_limit, res.hard_limit)
|
||||||
|
|
||||||
|
def test_get_all_project_quota(self):
|
||||||
|
quota_1 = utils.create_test_quota(context=self.ctx,
|
||||||
|
project_d=self.project_id,
|
||||||
|
resource='resource_1',
|
||||||
|
limit=10)
|
||||||
|
quota_2 = utils.create_test_quota(context=self.ctx,
|
||||||
|
project_id=self.project_id,
|
||||||
|
resource='resource_2',
|
||||||
|
limit=20)
|
||||||
|
quotas = dbapi.quota_get_all_by_project(self.ctx, self.project_id)
|
||||||
|
self.assertEqual(quotas['project_id'], self.project_id)
|
||||||
|
self.assertEqual(quotas[quota_1.resource], quota_1.hard_limit)
|
||||||
|
self.assertEqual(quotas[quota_2.resource], quota_2.hard_limit)
|
||||||
|
|
||||||
|
def test_destroy_quota(self):
|
||||||
|
quota = utils.create_test_quota(context=self.ctx,
|
||||||
|
project_id=self.project_id,
|
||||||
|
resource=self.resource,
|
||||||
|
limit=self.limit)
|
||||||
|
dbapi.quota_destroy(self.ctx, quota.project_id, quota.resource)
|
||||||
|
self.assertRaises(exception.ProjectQuotaNotFound, dbapi.quota_get,
|
||||||
|
self.ctx, quota.project_id, quota.resource)
|
||||||
|
|
||||||
|
def test_update_quota(self):
|
||||||
|
quota = utils.create_test_quota(context=self.ctx,
|
||||||
|
project_id=self.project_id,
|
||||||
|
resource=self.resource,
|
||||||
|
limit=self.limit)
|
||||||
|
dbapi.quota_update(self.ctx, quota.project_id,
|
||||||
|
quota.resource, 200)
|
||||||
|
updated_quota = dbapi.quota_get(self.ctx, quota.project_id,
|
||||||
|
quota.resource)
|
||||||
|
self.assertEqual(updated_quota.hard_limit, 200)
|
@ -495,3 +495,21 @@ def get_test_action_event(**kwargs):
|
|||||||
for k, v in event_values.items():
|
for k, v in event_values.items():
|
||||||
setattr(fake_event, k, v)
|
setattr(fake_event, k, v)
|
||||||
return fake_event
|
return fake_event
|
||||||
|
|
||||||
|
|
||||||
|
def create_test_quota(**kwargs):
|
||||||
|
context = kwargs.get('context')
|
||||||
|
project_id = kwargs.get('project_id', 'fake_project_id')
|
||||||
|
resource = kwargs.get('resource', 'containers')
|
||||||
|
limit = kwargs.get('limit', 100)
|
||||||
|
dbapi = _get_dbapi()
|
||||||
|
return dbapi.quota_create(context, project_id, resource, limit)
|
||||||
|
|
||||||
|
|
||||||
|
def create_test_quota_class(**kwargs):
|
||||||
|
context = kwargs.get('context')
|
||||||
|
class_name = kwargs.get('class_name', 'default')
|
||||||
|
resource = kwargs.get('resource', 'containers')
|
||||||
|
limit = kwargs.get('limit', 100)
|
||||||
|
dbapi = _get_dbapi()
|
||||||
|
return dbapi.quota_class_create(context, class_name, resource, limit)
|
||||||
|
Loading…
Reference in New Issue
Block a user