diff --git a/inventory_provider/routes/poller.py b/inventory_provider/routes/poller.py index b9b21ea06b2985bd290f53618d897fa7a1ec0ebb..c6cf843b6bce58c13c4c8b1dfd991ec3ab97a015 100644 --- a/inventory_provider/routes/poller.py +++ b/inventory_provider/routes/poller.py @@ -30,6 +30,12 @@ These endpoints are intended for use by BRIAN. .. autofunction:: inventory_provider.routes.poller.gws_direct +/poller/gws/direct-config +--------------------------------- + +.. autofunction:: inventory_provider.routes.poller.gws_direct_config + + /poller/gws/indirect --------------------------------- @@ -53,13 +59,14 @@ support method: _get_dashboards .. autofunction:: inventory_provider.routes.poller._get_dashboards + """ from enum import Enum, auto import json import logging import re -from flask import Blueprint, Response, current_app, request +from flask import Blueprint, Response, current_app, request, jsonify from lxml import etree from inventory_provider import juniper @@ -422,7 +429,7 @@ def _get_dashboards(interface): yield BRIAN_DASHBOARDS.IAS_CUSTOMER if 'SRV_IAS UPSTREAM' in description: yield BRIAN_DASHBOARDS.IAS_UPSTREAM - if 'SRV_GLOBAL RE_INTERCONNECT' in description: + if re.match('(SRV_GLOBAL|SRV_L3VPN|LAG) RE_INTERCONNECT', description): yield BRIAN_DASHBOARDS.RE_PEER if re.match(r'(PHY|LAG|SRV_GLOBAL) CUSTOMER', description): yield BRIAN_DASHBOARDS.RE_CUST @@ -1278,3 +1285,76 @@ def get_service_types(): redis.set(cache_key, service_types) return Response(service_types, mimetype='application/json') + + +@routes.route('/gws/direct-config', methods=['GET', 'POST']) +def gws_direct_config(): + """ + Handler for `/poller/gws/direct-config` which returns + the basic gws-direct config. + + This api is only intended for config validation. + :return: + """ + + format = request.args.get('format', default='json', type=str) + format = format.lower() + if format not in ('html', 'json'): + return Response( + response='format must be one of: html, json', + status=400, + mimetype="text/html") + + def _counters(): + config_params = current_app.config['INVENTORY_PROVIDER_CONFIG'] + for nren_isp in config_params['gws-direct']: + for host in nren_isp['hosts']: + snmp_version = '2' if 'community' in host.keys() else '3' + for ifc in host['interfaces']: + for field, oid in ifc['counters'].items(): + yield { + 'nren': nren_isp['nren'], + 'isp': nren_isp['isp'], + 'hostname': host['hostname'], + 'snmp': snmp_version, + 'interface': ifc['tag'], + 'field': field, + 'oid': oid + } + + def _to_row(counter, header=False): + _columns = ( + 'nren', 'isp', 'hostname', 'snmp', 'interface', 'field', 'oid') + elems = ['<tr>'] + for name in _columns: + if header: + elems.append(f'<th>{name}</th>') + else: + elems.append(f'<td>{counter[name]}</td>') + elems.append('</tr>') + return ''.join(elems) + + if format == 'json': + if not request.accept_mimetypes.accept_json: + return Response( + response="response will be json", + status=406, + mimetype="text/html") + else: + return jsonify(list(_counters())) + + if not request.accept_mimetypes.accept_html: + return Response( + response="response will be html", + status=406, + mimetype="text/html") + + elems = ['<html>', '<body>', '<table>'] + elems.append(_to_row(None, header=True)) + elems += map(_to_row, _counters()) + elems += ['</table>', '</body>', '</html>'] + + return Response( + response=''.join(elems), + status=200, + mimetype="text/html") diff --git a/test/test_general_poller_routes.py b/test/test_general_poller_routes.py index 571875bbeb6b0bb40c0ebf5727fd885fa5df57f3..c528635a77499f20e77e3a00fa8fd12815bdf982 100644 --- a/test/test_general_poller_routes.py +++ b/test/test_general_poller_routes.py @@ -4,7 +4,6 @@ import pytest from inventory_provider.routes import poller DEFAULT_REQUEST_HEADERS = { - # 'Content-type': 'application/json', 'Accept': ['application/json'] } @@ -239,7 +238,7 @@ def test_fw_counter_bytes_oid_values(customer, interface_name, expected_oid): ('SRV_IAS UPSTREAM COGENT #COGENT_GWS_VIE | ASN174', ['IAS_UPSTREAM']), ('SRV_L3VPN RE_INTERCONNECT CLARA #REDCLARA-LIS-LHCONE | ASN27750', - ['LHCONE', 'LHCONE_PEER']), + ['LHCONE', 'LHCONE_PEER', 'RE_PEER']), ('SRV_MDVPN CUSTOMER REDIRIS #RedIRIS_AP1_BGP_LU_CoC_1 | MD VPN CoC-REDIRIS - ', # noqa: E501 ['MDVPN_CUSTOMERS', 'NREN']), ('SRV_L2CIRCUIT CUSTOMER TENET PSNC #lon-lon-GEANTOPEN-PSNC-TENET-18067 |', # noqa: E501 @@ -299,7 +298,7 @@ def test_interface_dashboard_mapping(description, expected_dashboards): }, {'name': 'COGENT', 'interface_type': 'LOGICAL'}), ({ 'description': 'SRV_L3VPN RE_INTERCONNECT CLARA #REDCLARA-LIS-LHCONE | ASN27750', # noqa: E501 - 'dashboards': ['LHCONE', 'LHCONE_PEER'] + 'dashboards': ['LHCONE', 'LHCONE_PEER', 'RE_PEER'] }, {'name': 'CLARA', 'interface_type': 'LOGICAL'}), ({ 'description': 'SRV_MDVPN CUSTOMER REDIRIS #RedIRIS_AP1_BGP_LU_CoC_1 | MD VPN CoC-REDIRIS - ', # noqa: E501 @@ -315,3 +314,27 @@ def test_description_dashboard_parsing(interface, dashboard_info): updated = poller._get_dashboard_data(interface) info = updated['dashboard_info'] assert info == dashboard_info + + +def test_gws_config_json(client): + rv = client.get( + '/poller/gws/direct-config', + headers={'Accept': ['application/json']}) + assert rv.status_code == 200 + assert rv.is_json + response_data = json.loads(rv.data.decode('utf-8')) + # just a sanity check, no validation + # ... for now, this isn't an important interface + assert response_data + + +def test_gws_config_html(client): + rv = client.get( + '/poller/gws/direct-config?format=html', + headers={'Accept': ['text/html']}) + assert rv.status_code == 200 + response_data = rv.data.decode('utf-8') + # just a sanity check, no validation + # ... for now, this isn't an important interface + assert response_data.startswith('<html>') + assert response_data.endswith('</html>')