blob: 28dee8448b4f6f588d03fdef6592bb608c466d0c [file] [log] [blame]
Wludzik, Jozef405c1e42021-01-28 16:24:27 +01001import enum
2import math
3import re
4import requests
5
6
7class RedfishHttpStatus(enum.IntEnum):
8 ok = 200
9 created = 201
10 no_content = 204
11 bad_request = 400
12 not_found = 404
13 internal_server_error = 500
14
15
16class RedfishRequest:
17 telemetry_service_path = '/redfish/v1/TelemetryService'
18 metric_definition_path = f'{telemetry_service_path}/MetricDefinitions'
19 metric_report_definition_path = \
20 f'{telemetry_service_path}/MetricReportDefinitions'
21 metric_report_path = f'{telemetry_service_path}/MetricReports'
22
23 def __init__(self, host_addr, username, password):
24 self.host_addr = host_addr
25 self.username = username
26 self.password = password
27
28 def get(self, path, code=RedfishHttpStatus.ok):
29 u = self.host_addr + path
30 r = requests.get(u, auth=(self.username, self.password), verify=False)
31 assert r.status_code == code, \
32 f'{r.status_code} == {code} on path {u}\n{r.text}'
33 print(r.text)
34 return r.json()
35
36 def post(self, path, body, code=RedfishHttpStatus.created):
37 u = self.host_addr + path
38 r = requests.post(u, auth=(self.username, self.password), verify=False,
39 json=body)
40 assert r.status_code == code, \
41 f'{r.status_code} == {code} on path {u}\n{r.text}'
42 print(r.text)
43 return r.json()
44
45 def delete(self, path, code=RedfishHttpStatus.no_content):
46 u = self.host_addr + path
47 r = requests.delete(u, auth=(self.username, self.password),
48 verify=False)
49 assert r.status_code == code, \
50 f'{r.status_code} == {code} on path {u}\n{r.text}'
51
52
53class TelemetryService:
54 def __init__(self, redfish, metric_limit):
55 r = redfish.get(redfish.telemetry_service_path)
56 self.min_interval = Duration.to_seconds(r['MinCollectionInterval'])
57 self.max_reports = r['MaxReports']
58 self.metrics = []
59 r = redfish.get(redfish.metric_definition_path)
60 for m in r['Members']:
61 path = m['@odata.id']
62 metricDef = redfish.get(path)
63 self.metrics += [x for x in metricDef['MetricProperties']]
64 self.metrics = self.metrics[:metric_limit]
65
66
67class ReportDef:
68 def __init__(self, redfish):
69 self.redfish = redfish
70
71 def get_collection(self):
72 r = self.redfish.get(self.redfish.metric_report_definition_path)
73 return [x['@odata.id'] for x in r['Members']]
74
75 def add_report(self, id, metrics=None, type='OnRequest', actions=None,
76 interval=None, code=RedfishHttpStatus.created):
77 body = {
78 'Id': id,
79 'Metrics': [],
80 'MetricReportDefinitionType': type,
81 'ReportActions': ['RedfishEvent', 'LogToMetricReportsCollection']
82 }
83 if metrics is not None:
84 body['Metrics'] = metrics
85 if actions is not None:
86 body['ReportActions'] = actions
87 if interval is not None:
88 body['Schedule'] = {'RecurrenceInterval': interval}
89 return self.redfish.post(self.redfish.metric_report_definition_path,
90 body, code)
91
92 def delete_report(self, path):
93 self.redfish.delete(f'{path}')
94
95
96class Duration:
97 def __init__(self):
98 pass
99
100 def to_iso8061(time):
101 assert time >= 0, 'Invalid argument, time is negative'
102 days = int(time / (24 * 60 * 60))
103 time = math.fmod(time, (24 * 60 * 60))
104 hours = int(time / (60 * 60))
105 time = math.fmod(time, (60 * 60))
106 minutes = int(time / 60)
107 time = round(math.fmod(time, 60), 3)
108 return f'P{str(days)}DT{str(hours)}H{str(minutes)}M{str(time)}S'
109
110 def to_seconds(duration):
111 r = re.fullmatch(r'-?P(\d+D)?(T(\d+H)?(\d+M)?(\d+(.\d+)?S)?)?',
112 duration)
113 assert r, 'Invalid argument, not match with regex'
114 days = r.group(1)
115 hours = r.group(3)
116 minutes = r.group(4)
117 seconds = r.group(5)
118 result = 0
119 if days is not None:
120 result += int(days[:-1]) * 60 * 60 * 24
121 if hours is not None:
122 result += int(hours[:-1]) * 60 * 60
123 if minutes is not None:
124 result += int(minutes[:-1]) * 60
125 if seconds is not None:
126 result += float(seconds[:-1])
127 return result