2
0
mirror of https://opendev.org/x/pyghmi synced 2026-01-11 18:52:33 +00:00

Add hostname for FPC and XCC

Provide access to hostname and dns domain on FPC.  Also, make the
webclient a bit more robust.

Change-Id: I7176adf821a01c5cf7f20cc8227118a6b8dbd4a3
This commit is contained in:
Jarrod Johnson
2018-03-27 15:13:46 -04:00
parent 3db33fafb5
commit 5c5a0269d7
6 changed files with 147 additions and 9 deletions

View File

@@ -1142,6 +1142,23 @@ class Command(object):
if not ip == '0.0.0.0':
self._assure_alert_policy(channel, destination)
def get_hostname(self):
"""Get the hostname used by the BMC in various contexts
This can vary somewhat in interpretation, but generally speaking
this should be the name that shows up on UIs and in DHCP requests and
DNS registration requests, as applicable.
:return: current hostname
"""
self.oem_init()
try:
return self._oem.get_hostname()
except exc.UnsupportedFunctionality:
# Use the DCMI MCI field as a fallback, since it's the closest
# thing in the IPMI Spec for this
return self.get_mci()
def get_mci(self):
"""Get the Management Controller Identifier, per DCMI specification
@@ -1149,6 +1166,20 @@ class Command(object):
"""
return self._chunkwise_dcmi_fetch(9)
def set_hostname(self, hostname):
"""Set the hostname to be used by the BMC in various contexts.
See get_hostname for details
:param hostname: The hostname to set
:return: Nothing
"""
self.oem_init()
try:
return self._oem.set_hostname(hostname)
except exc.UnsupportedFunctionality:
return self.set_mci(hostname)
def set_mci(self, mci):
"""Set the management controller identifier, per DCMI specification

View File

@@ -278,6 +278,18 @@ class OEMHandler(object):
"""
return
def set_hostname(self, hostname):
"""OEM specific hook to specify name information
"""
raise exc.UnsupportedFunctionality()
def get_hostname(self):
"""OEM specific hook to specify name information
"""
raise exc.UnsupportedFunctionality()
def set_alert_ipv6_destination(self, ip, destination, channel):
"""Set an IPv6 alert destination

View File

@@ -652,6 +652,8 @@ class OEMHandler(generic.OEMHandler):
data=(4, i))
name += rsp['data'][:]
return name.rstrip('\x00')
elif self.is_fpc:
return self.smmhandler.get_domain()
def set_oem_domain_name(self, name):
if self.has_tsm:
@@ -669,6 +671,22 @@ class OEMHandler(generic.OEMHandler):
self._restart_dns()
return
elif self.is_fpc:
self.smmhandler.set_domain(name)
def set_hostname(self, hostname):
if self.is_fpc:
return self.smmhandler.set_hostname(hostname)
elif self.has_xcc:
return self.immhandler.set_hostname(hostname)
return super(OEMHandler, self).set_hostname(hostname)
def get_hostname(self):
if self.is_fpc:
return self.smmhandler.get_hostname()
elif self.has_xcc:
return self.immhandler.get_hostname()
return super(OEMHandler, self).get_hostname()
""" Gets a remote console launcher for a Lenovo ThinkServer.

View File

@@ -1123,6 +1123,16 @@ class XCCClient(IMMClient):
if '_csrf_token' in wc.cookies:
wc.set_header('X-XSRF-TOKEN', self.wc.cookies['_csrf_token'])
def set_hostname(self, hostname):
self.wc.grab_json_response('/api/dataset', {'IMM_HostName': hostname})
self.wc.grab_json_response('/api/dataset', {'IMM_DescName': hostname})
self.weblogout()
def get_hostname(self):
rsp = self.wc.grab_json_response('/api/dataset/sys_info')
self.weblogout()
return rsp['items'][0]['system_name']
def update_firmware_backend(self, filename, data=None, progress=None,
bank=None):
self.weblogout()

View File

@@ -233,6 +233,7 @@ def get_sensor_reading(name, ipmicmd, sz):
class SMMClient(object):
def __init__(self, ipmicmd):
self.ipmicmd = weakref.proxy(ipmicmd)
self.smm = ipmicmd.bmc
@@ -275,9 +276,64 @@ class SMMClient(object):
self.st1 = data.text
for data in authdata.findall('st2'):
self.st2 = data.text
if not self.st2:
# This firmware puts tokens in the html file, parse that
wc.request('GET', '/index.html')
rsp = wc.getresponse()
if rsp.status != 200:
raise Exception(rsp.read())
indexhtml = rsp.read()
for line in indexhtml.split('\n'):
if '"ST1"' in line:
self.st1 = line.split()[-1].replace(
'"', '').replace(',', '')
if '"ST2"' in line:
self.st2 = line.split()[-1].replace(
'"', '').replace(',', '')
wc.set_header('ST2', self.st2)
return wc
def set_hostname(self, hostname):
self.wc.request('POST', '/data', 'set=hostname:' + hostname)
rsp = self.wc.getresponse()
if rsp.status != 200:
raise Exception(rsp.read())
rsp.read()
self.logout()
def get_hostname(self):
currinfo = self.get_netinfo()
self.logout()
for data in currinfo.find('netConfig').findall('hostname'):
return data.text
def get_netinfo(self):
self.wc.request('POST', '/data', 'get=hostname')
rsp = self.wc.getresponse()
data = rsp.read()
if rsp.status == 400:
self.wc.request('POST', '/data?get=hostname', '')
rsp = self.wc.getresponse()
data = rsp.read()
if rsp.status != 200:
raise Exception(data)
currinfo = fromstring(data)
return currinfo
def set_domain(self, domain):
self.wc.request('POST', '/data', 'set=dnsDomain:' + domain)
rsp = self.wc.getresponse()
if rsp.status != 200:
raise Exception(rsp.read())
rsp.read()
self.logout()
def get_domain(self):
currinfo = self.get_netinfo()
self.logout()
for data in currinfo.find('netConfig').findall('dnsDomain'):
return data.text
def get_ntp_enabled(self, variant):
self.wc.request('POST', '/data', 'get=ntpOpMode')
rsp = self.wc.getresponse()
@@ -370,6 +426,6 @@ class SMMClient(object):
@property
def wc(self):
if not self._wc:
if not self._wc or self._wc.broken:
self._wc = self.get_webclient()
return self._wc

View File

@@ -69,6 +69,7 @@ class SecureHTTPConnection(httplib.HTTPConnection, object):
**kwargs):
if 'timeout' not in kwargs:
kwargs['timeout'] = 60
self.broken = False
self.thehost = host
self.theport = port
httplib.HTTPConnection.__init__(self, host, port, strict, **kwargs)
@@ -107,12 +108,16 @@ class SecureHTTPConnection(httplib.HTTPConnection, object):
bincert)
def getresponse(self):
rsp = super(SecureHTTPConnection, self).getresponse()
for hdr in rsp.msg.headers:
if hdr.startswith('Set-Cookie:'):
c = Cookie.BaseCookie(hdr[11:])
for k in c:
self.cookies[k] = c[k].value
try:
rsp = super(SecureHTTPConnection, self).getresponse()
for hdr in rsp.msg.headers:
if hdr.startswith('Set-Cookie:'):
c = Cookie.BaseCookie(hdr[11:])
for k in c:
self.cookies[k] = c[k].value
except httplib.BadStatusLine:
self.broken = True
raise
return rsp
def grab_json_response(self, url, data=None, referer=None):
@@ -164,6 +169,8 @@ class SecureHTTPConnection(httplib.HTTPConnection, object):
headers = self.stdheaders.copy()
if method == 'GET' and 'Content-Type' in headers:
del headers['Content-Type']
if method == 'POST' and body and 'Content-Type' not in headers:
headers['Content-Type'] = 'application/x-www-form-urlencoded'
if self.cookies:
cookies = []
for ckey in self.cookies:
@@ -175,5 +182,9 @@ class SecureHTTPConnection(httplib.HTTPConnection, object):
headers['Cookie'] += '; ' + '; '.join(cookies)
if referer:
headers['Referer'] = referer
return super(SecureHTTPConnection, self).request(method, url, body,
headers)
try:
return super(SecureHTTPConnection, self).request(method, url, body,
headers)
except httplib.CannotSendRequest:
self.broken = True
raise