diff --git a/nova/conf/scheduler.py b/nova/conf/scheduler.py index 3923ca774145..eaadc18c2634 100644 --- a/nova/conf/scheduler.py +++ b/nova/conf/scheduler.py @@ -245,12 +245,20 @@ configuration. """) sched_driver_host_mgr_opt = cfg.StrOpt("scheduler_host_manager", - default="nova.scheduler.host_manager.HostManager", + default="host_manager", help=""" -The scheduler host manager class to use. Aside from the default, the only other -option as of the Mitaka release is -'nova.scheduler.ironic_host_manager.IronicHostManager', which should be used if -you're using Ironic to provision bare-metal instances. +The scheduler host manager to use, which manages the in-memory picture of the +hosts that the scheduler uses. + +The option value should be chosen from one of the entrypoints under the +namespace 'nova.scheduler.host_manager' of file 'setup.cfg'. For example, +'host_manager' is the default setting. Aside from the default, the only other +option as of the Mitaka release is 'ironic_host_manager', which should be used +if you're using Ironic to provision bare-metal instances. + +This option also supports a full class path style, for example +"nova.scheduler.host_manager.HostManager", but note this support is deprecated +and will be dropped in the N release. * Services that use this: diff --git a/nova/scheduler/driver.py b/nova/scheduler/driver.py index fde07fee2f60..a695fdcd1b7a 100644 --- a/nova/scheduler/driver.py +++ b/nova/scheduler/driver.py @@ -21,23 +21,49 @@ Scheduler base class that all Schedulers should inherit from import abc +from oslo_log import log as logging from oslo_utils import importutils import six +from stevedore import driver import nova.conf +from nova.i18n import _, _LW from nova import objects from nova import servicegroup CONF = nova.conf.CONF +LOG = logging.getLogger(__name__) + @six.add_metaclass(abc.ABCMeta) class Scheduler(object): """The base class that all Scheduler classes should inherit from.""" def __init__(self): - self.host_manager = importutils.import_object( - CONF.scheduler_host_manager) + try: + self.host_manager = driver.DriverManager( + "nova.scheduler.host_manager", + CONF.scheduler_host_manager, + invoke_on_load=True).driver + # TODO(Yingxin): Change to catch stevedore.exceptions.NoMatches + # after stevedore v1.9.0 + except RuntimeError: + # NOTE(Yingxin): Loading full class path is deprecated and + # should be removed in the N release. + try: + self.host_manager = importutils.import_object( + CONF.scheduler_host_manager) + LOG.warning(_LW("DEPRECATED: scheduler_host_manager uses " + "classloader to load %(path)s. This legacy " + "loading style will be removed in the " + "N release."), + {'path': CONF.scheduler_host_manager}) + except (ImportError, ValueError): + raise RuntimeError( + _("Cannot load host manager from configuration " + "scheduler_host_manager = %(conf)s."), + {'conf': CONF.scheduler_host_manager}) self.servicegroup_api = servicegroup.API() def run_periodic_tasks(self, context): diff --git a/nova/tests/unit/scheduler/test_scheduler.py b/nova/tests/unit/scheduler/test_scheduler.py index a0b0ec967911..7f2e2c0cf3bf 100644 --- a/nova/tests/unit/scheduler/test_scheduler.py +++ b/nova/tests/unit/scheduler/test_scheduler.py @@ -21,7 +21,9 @@ import mock from nova import context from nova import objects +from nova.scheduler import driver from nova.scheduler import host_manager +from nova.scheduler import ironic_host_manager from nova.scheduler import manager from nova import servicegroup from nova import test @@ -117,6 +119,54 @@ class SchedulerManagerTestCase(test.NoDBTestCase): mock.sentinel.instance_uuids) +class SchedulerInitTestCase(test.NoDBTestCase): + """Test case for base scheduler driver initiation.""" + + driver_cls = fakes.FakeScheduler + + @mock.patch.object(host_manager.HostManager, '_init_instance_info') + @mock.patch.object(host_manager.HostManager, '_init_aggregates') + def test_init_using_default_hostmanager(self, + mock_init_agg, + mock_init_inst): + manager = self.driver_cls().host_manager + self.assertIsInstance(manager, host_manager.HostManager) + + @mock.patch.object(host_manager.HostManager, '_init_instance_info') + @mock.patch.object(host_manager.HostManager, '_init_aggregates') + def test_init_using_ironic_hostmanager(self, + mock_init_agg, + mock_init_inst): + self.flags(scheduler_host_manager='ironic_host_manager') + manager = self.driver_cls().host_manager + self.assertIsInstance(manager, ironic_host_manager.IronicHostManager) + + @mock.patch.object(host_manager.HostManager, '_init_instance_info') + @mock.patch.object(host_manager.HostManager, '_init_aggregates') + def test_init_nonexist_hostmanager(self, + mock_init_agg, + mock_init_inst): + self.flags(scheduler_host_manager='nonexist_host_manager') + self.assertRaises(RuntimeError, self.driver_cls) + + # NOTE(Yingxin): Loading full class path is deprecated and should be + # removed in the N release. + @mock.patch.object(driver.LOG, 'warning') + @mock.patch.object(host_manager.HostManager, '_init_instance_info') + @mock.patch.object(host_manager.HostManager, '_init_aggregates') + def test_init_using_classpath_to_hostmanager(self, + mock_init_agg, + mock_init_inst, + mock_warning): + self.flags( + scheduler_host_manager= + 'nova.scheduler.ironic_host_manager.IronicHostManager') + manager = self.driver_cls().host_manager + self.assertIsInstance(manager, ironic_host_manager.IronicHostManager) + warn_args, kwargs = mock_warning.call_args + self.assertIn("DEPRECATED", warn_args[0]) + + class SchedulerTestCase(test.NoDBTestCase): """Test case for base scheduler driver class.""" diff --git a/releasenotes/notes/config_scheduler_host_manager_driver-a543a74ea70f5e90.yaml b/releasenotes/notes/config_scheduler_host_manager_driver-a543a74ea70f5e90.yaml new file mode 100644 index 000000000000..f3f1a41e61d3 --- /dev/null +++ b/releasenotes/notes/config_scheduler_host_manager_driver-a543a74ea70f5e90.yaml @@ -0,0 +1,9 @@ +--- +upgrade: + - | + The option ``scheduler_host_manager`` is now changed to use entrypoint + instead of full class path. Set one of the entrypoints under the namespace + 'nova.scheduler.host_manager' in 'setup.cfg'. Its default value is + 'host_manager'. The full class path style is still supported in current + release. But it is not recommended because class path can be changed and + this support will be dropped in the next major release. diff --git a/setup.cfg b/setup.cfg index b31b8513cd05..39fee7358741 100644 --- a/setup.cfg +++ b/setup.cfg @@ -187,6 +187,10 @@ nova.ipv6_backend = rfc2462 = nova.ipv6.rfc2462 account_identifier = nova.ipv6.account_identifier +nova.scheduler.host_manager = + host_manager = nova.scheduler.host_manager:HostManager + ironic_host_manager = nova.scheduler.ironic_host_manager:IronicHostManager + [build_sphinx] all_files = 1 build-dir = doc/build