Merge "Enable processing of active nodes"
This commit is contained in:
commit
c04f54ced0
@ -27,8 +27,11 @@ CONF = cfg.CONF
|
|||||||
LOG = utils.getProcessingLogger(__name__)
|
LOG = utils.getProcessingLogger(__name__)
|
||||||
|
|
||||||
# See https://docs.openstack.org/ironic/latest/contributor/states.html # noqa
|
# See https://docs.openstack.org/ironic/latest/contributor/states.html # noqa
|
||||||
VALID_STATES = {'enroll', 'manageable', 'inspecting', 'inspect wait',
|
VALID_STATES = frozenset(['enroll', 'manageable', 'inspecting', 'inspect wait',
|
||||||
'inspect failed'}
|
'inspect failed'])
|
||||||
|
|
||||||
|
# States where an instance is deployed and an admin may be doing something.
|
||||||
|
VALID_ACTIVE_STATES = frozenset(['active', 'rescue'])
|
||||||
|
|
||||||
# 1.38 is the latest API version in the Queens release series, 10.1.0.
|
# 1.38 is the latest API version in the Queens release series, 10.1.0.
|
||||||
# 1.46 is the latest API version in the Rocky release series, 11.1.0.
|
# 1.46 is the latest API version in the Rocky release series, 11.1.0.
|
||||||
@ -135,11 +138,27 @@ def get_client(token=None,
|
|||||||
|
|
||||||
|
|
||||||
def check_provision_state(node):
|
def check_provision_state(node):
|
||||||
|
"""Sanity checks the provision state of the node.
|
||||||
|
|
||||||
|
:param node: An API client returned node object describing
|
||||||
|
the baremetal node according to ironic's node
|
||||||
|
data model.
|
||||||
|
:returns: None if no action is to be taken, True if the
|
||||||
|
power node state should not be modified.
|
||||||
|
:raises: Error on an invalid state being detected.
|
||||||
|
"""
|
||||||
state = node.provision_state.lower()
|
state = node.provision_state.lower()
|
||||||
if state not in VALID_STATES:
|
if state not in VALID_STATES:
|
||||||
|
if (CONF.processing.permit_active_introspection
|
||||||
|
and state in VALID_ACTIVE_STATES):
|
||||||
|
# Hey, we can leave the power on! Lets return
|
||||||
|
# True to let the caller know.
|
||||||
|
return True
|
||||||
|
|
||||||
msg = _('Invalid provision state for introspection: '
|
msg = _('Invalid provision state for introspection: '
|
||||||
'"%(state)s", valid states are "%(valid)s"')
|
'"%(state)s", valid states are "%(valid)s"')
|
||||||
raise utils.Error(msg % {'state': state, 'valid': list(VALID_STATES)},
|
raise utils.Error(msg % {'state': state,
|
||||||
|
'valid': list(VALID_STATES)},
|
||||||
node_info=node)
|
node_info=node)
|
||||||
|
|
||||||
|
|
||||||
|
@ -94,7 +94,15 @@ _OPTS = [
|
|||||||
'{mac} - PXE booting MAC or "unknown".')),
|
'{mac} - PXE booting MAC or "unknown".')),
|
||||||
cfg.BoolOpt('power_off',
|
cfg.BoolOpt('power_off',
|
||||||
default=True,
|
default=True,
|
||||||
help=_('Whether to power off a node after introspection.')),
|
help=_('Whether to power off a node after introspection.'
|
||||||
|
'Nodes in active or rescue states which submit '
|
||||||
|
'introspection data will be left on if the feature '
|
||||||
|
'is enabled via the \'permit_active_introspection\' '
|
||||||
|
'configuration option.')),
|
||||||
|
cfg.BoolOpt('permit_active_introspection',
|
||||||
|
default=False,
|
||||||
|
help=_('Whether to process nodes that are in running '
|
||||||
|
'states.')),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -259,7 +259,8 @@ def _run_post_hooks(node_info, introspection_data):
|
|||||||
@node_cache.fsm_transition(istate.Events.process, reentrant=False)
|
@node_cache.fsm_transition(istate.Events.process, reentrant=False)
|
||||||
def _process_node(node_info, node, introspection_data):
|
def _process_node(node_info, node, introspection_data):
|
||||||
# NOTE(dtantsur): repeat the check in case something changed
|
# NOTE(dtantsur): repeat the check in case something changed
|
||||||
ir_utils.check_provision_state(node)
|
keep_power_on = ir_utils.check_provision_state(node)
|
||||||
|
|
||||||
_run_post_hooks(node_info, introspection_data)
|
_run_post_hooks(node_info, introspection_data)
|
||||||
store_introspection_data(node_info.uuid, introspection_data)
|
store_introspection_data(node_info.uuid, introspection_data)
|
||||||
|
|
||||||
@ -271,8 +272,13 @@ def _process_node(node_info, node, introspection_data):
|
|||||||
|
|
||||||
resp = {'uuid': node.uuid}
|
resp = {'uuid': node.uuid}
|
||||||
|
|
||||||
|
# determine how to handle power
|
||||||
|
if keep_power_on:
|
||||||
|
power_action = False
|
||||||
|
else:
|
||||||
|
power_action = CONF.processing.power_off
|
||||||
utils.executor().submit(_finish, node_info, ironic, introspection_data,
|
utils.executor().submit(_finish, node_info, ironic, introspection_data,
|
||||||
power_off=CONF.processing.power_off)
|
power_off=power_action)
|
||||||
|
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
@ -433,6 +433,30 @@ class TestProcessNode(BaseTest):
|
|||||||
post_hook_mock.assert_called_once_with(self.data, self.node_info)
|
post_hook_mock.assert_called_once_with(self.data, self.node_info)
|
||||||
finished_mock.assert_called_once_with(mock.ANY, istate.Events.finish)
|
finished_mock.assert_called_once_with(mock.ANY, istate.Events.finish)
|
||||||
|
|
||||||
|
@mock.patch.object(example_plugin.ExampleProcessingHook, 'before_update',
|
||||||
|
autospec=True)
|
||||||
|
@mock.patch.object(node_cache.NodeInfo, 'finished', autospec=True)
|
||||||
|
def test_ok_node_active(self, finished_mock, post_hook_mock):
|
||||||
|
self.node.provision_state = 'active'
|
||||||
|
CONF.set_override('permit_active_introspection', True, 'processing')
|
||||||
|
process._process_node(self.node_info, self.node, self.data)
|
||||||
|
|
||||||
|
self.cli.port.create.assert_any_call(node_uuid=self.uuid,
|
||||||
|
address=self.macs[0],
|
||||||
|
extra={},
|
||||||
|
pxe_enabled=True)
|
||||||
|
self.cli.port.create.assert_any_call(node_uuid=self.uuid,
|
||||||
|
address=self.macs[1],
|
||||||
|
extra={},
|
||||||
|
pxe_enabled=False)
|
||||||
|
|
||||||
|
self.cli.node.set_power_state.assert_not_called()
|
||||||
|
self.assertFalse(self.cli.node.validate.called)
|
||||||
|
|
||||||
|
post_hook_mock.assert_called_once_with(mock.ANY, self.data,
|
||||||
|
self.node_info)
|
||||||
|
finished_mock.assert_called_once_with(mock.ANY, istate.Events.finish)
|
||||||
|
|
||||||
def test_port_failed(self):
|
def test_port_failed(self):
|
||||||
self.cli.port.create.side_effect = (
|
self.cli.port.create.side_effect = (
|
||||||
[exceptions.Conflict()] + self.ports[1:])
|
[exceptions.Conflict()] + self.ports[1:])
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Adds the capability for introspection data to be posted to the API
|
||||||
|
when a baremetal node is in ``active`` or ``rescue`` states. This
|
||||||
|
feature may be useful for data center operators who wish to update
|
||||||
|
introspection data periodically.
|
||||||
|
|
||||||
|
To enable this feature, set ``[processing]permit_active_introspection``
|
||||||
|
to ``True``. When this is set, the value of ``[processing]power_off`` is
|
||||||
|
overridden for nodes in ``active`` or ``rescue`` states.
|
Loading…
Reference in New Issue
Block a user