get rid of all mention of drivers ... it's filter only now
This commit is contained in:
@@ -465,9 +465,8 @@ class ZoneNotFound(NotFound):
|
|||||||
message = _("Zone %(zone_id)s could not be found.")
|
message = _("Zone %(zone_id)s could not be found.")
|
||||||
|
|
||||||
|
|
||||||
class SchedulerHostFilterDriverNotFound(NotFound):
|
class SchedulerHostFilterNotFound(NotFound):
|
||||||
message = _("Scheduler Host Filter Driver %(driver_name)s could"
|
message = _("Scheduler Host Filter %(filter_name)s could not be found.")
|
||||||
" not be found.")
|
|
||||||
|
|
||||||
|
|
||||||
class InstanceMetadataNotFound(NotFound):
|
class InstanceMetadataNotFound(NotFound):
|
||||||
|
|||||||
@@ -14,8 +14,8 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Host Filter is a driver mechanism for requesting instance resources.
|
Host Filter is a mechanism for requesting instance resources.
|
||||||
Three drivers are included: AllHosts, Flavor & JSON. AllHosts just
|
Three filters are included: AllHosts, Flavor & JSON. AllHosts just
|
||||||
returns the full, unfiltered list of hosts. Flavor is a hard coded
|
returns the full, unfiltered list of hosts. Flavor is a hard coded
|
||||||
matching mechanism based on flavor criteria and JSON is an ad-hoc
|
matching mechanism based on flavor criteria and JSON is an ad-hoc
|
||||||
filter grammar.
|
filter grammar.
|
||||||
@@ -47,13 +47,13 @@ from nova.scheduler import zone_aware_scheduler
|
|||||||
LOG = logging.getLogger('nova.scheduler.host_filter')
|
LOG = logging.getLogger('nova.scheduler.host_filter')
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
flags.DEFINE_string('default_host_filter_driver',
|
flags.DEFINE_string('default_host_filter',
|
||||||
'nova.scheduler.host_filter.AllHostsFilter',
|
'nova.scheduler.host_filter.AllHostsFilter',
|
||||||
'Which driver to use for filtering hosts.')
|
'Which filter to use for filtering hosts.')
|
||||||
|
|
||||||
|
|
||||||
class HostFilter(object):
|
class HostFilter(object):
|
||||||
"""Base class for host filter drivers."""
|
"""Base class for host filters."""
|
||||||
|
|
||||||
def instance_type_to_filter(self, instance_type):
|
def instance_type_to_filter(self, instance_type):
|
||||||
"""Convert instance_type into a filter for most common use-case."""
|
"""Convert instance_type into a filter for most common use-case."""
|
||||||
@@ -64,12 +64,12 @@ class HostFilter(object):
|
|||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def _full_name(self):
|
def _full_name(self):
|
||||||
"""module.classname of the filter driver"""
|
"""module.classname of the filter."""
|
||||||
return "%s.%s" % (self.__module__, self.__class__.__name__)
|
return "%s.%s" % (self.__module__, self.__class__.__name__)
|
||||||
|
|
||||||
|
|
||||||
class AllHostsFilter(HostFilter):
|
class AllHostsFilter(HostFilter):
|
||||||
"""NOP host filter driver. Returns all hosts in ZoneManager.
|
"""NOP host filter. Returns all hosts in ZoneManager.
|
||||||
This essentially does what the old Scheduler+Chance used
|
This essentially does what the old Scheduler+Chance used
|
||||||
to give us."""
|
to give us."""
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ class AllHostsFilter(HostFilter):
|
|||||||
|
|
||||||
|
|
||||||
class InstanceTypeFilter(HostFilter):
|
class InstanceTypeFilter(HostFilter):
|
||||||
"""HostFilter driver hard-coded to work with InstanceType records."""
|
"""HostFilter hard-coded to work with InstanceType records."""
|
||||||
|
|
||||||
def instance_type_to_filter(self, instance_type):
|
def instance_type_to_filter(self, instance_type):
|
||||||
"""Use instance_type to filter hosts."""
|
"""Use instance_type to filter hosts."""
|
||||||
@@ -133,7 +133,7 @@ class InstanceTypeFilter(HostFilter):
|
|||||||
|
|
||||||
|
|
||||||
class JsonFilter(HostFilter):
|
class JsonFilter(HostFilter):
|
||||||
"""Host Filter driver to allow simple JSON-based grammar for
|
"""Host Filter to allow simple JSON-based grammar for
|
||||||
selecting hosts."""
|
selecting hosts."""
|
||||||
|
|
||||||
def _equals(self, args):
|
def _equals(self, args):
|
||||||
@@ -273,43 +273,44 @@ class JsonFilter(HostFilter):
|
|||||||
return hosts
|
return hosts
|
||||||
|
|
||||||
|
|
||||||
DRIVERS = [AllHostsFilter, InstanceTypeFilter, JsonFilter]
|
FILTERS = [AllHostsFilter, InstanceTypeFilter, JsonFilter]
|
||||||
|
|
||||||
|
|
||||||
def choose_driver(driver_name=None):
|
def choose_host_filter(filter_name=None):
|
||||||
"""Since the caller may specify which driver to use we need
|
"""Since the caller may specify which filter to use we need
|
||||||
to have an authoritative list of what is permissible. This
|
to have an authoritative list of what is permissible. This
|
||||||
function checks the driver name against a predefined set
|
function checks the filter name against a predefined set
|
||||||
of acceptable drivers."""
|
of acceptable filters."""
|
||||||
|
|
||||||
if not driver_name:
|
if not filter_name:
|
||||||
driver_name = FLAGS.default_host_filter_driver
|
filter_name = FLAGS.default_host_filter
|
||||||
for driver in DRIVERS:
|
for filter_class in FILTERS:
|
||||||
if "%s.%s" % (driver.__module__, driver.__name__) == driver_name:
|
if "%s.%s" % (filter_class.__module__, filter_class.__name__) == \
|
||||||
return driver()
|
filter_name:
|
||||||
raise exception.SchedulerHostFilterDriverNotFound(driver_name=driver_name)
|
return filter_class()
|
||||||
|
raise exception.SchedulerHostFilterNotFound(filter_name=filter_name)
|
||||||
|
|
||||||
|
|
||||||
class HostFilterScheduler(zone_aware_scheduler.ZoneAwareScheduler):
|
class HostFilterScheduler(zone_aware_scheduler.ZoneAwareScheduler):
|
||||||
"""The HostFilterScheduler uses the HostFilter drivers to filter
|
"""The HostFilterScheduler uses the HostFilter to filter
|
||||||
hosts for weighing. The particular driver used may be passed in
|
hosts for weighing. The particular filter used may be passed in
|
||||||
as an argument or the default will be used.
|
as an argument or the default will be used.
|
||||||
|
|
||||||
request_spec = {'filter_driver': <Filter Driver name>,
|
request_spec = {'filter_name': <Filter name>,
|
||||||
'instance_type': <InstanceType dict>}
|
'instance_type': <InstanceType dict>}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def filter_hosts(self, num, request_spec):
|
def filter_hosts(self, num, request_spec):
|
||||||
"""Filter the full host list (from the ZoneManager)"""
|
"""Filter the full host list (from the ZoneManager)"""
|
||||||
driver_name = request_spec.get('filter_driver', None)
|
filter_name = request_spec.get('filter_name', None)
|
||||||
driver = choose_driver(driver_name)
|
host_filter = choose_host_filter(filter_name)
|
||||||
|
|
||||||
# TODO(sandy): We're only using InstanceType-based specs
|
# TODO(sandy): We're only using InstanceType-based specs
|
||||||
# currently. Later we'll need to snoop for more detailed
|
# currently. Later we'll need to snoop for more detailed
|
||||||
# host filter requests.
|
# host filter requests.
|
||||||
instance_type = request_spec['instance_type']
|
instance_type = request_spec['instance_type']
|
||||||
name, query = driver.instance_type_to_filter(instance_type)
|
name, query = host_filter.instance_type_to_filter(instance_type)
|
||||||
return driver.filter_hosts(self.zone_manager, query)
|
return host_filter.filter_hosts(self.zone_manager, query)
|
||||||
|
|
||||||
def weigh_hosts(self, num, request_spec, hosts):
|
def weigh_hosts(self, num, request_spec, hosts):
|
||||||
"""Derived classes must override this method and return
|
"""Derived classes must override this method and return
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
"""
|
"""
|
||||||
Tests For Scheduler Host Filter Drivers.
|
Tests For Scheduler Host Filters.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import json
|
import json
|
||||||
@@ -31,7 +31,7 @@ class FakeZoneManager:
|
|||||||
|
|
||||||
|
|
||||||
class HostFilterTestCase(test.TestCase):
|
class HostFilterTestCase(test.TestCase):
|
||||||
"""Test case for host filter drivers."""
|
"""Test case for host filters."""
|
||||||
|
|
||||||
def _host_caps(self, multiplier):
|
def _host_caps(self, multiplier):
|
||||||
# Returns host capabilities in the following way:
|
# Returns host capabilities in the following way:
|
||||||
@@ -57,8 +57,8 @@ class HostFilterTestCase(test.TestCase):
|
|||||||
'host_name-label': 'xs-%s' % multiplier}
|
'host_name-label': 'xs-%s' % multiplier}
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.old_flag = FLAGS.default_host_filter_driver
|
self.old_flag = FLAGS.default_host_filter
|
||||||
FLAGS.default_host_filter_driver = \
|
FLAGS.default_host_filter = \
|
||||||
'nova.scheduler.host_filter.AllHostsFilter'
|
'nova.scheduler.host_filter.AllHostsFilter'
|
||||||
self.instance_type = dict(name='tiny',
|
self.instance_type = dict(name='tiny',
|
||||||
memory_mb=50,
|
memory_mb=50,
|
||||||
@@ -76,52 +76,52 @@ class HostFilterTestCase(test.TestCase):
|
|||||||
self.zone_manager.service_states = states
|
self.zone_manager.service_states = states
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
FLAGS.default_host_filter_driver = self.old_flag
|
FLAGS.default_host_filter = self.old_flag
|
||||||
|
|
||||||
def test_choose_driver(self):
|
def test_choose_filter(self):
|
||||||
# Test default driver ...
|
# Test default filter ...
|
||||||
driver = host_filter.choose_driver()
|
hf = host_filter.choose_host_filter()
|
||||||
self.assertEquals(driver._full_name(),
|
self.assertEquals(hf._full_name(),
|
||||||
'nova.scheduler.host_filter.AllHostsFilter')
|
'nova.scheduler.host_filter.AllHostsFilter')
|
||||||
# Test valid driver ...
|
# Test valid filter ...
|
||||||
driver = host_filter.choose_driver(
|
hf = host_filter.choose_host_filter(
|
||||||
'nova.scheduler.host_filter.InstanceTypeFilter')
|
'nova.scheduler.host_filter.InstanceTypeFilter')
|
||||||
self.assertEquals(driver._full_name(),
|
self.assertEquals(hf._full_name(),
|
||||||
'nova.scheduler.host_filter.InstanceTypeFilter')
|
'nova.scheduler.host_filter.InstanceTypeFilter')
|
||||||
# Test invalid driver ...
|
# Test invalid filter ...
|
||||||
try:
|
try:
|
||||||
host_filter.choose_driver('does not exist')
|
host_filter.choose_host_filter('does not exist')
|
||||||
self.fail("Should not find driver")
|
self.fail("Should not find host filter.")
|
||||||
except exception.SchedulerHostFilterDriverNotFound:
|
except exception.SchedulerHostFilterNotFound:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_all_host_driver(self):
|
def test_all_host_filter(self):
|
||||||
driver = host_filter.AllHostsFilter()
|
hf = host_filter.AllHostsFilter()
|
||||||
cooked = driver.instance_type_to_filter(self.instance_type)
|
cooked = hf.instance_type_to_filter(self.instance_type)
|
||||||
hosts = driver.filter_hosts(self.zone_manager, cooked)
|
hosts = hf.filter_hosts(self.zone_manager, cooked)
|
||||||
self.assertEquals(10, len(hosts))
|
self.assertEquals(10, len(hosts))
|
||||||
for host, capabilities in hosts:
|
for host, capabilities in hosts:
|
||||||
self.assertTrue(host.startswith('host'))
|
self.assertTrue(host.startswith('host'))
|
||||||
|
|
||||||
def test_instance_type_driver(self):
|
def test_instance_type_filter(self):
|
||||||
driver = host_filter.InstanceTypeFilter()
|
hf = host_filter.InstanceTypeFilter()
|
||||||
# filter all hosts that can support 50 ram and 500 disk
|
# filter all hosts that can support 50 ram and 500 disk
|
||||||
name, cooked = driver.instance_type_to_filter(self.instance_type)
|
name, cooked = hf.instance_type_to_filter(self.instance_type)
|
||||||
self.assertEquals('nova.scheduler.host_filter.InstanceTypeFilter',
|
self.assertEquals('nova.scheduler.host_filter.InstanceTypeFilter',
|
||||||
name)
|
name)
|
||||||
hosts = driver.filter_hosts(self.zone_manager, cooked)
|
hosts = hf.filter_hosts(self.zone_manager, cooked)
|
||||||
self.assertEquals(6, len(hosts))
|
self.assertEquals(6, len(hosts))
|
||||||
just_hosts = [host for host, caps in hosts]
|
just_hosts = [host for host, caps in hosts]
|
||||||
just_hosts.sort()
|
just_hosts.sort()
|
||||||
self.assertEquals('host05', just_hosts[0])
|
self.assertEquals('host05', just_hosts[0])
|
||||||
self.assertEquals('host10', just_hosts[5])
|
self.assertEquals('host10', just_hosts[5])
|
||||||
|
|
||||||
def test_json_driver(self):
|
def test_json_filter(self):
|
||||||
driver = host_filter.JsonFilter()
|
hf = host_filter.JsonFilter()
|
||||||
# filter all hosts that can support 50 ram and 500 disk
|
# filter all hosts that can support 50 ram and 500 disk
|
||||||
name, cooked = driver.instance_type_to_filter(self.instance_type)
|
name, cooked = hf.instance_type_to_filter(self.instance_type)
|
||||||
self.assertEquals('nova.scheduler.host_filter.JsonFilter', name)
|
self.assertEquals('nova.scheduler.host_filter.JsonFilter', name)
|
||||||
hosts = driver.filter_hosts(self.zone_manager, cooked)
|
hosts = hf.filter_hosts(self.zone_manager, cooked)
|
||||||
self.assertEquals(6, len(hosts))
|
self.assertEquals(6, len(hosts))
|
||||||
just_hosts = [host for host, caps in hosts]
|
just_hosts = [host for host, caps in hosts]
|
||||||
just_hosts.sort()
|
just_hosts.sort()
|
||||||
@@ -141,7 +141,7 @@ class HostFilterTestCase(test.TestCase):
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
cooked = json.dumps(raw)
|
cooked = json.dumps(raw)
|
||||||
hosts = driver.filter_hosts(self.zone_manager, cooked)
|
hosts = hf.filter_hosts(self.zone_manager, cooked)
|
||||||
|
|
||||||
self.assertEquals(5, len(hosts))
|
self.assertEquals(5, len(hosts))
|
||||||
just_hosts = [host for host, caps in hosts]
|
just_hosts = [host for host, caps in hosts]
|
||||||
@@ -153,7 +153,7 @@ class HostFilterTestCase(test.TestCase):
|
|||||||
['=', '$compute.host_memory_free', 30],
|
['=', '$compute.host_memory_free', 30],
|
||||||
]
|
]
|
||||||
cooked = json.dumps(raw)
|
cooked = json.dumps(raw)
|
||||||
hosts = driver.filter_hosts(self.zone_manager, cooked)
|
hosts = hf.filter_hosts(self.zone_manager, cooked)
|
||||||
|
|
||||||
self.assertEquals(9, len(hosts))
|
self.assertEquals(9, len(hosts))
|
||||||
just_hosts = [host for host, caps in hosts]
|
just_hosts = [host for host, caps in hosts]
|
||||||
@@ -163,7 +163,7 @@ class HostFilterTestCase(test.TestCase):
|
|||||||
|
|
||||||
raw = ['in', '$compute.host_memory_free', 20, 40, 60, 80, 100]
|
raw = ['in', '$compute.host_memory_free', 20, 40, 60, 80, 100]
|
||||||
cooked = json.dumps(raw)
|
cooked = json.dumps(raw)
|
||||||
hosts = driver.filter_hosts(self.zone_manager, cooked)
|
hosts = hf.filter_hosts(self.zone_manager, cooked)
|
||||||
|
|
||||||
self.assertEquals(5, len(hosts))
|
self.assertEquals(5, len(hosts))
|
||||||
just_hosts = [host for host, caps in hosts]
|
just_hosts = [host for host, caps in hosts]
|
||||||
@@ -175,35 +175,32 @@ class HostFilterTestCase(test.TestCase):
|
|||||||
raw = ['unknown command', ]
|
raw = ['unknown command', ]
|
||||||
cooked = json.dumps(raw)
|
cooked = json.dumps(raw)
|
||||||
try:
|
try:
|
||||||
driver.filter_hosts(self.zone_manager, cooked)
|
hf.filter_hosts(self.zone_manager, cooked)
|
||||||
self.fail("Should give KeyError")
|
self.fail("Should give KeyError")
|
||||||
except KeyError, e:
|
except KeyError, e:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
self.assertTrue(driver.filter_hosts(self.zone_manager, json.dumps([])))
|
self.assertTrue(hf.filter_hosts(self.zone_manager, json.dumps([])))
|
||||||
self.assertTrue(driver.filter_hosts(self.zone_manager, json.dumps({})))
|
self.assertTrue(hf.filter_hosts(self.zone_manager, json.dumps({})))
|
||||||
self.assertTrue(driver.filter_hosts(self.zone_manager, json.dumps(
|
self.assertTrue(hf.filter_hosts(self.zone_manager, json.dumps(
|
||||||
['not', True, False, True, False]
|
['not', True, False, True, False]
|
||||||
)))
|
)))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
driver.filter_hosts(self.zone_manager, json.dumps(
|
hf.filter_hosts(self.zone_manager, json.dumps(
|
||||||
'not', True, False, True, False
|
'not', True, False, True, False
|
||||||
))
|
))
|
||||||
self.fail("Should give KeyError")
|
self.fail("Should give KeyError")
|
||||||
except KeyError, e:
|
except KeyError, e:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
self.assertFalse(driver.filter_hosts(self.zone_manager, json.dumps(
|
self.assertFalse(hf.filter_hosts(self.zone_manager,
|
||||||
['=', '$foo', 100]
|
json.dumps(['=', '$foo', 100])))
|
||||||
)))
|
self.assertFalse(hf.filter_hosts(self.zone_manager,
|
||||||
self.assertFalse(driver.filter_hosts(self.zone_manager, json.dumps(
|
json.dumps(['=', '$.....', 100])))
|
||||||
['=', '$.....', 100]
|
self.assertFalse(hf.filter_hosts(self.zone_manager,
|
||||||
)))
|
json.dumps(
|
||||||
self.assertFalse(driver.filter_hosts(self.zone_manager, json.dumps(
|
['>', ['and', ['or', ['not', ['<', ['>=', ['<=', ['in', ]]]]]]]])))
|
||||||
['>', ['and', ['or', ['not', ['<', ['>=', ['<=', ['in', ]]]]]]]]
|
|
||||||
)))
|
|
||||||
|
|
||||||
self.assertFalse(driver.filter_hosts(self.zone_manager, json.dumps(
|
self.assertFalse(hf.filter_hosts(self.zone_manager,
|
||||||
['=', {}, ['>', '$missing....foo']]
|
json.dumps(['=', {}, ['>', '$missing....foo']])))
|
||||||
)))
|
|
||||||
|
|||||||
Reference in New Issue
Block a user