diff --git a/doc/source/devref/filter_scheduler.rst b/doc/source/devref/filter_scheduler.rst index a5a0ef988..9b75ab4a4 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/nova/scheduler/filters/isolated_hosts_filter.py b/nova/scheduler/filters/isolated_hosts_filter.py index 05b32f418..12f533a59 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 d2f8c90dc..53251f6a1 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,