Removes constraints from instance and volume types
* Gets rid of annoying purge semantics * removes unique constraints from the db * deletes extra specs when a volume is deleted * adds exceptions for when the type already exists * fixes bug 854930 * fixes bug 925823 Change-Id: I4618759e31501b2e85325f4e9b9895f04dc151d0
This commit is contained in:
parent
b42839be64
commit
faa938c165
|
@ -1415,7 +1415,7 @@ class VsaCommands(object):
|
|||
not self.manager.is_project_member(user_id, project_id):
|
||||
msg = _("%(user_id)s must be an admin or a "
|
||||
"member of %(project_id)s")
|
||||
LOG.warn(msg % locals())
|
||||
logging.warn(msg % locals())
|
||||
raise ValueError(msg % locals())
|
||||
|
||||
# Sanity check for storage string
|
||||
|
@ -1590,22 +1590,23 @@ class VsaDriveTypeCommands(object):
|
|||
if capabilities is not None and capabilities != '':
|
||||
extra_specs['capabilities'] = capabilities
|
||||
|
||||
volume_types.create(self.context, name, extra_specs)
|
||||
result = volume_types.get_volume_type_by_name(self.context, name)
|
||||
self._list({name: result})
|
||||
try:
|
||||
volume_types.create(self.context, name, extra_specs)
|
||||
result = volume_types.get_volume_type_by_name(self.context, name)
|
||||
self._list({name: result})
|
||||
except exception.VolumeTypeExists:
|
||||
print
|
||||
print "Volume Type Exists"
|
||||
print "Please ensure volume_type name is unique."
|
||||
print "Currently defined volume types:"
|
||||
print
|
||||
self.list()
|
||||
|
||||
@args('--name', dest='name', metavar="<name>", help='Drive name')
|
||||
@args('--purge', action="store_true", dest='purge', default=False,
|
||||
help='purge record from database')
|
||||
def delete(self, name, purge):
|
||||
"""Marks instance types / flavors as deleted"""
|
||||
def delete(self, name):
|
||||
"""Marks volume types as deleted"""
|
||||
try:
|
||||
if purge:
|
||||
volume_types.purge(self.context, name)
|
||||
verb = "purged"
|
||||
else:
|
||||
volume_types.destroy(self.context, name)
|
||||
verb = "deleted"
|
||||
volume_types.destroy(self.context, name)
|
||||
except exception.ApiError:
|
||||
print "Valid volume type name is required"
|
||||
sys.exit(1)
|
||||
|
@ -1615,7 +1616,7 @@ class VsaDriveTypeCommands(object):
|
|||
except Exception:
|
||||
sys.exit(3)
|
||||
else:
|
||||
print "%s %s" % (name, verb)
|
||||
print "%s deleted" % name
|
||||
|
||||
@args('--all', dest='all', action="store_true", default=False,
|
||||
help='Show all drives (including invisible)')
|
||||
|
@ -1766,14 +1767,12 @@ class InstanceTypeCommands(object):
|
|||
print "Must supply valid parameters to create instance_type"
|
||||
print e
|
||||
sys.exit(1)
|
||||
except exception.ApiError, e:
|
||||
print "\n\n"
|
||||
print "\n%s" % e
|
||||
except exception.InstanceTypeExists:
|
||||
print "Instance Type exists."
|
||||
print "Please ensure instance_type name and flavorid are unique."
|
||||
print "To complete remove a instance_type, use the --purge flag:"
|
||||
print "\n # nova-manage instance_type delete <name> --purge\n"
|
||||
print "Currently defined instance_type names and flavorids:"
|
||||
self.list("--all")
|
||||
print
|
||||
self.list()
|
||||
sys.exit(2)
|
||||
except Exception:
|
||||
print "Unknown error"
|
||||
|
@ -1783,17 +1782,10 @@ class InstanceTypeCommands(object):
|
|||
|
||||
@args('--name', dest='name', metavar='<name>',
|
||||
help='Name of instance type/flavor')
|
||||
@args('--purge', action="store_true", dest='purge', default=False,
|
||||
help='purge record from database')
|
||||
def delete(self, name, purge):
|
||||
def delete(self, name):
|
||||
"""Marks instance types / flavors as deleted"""
|
||||
try:
|
||||
if purge:
|
||||
instance_types.purge(name)
|
||||
verb = "purged"
|
||||
else:
|
||||
instance_types.destroy(name)
|
||||
verb = "deleted"
|
||||
instance_types.destroy(name)
|
||||
except exception.ApiError:
|
||||
print "Valid instance type name is required"
|
||||
sys.exit(1)
|
||||
|
@ -1803,7 +1795,7 @@ class InstanceTypeCommands(object):
|
|||
except Exception:
|
||||
sys.exit(3)
|
||||
else:
|
||||
print "%s %s" % (name, verb)
|
||||
print "%s deleted" % name
|
||||
|
||||
@args('--name', dest='name', metavar='<name>',
|
||||
help='Name of instance type/flavor')
|
||||
|
@ -1812,8 +1804,6 @@ class InstanceTypeCommands(object):
|
|||
try:
|
||||
if name is None:
|
||||
inst_types = instance_types.get_all_types()
|
||||
elif name == "--all":
|
||||
inst_types = instance_types.get_all_types(True)
|
||||
else:
|
||||
inst_types = instance_types.get_instance_type_by_name(name)
|
||||
except exception.DBError, e:
|
||||
|
|
|
@ -87,16 +87,6 @@ def destroy(name):
|
|||
raise exception.InstanceTypeNotFoundByName(instance_type_name=name)
|
||||
|
||||
|
||||
def purge(name):
|
||||
"""Removes instance types from database."""
|
||||
try:
|
||||
assert name is not None
|
||||
db.instance_type_purge(context.get_admin_context(), name)
|
||||
except (AssertionError, exception.NotFound):
|
||||
LOG.exception(_('Instance type %s not found for purge') % name)
|
||||
raise exception.InstanceTypeNotFoundByName(instance_type_name=name)
|
||||
|
||||
|
||||
def get_all_types(inactive=0, filters=None):
|
||||
"""Get all non-deleted instance_types.
|
||||
|
||||
|
|
|
@ -1450,15 +1450,6 @@ def instance_type_destroy(context, name):
|
|||
return IMPL.instance_type_destroy(context, name)
|
||||
|
||||
|
||||
def instance_type_purge(context, name):
|
||||
"""Purges (removes) an instance type from DB.
|
||||
|
||||
Use instance_type_destroy for most cases
|
||||
|
||||
"""
|
||||
return IMPL.instance_type_purge(context, name)
|
||||
|
||||
|
||||
####################
|
||||
|
||||
|
||||
|
@ -1628,15 +1619,6 @@ def volume_type_destroy(context, name):
|
|||
return IMPL.volume_type_destroy(context, name)
|
||||
|
||||
|
||||
def volume_type_purge(context, name):
|
||||
"""Purges (removes) a volume type from DB.
|
||||
|
||||
Use volume_type_destroy for most cases
|
||||
|
||||
"""
|
||||
return IMPL.volume_type_purge(context, name)
|
||||
|
||||
|
||||
####################
|
||||
|
||||
|
||||
|
|
|
@ -3356,22 +3356,35 @@ def instance_type_create(context, values):
|
|||
{'extra_specs' : {'k1': 'v1', 'k2': 'v2', ...}}
|
||||
|
||||
"""
|
||||
try:
|
||||
specs = values.get('extra_specs')
|
||||
specs_refs = []
|
||||
if specs:
|
||||
for k, v in specs.iteritems():
|
||||
specs_ref = models.InstanceTypeExtraSpecs()
|
||||
specs_ref['key'] = k
|
||||
specs_ref['value'] = v
|
||||
specs_refs.append(specs_ref)
|
||||
values['extra_specs'] = specs_refs
|
||||
instance_type_ref = models.InstanceTypes()
|
||||
instance_type_ref.update(values)
|
||||
instance_type_ref.save()
|
||||
except Exception, e:
|
||||
raise exception.DBError(e)
|
||||
return _dict_with_extra_specs(instance_type_ref)
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
try:
|
||||
instance_type_get_by_name(context, values['name'], session)
|
||||
raise exception.InstanceTypeExists(name=values['name'])
|
||||
except exception.InstanceTypeNotFoundByName:
|
||||
pass
|
||||
try:
|
||||
instance_type_get_by_flavor_id(context, values['flavorid'],
|
||||
session)
|
||||
raise exception.InstanceTypeExists(name=values['name'])
|
||||
except exception.FlavorNotFound:
|
||||
pass
|
||||
try:
|
||||
specs = values.get('extra_specs')
|
||||
specs_refs = []
|
||||
if specs:
|
||||
for k, v in specs.iteritems():
|
||||
specs_ref = models.InstanceTypeExtraSpecs()
|
||||
specs_ref['key'] = k
|
||||
specs_ref['value'] = v
|
||||
specs_refs.append(specs_ref)
|
||||
values['extra_specs'] = specs_refs
|
||||
instance_type_ref = models.InstanceTypes()
|
||||
instance_type_ref.update(values)
|
||||
instance_type_ref.save(session=session)
|
||||
except Exception, e:
|
||||
raise exception.DBError(e)
|
||||
return _dict_with_extra_specs(instance_type_ref)
|
||||
|
||||
|
||||
def _dict_with_extra_specs(inst_type_query):
|
||||
|
@ -3421,9 +3434,9 @@ def instance_type_get_all(context, inactive=False, filters=None):
|
|||
|
||||
|
||||
@require_context
|
||||
def instance_type_get(context, id):
|
||||
def instance_type_get(context, id, session=None):
|
||||
"""Returns a dict describing specific instance_type"""
|
||||
result = _instance_type_get_query(context, read_deleted="yes").\
|
||||
result = _instance_type_get_query(context, session=session).\
|
||||
filter_by(id=id).\
|
||||
first()
|
||||
|
||||
|
@ -3434,9 +3447,9 @@ def instance_type_get(context, id):
|
|||
|
||||
|
||||
@require_context
|
||||
def instance_type_get_by_name(context, name):
|
||||
def instance_type_get_by_name(context, name, session=None):
|
||||
"""Returns a dict describing specific instance_type"""
|
||||
result = _instance_type_get_query(context, read_deleted="yes").\
|
||||
result = _instance_type_get_query(context, session=session).\
|
||||
filter_by(name=name).\
|
||||
first()
|
||||
|
||||
|
@ -3447,9 +3460,9 @@ def instance_type_get_by_name(context, name):
|
|||
|
||||
|
||||
@require_context
|
||||
def instance_type_get_by_flavor_id(context, flavor_id):
|
||||
def instance_type_get_by_flavor_id(context, flavor_id, session=None):
|
||||
"""Returns a dict describing specific flavor_id"""
|
||||
result = _instance_type_get_query(context, read_deleted="yes").\
|
||||
result = _instance_type_get_query(context, session=session).\
|
||||
filter_by(flavorid=flavor_id).\
|
||||
first()
|
||||
|
||||
|
@ -3461,35 +3474,22 @@ def instance_type_get_by_flavor_id(context, flavor_id):
|
|||
|
||||
@require_admin_context
|
||||
def instance_type_destroy(context, name):
|
||||
""" Marks specific instance_type as deleted"""
|
||||
instance_type_ref = model_query(context, models.InstanceTypes,
|
||||
read_deleted="yes").\
|
||||
filter_by(name=name)
|
||||
|
||||
# FIXME(sirp): this should update deleted_at and updated_at as well
|
||||
records = instance_type_ref.update(dict(deleted=True))
|
||||
|
||||
if records == 0:
|
||||
raise exception.InstanceTypeNotFoundByName(instance_type_name=name)
|
||||
else:
|
||||
return instance_type_ref
|
||||
|
||||
|
||||
@require_admin_context
|
||||
def instance_type_purge(context, name):
|
||||
""" Removes specific instance_type from DB
|
||||
Usually instance_type_destroy should be used
|
||||
"""
|
||||
instance_type_ref = model_query(context, models.InstanceTypes,
|
||||
read_deleted="yes").\
|
||||
filter_by(name=name)
|
||||
|
||||
records = instance_type_ref.delete()
|
||||
|
||||
if records == 0:
|
||||
raise exception.InstanceTypeNotFoundByName(instance_type_name=name)
|
||||
else:
|
||||
return instance_type_ref
|
||||
"""Marks specific instance_type as deleted"""
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
instance_type_ref = instance_type_get_by_name(context, name,
|
||||
session=session)
|
||||
instance_type_id = instance_type_ref['id']
|
||||
session.query(models.InstanceTypes).\
|
||||
filter_by(id=instance_type_id).\
|
||||
update({'deleted': True,
|
||||
'deleted_at': utils.utcnow(),
|
||||
'updated_at': literal_column('updated_at')})
|
||||
session.query(models.InstanceTypeExtraSpecs).\
|
||||
filter_by(instance_type_id=instance_type_id).\
|
||||
update({'deleted': True,
|
||||
'deleted_at': utils.utcnow(),
|
||||
'updated_at': literal_column('updated_at')})
|
||||
|
||||
|
||||
####################
|
||||
|
@ -3512,7 +3512,7 @@ def _zone_get_by_id_query(context, zone_id, session=None):
|
|||
def zone_update(context, zone_id, values):
|
||||
zone = zone_get(context, zone_id)
|
||||
zone.update(values)
|
||||
zone.save(session=session)
|
||||
zone.save()
|
||||
return zone
|
||||
|
||||
|
||||
|
@ -3814,17 +3814,24 @@ def volume_type_create(context, values):
|
|||
{'extra_specs' : {'k1': 'v1', 'k2': 'v2', ...}}
|
||||
|
||||
"""
|
||||
try:
|
||||
specs = values.get('extra_specs')
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
try:
|
||||
volume_type_get_by_name(context, values['name'], session)
|
||||
raise exception.VolumeTypeExists(name=values['name'])
|
||||
except exception.VolumeTypeNotFoundByName:
|
||||
pass
|
||||
try:
|
||||
specs = values.get('extra_specs')
|
||||
|
||||
values['extra_specs'] = _metadata_refs(values.get('extra_specs'),
|
||||
models.VolumeTypeExtraSpecs)
|
||||
volume_type_ref = models.VolumeTypes()
|
||||
volume_type_ref.update(values)
|
||||
volume_type_ref.save()
|
||||
except Exception, e:
|
||||
raise exception.DBError(e)
|
||||
return volume_type_ref
|
||||
values['extra_specs'] = _metadata_refs(values.get('extra_specs'),
|
||||
models.VolumeTypeExtraSpecs)
|
||||
volume_type_ref = models.VolumeTypes()
|
||||
volume_type_ref.update(values)
|
||||
volume_type_ref.save()
|
||||
except Exception, e:
|
||||
raise exception.DBError(e)
|
||||
return volume_type_ref
|
||||
|
||||
|
||||
@require_context
|
||||
|
@ -3851,9 +3858,9 @@ def volume_type_get_all(context, inactive=False, filters=None):
|
|||
|
||||
|
||||
@require_context
|
||||
def volume_type_get(context, id):
|
||||
def volume_type_get(context, id, session=None):
|
||||
"""Returns a dict describing specific volume_type"""
|
||||
result = model_query(context, models.VolumeTypes, read_deleted="yes").\
|
||||
result = model_query(context, models.VolumeTypes, session=session).\
|
||||
options(joinedload('extra_specs')).\
|
||||
filter_by(id=id).\
|
||||
first()
|
||||
|
@ -3865,9 +3872,9 @@ def volume_type_get(context, id):
|
|||
|
||||
|
||||
@require_context
|
||||
def volume_type_get_by_name(context, name):
|
||||
def volume_type_get_by_name(context, name, session=None):
|
||||
"""Returns a dict describing specific volume_type"""
|
||||
result = model_query(context, models.VolumeTypes, read_deleted="yes").\
|
||||
result = model_query(context, models.VolumeTypes, session=session).\
|
||||
options(joinedload('extra_specs')).\
|
||||
filter_by(name=name).\
|
||||
first()
|
||||
|
@ -3880,32 +3887,21 @@ def volume_type_get_by_name(context, name):
|
|||
|
||||
@require_admin_context
|
||||
def volume_type_destroy(context, name):
|
||||
""" Marks specific volume_type as deleted"""
|
||||
volume_type_ref = model_query(context, models.VolumeTypes,
|
||||
read_deleted="yes").\
|
||||
filter_by(name=name)
|
||||
|
||||
# FIXME(sirp): we should be setting deleted_at and updated_at here
|
||||
records = volume_type_ref.update(dict(deleted=True))
|
||||
if records == 0:
|
||||
raise exception.VolumeTypeNotFoundByName(volume_type_name=name)
|
||||
else:
|
||||
return volume_type_ref
|
||||
|
||||
|
||||
@require_admin_context
|
||||
def volume_type_purge(context, name):
|
||||
""" Removes specific volume_type from DB
|
||||
Usually volume_type_destroy should be used
|
||||
"""
|
||||
volume_type_ref = model_query(context, models.VolumeTypes,
|
||||
read_deleted="yes").\
|
||||
filter_by(name=name)
|
||||
records = volume_type_ref.delete()
|
||||
if records == 0:
|
||||
raise exception.VolumeTypeNotFoundByName(volume_type_name=name)
|
||||
else:
|
||||
return volume_type_ref
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
volume_type_ref = volume_type_get_by_name(context, name,
|
||||
session=session)
|
||||
volume_type_id = volume_type_ref['id']
|
||||
session.query(models.VolumeTypes).\
|
||||
filter_by(id=volume_type_id).\
|
||||
update({'deleted': True,
|
||||
'deleted_at': utils.utcnow(),
|
||||
'updated_at': literal_column('updated_at')})
|
||||
session.query(models.VolumeTypeExtraSpecs).\
|
||||
filter_by(volume_type_id=volume_type_id).\
|
||||
update({'deleted': True,
|
||||
'deleted_at': utils.utcnow(),
|
||||
'updated_at': literal_column('updated_at')})
|
||||
|
||||
|
||||
####################
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright (c) OpenStack, LLC
|
||||
# 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.from sqlalchemy import *
|
||||
|
||||
from sqlalchemy import MetaData, Table
|
||||
from migrate.changeset.constraint import UniqueConstraint
|
||||
|
||||
meta = MetaData()
|
||||
|
||||
|
||||
def upgrade(migrate_engine):
|
||||
meta.bind = migrate_engine
|
||||
table = Table('instance_types', meta, autoload=True)
|
||||
# NOTE(vish): These constraint names may be dependent on the backend, but
|
||||
# there doesn't seem to be we a way to determine the proper
|
||||
# name for existing constraints. These names are correct for
|
||||
# mysql.
|
||||
cons = UniqueConstraint('name',
|
||||
name='name',
|
||||
table=table)
|
||||
cons.drop()
|
||||
cons = UniqueConstraint('flavorid',
|
||||
name='instance_types_flavorid_str_key',
|
||||
table=table)
|
||||
cons.drop()
|
||||
table = Table('volume_types', meta, autoload=True)
|
||||
cons = UniqueConstraint('name',
|
||||
name='name',
|
||||
table=table)
|
||||
cons.drop()
|
||||
|
||||
|
||||
def downgrade(migrate_engine):
|
||||
meta.bind = migrate_engine
|
||||
table = Table('instance_types', meta, autoload=True)
|
||||
# NOTE(vish): These constraint names may be dependent on the backend, but
|
||||
# there doesn't seem to be we a way to determine the proper
|
||||
# name for existing constraints. These names are correct for
|
||||
# mysql.
|
||||
cons = UniqueConstraint('name',
|
||||
name='name',
|
||||
table=table)
|
||||
cons.create()
|
||||
table = Table('instance_types', meta, autoload=True)
|
||||
cons = UniqueConstraint('flavorid',
|
||||
name='instance_types_flavorid_str_key',
|
||||
table=table)
|
||||
cons.create()
|
||||
table = Table('volume_types', meta, autoload=True)
|
||||
cons = UniqueConstraint('name',
|
||||
name='name',
|
||||
table=table)
|
||||
cons.create()
|
|
@ -0,0 +1,61 @@
|
|||
-- sqlalchemy-migrate is surprisingly broken when it comes to migrations
|
||||
-- for sqlite. As a result, we have to do much of the work manually here
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE instance_types_temp (
|
||||
created_at DATETIME,
|
||||
updated_at DATETIME,
|
||||
deleted_at DATETIME,
|
||||
deleted BOOLEAN,
|
||||
name VARCHAR(255),
|
||||
id INTEGER NOT NULL,
|
||||
memory_mb INTEGER NOT NULL,
|
||||
vcpus INTEGER NOT NULL,
|
||||
root_gb INTEGER NOT NULL,
|
||||
ephemeral_gb INTEGER NOT NULL,
|
||||
swap INTEGER NOT NULL,
|
||||
rxtx_factor FLOAT,
|
||||
vcpu_weight INTEGER,
|
||||
flavorid VARCHAR(255),
|
||||
PRIMARY KEY (id),
|
||||
CHECK (deleted IN (0, 1))
|
||||
);
|
||||
INSERT INTO instance_types_temp SELECT
|
||||
created_at,
|
||||
updated_at,
|
||||
deleted_at,
|
||||
deleted,
|
||||
name,
|
||||
id,
|
||||
memory_mb,
|
||||
vcpus,
|
||||
root_gb,
|
||||
ephemeral_gb,
|
||||
swap,
|
||||
rxtx_factor,
|
||||
vcpu_weight,
|
||||
flavorid
|
||||
FROM instance_types;
|
||||
DROP TABLE instance_types;
|
||||
ALTER TABLE instance_types_temp RENAME TO instance_types;
|
||||
CREATE TABLE volume_types_temp (
|
||||
created_at DATETIME,
|
||||
updated_at DATETIME,
|
||||
deleted_at DATETIME,
|
||||
deleted BOOLEAN,
|
||||
name VARCHAR(255),
|
||||
id INTEGER NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
CHECK (deleted IN (0, 1))
|
||||
);
|
||||
INSERT INTO volume_types_temp SELECT
|
||||
created_at,
|
||||
updated_at,
|
||||
deleted_at,
|
||||
deleted,
|
||||
name,
|
||||
id
|
||||
FROM volume_types;
|
||||
DROP TABLE volume_types;
|
||||
ALTER TABLE volume_types_temp RENAME TO volume_types;
|
||||
COMMIT;
|
|
@ -337,12 +337,12 @@ class InstanceTypes(BASE, NovaBase):
|
|||
"""Represent possible instance_types or flavor of VM offered"""
|
||||
__tablename__ = "instance_types"
|
||||
id = Column(Integer, primary_key=True)
|
||||
name = Column(String(255), unique=True)
|
||||
name = Column(String(255))
|
||||
memory_mb = Column(Integer)
|
||||
vcpus = Column(Integer)
|
||||
root_gb = Column(Integer)
|
||||
ephemeral_gb = Column(Integer)
|
||||
flavorid = Column(String(255), unique=True)
|
||||
flavorid = Column(String(255))
|
||||
swap = Column(Integer, nullable=False, default=0)
|
||||
rxtx_factor = Column(Float, nullable=False, default=1)
|
||||
vcpu_weight = Column(Integer, nullable=True)
|
||||
|
@ -350,14 +350,17 @@ class InstanceTypes(BASE, NovaBase):
|
|||
instances = relationship(Instance,
|
||||
backref=backref('instance_type', uselist=False),
|
||||
foreign_keys=id,
|
||||
primaryjoin='and_(Instance.instance_type_id == '
|
||||
'InstanceTypes.id)')
|
||||
primaryjoin='and_('
|
||||
'Instance.instance_type_id == '
|
||||
'InstanceTypes.id, '
|
||||
'InstanceTypes.deleted == False)')
|
||||
|
||||
vsas = relationship(VirtualStorageArray,
|
||||
backref=backref('vsa_instance_type', uselist=False),
|
||||
foreign_keys=id,
|
||||
primaryjoin='and_(VirtualStorageArray.instance_type_id'
|
||||
' == InstanceTypes.id)')
|
||||
primaryjoin='and_('
|
||||
'VirtualStorageArray.instance_type_id == '
|
||||
'InstanceTypes.id, InstanceTypes.deleted == False)')
|
||||
|
||||
|
||||
class Volume(BASE, NovaBase):
|
||||
|
@ -419,13 +422,14 @@ class VolumeTypes(BASE, NovaBase):
|
|||
"""Represent possible volume_types of volumes offered"""
|
||||
__tablename__ = "volume_types"
|
||||
id = Column(Integer, primary_key=True)
|
||||
name = Column(String(255), unique=True)
|
||||
name = Column(String(255))
|
||||
|
||||
volumes = relationship(Volume,
|
||||
backref=backref('volume_type', uselist=False),
|
||||
foreign_keys=id,
|
||||
primaryjoin='and_(Volume.volume_type_id == '
|
||||
'VolumeTypes.id)')
|
||||
primaryjoin='and_('
|
||||
'Volume.volume_type_id == VolumeTypes.id, '
|
||||
'VolumeTypes.deleted == False)')
|
||||
|
||||
|
||||
class VolumeTypeExtraSpecs(BASE, NovaBase):
|
||||
|
|
|
@ -843,6 +843,14 @@ class InstanceExists(Duplicate):
|
|||
message = _("Instance %(name)s already exists.")
|
||||
|
||||
|
||||
class InstanceTypeExists(Duplicate):
|
||||
message = _("Instance Type %(name)s already exists.")
|
||||
|
||||
|
||||
class VolumeTypeExists(Duplicate):
|
||||
message = _("Volume Type %(name)s already exists.")
|
||||
|
||||
|
||||
class InvalidSharedStorage(NovaException):
|
||||
message = _("%(path)s is on shared storage: %(reason)s")
|
||||
|
||||
|
|
|
@ -47,10 +47,6 @@ def fake_get_instance_type_by_flavor_id(flavorid):
|
|||
}
|
||||
|
||||
|
||||
def fake_purge(flavorname):
|
||||
pass
|
||||
|
||||
|
||||
def fake_destroy(flavorname):
|
||||
pass
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ class VsaSchedulerTestCase(test_scheduler.SchedulerTestCase):
|
|||
|
||||
def tearDown(self):
|
||||
for name in self.created_types_lst:
|
||||
volume_types.purge(self.context.elevated(), name)
|
||||
volume_types.destroy(self.context.elevated(), name)
|
||||
super(VsaSchedulerTestCase, self).tearDown()
|
||||
|
||||
def _get_vol_creation_request(self, num_vols, drive_ix, size=0):
|
||||
|
@ -89,7 +89,7 @@ class VsaSchedulerTestCase(test_scheduler.SchedulerTestCase):
|
|||
'drive_type': 'type_' + str(drive_ix),
|
||||
'drive_size': 1 + 100 * (drive_ix)})
|
||||
self.created_types_lst.append(name)
|
||||
except exception.ApiError:
|
||||
except exception.VolumeTypeExists:
|
||||
# type is already created
|
||||
pass
|
||||
|
||||
|
|
|
@ -84,21 +84,14 @@ class InstanceTypeTestCase(test.TestCase):
|
|||
self.assertNotEqual(len(original_list), len(new_list),
|
||||
'instance type was not created')
|
||||
|
||||
# destroy instance and make sure deleted flag is set to True
|
||||
instance_types.destroy(name)
|
||||
inst_type = instance_types.get_instance_type(inst_type_id)
|
||||
self.assertEqual(1, inst_type["deleted"])
|
||||
self.assertRaises(exception.ApiError,
|
||||
instance_types.get_instance_type, inst_type_id)
|
||||
|
||||
# deleted instance should not be in list anymoer
|
||||
new_list = instance_types.get_all_types()
|
||||
self.assertEqual(original_list, new_list)
|
||||
|
||||
# ensure instances are gone after purge
|
||||
instance_types.purge(name)
|
||||
new_list = instance_types.get_all_types()
|
||||
self.assertEqual(original_list, new_list,
|
||||
'instance type not purged')
|
||||
|
||||
def test_get_all_instance_types(self):
|
||||
"""Ensures that all instance types can be retrieved"""
|
||||
session = get_session()
|
||||
|
@ -143,15 +136,15 @@ class InstanceTypeTestCase(test.TestCase):
|
|||
"""Ensures that name duplicates raise ApiError"""
|
||||
name = 'some_name'
|
||||
instance_types.create(name, 256, 1, 120, 200, 'flavor1')
|
||||
self.assertRaises(exception.ApiError,
|
||||
self.assertRaises(exception.InstanceTypeExists,
|
||||
instance_types.create,
|
||||
name, "256", 1, 120, 200, 'flavor2')
|
||||
name, 256, 1, 120, 200, 'flavor2')
|
||||
|
||||
def test_duplicate_flavorids_fail(self):
|
||||
"""Ensures that flavorid duplicates raise ApiError"""
|
||||
flavorid = 'flavor1'
|
||||
instance_types.create('name one', 256, 1, 120, 200, flavorid)
|
||||
self.assertRaises(exception.ApiError,
|
||||
self.assertRaises(exception.InstanceTypeExists,
|
||||
instance_types.create,
|
||||
'name two', 256, 1, 120, 200, flavorid)
|
||||
|
||||
|
@ -160,17 +153,6 @@ class InstanceTypeTestCase(test.TestCase):
|
|||
self.assertRaises(exception.InstanceTypeNotFoundByName,
|
||||
instance_types.destroy, None)
|
||||
|
||||
def test_will_not_purge_without_name(self):
|
||||
"""Ensure purge without a name raises error"""
|
||||
self.assertRaises(exception.InstanceTypeNotFoundByName,
|
||||
instance_types.purge, None)
|
||||
|
||||
def test_will_not_purge_with_wrong_name(self):
|
||||
"""Ensure purge without correct name raises error"""
|
||||
self.assertRaises(exception.InstanceTypeNotFound,
|
||||
instance_types.purge,
|
||||
'unknown_flavor')
|
||||
|
||||
def test_will_not_get_bad_default_instance_type(self):
|
||||
"""ensures error raised on bad default instance type"""
|
||||
FLAGS.default_instance_type = 'unknown_flavor'
|
||||
|
|
|
@ -44,7 +44,7 @@ class InstanceTypeExtraSpecsTestCase(test.TestCase):
|
|||
|
||||
def tearDown(self):
|
||||
# Remove the instance type from the database
|
||||
db.instance_type_purge(self.context, "cg1.4xlarge")
|
||||
db.instance_type_destroy(self.context, "cg1.4xlarge")
|
||||
super(InstanceTypeExtraSpecsTestCase, self).tearDown()
|
||||
|
||||
def test_instance_type_specs_get(self):
|
||||
|
|
|
@ -75,37 +75,6 @@ class VolumeTypeTestCase(test.TestCase):
|
|||
new_all_vtypes,
|
||||
'drive type was not deleted')
|
||||
|
||||
def test_volume_type_create_then_purge(self):
|
||||
"""Ensure volume types can be created and deleted"""
|
||||
prev_all_vtypes = volume_types.get_all_types(self.ctxt, inactive=1)
|
||||
|
||||
volume_types.create(self.ctxt,
|
||||
self.vol_type1_name,
|
||||
self.vol_type1_specs)
|
||||
new = volume_types.get_volume_type_by_name(self.ctxt,
|
||||
self.vol_type1_name)
|
||||
|
||||
for k, v in self.vol_type1_specs.iteritems():
|
||||
self.assertEqual(v, new['extra_specs'][k],
|
||||
'one of fields doesnt match')
|
||||
|
||||
new_all_vtypes = volume_types.get_all_types(self.ctxt, inactive=1)
|
||||
self.assertEqual(len(prev_all_vtypes) + 1,
|
||||
len(new_all_vtypes),
|
||||
'drive type was not created')
|
||||
|
||||
volume_types.destroy(self.ctxt, self.vol_type1_name)
|
||||
new_all_vtypes2 = volume_types.get_all_types(self.ctxt, inactive=1)
|
||||
self.assertEqual(len(new_all_vtypes),
|
||||
len(new_all_vtypes2),
|
||||
'drive type was incorrectly deleted')
|
||||
|
||||
volume_types.purge(self.ctxt, self.vol_type1_name)
|
||||
new_all_vtypes2 = volume_types.get_all_types(self.ctxt, inactive=1)
|
||||
self.assertEqual(len(new_all_vtypes) - 1,
|
||||
len(new_all_vtypes2),
|
||||
'drive type was not purged')
|
||||
|
||||
def test_get_all_volume_types(self):
|
||||
"""Ensures that all volume types can be retrieved"""
|
||||
session = get_session()
|
||||
|
@ -114,26 +83,22 @@ class VolumeTypeTestCase(test.TestCase):
|
|||
vol_types = volume_types.get_all_types(self.ctxt)
|
||||
self.assertEqual(total_volume_types, len(vol_types))
|
||||
|
||||
def test_non_existant_inst_type_shouldnt_delete(self):
|
||||
def test_non_existant_vol_type_shouldnt_delete(self):
|
||||
"""Ensures that volume type creation fails with invalid args"""
|
||||
self.assertRaises(exception.ApiError,
|
||||
volume_types.destroy, self.ctxt, "sfsfsdfdfs")
|
||||
|
||||
def test_repeated_vol_types_should_raise_api_error(self):
|
||||
"""Ensures that volume duplicates raises ApiError"""
|
||||
def test_repeated_vol_types_shouldnt_raise(self):
|
||||
"""Ensures that volume duplicates don't raise"""
|
||||
new_name = self.vol_type1_name + "dup"
|
||||
volume_types.create(self.ctxt, new_name)
|
||||
volume_types.destroy(self.ctxt, new_name)
|
||||
self.assertRaises(
|
||||
exception.ApiError,
|
||||
volume_types.create, self.ctxt, new_name)
|
||||
volume_types.create(self.ctxt, new_name)
|
||||
|
||||
def test_invalid_volume_types_params(self):
|
||||
"""Ensures that volume type creation fails with invalid args"""
|
||||
self.assertRaises(exception.InvalidVolumeType,
|
||||
volume_types.destroy, self.ctxt, None)
|
||||
self.assertRaises(exception.InvalidVolumeType,
|
||||
volume_types.purge, self.ctxt, None)
|
||||
self.assertRaises(exception.InvalidVolumeType,
|
||||
volume_types.get_volume_type, self.ctxt, None)
|
||||
self.assertRaises(exception.InvalidVolumeType,
|
||||
|
|
|
@ -43,11 +43,11 @@ class VolumeTypeExtraSpecsTestCase(test.TestCase):
|
|||
self.vol_type2_id = ref.id
|
||||
|
||||
def tearDown(self):
|
||||
# Remove the instance type from the database
|
||||
db.volume_type_purge(context.get_admin_context(),
|
||||
self.vol_type1['name'])
|
||||
db.volume_type_purge(context.get_admin_context(),
|
||||
self.vol_type2_noextra['name'])
|
||||
# Remove the volume type from the database
|
||||
db.volume_type_destroy(context.get_admin_context(),
|
||||
self.vol_type1['name'])
|
||||
db.volume_type_destroy(context.get_admin_context(),
|
||||
self.vol_type2_noextra['name'])
|
||||
super(VolumeTypeExtraSpecsTestCase, self).tearDown()
|
||||
|
||||
def test_volume_type_specs_get(self):
|
||||
|
|
|
@ -39,6 +39,7 @@ def get_test_instance_type(context=None):
|
|||
context = get_test_admin_context()
|
||||
|
||||
test_instance_type = {'name': 'kinda.big',
|
||||
'flavorid': 'someid',
|
||||
'memory_mb': 2048,
|
||||
'vcpus': 4,
|
||||
'root_gb': 40,
|
||||
|
|
|
@ -56,18 +56,6 @@ def destroy(context, name):
|
|||
raise exception.ApiError(_("Unknown volume type: %s") % name)
|
||||
|
||||
|
||||
def purge(context, name):
|
||||
"""Removes volume types from database."""
|
||||
if name is None:
|
||||
raise exception.InvalidVolumeType(volume_type=name)
|
||||
else:
|
||||
try:
|
||||
db.volume_type_purge(context, name)
|
||||
except exception.NotFound:
|
||||
LOG.exception(_('Volume type %s not found for purge') % name)
|
||||
raise exception.ApiError(_("Unknown volume type: %s") % name)
|
||||
|
||||
|
||||
def get_all_types(context, inactive=0, search_opts={}):
|
||||
"""Get all non-deleted volume_types.
|
||||
|
||||
|
|
Loading…
Reference in New Issue