diff --git a/brian_polling_manager/configuration.py b/brian_polling_manager/configuration.py
index 699633a04bf94e468488f8eeaea150b47a8a44e6..160b07dcbe8870351dc5a27b418ca4dc91a108d8 100644
--- a/brian_polling_manager/configuration.py
+++ b/brian_polling_manager/configuration.py
@@ -31,6 +31,10 @@ _DEFAULT_CONFIG = {
'config': '/var/lib/sensu/conf/get-interface-stats.config.json',
'command': '{script} --config {config} {args}',
},
+ 'snmp-interface-check': {
+ 'script': '/var/lib/sensu/bin/counter2influx-v6.sh',
+ 'measurement': 'counters',
+ },
'gws-direct-interface-check': {
'script': '/var/lib/sensu/bin/poll-gws-direct.sh',
'measurement': 'gwsd_counters',
@@ -81,6 +85,15 @@ CONFIG_SCHEMA = {
'required': ['script', 'config', 'command'],
'additionalProperties': False
},
+ 'snmp-interface-check': {
+ 'type': 'object',
+ 'properties': {
+ 'script': {'type': 'string'},
+ 'measurement': {'type': 'string'},
+ },
+ 'required': ['script', 'measurement'],
+ 'additionalProperties': False
+ },
'sensu': {
'type': 'object',
'properties': {
@@ -92,6 +105,8 @@ CONFIG_SCHEMA = {
'api-key': {'type': 'string'},
'interface-check':
{'$ref': '#/definitions/router-check'},
+ 'snmp-interface-check':
+ {'$ref': '#/definitions/snmp-interface-check'},
'gws-direct-interface-check':
{'$ref': '#/definitions/influx-check'},
'dscp32-service-check':
diff --git a/brian_polling_manager/interfaces.py b/brian_polling_manager/interfaces.py
index bdcfbbec2b030115e286a3eebf19bdccf7db7876..4aaf2a7e940e7fde0cebb5619a32ac3ff869b199 100644
--- a/brian_polling_manager/interfaces.py
+++ b/brian_polling_manager/interfaces.py
@@ -9,8 +9,6 @@ logger = logging.getLogger(__name__)
def _is_rtr_check(check):
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)
@@ -26,8 +24,7 @@ def load_checks(sensu_params, filter_by):
return {c["metadata"]["name"]: c for c in checks}
-# TODO [POL1-797] rm after POL1-773 runs in production
-def load_deprecated_ifc_checks(sensu_params):
+def load_ifc_checks(sensu_params):
return load_checks(sensu_params, _is_ifc_check)
@@ -35,6 +32,45 @@ def load_router_checks(sensu_params):
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):
METRIC_FORMAT = ""
METRIC_HANDLERS = None
@@ -68,7 +104,7 @@ class NetconfRouterCheck(sensu.AbstractCheck):
return self.router
-def refresh(sensu_params, inventory_interfaces):
+def netconf_router_refresh(sensu_params, inventory_interfaces):
routers_w_vendor = {
(ifc["router"], ifc.get("vendor")) for ifc in inventory_interfaces
}
@@ -78,12 +114,16 @@ def refresh(sensu_params, inventory_interfaces):
for router, vendor in routers_w_vendor
]
- r1 = sensu.refresh(sensu_params, [], load_deprecated_ifc_checks(sensu_params))
- r2 = sensu.refresh(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"],
- "updated": r1["updated"] + r2["updated"],
- "deleted": r1["deleted"] + r2["deleted"],
- }
+ return sensu.refresh(
+ sensu_params, required_checks, load_router_checks(sensu_params)
+ )
+
+
+def snmp_interfaces_refresh(sensu_params, inventory_interfaces):
+ required_checks = [
+ 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))
diff --git a/brian_polling_manager/main.py b/brian_polling_manager/main.py
index 1228b238a0b512b172b8cc631e8e646ca81e4797..6e7cd985f8778012c53a8db4b3875e32e5e46204 100644
--- a/brian_polling_manager/main.py
+++ b/brian_polling_manager/main.py
@@ -52,12 +52,13 @@ REFRESH_RESULT_SCHEMA = {
},
'type': 'object',
'properties': {
- 'interfaces': {'$ref': '#/definitions/refresh-result'},
+ 'netconf': {'$ref': '#/definitions/refresh-result'},
+ 'snmp': {'$ref': '#/definitions/refresh-result'},
'gws_direct': {'$ref': '#/definitions/refresh-result'},
'gws_indirect': {'$ref': '#/definitions/refresh-result'},
'eumetsat_multicast': {'$ref': '#/definitions/refresh-result'},
},
- 'required': ['interfaces'],
+ 'required': ['netconf'],
'additionalProperties': False
}
@@ -90,7 +91,8 @@ def refresh(config, force=False):
= inventory.load_eumetsat_multicast_subscriptions(
config['inventory'])
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_indirect': gws_indirect.refresh(
config['sensu'], state.gws_indirect),
diff --git a/test/conftest.py b/test/conftest.py
index e2bd49b1f5ce643b6aefb26d57925b9947fb3360..e8850df8b5ba6f2a828cd8936366de43bf20f717 100644
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -44,6 +44,10 @@ def config():
"config": "/var/lib/sensu/conf/get-interface-stats.config.json",
"command": "{script} --config {config} {args}",
},
+ "snmp-interface-check": {
+ "script": "/var/lib/sensu/bin/counter2influx-v6.sh",
+ "measurement": "counters",
+ },
"gws-direct-interface-check": {
"script": "/var/lib/sensu/bin/poll-gws-direct.sh",
"measurement": "gwsd_counters",
diff --git a/test/data/interfaces.json b/test/data/interfaces.json
index 04a1eeda7b4c115e6950e92ecac6d25f420c0a9e..86d8a747847f6e020b4f170b98aba6995b62ba24 100644
--- a/test/data/interfaces.json
+++ b/test/data/interfaces.json
@@ -55,5 +55,21 @@
"description": "blah blah nokia router",
"circuits": [],
"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
}
]
diff --git a/test/test_sensu_checks.py b/test/test_sensu_checks.py
index fd03063c802896b28b1c9310afffc16541619536..f331c4bbc74468615d958411640b48ab5ccf69d0 100644
--- a/test/test_sensu_checks.py
+++ b/test/test_sensu_checks.py
@@ -53,6 +53,30 @@ def test_router_check(config):
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):
check = interfaces.NetconfRouterCheck(
config["sensu"]["interface-check"], "xyz", vendor="nokia"
@@ -68,22 +92,14 @@ def test_nokia_router_check(config):
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
def test_runs_idempotent(config, mocked_sensu, mocked_inventory):
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()
- 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}