Use stevedore for scheduler driver

Avoid having to configure the full class path of scheduler driver,
change to load by stevedore driver plugin using entrypoints.

Change 'scheduler_driver' to use entrypoint with the namespace
'nova.scheduler.driver' in 'setup.cfg'. Meanwhile, still maintain the
compatibility for class path configuration until the next major release.

Change all related tests with flag 'scheduler_driver' to use stevedore
entrypoint.

UpgradeImpact - see the reno file attached.
Implements: blueprint scheduler-driver-use-stevedore
Change-Id: I8c169e12d9bfacdbdb1dadf68b8a1fa98c5ea5bc
This commit is contained in:
Yingxin 2015-12-08 13:47:32 +00:00
parent 158c6d64c2
commit 33d906a2e0
7 changed files with 120 additions and 16 deletions

View File

@ -270,20 +270,26 @@ and will be dropped in the N release.
""")
driver_opt = cfg.StrOpt("scheduler_driver",
default="nova.scheduler.filter_scheduler.FilterScheduler",
default="filter_scheduler",
help="""
The class of the driver used by the scheduler. This should be the full Python
path to the class to be used. If nothing is specified in this option, the
FilterScheduler is used.
The class of the driver used by the scheduler. This should be chosen from one
of the entrypoints under the namespace 'nova.scheduler.driver' of file
'setup.cfg'. If nothing is specified in this option, the 'filter_scheduler' is
used.
This option also supports deprecated full Python path to the class to be used.
For example, "nova.scheduler.filter_scheduler.FilterScheduler". But note: this
support will be dropped in the N Release.
Other options are:
* 'nova.scheduler.caching_scheduler.CachingScheduler' which aggressively
caches the system state for better individual scheduler performance at
the risk of more retries when running multiple schedulers.
* 'caching_scheduler' which aggressively caches the system state for better
individual scheduler performance at the risk of more retries when running
multiple schedulers.
* 'nova.scheduler.chance.ChanceScheduler' which simply picks a host at
random.
* 'chance_scheduler' which simply picks a host at random.
* 'fake_scheduler' which is used for testing.
* Services that use this:

View File

@ -19,18 +19,23 @@
Scheduler Service
"""
from oslo_log import log as logging
import oslo_messaging as messaging
from oslo_serialization import jsonutils
from oslo_service import periodic_task
from oslo_utils import importutils
from stevedore import driver
import nova.conf
from nova import exception
from nova.i18n import _, _LW
from nova import manager
from nova import objects
from nova import quota
LOG = logging.getLogger(__name__)
CONF = nova.conf.CONF
QUOTAS = quota.QUOTAS
@ -46,7 +51,28 @@ class SchedulerManager(manager.Manager):
def __init__(self, scheduler_driver=None, *args, **kwargs):
if not scheduler_driver:
scheduler_driver = CONF.scheduler_driver
self.driver = importutils.import_object(scheduler_driver)
try:
self.driver = driver.DriverManager(
"nova.scheduler.driver",
scheduler_driver,
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.driver = importutils.import_object(scheduler_driver)
LOG.warning(_LW("DEPRECATED: scheduler_driver uses "
"classloader to load %(path)s. This legacy "
"loading style will be removed in the "
"N release."),
{'path': scheduler_driver})
except (ImportError, ValueError):
raise RuntimeError(
_("Cannot load scheduler driver from configuration "
"%(conf)s."),
{'conf': scheduler_driver})
super(SchedulerManager, self).__init__(service_name='scheduler',
*args, **kwargs)

View File

@ -92,8 +92,7 @@ class _IntegratedTestBase(test.TestCase):
return self.start_service('compute')
def _setup_scheduler_service(self):
self.flags(scheduler_driver='nova.scheduler.'
'chance.ChanceScheduler')
self.flags(scheduler_driver='chance_scheduler')
return self.start_service('scheduler')
def _setup_services(self):

View File

@ -79,8 +79,7 @@ class NUMAServersTest(ServersTestBase):
def _setup_scheduler_service(self):
self.flags(compute_driver='nova.virt.libvirt.LibvirtDriver')
self.flags(scheduler_driver='nova.scheduler.'
'filter_scheduler.FilterScheduler')
self.flags(scheduler_driver='filter_scheduler')
self.flags(scheduler_default_filters=CONF.scheduler_default_filters
+ ['NUMATopologyFilter'])
return self.start_service('scheduler')

View File

@ -21,7 +21,10 @@ import mock
from nova import context
from nova import objects
from nova.scheduler import caching_scheduler
from nova.scheduler import chance
from nova.scheduler import driver
from nova.scheduler import filter_scheduler
from nova.scheduler import host_manager
from nova.scheduler import ironic_host_manager
from nova.scheduler import manager
@ -31,18 +34,74 @@ from nova.tests.unit import fake_server_actions
from nova.tests.unit.scheduler import fakes
class SchedulerManagerInitTestCase(test.NoDBTestCase):
"""Test case for scheduler manager initiation."""
manager_cls = manager.SchedulerManager
@mock.patch.object(host_manager.HostManager, '_init_instance_info')
@mock.patch.object(host_manager.HostManager, '_init_aggregates')
def test_init_using_default_schedulerdriver(self,
mock_init_agg,
mock_init_inst):
driver = self.manager_cls().driver
self.assertIsInstance(driver, filter_scheduler.FilterScheduler)
@mock.patch.object(host_manager.HostManager, '_init_instance_info')
@mock.patch.object(host_manager.HostManager, '_init_aggregates')
def test_init_using_chance_schedulerdriver(self,
mock_init_agg,
mock_init_inst):
self.flags(scheduler_driver='chance_scheduler')
driver = self.manager_cls().driver
self.assertIsInstance(driver, chance.ChanceScheduler)
@mock.patch.object(host_manager.HostManager, '_init_instance_info')
@mock.patch.object(host_manager.HostManager, '_init_aggregates')
def test_init_using_caching_schedulerdriver(self,
mock_init_agg,
mock_init_inst):
self.flags(scheduler_driver='caching_scheduler')
driver = self.manager_cls().driver
self.assertIsInstance(driver, caching_scheduler.CachingScheduler)
@mock.patch.object(host_manager.HostManager, '_init_instance_info')
@mock.patch.object(host_manager.HostManager, '_init_aggregates')
def test_init_nonexist_schedulerdriver(self,
mock_init_agg,
mock_init_inst):
self.flags(scheduler_driver='nonexist_scheduler')
self.assertRaises(RuntimeError, self.manager_cls)
# NOTE(Yingxin): Loading full class path is deprecated and should be
# removed in the N release.
@mock.patch.object(manager.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_schedulerdriver(self,
mock_init_agg,
mock_init_inst,
mock_warning):
self.flags(
scheduler_driver=
'nova.scheduler.chance.ChanceScheduler')
driver = self.manager_cls().driver
self.assertIsInstance(driver, chance.ChanceScheduler)
warn_args, kwargs = mock_warning.call_args
self.assertIn("DEPRECATED", warn_args[0])
class SchedulerManagerTestCase(test.NoDBTestCase):
"""Test case for scheduler manager."""
manager_cls = manager.SchedulerManager
driver_cls = fakes.FakeScheduler
driver_cls_name = 'nova.tests.unit.scheduler.fakes.FakeScheduler'
driver_plugin_name = 'fake_scheduler'
@mock.patch.object(host_manager.HostManager, '_init_instance_info')
@mock.patch.object(host_manager.HostManager, '_init_aggregates')
def setUp(self, mock_init_agg, mock_init_inst):
super(SchedulerManagerTestCase, self).setUp()
self.flags(scheduler_driver=self.driver_cls_name)
self.flags(scheduler_driver=self.driver_plugin_name)
with mock.patch.object(host_manager.HostManager, '_init_aggregates'):
self.manager = self.manager_cls()
self.context = context.RequestContext('fake_user', 'fake_project')

View File

@ -0,0 +1,9 @@
---
upgrade:
- |
The option ``scheduler_driver`` is now changed to use entrypoint instead of
full class path. Set one of the entrypoints under the namespace
'nova.scheduler.driver' 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.

View File

@ -191,6 +191,12 @@ nova.scheduler.host_manager =
host_manager = nova.scheduler.host_manager:HostManager
ironic_host_manager = nova.scheduler.ironic_host_manager:IronicHostManager
nova.scheduler.driver =
filter_scheduler = nova.scheduler.filter_scheduler:FilterScheduler
caching_scheduler = nova.scheduler.caching_scheduler:CachingScheduler
chance_scheduler = nova.scheduler.chance:ChanceScheduler
fake_scheduler = nova.tests.unit.scheduler.fakes:FakeScheduler
[build_sphinx]
all_files = 1
build-dir = doc/build