DRAC : idrac-redfish inspect updates pxe port
Extends generic Redfish OOB inspection to add setting pxe_enabled on the discovered ports for the idrac hardware type. It retrieves the list of PXE device MAC addresses using an OEM extension to the Redfish API if necessary and updates the pxe_enabled field of Port. Change-Id: Ife8387a3bdb75717b896cf1067d2490084665e49 Story: 2006819 Task: 37380 Co-Authored-By: Mahendra Kamble <mahendra.kamble358@gmail.com> Co-Authored-By: Sonali Borkar <sonaliborkar85@gmail.com>
This commit is contained in:
parent
8e34aa53ce
commit
7d82d7f3dd
@ -20,31 +20,147 @@ from oslo_log import log as logging
|
|||||||
from oslo_utils import importutils
|
from oslo_utils import importutils
|
||||||
from oslo_utils import units
|
from oslo_utils import units
|
||||||
|
|
||||||
|
from ironic.common import boot_modes
|
||||||
from ironic.common import exception
|
from ironic.common import exception
|
||||||
from ironic.common.i18n import _
|
from ironic.common.i18n import _
|
||||||
from ironic.common import states
|
from ironic.common import states
|
||||||
from ironic.common import utils
|
from ironic.common import utils
|
||||||
from ironic.drivers import base
|
from ironic.drivers import base
|
||||||
from ironic.drivers.modules.drac import common as drac_common
|
from ironic.drivers.modules.drac import common as drac_common
|
||||||
|
from ironic.drivers.modules import inspect_utils
|
||||||
from ironic.drivers.modules.redfish import inspect as redfish_inspect
|
from ironic.drivers.modules.redfish import inspect as redfish_inspect
|
||||||
|
from ironic.drivers.modules.redfish import utils as redfish_utils
|
||||||
from ironic import objects
|
from ironic import objects
|
||||||
|
|
||||||
drac_exceptions = importutils.try_import('dracclient.exceptions')
|
drac_exceptions = importutils.try_import('dracclient.exceptions')
|
||||||
|
sushy = importutils.try_import('sushy')
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
METRICS = metrics_utils.get_metrics_logger(__name__)
|
METRICS = metrics_utils.get_metrics_logger(__name__)
|
||||||
|
|
||||||
|
_PXE_DEV_ENABLED_INTERFACES = [('PxeDev1EnDis', 'PxeDev1Interface'),
|
||||||
|
('PxeDev2EnDis', 'PxeDev2Interface'),
|
||||||
|
('PxeDev3EnDis', 'PxeDev3Interface'),
|
||||||
|
('PxeDev4EnDis', 'PxeDev4Interface')]
|
||||||
|
_BIOS_ENABLED_VALUE = 'Enabled'
|
||||||
|
|
||||||
|
|
||||||
class DracRedfishInspect(redfish_inspect.RedfishInspect):
|
class DracRedfishInspect(redfish_inspect.RedfishInspect):
|
||||||
"""iDRAC Redfish interface for inspection-related actions.
|
"""iDRAC Redfish interface for inspection-related actions."""
|
||||||
|
|
||||||
|
def inspect_hardware(self, task):
|
||||||
|
"""Inspect hardware to get the hardware properties.
|
||||||
|
|
||||||
|
Inspects hardware to get the essential properties.
|
||||||
|
It fails if any of the essential properties
|
||||||
|
are not received from the node.
|
||||||
|
|
||||||
|
:param task: a TaskManager instance.
|
||||||
|
:raises: HardwareInspectionFailure if essential properties
|
||||||
|
could not be retrieved successfully.
|
||||||
|
:returns: The resulting state of inspection.
|
||||||
|
|
||||||
Presently, this class entirely defers to its base class, a generic,
|
|
||||||
vendor-independent Redfish interface. Future resolution of Dell EMC-
|
|
||||||
specific incompatibilities and introduction of vendor value added
|
|
||||||
should be implemented by this class.
|
|
||||||
"""
|
"""
|
||||||
pass
|
# Ensure we create a port for every NIC port found for consistency
|
||||||
|
# with our WSMAN inspect behavior and to work around a bug in some
|
||||||
|
# versions of the firmware where the port state is not being
|
||||||
|
# reported correctly.
|
||||||
|
|
||||||
|
ethernet_interfaces_mac = self._get_mac_address(task)
|
||||||
|
inspect_utils.create_ports_if_not_exist(task, ethernet_interfaces_mac)
|
||||||
|
return super(DracRedfishInspect, self).inspect_hardware(task)
|
||||||
|
|
||||||
|
def _get_mac_address(self, task):
|
||||||
|
"""Get a list of MAC addresses
|
||||||
|
|
||||||
|
:param task: a TaskManager instance.
|
||||||
|
:returns: Returns list of MAC addresses.
|
||||||
|
"""
|
||||||
|
system = redfish_utils.get_system(task.node)
|
||||||
|
# Get dictionary of ethernet interfaces
|
||||||
|
if system.ethernet_interfaces and system.ethernet_interfaces.summary:
|
||||||
|
ethernet_interfaces = system.ethernet_interfaces.get_members()
|
||||||
|
ethernet_interfaces_mac = {
|
||||||
|
interface.identity: interface.mac_address
|
||||||
|
for interface in ethernet_interfaces}
|
||||||
|
return ethernet_interfaces_mac
|
||||||
|
else:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def _get_pxe_port_macs(self, task):
|
||||||
|
"""Get a list of PXE port MAC addresses.
|
||||||
|
|
||||||
|
:param task: a TaskManager instance.
|
||||||
|
:returns: Returns list of PXE port MAC addresses.
|
||||||
|
"""
|
||||||
|
system = redfish_utils.get_system(task.node)
|
||||||
|
ethernet_interfaces_mac = self._get_mac_address(task)
|
||||||
|
pxe_port_macs = []
|
||||||
|
|
||||||
|
if system.boot.mode == boot_modes.UEFI:
|
||||||
|
# When a server is in UEFI boot mode, the PXE NIC ports are
|
||||||
|
# stored in the PxeDevXEnDis and PxeDevXInterface BIOS
|
||||||
|
# settings. Get the PXE NIC ports from these settings and
|
||||||
|
# their MAC addresses.
|
||||||
|
for param, nic in _PXE_DEV_ENABLED_INTERFACES:
|
||||||
|
if system.bios.attributes[param] == _BIOS_ENABLED_VALUE:
|
||||||
|
nic_id = system.bios.attributes[nic]
|
||||||
|
# Get MAC address of the given nic_id
|
||||||
|
mac_address = ethernet_interfaces_mac[nic_id]
|
||||||
|
pxe_port_macs.append(mac_address)
|
||||||
|
elif system.boot.mode == boot_modes.LEGACY_BIOS:
|
||||||
|
# When a server is in BIOS boot mode, whether or not a
|
||||||
|
# NIC port is set to PXE boot is stored on the NIC port
|
||||||
|
# itself internally to the BMC. Getting this information
|
||||||
|
# requires using an OEM extension to export the system
|
||||||
|
# configuration, as the redfish standard does not specify
|
||||||
|
# how to get it, and Dell does not have OEM redfish calls
|
||||||
|
# to selectively retrieve it at this time.
|
||||||
|
# Get instance of Sushy OEM manager object
|
||||||
|
|
||||||
|
for manager in system.managers:
|
||||||
|
try:
|
||||||
|
# Get instance of Sushy OEM manager object
|
||||||
|
oem_manager = manager.get_oem_extension('Dell')
|
||||||
|
except sushy.exceptions.OEMExtensionNotFoundError as e:
|
||||||
|
error_msg = (_("Search for Sushy OEM extension package "
|
||||||
|
"'sushy-oem-idrac' failed for node "
|
||||||
|
"%(node)s. Ensure it's installed. "
|
||||||
|
" Error: %(error)s") %
|
||||||
|
{'node': task.node.uuid, 'error': e})
|
||||||
|
LOG.error(error_msg)
|
||||||
|
raise exception.RedfishError(error=error_msg)
|
||||||
|
|
||||||
|
try:
|
||||||
|
pxe_port_macs_list = oem_manager.get_pxe_port_macs_bios(
|
||||||
|
ethernet_interfaces_mac)
|
||||||
|
pxe_port_macs = [mac for mac in pxe_port_macs_list]
|
||||||
|
return pxe_port_macs
|
||||||
|
except sushy.exceptions.OEMExtensionNotFoundError as e:
|
||||||
|
error_msg = (_("Search for Sushy OEM extension package "
|
||||||
|
"'sushy-oem-idrac' failed for node "
|
||||||
|
" %(node)s. Ensure it is installed. "
|
||||||
|
"Error: %(error)s") %
|
||||||
|
{'node': task.node.uuid, 'error': e})
|
||||||
|
LOG.debug(error_msg)
|
||||||
|
continue
|
||||||
|
LOG.info("Get pxe port MAC addresses for %(node)s via OEM",
|
||||||
|
{'node': task.node.uuid})
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
error_msg = (_('iDRAC Redfish Get pxe port MAC addresse '
|
||||||
|
'failed for node %(node)s, because system '
|
||||||
|
'%(system)s has no '
|
||||||
|
'manager%(no_manager)s.') %
|
||||||
|
{'node': task.node.uuid,
|
||||||
|
'system': system.uuid if system.uuid else
|
||||||
|
system.identity,
|
||||||
|
'no_manager': '' if not system.managers else
|
||||||
|
' which could'})
|
||||||
|
LOG.error(error_msg)
|
||||||
|
raise exception.RedfishError(error=error_msg)
|
||||||
|
return pxe_port_macs
|
||||||
|
|
||||||
|
|
||||||
class DracWSManInspect(base.InspectInterface):
|
class DracWSManInspect(base.InspectInterface):
|
||||||
|
@ -26,6 +26,7 @@ from ironic.drivers import base
|
|||||||
from ironic.drivers.modules import inspect_utils
|
from ironic.drivers.modules import inspect_utils
|
||||||
from ironic.drivers.modules.redfish import utils as redfish_utils
|
from ironic.drivers.modules.redfish import utils as redfish_utils
|
||||||
from ironic.drivers import utils as drivers_utils
|
from ironic.drivers import utils as drivers_utils
|
||||||
|
from ironic import objects
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
@ -157,6 +158,32 @@ class RedfishInspect(base.InspectInterface):
|
|||||||
|
|
||||||
self._create_ports(task, system)
|
self._create_ports(task, system)
|
||||||
|
|
||||||
|
pxe_port_macs = self._get_pxe_port_macs(task)
|
||||||
|
if pxe_port_macs is None:
|
||||||
|
LOG.warning("No PXE enabled NIC was found for node "
|
||||||
|
"%(node_uuid)s.", {'node_uuid': task.node.uuid})
|
||||||
|
else:
|
||||||
|
pxe_port_macs = [macs.lower() for macs in pxe_port_macs]
|
||||||
|
|
||||||
|
ports = objects.Port.list_by_node_id(task.context, task.node.id)
|
||||||
|
if ports:
|
||||||
|
for port in ports:
|
||||||
|
is_baremetal_pxe_port = (port.address.lower()
|
||||||
|
in pxe_port_macs)
|
||||||
|
if port.pxe_enabled != is_baremetal_pxe_port:
|
||||||
|
port.pxe_enabled = is_baremetal_pxe_port
|
||||||
|
port.save()
|
||||||
|
LOG.info('Port %(port)s having %(mac_address)s '
|
||||||
|
'updated with pxe_enabled %(pxe)s for '
|
||||||
|
'node %(node_uuid)s during inspection',
|
||||||
|
{'port': port.uuid,
|
||||||
|
'mac_address': port.address,
|
||||||
|
'pxe': port.pxe_enabled,
|
||||||
|
'node_uuid': task.node.uuid})
|
||||||
|
else:
|
||||||
|
LOG.warning("No port information discovered "
|
||||||
|
"for node %(node)s", {'node': task.node.uuid})
|
||||||
|
|
||||||
return states.MANAGEABLE
|
return states.MANAGEABLE
|
||||||
|
|
||||||
def _create_ports(self, task, system):
|
def _create_ports(self, task, system):
|
||||||
@ -236,3 +263,12 @@ class RedfishInspect(base.InspectInterface):
|
|||||||
# value by 1 GB as consumers like Ironic requires the ``local_gb``
|
# value by 1 GB as consumers like Ironic requires the ``local_gb``
|
||||||
# to be returned 1 less than actual size.
|
# to be returned 1 less than actual size.
|
||||||
return max(0, int(local_gb / units.Gi - 1))
|
return max(0, int(local_gb / units.Gi - 1))
|
||||||
|
|
||||||
|
def _get_pxe_port_macs(self, task):
|
||||||
|
"""Get a list of PXE port MAC addresses.
|
||||||
|
|
||||||
|
:param task: a TaskManager instance.
|
||||||
|
:returns: Returns list of PXE port MAC addresses.
|
||||||
|
If cannot be determined, returns None.
|
||||||
|
"""
|
||||||
|
return None
|
||||||
|
@ -18,16 +18,23 @@ Test class for DRAC inspection interface
|
|||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
from dracclient import exceptions as drac_exceptions
|
from dracclient import exceptions as drac_exceptions
|
||||||
|
from oslo_utils import importutils
|
||||||
|
from oslo_utils import units
|
||||||
|
|
||||||
from ironic.common import exception
|
from ironic.common import exception
|
||||||
from ironic.common import states
|
from ironic.common import states
|
||||||
from ironic.conductor import task_manager
|
from ironic.conductor import task_manager
|
||||||
from ironic.drivers.modules.drac import common as drac_common
|
from ironic.drivers.modules.drac import common as drac_common
|
||||||
from ironic.drivers.modules.drac import inspect as drac_inspect
|
from ironic.drivers.modules.drac import inspect as drac_inspect
|
||||||
|
from ironic.drivers.modules import inspect_utils
|
||||||
|
from ironic.drivers.modules.redfish import inspect as redfish_inspect
|
||||||
|
from ironic.drivers.modules.redfish import utils as redfish_utils
|
||||||
from ironic import objects
|
from ironic import objects
|
||||||
from ironic.tests.unit.drivers.modules.drac import utils as test_utils
|
from ironic.tests.unit.drivers.modules.drac import utils as test_utils
|
||||||
from ironic.tests.unit.objects import utils as obj_utils
|
from ironic.tests.unit.objects import utils as obj_utils
|
||||||
|
|
||||||
|
sushy = importutils.try_import('sushy')
|
||||||
|
|
||||||
INFO_DICT = test_utils.INFO_DICT
|
INFO_DICT = test_utils.INFO_DICT
|
||||||
|
|
||||||
|
|
||||||
@ -538,3 +545,158 @@ class DracInspectionTestCase(test_utils.BaseDracTest):
|
|||||||
mock_client, self.nics, self.node)
|
mock_client, self.nics, self.node)
|
||||||
|
|
||||||
self.assertEqual(expected_pxe_nic, pxe_dev_nics)
|
self.assertEqual(expected_pxe_nic, pxe_dev_nics)
|
||||||
|
|
||||||
|
|
||||||
|
class DracRedfishInspectionTestCase(test_utils.BaseDracTest):
|
||||||
|
def setUp(self):
|
||||||
|
super(DracRedfishInspectionTestCase, self).setUp()
|
||||||
|
self.config(enabled_hardware_types=['idrac'],
|
||||||
|
enabled_power_interfaces=['idrac-redfish'],
|
||||||
|
enabled_management_interfaces=['idrac-redfish'],
|
||||||
|
enabled_inspect_interfaces=['idrac-redfish'])
|
||||||
|
self.node = obj_utils.create_test_node(
|
||||||
|
self.context, driver='idrac',
|
||||||
|
driver_info=INFO_DICT)
|
||||||
|
|
||||||
|
def init_system_mock(self, system_mock, **properties):
|
||||||
|
system_mock.reset()
|
||||||
|
system_mock.boot.mode = 'uefi'
|
||||||
|
system_mock.bios.attributes = {
|
||||||
|
'PxeDev1EnDis': 'Enabled', 'PxeDev2EnDis': 'Disabled',
|
||||||
|
'PxeDev3EnDis': 'Disabled', 'PxeDev4EnDis': 'Disabled',
|
||||||
|
'PxeDev1Interface': 'NIC.Integrated.1-1-1',
|
||||||
|
'PxeDev2Interface': None, 'PxeDev3Interface': None,
|
||||||
|
'PxeDev4Interface': None}
|
||||||
|
|
||||||
|
system_mock.memory_summary.size_gib = 2
|
||||||
|
|
||||||
|
system_mock.processors.summary = '8', 'MIPS'
|
||||||
|
|
||||||
|
system_mock.simple_storage.disks_sizes_bytes = (
|
||||||
|
1 * units.Gi, units.Gi * 3, units.Gi * 5)
|
||||||
|
system_mock.storage.volumes_sizes_bytes = (
|
||||||
|
2 * units.Gi, units.Gi * 4, units.Gi * 6)
|
||||||
|
|
||||||
|
system_mock.ethernet_interfaces.summary = {
|
||||||
|
'00:11:22:33:44:55': sushy.STATE_ENABLED,
|
||||||
|
'24:6E:96:70:49:00': sushy.STATE_DISABLED}
|
||||||
|
member_data = [{
|
||||||
|
'description': 'Integrated NIC 1 Port 1 Partition 1',
|
||||||
|
'name': 'System Ethernet Interface',
|
||||||
|
'full_duplex': False,
|
||||||
|
'identity': 'NIC.Integrated.1-1-1',
|
||||||
|
'mac_address': '24:6E:96:70:49:00',
|
||||||
|
'mtu_size': None,
|
||||||
|
'speed_mbps': 0,
|
||||||
|
'vlan': None}]
|
||||||
|
system_mock.ethernet_interfaces.get_members.return_value = [
|
||||||
|
test_utils.dict_to_namedtuple(values=interface)
|
||||||
|
for interface in member_data
|
||||||
|
]
|
||||||
|
return system_mock
|
||||||
|
|
||||||
|
def test_get_properties(self):
|
||||||
|
expected = redfish_utils.COMMON_PROPERTIES
|
||||||
|
driver = drac_inspect.DracRedfishInspect()
|
||||||
|
self.assertEqual(expected, driver.get_properties())
|
||||||
|
|
||||||
|
@mock.patch.object(redfish_utils, 'get_system', autospec=True)
|
||||||
|
def test__get_pxe_port_macs_with_UEFI_boot_mode(self, mock_get_system):
|
||||||
|
system_mock = self.init_system_mock(mock_get_system.return_value)
|
||||||
|
system_mock.boot.mode = 'uefi'
|
||||||
|
expected_pxe_mac = ['24:6E:96:70:49:00']
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
pxe_port_macs = task.driver.inspect._get_pxe_port_macs(task)
|
||||||
|
self.assertEqual(expected_pxe_mac, pxe_port_macs)
|
||||||
|
|
||||||
|
@mock.patch.object(redfish_utils, 'get_system', autospec=True)
|
||||||
|
def test__get_pxe_port_macs_with_BIOS_boot_mode(self, mock_get_system):
|
||||||
|
system_mock = self.init_system_mock(mock_get_system.return_value)
|
||||||
|
system_mock.boot.mode = 'bios'
|
||||||
|
mock_manager = mock.MagicMock()
|
||||||
|
system_mock.managers = [mock_manager]
|
||||||
|
mock_manager_oem = mock_manager.get_oem_extension.return_value
|
||||||
|
mock_manager_oem.get_pxe_port_macs_bios.return_value = \
|
||||||
|
['24:6E:96:70:49:00']
|
||||||
|
expected_pxe_mac = ['24:6E:96:70:49:00']
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
pxe_port_macs = task.driver.inspect._get_pxe_port_macs(task)
|
||||||
|
self.assertEqual(expected_pxe_mac, pxe_port_macs)
|
||||||
|
|
||||||
|
@mock.patch.object(redfish_utils, 'get_system', autospec=True)
|
||||||
|
def test__get_pxe_port_macs_without_boot_mode(self, mock_get_system):
|
||||||
|
system_mock = self.init_system_mock(mock_get_system.return_value)
|
||||||
|
system_mock.boot.mode = None
|
||||||
|
expected_pxe_mac = []
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
pxe_port_macs = task.driver.inspect._get_pxe_port_macs(task)
|
||||||
|
self.assertEqual(expected_pxe_mac, pxe_port_macs)
|
||||||
|
|
||||||
|
@mock.patch.object(redfish_utils, 'get_system', autospec=True)
|
||||||
|
def test__get_pxe_port_macs_missing_oem(self, mock_get_system):
|
||||||
|
mock_system = self.init_system_mock(mock_get_system.return_value)
|
||||||
|
mock_manager = mock.MagicMock()
|
||||||
|
mock_system.boot.mode = 'bios'
|
||||||
|
mock_system.managers = [mock_manager]
|
||||||
|
set_mgr = (
|
||||||
|
mock_manager.get_oem_extension.return_value.get_pxe_port_macs_bios)
|
||||||
|
set_mgr.side_effect = sushy.exceptions.OEMExtensionNotFoundError
|
||||||
|
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=False) as task:
|
||||||
|
self.assertRaises(exception.RedfishError,
|
||||||
|
task.driver.inspect._get_pxe_port_macs,
|
||||||
|
task)
|
||||||
|
|
||||||
|
@mock.patch.object(redfish_utils, 'get_system', autospec=True)
|
||||||
|
def test__get_pxe_port_macs_no_manager(self, mock_get_system):
|
||||||
|
mock_system = self.init_system_mock(mock_get_system.return_value)
|
||||||
|
mock_system.boot.mode = 'bios'
|
||||||
|
mock_system.managers = []
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
self.assertRaises(exception.RedfishError,
|
||||||
|
task.driver.inspect._get_pxe_port_macs,
|
||||||
|
task)
|
||||||
|
|
||||||
|
@mock.patch.object(redfish_inspect.RedfishInspect, 'inspect_hardware',
|
||||||
|
autospec=True)
|
||||||
|
@mock.patch.object(inspect_utils, 'create_ports_if_not_exist',
|
||||||
|
autospec=True)
|
||||||
|
def test_inspect_hardware_with_ethernet_interfaces_mac(
|
||||||
|
self, mock_create_ports_if_not_exist, mock_inspect_hardware):
|
||||||
|
ethernet_interfaces_mac = {'NIC.Integrated.1-1-1':
|
||||||
|
'24:6E:96:70:49:00'}
|
||||||
|
mock_inspect_hardware.return_value = states.MANAGEABLE
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
task.driver.inspect._get_mac_address = mock.Mock()
|
||||||
|
task.driver.inspect._get_mac_address.return_value = \
|
||||||
|
ethernet_interfaces_mac
|
||||||
|
return_value = task.driver.inspect.inspect_hardware(task)
|
||||||
|
self.assertEqual(states.MANAGEABLE, return_value)
|
||||||
|
mock_create_ports_if_not_exist.assert_called_once_with(
|
||||||
|
task, ethernet_interfaces_mac)
|
||||||
|
|
||||||
|
@mock.patch.object(redfish_utils, 'get_system', autospec=True)
|
||||||
|
def test__get_mac_address_with_ethernet_interfaces(self, mock_get_system):
|
||||||
|
self.init_system_mock(mock_get_system.return_value)
|
||||||
|
expected_value = {'NIC.Integrated.1-1-1': '24:6E:96:70:49:00'}
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
return_value = task.driver.inspect._get_mac_address(task)
|
||||||
|
self.assertEqual(expected_value, return_value)
|
||||||
|
|
||||||
|
@mock.patch.object(redfish_utils, 'get_system', autospec=True)
|
||||||
|
def test__get_mac_address_without_ethernet_interfaces(self,
|
||||||
|
mock_get_system):
|
||||||
|
mock_system = self.init_system_mock(mock_get_system.return_value)
|
||||||
|
mock_system.ethernet_interfaces.summary = None
|
||||||
|
expected_value = {}
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
return_value = task.driver.inspect._get_mac_address(task)
|
||||||
|
self.assertEqual(expected_value, return_value)
|
||||||
|
@ -19,9 +19,12 @@ from oslo_utils import importutils
|
|||||||
from oslo_utils import units
|
from oslo_utils import units
|
||||||
|
|
||||||
from ironic.common import exception
|
from ironic.common import exception
|
||||||
|
from ironic.common import states
|
||||||
from ironic.conductor import task_manager
|
from ironic.conductor import task_manager
|
||||||
from ironic.drivers.modules import inspect_utils
|
from ironic.drivers.modules import inspect_utils
|
||||||
|
from ironic.drivers.modules.redfish import inspect
|
||||||
from ironic.drivers.modules.redfish import utils as redfish_utils
|
from ironic.drivers.modules.redfish import utils as redfish_utils
|
||||||
|
from ironic import objects
|
||||||
from ironic.tests.unit.db import base as db_base
|
from ironic.tests.unit.db import base as db_base
|
||||||
from ironic.tests.unit.db import utils as db_utils
|
from ironic.tests.unit.db import utils as db_utils
|
||||||
from ironic.tests.unit.objects import utils as obj_utils
|
from ironic.tests.unit.objects import utils as obj_utils
|
||||||
@ -235,3 +238,105 @@ class RedfishInspectTestCase(db_base.DbTestCase):
|
|||||||
}
|
}
|
||||||
task.driver.inspect.inspect_hardware(task)
|
task.driver.inspect.inspect_hardware(task)
|
||||||
self.assertEqual(expected_properties, task.node.properties)
|
self.assertEqual(expected_properties, task.node.properties)
|
||||||
|
|
||||||
|
@mock.patch.object(objects.Port, 'list_by_node_id') # noqa
|
||||||
|
@mock.patch.object(redfish_utils, 'get_system', autospec=True)
|
||||||
|
def test_inspect_hardware_with_set_port_pxe_enabled(
|
||||||
|
self, mock_get_system, mock_list_by_node_id):
|
||||||
|
self.init_system_mock(mock_get_system.return_value)
|
||||||
|
|
||||||
|
pxe_disabled_port = obj_utils.create_test_port(
|
||||||
|
self.context, uuid=self.node.uuid, node_id=self.node.id,
|
||||||
|
address='24:6E:96:70:49:00', pxe_enabled=False)
|
||||||
|
mock_list_by_node_id.return_value = [pxe_disabled_port]
|
||||||
|
port = mock_list_by_node_id.return_value
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
task.driver.inspect._get_pxe_port_macs = mock.Mock()
|
||||||
|
task.driver.inspect._get_pxe_port_macs.return_value = \
|
||||||
|
['24:6E:96:70:49:00']
|
||||||
|
task.driver.inspect.inspect_hardware(task)
|
||||||
|
self.assertTrue(port[0].pxe_enabled)
|
||||||
|
|
||||||
|
@mock.patch.object(objects.Port, 'list_by_node_id') # noqa
|
||||||
|
@mock.patch.object(redfish_utils, 'get_system', autospec=True)
|
||||||
|
def test_inspect_hardware_with_set_port_pxe_disabled(
|
||||||
|
self, mock_get_system, mock_list_by_node_id):
|
||||||
|
self.init_system_mock(mock_get_system.return_value)
|
||||||
|
|
||||||
|
pxe_enabled_port = obj_utils.create_test_port(
|
||||||
|
self.context, uuid=self.node.uuid,
|
||||||
|
node_id=self.node.id, address='24:6E:96:70:49:01',
|
||||||
|
pxe_enabled=True)
|
||||||
|
mock_list_by_node_id.return_value = [pxe_enabled_port]
|
||||||
|
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
task.driver.inspect._get_pxe_port_macs = mock.Mock()
|
||||||
|
task.driver.inspect._get_pxe_port_macs.return_value = \
|
||||||
|
['24:6E:96:70:49:00']
|
||||||
|
task.driver.inspect.inspect_hardware(task)
|
||||||
|
port = mock_list_by_node_id.return_value
|
||||||
|
self.assertFalse(port[0].pxe_enabled)
|
||||||
|
|
||||||
|
@mock.patch.object(objects.Port, 'list_by_node_id') # noqa
|
||||||
|
@mock.patch.object(redfish_utils, 'get_system', autospec=True)
|
||||||
|
def test_inspect_hardware_with_empty_pxe_port_macs(
|
||||||
|
self, mock_get_system, mock_list_by_node_id):
|
||||||
|
self.init_system_mock(mock_get_system.return_value)
|
||||||
|
|
||||||
|
pxe_enabled_port = obj_utils.create_test_port(
|
||||||
|
self.context, uuid=self.node.uuid,
|
||||||
|
node_id=self.node.id, address='24:6E:96:70:49:01',
|
||||||
|
pxe_enabled=True)
|
||||||
|
mock_list_by_node_id.return_value = [pxe_enabled_port]
|
||||||
|
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
task.driver.inspect._get_pxe_port_macs = mock.Mock()
|
||||||
|
task.driver.inspect._get_pxe_port_macs.return_value = []
|
||||||
|
return_value = task.driver.inspect.inspect_hardware(task)
|
||||||
|
port = mock_list_by_node_id.return_value
|
||||||
|
self.assertFalse(port[0].pxe_enabled)
|
||||||
|
self.assertEqual(states.MANAGEABLE, return_value)
|
||||||
|
|
||||||
|
@mock.patch.object(objects.Port, 'list_by_node_id') # noqa
|
||||||
|
@mock.patch.object(redfish_utils, 'get_system', autospec=True)
|
||||||
|
@mock.patch.object(inspect.LOG, 'warning', autospec=True)
|
||||||
|
def test_inspect_hardware_with_none_pxe_port_macs(
|
||||||
|
self, mock_log, mock_get_system, mock_list_by_node_id):
|
||||||
|
self.init_system_mock(mock_get_system.return_value)
|
||||||
|
|
||||||
|
pxe_enabled_port = obj_utils.create_test_port(
|
||||||
|
self.context, uuid=self.node.uuid,
|
||||||
|
node_id=self.node.id, address='24:6E:96:70:49:01',
|
||||||
|
pxe_enabled=True)
|
||||||
|
mock_list_by_node_id.return_value = [pxe_enabled_port]
|
||||||
|
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
task.driver.inspect._get_pxe_port_macs = mock.Mock()
|
||||||
|
task.driver.inspect._get_pxe_port_macs.return_value = None
|
||||||
|
task.driver.inspect.inspect_hardware(task)
|
||||||
|
port = mock_list_by_node_id.return_value
|
||||||
|
self.assertTrue(port[0].pxe_enabled)
|
||||||
|
mock_log.assert_called_once()
|
||||||
|
|
||||||
|
@mock.patch.object(redfish_utils, 'get_system', autospec=True)
|
||||||
|
def test_create_port_when_its_state_is_none(self, mock_get_system):
|
||||||
|
self.init_system_mock(mock_get_system.return_value)
|
||||||
|
expected_port_mac_list = ["00:11:22:33:44:55", "24:6e:96:70:49:00"]
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
task.driver.inspect.inspect_hardware(task)
|
||||||
|
ports = objects.Port.list_by_node_id(task.context, self.node.id)
|
||||||
|
for port in ports:
|
||||||
|
self.assertIn(port.address, expected_port_mac_list)
|
||||||
|
|
||||||
|
def test_get_pxe_port_macs(self):
|
||||||
|
expected_properties = None
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
task.driver.inspect._get_pxe_port_macs(task)
|
||||||
|
self.assertEqual(expected_properties,
|
||||||
|
task.driver.inspect._get_pxe_port_macs(task))
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Adds support for the discovery of PXE Enabled NICs using the
|
||||||
|
``idrac-redfish`` inspect interface with the ``idrac`` hardware
|
||||||
|
type. With this feature, a port's ``pxe_enabled`` status will
|
||||||
|
be recorded on the bare metal port.
|
Loading…
Reference in New Issue
Block a user