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