2
0
mirror of https://opendev.org/x/pyghmi synced 2026-01-10 18:22:32 +00:00

Fix SMM3 update process

First, break up the generic update into
distinct pieces.

For SMMv3, first supersede getting the upload url, as
multipart is advertised, but doesn't work, but simpleupdate (deprecated) works.

Then after upload,
switch to hard coded logic specific to SMMv3 to determine how to start the update and where to monitor results.

Then hand back over to generic to finish out monitoring.

Change-Id: I33b2e67603400b920aca4aa11047c11978c3c6f6
This commit is contained in:
Jarrod Johnson
2025-08-13 12:45:08 -04:00
parent 89d06043c5
commit a70194cd39
2 changed files with 64 additions and 20 deletions

View File

@@ -21,6 +21,7 @@ import re
from datetime import datetime
from datetime import timedelta
from dateutil import tz
import socket
import time
import pyghmi.constants as const
@@ -1065,22 +1066,7 @@ class OEMHandler(object):
def update_firmware(self, filename, data=None, progress=None, bank=None, otherfields=()):
# disable cache to make sure we trigger the token renewal logic if needed
usd = self._do_web_request('/redfish/v1/UpdateService', cache=False)
upurl = usd.get('MultipartHttpPushUri', None)
ismultipart = True
if not upurl:
ismultipart = False
if usd.get('HttpPushUriTargetsBusy', False):
raise exc.TemporaryError('Cannot run multtiple updates to '
'same target concurrently')
try:
upurl = usd['HttpPushUri']
except KeyError:
raise exc.UnsupportedFunctionality('Redfish firmware update only supported for implementations with push update support')
if 'HttpPushUriTargetsBusy' in usd:
self._do_web_request(
'/redfish/v1/UpdateService',
{'HttpPushUriTargetsBusy': True}, method='PATCH')
usd, upurl, ismultipart = self.retrieve_firmware_upload_url()
try:
uploadthread = webclient.FileUploader(
self.webclient, upurl, filename, data, formwrap=ismultipart,
@@ -1105,8 +1091,19 @@ class OEMHandler(object):
except Exception:
raise Exception(uploadthread.rsp)
raise Exception(errmsg)
return self.continue_update(uploadthread, progress)
finally:
if 'HttpPushUriTargetsBusy' in usd:
self._do_web_request(
'/redfish/v1/UpdateService',
{'HttpPushUriTargetsBusy': False}, method='PATCH')
def continue_update(self, uploadthread, progress):
rsp = json.loads(uploadthread.rsp)
monitorurl = rsp['@odata.id']
return self.monitor_update_progress(monitorurl, progress)
def monitor_update_progress(self, monitorurl, progress):
complete = False
phase = "apply"
statetype = 'TaskState'
@@ -1151,11 +1148,26 @@ class OEMHandler(object):
if not retry:
raise Exception('Falied to monitor update progress due to excessive timeouts')
return 'pending'
finally:
def retrieve_firmware_upload_url(self):
usd = self._do_web_request('/redfish/v1/UpdateService', cache=False)
upurl = usd.get('MultipartHttpPushUri', None)
ismultipart = True
if not upurl:
ismultipart = False
if usd.get('HttpPushUriTargetsBusy', False):
raise exc.TemporaryError('Cannot run multtiple updates to '
'same target concurrently')
try:
upurl = usd['HttpPushUri']
except KeyError:
raise exc.UnsupportedFunctionality('Redfish firmware update only supported for implementations with push update support')
if 'HttpPushUriTargetsBusy' in usd:
self._do_web_request(
'/redfish/v1/UpdateService',
{'HttpPushUriTargetsBusy': False}, method='PATCH')
self._do_web_request('/redfish/v1/UpdateService',
{'HttpPushUriTargetsBusy': True}, method='PATCH')
return usd,upurl,ismultipart
def _do_bulk_requests(self, urls, cache=True):

View File

@@ -19,6 +19,7 @@ import pyghmi.constants as pygconst
import pyghmi.util.webclient as webclient
import pyghmi.exceptions as exc
import time
import socket
healthlookup = {
'ok': pygconst.Health.Ok,
@@ -78,6 +79,37 @@ class OEMHandler(generic.OEMHandler):
def get_system_configuration(self, hideadvanced=True, fishclient=None):
return {}
def retrieve_firmware_upload_url(self):
# SMMv3 needs to do the non-multipart upload
usd = self._do_web_request('/redfish/v1/UpdateService', cache=False)
if usd.get('HttpPushUriTargetsBusy', False):
raise exc.TemporaryError('Cannot run multtiple updates to '
'same target concurrently')
try:
upurl = usd['HttpPushUri']
except KeyError:
raise exc.UnsupportedFunctionality('Redfish firmware update only supported for implementations with push update support')
if 'HttpPushUriTargetsBusy' in usd:
self._do_web_request(
'/redfish/v1/UpdateService',
{'HttpPushUriTargetsBusy': True}, method='PATCH')
return usd,upurl,False
def continue_update(self, uploadthread, progress):
# SMMv3 does not provide a response, must hardcode the continuation
# /redfish/v1/UpdateService/FirmwareInventory/fwuimage
rsp = self._do_web_request('/redfish/v1/UpdateService/FirmwareInventory/fwuimage')
for ri in rsp.get('RelatedItem', []):
targ = ri.get('@odata.id', None)
parms = {'Oem': {'Lenovo': {'SecureRollBack': False}}}
rsp = self._do_web_request('/redfish/v1/UpdateService', parms, method='PATCH')
targspec = {'target': targ}
rsp = self._do_web_request('/redfish/v1/UpdateService/Actions/UpdateService.StartUpdate', targspec)
monitorurl = rsp.get('@odata.id', None)
return self.monitor_update_progress(monitorurl, progress)
def get_diagnostic_data(self, savefile, progress=None, autosuffix=False):
tsk = self._do_web_request(
'/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData',