mirror of
https://opendev.org/x/pyghmi
synced 2025-08-23 11:30:18 +00:00
Implement firmware update for ThinkSystem SMM
Provide similar support for ThinkSystem SMM as the XCC devices. Change-Id: I9173ef1c509b2965469ee610cca58590fe42cb69
This commit is contained in:
@@ -154,6 +154,8 @@ class OEMHandler(generic.OEMHandler):
|
||||
self.immhandler = imm.XCCClient(ipmicmd)
|
||||
elif self.has_imm:
|
||||
self.immhandler = imm.IMMClient(ipmicmd)
|
||||
elif self.is_fpc:
|
||||
self.smmhandler = nextscale.SMMClient(ipmicmd)
|
||||
|
||||
@property
|
||||
def _megarac_eth_index(self):
|
||||
@@ -832,6 +834,9 @@ class OEMHandler(generic.OEMHandler):
|
||||
if self.has_xcc:
|
||||
return self.immhandler.update_firmware(
|
||||
filename, data=data, progress=progress)
|
||||
if self.is_fpc:
|
||||
return self.smmhandler.update_firmware(
|
||||
filename, data=data, progress=progress)
|
||||
super(OEMHandler, self).update_firmware(filename, data=data,
|
||||
progress=progress)
|
||||
|
||||
|
@@ -16,8 +16,14 @@
|
||||
|
||||
import pyghmi.constants as pygconst
|
||||
import pyghmi.exceptions as pygexc
|
||||
import pyghmi.ipmi.private.session as ipmisession
|
||||
import pyghmi.ipmi.sdr as sdr
|
||||
import pyghmi.util.webclient as webclient
|
||||
import struct
|
||||
import urllib
|
||||
import weakref
|
||||
from xml.etree.ElementTree import fromstring
|
||||
import zipfile
|
||||
|
||||
try:
|
||||
range = xrange
|
||||
@@ -224,3 +230,89 @@ def get_sensor_reading(name, ipmicmd, sz):
|
||||
'type': sensor['type']},
|
||||
sensor['units'])
|
||||
raise Exception('Sensor not found: ' + name)
|
||||
|
||||
|
||||
class SMMClient(object):
|
||||
def __init__(self, ipmicmd):
|
||||
self.ipmicmd = weakref.proxy(ipmicmd)
|
||||
self.smm = ipmicmd.bmc
|
||||
self.username = ipmicmd.ipmi_session.userid
|
||||
self.password = ipmicmd.ipmi_session.password
|
||||
self._wc = None
|
||||
|
||||
def get_webclient(self):
|
||||
cv = self.ipmicmd.certverify
|
||||
wc = webclient.SecureHTTPConnection(self.smm, 443, verifycallback=cv)
|
||||
wc.connect()
|
||||
loginform = urllib.urlencode({'user': self.username,
|
||||
'password': self.password})
|
||||
wc.request('POST', '/data/login', loginform)
|
||||
rsp = wc.getresponse()
|
||||
if rsp.status != 200:
|
||||
raise Exception(rsp.read())
|
||||
authdata = rsp.read()
|
||||
authdata = fromstring(authdata)
|
||||
for data in authdata.findall('authResult'):
|
||||
if int(data.text) != 0:
|
||||
raise Exception("Firmware update already in progress")
|
||||
self.st1 = None
|
||||
self.st2 = None
|
||||
for data in authdata.findall('st1'):
|
||||
self.st1 = data.text
|
||||
for data in authdata.findall('st2'):
|
||||
self.st2 = data.text
|
||||
wc.set_header('ST2', self.st2)
|
||||
return wc
|
||||
|
||||
def update_firmware(self, filename, data=None, progress=None):
|
||||
if progress is None:
|
||||
progress = lambda x: True
|
||||
if not data and zipfile.is_zipfile(filename):
|
||||
z = zipfile.ZipFile(filename)
|
||||
for tmpname in z.namelist():
|
||||
if tmpname.endswith('.rom'):
|
||||
filename = tmpname
|
||||
data = z.open(filename)
|
||||
break
|
||||
progress({'phase': 'upload', 'progress': 0.0})
|
||||
url = self.wc
|
||||
url = '/fwupload/fwupload.esp?ST1={0}'.format(self.st1)
|
||||
self.wc.upload(url, filename, data, formname='fileUpload',
|
||||
otherfields={'preConfig': 'on'})
|
||||
progress({'phase': 'validating', 'progress': 0.0})
|
||||
url = '/data'
|
||||
self.wc.request('POST', url, 'get=fwVersion,spfwInfo')
|
||||
rsp = self.wc.getresponse()
|
||||
rsp.read()
|
||||
if rsp.status != 200:
|
||||
raise Exception('Error validating firmware')
|
||||
progress({'phase': 'apply', 'progress': 0.0})
|
||||
self.wc.request('POST', '/data', 'set=fwUpdate:1')
|
||||
rsp = self.wc.getresponse()
|
||||
rsp.read()
|
||||
complete = False
|
||||
while not complete:
|
||||
ipmisession.Session.pause(3)
|
||||
self.wc.request('POST', '/data', 'get=fwProgress,fwUpdate')
|
||||
rsp = self.wc.getresponse()
|
||||
progdata = rsp.read()
|
||||
if rsp.status != 200:
|
||||
raise Exception('Error applying firmware')
|
||||
progdata = fromstring(progdata)
|
||||
percent = float(progdata.findall('fwProgress')[0].text)
|
||||
|
||||
progress({'phase': 'apply',
|
||||
'progress': percent})
|
||||
complete = percent >= 100.0
|
||||
|
||||
def logout(self):
|
||||
self.wc.request('POST', '/data/logout', None)
|
||||
rsp = self.wc.getresponse()
|
||||
rsp.read()
|
||||
self._wc = None
|
||||
|
||||
@property
|
||||
def wc(self):
|
||||
if not self._wc:
|
||||
self._wc = self.get_webclient()
|
||||
return self._wc
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright 2015 Lenovo
|
||||
# Copyright 2015-2017 Lenovo
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -39,15 +39,23 @@ BND = 'TbqbLUSn0QFjx9gxiQLtgBK4Zu6ehLqtLs4JOBS50EgxXJ2yoRMhTrmRXxO1lkoAQdZx16'
|
||||
uploadforms = {}
|
||||
|
||||
|
||||
def get_upload_form(filename, data):
|
||||
def get_upload_form(filename, data, formname, otherfields):
|
||||
if not formname:
|
||||
formname = filename
|
||||
try:
|
||||
return uploadforms[filename]
|
||||
except KeyError:
|
||||
if isinstance(data, file):
|
||||
try:
|
||||
data = data.read()
|
||||
except AttributeError:
|
||||
pass
|
||||
form = '--' + BND + '\r\nContent-Disposition: form-data; ' \
|
||||
'name="{0}"; filename="{0}"\r\n'.format(filename)
|
||||
'name="{0}"; filename="{1}"\r\n'.format(formname,
|
||||
filename)
|
||||
form += 'Content-Type: application/octet-stream\r\n\r\n' + data
|
||||
for ofield in otherfields:
|
||||
form += '\r\n--' + BND + '\r\nContent-Disposition: form-data; ' \
|
||||
'name="{0}"\r\n\r\n{1}'.format(ofield, otherfields[ofield])
|
||||
form += '\r\n--' + BND + '--\r\n'
|
||||
uploadforms[filename] = form
|
||||
return form
|
||||
@@ -115,7 +123,8 @@ class SecureHTTPConnection(httplib.HTTPConnection, object):
|
||||
rsp.read()
|
||||
return {}
|
||||
|
||||
def upload(self, url, filename, data=None):
|
||||
def upload(self, url, filename, data=None, formname=None,
|
||||
otherfields=()):
|
||||
"""Upload a file to the url
|
||||
|
||||
:param url:
|
||||
@@ -126,7 +135,7 @@ class SecureHTTPConnection(httplib.HTTPConnection, object):
|
||||
"""
|
||||
if data is None:
|
||||
data = open(filename, 'rb')
|
||||
form = get_upload_form(filename, data)
|
||||
form = get_upload_form(filename, data, formname, otherfields)
|
||||
ulheaders = self.stdheaders.copy()
|
||||
ulheaders['Content-Type'] = 'multipart/form-data; boundary=' + BND
|
||||
self.request('POST', url, form, ulheaders)
|
||||
|
Reference in New Issue
Block a user