Add setBootOveride config support to redfishtool
The recent upgrade of redfishtool from 1.1.5 to 1.1.8 introduced a change that added a BootSourceOverrideMode key:value pair to the payload of the 'setBootOverride Once <target>' patch request. An issue was found were some or all servers from a manufacturer exhibit undesirable behavior when the 'setBootOverride Once <target>' patch request payload includes a BootSourceOverrideMode key:value pair. The undesirable behavior ranges from outright command failure or triggers the BMC to run a time consuming BIOS reconfiguraiton job followed by an extra reboot. This update remedies that by introducing a configuration file and source code patch to the opensource redfishtool package and uses the contents of the new configuraiton file and patch to change the behavior of the setBootOverride command handling for select servers. The configuration file contains a setBootOverride_overrides section with two BootSourceOverrideMode exclude string lists, one of server models and one of server manufacturers. [setBootOverride_overrides] exclude_BootSourceOverrideMode_Models = "<model>", "<model>" exclude_BootSourceOverrideMode_Manufacturers = "<manufacturer>" This update allows the new configuration file to be populated with server model or manufacturer names that should exclude (not include) the BootSourceOverrideMode as part of the payload thereby avoiding the undesirable behavior. If current server is found in either the models or manufacturers lists then it is excluded from getting the BootSourceOverrideMode key:value pair added to the 'setBootOverride Once <target>' patch request. Test Plan: PASS: Verify build and install of patched opensource redfishtool pkg PASS: Verify install of AIO SX/AIO DX PASS: - with/without excluded servers PASS: - IPV4 and IPV6 PASS: Verify DC system install with HPE servers PASS: Verify handling defaults to no exclusions if PASS: - the new config file is missing PASS: - the setBootOverride_overrides section is missing PASS: - both exclude_BootSourceOverrideMode lists are missing PASS: Verify handling when exclude_BootSourceOverrideMode lists PASS: - are missing or empty. PASS: - contain a badly formatted string like a missing a quote PASS: Verify handling if a server provides an empty PASS: - model string PASS: - manufacturer string PASS: Verify newly added debug logging (level 4 with -vvvv) PASS: Verify HPE server setBootOverride Once Pxe works Closes-Bug: 2091879 Change-Id: Idcee7be6edc62438fe29a9e8ce031ee94328e508 Signed-off-by: Eric MacDonald <eric.macdonald@windriver.com>
This commit is contained in:
parent
6705cfca37
commit
4217f4ba6d
@ -1,3 +1,4 @@
|
||||
usr/bin/redfishtool
|
||||
usr/bin/redfishtool.py
|
||||
usr/lib/python3/dist-packages/redfishtoollib/*
|
||||
etc/redfishtool/redfishtool.ini
|
||||
|
@ -9,4 +9,5 @@ export PBR_VERSION=1.0.0
|
||||
dh $@ --with python3 --buildsystem=pybuild
|
||||
|
||||
override_dh_install:
|
||||
# nothing to do here
|
||||
mkdir -p $(CURDIR)/debian/redfishtool/etc/redfishtool
|
||||
cp $(CURDIR)/redfishtool.ini $(CURDIR)/debian/redfishtool/etc/redfishtool
|
||||
|
15
bmc/redfishtool/debian/files/redfishtool.ini
Normal file
15
bmc/redfishtool/debian/files/redfishtool.ini
Normal file
@ -0,0 +1,15 @@
|
||||
[setBootOverride_overrides]
|
||||
|
||||
# The following list of server models should not receive a
|
||||
# BootSourceOverrideMode key:value pair in the
|
||||
# 'setBootOverride Once' PATCH request. When present:
|
||||
# - HP Proliant servers fail the request.
|
||||
# - Dell PowerEdge R7xxx servers initiate a BIOS reconfig update/reboot
|
||||
|
||||
# For specific servers - first filter
|
||||
exclude_BootSourceOverrideMode_Models = "R740XD vSAN Ready Node", "PowerEdge R750"
|
||||
|
||||
# For entire manufacturers - second filter
|
||||
exclude_BootSourceOverrideMode_Manufacturers = "HPE", "Dell Inc."
|
||||
|
||||
[Settings]
|
@ -0,0 +1,131 @@
|
||||
From: Eric Macdonald <eric.macdonald@windriver.com>
|
||||
Date: Sun, 15 Dec 2024 22:41:27 +0000
|
||||
Subject: Add config file based BootSourceOverrideMode handling to
|
||||
setBootOveride
|
||||
|
||||
This patch reads /etc/redfishtool/redfishtool.ini config file in
|
||||
search for the setBootOverride_overrides section that has a
|
||||
list of manufacturers and models that should not receive the
|
||||
BootSourceOverrideMode key:value pair as part of the payload
|
||||
to the 'setBootOverride Once <target>' patch request.
|
||||
|
||||
[setBootOverride_overrides]
|
||||
exclude_BootSourceOverrideMode_Models = "<model>", "<model>"
|
||||
exclude_BootSourceOverrideMode_Manufacturers = "<manufacturer>"
|
||||
|
||||
If current server is found in either the models or manufacturers lists
|
||||
then it is excluded from getting the BootSourceOverrideMode key:value
|
||||
pair added to the 'setBootOverride Once <target>' patch request.
|
||||
|
||||
Signed-off-by: Eric Macdonald <eric.macdonald@windriver.com>
|
||||
---
|
||||
redfishtoollib/Systems.py | 78 ++++++++++++++++++++++++++++++++++++++++++++---
|
||||
1 file changed, 73 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/redfishtoollib/Systems.py b/redfishtoollib/Systems.py
|
||||
index a0be4ad..6abee66 100644
|
||||
--- a/redfishtoollib/Systems.py
|
||||
+++ b/redfishtoollib/Systems.py
|
||||
@@ -503,6 +503,65 @@ class RfSystemsOperations():
|
||||
return op.iterate_op(op.setIndicatorLed_single, sc, op, rft, cmdTop=cmdTop, prop=prop)
|
||||
|
||||
|
||||
+ def get_exclude_BootSourceOverrideMode(self, rft, d):
|
||||
+ """
|
||||
+ Query redfishtool.ini for models or manufacturers that should not
|
||||
+ not have the BootSourceOverrideMode key:value pair added to the
|
||||
+ setBootOverride patch request.
|
||||
+ """
|
||||
+
|
||||
+ # include the config file parser
|
||||
+ import configparser
|
||||
+
|
||||
+ manufacturer=d["Manufacturer"]
|
||||
+ model=d["Model"]
|
||||
+ rft.printVerbose(4, "Manufacturer: {}".format(d["Manufacturer"]))
|
||||
+ rft.printVerbose(4, "Model : {}".format(d["Model"]))
|
||||
+
|
||||
+ # the config file path
|
||||
+ config_file="/etc/redfishtool/redfishtool.ini"
|
||||
+ config = configparser.ConfigParser()
|
||||
+ # read the configuration file
|
||||
+ files_read = config.read(config_file)
|
||||
+ if not files_read:
|
||||
+ rft.printVerbose(0, "Configuration file '{}' not found or could not be read.".format(config_file))
|
||||
+ return(False)
|
||||
+
|
||||
+ section="setBootOverride_overrides"
|
||||
+ exclude_BootSourceOverrideMode_Models="exclude_BootSourceOverrideMode_Models"
|
||||
+ exclude_BootSourceOverrideMode_Manufacturers="exclude_BootSourceOverrideMode_Manufacturers"
|
||||
+
|
||||
+ # get the model and manufacturers exclude lists
|
||||
+ exclude_models_list=[]
|
||||
+ exclude_manufacturers_list=[]
|
||||
+ exclude_BootSourceOverrideMode=False
|
||||
+
|
||||
+ # don't fail based on missing file. Just run with default behavior.
|
||||
+ if section in config:
|
||||
+ if exclude_BootSourceOverrideMode_Models not in config[section]:
|
||||
+ rft.printVerbose(4, "Option '{}' not found in section '{}' of the configuration file {}."\
|
||||
+ .format(exclude_BootSourceOverrideMode_Models, section, config_file))
|
||||
+ else:
|
||||
+ exclude_models_list = config[section][exclude_BootSourceOverrideMode_Models]
|
||||
+ rft.printVerbose(4, "Models Exclude List: {}".format(exclude_models_list))
|
||||
+
|
||||
+ if exclude_BootSourceOverrideMode_Manufacturers not in config[section]:
|
||||
+ rft.printVerbose(4, "Option '{}' not found in section '{}' of the configuration file {}."\
|
||||
+ .format(exclude_BootSourceOverrideMode_Manufacturers, section, config_file))
|
||||
+ else:
|
||||
+ exclude_manufacturers_list = config[section][exclude_BootSourceOverrideMode_Manufacturers]
|
||||
+ rft.printVerbose(4, "Manufacturer Exclude List: {}".format(exclude_manufacturers_list))
|
||||
+
|
||||
+ exclude_BootSourceOverrideMode=False
|
||||
+ if model in exclude_models_list:
|
||||
+ rft.printVerbose(0, "Excluding BootSourceOverrideMode for server model: '{}'".format(model))
|
||||
+ exclude_BootSourceOverrideMode = True
|
||||
+ elif manufacturer in exclude_manufacturers_list:
|
||||
+ rft.printVerbose(0, "Excluding BootSourceOverrideMode for server manufacturer: '{}'".format(manufacturer))
|
||||
+ exclude_BootSourceOverrideMode = True
|
||||
+ return (exclude_BootSourceOverrideMode)
|
||||
+
|
||||
+
|
||||
def setBootOverride_single(self,sc,op,rft,cmdTop=False, prop=None):
|
||||
# this operation has argument syntaxes below:
|
||||
# ...setBootOverride <enabledVal> [<targetVal>]
|
||||
@@ -533,11 +592,17 @@ class RfSystemsOperations():
|
||||
#now read target,
|
||||
# we will need to check that the properties we are patching are there, and chk for etag hdr
|
||||
# and to see if the value specified is one of the allowable values for this rhost
|
||||
- rc,r,j,d=op.get(sc,op,rft,prop="Boot")
|
||||
+ rc,r,j,d=op.get(sc,op,rft)
|
||||
if(rc != 0):
|
||||
print("Error, can't read boot properties from remote service")
|
||||
return(8,None,False,None)
|
||||
-
|
||||
+
|
||||
+ # this call will open the redfishtool.ini file and search for server models or
|
||||
+ # manufacturers that don't support or behave well when the 'setBootOverride Once <target>'
|
||||
+ # key:value pair is part of the payload of the PATCH method.
|
||||
+ # If found then a True (to exclude) is returned.
|
||||
+ exclude_BootSourceOverrideMode = op.get_exclude_BootSourceOverrideMode(rft, d)
|
||||
+
|
||||
# verify that they have a BootSourceOverrideEnabled prop
|
||||
bootRes=d["Boot"]
|
||||
if( not "BootSourceOverrideEnabled" in bootRes ):
|
||||
@@ -587,10 +652,13 @@ class RfSystemsOperations():
|
||||
|
||||
# Get the value of "BootSourceOverrideTarget" property and pass it in the patch request.
|
||||
# Some HW vendors need this property to be passed explicitly.
|
||||
- if "BootSourceOverrideMode" in d["Boot"]:
|
||||
- patchData={"Boot": {"BootSourceOverrideEnabled": enabledVal, "BootSourceOverrideTarget": targetVal, "BootSourceOverrideMode": d["Boot"]["BootSourceOverrideMode"] } }
|
||||
+ if exclude_BootSourceOverrideMode is True:
|
||||
+ patchData={"Boot": {"BootSourceOverrideEnabled": enabledVal,\
|
||||
+ "BootSourceOverrideTarget": targetVal } }
|
||||
else:
|
||||
- patchData={"Boot": {"BootSourceOverrideEnabled": enabledVal, "BootSourceOverrideTarget": targetVal } }
|
||||
+ patchData={"Boot": {"BootSourceOverrideEnabled": enabledVal,\
|
||||
+ "BootSourceOverrideTarget": targetVal,\
|
||||
+ "BootSourceOverrideMode": d["Boot"]["BootSourceOverrideMode"] } }
|
||||
|
||||
#call the generic patch command to send the patch. This takes care of etag support
|
||||
rc,r,j,d=rft.patchResource(rft, r, patchData)
|
@ -1,83 +0,0 @@
|
||||
From: Eric Macdonald <eric.macdonald@windriver.com>
|
||||
Date: Tue, 10 Dec 2024 17:05:13 +0000
|
||||
Subject: Add retry to BootSourceOverrideMode handling
|
||||
|
||||
Redfishtool version 1.1.8 added a condition where if
|
||||
'BootSourceOverrideMode' exists in the boot query response
|
||||
then it adds the following to the Boot Source Override command
|
||||
json string for the setBootOverride_single command.
|
||||
|
||||
"BootSourceOverrideMode": d["Boot"]["BootSourceOverrideMode"]
|
||||
|
||||
This change is leading to this Bad Request error for some servers.
|
||||
|
||||
redfishtool: Transport: Response Error: status_code: 400 -- Bad Request
|
||||
|
||||
Servers known to fail in this way are HP Proliant e910t, e920t as well
|
||||
as DL360 and DL380 server models with HP iLO versions 3.01, 3.04 and
|
||||
3.6.
|
||||
|
||||
This update introduces a legacy mode retry to the setBootOverride
|
||||
operation if the new method fails in a 400 - Bad Request.
|
||||
|
||||
Signed-off-by: Eric Macdonald <eric.macdonald@windriver.com>
|
||||
---
|
||||
redfishtoollib/Systems.py | 30 ++++++++++++++++++++++--------
|
||||
1 file changed, 22 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/redfishtoollib/Systems.py b/redfishtoollib/Systems.py
|
||||
index a0be4ad..e2cbe01 100644
|
||||
--- a/redfishtoollib/Systems.py
|
||||
+++ b/redfishtoollib/Systems.py
|
||||
@@ -182,7 +182,7 @@ class RfSystemsOperations():
|
||||
def __init__(self):
|
||||
self.systemsPath=None
|
||||
self.systemsCollectionDict=None
|
||||
-
|
||||
+ self.setBootOverride_legacy_mode=False
|
||||
|
||||
def hello(self,sc,op,rft,cmdTop=False):
|
||||
rft.printVerbose(4,"in hello")
|
||||
@@ -584,13 +584,19 @@ class RfSystemsOperations():
|
||||
return(8,None,False,None)
|
||||
|
||||
#form the patch data
|
||||
-
|
||||
- # Get the value of "BootSourceOverrideTarget" property and pass it in the patch request.
|
||||
- # Some HW vendors need this property to be passed explicitly.
|
||||
- if "BootSourceOverrideMode" in d["Boot"]:
|
||||
- patchData={"Boot": {"BootSourceOverrideEnabled": enabledVal, "BootSourceOverrideTarget": targetVal, "BootSourceOverrideMode": d["Boot"]["BootSourceOverrideMode"] } }
|
||||
- else:
|
||||
+ if self.setBootOverride_legacy_mode:
|
||||
+ # Some servers don't like the BootSourceOverrideMode added to the payload
|
||||
+ # even when BootSourceOverrideMode is set in d["Boot"].
|
||||
+ # The caller has the option to set self.setBootOverride_legacy_mode True
|
||||
+ # and call this function to use the 'legacy' mode patchData.
|
||||
patchData={"Boot": {"BootSourceOverrideEnabled": enabledVal, "BootSourceOverrideTarget": targetVal } }
|
||||
+ else:
|
||||
+ # Get the value of "BootSourceOverrideTarget" property and pass it in the patch request.
|
||||
+ # Some HW vendors need this property to be passed explicitly.
|
||||
+ if "BootSourceOverrideMode" in d["Boot"]:
|
||||
+ patchData={"Boot": {"BootSourceOverrideEnabled": enabledVal, "BootSourceOverrideTarget": targetVal, "BootSourceOverrideMode": d["Boot"]["BootSourceOverrideMode"] } }
|
||||
+ else:
|
||||
+ patchData={"Boot": {"BootSourceOverrideEnabled": enabledVal, "BootSourceOverrideTarget": targetVal } }
|
||||
|
||||
#call the generic patch command to send the patch. This takes care of etag support
|
||||
rc,r,j,d=rft.patchResource(rft, r, patchData)
|
||||
@@ -605,7 +611,15 @@ class RfSystemsOperations():
|
||||
|
||||
|
||||
def setBootOverride(self, sc, op, rft, cmdTop=False, prop=None):
|
||||
- return op.iterate_op(op.setBootOverride_single, sc, op, rft, cmdTop=cmdTop, prop=prop)
|
||||
+ rc,r,j,d=op.iterate_op(op.setBootOverride_single, sc, op, rft, cmdTop=cmdTop, prop=prop)
|
||||
+ if ( rc == 5 and r is not None ):
|
||||
+ # added a retry in legacyMode if the http response
|
||||
+ # in 'r' is <Response [400]> - Bad Request
|
||||
+ if r.status_code == 400:
|
||||
+ rft.printVerbose(0," redfishtool: setBootOverride operation failed, retrying in legacy mode")
|
||||
+ self.setBootOverride_legacy_mode = True
|
||||
+ rc,r,j,d=op.iterate_op(op.setBootOverride_single, sc, op, rft, cmdTop=cmdTop, prop=prop)
|
||||
+ return(rc,r,j,d)
|
||||
|
||||
|
||||
def getProcessors(self,sc,op, rft, cmdTop=False, prop=None):
|
@ -1,2 +1,2 @@
|
||||
0001-1.1.8-versioning.patch
|
||||
0002-Add-retry-to-BootSourceOverrideMode-handling.patch
|
||||
0002-Add-config-file-based-BootSourceOverrideMode-handlin.patch
|
||||
|
Loading…
Reference in New Issue
Block a user