From 35925e5d280412028362f5be87a66fbc3f6532e9 Mon Sep 17 00:00:00 2001 From: Yassine Lamgarchal Date: Fri, 2 Aug 2013 16:44:54 +0200 Subject: [PATCH] Add flag to make IsolatedHostsFilter less restrictive This patch allows to run 'isolated' and 'non isolated' images on isolated hosts by adding a flag 'restrict_isolated_hosts_to_isolated_images'. If the flag is set to True then 'non isolated' images can't be run on isolated hosts (same behaviour as the current filter) otherwise they can be run on isolated hosts. DocImpact blueprint improve-isolatedhostsfilter Change-Id: I8c092caf32c05be88a547a7e8cb0530cc4925080 --- doc/source/devref/filter_scheduler.rst | 7 +++-- etc/nova/nova.conf.sample | 4 +++ .../filters/isolated_hosts_filter.py | 30 +++++++++++++++---- nova/tests/scheduler/test_host_filters.py | 19 ++++++++++-- 4 files changed, 50 insertions(+), 10 deletions(-) diff --git a/doc/source/devref/filter_scheduler.rst b/doc/source/devref/filter_scheduler.rst index a5a0ef988c..9b75ab4a44 100644 --- a/doc/source/devref/filter_scheduler.rst +++ b/doc/source/devref/filter_scheduler.rst @@ -79,8 +79,8 @@ There are some standard filter classes to use (:mod:`nova.scheduler.filters`): fall back to the global default ``cpu_allocation_ratio``. If more than one value is found for a host (meaning the host is in two differenet aggregate with different ratio settings), the minimum value will be used. -* |IsolatedHostsFilter| - filter based on ``image_isolated`` and ``host_isolated`` - flags. +* |IsolatedHostsFilter| - filter based on ``image_isolated``, ``host_isolated`` + and ``restrict_isolated_hosts_to_isolated_images`` flags. * |JsonFilter| - allows simple JSON-based grammar for selecting hosts. * |RamFilter| - filters hosts by their RAM. Only hosts with sufficient RAM to host the instance are passed. @@ -166,7 +166,8 @@ Now we are going to |IsolatedHostsFilter|. There can be some special hosts reserved for specific images. These hosts are called **isolated**. So the images to run on the isolated hosts are also called isolated. This Scheduler checks if ``image_isolated`` flag named in instance specifications is the same -that the host has. +that the host has. Isolated hosts can run non isolated images if the flag +``restrict_isolated_hosts_to_isolated_images`` is set to false. |DifferentHostFilter| - its method ``host_passes`` returns ``True`` if host to place instance on is different from all the hosts used by set of instances. diff --git a/etc/nova/nova.conf.sample b/etc/nova/nova.conf.sample index a28e4fc1d8..23decf1581 100644 --- a/etc/nova/nova.conf.sample +++ b/etc/nova/nova.conf.sample @@ -1714,6 +1714,10 @@ # Host reserved for specific images (list value) #isolated_hosts= +# Whether to force isolated hosts to run only isolated images +# (boolean value) +#restrict_isolated_hosts_to_isolated_images=true + # # Options defined in nova.scheduler.filters.num_instances_filter diff --git a/nova/scheduler/filters/isolated_hosts_filter.py b/nova/scheduler/filters/isolated_hosts_filter.py index 05b32f418b..12f533a592 100644 --- a/nova/scheduler/filters/isolated_hosts_filter.py +++ b/nova/scheduler/filters/isolated_hosts_filter.py @@ -24,6 +24,10 @@ isolated_opts = [ cfg.ListOpt('isolated_hosts', default=[], help='Host reserved for specific images'), + cfg.BoolOpt('restrict_isolated_hosts_to_isolated_images', + default=True, + help='Whether to force isolated hosts to run only isolated ' + 'images'), ] CONF = cfg.CONF CONF.register_opts(isolated_opts) @@ -37,26 +41,42 @@ class IsolatedHostsFilter(filters.BaseHostFilter): def host_passes(self, host_state, filter_properties): """ - Result Matrix: + Result Matrix with 'restrict_isolated_hosts_to_isolated_images' set + to True: | isolated_image | non_isolated_image -------------+----------------+------------------- iso_host | True | False non_iso_host | False | True + Result Matrix with 'restrict_isolated_hosts_to_isolated_images' set + to False: + | isolated_image | non_isolated_image + -------------+----------------+------------------- + iso_host | True | True + non_iso_host | False | True + """ # If the configuration does not list any hosts, the filter will always # return True, assuming a configuration error, so letting all hosts # through. isolated_hosts = CONF.isolated_hosts isolated_images = CONF.isolated_images + restrict_isolated_hosts_to_isolated_images = (CONF. + restrict_isolated_hosts_to_isolated_images) if not isolated_images: - # As there are no images to match, return False if the host is in - # the isolation list - return host_state.host not in isolated_hosts + # As there are no images to match, return True if the filter is + # not restrictive otherwise return False if the host is in the + # isolation list. + return ((not restrict_isolated_hosts_to_isolated_images) or + (host_state.host not in isolated_hosts)) spec = filter_properties.get('request_spec', {}) props = spec.get('instance_properties', {}) image_ref = props.get('image_ref') image_isolated = image_ref in isolated_images host_isolated = host_state.host in isolated_hosts - return image_isolated == host_isolated + + if restrict_isolated_hosts_to_isolated_images: + return (image_isolated == host_isolated) + else: + return (not image_isolated) or host_isolated diff --git a/nova/tests/scheduler/test_host_filters.py b/nova/tests/scheduler/test_host_filters.py index d2f8c90dcd..53251f6a15 100644 --- a/nova/tests/scheduler/test_host_filters.py +++ b/nova/tests/scheduler/test_host_filters.py @@ -896,10 +896,13 @@ class HostFiltersTestCase(test.NoDBTestCase): passes=False) def _do_test_isolated_hosts(self, host_in_list, image_in_list, - set_flags=True): + set_flags=True, + restrict_isolated_hosts_to_isolated_images=True): if set_flags: self.flags(isolated_images=['isolated_image'], - isolated_hosts=['isolated_host']) + isolated_hosts=['isolated_host'], + restrict_isolated_hosts_to_isolated_images= + restrict_isolated_hosts_to_isolated_images) host_name = 'isolated_host' if host_in_list else 'free_host' image_ref = 'isolated_image' if image_in_list else 'free_image' filter_properties = { @@ -949,6 +952,18 @@ class HostFiltersTestCase(test.NoDBTestCase): self.assertFalse(self._do_test_isolated_hosts(True, True, False)) self.assertTrue(self._do_test_isolated_hosts(False, False, False)) + def test_isolated_hosts_less_restrictive(self): + # If there are isolated hosts and non isolated images + self.assertTrue(self._do_test_isolated_hosts(True, False, True, False)) + # If there are isolated hosts and isolated images + self.assertTrue(self._do_test_isolated_hosts(True, True, True, False)) + # If there are non isolated hosts and non isolated images + self.assertTrue(self._do_test_isolated_hosts(False, False, True, + False)) + # If there are non isolated hosts and isolated images + self.assertFalse(self._do_test_isolated_hosts(False, True, True, + False)) + def test_json_filter_passes(self): filt_cls = self.class_map['JsonFilter']() filter_properties = {'instance_type': {'memory_mb': 1024,