From 03471be1ede078a31ca8e5d993e2f2dff1c07f69 Mon Sep 17 00:00:00 2001 From: Richard Pioso Date: Mon, 12 Aug 2019 18:08:04 -0400 Subject: [PATCH] Add first idrac HW type Redfish interface support This change adds initial idrac hardware type support of interface implementations that utilize the Redfish out-of-band (OOB) management protocol and are compatible with the integrated Dell Remote Access Controller (iDRAC) baseboard management controller (BMC), presently those of the management and power hardware interfaces. They are named 'idrac-redfish'. It also introduces a new name for the 'idrac' interface implementations, 'idrac-wsman', and deprecates 'idrac'. They both use the Web Services Management (WS-Man) OOB management protocol. The idrac hardware type declares support for those new interface implementations, in addition to all interface implementations it has been supporting. The priority order of supported interfaces remains the same. Interface implementations which rely on WS-Man continue to have the highest priority, and the new 'idrac-wsman' is listed before the deprecated 'idrac'. Story: 2004592 Task: 36275 Change-Id: I11f002eff78d27369b3dbe9a9fbd5fc73496a5eb --- ironic/drivers/drac.py | 13 +++-- ironic/drivers/modules/drac/inspect.py | 19 ++++++- ironic/drivers/modules/drac/management.py | 33 +++++++++++- ironic/drivers/modules/drac/power.py | 31 ++++++++++- ironic/drivers/modules/drac/raid.py | 19 ++++++- .../drivers/modules/drac/vendor_passthru.py | 23 +++++++- .../tests/unit/drivers/modules/drac/utils.py | 12 +++-- ironic/tests/unit/drivers/test_drac.py | 52 +++++++++++++++---- ...tial-redfish-support-27f27f18f3c1cd91.yaml | 44 ++++++++++++++++ setup.cfg | 7 +++ 10 files changed, 226 insertions(+), 27 deletions(-) create mode 100644 releasenotes/notes/idrac-add-initial-redfish-support-27f27f18f3c1cd91.yaml diff --git a/ironic/drivers/drac.py b/ironic/drivers/drac.py index 10fdc5c928..bef9b66017 100644 --- a/ironic/drivers/drac.py +++ b/ironic/drivers/drac.py @@ -38,12 +38,13 @@ class IDRACHardware(generic.GenericHardware): @property def supported_management_interfaces(self): """List of supported management interfaces.""" - return [management.DracManagement] + return [management.DracWSManManagement, management.DracManagement, + management.DracRedfishManagement] @property def supported_power_interfaces(self): """List of supported power interfaces.""" - return [power.DracPower] + return [power.DracWSManPower, power.DracPower, power.DracRedfishPower] # Optional hardware interfaces @@ -53,14 +54,16 @@ class IDRACHardware(generic.GenericHardware): # Inspector support should have a higher priority than NoInspect # if it is enabled by an operator (implying that the service is # installed). - return [drac_inspect.DracInspect, inspector.Inspector, noop.NoInspect] + return [drac_inspect.DracWSManInspect, drac_inspect.DracInspect, + inspector.Inspector, noop.NoInspect] @property def supported_raid_interfaces(self): """List of supported raid interfaces.""" - return [raid.DracRAID, noop.NoRAID] + return [raid.DracWSManRAID, raid.DracRAID, noop.NoRAID] @property def supported_vendor_interfaces(self): """List of supported vendor interfaces.""" - return [vendor_passthru.DracVendorPassthru, noop.NoVendor] + return [vendor_passthru.DracWSManVendorPassthru, + vendor_passthru.DracVendorPassthru, noop.NoVendor] diff --git a/ironic/drivers/modules/drac/inspect.py b/ironic/drivers/modules/drac/inspect.py index a8e5a6cde4..f871a2e3dd 100644 --- a/ironic/drivers/modules/drac/inspect.py +++ b/ironic/drivers/modules/drac/inspect.py @@ -35,7 +35,7 @@ LOG = logging.getLogger(__name__) METRICS = metrics_utils.get_metrics_logger(__name__) -class DracInspect(base.InspectInterface): +class DracWSManInspect(base.InspectInterface): def get_properties(self): """Return the properties of the interface. @@ -221,3 +221,20 @@ class DracInspect(base.InspectInterface): pxe_dev_nics.append(nic.id) return pxe_dev_nics + + +class DracInspect(DracWSManInspect): + """Class alias of class DracWSManInspect. + + This class provides ongoing support of the deprecated 'idrac' + inspect interface implementation entrypoint. + + All bug fixes and new features should be implemented in its base + class, DracWSManInspect. That makes them available to both the + deprecated 'idrac' and new 'idrac-wsman' entrypoints. Such changes + should not be made to this class. + """ + + def __init__(self): + LOG.warning("Inspect interface 'idrac' is deprecated and may be " + "removed in a future release. Use 'idrac-wsman' instead.") diff --git a/ironic/drivers/modules/drac/management.py b/ironic/drivers/modules/drac/management.py index a7da4e4749..37f9ca846c 100644 --- a/ironic/drivers/modules/drac/management.py +++ b/ironic/drivers/modules/drac/management.py @@ -2,7 +2,7 @@ # # Copyright 2014 Red Hat, Inc. # All Rights Reserved. -# Copyright (c) 2017-2018 Dell Inc. or its subsidiaries. +# Copyright (c) 2017-2019 Dell Inc. or its subsidiaries. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -34,6 +34,7 @@ from ironic.conf import CONF from ironic.drivers import base from ironic.drivers.modules.drac import common as drac_common from ironic.drivers.modules.drac import job as drac_job +from ironic.drivers.modules.redfish import management as redfish_management drac_exceptions = importutils.try_import('dracclient.exceptions') @@ -294,7 +295,18 @@ def set_boot_device(node, device, persistent=False): raise exception.DracOperationError(error=exc) -class DracManagement(base.ManagementInterface): +class DracRedfishManagement(redfish_management.RedfishManagement): + """iDRAC Redfish interface for management-related actions. + + 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 + + +class DracWSManManagement(base.ManagementInterface): def get_properties(self): """Return the properties of the interface.""" @@ -446,3 +458,20 @@ class DracManagement(base.ManagementInterface): '%(node_uuid)s. Reason: %(error)s.', {'node_uuid': node.uuid, 'error': exc}) raise exception.DracOperationError(error=exc) + + +class DracManagement(DracWSManManagement): + """Class alias of class DracWSManManagement. + + This class provides ongoing support of the deprecated 'idrac' + management interface implementation entrypoint. + + All bug fixes and new features should be implemented in its base + class, DracWSManManagement. That makes them available to both the + deprecated 'idrac' and new 'idrac-wsman' entrypoints. Such changes + should not be made to this class. + """ + + def __init__(self): + LOG.warning("Management interface 'idrac' is deprecated and may be " + "removed in a future release. Use 'idrac-wsman' instead.") diff --git a/ironic/drivers/modules/drac/power.py b/ironic/drivers/modules/drac/power.py index fe02fe5159..3ace62f7d8 100644 --- a/ironic/drivers/modules/drac/power.py +++ b/ironic/drivers/modules/drac/power.py @@ -25,6 +25,7 @@ from ironic.conductor import task_manager from ironic.drivers import base from ironic.drivers.modules.drac import common as drac_common from ironic.drivers.modules.drac import management as drac_management +from ironic.drivers.modules.redfish import power as redfish_power drac_constants = importutils.try_import('dracclient.constants') drac_exceptions = importutils.try_import('dracclient.exceptions') @@ -114,7 +115,18 @@ def _set_power_state(node, power_state): raise exception.DracOperationError(error=exc) -class DracPower(base.PowerInterface): +class DracRedfishPower(redfish_power.RedfishPower): + """iDRAC Redfish interface for power-related actions. + + 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 + + +class DracWSManPower(base.PowerInterface): """Interface for power-related actions.""" def get_properties(self): @@ -194,3 +206,20 @@ class DracPower(base.PowerInterface): target_power_state = states.POWER_ON _set_power_state(task.node, target_power_state) + + +class DracPower(DracWSManPower): + """Class alias of class DracWSManPower. + + This class provides ongoing support of the deprecated 'idrac' power + interface implementation entrypoint. + + All bug fixes and new features should be implemented in its base + class, DracWSManPower. That makes them available to both the + deprecated 'idrac' and new 'idrac-wsman' entrypoints. Such changes + should not be made to this class. + """ + + def __init__(self): + LOG.warning("Power interface 'idrac' is deprecated and may be removed " + "in a future release. Use 'idrac-wsman' instead.") diff --git a/ironic/drivers/modules/drac/raid.py b/ironic/drivers/modules/drac/raid.py index 751f9d950d..de5dd6af71 100644 --- a/ironic/drivers/modules/drac/raid.py +++ b/ironic/drivers/modules/drac/raid.py @@ -801,7 +801,7 @@ def _commit_to_controllers(node, controllers, substep="completed"): return states.CLEANWAIT -class DracRAID(base.RAIDInterface): +class DracWSManRAID(base.RAIDInterface): def get_properties(self): """Return the properties of the interface.""" @@ -1093,3 +1093,20 @@ class DracRAID(base.RAIDInterface): task.node.driver_internal_info = driver_internal_info task.node.save() manager_utils.notify_conductor_resume_clean(task) + + +class DracRAID(DracWSManRAID): + """Class alias of class DracWSManRAID. + + This class provides ongoing support of the deprecated 'idrac' RAID + interface implementation entrypoint. + + All bug fixes and new features should be implemented in its base + class, DracWSManRAID. That makes them available to both the + deprecated 'idrac' and new 'idrac-wsman' entrypoints. Such changes + should not be made to this class. + """ + + def __init__(self): + LOG.warning("RAID interface 'idrac' is deprecated and may be removed " + "in a future release. Use 'idrac-wsman' instead.") diff --git a/ironic/drivers/modules/drac/vendor_passthru.py b/ironic/drivers/modules/drac/vendor_passthru.py index 1bf708a847..620ea93e1a 100644 --- a/ironic/drivers/modules/drac/vendor_passthru.py +++ b/ironic/drivers/modules/drac/vendor_passthru.py @@ -16,6 +16,7 @@ DRAC vendor-passthru interface """ from ironic_lib import metrics_utils +from oslo_log import log as logging from ironic.common.i18n import _ from ironic.conductor import task_manager @@ -24,10 +25,12 @@ from ironic.drivers.modules.drac import bios as drac_bios from ironic.drivers.modules.drac import common as drac_common from ironic.drivers.modules.drac import job as drac_job +LOG = logging.getLogger(__name__) + METRICS = metrics_utils.get_metrics_logger(__name__) -class DracVendorPassthru(base.VendorInterface): +class DracWSManVendorPassthru(base.VendorInterface): """Interface for DRAC specific methods.""" def get_properties(self): @@ -168,3 +171,21 @@ class DracVendorPassthru(base.VendorInterface): jobs = drac_job.list_unfinished_jobs(task.node) # FIXME(mgould) Do this without calling private methods. return {'unfinished_jobs': [job._asdict() for job in jobs]} + + +class DracVendorPassthru(DracWSManVendorPassthru): + """Class alias of class DracWSManVendorPassthru. + + This class provides ongoing support of the deprecated 'idrac' vendor + passthru interface implementation entrypoint. + + All bug fixes and new features should be implemented in its base + class, DracWSManVendorPassthru. That makes them available to both + the deprecated 'idrac' and new 'idrac-wsman' entrypoints. Such + changes should not be made to this class. + """ + + def __init__(self): + LOG.warning("Vendor passthru interface 'idrac' is deprecated and may " + "be removed in a future release. Use 'idrac-wsman' " + "instead.") diff --git a/ironic/tests/unit/drivers/modules/drac/utils.py b/ironic/tests/unit/drivers/modules/drac/utils.py index b65260924c..f9bc6fc634 100644 --- a/ironic/tests/unit/drivers/modules/drac/utils.py +++ b/ironic/tests/unit/drivers/modules/drac/utils.py @@ -29,11 +29,13 @@ class BaseDracTest(db_base.DbTestCase): def setUp(self): super(BaseDracTest, self).setUp() self.config(enabled_hardware_types=['idrac', 'fake-hardware'], - enabled_power_interfaces=['idrac', 'fake'], - enabled_management_interfaces=['idrac', 'fake'], - enabled_inspect_interfaces=['idrac', 'fake', 'no-inspect'], - enabled_vendor_interfaces=['idrac', 'fake', 'no-vendor'], - enabled_raid_interfaces=['idrac', 'fake', 'no-raid']) + enabled_power_interfaces=['idrac-wsman', 'fake'], + enabled_management_interfaces=['idrac-wsman', 'fake'], + enabled_inspect_interfaces=[ + 'idrac-wsman', 'fake', 'no-inspect'], + enabled_vendor_interfaces=[ + 'idrac-wsman', 'fake', 'no-vendor'], + enabled_raid_interfaces=['idrac-wsman', 'fake', 'no-raid']) class DictToObj(object): diff --git a/ironic/tests/unit/drivers/test_drac.py b/ironic/tests/unit/drivers/test_drac.py index dc08566c63..69dd89eb96 100644 --- a/ironic/tests/unit/drivers/test_drac.py +++ b/ironic/tests/unit/drivers/test_drac.py @@ -1,4 +1,4 @@ -# Copyright (c) 2017 Dell Inc. or its subsidiaries. +# Copyright (c) 2017-2019 Dell Inc. or its subsidiaries. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -30,13 +30,17 @@ class IDRACHardwareTestCase(db_base.DbTestCase): def setUp(self): super(IDRACHardwareTestCase, self).setUp() self.config(enabled_hardware_types=['idrac'], - enabled_management_interfaces=['idrac'], - enabled_power_interfaces=['idrac'], + enabled_management_interfaces=[ + 'idrac', 'idrac-wsman', 'idrac-redfish'], + enabled_power_interfaces=[ + 'idrac', 'idrac-wsman', 'idrac-redfish'], enabled_inspect_interfaces=[ - 'idrac', 'inspector', 'no-inspect'], + 'idrac', 'idrac-wsman', 'inspector', 'no-inspect'], enabled_network_interfaces=['flat', 'neutron', 'noop'], - enabled_raid_interfaces=['idrac', 'no-raid'], - enabled_vendor_interfaces=['idrac', 'no-vendor']) + enabled_raid_interfaces=[ + 'idrac', 'idrac-wsman', 'no-raid'], + enabled_vendor_interfaces=[ + 'idrac', 'idrac-wsman', 'no-vendor']) def _validate_interfaces(self, driver, **kwargs): self.assertIsInstance( @@ -47,10 +51,10 @@ class IDRACHardwareTestCase(db_base.DbTestCase): kwargs.get('deploy', iscsi_deploy.ISCSIDeploy)) self.assertIsInstance( driver.management, - kwargs.get('management', drac.management.DracManagement)) + kwargs.get('management', drac.management.DracWSManManagement)) self.assertIsInstance( driver.power, - kwargs.get('power', drac.power.DracPower)) + kwargs.get('power', drac.power.DracWSManPower)) self.assertIsInstance( driver.console, @@ -58,7 +62,7 @@ class IDRACHardwareTestCase(db_base.DbTestCase): self.assertIsInstance( driver.inspect, - kwargs.get('inspect', drac.inspect.DracInspect)) + kwargs.get('inspect', drac.inspect.DracWSManInspect)) self.assertIsInstance( driver.network, @@ -66,7 +70,7 @@ class IDRACHardwareTestCase(db_base.DbTestCase): self.assertIsInstance( driver.raid, - kwargs.get('raid', drac.raid.DracRAID)) + kwargs.get('raid', drac.raid.DracWSManRAID)) self.assertIsInstance( driver.storage, @@ -74,7 +78,7 @@ class IDRACHardwareTestCase(db_base.DbTestCase): self.assertIsInstance( driver.vendor, - kwargs.get('vendor', drac.vendor_passthru.DracVendorPassthru)) + kwargs.get('vendor', drac.vendor_passthru.DracWSManVendorPassthru)) def test_default_interfaces(self): node = obj_utils.create_test_node(self.context, driver='idrac') @@ -110,3 +114,29 @@ class IDRACHardwareTestCase(db_base.DbTestCase): with task_manager.acquire(self.context, node.id) as task: self._validate_interfaces(task.driver, vendor=noop.NoVendor) + + def test_override_with_idrac(self): + node = obj_utils.create_test_node(self.context, driver='idrac', + management_interface='idrac', + power_interface='idrac', + inspect_interface='idrac', + raid_interface='idrac', + vendor_interface='idrac') + with task_manager.acquire(self.context, node.id) as task: + self._validate_interfaces( + task.driver, + management=drac.management.DracManagement, + power=drac.power.DracPower, + inspect=drac.inspect.DracInspect, + raid=drac.raid.DracRAID, + vendor=drac.vendor_passthru.DracVendorPassthru) + + def test_override_with_redfish_management_and_power(self): + node = obj_utils.create_test_node(self.context, driver='idrac', + management_interface='idrac-redfish', + power_interface='idrac-redfish') + with task_manager.acquire(self.context, node.id) as task: + self._validate_interfaces( + task.driver, + management=drac.management.DracRedfishManagement, + power=drac.power.DracRedfishPower) diff --git a/releasenotes/notes/idrac-add-initial-redfish-support-27f27f18f3c1cd91.yaml b/releasenotes/notes/idrac-add-initial-redfish-support-27f27f18f3c1cd91.yaml new file mode 100644 index 0000000000..cf624b13c1 --- /dev/null +++ b/releasenotes/notes/idrac-add-initial-redfish-support-27f27f18f3c1cd91.yaml @@ -0,0 +1,44 @@ +--- +features: + - | + Adds initial ``idrac`` hardware type support of interface + implementations that utilize the Redfish out-of-band (OOB) + management protocol and are compatible with the integrated Dell + Remote Access Controller (iDRAC) baseboard management controller + (BMC), presently those of the management and power hardware + interfaces. They are named ``idrac-redfish``. + + Introduces a new name for the ``idrac`` interface implementations, + ``idrac-wsman``, and deprecates ``idrac``. They both use the Web + Services Management (WS-Man) OOB management protocol. + + The ``idrac`` hardware type declares support for those new interface + implementations, in addition to all interface implementations it has + been supporting. The priority order of supported interfaces remains + the same. Interface implementations which rely on WS-Man continue to + have the highest priority, and the new ``idrac-wsman`` is listed + before the deprecated ``idrac``. It now supports the following + interface implementations, which are listed in priority order from + highest to lowest: + + * bios: ``no-bios`` + * boot: ``ipxe``, ``pxe`` + * console: ``no-console`` + * deploy: ``iscsi``, ``direct``, ``ansible``, ``ramdisk`` + * inspect: ``idrac-wsman``, ``idrac``, ``inspector``, ``no-inspect`` + * management: ``idrac-wsman``, ``idrac``, ``idrac-redfish`` + * network: ``flat``, ``neutron``, ``noop`` + * power: ``idrac-wsman``, ``idrac``, ``idrac-redfish`` + * raid: ``idrac-wsman``, ``idrac``, ``no-raid`` + * rescue: ``no-rescue``, ``agent`` + * storage: ``noop``, ``cinder``, ``external`` + * vendor: ``idrac-wsman``, ``idrac``, ``no-vendor`` + + For more information, see `story 2004592 + `_. +deprecations: + - | + The ``idrac`` interface implementation name is deprecated in favor + of a new name, ``idrac-wsman``, and may be removed in a future + release. A deprecation warning will be logged for every loaded + ``idrac`` interface implementation. Use ``idrac-wsman`` instead. diff --git a/setup.cfg b/setup.cfg index d5d5e91fff..ada0c88cad 100644 --- a/setup.cfg +++ b/setup.cfg @@ -89,6 +89,7 @@ ironic.hardware.interfaces.deploy = ironic.hardware.interfaces.inspect = fake = ironic.drivers.modules.fake:FakeInspect idrac = ironic.drivers.modules.drac.inspect:DracInspect + idrac-wsman = ironic.drivers.modules.drac.inspect:DracWSManInspect ilo = ironic.drivers.modules.ilo.inspect:IloInspect inspector = ironic.drivers.modules.inspector:Inspector irmc = ironic.drivers.modules.irmc.inspect:IRMCInspect @@ -99,6 +100,8 @@ ironic.hardware.interfaces.management = fake = ironic.drivers.modules.fake:FakeManagement ibmc = ironic.drivers.modules.ibmc.management:IBMCManagement idrac = ironic.drivers.modules.drac.management:DracManagement + idrac-redfish = ironic.drivers.modules.drac.management:DracRedfishManagement + idrac-wsman = ironic.drivers.modules.drac.management:DracWSManManagement ilo = ironic.drivers.modules.ilo.management:IloManagement ilo5 = ironic.drivers.modules.ilo.management:Ilo5Management intel-ipmitool = ironic.drivers.modules.intel_ipmi.management:IntelIPMIManagement @@ -117,6 +120,8 @@ ironic.hardware.interfaces.power = fake = ironic.drivers.modules.fake:FakePower ibmc = ironic.drivers.modules.ibmc.power:IBMCPower idrac = ironic.drivers.modules.drac.power:DracPower + idrac-redfish = ironic.drivers.modules.drac.power:DracRedfishPower + idrac-wsman = ironic.drivers.modules.drac.power:DracWSManPower ilo = ironic.drivers.modules.ilo.power:IloPower ipmitool = ironic.drivers.modules.ipmitool:IPMIPower irmc = ironic.drivers.modules.irmc.power:IRMCPower @@ -128,6 +133,7 @@ ironic.hardware.interfaces.raid = agent = ironic.drivers.modules.agent:AgentRAID fake = ironic.drivers.modules.fake:FakeRAID idrac = ironic.drivers.modules.drac.raid:DracRAID + idrac-wsman = ironic.drivers.modules.drac.raid:DracWSManRAID ilo5 = ironic.drivers.modules.ilo.raid:Ilo5RAID irmc = ironic.drivers.modules.irmc.raid:IRMCRAID no-raid = ironic.drivers.modules.noop:NoRAID @@ -147,6 +153,7 @@ ironic.hardware.interfaces.vendor = fake = ironic.drivers.modules.fake:FakeVendorB ibmc = ironic.drivers.modules.ibmc.vendor:IBMCVendor idrac = ironic.drivers.modules.drac.vendor_passthru:DracVendorPassthru + idrac-wsman = ironic.drivers.modules.drac.vendor_passthru:DracWSManVendorPassthru ilo = ironic.drivers.modules.ilo.vendor:VendorPassthru ipmitool = ironic.drivers.modules.ipmitool:VendorPassthru no-vendor = ironic.drivers.modules.noop:NoVendor