diff options
author | Jenkins <jenkins@review.openstack.org> | 2016-07-13 00:34:28 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2016-07-13 00:34:29 +0000 |
commit | 8a276a4483cf5f0cfce2ab3f4484289a910902f7 (patch) | |
tree | 670c17ad7f4947e698de4fbf643f044f1e20e375 /contrib | |
parent | bcdf7a049fd374e0a5d9ed0b16285daa61ac56e1 (diff) | |
parent | d8fefed1773133bbdf58a3392bafbc12f82e4fe2 (diff) | |
download | heat-8a276a4483cf5f0cfce2ab3f4484289a910902f7.tar.gz |
Merge "Fix Cloud Server image/flavor combination validation"
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/rackspace/rackspace/resources/cloud_server.py | 23 | ||||
-rw-r--r-- | contrib/rackspace/rackspace/tests/test_rackspace_cloud_server.py | 60 |
2 files changed, 78 insertions, 5 deletions
diff --git a/contrib/rackspace/rackspace/resources/cloud_server.py b/contrib/rackspace/rackspace/resources/cloud_server.py index 4583008d0..710a5835e 100644 --- a/contrib/rackspace/rackspace/resources/cloud_server.py +++ b/contrib/rackspace/rackspace/resources/cloud_server.py @@ -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) diff --git a/contrib/rackspace/rackspace/tests/test_rackspace_cloud_server.py b/contrib/rackspace/rackspace/tests/test_rackspace_cloud_server.py index 5cb1bb855..941b1f6f0 100644 --- a/contrib/rackspace/rackspace/tests/test_rackspace_cloud_server.py +++ b/contrib/rackspace/rackspace/tests/test_rackspace_cloud_server.py @@ -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()) |