Merge "Skip BMC detection in IPA for out-of-band management"

This commit is contained in:
Zuul
2025-11-22 07:07:43 +00:00
committed by Gerrit Code Review
3 changed files with 111 additions and 3 deletions
+21 -2
View File
@@ -43,7 +43,23 @@ _LOOKUP_RETURN_FIELDS = ['uuid', 'properties', 'instance_info',
AGENT_VALID_STATES = ['start', 'end', 'error']
def config(token):
def config(token, node=None):
# Skip BMC detection for out-of-band management interfaces where
# the BMC address is already known and configured in Ironic
skip_bmc_detect = False
if node:
mgmt_iface = getattr(node, 'management_interface', '')
# Out-of-band interfaces that don't need BMC detection
skip_bmc_detect = mgmt_iface in (
'redfish', 'idrac-redfish',
'ilo', 'ilo5', 'ilo6',
'irmc'
)
if skip_bmc_detect:
LOG.debug('Skipping BMC detection for node %(node)s with '
'out-of-band management interface %(interface)s',
{'node': node.uuid, 'interface': mgmt_iface})
return {
'metrics': {
'backend': CONF.metrics.agent_backend,
@@ -74,13 +90,16 @@ def config(token):
'agent_md5_checksum_enable': CONF.agent.allow_md5_checksum,
'disable_deep_image_inspection': CONF.conductor.disable_deep_image_inspection, # noqa
'permitted_image_formats': CONF.conductor.permitted_image_formats,
'agent_skip_bmc_detect': skip_bmc_detect,
}
def convert_with_links(node):
token = node.driver_internal_info.get('agent_secret_token')
# Keep raw node for management_interface check before conversion
raw_node = node
node = node_ctl.node_convert_with_links(node, _LOOKUP_RETURN_FIELDS)
return {'node': node, 'config': config(token)}
return {'node': node, 'config': config(token, raw_node)}
def get_valid_mac_addresses(addresses, node_uuid=None):
@@ -64,7 +64,7 @@ class TestLookup(test_api_base.BaseApiTest):
node.driver_internal_info = driver_internal
self.mock_get_node_with_token.return_value = node
def _check_config(self, data):
def _check_config(self, data, skip_bmc_detect=False):
expected_config = {
'agent_containers': {
'allow_arbitrary_containers': CONF.agent_containers
@@ -97,6 +97,7 @@ class TestLookup(test_api_base.BaseApiTest):
'agent_md5_checksum_enable': CONF.agent.allow_md5_checksum,
'disable_deep_image_inspection': CONF.conductor.disable_deep_image_inspection, # noqa
'permitted_image_formats': CONF.conductor.permitted_image_formats,
'agent_skip_bmc_detect': skip_bmc_detect,
}
self.assertEqual(expected_config, data['config'])
self.assertIsNotNone(data['config']['agent_token'])
@@ -226,6 +227,85 @@ class TestLookup(test_api_base.BaseApiTest):
headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(self.node.uuid, data['node']['uuid'])
def test_bmc_detect_skip_for_redfish(self):
"""Test BMC detection skip is enabled for Redfish interface."""
self.node.management_interface = 'redfish'
self.node.save()
self._set_secret_mock(self.node, 'test-token')
data = self.get_json(
'/lookup?node_uuid=%s' % self.node.uuid,
headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(self.node.uuid, data['node']['uuid'])
self._check_config(data, skip_bmc_detect=True)
def test_bmc_detect_skip_for_ilo_variants(self):
"""Test BMC detection skip is enabled for iLO variants."""
for ilo_interface in ['ilo', 'ilo5', 'ilo6']:
self.node.management_interface = ilo_interface
self.node.save()
self._set_secret_mock(self.node, 'test-token')
data = self.get_json(
'/lookup?node_uuid=%s' % self.node.uuid,
headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(self.node.uuid, data['node']['uuid'])
self._check_config(data, skip_bmc_detect=True)
def test_bmc_detect_skip_for_idrac_redfish(self):
"""Test BMC detection skip is enabled for iDRAC Redfish."""
self.node.management_interface = 'idrac-redfish'
self.node.save()
self._set_secret_mock(self.node, 'test-token')
data = self.get_json(
'/lookup?node_uuid=%s' % self.node.uuid,
headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(self.node.uuid, data['node']['uuid'])
self._check_config(data, skip_bmc_detect=True)
def test_bmc_detect_skip_for_irmc(self):
"""Test BMC detection skip is enabled for iRMC."""
self.node.management_interface = 'irmc'
self.node.save()
self._set_secret_mock(self.node, 'test-token')
data = self.get_json(
'/lookup?node_uuid=%s' % self.node.uuid,
headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(self.node.uuid, data['node']['uuid'])
self._check_config(data, skip_bmc_detect=True)
def test_bmc_detect_not_skipped_for_ipmi(self):
"""Test BMC detection is NOT skipped for IPMI interface."""
self.node.management_interface = 'ipmitool'
self.node.save()
self._set_secret_mock(self.node, 'test-token')
data = self.get_json(
'/lookup?node_uuid=%s' % self.node.uuid,
headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(self.node.uuid, data['node']['uuid'])
self._check_config(data, skip_bmc_detect=False)
def test_bmc_detect_not_skipped_for_fake(self):
"""Test BMC detection is NOT skipped for fake interface."""
self.node.management_interface = 'fake'
self.node.save()
self._set_secret_mock(self.node, 'test-token')
data = self.get_json(
'/lookup?node_uuid=%s' % self.node.uuid,
headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(self.node.uuid, data['node']['uuid'])
self._check_config(data, skip_bmc_detect=False)
@mock.patch.object(rpcapi.ConductorAPI, 'get_topic_for',
lambda *n: 'test-topic')
@@ -0,0 +1,9 @@
---
features:
- |
The lookup API now includes an ``agent_skip_bmc_detect`` configuration
flag that is automatically set to True when nodes use out-of-band
management interfaces (Redfish, iDRAC Redfish, iLO, iRMC). This tells
the agent to skip BMC detection via ipmitool, reducing deployment
time and avoiding unnecessary ipmitool calls when the BMC address is
already configured in Ironic.