diff options
Diffstat (limited to 'ironic/drivers/modules/drac/utils.py')
-rw-r--r-- | ironic/drivers/modules/drac/utils.py | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/ironic/drivers/modules/drac/utils.py b/ironic/drivers/modules/drac/utils.py new file mode 100644 index 000000000..21073d56e --- /dev/null +++ b/ironic/drivers/modules/drac/utils.py @@ -0,0 +1,121 @@ +# Copyright (c) 2021 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 +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from oslo_log import log +from oslo_utils import importutils + +from ironic.common import exception +from ironic.drivers.modules.redfish import utils as redfish_utils + +LOG = log.getLogger(__name__) + +sushy = importutils.try_import('sushy') + + +def execute_oem_manager_method( + task, process_name, lambda_oem_func, pass_manager=False): + """Loads OEM manager and executes passed method on it. + + Known iDRAC Redfish systems has only one manager, but as Redfish + schema allows a list this method iterates through all values in case + this changes in future. If there are several managers, this will + try starting from the first in the list until the first success. + + :param task: a TaskManager instance. + :param process_name: user friendly name of method to be executed. + Used in exception and log messages. + :param lambda_oem_func: method to execute as lambda function with + input parameter OEM extension manager. + Example: lambda m: m.reset_idrac() + For older versions also support second input parameter Redfish + manager itself when pass_manager set to True. + :param pass_manager: whether to pass manager itself to executed + OEM extension method. This is for backward compability, new + functions must not pass manager, but acquire it internally. Will + be removed in future. + :returns: Returned value of lambda_oem_func + :raises: RedfishError if can't execute OEM function either because + there are no managers to the system, failed to load OEM + extension or execution of the OEM method failed itself. + """ + + system = redfish_utils.get_system(task.node) + + if not system.managers: + raise exception.RedfishError( + "System %(system)s has no managers" % + {'system': system.uuid if system.uuid else system.identity}) + + oem_error_msgs = [] + for manager in system.managers: + # This call makes Sushy go fishing in the ocean of Sushy + # OEM extensions installed on the system. If it finds one + # for 'Dell' which implements the 'Manager' resource + # extension, it uses it to create an object which + # instantiates itself from the OEM JSON. The object is + # returned here. + # + # If the extension could not be found for one manager, it + # will not be found for any others until it is installed, so + # abruptly exit the for loop. The vendor and resource name, + # 'Dell' and 'Manager', respectively, used to search for the + # extension are invariant in the loop. + try: + manager_oem = manager.get_oem_extension('Dell') + except sushy.exceptions.OEMExtensionNotFoundError as e: + error_msg = (_("Search for Sushy OEM extension Python package " + "'sushy-oem-idrac' failed for node %(node)s. " + "Ensure it is installed. Error: %(error)s") % + {'node': task.node.uuid, 'error': e}) + LOG.error(error_msg) + raise exception.RedfishError(error=error_msg) + + try: + if pass_manager: + result = lambda_oem_func(manager_oem, manager) + else: + result = lambda_oem_func(manager_oem) + LOG.info("Completed: %(process_name)s with system %(system)s " + "manager %(manager)s for node %(node)s", + {'process_name': process_name, + 'system': system.uuid if system.uuid else + system.identity, + 'manager': manager.uuid if manager.uuid else + manager.identity, + 'node': task.node.uuid}) + return result + except sushy.exceptions.SushyError as e: + error_msg = (_("Manager %(manager)s: %(error)s" % + {'manager': manager.uuid if manager.uuid else + manager.identity, 'error': e})) + LOG.debug("Failed: %(process_name)s with system %(system)s " + "for node %(node)s. Will try next manager, if " + "available. Error: %(error)s", + {'process_name': process_name, + 'system': system.uuid if system.uuid else + system.identity, + 'node': task.node.uuid, + 'error': error_msg}) + oem_error_msgs.append(error_msg) + else: + error_msg = (_('In system %(system)s for node %(node)s all managers ' + 'failed: %(process_name)s. Errors: %(oem_error_msgs)s' % + {'system': system.uuid if system.uuid else + system.identity, + 'node': task.node.uuid, + 'process_name': process_name, + 'oem_error_msgs': oem_error_msgs if oem_error_msgs else + 'unknown'})) + LOG.error(error_msg) + raise exception.RedfishError(error=error_msg) |