summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.openstack.org>2019-01-23 12:18:33 +0000
committerGerrit Code Review <review@openstack.org>2019-01-23 12:18:33 +0000
commit009f5768d0c8547b012ddf510f5de81c083db144 (patch)
treea0c6d4dabf82c9f17bbd46c270841842d7da8b8e
parent42792587835d97c30c8ec63da89ed259ad0a33bc (diff)
parent828ec3ee397eb96427927ecd5f57d6f1c23a4af2 (diff)
downloadironic-009f5768d0c8547b012ddf510f5de81c083db144.tar.gz
Merge "Fix OOB introspection to use pxe_enabled flag in idrac driver" into stable/rocky11.1.2
-rw-r--r--ironic/drivers/modules/drac/inspect.py53
-rw-r--r--ironic/tests/unit/drivers/modules/drac/test_inspect.py102
-rw-r--r--ironic/tests/unit/drivers/modules/drac/utils.py17
-rw-r--r--releasenotes/notes/update-port-pxe-enabled-f954f934209cbf5b.yaml7
4 files changed, 178 insertions, 1 deletions
diff --git a/ironic/drivers/modules/drac/inspect.py b/ironic/drivers/modules/drac/inspect.py
index bdccfd018..b452da6b0 100644
--- a/ironic/drivers/modules/drac/inspect.py
+++ b/ironic/drivers/modules/drac/inspect.py
@@ -119,11 +119,18 @@ class DracInspect(base.InspectInterface):
{'node_uuid': node.uuid, 'error': exc})
raise exception.HardwareInspectionFailure(error=exc)
+ pxe_dev_nics = self._get_pxe_dev_nics(client, nics, node)
+ if pxe_dev_nics is None:
+ LOG.warning('No PXE enabled NIC was found for node '
+ '%(node_uuid)s.', {'node_uuid': node.uuid})
+
for nic in nics:
try:
port = objects.Port(task.context, address=nic.mac,
- node_id=node.id)
+ node_id=node.id,
+ pxe_enabled=(nic.id in pxe_dev_nics))
port.create()
+
LOG.info('Port created with MAC address %(mac)s '
'for node %(node_uuid)s during inspection',
{'mac': nic.mac, 'node_uuid': node.uuid})
@@ -161,3 +168,47 @@ class DracInspect(base.InspectInterface):
return cpu.cores * 2
else:
return cpu.cores
+
+ def _get_pxe_dev_nics(self, client, nics, node):
+ """Get a list of pxe device interfaces.
+
+ :param client: Dracclient to list the bios settings and nics
+ :param nics: list of nics
+
+ :returns: Returns list of pxe device interfaces.
+ """
+ pxe_dev_nics = []
+ pxe_params = ["PxeDev1EnDis", "PxeDev2EnDis",
+ "PxeDev3EnDis", "PxeDev4EnDis"]
+ pxe_nics = ["PxeDev1Interface", "PxeDev2Interface",
+ "PxeDev3Interface", "PxeDev4Interface"]
+
+ try:
+ bios_settings = client.list_bios_settings()
+ except drac_exceptions.BaseClientException as exc:
+ LOG.error('DRAC driver failed to list bios settings '
+ 'for %(node_uuid)s. Reason: %(error)s.',
+ {'node_uuid': node.uuid, 'error': exc})
+ raise exception.HardwareInspectionFailure(error=exc)
+
+ if bios_settings["BootMode"].current_value == "Uefi":
+ for param, nic in zip(pxe_params, pxe_nics):
+ if param in bios_settings and bios_settings[
+ param].current_value == "Enabled":
+ pxe_dev_nics.append(
+ bios_settings[nic].current_value)
+ elif bios_settings["BootMode"].current_value == "Bios":
+ for nic in nics:
+ try:
+ nic_cap = client.list_nic_settings(nic_id=nic.id)
+ except drac_exceptions.BaseClientException as exc:
+ LOG.error('DRAC driver failed to list nic settings '
+ 'for %(node_uuid)s. Reason: %(error)s.',
+ {'node_uuid': node.uuid, 'error': exc})
+ raise exception.HardwareInspectionFailure(error=exc)
+
+ if ("LegacyBootProto" in nic_cap and nic_cap[
+ 'LegacyBootProto'].current_value == "PXE"):
+ pxe_dev_nics.append(nic.id)
+
+ return pxe_dev_nics
diff --git a/ironic/tests/unit/drivers/modules/drac/test_inspect.py b/ironic/tests/unit/drivers/modules/drac/test_inspect.py
index 1d650e29f..9ab83939f 100644
--- a/ironic/tests/unit/drivers/modules/drac/test_inspect.py
+++ b/ironic/tests/unit/drivers/modules/drac/test_inspect.py
@@ -121,6 +121,20 @@ class DracInspectionTestCase(test_utils.BaseDracTest):
'speed': '1000 Mbps',
'duplex': 'full duplex',
'media_type': 'Base T'}]
+ bios_boot_settings = {'BootMode': {'current_value': 'Bios'}}
+ uefi_boot_settings = {'BootMode': {'current_value': 'Uefi'},
+ 'PxeDev1EnDis': {'current_value': 'Enabled'},
+ 'PxeDev2EnDis': {'current_value': 'Disabled'},
+ 'PxeDev3EnDis': {'current_value': 'Disabled'},
+ 'PxeDev4EnDis': {'current_value': 'Disabled'},
+ 'PxeDev1Interface': {
+ 'current_value': 'NIC.Embedded.1-1-1'},
+ 'PxeDev2Interface': None,
+ 'PxeDev3Interface': None,
+ 'PxeDev4Interface': None}
+ nic_settings = {'LegacyBootProto': {'current_value': 'PXE'},
+ 'FQDD': 'NIC.Embedded.1-1-1'}
+
self.memory = [test_utils.dict_to_namedtuple(values=m) for m in memory]
self.cpus = [test_utils.dict_to_namedtuple(values=c) for c in cpus]
self.virtual_disks = [test_utils.dict_to_namedtuple(values=vd)
@@ -128,6 +142,9 @@ class DracInspectionTestCase(test_utils.BaseDracTest):
self.physical_disks = [test_utils.dict_to_namedtuple(values=pd)
for pd in physical_disks]
self.nics = [test_utils.dict_to_namedtuple(values=n) for n in nics]
+ self.bios_boot_settings = test_utils.dict_of_object(bios_boot_settings)
+ self.uefi_boot_settings = test_utils.dict_of_object(uefi_boot_settings)
+ self.nic_settings = test_utils.dict_of_object(nic_settings)
def test_get_properties(self):
expected = drac_common.COMMON_PROPERTIES
@@ -149,6 +166,7 @@ class DracInspectionTestCase(test_utils.BaseDracTest):
mock_client.list_cpus.return_value = self.cpus
mock_client.list_virtual_disks.return_value = self.virtual_disks
mock_client.list_nics.return_value = self.nics
+ mock_client.list_bios_settings.return_value = self.uefi_boot_settings
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
@@ -193,6 +211,7 @@ class DracInspectionTestCase(test_utils.BaseDracTest):
mock_client.list_virtual_disks.return_value = []
mock_client.list_physical_disks.return_value = self.physical_disks
mock_client.list_nics.return_value = self.nics
+ mock_client.list_bios_settings.return_value = self.uefi_boot_settings
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
@@ -237,6 +256,8 @@ class DracInspectionTestCase(test_utils.BaseDracTest):
mock_client.list_cpus.return_value = self.cpus
mock_client.list_virtual_disks.return_value = self.virtual_disks
mock_client.list_nics.return_value = self.nics
+ mock_client.list_bios_settings.return_value = self.uefi_boot_settings
+
mock_port_create.side_effect = exception.MACAlreadyExists("boom")
with task_manager.acquire(self.context, self.node.uuid,
@@ -271,3 +292,84 @@ class DracInspectionTestCase(test_utils.BaseDracTest):
self.cpus[1])
self.assertEqual(6, cpu)
+
+ @mock.patch.object(drac_common, 'get_drac_client', spec_set=True,
+ autospec=True)
+ def test__get_pxe_dev_nics_with_UEFI_boot_mode(self, mock_get_drac_client):
+ expected_pxe_nic = self.uefi_boot_settings[
+ 'PxeDev1Interface'].current_value
+ mock_client = mock.Mock()
+ mock_get_drac_client.return_value = mock_client
+ mock_client.list_bios_settings.return_value = self.uefi_boot_settings
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ pxe_dev_nics = task.driver.inspect._get_pxe_dev_nics(
+ mock_client, self.nics, self.node)
+
+ self.assertEqual(expected_pxe_nic, pxe_dev_nics[0])
+
+ @mock.patch.object(drac_common, 'get_drac_client', spec_set=True,
+ autospec=True)
+ def test__get_pxe_dev_nics_with_BIOS_boot_mode(self, mock_get_drac_client):
+ expected_pxe_nic = self.nic_settings['FQDD']
+ mock_client = mock.Mock()
+ mock_get_drac_client.return_value = mock_client
+ mock_client.list_bios_settings.return_value = self.bios_boot_settings
+ mock_client.list_nic_settings.return_value = self.nic_settings
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ pxe_dev_nics = task.driver.inspect._get_pxe_dev_nics(
+ mock_client, self.nics, self.node)
+
+ self.assertEqual(expected_pxe_nic, pxe_dev_nics[0])
+
+ @mock.patch.object(drac_common, 'get_drac_client', spec_set=True,
+ autospec=True)
+ def test__get_pxe_dev_nics_list_boot_setting_failure(self,
+ mock_get_drac_client):
+ mock_client = mock.Mock()
+ mock_get_drac_client.return_value = mock_client
+ mock_client.list_bios_settings.side_effect = (
+ drac_exceptions.BaseClientException('foo'))
+
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ self.assertRaises(exception.HardwareInspectionFailure,
+ task.driver.inspect._get_pxe_dev_nics,
+ mock_client,
+ self.nics,
+ self.node)
+
+ @mock.patch.object(drac_common, 'get_drac_client', spec_set=True,
+ autospec=True)
+ def test__get_pxe_dev_nics_list_nic_setting_failure(self,
+ mock_get_drac_client):
+ mock_client = mock.Mock()
+ mock_get_drac_client.return_value = mock_client
+ mock_client.list_bios_settings.return_value = self.bios_boot_settings
+ mock_client.list_nic_settings.side_effect = (
+ drac_exceptions.BaseClientException('bar'))
+
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ self.assertRaises(exception.HardwareInspectionFailure,
+ task.driver.inspect._get_pxe_dev_nics,
+ mock_client,
+ self.nics,
+ self.node)
+
+ @mock.patch.object(drac_common, 'get_drac_client', spec_set=True,
+ autospec=True)
+ def test__get_pxe_dev_nics_with_empty_list(self, mock_get_drac_client):
+ expected_pxe_nic = []
+ nic_setting = []
+ mock_client = mock.Mock()
+ mock_get_drac_client.return_value = mock_client
+ mock_client.list_bios_settings.return_value = self.bios_boot_settings
+ mock_client.list_nic_settings.return_value = nic_setting
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ pxe_dev_nics = task.driver.inspect._get_pxe_dev_nics(
+ mock_client, self.nics, self.node)
+
+ self.assertEqual(expected_pxe_nic, pxe_dev_nics)
diff --git a/ironic/tests/unit/drivers/modules/drac/utils.py b/ironic/tests/unit/drivers/modules/drac/utils.py
index 4884a2cd0..319c4f050 100644
--- a/ironic/tests/unit/drivers/modules/drac/utils.py
+++ b/ironic/tests/unit/drivers/modules/drac/utils.py
@@ -31,6 +31,13 @@ class BaseDracTest(db_base.DbTestCase):
enabled_raid_interfaces=['idrac', 'fake', 'no-raid'])
+class DictToObj(object):
+ """Returns a dictionary into a class"""
+ def __init__(self, dictionary):
+ for key in dictionary:
+ setattr(self, key, dictionary[key])
+
+
def dict_to_namedtuple(name='GenericNamedTuple', values=None):
"""Converts a dict to a collections.namedtuple"""
@@ -38,3 +45,13 @@ def dict_to_namedtuple(name='GenericNamedTuple', values=None):
values = {}
return collections.namedtuple(name, list(values))(**values)
+
+
+def dict_of_object(data):
+ """Create a dictionary object"""
+
+ for k, v in data.items():
+ if isinstance(v, dict):
+ dict_obj = DictToObj(v)
+ data[k] = dict_obj
+ return data
diff --git a/releasenotes/notes/update-port-pxe-enabled-f954f934209cbf5b.yaml b/releasenotes/notes/update-port-pxe-enabled-f954f934209cbf5b.yaml
new file mode 100644
index 000000000..1e0bfa1d1
--- /dev/null
+++ b/releasenotes/notes/update-port-pxe-enabled-f954f934209cbf5b.yaml
@@ -0,0 +1,7 @@
+---
+fixes:
+ - |
+ Fixes a bug where ironic port is not updated in node introspection as per
+ PXE enabled setting for ``idrac`` hardware type.
+ See bug `2004340
+ <https://storyboard.openstack.org/#!/story/2004340>`_ for details.