Compare commits

..

2 Commits
master ... 2.0

Author SHA1 Message Date
gpochiscan
ffe574da56
Update README.MD 2021-12-13 12:08:21 +02:00
George Pochiscan
43179b7073 Added compatibility with CheckMK 2.0 2021-12-13 12:03:32 +02:00
97 changed files with 52 additions and 8769 deletions

3
.gitmodules vendored
View File

@ -1,6 +1,3 @@
[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

Binary file not shown.

View File

@ -1,106 +0,0 @@
#!/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',
)

View File

@ -1,86 +0,0 @@
#!/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"),
)
)

View File

@ -1,20 +0,0 @@
# 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

View File

@ -1,92 +0,0 @@
#!/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
)

View File

@ -1,134 +0,0 @@
#!/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"},
)

View File

@ -1,152 +0,0 @@
#!/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)

View File

@ -1,15 +0,0 @@
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

View File

@ -1,15 +0,0 @@
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

View File

@ -1,72 +0,0 @@
#!/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,
)

View File

@ -1,26 +0,0 @@
#!/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

View File

@ -1,16 +0,0 @@
#!/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

View File

@ -1,110 +0,0 @@
#!/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,
)
)

View File

@ -1,278 +0,0 @@
#!/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,
)

View File

@ -1,184 +0,0 @@
#!/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}&timespan={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),
})

View File

@ -1,6 +0,0 @@
#!/bin/bash
echo '<<<azure_defender:sep(0)>>>'
dir=$(dirname -- "${BASH_SOURCE[0]}")
"$dir"/agent_azure_common defender "$1" "$2" "$3" "$4"

View File

@ -1,6 +0,0 @@
#!/bin/bash
echo '<<<azure_firewall:sep(0)>>>'
dir=$(dirname -- "${BASH_SOURCE[0]}")
"$dir"/agent_azure_common firewall "$1" "$2" "$3" "$4"

View File

@ -1,6 +0,0 @@
#!/bin/bash
echo '<<<azure_keyvault:sep(0)>>>'
dir=$(dirname -- "${BASH_SOURCE[0]}")
"$dir"/agent_azure_common keyvault "$1" "$2" "$3" "$4"

View File

@ -1,25 +0,0 @@
#!/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

View File

@ -1,217 +0,0 @@
#!/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 +0,0 @@
Subproject commit d041278cbe5e329ee3a8a63b1d21530f69fbfaa2

View File

@ -1 +0,0 @@
This is a modification of a GPL plugin to additionally support CISCO-BGP4-MIB::CbgpPeer3Entry

View File

@ -1,665 +0,0 @@
#!/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',
)

View File

@ -1,178 +0,0 @@
#!/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,
}
]))

View File

@ -1,126 +0,0 @@
#!/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'),
))

View File

@ -1 +0,0 @@
This plugin checks the registration status (and KEK key timeout) of GDOI Group Members with GDOI Key Servers.

View File

@ -1,98 +0,0 @@
#!/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",
)

View File

@ -1 +0,0 @@
This is a modification of a Tribe29 GPL plugin to support tracking packet loss as well.

View File

@ -1,208 +0,0 @@
#!/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"),
)
)

View File

@ -1,237 +0,0 @@
#!/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
]
)
],
}

View File

@ -1,20 +0,0 @@
{'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'}

View File

@ -1,13 +0,0 @@
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.

View File

@ -1,13 +0,0 @@
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.

View File

@ -1,13 +0,0 @@
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.

View File

@ -1,129 +0,0 @@
#!/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',
}

View File

@ -1,127 +0,0 @@
#!/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',
}

View File

@ -1,49 +0,0 @@
#!/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'],
}

View File

@ -1,49 +0,0 @@
#!/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'],
}

View File

@ -1,49 +0,0 @@
#!/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'],
}

View File

@ -1,49 +0,0 @@
#!/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'],
}

View File

@ -1,83 +0,0 @@
#!/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"),
)
)

View File

@ -1,13 +0,0 @@
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.

View File

@ -1,13 +0,0 @@
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.

View File

@ -1,13 +0,0 @@
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.

View File

@ -1,20 +0,0 @@
{'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'}

View File

@ -1,126 +0,0 @@
#!/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),
},
)

View File

@ -1,125 +0,0 @@
#!/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),
},
)

View File

@ -1,64 +0,0 @@
#!/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={},
)

View File

@ -1,64 +0,0 @@
#!/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={},
)

View File

@ -1,69 +0,0 @@
#!/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={},
)

View File

@ -1,69 +0,0 @@
#!/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={},
)

View File

@ -1,33 +0,0 @@
#!/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),
)

View File

@ -1,65 +0,0 @@
#!/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"),
)
)

View File

@ -1,92 +0,0 @@
#!/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"),
)
)

View File

@ -1,154 +0,0 @@
#!/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())

View File

@ -1,11 +0,0 @@
#!/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())

View File

@ -1,39 +0,0 @@
#!/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

View File

@ -1,81 +0,0 @@
#!/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",
}

View File

@ -1,97 +0,0 @@
#!/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,
)
)

View File

@ -1,3 +1,5 @@
This version is compatible with CheckMK 2.0
Extend the current infoblox checks with following metrics:
DNS AAT5 Latency

Binary file not shown.

View File

@ -1,28 +1,14 @@
#!/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.
#!/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.infoblox import * # pylint: disable=wildcard-import,unused-wildcard-import
#ibNetworkMonitorDNSAAT5Count(.1.3.6.1.4.1.7779.3.1.1.2.1.3.1.3.2.2.0)--)--DNS AAT5 Count"
@ -43,12 +29,12 @@ def check_infoblox_aat5_count(item, params, info):
if count > warn:
if count > crit:
state = 2
count_info = "Number of AAT5 Requests is %s (crit above %s requests)" % (count, crit)
count_info = "Number of AAT Requests is %s (crit above %s requests)" % (count, crit)
else:
state = 1
count_info = "Number of AAT5 Requests is %s (warn above %s requests)" % (count, warn)
count_info = "Number of AAT Requests is %s (warn above %s requests)" % (count, warn)
else:
count_info = "Number of AAT5 Requests is %s" % count
count_info = "Number of AAT Requests is %s" % count
yield state, count_info, [('Count', count, warn, crit)]
check_info['infoblox_aat5_count'] = {
@ -60,5 +46,4 @@ check_info['infoblox_aat5_count'] = {
'snmp_scan_function': scan_infoblox,
'has_perfdata': True,
'group': 'infoblox_count',
'includes': ["infoblox.include"],
}

View File

@ -1,28 +1,14 @@
#!/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.
#!/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.infoblox import * # pylint: disable=wildcard-import,unused-wildcard-import
#ibNetworkMonitorDNSAAT5AvgLatency(.1.3.6.1.4.1.7779.3.1.1.2.1.3.1.3.2.1.0)--)--DNS AAT5 Latency
@ -60,5 +46,4 @@ check_info['infoblox_aat5_latency'] = {
'snmp_scan_function': scan_infoblox,
'has_perfdata': True,
'group': 'infoblox_latency',
'includes': ["infoblox.include"],
}

View File

@ -1,29 +1,14 @@
#!/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.
#!/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.infoblox import * # pylint: disable=wildcard-import,unused-wildcard-import
#ibNetworkMonitorDNSNonAAT5Count(.1.3.6.1.4.1.7779.3.1.1.2.1.3.1.2.2.2.0)--)--DNS NonAAT5 Count
infoblox_nonaat5_count_default_levels = (50, 100)
@ -44,12 +29,12 @@ def check_infoblox_nonaat5_count(item, params, info):
if count > warn:
if count > crit:
state = 2
count_info = "Number of NonAAT5 Requests is %s (crit above %s requests)" % (count, crit)
count_info = "Number of NonAAT Requests is %s (crit above %s requests)" % (count, crit)
else:
state = 1
count_info = "Number of NonAAT5 Requests is %s (warn above %s requests)" % (count, warn)
count_info = "Number of NonAAT Requests is %s (warn above %s requests)" % (count, warn)
else:
count_info = "Number of NonAAT5 Requests is %s" % count
count_info = "Number of NonAAT Requests is %s" % count
yield state, count_info, [('Count', count, warn, crit)]
check_info['infoblox_nonaat5_count'] = {
@ -61,5 +46,4 @@ check_info['infoblox_nonaat5_count'] = {
'snmp_scan_function': scan_infoblox,
'has_perfdata': True,
'group': 'infoblox_count',
'includes': ["infoblox.include"],
}

View File

@ -1,29 +1,14 @@
#!/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.
#!/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.infoblox import * # pylint: disable=wildcard-import,unused-wildcard-import
#ibNetworkMonitorDNSNonAAT5AvgLatency(.1.3.6.1.4.1.7779.3.1.1.2.1.3.1.2.2.1.0)--DNS NonAAT5 Latency
infoblox_nonaat5_latency_default_levels = (50, 100)
@ -61,5 +46,4 @@ check_info['infoblox_nonaat5_latency'] = {
'snmp_scan_function': scan_infoblox,
'has_perfdata': True,
'group': 'infoblox_latency',
'includes': ["infoblox.include"],
}

View File

@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/env python3
# -*- encoding: utf-8; py-indent-offset: 4 -*-
# +------------------------------------------------------------------+
# | ____ _ _ __ __ _ __ |

View File

@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/env python3
# -*- encoding: utf-8; py-indent-offset: 4 -*-
# +------------------------------------------------------------------+
# | ____ _ _ __ __ _ __ |

View File

@ -1,22 +0,0 @@
{'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}

View File

@ -1,16 +0,0 @@
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.

View File

@ -1,16 +0,0 @@
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.

View File

@ -1,16 +0,0 @@
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.

View File

@ -1,143 +0,0 @@
#!/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',
}

View File

@ -1,296 +0,0 @@
#!/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

View File

@ -1,44 +0,0 @@
#!/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"),
))

View File

@ -1,9 +0,0 @@
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.

View File

@ -1,167 +0,0 @@
#!/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(),
}

View File

@ -1,52 +0,0 @@
#!/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"),
)
)

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +0,0 @@
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.

View File

@ -1,196 +0,0 @@
#!/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')
}

View File

@ -1,139 +0,0 @@
#!/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'),
)
)

View File

@ -1,184 +0,0 @@
#!/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',
)

View File

@ -1,131 +0,0 @@
#!/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,
)
)

View File

@ -1,17 +0,0 @@
#!/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))