Compare commits
2 Commits
master
...
marsell-az
Author | SHA1 | Date | |
---|---|---|---|
56f9e95f62 | |||
bd7027e93b |
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -2,5 +2,5 @@
|
|||||||
path = juniper
|
path = juniper
|
||||||
url = https://github.com/spearheadsys/check_mk.git
|
url = https://github.com/spearheadsys/check_mk.git
|
||||||
[submodule "check_mk-check-selinux"]
|
[submodule "check_mk-check-selinux"]
|
||||||
path = selinux
|
path = check_mk-check-selinux
|
||||||
url = https://code.spearhead.cloud/Spearhead/check_mk-check-selinux.git
|
url = https://code.spearhead.cloud/Spearhead/check_mk-check-selinux.git
|
||||||
|
Binary file not shown.
@ -1,311 +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. If not, add the 'location' field 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. This applies for KeyVault and
|
|
||||||
# Firewall.
|
|
||||||
def discover(section):
|
|
||||||
for name, details in sorted(section.items()):
|
|
||||||
yield Service(item=name)
|
|
||||||
|
|
||||||
|
|
||||||
# Produce a list of Azure resource group objects for discovery. This applies to
|
|
||||||
# Defender. We also assume each section comes entirely from the same resource
|
|
||||||
# group (this should be true given our special agent).
|
|
||||||
def discover_defender(section):
|
|
||||||
items = list(section.values())
|
|
||||||
|
|
||||||
if items != []:
|
|
||||||
yield Service(item=items[0]["resource_group"])
|
|
||||||
else:
|
|
||||||
yield Service(item=None)
|
|
||||||
|
|
||||||
|
|
||||||
# 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", 0)
|
|
||||||
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):
|
|
||||||
num_high = 0
|
|
||||||
num_med = 0
|
|
||||||
num_low = 0
|
|
||||||
num_info = 0
|
|
||||||
|
|
||||||
final_state = State.OK
|
|
||||||
region_details = []
|
|
||||||
|
|
||||||
for name, alert in sorted(section.items()):
|
|
||||||
details = alert["alert"]
|
|
||||||
status = details["status"]
|
|
||||||
|
|
||||||
if status != "Active" and status != "InProgress":
|
|
||||||
continue
|
|
||||||
|
|
||||||
severity = details["severity"]
|
|
||||||
url = details["url"]
|
|
||||||
info = details["info"]
|
|
||||||
|
|
||||||
if severity == "High":
|
|
||||||
num_high += 1
|
|
||||||
state = State(params.get("severity_high", State.CRIT))
|
|
||||||
elif severity == "Medium":
|
|
||||||
num_med += 1
|
|
||||||
state = State(params.get("severity_medium", State.WARN))
|
|
||||||
elif severity == "Low":
|
|
||||||
num_low += 1
|
|
||||||
state = State(params.get("severity_low", State.WARN))
|
|
||||||
elif severity == "Informational":
|
|
||||||
num_info += 1
|
|
||||||
state = State(params.get("severity_informational", State.OK))
|
|
||||||
else:
|
|
||||||
state = State.UNKNOWN
|
|
||||||
|
|
||||||
final_state = State(max(final_state.value, state.value))
|
|
||||||
|
|
||||||
if state.value > State.OK.value:
|
|
||||||
region_details.append(f"{severity}: {info}: {url}")
|
|
||||||
|
|
||||||
if region_details == []:
|
|
||||||
region_details = ["No Defender alerts"]
|
|
||||||
|
|
||||||
yield Result(
|
|
||||||
state=final_state,
|
|
||||||
summary=f"High: {num_high}, Medium: {num_med}, Low: {num_low}, Informational: {num_info}",
|
|
||||||
details="\n".join(region_details)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
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_defender,
|
|
||||||
)
|
|
@ -1,4 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
dir=$(dirname -- "${BASH_SOURCE[0]}")
|
|
||||||
"$dir"/agent_azure_common defender "$1" "$2" "$3" "$4"
|
|
@ -1,4 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
dir=$(dirname -- "${BASH_SOURCE[0]}")
|
|
||||||
"$dir"/agent_azure_common firewall "$1" "$2" "$3" "$4"
|
|
@ -1,4 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
dir=$(dirname -- "${BASH_SOURCE[0]}")
|
|
||||||
"$dir"/agent_azure_common keyvault "$1" "$2" "$3" "$4"
|
|
@ -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
|
|
@ -0,0 +1,199 @@
|
|||||||
|
#!/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
|
||||||
|
|
||||||
|
|
||||||
|
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_str in string_table:
|
||||||
|
obj = json.loads(json_str)
|
||||||
|
name = obj["name"]
|
||||||
|
group = obj["resource_group"]
|
||||||
|
lookup[f"{name}#{resource_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:
|
||||||
|
check_state_below(alert_availability_percent, availability)
|
||||||
|
yield Metric(
|
||||||
|
name="availability",
|
||||||
|
value=availability,
|
||||||
|
levels=alert_availability_percent,
|
||||||
|
boundaries=(0, 100)
|
||||||
|
)
|
||||||
|
|
||||||
|
if capacity:
|
||||||
|
check_state_above(alert_capacity_percent, capacity)
|
||||||
|
yield Metric(
|
||||||
|
name="capacity",
|
||||||
|
value=capacity,
|
||||||
|
levels=alert_capacity_percent,
|
||||||
|
boundaries=(0, 100)
|
||||||
|
)
|
||||||
|
|
||||||
|
if latency:
|
||||||
|
check_state_above(alert_latency_milliseconds, latency)
|
||||||
|
yield Metric(
|
||||||
|
name="latency",
|
||||||
|
value=latency,
|
||||||
|
levels=alert_latency_milliseconds,
|
||||||
|
boundaries=(0, None)
|
||||||
|
)
|
||||||
|
|
||||||
|
if hits:
|
||||||
|
yield Metric(
|
||||||
|
name="hits",
|
||||||
|
value=hits,
|
||||||
|
boundaries=(0, None)
|
||||||
|
)
|
||||||
|
|
||||||
|
if results:
|
||||||
|
yield Metric(
|
||||||
|
name="results",
|
||||||
|
value=results,
|
||||||
|
boundaries=(0, None)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# 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 = vault["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:
|
||||||
|
check_state_below(alert_availability_percent, availability)
|
||||||
|
yield Metric(
|
||||||
|
name="availability",
|
||||||
|
value=availability,
|
||||||
|
levels=alert_availability_percent,
|
||||||
|
boundaries=(0, 100)
|
||||||
|
)
|
||||||
|
|
||||||
|
if latency:
|
||||||
|
check_state_above(alert_latency_milliseconds, latency)
|
||||||
|
yield Metric(
|
||||||
|
name="latency",
|
||||||
|
value=latency,
|
||||||
|
levels=alert_latency_milliseconds,
|
||||||
|
boundaries=(0, None)
|
||||||
|
)
|
||||||
|
|
||||||
|
if throughput:
|
||||||
|
yield Metric(
|
||||||
|
name="throughput",
|
||||||
|
value=thoughput,
|
||||||
|
boundaries=(0, None)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def check_defender(item, params, section):
|
||||||
|
yield Result(state=state, summary="Expires in %d days" % remaining_days)
|
||||||
|
|
||||||
|
|
||||||
|
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,
|
||||||
|
)
|
@ -28,8 +28,6 @@ RESOURCE_GROUP_RE = re.compile('/resourceGroups/(.+?)/')
|
|||||||
|
|
||||||
# https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/request-limits-and-throttling
|
# https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/request-limits-and-throttling
|
||||||
def get_url(req, default):
|
def get_url(req, default):
|
||||||
#import http.client
|
|
||||||
#http.client.HTTPConnection.debuglevel = 1
|
|
||||||
try:
|
try:
|
||||||
res = request.urlopen(req)
|
res = request.urlopen(req)
|
||||||
return res.read()
|
return res.read()
|
||||||
@ -40,33 +38,20 @@ def get_url(req, default):
|
|||||||
raise e
|
raise e
|
||||||
|
|
||||||
|
|
||||||
def set_proxy(req, proxy):
|
def get_token(tenant, username, password):
|
||||||
if proxy is None or proxy == '':
|
|
||||||
return
|
|
||||||
|
|
||||||
match = re.match('(https?)://(.+?)/?$', proxy, re.I)
|
|
||||||
req.set_proxy(match[2], match[1].lower())
|
|
||||||
|
|
||||||
# The explicit Host header is required for this to also work with a proxy.
|
|
||||||
# If we don't include it, Python sends the proxy's Host to Microsoft
|
|
||||||
# instead! So we have to set the Host to the Microsoft domain manually.
|
|
||||||
match = re.match('https://(.+?)/', req.full_url, re.I)
|
|
||||||
req.add_header('Host', match[1] + ":443")
|
|
||||||
|
|
||||||
|
|
||||||
def get_token(tenant, username, password, proxy):
|
|
||||||
data = parse.urlencode({
|
data = parse.urlencode({
|
||||||
'client_id': username,
|
'username': username,
|
||||||
'client_secret': password,
|
'password': password,
|
||||||
'grant_type': 'client_credentials',
|
'grant_type': 'password',
|
||||||
'claims': '{"access_token": {"xms_cc": {"values": ["CP1"]}}}',
|
'claims': '{"access_token": {"xms_cc": {"values": ["CP1"]}}}',
|
||||||
'scope': 'https://management.core.windows.net//.default offline_access openid profile',
|
'scope': 'https://management.core.windows.net//.default offline_access openid profile',
|
||||||
'client_info': 1,
|
'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',
|
req = request.Request(f'https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token',
|
||||||
data=str.encode(data))
|
data=str.encode(data))
|
||||||
set_proxy(req, proxy)
|
|
||||||
|
|
||||||
res = get_url(req, None)
|
res = get_url(req, None)
|
||||||
if res is None:
|
if res is None:
|
||||||
@ -77,32 +62,31 @@ def get_token(tenant, username, password, proxy):
|
|||||||
return token
|
return token
|
||||||
|
|
||||||
|
|
||||||
def get_json(token, proxy, path, version='2023-07-01'):
|
def get_json(token, path, version='2023-07-01'):
|
||||||
url = f"https://management.azure.com{path}{'?' in path and '&' or '?'}api-version={version}"
|
url = f"https://management.azure.com{path}{'?' in path and '&' or '?'}api-version={version}"
|
||||||
req = request.Request(url, headers={'Authorization': f'Bearer {token}'})
|
req = request.Request(url, headers={'Authorization': f'Bearer {token}'})
|
||||||
set_proxy(req, proxy)
|
|
||||||
res = get_url(req, "[]")
|
res = get_url(req, "[]")
|
||||||
data = json.loads(res)
|
data = json.loads(res)
|
||||||
return data['value']
|
return data['value']
|
||||||
|
|
||||||
|
|
||||||
def list_subscriptions(token, proxy):
|
def list_subscriptions(token):
|
||||||
return get_json(token, proxy, '/subscriptions')
|
return get_json(token, '/subscriptions')
|
||||||
|
|
||||||
|
|
||||||
def list_vaults(token, proxy, subscription):
|
def list_vaults(token, subscription):
|
||||||
return get_json(token, proxy, f'/subscriptions/{subscription}/resources?$filter=resourceType%20eq%20%27Microsoft.KeyVault%2Fvaults%27')
|
return get_json(token, f'/subscriptions/{subscription}/resources?$filter=resourceType%20eq%20%27Microsoft.KeyVault%2Fvaults%27')
|
||||||
|
|
||||||
|
|
||||||
def list_firewalls(token, proxy, subscription):
|
def list_firewalls(token, subscription):
|
||||||
return get_json(token, proxy, f'/subscriptions/{subscription}/resources?$filter=resourceType%20eq%20%27Microsoft.Network%2FazureFirewalls%27')
|
return get_json(token, f'/subscriptions/{subscription}/resources?$filter=resourceType%20eq%20%27Microsoft.Network%2FazureFirewalls%27')
|
||||||
|
|
||||||
|
|
||||||
def list_defender_alerts(token, proxy, subscription):
|
def list_defender_alerts(token, subscription):
|
||||||
return get_json(token, proxy, f'/subscriptions/{subscription}/providers/Microsoft.Security/alerts', '2022-01-01')
|
return get_json(token, f'/subscriptions/{subscription}/providers/Microsoft.Security/alerts', '2022-01-01')
|
||||||
|
|
||||||
|
|
||||||
def get_recent_metrics(token, proxy, path, metrics):
|
def get_recent_metrics(token, path, metrics):
|
||||||
end = datetime.now()
|
end = datetime.now()
|
||||||
start = end - timedelta(minutes=2)
|
start = end - timedelta(minutes=2)
|
||||||
|
|
||||||
@ -110,7 +94,7 @@ def get_recent_metrics(token, proxy, path, metrics):
|
|||||||
end_str = end.isoformat().split('.')[0] + 'Z'
|
end_str = end.isoformat().split('.')[0] + 'Z'
|
||||||
metrics_str = ','.join(metrics)
|
metrics_str = ','.join(metrics)
|
||||||
|
|
||||||
return get_json(token, proxy, f'{path}/providers/microsoft.insights/metrics?metricnames={metrics_str}×pan={start_str}/{end_str}', '2023-10-01')
|
return get_json(token, f'{path}/providers/microsoft.insights/metrics?metricnames={metrics_str}×pan={start_str}/{end_str}', '2023-10-01')
|
||||||
|
|
||||||
|
|
||||||
def metrics_to_lookup(metrics):
|
def metrics_to_lookup(metrics):
|
||||||
@ -128,47 +112,39 @@ def metrics_to_lookup(metrics):
|
|||||||
|
|
||||||
|
|
||||||
def get_args(argv):
|
def get_args(argv):
|
||||||
if (len(argv) != 5 and len(argv) != 6) or argv[1] not in ['keyvault', 'firewall', 'defender']:
|
if len(argv) != 5 or not argv[1] in ['keyvault', 'firewall', 'defender']:
|
||||||
print(f"{sys.argv[0]} <command> <tenant ID> <username> <password> <proxy>", file=sys.stderr)
|
print(f"{sys.argv[0]} <command> <tenand ID> <username> <password>", file=sys.stderr)
|
||||||
print(f"Valid commands are: 'keyvault', 'firewall', 'defender'", 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)
|
exit(1)
|
||||||
return argv[1], argv[2], argv[3], argv[4], (argv[5] if len(argv) == 6 else None)
|
return argv[1], argv[2], argv[3], argv[4]
|
||||||
|
|
||||||
|
|
||||||
def print_json(obj):
|
def print_json(obj):
|
||||||
print(json.dumps(obj))
|
print(json.dumps(obj))
|
||||||
|
|
||||||
|
|
||||||
def get_resource_group(obj):
|
command, tenant, username, password = get_args(sys.argv)
|
||||||
found = re.search(RESOURCE_GROUP_RE, obj['id'])
|
|
||||||
if found:
|
|
||||||
return found[1]
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
print(f"<<<azure_{command}:sep(0)>>>")
|
||||||
|
|
||||||
resource_groups = {}
|
token = get_token(tenant, username, password)
|
||||||
command, tenant, username, password, proxy = get_args(sys.argv)
|
|
||||||
token = get_token(tenant, username, password, proxy)
|
|
||||||
|
|
||||||
for subscription in list_subscriptions(token, proxy):
|
for subscription in list_subscriptions(token):
|
||||||
subscription_id = subscription['subscriptionId']
|
subscription_id = subscription['subscriptionId']
|
||||||
|
|
||||||
if command == 'defender':
|
if command == 'defender':
|
||||||
for alert in list_defender_alerts(token, proxy, subscription_id):
|
for alert in list_defender_alerts(token, subscription_id):
|
||||||
properties = alert['properties']
|
properties = alert['properties']
|
||||||
status = properties['status']
|
status = properties['status']
|
||||||
|
|
||||||
if not status in ['Active', 'InProgress']:
|
if not status in ['Active', 'InProgress']:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
group = get_resource_group(alert)
|
print_json({
|
||||||
|
|
||||||
resource_groups.setdefault(group, []).append({
|
|
||||||
'type': command,
|
'type': command,
|
||||||
'name': alert['name'],
|
'name': alert['name'],
|
||||||
'location': re.search(REGION_RE, alert['id'])[1],
|
'location': re.search(REGION_RE, alert['id'])[1],
|
||||||
'resource_group': group,
|
'resource_group': re.search(RESOURCE_GROUP_RE, alert['id'])[1],
|
||||||
'alert': {
|
'alert': {
|
||||||
'status': status,
|
'status': status,
|
||||||
'severity': properties['severity'],
|
'severity': properties['severity'],
|
||||||
@ -179,37 +155,23 @@ for subscription in list_subscriptions(token, proxy):
|
|||||||
})
|
})
|
||||||
|
|
||||||
elif command == 'firewall':
|
elif command == 'firewall':
|
||||||
for firewall in list_firewalls(token, proxy, subscription_id):
|
for firewall in list_firewalls(token, subscription_id):
|
||||||
metrics = get_recent_metrics(token, proxy, firewall['id'], FIREWALL_METRICS)
|
metrics = get_recent_metrics(token, firewall['id'], FIREWALL_METRICS)
|
||||||
group = get_resource_group(firewall)
|
print_json({
|
||||||
|
|
||||||
resource_groups.setdefault(group, []).append({
|
|
||||||
'type': command,
|
'type': command,
|
||||||
'name': firewall['name'],
|
'name': firewall['name'],
|
||||||
'location': firewall['location'],
|
'location': firewall['location'],
|
||||||
'resource_group': get_resource_group(firewall),
|
'resource_group': re.search(RESOURCE_GROUP_RE, firewall['id'])[1],
|
||||||
'metrics': metrics_to_lookup(metrics),
|
'metrics': metrics_to_lookup(metrics),
|
||||||
})
|
})
|
||||||
|
|
||||||
elif command == 'keyvault':
|
elif command == 'keyvault':
|
||||||
for vault in list_vaults(token, proxy, subscription_id):
|
for vault in list_vaults(token, subscription_id):
|
||||||
metrics = get_recent_metrics(token, proxy, vault['id'], VAULT_METRICS)
|
metrics = get_recent_metrics(token, vault['id'], VAULT_METRICS)
|
||||||
group = get_resource_group(vault)
|
print_json({
|
||||||
|
|
||||||
resource_groups.setdefault(group, []).append({
|
|
||||||
'type': command,
|
'type': command,
|
||||||
'name': vault['name'],
|
'name': vault['name'],
|
||||||
'location': vault['location'],
|
'location': vault['location'],
|
||||||
'resource_group': group,
|
'resource_group': re.search(RESOURCE_GROUP_RE, vault['id'])[1],
|
||||||
'metrics': metrics_to_lookup(metrics),
|
'metrics': metrics_to_lookup(metrics),
|
||||||
})
|
})
|
||||||
|
|
||||||
for group, results in resource_groups.items():
|
|
||||||
if group is None:
|
|
||||||
print(f"<<<<>>>>")
|
|
||||||
else:
|
|
||||||
print(f"<<<<{group}>>>>")
|
|
||||||
|
|
||||||
print(f"<<<azure_{command}:sep(0)>>>")
|
|
||||||
for result in results:
|
|
||||||
print_json(result)
|
|
@ -0,0 +1 @@
|
|||||||
|
agent_azure
|
@ -0,0 +1 @@
|
|||||||
|
agent_azure
|
@ -0,0 +1 @@
|
|||||||
|
agent_azure
|
22
check_mk-azure/local/share/check_mk/checks/agent_azure
Normal file
22
check_mk-azure/local/share/check_mk/checks/agent_azure
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# Copyright (C) 2024 Spearhead Systems SRL
|
||||||
|
|
||||||
|
def get_params(params):
|
||||||
|
return params["tenant"], params["client"], params["secret"]
|
||||||
|
|
||||||
|
def agent_azure_keyvault(params, hostname, ipaddress):
|
||||||
|
tenant, client, secret = get_params(params)
|
||||||
|
return ["keyvault", tenant, client, secret]
|
||||||
|
|
||||||
|
def agent_azure_firewall(params, hostname, ipaddress):
|
||||||
|
tenant, client, secret = get_params(params)
|
||||||
|
return ["firewall", tenant, client, secret]
|
||||||
|
|
||||||
|
def agent_azure_defender(params, hostname, ipaddress):
|
||||||
|
tenant, client, secret = get_params(params)
|
||||||
|
return ["defender", tenant, client, secret]
|
||||||
|
|
||||||
|
special_agent_info["azure_keyvault"] = agent_azure_keyvault
|
||||||
|
special_agent_info["azure_firewall"] = agent_azure_firewall
|
||||||
|
special_agent_info["azure_defender"] = agent_azure_defender
|
||||||
|
|
@ -2,7 +2,6 @@
|
|||||||
# Copyright (C) 2024 Spearhead Systems SRL
|
# Copyright (C) 2024 Spearhead Systems SRL
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
from cmk.base.plugins.agent_based.agent_based_api.v1 import State
|
|
||||||
from cmk.gui.i18n import _
|
from cmk.gui.i18n import _
|
||||||
from cmk.gui.plugins.wato.utils import (
|
from cmk.gui.plugins.wato.utils import (
|
||||||
rulespec_registry,
|
rulespec_registry,
|
||||||
@ -21,52 +20,39 @@ from cmk.gui.valuespec import (
|
|||||||
Password
|
Password
|
||||||
)
|
)
|
||||||
|
|
||||||
def _discovery(title):
|
|
||||||
|
def _valuespec_special_agents_azure_discovery():
|
||||||
return Dictionary(
|
return Dictionary(
|
||||||
title=_(title),
|
title=_("Azure Discovery"),
|
||||||
required_keys=["tenant", "username", "password"],
|
|
||||||
elements=[
|
elements=[
|
||||||
(
|
(
|
||||||
"tenant",
|
"tenant",
|
||||||
TextInput(
|
TextInput(
|
||||||
title=_("Tenant ID / Directory ID"),
|
title=_("Tenant ID / Directory ID"),
|
||||||
allow_empty=False,
|
allow_empty=False,
|
||||||
|
size=45,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"username",
|
"client",
|
||||||
TextInput(
|
TextInput(
|
||||||
title=_("Client ID / Application ID"),
|
title=_("Client ID / Application ID"),
|
||||||
allow_empty=False,
|
allow_empty=False,
|
||||||
|
size=45,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"password",
|
"secret",
|
||||||
IndividualOrStoredPassword(
|
IndividualOrStoredPassword(
|
||||||
# Password(
|
# Password(
|
||||||
title=_("Client Secret"),
|
title=_("Client Secret"),
|
||||||
allow_empty=False,
|
allow_empty=False,
|
||||||
|
size=45,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
|
||||||
"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():
|
def _valuespec_special_agents_azure_keyvault_check():
|
||||||
return Dictionary(
|
return Dictionary(
|
||||||
title=_("Azure Key Vault Metric Checks"),
|
title=_("Azure Key Vault Metric Checks"),
|
||||||
@ -170,71 +156,12 @@ def _valuespec_special_agents_azure_firewall_check():
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
def _valuespec_special_agents_azure_defender_check():
|
|
||||||
return Dictionary(
|
|
||||||
title=_("Azure Defender Alerts Severity"),
|
|
||||||
elements=[
|
|
||||||
(
|
|
||||||
"severity_high",
|
|
||||||
DropdownChoice(
|
|
||||||
title=_("Defender severity 'High'"),
|
|
||||||
help=_("What CheckMK criticality should this Azure Defender severity trigger"),
|
|
||||||
default_value=State.CRIT.value,
|
|
||||||
choices=[
|
|
||||||
(State.CRIT.value, _(State.CRIT.name)),
|
|
||||||
(State.WARN.value, _(State.WARN.name)),
|
|
||||||
(State.OK.value, _(State.OK.name)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"severity_medium",
|
|
||||||
DropdownChoice(
|
|
||||||
title=_("Defender severity 'Medium'"),
|
|
||||||
help=_("What CheckMK criticality should this Azure Defender severity trigger"),
|
|
||||||
default_value=State.WARN.value,
|
|
||||||
choices=[
|
|
||||||
(State.CRIT.value, _(State.CRIT.name)),
|
|
||||||
(State.WARN.value, _(State.WARN.name)),
|
|
||||||
(State.OK.value, _(State.OK.name)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"severity_low",
|
|
||||||
DropdownChoice(
|
|
||||||
title=_("Defender severity 'Low'"),
|
|
||||||
help=_("What CheckMK criticality should this Azure Defender severity trigger"),
|
|
||||||
default_value=State.WARN.value,
|
|
||||||
choices=[
|
|
||||||
(State.CRIT.value, _(State.CRIT.name)),
|
|
||||||
(State.WARN.value, _(State.WARN.name)),
|
|
||||||
(State.OK.value, _(State.OK.name)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"severity_informational",
|
|
||||||
DropdownChoice(
|
|
||||||
title=_("Defender severity 'Informational'"),
|
|
||||||
help=_("What CheckMK criticality should this Azure Defender severity trigger"),
|
|
||||||
default_value=State.OK.value,
|
|
||||||
choices=[
|
|
||||||
(State.CRIT.value, _(State.CRIT.name)),
|
|
||||||
(State.WARN.value, _(State.WARN.name)),
|
|
||||||
(State.OK.value, _(State.OK.name)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
rulespec_registry.register(
|
rulespec_registry.register(
|
||||||
HostRulespec(
|
HostRulespec(
|
||||||
name="special_agents:azure_keyvault",
|
name="special_agents:azure_keyvault",
|
||||||
group=RulespecGroupCheckParametersDiscovery,
|
group=RulespecGroupCheckParametersDiscovery,
|
||||||
match_type='dict',
|
match_type='dict',
|
||||||
valuespec=_valuespec_special_agents_azure_keyvault_discovery,
|
valuespec=_valuespec_special_agents_azure_discovery,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
rulespec_registry.register(
|
rulespec_registry.register(
|
||||||
@ -242,7 +169,7 @@ rulespec_registry.register(
|
|||||||
name="special_agents:azure_firewall",
|
name="special_agents:azure_firewall",
|
||||||
group=RulespecGroupCheckParametersDiscovery,
|
group=RulespecGroupCheckParametersDiscovery,
|
||||||
match_type='dict',
|
match_type='dict',
|
||||||
valuespec=_valuespec_special_agents_azure_firewall_discovery,
|
valuespec=_valuespec_special_agents_azure_discovery,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
rulespec_registry.register(
|
rulespec_registry.register(
|
||||||
@ -250,7 +177,7 @@ rulespec_registry.register(
|
|||||||
name="special_agents:azure_defender",
|
name="special_agents:azure_defender",
|
||||||
group=RulespecGroupCheckParametersDiscovery,
|
group=RulespecGroupCheckParametersDiscovery,
|
||||||
match_type='dict',
|
match_type='dict',
|
||||||
valuespec=_valuespec_special_agents_azure_defender_discovery,
|
valuespec=_valuespec_special_agents_azure_discovery,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -260,8 +187,6 @@ rulespec_registry.register(
|
|||||||
group=RulespecGroupCheckParametersApplications,
|
group=RulespecGroupCheckParametersApplications,
|
||||||
match_type="dict",
|
match_type="dict",
|
||||||
parameter_valuespec=_valuespec_special_agents_azure_keyvault_check,
|
parameter_valuespec=_valuespec_special_agents_azure_keyvault_check,
|
||||||
item_spec=lambda: TextInput(title=_("Key Vault")),
|
|
||||||
title=lambda: _("Azure Key Vault Metrics"),
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
rulespec_registry.register(
|
rulespec_registry.register(
|
||||||
@ -270,17 +195,5 @@ rulespec_registry.register(
|
|||||||
group=RulespecGroupCheckParametersApplications,
|
group=RulespecGroupCheckParametersApplications,
|
||||||
match_type="dict",
|
match_type="dict",
|
||||||
parameter_valuespec=_valuespec_special_agents_azure_firewall_check,
|
parameter_valuespec=_valuespec_special_agents_azure_firewall_check,
|
||||||
item_spec=lambda: TextInput(title=_("Firewall")),
|
|
||||||
title=lambda: _("Azure Firewall Metrics"),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
rulespec_registry.register(
|
|
||||||
CheckParameterRulespecWithItem(
|
|
||||||
check_group_name="azure_defender",
|
|
||||||
group=RulespecGroupCheckParametersApplications,
|
|
||||||
match_type="dict",
|
|
||||||
parameter_valuespec=_valuespec_special_agents_azure_defender_check,
|
|
||||||
item_spec=lambda: TextInput(title=_("Defender")),
|
|
||||||
title=lambda: _("Azure Defender Alerts Severity"),
|
|
||||||
)
|
)
|
||||||
)
|
)
|
@ -161,7 +161,7 @@ def check_cisco_ip_sla(_item, params, data):
|
|||||||
if state:
|
if state:
|
||||||
infotext += " (warn/crit at %s/%s)" % (warn, crit)
|
infotext += " (warn/crit at %s/%s)" % (warn, crit)
|
||||||
|
|
||||||
if unit == "ms" or unit == "us" or unit == "ms/us":
|
if unit == "ms/us":
|
||||||
factor = 1e3 if unit == "ms" else 1e6
|
factor = 1e3 if unit == "ms" else 1e6
|
||||||
perfdata = [
|
perfdata = [
|
||||||
("rtt", value / factor, warn / factor, crit / factor)
|
("rtt", value / factor, warn / factor, crit / factor)
|
||||||
@ -183,8 +183,8 @@ check_info["cisco_ip_sla"] = {
|
|||||||
"default_levels_variable": "cisco_ip_sla_default_levels",
|
"default_levels_variable": "cisco_ip_sla_default_levels",
|
||||||
"has_perfdata": True,
|
"has_perfdata": True,
|
||||||
"snmp_scan_function": lambda oid: "cisco" in oid(".1.3.6.1.2.1.1.1.0").lower()
|
"snmp_scan_function": lambda oid: "cisco" in oid(".1.3.6.1.2.1.1.1.0").lower()
|
||||||
and "os" 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.*"),
|
and oid(".1.3.6.1.4.1.9.9.42.1.2.2.1.37.*"),
|
||||||
"snmp_info": [
|
"snmp_info": [
|
||||||
(
|
(
|
||||||
".1.3.6.1.4.1.9.9.42.1.2.2.1",
|
".1.3.6.1.4.1.9.9.42.1.2.2.1",
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user