From 158c6d64c2da48ec5fb3382eb64cd5c5e9c5c2d9 Mon Sep 17 00:00:00 2001 From: Yingxin Date: Tue, 17 Nov 2015 07:27:34 +0000 Subject: [PATCH] Use stevedore for scheduler host manager Avoid having to configure the full class path of host manager using classloader. Change to load the class by stevedore driver plugin using entrypoints. Change 'scheduler_host_manager' to use entrypoint with the namespace 'nova.scheduler.host_manager' in 'setup.cfg'. Meanwhile, still maintain the compatibility for class path configuration until the next major release. UpgradeImpact - see the reno file attached. Change-Id: I3fd42ead44487a21eb5cfaf5a91209277ce30ad0 Partially-Implements: blueprint scheduler-driver-use-stevedore --- nova/conf/scheduler.py | 18 +++++-- nova/scheduler/driver.py | 30 ++++++++++- nova/tests/unit/scheduler/test_scheduler.py | 50 +++++++++++++++++++ ..._host_manager_driver-a543a74ea70f5e90.yaml | 9 ++++ setup.cfg | 4 ++ 5 files changed, 104 insertions(+), 7 deletions(-) create mode 100644 releasenotes/notes/config_scheduler_host_manager_driver-a543a74ea70f5e90.yaml 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