From bafa688c460683467079f20afff6f72bf95fb9cb Mon Sep 17 00:00:00 2001 From: "Haeger, Sebastian" Date: Mon, 8 Jun 2026 14:43:25 +0200 Subject: [PATCH] add MKP to current checkmk master --- .../agent_based/pure_storage_fa_arrays.py | 43 ++++++ .../pure_storage_fa_certificates.py | 89 +++++++++++++ .../pure_storage_fa_connections.py | 93 +++++++++++++ .../agent_based/pure_storage_fa_dns.py | 72 +++++++++++ .../agent_based/pure_storage_fa_drives.py | 93 +++++++++++++ .../agent_based/pure_storage_fa_hardware.py | 68 ++++++++++ .../pure_storage_fa_host_groups.py | 82 ++++++++++++ .../pure_storage_fa_network_interfaces.py | 122 ++++++++++++++++++ .../pure_storage_fa_single_sign_on.py | 75 +++++++++++ .../checkman/pure_storage_fa_certificates | 22 ++++ .../checkman/pure_storage_fa_connections | 25 ++++ .../checkman/pure_storage_fa_dns | 19 +++ .../checkman/pure_storage_fa_drives | 23 ++++ .../checkman/pure_storage_fa_id | 15 +++ .../pure_storage_fa_network_interfaces | 25 ++++ .../checkman/pure_storage_fa_power_supply | 24 ++++ .../checkman/pure_storage_fa_serial_chassis | 15 +++ .../checkman/pure_storage_fa_single_sign_on | 19 +++ .../checkman/pure_storage_fa_version | 15 +++ .../checkman/pure_storage_host_groups | 20 +++ .../special_agent/agent_pure_storage_fa.py | 40 ++++++ 21 files changed, 999 insertions(+) create mode 100644 packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_certificates.py create mode 100644 packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_connections.py create mode 100644 packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_dns.py create mode 100644 packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_drives.py create mode 100644 packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_host_groups.py create mode 100644 packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_network_interfaces.py create mode 100644 packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_single_sign_on.py create mode 100644 packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_certificates create mode 100644 packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_connections create mode 100644 packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_dns create mode 100644 packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_drives create mode 100644 packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_id create mode 100644 packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_network_interfaces create mode 100644 packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_power_supply create mode 100644 packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_serial_chassis create mode 100644 packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_single_sign_on create mode 100644 packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_version create mode 100644 packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_host_groups diff --git a/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_arrays.py b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_arrays.py index 6b5b5ad5545..e545c6b9860 100644 --- a/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_arrays.py +++ b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_arrays.py @@ -38,6 +38,8 @@ class Array(BaseModel, frozen=True): shared: float system: float | None replication: float + version: str + id: str def parse_array(string_table: StringTable) -> Array | None: @@ -57,6 +59,8 @@ def parse_array(string_table: StringTable) -> Array | None: shared=array["space"]["shared"], system=array["space"]["system"], replication=array["space"]["replication"], + version=array["version"], + id=array["id"], ) @@ -125,3 +129,42 @@ def check_overall_capacity(item: str, params: Mapping[str, Any], section: Array) **MAGIC_FACTOR_DEFAULT_PARAMS, }, ) + + +def discovery_pure_storage_fa_version(section: Array) -> DiscoveryResult: + if section.version: + yield Service() + + +def check_pure_storage_fa_version(section: Array) -> CheckResult: + yield Result( + state=State.OK, + summary=f"Version: {section.version}", + ) + + +check_plugin_pure_storage_fa_version = CheckPlugin( + sections=["pure_storage_fa_arrays"], + name="pure_storage_fa_version", + discovery_function=discovery_pure_storage_fa_version, + check_function=check_pure_storage_fa_version, + service_name="FlashArray Version", +) + + +def discovery_pure_storage_fa_id(section: Array) -> DiscoveryResult: + if section.id: + yield Service() + + +def check_pure_storage_fa_id(section: Array) -> CheckResult: + yield Result(state=State.OK, summary=f"ID: {section.id}") + + +check_plugin_pure_storage_fa_id = CheckPlugin( + sections=["pure_storage_fa_arrays"], + name="pure_storage_fa_id", + discovery_function=discovery_pure_storage_fa_id, + check_function=check_pure_storage_fa_id, + service_name="FlashArray ID", +) diff --git a/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_certificates.py b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_certificates.py new file mode 100644 index 00000000000..e2541d224af --- /dev/null +++ b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_certificates.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 +# Copyright (C) 2023 Checkmk GmbH - License: GNU General Public License v2 +# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and +# conditions defined in the file COPYING, which is part of this source code package. + +import json +from datetime import datetime, timezone +from pydantic import BaseModel +from typing import Optional + + +from cmk.agent_based.v2 import ( + AgentSection, + CheckPlugin, + CheckResult, + DiscoveryResult, + Result, + Service, + State, + StringTable, +) + + +class Certificate(BaseModel, frozen=True): + name: Optional[str] = None + status: Optional[str] = None + state: Optional[str] = None + country: Optional[str] = None + certificate_type: Optional[str] = None + intermediate_certificate: Optional[str] = None + email: Optional[str] = None + subject_alternative_names: Optional[list] = None + common_name: Optional[str] = None + organization: Optional[str] = None + organizational_unit: Optional[str] = None + locality: Optional[str] = None + key_algorithm: Optional[str] = None + key_size: Optional[int] = None + issued_by: Optional[str] = None + issued_to: Optional[str] = None + valid_from: Optional[int] = None + valid_to: Optional[int] = None + + +def parse_certificates(string_table: StringTable) -> list[Certificate]: + json_data = json.loads(string_table[0][0]) + if "items" not in json_data: + return None + parsed = [] + for cert in json_data["items"]: + parsed.append(Certificate(**cert)) + + return parsed + + +agent_section_pure_storage_fa_certificates = AgentSection( + name="pure_storage_fa_certificates", + parse_function=parse_certificates, +) + + +def discover_certificates(section: list[Certificate]) -> DiscoveryResult: + for cert in section: + yield Service(item=cert.name) + + +def check_certificates(item, section: list[Certificate]) -> CheckResult: + for certificate in section: + if item == certificate.name: + now = datetime.now(timezone.utc) + valid_to = datetime.fromtimestamp( + certificate.valid_to / 1000, tz=timezone.utc + ) + + if valid_to < now: + yield Result(state=State.CRIT, summary="Certificate ran out") + else: + yield Result( + state=State.OK, + summary=f"{certificate.status} certificate valid until {valid_to.strftime('%d.%m.%Y')}", + ) + + +check_plugin_pure_storage_fa_certificates = CheckPlugin( + name="pure_storage_fa_certificates", + service_name="PureStorage Certificate Status %s", + discovery_function=discover_certificates, + check_function=check_certificates, +) diff --git a/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_connections.py b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_connections.py new file mode 100644 index 00000000000..60aec432254 --- /dev/null +++ b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_connections.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 +# Copyright (C) 2023 Checkmk GmbH - License: GNU General Public License v2 +# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and +# conditions defined in the file COPYING, which is part of this source code package. + +import json +from pydantic import BaseModel +from typing import Optional + +from cmk.agent_based.v2 import ( + AgentSection, + CheckPlugin, + CheckResult, + DiscoveryResult, + Result, + Service, + State, + StringTable, +) + + +class Connections(BaseModel, frozen=True): + id: Optional[str] = None + name: Optional[str] = None + management_address: Optional[str] = None + replication_addresses: Optional[list] = None + status: Optional[str] = None + type: Optional[str] = None + replication_transport: Optional[str] = None + version: Optional[str] = None + throttle: Optional[dict] = None + + +def parse_connections(string_table: StringTable) -> list[Connections]: + json_data = json.loads(string_table[0][0]) + if "items" not in json_data: + return None + parsed = [] + for connection in json_data["items"]: + parsed.append(Connections(**connection)) + + return parsed + + +agent_section_pure_storage_fa_connections = AgentSection( + name="pure_storage_fa_connections", + parse_function=parse_connections, +) + + +def discover_connections(section: list[Connections]) -> DiscoveryResult: + for connections in section: + params = { + "discovered_state": ["connected", connections.status], + "discovered_throttled": ["False", connections.throttle], + } + yield Service(item=connections.name, parameters=dict(params)) + + +def check_connections(item, params, section: list[Connections]) -> CheckResult: + if section == []: + yield Result(state=State.CRIT, summary="No Array Connection found") + return + + for connection in section: + if item == connection.name: + if connection.status in params["discovered_state"]: + if connection.throttle in params["discovered_throttled"]: + summary = f"Array {connection.name} is {connection.status}." + details = f"Throttled: {connection.throttle}\nVersion: {connection.version}\nManagement Address: {connection.management_address}\nReplication Addresses: {connection.replication_addresses}\nType: {connection.type}" + state = State.OK + else: + summary = f"Array {connection.name} is {connection.status}, but throttled." + details = f"Version: {connection.version}\nManagement Address: {connection.management_address}\nReplication Addresses: {connection.replication_addresses}\nType: {connection.type}" + state = State.WARN + else: + summary = ( + f"Array {connection.name} is {connection.status}, but throttled." + ) + details = f"Throttled: {connection.throttle}\nVersion: {connection.version}\nManagement Address: {connection.management_address}\nReplication Addresses: {connection.replication_addresses}\nType: {connection.type}" + state = State.CRIT + + yield Result(state=state, summary=summary, details=details) + + +check_plugin_pure_storage_fa_connections = CheckPlugin( + name="pure_storage_fa_connections", + service_name="Connection to %s", + discovery_function=discover_connections, + check_function=check_connections, + check_ruleset_name="array_connections_default_levels", + check_default_parameters={}, +) diff --git a/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_dns.py b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_dns.py new file mode 100644 index 00000000000..b7583ada7b1 --- /dev/null +++ b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_dns.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 +# Copyright (C) 2023 Checkmk GmbH - License: GNU General Public License v2 +# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and +# conditions defined in the file COPYING, which is part of this source code package. + +import json +from typing import List +from pydantic import BaseModel + +from cmk.agent_based.v2 import ( + AgentSection, + CheckPlugin, + CheckResult, + DiscoveryResult, + Result, + Service, + State, + StringTable, + check_levels, + Metric, +) + + +class DNSServer(BaseModel, frozen=True): + domain: str + dns_server: List[str] + + +def parse_dns(string_table: StringTable) -> DNSServer | None: + json_data = json.loads(string_table[0][0]) + if "items" not in json_data: + return None + return DNSServer( + domain=json_data["items"][0]["domain"], + dns_server=json_data["items"][0]["nameservers"], + ) + + +agent_section_pure_storage_fa_dns = AgentSection( + name="pure_storage_fa_dns", + parse_function=parse_dns, +) + + +def discover_dns(section: DNSServer) -> DiscoveryResult: + if section is not None: + yield Service() + + +def check_dns(section: DNSServer) -> CheckResult: + if len(section.dns_server) == 0: + yield Result( + state=State.CRIT, + summary=f"No DNS Server for Domain {section.domain} found!", + ) + yield Metric("pure_storage_fa_dns", len(section.dns_server)) + else: + yield from check_levels( + len(section.dns_server), + metric_name="pure_storage_fa_dns", + render_func=lambda v: ( + f"{v} DNS Server in Domain {section.domain} found: {', '.join(section.dns_server)}" + ), + ) + + +check_plugin_pure_storage_fa_dns = CheckPlugin( + name="pure_storage_fa_dns", + service_name="DNS Server", + discovery_function=discover_dns, + check_function=check_dns, +) diff --git a/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_drives.py b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_drives.py new file mode 100644 index 00000000000..23802a96255 --- /dev/null +++ b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_drives.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 +# Copyright (C) 2023 Checkmk GmbH - License: GNU General Public License v2 +# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and +# conditions defined in the file COPYING, which is part of this source code package. + +import json +from typing import Optional + +from pydantic import BaseModel + +from cmk.agent_based.v2 import ( + AgentSection, + CheckPlugin, + CheckResult, + DiscoveryResult, + Result, + Service, + State, + StringTable, + check_levels, + Metric, +) + + +class Drives(BaseModel, frozen=True): + type: Optional[str] = None + name: Optional[str] = None + protocol: Optional[str] = None + status: Optional[str] = None + capacity: Optional[int] = None + capacity_installed: Optional[int] = None + details: Optional[str] = None + + +def parse_drives(string_table: StringTable) -> Drives | None: + json_data = json.loads(string_table[0][0]) + if "items" not in json_data: + return None + parsed = [] + for drive in json_data["items"]: + parsed.append(Drives(**drive)) + + return parsed + + +agent_section_pure_storage_fa_drives = AgentSection( + name="pure_storage_fa_drives", + parse_function=parse_drives, +) + + +def discover_drives(section: list[Drives]) -> DiscoveryResult: + for drive in section: + yield Service( + item=drive.name, parameters=dict({"discovered_state": drive.status}) + ) + + +def check_drives(item, params, section: Drives) -> CheckResult: + if section == []: + yield Result(state=State.CRIT, summary="No Drives found!") + for drive in section: + if item == drive.name: + if ( + drive.status in params["discovered_state"] + or drive.status in params["state"] + ): + yield Result( + state=State.OK, + summary=f"{drive.type} {item} is {drive.status}", + ) + yield from check_levels( + drive.capacity / 1000000000, + metric_name="pure_storage_fa_drive_capacity", + render_func=lambda v: ( + f"Capacity: {v} GB,\nProtocol: {drive.protocol}" + ), + notice_only=True, + ) + else: + yield Metric("pure_storage_fa_drive_capacity", drive.capacity) + yield Result( + state=State.CRIT, summary=f"{drive.name} is {drive.status}" + ) + + +check_plugin_pure_storage_fa_drives = CheckPlugin( + name="pure_storage_fa_drives", + service_name="Drive %s", + discovery_function=discover_drives, + check_function=check_drives, + check_default_parameters={"state": "healthy"}, +) diff --git a/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_hardware.py b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_hardware.py index 1b1c5d63d81..d735389d387 100644 --- a/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_hardware.py +++ b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_hardware.py @@ -17,6 +17,7 @@ Service, State, StringTable, + Metric, ) @@ -25,6 +26,10 @@ class Device(BaseModel, frozen=True): status: str type: str details: str | None = None + model: str | None = None + voltage: int | None = None + model: str | None = None + serial: str | None = None class Hardware(BaseModel, frozen=True): @@ -33,6 +38,8 @@ class Hardware(BaseModel, frozen=True): fibre_channel_ports: Mapping[str, Device] infiniband_ports: Mapping[str, Device] fans: Mapping[str, Device] + power_supply: Mapping[str, Device] + chassis: Mapping[str, Device] MAP_DEVICE_STATUS = { @@ -60,6 +67,8 @@ def parse_hardware(string_table: StringTable) -> Hardware | None: fibre_channel_ports={d.name: d for d in devices if d.type == "fc_port"}, infiniband_ports={d.name: d for d in devices if d.type == "ib_port"}, fans={d.name: d for d in devices if d.type == "cooling"}, + power_supply={d.name: d for d in devices if d.type == "power_supply"}, + chassis={d.name: d for d in devices if d.type == "chassis"}, ) @@ -243,3 +252,62 @@ def check_fan(item: str, section: Hardware) -> CheckResult: discovery_function=discover_fan, check_function=check_fan, ) + + +def discover_power_supply(section: Hardware) -> DiscoveryResult: + for item in section.power_supply: + yield Service(item=item) + + +def check_power_supply(item: str, section: Hardware) -> CheckResult: + if (power_supply := section.power_supply.get(item)) is None: + return + state = State.UNKNOWN + summary = "Check failed" + if power_supply.status == "ok": + state = State.OK + summary = f"{power_supply.name} (Model {power_supply.model}) is running with {power_supply.voltage} Volt" + elif int(power_supply.voltage) < 50: + state = State.WARN + summary = ( + f"{power_supply.name} is running with only {power_supply.voltage} Volt" + ) + if int(power_supply.voltage) < 10: + state = State.CRIT + else: + state = State.CRIT + summary = f"{power_supply.name} (Model {power_supply.model}) has state {power_supply.status} with {power_supply.voltage} Volt (could not set state)" + yield Metric("pure_storage_fa_power_supply", int(power_supply.voltage)) + yield Result(state=state, summary=summary) + + +check_plugin_pure_storage_fa_power_supply = CheckPlugin( + name="pure_storage_fa_power_supply", + sections=["pure_storage_fa_hardware"], + service_name="Power Supply %s", + discovery_function=discover_power_supply, + check_function=check_power_supply, +) + + +def discover_serial_chassis(section: Hardware) -> DiscoveryResult: + if section.chassis: + yield Service() + + +def check_serial_chassis(section: Hardware) -> CheckResult: + if (chassis := section.chassis.get("CH0")) is None: + return + yield Result( + state=State.OK, + summary=f"{chassis.name}, Model: {chassis.model}, Serial: {chassis.serial}", + ) + + +check_plugin_pure_storage_fa_serial_chassis = CheckPlugin( + name="pure_storage_fa_serial_chassis", + sections=["pure_storage_fa_hardware"], + service_name="Chassis Serial Number", + discovery_function=discover_serial_chassis, + check_function=check_serial_chassis, +) diff --git a/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_host_groups.py b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_host_groups.py new file mode 100644 index 00000000000..532a46f5608 --- /dev/null +++ b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_host_groups.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 +# Copyright (C) 2023 Checkmk GmbH - License: GNU General Public License v2 +# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and +# conditions defined in the file COPYING, which is part of this source code package. + +import json +from collections import defaultdict +from typing import Optional +from pydantic import BaseModel + +from cmk.agent_based.v2 import ( + AgentSection, + CheckPlugin, + CheckResult, + DiscoveryResult, + Result, + Service, + State, + StringTable, +) + + +class Name(BaseModel, frozen=True): + name: Optional[str] = None + + +class HostGroups(BaseModel, frozen=True): + group: Optional[Name] = None + members: Optional[list[Name]] = None + + +def parse_host_groups(string_table: StringTable) -> HostGroups | None: + json_data = json.loads(string_table[0][0]) + if "items" not in json_data: + return None + grouped = defaultdict(list) + + for entry in json_data["items"]: + group_name = entry.get("group", {}).get("name") + member_name = entry.get("member", {}).get("name") + + if group_name and member_name: + grouped[group_name].append(member_name) + + parsed = [] + for group_name, members in grouped.items(): + parsed.append( + HostGroups( + group=Name(name=group_name), members=[Name(name=m) for m in members] + ) + ) + + return parsed + + +agent_section_pure_storage_fa_host_groups = AgentSection( + name="pure_storage_fa_host_groups", + parse_function=parse_host_groups, +) + + +def discover_host_groups(section: list[HostGroups]) -> DiscoveryResult: + for hgroup in section: + yield Service(item=hgroup.group.name) + + +def check_host_groups(item: str, section: HostGroups) -> CheckResult: + for hgroup in section: + if item == hgroup.group.name: + if hgroup.members: + names = [m.name for m in hgroup.members if m.name] + yield Result(state=State.OK, summary=f"Members: {', '.join(names)}") + else: + yield Result(state=State.OK, summary="No Members found") + + +check_plugin_pure_storage_fa_host_groups = CheckPlugin( + name="pure_storage_fa_host_groups", + service_name="Host Group %s", + discovery_function=discover_host_groups, + check_function=check_host_groups, +) diff --git a/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_network_interfaces.py b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_network_interfaces.py new file mode 100644 index 00000000000..0d54131e3ac --- /dev/null +++ b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_network_interfaces.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python3 +# Copyright (C) 2023 Checkmk GmbH - License: GNU General Public License v2 +# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and +# conditions defined in the file COPYING, which is part of this source code package. + +import json +from typing import Optional +from pydantic import BaseModel + +from cmk.agent_based.v2 import ( + AgentSection, + CheckPlugin, + CheckResult, + DiscoveryResult, + Result, + Service, + State, + StringTable, + Metric, +) + + +class Name(BaseModel, frozen=True): + name: Optional[str] = None + + +class Eth(BaseModel, frozen=True): + address: Optional[str] = None + mac_address: Optional[str] = None + gateway: Optional[str] = None + vlan: Optional[int] = None + mtu: Optional[int] = None + netmask: Optional[str] = None + subinterfaces: Optional[list] = None + subtype: Optional[str] = None + subnet: Optional[Name] = None + + +class Interface(BaseModel, frozen=True): + name: Optional[str] = None + services: Optional[list] = None + enabled: Optional[bool] = None + interface_type: Optional[str] = None + speed: Optional[int] = None + attached_servers: Optional[list] = None + eth: Optional[Eth] = None + services: Optional[list] = None + + +def parse_network_interfaces(string_table: StringTable) -> list[Interface] | None: + json_data = json.loads(string_table[0][0]) + if "items" not in json_data: + return None + parsed = [] + for interface in json_data["items"]: + parsed.append(Interface(**interface)) + + return parsed + + +agent_section_pure_storage_fa_network_interfaces = AgentSection( + name="pure_storage_fa_network_interfaces", + parse_function=parse_network_interfaces, +) + + +def discover_network_interfaces(section: list[Interface]) -> DiscoveryResult: + for interface in section: + params = { + "discovered_state": [interface.enabled, "True"], + "discovered_speed": interface.speed, + } + yield Service(item=interface.name, parameters=dict(params)) + + +def check_network_interfaces(item, params, section: list[Interface]) -> CheckResult: + if section == []: + yield Result(state=State.CRIT, summary="No Network Interfaces found") + + for interface in section: + if item == interface.name: + details = "" + if ( + interface.enabled in params["discovered_state"] + and interface.speed >= params["discovered_speed"] + ): + if interface.enabled: + state = State.OK + summary = f"Interface {interface.name} running with IP {interface.eth.address}, MAC {interface.eth.mac_address} and {int(interface.speed) / 1000000000} Gbps." + details = f"Gateway: {interface.eth.gateway}\nNetmask: {interface.eth.netmask}\nMTU: {interface.eth.mtu}\nSubnet: {interface.eth.subnet.name}" + else: + state = State.OK + summary = f"Interface {interface.name} is currently not running" + details = f"MAC: {interface.eth.mac_address}\nMTU: {interface.eth.mtu}\nSpeed: {int(interface.speed) / 1000000000} Gbps." + elif ( + interface.enabled in params["discovered_state"] + and interface.speed < params["discovered_speed"] + ): + if interface.enabled: + state = State.WARN + summary = f"Interface {interface.name} running with only {int(interface.speed) / 1000000000} Gbps." + details = f"Normal Speed: {params['discovered_speed']}\nIP: {interface.eth.address}\nMAC: {interface.eth.mac_address}\nGateway: {interface.eth.gateway}\nNetmask: {interface.eth.netmask}\nMTU: {interface.eth.mtu}\nSubnet: {interface.eth.subnet.name}" + else: + state = State.WARN + summary = f"Interface {interface.name} is currently not running, but check speed please" + details = f"Speed: {int(interface.speed) / 1000000000}\nNormal Speed: {params['discovered_speed']}\nIP: {interface.eth.address}\nMAC: {interface.eth.mac_address}\nGateway: {interface.eth.gateway}\nNetmask: {interface.eth.netmask}\nMTU: {interface.eth.mtu}\nSubnet: {interface.eth.subnet.name}" + else: + state = State.CRIT + summary = f"Interface {interface.name} is down" + details = f"Speed: {int(interface.speed) / 1000000000}\nNormal Speed: {params['discovered_speed']}\nIP: {interface.eth.address}\nMAC: {interface.eth.mac_address}Gateway: {interface.eth.gateway}\nNetmask: {interface.eth.netmask}\nMTU: {interface.eth.mtu}\nSubnet: {interface.eth.subnet.name}" + + yield Metric("pure_storage_fa_network_interfaces_speed", int(interface.speed) / 1000000000) + yield Result(state=state, summary=summary, details=details) + + +check_plugin_pure_storage_fa_network_interfaces = CheckPlugin( + name="pure_storage_fa_network_interfaces", + service_name="Interface %s", + discovery_function=discover_network_interfaces, + check_function=check_network_interfaces, + check_default_parameters={}, +) diff --git a/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_single_sign_on.py b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_single_sign_on.py new file mode 100644 index 00000000000..5c8266a725d --- /dev/null +++ b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/agent_based/pure_storage_fa_single_sign_on.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +# Copyright (C) 2023 Checkmk GmbH - License: GNU General Public License v2 +# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and +# conditions defined in the file COPYING, which is part of this source code package. + +import json +from pydantic import BaseModel + +from cmk.agent_based.v2 import ( + AgentSection, + CheckPlugin, + CheckResult, + DiscoveryResult, + Result, + Service, + State, + StringTable, +) + + +class SingleSignOn(BaseModel, frozen=True): + single_sign_on_enabled: bool + + +def parse_admins_settings(string_table: StringTable) -> SingleSignOn | None: + json_data = json.loads(string_table[0][0]) + if "items" not in json_data: + return None + return SingleSignOn( + single_sign_on_enabled=json_data["items"][0]["single_sign_on_enabled"], + ) + + +agent_section_pure_storage_fa_admins_settings = AgentSection( + name="pure_storage_fa_admins_settings", + parse_function=parse_admins_settings, +) + + +def discover_single_sign_on(section: SingleSignOn) -> DiscoveryResult: + yield Service(parameters={"discovered_state": section.single_sign_on_enabled}) + + +def check_single_sign_on(params, section: SingleSignOn) -> CheckResult: + data = section.single_sign_on_enabled + state = State.CRIT + summary = "Could not find enough data" + if params["discovered_state"] is data: + if data: + state = State.OK + summary = "SSO Enabled" + else: + state = State.OK + summary = "SSO disabled! (Discovered State)" + else: + if data: + state = State.OK + summary = "SSO Status changed to 'Enabled'!" + else: + state = State.WARN + summary = "SSO Status changed to 'Disabled'!" + + yield Result(state=state, summary=summary) + + +check_plugin_pure_storage_fa_single_sign_on = CheckPlugin( + name="pure_storage_fa_single_sign_on", + sections=["pure_storage_fa_admins_settings"], + service_name="Single-Sign-On", + discovery_function=discover_single_sign_on, + check_function=check_single_sign_on, + check_default_parameters={ + "discovered_state": True, + }, +) diff --git a/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_certificates b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_certificates new file mode 100644 index 00000000000..c93717e12b6 --- /dev/null +++ b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_certificates @@ -0,0 +1,22 @@ +title: Pure Storage FlashArray: Certificate Status +agents: pure_storage_fa +catalog: hw/storagehw/pure_storage +license: GPLv2 +distribution: check_mk +description: + This check monitors the status of a Pure Storage Ethernet Port. + + The status is mapped to the following Checkmk state: + + - {OK} if certificate is valid + + - {CRIT} if certificate isn't valid + + To make this check work you have to configure the related special agent + {Pure Storage FlashArray}. + +item: + Name of the certificate. + +discovery: + One service per certificate is created. diff --git a/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_connections b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_connections new file mode 100644 index 00000000000..a5cae7e7079 --- /dev/null +++ b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_connections @@ -0,0 +1,25 @@ +title: Pure Storage FlashArray: Connection to +agents: pure_storage_fa +catalog: hw/storagehw/pure_storage +license: GPLv2 +distribution: check_mk +description: + This check monitors the connections of a Pure Storage. + Monitoring state, throttled-state, version, management address, replication addresses and type. + + The status is mapped to the following Checkmk state: + + - {OK} if state is connected and not throttled unless the service was discovered another state + + - {WARN} if state is connected but throttled and was not discovered throttled + + - {CRIT} if state is disconnected and as not discovered disconnected + + To make this check work you have to configure the related special agent + {Pure Storage FlashArray}. + +item: + Name of the connection. + +discovery: + One service per connection is created. diff --git a/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_dns b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_dns new file mode 100644 index 00000000000..e8a4c5a78f7 --- /dev/null +++ b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_dns @@ -0,0 +1,19 @@ +title: Pure Storage FlashArray: DNS Server +agents: pure_storage_fa +catalog: hw/storagehw/pure_storage +license: GPLv2 +distribution: check_mk +description: + This check monitors the connected DNS Server of a Pure Storage. + + The status is mapped to the following Checkmk state: + + - {OK} if DNS Server is found + + - {CRIT} if no DNS Server is found + + To make this check work you have to configure the related special agent + {Pure Storage FlashArray}. + +discovery: + One service per host is created. diff --git a/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_drives b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_drives new file mode 100644 index 00000000000..078842908d0 --- /dev/null +++ b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_drives @@ -0,0 +1,23 @@ +title: Pure Storage FlashArray: Drive +agents: pure_storage_fa +catalog: hw/storagehw/pure_storage +license: GPLv2 +distribution: check_mk +description: + This check monitors the drive of a Pure Storage. + Monitoring type, name, state, capacity and protocol + + The status is mapped to the following Checkmk state: + + - {OK} if "state" is "healthy" or as discovered + + - {CRIT} if "state" is not "healthy" and not as discovered + + To make this check work you have to configure the related special agent + {Pure Storage FlashArray}. + +item: + Name of the drive. + +discovery: + One service per drive is created. diff --git a/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_id b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_id new file mode 100644 index 00000000000..d57bd19c07e --- /dev/null +++ b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_id @@ -0,0 +1,15 @@ +title: Pure Storage FlashArray: FlashArray ID +agents: pure_storage_fa +catalog: hw/storagehw/pure_storage +license: GPLv2 +distribution: check_mk +description: + This check monitors the flasharray id of a Pure Storage. + + The status is always {ok} + + To make this check work you have to configure the related special agent + {Pure Storage FlashArray}. + +discovery: + One service per host is created. diff --git a/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_network_interfaces b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_network_interfaces new file mode 100644 index 00000000000..d1f9186b83f --- /dev/null +++ b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_network_interfaces @@ -0,0 +1,25 @@ +title: Pure Storage FlashArray: Network Interfaces +agents: pure_storage_fa +catalog: hw/storagehw/pure_storage +license: GPLv2 +distribution: check_mk +description: + This check monitors the network interfaces of a Pure Storage. + Monitoring name, speed, ip, MAC, Gateway, Netmask, MTU and Subnet + + The status is mapped to the following Checkmk state: + + - {OK} if "enabled" as discovered and no bad speed changes + + - {WARN} if "enabled" as discovered and bad speed changes + + - {CRIT} if "disabled" + + To make this check work you have to configure the related special agent + {Pure Storage FlashArray}. + +item: + Name of the interface. + +discovery: + One service per interface is created. diff --git a/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_power_supply b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_power_supply new file mode 100644 index 00000000000..97fdb9b4ca6 --- /dev/null +++ b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_power_supply @@ -0,0 +1,24 @@ +title: Pure Storage FlashArray: Power Supply +agents: pure_storage_fa +catalog: hw/storagehw/pure_storage +license: GPLv2 +distribution: check_mk +description: + This check monitors the power supply of a Pure Storage. + + The status is mapped to the following Checkmk state: + + - {OK} status is "ok" + + - {WARN} if power supply lower 50 + + - {CRIT} if power supply lower 10 or status != "ok" + + To make this check work you have to configure the related special agent + {Pure Storage FlashArray}. + +item: + Name of the pwoer supply. + +discovery: + One service per pwoer supply is created. diff --git a/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_serial_chassis b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_serial_chassis new file mode 100644 index 00000000000..2d2dc45c703 --- /dev/null +++ b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_serial_chassis @@ -0,0 +1,15 @@ +title: Pure Storage FlashArray: Chassis Serial Number +agents: pure_storage_fa +catalog: hw/storagehw/pure_storage +license: GPLv2 +distribution: check_mk +description: + This check monitors the chassis serial number of a Pure Storage. + + The status is always {ok} + + To make this check work you have to configure the related special agent + {Pure Storage FlashArray}. + +discovery: + One service per host is created. diff --git a/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_single_sign_on b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_single_sign_on new file mode 100644 index 00000000000..b5881906d76 --- /dev/null +++ b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_single_sign_on @@ -0,0 +1,19 @@ +title: Pure Storage FlashArray: Single Sign On +agents: pure_storage_fa +catalog: hw/storagehw/pure_storage +license: GPLv2 +distribution: check_mk +description: + This check monitors the sso of a Pure Storage. + + The status is mapped to the following Checkmk state: + + - {OK} SSO Status enabled, or as discovered + + - {Warn} SSO Status changed to 'Disabled'!, not as discovert + + To make this check work you have to configure the related special agent + {Pure Storage FlashArray}. + +discovery: + One service per host is created. diff --git a/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_version b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_version new file mode 100644 index 00000000000..41c9e2611bf --- /dev/null +++ b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_fa_version @@ -0,0 +1,15 @@ +title: Pure Storage FlashArray: FlashArray Version +agents: pure_storage_fa +catalog: hw/storagehw/pure_storage +license: GPLv2 +distribution: check_mk +description: + This check monitors the flasharray version of a Pure Storage. + + The status is always {ok} + + To make this check work you have to configure the related special agent + {Pure Storage FlashArray}. + +discovery: + One service per host is created. diff --git a/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_host_groups b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_host_groups new file mode 100644 index 00000000000..db014dc1fb7 --- /dev/null +++ b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/checkman/pure_storage_host_groups @@ -0,0 +1,20 @@ +title: Pure Storage FlashArray: Host Group +agents: pure_storage_fa +catalog: hw/storagehw/pure_storage +license: GPLv2 +distribution: check_mk +description: + This check monitors the host groups of a Pure Storage. + + The status is mapped to the following Checkmk state: + + - {OK} always + + To make this check work you have to configure the related special agent + {Pure Storage FlashArray}. + +item: + Name of the host group. + +discovery: + One service per host group is created. diff --git a/packages/cmk-plugins/cmk/plugins/pure_storage_fa/special_agent/agent_pure_storage_fa.py b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/special_agent/agent_pure_storage_fa.py index 063ea855384..bacdbf712ae 100644 --- a/packages/cmk-plugins/cmk/plugins/pure_storage_fa/special_agent/agent_pure_storage_fa.py +++ b/packages/cmk-plugins/cmk/plugins/pure_storage_fa/special_agent/agent_pure_storage_fa.py @@ -88,6 +88,46 @@ class _SectionSpec: min_version=_RestVersion(2, 2), params={"filter": "state='open'"}, ), + _SectionSpec( + name="network_interfaces", + path="network-interfaces", + min_version=_RestVersion(2, 4), + ), + _SectionSpec( + name="drives", + path="drives", + min_version=_RestVersion(2, 4), + ), + _SectionSpec( + name="host_groups", + path="host-groups/hosts", + min_version=_RestVersion(2, 0), + ), + _SectionSpec( + name="admins", + path="admins", + min_version=_RestVersion(2, 2), + ), + _SectionSpec( + name="connections", + path="array-connections", + min_version=_RestVersion(2, 4), + ), + _SectionSpec( + name="certificates", + path="certificates", + min_version=_RestVersion(2, 4), + ), + _SectionSpec( + name="admins_settings", + path="admins/settings", + min_version=_RestVersion(2, 2), + ), + _SectionSpec( + name="dns", + path="dns", + min_version=_RestVersion(2, 2), + ) ]