blob: 28dee8448b4f6f588d03fdef6592bb608c466d0c [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