Skip to content

Commit

Permalink
Merge pull request #127 from DMTF/Fix111-Boot-Override-Workaround
Browse files Browse the repository at this point in the history
Added workaround flag to attempt to set boot override properties on settings resources for non-conformant implementations
  • Loading branch information
mraineri authored Sep 15, 2023
2 parents 833aab8 + 5f628e0 commit 6ffa02b
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 2 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,9 @@ optional arguments:
--mode MODE, -m MODE The requested boot mode ('UEFI' or 'Legacy')
--reset, -reset Signifies that the system is reset after the boot
override is set
--workaround, -workaround
Indicates if workarounds should be attempted for non-
conformant services
--debug Creates debug file showing HTTP traces and exceptions
```

Expand Down
51 changes: 49 additions & 2 deletions redfish_utilities/systems.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,37 @@ def get_system_boot( context, system_id = None ):
"""

system = get_system( context, system_id )
if "Boot" not in system.dict:
boot_obj = system.dict.get( "Boot" )

if config.__workarounds__:
# Try getting boot information from the settings resource
settings_uris = [ "Settings", "SD" ]
for setting_ext in settings_uris:
system_settings = context.get( system.dict["@odata.id"] + "/" + setting_ext )
if system_settings.status == 200:
if "Boot" in system_settings.dict:
if boot_obj is None:
# Boot property only exists in settings, which is not expected
warnings.warn( "System '{}' only reports boot information in the settings resource. Contact your vendor.".format( system_id ) )
boot_obj = system_settings.dict["Boot"]
else:
# Check the boot override properties; these are expected to only be in the active resource
boot_override_props = [ "BootSourceOverrideTarget", "BootSourceOverrideEnabled", "BootSourceOverrideMode", "UefiTargetBootSourceOverride", "BootNext" ]
boot_ov_found = False
for prop in boot_override_props:
if prop in system_settings.dict["Boot"]:
# Boot override property found; copy it over
boot_ov_found = True
boot_obj[prop] = system_settings.dict["Boot"][prop]
if prop + "@Redfish.AllowableValues" in system_settings.dict["Boot"]:
boot_obj[prop + "@Redfish.AllowableValues"] = system_settings.dict["Boot"][prop + "@Redfish.AllowableValues"]
if boot_ov_found:
warnings.warn( "System '{}' contains one or more boot override properties in the settings resource. Contact your vendor.".format( system_id ) )
break

if boot_obj is None:
raise RedfishSystemBootNotFoundError( "System '{}' does not contain the boot object".format( system.dict["Id"] ) )
return system.dict["Boot"]
return boot_obj

def set_system_boot( context, system_id = None, ov_target = None, ov_enabled = None, ov_mode = None, ov_uefi_target = None, ov_boot_next = None ):
"""
Expand Down Expand Up @@ -185,6 +213,25 @@ def set_system_boot( context, system_id = None, ov_target = None, ov_enabled = N
if etag is not None:
headers = { "If-Match": etag }
response = context.patch( system.dict["@odata.id"], body = payload, headers = headers )

# Attempt workarounds if needed
if config.__workarounds__ and response.status >= 400:
# Try directing the request to the settings resource
settings_uris = [ "Settings", "SD" ]
for setting_ext in settings_uris:
system_settings = context.get( system.dict["@odata.id"] + "/" + setting_ext )
if system_settings.status == 200:
headers = None
etag = system_settings.getheader( "ETag" )
if etag is not None:
headers = { "If-Match": etag }
settings_response = context.patch( system.dict["@odata.id"] + "/" + setting_ext, body = payload, headers = headers )
if settings_response.status < 400:
# Workaround successful; swap out the response object to return
warnings.warn( "System '{}' incorrectly required applying the boot override configuration to the settings resource. Contact your vendor.".format( system_id ) )
response = settings_response
break

verify_response( response )
return response

Expand Down
4 changes: 4 additions & 0 deletions scripts/rf_boot_override.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
argget.add_argument( "--uefi", "-uefi", type = str, help = "If target is 'UefiTarget', the UEFI Device Path of the device to boot. If target is 'UefiBootNext', the UEFI Boot Option string of the device to boot." )
argget.add_argument( "--mode", "-m", type = str, help = "The requested boot mode ('UEFI' or 'Legacy')" )
argget.add_argument( "--reset", "-reset", action = "store_true", help = "Signifies that the system is reset after the boot override is set" )
argget.add_argument( "--workaround", "-workaround", action = "store_true", help = "Indicates if workarounds should be attempted for non-conformant services", default = False )
argget.add_argument( "--debug", action = "store_true", help = "Creates debug file showing HTTP traces and exceptions" )
args = argget.parse_args()

Expand All @@ -41,6 +42,9 @@
if args.uefi or args.mode or args.reset:
argget.error( "Cannot use '--uefi', '--mode', or '--reset' without '--target'" )

if args.workaround:
redfish_utilities.config.__workarounds__ = True

if args.debug:
log_file = "rf_boot_override-{}.log".format( datetime.datetime.now().strftime( "%Y-%m-%d-%H%M%S" ) )
log_format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
Expand Down

0 comments on commit 6ffa02b

Please sign in to comment.