Conductor errors if enabled_drivers are not found

The conductor service should fail during startup if a configured driver,
eg. one that is specified in "enabled_drivers", is not found. At the
moment, it merely ignores missing drivers.

In addition to adding a check that all configured drivers are loaded,
this patch re-arranges some of the initialization of ConductorManager
such that an exception during init_host() does not result in
secondary exceptions being logged and obfuscating the cause, namely,
that no drivers were loaded.

Closes-bug: #1417954

Change-Id: I6a96f4b49891c92859479656fe36d2bbd38fe602
This commit is contained in:
Devananda van der Veen 2015-02-02 01:18:26 -08:00
parent e4d2622c86
commit a53a003030
5 changed files with 33 additions and 15 deletions

View File

@ -124,6 +124,17 @@ class DriverFactory(object):
_check_func,
invoke_on_load=True,
on_load_failure_callback=_catch_driver_not_found))
# NOTE(deva): if we were unable to load any configured driver, perhaps
# because it is not present on the system, raise an error.
if (sorted(CONF.enabled_drivers) !=
sorted(cls._extension_manager.names())):
found = cls._extension_manager.names()
names = [n for n in CONF.enabled_drivers if n not in found]
# just in case more than one could not be found ...
names = ', '.join(names)
raise exception.DriverNotFound(driver_name=names)
LOG.info(_LI("Loaded the following drivers: %s"),
cls._extension_manager.names())

View File

@ -206,7 +206,7 @@ class DHCPNotFound(NotFound):
class DriverNotFound(NotFound):
message = _("Failed to load driver %(driver_name)s.")
message = _("Could not find the following driver(s): %(driver_name)s.")
class ImageNotFound(NotFound):

View File

@ -64,17 +64,19 @@ class RPCService(service.Service):
def start(self):
super(RPCService, self).start()
admin_context = context.RequestContext('admin', 'admin', is_admin=True)
self.manager.init_host()
self.tg.add_dynamic_timer(
self.manager.periodic_tasks,
periodic_interval_max=cfg.CONF.periodic_interval,
context=admin_context)
target = messaging.Target(topic=self.topic, server=self.host)
endpoints = [self.manager]
serializer = objects_base.IronicObjectSerializer()
self.rpcserver = rpc.get_server(target, endpoints, serializer)
self.rpcserver.start()
self.manager.init_host()
self.tg.add_dynamic_timer(
self.manager.periodic_tasks,
periodic_interval_max=cfg.CONF.periodic_interval,
context=admin_context)
LOG.info(_LI('Created RPC server for service %(service)s on host '
'%(host)s.'),
{'service': self.topic, 'host': self.host})

View File

@ -202,7 +202,20 @@ class ConductorManager(periodic_task.PeriodicTasks):
def init_host(self):
self.dbapi = dbapi.get_instance()
self._keepalive_evt = threading.Event()
"""Event for the keepalive thread."""
self._worker_pool = greenpool.GreenPool(
size=CONF.conductor.workers_pool_size)
"""GreenPool of background workers for performing tasks async."""
self.ring_manager = hash.HashRingManager()
"""Consistent hash ring which maps drivers to conductors."""
# NOTE(deva): instantiating DriverFactory may raise DriverLoadError
# or DriverNotFound
self._driver_factory = driver_factory.DriverFactory()
"""Driver factory loads all enabled drivers."""
self.drivers = self._driver_factory.names
"""List of driver names which this conductor supports."""
@ -241,16 +254,8 @@ class ConductorManager(periodic_task.PeriodicTasks):
update_existing=True)
self.conductor = cdr
self.ring_manager = hash.HashRingManager()
"""Consistent hash ring which maps drivers to conductors."""
self._worker_pool = greenpool.GreenPool(
size=CONF.conductor.workers_pool_size)
"""GreenPool of background workers for performing tasks async."""
# Spawn a dedicated greenthread for the keepalive
try:
self._keepalive_evt = threading.Event()
self._spawn_worker(self._conductor_service_record_keepalive)
LOG.info(_LI('Successfuly started conductor with hostname '
'%(hostname)s.'),

View File

@ -58,4 +58,4 @@ class DriverLoadTestCase(base.TestCase):
with mock.patch.object(dispatch.NameDispatchExtensionManager,
'__init__', self._fake_init_driver_err):
driver_factory.DriverFactory._init_extension_manager()
mock_em.assert_called_once_with()
self.assertEqual(2, mock_em.call_count)