Improve enabled_*_interfaces config help and validation

This adds additional constraints to the help messages for the
enabled_*_interfaces config options. It also checks if they are
empty at conductor startup, and if any are empty, errors out
with a better error message than previously provided.

Change-Id: I97fc318ce00291d5e43b70423930981c2f5a2de0
Partial-Bug: #1524745
This commit is contained in:
Jim Rollenhagen 2017-02-02 15:50:45 +00:00
parent 6206c47720
commit 1f25244bf6
4 changed files with 118 additions and 30 deletions

View File

@ -43,9 +43,12 @@
# Specify the list of boot interfaces to load during service
# initialization. Missing boot interfaces, or boot interfaces
# which fail to initialize, will prevent the ironic-conductor
# service from starting. The default value is a recommended
# set of production-oriented boot interfaces. A complete list
# of boot interfaces present on your system may be found by
# service from starting. At least one boot interface that is
# supported by each enabled hardware type must be enabled
# here, or the ironic-conductor service will not start. Must
# not be an empty list. The default value is a recommended set
# of production-oriented boot interfaces. A complete list of
# boot interfaces present on your system may be found by
# enumerating the "ironic.hardware.interfaces.boot"
# entrypoint. When setting this value, please make sure that
# every enabled hardware type will have the same set of
@ -62,8 +65,11 @@
# Specify the list of console interfaces to load during
# service initialization. Missing console interfaces, or
# console interfaces which fail to initialize, will prevent
# the ironic-conductor service from starting. The default
# value is a recommended set of production-oriented console
# the ironic-conductor service from starting. At least one
# console interface that is supported by each enabled hardware
# type must be enabled here, or the ironic-conductor service
# will not start. Must not be an empty list. The default value
# is a recommended set of production-oriented console
# interfaces. A complete list of console interfaces present on
# your system may be found by enumerating the
# "ironic.hardware.interfaces.console" entrypoint. When
@ -82,9 +88,12 @@
# Specify the list of deploy interfaces to load during service
# initialization. Missing deploy interfaces, or deploy
# interfaces which fail to initialize, will prevent the
# ironic-conductor service from starting. The default value is
# a recommended set of production-oriented deploy interfaces.
# A complete list of deploy interfaces present on your system
# ironic-conductor service from starting. At least one deploy
# interface that is supported by each enabled hardware type
# must be enabled here, or the ironic-conductor service will
# not start. Must not be an empty list. The default value is a
# recommended set of production-oriented deploy interfaces. A
# complete list of deploy interfaces present on your system
# may be found by enumerating the
# "ironic.hardware.interfaces.deploy" entrypoint. When setting
# this value, please make sure that every enabled hardware
@ -102,8 +111,11 @@
# Specify the list of inspect interfaces to load during
# service initialization. Missing inspect interfaces, or
# inspect interfaces which fail to initialize, will prevent
# the ironic-conductor service from starting. The default
# value is a recommended set of production-oriented inspect
# the ironic-conductor service from starting. At least one
# inspect interface that is supported by each enabled hardware
# type must be enabled here, or the ironic-conductor service
# will not start. Must not be an empty list. The default value
# is a recommended set of production-oriented inspect
# interfaces. A complete list of inspect interfaces present on
# your system may be found by enumerating the
# "ironic.hardware.interfaces.inspect" entrypoint. When
@ -122,14 +134,18 @@
# Specify the list of management interfaces to load during
# service initialization. Missing management interfaces, or
# management interfaces which fail to initialize, will prevent
# the ironic-conductor service from starting. The default
# value is a recommended set of production-oriented management
# interfaces. A complete list of management interfaces present
# on your system may be found by enumerating the
# "ironic.hardware.interfaces.management" entrypoint. When
# setting this value, please make sure that every enabled
# hardware type will have the same set of enabled management
# interfaces on every ironic-conductor service. (list value)
# the ironic-conductor service from starting. At least one
# management interface that is supported by each enabled
# hardware type must be enabled here, or the ironic-conductor
# service will not start. Must not be an empty list. The
# default value is a recommended set of production-oriented
# management interfaces. A complete list of management
# interfaces present on your system may be found by
# enumerating the "ironic.hardware.interfaces.management"
# entrypoint. When setting this value, please make sure that
# every enabled hardware type will have the same set of
# enabled management interfaces on every ironic-conductor
# service. (list value)
#enabled_management_interfaces = ipmitool
# Default management interface to be used for nodes that do
@ -142,8 +158,11 @@
# Specify the list of network interfaces to load during
# service initialization. Missing network interfaces, or
# network interfaces which fail to initialize, will prevent
# the ironic-conductor service from starting. The default
# value is a recommended set of production-oriented network
# the ironic-conductor service from starting. At least one
# network interface that is supported by each enabled hardware
# type must be enabled here, or the ironic-conductor service
# will not start. Must not be an empty list. The default value
# is a recommended set of production-oriented network
# interfaces. A complete list of network interfaces present on
# your system may be found by enumerating the
# "ironic.hardware.interfaces.network" entrypoint. When
@ -162,8 +181,11 @@
# Specify the list of power interfaces to load during service
# initialization. Missing power interfaces, or power
# interfaces which fail to initialize, will prevent the
# ironic-conductor service from starting. The default value is
# a recommended set of production-oriented power interfaces. A
# ironic-conductor service from starting. At least one power
# interface that is supported by each enabled hardware type
# must be enabled here, or the ironic-conductor service will
# not start. Must not be an empty list. The default value is a
# recommended set of production-oriented power interfaces. A
# complete list of power interfaces present on your system may
# be found by enumerating the
# "ironic.hardware.interfaces.power" entrypoint. When setting
@ -182,9 +204,12 @@
# Specify the list of raid interfaces to load during service
# initialization. Missing raid interfaces, or raid interfaces
# which fail to initialize, will prevent the ironic-conductor
# service from starting. The default value is a recommended
# set of production-oriented raid interfaces. A complete list
# of raid interfaces present on your system may be found by
# service from starting. At least one raid interface that is
# supported by each enabled hardware type must be enabled
# here, or the ironic-conductor service will not start. Must
# not be an empty list. The default value is a recommended set
# of production-oriented raid interfaces. A complete list of
# raid interfaces present on your system may be found by
# enumerating the "ironic.hardware.interfaces.raid"
# entrypoint. When setting this value, please make sure that
# every enabled hardware type will have the same set of
@ -201,8 +226,11 @@
# Specify the list of storage interfaces to load during
# service initialization. Missing storage interfaces, or
# storage interfaces which fail to initialize, will prevent
# the ironic-conductor service from starting. The default
# value is a recommended set of production-oriented storage
# the ironic-conductor service from starting. At least one
# storage interface that is supported by each enabled hardware
# type must be enabled here, or the ironic-conductor service
# will not start. Must not be an empty list. The default value
# is a recommended set of production-oriented storage
# interfaces. A complete list of storage interfaces present on
# your system may be found by enumerating the
# "ironic.hardware.interfaces.storage" entrypoint. When
@ -221,9 +249,12 @@
# Specify the list of vendor interfaces to load during service
# initialization. Missing vendor interfaces, or vendor
# interfaces which fail to initialize, will prevent the
# ironic-conductor service from starting. The default value is
# a recommended set of production-oriented vendor interfaces.
# A complete list of vendor interfaces present on your system
# ironic-conductor service from starting. At least one vendor
# interface that is supported by each enabled hardware type
# must be enabled here, or the ironic-conductor service will
# not start. Must not be an empty list. The default value is a
# recommended set of production-oriented vendor interfaces. A
# complete list of vendor interfaces present on your system
# may be found by enumerating the
# "ironic.hardware.interfaces.vendor" entrypoint. When setting
# this value, please make sure that every enabled hardware

View File

@ -34,6 +34,7 @@ from ironic.conductor import notification_utils as notify_utils
from ironic.conductor import task_manager
from ironic.conf import CONF
from ironic.db import api as dbapi
from ironic.drivers import base as driver_base
from ironic import objects
from ironic.objects import fields as obj_fields
@ -41,6 +42,28 @@ from ironic.objects import fields as obj_fields
LOG = log.getLogger(__name__)
def _check_enabled_interfaces():
"""Sanity-check enabled_*_interfaces configs.
We do this before we even bother to try to load up drivers. If we have any
dynamic drivers enabled, then we need interfaces enabled as well.
:raises: ConfigInvalid if an enabled interfaces config option is empty.
"""
if CONF.enabled_hardware_types:
empty_confs = []
iface_types = ['enabled_%s_interfaces' % i
for i in driver_base.ALL_INTERFACES]
for iface_type in iface_types:
conf_value = getattr(CONF, iface_type)
if not conf_value:
empty_confs.append(iface_type)
if empty_confs:
msg = (_('Configuration options %s cannot be an empty list.') %
', '.join(empty_confs))
raise exception.ConfigInvalid(error_msg=msg)
class BaseConductorManager(object):
def __init__(self, host, topic):
@ -83,6 +106,8 @@ class BaseConductorManager(object):
self.ring_manager = hash_ring.HashRingManager()
"""Consistent hash ring which maps drivers to conductors."""
_check_enabled_interfaces()
# NOTE(deva): these calls may raise DriverLoadError or DriverNotFound
# NOTE(vdrok): Instantiate network and storage interface factory on
# startup so that all the interfaces are loaded at the very

View File

@ -31,6 +31,10 @@ _ENABLED_IFACE_HELP = _('Specify the list of {0} interfaces to load during '
'service initialization. Missing {0} interfaces, '
'or {0} interfaces which fail to initialize, will '
'prevent the ironic-conductor service from starting. '
'At least one {0} interface that is supported by each '
'enabled hardware type must be enabled here, or the '
'ironic-conductor service will not start. '
'Must not be an empty list. '
'The default value is a recommended set of '
'production-oriented {0} interfaces. A complete '
'list of {0} interfaces present on your system may '

View File

@ -158,6 +158,17 @@ class StartStopTestCase(mgr_utils.ServiceSetUpMixin, tests_db_base.DbTestCase):
self.assertTrue(mock_df.called)
self.assertFalse(mock_reg.called)
def test_start_fails_on_no_enabled_interfaces(self):
self.config(enabled_boot_interfaces=[])
self.assertRaisesRegex(exception.ConfigInvalid,
'options enabled_boot_interfaces',
self.service.init_host)
def test_starts_without_enabled_hardware_types(self):
self.config(enabled_hardware_types=[])
self.config(enabled_boot_interfaces=[])
self._start_service()
@mock.patch.object(base_manager, 'LOG')
@mock.patch.object(driver_factory, 'HardwareTypesFactory')
@mock.patch.object(driver_factory, 'DriverFactory')
@ -240,6 +251,23 @@ class StartStopTestCase(mgr_utils.ServiceSetUpMixin, tests_db_base.DbTestCase):
self.assertTrue(wait_mock.called)
class CheckInterfacesTestCase(mgr_utils.ServiceSetUpMixin,
tests_db_base.DbTestCase):
def test__check_enabled_interfaces_success(self):
base_manager._check_enabled_interfaces()
def test__check_enabled_interfaces_failure(self):
self.config(enabled_boot_interfaces=[])
self.assertRaisesRegex(exception.ConfigInvalid,
'options enabled_boot_interfaces',
base_manager._check_enabled_interfaces)
def test__check_enabled_interfaces_skip_if_no_hw_types(self):
self.config(enabled_hardware_types=[])
self.config(enabled_boot_interfaces=[])
base_manager._check_enabled_interfaces()
class KeepAliveTestCase(mgr_utils.ServiceSetUpMixin, tests_db_base.DbTestCase):
def test__conductor_service_record_keepalive(self):
self._start_service()