diff --git a/brian_polling_manager/configuration.py b/brian_polling_manager/configuration.py index ec177a678265d24a70d72026a970ef5c83ce6994..38de9c9da94743a7be69f56ed0089cb0b0050363 100644 --- a/brian_polling_manager/configuration.py +++ b/brian_polling_manager/configuration.py @@ -32,6 +32,11 @@ _DEFAULT_CONFIG = { 'command': ('{script} {measurement} ' '{community} {hostname} ' '{interface} {ifIndex}'), + }, + 'gws-direct-interface-check': { + 'script': '/var/lib/sensu/bin/poll-gws-direct.sh', + 'measurement': 'gwsd_counters', + 'command': '{script} {measurement} {nren} {isp} {hostname} {tag}' } }, 'statedir': '/tmp/', @@ -65,9 +70,13 @@ CONFIG_SCHEMA = { 'minItems': 1 }, 'api-key': {'type': 'string'}, - 'interface-check': {'$ref': '#/definitions/influx-check'} + 'interface-check': {'$ref': '#/definitions/influx-check'}, + 'gws-direct-interface-check': + {'$ref': '#/definitions/influx-check'} }, - 'required': ['api-base', 'api-key', 'interface-check'], + 'required': [ + 'api-base', 'api-key', + 'interface-check', 'gws-direct-interface-check'], 'additionalProperties': False }, 'statsd': { @@ -116,9 +125,10 @@ class State(object): def __init__(self, state_dir: str): assert os.path.isdir(state_dir) - self.filenames = { + self.cache_filenames = { 'state': os.path.join(state_dir, State.STATE), - 'cache': os.path.join(state_dir, State.INTERFACES) + 'interfaces': os.path.join(state_dir, State.INTERFACES), + 'gws-direct': os.path.join(state_dir, State.GWS_DIRECT) } @staticmethod @@ -133,38 +143,58 @@ class State(object): f'unable to open state file {filename}') return None + @staticmethod + def _save_json(filename, new_data, schema): + try: + jsonschema.validate(new_data, schema) + except jsonschema.ValidationError: + logger.exception('invalid interface state data') + return + + with open(filename, 'w') as f: + f.write(json.dumps(new_data)) + @property def last(self) -> int: - state = State._load_json(self.filenames['state'], State.STATE_SCHEMA) + state = State._load_json( + self.cache_filenames['state'], State.STATE_SCHEMA) return state['last'] if state else -1 @last.setter def last(self, new_last: Union[float, None]): if not new_last or new_last < 0: - os.unlink(self.filenames['state']) + os.unlink(self.cache_filenames['state']) else: - state = {'last': new_last} - with open(self.filenames['state'], 'w') as f: - f.write(json.dumps(state)) + State._save_json( + self.cache_filenames['state'], + {'last': new_last}, + State.STATE_SCHEMA) @property def interfaces(self) -> list: return State._load_json( - self.filenames['cache'], + self.cache_filenames['interfaces'], inventory.INVENTORY_INTERFACES_SCHEMA) @interfaces.setter def interfaces(self, new_interfaces): - try: - jsonschema.validate( - new_interfaces, - inventory.INVENTORY_INTERFACES_SCHEMA) - except jsonschema.ValidationError: - logger.exception('invalid interface state data') - return + State._save_json( + self.cache_filenames['interfaces'], + new_interfaces, + inventory.INVENTORY_INTERFACES_SCHEMA) - with open(self.filenames['cache'], 'w') as f: - f.write(json.dumps(new_interfaces)) + @property + def gws_direct(self) -> list: + return State._load_json( + self.cache_filenames['gws-direct'], + inventory.GWS_DIRECT_SCHEMA) + + @gws_direct.setter + def gws_direct(self, new_interfaces): + State._save_json( + self.cache_filenames['gws-direct'], + new_interfaces, + inventory.GWS_DIRECT_SCHEMA) def _setup_logging(filename=None): diff --git a/brian_polling_manager/inventory.py b/brian_polling_manager/inventory.py index ac950c461f3ecdb11f40912c0fd0ae5e4620596e..1b6ceae885b7802bfb7229aa5b778e32fbd9d3bb 100644 --- a/brian_polling_manager/inventory.py +++ b/brian_polling_manager/inventory.py @@ -181,20 +181,8 @@ def load_gws_direct_interfaces(base_urls): :param base_urls: inventory provider base api url, or a list of them :return: an interable of interface-specific check data """ - - gws_direct_config = _load_inventory_json( - 'poller/gws/direct', base_urls, INVENTORY_INTERFACES_SCHEMA) - - def _ifc_check_params(config_item): - # i.e. all but the counters element - return { - 'nren': config_item['nren'], - 'isp': config_item['isp'], - 'hostname': config_item['hostname'], - 'tag': config_item['tag'] - } - - return map(_ifc_check_params, gws_direct_config) + return _load_inventory_json( + 'poller/gws/direct', base_urls, GWS_DIRECT_SCHEMA) def last_update_timestamp(base_urls) -> float: diff --git a/brian_polling_manager/main.py b/brian_polling_manager/main.py index b11406b90d8ff2372fc5ea00d13cdea71e123d3f..4fc22b306f19739192a94ff2b1303d76bf873a71 100644 --- a/brian_polling_manager/main.py +++ b/brian_polling_manager/main.py @@ -52,7 +52,8 @@ REFRESH_RESULT_SCHEMA = { }, 'type': 'object', 'properties': { - 'interfaces': {'$ref': '#/definitions/refresh-result'} + 'interfaces': {'$ref': '#/definitions/refresh-result'}, + 'gws_direct': {'$ref': '#/definitions/refresh-result'} }, 'required': ['interfaces'], 'additionalProperties': False @@ -77,26 +78,27 @@ def refresh(config, force=False): if force or not last or last != state.last: state.last = last state.interfaces = inventory.load_interfaces(config['inventory']) - # state.gws_direct = inventory.load_gws_direct_interfaces( - # config['inventory']) + state.gws_direct = inventory.load_gws_direct_interfaces( + config['inventory']) result = { 'interfaces': interfaces.refresh(config['sensu'], state.interfaces), - # 'gws direct': gws_direct.refresh(config['sensu'], state) + 'gws_direct': gws_direct.refresh(config['sensu'], state.gws_direct) } + jsonschema.validate(result, REFRESH_RESULT_SCHEMA) # sanity statsd_config = config.get('statsd', None) if statsd_config: - statsd = StatsClient( - host=statsd_config['hostname'], - port=statsd_config['port'], - prefix=f'{statsd_config["prefix"]}_interfaces') - statsd.gauge('checks', result['interfaces']['checks']) - statsd.gauge('input', result['interfaces']['input']) - statsd.gauge('created', result['interfaces']['created']) - statsd.gauge('updated', result['interfaces']['updated']) - statsd.gauge('deleted', result['interfaces']['deleted']) + for key, counts in result.items(): + statsd = StatsClient( + host=statsd_config['hostname'], + port=statsd_config['port'], + prefix=f'{statsd_config["prefix"]}_{key}') + statsd.gauge('checks', counts['checks']) + statsd.gauge('input', counts['input']) + statsd.gauge('created', counts['created']) + statsd.gauge('updated', counts['updated']) + statsd.gauge('deleted', counts['deleted']) - jsonschema.validate(result, REFRESH_RESULT_SCHEMA) # sanity return result diff --git a/test/conftest.py b/test/conftest.py index 4b6295e2e525d036daae16c59df24f63581a8ee1..da76a08afe7ed2c9685d3427cf5f2203a122d5e2 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -39,6 +39,11 @@ def config(): 'command': ('{script} {measurement} ' '{community} {hostname} ' '{interface} {ifIndex}'), + }, + 'gws-direct-interface-check': { + 'script': '/var/lib/sensu/bin/poll-gws-direct.sh', + 'measurement': 'gwsd_counters', + 'command': '{script} {measurement} {nren} {isp} {hostname} {tag}' } }, 'statedir': state_dir_name, @@ -164,6 +169,12 @@ def mocked_inventory(): 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')) + bogus_version = {'latch': {'timestamp': 10000 * random.random()}} # mocked api for returning all checks responses.add( diff --git a/test/data/gws-direct.json b/test/data/gws-direct.json new file mode 100644 index 0000000000000000000000000000000000000000..445a34058ddfa9818bda2f3ff51a80a919e87117 --- /dev/null +++ b/test/data/gws-direct.json @@ -0,0 +1 @@ +[{"nren": "ARNES", "isp": "Cogent", "hostname": "88.200.0.63", "tag": "a", "counters": [{"field": "discards_in", "oid": "1.3.6.1.2.1.2.2.1.13.533", "community": "gn2nocT3st"}, {"field": "discards_out", "oid": "1.3.6.1.2.1.2.2.1.19.533", "community": "gn2nocT3st"}, {"field": "errors_in", "oid": "1.3.6.1.2.1.2.2.1.14.533", "community": "gn2nocT3st"}, {"field": "errors_out", "oid": "1.3.6.1.2.1.2.2.1.20.533", "community": "gn2nocT3st"}]}, {"nren": "ARNES", "isp": "Cogent", "hostname": "88.200.0.63", "tag": "b", "counters": [{"field": "traffic_in", "oid": "1.3.6.1.2.1.31.1.1.1.6.531", "community": "gn2nocT3st"}, {"field": "traffic_out", "oid": "1.3.6.1.2.1.31.1.1.1.10.531", "community": "gn2nocT3st"}]}, {"nren": "ARNES", "isp": "Cogent", "hostname": "88.200.0.63", "tag": "c", "counters": [{"field": "traffic_in", "oid": "1.3.6.1.2.1.31.1.1.1.6.525", "community": "gn2nocT3st"}, {"field": "traffic_out", "oid": "1.3.6.1.2.1.31.1.1.1.10.525", "community": "gn2nocT3st"}]}, {"nren": "ARNES", "isp": "Cogent", "hostname": "88.200.0.63", "tag": "d", "counters": [{"field": "traffic_in", "oid": "1.3.6.1.2.1.31.1.1.1.6.553", "community": "gn2nocT3st"}, {"field": "traffic_out", "oid": "1.3.6.1.2.1.31.1.1.1.10.553", "community": "gn2nocT3st"}]}, {"nren": "ARNES", "isp": "Cogent", "hostname": "88.200.0.63", "tag": "e", "counters": [{"field": "traffic_in", "oid": "1.3.6.1.2.1.31.1.1.1.6.563", "community": "gn2nocT3st"}, {"field": "traffic_out", "oid": "1.3.6.1.2.1.31.1.1.1.10.563", "community": "gn2nocT3st"}]}, {"nren": "ARNES", "isp": "Telia", "hostname": "62.40.124.6", "tag": "a", "counters": [{"field": "traffic_in", "oid": "1.3.6.1.2.1.31.1.1.1.6.611", "community": "gn2nocT3st"}, {"field": "traffic_out", "oid": "1.3.6.1.2.1.31.1.1.1.10.611", "community": "gn2nocT3st"}]}, {"nren": "ARNES", "isp": "Telia", "hostname": "62.40.124.6", "tag": "b", "counters": [{"field": "traffic_in", "oid": "1.3.6.1.2.1.31.1.1.1.6.589", "community": "gn2nocT3st"}, {"field": "traffic_out", "oid": "1.3.6.1.2.1.31.1.1.1.10.589", "community": "gn2nocT3st"}]}, {"nren": "CARNET", "isp": "Cogent", "hostname": "62.40.124.10", "tag": "a", "counters": [{"field": "traffic_in", "oid": "1.3.6.1.2.1.31.1.1.1.6.35", "community": "atlas1453"}, {"field": "traffic_out", "oid": "1.3.6.1.2.1.31.1.1.1.10.35", "community": "atlas1453"}]}, {"nren": "CARNET", "isp": "Telia", "hostname": "62.40.125.150", "tag": "a", "counters": [{"field": "traffic_in", "oid": "1.3.6.1.2.1.31.1.1.1.6.48", "community": "atlas1453"}, {"field": "traffic_out", "oid": "1.3.6.1.2.1.31.1.1.1.10.48", "community": "atlas1453"}]}, {"nren": "KIFU", "isp": "Cogent", "hostname": "195.111.97.108", "tag": "a", "counters": [{"field": "traffic_in", "oid": "1.3.6.1.2.1.31.1.1.1.6.155", "community": "atlas1453"}, {"field": "traffic_out", "oid": "1.3.6.1.2.1.31.1.1.1.10.155", "community": "atlas1453"}]}, {"nren": "KIFU", "isp": "Telia", "hostname": "195.111.97.108", "tag": "a", "counters": [{"field": "traffic_in", "oid": "1.3.6.1.2.1.31.1.1.1.6.148", "community": "atlas1453"}, {"field": "traffic_out", "oid": "1.3.6.1.2.1.31.1.1.1.10.148", "community": "atlas1453"}]}, {"nren": "RedIRIS", "isp": "Telia", "hostname": "130.206.206.250", "tag": "a", "counters": [{"field": "traffic_in", "oid": "1.3.6.1.2.1.31.1.1.1.6.1487", "community": "atlas1453"}, {"field": "traffic_out", "oid": "1.3.6.1.2.1.31.1.1.1.10.1487", "community": "atlas1453"}]}, {"nren": "RedIRIS", "isp": "Telia", "hostname": "130.206.206.250", "tag": "b", "counters": [{"field": "traffic_in", "oid": "1.3.6.1.2.1.31.1.1.1.6.1488", "community": "atlas1453"}, {"field": "traffic_out", "oid": "1.3.6.1.2.1.31.1.1.1.10.1488", "community": "atlas1453"}]}, {"nren": "RedIRIS", "isp": "Telia", "hostname": "130.206.206.250", "tag": "c", "counters": [{"field": "traffic_in", "oid": "1.3.6.1.2.1.31.1.1.1.6.1489", "community": "atlas1453"}, {"field": "traffic_out", "oid": "1.3.6.1.2.1.31.1.1.1.10.1489", "community": "atlas1453"}]}, {"nren": "RedIRIS", "isp": "Telia", "hostname": "130.206.206.250", "tag": "d", "counters": [{"field": "traffic_in", "oid": "1.3.6.1.2.1.31.1.1.1.6.760", "community": "atlas1453"}, {"field": "traffic_out", "oid": "1.3.6.1.2.1.31.1.1.1.10.760", "community": "atlas1453"}]}, {"nren": "RedIRIS", "isp": "Telia", "hostname": "130.206.206.250", "tag": "e", "counters": [{"field": "traffic_in", "oid": "1.3.6.1.2.1.31.1.1.1.6.796", "community": "atlas1453"}, {"field": "traffic_out", "oid": "1.3.6.1.2.1.31.1.1.1.10.796", "community": "atlas1453"}]}, {"nren": "RoEduNet", "isp": "Cogent", "hostname": "149.6.50.10", "tag": "a", "counters": [{"field": "traffic_in", "oid": "1.3.6.1.2.1.31.1.1.1.6.531", "community": "dante"}, {"field": "traffic_out", "oid": "1.3.6.1.2.1.31.1.1.1.10.531", "community": "dante"}]}, {"nren": "RoEduNet", "isp": "Century Link", "hostname": "212.162.45.194", "tag": "a", "counters": [{"field": "traffic_in", "oid": "1.3.6.1.2.1.31.1.1.1.6.9", "community": "dante"}, {"field": "traffic_out", "oid": "1.3.6.1.2.1.31.1.1.1.10.9", "community": "dante"}]}, {"nren": "EENet", "isp": "Telia", "hostname": "193.40.133.2", "tag": "a", "counters": [{"field": "traffic_in", "oid": "1.3.6.1.2.1.31.1.1.1.6.263", "community": "geant-mon-telia"}, {"field": "traffic_out", "oid": "1.3.6.1.2.1.31.1.1.1.10.263", "community": "geant-mon-telia"}]}, {"nren": "PSNC", "isp": "Century Link", "hostname": "212.191.126.6", "tag": "a", "counters": [{"field": "traffic_in", "oid": "1.3.6.1.2.1.31.1.1.1.6.675", "community": "atlas1453"}, {"field": "traffic_out", "oid": "1.3.6.1.2.1.31.1.1.1.10.675", "community": "atlas1453"}]}, {"nren": "PSNC", "isp": "Century Link", "hostname": "212.191.126.7", "tag": "a", "counters": [{"field": "traffic_in", "oid": "1.3.6.1.2.1.31.1.1.1.6.677", "community": "atlas1453"}, {"field": "traffic_out", "oid": "1.3.6.1.2.1.31.1.1.1.10.677", "community": "atlas1453"}]}, {"nren": "FCCN", "isp": "Cogent", "hostname": "193.136.5.43", "tag": "a", "counters": [{"field": "traffic_in", "oid": "1.3.6.1.2.1.31.1.1.1.6.47", "community": "geantcom"}, {"field": "traffic_out", "oid": "1.3.6.1.2.1.31.1.1.1.10.47", "community": "geantcom"}]}] \ No newline at end of file