1405c1e4bSWludzik, Jozefimport enum 2405c1e4bSWludzik, Jozefimport math 3405c1e4bSWludzik, Jozefimport re 4*2d5404f1SPatrick Williams 5405c1e4bSWludzik, Jozefimport requests 6405c1e4bSWludzik, Jozef 7405c1e4bSWludzik, Jozef 8405c1e4bSWludzik, Jozefclass RedfishHttpStatus(enum.IntEnum): 9405c1e4bSWludzik, Jozef ok = 200 10405c1e4bSWludzik, Jozef created = 201 11405c1e4bSWludzik, Jozef no_content = 204 12405c1e4bSWludzik, Jozef bad_request = 400 13405c1e4bSWludzik, Jozef not_found = 404 14405c1e4bSWludzik, Jozef internal_server_error = 500 15405c1e4bSWludzik, Jozef 16405c1e4bSWludzik, Jozef 17405c1e4bSWludzik, Jozefclass RedfishRequest: 18*2d5404f1SPatrick Williams telemetry_service_path = "/redfish/v1/TelemetryService" 19*2d5404f1SPatrick Williams metric_definition_path = f"{telemetry_service_path}/MetricDefinitions" 20*2d5404f1SPatrick Williams metric_report_definition_path = ( 21*2d5404f1SPatrick Williams f"{telemetry_service_path}/MetricReportDefinitions" 22*2d5404f1SPatrick Williams ) 23*2d5404f1SPatrick Williams metric_report_path = f"{telemetry_service_path}/MetricReports" 24405c1e4bSWludzik, Jozef 25405c1e4bSWludzik, Jozef def __init__(self, host_addr, username, password): 26405c1e4bSWludzik, Jozef self.host_addr = host_addr 27405c1e4bSWludzik, Jozef self.username = username 28405c1e4bSWludzik, Jozef self.password = password 29405c1e4bSWludzik, Jozef 30405c1e4bSWludzik, Jozef def get(self, path, code=RedfishHttpStatus.ok): 31405c1e4bSWludzik, Jozef u = self.host_addr + path 32405c1e4bSWludzik, Jozef r = requests.get(u, auth=(self.username, self.password), verify=False) 33*2d5404f1SPatrick Williams assert ( 34*2d5404f1SPatrick Williams r.status_code == code 35*2d5404f1SPatrick Williams ), f"{r.status_code} == {code} on path {u}\n{r.text}" 36405c1e4bSWludzik, Jozef print(r.text) 37405c1e4bSWludzik, Jozef return r.json() 38405c1e4bSWludzik, Jozef 39405c1e4bSWludzik, Jozef def post(self, path, body, code=RedfishHttpStatus.created): 40405c1e4bSWludzik, Jozef u = self.host_addr + path 41*2d5404f1SPatrick Williams r = requests.post( 42*2d5404f1SPatrick Williams u, auth=(self.username, self.password), verify=False, json=body 43*2d5404f1SPatrick Williams ) 44*2d5404f1SPatrick Williams assert ( 45*2d5404f1SPatrick Williams r.status_code == code 46*2d5404f1SPatrick Williams ), f"{r.status_code} == {code} on path {u}\n{r.text}" 47405c1e4bSWludzik, Jozef print(r.text) 48405c1e4bSWludzik, Jozef return r.json() 49405c1e4bSWludzik, Jozef 50405c1e4bSWludzik, Jozef def delete(self, path, code=RedfishHttpStatus.no_content): 51405c1e4bSWludzik, Jozef u = self.host_addr + path 52*2d5404f1SPatrick Williams r = requests.delete( 53*2d5404f1SPatrick Williams u, auth=(self.username, self.password), verify=False 54*2d5404f1SPatrick Williams ) 55*2d5404f1SPatrick Williams assert ( 56*2d5404f1SPatrick Williams r.status_code == code 57*2d5404f1SPatrick Williams ), f"{r.status_code} == {code} on path {u}\n{r.text}" 58405c1e4bSWludzik, Jozef 59405c1e4bSWludzik, Jozef 60405c1e4bSWludzik, Jozefclass TelemetryService: 61405c1e4bSWludzik, Jozef def __init__(self, redfish, metric_limit): 62405c1e4bSWludzik, Jozef r = redfish.get(redfish.telemetry_service_path) 63*2d5404f1SPatrick Williams self.min_interval = Duration.to_seconds(r["MinCollectionInterval"]) 64*2d5404f1SPatrick Williams self.max_reports = r["MaxReports"] 65405c1e4bSWludzik, Jozef self.metrics = [] 66405c1e4bSWludzik, Jozef r = redfish.get(redfish.metric_definition_path) 67*2d5404f1SPatrick Williams for m in r["Members"]: 68*2d5404f1SPatrick Williams path = m["@odata.id"] 69405c1e4bSWludzik, Jozef metricDef = redfish.get(path) 70*2d5404f1SPatrick Williams self.metrics += [x for x in metricDef["MetricProperties"]] 71405c1e4bSWludzik, Jozef self.metrics = self.metrics[:metric_limit] 72405c1e4bSWludzik, Jozef 73405c1e4bSWludzik, Jozef 74405c1e4bSWludzik, Jozefclass ReportDef: 75405c1e4bSWludzik, Jozef def __init__(self, redfish): 76405c1e4bSWludzik, Jozef self.redfish = redfish 77405c1e4bSWludzik, Jozef 78405c1e4bSWludzik, Jozef def get_collection(self): 79405c1e4bSWludzik, Jozef r = self.redfish.get(self.redfish.metric_report_definition_path) 80*2d5404f1SPatrick Williams return [x["@odata.id"] for x in r["Members"]] 81405c1e4bSWludzik, Jozef 82*2d5404f1SPatrick Williams def add_report( 83*2d5404f1SPatrick Williams self, 84*2d5404f1SPatrick Williams id, 85*2d5404f1SPatrick Williams metrics=None, 86*2d5404f1SPatrick Williams type="OnRequest", 87*2d5404f1SPatrick Williams actions=None, 88*2d5404f1SPatrick Williams interval=None, 89*2d5404f1SPatrick Williams code=RedfishHttpStatus.created, 90*2d5404f1SPatrick Williams ): 91405c1e4bSWludzik, Jozef body = { 92*2d5404f1SPatrick Williams "Id": id, 93*2d5404f1SPatrick Williams "Metrics": [], 94*2d5404f1SPatrick Williams "MetricReportDefinitionType": type, 95*2d5404f1SPatrick Williams "ReportActions": ["RedfishEvent", "LogToMetricReportsCollection"], 96405c1e4bSWludzik, Jozef } 97405c1e4bSWludzik, Jozef if metrics is not None: 98*2d5404f1SPatrick Williams body["Metrics"] = metrics 99405c1e4bSWludzik, Jozef if actions is not None: 100*2d5404f1SPatrick Williams body["ReportActions"] = actions 101405c1e4bSWludzik, Jozef if interval is not None: 102*2d5404f1SPatrick Williams body["Schedule"] = {"RecurrenceInterval": interval} 103*2d5404f1SPatrick Williams return self.redfish.post( 104*2d5404f1SPatrick Williams self.redfish.metric_report_definition_path, body, code 105*2d5404f1SPatrick Williams ) 106405c1e4bSWludzik, Jozef 107405c1e4bSWludzik, Jozef def delete_report(self, path): 108*2d5404f1SPatrick Williams self.redfish.delete(f"{path}") 109405c1e4bSWludzik, Jozef 110405c1e4bSWludzik, Jozef 111405c1e4bSWludzik, Jozefclass Duration: 112405c1e4bSWludzik, Jozef def __init__(self): 113405c1e4bSWludzik, Jozef pass 114405c1e4bSWludzik, Jozef 115405c1e4bSWludzik, Jozef def to_iso8061(time): 116*2d5404f1SPatrick Williams assert time >= 0, "Invalid argument, time is negative" 117405c1e4bSWludzik, Jozef days = int(time / (24 * 60 * 60)) 118405c1e4bSWludzik, Jozef time = math.fmod(time, (24 * 60 * 60)) 119405c1e4bSWludzik, Jozef hours = int(time / (60 * 60)) 120405c1e4bSWludzik, Jozef time = math.fmod(time, (60 * 60)) 121405c1e4bSWludzik, Jozef minutes = int(time / 60) 122405c1e4bSWludzik, Jozef time = round(math.fmod(time, 60), 3) 123*2d5404f1SPatrick Williams return f"P{str(days)}DT{str(hours)}H{str(minutes)}M{str(time)}S" 124405c1e4bSWludzik, Jozef 125405c1e4bSWludzik, Jozef def to_seconds(duration): 126*2d5404f1SPatrick Williams r = re.fullmatch( 127*2d5404f1SPatrick Williams r"-?P(\d+D)?(T(\d+H)?(\d+M)?(\d+(.\d+)?S)?)?", duration 128*2d5404f1SPatrick Williams ) 129*2d5404f1SPatrick Williams assert r, "Invalid argument, not match with regex" 130405c1e4bSWludzik, Jozef days = r.group(1) 131405c1e4bSWludzik, Jozef hours = r.group(3) 132405c1e4bSWludzik, Jozef minutes = r.group(4) 133405c1e4bSWludzik, Jozef seconds = r.group(5) 134405c1e4bSWludzik, Jozef result = 0 135405c1e4bSWludzik, Jozef if days is not None: 136405c1e4bSWludzik, Jozef result += int(days[:-1]) * 60 * 60 * 24 137405c1e4bSWludzik, Jozef if hours is not None: 138405c1e4bSWludzik, Jozef result += int(hours[:-1]) * 60 * 60 139405c1e4bSWludzik, Jozef if minutes is not None: 140405c1e4bSWludzik, Jozef result += int(minutes[:-1]) * 60 141405c1e4bSWludzik, Jozef if seconds is not None: 142405c1e4bSWludzik, Jozef result += float(seconds[:-1]) 143405c1e4bSWludzik, Jozef return result 144