Skip to content
Snippets Groups Projects
Commit f3b8f645 authored by Pelle Koster's avatar Pelle Koster
Browse files

Merge branch 'feature/POL1-826-snmp-check-for-ipv6' into 'develop'

POL1-826: reintroduce snmp check for ipv6 counters on juniper ae subinterfaces

See merge request live-projects/brian-polling-manager!13
parents ef63141e 8b533abe
No related branches found
No related tags found
No related merge requests found
...@@ -31,6 +31,10 @@ _DEFAULT_CONFIG = { ...@@ -31,6 +31,10 @@ _DEFAULT_CONFIG = {
'config': '/var/lib/sensu/conf/get-interface-stats.config.json', 'config': '/var/lib/sensu/conf/get-interface-stats.config.json',
'command': '{script} --config {config} {args}', 'command': '{script} --config {config} {args}',
}, },
'snmp-interface-check': {
'script': '/var/lib/sensu/bin/counter2influx-v6.sh',
'measurement': 'counters',
},
'gws-direct-interface-check': { 'gws-direct-interface-check': {
'script': '/var/lib/sensu/bin/poll-gws-direct.sh', 'script': '/var/lib/sensu/bin/poll-gws-direct.sh',
'measurement': 'gwsd_counters', 'measurement': 'gwsd_counters',
...@@ -81,6 +85,15 @@ CONFIG_SCHEMA = { ...@@ -81,6 +85,15 @@ CONFIG_SCHEMA = {
'required': ['script', 'config', 'command'], 'required': ['script', 'config', 'command'],
'additionalProperties': False 'additionalProperties': False
}, },
'snmp-interface-check': {
'type': 'object',
'properties': {
'script': {'type': 'string'},
'measurement': {'type': 'string'},
},
'required': ['script', 'measurement'],
'additionalProperties': False
},
'sensu': { 'sensu': {
'type': 'object', 'type': 'object',
'properties': { 'properties': {
...@@ -92,6 +105,8 @@ CONFIG_SCHEMA = { ...@@ -92,6 +105,8 @@ CONFIG_SCHEMA = {
'api-key': {'type': 'string'}, 'api-key': {'type': 'string'},
'interface-check': 'interface-check':
{'$ref': '#/definitions/router-check'}, {'$ref': '#/definitions/router-check'},
'snmp-interface-check':
{'$ref': '#/definitions/snmp-interface-check'},
'gws-direct-interface-check': 'gws-direct-interface-check':
{'$ref': '#/definitions/influx-check'}, {'$ref': '#/definitions/influx-check'},
'dscp32-service-check': 'dscp32-service-check':
......
...@@ -9,8 +9,6 @@ logger = logging.getLogger(__name__) ...@@ -9,8 +9,6 @@ logger = logging.getLogger(__name__)
def _is_rtr_check(check): def _is_rtr_check(check):
name = check["metadata"]["name"] name = check["metadata"]["name"]
# check-* is the old-style name (add to the returned
# data so it can be deleted)
return re.match(r"^(rtr)-[^-]+\.geant\.net$", name) return re.match(r"^(rtr)-[^-]+\.geant\.net$", name)
...@@ -26,8 +24,7 @@ def load_checks(sensu_params, filter_by): ...@@ -26,8 +24,7 @@ def load_checks(sensu_params, filter_by):
return {c["metadata"]["name"]: c for c in checks} return {c["metadata"]["name"]: c for c in checks}
# TODO [POL1-797] rm after POL1-773 runs in production def load_ifc_checks(sensu_params):
def load_deprecated_ifc_checks(sensu_params):
return load_checks(sensu_params, _is_ifc_check) return load_checks(sensu_params, _is_ifc_check)
...@@ -35,6 +32,45 @@ def load_router_checks(sensu_params): ...@@ -35,6 +32,45 @@ def load_router_checks(sensu_params):
return load_checks(sensu_params, _is_rtr_check) return load_checks(sensu_params, _is_rtr_check)
class SNMPInterfaceCheck(sensu.AbstractCheck):
COMMAND_STR = "{script} {measurement} {community} {hostname} {interface} {if_index}"
def __init__(self, ifc_check_params, interface):
super().__init__()
self.ifc_check_params = ifc_check_params
self.interface = interface
@sensu.AbstractCheck.name.getter
def name(self):
# fix POL1-386 - replace : in interface name with .
# https://docs.sensu.io/sensu-go/latest/observability-pipeline/
# observe-schedule/checks/#metadata-attributes
ifc_name = self.interface["name"].replace("/", "-").replace(":", ".")
return f'ifc-{self.interface["router"]}-{ifc_name}'
@sensu.AbstractCheck.command.getter
def command(self):
return self.COMMAND_STR.format(
script=self.ifc_check_params["script"],
measurement=self.ifc_check_params["measurement"],
# TODO: add community string to /poller/interfaces response
# (cf. POL1-339)
community="0pBiFbD",
hostname=self.interface["router"],
interface=self.interface["name"],
if_index=self.interface["snmp-index"],
)
@sensu.AbstractCheck.proxy_entity_name.getter
def proxy_entity_name(self):
return self.interface["router"]
@staticmethod
def requires_snmp_check(interface):
# only juniper ae subinterfaces for now
return re.match(r"^ae\d+\.\d+", interface["name"])
class NetconfRouterCheck(sensu.AbstractCheck): class NetconfRouterCheck(sensu.AbstractCheck):
METRIC_FORMAT = "" METRIC_FORMAT = ""
METRIC_HANDLERS = None METRIC_HANDLERS = None
...@@ -68,7 +104,7 @@ class NetconfRouterCheck(sensu.AbstractCheck): ...@@ -68,7 +104,7 @@ class NetconfRouterCheck(sensu.AbstractCheck):
return self.router return self.router
def refresh(sensu_params, inventory_interfaces): def netconf_router_refresh(sensu_params, inventory_interfaces):
routers_w_vendor = { routers_w_vendor = {
(ifc["router"], ifc.get("vendor")) for ifc in inventory_interfaces (ifc["router"], ifc.get("vendor")) for ifc in inventory_interfaces
} }
...@@ -78,12 +114,16 @@ def refresh(sensu_params, inventory_interfaces): ...@@ -78,12 +114,16 @@ def refresh(sensu_params, inventory_interfaces):
for router, vendor in routers_w_vendor for router, vendor in routers_w_vendor
] ]
r1 = sensu.refresh(sensu_params, [], load_deprecated_ifc_checks(sensu_params)) return sensu.refresh(
r2 = sensu.refresh(sensu_params, required_checks, load_router_checks(sensu_params)) sensu_params, required_checks, load_router_checks(sensu_params)
return { )
"checks": r1["checks"] + r2["checks"],
"input": r1["input"] + r2["input"],
"created": r1["created"] + r2["created"], def snmp_interfaces_refresh(sensu_params, inventory_interfaces):
"updated": r1["updated"] + r2["updated"], required_checks = [
"deleted": r1["deleted"] + r2["deleted"], SNMPInterfaceCheck(sensu_params["snmp-interface-check"], ifc)
} for ifc in inventory_interfaces
if SNMPInterfaceCheck.requires_snmp_check(ifc)
]
return sensu.refresh(sensu_params, required_checks, load_ifc_checks(sensu_params))
...@@ -52,12 +52,13 @@ REFRESH_RESULT_SCHEMA = { ...@@ -52,12 +52,13 @@ REFRESH_RESULT_SCHEMA = {
}, },
'type': 'object', 'type': 'object',
'properties': { 'properties': {
'interfaces': {'$ref': '#/definitions/refresh-result'}, 'netconf': {'$ref': '#/definitions/refresh-result'},
'snmp': {'$ref': '#/definitions/refresh-result'},
'gws_direct': {'$ref': '#/definitions/refresh-result'}, 'gws_direct': {'$ref': '#/definitions/refresh-result'},
'gws_indirect': {'$ref': '#/definitions/refresh-result'}, 'gws_indirect': {'$ref': '#/definitions/refresh-result'},
'eumetsat_multicast': {'$ref': '#/definitions/refresh-result'}, 'eumetsat_multicast': {'$ref': '#/definitions/refresh-result'},
}, },
'required': ['interfaces'], 'required': ['netconf'],
'additionalProperties': False 'additionalProperties': False
} }
...@@ -90,7 +91,8 @@ def refresh(config, force=False): ...@@ -90,7 +91,8 @@ def refresh(config, force=False):
= inventory.load_eumetsat_multicast_subscriptions( = inventory.load_eumetsat_multicast_subscriptions(
config['inventory']) config['inventory'])
result = { result = {
'interfaces': interfaces.refresh(config['sensu'], state.interfaces), 'netconf': interfaces.netconf_router_refresh(config['sensu'], state.interfaces),
'snmp': interfaces.snmp_interfaces_refresh(config['sensu'], state.interfaces),
'gws_direct': gws_direct.refresh(config['sensu'], state.gws_direct), 'gws_direct': gws_direct.refresh(config['sensu'], state.gws_direct),
'gws_indirect': gws_indirect.refresh( 'gws_indirect': gws_indirect.refresh(
config['sensu'], state.gws_indirect), config['sensu'], state.gws_indirect),
......
...@@ -44,6 +44,10 @@ def config(): ...@@ -44,6 +44,10 @@ def config():
"config": "/var/lib/sensu/conf/get-interface-stats.config.json", "config": "/var/lib/sensu/conf/get-interface-stats.config.json",
"command": "{script} --config {config} {args}", "command": "{script} --config {config} {args}",
}, },
"snmp-interface-check": {
"script": "/var/lib/sensu/bin/counter2influx-v6.sh",
"measurement": "counters",
},
"gws-direct-interface-check": { "gws-direct-interface-check": {
"script": "/var/lib/sensu/bin/poll-gws-direct.sh", "script": "/var/lib/sensu/bin/poll-gws-direct.sh",
"measurement": "gwsd_counters", "measurement": "gwsd_counters",
......
...@@ -55,5 +55,21 @@ ...@@ -55,5 +55,21 @@
"description": "blah blah nokia router", "description": "blah blah nokia router",
"circuits": [], "circuits": [],
"snmp-index": 9999 "snmp-index": 9999
},
{
"router": "mx1.fra.de.geant.net",
"name": "ae10.1",
"bundle": [],
"bundle-parents": [],
"description": "blah blah",
"circuits": [
{
"id": 50028,
"name": "something",
"type": "SERVICE",
"status": "operational"
}
],
"snmp-index": 9999
} }
] ]
...@@ -53,6 +53,30 @@ def test_router_check(config): ...@@ -53,6 +53,30 @@ def test_router_check(config):
assert check["output_metric_handlers"] == [] assert check["output_metric_handlers"] == []
def test_snmp_interface_check(config):
check = interfaces.SNMPInterfaceCheck(
config["sensu"]["snmp-interface-check"],
{"router": "bogus.router", "name": "bogus/1/1", "snmp-index": 123},
).to_dict()
assert check["command"] == (
"/var/lib/sensu/bin/counter2influx-v6.sh counters 0pBiFbD bogus.router "
"bogus/1/1 123"
)
assert check["proxy_entity_name"] == "bogus.router"
assert check["metadata"]["name"] == "ifc-bogus.router-bogus-1-1"
assert check["output_metric_format"] == "influxdb_line"
assert check["output_metric_handlers"] == ["influx-db-handler"]
@responses.activate
def test_snmp_interface_refresh(config, mocked_sensu, mocked_inventory):
routers = inventory.load_interfaces("http://inventory1")
result = interfaces.snmp_interfaces_refresh(
config["sensu"], inventory_interfaces=routers
)
assert result == {"checks": 3, "input": 1, "created": 1, "updated": 0, "deleted": 3}
def test_nokia_router_check(config): def test_nokia_router_check(config):
check = interfaces.NetconfRouterCheck( check = interfaces.NetconfRouterCheck(
config["sensu"]["interface-check"], "xyz", vendor="nokia" config["sensu"]["interface-check"], "xyz", vendor="nokia"
...@@ -68,22 +92,14 @@ def test_nokia_router_check(config): ...@@ -68,22 +92,14 @@ def test_nokia_router_check(config):
assert check["output_metric_handlers"] == [] assert check["output_metric_handlers"] == []
@responses.activate
def test_cleans_up_old_interface_checks(config, mocked_sensu, mocked_inventory):
routers = inventory.load_interfaces("http://inventory1")
result = interfaces.refresh(config["sensu"], inventory_interfaces=routers)
assert result == {"checks": 3, "input": 3, "created": 3, "updated": 0, "deleted": 3}
sensu.clear_cached_values()
result = interfaces.refresh(config["sensu"], inventory_interfaces=routers)
assert result == {"checks": 3, "input": 3, "created": 0, "updated": 0, "deleted": 0}
@responses.activate @responses.activate
def test_runs_idempotent(config, mocked_sensu, mocked_inventory): def test_runs_idempotent(config, mocked_sensu, mocked_inventory):
routers = inventory.load_interfaces("http://inventory1") routers = inventory.load_interfaces("http://inventory1")
interfaces.refresh(config["sensu"], inventory_interfaces=routers) interfaces.netconf_router_refresh(config["sensu"], inventory_interfaces=routers)
sensu.clear_cached_values() sensu.clear_cached_values()
result = interfaces.refresh(config["sensu"], inventory_interfaces=routers) result = interfaces.netconf_router_refresh(
config["sensu"], inventory_interfaces=routers
)
assert result == {"checks": 3, "input": 3, "created": 0, "updated": 0, "deleted": 0} assert result == {"checks": 3, "input": 3, "created": 0, "updated": 0, "deleted": 0}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment