Compare commits
21 Commits
Author | SHA1 | Date | |
---|---|---|---|
d4b0c9497d | |||
270d9ac22c | |||
36a998cfc6 | |||
5fa472f450 | |||
52f417215b | |||
62518edf2c | |||
5ba99c1c15 | |||
8f9970a40c | |||
775f9515a1 | |||
15f69ddc0c | |||
3d9e54f470 | |||
6de602a399 | |||
44aa214b85 | |||
bb424f90fe | |||
|
0aa461839b | ||
|
d7ba6d93f4 | ||
|
c26de603bb | ||
|
b3a43a96b1 | ||
|
0f60e5725e | ||
a1b017d260 | |||
|
2b522d2553 |
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +1,6 @@
|
||||
[submodule "juniper"]
|
||||
path = juniper
|
||||
url = https://github.com/spearheadsys/check_mk.git
|
||||
[submodule "check_mk-check-selinux"]
|
||||
path = check_mk-check-selinux
|
||||
url = https://code.spearhead.cloud/Spearhead/check_mk-check-selinux.git
|
||||
|
BIN
check_mk-amd-gpu/amd-gpu-0.1.1.mkp
Executable file
BIN
check_mk-amd-gpu/amd-gpu-0.1.1.mkp
Executable file
Binary file not shown.
@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright 2024 Spearhead Systems SRL
|
||||
|
||||
from cmk.base.plugins.agent_based.agent_based_api.v1 import (
|
||||
register,
|
||||
Service,
|
||||
Result,
|
||||
Metric,
|
||||
State,
|
||||
)
|
||||
|
||||
|
||||
def discovery_amd_gpu(section):
|
||||
name = section[0][0]
|
||||
yield Service(item=name)
|
||||
|
||||
|
||||
def check_state(alert_percentages, measured_percent):
|
||||
if alert_percentages:
|
||||
if alert_percentages[1] <= measured_percent:
|
||||
return State.CRIT
|
||||
elif alert_percentages[0] <= measured_percent:
|
||||
return State.WARN
|
||||
return State.OK
|
||||
|
||||
|
||||
def get_levels(alert_levels, total=None):
|
||||
if alert_levels == None:
|
||||
return
|
||||
|
||||
if total == None:
|
||||
return alert_levels
|
||||
|
||||
return (alert_levels[0] / 100 * total, alert_levels[1] / 100 * total)
|
||||
|
||||
|
||||
def check_amd_gpu(item, params, section):
|
||||
if item != section[0][0]:
|
||||
return
|
||||
|
||||
gpu_percent = int(float(section[1][0]))
|
||||
vram_bytes_used = int(section[2][0])
|
||||
vram_bytes_total = int(section[3][0])
|
||||
vram_bytes_free = max(0, vram_bytes_total - vram_bytes_used)
|
||||
|
||||
vram_mb_used = vram_bytes_used // 1048576
|
||||
vram_mb_total = vram_bytes_total // 1048576
|
||||
vram_mb_free = vram_bytes_free // 1048576
|
||||
|
||||
alert_gpu_percent = params.get("gpu_percent")
|
||||
alert_vram_used_percent = params.get("vram_used_percent")
|
||||
alert_vram_free_percent = params.get("vram_free_percent")
|
||||
|
||||
vram_used_percent = vram_bytes_used / vram_bytes_total * 100
|
||||
vram_free_percent = 100 - vram_used_percent
|
||||
|
||||
yield Result(
|
||||
state=check_state(alert_gpu_percent, gpu_percent),
|
||||
summary=f"GPU: {gpu_percent}%"
|
||||
)
|
||||
|
||||
yield Result(
|
||||
state=check_state(alert_vram_free_percent, vram_free_percent),
|
||||
summary=f"VRAM free: {vram_mb_free} MiB"
|
||||
)
|
||||
|
||||
yield Result(
|
||||
state=check_state(alert_vram_used_percent, vram_used_percent),
|
||||
summary=f"VRAM used: {vram_mb_used} MiB"
|
||||
)
|
||||
|
||||
yield Result(
|
||||
state=State.OK,
|
||||
summary=f"VRAM total: {vram_mb_total} MiB"
|
||||
)
|
||||
|
||||
yield Metric(
|
||||
name="gpu_percent",
|
||||
value=gpu_percent,
|
||||
levels=get_levels(alert_gpu_percent),
|
||||
boundaries=(0, 100)
|
||||
)
|
||||
|
||||
yield Metric(
|
||||
name="vram_used",
|
||||
value=vram_mb_used,
|
||||
levels=get_levels(alert_vram_used_percent, vram_mb_total),
|
||||
boundaries=(0, vram_mb_total)
|
||||
)
|
||||
|
||||
yield Metric(
|
||||
name="vram_free",
|
||||
value=vram_mb_free,
|
||||
levels=get_levels(alert_vram_free_percent, vram_mb_total),
|
||||
boundaries=(0, vram_mb_total)
|
||||
)
|
||||
|
||||
register.check_plugin(
|
||||
name='amd_gpu',
|
||||
service_name='AMD GPU - %s',
|
||||
discovery_function=discovery_amd_gpu,
|
||||
check_function=check_amd_gpu,
|
||||
check_default_parameters={},
|
||||
check_ruleset_name='amd_gpu',
|
||||
)
|
@ -0,0 +1,86 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright 2024 Spearhead Systems SRL
|
||||
|
||||
from cmk.gui.i18n import _
|
||||
from cmk.gui.plugins.wato.utils import (
|
||||
CheckParameterRulespecWithItem,
|
||||
rulespec_registry,
|
||||
RulespecGroupCheckParametersHardware,
|
||||
)
|
||||
from cmk.gui.valuespec import Dictionary, Percentage, TextInput, Tuple
|
||||
|
||||
|
||||
def _parameter_valuespec_amd_gpu():
|
||||
return Dictionary(
|
||||
title=_("GPU utilization"),
|
||||
help=_(
|
||||
"These metrics are queried directly from the AMD GPU. "
|
||||
"Upper and lower levels can be specified for individual metrics."
|
||||
),
|
||||
elements=[
|
||||
(
|
||||
"gpu_percent",
|
||||
Tuple(
|
||||
title=_("GPU Used"),
|
||||
help=_("If usage of total GPU compute goes above these percentages, issue alerts."),
|
||||
elements=[
|
||||
Percentage(
|
||||
title=_("Warn if above"),
|
||||
default_value=90
|
||||
),
|
||||
Percentage(
|
||||
title=_("Crit if above"),
|
||||
default_value=100
|
||||
)
|
||||
]
|
||||
)
|
||||
),
|
||||
(
|
||||
"vram_free_percent",
|
||||
Tuple(
|
||||
title=_("VRAM Free"),
|
||||
help=_("If free VRAM goes above these percentages, issue alerts."),
|
||||
elements=[
|
||||
Percentage(
|
||||
title="Warn if above",
|
||||
default_value=70
|
||||
),
|
||||
Percentage(
|
||||
title="Crit if above",
|
||||
default_value=90
|
||||
)
|
||||
]
|
||||
)
|
||||
),
|
||||
(
|
||||
"vram_used_percent",
|
||||
Tuple(
|
||||
title=_("VRAM Used"),
|
||||
help=_("If used VRAM goes above these percentages, issue alerts."),
|
||||
elements=[
|
||||
Percentage(
|
||||
title="Warn if above",
|
||||
default_value=70
|
||||
),
|
||||
Percentage(
|
||||
title="Crit if above",
|
||||
default_value=90
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
rulespec_registry.register(
|
||||
CheckParameterRulespecWithItem(
|
||||
check_group_name="amd_gpu",
|
||||
group=RulespecGroupCheckParametersHardware,
|
||||
match_type="dict",
|
||||
parameter_valuespec=_parameter_valuespec_amd_gpu,
|
||||
item_spec=lambda: TextInput(title=_("GPU")),
|
||||
title=lambda: _("AMD GPU Metrics"),
|
||||
)
|
||||
)
|
@ -0,0 +1,20 @@
|
||||
# Copyright 2024 Spearhead Systems SRL
|
||||
#
|
||||
# This goes in C:\ProgramData\checkmk\agent\plugins. It should be added automatically by
|
||||
# baking a new MSI after setting "Agent Rules" > "Deploy Custom Files With Agent" with
|
||||
# "Deploy Custom Files With Agent" including "amd_gpu".
|
||||
|
||||
foreach ($Item in Get-ChildItem "HKLM:\SYSTEM\CurrentControlSet\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}" -Name -Include 000*) {
|
||||
$Name = Get-ItemPropertyValue "HKLM:\SYSTEM\CurrentControlSet\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\$Item" "DriverDesc"
|
||||
if ($Name -match 'Radeon') {
|
||||
$GpuBytesTotal = Get-ItemPropertyValue "HKLM:\SYSTEM\CurrentControlSet\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\$Item" "HardwareInformation.qwMemorySize"
|
||||
$GpuRawName = Get-ItemPropertyValue "HKLM:\SYSTEM\CurrentControlSet\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\$Item" "HardwareInformation.AdapterString"
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
$GpuName = [System.Text.Encoding]::Unicode.GetString($GpuRawName)
|
||||
$GpuPercent = (((Get-Counter "\GPU Engine(*)\Utilization Percentage" ).CounterSamples).CookedValue | measure -sum).sum
|
||||
$GpuBytesUsed = (((Get-Counter "\GPU Process Memory(*)\Dedicated Usage").CounterSamples).CookedValue | measure -sum).sum
|
||||
|
||||
Write-Output "<<<amd_gpu:sep(0)>>>", $GpuName, $GpuPercent, $GpuBytesUsed, $GpuBytesTotal
|
BIN
check_mk-avocent/avocent_acs_800-1.0.1.mkp
Normal file
BIN
check_mk-avocent/avocent_acs_800-1.0.1.mkp
Normal file
Binary file not shown.
BIN
check_mk-avocent/cmk20-cmk21/Avocent-1.1.mkp
Normal file
BIN
check_mk-avocent/cmk20-cmk21/Avocent-1.1.mkp
Normal file
Binary file not shown.
@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2019 tribe29 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.
|
||||
from typing import List
|
||||
from cmk.base.plugins.agent_based.agent_based_api.v1 import (
|
||||
register,
|
||||
Result,
|
||||
Service,
|
||||
SNMPTree,
|
||||
startswith,
|
||||
State,
|
||||
)
|
||||
from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
|
||||
CheckResult,
|
||||
DiscoveryResult,
|
||||
StringTable,
|
||||
)
|
||||
|
||||
Section = []
|
||||
def parse_avocent_psu(string_table: List[StringTable]) -> Section:
|
||||
return string_table[0][0]
|
||||
|
||||
|
||||
register.snmp_section(
|
||||
name="avocent_psu",
|
||||
detect=startswith(".1.3.6.1.2.1.1.1.0", "Avocent"),
|
||||
parse_function=parse_avocent_psu,
|
||||
fetch=[
|
||||
SNMPTree(
|
||||
base=".1.3.6.1.4.1.10418.26.2.1.8",
|
||||
oids=[
|
||||
"1", #Number of PSU installed
|
||||
"2", #PowerSupply1 state
|
||||
"3", #PowerSupply2 state
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
def discovery_avocent_psu(section: Section) -> DiscoveryResult:
|
||||
yield Service()
|
||||
|
||||
|
||||
def _power_supply_status_descr(status_nr: str) -> str:
|
||||
return {
|
||||
"1": "Powered On",
|
||||
"2": "Powered Off",
|
||||
"9999": "Power Supply is not installed",
|
||||
}.get(status_nr, status_nr)
|
||||
|
||||
def _power_supply_state(status_nr: str) -> State:
|
||||
return {
|
||||
"1": State.OK,
|
||||
"2": State.CRIT,
|
||||
"9999": State.OK
|
||||
}.get(status_nr, State.UNKNOWN)
|
||||
|
||||
|
||||
|
||||
def check_avocent_psu(
|
||||
section: Section,
|
||||
) -> CheckResult:
|
||||
number_of_psu=section[0]
|
||||
state_psu_1=section[1]
|
||||
state_psu_2=section[2]
|
||||
|
||||
yield Result(
|
||||
state=State.OK,
|
||||
summary="Number of PSU installed: %s" % number_of_psu,
|
||||
)
|
||||
|
||||
yield Result(
|
||||
state=_power_supply_state(state_psu_1),
|
||||
summary="Power Supply 1 is %s" % _power_supply_status_descr(state_psu_1),
|
||||
)
|
||||
|
||||
yield Result(
|
||||
state=_power_supply_state(state_psu_2),
|
||||
summary="Power Supply 2 is %s" % _power_supply_status_descr(state_psu_2),
|
||||
)
|
||||
|
||||
|
||||
register.check_plugin(
|
||||
name="avocent_psu",
|
||||
sections=["avocent_psu"],
|
||||
service_name="Power Supplies",
|
||||
discovery_function=discovery_avocent_psu,
|
||||
check_function=check_avocent_psu
|
||||
)
|
||||
|
@ -0,0 +1,134 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2019 tribe29 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 dataclasses
|
||||
from typing import Mapping
|
||||
|
||||
from .agent_based_api.v1 import (
|
||||
contains,
|
||||
get_value_store,
|
||||
Metric,
|
||||
register,
|
||||
Result,
|
||||
Service,
|
||||
SNMPTree,
|
||||
State,
|
||||
startswith
|
||||
)
|
||||
from .agent_based_api.v1.type_defs import CheckResult, DiscoveryResult, StringTable
|
||||
from .utils.temperature import check_temperature, TempParamType
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class Sensor:
|
||||
value: float
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class VoltageSensor(Sensor):
|
||||
...
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class Section:
|
||||
temperature_sensors: Mapping[str, Sensor]
|
||||
voltage_sensors: Mapping[str, Sensor]
|
||||
|
||||
temperature_sensors_name = ['CPU','Board']
|
||||
voltage_sensors_name = ['PSU 1','PSU 2']
|
||||
|
||||
def parse_avocent_sensors(string_table: StringTable) -> Section:
|
||||
temperature_sensors = {}
|
||||
voltage_sensors = {}
|
||||
position = 0
|
||||
for temp_sens_name in temperature_sensors_name:
|
||||
temperature_sensors[temp_sens_name] = Sensor(value=int(string_table[0][position]))
|
||||
position +=1
|
||||
|
||||
pos = 2
|
||||
for volt_sens_name in voltage_sensors_name:
|
||||
voltage_sensors[volt_sens_name] = Sensor(value=float(string_table[0][pos])/100)
|
||||
pos += 1
|
||||
|
||||
return Section(
|
||||
temperature_sensors=temperature_sensors,
|
||||
voltage_sensors=voltage_sensors,
|
||||
)
|
||||
|
||||
register.snmp_section(
|
||||
name="avocent_sensors",
|
||||
detect=startswith(".1.3.6.1.2.1.1.1.0", "Avocent"),
|
||||
parse_function=parse_avocent_sensors,
|
||||
fetch=SNMPTree(
|
||||
base=".1.3.6.1.4.1.10418.26.2.7",
|
||||
oids=[
|
||||
"1", #acsSensorsInternalCurrentCPUTemperature
|
||||
"6", #acsSensorsInternalCurrentBoardTemperature
|
||||
"17", #acsSensorsVoltagePowerSupply1
|
||||
"18", #acsSensorsVoltagePowerSupply2
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
|
||||
def discover_avocent_voltage_sensors(section: Section) -> DiscoveryResult:
|
||||
yield from (Service(item=sensor_name) for sensor_name in section.voltage_sensors)
|
||||
|
||||
|
||||
def check_avocent_voltage_sensors(
|
||||
item: str,
|
||||
section: Section,
|
||||
) -> CheckResult:
|
||||
if not (sensor := section.voltage_sensors.get(item)):
|
||||
return
|
||||
|
||||
yield Result(
|
||||
state=State.OK,
|
||||
summary=f"{sensor.value:.1f} V",
|
||||
)
|
||||
|
||||
yield Metric(
|
||||
name="voltage",
|
||||
value=sensor.value,
|
||||
)
|
||||
|
||||
|
||||
register.check_plugin(
|
||||
name="avocent_voltage_sensors",
|
||||
sections=["avocent_sensors"],
|
||||
service_name="Voltage %s",
|
||||
discovery_function=discover_avocent_voltage_sensors,
|
||||
check_function=check_avocent_voltage_sensors,
|
||||
)
|
||||
|
||||
|
||||
def discover_avocent_sensors_temp(section: Section) -> DiscoveryResult:
|
||||
yield from (Service(item=sensor_name) for sensor_name in section.temperature_sensors)
|
||||
|
||||
|
||||
def check_avocent_sensors_temp(
|
||||
item: str,
|
||||
params: TempParamType,
|
||||
section: Section,
|
||||
) -> CheckResult:
|
||||
if not (sensor := section.temperature_sensors.get(item)):
|
||||
return
|
||||
yield from check_temperature(
|
||||
reading=sensor.value,
|
||||
params=params,
|
||||
unique_name=item,
|
||||
value_store=get_value_store(),
|
||||
)
|
||||
|
||||
register.check_plugin(
|
||||
name="avocent_sensors_temp",
|
||||
sections=["avocent_sensors"],
|
||||
service_name="Temperature %s",
|
||||
discovery_function=discover_avocent_sensors_temp,
|
||||
check_function=check_avocent_sensors_temp,
|
||||
check_ruleset_name="temperature",
|
||||
check_default_parameters={"device_levels_handling": "devdefault"},
|
||||
)
|
@ -0,0 +1,152 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2019 tribe29 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.
|
||||
|
||||
from ..agent_based_api.v1 import (
|
||||
all_of,
|
||||
any_of,
|
||||
contains,
|
||||
equals,
|
||||
exists,
|
||||
not_contains,
|
||||
not_equals,
|
||||
not_exists,
|
||||
not_startswith,
|
||||
startswith,
|
||||
)
|
||||
|
||||
# We are not sure how to safely detect the UCD SNMP Daemon. We know that
|
||||
# it is mainly used on Linux, but not only. But fetching and OID outside
|
||||
# of the info area for scanning is not a good idea. It will slow down
|
||||
# scans for *all* hosts.
|
||||
|
||||
# ---ucd cpu load---------------------------------------------------------
|
||||
|
||||
# We prefer HOST-RESOURCES-MIB implementation but not in case
|
||||
# of check 'ucd_cpu_load' because the HR-MIB has not data
|
||||
# about cpu load
|
||||
|
||||
# ---general ucd/hr-------------------------------------------------------
|
||||
|
||||
HR = exists(".1.3.6.1.2.1.25.1.1.0")
|
||||
|
||||
_NOT_HR = not_exists(".1.3.6.1.2.1.25.1.1.0")
|
||||
|
||||
UCD = any_of(
|
||||
contains(".1.3.6.1.2.1.1.1.0", "linux"),
|
||||
contains(".1.3.6.1.2.1.1.1.0", "cmc-tc"),
|
||||
contains(".1.3.6.1.2.1.1.1.0", "hp onboard administrator"),
|
||||
contains(".1.3.6.1.2.1.1.1.0", "barracuda"),
|
||||
contains(".1.3.6.1.2.1.1.1.0", "pfsense"),
|
||||
contains(".1.3.6.1.2.1.1.1.0", "genugate"),
|
||||
contains(".1.3.6.1.2.1.1.1.0", "bomgar"),
|
||||
contains(".1.3.6.1.2.1.1.1.0", "pulse secure"),
|
||||
contains(".1.3.6.1.2.1.1.1.0", "microsens"),
|
||||
contains(".1.3.6.1.2.1.1.1.0", "avocent"),
|
||||
all_of( # Artec email archive appliances
|
||||
equals(".1.3.6.1.2.1.1.2.0", ".1.3.6.1.4.1.8072.3.2.10"),
|
||||
contains(".1.3.6.1.2.1.1.1.0", "version"),
|
||||
contains(".1.3.6.1.2.1.1.1.0", "serial"),
|
||||
),
|
||||
all_of(
|
||||
equals(".1.3.6.1.2.1.1.1.0", ""),
|
||||
exists(".1.3.6.1.4.1.2021.*"),
|
||||
),
|
||||
)
|
||||
|
||||
_NOT_UCD = all_of(
|
||||
# This is an explicit negation of the constant above.
|
||||
# We don't have a generic negation function as we want
|
||||
# discourage constructs like this.
|
||||
# In the future this will be acomplished using the 'supersedes'
|
||||
# feature (according to CMK-4232), and this can be removed.
|
||||
not_contains(".1.3.6.1.2.1.1.1.0", "linux"),
|
||||
not_contains(".1.3.6.1.2.1.1.1.0", "cmc-tc"),
|
||||
not_contains(".1.3.6.1.2.1.1.1.0", "hp onboard administrator"),
|
||||
not_contains(".1.3.6.1.2.1.1.1.0", "barracuda"),
|
||||
not_contains(".1.3.6.1.2.1.1.1.0", "pfsense"),
|
||||
not_contains(".1.3.6.1.2.1.1.1.0", "genugate"),
|
||||
not_contains(".1.3.6.1.2.1.1.1.0", "bomgar"),
|
||||
not_contains(".1.3.6.1.2.1.1.1.0", "pulse secure"),
|
||||
not_contains(".1.3.6.1.2.1.1.1.0", "microsens"),
|
||||
not_contains(".1.3.6.1.2.1.1.1.0", "avocent"),
|
||||
any_of( # Artec email archive appliances
|
||||
not_equals(".1.3.6.1.2.1.1.2.0", ".1.3.6.1.4.1.8072.3.2.10"),
|
||||
not_contains(".1.3.6.1.2.1.1.1.0", "version"),
|
||||
not_contains(".1.3.6.1.2.1.1.1.0", "serial"),
|
||||
),
|
||||
)
|
||||
|
||||
PREFER_HR_ELSE_UCD = all_of(UCD, _NOT_HR)
|
||||
|
||||
# ---helper---------------------------------------------------------------
|
||||
|
||||
# Within _is_ucd or _is_ucd_mem we make use of a whitelist
|
||||
# in order to expand this list of devices easily.
|
||||
|
||||
_UCD_MEM = any_of(
|
||||
# Devices for which ucd_mem should be used
|
||||
# if and only if HR-table is not available
|
||||
all_of(
|
||||
contains(".1.3.6.1.2.1.1.1.0", "pfsense"),
|
||||
not_exists(".1.3.6.1.2.1.25.1.1.0"),
|
||||
),
|
||||
all_of(
|
||||
contains(".1.3.6.1.2.1.1.1.0", "ironport model c3"),
|
||||
not_exists(".1.3.6.1.2.1.25.1.1.0"),
|
||||
),
|
||||
all_of(
|
||||
contains(".1.3.6.1.2.1.1.1.0", "bomgar"),
|
||||
not_exists(".1.3.6.1.2.1.25.1.1.0"),
|
||||
),
|
||||
all_of(
|
||||
# Astaro and Synology are Linux but should use hr_mem
|
||||
# Otherwise Cache/Buffers are included in used memory
|
||||
# generating critical state
|
||||
not_startswith(".1.3.6.1.2.1.1.2.0", ".1.3.6.1.4.1.8072."),
|
||||
# Otherwise use ucd_mem for listed devices in UCD.
|
||||
UCD,
|
||||
),
|
||||
)
|
||||
|
||||
_NOT_UCD_MEM = all_of(
|
||||
# This is an explicit negation of the constant above.
|
||||
# We don't have a generic negation function as we want
|
||||
# discourage constructs like this.
|
||||
# In the future this will be acomplished using the 'supersedes'
|
||||
# feature (according to CMK-4232), and this can be removed.
|
||||
any_of(
|
||||
not_contains(".1.3.6.1.2.1.1.1.0", "pfsense"),
|
||||
exists(".1.3.6.1.2.1.25.1.1.0"),
|
||||
),
|
||||
any_of(
|
||||
not_contains(".1.3.6.1.2.1.1.1.0", "ironport model c3"),
|
||||
exists(".1.3.6.1.2.1.25.1.1.0"),
|
||||
),
|
||||
any_of(
|
||||
not_contains(".1.3.6.1.2.1.1.1.0", "bomgar"),
|
||||
exists(".1.3.6.1.2.1.25.1.1.0"),
|
||||
),
|
||||
any_of(
|
||||
# Astaro and Synology are Linux but should use hr_mem
|
||||
# Otherwise Cache/Buffers are included in used memory
|
||||
# generating critical state
|
||||
startswith(".1.3.6.1.2.1.1.2.0", ".1.3.6.1.4.1.8072."),
|
||||
# Otherwise use ucd_mem for listed devices in UCD.
|
||||
_NOT_UCD,
|
||||
),
|
||||
)
|
||||
|
||||
# Some devices report incorrect data on both HR and UCD, eg. F5 BigIP
|
||||
_NOT_BROKEN_MEM = all_of(
|
||||
not_startswith(".1.3.6.1.2.1.1.2.0", ".1.3.6.1.4.1.3375"),
|
||||
not_startswith(".1.3.6.1.2.1.1.2.0", ".1.3.6.1.4.1.2620"),
|
||||
)
|
||||
|
||||
# ---memory---------------------------------------------------------------
|
||||
|
||||
USE_UCD_MEM = all_of(_NOT_BROKEN_MEM, _UCD_MEM)
|
||||
|
||||
USE_HR_MEM = all_of(_NOT_BROKEN_MEM, _NOT_UCD_MEM)
|
@ -0,0 +1,15 @@
|
||||
title: Avocent ACS 800 CPU and Board Temperature
|
||||
agents: snmp
|
||||
catalog: hw/network/avocent
|
||||
license: GPLv2
|
||||
distribution: check_mk
|
||||
description:
|
||||
Checks by SNMP the Temperature for CPU and Board sensors of Avocent ACS 800 devices.
|
||||
|
||||
Return {OK} if no temperature rule is created, otherwise based on the level in
|
||||
the configured temperature rule.
|
||||
item:
|
||||
CPU Temperature and Board Temperature
|
||||
|
||||
discovery:
|
||||
One service is created for CPU Temperature and one service for Board Temperature
|
@ -0,0 +1,15 @@
|
||||
title: Avocent ACS 800 Power Supply Voltage Sensors
|
||||
agents: snmp
|
||||
catalog: hw/network/avocent
|
||||
license: GPLv2
|
||||
distribution: check_mk
|
||||
description:
|
||||
Checks by SNMP the power supply voltage sensors of Avocent ACS 800 devices.
|
||||
|
||||
Returns {OK} Always.
|
||||
|
||||
item:
|
||||
The Voltage for each power supply.
|
||||
|
||||
discovery:
|
||||
Two services created, one for each Power Supply
|
@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2023 Spearhead Systems SRL - License: GNU General Public License v2
|
||||
|
||||
import json
|
||||
from datetime import datetime, timezone
|
||||
from cmk.base.plugins.agent_based.agent_based_api.v1 import register, Result, Service, State
|
||||
|
||||
|
||||
# Convert JSON entries into dictionaries indexed by certificate name.
|
||||
def parse_keyvault(string_table):
|
||||
raw_json = ""
|
||||
cert_data = []
|
||||
|
||||
for row in string_table:
|
||||
line = row[0]
|
||||
raw_json += line
|
||||
if line == "]":
|
||||
cert_data.extend(json.loads(raw_json))
|
||||
raw_json = ""
|
||||
|
||||
lookup = {}
|
||||
for cert in cert_data:
|
||||
lookup[cert["name"]] = cert
|
||||
|
||||
return lookup
|
||||
|
||||
|
||||
register.agent_section(
|
||||
name="azure_keyvault",
|
||||
parse_function=parse_keyvault
|
||||
)
|
||||
|
||||
|
||||
# Produce a list of certificates based on the parsed output.
|
||||
def discover_keyvault(section):
|
||||
for name, details in sorted(section.items()):
|
||||
yield Service(item=name)
|
||||
|
||||
|
||||
# Given a specific certificate, look it up in the parsed output, and produce
|
||||
# results on that service based upon the certificate's expiry.
|
||||
def check_keyvault(item, params, section):
|
||||
warn_days = params.get("warn_days")
|
||||
crit_days = params.get("crit_days")
|
||||
|
||||
cert = section.get(item)
|
||||
if cert is None:
|
||||
return
|
||||
|
||||
expires = datetime.fromisoformat(cert["attributes"]["expires"])
|
||||
now = datetime.now(timezone.utc)
|
||||
remaining_days = (expires - now).days
|
||||
|
||||
state = State.OK
|
||||
if crit_days is not None and remaining_days < crit_days:
|
||||
state = State.CRIT
|
||||
elif warn_days is not None and remaining_days < warn_days:
|
||||
state = State.WARN
|
||||
|
||||
yield Result(state=state, summary="Expires in %d days" % remaining_days)
|
||||
|
||||
|
||||
register.check_plugin(
|
||||
name="azure_keyvault",
|
||||
service_name="Azure Keyvault Certificate %s",
|
||||
|
||||
check_function=check_keyvault,
|
||||
check_default_parameters={},
|
||||
check_ruleset_name="azure_keyvault",
|
||||
|
||||
discovery_function=discover_keyvault,
|
||||
)
|
@ -0,0 +1,26 @@
|
||||
#!/bin/bash
|
||||
# Copyright (C) 2023 Spearhead Systems SRL - License: GNU General Public License v2
|
||||
|
||||
az=/usr/bin/az
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if [ "$#" -lt 4 ]; then
|
||||
echo "Usage: $0 <tenant> <user> <password> <vault1> ... [vaultN]" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
tenant="$1"
|
||||
user="$2"
|
||||
password="$3"
|
||||
vaults="${@:4}"
|
||||
|
||||
echo "<<<azure_keyvault:sep(0)>>>"
|
||||
|
||||
"$az" login --service-principal --tenant="$tenant" --user="$user" --password="$password" > /dev/null
|
||||
|
||||
for vault in $vaults; do
|
||||
"$az" keyvault certificate list --vault-name="$vault"
|
||||
done
|
||||
|
||||
"$az" logout
|
@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2023 Spearhead Systems SRL - License: GNU General Public License v2
|
||||
|
||||
def agent_azure_keyvault(params, hostname, ipaddress):
|
||||
tenant = params["tenant"]
|
||||
client = params["client"]
|
||||
secret = params["secret"]
|
||||
|
||||
args = [tenant, client, secret]
|
||||
|
||||
for vault in params["vaults"]:
|
||||
args.extend([vault.strip()])
|
||||
|
||||
return args
|
||||
|
||||
special_agent_info["azure_keyvault"] = agent_azure_keyvault
|
@ -0,0 +1,110 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2023 Spearhead Systems SRL - License: GNU General Public License v2
|
||||
|
||||
import copy
|
||||
from cmk.gui.i18n import _
|
||||
from cmk.gui.plugins.wato.utils import (
|
||||
rulespec_registry,
|
||||
HostRulespec,
|
||||
IndividualOrStoredPassword,
|
||||
RulespecGroupCheckParametersDiscovery,
|
||||
CheckParameterRulespecWithItem,
|
||||
RulespecGroupCheckParametersApplications,
|
||||
)
|
||||
from cmk.gui.watolib.rulespecs import Rulespec
|
||||
from cmk.gui.valuespec import (
|
||||
Dictionary,
|
||||
TextInput,
|
||||
Integer,
|
||||
ListOfStrings,
|
||||
Password
|
||||
)
|
||||
|
||||
|
||||
def _valuespec_special_agents_azure_keyvault_check():
|
||||
return Dictionary(
|
||||
title=_("Azure Key Vault Certificate Checks"),
|
||||
optional_keys=["warn_days", "crit_days"],
|
||||
elements=[
|
||||
(
|
||||
"warn_days",
|
||||
Integer(
|
||||
minvalue=0,
|
||||
default_value=30,
|
||||
title=_("Certificate Days to Warn"),
|
||||
help=_(
|
||||
"How many days to warn before a certificate in this key vault will expire"
|
||||
),
|
||||
),
|
||||
),
|
||||
(
|
||||
"crit_days",
|
||||
Integer(
|
||||
minvalue=0,
|
||||
default_value=3,
|
||||
title=_("Certificate Days to Crit"),
|
||||
help=_(
|
||||
"How many days to crit before a certificate in this key vault will expire"
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
def _valuespec_special_agents_azure_keyvault_discovery():
|
||||
return Dictionary(
|
||||
title=_("Azure Key Vault Certificate Discovery"),
|
||||
elements=[
|
||||
(
|
||||
"tenant",
|
||||
TextInput(
|
||||
title=_("Tenant ID / Directory ID"),
|
||||
allow_empty=False,
|
||||
size=45,
|
||||
),
|
||||
),
|
||||
(
|
||||
"client",
|
||||
TextInput(
|
||||
title=_("Client ID / Application ID"),
|
||||
allow_empty=False,
|
||||
size=45,
|
||||
),
|
||||
),
|
||||
(
|
||||
"secret",
|
||||
IndividualOrStoredPassword(
|
||||
# Password(
|
||||
title=_("Client Secret"),
|
||||
allow_empty=False,
|
||||
size=45,
|
||||
),
|
||||
),
|
||||
(
|
||||
"vaults",
|
||||
ListOfStrings(
|
||||
title=_("Keyvaults"),
|
||||
allow_empty=False,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
rulespec_registry.register(
|
||||
CheckParameterRulespecWithItem(
|
||||
check_group_name="azure_keyvault",
|
||||
group=RulespecGroupCheckParametersApplications,
|
||||
match_type='dict',
|
||||
parameter_valuespec=_valuespec_special_agents_azure_keyvault_check,
|
||||
)
|
||||
)
|
||||
|
||||
rulespec_registry.register(
|
||||
HostRulespec(
|
||||
group=RulespecGroupCheckParametersDiscovery,
|
||||
match_type='dict',
|
||||
name="special_agents:azure_keyvault",
|
||||
valuespec=_valuespec_special_agents_azure_keyvault_discovery,
|
||||
)
|
||||
)
|
BIN
check_mk-azure/azure-spearhead-0.2.0.mkp
Executable file
BIN
check_mk-azure/azure-spearhead-0.2.0.mkp
Executable file
Binary file not shown.
@ -0,0 +1,278 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2024 Spearhead Systems SRL
|
||||
|
||||
import json
|
||||
from datetime import datetime, timezone
|
||||
from cmk.base.plugins.agent_based.agent_based_api.v1 import register, Result, Service, State, Metric
|
||||
|
||||
|
||||
def check_state_below(alert_percentages, measured_percent):
|
||||
if alert_percentages:
|
||||
if alert_percentages[1] >= measured_percent:
|
||||
return State.CRIT
|
||||
elif alert_percentages[0] >= measured_percent:
|
||||
return State.WARN
|
||||
return State.OK
|
||||
|
||||
|
||||
def check_state_above(alert_percentages, measured_percent):
|
||||
if alert_percentages:
|
||||
if alert_percentages[1] <= measured_percent:
|
||||
return State.CRIT
|
||||
elif alert_percentages[0] <= measured_percent:
|
||||
return State.WARN
|
||||
return State.OK
|
||||
|
||||
|
||||
# Convert JSON entries into dictionaries indexed by name. We're assuming here
|
||||
# that the name is unique across AZs and resource groups. If not, add the
|
||||
# 'location' and 'resource_group' fields in each object to the name.
|
||||
def parse(string_table):
|
||||
lookup = {}
|
||||
|
||||
for json_data in string_table:
|
||||
obj = json.loads(json_data[0])
|
||||
name = obj["name"]
|
||||
group = obj["resource_group"]
|
||||
lookup[f"{name}#{group}"] = obj
|
||||
|
||||
return lookup
|
||||
|
||||
|
||||
# Produce a list of Azure objects for discovery.
|
||||
def discover(section):
|
||||
for name, details in sorted(section.items()):
|
||||
yield Service(item=name)
|
||||
|
||||
|
||||
# Given a specific keyvault metric, look it up in the parsed output, and produce
|
||||
# results on that service based upon the metric's range.
|
||||
def check_keyvault(item, params, section):
|
||||
vault = section.get(item)
|
||||
if vault is None:
|
||||
return
|
||||
|
||||
metrics = vault["metrics"]
|
||||
|
||||
availability = metrics.get("Availability")
|
||||
capacity = metrics.get("SaturationShoebox")
|
||||
latency = metrics.get("ServiceApiLatency")
|
||||
hits = metrics.get("ServiceApiHit")
|
||||
results = metrics.get("ServiceApiResult")
|
||||
|
||||
alert_availability_percent = params.get("availability")
|
||||
alert_capacity_percent = params.get("capacity")
|
||||
alert_latency_milliseconds = params.get("latency")
|
||||
|
||||
if availability is not None:
|
||||
yield Result(
|
||||
state=check_state_below(alert_availability_percent, availability),
|
||||
summary=f"Availability: {availability}%",
|
||||
)
|
||||
yield Metric(
|
||||
name="availability",
|
||||
value=availability,
|
||||
boundaries=(0, 100),
|
||||
)
|
||||
else:
|
||||
yield Result(
|
||||
state=State.UNKNOWN,
|
||||
summary="Availability: N/A",
|
||||
)
|
||||
|
||||
if capacity is not None:
|
||||
yield Result(
|
||||
state=check_state_above(alert_capacity_percent, capacity),
|
||||
summary=f"Capacity: {capacity}%"
|
||||
)
|
||||
yield Metric(
|
||||
name="capacity",
|
||||
value=capacity,
|
||||
boundaries=(0, 100),
|
||||
)
|
||||
else:
|
||||
yield Result(
|
||||
state=State.UNKNOWN,
|
||||
summary="Capacity: N/A",
|
||||
)
|
||||
|
||||
|
||||
if latency is not None:
|
||||
yield Result(
|
||||
state=check_state_above(alert_latency_milliseconds, latency),
|
||||
summary=f"Latency: {latency}ms",
|
||||
)
|
||||
yield Metric(
|
||||
name="latency",
|
||||
value=latency,
|
||||
boundaries=(0, None),
|
||||
)
|
||||
else:
|
||||
yield Result(
|
||||
state=State.UNKNOWN,
|
||||
summary="Latency: N/A",
|
||||
)
|
||||
|
||||
|
||||
if hits is not None:
|
||||
yield Metric(
|
||||
name="hits",
|
||||
value=hits,
|
||||
boundaries=(0, None),
|
||||
)
|
||||
else:
|
||||
yield Result(
|
||||
state=State.UNKNOWN,
|
||||
summary="Hits: N/A",
|
||||
)
|
||||
|
||||
if results is not None:
|
||||
yield Metric(
|
||||
name="results",
|
||||
value=results,
|
||||
boundaries=(0, None),
|
||||
)
|
||||
else:
|
||||
yield Result(
|
||||
state=State.UNKNOWN,
|
||||
summary="Results: N/A",
|
||||
)
|
||||
|
||||
|
||||
# Given a specific firewall metric, look it up in the parsed output, and produce
|
||||
# results on that service based upon the metric's range.
|
||||
def check_firewall(item, params, section):
|
||||
firewall = section.get(item)
|
||||
if firewall is None:
|
||||
return
|
||||
|
||||
metrics = firewall["metrics"]
|
||||
|
||||
availability = metrics.get("FirewallHealth")
|
||||
throughput = metrics.get("Throughput")
|
||||
latency = metrics.get("FirewallLatencyPng")
|
||||
|
||||
alert_availability_percent = params.get("availability")
|
||||
alert_latency_milliseconds = params.get("latency")
|
||||
|
||||
if availability is not None:
|
||||
yield Result(
|
||||
state=check_state_below(alert_availability_percent, availability),
|
||||
summary=f"Availability: {availability}%",
|
||||
)
|
||||
yield Metric(
|
||||
name="availability",
|
||||
value=availability,
|
||||
boundaries=(0, 100)
|
||||
)
|
||||
else:
|
||||
yield Result(
|
||||
state=State.UNKNOWN,
|
||||
summary="Availability: N/A",
|
||||
)
|
||||
|
||||
if latency is not None:
|
||||
yield Result(
|
||||
state=check_state_above(alert_latency_milliseconds, latency),
|
||||
summary=f"Latency: {latency}ms",
|
||||
)
|
||||
yield Metric(
|
||||
name="latency",
|
||||
value=latency,
|
||||
boundaries=(0, None)
|
||||
)
|
||||
else:
|
||||
yield Result(
|
||||
state=State.UNKNOWN,
|
||||
summary="Latency: N/A",
|
||||
)
|
||||
|
||||
if throughput is not None:
|
||||
yield Metric(
|
||||
name="throughput",
|
||||
value=throughput,
|
||||
boundaries=(0, None)
|
||||
)
|
||||
else:
|
||||
yield Result(
|
||||
state=State.UNKNOWN,
|
||||
summary="Throughput: N/A",
|
||||
)
|
||||
|
||||
def check_defender(item, params, section):
|
||||
alert = section.get(item)
|
||||
if alert is None:
|
||||
return
|
||||
|
||||
details = alert["alert"]
|
||||
status = details["status"]
|
||||
|
||||
if status != "Active" and status != "InProgress":
|
||||
return
|
||||
|
||||
severity = details["severity"]
|
||||
url = details["url"]
|
||||
info = details["info"]
|
||||
|
||||
if severity == "High":
|
||||
state = State.CRIT
|
||||
elif severity == "Medium":
|
||||
state = State.WARN
|
||||
elif severity == "Low":
|
||||
state = State.OK
|
||||
else:
|
||||
state = State.UNKNOWN
|
||||
|
||||
yield Result(
|
||||
state=state,
|
||||
summary=f"{status}: {info}: {url}"
|
||||
)
|
||||
|
||||
|
||||
register.agent_section(
|
||||
name="azure_keyvault",
|
||||
parse_function=parse
|
||||
)
|
||||
|
||||
register.check_plugin(
|
||||
name="azure_keyvault",
|
||||
service_name="Azure Keyvault Metric %s",
|
||||
|
||||
check_function=check_keyvault,
|
||||
check_default_parameters={},
|
||||
check_ruleset_name="azure_keyvault",
|
||||
|
||||
discovery_function=discover,
|
||||
)
|
||||
|
||||
register.agent_section(
|
||||
name="azure_firewall",
|
||||
parse_function=parse
|
||||
)
|
||||
|
||||
register.check_plugin(
|
||||
name="azure_firewall",
|
||||
service_name="Azure Firewall Metric %s",
|
||||
|
||||
check_function=check_firewall,
|
||||
check_default_parameters={},
|
||||
check_ruleset_name="azure_firewall",
|
||||
|
||||
discovery_function=discover,
|
||||
)
|
||||
|
||||
register.agent_section(
|
||||
name="azure_defender",
|
||||
parse_function=parse
|
||||
)
|
||||
|
||||
register.check_plugin(
|
||||
name="azure_defender",
|
||||
service_name="Azure Defender Alert %s",
|
||||
|
||||
check_function=check_defender,
|
||||
check_default_parameters={},
|
||||
check_ruleset_name="azure_defender",
|
||||
|
||||
discovery_function=discover,
|
||||
)
|
184
check_mk-azure/local/share/check_mk/agents/special/agent_azure_common
Executable file
184
check_mk-azure/local/share/check_mk/agents/special/agent_azure_common
Executable file
@ -0,0 +1,184 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2024 Spearhead Systems SRL
|
||||
|
||||
from urllib import request, parse, error
|
||||
from datetime import datetime, timezone, timedelta
|
||||
import json
|
||||
import sys
|
||||
import re
|
||||
|
||||
|
||||
VAULT_METRICS = [
|
||||
'Availability',
|
||||
'SaturationShoebox',
|
||||
'ServiceApiLatency',
|
||||
'ServiceApiHit',
|
||||
'ServiceApiResult',
|
||||
]
|
||||
|
||||
FIREWALL_METRICS = [
|
||||
'FirewallHealth',
|
||||
'Throughput',
|
||||
'FirewallLatencyPng',
|
||||
]
|
||||
|
||||
REGION_RE = re.compile('/locations/(.+?)/')
|
||||
RESOURCE_GROUP_RE = re.compile('/resourceGroups/(.+?)/')
|
||||
|
||||
|
||||
# https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/request-limits-and-throttling
|
||||
def get_url(req, default):
|
||||
try:
|
||||
res = request.urlopen(req)
|
||||
return res.read()
|
||||
except error.HTTPError as e:
|
||||
if e.code == 429:
|
||||
return default
|
||||
else:
|
||||
raise e
|
||||
|
||||
|
||||
def set_proxy(req, proxy):
|
||||
if proxy is None or proxy == '':
|
||||
return
|
||||
match = re.match('(https?)://(.+?)/?$', proxy, re.I)
|
||||
req.set_proxy(match[2], match[1].lower())
|
||||
|
||||
|
||||
def get_token(tenant, username, password, proxy):
|
||||
data = parse.urlencode({
|
||||
'username': username,
|
||||
'password': password,
|
||||
'grant_type': 'password',
|
||||
'claims': '{"access_token": {"xms_cc": {"values": ["CP1"]}}}',
|
||||
'scope': 'https://management.core.windows.net//.default offline_access openid profile',
|
||||
'client_info': 1,
|
||||
# This is actually the client ID of the Azure CLI tools
|
||||
'client_id': '04b07795-8ddb-461a-bbee-02f9e1bf7b46',
|
||||
})
|
||||
|
||||
req = request.Request(f'https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token',
|
||||
data=str.encode(data))
|
||||
set_proxy(req, proxy)
|
||||
|
||||
res = get_url(req, None)
|
||||
if res is None:
|
||||
return
|
||||
|
||||
token_data = json.loads(res)
|
||||
token = token_data['access_token']
|
||||
return token
|
||||
|
||||
|
||||
def get_json(token, proxy, path, version='2023-07-01'):
|
||||
url = f"https://management.azure.com{path}{'?' in path and '&' or '?'}api-version={version}"
|
||||
req = request.Request(url, headers={'Authorization': f'Bearer {token}'})
|
||||
set_proxy(req, proxy)
|
||||
res = get_url(req, "[]")
|
||||
data = json.loads(res)
|
||||
return data['value']
|
||||
|
||||
|
||||
def list_subscriptions(token, proxy):
|
||||
return get_json(token, proxy, '/subscriptions')
|
||||
|
||||
|
||||
def list_vaults(token, proxy, subscription):
|
||||
return get_json(token, proxy, f'/subscriptions/{subscription}/resources?$filter=resourceType%20eq%20%27Microsoft.KeyVault%2Fvaults%27')
|
||||
|
||||
|
||||
def list_firewalls(token, proxy, subscription):
|
||||
return get_json(token, proxy, f'/subscriptions/{subscription}/resources?$filter=resourceType%20eq%20%27Microsoft.Network%2FazureFirewalls%27')
|
||||
|
||||
|
||||
def list_defender_alerts(token, proxy, subscription):
|
||||
return get_json(token, proxy, f'/subscriptions/{subscription}/providers/Microsoft.Security/alerts', '2022-01-01')
|
||||
|
||||
|
||||
def get_recent_metrics(token, proxy, path, metrics):
|
||||
end = datetime.now()
|
||||
start = end - timedelta(minutes=2)
|
||||
|
||||
start_str = start.isoformat().split('.')[0] + 'Z'
|
||||
end_str = end.isoformat().split('.')[0] + 'Z'
|
||||
metrics_str = ','.join(metrics)
|
||||
|
||||
return get_json(token, proxy, f'{path}/providers/microsoft.insights/metrics?metricnames={metrics_str}×pan={start_str}/{end_str}', '2023-10-01')
|
||||
|
||||
|
||||
def metrics_to_lookup(metrics):
|
||||
lookup = {}
|
||||
|
||||
for metric in metrics:
|
||||
name = metric['name']['value']
|
||||
series = metric['timeseries']
|
||||
if series:
|
||||
value = series[0]['data'][-1]
|
||||
key = next(filter(lambda foo: foo != 'timeStamp', value), None)
|
||||
lookup[name] = value.get(key)
|
||||
|
||||
return lookup
|
||||
|
||||
|
||||
def get_args(argv):
|
||||
if (len(argv) != 5 and len(argv) != 6) or argv[1] not in ['keyvault', 'firewall', 'defender']:
|
||||
print(f"{sys.argv[0]} <command> <tenant ID> <username> <password> <proxy>", file=sys.stderr)
|
||||
print(f"Valid commands are: 'keyvault', 'firewall', 'defender'", file=sys.stderr)
|
||||
print(f"Proxy is an optional argument", file=sys.stderr)
|
||||
exit(1)
|
||||
return argv[1], argv[2], argv[3], argv[4], (argv[5] if len(argv) == 6 else None)
|
||||
|
||||
|
||||
def print_json(obj):
|
||||
print(json.dumps(obj))
|
||||
|
||||
|
||||
command, tenant, username, password, proxy = get_args(sys.argv)
|
||||
token = get_token(tenant, username, password, proxy)
|
||||
|
||||
for subscription in list_subscriptions(token, proxy):
|
||||
subscription_id = subscription['subscriptionId']
|
||||
|
||||
if command == 'defender':
|
||||
for alert in list_defender_alerts(token, proxy, subscription_id):
|
||||
properties = alert['properties']
|
||||
status = properties['status']
|
||||
|
||||
if not status in ['Active', 'InProgress']:
|
||||
continue
|
||||
|
||||
print_json({
|
||||
'type': command,
|
||||
'name': alert['name'],
|
||||
'location': re.search(REGION_RE, alert['id'])[1],
|
||||
'resource_group': re.search(RESOURCE_GROUP_RE, alert['id'])[1],
|
||||
'alert': {
|
||||
'status': status,
|
||||
'severity': properties['severity'],
|
||||
'url': properties['alertUri'],
|
||||
'info': properties['alertDisplayName']
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
elif command == 'firewall':
|
||||
for firewall in list_firewalls(token, proxy, subscription_id):
|
||||
metrics = get_recent_metrics(token, proxy, firewall['id'], FIREWALL_METRICS)
|
||||
print_json({
|
||||
'type': command,
|
||||
'name': firewall['name'],
|
||||
'location': firewall['location'],
|
||||
'resource_group': re.search(RESOURCE_GROUP_RE, firewall['id'])[1],
|
||||
'metrics': metrics_to_lookup(metrics),
|
||||
})
|
||||
|
||||
elif command == 'keyvault':
|
||||
for vault in list_vaults(token, proxy, subscription_id):
|
||||
metrics = get_recent_metrics(token, proxy, vault['id'], VAULT_METRICS)
|
||||
print_json({
|
||||
'type': command,
|
||||
'name': vault['name'],
|
||||
'location': vault['location'],
|
||||
'resource_group': re.search(RESOURCE_GROUP_RE, vault['id'])[1],
|
||||
'metrics': metrics_to_lookup(metrics),
|
||||
})
|
6
check_mk-azure/local/share/check_mk/agents/special/agent_azure_defender
Executable file
6
check_mk-azure/local/share/check_mk/agents/special/agent_azure_defender
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo '<<<azure_defender:sep(0)>>>'
|
||||
|
||||
dir=$(dirname -- "${BASH_SOURCE[0]}")
|
||||
"$dir"/agent_azure_common defender "$1" "$2" "$3" "$4"
|
6
check_mk-azure/local/share/check_mk/agents/special/agent_azure_firewall
Executable file
6
check_mk-azure/local/share/check_mk/agents/special/agent_azure_firewall
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo '<<<azure_firewall:sep(0)>>>'
|
||||
|
||||
dir=$(dirname -- "${BASH_SOURCE[0]}")
|
||||
"$dir"/agent_azure_common firewall "$1" "$2" "$3" "$4"
|
6
check_mk-azure/local/share/check_mk/agents/special/agent_azure_keyvault
Executable file
6
check_mk-azure/local/share/check_mk/agents/special/agent_azure_keyvault
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo '<<<azure_keyvault:sep(0)>>>'
|
||||
|
||||
dir=$(dirname -- "${BASH_SOURCE[0]}")
|
||||
"$dir"/agent_azure_common keyvault "$1" "$2" "$3" "$4"
|
@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2024 Spearhead Systems SRL
|
||||
|
||||
import cmk.utils.password_store
|
||||
|
||||
def agent_azure_args(params, hostname, ipaddress):
|
||||
# Extract password either from params, or from password store:
|
||||
# ('password', '<some password>'): password is in params directly
|
||||
# ('store', '<password name>'): password must be looked up in store by name
|
||||
password_info = params["password"]
|
||||
if password_info[0] == "password":
|
||||
password = password_info[1]
|
||||
else:
|
||||
password = cmk.utils.password_store.extract(password_info[1])
|
||||
|
||||
return [
|
||||
params["tenant"],
|
||||
params["username"],
|
||||
password,
|
||||
params.get("proxy") or "" # optional
|
||||
]
|
||||
|
||||
special_agent_info["azure_keyvault"] = agent_azure_args
|
||||
special_agent_info["azure_firewall"] = agent_azure_args
|
||||
special_agent_info["azure_defender"] = agent_azure_args
|
@ -0,0 +1,217 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2024 Spearhead Systems SRL
|
||||
|
||||
import copy
|
||||
from cmk.gui.i18n import _
|
||||
from cmk.gui.plugins.wato.utils import (
|
||||
rulespec_registry,
|
||||
HostRulespec,
|
||||
IndividualOrStoredPassword,
|
||||
RulespecGroupCheckParametersDiscovery,
|
||||
CheckParameterRulespecWithItem,
|
||||
RulespecGroupCheckParametersApplications,
|
||||
)
|
||||
from cmk.gui.watolib.rulespecs import Rulespec
|
||||
from cmk.gui.valuespec import (
|
||||
Dictionary,
|
||||
TextInput,
|
||||
Integer,
|
||||
ListOfStrings,
|
||||
Password
|
||||
)
|
||||
|
||||
|
||||
def _discovery(title):
|
||||
return Dictionary(
|
||||
title=_(title),
|
||||
required_keys=["tenant", "username", "password"],
|
||||
elements=[
|
||||
(
|
||||
"tenant",
|
||||
TextInput(
|
||||
title=_("Tenant ID"),
|
||||
allow_empty=False,
|
||||
),
|
||||
),
|
||||
(
|
||||
"username",
|
||||
TextInput(
|
||||
title=_("Username"),
|
||||
allow_empty=False,
|
||||
),
|
||||
),
|
||||
(
|
||||
"password",
|
||||
IndividualOrStoredPassword(
|
||||
# Password(
|
||||
title=_("Password"),
|
||||
allow_empty=False,
|
||||
),
|
||||
),
|
||||
(
|
||||
"proxy",
|
||||
TextInput(
|
||||
title=_("Proxy"),
|
||||
),
|
||||
),
|
||||
|
||||
],
|
||||
)
|
||||
|
||||
def _valuespec_special_agents_azure_keyvault_discovery():
|
||||
return _discovery("Azure Key Vault Metrics Discovery")
|
||||
|
||||
def _valuespec_special_agents_azure_firewall_discovery():
|
||||
return _discovery("Azure Firewall Metrics Discovery")
|
||||
|
||||
def _valuespec_special_agents_azure_defender_discovery():
|
||||
return _discovery("Azure Defender Alerts Discovery")
|
||||
|
||||
def _valuespec_special_agents_azure_keyvault_check():
|
||||
return Dictionary(
|
||||
title=_("Azure Key Vault Metric Checks"),
|
||||
elements=[
|
||||
(
|
||||
"availability",
|
||||
Tuple(
|
||||
title=_("Availability"),
|
||||
help=_("If drops below these percentages over the past minute, issue alert"),
|
||||
elements=[
|
||||
Percentage(
|
||||
title=_("Warn if below"),
|
||||
default_value=98
|
||||
),
|
||||
Percentage(
|
||||
title=_("Crit if below"),
|
||||
default_value=90
|
||||
)
|
||||
]
|
||||
)
|
||||
),
|
||||
(
|
||||
"capacity",
|
||||
Tuple(
|
||||
title=_("Capacity used"),
|
||||
help=_("If goes above these percentages over the past minute, issue alert"),
|
||||
elements=[
|
||||
Percentage(
|
||||
title=_("Warn if above"),
|
||||
default_value=80
|
||||
),
|
||||
Percentage(
|
||||
title=_("Crit if above"),
|
||||
default_value=98
|
||||
)
|
||||
]
|
||||
)
|
||||
),
|
||||
(
|
||||
"latency",
|
||||
Tuple(
|
||||
title=_("Request latency"),
|
||||
help=_("If goes above the average milliseconds over the past minute, issue alert"),
|
||||
elements=[
|
||||
Integer(
|
||||
title=_("Warn if above"),
|
||||
default_value=100,
|
||||
minvalue=0,
|
||||
),
|
||||
Integer(
|
||||
title=_("Crit if above"),
|
||||
default_value=2000,
|
||||
minvalue=0,
|
||||
)
|
||||
]
|
||||
)
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
def _valuespec_special_agents_azure_firewall_check():
|
||||
return Dictionary(
|
||||
title=_("Azure Firewall Metric Checks"),
|
||||
elements=[
|
||||
(
|
||||
"availability",
|
||||
Tuple(
|
||||
title=_("Availability"),
|
||||
help=_("If drops below these percentages over the past minute, issue alert"),
|
||||
elements=[
|
||||
Percentage(
|
||||
title=_("Warn if below"),
|
||||
default_value=98
|
||||
),
|
||||
Percentage(
|
||||
title=_("Crit if below"),
|
||||
default_value=90
|
||||
)
|
||||
]
|
||||
)
|
||||
),
|
||||
(
|
||||
"latency",
|
||||
Tuple(
|
||||
title=_("Request latency"),
|
||||
help=_("If goes above the average milliseconds over the past minute, issue alert"),
|
||||
elements=[
|
||||
Integer(
|
||||
title=_("Warn if above"),
|
||||
default_value=100,
|
||||
minvalue=0,
|
||||
),
|
||||
Integer(
|
||||
title=_("Crit if above"),
|
||||
default_value=2000,
|
||||
minvalue=0,
|
||||
)
|
||||
]
|
||||
)
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
rulespec_registry.register(
|
||||
HostRulespec(
|
||||
name="special_agents:azure_keyvault",
|
||||
group=RulespecGroupCheckParametersDiscovery,
|
||||
match_type='dict',
|
||||
valuespec=_valuespec_special_agents_azure_keyvault_discovery,
|
||||
)
|
||||
)
|
||||
rulespec_registry.register(
|
||||
HostRulespec(
|
||||
name="special_agents:azure_firewall",
|
||||
group=RulespecGroupCheckParametersDiscovery,
|
||||
match_type='dict',
|
||||
valuespec=_valuespec_special_agents_azure_firewall_discovery,
|
||||
)
|
||||
)
|
||||
rulespec_registry.register(
|
||||
HostRulespec(
|
||||
name="special_agents:azure_defender",
|
||||
group=RulespecGroupCheckParametersDiscovery,
|
||||
match_type='dict',
|
||||
valuespec=_valuespec_special_agents_azure_defender_discovery,
|
||||
)
|
||||
)
|
||||
|
||||
rulespec_registry.register(
|
||||
CheckParameterRulespecWithItem(
|
||||
check_group_name="azure_keyvault",
|
||||
group=RulespecGroupCheckParametersApplications,
|
||||
match_type="dict",
|
||||
parameter_valuespec=_valuespec_special_agents_azure_keyvault_check,
|
||||
item_spec=lambda: TextInput(title=_("Key Vault")),
|
||||
title=lambda: _("Azure Key Vault Metrics"),
|
||||
)
|
||||
)
|
||||
rulespec_registry.register(
|
||||
CheckParameterRulespecWithItem(
|
||||
check_group_name="azure_firewall",
|
||||
group=RulespecGroupCheckParametersApplications,
|
||||
match_type="dict",
|
||||
parameter_valuespec=_valuespec_special_agents_azure_firewall_check,
|
||||
item_spec=lambda: TextInput(title=_("Firewall")),
|
||||
title=lambda: _("Azure Firewall Metrics"),
|
||||
)
|
||||
)
|
1
check_mk-check-selinux
Submodule
1
check_mk-check-selinux
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit d041278cbe5e329ee3a8a63b1d21530f69fbfaa2
|
BIN
check_mk-cisco_bgp_peer/Cisco_BGP_Peer3-1.1.mkp
Executable file
BIN
check_mk-cisco_bgp_peer/Cisco_BGP_Peer3-1.1.mkp
Executable file
Binary file not shown.
1
check_mk-cisco_bgp_peer/README.md
Normal file
1
check_mk-cisco_bgp_peer/README.md
Normal file
@ -0,0 +1 @@
|
||||
This is a modification of a GPL plugin to additionally support CISCO-BGP4-MIB::CbgpPeer3Entry
|
@ -0,0 +1,665 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# License: GNU General Public License v2
|
||||
#
|
||||
# Author: thl-cmk[at]outlook[dot]com
|
||||
# URL : https://thl-cmk.hopto.org
|
||||
# Date : 2017-12-26
|
||||
#
|
||||
# Monitor status of Cisco BGP Peer (IPv4 and IPv6)
|
||||
#
|
||||
# 2018-05-24: changed counters to 1/s
|
||||
# 2018-05-25: a lot of code cleanup
|
||||
# packet name changed from cisco_bgp to cisco_bgp_peer
|
||||
# added support of more then one address family per peer
|
||||
# (changed item from remoteip to remoteip+familyname, rewrite of parer, inventory and check function)
|
||||
# 2018-05-27: changed scan function from '.1.3.6.1.4.1.9.9.187.1.2.7.1.3.* to sysdecr contains cisco
|
||||
# 2018-05-28: changed wato, added peer alias, state if not found, infotext values
|
||||
# 2018-05-29: fixed longoutpout (removed not configured)
|
||||
# 2018-11-02: modified scanfunction (from "find 'cisco' =-1" to "'cisco' in OID"
|
||||
# 2019-18-02: added fix for empty values ("" instead of "0") sugested by Laurent Barbier (lbarbier[at]arkane-studios[dot]com)
|
||||
# 2020-02-24: added workaround for missing cbgpPeer2AddrFamily (example L2VPN EVPN peers, Fix for jonale82[at]gmail[dot]com)
|
||||
# 2020-03-02: changed handling of perfdata, add only data the are really there (not None, instead of setting them to 0)
|
||||
# 2020-06-04: code cleanup --> changed isdigit test to try/except loop, changed peer.get test to try/except loop
|
||||
# 2020-09-10: fixed typo in metrics file. FMS --> FSM (thanks martin[dot]pechstein[at]posteo[dot]de)
|
||||
# 2021-03-27: rewrite for CMK2.0
|
||||
# 2021-03-28: added warning for missing admin prefix limit/warn threshold
|
||||
# 2023-01-15: modified by Spearhead Systems to support CISCO-BGP4-MIB::CbgpPeer3Entry
|
||||
|
||||
#
|
||||
# snmpwalk sample
|
||||
#
|
||||
# CISCO-BGP4-MIB::cbgpPeer2AddrFamilyEntry
|
||||
#
|
||||
# OMD[mysite]:~$ snmpwalk -ObentU -v2c -c <removed> simulant 1.3.6.1.4.1.9.9.187.1.2.7
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.7.1.3.1.4.62.214.127.57.1.1 = STRING: "IPv4 Unicast"
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.7.1.3.1.4.217.119.208.1.1.1 = STRING: "IPv4 Unicast"
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.7.1.3.1.4.217.119.208.33.1.1 = STRING: "IPv4 Unicast"
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.7.1.3.2.16.32.1.20.56.7.0.0.39.0.0.0.0.0.0.0.1.2.1 = STRING: "IPv6 Unicast"
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.7.1.3.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = STRING: "IPv6 Unicast"
|
||||
#
|
||||
# CISCO-BGP4-MIB::CbgpPeer2Entry (IPv4)
|
||||
#
|
||||
# OMD[mysite]:~$ snmpwalk -ObentU -v2c -c <removed> simulant 1.3.6.1.4.1.9.9.187.1.2.5.1| grep 62.214.127.57
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.3.1.4.62.214.127.57 = INTEGER: 6
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.4.1.4.62.214.127.57 = INTEGER: 2
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.5.1.4.62.214.127.57 = INTEGER: 4
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.6.1.4.62.214.127.57 = Hex-STRING: 3E D6 7F 3A
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.7.1.4.62.214.127.57 = Gauge32: 29418
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.8.1.4.62.214.127.57 = Gauge32: 0
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.9.1.4.62.214.127.57 = IpAddress: 217.119.208.2
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.10.1.4.62.214.127.57 = Gauge32: 179
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.11.1.4.62.214.127.57 = Gauge32: 8881
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.12.1.4.62.214.127.57 = IpAddress: 62.214.127.57
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.13.1.4.62.214.127.57 = Counter32: 18
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.14.1.4.62.214.127.57 = Counter32: 2
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.15.1.4.62.214.127.57 = Counter32: 205
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.16.1.4.62.214.127.57 = Counter32: 195
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.17.1.4.62.214.127.57 = Hex-STRING: 00 00
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.18.1.4.62.214.127.57 = Counter32: 1
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.19.1.4.62.214.127.57 = Gauge32: 10446
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.20.1.4.62.214.127.57 = INTEGER: 60
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.21.1.4.62.214.127.57 = INTEGER: 180
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.22.1.4.62.214.127.57 = INTEGER: 60
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.23.1.4.62.214.127.57 = INTEGER: 180
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.24.1.4.62.214.127.57 = INTEGER: 60
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.25.1.4.62.214.127.57 = INTEGER: 30
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.26.1.4.62.214.127.57 = INTEGER: 30
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.27.1.4.62.214.127.57 = Gauge32: 5824
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.28.1.4.62.214.127.57 = ""
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.29.1.4.62.214.127.57 = INTEGER: 5
|
||||
#
|
||||
#
|
||||
# CISCO-BGP4-MIB::CbgpPeer2Entry (IPv6)
|
||||
#
|
||||
# OMD[mysite]:~$ snmpwalk -ObentU -v2c -c <removed> simulant 1.3.6.1.4.1.9.9.187.1.2.5.1| grep 16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.3.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = INTEGER: 6
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.4.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = INTEGER: 2
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.5.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = INTEGER: 4
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.6.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = Hex-STRING: 2A 05 57 C0 00 00 FF FF 00 00 00 00 00 00 00 11
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.7.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = Gauge32: 179
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.8.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = Gauge32: 0
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.9.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = IpAddress: 217.119.208.2
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.10.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = Gauge32: 35062
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.11.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = Gauge32: 31259
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.12.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = IpAddress: 217.119.208.1
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.13.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = Counter32: 5
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.14.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = Counter32: 6
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.15.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = Counter32: 157
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.16.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = Counter32: 161
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.17.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = Hex-STRING: 06 04
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.18.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = Counter32: 2
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.19.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = Gauge32: 8430
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.20.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = INTEGER: 60
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.21.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = INTEGER: 180
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.22.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = INTEGER: 60
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.23.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = INTEGER: 180
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.24.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = INTEGER: 60
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.25.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = INTEGER: 0
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.26.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = INTEGER: 0
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.27.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = Gauge32: 1494
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.28.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = STRING: "Administrative Reset"
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.5.1.29.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = INTEGER: 5
|
||||
#
|
||||
#
|
||||
# CISCO-BGP4-MIB::cbgpPeer2AddrFamilyPrefixEntry (IPv4)
|
||||
#
|
||||
# OMD[mysite]:~$ snmpwalk -ObentU -v2c -c <removed> simulant 1.3.6.1.4.1.9.9.187.1.2.8.1| grep 16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.8.1.1.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Counter32: 2
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.8.1.2.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 0
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.8.1.3.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 100000
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.8.1.4.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 85
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.8.1.5.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 80
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.8.1.6.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 10
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.8.1.7.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 0
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.8.1.8.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 0
|
||||
#
|
||||
#
|
||||
# CISCO-BGP4-MIB::cbgpPeer2AddrFamilyPrefixEntry (IPv6)
|
||||
#
|
||||
# OMD[mysite]:~$ snmpwalk -ObentU -v2c -c <removed> simulant 1.3.6.1.4.1.9.9.187.1.2.8.1| grep 16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.8.1.1.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Counter32: 2
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.8.1.2.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 0
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.8.1.3.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 100000
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.8.1.4.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 85
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.8.1.5.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 80
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.8.1.6.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 10
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.8.1.7.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 0
|
||||
# .1.3.6.1.4.1.9.9.187.1.2.8.1.8.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 0
|
||||
#
|
||||
#
|
||||
# sample info
|
||||
#
|
||||
# [
|
||||
# [
|
||||
# ['1.4.77.235.182.229', '6', '2', 'M\xeb\xb6\xe6', '0', '217.119.208.1', '21413', '77.235.182.229', '1', '3', '48',
|
||||
# '53', '\x04\x00', '8', '2581', '2581', 'hold time expired', '5'],
|
||||
# ['1.4.217.119.208.2', '6', '2', '\xd9w\xd0\x01', '0', '217.119.208.1', '31259', '217.119.208.2', '11', '23', '168',
|
||||
# '170', '\x06\x04', '3', '8380', '5774', 'Administrative Reset', '5'],
|
||||
# ['1.4.217.119.208.34', '6', '2', '\xd9w\xd0!', '0', '217.119.208.1', '31259', '217.119.208.2', '11', '23', '168',
|
||||
# '170', '\x06\x04', '3', '8377', '5774', 'Administrative Reset', '5'],
|
||||
# ['2.16.42.0.28.160.16.0.1.53.0.0.0.0.0.0.0.1', '6', '2', '*\x00\x1c\xa0\x10\x00\x015\x00\x00\x00\x00\x00\x00\x00\x02',
|
||||
# '0', '217.119.208.1', '21413', '77.235.182.229', '0', '4', '108', '121', '\x06\x04', '6', '6295', '0',
|
||||
# 'Administrative Reset', '5'],
|
||||
# ['2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.17', '6', '2', '*\x05W\xc0\x00\x00\xff\xff\x00\x00\x00\x00\x00\x00\x00\x10',
|
||||
# '0', '217.119.208.1', '31259', '217.119.208.2', '6', '5', '160', '157', '\x06\x04', '2', '8380', '1409',
|
||||
# 'Administrative Reset', '5']
|
||||
# ],
|
||||
# [
|
||||
# ['1.4.77.235.182.229.1.1', 'IPv4 Unicast', '1', '0', '', '', '', '6', '0', '0'],
|
||||
# ['1.4.217.119.208.2.1.1', 'IPv4 Unicast', '4', '0', '', '', '', '17', '0', '10'],
|
||||
# ['1.4.217.119.208.34.1.1', 'IPv4 Unicast', '4', '0', '', '', '', '17', '0', '10'],
|
||||
# ['2.16.42.0.28.160.16.0.1.53.0.0.0.0.0.0.0.1.2.1', 'IPv6 Unicast', '0', '0', '100000', '85', '80', '6', '0', '0'],
|
||||
# ['2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.17.2.1', 'IPv6 Unicast', '2', '0', '100000', '85', '80', '8', '0', '0']
|
||||
# ]
|
||||
# ]
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
from dataclasses import dataclass
|
||||
import re, time
|
||||
from typing import Mapping, Dict, List, Tuple, NamedTuple
|
||||
|
||||
from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
|
||||
DiscoveryResult,
|
||||
CheckResult,
|
||||
StringTable,
|
||||
)
|
||||
|
||||
from cmk.base.plugins.agent_based.agent_based_api.v1 import (
|
||||
register,
|
||||
Service,
|
||||
Result,
|
||||
check_levels,
|
||||
State,
|
||||
SNMPTree,
|
||||
contains,
|
||||
OIDEnd,
|
||||
get_rate,
|
||||
get_value_store,
|
||||
Metric,
|
||||
render,
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class Section:
|
||||
peer_prefixes: dict
|
||||
peer_table: dict
|
||||
|
||||
|
||||
###########################################################################
|
||||
#
|
||||
# DATA Parser function
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
|
||||
def parse_cisco_bgp_peer(string_table: List[StringTable]) -> Section:
|
||||
def bgp_render_ipv4_address(bytestring):
|
||||
return ".".join(["%s" % ord(m) for m in bytestring])
|
||||
|
||||
def bgp_shorten_ipv6_adress(address):
|
||||
address = address.split(':')
|
||||
span = 2
|
||||
address = [''.join(address[i:i + span]) for i in range(0, len(address), span)]
|
||||
for m in range(0, len(address)):
|
||||
address[m] = re.sub(r'^0{1,3}', r'', address[m])
|
||||
address = ':'.join(address)
|
||||
zeros = ':0:0:0:0:0:0:'
|
||||
while not zeros == '':
|
||||
if zeros in address:
|
||||
address = re.sub(r'%s' % zeros, r'::', address)
|
||||
zeros = ''
|
||||
else:
|
||||
zeros = zeros[:-2]
|
||||
return address
|
||||
|
||||
def bgp_render_ipv6_address(bytestring):
|
||||
address = ":".join(["%02s" % hex(ord(m))[2:] for m in bytestring]).replace(' ', '0').upper()
|
||||
address = bgp_shorten_ipv6_adress(address)
|
||||
|
||||
return address
|
||||
|
||||
def bgp_render_ip_address(bytestring):
|
||||
if len(bytestring) == 4:
|
||||
return bgp_render_ipv4_address(bytestring)
|
||||
elif len(bytestring) == 16:
|
||||
return bgp_render_ipv6_address(bytestring)
|
||||
else:
|
||||
return ''
|
||||
|
||||
def cisco_bgp_get_peer(OID_END):
|
||||
# returns peer address string from OID_END
|
||||
# u'1.4.217.119.208.34.1.1' --> 217.119.208.34
|
||||
# u'2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.17.2.1' --> 42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.17
|
||||
peer_ip = ''
|
||||
OID_END = OID_END.split('.')
|
||||
if int(len(OID_END)) == 7: # length of ip address
|
||||
peer_ip = '.'.join(OID_END[3:7]) # ipv4 address
|
||||
elif int(OID_END[1]) == 16: # ipv6 address
|
||||
peer_ip = ':'.join('%02s' % hex(int(m))[2:] for m in OID_END[2:18]).replace(' ', '0').upper()
|
||||
peer_ip = bgp_shorten_ipv6_adress(peer_ip)
|
||||
|
||||
return peer_ip
|
||||
|
||||
def cisco_bgp_errors(bytestring):
|
||||
lasterrorhex = ''.join(["%02X " % ord(x) for x in bytestring]).strip()
|
||||
byte1, byte2 = lasterrorhex.split()
|
||||
|
||||
names = {}
|
||||
names[0] = {0: 'NO ERROR'}
|
||||
names[1] = {0: 'Message',
|
||||
2: 'Connection Not Synchronized',
|
||||
3: 'Bad Message Length',
|
||||
4: 'Bad Message Type',
|
||||
}
|
||||
names[2] = {0: 'OPEN',
|
||||
1: 'Unsupported Version Number',
|
||||
2: 'Bad Peer AS',
|
||||
3: 'Bad BGP Identifier',
|
||||
4: 'Unsupported Optional Parameter',
|
||||
5: 'Authentication Failure',
|
||||
6: 'Unacceptable Hold',
|
||||
}
|
||||
names[3] = {0: 'UPDATE',
|
||||
1: 'Malformed Attribute List',
|
||||
2: 'Unrecognized Well-known Attribute',
|
||||
3: 'Missing Well-known Attribute',
|
||||
4: 'Attribute Flags Error',
|
||||
5: 'Attribute Length Error',
|
||||
6: 'Invalid ORIGIN Attribute',
|
||||
7: 'AS Routing Loop',
|
||||
8: 'Invalid NEXT_HOP Attribute',
|
||||
9: 'Optional Attribute Error',
|
||||
10: 'Invalid Network Field',
|
||||
11: 'Malformed AS_PATH',
|
||||
}
|
||||
names[4] = {0: 'Hold Timer Expired', }
|
||||
|
||||
names[5] = {0: 'Finite State Machine Error', }
|
||||
|
||||
names[6] = {0: 'Administratively Shutdown',
|
||||
1: 'Max Prefix Reached',
|
||||
2: 'Peer Unconfigured',
|
||||
3: 'Administratively Reset',
|
||||
4: 'Connection Rejected',
|
||||
5: 'Other Configuration Change',
|
||||
}
|
||||
|
||||
return names[int(byte1, 16)].get(int(byte2, 16))
|
||||
|
||||
# bgp not active
|
||||
if not string_table == [[], [], []]:
|
||||
|
||||
cbgpPeer2Entry, cbgpPeer3Entry, cbgpPeer2AddrFamily = string_table
|
||||
cbgpPeerEntry = cbgpPeer2Entry + cbgpPeer3Entry
|
||||
|
||||
peer_prefixes = {}
|
||||
# create dictionary from cbgpPeer2AddrFamily ('remoteip addrfamilyname' as index)
|
||||
if len(cbgpPeer2AddrFamily) > 0:
|
||||
for entry in cbgpPeer2AddrFamily:
|
||||
oid_end, addrfamilyname, acceptedprefixes, deniedprefixes, prefixadminlimit, prefixthreshold, \
|
||||
prefixclearthreshold, advertisedprefixes, suppressedprefixes, withdrawnprefixes = entry
|
||||
|
||||
remoteaddr = cisco_bgp_get_peer(entry[0])
|
||||
peer = {
|
||||
'remoteaddr': remoteaddr,
|
||||
'addrfamilyname': addrfamilyname
|
||||
}
|
||||
|
||||
for key, value in [
|
||||
('prefixadminlimit', prefixadminlimit),
|
||||
('prefixthreshold', prefixthreshold),
|
||||
('prefixclearthreshold', prefixclearthreshold),
|
||||
('acceptedprefixes', acceptedprefixes),
|
||||
('advertisedprefixes', advertisedprefixes),
|
||||
('deniedprefixes', deniedprefixes),
|
||||
('suppressedprefixes', suppressedprefixes),
|
||||
('withdrawnprefixes', withdrawnprefixes),
|
||||
]:
|
||||
try:
|
||||
peer[key] = int(value)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
peer_prefixes.update({'%s %s' % (remoteaddr, addrfamilyname): peer})
|
||||
|
||||
# workaround: get remote ip from cbgpPeerEntry if cbgpPeer2AddrFamilyName is missing :-(
|
||||
elif len(cbgpPeerEntry) > 0:
|
||||
for entry in cbgpPeerEntry:
|
||||
remoteaddr = cisco_bgp_get_peer(entry[0])
|
||||
addrfamilyname = ''
|
||||
|
||||
peer = {'remoteaddr': remoteaddr, }
|
||||
|
||||
peer_prefixes.update({'%s %s' % (remoteaddr, addrfamilyname): peer})
|
||||
|
||||
# create dictionary from cbgpPeerEntry (peer ip address as index)
|
||||
peer_table = {}
|
||||
for entry in cbgpPeerEntry:
|
||||
oid_end, state, adminstatus, localaddr, localas, localidentifier, remoteas, remoteidentifier, inupdates, \
|
||||
outupdates, intotalmessages, outtotalmessages, lasterror, fsmestablishedtransitions, fsmestablishedtime, \
|
||||
inupdateelapsedtime, lasterrortxt, prevstate = entry
|
||||
|
||||
peer = {'remoteaddr': cisco_bgp_get_peer(oid_end),
|
||||
'localaddr': bgp_render_ip_address(localaddr),
|
||||
'localid': localidentifier,
|
||||
'remoteid': remoteidentifier,
|
||||
'lasterror': cisco_bgp_errors(lasterror),
|
||||
'lasterrortxt': lasterrortxt,
|
||||
'prevstate': int(prevstate),
|
||||
}
|
||||
|
||||
for key, value in [
|
||||
('state', state),
|
||||
('adminstate', adminstatus),
|
||||
('localas', localas),
|
||||
('remoteas', remoteas),
|
||||
('inupdates', inupdates),
|
||||
('outupdates', outupdates),
|
||||
('intotalmessages', intotalmessages),
|
||||
('outtotalmessages', outtotalmessages),
|
||||
('fsmestablishedtransitions', fsmestablishedtransitions),
|
||||
('fsmestablishedtime', fsmestablishedtime),
|
||||
('inupdateelapsedtime', inupdateelapsedtime),
|
||||
]:
|
||||
try:
|
||||
peer[key] = int(value)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
peer_table.update({'%s' % cisco_bgp_get_peer(oid_end): peer})
|
||||
|
||||
return Section(
|
||||
peer_prefixes=peer_prefixes,
|
||||
peer_table=peer_table,
|
||||
)
|
||||
|
||||
|
||||
###########################################################################
|
||||
#
|
||||
# INVENTORY function
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
|
||||
def discovery_cisco_bgp_peer(section: Section) -> DiscoveryResult:
|
||||
for key in section.peer_prefixes.keys():
|
||||
yield Service(item=key)
|
||||
|
||||
|
||||
###########################################################################
|
||||
#
|
||||
# CHECK function
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
|
||||
def check_cisco_bgp_peer(item, params, section) -> CheckResult:
|
||||
def cisco_bgp_adminstate(state):
|
||||
names = {1: 'stop',
|
||||
2: 'start', }
|
||||
return names.get(state, 'unknown (%s)' % state)
|
||||
|
||||
def cisco_bgp_peerstate(state):
|
||||
names = {0: 'none',
|
||||
1: 'idle',
|
||||
2: 'connect',
|
||||
3: 'active',
|
||||
4: 'opensned',
|
||||
5: 'openconfirm',
|
||||
6: 'established'}
|
||||
return names.get(state, 'unknown (%s)' % state)
|
||||
|
||||
peer_prefixes = section.peer_prefixes
|
||||
peer_table = section.peer_table
|
||||
|
||||
prefixes = peer_prefixes.get(item, None)
|
||||
|
||||
alias = ''
|
||||
peer_not_found_state = 3
|
||||
|
||||
for bgp_connection, bgp_alias, not_found_state in params.get('peer_list', []):
|
||||
if item == bgp_connection:
|
||||
alias = bgp_alias
|
||||
peer_not_found_state = not_found_state
|
||||
|
||||
if prefixes:
|
||||
longoutput = ''
|
||||
|
||||
peer = peer_table.get(prefixes.get('remoteaddr'))
|
||||
|
||||
if peer.get('localas') == 0:
|
||||
peer.update({'localas': params.get('useaslocalas')})
|
||||
|
||||
if alias != '':
|
||||
yield Result(state=State.OK, summary='Alias: %s' % alias)
|
||||
|
||||
peerstate = peer.get('state')
|
||||
adminstate = peer.get('adminstate')
|
||||
establishedtime = peer.get('fsmestablishedtime')
|
||||
|
||||
if peerstate == 1: # idle
|
||||
yield Result(state=State.CRIT, summary='Peer state: %s' % cisco_bgp_peerstate(peerstate))
|
||||
elif peerstate == 6: # established
|
||||
yield from check_levels(
|
||||
value=establishedtime,
|
||||
label='Uptime',
|
||||
levels_lower=params['minuptime'],
|
||||
render_func=render.timespan
|
||||
)
|
||||
|
||||
else: # everything else
|
||||
yield Result(state=State.WARN, summary='Peer state: %s' % cisco_bgp_peerstate(peerstate))
|
||||
|
||||
if not adminstate == 2: # not start
|
||||
yield Result(state=State.WARN, summary='Admin state: %s' % cisco_bgp_adminstate(adminstate))
|
||||
|
||||
for key, value in [
|
||||
('remoteid', 'Remote ID: %s'),
|
||||
('remoteas', 'Remote AS: %s'),
|
||||
('localaddr', 'Local address: %s'),
|
||||
('localid', 'Local ID: %s'),
|
||||
('localas', 'Local AS: %s'),
|
||||
]:
|
||||
if key in params['infotext_values']:
|
||||
try:
|
||||
yield Result(state=State.OK, summary=value % peer[key])
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
bgptype = ''
|
||||
if not peer.get('localas') == 0:
|
||||
if peer.get('remoteas') == peer.get('localas'):
|
||||
bgptype = ' (iBGP)'
|
||||
else:
|
||||
bgptype = ' (eBGP)'
|
||||
|
||||
longoutput_data = [
|
||||
['IP-address (remote/local)', peer.get('remoteaddr'), peer.get('localaddr')],
|
||||
['Router-ID (remote/local)', peer.get('remoteid'), peer.get('localid')],
|
||||
['Autonomus System (remote/local)', peer.get('remoteas'), str(peer.get('localas')) + bgptype],
|
||||
['State', cisco_bgp_peerstate(peerstate), ''],
|
||||
['Admin state', cisco_bgp_adminstate(adminstate), ''],
|
||||
['Last error', peer.get('lasterror'), ''],
|
||||
['Last error text', peer.get('lasterrortxt'), ''],
|
||||
['Previous state', cisco_bgp_peerstate(peer.get('prevstate')), ''],
|
||||
['Address family name', prefixes.get('addrfamilyname', 'unknown'), ''],
|
||||
['Prefix clear threshold (%)', '%.0d' % prefixes.get('prefixclearthreshold', 0), '']
|
||||
,
|
||||
]
|
||||
|
||||
acceptedprefixes = prefixes.get('acceptedprefixes', None)
|
||||
prefixadminlimit = prefixes.get('prefixadminlimit', None)
|
||||
prefixthreshold = prefixes.get('prefixthreshold', None)
|
||||
|
||||
if prefixadminlimit is not None and prefixthreshold is not None:
|
||||
warnthreshold = prefixadminlimit / 100.0 * prefixthreshold # use float (100.0) to get xx.xx in division
|
||||
longoutput_data.append(['Prefix admin limit (prefixes)', '%.0d' % prefixadminlimit, ''])
|
||||
longoutput_data.append(['Prefix threshold (prefixes/%)', '%.0d' % warnthreshold, '%.0d' % prefixthreshold])
|
||||
else:
|
||||
yield Result(state=State(params['noprefixlimit']), notice='No admin prefix limit/warn threshold configured on the device.')
|
||||
warnthreshold = None
|
||||
|
||||
if params.get('htmloutput', False):
|
||||
#
|
||||
# disable 'Escape HTML codes in plugin output' in wato --> global settings
|
||||
#
|
||||
table_bracket = '<table border="1">%s</table>'
|
||||
line_bracket = '<tr>%s</tr>'
|
||||
cell_bracket = '<td>%s</td><td>%s</td><td>%s</td>'
|
||||
cell_seperator = ''
|
||||
|
||||
longoutput = '\n' + table_bracket % (''.join(
|
||||
[line_bracket % cell_seperator.join([cell_bracket % (entry[0], entry[1], entry[2])]) for entry in
|
||||
longoutput_data]))
|
||||
else:
|
||||
longoutput += '\nfor nicer output' \
|
||||
'\ndisable \'Escape HTML codes in plugin output\' in wato -> global settings and enable HTML output in \'Parameters for this service\''
|
||||
for entry in longoutput_data:
|
||||
if not entry[2] == '':
|
||||
longoutput += '\n{}: {} / {}'.format(entry[0], entry[1], entry[2])
|
||||
else:
|
||||
longoutput += '\n{}: {}'.format(entry[0], entry[1])
|
||||
|
||||
if prefixadminlimit is not None:
|
||||
yield from check_levels(
|
||||
value=acceptedprefixes,
|
||||
metric_name='cisco_bgp_peer_acceptedprefixes',
|
||||
levels_upper=(warnthreshold, prefixadminlimit),
|
||||
label='Prefixes accepted',
|
||||
render_func=lambda v: '%s' % str(v)
|
||||
)
|
||||
|
||||
now_time = time.time()
|
||||
value_store = get_value_store()
|
||||
rate_item = item.replace(' ', '_').replace(':', '_')
|
||||
|
||||
for key in [
|
||||
'deniedprefixes',
|
||||
'advertisedprefixes',
|
||||
'withdrawnprefixes',
|
||||
'suppressedprefixes',
|
||||
'inupdates',
|
||||
'outupdates',
|
||||
'intotalmessages',
|
||||
'outtotalmessages',
|
||||
]:
|
||||
try:
|
||||
value = get_rate(value_store, 'cisco_bgp_peer.%s.%s' % (key, rate_item), now_time, prefixes[key],
|
||||
raise_overflow=False)
|
||||
yield Metric(name='cisco_bgp_peer_%s' % key, value=value, boundaries=(0, None))
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
for key in [
|
||||
'fsmestablishedtransitions',
|
||||
'fsmestablishedtime',
|
||||
'inupdateelapsedtime'
|
||||
]:
|
||||
try:
|
||||
yield Metric(name='cisco_bgp_peer_%s' % key, value=peer[key], boundaries=(0, None))
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
yield Result(state=State.OK, notice=longoutput)
|
||||
else:
|
||||
if alias != '':
|
||||
yield Result(state=State.OK, summary=', Alias: %s' % alias)
|
||||
yield Result(state=State(peer_not_found_state), summary='Item not found in SNMP data')
|
||||
|
||||
|
||||
###########################################################################
|
||||
#
|
||||
# CHECK info
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
register.snmp_section(
|
||||
name='cisco_bgp_peer',
|
||||
parse_function=parse_cisco_bgp_peer,
|
||||
fetch=[
|
||||
SNMPTree(
|
||||
base='.1.3.6.1.4.1.9.9.187.1.2.5.1', # CCISCO-BGP4-MIB::cbgpPeer2Entry
|
||||
oids=[
|
||||
OIDEnd(),
|
||||
'3', # cbgpPeer2State
|
||||
'4', # cbgpPeer2AdminStatus
|
||||
'6', # cbgpPeer2LocalAddr
|
||||
'8', # cbgpPeer2LocalAs -> empty
|
||||
'9', # cbgpPeer2LocalIdentifier
|
||||
'11', # cbgpPeer2RemoteAs
|
||||
'12', # cbgpPeer2RemoteIdentifier
|
||||
'13', # cbgpPeer2InUpdates
|
||||
'14', # cbgpPeer2OutUpdates
|
||||
'15', # cbgpPeer2InTotalMessages
|
||||
'16', # cbgpPeer2OutTotalMessages
|
||||
'17', # cbgpPeer2LastError
|
||||
'18', # cbgpPeer2FsmEstablishedTransitions
|
||||
'19', # cbgpPeer2FsmEstablishedTime
|
||||
'27', # cbgpPeer2InUpdateElapsedTime
|
||||
'28', # cbgpPeer2LastErrorTxt
|
||||
'29', # cbgpPeer2PrevState
|
||||
]
|
||||
),
|
||||
SNMPTree(
|
||||
base='.1.3.6.1.4.1.9.9.187.1.2.9.1', # CCISCO-BGP4-MIB::cbgpPeer3Entry
|
||||
oids=[
|
||||
OIDEnd(),
|
||||
'5', # cbgpPeer3State
|
||||
'6', # cbgpPeer3AdminStatus
|
||||
'8', # cbgpPeer3LocalAddr
|
||||
'10', # cbgpPeer3LocalAs -> empty
|
||||
'11', # cbgpPeer3LocalIdentifier
|
||||
'13', # cbgpPeer3RemoteAs
|
||||
'14', # cbgpPeer3RemoteIdentifier
|
||||
'15', # cbgpPeer3InUpdates
|
||||
'16', # cbgpPeer3OutUpdates
|
||||
'17', # cbgpPeer3InTotalMessages
|
||||
'18', # cbgpPeer3OutTotalMessages
|
||||
'19', # cbgpPeer3LastError
|
||||
'20', # cbgpPeer3FsmEstablishedTransitions
|
||||
'21', # cbgpPeer3FsmEstablishedTime
|
||||
'29', # cbgpPeer3InUpdateElapsedTime
|
||||
'30', # cbgpPeer3LastErrorTxt
|
||||
'31', # cbgpPeer3PrevState
|
||||
]
|
||||
),
|
||||
SNMPTree(
|
||||
base='.1.3.6.1.4.1.9.9.187.1.2', # cbgpPeer
|
||||
oids=[
|
||||
OIDEnd(), #
|
||||
# .7.1 --> cbgpPeer2AddrFamilyEntry
|
||||
'7.1.3', # cbgpPeer2AddrFamilyName
|
||||
# .8.1 --> cbgpPeer2AddrFamilyPrefixEntry
|
||||
'8.1.1', # cbgpPeer2AcceptedPrefixes
|
||||
'8.1.2', # cbgpPeer2DeniedPrefixes
|
||||
'8.1.3', # cbgpPeer2PrefixAdminLimit
|
||||
'8.1.4', # cbgpPeer2PrefixThreshold
|
||||
'8.1.5', # cbgpPeer2PrefixClearThreshold
|
||||
'8.1.6', # cbgpPeer2AdvertisedPrefixes
|
||||
'8.1.7', # cbgpPeer2SuppressedPrefixes
|
||||
'8.1.8', # cbgpPeer2WithdrawnPrefixes
|
||||
]
|
||||
)
|
||||
],
|
||||
detect=contains('.1.3.6.1.2.1.1.1.0', 'Cisco'),
|
||||
)
|
||||
|
||||
register.check_plugin(
|
||||
name='cisco_bgp_peer',
|
||||
service_name='Cisco BGP peer %s',
|
||||
discovery_function=discovery_cisco_bgp_peer,
|
||||
check_function=check_cisco_bgp_peer,
|
||||
check_default_parameters={
|
||||
'minuptime': (7200, 3600),
|
||||
'useaslocalas': 0,
|
||||
'htmloutput': False,
|
||||
'noprefixlimit': 1,
|
||||
'infotext_values': [],
|
||||
'peer_list': [],
|
||||
},
|
||||
check_ruleset_name='cisco_bgp_peer',
|
||||
)
|
@ -0,0 +1,178 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# License: GNU General Public License v2
|
||||
#
|
||||
# Author: thl-cmk[at]outlook[dot]com
|
||||
# URL : https://thl-cmk.hopto.org
|
||||
# Date : 2017-12-26
|
||||
#
|
||||
# Cisco BGP Peer metrics plugin
|
||||
#
|
||||
# 2018-05-25: cleanup
|
||||
# 2020-09-10: fixed typo FMS --> FSM (Thanks martin[dot]pechstein[at]posteo[dot]de)
|
||||
# 2021-03-27: rewrite for CMK 2.0
|
||||
#
|
||||
from cmk.gui.i18n import _
|
||||
|
||||
from cmk.gui.plugins.metrics import (
|
||||
metric_info,
|
||||
graph_info,
|
||||
perfometer_info
|
||||
)
|
||||
|
||||
|
||||
#####################################################################################################################
|
||||
#
|
||||
# define metrics for bgp peer perfdata
|
||||
#
|
||||
#####################################################################################################################
|
||||
|
||||
metric_info['cisco_bgp_peer_acceptedprefixes'] = {
|
||||
'title': _('Prefixes accepted'),
|
||||
'help': _('number of accepted prefixes'),
|
||||
'unit': 'count',
|
||||
'color': '11/a',
|
||||
}
|
||||
metric_info['cisco_bgp_peer_deniedprefixes'] = {
|
||||
'title': _('Prefixes denied'),
|
||||
'unit': '1/s',
|
||||
'color': '21/a',
|
||||
}
|
||||
metric_info['cisco_bgp_peer_advertisedprefixes'] = {
|
||||
'title': _('Prefixes advertised'),
|
||||
'unit': '1/s',
|
||||
'color': '31/a',
|
||||
}
|
||||
metric_info['cisco_bgp_peer_withdrawnprefixes'] = {
|
||||
'title': _('Prefixes withdrawn'),
|
||||
'unit': '1/s',
|
||||
'color': '41/a',
|
||||
}
|
||||
metric_info['cisco_bgp_peer_suppressedprefixes'] = {
|
||||
'title': _('Prefixes suppressed'),
|
||||
'unit': '1/s',
|
||||
'color': '12/a',
|
||||
}
|
||||
metric_info['cisco_bgp_peer_inupdates'] = {
|
||||
'title': _('Updates received'),
|
||||
'unit': '1/s',
|
||||
'color': '22/a',
|
||||
}
|
||||
metric_info['cisco_bgp_peer_outupdates'] = {
|
||||
'title': _('Updates send'),
|
||||
'unit': '1/s',
|
||||
'color': '32/a',
|
||||
}
|
||||
metric_info['cisco_bgp_peer_intotalmessages'] = {
|
||||
'title': _('Total messages received'),
|
||||
'unit': '1/s',
|
||||
'color': '42/a',
|
||||
}
|
||||
metric_info['cisco_bgp_peer_outtotalmessages'] = {
|
||||
'title': _('Total messages send'),
|
||||
'unit': '1/s',
|
||||
'color': '13/a',
|
||||
}
|
||||
metric_info['cisco_bgp_peer_fsmestablishedtransitions'] = {
|
||||
'title': _('FSM transitions'),
|
||||
'unit': 'count',
|
||||
'color': '23/a',
|
||||
}
|
||||
metric_info['cisco_bgp_peer_fsmestablishedtime'] = {
|
||||
'title': _('FSM last change'),
|
||||
'unit': 's',
|
||||
'color': '26/a',
|
||||
}
|
||||
metric_info['cisco_bgp_peer_inupdateelapsedtime'] = {
|
||||
'title': _('Last update received'),
|
||||
'unit': 's',
|
||||
'color': '43/a',
|
||||
}
|
||||
|
||||
|
||||
######################################################################################################################
|
||||
#
|
||||
# how to graph perdata for bgp peer
|
||||
#
|
||||
######################################################################################################################
|
||||
|
||||
graph_info['cisco_bgp_peer.prefixes_accepted']={
|
||||
'title': _('Accepted Prefixes'),
|
||||
'metrics': [
|
||||
('cisco_bgp_peer_acceptedprefixes', 'line'),
|
||||
],
|
||||
'scalars': [
|
||||
('cisco_bgp_peer_acceptedprefixes:crit', _('crit')),
|
||||
('cisco_bgp_peer_acceptedprefixes:warn', _('warn')),
|
||||
],
|
||||
}
|
||||
|
||||
graph_info['cisco_bgp_peer.prefixes_per_second']={
|
||||
'title': _('Prefixes/s'),
|
||||
'metrics': [
|
||||
('cisco_bgp_peer_deniedprefixes', 'line'),
|
||||
('cisco_bgp_peer_advertisedprefixes', 'line'),
|
||||
('cisco_bgp_peer_withdrawnprefixes', 'line'),
|
||||
('cisco_bgp_peer_suppressedprefixes', 'line'),
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
graph_info['cisco_bgp_peer.updates_in_out']={
|
||||
'title': _('Updates'),
|
||||
'metrics': [
|
||||
('cisco_bgp_peer_inupdates', 'area'),
|
||||
('cisco_bgp_peer_outupdates', '-area'),
|
||||
]
|
||||
}
|
||||
|
||||
graph_info['cisco_bgp_peer.messages_in_out']={
|
||||
'title': _('Total messages'),
|
||||
'metrics': [
|
||||
('cisco_bgp_peer_intotalmessages', 'area'),
|
||||
('cisco_bgp_peer_outtotalmessages', '-area'),
|
||||
]
|
||||
}
|
||||
|
||||
graph_info['cisco_bgp_peer.fms_transitions_from_to']={
|
||||
'title': _('FSM transitions from/to established'),
|
||||
'metrics': [
|
||||
('cisco_bgp_peer_fsmestablishedtransitions', 'line'),
|
||||
],
|
||||
}
|
||||
|
||||
graph_info['cisco_bgp_peer.fms_transitions_last_change']={
|
||||
'title': _('FSM established last change'),
|
||||
'metrics': [
|
||||
('cisco_bgp_peer_fsmestablishedtime', 'line'),
|
||||
]
|
||||
}
|
||||
|
||||
graph_info['cisco_bgp_peer.time_since_last_update']={
|
||||
'title': _('Time since last update received'),
|
||||
'metrics': [
|
||||
('cisco_bgp_peer_inupdateelapsedtime', 'line'),
|
||||
]
|
||||
}
|
||||
|
||||
######################################################################################################################
|
||||
#
|
||||
# define perf-o-meter for bgp peer uptime + prefixes accepted/advertised
|
||||
#
|
||||
######################################################################################################################
|
||||
|
||||
perfometer_info.append(('stacked', [
|
||||
{
|
||||
'type': 'logarithmic',
|
||||
'metric': 'cisco_bgp_peer_fsmestablishedtime',
|
||||
'half_value': 2592000.0, # ome month
|
||||
'exponent': 2,
|
||||
},
|
||||
{
|
||||
'type': 'logarithmic',
|
||||
'metric': 'cisco_bgp_peer_acceptedprefixes',
|
||||
'half_value': 500000.0,
|
||||
'exponent': 2,
|
||||
}
|
||||
]))
|
@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# License: GNU General Public License v2
|
||||
#
|
||||
# Author: thl-cmk[at]outlook[dot]com
|
||||
# URL : https://thl-cmk.hopto.org
|
||||
# Date : 2017-12-25
|
||||
#
|
||||
# Check_MK cisco_bgp_peers WATO plugin
|
||||
#
|
||||
# 2021-03-27: rewrite for CMK 2.0
|
||||
#
|
||||
|
||||
from cmk.gui.i18n import _
|
||||
from cmk.gui.valuespec import (
|
||||
Dictionary,
|
||||
Integer,
|
||||
TextAscii,
|
||||
ListOfStrings,
|
||||
FixedValue,
|
||||
ListChoice,
|
||||
ListOf,
|
||||
Tuple,
|
||||
TextUnicode,
|
||||
MonitoringState,
|
||||
)
|
||||
|
||||
from cmk.gui.plugins.wato import (
|
||||
CheckParameterRulespecWithItem,
|
||||
rulespec_registry,
|
||||
RulespecGroupCheckParametersNetworking,
|
||||
)
|
||||
|
||||
cisco_bgp_peer_infotext_values = [
|
||||
('remoteid', 'Remote router ID'),
|
||||
('remoteas', 'Remote autonomous system'),
|
||||
('localaddr', 'Local peer IP address'),
|
||||
('localid', 'Local router ID'),
|
||||
('localas', 'Local autonomous system'),
|
||||
]
|
||||
|
||||
|
||||
def _parameter_valuespec_cisco_bgp_peer():
|
||||
return Dictionary(elements=[
|
||||
('minuptime',
|
||||
Tuple(
|
||||
title=_('Minimum uptime for peer'),
|
||||
help=_('Set the time in seconds, a peer must be up before the peer is considered sable.'
|
||||
'If the peer uptime less then X, the check outcome is set to warning.'),
|
||||
elements=[
|
||||
Integer(title=_('Warning if below'), unit='seconds', default_value=7200, minvalue=0),
|
||||
Integer(title=_('Critical if below'), unit='seconsa', default_value=3600, minvalue=0)
|
||||
],
|
||||
),
|
||||
),
|
||||
('useaslocalas',
|
||||
Integer(
|
||||
help=_('Use this AS number if the SNMP Value for CISCO-BGP4-MIB::cbgpPeer2LocalAs is \'0\'.'),
|
||||
title=_('Use AS as local AS, if SNMP cbgpPeer2LocalAs is not valid.'),
|
||||
default_value=0,
|
||||
# allow_empty=False,
|
||||
),
|
||||
),
|
||||
('htmloutput',
|
||||
FixedValue(
|
||||
True,
|
||||
help=_('render long output of check plugin (multiline) as HTML table. Needs \'Escape HTML codes in plugin output\' in wato --> global settings disabled'),
|
||||
title=_('enable HTML Output for long output of check plugin (multiline)'),
|
||||
totext=_('enable HTML Output for long output of check plugin (multiline)'),
|
||||
default_value=False,
|
||||
)),
|
||||
('noprefixlimit',
|
||||
MonitoringState(
|
||||
default_value=1,
|
||||
title=_('State if no admin prefix limit/warn threshold configured.'),
|
||||
help=_('The admin prefix limit and warn threshold needs to be configured on the device. '
|
||||
'For example: neighbor 172.17.10.10 maximum-prefix 10000 80. The threshold is in percentage '
|
||||
'of the prefix limit')
|
||||
)),
|
||||
('infotext_values',
|
||||
ListChoice(
|
||||
title=_('Add values to check info'),
|
||||
help=_('Select values to add to the check output.'),
|
||||
choices=cisco_bgp_peer_infotext_values,
|
||||
default_value=[],
|
||||
)),
|
||||
('peer_list',
|
||||
ListOf(
|
||||
Tuple(
|
||||
# title=('BGP Peers'),
|
||||
elements=[
|
||||
TextUnicode(
|
||||
title=_('BGP Peer item name (without "Cisco BGP peer")'),
|
||||
help=_('The configured value must match a BGP item reported by the monitored '
|
||||
'device. For example: "10.194.115.98 IPv4 Unicast"'),
|
||||
allow_empty=False,
|
||||
),
|
||||
TextUnicode(
|
||||
title=_('BGP Peer Alias'),
|
||||
help=_('You can configure an individual alias here for the BGP peer matching '
|
||||
'the text configured in the "BGP Peer item name" field. The alias will '
|
||||
'be shown in the infotext'),
|
||||
),
|
||||
MonitoringState(
|
||||
default_value=2,
|
||||
title=_('State if not found'),
|
||||
help=_('You can configure an individual state if the BGP peer matching the text '
|
||||
'configured in the "BGP Peer item name" field is not found')
|
||||
),
|
||||
]),
|
||||
add_label=_('Add BGP peer'),
|
||||
movable=False,
|
||||
title=_('BGP Peers'),
|
||||
)),
|
||||
])
|
||||
|
||||
rulespec_registry.register(
|
||||
CheckParameterRulespecWithItem(
|
||||
check_group_name='cisco_bgp_peer',
|
||||
group=RulespecGroupCheckParametersNetworking,
|
||||
item_spec=lambda: TextAscii(title=_('BGP peer specific configuration'), ),
|
||||
match_type='dict',
|
||||
parameter_valuespec=_parameter_valuespec_cisco_bgp_peer,
|
||||
title=lambda: _('Cisco BGP peer'),
|
||||
))
|
1
check_mk-cisco_gdoi/README.md
Normal file
1
check_mk-cisco_gdoi/README.md
Normal file
@ -0,0 +1 @@
|
||||
This plugin checks the registration status (and KEK key timeout) of GDOI Group Members with GDOI Key Servers.
|
BIN
check_mk-cisco_gdoi/cisco_gdoi-1.1.0.mkp
Executable file
BIN
check_mk-cisco_gdoi/cisco_gdoi-1.1.0.mkp
Executable file
Binary file not shown.
@ -0,0 +1,98 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# More information about this Cisco system:
|
||||
# https://www.cisco.com/en/US/docs/ios-xml/ios/sec_conn_getvpn/configuration/15-2mt/sec-get-vpn.html
|
||||
#
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Dict, List
|
||||
|
||||
from cmk.base.plugins.agent_based.agent_based_api.v1 import (
|
||||
register,
|
||||
Service,
|
||||
Result,
|
||||
State,
|
||||
SNMPTree,
|
||||
contains,
|
||||
OIDEnd,
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class Section:
|
||||
kek_info: dict
|
||||
|
||||
def chars_to_ip_addr(chars):
|
||||
return ".".join(map(lambda c: str(ord(c)), [*chars]))
|
||||
|
||||
conversions = {
|
||||
"1": "using",
|
||||
"2": "new",
|
||||
"3": "old",
|
||||
}
|
||||
|
||||
# SNMP parsing function
|
||||
def parse_cisco_gdoi(string_table):
|
||||
def parse(data):
|
||||
lookup = {}
|
||||
|
||||
for val in data:
|
||||
ip = chars_to_ip_addr(val[0])
|
||||
remaining = int(val[1])
|
||||
state = conversions[val[2]]
|
||||
|
||||
lookup.setdefault(ip, {})
|
||||
lookup[ip][state] = remaining
|
||||
|
||||
return lookup
|
||||
|
||||
if string_table == [[]]:
|
||||
return
|
||||
|
||||
return Section(
|
||||
kek_info=parse(string_table[0]),
|
||||
)
|
||||
|
||||
# Inventory function, returning inventory based upon SNMP parsed result above
|
||||
def discovery_cisco_gdoi(section):
|
||||
yield Service(item="Keyservers", parameters=section.kek_info)
|
||||
|
||||
# Check function, returning ok/crit based upon SNMP parsed result above
|
||||
def check_cisco_gdoi(item, params, section):
|
||||
state = params
|
||||
registered = False
|
||||
|
||||
for ip, state in params.items():
|
||||
in_use = state.get("using")
|
||||
|
||||
if in_use > 0:
|
||||
registered = True
|
||||
yield Result(state=State.OK, summary="Registered, using KEK from " + ip)
|
||||
|
||||
if not registered:
|
||||
yield Result(state=State.CRIT, summary="Unregistered")
|
||||
|
||||
register.snmp_section(
|
||||
name="cisco_gdoi",
|
||||
parse_function=parse_cisco_gdoi,
|
||||
fetch=[
|
||||
SNMPTree(
|
||||
# ciscoGdoiMIB::cgmGdoiGmKekRemainingLifetime
|
||||
base=".1.3.6.1.4.1.9.9.759.1.3.2.1",
|
||||
oids=[
|
||||
"5", # cgmGdoiGmKekSrcIdValue
|
||||
"20", # cgmGdoiGmKekRemainingLifetime
|
||||
"21", # cgmGdoiGmKekStatus
|
||||
]
|
||||
),
|
||||
],
|
||||
detect=contains(".1.3.6.1.2.1.1.1.0", "Cisco"),
|
||||
)
|
||||
|
||||
register.check_plugin(
|
||||
name="cisco_gdoi",
|
||||
service_name="Cisco GDOI %s",
|
||||
discovery_function=discovery_cisco_gdoi,
|
||||
check_function=check_cisco_gdoi,
|
||||
check_default_parameters={},
|
||||
check_ruleset_name="cisco_gdoi",
|
||||
)
|
1
check_mk-cisco_ip_sla/README.md
Normal file
1
check_mk-cisco_ip_sla/README.md
Normal file
@ -0,0 +1 @@
|
||||
This is a modification of a Tribe29 GPL plugin to support tracking packet loss as well.
|
BIN
check_mk-cisco_ip_sla/cisco_ip_sla-1.0.1.mkp
Normal file
BIN
check_mk-cisco_ip_sla/cisco_ip_sla-1.0.1.mkp
Normal file
Binary file not shown.
@ -0,0 +1,208 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2019 tribe29 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.
|
||||
|
||||
from cmk.gui.i18n import _
|
||||
from cmk.gui.plugins.wato.utils import (
|
||||
CheckParameterRulespecWithItem,
|
||||
rulespec_registry,
|
||||
RulespecGroupCheckParametersNetworking,
|
||||
)
|
||||
from cmk.gui.valuespec import Dictionary, DropdownChoice, Integer, TextInput, Tuple
|
||||
|
||||
|
||||
def _item_spec_cisco_ip_sla():
|
||||
return TextInput(
|
||||
title=_("RTT row index of the service"),
|
||||
allow_empty=True,
|
||||
)
|
||||
|
||||
|
||||
def _parameter_valuespec_cisco_ip_sla():
|
||||
return Dictionary(
|
||||
elements=[
|
||||
(
|
||||
"rtt_type",
|
||||
DropdownChoice(
|
||||
title=_("RTT type"),
|
||||
choices=[
|
||||
("echo", _("echo")),
|
||||
("path echo", _("path echo")),
|
||||
("file IO", _("file IO")),
|
||||
("UDP echo", _("UDP echo")),
|
||||
("TCP connect", _("TCP connect")),
|
||||
("HTTP", _("HTTP")),
|
||||
("DNS", _("DNS")),
|
||||
("jitter", _("jitter")),
|
||||
("DLSw", _("DLSw")),
|
||||
("DHCP", _("DHCP")),
|
||||
("FTP", _("FTP")),
|
||||
("VoIP", _("VoIP")),
|
||||
("RTP", _("RTP")),
|
||||
("LSP group", _("LSP group")),
|
||||
("ICMP jitter", _("ICMP jitter")),
|
||||
("LSP ping", _("LSP ping")),
|
||||
("LSP trace", _("LSP trace")),
|
||||
("ethernet ping", _("ethernet ping")),
|
||||
("ethernet jitter", _("ethernet jitter")),
|
||||
("LSP ping pseudowire", _("LSP ping pseudowire")),
|
||||
],
|
||||
default_value="echo",
|
||||
),
|
||||
),
|
||||
(
|
||||
"threshold",
|
||||
Integer(
|
||||
title=_("Treshold"),
|
||||
help=_(
|
||||
"Depending on the precision the unit can be "
|
||||
"either milliseconds or micoseconds."
|
||||
),
|
||||
unit=_("ms/us"),
|
||||
minvalue=1,
|
||||
default_value=5000,
|
||||
),
|
||||
),
|
||||
(
|
||||
"state",
|
||||
DropdownChoice(
|
||||
title=_("State"),
|
||||
choices=[
|
||||
("active", _("active")),
|
||||
("inactive", _("inactive")),
|
||||
("reset", _("reset")),
|
||||
("orderly stop", _("orderly stop")),
|
||||
("immediate stop", _("immediate stop")),
|
||||
("pending", _("pending")),
|
||||
("restart", _("restart")),
|
||||
],
|
||||
default_value="active",
|
||||
),
|
||||
),
|
||||
(
|
||||
"connection_lost_occured",
|
||||
DropdownChoice(
|
||||
title=_("Connection lost occured"),
|
||||
choices=[
|
||||
("yes", _("yes")),
|
||||
("no", _("no")),
|
||||
],
|
||||
default_value="no",
|
||||
),
|
||||
),
|
||||
(
|
||||
"timeout_occured",
|
||||
DropdownChoice(
|
||||
title=_("Timeout occured"),
|
||||
choices=[
|
||||
("yes", _("yes")),
|
||||
("no", _("no")),
|
||||
],
|
||||
default_value="no",
|
||||
),
|
||||
),
|
||||
(
|
||||
"completion_time_over_treshold_occured",
|
||||
DropdownChoice(
|
||||
title=_("Completion time over treshold occured"),
|
||||
choices=[
|
||||
("yes", _("yes")),
|
||||
("no", _("no")),
|
||||
],
|
||||
default_value="no",
|
||||
),
|
||||
),
|
||||
(
|
||||
"latest_rtt_completion_time",
|
||||
Tuple(
|
||||
title=_("Latest RTT completion time"),
|
||||
help=_(
|
||||
"Depending on the precision the unit can be "
|
||||
"either milliseconds or micoseconds."
|
||||
),
|
||||
elements=[
|
||||
Integer(
|
||||
title=_("Warning at"),
|
||||
unit=_("ms/us"),
|
||||
minvalue=1,
|
||||
default_value=100,
|
||||
),
|
||||
Integer(
|
||||
title=_("Critical at"),
|
||||
unit=_("ms/us"),
|
||||
minvalue=1,
|
||||
default_value=200,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
(
|
||||
"latest_rtt_state",
|
||||
DropdownChoice(
|
||||
title=_("Latest RTT state"),
|
||||
choices=[
|
||||
("ok", _("OK")),
|
||||
("disconnected", _("disconnected")),
|
||||
("over treshold", _("over treshold")),
|
||||
("timeout", _("timeout")),
|
||||
("other", _("other")),
|
||||
],
|
||||
default_value="ok",
|
||||
),
|
||||
),
|
||||
(
|
||||
"packets_lost_src->dest",
|
||||
Tuple(
|
||||
title=_("Packets lost src->dest"),
|
||||
elements=[
|
||||
Integer(
|
||||
title=_("Warning at"),
|
||||
unit=_("packets"),
|
||||
minvalue=1,
|
||||
default_value=100,
|
||||
),
|
||||
Integer(
|
||||
title=_("Critical at"),
|
||||
unit=_("packets"),
|
||||
minvalue=1,
|
||||
default_value=1000,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
(
|
||||
"packets_lost_dest->src",
|
||||
Tuple(
|
||||
title=_("Packets lost dest->src"),
|
||||
elements=[
|
||||
Integer(
|
||||
title=_("Warning at"),
|
||||
unit=_("packets"),
|
||||
minvalue=1,
|
||||
default_value=100,
|
||||
),
|
||||
Integer(
|
||||
title=_("Critical at"),
|
||||
unit=_("packets"),
|
||||
minvalue=1,
|
||||
default_value=1000,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
rulespec_registry.register(
|
||||
CheckParameterRulespecWithItem(
|
||||
check_group_name="cisco_ip_sla",
|
||||
group=RulespecGroupCheckParametersNetworking,
|
||||
item_spec=_item_spec_cisco_ip_sla,
|
||||
match_type="dict",
|
||||
parameter_valuespec=_parameter_valuespec_cisco_ip_sla,
|
||||
title=lambda: _("Cisco IP SLA"),
|
||||
)
|
||||
)
|
237
check_mk-cisco_ip_sla/local/share/check_mk/checks/cisco_ip_sla
Normal file
237
check_mk-cisco_ip_sla/local/share/check_mk/checks/cisco_ip_sla
Normal file
@ -0,0 +1,237 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2019 tribe29 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.
|
||||
|
||||
factory_settings["cisco_ip_sla_default_levels"] = {
|
||||
"state": "active",
|
||||
"connection_lost_occured": "no",
|
||||
"timeout_occured": "no",
|
||||
"completion_time_over_treshold_occured": "no",
|
||||
"latest_rtt_completion_time": (250, 500),
|
||||
"latest_rtt_state": "ok",
|
||||
"packets_lost_src->dest": (100, 1000),
|
||||
"packets_lost_dest->src": (100, 1000),
|
||||
}
|
||||
|
||||
|
||||
def parse_cisco_ip_sla(info):
|
||||
precisions = {line[0]: "ms" if line[-1] == "1" else "us" for line in info[0]}
|
||||
|
||||
rtt_types = {
|
||||
"1": "echo",
|
||||
"2": "path echo",
|
||||
"3": "file IO",
|
||||
"4": "script",
|
||||
"5": "UDP echo",
|
||||
"6": "TCP connect",
|
||||
"7": "HTTP",
|
||||
"8": "DNS",
|
||||
"9": "jitter",
|
||||
"10": "DLSw",
|
||||
"11": "DHCP",
|
||||
"12": "FTP",
|
||||
"13": "VoIP",
|
||||
"14": "RTP",
|
||||
"15": "LSP group",
|
||||
"16": "ICMP jitter",
|
||||
"17": "LSP ping",
|
||||
"18": "LSP trace",
|
||||
"19": "ethernet ping",
|
||||
"20": "ethernet jitter",
|
||||
"21": "LSP ping pseudowire",
|
||||
}
|
||||
|
||||
states = {
|
||||
"1": "reset",
|
||||
"2": "orderly stop",
|
||||
"3": "immediate stop",
|
||||
"4": "pending",
|
||||
"5": "inactive",
|
||||
"6": "active",
|
||||
"7": "restart",
|
||||
}
|
||||
|
||||
rtt_states = {
|
||||
"0": "other",
|
||||
"1": "ok",
|
||||
"2": "disconnected",
|
||||
"3": "over threshold",
|
||||
"4": "timeout",
|
||||
"5": "busy",
|
||||
"6": "not connected",
|
||||
"7": "dropped",
|
||||
"8": "sequence error",
|
||||
"9": "verify error",
|
||||
"10": "application specific error",
|
||||
}
|
||||
|
||||
def to_ip_address(int_list):
|
||||
if len(int_list) == 4:
|
||||
return "%d.%d.%d.%d" % tuple(int_list)
|
||||
elif len(int_list) == 6:
|
||||
return "%d:%d:%d:%d:%d:%d" % tuple(int_list)
|
||||
return ""
|
||||
|
||||
# contains description, parse function, unit and type
|
||||
contents = [
|
||||
( # rttMonEchoAdminEntry
|
||||
("Target address", to_ip_address, "", None),
|
||||
("Source address", to_ip_address, "", None),
|
||||
# rttMonEchoAdminPrecision is deliberatly dropped by zip below
|
||||
),
|
||||
( # rttMonCtrlAdminEntry
|
||||
("Owner", None, "", None),
|
||||
("Tag", None, "", None),
|
||||
("RTT type", lambda x: rtt_types.get(x, "unknown"), "", "option"),
|
||||
("Threshold", int, "ms", "option"),
|
||||
),
|
||||
( # rttMonCtrlOperEntry
|
||||
("State", lambda x: states.get(x, "unknown"), "", "option"),
|
||||
("Text", None, "", None),
|
||||
("Connection lost occured", lambda x: "yes" if x == "1" else "no", "", "option"),
|
||||
("Timeout occured", lambda x: "yes" if x == "1" else "no", "", "option"),
|
||||
(
|
||||
"Completion time over treshold occured",
|
||||
lambda x: "yes" if x == "1" else "no",
|
||||
"",
|
||||
"option",
|
||||
),
|
||||
),
|
||||
( # rttMonLatestRttOperEntry
|
||||
("Latest RTT completion time", int, "ms/us", "level"),
|
||||
("Latest RTT state", lambda x: rtt_states.get(x, "unknown"), "", "option"),
|
||||
),
|
||||
( # rttMonJitterStatsEntry
|
||||
("Packets lost src->dest", int, "packets", "level"),
|
||||
("Packets lost dest->src", int, "packets", "level"),
|
||||
),
|
||||
]
|
||||
|
||||
parsed = {}
|
||||
for content, entries in zip(contents, info):
|
||||
if not entries:
|
||||
continue
|
||||
|
||||
for entry in entries:
|
||||
index, values = entry[0], entry[1:]
|
||||
data = parsed.setdefault(index, [])
|
||||
for (description, parser, unit, type_), value in zip(content, values):
|
||||
if parser:
|
||||
value = parser(value)
|
||||
if unit == "ms/us":
|
||||
unit = precisions[index]
|
||||
data.append((description, value, unit, type_))
|
||||
|
||||
return parsed
|
||||
|
||||
|
||||
def inventory_cisco_ip_sla(parsed):
|
||||
for index in parsed:
|
||||
yield index, {}
|
||||
|
||||
|
||||
@get_parsed_item_data
|
||||
def check_cisco_ip_sla(_item, params, data):
|
||||
for description, value, unit, type_ in data:
|
||||
if not value and "packets" not in unit:
|
||||
continue
|
||||
|
||||
state = 0
|
||||
if unit:
|
||||
infotext = "%s: %s %s" % (description, value, unit)
|
||||
else:
|
||||
infotext = "%s: %s" % (description, value)
|
||||
perfdata = []
|
||||
|
||||
param = params.get(description.lower().replace(" ", "_"))
|
||||
|
||||
if type_ == "option":
|
||||
if param and param != value:
|
||||
state = 1
|
||||
infotext += " (expected %s)" % param
|
||||
elif type_ == "level":
|
||||
warn, crit = param # a default level hat to exist
|
||||
if value >= crit:
|
||||
state = 2
|
||||
elif value >= warn:
|
||||
state = 1
|
||||
|
||||
if state:
|
||||
infotext += " (warn/crit at %s/%s)" % (warn, crit)
|
||||
|
||||
if unit == "ms/us":
|
||||
factor = 1e3 if unit == "ms" else 1e6
|
||||
perfdata = [
|
||||
("rtt", value / factor, warn / factor, crit / factor)
|
||||
] # fixed: true-division
|
||||
elif unit == "packets":
|
||||
perfdata = [
|
||||
("lost", value, warn, crit)
|
||||
]
|
||||
|
||||
yield state, infotext, perfdata
|
||||
|
||||
|
||||
check_info["cisco_ip_sla"] = {
|
||||
"parse_function": parse_cisco_ip_sla,
|
||||
"inventory_function": inventory_cisco_ip_sla,
|
||||
"check_function": check_cisco_ip_sla,
|
||||
"service_description": "Cisco IP SLA %s",
|
||||
"group": "cisco_ip_sla",
|
||||
"default_levels_variable": "cisco_ip_sla_default_levels",
|
||||
"has_perfdata": True,
|
||||
"snmp_scan_function": lambda oid: "cisco" in oid(".1.3.6.1.2.1.1.1.0").lower()
|
||||
and "ios" in oid(".1.3.6.1.2.1.1.1.0").lower()
|
||||
and oid(".1.3.6.1.4.1.9.9.42.1.2.2.1.37.*"),
|
||||
"snmp_info": [
|
||||
(
|
||||
".1.3.6.1.4.1.9.9.42.1.2.2.1",
|
||||
[
|
||||
OID_END,
|
||||
BINARY(2), # rttMonEchoAdminTargetAddress
|
||||
BINARY(6), # rttMonEchoAdminSourceAddress
|
||||
# only needed to determine the unit (ms/us)
|
||||
37, # rttMonEchoAdminPrecision
|
||||
],
|
||||
),
|
||||
(
|
||||
".1.3.6.1.4.1.9.9.42.1.2.1.1",
|
||||
[
|
||||
OID_END,
|
||||
2, # rttMonCtrlAdminOwner
|
||||
3, # rttMonCtrlAdminTag
|
||||
4, # rttMonCtrlAdminRttType
|
||||
5, # rttMonCtrlAdminThreshold
|
||||
],
|
||||
),
|
||||
(
|
||||
".1.3.6.1.4.1.9.9.42.1.2.9.1",
|
||||
[
|
||||
OID_END,
|
||||
10, # rttMonCtrlOperState
|
||||
2, # rttMonCtrlOperDiagText
|
||||
5, # rttMonCtrlOperConnectionLostOccurred
|
||||
6, # rttMonCtrlOperTimeoutOccurred
|
||||
7, # rttMonCtrlOperOverThresholdOccurred
|
||||
],
|
||||
),
|
||||
(
|
||||
".1.3.6.1.4.1.9.9.42.1.2.10.1",
|
||||
[
|
||||
OID_END,
|
||||
1, # rttMonLatestRttOperCompletionTime
|
||||
2, # rttMonLatestRttOperSense
|
||||
],
|
||||
),
|
||||
(
|
||||
".1.3.6.1.4.1.9.9.42.1.5.2.1",
|
||||
[
|
||||
OID_END,
|
||||
26, # rttMonLatestJitterOperPacketLossSD
|
||||
27, # rttMonLatestJitterOperPacketLossDS
|
||||
]
|
||||
)
|
||||
],
|
||||
}
|
20
check_mk-clever-pdu/cmk1.6/README
Normal file
20
check_mk-clever-pdu/cmk1.6/README
Normal file
@ -0,0 +1,20 @@
|
||||
{'author': u'George Pochiscan',
|
||||
'description': u'',
|
||||
'download_url': '',
|
||||
'files': {'checkman': ['clever_pdu',
|
||||
'clever_pdu_humidity',
|
||||
'clever_pdu_temp'],
|
||||
'checks': ['clever_pdu_120',
|
||||
'clever_pdu_130',
|
||||
'clever_pdu_humidity_120',
|
||||
'clever_pdu_humidity_130',
|
||||
'clever_pdu_temp_120',
|
||||
'clever_pdu_temp_130'],
|
||||
'web': ['plugins/wato/clever_pdu.py']},
|
||||
'name': 'clever_pdu_1-6',
|
||||
'num_files': 10,
|
||||
'title': u'Clever PDU checks for Checkmk 1.6',
|
||||
'version': '1.1',
|
||||
'version.min_required': '1.6.0p20',
|
||||
'version.packaged': '1.6.0p29',
|
||||
'version.usable_until': '2.0.0p1'}
|
BIN
check_mk-clever-pdu/cmk1.6/clever_pdu_1-6-1.1.mkp
Normal file
BIN
check_mk-clever-pdu/cmk1.6/clever_pdu_1-6-1.1.mkp
Normal file
Binary file not shown.
@ -0,0 +1,13 @@
|
||||
title: Clever PDU Units: Power and Voltage
|
||||
agents: snmp
|
||||
catalog: hw/power/clever
|
||||
license: GPLv2
|
||||
distribution: check_mk
|
||||
description:
|
||||
Monitors Power, Voltage and energy on Clever PDU Units.
|
||||
|
||||
item:
|
||||
ID of the Line.
|
||||
|
||||
discovery:
|
||||
One service is created for each Line.
|
@ -0,0 +1,13 @@
|
||||
title: Clever PDU Units: Master Humidity
|
||||
agents: snmp
|
||||
catalog: hw/power/clever
|
||||
license: GPLv2
|
||||
distribution: check_mk
|
||||
description:
|
||||
Monitors Master Humidity on Clever PDU Units.
|
||||
|
||||
item:
|
||||
Master Humidity.
|
||||
|
||||
discovery:
|
||||
One service is created.
|
@ -0,0 +1,13 @@
|
||||
title: Clever PDU Units: Master Temperature
|
||||
agents: snmp
|
||||
catalog: hw/power/clever
|
||||
license: GPLv2
|
||||
distribution: check_mk
|
||||
description:
|
||||
Monitors Master Temperature on Clever PDU Units.
|
||||
|
||||
item:
|
||||
Master Temperature.
|
||||
|
||||
discovery:
|
||||
One service is created.
|
@ -0,0 +1,129 @@
|
||||
#!/usr/bin/python
|
||||
# -*- encoding: utf-8; py-indent-offset: 4 -*-
|
||||
# +------------------------------------------------------------------+
|
||||
# | ____ _ _ __ __ _ __ |
|
||||
# | / ___| |__ ___ ___| | __ | \/ | |/ / |
|
||||
# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
|
||||
# | | |___| | | | __/ (__| < | | | | . \ |
|
||||
# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
|
||||
# | |
|
||||
# | Copyright Mathias Kettner 2016 mk@mathias-kettner.de |
|
||||
# +------------------------------------------------------------------+
|
||||
#
|
||||
# This file is part of Check_MK.
|
||||
# The official homepage is at http://mathias-kettner.de/check_mk.
|
||||
#
|
||||
# check_mk is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation in version 2. check_mk is distributed
|
||||
# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
|
||||
# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE. See the GNU General Public License for more de-
|
||||
# tails. You should have received a copy of the GNU General Public
|
||||
# License along with GNU Make; see the file COPYING. If not, write
|
||||
# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
# Boston, MA 02110-1301 USA.
|
||||
|
||||
factory_settings["clever_pdu_default_levels"] ={
|
||||
"voltage": (240, 250),
|
||||
"current": (32, 33),
|
||||
"energy": (35000, 36000),
|
||||
}
|
||||
|
||||
lines = {"Line 1", "Line 2", "Line 3"}
|
||||
_UNIT_MAP = {
|
||||
"voltage": "V" ,
|
||||
"current": "A" ,
|
||||
"energy": "W",
|
||||
}
|
||||
|
||||
def parse_clever_pdu_120(info):
|
||||
data=info[0]
|
||||
parsed = {}
|
||||
parsed = {
|
||||
"Line 1" : {
|
||||
"voltage": float(data[0]),
|
||||
"current": float(data[3])/10,
|
||||
"energy": float(data[6]),
|
||||
},
|
||||
"Line 2" : {
|
||||
"voltage": float(data[1]),
|
||||
"current": float(data[4])/10,
|
||||
"energy": float(data[7]),
|
||||
},
|
||||
"Line 3" : {
|
||||
"voltage": float(data[2]),
|
||||
"current": float(data[5])/10,
|
||||
"energy": float(data[8]),
|
||||
},
|
||||
"Total Energy" : {
|
||||
"energy" : float((float(data[0])*float(data[3])/10)) + float((float(data[1])*float(data[4])/10)) + float((float(data[2])*float(data[5])/10)),
|
||||
},
|
||||
|
||||
}
|
||||
return parsed
|
||||
|
||||
def inventory_clever_pdu_120(parsed):
|
||||
for line in parsed:
|
||||
yield line, {}
|
||||
|
||||
|
||||
def check_clever_pdu_120(item, params, parsed):
|
||||
if "Total" not in item:
|
||||
for param in params:
|
||||
levels_lower = levels_upper = None
|
||||
warn, crit = params.get(param)
|
||||
if warn > crit:
|
||||
levels_lower = warn, crit
|
||||
else:
|
||||
levels_upper = warn, crit
|
||||
|
||||
yield check_levels(
|
||||
parsed.get(item).get(param),
|
||||
param,
|
||||
(warn, crit),
|
||||
unit = _UNIT_MAP.get(param),
|
||||
infoname = param
|
||||
)
|
||||
else:
|
||||
for param in params:
|
||||
if "energy" in param:
|
||||
levels_lower = levels_upper = None
|
||||
warn, crit = params.get(param)
|
||||
if warn > crit:
|
||||
levels_lower = warn, crit
|
||||
else:
|
||||
levels_upper = warn, crit
|
||||
yield check_levels(
|
||||
parsed.get(item).get(param),
|
||||
param,
|
||||
(warn, crit),
|
||||
unit = _UNIT_MAP.get(param),
|
||||
infoname = param
|
||||
)
|
||||
|
||||
|
||||
|
||||
check_info['clever_pdu_120'] = {
|
||||
'parse_function' : parse_clever_pdu_120,
|
||||
'inventory_function' : inventory_clever_pdu_120,
|
||||
'check_function' : check_clever_pdu_120,
|
||||
'service_description' : '%s',
|
||||
'has_perfdata' : True,
|
||||
'group' : "clever_pdu",
|
||||
'snmp_info' : ('.1.3.6.1.4.1.30966.10.3.2',
|
||||
[
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
'7',
|
||||
'8',
|
||||
'9',
|
||||
],
|
||||
),
|
||||
'snmp_scan_function' : lambda oid: oid(".1.3.6.1.2.1.1.2.0").startswith(".1.3.6.1.4.1.30966") and oid(".1.3.6.1.4.1.30966.10.3.2.70.0"),
|
||||
'default_levels_variable' : 'clever_pdu_default_levels',
|
||||
}
|
@ -0,0 +1,127 @@
|
||||
#!/usr/bin/python
|
||||
# -*- encoding: utf-8; py-indent-offset: 4 -*-
|
||||
# +------------------------------------------------------------------+
|
||||
# | ____ _ _ __ __ _ __ |
|
||||
# | / ___| |__ ___ ___| | __ | \/ | |/ / |
|
||||
# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
|
||||
# | | |___| | | | __/ (__| < | | | | . \ |
|
||||
# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
|
||||
# | |
|
||||
# | Copyright Mathias Kettner 2016 mk@mathias-kettner.de |
|
||||
# +------------------------------------------------------------------+
|
||||
#
|
||||
# This file is part of Check_MK.
|
||||
# The official homepage is at http://mathias-kettner.de/check_mk.
|
||||
#
|
||||
# check_mk is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation in version 2. check_mk is distributed
|
||||
# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
|
||||
# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE. See the GNU General Public License for more de-
|
||||
# tails. You should have received a copy of the GNU General Public
|
||||
# License along with GNU Make; see the file COPYING. If not, write
|
||||
# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
# Boston, MA 02110-1301 USA.
|
||||
|
||||
factory_settings["clever_pdu_default_levels"] ={
|
||||
"voltage": (240, 250),
|
||||
"current": (32, 33),
|
||||
"energy": (35000, 36000),
|
||||
}
|
||||
|
||||
lines = {"Line 1", "Line 2", "Line 3"}
|
||||
_UNIT_MAP = {
|
||||
"voltage": "V" ,
|
||||
"current": "A" ,
|
||||
"energy": "W",
|
||||
}
|
||||
|
||||
|
||||
|
||||
def parse_clever_pdu(info):
|
||||
data=info[0]
|
||||
parsed = {}
|
||||
parsed = {
|
||||
"Line 1" : {
|
||||
"voltage": float(data[0]),
|
||||
"current": float(float(data[3])/10),
|
||||
"energy" : float((float(data[0])*float(data[3])/10)),
|
||||
},
|
||||
"Line 2" : {
|
||||
"voltage": float(data[1]),
|
||||
"current": float(float(data[4])/10),
|
||||
"energy" : float((float(data[1])*float(data[4])/10)),
|
||||
},
|
||||
"Line 3" : {
|
||||
"voltage": float(data[2]),
|
||||
"current": float(float(data[5])/10),
|
||||
"energy" : float((float(data[2])*float(data[5])/10)),
|
||||
},
|
||||
"Total Energy" : {
|
||||
"energy" : float((float(data[0])*float(data[3])/10)) + float((float(data[1])*float(data[4])/10)) + float((float(data[2])*float(data[5])/10)),
|
||||
},
|
||||
|
||||
}
|
||||
return parsed
|
||||
|
||||
def inventory_clever_pdu(parsed):
|
||||
for line in parsed:
|
||||
yield line, {}
|
||||
|
||||
|
||||
def check_clever_pdu(item, params, parsed):
|
||||
if "Total" not in item:
|
||||
for param in params:
|
||||
levels_lower = levels_upper = None
|
||||
warn, crit = params.get(param)
|
||||
if warn > crit:
|
||||
levels_lower = warn, crit
|
||||
else:
|
||||
levels_upper = warn, crit
|
||||
|
||||
yield check_levels(
|
||||
parsed.get(item).get(param),
|
||||
param,
|
||||
(warn, crit),
|
||||
unit = _UNIT_MAP.get(param),
|
||||
infoname = param
|
||||
)
|
||||
else:
|
||||
for param in params:
|
||||
if "energy" in param:
|
||||
levels_lower = levels_upper = None
|
||||
warn, crit = params.get(param)
|
||||
if warn > crit:
|
||||
levels_lower = warn, crit
|
||||
else:
|
||||
levels_upper = warn, crit
|
||||
yield check_levels(
|
||||
parsed.get(item).get(param),
|
||||
param,
|
||||
(warn, crit),
|
||||
unit = _UNIT_MAP.get(param),
|
||||
infoname = param
|
||||
)
|
||||
|
||||
|
||||
check_info['clever_pdu'] = {
|
||||
'parse_function' : parse_clever_pdu,
|
||||
'inventory_function' : inventory_clever_pdu,
|
||||
'check_function' : check_clever_pdu,
|
||||
'service_description' : '%s',
|
||||
'has_perfdata' : True,
|
||||
'group' : "clever_pdu",
|
||||
'snmp_info' : ('.1.3.6.1.4.1.30966.10.3.2',
|
||||
[
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
],
|
||||
),
|
||||
'snmp_scan_function' : lambda oid: oid(".1.3.6.1.2.1.1.2.0").startswith(".1.3.6.1.4.1.30966") and not oid(".1.3.6.1.4.1.30966.10.3.2.70.0"),
|
||||
'default_levels_variable' : 'clever_pdu_default_levels',
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
#!/usr/bin/python
|
||||
# -*- encoding: utf-8; py-indent-offset: 4 -*-
|
||||
# +------------------------------------------------------------------+
|
||||
# | ____ _ _ __ __ _ __ |
|
||||
# | / ___| |__ ___ ___| | __ | \/ | |/ / |
|
||||
# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
|
||||
# | | |___| | | | __/ (__| < | | | | . \ |
|
||||
# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
|
||||
# | |
|
||||
# | Copyright Mathias Kettner 2016 mk@mathias-kettner.de |
|
||||
# +------------------------------------------------------------------+
|
||||
#
|
||||
# This file is part of Check_MK.
|
||||
# The official homepage is at http://mathias-kettner.de/check_mk.
|
||||
#
|
||||
# check_mk is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation in version 2. check_mk is distributed
|
||||
# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
|
||||
# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE. See the GNU General Public License for more de-
|
||||
# tails. You should have received a copy of the GNU General Public
|
||||
# License along with GNU Make; see the file COPYING. If not, write
|
||||
# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
# Boston, MA 02110-1301 USA.
|
||||
|
||||
factory_settings["clever_pdu_humidity_default_levels"] = {
|
||||
"levels": (60, 70),
|
||||
}
|
||||
|
||||
def inventory_clever_pdu_humidity_120(info):
|
||||
yield "Master humidity", {}
|
||||
|
||||
|
||||
def check_clever_pdu_humidity_120(item, params, info):
|
||||
return check_humidity(float(info[0][0]), params)
|
||||
|
||||
|
||||
check_info['clever_pdu_humidity_120'] = {
|
||||
'inventory_function' : inventory_clever_pdu_humidity_120,
|
||||
'check_function' : check_clever_pdu_humidity_120,
|
||||
'service_description' : '%s',
|
||||
'has_perfdata' : True,
|
||||
'snmp_info' : ('.1.3.6.1.4.1.30966.10.3.2.14', ['0']),
|
||||
'snmp_scan_function' : lambda oid: oid(".1.3.6.1.2.1.1.2.0").startswith(".1.3.6.1.4.1.30966") and oid(".1.3.6.1.4.1.30966.10.3.2.70.0"),
|
||||
'group' : 'humidity',
|
||||
'default_levels_variable' : 'clever_pdu_humidity_default_levels',
|
||||
'includes' : ['humidity.include'],
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
#!/usr/bin/python
|
||||
# -*- encoding: utf-8; py-indent-offset: 4 -*-
|
||||
# +------------------------------------------------------------------+
|
||||
# | ____ _ _ __ __ _ __ |
|
||||
# | / ___| |__ ___ ___| | __ | \/ | |/ / |
|
||||
# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
|
||||
# | | |___| | | | __/ (__| < | | | | . \ |
|
||||
# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
|
||||
# | |
|
||||
# | Copyright Mathias Kettner 2016 mk@mathias-kettner.de |
|
||||
# +------------------------------------------------------------------+
|
||||
#
|
||||
# This file is part of Check_MK.
|
||||
# The official homepage is at http://mathias-kettner.de/check_mk.
|
||||
#
|
||||
# check_mk is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation in version 2. check_mk is distributed
|
||||
# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
|
||||
# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE. See the GNU General Public License for more de-
|
||||
# tails. You should have received a copy of the GNU General Public
|
||||
# License along with GNU Make; see the file COPYING. If not, write
|
||||
# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
# Boston, MA 02110-1301 USA.
|
||||
|
||||
factory_settings["clever_pdu_humidity_default_levels"] = {
|
||||
"levels": (60, 70),
|
||||
}
|
||||
|
||||
def inventory_clever_pdu_humidity(info):
|
||||
yield "Master humidity", {}
|
||||
|
||||
|
||||
def check_clever_pdu_humidity(item, params, info):
|
||||
return check_humidity(float(info[0][0]), params)
|
||||
|
||||
|
||||
check_info['clever_pdu_humidity'] = {
|
||||
'inventory_function' : inventory_clever_pdu_humidity,
|
||||
'check_function' : check_clever_pdu_humidity,
|
||||
'service_description' : '%s',
|
||||
'has_perfdata' : True,
|
||||
'snmp_info' : ('.1.3.6.1.4.1.30966.10.3.2.11', ['0']),
|
||||
'snmp_scan_function' : lambda oid: oid(".1.3.6.1.2.1.1.2.0").startswith(".1.3.6.1.4.1.30966") and not oid(".1.3.6.1.4.1.30966.10.3.2.70.0"),
|
||||
'group' : 'humidity',
|
||||
'default_levels_variable' : 'clever_pdu_humidity_default_levels',
|
||||
'includes' : ['humidity.include'],
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
#!/usr/bin/python
|
||||
# -*- encoding: utf-8; py-indent-offset: 4 -*-
|
||||
# +------------------------------------------------------------------+
|
||||
# | ____ _ _ __ __ _ __ |
|
||||
# | / ___| |__ ___ ___| | __ | \/ | |/ / |
|
||||
# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
|
||||
# | | |___| | | | __/ (__| < | | | | . \ |
|
||||
# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
|
||||
# | |
|
||||
# | Copyright Mathias Kettner 2016 mk@mathias-kettner.de |
|
||||
# +------------------------------------------------------------------+
|
||||
#
|
||||
# This file is part of Check_MK.
|
||||
# The official homepage is at http://mathias-kettner.de/check_mk.
|
||||
#
|
||||
# check_mk is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation in version 2. check_mk is distributed
|
||||
# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
|
||||
# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE. See the GNU General Public License for more de-
|
||||
# tails. You should have received a copy of the GNU General Public
|
||||
# License along with GNU Make; see the file COPYING. If not, write
|
||||
# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
# Boston, MA 02110-1301 USA.
|
||||
|
||||
factory_settings["clever_pdu_temp_default_levels"] = {
|
||||
"levels": (60, 70),
|
||||
}
|
||||
|
||||
def inventory_clever_pdu_temp_120(info):
|
||||
yield "Master Temperature", {}
|
||||
|
||||
|
||||
def check_clever_pdu_temp_120(item, params, info):
|
||||
return check_temperature(float(info[0][0]), params, "Master Temperature %s" %item)
|
||||
|
||||
|
||||
check_info['clever_pdu_temp_120'] = {
|
||||
'inventory_function' : inventory_clever_pdu_temp_120,
|
||||
'check_function' : check_clever_pdu_temp_120,
|
||||
'service_description' : '%s',
|
||||
'has_perfdata' : True,
|
||||
'snmp_info' : ('.1.3.6.1.4.1.30966.10.3.2.13', ['0']),
|
||||
'snmp_scan_function' : lambda oid: oid(".1.3.6.1.2.1.1.2.0").startswith(".1.3.6.1.4.1.30966") and oid(".1.3.6.1.4.1.30966.10.3.2.70.0"),
|
||||
'group' : 'temperature',
|
||||
'default_levels_variable' : 'clever_pdu_temp_default_levels',
|
||||
'includes' : ['temperature.include'],
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
#!/usr/bin/python
|
||||
# -*- encoding: utf-8; py-indent-offset: 4 -*-
|
||||
# +------------------------------------------------------------------+
|
||||
# | ____ _ _ __ __ _ __ |
|
||||
# | / ___| |__ ___ ___| | __ | \/ | |/ / |
|
||||
# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
|
||||
# | | |___| | | | __/ (__| < | | | | . \ |
|
||||
# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
|
||||
# | |
|
||||
# | Copyright Mathias Kettner 2016 mk@mathias-kettner.de |
|
||||
# +------------------------------------------------------------------+
|
||||
#
|
||||
# This file is part of Check_MK.
|
||||
# The official homepage is at http://mathias-kettner.de/check_mk.
|
||||
#
|
||||
# check_mk is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation in version 2. check_mk is distributed
|
||||
# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
|
||||
# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE. See the GNU General Public License for more de-
|
||||
# tails. You should have received a copy of the GNU General Public
|
||||
# License along with GNU Make; see the file COPYING. If not, write
|
||||
# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
# Boston, MA 02110-1301 USA.
|
||||
|
||||
factory_settings["clever_pdu_temp_default_levels"] = {
|
||||
"levels": (60, 70),
|
||||
}
|
||||
|
||||
def inventory_clever_pdu_temp(info):
|
||||
yield "Master Temperature", {}
|
||||
|
||||
|
||||
def check_clever_pdu_temp(item, params, info):
|
||||
return check_temperature(float(info[0][0]), params, "Master Temperature %s" %item)
|
||||
|
||||
|
||||
check_info['clever_pdu_temp'] = {
|
||||
'inventory_function' : inventory_clever_pdu_temp,
|
||||
'check_function' : check_clever_pdu_temp,
|
||||
'service_description' : '%s',
|
||||
'has_perfdata' : True,
|
||||
'snmp_info' : ('.1.3.6.1.4.1.30966.10.3.2.10', ['0']),
|
||||
'snmp_scan_function' : lambda oid: oid(".1.3.6.1.2.1.1.2.0").startswith(".1.3.6.1.4.1.30966") and not oid(".1.3.6.1.4.1.30966.10.3.2.70.0"),
|
||||
'group' : 'temperature',
|
||||
'default_levels_variable' : 'clever_pdu_temp_default_levels',
|
||||
'includes' : ['temperature.include'],
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
#!/usr/bin/python
|
||||
# -*- encoding: utf-8; py-indent-offset: 4 -*-
|
||||
# +------------------------------------------------------------------+
|
||||
# | ____ _ _ __ __ _ __ |
|
||||
# | / ___| |__ ___ ___| | __ | \/ | |/ / |
|
||||
# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
|
||||
# | | |___| | | | __/ (__| < | | | | . \ |
|
||||
# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
|
||||
# | |
|
||||
# | Copyright Mathias Kettner 2014 mk@mathias-kettner.de |
|
||||
# +------------------------------------------------------------------+
|
||||
#
|
||||
# This file is part of Check_MK.
|
||||
# The official homepage is at http://mathias-kettner.de/check_mk.
|
||||
#
|
||||
# check_mk is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation in version 2. check_mk is distributed
|
||||
# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
|
||||
# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE. See the GNU General Public License for more de-
|
||||
# tails. You should have received a copy of the GNU General Public
|
||||
# License along with GNU Make; see the file COPYING. If not, write
|
||||
# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
# Boston, MA 02110-1301 USA.
|
||||
|
||||
from cmk.gui.i18n import _
|
||||
from cmk.gui.plugins.wato import (
|
||||
CheckParameterRulespecWithItem,
|
||||
rulespec_registry,
|
||||
RulespecGroupCheckParametersEnvironment,
|
||||
)
|
||||
from cmk.gui.valuespec import Dictionary, Integer, TextAscii, Tuple
|
||||
|
||||
|
||||
def _parameter_valuespec_clever_pdu():
|
||||
return Dictionary(
|
||||
elements=[
|
||||
(
|
||||
"voltage",
|
||||
Tuple(
|
||||
title=_("Voltage on Line"),
|
||||
elements=[
|
||||
Integer(title=_("warning at"), unit=_("V")),
|
||||
Integer(title=_("critical at"), unit=_("V")),
|
||||
],
|
||||
),
|
||||
),
|
||||
(
|
||||
"current",
|
||||
Tuple(
|
||||
title=_("Current on Power Channel"),
|
||||
elements=[
|
||||
Integer(title=_("warning if below"), unit=_("A")),
|
||||
Integer(title=_("critical if below"), unit=_("A")),
|
||||
],
|
||||
),
|
||||
),
|
||||
(
|
||||
"energy",
|
||||
Tuple(
|
||||
title=_("Active Energy of Line"),
|
||||
elements=[
|
||||
Integer(title=_("warning at"), unit=_("W")),
|
||||
Integer(title=_("critical at"), unit=_("W")),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
rulespec_registry.register(
|
||||
CheckParameterRulespecWithItem(
|
||||
check_group_name="clever_pdu",
|
||||
group=RulespecGroupCheckParametersEnvironment,
|
||||
item_spec=lambda: TextAscii(title=_("Line"),),
|
||||
match_type="dict",
|
||||
parameter_valuespec=_parameter_valuespec_clever_pdu,
|
||||
title=lambda: _("Levels for Clever AC PDU Devices"),
|
||||
)
|
||||
)
|
||||
|
13
check_mk-clever-pdu/cmk2/checkman/clever_pdu
Normal file
13
check_mk-clever-pdu/cmk2/checkman/clever_pdu
Normal file
@ -0,0 +1,13 @@
|
||||
title: Clever PDU Units: Power and Voltage
|
||||
agents: snmp
|
||||
catalog: hw/power/clever
|
||||
license: GPLv2
|
||||
distribution: check_mk
|
||||
description:
|
||||
Monitors Power, Voltage and energy on Clever PDU Units.
|
||||
|
||||
item:
|
||||
ID of the Line.
|
||||
|
||||
discovery:
|
||||
One service is created for each Line.
|
13
check_mk-clever-pdu/cmk2/checkman/clever_pdu_humidity
Normal file
13
check_mk-clever-pdu/cmk2/checkman/clever_pdu_humidity
Normal file
@ -0,0 +1,13 @@
|
||||
title: Clever PDU Units: Master Humidity
|
||||
agents: snmp
|
||||
catalog: hw/power/clever
|
||||
license: GPLv2
|
||||
distribution: check_mk
|
||||
description:
|
||||
Monitors Master Humidity on Clever PDU Units.
|
||||
|
||||
item:
|
||||
Master Humidity.
|
||||
|
||||
discovery:
|
||||
One service is created.
|
13
check_mk-clever-pdu/cmk2/checkman/clever_pdu_temp
Normal file
13
check_mk-clever-pdu/cmk2/checkman/clever_pdu_temp
Normal file
@ -0,0 +1,13 @@
|
||||
title: Clever PDU Units: Master Temperature
|
||||
agents: snmp
|
||||
catalog: hw/power/clever
|
||||
license: GPLv2
|
||||
distribution: check_mk
|
||||
description:
|
||||
Monitors Master Temperature on Clever PDU Units.
|
||||
|
||||
item:
|
||||
Master Temperature.
|
||||
|
||||
discovery:
|
||||
One service is created.
|
BIN
check_mk-clever-pdu/cmk2/clever_pdu_2-1.0.1.mkp
Normal file
BIN
check_mk-clever-pdu/cmk2/clever_pdu_2-1.0.1.mkp
Normal file
Binary file not shown.
20
check_mk-clever-pdu/cmk2/info
Normal file
20
check_mk-clever-pdu/cmk2/info
Normal file
@ -0,0 +1,20 @@
|
||||
{'author': 'George Pochiscan',
|
||||
'description': 'Ported Clever AC PDU from 2.1.0 checkmk version to 2.0.0 '
|
||||
'checkmk version.\n',
|
||||
'download_url': '',
|
||||
'files': {'agent_based': ['utils/humidity.py',
|
||||
'clever_pdu_120.py',
|
||||
'clever_pdu_130.py',
|
||||
'clever_pdu_humidity_120.py',
|
||||
'clever_pdu_humidity_130.py',
|
||||
'clever_pdu_temp_120.py',
|
||||
'clever_pdu_temp_130.py'],
|
||||
'checkman': ['clever_pdu', 'clever_pdu_humidity', 'clever_pdu_temp'],
|
||||
'web': ['plugins/wato/clever_pdu.py']},
|
||||
'name': 'clever_pdu_2',
|
||||
'num_files': 11,
|
||||
'title': 'Clever PDU checks for 2.0 checkmk version',
|
||||
'version': '1.0.1',
|
||||
'version.min_required': '2.0.0p20',
|
||||
'version.packaged': '2.0.0p29',
|
||||
'version.usable_until': '2.1.0p20'}
|
@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2019 tribe29 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.
|
||||
from dataclasses import dataclass
|
||||
from typing import Iterable, Mapping, Tuple, NamedTuple
|
||||
from .agent_based_api.v1 import check_levels, equals, register, Service, SNMPTree, all_of, exists
|
||||
from .agent_based_api.v1.type_defs import CheckResult, DiscoveryResult, StringTable
|
||||
|
||||
|
||||
def parse_clever_pdu_120(string_table: StringTable):
|
||||
data=string_table[0]
|
||||
parsed = {}
|
||||
parsed = {
|
||||
"Line 1" : {
|
||||
"voltage": float(data[0]),
|
||||
"current": float(data[3])/10,
|
||||
"energy": float(data[6]),
|
||||
},
|
||||
"Line 2" : {
|
||||
"voltage": float(data[1]),
|
||||
"current": float(data[4])/10,
|
||||
"energy": float(data[7]),
|
||||
},
|
||||
"Line 3" : {
|
||||
"voltage": float(data[2]),
|
||||
"current": float(data[5])/10,
|
||||
"energy": float(data[8]),
|
||||
},
|
||||
"Total Energy" : {
|
||||
"energy" : float((float(data[0])*float(data[3])/10)) + float((float(data[1])*float(data[4])/10)) + float((float(data[2])*float(data[5])/10)),
|
||||
},
|
||||
}
|
||||
return parsed
|
||||
|
||||
|
||||
_UNIT_MAP = {
|
||||
"voltage": "V" ,
|
||||
"current": "A" ,
|
||||
"energy": "W",
|
||||
}
|
||||
|
||||
|
||||
register.snmp_section(
|
||||
name="clever_pdu_120",
|
||||
parsed_section_name="clever_pdu_120",
|
||||
parse_function=parse_clever_pdu_120,
|
||||
detect = all_of(
|
||||
equals(
|
||||
".1.3.6.1.2.1.1.2.0",
|
||||
".1.3.6.1.4.1.30966",
|
||||
),
|
||||
exists(".1.3.6.1.4.1.30966.10.3.2.70.0"),
|
||||
),
|
||||
fetch=SNMPTree(
|
||||
".1.3.6.1.4.1.30966.10.3.2",
|
||||
[
|
||||
"1", # mVoltageA
|
||||
"2", # mVoltageB
|
||||
"3", # mVoltageC
|
||||
"4", # mCurrentA
|
||||
"5", # mCurrentB
|
||||
"6", # mCurrentC
|
||||
"7", # mEnergyA
|
||||
"8", # mEnergyB
|
||||
"9", # mEnergyC
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def discover_clever_pdu_120(section) -> DiscoveryResult:
|
||||
yield from (Service(item=line_num) for line_num in section)
|
||||
|
||||
|
||||
def check_clever_pdu_120(item, params, section) -> CheckResult:
|
||||
if "Total" not in item:
|
||||
for param in params:
|
||||
levels_lower = levels_upper = None
|
||||
warn, crit = params.get(param)
|
||||
if warn > crit:
|
||||
levels_lower = warn, crit
|
||||
else:
|
||||
levels_upper = warn, crit
|
||||
|
||||
yield from check_levels(
|
||||
section.get(item)[param],
|
||||
levels_upper = levels_upper,
|
||||
levels_lower = levels_lower,
|
||||
metric_name = param,
|
||||
render_func=lambda v: f"{v:.2f} {_UNIT_MAP[param]}",
|
||||
label = param,
|
||||
)
|
||||
else:
|
||||
for param in params:
|
||||
if "energy" in param:
|
||||
levels_lower = levels_upper = None
|
||||
warn, crit = params.get(param)
|
||||
if warn > crit:
|
||||
levels_lower = warn, crit
|
||||
else:
|
||||
levels_upper = warn, crit
|
||||
yield from check_levels(
|
||||
section.get(item)[param],
|
||||
levels_upper = levels_upper,
|
||||
levels_lower = levels_lower,
|
||||
metric_name = param,
|
||||
render_func=lambda v: f"{v:.2f} {_UNIT_MAP[param]}",
|
||||
label = param,
|
||||
)
|
||||
|
||||
|
||||
|
||||
register.check_plugin(
|
||||
name="clever_pdu_120",
|
||||
service_name="%s",
|
||||
discovery_function=discover_clever_pdu_120,
|
||||
check_function=check_clever_pdu_120,
|
||||
check_ruleset_name="clever_pdu",
|
||||
check_default_parameters={
|
||||
"voltage": (220, 210),
|
||||
"current": (32, 33),
|
||||
"energy": (35000, 36000),
|
||||
},
|
||||
)
|
@ -0,0 +1,125 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2019 tribe29 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.
|
||||
from dataclasses import dataclass
|
||||
from typing import Iterable, Mapping, Tuple, NamedTuple
|
||||
from .agent_based_api.v1 import check_levels, equals, register, Service, SNMPTree, all_of, not_exists
|
||||
from .agent_based_api.v1.type_defs import CheckResult, DiscoveryResult, StringTable
|
||||
|
||||
|
||||
def parse_clever_pdu_130(string_table: StringTable):
|
||||
data=string_table[0]
|
||||
parsed = {}
|
||||
parsed = {
|
||||
"Line 1" : {
|
||||
"voltage": float(data[0]),
|
||||
"current": float(data[3])/10,
|
||||
"energy" : float((float(data[0])*float(data[3])/10)),
|
||||
},
|
||||
"Line 2" : {
|
||||
"voltage": float(data[1]),
|
||||
"current": float(data[4])/10,
|
||||
"energy" : float((float(data[1])*float(data[4])/10)),
|
||||
},
|
||||
"Line 3" : {
|
||||
"voltage": float(data[2]),
|
||||
"current": float(data[5])/10,
|
||||
"energy" : float((float(data[2])*float(data[5])/10)),
|
||||
},
|
||||
"Total Energy" : {
|
||||
"energy" : float((float(data[0])*float(data[3])/10)) + float((float(data[1])*float(data[4])/10)) + float((float(data[2])*float(data[5])/10)),
|
||||
},
|
||||
}
|
||||
return parsed
|
||||
|
||||
lines = {"Line 1", "Line 2", "Line 3"}
|
||||
|
||||
|
||||
_UNIT_MAP = {
|
||||
"voltage": "V" ,
|
||||
"current": "A" ,
|
||||
"energy": "W",
|
||||
}
|
||||
|
||||
|
||||
register.snmp_section(
|
||||
name="clever_pdu_130",
|
||||
parsed_section_name="clever_pdu_130",
|
||||
parse_function=parse_clever_pdu_130,
|
||||
detect = all_of(
|
||||
equals(
|
||||
".1.3.6.1.2.1.1.2.0",
|
||||
".1.3.6.1.4.1.30966",
|
||||
),
|
||||
not_exists(".1.3.6.1.4.1.30966.10.3.2.70.0"),
|
||||
),
|
||||
fetch=SNMPTree(
|
||||
".1.3.6.1.4.1.30966.10.3.2",
|
||||
[
|
||||
"1", # mVoltageA
|
||||
"2", # mVoltageB
|
||||
"3", # mVoltageC
|
||||
"4", # mCurrentA
|
||||
"5", # mCurrentB
|
||||
"6", # mCurrentC
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def discover_clever_pdu_130(section) -> DiscoveryResult:
|
||||
yield from (Service(item=line_num) for line_num in section)
|
||||
|
||||
|
||||
def check_clever_pdu_130(item, params, section) -> CheckResult:
|
||||
if "Total" not in item:
|
||||
for param in params:
|
||||
levels_lower = levels_upper = None
|
||||
warn, crit = params.get(param)
|
||||
if warn > crit:
|
||||
levels_lower = warn, crit
|
||||
else:
|
||||
levels_upper = warn, crit
|
||||
|
||||
yield from check_levels(
|
||||
section.get(item)[param],
|
||||
levels_upper = levels_upper,
|
||||
levels_lower = levels_lower,
|
||||
metric_name = param,
|
||||
render_func=lambda v: f"{v:.2f} {_UNIT_MAP[param]}",
|
||||
label = param,
|
||||
)
|
||||
else:
|
||||
for param in params:
|
||||
if "energy" in param:
|
||||
levels_lower = levels_upper = None
|
||||
warn, crit = params.get(param)
|
||||
if warn > crit:
|
||||
levels_lower = warn, crit
|
||||
else:
|
||||
levels_upper = warn, crit
|
||||
yield from check_levels(
|
||||
section.get(item)[param],
|
||||
levels_upper = levels_upper,
|
||||
levels_lower = levels_lower,
|
||||
metric_name = param,
|
||||
render_func=lambda v: f"{v:.2f} {_UNIT_MAP[param]}",
|
||||
label = param,
|
||||
)
|
||||
|
||||
|
||||
|
||||
register.check_plugin(
|
||||
name="clever_pdu_130",
|
||||
service_name="%s",
|
||||
discovery_function=discover_clever_pdu_130,
|
||||
check_function=check_clever_pdu_130,
|
||||
check_ruleset_name="clever_pdu",
|
||||
check_default_parameters={
|
||||
"voltage": (220, 210),
|
||||
"current": (32, 33),
|
||||
"energy": (35000, 36000),
|
||||
},
|
||||
)
|
@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2019 tribe29 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.
|
||||
from typing import Mapping, Any
|
||||
from .agent_based_api.v1 import check_levels, equals, register, Service, SNMPTree, get_value_store, all_of, exists
|
||||
from .agent_based_api.v1.type_defs import CheckResult, DiscoveryResult, StringTable
|
||||
from .utils.humidity import check_humidity
|
||||
|
||||
CheckParams = Mapping[str, Any]
|
||||
|
||||
def parse_clever_pdu_humidity_120(string_table: StringTable):
|
||||
data=string_table[0]
|
||||
parsed = {}
|
||||
parsed = {
|
||||
"Master Humidity" : int(data[0]),
|
||||
}
|
||||
return parsed
|
||||
|
||||
|
||||
|
||||
register.snmp_section(
|
||||
name="clever_pdu_humidity_120",
|
||||
parsed_section_name="clever_pdu_humidity_120",
|
||||
parse_function=parse_clever_pdu_humidity_120,
|
||||
detect=all_of(
|
||||
equals(
|
||||
".1.3.6.1.2.1.1.2.0",
|
||||
".1.3.6.1.4.1.30966",
|
||||
),
|
||||
exists(".1.3.6.1.4.1.30966.10.3.2.70.0"),
|
||||
),
|
||||
fetch=SNMPTree(
|
||||
".1.3.6.1.4.1.30966.10.3.2",
|
||||
[
|
||||
"14", # mHumidity
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def discover_clever_pdu_humidity_120(section) -> DiscoveryResult:
|
||||
if section.get("Master Humidity") == 0:
|
||||
return
|
||||
else:
|
||||
yield from (Service(item=item) for item in section)
|
||||
|
||||
|
||||
def check_clever_pdu_humidity_120(item, params: CheckParams, section) -> CheckResult:
|
||||
yield from check_humidity(
|
||||
section.get("Master Humidity"),
|
||||
params,
|
||||
)
|
||||
|
||||
register.check_plugin(
|
||||
name="clever_pdu_humidity_120",
|
||||
service_name="%s",
|
||||
discovery_function=discover_clever_pdu_humidity_120,
|
||||
check_function=check_clever_pdu_humidity_120,
|
||||
check_ruleset_name="humidity",
|
||||
check_default_parameters={},
|
||||
|
||||
)
|
@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2019 tribe29 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.
|
||||
from typing import Mapping, Any
|
||||
from .agent_based_api.v1 import check_levels, equals, register, Service, SNMPTree, get_value_store, all_of, not_exists
|
||||
from .agent_based_api.v1.type_defs import CheckResult, DiscoveryResult, StringTable
|
||||
from .utils.humidity import check_humidity
|
||||
|
||||
CheckParams = Mapping[str, Any]
|
||||
|
||||
def parse_clever_pdu_humidity(string_table: StringTable):
|
||||
data=string_table[0]
|
||||
parsed = {}
|
||||
parsed = {
|
||||
"Master Humidity" : int(data[0]),
|
||||
}
|
||||
return parsed
|
||||
|
||||
|
||||
|
||||
register.snmp_section(
|
||||
name="clever_pdu_humidity",
|
||||
parsed_section_name="clever_pdu_humidity",
|
||||
parse_function=parse_clever_pdu_humidity,
|
||||
detect=all_of(
|
||||
equals(
|
||||
".1.3.6.1.2.1.1.2.0",
|
||||
".1.3.6.1.4.1.30966",
|
||||
),
|
||||
not_exists(".1.3.6.1.4.1.30966.10.3.2.70.0"),
|
||||
),
|
||||
fetch=SNMPTree(
|
||||
".1.3.6.1.4.1.30966.10.3.2",
|
||||
[
|
||||
"11", # mHumidity
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def discover_clever_pdu_humidity(section) -> DiscoveryResult:
|
||||
if section.get("Master Humidity") == 0:
|
||||
return
|
||||
else:
|
||||
yield from (Service(item=item) for item in section)
|
||||
|
||||
|
||||
def check_clever_pdu_humidity(item, params: CheckParams, section) -> CheckResult:
|
||||
yield from check_humidity(
|
||||
section.get("Master Humidity"),
|
||||
params,
|
||||
)
|
||||
|
||||
register.check_plugin(
|
||||
name="clever_pdu_humidity",
|
||||
service_name="%s",
|
||||
discovery_function=discover_clever_pdu_humidity,
|
||||
check_function=check_clever_pdu_humidity,
|
||||
check_ruleset_name="humidity",
|
||||
check_default_parameters={},
|
||||
|
||||
)
|
@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2019 tribe29 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.
|
||||
from dataclasses import dataclass
|
||||
from typing import Iterable, Mapping, Tuple, NamedTuple
|
||||
from .agent_based_api.v1 import check_levels, equals, register, Service, SNMPTree, get_value_store, all_of, exists
|
||||
from .agent_based_api.v1.type_defs import CheckResult, DiscoveryResult, StringTable
|
||||
from .utils.temperature import check_temperature, TempParamDict
|
||||
|
||||
def parse_clever_pdu_temp_120(string_table: StringTable):
|
||||
data=string_table[0]
|
||||
parsed = {}
|
||||
parsed = {
|
||||
"Master Temperature" : int(data[0]),
|
||||
}
|
||||
return parsed
|
||||
|
||||
|
||||
|
||||
register.snmp_section(
|
||||
name="clever_pdu_temp_120",
|
||||
parsed_section_name="clever_pdu_temp_120",
|
||||
parse_function=parse_clever_pdu_temp_120,
|
||||
detect = all_of(
|
||||
equals(
|
||||
".1.3.6.1.2.1.1.2.0",
|
||||
".1.3.6.1.4.1.30966",
|
||||
),
|
||||
exists(".1.3.6.1.4.1.30966.10.3.2.70.0"),
|
||||
),
|
||||
fetch=SNMPTree(
|
||||
".1.3.6.1.4.1.30966.10.3.2",
|
||||
[
|
||||
"13", # mTemperature
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def discover_clever_pdu_temp_120(section) -> DiscoveryResult:
|
||||
if section.get("Master Temperature") == 0:
|
||||
return
|
||||
else:
|
||||
yield from (Service(item=item) for item in section)
|
||||
|
||||
|
||||
def check_clever_pdu_temp_120(item, params: TempParamDict, section) -> CheckResult:
|
||||
if (temperature := section.get(item)) is None:
|
||||
return
|
||||
yield from check_temperature(
|
||||
reading=temperature,
|
||||
params=params,
|
||||
unique_name=item,
|
||||
value_store=get_value_store(),
|
||||
)
|
||||
|
||||
|
||||
|
||||
register.check_plugin(
|
||||
name="clever_pdu_temp_120",
|
||||
service_name="%s",
|
||||
discovery_function=discover_clever_pdu_temp_120,
|
||||
check_function=check_clever_pdu_temp_120,
|
||||
check_ruleset_name="temperature",
|
||||
check_default_parameters={},
|
||||
|
||||
)
|
@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2019 tribe29 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.
|
||||
from dataclasses import dataclass
|
||||
from typing import Iterable, Mapping, Tuple, NamedTuple
|
||||
from .agent_based_api.v1 import check_levels, equals, register, Service, SNMPTree, get_value_store, all_of, not_exists
|
||||
from .agent_based_api.v1.type_defs import CheckResult, DiscoveryResult, StringTable
|
||||
from .utils.temperature import check_temperature, TempParamDict
|
||||
|
||||
def parse_clever_pdu_temp(string_table: StringTable):
|
||||
data=string_table[0]
|
||||
parsed = {}
|
||||
parsed = {
|
||||
"Master Temperature" : int(data[0]),
|
||||
}
|
||||
return parsed
|
||||
|
||||
|
||||
|
||||
register.snmp_section(
|
||||
name="clever_pdu_temp",
|
||||
parsed_section_name="clever_pdu_temp",
|
||||
parse_function=parse_clever_pdu_temp,
|
||||
detect = all_of(
|
||||
equals(
|
||||
".1.3.6.1.2.1.1.2.0",
|
||||
".1.3.6.1.4.1.30966",
|
||||
),
|
||||
not_exists(".1.3.6.1.4.1.30966.10.3.2.70.0"),
|
||||
),
|
||||
fetch=SNMPTree(
|
||||
".1.3.6.1.4.1.30966.10.3.2",
|
||||
[
|
||||
"10", # mTemperature
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def discover_clever_pdu_temp(section) -> DiscoveryResult:
|
||||
if section.get("Master Temperature") == 0:
|
||||
return
|
||||
else:
|
||||
yield from (Service(item=item) for item in section)
|
||||
|
||||
|
||||
def check_clever_pdu_temp(item, params: TempParamDict, section) -> CheckResult:
|
||||
if (temperature := section.get(item)) is None:
|
||||
return
|
||||
yield from check_temperature(
|
||||
reading=temperature,
|
||||
params=params,
|
||||
unique_name=item,
|
||||
value_store=get_value_store(),
|
||||
)
|
||||
|
||||
|
||||
|
||||
register.check_plugin(
|
||||
name="clever_pdu_temp",
|
||||
service_name="%s",
|
||||
discovery_function=discover_clever_pdu_temp,
|
||||
check_function=check_clever_pdu_temp,
|
||||
check_ruleset_name="temperature",
|
||||
check_default_parameters={},
|
||||
|
||||
)
|
@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2019 tribe29 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.
|
||||
|
||||
from typing import Any, List, Mapping, Optional, Tuple, Union
|
||||
|
||||
from ..agent_based_api.v1 import check_levels, render, type_defs
|
||||
|
||||
CheckParams = Union[
|
||||
None, Mapping[str, Any], Optional[List[float]], Tuple[float, float, float, float]
|
||||
]
|
||||
|
||||
|
||||
def check_humidity(humidity: float, params: CheckParams) -> type_defs.CheckResult:
|
||||
levels_upper, levels_lower = None, None
|
||||
if isinstance(params, dict):
|
||||
levels_upper = params.get("levels") or None
|
||||
levels_lower = params.get("levels_lower") or None
|
||||
elif isinstance(params, (list, tuple)):
|
||||
# old params = (crit_low , warn_low, warn, crit)
|
||||
levels_upper = params[2], params[3]
|
||||
levels_lower = params[1], params[0]
|
||||
|
||||
yield from check_levels(
|
||||
humidity,
|
||||
levels_upper=levels_upper,
|
||||
levels_lower=levels_lower,
|
||||
metric_name="humidity",
|
||||
render_func=render.percent,
|
||||
boundaries=(0, 100),
|
||||
)
|
65
check_mk-clever-pdu/cmk2/plugins/wato/clever_pdu.py
Normal file
65
check_mk-clever-pdu/cmk2/plugins/wato/clever_pdu.py
Normal file
@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2019 tribe29 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.
|
||||
|
||||
from cmk.gui.i18n import _
|
||||
from cmk.gui.plugins.wato.utils import (
|
||||
CheckParameterRulespecWithItem,
|
||||
rulespec_registry,
|
||||
RulespecGroupCheckParametersEnvironment,
|
||||
)
|
||||
from cmk.gui.valuespec import Dictionary, Integer, TextInput, Tuple
|
||||
|
||||
|
||||
def _parameter_valuespec_clever_pdu():
|
||||
return Dictionary(
|
||||
elements=[
|
||||
(
|
||||
"voltage",
|
||||
Tuple(
|
||||
title=_("Voltage on Line"),
|
||||
elements=[
|
||||
Integer(title=_("warning at"), unit=_("V")),
|
||||
Integer(title=_("critical at"), unit=_("V")),
|
||||
],
|
||||
),
|
||||
),
|
||||
(
|
||||
"current",
|
||||
Tuple(
|
||||
title=_("Current on Power Channel"),
|
||||
elements=[
|
||||
Integer(title=_("warning if below"), unit=_("A")),
|
||||
Integer(title=_("critical if below"), unit=_("A")),
|
||||
],
|
||||
),
|
||||
),
|
||||
(
|
||||
"energy",
|
||||
Tuple(
|
||||
title=_("Active Energy of Line"),
|
||||
elements=[
|
||||
Integer(title=_("warning at"), unit=_("W")),
|
||||
Integer(title=_("critical at"), unit=_("W")),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
rulespec_registry.register(
|
||||
CheckParameterRulespecWithItem(
|
||||
check_group_name="clever_pdu",
|
||||
group=RulespecGroupCheckParametersEnvironment,
|
||||
item_spec=lambda: TextInput(
|
||||
title=_("Line"), help=_("The Line Number. Example: 'Line 1'.")
|
||||
),
|
||||
match_type="dict",
|
||||
parameter_valuespec=_parameter_valuespec_clever_pdu,
|
||||
title=lambda: _("Levels for Clever AC PDU Devices"),
|
||||
)
|
||||
)
|
||||
|
BIN
check_mk-graylog_metrics/graylog_input_metrics-0.0.3.mkp
Normal file
BIN
check_mk-graylog_metrics/graylog_input_metrics-0.0.3.mkp
Normal file
Binary file not shown.
@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2019 tribe29 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.
|
||||
|
||||
from cmk.gui.i18n import _
|
||||
from cmk.gui.plugins.wato.utils import (
|
||||
CheckParameterRulespecWithItem,
|
||||
rulespec_registry,
|
||||
RulespecGroupCheckParametersDiscovery,
|
||||
)
|
||||
from cmk.gui.valuespec import Dictionary, Float, Tuple
|
||||
|
||||
defaults={
|
||||
"im_rate_upper": 999999,
|
||||
"im_rate_lower": 0,
|
||||
"rs_rate_upper": 999999,
|
||||
"rs_rate_lower": 0,
|
||||
}
|
||||
mappings={
|
||||
"im": "messages",
|
||||
"rs": "bytes",
|
||||
"upper": "above",
|
||||
"lower": "below",
|
||||
}
|
||||
|
||||
|
||||
def _rate(metric, time, level):
|
||||
unit=mappings[metric]
|
||||
direction=mappings[level]
|
||||
return (
|
||||
f"{metric}_{time}_rate_{level}",
|
||||
Tuple(
|
||||
title=_(f"{level.capitalize()} level"),
|
||||
elements=[
|
||||
Float(
|
||||
title=_(f"Warning {direction}"),
|
||||
unit=f"{unit}/{time[1:]}min",
|
||||
default_value=defaults[f"{metric}_rate_{level}"],
|
||||
),
|
||||
Float(
|
||||
title=_(f"Critical {direction}"),
|
||||
unit=f"{unit}/{time[1:]}min",
|
||||
default_value=defaults[f"{metric}_rate_{level}"],
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def _element(metric, time):
|
||||
return (
|
||||
f"{metric}_{time}_rate",
|
||||
Dictionary(
|
||||
title=_(f"Incoming {mappings[metric]} for past {time[1:]} minute"),
|
||||
elements=[
|
||||
_rate(metric, time, "upper"),
|
||||
_rate(metric, time, "lower")
|
||||
]
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def _parameter_valuespec_graylog_input_metrics():
|
||||
matrix=[
|
||||
("im", "m1"), ("im", "m5"), ("im", "m15"),
|
||||
("rs", "m1"), ("rs", "m5"), ("rs", "m15"),
|
||||
]
|
||||
|
||||
elements=[
|
||||
_element(metric, time) for metric, time in matrix
|
||||
]
|
||||
|
||||
return Dictionary(
|
||||
title=_("Message and data rates"),
|
||||
help=_(
|
||||
"These rates are queried directly from the Graylog instance. "
|
||||
"Upper and lower levels can be specified for individual metric."
|
||||
),
|
||||
elements=elements
|
||||
)
|
||||
|
||||
|
||||
rulespec_registry.register(
|
||||
CheckParameterRulespecWithItem(
|
||||
check_group_name="graylog_input_metrics",
|
||||
group=RulespecGroupCheckParametersDiscovery,
|
||||
match_type="dict",
|
||||
parameter_valuespec=_parameter_valuespec_graylog_input_metrics,
|
||||
title=lambda: _("Graylog input metrics"),
|
||||
)
|
||||
)
|
@ -0,0 +1,154 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2019 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 argparse
|
||||
import json
|
||||
import sys
|
||||
from typing import NamedTuple
|
||||
|
||||
import requests
|
||||
import urllib3
|
||||
|
||||
import cmk.utils.password_store
|
||||
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
cmk.utils.password_store.replace_passwords()
|
||||
|
||||
|
||||
class GraylogSection(NamedTuple):
|
||||
name: str
|
||||
uri: str
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
if argv is None:
|
||||
argv = sys.argv[1:]
|
||||
|
||||
args = parse_arguments(argv)
|
||||
|
||||
try:
|
||||
handle_request(args)
|
||||
except Exception:
|
||||
if args.debug:
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def handle_request(args): # pylint: disable=too-many-branches
|
||||
url_base = f"{args.proto}://{args.hostname}:{args.port}/api"
|
||||
url = url_base + "/system/metrics"
|
||||
value = handle_response(url, args).json()
|
||||
|
||||
# Handle the input_metrics section. We need to merge information from
|
||||
# both inputstates and input_metrics, and we do that by extracting the
|
||||
# ids returned by both calls. Once merged, we return a single dictionary
|
||||
# with state, name, type, port, and the various rates (either raw or
|
||||
# incomingMessages).
|
||||
url_inputs_data = url_base + "/cluster/inputstates"
|
||||
inputs_data = handle_response(url_inputs_data, args).json()
|
||||
inputs_data = tuple(inputs_data.values())[0]
|
||||
metrics_data = value.get("meters")
|
||||
|
||||
if inputs_data is None or metrics_data is None:
|
||||
return
|
||||
|
||||
# Create a dictionary, containing all metrics with substrings
|
||||
# "incomingMessages" and "rawSize".
|
||||
# All rates should exist, created and with values as low as "0.0".
|
||||
metrics_dict = {}
|
||||
for metric, metric_rate in metrics_data.items():
|
||||
metric_id = metric.split(".")[-2]
|
||||
metric_type = None
|
||||
if "incomingMessages" in metric:
|
||||
metric_type = "im"
|
||||
elif "rawSize" in metric:
|
||||
metric_type = "rs"
|
||||
if metric_type:
|
||||
metric_key = metrics_dict.setdefault(metric_id, {})
|
||||
metric_key[f"{metric_type}_m1_rate"] = metric_rate["m1_rate"]
|
||||
metric_key[f"{metric_type}_m5_rate"] = metric_rate["m5_rate"]
|
||||
metric_key[f"{metric_type}_m15_rate"] = metric_rate["m15_rate"]
|
||||
|
||||
# Create a dictionary with all inputs and add the rates from
|
||||
# the previous dictionary, metrics_dict. This is passed as output.
|
||||
# Some inputs don't have a "port", so we handle this with .get("port").
|
||||
inputs_dict = {}
|
||||
for inputs in inputs_data:
|
||||
message_input = inputs["message_input"]
|
||||
input_id = inputs["id"]
|
||||
input_state = inputs["state"]
|
||||
input_name = message_input["title"]
|
||||
input_type = message_input["name"]
|
||||
input_port = message_input["attributes"].get("port")
|
||||
input_rate = metrics_dict[input_id]
|
||||
inputs_dict[input_id] = {
|
||||
"input_state": input_state,
|
||||
"input_name": input_name,
|
||||
"input_type": input_type,
|
||||
"input_port": input_port,
|
||||
"im_m1_rate": input_rate["im_m1_rate"],
|
||||
"im_m5_rate": input_rate["im_m5_rate"],
|
||||
"im_m15_rate": input_rate["im_m15_rate"],
|
||||
"rs_m1_rate": input_rate["rs_m1_rate"],
|
||||
"rs_m5_rate": input_rate["rs_m5_rate"],
|
||||
"rs_m15_rate": input_rate["rs_m15_rate"]
|
||||
}
|
||||
|
||||
if inputs_dict:
|
||||
handle_output(inputs_dict)
|
||||
|
||||
|
||||
def handle_response(url, args):
|
||||
try:
|
||||
return requests.get(url, auth=(args.user, args.password), verify=not args.no_cert_check)
|
||||
except requests.exceptions.RequestException as e:
|
||||
sys.stderr.write("Error: %s\n" % e)
|
||||
if args.debug:
|
||||
raise
|
||||
|
||||
|
||||
def handle_output(value):
|
||||
sys.stdout.write("<<<graylog_input_metrics:sep(0)>>>\n")
|
||||
if isinstance(value, list):
|
||||
for entry in value:
|
||||
sys.stdout.write("%s\n" % json.dumps(entry))
|
||||
return
|
||||
|
||||
sys.stdout.write("%s\n" % json.dumps(value))
|
||||
|
||||
return
|
||||
|
||||
|
||||
def parse_arguments(argv):
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
|
||||
parser.add_argument("-u", "--user", default=None, help="Username for graylog login")
|
||||
parser.add_argument("-s", "--password", default=None, help="Password for graylog login")
|
||||
parser.add_argument(
|
||||
"-P",
|
||||
"--proto",
|
||||
default="https",
|
||||
help="Use 'http' or 'https' for connection to graylog (default=https)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-p", "--port", default=443, type=int, help="Use alternative port (default: 443)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--debug", action="store_true", help="Debug mode: let Python exceptions come through"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--no-cert-check", action="store_true", help="Disable SSL certificate validation"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"hostname", metavar="HOSTNAME", help="Name of the graylog instance to query."
|
||||
)
|
||||
|
||||
return parser.parse_args(argv)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2019 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 sys
|
||||
|
||||
from cmk.special_agents.agent_graylog_input_metrics import main
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2019 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.
|
||||
#
|
||||
# {
|
||||
# 'proto': 'http',
|
||||
# 'port': 9000,
|
||||
# 'user': 'hell',
|
||||
# 'password': 'yeah',
|
||||
# }
|
||||
|
||||
from typing import Any, Mapping, Optional, Sequence, Union
|
||||
|
||||
|
||||
def agent_graylog_input_metrics_arguments(
|
||||
params: Mapping[str, Any], hostname: str, ipaddress: Optional[str]
|
||||
) -> Sequence[Union[str, tuple[str, str, str]]]:
|
||||
args = [
|
||||
"-P",
|
||||
params["protocol"],
|
||||
"-u",
|
||||
params["user"],
|
||||
"-s",
|
||||
passwordstore_get_cmdline("%s", params["password"]),
|
||||
]
|
||||
|
||||
if "port" in params:
|
||||
args += ["-p", params["port"]]
|
||||
|
||||
if "no-cert-check" in params:
|
||||
args += ["--no-cert-check"]
|
||||
|
||||
args.append(params["instance"])
|
||||
|
||||
return args
|
||||
|
||||
|
||||
special_agent_info["graylog_input_metrics"] = agent_graylog_input_metrics_arguments
|
@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env python3
|
||||
# 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.
|
||||
|
||||
# NOTE: Careful when replacing the *-import below with a more specific import. This can cause
|
||||
# problems because it might remove variables from the check-context which are necessary for
|
||||
# resolving legacy discovery results such as [("SUMMARY", "diskstat_default_levels")]. Furthermore,
|
||||
# it might also remove variables needed for accessing discovery rulesets.
|
||||
import json
|
||||
|
||||
#<<<graylog_input_metrics:sep(0)>>>
|
||||
# {"641e88d05d447a677efde199": {"input_state": "FAILED", "input_name": "kafka_cef_test",
|
||||
# "input_type": "CEF Kafka", "input_port": null, "im_m1_rate": 0.0, "im_m5_rate": 0.0,
|
||||
# "im_m15_rate": 0.0, "rs_m1_rate": 0.0, "rs_m5_rate": 0.0, "rs_m15_rate": 0.0},
|
||||
# "641e32885d447a677efd2dbf": {"input_state": "RUNNING", "input_name": "UDP-test",
|
||||
# "input_type": "Syslog UDP", "input_port": 1514, "im_m1_rate": 1.0846244336700077,
|
||||
# "im_m5_rate": 1.3700826278955827, "im_m15_rate": 1.254406787430692, "rs_m1_rate": 145.45579305762527,
|
||||
# "rs_m5_rate": 180.6486220431909, "rs_m15_rate": 165.26666376319292},
|
||||
# "641e32795d447a677efd2d9e": {"input_state": "RUNNING", "input_name": "testTCP", "input_type": "Syslog TCP",
|
||||
# "input_port": 1515, "im_m1_rate": 1.057872514816615, "im_m5_rate": 1.364957693749168,
|
||||
# "im_m15_rate": 1.2528742858546844, "rs_m1_rate": 140.4719944116262, "rs_m5_rate": 178.57816158901215,
|
||||
# "rs_m15_rate": 163.80530659055356}}
|
||||
|
||||
def parse_graylog_input_metrics(section):
|
||||
parsed = json.loads(section[0][0])
|
||||
return parsed
|
||||
|
||||
|
||||
def inventory_graylog_input_metrics(parsed):
|
||||
for input_id, input_info in parsed.items():
|
||||
input_name = input_info["input_name"]
|
||||
yield Service(f"{input_name} ({input_id})")
|
||||
|
||||
|
||||
def check_graylog_input_metrics(item, params, parsed):
|
||||
# if parsed is None: return
|
||||
|
||||
item_id = item.split()[-1][1:-1]
|
||||
input_info = parsed[item_id]
|
||||
input_state = input_info["input_state"]
|
||||
|
||||
state = 1
|
||||
if input_state == "RUNNING": state = 0
|
||||
elif input_state == "FAILED": state = 2
|
||||
|
||||
yield state, "State: %s" % input_state
|
||||
yield 0, "Type: %s" % input_info["input_type"]
|
||||
|
||||
if input_info["input_port"]:
|
||||
yield 0, "Port: %s" % input_info["input_port"]
|
||||
|
||||
for key, dsname, unit, unit_func, infotext in [
|
||||
("im_m1_rate", "im_m1_rate", "/1min", float, "Incoming messages"),
|
||||
("im_m5_rate", "im_m5_rate", "/5min", float, ""),
|
||||
("im_m15_rate", "im_m15_rate", "/15min", float, ""),
|
||||
("rs_m1_rate", "rs_m1_rate", "/1min", get_bytes_human_readable, "Incoming data"),
|
||||
("rs_m5_rate", "rs_m5_rate", "/5min", get_bytes_human_readable, ""),
|
||||
("rs_m15_rate", "rs_m15_rate", "/15min", get_bytes_human_readable, ""),
|
||||
]:
|
||||
|
||||
value = parsed[item_id][key]
|
||||
value = round(value, 2)
|
||||
rate_upper = params.get(key, {}).get("%s_upper" % key, (None, None))
|
||||
rate_lower = params.get(key, {}).get("%s_lower" % key, (None, None))
|
||||
yield check_levels(
|
||||
value,
|
||||
dsname,
|
||||
rate_upper + rate_lower,
|
||||
human_readable_func=unit_func,
|
||||
unit=unit,
|
||||
infoname=infotext
|
||||
)
|
||||
|
||||
check_info["graylog_input_metrics"] = {
|
||||
"parse_function": parse_graylog_input_metrics,
|
||||
"check_function": check_graylog_input_metrics,
|
||||
"inventory_function": inventory_graylog_input_metrics,
|
||||
"service_description": "Graylog Input %s",
|
||||
"has_perfdata": True,
|
||||
"group": "graylog_input_metrics",
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2019 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.
|
||||
|
||||
|
||||
from cmk.gui.i18n import _
|
||||
from cmk.gui.plugins.wato.special_agents.common import RulespecGroupDatasourceProgramsApps
|
||||
from cmk.gui.plugins.wato.utils import HostRulespec, IndividualOrStoredPassword, rulespec_registry
|
||||
from cmk.gui.valuespec import Age, Dictionary, DropdownChoice, Integer, ListChoice, TextInput
|
||||
from cmk.gui.watolib.rulespecs import Rulespec
|
||||
|
||||
|
||||
def _factory_default_special_agents_graylog_input_metrics():
|
||||
# No default, do not use setting if no rule matches
|
||||
return Rulespec.FACTORY_DEFAULT_UNUSED
|
||||
|
||||
|
||||
def _valuespec_special_agents_graylog_input_metrics():
|
||||
return Dictionary(
|
||||
title=_("Graylog Input Metrics"),
|
||||
help=_("Requests input metrics data from a Graylog instance."),
|
||||
optional_keys=["port", "no-cert-check"],
|
||||
elements=[
|
||||
(
|
||||
"instance",
|
||||
TextInput(
|
||||
title=_("Graylog instance to query"),
|
||||
help=_(
|
||||
"Use this option to set which instance should be "
|
||||
"checked by the special agent. Please add the "
|
||||
"hostname here, eg. my_graylog.com."
|
||||
),
|
||||
size=32,
|
||||
allow_empty=False,
|
||||
),
|
||||
),
|
||||
(
|
||||
"user",
|
||||
TextInput(
|
||||
title=_("Username"),
|
||||
help=_(
|
||||
"The username that should be used for accessing the "
|
||||
"Graylog API. Has to have read permissions at least."
|
||||
),
|
||||
size=32,
|
||||
allow_empty=False,
|
||||
),
|
||||
),
|
||||
(
|
||||
"password",
|
||||
IndividualOrStoredPassword(
|
||||
title=_("Password of the user"),
|
||||
allow_empty=False,
|
||||
),
|
||||
),
|
||||
(
|
||||
"protocol",
|
||||
DropdownChoice(
|
||||
title=_("Protocol"),
|
||||
choices=[
|
||||
("http", "HTTP"),
|
||||
("https", "HTTPS"),
|
||||
],
|
||||
default_value="https",
|
||||
),
|
||||
),
|
||||
(
|
||||
"port",
|
||||
Integer(
|
||||
title=_("Port"),
|
||||
help=_(
|
||||
"Use this option to query a port which is different from standard port 443."
|
||||
),
|
||||
default_value=443,
|
||||
),
|
||||
),
|
||||
(
|
||||
"no-cert-check",
|
||||
FixedValue(
|
||||
True,
|
||||
title=_("Disable SSL certificate validation"),
|
||||
totext=_("SSL certificate validation is disabled"),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
rulespec_registry.register(
|
||||
HostRulespec(
|
||||
factory_default=_factory_default_special_agents_graylog_input_metrics(),
|
||||
group=RulespecGroupDatasourceProgramsApps,
|
||||
name="special_agents:graylog_input_metrics",
|
||||
valuespec=_valuespec_special_agents_graylog_input_metrics,
|
||||
)
|
||||
)
|
BIN
check_mk-informix/Informix_transactions-1.0.1.mkp
Normal file
BIN
check_mk-informix/Informix_transactions-1.0.1.mkp
Normal file
Binary file not shown.
22
check_mk-informix/README.MD
Normal file
22
check_mk-informix/README.MD
Normal file
@ -0,0 +1,22 @@
|
||||
{'author': 'George Pochiscan',
|
||||
'description': 'This package extends current informix package with the '
|
||||
'following checks:\n'
|
||||
'\n'
|
||||
'Alert if the number of locks kept by a session is higher than '
|
||||
'a specific number (configured by WATO rule).\n'
|
||||
'Inactive transactions with locks \n'
|
||||
'Long transactions\n',
|
||||
'download_url': '',
|
||||
'files': {'agents': ['plugins/mk_informix'],
|
||||
'checkman': ['informix_transactions_activity',
|
||||
'informix_transactions_locks',
|
||||
'informix_transactions_long_transactions'],
|
||||
'checks': ['informix_transactions'],
|
||||
'web': ['plugins/wato/informix_nlocks.py']},
|
||||
'name': 'Informix_transactions',
|
||||
'num_files': 6,
|
||||
'title': 'Informix monitoring',
|
||||
'version': '1.0.1',
|
||||
'version.min_required': '2.0.0p17',
|
||||
'version.packaged': '2.0.0p17',
|
||||
'version.usable_until': None}
|
16
check_mk-informix/checkman/informix_transactions_activity
Normal file
16
check_mk-informix/checkman/informix_transactions_activity
Normal file
@ -0,0 +1,16 @@
|
||||
title: Informix DB: Sessions with no activity in current log
|
||||
agents: linux
|
||||
catalog: app/informix
|
||||
license: GPL
|
||||
distribution: check_mk
|
||||
description:
|
||||
This checks monitors the transactions that doesn't
|
||||
have activity in current log in Informix Database application.
|
||||
|
||||
No rules are needed.
|
||||
|
||||
item:
|
||||
Name of the instance
|
||||
|
||||
inventory:
|
||||
One service is created for each instance.
|
16
check_mk-informix/checkman/informix_transactions_locks
Normal file
16
check_mk-informix/checkman/informix_transactions_locks
Normal file
@ -0,0 +1,16 @@
|
||||
title: Informix DB: Sessions with high number of locks
|
||||
agents: linux
|
||||
catalog: app/informix
|
||||
license: GPL
|
||||
distribution: check_mk
|
||||
description:
|
||||
This checks monitors the sessions that have
|
||||
high number of locks in Informix Database application.
|
||||
|
||||
WARN and CRIT levels can be specified.
|
||||
|
||||
item:
|
||||
Name of the instance
|
||||
|
||||
inventory:
|
||||
One service is created for each instance.
|
@ -0,0 +1,16 @@
|
||||
title: Informix DB: Long transactions that are using more than 3 logical logs
|
||||
agents: linux
|
||||
catalog: app/informix
|
||||
license: GPL
|
||||
distribution: check_mk
|
||||
description:
|
||||
This checks monitors the transactions that are using
|
||||
more than 3 logical logs in Informix Database application.
|
||||
|
||||
No rules are needed.
|
||||
|
||||
item:
|
||||
Name of the instance
|
||||
|
||||
inventory:
|
||||
One service is created for each instance.
|
143
check_mk-informix/checks/informix_transactions
Normal file
143
check_mk-informix/checks/informix_transactions
Normal file
@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2019 tribe29 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.
|
||||
|
||||
factory_settings['informix_transactions_default_levels'] = {
|
||||
'levels': (70, 80),
|
||||
}
|
||||
#first line represents current log ID
|
||||
#line[2]= sessionID
|
||||
#line[3]= number of locks kept by sessionID
|
||||
#line[4]= begin log position
|
||||
#line[5]= current log position
|
||||
|
||||
|
||||
def parse_informix_transactions(info):
|
||||
parsed = {}
|
||||
instance = None
|
||||
entry = None
|
||||
for line in info:
|
||||
if line[0].startswith("[[[") and line[0].endswith("]]]"):
|
||||
instance = line[0][3:-3]
|
||||
elif instance is not None:
|
||||
entry = {}
|
||||
parsed.setdefault(instance, [])
|
||||
parsed[instance].append(entry)
|
||||
|
||||
if len(line) > 2:
|
||||
if "C" in line[2]:
|
||||
entry.setdefault("current_log_id", line[3])
|
||||
elif entry is not None:
|
||||
if ":" in str(line[4]):
|
||||
line[4] = line[4].split(":",1)[0]
|
||||
if ":" in str(line[5]):
|
||||
line[5] = line[5].split(":",1)[0]
|
||||
|
||||
entry.setdefault("session", [line[2], line[3], line[4], line[5]])
|
||||
return parsed
|
||||
|
||||
#############Transaction with more than 70 locks
|
||||
def inventory_informix_transactions_locks(parsed):
|
||||
return [(instance, {}) for instance in parsed]
|
||||
|
||||
|
||||
def check_informix_transactions_locks(item, params, parsed):
|
||||
if item in parsed:
|
||||
warn, crit = params['levels']
|
||||
data = parsed[item]
|
||||
infotext = ""
|
||||
state = 0
|
||||
for session in data[1:]:
|
||||
if session and session["session"][2]:
|
||||
if "-" not in session["session"][1]:
|
||||
if int(session["session"][1]) >= crit:
|
||||
state = 2
|
||||
infotext += 'Session with ID %s has %s locks; ' % (session["session"][0], session["session"][1])
|
||||
elif int(session["session"][1]) >= warn:
|
||||
state = 1
|
||||
infotext += 'Session with ID %s has %s locks; ' % (session["session"][0], session["session"][1])
|
||||
|
||||
if state:
|
||||
infotext += " (warn/crit at %s/%s)" % (warn, crit)
|
||||
else:
|
||||
infotext = 'There are no sessions with high number of locks'
|
||||
return state, infotext, []
|
||||
|
||||
|
||||
check_info['informix_transactions.locks'] = {
|
||||
'parse_function': parse_informix_transactions,
|
||||
'inventory_function': inventory_informix_transactions_locks,
|
||||
'check_function': check_informix_transactions_locks,
|
||||
'has_perfdata': False,
|
||||
'service_description': 'Informix sessions nLocks %s',
|
||||
"group": "informix_nlocks",
|
||||
'default_levels_variable': 'informix_transactions_default_levels',
|
||||
}
|
||||
|
||||
|
||||
#############Sesiuni fara activitate in logul curent
|
||||
def inventory_informix_transactions_activity(parsed):
|
||||
return [(instance, {}) for instance in parsed]
|
||||
|
||||
|
||||
def check_informix_transactions_activity(item, no_params, parsed):
|
||||
if item in parsed:
|
||||
data = parsed[item]
|
||||
state = 0
|
||||
infotext = ''
|
||||
for session in data[1:]:
|
||||
if session and session["session"][2]:
|
||||
if "-" not in session["session"][2]:
|
||||
if int(session["session"][2]) < int(data[0]['current_log_id']):
|
||||
state = 2
|
||||
infotext += "Session %s doesn't have activity in current log; " % (session["session"][0])
|
||||
|
||||
|
||||
if not state:
|
||||
infotext = 'There are no sessions with no activity in current log; '
|
||||
|
||||
return state, infotext, []
|
||||
|
||||
|
||||
check_info['informix_transactions.activity'] = {
|
||||
'parse_function': parse_informix_transactions,
|
||||
'inventory_function': inventory_informix_transactions_activity,
|
||||
'check_function': check_informix_transactions_activity,
|
||||
'has_perfdata': False,
|
||||
'service_description': 'Informix sessions activity %s',
|
||||
}
|
||||
|
||||
#############Long transactions (over 3 logical logs used)
|
||||
def inventory_informix_long_transactions(parsed):
|
||||
return [(instance, {}) for instance in parsed]
|
||||
|
||||
|
||||
def check_informix_long_transactions(item, no_params, parsed):
|
||||
if item in parsed:
|
||||
data = parsed[item]
|
||||
state = 0
|
||||
infotext = ''
|
||||
for session in data[1:]:
|
||||
if session and session["session"][2]:
|
||||
if "-" not in session["session"][2]:
|
||||
if (int(session["session"][2]) - int(session["session"][3])) < 2:
|
||||
state = 2
|
||||
infotext += "Session %s is using more than 3 logical logs; " % (session["session"][0])
|
||||
|
||||
|
||||
if not state:
|
||||
infotext = 'There are no long running transactions; '
|
||||
|
||||
return state, infotext, []
|
||||
|
||||
|
||||
check_info['informix_transactions.long_transactions'] = {
|
||||
'parse_function': parse_informix_transactions,
|
||||
'inventory_function': inventory_informix_long_transactions,
|
||||
'check_function': check_informix_long_transactions,
|
||||
'has_perfdata': False,
|
||||
'service_description': 'Informix sessions Long transactions %s',
|
||||
}
|
||||
|
296
check_mk-informix/plugins/mk_informix
Executable file
296
check_mk-informix/plugins/mk_informix
Executable file
@ -0,0 +1,296 @@
|
||||
#!/bin/bash
|
||||
# Copyright (C) 2019 tribe29 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.
|
||||
|
||||
# Reason for this no-op: shellcheck disable=... before the first command disables the error for the
|
||||
# entire script.
|
||||
:
|
||||
|
||||
# Disable unused variable error (needed to keep track of version)
|
||||
# shellcheck disable=SC2034
|
||||
CMK_VERSION="2.0.0p17"
|
||||
|
||||
# Informix
|
||||
# Make ENV-VARs avail for subshells
|
||||
set -a
|
||||
|
||||
# .--helper--------------------------------------------------------------.
|
||||
# | _ _ |
|
||||
# | | |__ ___| |_ __ ___ _ __ |
|
||||
# | | '_ \ / _ \ | '_ \ / _ \ '__| |
|
||||
# | | | | | __/ | |_) | __/ | |
|
||||
# | |_| |_|\___|_| .__/ \___|_| |
|
||||
# | |_| |
|
||||
# '----------------------------------------------------------------------'
|
||||
|
||||
|
||||
function do_check () {
|
||||
# $1:section, $2:excludelist
|
||||
if echo "$2" | grep -qe "${1}"; then
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
function sql () {
|
||||
db="sysmaster"
|
||||
sqltxt="$1"
|
||||
export DBDELIMITER="|"
|
||||
echo "$sqltxt" | dbaccess ${db}
|
||||
}
|
||||
|
||||
|
||||
function set_excludes () {
|
||||
excludes=""
|
||||
if [ "$EXCLUDES" = "ALL" ]; then
|
||||
excludes="$all_sections"
|
||||
global_exclude=true
|
||||
elif [ ! -z "$EXCLUDES" ]; then
|
||||
excludes=$EXCLUDES
|
||||
global_exclude=true
|
||||
else
|
||||
global_exclude=false
|
||||
fi
|
||||
|
||||
if [ "$global_exclude" = "false" ]; then
|
||||
excludes_i="EXCLUDES_${1}"
|
||||
if [ "${!excludes_i}" = "ALL" ]; then
|
||||
excludes="$all_sections"
|
||||
elif [ ! -z "${!excludes_i}" ]; then
|
||||
excludes=${!excludes_i}
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
#.
|
||||
# .--sqls----------------------------------------------------------------.
|
||||
# | _ |
|
||||
# | ___ __ _| |___ |
|
||||
# | / __|/ _` | / __| |
|
||||
# | \__ \ (_| | \__ \ |
|
||||
# | |___/\__, |_|___/ |
|
||||
# | |_| |
|
||||
# '----------------------------------------------------------------------'
|
||||
|
||||
|
||||
all_sections="sessions locks tabextents dbspaces logusage"
|
||||
|
||||
|
||||
function informix_status(){
|
||||
echo "<<<informix_status:sep(58)>>>"
|
||||
echo "[[[$INFORMIXSERVER/$SERVERNUM]]]"
|
||||
$INFORMIXDIR/bin/onstat - >/dev/null 2>&1
|
||||
state=$?
|
||||
echo "Status:"$state
|
||||
$INFORMIXDIR/bin/onstat -g dis
|
||||
port=$(grep $INFORMIXSERVER /etc/services)
|
||||
echo "PORT:"$port
|
||||
}
|
||||
|
||||
|
||||
function informix_sessions(){
|
||||
echo "<<<informix_sessions>>>"
|
||||
echo "[[[$INFORMIXSERVER/$SERVERNUM]]]"
|
||||
# don't count our own session
|
||||
sql "select 'SESSIONS', (count(*)-1)::int from syssessions"
|
||||
}
|
||||
|
||||
|
||||
function informix_locks(){
|
||||
echo "<<<informix_locks>>>"
|
||||
echo "[[[$INFORMIXSERVER/$SERVERNUM]]]"
|
||||
# don't count our own session
|
||||
sql "select 'LOCKS', (count(*)-1)::int, type from syslocks group by type"
|
||||
}
|
||||
|
||||
|
||||
function informix_tabextents(){
|
||||
echo "<<<informix_tabextents>>>"
|
||||
echo "[[[$INFORMIXSERVER/$SERVERNUM]]]"
|
||||
sql "select first 10
|
||||
'TABEXTENTS',
|
||||
trim(n.dbsname) db,
|
||||
trim(n.tabname) tab,
|
||||
h.nextns extents,
|
||||
nrows
|
||||
from sysptnhdr h, systabnames n
|
||||
where h.partnum = n.partnum
|
||||
and nrows > 0
|
||||
and n.dbsname not in ( 'sysadmin', 'sysuser', 'sysutils', 'sysmaster' )
|
||||
and n.tabname not like 'sys%'
|
||||
order by extents desc"
|
||||
}
|
||||
|
||||
|
||||
function informix_dbspaces(){
|
||||
echo "<<<informix_dbspaces>>>"
|
||||
echo "[[[$INFORMIXSERVER/$SERVERNUM]]]"
|
||||
sql "select
|
||||
trim(sd.name) || ' DBSPACE',
|
||||
sd.dbsnum,
|
||||
sd.is_temp,
|
||||
sd.flags,
|
||||
'CHUNK',
|
||||
sc.fname,
|
||||
sc.pagesize,
|
||||
sc.chksize,
|
||||
sc.nfree,
|
||||
sc.flags,
|
||||
trim(sc.mfname),
|
||||
sc.mflags
|
||||
from sysdbspaces sd, syschunks sc
|
||||
where sd.dbsnum = sc.dbsnum
|
||||
-- NO SBSPACE CURRENTLY
|
||||
and sd.is_sbspace = 0
|
||||
order by sd.name"
|
||||
}
|
||||
|
||||
|
||||
function informix_logusage(){
|
||||
echo "<<<informix_logusage>>>"
|
||||
echo "[[[$INFORMIXSERVER/$SERVERNUM]]]"
|
||||
sql "select 'LOGUSAGE',
|
||||
number,
|
||||
sh_pagesize,
|
||||
size,
|
||||
used,
|
||||
flags,
|
||||
'is_used:'||is_used,
|
||||
'is_current:'||is_current,
|
||||
'is_backed_up:'||is_backed_up,
|
||||
'is_new:'||is_new,
|
||||
'is_archived:'||is_archived,
|
||||
'is_temp:'||is_temp,
|
||||
'is_pre_dropped:'||is_pre_dropped
|
||||
from syslogs, sysshmvals
|
||||
order by number"
|
||||
}
|
||||
|
||||
|
||||
function informix_transactions(){
|
||||
echo "<<<informix_transactions>>>"
|
||||
echo "[[[$INFORMIXSERVER/$SERVERNUM]]]"
|
||||
$INFORMIXDIR/bin/onstat -l | grep C | tail -n 1
|
||||
$INFORMIXDIR/bin/onstat -x |egrep -v "IBM|maximum|Transactions|est.|userthread" | sed 's/:[^:]*$//'
|
||||
}
|
||||
#.
|
||||
# .--config--------------------------------------------------------------.
|
||||
# | __ _ |
|
||||
# | ___ ___ _ __ / _(_) __ _ |
|
||||
# | / __/ _ \| '_ \| |_| |/ _` | |
|
||||
# | | (_| (_) | | | | _| | (_| | |
|
||||
# | \___\___/|_| |_|_| |_|\__, | |
|
||||
# | |___/ |
|
||||
# '----------------------------------------------------------------------'
|
||||
|
||||
|
||||
# Config opts:
|
||||
# - oninit-path; Default is empty, which means autodetection:
|
||||
# ONINIT_PATH=<path to oninit-binary>
|
||||
# - Excluding sections ("status sessions locks tabextents dbspaces logusage"):
|
||||
# EXCLUDES_INFORMIX_INSTANCE="SECTION SECTION ..."
|
||||
# EXCLUDES_INFORMIX_INSTANCE=ALL
|
||||
# EXCLUDES="SECTION SECTION ..."
|
||||
# EXCLUDES=ALL
|
||||
|
||||
|
||||
if [ -f "$MK_CONFDIR/informix.cfg" ]; then
|
||||
. $MK_CONFDIR/informix.cfg
|
||||
fi
|
||||
|
||||
|
||||
if [ -z "$ONINIT_PATH" -o ! -x "$ONINIT_PATH" ]; then
|
||||
ONINIT=$(UNIX95=true ps ax | grep oninit | grep -v grep | head -1 | awk '{print $1 " " $5}')
|
||||
if [ -z "$ONINIT" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
ONINIT_PATH=${ONINIT#* }
|
||||
ONINIT_PID=${ONINIT% *}
|
||||
case "$ONINIT_PATH" in
|
||||
/*)
|
||||
;;
|
||||
*) # BUG not platform independent!
|
||||
ONINIT_PATH=$(ls -l /proc/$ONINIT_PID/exe 2>/dev/null| sed 's/.* //')
|
||||
;;
|
||||
esac
|
||||
|
||||
# If not set in config or not found we end up here
|
||||
if [ -z "$ONINIT_PATH" -o ! -f "$ONINIT_PATH" ]; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
#.
|
||||
# .--main----------------------------------------------------------------.
|
||||
# | _ |
|
||||
# | _ __ ___ __ _(_)_ __ |
|
||||
# | | '_ ` _ \ / _` | | '_ \ |
|
||||
# | | | | | | | (_| | | | | | |
|
||||
# | |_| |_| |_|\__,_|_|_| |_| |
|
||||
# | |
|
||||
# '----------------------------------------------------------------------'
|
||||
|
||||
|
||||
for IDSENV in $( export INFORMIXDIR=${ONINIT_PATH%/bin*}
|
||||
$INFORMIXDIR/bin/onstat -g dis | \
|
||||
egrep '^Server[ ]*:|^Server Number[ ]*:|^INFORMIX|^SQLHOSTS|^ONCONFIG' | \
|
||||
sed -e 's/Server Number/SERVERNUM/' \
|
||||
-e 's/Server/INFORMIXSERVER/' \
|
||||
-e 's/SQLHOSTS/INFORMIXSQLHOSTS/' \
|
||||
-e 's/[ ]*:[ ]*/=/' | \
|
||||
tr '\n' ';' | \
|
||||
sed -e 's/;$/\\n/' -e 's/;\(INFORMIXSERVER=[^;]*;\)/\\n\1/g' | \
|
||||
awk '{ gsub(/\\n/,"\n")}1'
|
||||
) ; do
|
||||
(
|
||||
# Set environment
|
||||
eval $IDSENV
|
||||
PATH=$INFORMIXDIR/bin:$PATH
|
||||
|
||||
# try to set them via 'onstat -g env' otherwise
|
||||
# DB HAS TO BE RUNNING
|
||||
if [ -z "$INFORMIXSQLHOSTS" -o -z "$ONCONFIG" ]; then
|
||||
onstat -g env | egrep -e '^INFORMIXSQLHOSTS' \
|
||||
-e '^ONCONFIG' | \
|
||||
sed -e 's/[ ][ ]*/=/'
|
||||
fi
|
||||
|
||||
informix_status
|
||||
|
||||
set_excludes $INFORMIXSERVER
|
||||
|
||||
if do_check "sessions" "$excludes"; then
|
||||
informix_sessions
|
||||
fi
|
||||
|
||||
if do_check "locks" "$excludes"; then
|
||||
informix_locks
|
||||
fi
|
||||
|
||||
if do_check "tabextents" "$excludes"; then
|
||||
informix_tabextents
|
||||
fi
|
||||
|
||||
if do_check "dbspaces" "$excludes"; then
|
||||
informix_dbspaces
|
||||
fi
|
||||
|
||||
if do_check "logusage" "$excludes"; then
|
||||
informix_logusage
|
||||
fi
|
||||
|
||||
if do_check "transactions" "$excludes"; then
|
||||
informix_transactions
|
||||
fi
|
||||
|
||||
)
|
||||
done
|
||||
|
||||
|
||||
|
44
check_mk-informix/web/plugins/wato/informix_nlocks.py
Normal file
44
check_mk-informix/web/plugins/wato/informix_nlocks.py
Normal file
@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2019 tribe29 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.
|
||||
|
||||
from cmk.gui.i18n import _
|
||||
from cmk.gui.valuespec import (
|
||||
Dictionary,
|
||||
Integer,
|
||||
Tuple,
|
||||
)
|
||||
|
||||
from cmk.gui.plugins.wato import (
|
||||
CheckParameterRulespecWithoutItem,
|
||||
rulespec_registry,
|
||||
RulespecGroupCheckParametersApplications,
|
||||
)
|
||||
|
||||
|
||||
def _parameter_valuespec_informix_nlocks():
|
||||
return Dictionary(elements=[
|
||||
("levels",
|
||||
Tuple(
|
||||
title=_("Levels for number of locks for a session"),
|
||||
help=
|
||||
_("You can set a limit to the number of locks for a session in Informix Database application"
|
||||
),
|
||||
elements=[
|
||||
Integer(title=_("Warning at"), default_value=40),
|
||||
Integer(title=_("Critical at"), default_value=70),
|
||||
],
|
||||
)),
|
||||
])
|
||||
|
||||
|
||||
rulespec_registry.register(
|
||||
CheckParameterRulespecWithoutItem(
|
||||
check_group_name="informix_nlocks",
|
||||
group=RulespecGroupCheckParametersApplications,
|
||||
match_type="dict",
|
||||
parameter_valuespec=_parameter_valuespec_informix_nlocks,
|
||||
title=lambda: _("Informix number of Locks"),
|
||||
))
|
9
check_mk-scality-ring/README.MD
Normal file
9
check_mk-scality-ring/README.MD
Normal file
@ -0,0 +1,9 @@
|
||||
This plugin monitors Scality Ring Supervisor through SNMP.
|
||||
New checks added:
|
||||
Ring Disks: Monitors the number of disks per ring. Parameters can be set for warn/crit if the number of disks reported is below a value.
|
||||
|
||||
Ring Stage: Monitors the Ring Status. If the ring is not in Run State, service will be CRIT.
|
||||
|
||||
Ring Storage: Storage used per Ring. Parameters can be set and the general filesystem parameters are used.
|
||||
|
||||
Supervisor Status: Monitors the supervisor status and server status. If the supervisor is not available or any of the servers are not OK, the service goes CRIT.
|
BIN
check_mk-scality-ring/ScalityRing-1.0.1.mkp
Normal file
BIN
check_mk-scality-ring/ScalityRing-1.0.1.mkp
Normal file
Binary file not shown.
167
check_mk-scality-ring/local/share/check_mk/checks/scality
Normal file
167
check_mk-scality-ring/local/share/check_mk/checks/scality
Normal file
@ -0,0 +1,167 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2019 tribe29 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.
|
||||
|
||||
# NOTE: Careful when replacing the *-import below with a more specific import. This can cause
|
||||
# problems because it might remove variables from the check-context which are necessary for
|
||||
# resolving legacy discovery results such as [("SUMMARY", "diskstat_default_levels")]. Furthermore,
|
||||
# it might also remove variables needed for accessing discovery rulesets.
|
||||
#from cmk.base.check_legacy_includes.cisco_sensor_item import * # pylint: disable=wildcard-import,unused-wildcard-import
|
||||
|
||||
|
||||
def inventory_scality_disk(info):
|
||||
for line in info[0]:
|
||||
yield (line[0],{})
|
||||
|
||||
def check_scality_disk(item, params, info):
|
||||
if params.get("disks"):
|
||||
warn, crit = params["disks"]
|
||||
for line in info[0]:
|
||||
if item in line:
|
||||
ringdisktotal = int(line[3])
|
||||
perfdata = [("Disks", ringdisktotal)]
|
||||
infotext = "Number of disks: %s. " %ringdisktotal
|
||||
if ringdisktotal <= warn:
|
||||
if ringdisktotal <= crit:
|
||||
infotext += "This is lower or equal with %s, critical level" %crit
|
||||
yield 2, infotext, perfdata
|
||||
else:
|
||||
infotext += "This is lower or equal with %s, warning level" %warn
|
||||
yield 1, infotext, perfdata
|
||||
else:
|
||||
yield 0, infotext, perfdata
|
||||
|
||||
else:
|
||||
for line in info[0]:
|
||||
if item in line:
|
||||
ringdisktotal = line[3]
|
||||
perfdata = [("Disks", ringdisktotal)]
|
||||
infotext = "Number of disks: %s" %ringdisktotal
|
||||
yield 0, infotext, perfdata
|
||||
|
||||
check_info["scality_ring.disk"] = {
|
||||
"check_function": check_scality_disk,
|
||||
"inventory_function": inventory_scality_disk,
|
||||
"service_description": "Ring %s Disks",
|
||||
"has_perfdata": True,
|
||||
"group": "scality_disks"
|
||||
}
|
||||
##############RING STATUS############
|
||||
def inventory_scality_supervisor(info):
|
||||
for line in info[1]:
|
||||
yield (line[0],{})
|
||||
|
||||
def check_scality_supervisor(item, no_params, info):
|
||||
for line in info[1]:
|
||||
if item == str(line[0]):
|
||||
infotext = ""
|
||||
status = 0
|
||||
supNbSrvTotal = int(line[1])
|
||||
supNbSrvOk = int(line[2])
|
||||
supNbSrvNok = int(line[3])
|
||||
supAvailable = int(line[4])
|
||||
if supAvailable != 1 :
|
||||
status = 2
|
||||
infotext += "Supervisor is not available"
|
||||
yield status, infotext
|
||||
else:
|
||||
infotext = "Supervisor is available "
|
||||
yield status, infotext
|
||||
if supNbSrvNok > 0 :
|
||||
status = 2
|
||||
infotext = "There are %s unavailable servers" %supNbSrvNok
|
||||
yield status, infotext
|
||||
else:
|
||||
infotext = "All servers are available"
|
||||
yield status, infotext
|
||||
|
||||
|
||||
|
||||
check_info["scality_ring.supervisor"] = {
|
||||
"check_function": check_scality_supervisor,
|
||||
"inventory_function": inventory_scality_supervisor,
|
||||
"service_description": "Supervisor %s",
|
||||
}
|
||||
|
||||
|
||||
#############Storage#############
|
||||
from cmk.base.check_legacy_includes.df import *
|
||||
from cmk.base.check_legacy_includes.size_trend import *
|
||||
#factory_settings["filesystem_default_levels"] = FILESYSTEM_DEFAULT_LEVELS
|
||||
|
||||
def inventory_scality_storage(info):
|
||||
for line in info[0]:
|
||||
yield (line[0],{})
|
||||
|
||||
def check_scality_storage(item, params, info):
|
||||
for line in info[0]:
|
||||
if item in line:
|
||||
ringStorageAvailable = float(line[5])
|
||||
ringStorageTotal = float(line[6])
|
||||
fslist=[(item, ringStorageTotal, ringStorageAvailable, 0)]
|
||||
return df_check_filesystem_list(item, params, fslist)
|
||||
|
||||
check_info["scality_ring.storage"] = {
|
||||
"check_function": check_scality_storage,
|
||||
"inventory_function": inventory_scality_storage,
|
||||
"service_description": "Ring %s Storage",
|
||||
"default_levels_variable": "filesystem_default_levels",
|
||||
"has_perfdata": True,
|
||||
"group": "filesystem",
|
||||
}
|
||||
|
||||
|
||||
##############RING STATUS############
|
||||
def inventory_scality_ring(info):
|
||||
for line in info[0]:
|
||||
yield (line[0],{})
|
||||
|
||||
def check_scality_ring(item, no_params, info):
|
||||
for line in info[0]:
|
||||
if item in line:
|
||||
ringstaterun = line[1]
|
||||
ringstate = line[2]
|
||||
if ringstate == "RUN":
|
||||
status = 0
|
||||
text = "Ring is in Run State"
|
||||
elif ringstate =="LOOP":
|
||||
status = 2
|
||||
text = "Ring is LOOP State"
|
||||
else:
|
||||
status = 2
|
||||
text = "Ring is in Balancing State"
|
||||
|
||||
yield status, text
|
||||
|
||||
|
||||
|
||||
check_info["scality_ring"] = {
|
||||
"check_function": check_scality_ring,
|
||||
"inventory_function": inventory_scality_ring,
|
||||
"service_description": "Ring %s State",
|
||||
"snmp_info": [
|
||||
(".1.3.6.1.4.1.37489.2.1.1.1.4.1.1",
|
||||
[
|
||||
"2", #ringName
|
||||
"3", #ringStateRun
|
||||
"8", #ringState
|
||||
"9", #ringDiskTotal
|
||||
"13", #ringStorageUsed
|
||||
"14", #ringStorageAvailable
|
||||
"15", #ringStorageTotal
|
||||
]),
|
||||
(".1.3.6.1.4.1.37489.2.1.1.1.4.2.1",
|
||||
[
|
||||
"2", #supName
|
||||
"5", #supNbSrvTotal
|
||||
"6", #supNbSrvOK
|
||||
"7", #supNbSrvNok
|
||||
"8", #supAvailable
|
||||
],
|
||||
),
|
||||
],
|
||||
"snmp_scan_function": lambda oid: "scality" in oid(".1.3.6.1.2.1.1.1.0").lower(),
|
||||
}
|
||||
|
@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2019 tribe29 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.
|
||||
|
||||
from cmk.gui.i18n import _
|
||||
from cmk.gui.plugins.wato.utils import (
|
||||
CheckParameterRulespecWithItem,
|
||||
rulespec_registry,
|
||||
RulespecGroupCheckParametersApplications,
|
||||
Transform,
|
||||
)
|
||||
from cmk.gui.valuespec import Dictionary, Integer, Tuple, TextInput
|
||||
|
||||
def _item_spec_scality_disks():
|
||||
return TextInput(
|
||||
title=_("Ring"), help=_("Ring Name")
|
||||
)
|
||||
|
||||
|
||||
def _parameter_valuespec_scality_disks():
|
||||
return Dictionary(
|
||||
elements=[
|
||||
(
|
||||
"disks",
|
||||
Tuple(
|
||||
help=_(
|
||||
"This rule sets lower limits for the number of disks in the "
|
||||
"scality ring system and it's applied for each RING"
|
||||
),
|
||||
title=_("Minimum number of disks:"),
|
||||
elements=[
|
||||
Integer(title=_("Warning below")),
|
||||
Integer(title=_("Critical below")),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
rulespec_registry.register(
|
||||
CheckParameterRulespecWithItem(
|
||||
check_group_name="scality_disks",
|
||||
group=RulespecGroupCheckParametersApplications,
|
||||
item_spec=_item_spec_scality_disks,
|
||||
match_type="dict",
|
||||
parameter_valuespec=_parameter_valuespec_scality_disks,
|
||||
title=lambda: _("Scality Ring Disk Number"),
|
||||
)
|
||||
)
|
2365
check_mk-sentry-pdu/Sentry3.mib
Executable file
2365
check_mk-sentry-pdu/Sentry3.mib
Executable file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,17 @@
|
||||
title: Sentry PDU Devices: Outlet Power
|
||||
agents: snmp
|
||||
catalog: hw/power/servertech
|
||||
license: Proprietary
|
||||
distribution: Spearhead Systems SRL
|
||||
description:
|
||||
This check monitors the power of outlets in a Sentry PDU Device.
|
||||
Without configuration the status will always be OK, except when an infeed is
|
||||
returning no data.
|
||||
You are able to set warn/crit levels, such that the status may change to
|
||||
WARN or CRIT dependent on the levels.
|
||||
|
||||
item:
|
||||
The items are named "Outlet" with following socket ID and names.
|
||||
|
||||
inventory:
|
||||
One service per socket.
|
@ -0,0 +1,196 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2024 Spearhead Systems SRL
|
||||
#
|
||||
# Docs for this system:
|
||||
# https://cdn10.servertech.com/assets/documents/documents/135/original/manual_CDU_Y-30932L.pdf
|
||||
# https://cdn10.servertech.com/assets/documents/documents/793/original/Sentry3.mib
|
||||
|
||||
from itertools import chain
|
||||
|
||||
|
||||
# A note about MAX_SOCKETS:
|
||||
#
|
||||
# According to the MIB, MAX_SOCKETS should be 64. However, since CheckMK 1.6
|
||||
# doesn't appear to have something like 2.*'s SNMPTree functionality, we
|
||||
# brute-force by explicitly querying every possible socket. Unfortunately,
|
||||
# this means querying ~3K OIDs. In practice, the data received from the customer
|
||||
# shows that they only have two or four sockets per infeed, so I've set the
|
||||
# MAX_SOCKETS here to 16, which cuts the queried OIDs to 800. Using MAX_SOCKETS
|
||||
# of 4 would still satisfy the customer's current needs, but leaves no leeway
|
||||
# if the get more sockets in an infeed.
|
||||
MAX_TOWERS = 4
|
||||
MAX_INFEEDS = 4
|
||||
MAX_SOCKETS = 16 # XXX
|
||||
|
||||
TOWER_ARR_SIZE = MAX_TOWERS
|
||||
INFEED_ARR_SIZE = MAX_TOWERS * MAX_INFEEDS
|
||||
SOCKET_ARR_SIZE = MAX_TOWERS * MAX_INFEEDS * MAX_SOCKETS
|
||||
|
||||
TOWER_NUM_OFFSET = 0
|
||||
INFEED_NUM_OFFSET = TOWER_NUM_OFFSET + 1
|
||||
INFEED_ID_OFFSET = INFEED_NUM_OFFSET + TOWER_ARR_SIZE
|
||||
INFEED_NAME_OFFSET = INFEED_ID_OFFSET + INFEED_ARR_SIZE
|
||||
INFEED_VOLT_OFFSET = INFEED_NAME_OFFSET + INFEED_ARR_SIZE
|
||||
SOCKET_NUM_OFFSET = INFEED_VOLT_OFFSET + INFEED_ARR_SIZE
|
||||
SOCKET_ID_OFFSET = SOCKET_NUM_OFFSET + INFEED_ARR_SIZE
|
||||
SOCKET_NAME_OFFSET = SOCKET_ID_OFFSET + SOCKET_ARR_SIZE
|
||||
SOCKET_LOAD_OFFSET = SOCKET_NAME_OFFSET + SOCKET_ARR_SIZE
|
||||
|
||||
|
||||
def parse_sentry_pdu(info):
|
||||
outlets_info = {}
|
||||
results = info[0]
|
||||
num_towers = int(results[TOWER_NUM_OFFSET])
|
||||
|
||||
for tower_id in range(num_towers):
|
||||
num_infeeds = int(results[INFEED_NUM_OFFSET + tower_id])
|
||||
|
||||
for infeed_id in range(num_infeeds):
|
||||
infeed_idx = tower_id * MAX_TOWERS + infeed_id
|
||||
|
||||
infeed_sid = results[INFEED_ID_OFFSET + infeed_idx]
|
||||
infeed_name = results[INFEED_NAME_OFFSET + infeed_idx]
|
||||
infeed_voltage = float(results[INFEED_VOLT_OFFSET + infeed_idx]) / 10
|
||||
num_outlets = int(results[SOCKET_NUM_OFFSET + infeed_idx])
|
||||
|
||||
for outlet_id in range(num_outlets):
|
||||
outlet_idx = MAX_INFEEDS * MAX_SOCKETS * tower_id + MAX_SOCKETS * infeed_id + outlet_id
|
||||
outlet_sid = results[SOCKET_ID_OFFSET + outlet_idx]
|
||||
outlet_name = results[SOCKET_NAME_OFFSET + outlet_idx]
|
||||
outlet_load = float(results[SOCKET_LOAD_OFFSET + outlet_idx]) / 100
|
||||
|
||||
outlet_key = '%s.%s.%s' % (tower_id, infeed_id, outlet_id)
|
||||
outlets_info[outlet_key] = {
|
||||
'infeed_id': infeed_sid,
|
||||
'infeed_name': infeed_name,
|
||||
'infeed_voltage': infeed_voltage,
|
||||
'outlet_id': outlet_sid,
|
||||
'outlet_name': outlet_name,
|
||||
'outlet_load': outlet_load,
|
||||
}
|
||||
|
||||
return outlets_info
|
||||
|
||||
|
||||
# Check function, returning warn/crit based upon SNMP parsed result above
|
||||
def check_sentry_pdu(item, params, section):
|
||||
outlet = section.get(params['id'])
|
||||
if outlet is None:
|
||||
return (3, 'item not found in snmp data')
|
||||
|
||||
voltage = outlet['infeed_voltage']
|
||||
amps = outlet['outlet_load']
|
||||
|
||||
if voltage < 0:
|
||||
return (1, 'Infeed voltage unavailable')
|
||||
|
||||
if params['type'] == 'infeed':
|
||||
return check_metric(params, 'volts', voltage)
|
||||
|
||||
elif params['type'] == 'outlet':
|
||||
if amps < 0:
|
||||
return (1, 'Outlet load unavailable')
|
||||
return check_metric(params, 'watts', voltage * amps)
|
||||
|
||||
|
||||
def check_metric(params, metric_name, metric_value):
|
||||
crit_metric_above = params.get('crit_%s_above' % metric_name)
|
||||
warn_metric_above = params.get('warn_%s_above' % metric_name)
|
||||
warn_metric_below = params.get('warn_%s_below' % metric_name)
|
||||
crit_metric_below = params.get('crit_%s_below' % metric_name)
|
||||
|
||||
state = 0
|
||||
|
||||
if crit_metric_above and crit_metric_above < metric_value:
|
||||
state = 2
|
||||
elif crit_metric_below and crit_metric_below > metric_value:
|
||||
state = 2
|
||||
elif warn_metric_above and warn_metric_above < metric_value:
|
||||
state = 1
|
||||
elif warn_metric_below and warn_metric_below > metric_value:
|
||||
state = 1
|
||||
|
||||
return (state, '%.1f %s' % (metric_value, metric_name))
|
||||
|
||||
|
||||
# Inventory function, returning inventory based upon SNMP parsed result above
|
||||
def inventory_sentry_pdu(parsed):
|
||||
items = []
|
||||
|
||||
for id, outlet in parsed.items():
|
||||
plug_name = '%s %s [infeed %s] power' % (
|
||||
outlet['outlet_id'],
|
||||
outlet['outlet_name'],
|
||||
outlet['infeed_id']
|
||||
)
|
||||
infeed_name = 'Infeed %s %s' % (
|
||||
outlet['infeed_id'],
|
||||
outlet['infeed_name']
|
||||
)
|
||||
|
||||
items.append((plug_name, { 'id': id, 'type': 'outlet' }))
|
||||
items.append((infeed_name, { 'id': id, 'type': 'infeed' }))
|
||||
|
||||
return items
|
||||
|
||||
|
||||
check_info['sentry_pdu_outlets_power'] = {
|
||||
'parse_function': parse_sentry_pdu,
|
||||
'check_function': check_sentry_pdu,
|
||||
'inventory_function': inventory_sentry_pdu,
|
||||
'service_description': 'Outlet %s',
|
||||
'group': 'sentry_pdu_outlets_power',
|
||||
'snmp_info': (
|
||||
'.1.3.6.1.4.1.1718.3',
|
||||
# In CheckMK 2.* there is SMPTree, but 1.6 doesn't seem to have that.
|
||||
# Therefore we resort to this sledge-hammer approach to get the
|
||||
# information we need. It's... not ideal.
|
||||
list(chain(
|
||||
# Number of towers
|
||||
['1.4.0'],
|
||||
|
||||
# Number of infeeds
|
||||
# .1.3.6.1.4.1.1718.3.2.1.1.5.<tower #>
|
||||
['2.1.1.5.%s' % (x) for x in range(1, MAX_TOWERS+1)],
|
||||
|
||||
# Infeed IDs:
|
||||
# .1.3.6.1.4.1.1718.3.2.2.1.2.<tower #>.<infeed #>
|
||||
['2.2.1.2.%s.%s' % (x, y) for x in range(1, MAX_TOWERS+1)
|
||||
for y in range(1, MAX_INFEEDS+1)],
|
||||
|
||||
# Infeed names:
|
||||
# .1.3.6.1.4.1.1718.3.2.2.1.3.<tower #>.<infeed #>
|
||||
['2.2.1.3.%s.%s' % (x, y) for x in range(1, MAX_TOWERS+1)
|
||||
for y in range(1, MAX_INFEEDS+1)],
|
||||
|
||||
# Infeed voltage:
|
||||
# .1.3.6.1.4.1.1718.3.2.2.1.11.<tower #>.<infeed #>
|
||||
['2.2.1.11.%s.%s' % (x, y) for x in range(1, MAX_TOWERS+1)
|
||||
for y in range(1, MAX_INFEEDS+1)],
|
||||
|
||||
# Number of outlets
|
||||
# .1.3.6.1.4.1.1718.3.2.2.1.9.<tower #>.<infeed #>
|
||||
['2.2.1.9.%s.%s' % (x, y) for x in range(1, MAX_TOWERS+1)
|
||||
for y in range(1, MAX_INFEEDS+1)],
|
||||
|
||||
# Outlet IDs:
|
||||
# .1.3.6.1.4.1.1718.3.2.3.1.2.<tower #>.<infeed #>.<outlet #>
|
||||
['2.3.1.2.%s.%s.%s' % (x, y, z) for x in range(1, MAX_TOWERS+1)
|
||||
for y in range(1, MAX_INFEEDS+1)
|
||||
for z in range(1, MAX_SOCKETS+1)],
|
||||
|
||||
# Outlet names:
|
||||
# .1.3.6.1.4.1.1718.3.2.3.1.3.<tower #>.<infeed #>.<outlet #>
|
||||
['2.3.1.3.%s.%s.%s' % (x, y, z) for x in range(1, MAX_TOWERS+1)
|
||||
for y in range(1, MAX_INFEEDS+1)
|
||||
for z in range(1, MAX_SOCKETS+1)],
|
||||
|
||||
# Outlet load:
|
||||
# .1.3.6.1.4.1.1718.3.2.3.1.7.<tower #>.<infeed #>.<outlet #>
|
||||
['2.3.1.7.%s.%s.%s' % (x, y, z) for x in range(1, MAX_TOWERS+1)
|
||||
for y in range(1, MAX_INFEEDS+1)
|
||||
for z in range(1, MAX_SOCKETS+1)],
|
||||
))),
|
||||
'snmp_scan_function': lambda oid: 'Sentry Switched -48 VDC' in oid('.1.3.6.1.2.1.1.1.0')
|
||||
}
|
@ -0,0 +1,139 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright 2024 Spearhead Systems SRL
|
||||
|
||||
from cmk.gui.i18n import _
|
||||
from cmk.gui.plugins.wato import (
|
||||
rulespec_registry,
|
||||
CheckParameterRulespecWithItem,
|
||||
RulespecGroupCheckParametersEnvironment,
|
||||
)
|
||||
from cmk.gui.valuespec import (
|
||||
Dictionary,
|
||||
Integer,
|
||||
)
|
||||
|
||||
|
||||
def _valuespec_outlets_power_check():
|
||||
return Dictionary(
|
||||
optional_keys=[
|
||||
'crit_volts_above',
|
||||
'warn_volts_above',
|
||||
'warn_volts_below',
|
||||
'crit_volts_below',
|
||||
'crit_watts_above',
|
||||
'warn_watts_above',
|
||||
'warn_watts_below',
|
||||
'crit_watts_below',
|
||||
'type',
|
||||
],
|
||||
elements=[
|
||||
|
||||
(
|
||||
'crit_volts_above',
|
||||
Integer(
|
||||
minvalue=0,
|
||||
title=_('Crit when infeed above voltage'),
|
||||
unit=_('Volts'),
|
||||
help=_(
|
||||
'If the Voltage of an infeed goes above this number, enter a critical state.'
|
||||
),
|
||||
),
|
||||
),
|
||||
(
|
||||
'warn_volts_above',
|
||||
Integer(
|
||||
minvalue=0,
|
||||
title=_('Warn when infeed above voltage'),
|
||||
unit=_('Volts'),
|
||||
help=_(
|
||||
'If the Voltage of an infeed goes above this number, enter a warning state.'
|
||||
),
|
||||
),
|
||||
),
|
||||
(
|
||||
'warn_volts_below',
|
||||
Integer(
|
||||
minvalue=0,
|
||||
title=_('Warn when infeed below voltage'),
|
||||
unit=_('Volts'),
|
||||
help=_(
|
||||
'If the Voltage of an infeed goes below this number, enter a warning state.'
|
||||
),
|
||||
),
|
||||
),
|
||||
(
|
||||
'crit_volts_below',
|
||||
Integer(
|
||||
minvalue=0,
|
||||
title=_('Crit when infeed below voltage'),
|
||||
unit=_('Volts'),
|
||||
help=_(
|
||||
'If the Voltage of an infeed goes below this number, enter a critical state.'
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
(
|
||||
'crit_watts_above',
|
||||
Integer(
|
||||
minvalue=0,
|
||||
title=_('Crit when outlet above power'),
|
||||
unit=_('Watts'),
|
||||
help=_(
|
||||
'If the Wattage of an outlet goes above this number, enter a critical state.'
|
||||
),
|
||||
),
|
||||
),
|
||||
(
|
||||
'warn_watts_above',
|
||||
Integer(
|
||||
minvalue=0,
|
||||
title=_('Warn when outlet above power'),
|
||||
unit=_('Watts'),
|
||||
help=_(
|
||||
'If the Wattage of an outlet goes above this number, enter a warning state.'
|
||||
),
|
||||
),
|
||||
),
|
||||
(
|
||||
'warn_watts_below',
|
||||
Integer(
|
||||
minvalue=0,
|
||||
title=_('Warn when outlet below power'),
|
||||
unit=_('Watts'),
|
||||
help=_(
|
||||
'If the Wattage of an outlet goes below this number, enter a warning state.'
|
||||
),
|
||||
),
|
||||
),
|
||||
(
|
||||
'crit_watts_below',
|
||||
Integer(
|
||||
minvalue=0,
|
||||
title=_('Crit when outlet below power'),
|
||||
unit=_('Watts'),
|
||||
help=_(
|
||||
'If the Wattage of an outlet goes below this number, enter a critical state.'
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def _item_spec_outlets_power_check():
|
||||
return TextAscii(title=_('Socket Name'),
|
||||
help=_('The name of the socket'))
|
||||
|
||||
|
||||
rulespec_registry.register(
|
||||
CheckParameterRulespecWithItem(
|
||||
check_group_name='sentry_pdu_outlets_power',
|
||||
group=RulespecGroupCheckParametersEnvironment,
|
||||
match_type='dict',
|
||||
item_spec=_item_spec_outlets_power_check,
|
||||
parameter_valuespec=_valuespec_outlets_power_check,
|
||||
title=lambda: _('Sentry PDU Outlets Power Checks'),
|
||||
)
|
||||
)
|
@ -0,0 +1,184 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright 2024 Spearhead Systems SRL
|
||||
#
|
||||
# Docs for this system:
|
||||
# https://cdn10.servertech.com/assets/documents/documents/135/original/manual_CDU_Y-30932L.pdf
|
||||
# https://cdn10.servertech.com/assets/documents/documents/793/original/Sentry3.mib
|
||||
|
||||
from cmk.base.plugins.agent_based.agent_based_api.v1 import (
|
||||
register,
|
||||
Service,
|
||||
Result,
|
||||
State,
|
||||
SNMPTree,
|
||||
contains,
|
||||
OIDEnd,
|
||||
)
|
||||
|
||||
|
||||
def extract_outlet(tower_id, infeed_id, outlet_id, data):
|
||||
return next(filter(lambda x: x[0] == f'{tower_id+1}.{infeed_id+1}.{outlet_id+1}', data))[1]
|
||||
|
||||
|
||||
# SNMP parsing function
|
||||
def parse_sentry_pdu(string_table):
|
||||
outlets_info = {}
|
||||
num_towers = int(string_table[0][0][0])
|
||||
|
||||
for tower_id in range(num_towers):
|
||||
num_infeeds = int(string_table[1][0][tower_id])
|
||||
|
||||
for infeed_id in range(num_infeeds):
|
||||
infeed_sid = string_table[2][infeed_id][tower_id]
|
||||
infeed_name = string_table[3][infeed_id][tower_id]
|
||||
infeed_voltage = float(string_table[4][infeed_id][tower_id]) / 10
|
||||
num_outlets = int(string_table[5][infeed_id][tower_id])
|
||||
|
||||
for outlet_id in range(num_outlets):
|
||||
outlet_sid = extract_outlet(tower_id, infeed_id, outlet_id, string_table[6])
|
||||
outlet_name = extract_outlet(tower_id, infeed_id, outlet_id, string_table[7])
|
||||
outlet_load = float(extract_outlet(tower_id, infeed_id, outlet_id, string_table[8])) / 100
|
||||
|
||||
outlets_info[f'{tower_id}.{infeed_id}.{outlet_id}'] = {
|
||||
'infeed_id': infeed_sid,
|
||||
'infeed_name': infeed_name,
|
||||
'infeed_voltage': infeed_voltage,
|
||||
'outlet_id': outlet_sid,
|
||||
'outlet_name': outlet_name,
|
||||
'outlet_load': outlet_load
|
||||
}
|
||||
|
||||
return outlets_info
|
||||
|
||||
|
||||
# Inventory function, returning inventory based upon SNMP parsed result above
|
||||
def discovery_sentry_pdu(section):
|
||||
for key, outlet in section.items():
|
||||
plug_name = f'{outlet["outlet_id"]} {outlet["outlet_name"]} (infeed {outlet["infeed_id"]}) power'
|
||||
infeed_name = f'Infeed {outlet["infeed_id"]} {outlet["infeed_name"]}'
|
||||
yield Service(item=plug_name, parameters={ 'id': key, 'type': 'outlet' })
|
||||
yield Service(item=infeed_name, parameters={ 'id': key, 'type': 'infeed' })
|
||||
|
||||
|
||||
|
||||
# Check function, returning warn/crit based upon SNMP parsed result above
|
||||
def check_sentry_pdu(item, params, section):
|
||||
outlet = section.get(params['id'])
|
||||
if outlet is None:
|
||||
return
|
||||
|
||||
voltage = outlet['infeed_voltage']
|
||||
amps = outlet['outlet_load']
|
||||
|
||||
if voltage < 0:
|
||||
yield Result(state=State.WARN, summary='Infeed voltage unavailable')
|
||||
return
|
||||
|
||||
if params['type'] == 'infeed':
|
||||
yield check_metric(params, 'volts', voltage)
|
||||
|
||||
elif params['type'] == 'outlet':
|
||||
if amps < 0:
|
||||
yield Result(state=State.WARN, summary='Outlet load unavailable')
|
||||
return
|
||||
yield check_metric(params, 'watts', voltage * amps)
|
||||
|
||||
|
||||
def check_metric(params, metric_name, metric_value):
|
||||
crit_metric_above = params.get('crit_%s_above' % metric_name)
|
||||
warn_metric_above = params.get('warn_%s_above' % metric_name)
|
||||
warn_metric_below = params.get('warn_%s_below' % metric_name)
|
||||
crit_metric_below = params.get('crit_%s_below' % metric_name)
|
||||
|
||||
state = State.OK
|
||||
|
||||
if crit_metric_above and crit_metric_above < metric_value:
|
||||
state = State.CRIT
|
||||
elif crit_metric_below and crit_metric_below > metric_value:
|
||||
state = State.CRIT
|
||||
elif warn_metric_above and warn_metric_above < metric_value:
|
||||
state = State.WARN
|
||||
elif warn_metric_below and warn_metric_below > metric_value:
|
||||
state = State.WARN
|
||||
|
||||
return Result(state=state, summary=f'{metric_value:.1f} {metric_name}')
|
||||
|
||||
|
||||
register.snmp_section(
|
||||
name='sentry_pdu_outlets_power',
|
||||
parse_function=parse_sentry_pdu,
|
||||
fetch=[
|
||||
# Number of towers (integer from 0 to 4)
|
||||
SNMPTree(
|
||||
base='.1.3.6.1.4.1.1718.3.1.4',
|
||||
oids=['0']
|
||||
),
|
||||
|
||||
# Number of infeeds (integer from 0 to 4):
|
||||
# .1.3.6.1.4.1.1718.3.2.1.1.5.<tower #>
|
||||
SNMPTree(
|
||||
base='.1.3.6.1.4.1.1718.3.2.1.1.5',
|
||||
oids=['1', '2', '3', '4'],
|
||||
),
|
||||
|
||||
# Infeed IDs:
|
||||
# .1.3.6.1.4.1.1718.3.2.2.1.2.<tower #>.<infeed #>
|
||||
SNMPTree(
|
||||
base='.1.3.6.1.4.1.1718.3.2.2.1.2',
|
||||
oids=['1', '2', '3', '4'],
|
||||
),
|
||||
|
||||
# Infeed names:
|
||||
# .1.3.6.1.4.1.1718.3.2.2.1.3.<tower #>.<infeed #>
|
||||
SNMPTree(
|
||||
base='.1.3.6.1.4.1.1718.3.2.2.1.3',
|
||||
oids=['1', '2', '3', '4'],
|
||||
),
|
||||
|
||||
# Infeed voltage:
|
||||
# .1.3.6.1.4.1.1718.3.2.2.1.11.<tower #>.<infeed #>
|
||||
SNMPTree(
|
||||
base='.1.3.6.1.4.1.1718.3.2.2.1.11',
|
||||
oids=['1', '2', '3', '4'],
|
||||
),
|
||||
|
||||
# Number of outlets (integer from 0 to 64):
|
||||
# .1.3.6.1.4.1.1718.3.2.2.1.9.<tower #>.<infeed #>
|
||||
SNMPTree(
|
||||
base='.1.3.6.1.4.1.1718.3.2.2.1.9',
|
||||
oids=['1', '2', '3', '4'],
|
||||
),
|
||||
|
||||
# Outlet IDs:
|
||||
# .1.3.6.1.4.1.1718.3.2.3.1.2.<tower #>.<infeed #>.<outlet #>
|
||||
SNMPTree(
|
||||
base='.1.3.6.1.4.1.1718.3.2.3.1',
|
||||
oids=[OIDEnd(), '2'],
|
||||
),
|
||||
|
||||
# Outlet names:
|
||||
# .1.3.6.1.4.1.1718.3.2.3.1.3.<tower #>.<infeed #>.<outlet #>
|
||||
SNMPTree(
|
||||
base='.1.3.6.1.4.1.1718.3.2.3.1',
|
||||
oids=[OIDEnd(), '3'],
|
||||
),
|
||||
|
||||
# Outlet load:
|
||||
# .1.3.6.1.4.1.1718.3.2.3.1.7.<tower #>.<infeed #>.<outlet #>
|
||||
SNMPTree(
|
||||
base='.1.3.6.1.4.1.1718.3.2.3.1',
|
||||
oids=[OIDEnd(), '7']
|
||||
),
|
||||
],
|
||||
detect=contains('.1.3.6.1.2.1.1.1.0', 'Sentry Switched -48 VDC'),
|
||||
)
|
||||
|
||||
register.check_plugin(
|
||||
name='sentry_pdu_outlets_power',
|
||||
service_name='Outlet %s',
|
||||
discovery_function=discovery_sentry_pdu,
|
||||
check_function=check_sentry_pdu,
|
||||
check_default_parameters={},
|
||||
check_ruleset_name='sentry_pdu_outlets_power',
|
||||
)
|
@ -0,0 +1,131 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright 2024 Spearhead Systems SRL
|
||||
|
||||
from cmk.gui.i18n import _
|
||||
from cmk.gui.plugins.wato.utils import (
|
||||
rulespec_registry,
|
||||
CheckParameterRulespecWithItem,
|
||||
RulespecGroupCheckParametersEnvironment,
|
||||
)
|
||||
from cmk.gui.valuespec import (
|
||||
Dictionary,
|
||||
Integer,
|
||||
)
|
||||
|
||||
|
||||
def _valuespec_agents_sentry_pdu_outlets_power_check():
|
||||
return Dictionary(
|
||||
title=_('Sentry PDU Outlets Power Checks'),
|
||||
optional_keys=[
|
||||
'crit_volts_above',
|
||||
'warn_volts_above',
|
||||
'warn_volts_below',
|
||||
'crit_volts_below',
|
||||
'crit_watts_above',
|
||||
'warn_watts_above',
|
||||
'warn_watts_below',
|
||||
'crit_watts_below',
|
||||
],
|
||||
elements=[
|
||||
|
||||
(
|
||||
'crit_volts_above',
|
||||
Integer(
|
||||
minvalue=0,
|
||||
title=_('Crit when infeed above voltage'),
|
||||
unit=_('Volts'),
|
||||
help=_(
|
||||
'If the Voltage of an infeed goes above this number, enter a critical state.'
|
||||
),
|
||||
),
|
||||
),
|
||||
(
|
||||
'warn_volts_above',
|
||||
Integer(
|
||||
minvalue=0,
|
||||
title=_('Warn when infeed above voltage'),
|
||||
unit=_('Volts'),
|
||||
help=_(
|
||||
'If the Voltage of an infeed goes above this number, enter a warning state.'
|
||||
),
|
||||
),
|
||||
),
|
||||
(
|
||||
'warn_volts_below',
|
||||
Integer(
|
||||
minvalue=0,
|
||||
title=_('Warn when infeed below voltage'),
|
||||
unit=_('Volts'),
|
||||
help=_(
|
||||
'If the Voltage of an infeed goes below this number, enter a warning state.'
|
||||
),
|
||||
),
|
||||
),
|
||||
(
|
||||
'crit_volts_below',
|
||||
Integer(
|
||||
minvalue=0,
|
||||
title=_('Crit when infeed below voltage'),
|
||||
unit=_('Volts'),
|
||||
help=_(
|
||||
'If the Voltage of an infeed goes below this number, enter a critical state.'
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
(
|
||||
'crit_watts_above',
|
||||
Integer(
|
||||
minvalue=0,
|
||||
title=_('Crit when outlet above power'),
|
||||
unit=_('Watts'),
|
||||
help=_(
|
||||
'If the Wattage of an outlet goes above this number, enter a critical state.'
|
||||
),
|
||||
),
|
||||
),
|
||||
(
|
||||
'warn_watts_above',
|
||||
Integer(
|
||||
minvalue=0,
|
||||
title=_('Warn when outlet above power'),
|
||||
unit=_('Watts'),
|
||||
help=_(
|
||||
'If the Wattage of an outlet goes above this number, enter a warning state.'
|
||||
),
|
||||
),
|
||||
),
|
||||
(
|
||||
'warn_watts_below',
|
||||
Integer(
|
||||
minvalue=0,
|
||||
title=_('Warn when outlet below power'),
|
||||
unit=_('Watts'),
|
||||
help=_(
|
||||
'If the Wattage of an outlet goes below this number, enter a warning state.'
|
||||
),
|
||||
),
|
||||
),
|
||||
(
|
||||
'crit_watts_below',
|
||||
Integer(
|
||||
minvalue=0,
|
||||
title=_('Crit when outlet below power'),
|
||||
unit=_('Watts'),
|
||||
help=_(
|
||||
'If the Wattage of an outlet goes below this number, enter a critical state.'
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
rulespec_registry.register(
|
||||
CheckParameterRulespecWithItem(
|
||||
check_group_name='sentry_pdu_outlets_power',
|
||||
group=RulespecGroupCheckParametersEnvironment,
|
||||
match_type='dict',
|
||||
parameter_valuespec=_valuespec_agents_sentry_pdu_outlets_power_check,
|
||||
)
|
||||
)
|
17
local checks/livestatusstats.py
Normal file
17
local checks/livestatusstats.py
Normal file
@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env python
|
||||
with open("/opt/omd/sites/<SITENAME>/var/log/liveproxyd.state") as f:
|
||||
out = {}
|
||||
|
||||
for line in f:
|
||||
if line.strip().startswith('['):
|
||||
sitename = line
|
||||
if line.strip().startswith('Channels'):
|
||||
tmp = []
|
||||
for line in f:
|
||||
if line.strip().startswith("Clients"):
|
||||
out[sitename] = tmp
|
||||
break
|
||||
tmp.append(line)
|
||||
|
||||
for k,v in out.items():
|
||||
print("0 lp-{s} total={t};;|ready={r};;|busy={b};;|heartbeat={h};; {s} site livestatus channel states").format(s=k.strip()[1:-1],r=sum('ready' in s for s in v),b=sum('busy' in s for s in v),h=sum('heartbeat' in s for s in v),t=len(v))
|
Loading…
Reference in New Issue
Block a user