summaryrefslogtreecommitdiff
path: root/ironic/drivers/modules/drac/utils.py
diff options
context:
space:
mode:
Diffstat (limited to 'ironic/drivers/modules/drac/utils.py')
-rw-r--r--ironic/drivers/modules/drac/utils.py121
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)