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
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
#!/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 cmk.agent_based.v2 import InventoryPlugin, InventoryResult, TableRow
from cmk.plugins.redfish.lib import RedfishAPIData


def _extract_odata_ids(data, ids_set):
if isinstance(data, Mapping):
for key, value in data.items():
# if key '@odata.id' and value is a string, extract the OData ID value
if key == "@odata.id" and isinstance(value, str):
key_name = data.get("Name")
serial_number = data.get("SerialNumber", "nothing set")
part_number = data.get("PartNumber", "nothing set")
manufacturer = data.get("Manufacturer", "nothing set")
model = data.get("Model", "nothing set")
# if 'Oem' in data, skip this entry and go deeper
if "Oem" in value:
continue
if key_name:
# add name is not None add to set
ids_set.add(
(
value,
key_name,
serial_number,
part_number,
manufacturer,
model,
)
)
# else recursively call for nested mappings or sequences
else:
ids_set = _extract_odata_ids(value, ids_set)
elif isinstance(data, Sequence) and not isinstance(data, (str, bytes)):
for item in data:
# Rekursiv für jedes Element in der Liste/Tupel aufrufen
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 = set() # Set to remove duplicates
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 == "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={"name": name},
inventory_columns={
"id": item_id,
"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,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/usr/bin/env python3
"""check the power redundancy state 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,
Result,
Service,
State,
)
from cmk.plugins.redfish.lib import (
redfish_health_state,
RedfishAPIData,
)


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


def check_redfish_power_redundancy(section: RedfishAPIData) -> CheckResult:
redundancy = []
for key in section.keys():
if redundancy_element := section[key].get("Redundancy", None):
redundancy.extend(redundancy_element)

if not redundancy:
return

for element in redundancy:
dev_state, dev_msg = redfish_health_state(element.get("Status", {}))
yield Result(state=State(dev_state), summary=dev_msg)
details_msg = []
for i in ["Name", "Mode", "MinNumNeeded", "MaxNumSupported"]:
if value := element.get(i, None):
details_msg.append(f"{i}: {value}")
if (num_ps := len(element.get("RedundancySet", []))) > 0:
details_msg.append(f"Number of Power Supplies in Redundancy Set: {num_ps}")

if details_msg:
yield Result(state=State(0), notice="\n".join(details_msg))


check_plugin_redfish_power_redundancy = CheckPlugin(
name="redfish_power_redundancy",
service_name="Power redundancy",
sections=["redfish_power"],
discovery_function=discovery_redfish_power_redundancy,
check_function=check_redfish_power_redundancy,
)
Loading
Loading