feat: automatically manage session token
This commit is contained in:
parent
a0333d5b2f
commit
70e0d784ec
2 changed files with 38 additions and 15 deletions
|
@ -1,5 +1,6 @@
|
||||||
"""Provides the Client class."""
|
"""Provides the Client class."""
|
||||||
from time import time as now
|
from datetime import datetime
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
from requests import Session
|
from requests import Session
|
||||||
|
|
||||||
|
@ -15,19 +16,22 @@ KNOWN_SENSORS = ["pmbus", "sensor"]
|
||||||
class Client:
|
class Client:
|
||||||
"""Client used to access Supermicro BMCs."""
|
"""Client used to access Supermicro BMCs."""
|
||||||
|
|
||||||
def __init__(self, server, username, password):
|
def __init__(self, server, username, password, session_timeout=30):
|
||||||
"""Initialises an instance of smbmc.Client.
|
"""Initialises an instance of smbmc.Client.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
server: Address of server in form: 'http://192.168.1.1'.
|
server: Address of server in form: 'http://192.168.1.1'.
|
||||||
username: Username.
|
username: Username.
|
||||||
password: Password.
|
password: Password.
|
||||||
|
session_timeout: Session timeout of the BMC (in minutes).
|
||||||
"""
|
"""
|
||||||
self.server = server
|
self.server = server
|
||||||
self.username = username
|
self.username = username
|
||||||
self.password = password
|
self.password = password
|
||||||
self._session = Session()
|
self._session = Session()
|
||||||
self.last_call = None
|
self.initial_call = datetime(1970, 1, 1)
|
||||||
|
self.session_timeout = session_timeout
|
||||||
|
self.sid_expiry = timedelta(minutes=self.session_timeout)
|
||||||
|
|
||||||
def login(self):
|
def login(self):
|
||||||
"""Login to Supermicro web interface.
|
"""Login to Supermicro web interface.
|
||||||
|
@ -48,22 +52,44 @@ class Client:
|
||||||
)
|
)
|
||||||
|
|
||||||
if "SID" in self._session.cookies.get_dict().keys():
|
if "SID" in self._session.cookies.get_dict().keys():
|
||||||
self.last_call = now()
|
self.initial_call = datetime.now()
|
||||||
else:
|
else:
|
||||||
raise Exception("Authentication Error")
|
raise Exception("Authentication Error")
|
||||||
|
|
||||||
|
def _query(self, data, path="/cgi/ipmi.cgi"):
|
||||||
|
"""Query Supermicro BMC.
|
||||||
|
|
||||||
|
Performs session login & token refresh.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path: Path to query. Defaults to '/cgi/ipmi.cgi'.
|
||||||
|
data: Requested data.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
request.Response: Response object.
|
||||||
|
"""
|
||||||
|
self._refresh_token()
|
||||||
|
|
||||||
|
return self._session.post(
|
||||||
|
f"{self.server}{path}",
|
||||||
|
data=data,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _refresh_token(self):
|
||||||
|
"""Refresh SID token if timeout likely."""
|
||||||
|
if datetime.now() > (self.initial_call + self.sid_expiry):
|
||||||
|
self.login()
|
||||||
|
|
||||||
def get_pmbus_metrics(self):
|
def get_pmbus_metrics(self):
|
||||||
"""Acquire metrics for all power supplies.
|
"""Acquire metrics for all power supplies.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: XML response.
|
str: XML response.
|
||||||
"""
|
"""
|
||||||
self.last_call = now()
|
r = self._query(
|
||||||
r = self._session.post(
|
|
||||||
f"{self.server}/cgi/ipmi.cgi",
|
|
||||||
data={
|
data={
|
||||||
"Get_PSInfoReadings.XML": "(0,0)",
|
"Get_PSInfoReadings.XML": "(0,0)",
|
||||||
},
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
psu_list = extract_xml_attr(r.text, ".//PSItem")
|
psu_list = extract_xml_attr(r.text, ".//PSItem")
|
||||||
|
@ -77,13 +103,10 @@ class Client:
|
||||||
Returns:
|
Returns:
|
||||||
str: XML response.
|
str: XML response.
|
||||||
"""
|
"""
|
||||||
self.last_call = now()
|
r = self._query(
|
||||||
|
|
||||||
r = self._session.post(
|
|
||||||
f"{self.server}/cgi/ipmi.cgi",
|
|
||||||
data={
|
data={
|
||||||
"SENSOR_INFO.XML": "(1,ff)",
|
"SENSOR_INFO.XML": "(1,ff)",
|
||||||
},
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
sensor_list = extract_xml_attr(r.text, ".//SENSOR")
|
sensor_list = extract_xml_attr(r.text, ".//SENSOR")
|
||||||
|
@ -110,7 +133,7 @@ class Client:
|
||||||
if not contains_valid_items(KNOWN_SENSORS, metrics):
|
if not contains_valid_items(KNOWN_SENSORS, metrics):
|
||||||
raise Exception("metrics array contains invalid metrics")
|
raise Exception("metrics array contains invalid metrics")
|
||||||
|
|
||||||
self.login()
|
# self.login()
|
||||||
result = {}
|
result = {}
|
||||||
|
|
||||||
for metric in metrics:
|
for metric in metrics:
|
||||||
|
|
|
@ -40,7 +40,7 @@ class TestClient:
|
||||||
with self.recorder.use_cassette(cassette_name):
|
with self.recorder.use_cassette(cassette_name):
|
||||||
self.client.login()
|
self.client.login()
|
||||||
|
|
||||||
assert self.client.last_call is not None
|
assert self.client.initial_call is not None
|
||||||
assert "SID" in self.client._session.cookies.get_dict().keys()
|
assert "SID" in self.client._session.cookies.get_dict().keys()
|
||||||
assert self.client._session.cookies["SID"] is not None
|
assert self.client._session.cookies["SID"] is not None
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue