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:
@@ -1415,7 +1415,7 @@ class VsaCommands(object):
|
|||||||
not self.manager.is_project_member(user_id, project_id):
|
not self.manager.is_project_member(user_id, project_id):
|
||||||
msg = _("%(user_id)s must be an admin or a "
|
msg = _("%(user_id)s must be an admin or a "
|
||||||
"member of %(project_id)s")
|
"member of %(project_id)s")
|
||||||
LOG.warn(msg % locals())
|
logging.warn(msg % locals())
|
||||||
raise ValueError(msg % locals())
|
raise ValueError(msg % locals())
|
||||||
|
|
||||||
# Sanity check for storage string
|
# Sanity check for storage string
|
||||||
@@ -1590,22 +1590,23 @@ class VsaDriveTypeCommands(object):
|
|||||||
if capabilities is not None and capabilities != '':
|
if capabilities is not None and capabilities != '':
|
||||||
extra_specs['capabilities'] = capabilities
|
extra_specs['capabilities'] = capabilities
|
||||||
|
|
||||||
volume_types.create(self.context, name, extra_specs)
|
try:
|
||||||
result = volume_types.get_volume_type_by_name(self.context, name)
|
volume_types.create(self.context, name, extra_specs)
|
||||||
self._list({name: result})
|
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('--name', dest='name', metavar="<name>", help='Drive name')
|
||||||
@args('--purge', action="store_true", dest='purge', default=False,
|
def delete(self, name):
|
||||||
help='purge record from database')
|
"""Marks volume types as deleted"""
|
||||||
def delete(self, name, purge):
|
|
||||||
"""Marks instance types / flavors as deleted"""
|
|
||||||
try:
|
try:
|
||||||
if purge:
|
volume_types.destroy(self.context, name)
|
||||||
volume_types.purge(self.context, name)
|
|
||||||
verb = "purged"
|
|
||||||
else:
|
|
||||||
volume_types.destroy(self.context, name)
|
|
||||||
verb = "deleted"
|
|
||||||
except exception.ApiError:
|
except exception.ApiError:
|
||||||
print "Valid volume type name is required"
|
print "Valid volume type name is required"
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@@ -1615,7 +1616,7 @@ class VsaDriveTypeCommands(object):
|
|||||||
except Exception:
|
except Exception:
|
||||||
sys.exit(3)
|
sys.exit(3)
|
||||||
else:
|
else:
|
||||||
print "%s %s" % (name, verb)
|
print "%s deleted" % name
|
||||||
|
|
||||||
@args('--all', dest='all', action="store_true", default=False,
|
@args('--all', dest='all', action="store_true", default=False,
|
||||||
help='Show all drives (including invisible)')
|
help='Show all drives (including invisible)')
|
||||||
@@ -1766,14 +1767,12 @@ class InstanceTypeCommands(object):
|
|||||||
print "Must supply valid parameters to create instance_type"
|
print "Must supply valid parameters to create instance_type"
|
||||||
print e
|
print e
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
except exception.ApiError, e:
|
except exception.InstanceTypeExists:
|
||||||
print "\n\n"
|
print "Instance Type exists."
|
||||||
print "\n%s" % e
|
|
||||||
print "Please ensure instance_type name and flavorid are unique."
|
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:"
|
print "Currently defined instance_type names and flavorids:"
|
||||||
self.list("--all")
|
print
|
||||||
|
self.list()
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
except Exception:
|
except Exception:
|
||||||
print "Unknown error"
|
print "Unknown error"
|
||||||
@@ -1783,17 +1782,10 @@ class InstanceTypeCommands(object):
|
|||||||
|
|
||||||
@args('--name', dest='name', metavar='<name>',
|
@args('--name', dest='name', metavar='<name>',
|
||||||
help='Name of instance type/flavor')
|
help='Name of instance type/flavor')
|
||||||
@args('--purge', action="store_true", dest='purge', default=False,
|
def delete(self, name):
|
||||||
help='purge record from database')
|
|
||||||
def delete(self, name, purge):
|
|
||||||
"""Marks instance types / flavors as deleted"""
|
"""Marks instance types / flavors as deleted"""
|
||||||
try:
|
try:
|
||||||
if purge:
|
instance_types.destroy(name)
|
||||||
instance_types.purge(name)
|
|
||||||
verb = "purged"
|
|
||||||
else:
|
|
||||||
instance_types.destroy(name)
|
|
||||||
verb = "deleted"
|
|
||||||
except exception.ApiError:
|
except exception.ApiError:
|
||||||
print "Valid instance type name is required"
|
print "Valid instance type name is required"
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@@ -1803,7 +1795,7 @@ class InstanceTypeCommands(object):
|
|||||||
except Exception:
|
except Exception:
|
||||||
sys.exit(3)
|
sys.exit(3)
|
||||||
else:
|
else:
|
||||||
print "%s %s" % (name, verb)
|
print "%s deleted" % name
|
||||||
|
|
||||||
@args('--name', dest='name', metavar='<name>',
|
@args('--name', dest='name', metavar='<name>',
|
||||||
help='Name of instance type/flavor')
|
help='Name of instance type/flavor')
|
||||||
@@ -1812,8 +1804,6 @@ class InstanceTypeCommands(object):
|
|||||||
try:
|
try:
|
||||||
if name is None:
|
if name is None:
|
||||||
inst_types = instance_types.get_all_types()
|
inst_types = instance_types.get_all_types()
|
||||||
elif name == "--all":
|
|
||||||
inst_types = instance_types.get_all_types(True)
|
|
||||||
else:
|
else:
|
||||||
inst_types = instance_types.get_instance_type_by_name(name)
|
inst_types = instance_types.get_instance_type_by_name(name)
|
||||||
except exception.DBError, e:
|
except exception.DBError, e:
|
||||||
|
@@ -843,6 +843,14 @@ class InstanceExists(Duplicate):
|
|||||||
message = _("Instance %(name)s already exists.")
|
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):
|
class InvalidSharedStorage(NovaException):
|
||||||
message = _("%(path)s is on shared storage: %(reason)s")
|
message = _("%(path)s is on shared storage: %(reason)s")
|
||||||
|
|
||||||
|
@@ -74,7 +74,7 @@ class VsaSchedulerTestCase(test_scheduler.SchedulerTestCase):
|
|||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
for name in self.created_types_lst:
|
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()
|
super(VsaSchedulerTestCase, self).tearDown()
|
||||||
|
|
||||||
def _get_vol_creation_request(self, num_vols, drive_ix, size=0):
|
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_type': 'type_' + str(drive_ix),
|
||||||
'drive_size': 1 + 100 * (drive_ix)})
|
'drive_size': 1 + 100 * (drive_ix)})
|
||||||
self.created_types_lst.append(name)
|
self.created_types_lst.append(name)
|
||||||
except exception.ApiError:
|
except exception.VolumeTypeExists:
|
||||||
# type is already created
|
# type is already created
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@@ -84,21 +84,14 @@ class InstanceTypeTestCase(test.TestCase):
|
|||||||
self.assertNotEqual(len(original_list), len(new_list),
|
self.assertNotEqual(len(original_list), len(new_list),
|
||||||
'instance type was not created')
|
'instance type was not created')
|
||||||
|
|
||||||
# destroy instance and make sure deleted flag is set to True
|
|
||||||
instance_types.destroy(name)
|
instance_types.destroy(name)
|
||||||
inst_type = instance_types.get_instance_type(inst_type_id)
|
self.assertRaises(exception.ApiError,
|
||||||
self.assertEqual(1, inst_type["deleted"])
|
instance_types.get_instance_type, inst_type_id)
|
||||||
|
|
||||||
# deleted instance should not be in list anymoer
|
# deleted instance should not be in list anymoer
|
||||||
new_list = instance_types.get_all_types()
|
new_list = instance_types.get_all_types()
|
||||||
self.assertEqual(original_list, new_list)
|
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):
|
def test_get_all_instance_types(self):
|
||||||
"""Ensures that all instance types can be retrieved"""
|
"""Ensures that all instance types can be retrieved"""
|
||||||
session = get_session()
|
session = get_session()
|
||||||
@@ -143,15 +136,15 @@ class InstanceTypeTestCase(test.TestCase):
|
|||||||
"""Ensures that name duplicates raise ApiError"""
|
"""Ensures that name duplicates raise ApiError"""
|
||||||
name = 'some_name'
|
name = 'some_name'
|
||||||
instance_types.create(name, 256, 1, 120, 200, 'flavor1')
|
instance_types.create(name, 256, 1, 120, 200, 'flavor1')
|
||||||
self.assertRaises(exception.ApiError,
|
self.assertRaises(exception.InstanceTypeExists,
|
||||||
instance_types.create,
|
instance_types.create,
|
||||||
name, "256", 1, 120, 200, 'flavor2')
|
name, 256, 1, 120, 200, 'flavor2')
|
||||||
|
|
||||||
def test_duplicate_flavorids_fail(self):
|
def test_duplicate_flavorids_fail(self):
|
||||||
"""Ensures that flavorid duplicates raise ApiError"""
|
"""Ensures that flavorid duplicates raise ApiError"""
|
||||||
flavorid = 'flavor1'
|
flavorid = 'flavor1'
|
||||||
instance_types.create('name one', 256, 1, 120, 200, flavorid)
|
instance_types.create('name one', 256, 1, 120, 200, flavorid)
|
||||||
self.assertRaises(exception.ApiError,
|
self.assertRaises(exception.InstanceTypeExists,
|
||||||
instance_types.create,
|
instance_types.create,
|
||||||
'name two', 256, 1, 120, 200, flavorid)
|
'name two', 256, 1, 120, 200, flavorid)
|
||||||
|
|
||||||
@@ -160,17 +153,6 @@ class InstanceTypeTestCase(test.TestCase):
|
|||||||
self.assertRaises(exception.InstanceTypeNotFoundByName,
|
self.assertRaises(exception.InstanceTypeNotFoundByName,
|
||||||
instance_types.destroy, None)
|
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):
|
def test_will_not_get_bad_default_instance_type(self):
|
||||||
"""ensures error raised on bad default instance type"""
|
"""ensures error raised on bad default instance type"""
|
||||||
FLAGS.default_instance_type = 'unknown_flavor'
|
FLAGS.default_instance_type = 'unknown_flavor'
|
||||||
|
@@ -75,37 +75,6 @@ class VolumeTypeTestCase(test.TestCase):
|
|||||||
new_all_vtypes,
|
new_all_vtypes,
|
||||||
'drive type was not deleted')
|
'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):
|
def test_get_all_volume_types(self):
|
||||||
"""Ensures that all volume types can be retrieved"""
|
"""Ensures that all volume types can be retrieved"""
|
||||||
session = get_session()
|
session = get_session()
|
||||||
@@ -114,26 +83,22 @@ class VolumeTypeTestCase(test.TestCase):
|
|||||||
vol_types = volume_types.get_all_types(self.ctxt)
|
vol_types = volume_types.get_all_types(self.ctxt)
|
||||||
self.assertEqual(total_volume_types, len(vol_types))
|
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"""
|
"""Ensures that volume type creation fails with invalid args"""
|
||||||
self.assertRaises(exception.ApiError,
|
self.assertRaises(exception.ApiError,
|
||||||
volume_types.destroy, self.ctxt, "sfsfsdfdfs")
|
volume_types.destroy, self.ctxt, "sfsfsdfdfs")
|
||||||
|
|
||||||
def test_repeated_vol_types_should_raise_api_error(self):
|
def test_repeated_vol_types_shouldnt_raise(self):
|
||||||
"""Ensures that volume duplicates raises ApiError"""
|
"""Ensures that volume duplicates don't raise"""
|
||||||
new_name = self.vol_type1_name + "dup"
|
new_name = self.vol_type1_name + "dup"
|
||||||
volume_types.create(self.ctxt, new_name)
|
volume_types.create(self.ctxt, new_name)
|
||||||
volume_types.destroy(self.ctxt, new_name)
|
volume_types.destroy(self.ctxt, new_name)
|
||||||
self.assertRaises(
|
volume_types.create(self.ctxt, new_name)
|
||||||
exception.ApiError,
|
|
||||||
volume_types.create, self.ctxt, new_name)
|
|
||||||
|
|
||||||
def test_invalid_volume_types_params(self):
|
def test_invalid_volume_types_params(self):
|
||||||
"""Ensures that volume type creation fails with invalid args"""
|
"""Ensures that volume type creation fails with invalid args"""
|
||||||
self.assertRaises(exception.InvalidVolumeType,
|
self.assertRaises(exception.InvalidVolumeType,
|
||||||
volume_types.destroy, self.ctxt, None)
|
volume_types.destroy, self.ctxt, None)
|
||||||
self.assertRaises(exception.InvalidVolumeType,
|
|
||||||
volume_types.purge, self.ctxt, None)
|
|
||||||
self.assertRaises(exception.InvalidVolumeType,
|
self.assertRaises(exception.InvalidVolumeType,
|
||||||
volume_types.get_volume_type, self.ctxt, None)
|
volume_types.get_volume_type, self.ctxt, None)
|
||||||
self.assertRaises(exception.InvalidVolumeType,
|
self.assertRaises(exception.InvalidVolumeType,
|
||||||
|
@@ -43,11 +43,11 @@ class VolumeTypeExtraSpecsTestCase(test.TestCase):
|
|||||||
self.vol_type2_id = ref.id
|
self.vol_type2_id = ref.id
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
# Remove the instance type from the database
|
# Remove the volume type from the database
|
||||||
db.volume_type_purge(context.get_admin_context(),
|
db.volume_type_destroy(context.get_admin_context(),
|
||||||
self.vol_type1['name'])
|
self.vol_type1['name'])
|
||||||
db.volume_type_purge(context.get_admin_context(),
|
db.volume_type_destroy(context.get_admin_context(),
|
||||||
self.vol_type2_noextra['name'])
|
self.vol_type2_noextra['name'])
|
||||||
super(VolumeTypeExtraSpecsTestCase, self).tearDown()
|
super(VolumeTypeExtraSpecsTestCase, self).tearDown()
|
||||||
|
|
||||||
def test_volume_type_specs_get(self):
|
def test_volume_type_specs_get(self):
|
||||||
|
Reference in New Issue
Block a user