blob: 19c22e0e981999baeb7763f25f9202d9bf0cceb4 [file] [log] [blame]
import enum
import math
import re
import requests
class RedfishHttpStatus(enum.IntEnum):
ok = 200
created = 201
no_content = 204
bad_request = 400
not_found = 404
internal_server_error = 500
class RedfishRequest:
telemetry_service_path = "/redfish/v1/TelemetryService"
metric_definition_path = f"{telemetry_service_path}/MetricDefinitions"
metric_report_definition_path = (
f"{telemetry_service_path}/MetricReportDefinitions"
)
metric_report_path = f"{telemetry_service_path}/MetricReports"
def __init__(self, host_addr, username, password):
self.host_addr = host_addr
self.username = username
self.password = password
def get(self, path, code=RedfishHttpStatus.ok):
u = self.host_addr + path
r = requests.get(u, auth=(self.username, self.password), verify=False)
assert (
r.status_code == code
), f"{r.status_code} == {code} on path {u}\n{r.text}"
print(r.text)
return r.json()
def post(self, path, body, code=RedfishHttpStatus.created):
u = self.host_addr + path
r = requests.post(
u, auth=(self.username, self.password), verify=False, json=body
)
assert (
r.status_code == code
), f"{r.status_code} == {code} on path {u}\n{r.text}"
print(r.text)
return r.json()
def delete(self, path, code=RedfishHttpStatus.no_content):
u = self.host_addr + path
r = requests.delete(
u, auth=(self.username, self.password), verify=False
)
assert (
r.status_code == code
), f"{r.status_code} == {code} on path {u}\n{r.text}"
class TelemetryService:
def __init__(self, redfish, metric_limit):
r = redfish.get(redfish.telemetry_service_path)
self.min_interval = Duration.to_seconds(r["MinCollectionInterval"])
self.max_reports = r["MaxReports"]
self.metrics = []
r = redfish.get(redfish.metric_definition_path)
for m in r["Members"]:
path = m["@odata.id"]
metricDef = redfish.get(path)
self.metrics += [x for x in metricDef["MetricProperties"]]
self.metrics = self.metrics[:metric_limit]
class ReportDef:
def __init__(self, redfish):
self.redfish = redfish
def get_collection(self):
r = self.redfish.get(self.redfish.metric_report_definition_path)
return [x["@odata.id"] for x in r["Members"]]
def add_report(
self,
id,
metrics=None,
type="OnRequest",
actions=None,
interval=None,
code=RedfishHttpStatus.created,
):
body = {
"Id": id,
"Metrics": [],
"MetricReportDefinitionType": type,
"ReportActions": ["RedfishEvent", "LogToMetricReportsCollection"],
}
if metrics is not None:
body["Metrics"] = metrics
if actions is not None:
body["ReportActions"] = actions
if interval is not None:
body["Schedule"] = {"RecurrenceInterval": interval}
return self.redfish.post(
self.redfish.metric_report_definition_path, body, code
)
def delete_report(self, path):
self.redfish.delete(f"{path}")
class Duration:
def __init__(self):
pass
def to_iso8061(time):
assert time >= 0, "Invalid argument, time is negative"
days = int(time / (24 * 60 * 60))
time = math.fmod(time, (24 * 60 * 60))
hours = int(time / (60 * 60))
time = math.fmod(time, (60 * 60))
minutes = int(time / 60)
time = round(math.fmod(time, 60), 3)
return f"P{str(days)}DT{str(hours)}H{str(minutes)}M{str(time)}S"
def to_seconds(duration):
r = re.fullmatch(
r"-?P(\d+D)?(T(\d+H)?(\d+M)?(\d+(.\d+)?S)?)?", duration
)
assert r, "Invalid argument, not match with regex"
days = r.group(1)
hours = r.group(3)
minutes = r.group(4)
seconds = r.group(5)
result = 0
if days is not None:
result += int(days[:-1]) * 60 * 60 * 24
if hours is not None:
result += int(hours[:-1]) * 60 * 60
if minutes is not None:
result += int(minutes[:-1]) * 60
if seconds is not None:
result += float(seconds[:-1])
return result