Merge "New flavor"

This commit is contained in:
Jenkins 2017-05-13 05:53:47 +00:00 committed by Gerrit Code Review
commit c5126661c3
10 changed files with 320 additions and 8 deletions

View File

@ -56,6 +56,18 @@ class Flavor(base.APIBase):
description = wtypes.text
"""The description of the flavor"""
cpus = {wtypes.text: types.jsontype}
"""The cpus of the flavor"""
memory = {wtypes.text: types.jsontype}
"""The memory of the flavor"""
nics = wtypes.ArrayType(types.jsontype)
"""The nics of the flavor"""
disks = wtypes.ArrayType(types.jsontype)
"""The disks of the flavor"""
is_public = types.boolean
"""Indicates whether the flavor is public."""

View File

@ -23,6 +23,10 @@ create_flavor = {
'name': parameter_types.name,
'description': parameter_types.description,
'is_public': parameter_types.boolean,
'cpus': parameter_types.flavor_cpus,
'memory': parameter_types.flavor_memory,
'nics': parameter_types.flavor_nics,
'disks': parameter_types.flavor_disks,
},
'required': ['name', 'description'],
'additionalProperties': False,

View File

@ -106,3 +106,67 @@ boolean = {
False, 'False', 'FALSE', 'false', '0', 'OFF', 'Off', 'off',
'NO', 'No', 'no'],
}
positive_integer = {
'type': ['integer', 'string'],
'pattern': '^[0-9]*$', 'minimum': 1
}
flavor_cpus = {
'type': 'object',
'patternProperties': {
'model': {
'type': 'string', 'maxLength': 255
},
'cores': positive_integer,
},
'required': ['model', 'cores'],
'additionalProperties': False
}
flavor_memory = {
'type': 'object',
'patternProperties': {
'type': {
'type': 'string', 'maxLength': 255
},
'size_mb': positive_integer,
},
'required': ['type', 'size_mb'],
'additionalProperties': False
}
flavor_nics = {
'type': 'array',
'items': {
'type': 'object',
'patternProperties': {
'type': {
'type': 'string', 'maxLength': 255
},
'speed': {
'type': 'string', 'maxLength': 255
},
},
'additionalProperties': False,
},
}
flavor_disks = {
'type': 'array',
'items': {
'type': 'object',
'patternProperties': {
'type': {
'type': 'string', 'maxLength': 255
},
'size_gb': positive_integer,
},
'additionalProperties': False,
},
}

View File

@ -67,6 +67,62 @@ def upgrade():
mysql_ENGINE='InnoDB',
mysql_DEFAULT_CHARSET='UTF8'
)
op.create_table(
'flavor_cpus',
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('model', sa.String(length=255), nullable=True),
sa.Column('cores', sa.Integer(), nullable=False),
sa.Column('flavor_uuid', sa.String(length=36), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.ForeignKeyConstraint(['flavor_uuid'],
['flavors.uuid']),
mysql_ENGINE='InnoDB',
mysql_DEFAULT_CHARSET='UTF8'
)
op.create_table(
'flavor_memory',
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('type', sa.String(length=255), nullable=True),
sa.Column('size_mb', sa.Integer(), nullable=False),
sa.Column('flavor_uuid', sa.String(length=36), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.ForeignKeyConstraint(['flavor_uuid'],
['flavors.uuid']),
mysql_ENGINE='InnoDB',
mysql_DEFAULT_CHARSET='UTF8'
)
op.create_table(
'flavor_disks',
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('type', sa.String(length=255), nullable=True),
sa.Column('size_gb', sa.Integer(), nullable=False),
sa.Column('flavor_uuid', sa.String(length=36), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.ForeignKeyConstraint(['flavor_uuid'],
['flavors.uuid']),
mysql_ENGINE='InnoDB',
mysql_DEFAULT_CHARSET='UTF8'
)
op.create_table(
'flavor_nics',
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('type', sa.String(length=255), nullable=True),
sa.Column('speed', sa.String(length=255), nullable=False),
sa.Column('flavor_uuid', sa.String(length=36), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.ForeignKeyConstraint(['flavor_uuid'],
['flavors.uuid']),
mysql_ENGINE='InnoDB',
mysql_DEFAULT_CHARSET='UTF8'
)
op.create_table(
'servers',
sa.Column('created_at', sa.DateTime(), nullable=True),

View File

@ -96,12 +96,41 @@ def add_identity_filter(query, value):
raise exception.InvalidParameterValue(identity=value)
def _dict_with_extra_specs(flavor_query):
def _dict_with_extra_fields(flavor_query):
"""Takes a server type query and returns it as a dictionary."""
flavor_dict = dict(flavor_query)
# extra specs
extra_specs = {x['key']: x['value']
for x in flavor_query['extra_specs']}
flavor_dict['extra_specs'] = extra_specs
# cpus
cpus = {}
for c in flavor_query['cpus']:
cpus = {'model': c['model'], 'cores': c['cores']}
flavor_dict['cpus'] = cpus
# memory
memory = {}
for m in flavor_query['memory']:
memory = {'type': m['type'], 'size_mb': m['size_mb']}
flavor_dict['memory'] = memory
# nics
nics = []
for n in flavor_query['nics']:
nic = {'type': n['type'], 'speed': n['speed']}
nics.append(nic)
flavor_dict['nics'] = nics
# disks
disks = []
for d in flavor_query['disks']:
disk = {'type': d['type'], 'size_gb': d['size_gb']}
disks.append(disk)
flavor_dict['disks'] = disks
return flavor_dict
@ -119,16 +148,45 @@ class Connection(api.Connection):
if not values.get('description'):
values['description'] = ""
cpus = values.pop('cpus', None)
memory = values.pop('memory', None)
nics = values.pop('nics', [])
disks = values.pop('disks', [])
flavor = models.Flavors()
flavor.update(values)
with _session_for_write() as session:
try:
session.add(flavor)
# add flavor cpus
if cpus:
flavor_cpus = models.FlavorCpus()
cpus['flavor_uuid'] = values['uuid']
flavor_cpus.update(cpus)
session.add(flavor_cpus)
# add flavor memory
if memory:
flavor_mem = models.FlavorMemory()
memory['flavor_uuid'] = values['uuid']
flavor_mem.update(memory)
session.add(flavor_mem)
# add flavor nics
for nic in nics:
flavor_nic = models.FlavorNics()
nic['flavor_uuid'] = values['uuid']
flavor_nic.update(nic)
session.add(flavor_nic)
# add flavor disks
for disk in disks:
flavor_disk = models.FlavorDisks()
disk['flavor_uuid'] = values['uuid']
flavor_disk.update(disk)
session.add(flavor_disk)
session.flush()
except db_exc.DBDuplicateEntry:
raise exception.FlavorAlreadyExists(uuid=values['uuid'])
return _dict_with_extra_specs(flavor)
return _dict_with_extra_fields(flavor)
def flavor_get(self, context, flavor_uuid):
query = model_query(context, models.Flavors).filter_by(
@ -142,7 +200,7 @@ class Connection(api.Connection):
query = query.filter(or_(*the_filter))
try:
return _dict_with_extra_specs(query.one())
return _dict_with_extra_fields(query.one())
except NoResultFound:
raise exception.FlavorNotFound(
type_id=flavor_uuid)
@ -169,7 +227,7 @@ class Connection(api.Connection):
])
query = query.filter(or_(*the_filter))
return [_dict_with_extra_specs(i) for i in query.all()]
return [_dict_with_extra_fields(i) for i in query.all()]
def flavor_destroy(self, context, flavor_uuid):
with _session_for_write():
@ -181,6 +239,34 @@ class Connection(api.Connection):
flavor_uuid=type_id)
extra_query.delete()
# Clean up cpus related to this flavor
cpus_query = model_query(
context,
models.FlavorCpus).filter_by(
flavor_uuid=type_id)
cpus_query.delete()
# Clean up memory related to this flavor
memory_query = model_query(
context,
models.FlavorMemory).filter_by(
flavor_uuid=type_id)
memory_query.delete()
# Clean up nics related to this flavor
nics_query = model_query(
context,
models.FlavorNics).filter_by(
flavor_uuid=type_id)
nics_query.delete()
# Clean up disks related to this flavor
disks_query = model_query(
context,
models.FlavorDisks).filter_by(
flavor_uuid=type_id)
disks_query.delete()
# Clean up all access related to this flavor
project_query = model_query(
context,

View File

@ -231,6 +231,74 @@ class FlavorExtraSpecs(Base):
'== Flavors.uuid')
class FlavorCpus(Base):
"""Represents the flavor cpus."""
__tablename__ = 'flavor_cpus'
id = Column(Integer, primary_key=True)
model = Column(String(255), nullable=False)
cores = Column(Integer, nullable=False)
flavor_uuid = Column(String(36), ForeignKey('flavors.uuid'),
nullable=False)
flavor = orm.relationship(
Flavors,
backref='cpus',
foreign_keys=flavor_uuid,
primaryjoin='FlavorCpus.flavor_uuid '
'== Flavors.uuid')
class FlavorMemory(Base):
"""Represents the flavor memory."""
__tablename__ = 'flavor_memory'
id = Column(Integer, primary_key=True)
type = Column(String(255), nullable=False)
size_mb = Column(Integer, nullable=False)
flavor_uuid = Column(String(36), ForeignKey('flavors.uuid'),
nullable=False)
flavor = orm.relationship(
Flavors,
backref='memory',
foreign_keys=flavor_uuid,
primaryjoin='FlavorMemory.flavor_uuid '
'== Flavors.uuid')
class FlavorDisks(Base):
"""Represents the flavor disks."""
__tablename__ = 'flavor_disks'
id = Column(Integer, primary_key=True)
type = Column(String(255), nullable=False)
size_gb = Column(Integer, nullable=False)
flavor_uuid = Column(String(36), ForeignKey('flavors.uuid'),
nullable=False)
flavor = orm.relationship(
Flavors,
backref='disks',
foreign_keys=flavor_uuid,
primaryjoin='FlavorDisks.flavor_uuid '
'== Flavors.uuid')
class FlavorNics(Base):
"""Represents the flavor nics."""
__tablename__ = 'flavor_nics'
id = Column(Integer, primary_key=True)
type = Column(String(255), nullable=False)
speed = Column(String(255), nullable=False)
flavor_uuid = Column(String(36), ForeignKey('flavors.uuid'),
nullable=False)
flavor = orm.relationship(
Flavors,
backref='nics',
foreign_keys=flavor_uuid,
primaryjoin='FlavorNics.flavor_uuid '
'== Flavors.uuid')
class ServerFault(Base):
"""Represents fault info for server"""

View File

@ -35,6 +35,10 @@ class Flavor(base.MoganObject, object_base.VersionedObjectDictCompat):
'uuid': object_fields.UUIDField(nullable=True),
'name': object_fields.StringField(nullable=True),
'description': object_fields.StringField(nullable=True),
'cpus': object_fields.FlexibleDictField(),
'memory': object_fields.FlexibleDictField(),
'nics': object_fields.ListOfDictOfNullableStringsField(),
'disks': object_fields.ListOfDictOfNullableStringsField(),
'is_public': object_fields.BooleanField(),
'extra_specs': object_fields.FlexibleDictField(),
'projects': object_fields.ListOfStringsField(),
@ -131,6 +135,12 @@ class Flavor(base.MoganObject, object_base.VersionedObjectDictCompat):
updates = self.obj_get_changes()
projects = updates.pop('projects', None)
extra_specs = updates.pop('extra_specs', None)
updates.pop('cpus', None)
updates.pop('memory', None)
updates.pop('nics', None)
updates.pop('disks', None)
# extra specs
if extra_specs is not None:
deleted_keys = (set(self._orig_extra_specs.keys()) -
set(extra_specs.keys()))
@ -138,15 +148,16 @@ class Flavor(base.MoganObject, object_base.VersionedObjectDictCompat):
else:
added_keys = deleted_keys = None
if added_keys or deleted_keys:
self.save_extra_specs(context, self.extra_specs, deleted_keys)
# access projects
if projects is not None:
deleted_projects = set(self._orig_projects) - set(projects)
added_projects = set(projects) - set(self._orig_projects)
else:
added_projects = deleted_projects = None
if added_keys or deleted_keys:
self.save_extra_specs(context, self.extra_specs, deleted_keys)
if added_projects or deleted_projects:
self.save_projects(context, added_projects, deleted_projects)

View File

@ -199,6 +199,13 @@ def get_test_flavor(**kw):
'uuid': kw.get('uuid', uuidutils.generate_uuid()),
'name': kw.get('name', 'test'),
'description': kw.get('description', 'test'),
'cpus': kw.get('cpus', {'model': 'Dual Intel Xeon E5-2650 2.00GHz',
'cores': '16'}),
'memory': kw.get('memory', {'type': 'DDR3', 'size_mb': '8192'}),
'nics': kw.get('nics', [{'type': 'Ethernet', 'speed': '10 Gbps'},
{'type': 'InfiniBand', 'speed': '40 Gbps'}]),
'disks': kw.get('disks', [{'type': 'SSD', 'size_gb': 1024},
{'type': 'HDD', 'size_gb': 1024}]),
'is_public': kw.get('is_public', 1),
'updated_at': kw.get('updated_at'),
'created_at': kw.get('created_at'),

View File

@ -77,6 +77,10 @@ class TestFlavorObject(base.DbTestCase):
updates = flavor.obj_get_changes()
flavor.save(self.context)
updates.pop('extra_specs', None)
updates.pop('cpus', None)
updates.pop('memory', None)
updates.pop('disks', None)
updates.pop('nics', None)
mock_flavor_update.return_value = self.fake_type
mock_flavor_update.assert_called_once_with(
self.context, uuid, updates)

View File

@ -391,7 +391,7 @@ expected_object_fingerprints = {
'ComputeDiskList': '1.0-33a2e1bb91ad4082f9f63429b77c1244',
'ServerFault': '1.0-74349ff701259e4834b4e9dc2dac1b12',
'ServerFaultList': '1.0-43e8aad0258652921f929934e9e048fd',
'Flavor': '1.0-d1cf232312ff8101aa5a19908b476d67',
'Flavor': '1.0-7cc125bfe2dda6e5ffa07651d58047cd',
'MyObj': '1.1-aad62eedc5a5cc8bcaf2982c285e753f',
'ServerNic': '1.0-ebbd767c2f6a7f14bd524c6067f2b382',
'ServerNics': '1.0-33a2e1bb91ad4082f9f63429b77c1244',