diff --git a/pyghmi/redfish/oem/generic.py b/pyghmi/redfish/oem/generic.py index d1874ccd..ab4a7bb9 100644 --- a/pyghmi/redfish/oem/generic.py +++ b/pyghmi/redfish/oem/generic.py @@ -931,7 +931,7 @@ class OEMHandler(object): raise exc.UnsupportedFunctionality( 'Remote media upload not supported on this platform') - def update_firmware(self, filename, data=None, progress=None, bank=None): + 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) @@ -952,7 +952,7 @@ class OEMHandler(object): try: uploadthread = webclient.FileUploader( self.webclient, upurl, filename, data, formwrap=ismultipart, - excepterror=False) + excepterror=False, otherfields=otherfields) uploadthread.start() wc = self.webclient while uploadthread.isAlive(): diff --git a/pyghmi/redfish/oem/lenovo/xcc3.py b/pyghmi/redfish/oem/lenovo/xcc3.py index 37c8495b..3810d065 100644 --- a/pyghmi/redfish/oem/lenovo/xcc3.py +++ b/pyghmi/redfish/oem/lenovo/xcc3.py @@ -3,7 +3,8 @@ import json import pyghmi.redfish.oem.generic as generic import pyghmi.exceptions as pygexc import pyghmi.util.webclient as webclient - +import zipfile +import os.path class OEMHandler(generic.OEMHandler): @@ -82,6 +83,32 @@ class OEMHandler(generic.OEMHandler): 'password_lockout_period': 'AccountLockoutDuration', } + def update_firmware(self, filename, data=None, progress=None, bank=None, otherfields=()): + if not otherfields and bank == 'backup': + uxzcount = 0 + otherfields = {'UpdateParameters': {"Targets": ["/redfish/v1/UpdateService/FirmwareInventory/BMC-Backup"]}} + needseek = False + if data and hasattr(data, 'read'): + if zipfile.is_zipfile(data): + needseek = True + z = zipfile.ZipFile(data) + else: + data.seek(0) + elif data is None and zipfile.is_zipfile(filename): + z = zipfile.ZipFile(filename) + if z: + for tmpname in z.namelist(): + if tmpname.startswith('payloads/'): + uxzcount += 1 + if tmpname.endswith('.uxz'): + wrappedfilename = tmpname + if uxzcount == 1 and wrappedfilename: + filename = os.path.basename(wrappedfilename) + data = z.open(wrappedfilename) + elif needseek: + data.seek(0) + super().update_firmware(filename, data=data, progress=progress, bank=bank, otherfields=otherfields) + def get_bmc_configuration(self): settings = {} acctsrv = self._do_web_request('/redfish/v1/AccountService') diff --git a/pyghmi/util/webclient.py b/pyghmi/util/webclient.py index 55835222..079ac7fb 100644 --- a/pyghmi/util/webclient.py +++ b/pyghmi/util/webclient.py @@ -107,16 +107,22 @@ def get_upload_form(filename, data, formname, otherfields): data = data.read() except AttributeError: pass - form = (b'--' + BND + form = b'' + for ofield in otherfields: + tfield = otherfields[ofield] + xtra='' + if isinstance(tfield, dict): + tfield = json.dumps(tfield) + xtra = '\r\nContent-Type: application/json' + form += (b'--' + BND + + '\r\nContent-Disposition: form-data; ' + 'name="{0}"{1}\r\n\r\n{2}\r\n'.format( + ofield, xtra, tfield).encode('utf-8')) + form += (b'--' + BND + '\r\nContent-Disposition: form-data; ' 'name="{0}"; filename="{1}"\r\n'.format( formname, ffilename).encode('utf-8')) form += b'Content-Type: application/octet-stream\r\n\r\n' + data - for ofield in otherfields: - form += (b'\r\n--' + BND - + '\r\nContent-Disposition: form-data; ' - 'name="{0}"\r\n\r\n{1}'.format( - ofield, otherfields[ofield]).encode('utf-8')) form += b'\r\n--' + BND + b'--\r\n' uploadforms[filename] = form return form