Use uuid as the primary key

- Use uuid as the primary key
- Correct some attributes definitions of the DB models

NOTE: Nimble will support setting the scope check unique instance name in
following patches

Change-Id: Ia4cdaccb2162d15710dc0bdcc0e12ed1f7b76257
This commit is contained in:
liusheng 2016-11-28 14:29:13 +08:00
parent 49e32319f5
commit 357a2dcfc4
13 changed files with 92 additions and 125 deletions

View File

@ -145,7 +145,7 @@ class InvalidUUID(Invalid):
class InstanceTypeAlreadyExists(NimbleException):
_msg_fmt = _("InstanceType with name %(name)s already exists.")
_msg_fmt = _("InstanceType with uuid %(uuid)s already exists.")
class InstanceTypeNotFound(NotFound):

View File

@ -81,7 +81,7 @@ class Connection(object):
@abc.abstractmethod
def extra_specs_update_or_create(self, context,
instance_type_id, extra_specs):
instance_type_uuid, extra_specs):
"""Create or update instance type extra specs.
This adds or modifies the key/value pairs specified in the
@ -93,7 +93,7 @@ class Connection(object):
"""Get instance type extra specs"""
@abc.abstractmethod
def type_extra_specs_delete(self, context, instance_type_id, key):
def type_extra_specs_delete(self, context, instance_type_uuid, key):
"""Delete instance type extra specs.
This deletes the key/value pairs specified in the

View File

@ -32,13 +32,11 @@ def upgrade():
'instance_types',
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.Column('updated_at', sa.DateTime(), nullable=True),
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('uuid', sa.String(length=36), nullable=False),
sa.Column('name', sa.String(length=255), nullable=False),
sa.Column('description', sa.String(length=255), nullable=True),
sa.Column('is_public', sa.Boolean(), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('name', name='uniq_instance_types0name'),
sa.PrimaryKeyConstraint('uuid'),
mysql_ENGINE='InnoDB',
mysql_DEFAULT_CHARSET='UTF8'
)
@ -47,10 +45,11 @@ def upgrade():
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.Column('updated_at', sa.DateTime(), nullable=True),
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('instance_type_id', sa.Integer(), nullable=False),
sa.Column('instance_type_uuid', sa.String(length=36), nullable=False),
sa.Column('key', sa.String(length=255), nullable=False),
sa.Column('value', sa.String(length=255), nullable=False),
sa.ForeignKeyConstraint(['instance_type_id'], ['instance_types.id'], ),
sa.ForeignKeyConstraint(['instance_type_uuid'],
['instance_types.uuid']),
sa.PrimaryKeyConstraint('id'),
mysql_ENGINE='InnoDB',
mysql_DEFAULT_CHARSET='UTF8'
@ -60,9 +59,10 @@ def upgrade():
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.Column('updated_at', sa.DateTime(), nullable=True),
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('instance_type_id', sa.Integer(), nullable=True),
sa.Column('instance_type_uuid', sa.String(length=36), nullable=True),
sa.Column('project_id', sa.String(length=36), nullable=True),
sa.ForeignKeyConstraint(['instance_type_id'], ['instance_types.id'], ),
sa.ForeignKeyConstraint(['instance_type_uuid'],
['instance_types.uuid']),
sa.PrimaryKeyConstraint('id'),
mysql_ENGINE='InnoDB',
mysql_DEFAULT_CHARSET='UTF8'
@ -71,7 +71,6 @@ def upgrade():
'instances',
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.Column('updated_at', sa.DateTime(), nullable=True),
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('uuid', sa.String(length=36), nullable=True),
sa.Column('user_id', sa.String(length=36), nullable=True),
sa.Column('project_id', sa.String(length=36), nullable=True),
@ -85,9 +84,8 @@ def upgrade():
sa.Column('availability_zone', sa.String(length=255), nullable=True),
sa.Column('node_uuid', sa.String(length=36), nullable=True),
sa.Column('extra', sa.Text(), nullable=True),
sa.PrimaryKeyConstraint('id'),
sa.PrimaryKeyConstraint('uuid'),
sa.UniqueConstraint('uuid', name='uniq_instances0uuid'),
sa.UniqueConstraint('name', name='uniq_instances0name'),
mysql_ENGINE='InnoDB',
mysql_DEFAULT_CHARSET='UTF8'
)

View File

@ -120,7 +120,7 @@ class Connection(api.Connection):
session.add(instance_type)
session.flush()
except db_exc.DBDuplicateEntry:
raise exception.InstanceTypeAlreadyExists(name=values['name'])
raise exception.InstanceTypeAlreadyExists(uuid=values['uuid'])
return _dict_with_extra_specs(instance_type)
def instance_type_get(self, context, instance_type_uuid):
@ -143,7 +143,7 @@ class Connection(api.Connection):
extra_query = model_query(
context,
models.InstanceTypeExtraSpecs).filter_by(
instance_type_id=type_id)
instance_type_uuid=type_id)
extra_query.delete()
# Then delete the type record
@ -214,7 +214,8 @@ class Connection(api.Connection):
ref.update(values)
return ref
def extra_specs_update_or_create(self, context, instance_type_id, specs,
def extra_specs_update_or_create(self, context,
instance_type_uuid, specs,
max_retries=10):
"""Create or update instance type extra specs.
@ -226,7 +227,7 @@ class Connection(api.Connection):
try:
spec_refs = model_query(
context, models.InstanceTypeExtraSpecs). \
filter_by(instance_type_id=instance_type_id). \
filter_by(instance_type_uuid=instance_type_uuid). \
filter(models.InstanceTypeExtraSpecs.key.in_(
specs.keys())).with_lockmode('update').all()
@ -242,7 +243,7 @@ class Connection(api.Connection):
spec_ref = models.InstanceTypeExtraSpecs()
spec_ref.update(
{"key": key, "value": value,
"instance_type_id": instance_type_id})
"instance_type_uuid": instance_type_uuid})
session.add(spec_ref)
session.flush()
@ -253,7 +254,7 @@ class Connection(api.Connection):
# try again unless this was the last attempt
if attempt == max_retries - 1:
raise exception.TypeExtraSpecUpdateCreateFailed(
id=instance_type_id, retries=max_retries)
id=instance_type_uuid, retries=max_retries)
def instance_type_extra_specs_get(self, context, type_id):
rows = _type_extra_specs_get_query(context, type_id).all()
@ -278,9 +279,9 @@ def _type_get_id_from_type(context, type_id):
result = _type_get_id_from_type_query(context, type_id).first()
if not result:
raise exception.InstanceTypeNotFound(type_id=type_id)
return result.id
return result.uuid
def _type_extra_specs_get_query(context, type_id):
return model_query(context, models.InstanceTypeExtraSpecs). \
filter_by(instance_type_id=type_id)
filter_by(instance_type_uuid=type_id)

View File

@ -58,71 +58,15 @@ class NimbleBase(models.TimestampMixin,
Base = declarative_base(cls=NimbleBase)
class InstanceTypes(Base):
"""Represents possible types for instances."""
__tablename__ = 'instance_types'
__table_args__ = (
schema.UniqueConstraint('name', name='uniq_instance_types0name'),
table_args()
)
id = Column(Integer, primary_key=True)
uuid = Column(String(36), nullable=False)
name = Column(String(255), nullable=False)
description = Column(String(255), nullable=True)
is_public = Column(Boolean, default=True)
class InstanceTypeProjects(Base):
"""Represents projects associated instance_types."""
__tablename__ = 'instance_type_projects'
__table_args__ = (
schema.UniqueConstraint(
'instance_type_id', 'project_id',
name='uniq_instance_type_projects0instance_type_id0project_id'
),
table_args()
)
id = Column(Integer, primary_key=True)
instance_type_id = Column(Integer, nullable=True)
project_id = Column(String(36), nullable=True)
class InstanceTypeExtraSpecs(Base):
"""Represents additional specs as key/value pairs for an instance_type."""
__tablename__ = 'instance_type_extra_specs'
__table_args__ = (
schema.UniqueConstraint(
"instance_type_id", "key",
name=("uniq_instance_type_extra_specs0"
"instance_type_id")
),
{'mysql_collate': 'utf8_bin'},
)
id = Column(Integer, primary_key=True)
key = Column(String(255))
value = Column(String(255))
instance_type_id = Column(Integer, ForeignKey('instance_types.id'),
nullable=False)
instance_type = orm.relationship(
InstanceTypes, backref="extra_specs",
foreign_keys=instance_type_id,
primaryjoin='and_(InstanceTypeExtraSpecs.instance_type_id '
'== InstanceTypes.id)')
class Instance(Base):
"""Represents possible types for instances."""
__tablename__ = 'instances'
__table_args__ = (
schema.UniqueConstraint('uuid', name='uniq_instances0uuid'),
schema.UniqueConstraint('name', name='uniq_instances0name'),
table_args()
)
id = Column(Integer, primary_key=True)
uuid = Column(String(36), nullable=True)
uuid = Column(String(36), primary_key=True)
name = Column(String(255), nullable=False)
description = Column(String(255), nullable=True)
project_id = Column(String(36), nullable=True)
@ -135,3 +79,63 @@ class Instance(Base):
node_uuid = Column(String(36), nullable=True)
launched_at = Column(DateTime, nullable=True)
extra = Column(db_types.JsonEncodedDict)
class InstanceTypes(Base):
"""Represents possible types for instances."""
__tablename__ = 'instance_types'
uuid = Column(String(36), primary_key=True)
name = Column(String(255), nullable=False)
description = Column(String(255), nullable=True)
is_public = Column(Boolean, default=True)
instances = orm.relationship(
Instance,
backref=orm.backref('instance_type', uselist=False),
foreign_keys=uuid,
primaryjoin='Instance.instance_type_uuid == InstanceTypes.uuid')
class InstanceTypeProjects(Base):
"""Represents projects associated instance_types."""
__tablename__ = 'instance_type_projects'
__table_args__ = (
schema.UniqueConstraint(
'instance_type_uuid', 'project_id',
name='uniq_instance_type_projects0instance_type_uuid0project_id'
),
table_args()
)
id = Column(Integer, primary_key=True)
instance_type_uuid = Column(Integer, nullable=True)
project_id = Column(String(36), nullable=True)
instances = orm.relationship(
InstanceTypes,
backref=orm.backref('projects', uselist=False),
foreign_keys=instance_type_uuid,
primaryjoin='InstanceTypeProjects.instance_type_uuid'
' == InstanceTypes.uuid')
class InstanceTypeExtraSpecs(Base):
"""Represents additional specs as key/value pairs for an instance_type."""
__tablename__ = 'instance_type_extra_specs'
__table_args__ = (
schema.UniqueConstraint(
"instance_type_uuid", "key",
name=("uniq_instance_type_extra_specs0"
"instance_type_uuid")
),
{'mysql_collate': 'utf8_bin'},
)
id = Column(Integer, primary_key=True)
key = Column(String(255))
value = Column(String(255))
instance_type_uuid = Column(String(36), ForeignKey('instance_types.uuid'),
nullable=False)
instance_type = orm.relationship(
InstanceTypes, backref="extra_specs",
foreign_keys=instance_type_uuid,
primaryjoin='InstanceTypeExtraSpecs.instance_type_uuid '
'== InstanceTypes.uuid')

View File

@ -29,7 +29,6 @@ class Instance(base.NimbleObject, object_base.VersionedObjectDictCompat):
dbapi = dbapi.get_instance()
fields = {
'id': object_fields.IntegerField(),
'uuid': object_fields.UUIDField(nullable=True),
'name': object_fields.StringField(nullable=True),
'description': object_fields.StringField(nullable=True),

View File

@ -30,7 +30,6 @@ class InstanceType(base.NimbleObject, object_base.VersionedObjectDictCompat):
dbapi = dbapi.get_instance()
fields = {
'id': object_fields.IntegerField(),
'uuid': object_fields.UUIDField(nullable=True),
'name': object_fields.StringField(nullable=True),
'description': object_fields.StringField(nullable=True),
@ -71,10 +70,10 @@ class InstanceType(base.NimbleObject, object_base.VersionedObjectDictCompat):
context)
@classmethod
def get(cls, context, instance_type_id):
def get(cls, context, instance_type_uuid):
"""Find a Instance Type and return a Instance Type object."""
db_instance_type = cls.dbapi.instance_type_get(context,
instance_type_id)
instance_type_uuid)
instance_type = InstanceType._from_db_object(cls(context),
db_instance_type)
return instance_type

View File

@ -28,11 +28,6 @@ class DbInstanceTestCase(base.DbTestCase):
def test_instance_create(self):
utils.create_test_instance()
def test_instance_create_already_exist(self):
utils.create_test_instance()
self.assertRaises(exception.InstanceAlreadyExists,
utils.create_test_instance)
def test_instance_create_with_same_uuid(self):
utils.create_test_instance(uuid='uuid', name='instance1')
self.assertRaises(exception.InstanceAlreadyExists,
@ -40,17 +35,9 @@ class DbInstanceTestCase(base.DbTestCase):
uuid='uuid',
name='instance2')
def test_instance_create_with_duplicate_name(self):
utils.create_test_instance(uuid='uuid-1', name='instance')
self.assertRaises(exception.InstanceAlreadyExists,
utils.create_test_instance,
uuid='uuid-2',
name='instance')
def test_instance_get_by_uuid(self):
instance = utils.create_test_instance()
res = self.dbapi.instance_get(self.context, instance.uuid)
self.assertEqual(instance.id, res.id)
self.assertEqual(instance.uuid, res.uuid)
def test_instance_get_not_exist(self):
@ -119,7 +106,7 @@ class DbInstanceTestCase(base.DbTestCase):
self.assertNotEqual(old_extra, new_extra)
res = self.dbapi.instance_update(self.context,
instance.id,
instance.uuid,
{'extra': new_extra})
self.assertEqual(new_extra, res.extra)
@ -128,15 +115,5 @@ class DbInstanceTestCase(base.DbTestCase):
self.assertRaises(exception.InvalidParameterValue,
self.dbapi.instance_update,
self.context,
instance.id,
instance.uuid,
{'uuid': '12345678-9999-0000-aaaa-123456789012'})
def test_instance_update_with_duplicate_name(self):
instance1 = utils.create_test_instance(uuid=uuidutils.generate_uuid(),
name='spam')
instance2 = utils.create_test_instance(uuid=uuidutils.generate_uuid())
self.assertRaises(exception.DuplicateName,
self.dbapi.instance_update,
self.context,
instance2.id,
{'name': instance1.name})

View File

@ -14,6 +14,7 @@
# under the License.
"""Nimble test utilities."""
from oslo_utils import uuidutils
from nimble.db import api as db_api
from nimble.engine import status
@ -38,8 +39,7 @@ def get_test_instance(**kw):
}
return {
'id': kw.get('id', 123),
'uuid': kw.get('uuid', '1be26c0b-03f2-4d2e-ae87-c02d7f33c123'),
'uuid': kw.get('uuid', uuidutils.generate_uuid()),
'name': kw.get('name', 'test'),
'description': kw.get('description', 'test'),
'project_id': kw.get('project_id',
@ -72,9 +72,6 @@ def create_test_instance(context={}, **kw):
"""
instance = get_test_instance(**kw)
# Let DB generate ID if it isn't specified explicitly
if 'id' not in kw:
del instance['id']
dbapi = db_api.get_instance()
return dbapi.instance_create(context, instance)
@ -82,8 +79,7 @@ def create_test_instance(context={}, **kw):
def get_test_instance_type(**kw):
return {
'id': kw.get('id', 123),
'uuid': kw.get('uuid', 'e5ddde02-f84d-4da7-ade3-957c55072986'),
'uuid': kw.get('uuid', uuidutils.generate_uuid()),
'name': kw.get('name', 'test'),
'description': kw.get('description', 'test'),
'is_public': kw.get('is_public', 1),
@ -103,9 +99,6 @@ def create_test_instance_type(context={}, **kw):
"""
instance_type = get_test_instance_type(**kw)
# Let DB generate ID if it isn't specified explicitly
if 'id' not in kw:
del instance_type['id']
dbapi = db_api.get_instance()
return dbapi.instance_type_create(context, instance_type)

View File

@ -63,7 +63,7 @@ class TestInstanceObject(base.DbTestCase):
values = instance.obj_get_changes()
instance.create(self.context)
mock_instance_create.assert_called_once_with(self.context, values)
self.assertEqual(self.fake_instance['id'], instance['id'])
self.assertEqual(self.fake_instance['uuid'], instance['uuid'])
def test_destroy(self):
uuid = self.fake_instance['uuid']

View File

@ -59,7 +59,7 @@ class TestInstanceTypeObject(base.DbTestCase):
values = instance_type.obj_get_changes()
instance_type.create(self.context)
mock_type_create.assert_called_once_with(self.context, values)
self.assertEqual(self.fake_type['id'], instance_type['id'])
self.assertEqual(self.fake_type['uuid'], instance_type['uuid'])
def test_destroy(self):
uuid = self.fake_type['uuid']

View File

@ -382,8 +382,8 @@ class _TestObject(object):
# version bump. It is md5 hash of object fields and remotable methods.
# The fingerprint values should only be changed if there is a version bump.
expected_object_fingerprints = {
'Instance': '1.0-8e0020044883e77e6d8d02f6a28c50d8',
'InstanceType': '1.0-7f2a032fc45bb605dc792dc22462d98d',
'Instance': '1.0-b861be9748601f713458a7a709eafd6b',
'InstanceType': '1.0-589b096651fcdb30898ff50f748dd948',
'MyObj': '1.1-4f5efe8f0fcaf182bbe1c7fe3ba858db',
'FakeNode': '1.0-295d1b08ce3048535926c47dedd27211',
}

View File

@ -50,10 +50,6 @@ def get_test_instance(ctxt, **kw):
get_db_instance_checked = check_keyword_arguments(
db_utils.get_test_instance)
db_instance = get_db_instance_checked(**kw)
# Let DB generate ID if it isn't specified explicitly
if 'id' not in kw:
del db_instance['id']
instance = objects.Instance(ctxt)
for key in db_instance:
setattr(instance, key, db_instance[key])