Merge "Creates flavor* tables in API database"
This commit is contained in:
commit
67477ba3c9
@ -0,0 +1,88 @@
|
||||
# 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.
|
||||
|
||||
from migrate.changeset.constraint import ForeignKeyConstraint
|
||||
from migrate import UniqueConstraint
|
||||
from sqlalchemy import Boolean
|
||||
from sqlalchemy import Column
|
||||
from sqlalchemy import DateTime
|
||||
from sqlalchemy import Float
|
||||
from sqlalchemy import Index
|
||||
from sqlalchemy import Integer
|
||||
from sqlalchemy import MetaData
|
||||
from sqlalchemy import String
|
||||
from sqlalchemy import Table
|
||||
|
||||
|
||||
def upgrade(migrate_engine):
|
||||
meta = MetaData()
|
||||
meta.bind = migrate_engine
|
||||
|
||||
flavors = Table('flavors', meta,
|
||||
Column('created_at', DateTime),
|
||||
Column('updated_at', DateTime),
|
||||
Column('name', String(length=255), nullable=False),
|
||||
Column('id', Integer, primary_key=True, nullable=False),
|
||||
Column('memory_mb', Integer, nullable=False),
|
||||
Column('vcpus', Integer, nullable=False),
|
||||
Column('swap', Integer, nullable=False),
|
||||
Column('vcpu_weight', Integer),
|
||||
Column('flavorid', String(length=255), nullable=False),
|
||||
Column('rxtx_factor', Float),
|
||||
Column('root_gb', Integer),
|
||||
Column('ephemeral_gb', Integer),
|
||||
Column('disabled', Boolean),
|
||||
Column('is_public', Boolean),
|
||||
UniqueConstraint("flavorid", name="uniq_flavors0flavorid"),
|
||||
UniqueConstraint("name", name="uniq_flavors0name"),
|
||||
mysql_engine='InnoDB',
|
||||
mysql_charset='utf8'
|
||||
)
|
||||
flavors.create(checkfirst=True)
|
||||
|
||||
flavor_extra_specs = Table('flavor_extra_specs', meta,
|
||||
Column('created_at', DateTime),
|
||||
Column('updated_at', DateTime),
|
||||
Column('id', Integer, primary_key=True, nullable=False),
|
||||
Column('flavor_id', Integer, nullable=False),
|
||||
Column('key', String(length=255), nullable=False),
|
||||
Column('value', String(length=255)),
|
||||
UniqueConstraint('flavor_id', 'key',
|
||||
name='uniq_flavor_extra_specs0flavor_id0key'),
|
||||
ForeignKeyConstraint(columns=['flavor_id'], refcolumns=[flavors.c.id]),
|
||||
mysql_engine='InnoDB',
|
||||
mysql_charset='utf8'
|
||||
)
|
||||
|
||||
# NOTE(mriedem): DB2 creates an index when a unique constraint is created
|
||||
# so trying to add a second index on the flavor_id/key column will fail
|
||||
# with error SQL0605W, so omit the index in the case of DB2.
|
||||
if migrate_engine.name != 'ibm_db_sa':
|
||||
Index('flavor_extra_specs_flavor_id_key_idx',
|
||||
flavor_extra_specs.c.flavor_id,
|
||||
flavor_extra_specs.c.key)
|
||||
flavor_extra_specs.create(checkfirst=True)
|
||||
|
||||
flavor_projects = Table('flavor_projects', meta,
|
||||
Column('created_at', DateTime),
|
||||
Column('updated_at', DateTime),
|
||||
Column('id', Integer, primary_key=True, nullable=False),
|
||||
Column('flavor_id', Integer, nullable=False),
|
||||
Column('project_id', String(length=255), nullable=False),
|
||||
UniqueConstraint('flavor_id', 'project_id',
|
||||
name='uniq_flavor_projects0flavor_id0project_id'),
|
||||
ForeignKeyConstraint(columns=['flavor_id'],
|
||||
refcolumns=[flavors.c.id]),
|
||||
mysql_engine='InnoDB',
|
||||
mysql_charset='utf8'
|
||||
)
|
||||
flavor_projects.create(checkfirst=True)
|
@ -12,8 +12,10 @@
|
||||
|
||||
|
||||
from oslo_db.sqlalchemy import models
|
||||
from sqlalchemy import Boolean
|
||||
from sqlalchemy import Column
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy import Float
|
||||
from sqlalchemy import ForeignKey
|
||||
from sqlalchemy import Index
|
||||
from sqlalchemy import Integer
|
||||
@ -84,3 +86,51 @@ class RequestSpec(API_BASE):
|
||||
id = Column(Integer, primary_key=True)
|
||||
instance_uuid = Column(String(36), nullable=False)
|
||||
spec = Column(Text, nullable=False)
|
||||
|
||||
|
||||
class Flavors(API_BASE):
|
||||
"""Represents possible flavors for instances"""
|
||||
__tablename__ = 'flavors'
|
||||
__table_args__ = (
|
||||
schema.UniqueConstraint("flavorid", name="uniq_flavors0flavorid"),
|
||||
schema.UniqueConstraint("name", name="uniq_flavors0name"))
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
name = Column(String(255), nullable=False)
|
||||
memory_mb = Column(Integer, nullable=False)
|
||||
vcpus = Column(Integer, nullable=False)
|
||||
root_gb = Column(Integer)
|
||||
ephemeral_gb = Column(Integer)
|
||||
flavorid = Column(String(255), nullable=False)
|
||||
swap = Column(Integer, nullable=False, default=0)
|
||||
rxtx_factor = Column(Float, default=1)
|
||||
vcpu_weight = Column(Integer)
|
||||
disabled = Column(Boolean, default=False)
|
||||
is_public = Column(Boolean, default=True)
|
||||
|
||||
|
||||
class FlavorExtraSpecs(API_BASE):
|
||||
"""Represents additional specs as key/value pairs for a flavor"""
|
||||
__tablename__ = 'flavor_extra_specs'
|
||||
__table_args__ = (
|
||||
Index('flavor_extra_specs_flavor_id_key_idx', 'flavor_id', 'key'),
|
||||
schema.UniqueConstraint('flavor_id', 'key',
|
||||
name='uniq_flavor_extra_specs0flavor_id0key'),
|
||||
{'mysql_collate': 'utf8_bin'},
|
||||
)
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
key = Column(String(255), nullable=False)
|
||||
value = Column(String(255))
|
||||
flavor_id = Column(Integer, ForeignKey('flavors.id'), nullable=False)
|
||||
|
||||
|
||||
class FlavorProjects(API_BASE):
|
||||
"""Represents projects associated with flavors"""
|
||||
__tablename__ = 'flavor_projects'
|
||||
__table_args__ = (schema.UniqueConstraint('flavor_id', 'project_id',
|
||||
name='uniq_flavor_projects0flavor_id0project_id'),)
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
flavor_id = Column(Integer, ForeignKey('flavors.id'), nullable=False)
|
||||
project_id = Column(String(255), nullable=False)
|
||||
|
@ -194,6 +194,50 @@ class NovaAPIMigrationsWalk(test_migrations.WalkVersionsMixin):
|
||||
self.assertIndexExists(engine, 'request_specs',
|
||||
'request_spec_instance_uuid_idx')
|
||||
|
||||
def _check_005(self, engine, data):
|
||||
# flavors
|
||||
for column in ['created_at', 'updated_at', 'name', 'id', 'memory_mb',
|
||||
'vcpus', 'swap', 'vcpu_weight', 'flavorid', 'rxtx_factor',
|
||||
'root_gb', 'ephemeral_gb', 'disabled', 'is_public']:
|
||||
self.assertColumnExists(engine, 'flavors', column)
|
||||
self.assertUniqueConstraintExists(engine, 'flavors',
|
||||
['flavorid'])
|
||||
self.assertUniqueConstraintExists(engine, 'flavors',
|
||||
['name'])
|
||||
|
||||
# flavor_extra_specs
|
||||
for column in ['created_at', 'updated_at', 'id', 'flavor_id', 'key',
|
||||
'value']:
|
||||
self.assertColumnExists(engine, 'flavor_extra_specs', column)
|
||||
|
||||
if engine.name != 'ibm_db_sa':
|
||||
self.assertIndexExists(engine, 'flavor_extra_specs',
|
||||
'flavor_extra_specs_flavor_id_key_idx')
|
||||
self.assertUniqueConstraintExists(engine, 'flavor_extra_specs',
|
||||
['flavor_id', 'key'])
|
||||
|
||||
inspector = reflection.Inspector.from_engine(engine)
|
||||
# There should only be one foreign key here
|
||||
fk = inspector.get_foreign_keys('flavor_extra_specs')[0]
|
||||
self.assertEqual('flavors', fk['referred_table'])
|
||||
self.assertEqual(['id'], fk['referred_columns'])
|
||||
self.assertEqual(['flavor_id'], fk['constrained_columns'])
|
||||
|
||||
# flavor_projects
|
||||
for column in ['created_at', 'updated_at', 'id', 'flavor_id',
|
||||
'project_id']:
|
||||
self.assertColumnExists(engine, 'flavor_projects', column)
|
||||
|
||||
self.assertUniqueConstraintExists(engine, 'flavor_projects',
|
||||
['flavor_id', 'project_id'])
|
||||
|
||||
inspector = reflection.Inspector.from_engine(engine)
|
||||
# There should only be one foreign key here
|
||||
fk = inspector.get_foreign_keys('flavor_projects')[0]
|
||||
self.assertEqual('flavors', fk['referred_table'])
|
||||
self.assertEqual(['id'], fk['referred_columns'])
|
||||
self.assertEqual(['flavor_id'], fk['constrained_columns'])
|
||||
|
||||
|
||||
class TestNovaAPIMigrationsWalkSQLite(NovaAPIMigrationsWalk,
|
||||
test_base.DbTestCase,
|
||||
|
61
nova/tests/functional/db/test_flavor_model.py
Normal file
61
nova/tests/functional/db/test_flavor_model.py
Normal file
@ -0,0 +1,61 @@
|
||||
# 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.
|
||||
|
||||
from nova.db.sqlalchemy import api_models
|
||||
from nova.db.sqlalchemy import models
|
||||
from nova import test
|
||||
|
||||
|
||||
class FlavorTablesCompareTestCase(test.NoDBTestCase):
|
||||
def _get_columns_list(self, model):
|
||||
columns_list = [m.key for m in model.__table__.columns]
|
||||
return columns_list
|
||||
|
||||
def _check_column_list(self, columns_new, columns_old):
|
||||
columns_old.remove('deleted_at')
|
||||
columns_old.remove('deleted')
|
||||
intersect = set(columns_new).intersection(set(columns_old))
|
||||
if intersect != set(columns_new) or intersect != set(columns_old):
|
||||
return False
|
||||
return True
|
||||
|
||||
def test_tables_flavors_instance_types(self):
|
||||
flavors = api_models.Flavors()
|
||||
instance_types = models.InstanceTypes()
|
||||
columns_flavors = self._get_columns_list(flavors)
|
||||
columns_instance_types = self._get_columns_list(instance_types)
|
||||
self.assertTrue(self._check_column_list(columns_flavors,
|
||||
columns_instance_types))
|
||||
|
||||
def test_tables_flavor_instance_type_extra_specs(self):
|
||||
flavor_extra_specs = api_models.FlavorExtraSpecs()
|
||||
instance_type_extra_specs = models.InstanceTypeExtraSpecs()
|
||||
columns_flavor_extra_specs = self._get_columns_list(flavor_extra_specs)
|
||||
columns_instance_type_extra_specs = self._get_columns_list(
|
||||
instance_type_extra_specs)
|
||||
columns_flavor_extra_specs.remove('flavor_id')
|
||||
columns_instance_type_extra_specs.remove('instance_type_id')
|
||||
self.assertTrue(self._check_column_list(
|
||||
columns_flavor_extra_specs,
|
||||
columns_instance_type_extra_specs))
|
||||
|
||||
def test_tables_flavor_instance_type_projects(self):
|
||||
flavor_projects = api_models.FlavorProjects()
|
||||
instance_types_projects = models.InstanceTypeProjects()
|
||||
columns_flavor_projects = self._get_columns_list(flavor_projects)
|
||||
columns_instance_type_projects = self._get_columns_list(
|
||||
instance_types_projects)
|
||||
columns_flavor_projects.remove('flavor_id')
|
||||
columns_instance_type_projects.remove('instance_type_id')
|
||||
self.assertTrue(self._check_column_list(
|
||||
columns_flavor_projects,
|
||||
columns_instance_type_projects))
|
Loading…
Reference in New Issue
Block a user