add dataclass RedfishResource, update discover_redfish_resources, process_power_supply
This commit is contained in:
@@ -19,6 +19,22 @@ from prometheus_client import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class RedfishResource:
|
||||||
|
"""Container for Redfish resource URLs."""
|
||||||
|
chassis: str | None = None
|
||||||
|
systems: str | None = None
|
||||||
|
power: str | None = None
|
||||||
|
session_service: str | None = None
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class PowerMetrics:
|
||||||
|
"""Container for power metrics."""
|
||||||
|
voltage: float | None = None
|
||||||
|
watts: float | None = None
|
||||||
|
amps: float | None = None
|
||||||
|
serial: str | None = None
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class RedfishSession:
|
class RedfishSession:
|
||||||
"""Container for Redfish session data."""
|
"""Container for Redfish session data."""
|
||||||
@@ -132,8 +148,8 @@ async def login_hpe(session, host: HostConfig) -> bool:
|
|||||||
try:
|
try:
|
||||||
async with session.post(login_url, json=payload, ssl=False, timeout=10) as login_resp:
|
async with session.post(login_url, json=payload, ssl=False, timeout=10) as login_resp:
|
||||||
if login_resp.status == 201:
|
if login_resp.status == 201:
|
||||||
host.session_token = login_resp.headers.get("X-Auth-Token")
|
host.session.token = login_resp.headers.get("X-Auth-Token")
|
||||||
host.session_logout = login_resp.headers.get("Location")
|
host.session.logout_url = login_resp.headers.get("Location")
|
||||||
|
|
||||||
if not host.session.token or not host.session.logout_url:
|
if not host.session.token or not host.session.logout_url:
|
||||||
raise RuntimeError("Invalid login response")
|
raise RuntimeError("Invalid login response")
|
||||||
@@ -228,23 +244,25 @@ async def fetch_with_retry(session, host: HostConfig, url: str) -> dict | None:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
async def discover_redfish_resources(session, host: HostConfig) -> dict:
|
async def discover_redfish_resources(session, host: HostConfig) -> RedfishResource | None:
|
||||||
"""Discover available Redfish resources and return relevant URLs"""
|
"""Discover available Redfish resources and return relevant URLs"""
|
||||||
root_url = f"https://{host.fqdn}/redfish/v1/"
|
root_url = f"https://{host.fqdn}/redfish/v1/"
|
||||||
data = await fetch_with_retry(session, host, root_url)
|
data = await fetch_with_retry(session, host, root_url)
|
||||||
if not data:
|
if not data:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
# Extrahiere Links aus der Root-Antwort
|
# Create RedfishRessource object
|
||||||
links = {
|
resources = RedfishResource(
|
||||||
"Chassis": data.get("Chassis", {}).get("@odata.id"),
|
chassis=data.get("Chassis", {}).get("@odata.id"),
|
||||||
"Systems": data.get("Systems", {}).get("@odata.id"),
|
systems=data.get("Systems", {}).get("@odata.id"),
|
||||||
"SessionService": data.get("SessionService", {}).get("@odata.id"),
|
session_service=data.get("SessionService", {}).get("@odata.id"),
|
||||||
}
|
)
|
||||||
if not links["Chassis"]:
|
|
||||||
|
if not resources.chassis:
|
||||||
logging.error("No valid Chassis URL found for host %s", host.fqdn)
|
logging.error("No valid Chassis URL found for host %s", host.fqdn)
|
||||||
return {}
|
return None
|
||||||
return links
|
|
||||||
|
return resources
|
||||||
|
|
||||||
|
|
||||||
def get_power_resource_info(
|
def get_power_resource_info(
|
||||||
@@ -313,54 +331,46 @@ def process_power_supplies(
|
|||||||
|
|
||||||
async def process_power_supply(
|
async def process_power_supply(
|
||||||
session, host: HostConfig, psu_data: dict, power_resource_type: str
|
session, host: HostConfig, psu_data: dict, power_resource_type: str
|
||||||
):
|
) -> PowerMetrics | None:
|
||||||
"""Extract metrics from PowerSupply"""
|
"""Extract metrics from PowerSupply"""
|
||||||
serial = psu_data.get("SerialNumber")
|
serial = psu_data.get("SerialNumber")
|
||||||
|
metrics = PowerMetrics(serial=serial)
|
||||||
|
|
||||||
if power_resource_type == "PowerSubsystem":
|
if power_resource_type == "PowerSubsystem":
|
||||||
# Newer Redfish API: Metrics are an own "Metrics" ressource
|
# New Redfish API: Metrics are an own "Metrics" ressource
|
||||||
metrics_url = psu_data.get("Metrics", {}).get("@odata.id")
|
metrics_url = psu_data.get("Metrics", {}).get("@odata.id")
|
||||||
if not metrics_url:
|
if not metrics_url:
|
||||||
logging.warning("No Metrics found for PowerSupply %s", psu_data.get("Id"))
|
logging.warning("No Metrics found for PowerSupply %s", psu_data.get("Id"))
|
||||||
return
|
return None
|
||||||
|
|
||||||
metrics_url = f"https://{host.fqdn}{metrics_url}"
|
metrics_url = f"https://{host.fqdn}{metrics_url}"
|
||||||
metrics_data = await fetch_with_retry(session, host, metrics_url)
|
metrics_data = await fetch_with_retry(session, host, metrics_url)
|
||||||
if not metrics_data:
|
if not metrics_data:
|
||||||
return
|
return None
|
||||||
|
|
||||||
# Get metrics from Metrics ressource
|
# Get metrics from Metrics ressource
|
||||||
line_input_v = metrics_data.get("InputVoltage", {}).get("Reading")
|
metrics.voltage = metrics_data.get("InputVoltage", {}).get("Reading")
|
||||||
watts_input = metrics_data.get("InputPowerWatts", {}).get("Reading")
|
metrics.watts = metrics_data.get("InputPowerWatts", {}).get("Reading")
|
||||||
amps_input = metrics_data.get("InputCurrentAmps", {}).get("Reading")
|
metrics.amps = metrics_data.get("InputCurrentAmps", {}).get("Reading")
|
||||||
|
|
||||||
elif power_resource_type == "Power":
|
elif power_resource_type == "Power":
|
||||||
# Older Redfish API: Metrics are direct in PowerSupply as an array
|
# Older Redfish API: Metrics are direct in PowerSupply as an array
|
||||||
line_input_v = psu_data.get("LineInputVoltage")
|
metrics.voltage = psu_data.get("LineInputVoltage")
|
||||||
watts_input = psu_data.get("PowerInputWatts")
|
metrics.watts = psu_data.get("PowerInputWatts")
|
||||||
if watts_input is None:
|
if metrics.watts is None:
|
||||||
watts_input = psu_data.get("LastPowerOutputWatts")
|
metrics.watts = psu_data.get("LastPowerOutputWatts")
|
||||||
amps_input = psu_data.get("InputCurrentAmps")
|
metrics.amps = psu_data.get("InputCurrentAmps")
|
||||||
if amps_input is None:
|
if metrics.amps is None and metrics.voltage and metrics.watts:
|
||||||
if line_input_v and watts_input:
|
metrics.amps = round(metrics.watts / metrics.voltage, 2)
|
||||||
amps_input = round(watts_input / line_input_v, 2)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logging.error(
|
logging.error(
|
||||||
"Unknown power resource type for PowerSupply %s", psu_data.get("Id")
|
"Unknown power resource type for PowerSupply %s", psu_data.get("Id")
|
||||||
)
|
)
|
||||||
return
|
|
||||||
|
|
||||||
if amps_input is None and line_input_v and watts_input:
|
return None
|
||||||
amps_input = round(watts_input / line_input_v, 2)
|
|
||||||
|
|
||||||
# Update Prometheus metrics
|
return metrics
|
||||||
if line_input_v is not None:
|
|
||||||
VOLTAGE_GAUGE.labels(host=host.fqdn, psu_serial=serial).set(line_input_v)
|
|
||||||
if watts_input is not None:
|
|
||||||
WATTS_GAUGE.labels(host=host.fqdn, psu_serial=serial).set(watts_input)
|
|
||||||
if amps_input is not None:
|
|
||||||
AMPS_GAUGE.labels(host=host.fqdn, psu_serial=serial).set(amps_input)
|
|
||||||
|
|
||||||
|
|
||||||
def normalize_url(url: str) -> str:
|
def normalize_url(url: str) -> str:
|
||||||
|
|||||||
Reference in New Issue
Block a user