diff --git a/pyghmi/redfish/oem/generic.py b/pyghmi/redfish/oem/generic.py index 2fdb5ee6..ab0b445e 100644 --- a/pyghmi/redfish/oem/generic.py +++ b/pyghmi/redfish/oem/generic.py @@ -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): diff --git a/pyghmi/redfish/oem/lenovo/smm3.py b/pyghmi/redfish/oem/lenovo/smm3.py index 5c9491d6..def98502 100644 --- a/pyghmi/redfish/oem/lenovo/smm3.py +++ b/pyghmi/redfish/oem/lenovo/smm3.py @@ -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',