summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nova/exception.py5
-rw-r--r--nova/scheduler/host_filter.py (renamed from nova/scheduler/query.py)78
-rw-r--r--nova/tests/test_host_filter.py (renamed from nova/tests/test_query.py)44
3 files changed, 70 insertions, 57 deletions
diff --git a/nova/exception.py b/nova/exception.py
index 50f50de9d..9905fb19b 100644
--- a/nova/exception.py
+++ b/nova/exception.py
@@ -457,8 +457,9 @@ class ZoneNotFound(NotFound):
message = _("Zone %(zone_id)s could not be found.")
-class SchedulerQueryDriverNotFound(NotFound):
- message = _("Scheduler Query Driver %(driver_name)s could not be found.")
+class SchedulerHostFilterDriverNotFound(NotFound):
+ message = _("Scheduler Host Filter Driver %(driver_name)s could"
+ " not be found.")
class InstanceMetadataNotFound(NotFound):
diff --git a/nova/scheduler/query.py b/nova/scheduler/host_filter.py
index 1e294b595..aa6101c93 100644
--- a/nova/scheduler/query.py
+++ b/nova/scheduler/host_filter.py
@@ -14,14 +14,23 @@
# under the License.
"""
-Query is a plug-in mechanism for requesting instance resources.
-Three plug-ins are included: AllHosts, Flavor & JSON. AllHosts just
+Host Filter is a driver mechanism for requesting instance resources.
+Three drivers are included: AllHosts, Flavor & JSON. AllHosts just
returns the full, unfiltered list of hosts. Flavor is a hard coded
matching mechanism based on flavor criteria and JSON is an ad-hoc
-query grammar.
-
-Note: These are hard filters. All capabilities used must be present
-or the host will excluded. If you want soft filters use the weighting
+filter grammar.
+
+Why JSON? The requests for instances may come in through the
+REST interface from a user or a parent Zone.
+Currently Flavors and/or InstanceTypes are used for
+specifing the type of instance desired. Specific Nova users have
+noted a need for a more expressive way of specifying instances.
+Since we don't want to get into building full DSL this is a simple
+form as an example of how this could be done. In reality, most
+consumers will use the more rigid filters such as FlavorFilter.
+
+Note: These are hard filters. All capabilities used must be present
+or the host will be excluded. If you want soft filters use the weighting
mechanism which is intended for the more touchy-feely capabilities.
"""
@@ -32,36 +41,36 @@ from nova import flags
from nova import log as logging
from nova import utils
-LOG = logging.getLogger('nova.scheduler.query')
+LOG = logging.getLogger('nova.scheduler.host_filter')
FLAGS = flags.FLAGS
-flags.DEFINE_string('default_query_engine',
- 'nova.scheduler.query.AllHostsQuery',
- 'Which query engine to use for filtering hosts.')
+flags.DEFINE_string('default_host_filter_driver',
+ 'nova.scheduler.host_filter.AllHostsFilter',
+ 'Which driver to use for filtering hosts.')
-class Query(object):
- """Base class for query plug-ins."""
+class HostFilter(object):
+ """Base class for host filter drivers."""
- def instance_type_to_query(self, instance_type):
- """Convert instance_type into a query for most common use-case."""
+ def instance_type_to_filter(self, instance_type):
+ """Convert instance_type into a filter for most common use-case."""
raise NotImplementedError()
def filter_hosts(self, zone_manager, query):
- """Return a list of hosts that fulfill the query."""
+ """Return a list of hosts that fulfill the filter."""
raise NotImplementedError()
def _full_name(self):
- """module.classname of the Query object"""
+ """module.classname of the filter driver"""
return "%s.%s" % (self.__module__, self.__class__.__name__)
-class AllHostsQuery(Query):
- """NOP query plug-in. Returns all hosts in ZoneManager.
+class AllHostsFilter(HostFilter):
+ """NOP host filter driver. Returns all hosts in ZoneManager.
This essentially does what the old Scheduler+Chance used
to give us."""
- def instance_type_to_query(self, instance_type):
+ def instance_type_to_filter(self, instance_type):
"""Return anything to prevent base-class from raising
exception."""
return (self._full_name(), instance_type)
@@ -72,10 +81,10 @@ class AllHostsQuery(Query):
for host, services in zone_manager.service_states.iteritems()]
-class FlavorQuery(Query):
- """Query plug-in hard-coded to work with flavors."""
+class FlavorFilter(HostFilter):
+ """HostFilter driver hard-coded to work with flavors."""
- def instance_type_to_query(self, instance_type):
+ def instance_type_to_filter(self, instance_type):
"""Use instance_type to filter hosts."""
return (self._full_name(), instance_type)
@@ -119,8 +128,9 @@ class FlavorQuery(Query):
#rxtx_cap = Column(Integer, nullable=False, default=0)
-class JsonQuery(Query):
- """Query plug-in to allow simple JSON-based grammar for selecting hosts."""
+class JsonFilter(HostFilter):
+ """Host Filter driver to allow simple JSON-based grammar for
+ selecting hosts."""
def _equals(self, args):
"""First term is == all the other terms."""
@@ -204,8 +214,8 @@ class JsonQuery(Query):
'and': _and,
}
- def instance_type_to_query(self, instance_type):
- """Convert instance_type into JSON query object."""
+ def instance_type_to_filter(self, instance_type):
+ """Convert instance_type into JSON filter object."""
required_ram = instance_type['memory_mb']
required_disk = instance_type['local_gb']
query = ['and',
@@ -229,7 +239,7 @@ class JsonQuery(Query):
return None
return services
- def _process_query(self, zone_manager, query, host, services):
+ def _process_filter(self, zone_manager, query, host, services):
"""Recursively parse the query structure."""
if len(query) == 0:
return True
@@ -238,7 +248,7 @@ class JsonQuery(Query):
cooked_args = []
for arg in query[1:]:
if isinstance(arg, list):
- arg = self._process_query(zone_manager, arg, host, services)
+ arg = self._process_filter(zone_manager, arg, host, services)
elif isinstance(arg, basestring):
arg = self._parse_string(arg, host, services)
if arg != None:
@@ -247,11 +257,11 @@ class JsonQuery(Query):
return result
def filter_hosts(self, zone_manager, query):
- """Return a list of hosts that can fulfill query."""
+ """Return a list of hosts that can fulfill filter."""
expanded = json.loads(query)
hosts = []
for host, services in zone_manager.service_states.iteritems():
- r = self._process_query(zone_manager, expanded, host, services)
+ r = self._process_filter(zone_manager, expanded, host, services)
if isinstance(r, list):
r = True in r
if r:
@@ -259,7 +269,7 @@ class JsonQuery(Query):
return hosts
-DRIVERS = [AllHostsQuery, FlavorQuery, JsonQuery]
+DRIVERS = [AllHostsFilter, FlavorFilter, JsonFilter]
def choose_driver(driver_name=None):
@@ -267,10 +277,10 @@ def choose_driver(driver_name=None):
to have an authoritative list of what is permissible. This
function checks the driver name against a predefined set
of acceptable drivers."""
-
+
if not driver_name:
- driver_name = FLAGS.default_query_engine
+ driver_name = FLAGS.default_host_filter_driver
for driver in DRIVERS:
if "%s.%s" % (driver.__module__, driver.__name__) == driver_name:
return driver()
- raise exception.SchedulerQueryDriverNotFound(driver_name=driver_name)
+ raise exception.SchedulerHostFilterDriverNotFound(driver_name=driver_name)
diff --git a/nova/tests/test_query.py b/nova/tests/test_host_filter.py
index 9497a8c96..31e40ae1d 100644
--- a/nova/tests/test_query.py
+++ b/nova/tests/test_host_filter.py
@@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
"""
-Tests For Scheduler Query Drivers
+Tests For Scheduler Host Filter Drivers.
"""
import json
@@ -21,7 +21,7 @@ import json
from nova import exception
from nova import flags
from nova import test
-from nova.scheduler import query
+from nova.scheduler import host_filter
FLAGS = flags.FLAGS
@@ -30,8 +30,8 @@ class FakeZoneManager:
pass
-class QueryTestCase(test.TestCase):
- """Test case for query drivers."""
+class HostFilterTestCase(test.TestCase):
+ """Test case for host filter drivers."""
def _host_caps(self, multiplier):
# Returns host capabilities in the following way:
@@ -57,8 +57,9 @@ class QueryTestCase(test.TestCase):
'host_name-label': 'xs-%s' % multiplier}
def setUp(self):
- self.old_flag = FLAGS.default_query_engine
- FLAGS.default_query_engine = 'nova.scheduler.query.AllHostsQuery'
+ self.old_flag = FLAGS.default_host_filter_driver
+ FLAGS.default_host_filter_driver = \
+ 'nova.scheduler.host_filter.AllHostsFilter'
self.instance_type = dict(name='tiny',
memory_mb=50,
vcpus=10,
@@ -75,37 +76,38 @@ class QueryTestCase(test.TestCase):
self.zone_manager.service_states = states
def tearDown(self):
- FLAGS.default_query_engine = self.old_flag
+ FLAGS.default_host_filter_driver = self.old_flag
def test_choose_driver(self):
# Test default driver ...
- driver = query.choose_driver()
+ driver = host_filter.choose_driver()
self.assertEquals(driver._full_name(),
- 'nova.scheduler.query.AllHostsQuery')
+ 'nova.scheduler.host_filter.AllHostsFilter')
# Test valid driver ...
- driver = query.choose_driver('nova.scheduler.query.FlavorQuery')
+ driver = host_filter.choose_driver(
+ 'nova.scheduler.host_filter.FlavorFilter')
self.assertEquals(driver._full_name(),
- 'nova.scheduler.query.FlavorQuery')
+ 'nova.scheduler.host_filter.FlavorFilter')
# Test invalid driver ...
try:
- query.choose_driver('does not exist')
+ host_filter.choose_driver('does not exist')
self.fail("Should not find driver")
- except exception.SchedulerQueryDriverNotFound:
+ except exception.SchedulerHostFilterDriverNotFound:
pass
def test_all_host_driver(self):
- driver = query.AllHostsQuery()
- cooked = driver.instance_type_to_query(self.instance_type)
+ driver = host_filter.AllHostsFilter()
+ cooked = driver.instance_type_to_filter(self.instance_type)
hosts = driver.filter_hosts(self.zone_manager, cooked)
self.assertEquals(10, len(hosts))
for host, capabilities in hosts:
self.assertTrue(host.startswith('host'))
def test_flavor_driver(self):
- driver = query.FlavorQuery()
+ driver = host_filter.FlavorFilter()
# filter all hosts that can support 50 ram and 500 disk
- name, cooked = driver.instance_type_to_query(self.instance_type)
- self.assertEquals('nova.scheduler.query.FlavorQuery', name)
+ name, cooked = driver.instance_type_to_filter(self.instance_type)
+ self.assertEquals('nova.scheduler.host_filter.FlavorFilter', name)
hosts = driver.filter_hosts(self.zone_manager, cooked)
self.assertEquals(6, len(hosts))
just_hosts = [host for host, caps in hosts]
@@ -114,10 +116,10 @@ class QueryTestCase(test.TestCase):
self.assertEquals('host10', just_hosts[5])
def test_json_driver(self):
- driver = query.JsonQuery()
+ driver = host_filter.JsonFilter()
# filter all hosts that can support 50 ram and 500 disk
- name, cooked = driver.instance_type_to_query(self.instance_type)
- self.assertEquals('nova.scheduler.query.JsonQuery', name)
+ name, cooked = driver.instance_type_to_filter(self.instance_type)
+ self.assertEquals('nova.scheduler.host_filter.JsonFilter', name)
hosts = driver.filter_hosts(self.zone_manager, cooked)
self.assertEquals(6, len(hosts))
just_hosts = [host for host, caps in hosts]