diff --git a/doc/source/devref/filter_scheduler.rst b/doc/source/devref/filter_scheduler.rst index fa85e53a8fbe..933b152e1a0a 100644 --- a/doc/source/devref/filter_scheduler.rst +++ b/doc/source/devref/filter_scheduler.rst @@ -67,7 +67,8 @@ There are some standard filter classes to use (:mod:`nova.scheduler.filters`): * |AggregateInstanceExtraSpecsFilter| - checks that the aggregate metadata satisfies any extra specifications associated with the instance type (that - have no scope). It passes hosts that can create the specified instance type. + have no scope or are scoped with 'aggregate_instance_extra_specs'). + It passes hosts that can create the specified instance type. The extra specifications can have the same operators as |ComputeCapabilitiesFilter|. * |ComputeFilter| - passes all hosts that are operational and enabled. diff --git a/nova/scheduler/filters/aggregate_instance_extra_specs.py b/nova/scheduler/filters/aggregate_instance_extra_specs.py index 6888d29377ee..5dfc42dd6222 100644 --- a/nova/scheduler/filters/aggregate_instance_extra_specs.py +++ b/nova/scheduler/filters/aggregate_instance_extra_specs.py @@ -22,6 +22,8 @@ from nova.scheduler.filters import extra_specs_ops LOG = logging.getLogger(__name__) +_SCOPE = 'aggregate_instance_extra_specs' + class AggregateInstanceExtraSpecsFilter(filters.BaseHostFilter): """AggregateInstanceExtraSpecsFilter works with InstanceType records.""" @@ -43,10 +45,14 @@ class AggregateInstanceExtraSpecsFilter(filters.BaseHostFilter): metadata = db.aggregate_metadata_get_by_host(context, host_state.host) for key, req in instance_type['extra_specs'].iteritems(): - # NOTE(jogo) any key containing a scope (scope is terminated - # by a `:') will be ignored by this filter. (bug 1039386) - if key.count(':'): - continue + # Either not scope format, or aggregate_instance_extra_specs scope + scope = key.split(':', 1) + if len(scope) > 1: + if scope[0] != _SCOPE: + continue + else: + del scope[0] + key = scope[0] aggregate_vals = metadata.get(key, None) if not aggregate_vals: LOG.debug(_("%(host_state)s fails instance_type extra_specs " diff --git a/nova/tests/scheduler/test_host_filters.py b/nova/tests/scheduler/test_host_filters.py index 3e5b0c9b6389..93cd28d20975 100644 --- a/nova/tests/scheduler/test_host_filters.py +++ b/nova/tests/scheduler/test_host_filters.py @@ -860,11 +860,26 @@ class HostFiltersTestCase(test.NoDBTestCase): self.assertFalse(filt_cls.host_passes(host, filter_properties)) def test_aggregate_filter_passes_extra_specs_simple(self): + especs = { + # Un-scoped extra spec + 'opt1': '1', + # Scoped extra spec that applies to this filter + 'aggregate_instance_extra_specs:opt2': '2', + # Scoped extra spec that does not apply to this filter + 'trust:trusted_host': 'true', + } self._do_test_aggregate_filter_extra_specs( - emeta={'opt1': '1', 'opt2': '2'}, - especs={'opt1': '1', 'opt2': '2', - 'trust:trusted_host': 'true'}, - passes=True) + emeta={'opt1': '1', 'opt2': '2'}, especs=especs, passes=True) + + def test_aggregate_filter_passes_with_key_same_as_scope(self): + especs = { + # Un-scoped extra spec, make sure we don't blow up if it + # happens to match our scope. + 'aggregate_instance_extra_specs': '1', + } + self._do_test_aggregate_filter_extra_specs( + emeta={'aggregate_instance_extra_specs': '1'}, + especs=especs, passes=True) def test_aggregate_filter_fails_extra_specs_simple(self): self._do_test_aggregate_filter_extra_specs(