Merge "Resource Quota - Introduce Quota Table"

This commit is contained in:
Jenkins 2016-02-28 14:11:15 +00:00 committed by Gerrit Code Review
commit af4ecf6555
7 changed files with 176 additions and 0 deletions

View File

@ -559,3 +559,8 @@ class TrusteeCreateFailed(MagnumException):
class TrusteeDeleteFailed(MagnumException):
message = _("Failed to delete trustee %(trustee_id)")
class QuotaAlreadyExists(Conflict):
message = _("Quota for project %(project_id)s already exists "
"for resource %(resource)s.")

View File

@ -671,3 +671,31 @@ class Connection(object):
(asc, desc)
:returns: A list of tuples of the specified columns.
"""
@abc.abstractmethod
def create_quota(self, values):
"""Create a new Quota record for a resource in a project.
:param values: A dict containing several items used to identify
and track quota for a resource in a project.
::
{
'id': utils.generate_uuid(),
'project_id': 'fake_project',
'resource': 'fake_resource',
'hard_limit': 'fake_hardlimit',
}
:returns: A quota record.
"""
@abc.abstractmethod
def quota_get_all_by_project_id(self, project_id):
"""Gets Quota record for all the resources in a project.
:param project_id: Project identifier of the project.
:returns: Quota record for all resources in a project.
"""

View File

@ -0,0 +1,46 @@
# Copyright 2016 Yahoo! Inc. All rights reserved.
#
# 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.
"""Introduce Quotas
Revision ID: ee92b41b8809
Revises: 5d4caa6e0a42
Create Date: 2016-02-26 18:32:08.992964
"""
# revision identifiers, used by Alembic.
revision = 'ee92b41b8809'
down_revision = '5d4caa6e0a42'
from alembic import op
import sqlalchemy as sa
def upgrade():
op.create_table(
'quotas',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.Column('updated_at', sa.DateTime(), nullable=True),
sa.Column('project_id', sa.String(length=255), nullable=True),
sa.Column('resource', sa.String(length=255), nullable=True),
sa.Column('hard_limit', sa.Integer(), nullable=False),
sa.PrimaryKeyConstraint('id'),
mysql_ENGINE='InnoDB',
mysql_DEFAULT_CHARSET='UTF8'
)
op.create_unique_constraint(
"uniq_quotas0project_id0resource",
"quotas", ["project_id", "resource"])

View File

@ -909,3 +909,19 @@ class Connection(api.Connection):
return _paginate_query(models.MagnumService, limit, marker,
sort_key, sort_dir, query)
def create_quota(self, values):
quotas = models.Quota()
quotas.update(values)
try:
quotas.save()
except db_exc.DBDuplicateEntry:
raise exception.QuotaAlreadyExists(project_id=values['project_id'],
resource=values['resource'])
return quotas
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

View File

@ -291,3 +291,18 @@ class MagnumService(Base):
last_seen_up = Column(DateTime, nullable=True)
forced_down = Column(Boolean, default=False)
report_count = Column(Integer, nullable=False, default=0)
class Quota(Base):
"""Represents Quota for a resource within a project"""
__tablename__ = 'quotas'
__table_args__ = (
schema.UniqueConstraint(
"project_id", "resource",
name='uniq_quotas0project_id0resource'),
table_args()
)
id = Column(Integer, primary_key=True)
project_id = Column(String(255))
resource = Column(String(255))
hard_limit = Column(Integer())

View File

@ -0,0 +1,41 @@
# Copyright 2016 Yahoo! Inc.
# All Rights Reserved.
#
# 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 magnum.common import exception
from magnum.tests.unit.db import base
from magnum.tests.unit.db import utils
class DbQuotaTestCase(base.DbTestCase):
def test_create_quota(self):
utils.create_test_quotas()
def test_create_quota_already_exists(self):
utils.create_test_quotas()
self.assertRaises(exception.QuotaAlreadyExists,
utils.create_test_quotas)
def test_get_quota_all(self):
q = utils.create_test_quotas()
res = self.dbapi.quota_get_all_by_project_id(
project_id='fake_project')
for r in res:
self.assertEqual(q.id, r.id)
self.assertEqual(q.hard_limit, r.hard_limit)
self.assertEqual(q.project_id, r.project_id)
self.assertEqual(q.resource, r.resource)

View File

@ -308,3 +308,28 @@ def create_test_magnum_service(**kw):
del magnum_service['id']
dbapi = db_api.get_instance()
return dbapi.create_magnum_service(magnum_service)
def get_test_quotas(**kw):
return {
'id': kw.get('', 18),
'project_id': kw.get('project_id', 'fake_project'),
'resource': kw.get('resource', 'fake_resource'),
'hard_limit': kw.get('hard_limit', 10),
'created_at': kw.get('created_at'),
'updated_at': kw.get('updated_at'),
}
def create_test_quotas(**kw):
"""Create test quotas entry in DB and return quotas DB object.
:param kw: kwargs with overriding values for quota attributes.
:returns: Test quotas DB object.
"""
quotas = get_test_quotas(**kw)
# Let DB generate ID if it isn't specified explicitly
if 'id' not in kw:
del quotas['id']
dbapi = db_api.get_instance()
return dbapi.create_quota(quotas)