diff --git a/nova/scheduler/filters/aggregate_image_properties_isolation.py b/nova/scheduler/filters/aggregate_image_properties_isolation.py index bf83c6b50..461f91206 100644 --- a/nova/scheduler/filters/aggregate_image_properties_isolation.py +++ b/nova/scheduler/filters/aggregate_image_properties_isolation.py @@ -17,6 +17,7 @@ from oslo_log import log as logging import six import nova.conf +from nova.i18n import _LW from nova.scheduler import filters from nova.scheduler.filters import utils @@ -45,7 +46,15 @@ class AggregateImagePropertiesIsolation(filters.BaseHostFilter): if (cfg_namespace and not key.startswith(cfg_namespace + cfg_separator)): continue - prop = image_props.get(key) + prop = None + try: + prop = image_props.get(key) + except AttributeError: + LOG.warning(_LW("Host '%(host)s' has a metadata key '%(key)s' " + "that is not present in the image metadata.") % + {"host": host_state.host, "key": key}) + continue + # NOTE(sbauza): Aggregate metadata is only strings, we need to # stringify the property to match with the option # TODO(sbauza): Fix that very ugly pattern matching diff --git a/nova/tests/unit/scheduler/filters/test_aggregate_image_properties_isolation_filters.py b/nova/tests/unit/scheduler/filters/test_aggregate_image_properties_isolation_filters.py index 025de7795..1a7ad672a 100644 --- a/nova/tests/unit/scheduler/filters/test_aggregate_image_properties_isolation_filters.py +++ b/nova/tests/unit/scheduler/filters/test_aggregate_image_properties_isolation_filters.py @@ -103,3 +103,33 @@ class TestAggImagePropsIsolationFilter(test.NoDBTestCase): hw_vm_mode='hvm', img_owner_id='wrong'))) host = fakes.FakeHostState('host1', 'compute', {}) self.assertTrue(self.filt_cls.host_passes(host, spec_obj)) + + def test_aggregate_image_properties_iso_props_with_custom_meta(self, + agg_mock): + agg_mock.return_value = {'os': 'linux'} + spec_obj = objects.RequestSpec( + context=mock.sentinel.ctx, + image=objects.ImageMeta(properties=objects.ImageMetaProps( + os_type='linux'))) + host = fakes.FakeHostState('host1', 'compute', {}) + self.assertTrue(self.filt_cls.host_passes(host, spec_obj)) + + def test_aggregate_image_properties_iso_props_with_matching_meta_pass(self, + agg_mock): + agg_mock.return_value = {'os_type': 'linux'} + spec_obj = objects.RequestSpec( + context=mock.sentinel.ctx, + image=objects.ImageMeta(properties=objects.ImageMetaProps( + os_type='linux'))) + host = fakes.FakeHostState('host1', 'compute', {}) + self.assertTrue(self.filt_cls.host_passes(host, spec_obj)) + + def test_aggregate_image_properties_iso_props_with_matching_meta_fail( + self, agg_mock): + agg_mock.return_value = {'os_type': 'windows'} + spec_obj = objects.RequestSpec( + context=mock.sentinel.ctx, + image=objects.ImageMeta(properties=objects.ImageMetaProps( + os_type='linux'))) + host = fakes.FakeHostState('host1', 'compute', {}) + self.assertFalse(self.filt_cls.host_passes(host, spec_obj))