Add new style instance group scheduler filters

Prior to Icehouse, there was a different type of handling of the
'group' scheduler hint that got lost in the completion of the server
groups API.  This patch completes the code necessary to provide
backwards compatibility with the old behavior.

Previously, the policy for groups was simply based on what scheduler
filters you had enabled.  You could have either the affinity or
anti-affinity filter enabled and that would be applied to all groups.
These filters now act on groups with a policy type of 'legacy'.

New filters have been added that can be enabled simultaneously and act
based on the policy set on the group via the server group API.

DocImpact

Change-Id: Ia65c151396415ca48725cb3c756f33efa01d2fe5
Closes-bug: #1296913
This commit is contained in:
Russell Bryant 2014-03-27 20:40:23 +00:00
parent ea6d8403bd
commit 2bca0c9011
3 changed files with 91 additions and 19 deletions

View File

@ -119,10 +119,20 @@ 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.
* |GroupAntiAffinityFilter| - ensures that each instance in group is on a
different host.
* |GroupAffinityFilter| - ensures that each instance in group is on a same
host with one of the instance host in a group.
* |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,
provide a scheduler hint of 'group=<uuid>' where <uuid> is the UUID of the
server group you created. This will result in the server getting added to the
group. When the server gets scheduled, anti-affinity will be enforced among
all servers in that group.
* |ServerGroupAffinityFilter| - This filter works the same way as
ServerGroupAffinityFilter. The difference is that when you create the server
group, you should specify a policy of 'affinity'.
* |GroupAntiAffinityFilter| - This filter is deprecated in favor of
ServerGroupAntiAffinityFilter.
* |GroupAffinityFilter| - This filter is deprecated in favor of
ServerGroupAffinityFilter.
* |AggregateMultiTenancyIsolation| - isolate tenants in specific aggregates.
* |AggregateImagePropertiesIsolation| - isolates hosts based on image
properties and aggregate metadata.

View File

@ -99,15 +99,18 @@ class SimpleCIDRAffinityFilter(AffinityFilter):
return True
class GroupAntiAffinityFilter(AffinityFilter):
class _GroupAntiAffinityFilter(AffinityFilter):
"""Schedule the instance on a different host from a set of group
hosts.
"""
def __init__(self):
super(_GroupAntiAffinityFilter, self).__init__()
def host_passes(self, host_state, filter_properties):
# Only invoke the filter is 'anti-affinity' is configured
policies = filter_properties.get('group_policies', [])
if 'anti-affinity' not in policies:
if self.policy_name not in policies:
return True
group_hosts = filter_properties.get('group_hosts') or []
@ -121,14 +124,29 @@ class GroupAntiAffinityFilter(AffinityFilter):
return True
class GroupAffinityFilter(AffinityFilter):
class GroupAntiAffinityFilter(_GroupAntiAffinityFilter):
def __init__(self):
self.policy_name = 'legacy'
super(GroupAntiAffinityFilter, self).__init__()
class ServerGroupAntiAffinityFilter(_GroupAntiAffinityFilter):
def __init__(self):
self.policy_name = 'anti-affinity'
super(ServerGroupAntiAffinityFilter, self).__init__()
class _GroupAffinityFilter(AffinityFilter):
"""Schedule the instance on to host from a set of group hosts.
"""
def __init__(self):
super(_GroupAffinityFilter, self).__init__()
def host_passes(self, host_state, filter_properties):
# Only invoke the filter is 'affinity' is configured
policies = filter_properties.get('group_policies', [])
if 'affinity' not in policies:
if self.policy_name not in policies:
return True
group_hosts = filter_properties.get('group_hosts', [])
@ -140,3 +158,15 @@ class GroupAffinityFilter(AffinityFilter):
# No groups configured
return True
class GroupAffinityFilter(_GroupAffinityFilter):
def __init__(self):
self.policy_name = 'legacy'
super(GroupAffinityFilter, self).__init__()
class ServerGroupAffinityFilter(_GroupAffinityFilter):
def __init__(self):
self.policy_name = 'affinity'
super(ServerGroupAffinityFilter, self).__init__()

View File

@ -1555,28 +1555,44 @@ class HostFiltersTestCase(test.NoDBTestCase):
filter_properties = {}
self.assertFalse(filt_cls.host_passes(host, filter_properties))
def test_group_anti_affinity_filter_passes(self):
filt_cls = self.class_map['GroupAntiAffinityFilter']()
def _test_group_anti_affinity_filter_passes(self, cls, policy):
filt_cls = self.class_map[cls]()
host = fakes.FakeHostState('host1', 'node1', {})
filter_properties = {}
self.assertTrue(filt_cls.host_passes(host, filter_properties))
filter_properties = {'group_policies': ['affinity']}
self.assertTrue(filt_cls.host_passes(host, filter_properties))
filter_properties = {'group_policies': ['anti-affinity']}
filter_properties = {'group_policies': [policy]}
filter_properties['group_hosts'] = []
self.assertTrue(filt_cls.host_passes(host, filter_properties))
filter_properties['group_hosts'] = ['host2']
self.assertTrue(filt_cls.host_passes(host, filter_properties))
def test_group_anti_affinity_filter_fails(self):
filt_cls = self.class_map['GroupAntiAffinityFilter']()
def test_group_anti_affinity_filter_passes(self):
self._test_group_anti_affinity_filter_passes(
'ServerGroupAntiAffinityFilter', 'anti-affinity')
def test_group_anti_affinity_filter_passes_legacy(self):
self._test_group_anti_affinity_filter_passes(
'GroupAntiAffinityFilter', 'legacy')
def _test_group_anti_affinity_filter_fails(self, cls, policy):
filt_cls = self.class_map[cls]()
host = fakes.FakeHostState('host1', 'node1', {})
filter_properties = {'group_policies': ['anti-affinity'],
filter_properties = {'group_policies': [policy],
'group_hosts': ['host1']}
self.assertFalse(filt_cls.host_passes(host, filter_properties))
def test_group_affinity_filter_passes(self):
filt_cls = self.class_map['GroupAffinityFilter']()
def test_group_anti_affinity_filter_fails(self):
self._test_group_anti_affinity_filter_fails(
'ServerGroupAntiAffinityFilter', 'anti-affinity')
def test_group_anti_affinity_filter_fails_legacy(self):
self._test_group_anti_affinity_filter_fails(
'GroupAntiAffinityFilter', 'legacy')
def _test_group_affinity_filter_passes(self, cls, policy):
filt_cls = self.class_map['ServerGroupAffinityFilter']()
host = fakes.FakeHostState('host1', 'node1', {})
filter_properties = {}
self.assertTrue(filt_cls.host_passes(host, filter_properties))
@ -1586,13 +1602,29 @@ class HostFiltersTestCase(test.NoDBTestCase):
'group_hosts': ['host1']}
self.assertTrue(filt_cls.host_passes(host, filter_properties))
def test_group_affinity_filter_fails(self):
filt_cls = self.class_map['GroupAffinityFilter']()
def test_group_affinity_filter_passes(self):
self._test_group_affinity_filter_passes(
'ServerGroupAffinityFilter', 'affinity')
def test_group_affinity_filter_passes_legacy(self):
self._test_group_affinity_filter_passes(
'GroupAffinityFilter', 'legacy')
def _test_group_affinity_filter_fails(self, cls, policy):
filt_cls = self.class_map[cls]()
host = fakes.FakeHostState('host1', 'node1', {})
filter_properties = {'group_policies': ['affinity'],
filter_properties = {'group_policies': [policy],
'group_hosts': ['host2']}
self.assertFalse(filt_cls.host_passes(host, filter_properties))
def test_group_affinity_filter_fails(self):
self._test_group_affinity_filter_fails(
'ServerGroupAffinityFilter', 'affinity')
def test_group_affinity_filter_fails_legacy(self):
self._test_group_affinity_filter_fails(
'GroupAffinityFilter', 'legacy')
def test_aggregate_multi_tenancy_isolation_with_meta_passes(self):
self._stub_service_is_up(True)
filt_cls = self.class_map['AggregateMultiTenancyIsolation']()