2
0
mirror of https://opendev.org/x/pyghmi synced 2026-04-12 13:01:29 +00:00

Negotiate a redfish session, if possible

Particularly newer redfish implementations can
be much quicker if the user/password is omitted

Change-Id: Idd964dd6393d91196dce23a75a91c600e9f9d273
This commit is contained in:
Jarrod Johnson
2024-09-11 16:09:49 -04:00
parent ff04e4fa32
commit 4dd8b6403b
2 changed files with 53 additions and 1 deletions

View File

@@ -161,6 +161,7 @@ class Command(object):
self._gpool = pool
self._bmcv4ip = None
self._bmcv6ip = None
self.xauthtoken = None
for addrinf in socket.getaddrinfo(bmc, 0, 0, socket.SOCK_STREAM):
if addrinf[0] == socket.AF_INET:
self._bmcv4ip = socket.inet_pton(addrinf[0], addrinf[-1][0])
@@ -173,12 +174,14 @@ class Command(object):
self.wc.set_header('Accept-Encoding', 'gzip')
self.wc.set_header('OData-Version', '4.0')
overview = self.wc.grab_json_response('/redfish/v1/')
self.wc.set_basic_credentials(userid, password)
self.username = userid
self.password = password
self.wc.set_basic_credentials(self.username, self.password)
self.wc.set_header('Content-Type', 'application/json')
if 'Systems' not in overview:
raise exc.PyghmiException('Redfish not ready')
if 'SessionService' in overview:
self._get_session_token(self.wc)
systems = overview['Systems']['@odata.id']
res = self.wc.grab_json_response_with_status(systems)
if res[1] == 401:
@@ -206,6 +209,26 @@ class Command(object):
self.powerurl = self.sysinfo.get('Actions', {}).get(
'#ComputerSystem.Reset', {}).get('target', None)
def _get_session_token(self, wc):
# specification actually indicates we can skip straight to this url
username = self.username
password = self.password
if not isinstance(username, str):
username = username.decode()
if not isinstance(password, str):
password = password.decode()
rsp = wc.grab_rsp('/redfish/v1/SessionService/Sessions',
{'UserName': username, 'Password': password})
rsp.read()
self.xauthtoken = rsp.getheader('X-Auth-Token')
if self.xauthtoken:
if 'Authorization' in wc.stdheaders:
del wc.stdheaders['Authorization']
if 'Authorization' in self.wc.stdheaders:
del self.wc.stdheaders['Authorization']
wc.stdheaders['X-Auth-Token'] = self.xauthtoken
self.wc.stdheaders['X-Auth-Token'] = self.xauthtoken
@property
def _accountserviceurl(self):
sroot = self._do_web_request('/redfish/v1/')
@@ -520,6 +543,17 @@ class Command(object):
finally:
if 'If-Match' in wc.stdheaders:
del wc.stdheaders['If-Match']
if res[1] == 401 and self.xauthtoken:
wc.set_basic_credentials(self.username, self.password)
self._get_session_token(wc)
if etag:
wc.stdheaders['If-Match'] = etag
try:
res = wc.grab_json_response_with_status(url, payload,
method=method)
finally:
if 'If-Match' in wc.stdheaders:
del wc.stdheaders['If-Match']
if res[1] < 200 or res[1] >= 300:
try:
info = json.loads(res[0])
@@ -1430,3 +1464,4 @@ if __name__ == '__main__':
print(repr(
Command(sys.argv[1], os.environ['BMCUSER'], os.environ['BMCPASS'],
verifycallback=lambda x: True).get_power()))

View File

@@ -272,6 +272,22 @@ class SecureHTTPConnection(httplib.HTTPConnection, object):
return json.loads(body) if body else {}, rsp.status
return body, rsp.status
def grab_rsp(self, url, data=None, referer=None, headers=None, method=None):
webclient = self.dupe()
if isinstance(data, dict):
data = json.dumps(data)
if data:
if not method:
method = 'POST'
webclient.request(method, url, data, referer=referer,
headers=headers)
else:
if not method:
method = 'GET'
webclient.request(method, url, referer=referer, headers=headers)
rsp = webclient.getresponse()
return rsp
def download(self, url, file):
"""Download a file to filename or file object
@@ -390,3 +406,4 @@ class SecureHTTPConnection(httplib.HTTPConnection, object):
except httplib.CannotSendRequest:
self.broken = True
raise