iLO-manager first main commitgit status
This commit is contained in:
1 parent
e6f4cc04ca
commit
599d8da562
3271 files changed
+550655
No files matched your search
@@ -0,0 +1,365 @@
|
||||
###
|
||||
# Copyright 2020 Hewlett Packard Enterprise, Inc. All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
###
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""Error response handler for Redfish or LegacryRest responses. Extended information only available
|
||||
with registries available on system, otherwise will return generic error responses."""
|
||||
import logging
|
||||
|
||||
from redfish.ris.ris import SessionExpired
|
||||
from redfish.ris.rmc_helper import (
|
||||
EmptyRaiseForEAFP,
|
||||
IdTokenError,
|
||||
IloLicenseError,
|
||||
IloResponseError,
|
||||
ScepenabledError,
|
||||
ValueChangedError,
|
||||
)
|
||||
from redfish.ris.utils import (
|
||||
get_errmsg_type,
|
||||
json_traversal,
|
||||
print_handler,
|
||||
warning_handler,
|
||||
)
|
||||
|
||||
# ---------Debug logger---------
|
||||
|
||||
LOGGER = logging.getLogger()
|
||||
|
||||
|
||||
# ---------End of debug logger---------
|
||||
|
||||
|
||||
class ResponseHandler(object):
|
||||
"""Class to handle error responses from the server.
|
||||
|
||||
:param validation_mgr: ValidationManager instance to gather registries if needed. Available
|
||||
in an RmcApp class as an attribute.
|
||||
:type validation_mgr: ValidationManager
|
||||
:param msg_reg_type: Redfish (#MessageRegistry.) or LegacyRest (MessageRegistry.)
|
||||
message registry string. Available in Typesandpathdefines class.
|
||||
:type msg_reg_type: str
|
||||
"""
|
||||
|
||||
def __init__(self, validaition_mgr, msg_type):
|
||||
self.validation_mgr = validaition_mgr
|
||||
self.msg_reg_type = msg_type
|
||||
|
||||
def output_resp(self, response, dl_reg=False, verbosity=1, stderr_flag=False):
|
||||
"""Prints or logs parsed MessageId response. Will raise an IloResponseError or return
|
||||
a list of message response data which includes the information returned from
|
||||
message_handler.
|
||||
|
||||
:param response: message response of a call.
|
||||
:type response: :class:`redfish.rest.containers.RestResponse`
|
||||
:param dl_reg: Flag to download registry. If this is set to True a generic message response
|
||||
will be returned instead of gathered from registries.
|
||||
:type dl_reg: bool
|
||||
:param verbosity: Optional verbosity level. Only modifies what is output to log or screen.
|
||||
:type verbosity: int
|
||||
:returns: List of error response dictionaries.
|
||||
"""
|
||||
retdata = None
|
||||
|
||||
if response.status > 299:
|
||||
message_text = "No error message returned or unable to parse error response."
|
||||
else:
|
||||
message_text = "The operation completed successfully."
|
||||
|
||||
if response.status < 300 and (response._rest_request.method == "GET" or not response.read):
|
||||
# for rawget
|
||||
if verbosity == 0:
|
||||
verbosity = 1
|
||||
print_handler(
|
||||
self.verbosity_levels(
|
||||
message=message_text, response_status=response.status, verbosity=verbosity, dl_reg=dl_reg
|
||||
),
|
||||
stderr_flag,
|
||||
)
|
||||
elif response.status == 401:
|
||||
raise SessionExpired()
|
||||
elif response.status == 403:
|
||||
results = response.dict["error"]["@Message.ExtendedInfo"]
|
||||
for result in results:
|
||||
if "License" in list(result.values())[0] or "license" in list(result.values())[0]:
|
||||
raise IloLicenseError("")
|
||||
raise IdTokenError()
|
||||
elif response.status == 412:
|
||||
warning_handler(
|
||||
"The property you are trying to change has been updated. "
|
||||
"Please check entry again before manipulating it.\n",
|
||||
override=True,
|
||||
)
|
||||
raise ValueChangedError()
|
||||
else:
|
||||
retdata = self.message_handler(
|
||||
response_data=response,
|
||||
verbosity=verbosity,
|
||||
message_text=message_text,
|
||||
dl_reg=dl_reg,
|
||||
stderr_flag=stderr_flag,
|
||||
)
|
||||
if response.status == 400:
|
||||
results = response.dict["error"]["@Message.ExtendedInfo"]
|
||||
for result in results:
|
||||
if "License" in list(result.values())[0] or "license" in list(result.values())[0]:
|
||||
raise IloLicenseError("")
|
||||
if "UnsupportedOperationACEEnabled" in list(result.values())[0]:
|
||||
raise ScepenabledError("")
|
||||
if response.status > 299:
|
||||
raise IloResponseError("")
|
||||
else:
|
||||
return retdata
|
||||
|
||||
def message_handler(self, response_data, verbosity=0, message_text="No Response", dl_reg=False, stderr_flag=False):
|
||||
"""Prints or logs parsed MessageId response based on verbosity level and returns the
|
||||
following message information in a list:
|
||||
|
||||
* MessageArgs
|
||||
* MessageId
|
||||
* RestResponse status
|
||||
* Resolution
|
||||
* Full error message text
|
||||
|
||||
:param response_data: message response of a call.
|
||||
:type response_data: :class:`redfish.rest.containers.RestResponse`
|
||||
:param verbosity: Optional verbosity level. Only modifies what is output to log or screen.
|
||||
:type verbosity: int
|
||||
:param message_text: Response message text. If not provided, message_handler will attempt to
|
||||
parse it from the RestResponse and registries.
|
||||
:type message_text: str
|
||||
:param dl_reg: Flag to download registry. If this is set to True a generic message response
|
||||
will be returned instead of gathered from registries.
|
||||
:type dl_reg: bool
|
||||
:returns: List of error response dictionaries.
|
||||
"""
|
||||
_tmp_message_id = _tmp_description = _tmp_resolution = message_text
|
||||
retlist = list()
|
||||
response_error_str = ""
|
||||
try:
|
||||
response_status = response_data.status
|
||||
except (AttributeError, ValueError):
|
||||
response_status = "???"
|
||||
try:
|
||||
response_data = response_data.dict
|
||||
except (AttributeError, ValueError):
|
||||
pass
|
||||
try:
|
||||
for inst in self.get_message_data(response_data, dl_reg):
|
||||
try:
|
||||
for _key in inst.keys():
|
||||
if "messageid" in str(_key.lower()):
|
||||
_tmp_message_id = inst[_key]
|
||||
if "description" in str(_key.lower()):
|
||||
_tmp_description = inst[_key]
|
||||
if inst.get("Message") and inst.get("MessageArgs"):
|
||||
for i in range(inst["Message"].count("%")):
|
||||
inst["Message"] = inst["Message"].replace(
|
||||
"%" + str(i + 1), '"' + inst["MessageArgs"][i] + '"'
|
||||
)
|
||||
message_text = inst.get("Message", " ")
|
||||
elif inst.get("Message"):
|
||||
message_text = inst.get("Message", " ")
|
||||
elif response_status not in [200, 201]:
|
||||
message_text = _tmp_message_id
|
||||
_tmp_resolution = inst.get("Resolution", " ")
|
||||
except (KeyError, ValueError, TypeError):
|
||||
pass
|
||||
finally:
|
||||
response_error_str += "[%s] %s\n" % (response_status, message_text)
|
||||
print_handler(
|
||||
self.verbosity_levels(
|
||||
message_text,
|
||||
_tmp_message_id,
|
||||
_tmp_description,
|
||||
_tmp_resolution,
|
||||
response_status,
|
||||
verbosity,
|
||||
dl_reg,
|
||||
),
|
||||
stderr_flag,
|
||||
)
|
||||
retlist.append(inst)
|
||||
except Exception:
|
||||
if not message_text:
|
||||
message_text = _tmp_message_id
|
||||
response_error_str += "[%s] %s\n" % (response_status, message_text)
|
||||
print_handler(
|
||||
self.verbosity_levels(
|
||||
message_text,
|
||||
_tmp_message_id,
|
||||
_tmp_description,
|
||||
_tmp_resolution,
|
||||
response_status,
|
||||
verbosity,
|
||||
dl_reg,
|
||||
)
|
||||
)
|
||||
retlist.append(inst)
|
||||
finally:
|
||||
return retlist
|
||||
|
||||
def get_message_data(self, resp_data, dl_reg=False):
|
||||
"""Obtain relevant keys from rest response.
|
||||
|
||||
:param resp: response
|
||||
:type resp: :class:`redfish.rest.containers.RestResponse`
|
||||
:returns: list of error response dictionaries
|
||||
"""
|
||||
err_response_keys = ["MessageId", "Message", "MessageArgs", "Resolution"]
|
||||
try:
|
||||
if "messageid" in [_key.lower() for _key in resp_data.keys()]:
|
||||
data_extract = [resp_data]
|
||||
else:
|
||||
raise TypeError
|
||||
except (TypeError, KeyError):
|
||||
data_extract = json_traversal(resp_data, "messageid", ret_dict=True)
|
||||
if data_extract:
|
||||
try:
|
||||
if not dl_reg:
|
||||
for inst in data_extract:
|
||||
if [key.lower() for key in inst.keys()] not in [erk.lower() for erk in err_response_keys]:
|
||||
# Find the key that matches 'messageid' (case-insensitive)
|
||||
for key in inst.keys():
|
||||
if key.lower() == "messageid":
|
||||
inst.update(self.get_error_messages(inst[key]))
|
||||
break
|
||||
finally:
|
||||
return data_extract
|
||||
else:
|
||||
return None
|
||||
|
||||
def verbosity_levels(
|
||||
self,
|
||||
message,
|
||||
messageid=" ",
|
||||
description=" ",
|
||||
resolution=" ",
|
||||
response_status=None,
|
||||
verbosity=0,
|
||||
dl_reg=False,
|
||||
):
|
||||
"""Formatting based on verbosity level.
|
||||
|
||||
:param message: Message from BMC response combined with the registry model/schema.
|
||||
:type message: str
|
||||
:param messageid: Error code as classified by the BMC's error code registry.
|
||||
:type messageid: str
|
||||
:param resolution: Message from BMC registry model/schema with the suggested
|
||||
resolution for the given error.
|
||||
:type resolution: str
|
||||
:param response_status: HTTP response status code.
|
||||
:type response_status: int
|
||||
:param verbosity: Option to set/control output message (stderr) verbosity.
|
||||
:type verbosity: int
|
||||
:returns: Message to be returned to caller.
|
||||
"""
|
||||
resp_str = ""
|
||||
if response_status:
|
||||
resp_str = "[" + str(response_status) + "] "
|
||||
|
||||
if (verbosity == 1 or dl_reg) and message:
|
||||
return resp_str + message + "\n"
|
||||
elif verbosity > 1 and messageid and message and resolution:
|
||||
if not resp_str:
|
||||
resp_str = "None "
|
||||
return (
|
||||
"\nHTTP Response Code: "
|
||||
+ resp_str[:-1]
|
||||
+ "\nMessageId: "
|
||||
+ messageid
|
||||
+ "\nDescription: "
|
||||
+ description
|
||||
+ "\nMessage: "
|
||||
+ message
|
||||
+ "\nResolution: "
|
||||
+ resolution
|
||||
+ "\n"
|
||||
)
|
||||
else:
|
||||
if response_status == 400:
|
||||
return "" + message + "\n"
|
||||
else:
|
||||
return ""
|
||||
|
||||
# unused? (removal pending)
|
||||
@staticmethod
|
||||
def _get_errmsg_type(results):
|
||||
"""Return the registry type of a response.
|
||||
|
||||
:param resuts: rest response.
|
||||
:type results: RestResponse.
|
||||
:returns: returns a Registry Id type string, None if not match is found, or no_id if the
|
||||
response is not an error message.
|
||||
"""
|
||||
return get_errmsg_type(results)
|
||||
|
||||
def get_error_messages(self, regtype=None):
|
||||
"""Returns registry error messages. Can specify a specific registry to return by Id.
|
||||
|
||||
:param regtype: Id of registry type to add to list.
|
||||
:type regtype: str
|
||||
:returns: A list of error messages.
|
||||
"""
|
||||
LOGGER.info("Entering validation...")
|
||||
messages = None
|
||||
errmessages = {}
|
||||
reglist = []
|
||||
|
||||
# An error occurred during the shortcut method so let's go through each registry,
|
||||
# obtain the schema and narrow down the selected schema for the registry type provided
|
||||
try:
|
||||
_regtype = regtype.split(".")[0]
|
||||
for reg in self.validation_mgr.iterregmems():
|
||||
# gen 10 / gen 9 rest
|
||||
if _regtype:
|
||||
if reg and "Id" in reg and reg["Id"] == _regtype:
|
||||
try:
|
||||
reglist.append(reg["Registry"])
|
||||
except KeyError:
|
||||
reglist.append(reg["Schema"])
|
||||
break
|
||||
else:
|
||||
continue
|
||||
|
||||
if not reglist:
|
||||
# gen 9 redfish
|
||||
regval = [reg.get(arg, None) for arg in ["Registry", "Schema", "Id"]]
|
||||
regval = next(
|
||||
(val for val in regval if val and "biosattributeregistry" not in val),
|
||||
None,
|
||||
)
|
||||
if not regval and reg:
|
||||
reg = reg["@odata.id"].split("/")
|
||||
reg = reg[len(reg) - 2]
|
||||
if "biosattributeregistry" not in reg.lower():
|
||||
reglist.append(reg)
|
||||
elif regval:
|
||||
reglist.append(regval)
|
||||
|
||||
for reg in reglist:
|
||||
reg = reg.replace("%23", "#")
|
||||
messages = self.validation_mgr.get_registry_model(
|
||||
getmsg=True, currtype=reg, searchtype=self.msg_reg_type
|
||||
)
|
||||
if messages:
|
||||
errmessages.update(messages.get(next(iter(messages)))[regtype.split(".")[-1]])
|
||||
if not reglist or not errmessages:
|
||||
raise Exception
|
||||
except Exception:
|
||||
raise EmptyRaiseForEAFP("Unable to find registry schema with provided registry " "type: %s" % regtype)
|
||||
else:
|
||||
return errmessages
|
||||
Reference in new issue
Block a user