2
0
mirror of https://opendev.org/x/pyghmi synced 2026-04-09 11:31:29 +00:00

Merge "Ensure fresh webclient for SMM interaction"

This commit is contained in:
Zuul
2022-04-04 20:12:25 +00:00
committed by Gerrit Code Review

View File

@@ -23,6 +23,7 @@ import six
import pyghmi.constants as pygconst
import pyghmi.exceptions as pygexc
import pyghmi.ipmi.private.session as ipmisession
import pyghmi.ipmi.private.util as util
from pyghmi.ipmi import sdr
import pyghmi.util.webclient as webclient
@@ -414,13 +415,14 @@ class SMMClient(object):
def get_bmc_configuration(self):
settings = {}
self.wc.request(
wc = self.wc
wc.request(
'POST', '/data',
('get=passwordMinLength,passwordForceChange,passwordDurationDays,'
'passwordExpireWarningDays,passwordChangeInterval,'
'passwordReuseCheckNum,passwordFailAllowdNum,'
'passwordLockoutTimePeriod'))
rsp = self.wc.getresponse()
rsp = wc.getresponse()
rspbody = rsp.read()
accountinfo = fromstring(rspbody)
for rule in self.rulemap:
@@ -646,8 +648,9 @@ class SMMClient(object):
changeset[key]['value']))
if rules:
rules = 'set={0}'.format(','.join(rules))
self.wc.request('POST', '/data', rules)
self.wc.getresponse().read()
wc = self.wc
wc.request('POST', '/data', rules)
wc.getresponse().read()
if powercfg != [None, None]:
if variant != 6:
if None in powercfg:
@@ -676,10 +679,11 @@ class SMMClient(object):
username = bytes(rsp['data']).rstrip(b'\x00')
if not isinstance(username, str):
username = username.decode('utf8')
self.wc.request(
wc = self.wc
wc.request(
'POST', '/data', 'set=user({0},1,{1},511,,4,15,0)'.format(
uid, username))
rsp = self.wc.getresponse()
rsp = wc.getresponse()
rsp.read()
def reseat_bay(self, bay):
@@ -723,21 +727,22 @@ class SMMClient(object):
rsp = self.ipmicmd.xraw_command(netfn=0x34, command=0x12, data=[1])
if progress:
progress({'phase': 'initializing', 'progress': initpct})
if self.wc is None:
wc = self.wc
if wc is None:
raise Exception("Failed to connect to web api")
if variant and variant >> 5:
url = '/preview/smm2-ffdc.tgz?ST1={0}'.format(self.st1)
url = '/preview/smm2-ffdc.tgz?ST1={0}'.format(wc.st1)
else:
url = '/preview/smm-ffdc.tgz?ST1={0}'.format(self.st1)
url = '/preview/smm-ffdc.tgz?ST1={0}'.format(wc.st1)
if autosuffix and not savefile.endswith('.tgz'):
savefile += '-smm-ffdc.tgz'
fd = webclient.FileDownloader(self.wc, url, savefile)
fd = webclient.FileDownloader(wc, url, savefile)
fd.start()
while fd.isAlive():
fd.join(1)
if progress and self.wc.get_download_progress():
if progress and wc.get_download_progress():
progress({'phase': 'download',
'progress': 100 * self.wc.get_download_progress()})
'progress': 100 * wc.get_download_progress()})
if progress:
progress({'phase': 'complete'})
return savefile
@@ -759,6 +764,7 @@ class SMMClient(object):
def get_webclient(self):
cv = self.ipmicmd.certverify
wc = webclient.SecureHTTPConnection(self.smm, 443, verifycallback=cv)
wc.vintage = util._monotonic_time()
wc.connect()
loginform = urlencode(
{
@@ -779,13 +785,13 @@ class SMMClient(object):
if 'renew' in data.text:
raise Exception("Account password has expired on remote "
"device")
self.st1 = None
self.st2 = None
wc.st1 = None
wc.st2 = None
for data in authdata.findall('st1'):
self.st1 = data.text
wc.st1 = data.text
for data in authdata.findall('st2'):
self.st2 = data.text
if not self.st2:
wc.st2 = data.text
if not wc.st2:
# This firmware puts tokens in the html file, parse that
wc.request('GET', '/index.html')
rsp = wc.getresponse()
@@ -796,12 +802,12 @@ class SMMClient(object):
indexhtml = indexhtml.decode('utf8')
for line in indexhtml.split('\n'):
if '"ST1"' in line:
self.st1 = line.split()[-1].replace(
wc.st1 = line.split()[-1].replace(
'"', '').replace(',', '')
if '"ST2"' in line:
self.st2 = line.split()[-1].replace(
wc.st2 = line.split()[-1].replace(
'"', '').replace(',', '')
if not self.st2:
if not wc.st2:
wc.request('GET', '/scripts/index.ajs')
rsp = wc.getresponse()
body = rsp.read()
@@ -811,19 +817,20 @@ class SMMClient(object):
body = body.decode('utf8')
for line in body.split('\n'):
if '"ST1"' in line:
self.st1 = line.split()[-1].replace(
wc.st1 = line.split()[-1].replace(
'"', '').replace(',', '')
if '"ST2"' in line:
self.st2 = line.split()[-1].replace(
wc.st2 = line.split()[-1].replace(
'"', '').replace(',', '')
if not self.st2:
if not wc.st2:
raise Exception('Unable to locate ST2 token')
wc.set_header('ST2', self.st2)
wc.set_header('ST2', wc.st2)
return wc
def set_hostname(self, hostname):
self.wc.request('POST', '/data', 'set=hostname:' + hostname)
rsp = self.wc.getresponse()
wc = self.wc
wc.request('POST', '/data', 'set=hostname:' + hostname)
rsp = wc.getresponse()
if rsp.status != 200:
raise Exception(rsp.read())
rsp.read()
@@ -836,12 +843,13 @@ class SMMClient(object):
return data.text
def get_netinfo(self):
self.wc.request('POST', '/data', 'get=hostname')
rsp = self.wc.getresponse()
wc = self.wc
wc.request('POST', '/data', 'get=hostname')
rsp = wc.getresponse()
data = rsp.read()
if rsp.status == 400:
self.wc.request('POST', '/data?get=hostname', '')
rsp = self.wc.getresponse()
wc.request('POST', '/data?get=hostname', '')
rsp = wc.getresponse()
data = rsp.read()
if rsp.status != 200:
raise Exception(data)
@@ -849,8 +857,9 @@ class SMMClient(object):
return currinfo
def set_domain(self, domain):
self.wc.request('POST', '/data', 'set=dnsDomain:' + domain)
rsp = self.wc.getresponse()
wc = self.wc
wc.request('POST', '/data', 'set=dnsDomain:' + domain)
rsp = wc.getresponse()
if rsp.status != 200:
raise Exception(rsp.read())
rsp.read()
@@ -863,17 +872,19 @@ class SMMClient(object):
return data.text
def get_ntp_enabled(self, variant):
self.wc.request('POST', '/data', 'get=ntpOpMode')
rsp = self.wc.getresponse()
wc = self.wc
wc.request('POST', '/data', 'get=ntpOpMode')
rsp = wc.getresponse()
info = fromstring(rsp.read())
self.logout()
for data in info.findall('ntpOpMode'):
return data.text == '1'
def set_ntp_enabled(self, enabled):
self.wc.request('POST', '/data', 'set=ntpOpMode:{0}'.format(
wc = self.wc
wc.request('POST', '/data', 'set=ntpOpMode:{0}'.format(
1 if enabled else 0))
rsp = self.wc.getresponse()
rsp = wc.getresponse()
result = rsp.read()
if not isinstance(result, str):
result = result.decode('utf8')
@@ -882,9 +893,10 @@ class SMMClient(object):
raise Exception("Unrecognized result: " + result)
def set_ntp_server(self, server, index):
self.wc.request('POST', '/data', 'set=ntpServer{0}:{1}'.format(
wc = self.wc
wc.request('POST', '/data', 'set=ntpServer{0}:{1}'.format(
index + 1, server))
rsp = self.wc.getresponse()
rsp = wc.getresponse()
result = rsp.read()
if not isinstance(result, str):
result = result.decode('utf8')
@@ -894,9 +906,10 @@ class SMMClient(object):
return True
def get_ntp_servers(self):
self.wc.request(
wc = self.wc
wc.request(
'POST', '/data', 'get=ntpServer1,ntpServer2,ntpServer3')
rsp = self.wc.getresponse()
rsp = wc.getresponse()
result = fromstring(rsp.read())
srvs = []
for data in result.findall('ntpServer1'):
@@ -927,37 +940,38 @@ class SMMClient(object):
data = z.open(filename)
break
progress({'phase': 'upload', 'progress': 0.0})
self.wc.request('POST', '/data', 'set=fwType:10') # SMM firmware
rsp = self.wc.getresponse()
wc = self.wc
wc.request('POST', '/data', 'set=fwType:10') # SMM firmware
rsp = wc.getresponse()
rsp.read()
url = '/fwupload/fwupload.esp?ST1={0}'.format(self.st1)
url = '/fwupload/fwupload.esp?ST1={0}'.format(wc.st1)
fu = webclient.FileUploader(
self.wc, url, filename, data, formname='fileUpload',
wc, url, filename, data, formname='fileUpload',
otherfields={'preConfig': 'on'})
fu.start()
while fu.isAlive():
fu.join(3)
if progress:
progress({'phase': 'upload',
'progress': 100 * self.wc.get_upload_progress()})
'progress': 100 * wc.get_upload_progress()})
progress({'phase': 'validating', 'progress': 0.0})
url = '/data'
self.wc.request('POST', url, 'get=fwVersion,spfwInfo')
rsp = self.wc.getresponse()
wc.request('POST', url, 'get=fwVersion,spfwInfo')
rsp = 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=securityrollback:1')
self.wc.getresponse().read()
self.wc.request('POST', '/data', 'set=fwUpdate:1')
rsp = self.wc.getresponse()
wc.request('POST', '/data', 'set=securityrollback:1')
wc.getresponse().read()
wc.request('POST', '/data', 'set=fwUpdate:1')
rsp = 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()
wc.request('POST', '/data', 'get=fwProgress,fwUpdate')
rsp = wc.getresponse()
progdata = rsp.read()
if rsp.status != 200:
raise Exception('Error applying firmware')
@@ -1016,13 +1030,15 @@ class SMMClient(object):
return psui
def logout(self):
self.wc.request('POST', '/data/logout', None)
rsp = self.wc.getresponse()
wc = self.wc
wc.request('POST', '/data/logout', None)
rsp = wc.getresponse()
rsp.read()
self._wc = None
@property
def wc(self):
if not self._wc or self._wc.broken:
if (not self._wc or self._wc.broken
or self._wc.vintage < util._monotonic_time() + 30):
self._wc = self.get_webclient()
return self._wc