Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def _item_name(item_data, padding):

def inventorize_redfish_firmware(section: RedfishAPIData) -> InventoryResult:
"""create inventory table for firmware"""
path = ["hardware", "firmware", "redfish"]
path = ["hardware", "firmware"]
if section.get("FirmwareInventory", {}).get("Current"):
data = section.get("FirmwareInventory", {}).get("Current")
padding = len(str(len(data)))
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#!/usr/bin/env python3
"""Redfish HW/SW inventory plugin"""

# (c) Andreas Doehler <andreas.doehler@bechtle.com/andreas.doehler@gmail.com>
# License: GNU General Public License v2

from collections.abc import Mapping, Sequence
from typing import Any

from cmk.agent_based.v2 import InventoryPlugin, InventoryResult, TableRow
from cmk.plugins.redfish.lib import RedfishAPIData

IDSET = set[tuple[str, str, str, str, str, str]]


def _extract_odata_ids(
data: None | RedfishAPIData | Sequence[Mapping[str, Any]], ids_set: IDSET
) -> IDSET:
if data is None or isinstance(data, (str, int, float, bool)):
return ids_set

if isinstance(data, Mapping):
for key, value in data.items():
if key == "@odata.id" and isinstance(value, str):
if "Oem" not in value:
key_name = data.get("Name")
if key_name:
ids_set.add(
(
value,
key_name,
(data.get("SerialNumber") or "nothing set").strip(),
(data.get("PartNumber") or "nothing set").strip(),
(data.get("Manufacturer") or "nothing set").strip(),
(data.get("Model") or "nothing set").strip(),
)
)
else:
ids_set = _extract_odata_ids(value, ids_set)
else:
for item in data:
ids_set = _extract_odata_ids(item, ids_set)

return ids_set


def inventory_redfish_data(
section_redfish_storage: None | RedfishAPIData,
section_redfish_processors: None | RedfishAPIData,
section_redfish_drives: None | RedfishAPIData,
section_redfish_psu: None | RedfishAPIData,
section_redfish_memory: None | RedfishAPIData,
section_redfish_power: None | RedfishAPIData,
section_redfish_thermal: None | RedfishAPIData,
section_redfish_networkadapters: None | RedfishAPIData,
) -> InventoryResult:
result_path = ["redfish"]

odata_ids_set: IDSET = set()
odata_ids_set = _extract_odata_ids(section_redfish_processors, odata_ids_set)
odata_ids_set = _extract_odata_ids(section_redfish_storage, odata_ids_set)
odata_ids_set = _extract_odata_ids(section_redfish_drives, odata_ids_set)
odata_ids_set = _extract_odata_ids(section_redfish_psu, odata_ids_set)
odata_ids_set = _extract_odata_ids(section_redfish_memory, odata_ids_set)
odata_ids_set = _extract_odata_ids(section_redfish_power, odata_ids_set)
odata_ids_set = _extract_odata_ids(section_redfish_thermal, odata_ids_set)
odata_ids_set = _extract_odata_ids(section_redfish_networkadapters, odata_ids_set)

for path, name, serial, part_number, manufacturer, model in odata_ids_set:
if (
serial in ("nothing set", "NOT AVAILABLE")
and part_number in ("nothing set", "NOT AVAILABLE")
and manufacturer == "nothing set"
and model == "nothing set"
):
continue
if path.startswith("/redfish/"):
segments = (
path.replace("#", "")
.replace(":", "-")
.replace(".", "_")
.replace("'", "")
.replace("(", "_")
.replace(")", "_")
.replace("%", "_")
.strip("/")
.split("/")
)
result_path = [element for element in segments if element != ""]
item_id = result_path.pop()
if result_path[0] == "redfish":
result_path = result_path[1:]
if result_path[0] == "v1":
result_path = result_path[1:]
final_path = ["hardware"] + result_path
yield TableRow(
path=final_path,
key_columns={"id": item_id},
inventory_columns={
"name": name,
"serial": serial,
"part_number": part_number,
"manufacturer": manufacturer,
"model": model,
},
)


inventory_plugin_redfish_data = InventoryPlugin(
name="redfish_data",
sections=[
"redfish_storage",
"redfish_processors",
"redfish_drives",
"redfish_psu",
"redfish_memory",
"redfish_power",
"redfish_thermal",
"redfish_networkadapters",
],
inventory_function=inventory_redfish_data,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/env python3
"""check single redfish pdu state"""

# (c) Andreas Doehler <andreas.doehler@bechtle.com/andreas.doehler@gmail.com>
# License: GNU General Public License v2

from cmk.agent_based.v2 import (
AgentSection,
CheckPlugin,
CheckResult,
DiscoveryResult,
Result,
Service,
State,
)
from cmk.plugins.redfish.lib import (
parse_redfish_multiple,
redfish_health_state,
RedfishAPIData,
)

agent_section_redfish_pdus = AgentSection(
name="redfish_rackpdus",
parse_function=parse_redfish_multiple,
parsed_section_name="redfish_pdus",
)


def discovery_redfish_pdus(section: RedfishAPIData) -> DiscoveryResult:
"""Discover single pdus"""
for key in section.keys():
if section[key].get("Status", {}).get("State") == "Absent":
continue
item = key.split("/")[-1]
yield Service(item=item)


def check_redfish_pdus(item: str, section: RedfishAPIData) -> CheckResult:
"""Check single pdu state"""

for key in section.keys():
if key.endswith(f"/{item}"):
item = key
break
data = section.get(item, None)
if data is None:
return
print(data)
firmware = data.get("FirmwareVersion")
serial = data.get("SerialNumber")
model = data.get("Model")
manufacturer = data.get("Manufacturer")

yield Result(state=State.OK, summary=f"PDU {manufacturer} {model} S/N {serial} FW {firmware}")

dev_state, dev_msg = redfish_health_state(data.get("Status", {}))
yield Result(state=State(dev_state), summary=dev_msg)


check_plugin_redfish_pdus = CheckPlugin(
name="redfish_pdus",
service_name="PDU %s",
sections=["redfish_pdus"],
discovery_function=discovery_redfish_pdus,
check_function=check_redfish_pdus,
)
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,8 @@ def check_redfish_physicaldrives(item: str, section: RedfishAPIData) -> CheckRes
)
yield Metric("media_life_left", int(data.get("PredictedMediaLifeLeftPercent")))
elif data.get("SSDEnduranceUtilizationPercentage"):
disc_msg = (
f"{disc_msg}, SSD Utilization: "
f"{int(data.get('SSDEnduranceUtilizationPercentage', 0))}%"
)
media_life_left = 100 - int(data.get("SSDEnduranceUtilizationPercentage", 0))
disc_msg = f"{disc_msg}, Media Life Left: {media_life_left}%"
yield Metric("ssd_utilization", int(data.get("SSDEnduranceUtilizationPercentage")))
yield Result(state=State(0), summary=disc_msg)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#!/usr/bin/env python3
"""check the power consumption of a system via redfish"""

# (c) Andreas Doehler <andreas.doehler@bechtle.com/andreas.doehler@gmail.com>
# License: GNU General Public License v2

from cmk.agent_based.v2 import (
CheckPlugin,
CheckResult,
DiscoveryResult,
Metric,
Result,
Service,
State,
)
from cmk.plugins.redfish.lib import (
RedfishAPIData,
)


def discovery_redfish_power_consumption(section: RedfishAPIData) -> DiscoveryResult:
for key in section.keys():
if section[key].get("PowerControl", None):
yield Service()


def check_redfish_power_consumption(section: RedfishAPIData) -> CheckResult:
powercontrol = []
for key in section.keys():
if powercontrol_element := section[key].get("PowerControl", None):
powercontrol.extend(powercontrol_element)

if not powercontrol:
return
result_submited = False
for element in powercontrol:
summary_msg = []
mem_id = element.get("MemberId", "0")
mem_name = element.get("Name", "PowerControl")
system_wide_values = {}
for i in ["PowerCapacityWatts", "PowerConsumedWatts"]:
if (value := element.get(i, None)) is not None:
system_wide_values[i] = value
summary_msg.append(f"{i} - {value} W")

if summary_msg:
result_submited = True
yield Result(state=State(0), summary=f"{mem_name}: {' / '.join(summary_msg)}")
if metrics := element.get("PowerMetrics", None):
for metric_name in [
"AverageConsumedWatts",
"MinConsumedWatts",
"MaxConsumedWatts",
]:
if (metric_value := metrics.get(metric_name, None)) is not None:
maximum_value = system_wide_values.get("PowerCapacityWatts", None)
if maximum_value:
yield Metric(
name=f"{metric_name.lower()}_{mem_id}",
value=float(metric_value),
boundaries=(0, float(maximum_value)),
)
else:
yield Metric(
name=f"{metric_name.lower()}_{mem_id}",
value=float(metric_value),
)
if not result_submited:
yield Result(
state=State(0),
summary="No power consumption data available.",
)


check_plugin_redfish_power_consumption = CheckPlugin(
name="redfish_power_consumption",
service_name="Power consumption",
sections=["redfish_power"],
discovery_function=discovery_redfish_power_consumption,
check_function=check_redfish_power_consumption,
)
Loading