New flavor
This adds cpus, memory, nics, and disks properties to flavors. Change-Id: I8e7629c857dbb5164d596bf8e72f21e9d4bfcaba
This commit is contained in:
parent
dcd7a6b2b7
commit
aecfc71fdd
@ -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."""
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
},
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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,
|
||||
|
@ -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"""
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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'),
|
||||
|
@ -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)
|
||||
|
@ -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',
|
||||
|
Loading…
x
Reference in New Issue
Block a user