end of day
This commit is contained in:
75
nova/scheduler/host_filter.py
Normal file
75
nova/scheduler/host_filter.py
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
# Copyright (c) 2011 Openstack, LLC.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
"""
|
||||||
|
The Host Filter classes are a way to ensure that only hosts that are
|
||||||
|
appropriate are considered when creating a new instance. Hosts that are
|
||||||
|
either incompatible or insufficient to accept a newly-requested instance
|
||||||
|
are removed by Host Filter classes from consideration. Those that pass
|
||||||
|
the filter are then passed on for weighting or other process for ordering.
|
||||||
|
|
||||||
|
Three filters 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
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import types
|
||||||
|
|
||||||
|
from nova import exception
|
||||||
|
from nova import flags
|
||||||
|
from nova import log as logging
|
||||||
|
|
||||||
|
import nova.scheduler
|
||||||
|
|
||||||
|
|
||||||
|
LOG = logging.getLogger('nova.scheduler.host_filter')
|
||||||
|
FLAGS = flags.FLAGS
|
||||||
|
|
||||||
|
|
||||||
|
def _get_filters():
|
||||||
|
from nova.scheduler import filters
|
||||||
|
def get_itm(nm):
|
||||||
|
return getattr(filters, nm)
|
||||||
|
|
||||||
|
return [get_itm(itm) for itm in dir(filters)
|
||||||
|
if (type(get_itm(itm)) is types.TypeType)
|
||||||
|
and issubclass(get_itm(itm), filters.AbstractHostFilter)]
|
||||||
|
|
||||||
|
|
||||||
|
def choose_host_filter(filter_name=None):
|
||||||
|
"""Since the caller may specify which filter to use we need
|
||||||
|
to have an authoritative list of what is permissible. This
|
||||||
|
function checks the filter name against a predefined set
|
||||||
|
of acceptable filters.
|
||||||
|
"""
|
||||||
|
if not filter_name:
|
||||||
|
filter_name = FLAGS.default_host_filter
|
||||||
|
for filter_class in _get_filters():
|
||||||
|
host_match = "%s.%s" % (filter_class.__module__, filter_class.__name__)
|
||||||
|
if (host_match.startswith("nova.scheduler.filters") and
|
||||||
|
(host_match.split(".")[-1] == filter_name)):
|
||||||
|
return filter_class()
|
||||||
|
raise exception.SchedulerHostFilterNotFound(filter_name=filter_name)
|
||||||
@@ -20,6 +20,7 @@ import json
|
|||||||
|
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova import test
|
from nova import test
|
||||||
|
from nova.scheduler import host_filter
|
||||||
from nova.scheduler import filters
|
from nova.scheduler import filters
|
||||||
|
|
||||||
|
|
||||||
@@ -55,7 +56,7 @@ class HostFilterTestCase(test.TestCase):
|
|||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(HostFilterTestCase, self).setUp()
|
super(HostFilterTestCase, self).setUp()
|
||||||
default_host_filter = 'nova.scheduler.filteris.AllHostsFilter'
|
default_host_filter = 'AllHostsFilter'
|
||||||
self.flags(default_host_filter=default_host_filter)
|
self.flags(default_host_filter=default_host_filter)
|
||||||
self.instance_type = dict(name='tiny',
|
self.instance_type = dict(name='tiny',
|
||||||
memory_mb=50,
|
memory_mb=50,
|
||||||
@@ -98,13 +99,10 @@ class HostFilterTestCase(test.TestCase):
|
|||||||
def test_choose_filter(self):
|
def test_choose_filter(self):
|
||||||
# Test default filter ...
|
# Test default filter ...
|
||||||
hf = host_filter.choose_host_filter()
|
hf = host_filter.choose_host_filter()
|
||||||
self.assertEquals(hf._full_name(),
|
self.assertEquals(hf._full_name().split(".")[-1], 'AllHostsFilter')
|
||||||
'nova.scheduler.host_filter.AllHostsFilter')
|
|
||||||
# Test valid filter ...
|
# Test valid filter ...
|
||||||
hf = host_filter.choose_host_filter(
|
hf = host_filter.choose_host_filter('InstanceTypeFilter')
|
||||||
'nova.scheduler.host_filter.InstanceTypeFilter')
|
self.assertEquals(hf._full_name().split(".")[-1], 'InstanceTypeFilter')
|
||||||
self.assertEquals(hf._full_name(),
|
|
||||||
'nova.scheduler.host_filter.InstanceTypeFilter')
|
|
||||||
# Test invalid filter ...
|
# Test invalid filter ...
|
||||||
try:
|
try:
|
||||||
host_filter.choose_host_filter('does not exist')
|
host_filter.choose_host_filter('does not exist')
|
||||||
@@ -113,7 +111,7 @@ class HostFilterTestCase(test.TestCase):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def test_all_host_filter(self):
|
def test_all_host_filter(self):
|
||||||
hf = host_filter.AllHostsFilter()
|
hf = filters.AllHostsFilter()
|
||||||
cooked = hf.instance_type_to_filter(self.instance_type)
|
cooked = hf.instance_type_to_filter(self.instance_type)
|
||||||
hosts = hf.filter_hosts(self.zone_manager, cooked)
|
hosts = hf.filter_hosts(self.zone_manager, cooked)
|
||||||
self.assertEquals(10, len(hosts))
|
self.assertEquals(10, len(hosts))
|
||||||
@@ -121,11 +119,10 @@ class HostFilterTestCase(test.TestCase):
|
|||||||
self.assertTrue(host.startswith('host'))
|
self.assertTrue(host.startswith('host'))
|
||||||
|
|
||||||
def test_instance_type_filter(self):
|
def test_instance_type_filter(self):
|
||||||
hf = host_filter.InstanceTypeFilter()
|
hf = filters.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 = hf.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(name.split(".")[-1], 'InstanceTypeFilter')
|
||||||
name)
|
|
||||||
hosts = hf.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]
|
||||||
@@ -134,21 +131,20 @@ class HostFilterTestCase(test.TestCase):
|
|||||||
self.assertEquals('host10', just_hosts[5])
|
self.assertEquals('host10', just_hosts[5])
|
||||||
|
|
||||||
def test_instance_type_filter_extra_specs(self):
|
def test_instance_type_filter_extra_specs(self):
|
||||||
hf = host_filter.InstanceTypeFilter()
|
hf = filters.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 = hf.instance_type_to_filter(self.gpu_instance_type)
|
name, cooked = hf.instance_type_to_filter(self.gpu_instance_type)
|
||||||
self.assertEquals('nova.scheduler.host_filter.InstanceTypeFilter',
|
self.assertEquals(name.split(".")[-1], 'InstanceTypeFilter')
|
||||||
name)
|
|
||||||
hosts = hf.filter_hosts(self.zone_manager, cooked)
|
hosts = hf.filter_hosts(self.zone_manager, cooked)
|
||||||
self.assertEquals(1, len(hosts))
|
self.assertEquals(1, len(hosts))
|
||||||
just_hosts = [host for host, caps in hosts]
|
just_hosts = [host for host, caps in hosts]
|
||||||
self.assertEquals('host07', just_hosts[0])
|
self.assertEquals('host07', just_hosts[0])
|
||||||
|
|
||||||
def test_json_filter(self):
|
def test_json_filter(self):
|
||||||
hf = host_filter.JsonFilter()
|
hf = filters.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 = hf.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(name.split(".")[-1], 'JsonFilter')
|
||||||
hosts = hf.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]
|
||||||
@@ -191,6 +187,12 @@ 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)
|
||||||
|
def debug(*args):
|
||||||
|
with file("/tmp/debug", "a") as dbg:
|
||||||
|
msg = " ".join([str(arg) for arg in args])
|
||||||
|
dbg.write("%s\n" % msg)
|
||||||
|
|
||||||
|
debug("cooked", cooked, type(cooked))
|
||||||
hosts = hf.filter_hosts(self.zone_manager, cooked)
|
hosts = hf.filter_hosts(self.zone_manager, cooked)
|
||||||
|
|
||||||
self.assertEquals(5, len(hosts))
|
self.assertEquals(5, len(hosts))
|
||||||
|
|||||||
Reference in New Issue
Block a user