Merge "Fix Cloud Server image/flavor combination validation"

This commit is contained in:
Jenkins 2016-07-13 00:34:28 +00:00 committed by Gerrit Code Review
commit 8a276a4483
2 changed files with 78 additions and 5 deletions

View File

@ -68,6 +68,7 @@ class CloudServer(server.Server):
'general1', 'memory1', 'performance2', 'performance1',
'standard1', 'io1', 'onmetal', 'compute1',
)
BASE_IMAGE_REF = 'base_image_ref'
# flavor classes that can be booted ONLY from volume
BFV_VOLUME_REQUIRED = {MEMORY1, COMPUTE1}
@ -239,8 +240,22 @@ class CloudServer(server.Server):
return self._extend_networks(nets)
def _image_flavor_class_match(self, flavor_type, image_obj):
flavor_class_string = image_obj.get(self.FLAVOR_CLASSES_KEY, '')
def _base_image_obj(self, image):
image_obj = self.client_plugin('glance').get_image(image)
if self.BASE_IMAGE_REF in image_obj:
base_image = image_obj[self.BASE_IMAGE_REF]
return self.client_plugin('glance').get_image(base_image)
return image_obj
def _image_flavor_class_match(self, flavor_type, image):
base_image_obj = self._base_image_obj(image)
flavor_class_string = base_image_obj.get(self.FLAVOR_CLASSES_KEY)
# If the flavor_class_string metadata does not exist or is
# empty, do not validate image/flavor combo
if not flavor_class_string:
return True
flavor_class_excluded = "!{0}".format(flavor_type)
flavor_classes_accepted = flavor_class_string.split(',')
@ -273,9 +288,7 @@ class CloudServer(server.Server):
# is all the validation possible
return
image_obj = self.client_plugin('glance').get_image(image)
if not self._image_flavor_class_match(flavor_type, image_obj):
if not self._image_flavor_class_match(flavor_type, image):
msg = _('Flavor %(flavor)s cannot be used with image '
'%(image)s.') % {'image': image, 'flavor': flavor}
raise exception.StackValidationFailed(message=msg)

View File

@ -545,6 +545,7 @@ class CloudServersValidationTests(common.HeatTestCase):
mock_image = mock.Mock(status='ACTIVE', min_ram=2, min_disk=1)
mock_image.get.return_value = "memory1"
mock_image.__iter__ = mock.Mock(return_value=iter([]))
mock_plugin().get_flavor.return_value = mock_flavor
mock_plugin().get_image.return_value = mock_image
@ -564,6 +565,7 @@ class CloudServersValidationTests(common.HeatTestCase):
mock_image = mock.Mock(status='ACTIVE', min_ram=2, min_disk=1)
mock_image.get.return_value = "!standard1, *"
mock_image.__iter__ = mock.Mock(return_value=iter([]))
mock_flavor = mock.Mock(ram=4, disk=4)
mock_flavor.to_dict.return_value = {
@ -588,6 +590,7 @@ class CloudServersValidationTests(common.HeatTestCase):
mock_image = mock.Mock(size=1, status='ACTIVE', min_ram=2, min_disk=2)
mock_image.get.return_value = "standard1"
mock_image.__iter__ = mock.Mock(return_value=iter([]))
mock_flavor = mock.Mock(ram=4, disk=4)
mock_flavor.to_dict.return_value = {
@ -601,3 +604,60 @@ class CloudServersValidationTests(common.HeatTestCase):
mock_plugin().get_image.return_value = mock_image
self.assertIsNone(server.validate())
def test_validate_image_flavor_empty_metadata(self, mock_client,
mock_plugin):
server = cloud_server.CloudServer("test", self.rsrcdef, self.mockstack)
mock_image = mock.Mock(size=1, status='ACTIVE', min_ram=2, min_disk=2)
mock_image.get.return_value = ""
mock_image.__iter__ = mock.Mock(return_value=iter([]))
mock_flavor = mock.Mock(ram=4, disk=4)
mock_flavor.to_dict.return_value = {
'OS-FLV-WITH-EXT-SPECS:extra_specs': {
'flavor_classes': '',
},
}
mock_plugin().get_flavor.return_value = mock_flavor
mock_plugin().get_image.return_value = mock_image
self.assertIsNone(server.validate())
def test_validate_image_flavor_no_metadata(self, mock_client, mock_plugin):
server = cloud_server.CloudServer("test", self.rsrcdef, self.mockstack)
mock_image = mock.Mock(size=1, status='ACTIVE', min_ram=2, min_disk=2)
mock_image.get.return_value = None
mock_image.__iter__ = mock.Mock(return_value=iter([]))
mock_flavor = mock.Mock(ram=4, disk=4)
mock_flavor.to_dict.return_value = {}
mock_plugin().get_flavor.return_value = mock_flavor
mock_plugin().get_image.return_value = mock_image
self.assertIsNone(server.validate())
def test_validate_image_flavor_not_base(self, mock_client, mock_plugin):
server = cloud_server.CloudServer("test", self.rsrcdef, self.mockstack)
mock_image = mock.Mock(size=1, status='ACTIVE', min_ram=2, min_disk=2)
mock_image.get.return_value = None
mock_image.__iter__ = mock.Mock(return_value=iter(
['base_image_ref']))
mock_image.__getitem__ = mock.Mock(return_value='1234')
mock_base_image = mock.Mock(size=1, status='ACTIVE', min_ram=2,
min_disk=2)
mock_base_image.get.return_value = None
mock_base_image.__iter__ = mock.Mock(return_value=iter([]))
mock_flavor = mock.Mock(ram=4, disk=4)
mock_flavor.to_dict.return_value = {}
mock_plugin().get_flavor.return_value = mock_flavor
mock_plugin().get_image.side_effect = [mock_image, mock_base_image]
self.assertIsNone(server.validate())