diff --git a/brian_polling_manager/configuration.py b/brian_polling_manager/configuration.py index 38de9c9da94743a7be69f56ed0089cb0b0050363..a200bb881182fd2d521b7474ca318054b207f18a 100644 --- a/brian_polling_manager/configuration.py +++ b/brian_polling_manager/configuration.py @@ -37,6 +37,11 @@ _DEFAULT_CONFIG = { 'script': '/var/lib/sensu/bin/poll-gws-direct.sh', 'measurement': 'gwsd_counters', 'command': '{script} {measurement} {nren} {isp} {hostname} {tag}' + }, + 'dscp32-service-check': { + 'script': '/var/lib/sensu/bin/poll-gws-indirect.sh', + 'measurement': 'dscp32_counters', + 'command': '{script} {measurement} {service}' } }, 'statedir': '/tmp/', @@ -72,11 +77,14 @@ CONFIG_SCHEMA = { 'api-key': {'type': 'string'}, 'interface-check': {'$ref': '#/definitions/influx-check'}, 'gws-direct-interface-check': - {'$ref': '#/definitions/influx-check'} + {'$ref': '#/definitions/influx-check'}, + 'dscp32-service-check': {'$ref': '#/definitions/influx-check'}, }, 'required': [ 'api-base', 'api-key', - 'interface-check', 'gws-direct-interface-check'], + 'interface-check', + 'gws-direct-interface-check', + 'dscp32-service-check'], 'additionalProperties': False }, 'statsd': { @@ -110,6 +118,7 @@ CONFIG_SCHEMA = { class State(object): GWS_DIRECT = 'gws-direct.json' + GWS_INDIRECT = 'gws-indirect.json' INTERFACES = 'interfaces.json' STATE = 'state.json' @@ -128,7 +137,8 @@ class State(object): self.cache_filenames = { 'state': os.path.join(state_dir, State.STATE), 'interfaces': os.path.join(state_dir, State.INTERFACES), - 'gws-direct': os.path.join(state_dir, State.GWS_DIRECT) + 'gws-direct': os.path.join(state_dir, State.GWS_DIRECT), + 'gws-indirect': os.path.join(state_dir, State.GWS_INDIRECT) } @staticmethod @@ -196,6 +206,19 @@ class State(object): new_interfaces, inventory.GWS_DIRECT_SCHEMA) + @property + def gws_indirect(self) -> list: + return State._load_json( + self.cache_filenames['gws-indirect'], + inventory.GWS_INDIRECT_SCHEMA) + + @gws_indirect.setter + def gws_indirect(self, new_services): + State._save_json( + self.cache_filenames['gws-indirect'], + new_services, + inventory.GWS_INDIRECT_SCHEMA) + def _setup_logging(filename=None): """ diff --git a/brian_polling_manager/gws_indirect.py b/brian_polling_manager/gws_indirect.py new file mode 100644 index 0000000000000000000000000000000000000000..3c72b5c333a7f0b2912103ba53398bc5d4e1685c --- /dev/null +++ b/brian_polling_manager/gws_indirect.py @@ -0,0 +1,49 @@ +import binascii +import hashlib +import json + +from brian_polling_manager import sensu + + +def load_dscp32_checks(sensu_params): + def _is_dscp32_check(check): + name = check['metadata']['name'] + return name.startswith('dscp32') + ifc_checks = filter( + _is_dscp32_check, sensu.load_all_checks(sensu_params)) + return {c['metadata']['name']: c for c in ifc_checks} + + +class DSCP32CountersCheck(sensu.AbstractCheck): + + def __init__(self, sensu_check_params, service): + super().__init__() + self.sensu_check_params = sensu_check_params + self.service = service + + @sensu.AbstractCheck.name.getter + def name(self): + return f'dscp32-{self.service["name"]}' + + @sensu.AbstractCheck.command.getter + def command(self): + return self.sensu_check_params['command'].format( + script=self.sensu_check_params['script'], + measurement=self.sensu_check_params['measurement'], + service=self.service['name']) + + @sensu.AbstractCheck.proxy_entity_name.getter + def proxy_entity_name(self): + return self.service['hostname'] + + +def refresh(sensu_params, services): + + required_checks = [ + DSCP32CountersCheck(sensu_params['dscp32-service-check'], s) + for s in services] + + return sensu.refresh( + sensu_params, + required_checks, + load_dscp32_checks(sensu_params)) diff --git a/brian_polling_manager/inventory.py b/brian_polling_manager/inventory.py index 7fd483f541f9e54b8e8387500cf373e6c36fbaa6..4539f5af197140e0f8cf7c87088e6010e8c9d771 100644 --- a/brian_polling_manager/inventory.py +++ b/brian_polling_manager/inventory.py @@ -77,6 +77,25 @@ GWS_DIRECT_SCHEMA = { 'items': {'$ref': '#/definitions/interface-counters'} } +GWS_INDIRECT_SCHEMA = { + '$schema': 'http://json-schema.org/draft-07/schema#', + + 'definitions': { + 'service': { + 'type': 'object', + 'properties': { + # minimal validation for our purposes + 'name': {'type': 'string'}, + 'hostname': {'type': 'string'} + }, + 'required': ['name', 'hostname'] + } + }, + + 'type': 'array', + 'items': {'$ref': '#/definitions/service'} +} + def _pick_one(haystack): if not isinstance(haystack, (list, tuple, set)): @@ -129,6 +148,17 @@ def load_gws_direct_interfaces(base_urls): 'poller/gws/direct', base_urls, GWS_DIRECT_SCHEMA) +def load_gws_indirect_services(base_urls): + """ + Load /poller/gws/indirect from inventory provider + + :param base_urls: inventory provider base api url, or a list of them + :return: an iterable of strings (service names) + """ + return _load_inventory_json( + 'poller/gws/indirect', base_urls, GWS_INDIRECT_SCHEMA) + + def last_update_timestamp(base_urls) -> float: try: r = requests.get( diff --git a/brian_polling_manager/main.py b/brian_polling_manager/main.py index 4fc22b306f19739192a94ff2b1303d76bf873a71..ab837be04feb9235447bee664f800355493088b7 100644 --- a/brian_polling_manager/main.py +++ b/brian_polling_manager/main.py @@ -30,7 +30,7 @@ import jsonschema from statsd import StatsClient from brian_polling_manager \ - import inventory, configuration, interfaces, gws_direct + import inventory, configuration, interfaces, gws_direct, gws_indirect logger = logging.getLogger(__name__) @@ -53,7 +53,8 @@ REFRESH_RESULT_SCHEMA = { 'type': 'object', 'properties': { 'interfaces': {'$ref': '#/definitions/refresh-result'}, - 'gws_direct': {'$ref': '#/definitions/refresh-result'} + 'gws_direct': {'$ref': '#/definitions/refresh-result'}, + 'gws_indirect': {'$ref': '#/definitions/refresh-result'} }, 'required': ['interfaces'], 'additionalProperties': False @@ -80,9 +81,13 @@ def refresh(config, force=False): state.interfaces = inventory.load_interfaces(config['inventory']) state.gws_direct = inventory.load_gws_direct_interfaces( config['inventory']) + state.gws_indirect = inventory.load_gws_indirect_services( + config['inventory']) result = { 'interfaces': 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( + config['sensu'], state.gws_indirect), } jsonschema.validate(result, REFRESH_RESULT_SCHEMA) # sanity diff --git a/test/conftest.py b/test/conftest.py index fc4dd7766d6622b9d1154397113b1517fd22ca1e..a2e99401dcc03df611c1d555c74562ffb496191b 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -45,6 +45,11 @@ def config(): 'measurement': 'gwsd_counters', 'command': ('{script} {measurement} ' '{nren} {isp} {hostname} {tag}') + }, + 'dscp32-service-check': { + 'script': '/var/lib/sensu/bin/poll-gws-indirect.sh', + 'measurement': 'dscp32_counters', + 'command': '{script} {measurement} {service}' } }, 'statedir': state_dir_name, @@ -164,18 +169,21 @@ def mocked_sensu(): @pytest.fixture def mocked_inventory(): - # mocked api for returning all checks responses.add( method=responses.GET, url=re.compile(r'.*inventory.+/poller/interfaces.*'), body=_load_test_data('interfaces.json')) - # mocked api for returning all checks responses.add( method=responses.GET, url=re.compile(r'.*inventory.+/poller/gws/direct'), body=_load_test_data('gws-direct.json')) + responses.add( + method=responses.GET, + url=re.compile(r'.*inventory.+/poller/gws/indirect.*'), + body=_load_test_data('gws-indirect.json')) + bogus_version = {'latch': {'timestamp': 10000 * random.random()}} # mocked api for returning all checks responses.add( diff --git a/test/data/gws-indirect.json b/test/data/gws-indirect.json new file mode 100644 index 0000000000000000000000000000000000000000..c3b2d352adae77f4cf4f2f50e6d4cc74b53fa845 --- /dev/null +++ b/test/data/gws-indirect.json @@ -0,0 +1 @@ +[{"id": 662955, "name": "RENAM-AP-IAS", "customer": "RENAM", "speed": 10737418240, "pop": "BUCHAREST", "hostname": "mx1.buc.ro.geant.net", "interface": "ae12.333", "type": "GWS - INDIRECT", "status": "non-monitored"}, {"id": 702139, "name": "FR_ARN_IAS", "customer": "ARN", "speed": 10737418240, "pop": "MARSEILLE", "hostname": "mx1.mar.fr.geant.net", "interface": "ae18.333", "type": "GWS - INDIRECT", "status": "operational"}, {"id": 663103, "name": "AMRES-AP-IAS", "customer": "AMRES", "speed": 21474836480, "pop": "BUDAPEST", "hostname": "mx1.bud.hu.geant.net", "interface": "ae16.333", "type": "GWS - INDIRECT", "status": "operational"}, {"id": 663198, "name": "CYNET-AP3-IAS", "customer": "CYNET", "speed": 10737418240, "pop": "ATHENS 2", "hostname": "mx1.ath2.gr.geant.net", "interface": "ae12.333", "type": "GWS - INDIRECT", "status": "operational"}, {"id": 663075, "name": "BELNET-AP3-IAS", "customer": "BELNET", "speed": 107374182400, "pop": "AMSTERDAM", "hostname": "mx1.ams.nl.geant.net", "interface": "ae13.333", "type": "GWS - INDIRECT", "status": "operational"}, {"id": 661220, "name": "UK_ASREN_IAS", "customer": "ASREN", "speed": 10737418240, "pop": "LONDON 2", "hostname": "mx1.lon2.uk.geant.net", "interface": "ae17.333", "type": "GWS - INDIRECT", "status": "operational"}, {"id": 661313, "name": "MARNET-AP2-IAS", "customer": "MARNET", "speed": 10737418240, "pop": "VIENNA", "hostname": "mx1.vie.at.geant.net", "interface": "ae17.333", "type": "GWS - INDIRECT", "status": "operational"}, {"id": 661510, "name": "UOM-AP1-IAS", "customer": "UOM", "speed": 10737418240, "pop": "MILAN 2 CALDERA", "hostname": "mx1.mil2.it.geant.net", "interface": "xe-11/0/0.333", "type": "GWS - INDIRECT", "status": "operational"}, {"id": 661936, "name": "KIFU-AP2-IAS", "customer": "KIFU", "speed": 42949672960, "pop": "VIENNA", "hostname": "mx1.vie.at.geant.net", "interface": "ae18.333", "type": "GWS - INDIRECT", "status": "operational"}, {"id": 663070, "name": "KIFU_AP1_IAS", "customer": "KIFU", "speed": 107374182400, "pop": "BUDAPEST", "hostname": "mx1.bud.hu.geant.net", "interface": "ae10.333", "type": "GWS - INDIRECT", "status": "operational"}, {"id": 661641, "name": "FCCN-AP1-IAS", "customer": "FCCN", "speed": 42949672960, "pop": "LISBON", "hostname": "mx2.lis.pt.geant.net", "interface": "ae10.333", "type": "GWS - INDIRECT", "status": "operational"}, {"id": 663220, "name": "RESTENA-AP1-IAS", "customer": "RESTENA", "speed": 107374182400, "pop": "FRANKFURT", "hostname": "mx1.fra.de.geant.net", "interface": "ae18.333", "type": "GWS - INDIRECT", "status": "operational"}, {"id": 661496, "name": "SANET_AP_IAS", "customer": "SANET", "speed": 21474836480, "pop": "BRATISLAVA", "hostname": "mx2.bra.sk.geant.net", "interface": "ae13.421", "type": "GWS - INDIRECT", "status": "operational"}, {"id": 662908, "name": "MREN-AP-IAS", "customer": "MREN", "speed": 10737418240, "pop": "BUDAPEST", "hostname": "mx1.bud.hu.geant.net", "interface": "ae15.333", "type": "GWS - INDIRECT", "status": "operational"}, {"id": 661308, "name": "RASH-AP1-IAS", "customer": "RASH", "speed": 10737418240, "pop": "MILAN 2 CALDERA", "hostname": "mx1.mil2.it.geant.net", "interface": "ae13.333", "type": "GWS - INDIRECT", "status": "operational"}, {"id": 663228, "name": "IUCC-AP2-IAS", "customer": "IUCC", "speed": 32212254720, "pop": "FRANKFURT", "hostname": "mx1.fra.de.geant.net", "interface": "ae21.333", "type": "GWS - INDIRECT", "status": "operational"}, {"id": 679570, "name": "ROEDUNET-AP2-IAS", "customer": "ROEDUNET", "speed": 107374182400, "pop": "VIENNA", "hostname": "mx1.vie.at.geant.net", "interface": "ae21.333", "type": "GWS - INDIRECT", "status": "operational"}, {"id": 702074, "name": "CYNET_AP2_IAS", "customer": "CYNET", "speed": 10737418240, "pop": "FRANKFURT", "hostname": "mx1.fra.de.geant.net", "interface": "ae38.333", "type": "GWS - INDIRECT", "status": "operational"}, {"id": 707416, "name": "LITNET-AP2-IAS", "customer": "LITNET", "speed": 10737418240, "pop": "KAUNAS", "hostname": "rt1.kau.lt.geant.net", "interface": "xe-0/1/1.333", "type": "GWS - INDIRECT", "status": "operational"}, {"id": 662907, "name": "GRNET-AP2-IAS", "customer": "GRNET", "speed": 42949672960, "pop": "ATHENS 2", "hostname": "mx1.ath2.gr.geant.net", "interface": "ae11.333", "type": "GWS - INDIRECT", "status": "operational"}, {"id": 673674, "name": "BELNET_AP2_IAS", "customer": "BELNET", "speed": 107374182400, "pop": "LONDON", "hostname": "mx1.lon.uk.geant.net", "interface": "ae16.333", "type": "GWS - INDIRECT", "status": "operational"}, {"id": 661222, "name": "FCCN-AP2-IAS", "customer": "FCCN", "speed": 42949672960, "pop": "LISBON 2", "hostname": "mx1.lis.pt.geant.net", "interface": "ae10.333", "type": "GWS - INDIRECT", "status": "operational"}, {"id": 661977, "name": "GRNET-AP1-IAS", "customer": "GRNET", "speed": 42949672960, "pop": "ATHENS", "hostname": "mx2.ath.gr.geant.net", "interface": "ae10.333", "type": "GWS - INDIRECT", "status": "operational"}, {"id": 661500, "name": "IUCC-AP1-IAS", "customer": "IUCC", "speed": 32212254720, "pop": "LONDON", "hostname": "mx1.lon.uk.geant.net", "interface": "ae21.333", "type": "GWS - INDIRECT", "status": "operational"}, {"id": 663112, "name": "ROEDUNET_AP1_IAS", "customer": "ROEDUNET", "speed": 42949672960, "pop": "BUCHAREST", "hostname": "mx1.buc.ro.geant.net", "interface": "ae11.333", "type": "GWS - INDIRECT", "status": "operational"}, {"id": 678593, "name": "URAN-AP1-IAS", "customer": "URAN", "speed": 21474836480, "pop": "VIENNA", "hostname": "mx1.vie.at.geant.net", "interface": "ae20.333", "type": "GWS - INDIRECT", "status": "operational"}, {"id": 661703, "name": "LITNET_AP1_IAS", "customer": "LITNET", "speed": 10737418240, "pop": "KAUNAS", "hostname": "rt2.kau.lt.geant.net", "interface": "xe-0/1/1.333", "type": "GWS - INDIRECT", "status": "operational"}] \ No newline at end of file