blob: 19c22e0e981999baeb7763f25f9202d9bf0cceb4 [file] [log] [blame]
Wludzik, Jozef405c1e42021-01-28 16:24:27 +01001import enum
2import math
3import re
Patrick Williams2d5404f2022-12-08 06:18:23 -06004
Wludzik, Jozef405c1e42021-01-28 16:24:27 +01005import requests
6
7
8class RedfishHttpStatus(enum.IntEnum):
9 ok = 200
10 created = 201
11 no_content = 204
12 bad_request = 400
13 not_found = 404
14 internal_server_error = 500
15
16
17class RedfishRequest:
Patrick Williams2d5404f2022-12-08 06:18:23 -060018 telemetry_service_path = "/redfish/v1/TelemetryService"
19 metric_definition_path = f"{telemetry_service_path}/MetricDefinitions"
20 metric_report_definition_path = (
21 f"{telemetry_service_path}/MetricReportDefinitions"
22 )
23 metric_report_path = f"{telemetry_service_path}/MetricReports"
Wludzik, Jozef405c1e42021-01-28 16:24:27 +010024
25 def __init__(self, host_addr, username, password):
26 self.host_addr = host_addr
27 self.username = username
28 self.password = password
29
30 def get(self, path, code=RedfishHttpStatus.ok):
31 u = self.host_addr + path
32 r = requests.get(u, auth=(self.username, self.password), verify=False)
Patrick Williams2d5404f2022-12-08 06:18:23 -060033 assert (
34 r.status_code == code
35 ), f"{r.status_code} == {code} on path {u}\n{r.text}"
Wludzik, Jozef405c1e42021-01-28 16:24:27 +010036 print(r.text)
37 return r.json()
38
39 def post(self, path, body, code=RedfishHttpStatus.created):
40 u = self.host_addr + path
Patrick Williams2d5404f2022-12-08 06:18:23 -060041 r = requests.post(
42 u, auth=(self.username, self.password), verify=False, json=body
43 )
44 assert (
45 r.status_code == code
46 ), f"{r.status_code} == {code} on path {u}\n{r.text}"
Wludzik, Jozef405c1e42021-01-28 16:24:27 +010047 print(r.text)
48 return r.json()
49
50 def delete(self, path, code=RedfishHttpStatus.no_content):
51 u = self.host_addr + path
Patrick Williams2d5404f2022-12-08 06:18:23 -060052 r = requests.delete(
53 u, auth=(self.username, self.password), verify=False
54 )
55 assert (
56 r.status_code == code
57 ), f"{r.status_code} == {code} on path {u}\n{r.text}"
Wludzik, Jozef405c1e42021-01-28 16:24:27 +010058
59
60class TelemetryService:
61 def __init__(self, redfish, metric_limit):
62 r = redfish.get(redfish.telemetry_service_path)
Patrick Williams2d5404f2022-12-08 06:18:23 -060063 self.min_interval = Duration.to_seconds(r["MinCollectionInterval"])
64 self.max_reports = r["MaxReports"]
Wludzik, Jozef405c1e42021-01-28 16:24:27 +010065 self.metrics = []
66 r = redfish.get(redfish.metric_definition_path)
Patrick Williams2d5404f2022-12-08 06:18:23 -060067 for m in r["Members"]:
68 path = m["@odata.id"]
Wludzik, Jozef405c1e42021-01-28 16:24:27 +010069 metricDef = redfish.get(path)
Patrick Williams2d5404f2022-12-08 06:18:23 -060070 self.metrics += [x for x in metricDef["MetricProperties"]]
Wludzik, Jozef405c1e42021-01-28 16:24:27 +010071 self.metrics = self.metrics[:metric_limit]
72
73
74class ReportDef:
75 def __init__(self, redfish):
76 self.redfish = redfish
77
78 def get_collection(self):
79 r = self.redfish.get(self.redfish.metric_report_definition_path)
Patrick Williams2d5404f2022-12-08 06:18:23 -060080 return [x["@odata.id"] for x in r["Members"]]
Wludzik, Jozef405c1e42021-01-28 16:24:27 +010081
Patrick Williams2d5404f2022-12-08 06:18:23 -060082 def add_report(
83 self,
84 id,
85 metrics=None,
86 type="OnRequest",
87 actions=None,
88 interval=None,
89 code=RedfishHttpStatus.created,
90 ):
Wludzik, Jozef405c1e42021-01-28 16:24:27 +010091 body = {
Patrick Williams2d5404f2022-12-08 06:18:23 -060092 "Id": id,
93 "Metrics": [],
94 "MetricReportDefinitionType": type,
95 "ReportActions": ["RedfishEvent", "LogToMetricReportsCollection"],
Wludzik, Jozef405c1e42021-01-28 16:24:27 +010096 }
97 if metrics is not None:
Patrick Williams2d5404f2022-12-08 06:18:23 -060098 body["Metrics"] = metrics
Wludzik, Jozef405c1e42021-01-28 16:24:27 +010099 if actions is not None:
Patrick Williams2d5404f2022-12-08 06:18:23 -0600100 body["ReportActions"] = actions
Wludzik, Jozef405c1e42021-01-28 16:24:27 +0100101 if interval is not None:
Patrick Williams2d5404f2022-12-08 06:18:23 -0600102 body["Schedule"] = {"RecurrenceInterval": interval}
103 return self.redfish.post(
104 self.redfish.metric_report_definition_path, body, code
105 )
Wludzik, Jozef405c1e42021-01-28 16:24:27 +0100106
107 def delete_report(self, path):
Patrick Williams2d5404f2022-12-08 06:18:23 -0600108 self.redfish.delete(f"{path}")
Wludzik, Jozef405c1e42021-01-28 16:24:27 +0100109
110
111class Duration:
112 def __init__(self):
113 pass
114
115 def to_iso8061(time):
Patrick Williams2d5404f2022-12-08 06:18:23 -0600116 assert time >= 0, "Invalid argument, time is negative"
Wludzik, Jozef405c1e42021-01-28 16:24:27 +0100117 days = int(time / (24 * 60 * 60))
118 time = math.fmod(time, (24 * 60 * 60))
119 hours = int(time / (60 * 60))
120 time = math.fmod(time, (60 * 60))
121 minutes = int(time / 60)
122 time = round(math.fmod(time, 60), 3)
Patrick Williams2d5404f2022-12-08 06:18:23 -0600123 return f"P{str(days)}DT{str(hours)}H{str(minutes)}M{str(time)}S"
Wludzik, Jozef405c1e42021-01-28 16:24:27 +0100124
125 def to_seconds(duration):
Patrick Williams2d5404f2022-12-08 06:18:23 -0600126 r = re.fullmatch(
127 r"-?P(\d+D)?(T(\d+H)?(\d+M)?(\d+(.\d+)?S)?)?", duration
128 )
129 assert r, "Invalid argument, not match with regex"
Wludzik, Jozef405c1e42021-01-28 16:24:27 +0100130 days = r.group(1)
131 hours = r.group(3)
132 minutes = r.group(4)
133 seconds = r.group(5)
134 result = 0
135 if days is not None:
136 result += int(days[:-1]) * 60 * 60 * 24
137 if hours is not None:
138 result += int(hours[:-1]) * 60 * 60
139 if minutes is not None:
140 result += int(minutes[:-1]) * 60
141 if seconds is not None:
142 result += float(seconds[:-1])
143 return result