Add AggregateTypeAffinityFilter multi values support
This change allows the AggregateTypeAffinityFilter to function when multiple instance_type names are set in the Aggregate Metadata. This change implements and documents a new comma separated syntax for the aggregate instance_type metadata attribute. The legacy syntax is still supported when a single instace_type is specified. e.g. 'm1.nano' or "m1.nano,m1.small" DocImpact Change-Id: I0618a300754d012db62df52faa12cc3cedfe2b65 Closes-bug: #1399204
This commit is contained in:
parent
2a44b67dbb
commit
66e1427f14
|
@ -142,6 +142,11 @@ There are some standard filter classes to use (:mod:`nova.scheduler.filters`):
|
|||
* |TypeAffinityFilter| - Only passes hosts that are not already running an
|
||||
instance of the requested type.
|
||||
* |AggregateTypeAffinityFilter| - limits instance_type by aggregate.
|
||||
This filter passes hosts if no instance_type key is set or
|
||||
the instance_type aggregate metadata value contains the name of the
|
||||
instance_type requested. The value of the instance_type metadata entry is
|
||||
a string that may contain either a single instance_type name or a comma
|
||||
separated list of instance_type names. e.g. 'm1.nano' or "m1.nano,m1.small"
|
||||
* |ServerGroupAntiAffinityFilter| - This filter implements anti-affinity for a
|
||||
server group. First you must create a server group with a policy of
|
||||
'anti-affinity' via the server groups API. Then, when you boot a new server,
|
||||
|
|
|
@ -54,6 +54,8 @@ class AggregateTypeAffinityFilter(filters.BaseHostFilter):
|
|||
aggregate_vals = utils.aggregate_values_from_key(
|
||||
host_state, 'instance_type')
|
||||
|
||||
if not aggregate_vals:
|
||||
return True
|
||||
return instance_type['name'] in aggregate_vals
|
||||
for val in aggregate_vals:
|
||||
if (instance_type['name'] in
|
||||
[x.strip() for x in val.split(',')]):
|
||||
return True
|
||||
return not aggregate_vals
|
||||
|
|
|
@ -42,17 +42,80 @@ class TestTypeFilter(test.NoDBTestCase):
|
|||
self.assertFalse(self.filt_cls.host_passes(host, filter_properties))
|
||||
|
||||
@mock.patch('nova.scheduler.filters.utils.aggregate_values_from_key')
|
||||
def test_aggregate_type_filter(self, agg_mock):
|
||||
def test_aggregate_type_filter_no_metadata(self, agg_mock):
|
||||
self.filt_cls = type_filter.AggregateTypeAffinityFilter()
|
||||
|
||||
filter_properties = {'context': mock.sentinel.ctx,
|
||||
'instance_type': {'name': 'fake1'}}
|
||||
host = fakes.FakeHostState('fake_host', 'fake_node', {})
|
||||
|
||||
# tests when no instance_type is defined for aggregate
|
||||
agg_mock.return_value = set([])
|
||||
# True as no instance_type set for aggregate
|
||||
self.assertTrue(self.filt_cls.host_passes(host, filter_properties))
|
||||
agg_mock.assert_called_once_with(host, 'instance_type')
|
||||
|
||||
@mock.patch('nova.scheduler.filters.utils.aggregate_values_from_key')
|
||||
def test_aggregate_type_filter_single_instance_type(self, agg_mock):
|
||||
self.filt_cls = type_filter.AggregateTypeAffinityFilter()
|
||||
|
||||
filter_properties = {'context': mock.sentinel.ctx,
|
||||
'instance_type': {'name': 'fake1'}}
|
||||
filter2_properties = {'context': mock.sentinel.ctx,
|
||||
'instance_type': {'name': 'fake2'}}
|
||||
'instance_type': {'name': 'fake2'}}
|
||||
host = fakes.FakeHostState('fake_host', 'fake_node', {})
|
||||
|
||||
# tests when a single instance_type is defined for an aggregate
|
||||
# using legacy single value syntax
|
||||
agg_mock.return_value = set(['fake1'])
|
||||
# True since no aggregates
|
||||
|
||||
# True as instance_type is allowed for aggregate
|
||||
self.assertTrue(self.filt_cls.host_passes(host, filter_properties))
|
||||
agg_mock.assert_called_once_with(host, 'instance_type')
|
||||
# False since type matches aggregate, metadata
|
||||
|
||||
# False as instance_type is not allowed for aggregate
|
||||
self.assertFalse(self.filt_cls.host_passes(host, filter2_properties))
|
||||
|
||||
@mock.patch('nova.scheduler.filters.utils.aggregate_values_from_key')
|
||||
def test_aggregate_type_filter_multi_aggregate(self, agg_mock):
|
||||
self.filt_cls = type_filter.AggregateTypeAffinityFilter()
|
||||
|
||||
filter_properties = {'context': mock.sentinel.ctx,
|
||||
'instance_type': {'name': 'fake1'}}
|
||||
filter2_properties = {'context': mock.sentinel.ctx,
|
||||
'instance_type': {'name': 'fake2'}}
|
||||
filter3_properties = {'context': mock.sentinel.ctx,
|
||||
'instance_type': {'name': 'fake3'}}
|
||||
host = fakes.FakeHostState('fake_host', 'fake_node', {})
|
||||
|
||||
# tests when a single instance_type is defined for multiple aggregates
|
||||
# using legacy single value syntax
|
||||
agg_mock.return_value = set(['fake1', 'fake2'])
|
||||
|
||||
# True as instance_type is allowed for first aggregate
|
||||
self.assertTrue(self.filt_cls.host_passes(host, filter_properties))
|
||||
# True as instance_type is allowed for second aggregate
|
||||
self.assertTrue(self.filt_cls.host_passes(host, filter2_properties))
|
||||
# False as instance_type is not allowed for aggregates
|
||||
self.assertFalse(self.filt_cls.host_passes(host, filter3_properties))
|
||||
|
||||
@mock.patch('nova.scheduler.filters.utils.aggregate_values_from_key')
|
||||
def test_aggregate_type_filter_multi_instance_type(self, agg_mock):
|
||||
self.filt_cls = type_filter.AggregateTypeAffinityFilter()
|
||||
|
||||
filter_properties = {'context': mock.sentinel.ctx,
|
||||
'instance_type': {'name': 'fake1'}}
|
||||
filter2_properties = {'context': mock.sentinel.ctx,
|
||||
'instance_type': {'name': 'fake2'}}
|
||||
filter3_properties = {'context': mock.sentinel.ctx,
|
||||
'instance_type': {'name': 'fake3'}}
|
||||
host = fakes.FakeHostState('fake_host', 'fake_node', {})
|
||||
|
||||
# tests when multiple instance_types are defined for aggregate
|
||||
agg_mock.return_value = set(['fake1,fake2'])
|
||||
|
||||
# True as instance_type is allowed for aggregate
|
||||
self.assertTrue(self.filt_cls.host_passes(host, filter_properties))
|
||||
# True as instance_type is allowed for aggregate
|
||||
self.assertTrue(self.filt_cls.host_passes(host, filter2_properties))
|
||||
# False as instance_type is not allowed for aggregate
|
||||
self.assertFalse(self.filt_cls.host_passes(host, filter3_properties))
|
||||
|
|
Loading…
Reference in New Issue