cli.py 3.65 KiB
import contextlib
from functools import partial
import json
import click
import jsonschema
from brian_polling_manager.interface_stats import config, brian, juniper
from brian_polling_manager import inventory, influx
import json
import logging.config
import os
LOGGING_DEFAULT_CONFIG = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'simple': {
'format': '%(asctime)s - %(name)s '
'(%(lineno)d) - %(levelname)s - %(message)s'
}
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'level': 'DEBUG',
'formatter': 'simple',
'stream': 'ext://sys.stdout'
},
},
'loggers': {
'brian_polling_manager': {
'level': 'DEBUG',
'handlers': ['console'],
'propagate': False
}
},
'root': {
'level': 'INFO',
'handlers': ['console']
}
}
def setup_logging():
"""
set up logging using the configured filename
if LOGGING_CONFIG is defined in the environment, use this for
the filename, otherwise use LOGGING_DEFAULT_CONFIG
"""
logging_config = LOGGING_DEFAULT_CONFIG
if 'LOGGING_CONFIG' in os.environ:
filename = os.environ['LOGGING_CONFIG']
with open(filename) as f:
logging_config = json.loads(f.read())
# # TODO: this mac workaround should be removed ...
# import platform
# if platform.system() == 'Darwin':
# logging_config['handlers']['syslog_handler']['address'] \
# = '/var/run/syslog'
logging.config.dictConfig(logging_config)
def _validate_config(_unused_ctx, _unused_param, file):
try:
return config.load(file)
except json.JSONDecodeError:
raise click.BadParameter('config file is not valid json')
except jsonschema.ValidationError as e:
raise click.BadParameter(e)
def _managed_routers(inventory_base_urls):
return {_ifc['router'] for _ifc in inventory.load_interfaces(inventory_base_urls)}
def fqdn_netconf_doc_map(app_config_params):
_result = {}
for fqdn in _managed_routers(inventory_base_urls=app_config_params['inventory']):
_result[fqdn] = juniper.get_interface_info_ncrpc(fqdn)
return _result
def _brian_points(router_fqdn, netconf_doc, measurement_name):
interfaces = juniper.physical_interface_counters(netconf_doc)
counters = brian.counters(router_fqdn=router_fqdn, interface_counters=interfaces)
yield from map(partial(brian.ctr2point, measurement_name), counters)
interfaces = juniper.logical_interface_counters(netconf_doc)
counters = brian.counters(router_fqdn=router_fqdn, interface_counters=interfaces)
yield from map(partial(brian.ctr2point, measurement_name), counters)
def _main(app_config_params: dict):
"""
callable entry point, without click
... tmp, for testing
:param app_config_params:
:return:
"""
setup_logging()
nc_doc_map = fqdn_netconf_doc_map(app_config_params)
influx_params = app_config_params['influx']['brian-counters']
for _fqdn, _ncdoc in nc_doc_map.items():
points = _brian_points(
router_fqdn=_fqdn,
netconf_doc=_ncdoc,
measurement_name=influx_params['measurement'])
with contextlib.closing(influx.influx_client(influx_params)) as client:
client.write_points(points)
@click.command()
@click.option(
'--config', 'app_config_params',
required=True,
type=click.File('r'),
help='Config filename',
callback=_validate_config)
def main(app_config_params: dict):
_main(app_config_params)
if __name__ == '__main__':
main()