diff --git a/brian_dashboard_manager/config.py b/brian_dashboard_manager/config.py index 294e16e2b03b539f4451359f362f0754818053fb..c94da1d81b20df68db32c7992752797a8a7cf332 100644 --- a/brian_dashboard_manager/config.py +++ b/brian_dashboard_manager/config.py @@ -77,6 +77,8 @@ DEFAULT_ORGANIZATIONS = [ "IAS PUBLIC": True, "IAS UPSTREAM": True, "GWS PHY Upstream": True, + "GWS Direct": True, + "GWS Indirect": True, } }, { @@ -116,7 +118,9 @@ DEFAULT_ORGANIZATIONS = [ "IAS PRIVATE": True, "IAS PUBLIC": True, "IAS UPSTREAM": True, - "GWS PHY Upstream": True + "GWS PHY Upstream": True, + "GWS Direct": True, + "GWS Indirect": True, } } ] diff --git a/brian_dashboard_manager/dashboards/services_ias.json b/brian_dashboard_manager/dashboards/services_ias.json index d0644528905b1caada0daad603c263c0cbf58f23..5719b432a0a4ad905e566ae1639efc88d7bafb6c 100755 --- a/brian_dashboard_manager/dashboards/services_ias.json +++ b/brian_dashboard_manager/dashboards/services_ias.json @@ -46,7 +46,7 @@ "folderId": null, "gridPos": { "h": 25, - "w": 6, + "w": 4, "x": 0, "y": 0 }, @@ -114,8 +114,8 @@ "folderId": null, "gridPos": { "h": 25, - "w": 6, - "x": 6, + "w": 4, + "x": 4, "y": 0 }, "headings": false, @@ -182,8 +182,8 @@ "folderId": null, "gridPos": { "h": 25, - "w": 6, - "x": 12, + "w": 4, + "x": 8, "y": 0 }, "headings": false, @@ -250,8 +250,8 @@ "folderId": null, "gridPos": { "h": 25, - "w": 6, - "x": 18, + "w": 4, + "x": 12, "y": 0 }, "headings": false, @@ -306,6 +306,142 @@ "timeShift": null, "title": "IAS PRIVATE", "type": "dashlist" + }, + { + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "folderId": null, + "gridPos": { + "h": 25, + "w": 4, + "x": 16, + "y": 0 + }, + "headings": false, + "id": 6, + "limit": 100, + "pluginVersion": "7.1.4", + "query": "", + "recent": false, + "search": true, + "starred": false, + "tags": [ + "GWS_DIRECT" + ], + "targets": [ + { + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "GWS Direct", + "type": "dashlist" + }, + { + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "folderId": null, + "gridPos": { + "h": 25, + "w": 4, + "x": 20, + "y": 0 + }, + "headings": false, + "id": 7, + "limit": 100, + "pluginVersion": "7.1.4", + "query": "", + "recent": false, + "search": true, + "starred": false, + "tags": [ + "GWS_INDIRECT" + ], + "targets": [ + { + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "GWS Indirect", + "type": "dashlist" } ], "schemaVersion": 26, @@ -338,3 +474,4 @@ "title": "IAS", "version": 1 } + diff --git a/brian_dashboard_manager/grafana/provision.py b/brian_dashboard_manager/grafana/provision.py index 54b5bf90391a38e9cf48f87e5610f0bbba0ee793..f04d851b4dbb9016cf3fae1e4c9db1793725f385 100644 --- a/brian_dashboard_manager/grafana/provision.py +++ b/brian_dashboard_manager/grafana/provision.py @@ -8,6 +8,7 @@ import time import json import datetime from functools import reduce +from concurrent.futures import Future from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor from brian_dashboard_manager.config import DEFAULT_ORGANIZATIONS, STATE_PATH from brian_dashboard_manager.grafana.utils.request import \ @@ -23,7 +24,7 @@ from brian_dashboard_manager.grafana.datasource import \ from brian_dashboard_manager.grafana.folder import find_folder, \ delete_folder from brian_dashboard_manager.inventory_provider.interfaces import \ - get_interfaces + get_gws_direct, get_gws_indirect, get_interfaces from brian_dashboard_manager.templating.nren_access import generate_nrens from brian_dashboard_manager.templating.helpers import is_re_customer, \ @@ -34,6 +35,9 @@ from brian_dashboard_manager.templating.helpers import is_re_customer, \ get_interface_data, parse_backbone_name, parse_phy_upstream_name, \ get_dashboard_data, get_aggregate_interface_data +from brian_dashboard_manager.templating.gws import generate_gws, \ + generate_indirect + from brian_dashboard_manager.templating.render import render_dashboard logger = logging.getLogger(__name__) @@ -117,6 +121,9 @@ def provision_maybe(config): now = datetime.datetime.now() write_timestamp(now.timestamp(), val) provision(config) + except Exception as e: + logger.exception('Uncaught Exception:') + raise e finally: now = datetime.datetime.now() write_timestamp(now.timestamp(), False) @@ -180,7 +187,10 @@ def provision(config): def excluded(interface): desc = interface.get('description', '').lower() - return not any(nren.lower() in desc for nren in excluded_nrens) + lab = 'lab.office' in interface.get('router', '').lower() + excluded_desc = any( + nren.lower() in desc for nren in excluded_nrens) + return not (excluded_desc or lab) excluded_interfaces = list(filter(excluded, interfaces)) @@ -263,6 +273,14 @@ def provision(config): dash_list = find_dashboard(token_request) or [] dash_list = reduce(get_uid, dash_list, {}) + def update_dash_list(dashboards): + for dashboard in dashboards: + if isinstance(dashboard, Future): + dashboard = dashboard.result() + if dashboard is None: + continue + dash_list[dashboard.get('uid')] = True + with ProcessPoolExecutor(max_workers=4) as executor: provisioned = [] for folder_name, dash in dashboards.items(): @@ -282,14 +300,55 @@ def provision(config): excluded_interfaces, datasource_name, exclude) provisioned.append(res) + for result in provisioned: folder = result.result() if folder is None: continue - for dashboard in folder: - if dashboard is None: - continue - dash_list[dashboard.get('uid')] = True + update_dash_list(folder) + + # fetch GWS direct data and provision related dashboards + logger.info('Provisioning GWS Indirect dashboards') + folder_name = 'GWS Indirect' + exclude_indirect = excluded_folders.get(folder_name, False) + if isinstance(exclude_indirect, bool) and exclude_indirect: + # don't provision GWS Direct folder + delete_folder(token_request, folder_name) + else: + folder = find_folder(token_request, folder_name) + with ProcessPoolExecutor(max_workers=4) as executor: + gws_indirect_data = get_gws_indirect( + config['inventory_provider']) + provisioned = [] + dashes = generate_indirect(gws_indirect_data, datasource_name) + for dashboard in dashes: + rendered = render_dashboard(dashboard) + provisioned.append(executor.submit(create_dashboard, + token_request, + rendered, folder['id'])) + + update_dash_list(provisioned) + + # fetch GWS direct data and provision related dashboards + logger.info('Provisioning GWS Direct dashboards') + folder_name = 'GWS Direct' + exclude_gws = excluded_folders.get(folder_name, False) + if isinstance(exclude_gws, bool) and exclude_gws: + # don't provision GWS Direct folder + delete_folder(token_request, folder_name) + else: + folder = find_folder(token_request, folder_name) + with ProcessPoolExecutor(max_workers=4) as executor: + gws_data = get_gws_direct(config['inventory_provider']) + provisioned = [] + + for dashboard in generate_gws(gws_data, datasource_name): + rendered = render_dashboard(dashboard) + provisioned.append(executor.submit(create_dashboard, + token_request, + rendered, folder['id'])) + + update_dash_list(provisioned) aggregate_dashboards = { 'CLS PEERS': { @@ -319,7 +378,6 @@ def provision(config): if isinstance(exclude_agg, bool) and exclude_agg: # don't provision aggregate folder delete_folder(token_request, 'Aggregates') - pass else: with ProcessPoolExecutor(max_workers=4) as executor: provisioned = [] @@ -338,11 +396,7 @@ def provision(config): excluded_interfaces, datasource_name) provisioned.append(res) - for result in provisioned: - dashboard = result.result() - if dashboard is None: - continue - dash_list[dashboard.get('uid')] = True + update_dash_list(provisioned) # NREN Access dashboards # uses a different template than the above. diff --git a/brian_dashboard_manager/grafana/utils/request.py b/brian_dashboard_manager/grafana/utils/request.py index d55dc878a3dc4057e4e612417790a4698e620477..d1c5452340bc94f4b2ad93fd72444996d76e4314 100644 --- a/brian_dashboard_manager/grafana/utils/request.py +++ b/brian_dashboard_manager/grafana/utils/request.py @@ -1,4 +1,8 @@ import requests +import logging +from requests.models import HTTPError + +logger = logging.getLogger(__name__) class Request(object): @@ -11,47 +15,34 @@ class Request(object): self.BASE_URL = url - def get(self, endpoint: str, headers=None, **kwargs): - - r = requests.get( - self.BASE_URL + endpoint, - headers={**headers, **self.headers} if headers else self.headers, - **kwargs - ) - r.raise_for_status() + def do_request(self, method, endpoint, *args, **kwargs): + r = requests.request(method, self.BASE_URL + endpoint, + *args, + **kwargs, + headers={ + **kwargs.get('headers', {}), + **self.headers + }) + + try: + r.raise_for_status() + except HTTPError as e: + if e.response.status_code < 500: + logger.error(e.response.content.decode('utf-8')) + raise e return r.json() - def post(self, endpoint: str, headers=None, **kwargs): + def get(self, endpoint: str, *args, **kwargs): + return self.do_request('get', endpoint, *args, **kwargs) - r = requests.post( - self.BASE_URL + endpoint, - headers={**headers, **self.headers} if headers else self.headers, - **kwargs - ) - r.raise_for_status() + def post(self, endpoint: str, data=None, **kwargs): + return self.do_request('post', endpoint, data=data, **kwargs) - return r.json() + def put(self, endpoint: str, **kwargs): + return self.do_request('put', endpoint, **kwargs) - def put(self, endpoint: str, headers=None, **kwargs): - - r = requests.put( - self.BASE_URL + endpoint, - headers={**headers, **self.headers} if headers else self.headers, - **kwargs - ) - r.raise_for_status() - return r.json() - - def delete(self, endpoint: str, headers=None, **kwargs): - - r = requests.delete( - self.BASE_URL + endpoint, - headers={**headers, **self.headers} if headers else self.headers, - **kwargs - ) - r.raise_for_status() - - return r.json() + def delete(self, endpoint: str, **kwargs): + return self.do_request('delete', endpoint, **kwargs) class AdminRequest(Request): diff --git a/brian_dashboard_manager/inventory_provider/interfaces.py b/brian_dashboard_manager/inventory_provider/interfaces.py index a27ceecfaee82f49d18c984e012665ac9ff6050e..400db47e3f484f4d4b1a712b83f29b46a5bcb524 100644 --- a/brian_dashboard_manager/inventory_provider/interfaces.py +++ b/brian_dashboard_manager/inventory_provider/interfaces.py @@ -40,6 +40,8 @@ def get_interfaces(host): # pragma: no cover return interface ip = router.get(interface['name']) + if not ip: + return interface ipv4 = ip['ipv4'] ipv6 = ip['ipv6'] interface['ipv4'] = ipv4 @@ -47,3 +49,17 @@ def get_interfaces(host): # pragma: no cover return interface enriched = list(map(enrich, interfaces)) return enriched + + +def get_gws_direct(host): + r = requests.get(f'{host}/poller/gws/direct') + r.raise_for_status() + interfaces = r.json() + return interfaces + + +def get_gws_indirect(host): + r = requests.get(f'{host}/poller/gws/indirect') + r.raise_for_status() + interfaces = r.json() + return interfaces diff --git a/brian_dashboard_manager/routes/update.py b/brian_dashboard_manager/routes/update.py index 780d40d6affb7aa7784273df23d6760e2830902f..9b6fa58732e33ec6e2bfa602bb076c29d13b5fd9 100644 --- a/brian_dashboard_manager/routes/update.py +++ b/brian_dashboard_manager/routes/update.py @@ -40,6 +40,13 @@ def should_provision(): timestamp = datetime.datetime.fromtimestamp( state.get('timestamp', 1)) + now = datetime.datetime.now() + if provisioning and (now - timestamp).total_seconds() > 86400: + # if we stay in provisioning state + # for over a day, we probably restarted + # and the state file is out of sync. + provisioning = False + can_provision = not provisioning return can_provision, timestamp except FileNotFoundError: diff --git a/brian_dashboard_manager/templating/gws.py b/brian_dashboard_manager/templating/gws.py new file mode 100644 index 0000000000000000000000000000000000000000..b781fd63d482d18b2c8653d90c8a4eb6e1c760e6 --- /dev/null +++ b/brian_dashboard_manager/templating/gws.py @@ -0,0 +1,88 @@ +from typing import DefaultDict +from brian_dashboard_manager.templating.helpers import get_dashboard_data + + +def get_panel_data(interfaces): + result = DefaultDict(list) + + count = {} + + def add_num(iface): + name = iface['nren'] + iface['isp'] + iface['tag'] + count[name] = count.get(name, 0) + 1 + iface['num'] = count[name] + return iface + + # Add a number to multiple interfaces for same nren/isp combination, + # as they share the same tag if the hostnames are different. + interfaces = list(map(add_num, interfaces)) + + for interface in interfaces: + + isp = interface.get('isp') + nren = interface.get('nren') + hostname = interface.get('hostname') + + # identifier for interface, as we don't have their names + interface_tag = interface.get('tag') + if_num = interface.get('num') + + counters = interface.get('counters') + + skip = True + + for counter in counters: + if counter.get('field') in ['traffic_in', 'traffic_out']: + skip = False + + if skip: + # only process interfaces where we are polling traffic data + continue + + gws_measurement = 'gwsd_rates' + title = f'{nren} GWS Direct {isp} Interface {if_num} ({hostname})' + result[f'GWS Direct - {isp}'].append({ + 'isp': isp, + 'nren': nren, + 'measurement': gws_measurement, + 'title': title, + 'interface_tag': interface_tag, + 'hostname': hostname, + 'has_v6': False + }) + return result + + +def get_gws_indirect_panel_data(interfaces): + result = DefaultDict(list) + + for interface in interfaces: + + hostname = interface.get('hostname').replace('.geant.net', '') + if_name = interface.get('interface') + service_name = interface.get('name') + customer = interface.get('customer') + + measurement = 'dscp32_rates' + panel_title = f'{hostname} - {{}} - {if_name} - #{service_name} IASGWS' + result[f'GWS Indirect - {customer}'].append({ + 'measurement': measurement, + 'title': panel_title, + 'interface': if_name, + 'hostname': interface.get('hostname'), + 'has_v6': False + }) + return result + + +def generate_gws(gws_data, datasource): + + panel_data = get_panel_data(gws_data) + for dash in get_dashboard_data(panel_data, datasource, 'GWS_DIRECT'): + yield dash + + +def generate_indirect(gws_data, datasource): + panel_data = get_gws_indirect_panel_data(gws_data) + for dash in get_dashboard_data(panel_data, datasource, 'GWS_INDIRECT'): + yield dash diff --git a/brian_dashboard_manager/templating/helpers.py b/brian_dashboard_manager/templating/helpers.py index d2001f1156f5299a477bfb21c88746ce98ed1e85..5ce022c39c01206662da9017ef85c27f4cb02a77 100644 --- a/brian_dashboard_manager/templating/helpers.py +++ b/brian_dashboard_manager/templating/helpers.py @@ -294,7 +294,9 @@ def get_panel_fields(panel, panel_type, datasource): def get_target_data(alias, field): return { - **panel, # panel has target hostname and interface + # panel includes identifying information + # such as hostname, interface, etc. + **panel, 'alias': alias, 'refId': next(letters), 'select_field': field, @@ -344,9 +346,9 @@ def get_dashboard_data(data, datasource, tag, errors=False): {**panel, **next(gridPos)}, 'errors', datasource)) return result - for peer, panels in data.items(): + for dashboard_name, panels in data.items(): result = { - 'title': peer, + 'title': dashboard_name, 'datasource': datasource, 'panels': get_panel_definitions(panels, datasource), } diff --git a/brian_dashboard_manager/templating/templates/shared/panel_target.json.j2 b/brian_dashboard_manager/templating/templates/shared/panel_target.json.j2 index b98bd3c3b5e335c6c7f798ee1ac2ad8eead80143..0bcd9f694d3153a187f63012bb032a8bbc796cb4 100644 --- a/brian_dashboard_manager/templating/templates/shared/panel_target.json.j2 +++ b/brian_dashboard_manager/templating/templates/shared/panel_target.json.j2 @@ -12,7 +12,11 @@ } {% endif %} ], + {% if measurement %} + "measurement": "{{ measurement }}", + {% else %} "measurement": "interface_rates", + {% endif %} "orderByTime": null, "policy": null, "refId": "{{ refId }}", @@ -41,6 +45,7 @@ ] ], "tags": [ + {% if not isp %} { "condition": null, "key": "hostname", @@ -53,5 +58,25 @@ "operator": "=", "value": "{{ interface }}" } + {% else %} + { + "condition": null, + "key": "tag", + "operator": "=", + "value": "{{ interface_tag }}" + }, + { + "condition": "AND", + "key": "isp", + "operator": "=", + "value": "{{ isp }}" + }, + { + "condition": "AND", + "key": "nren", + "operator": "=", + "value": "{{ nren }}" + } + {% endif %} ] } \ No newline at end of file diff --git a/changelog.md b/changelog.md index 23becc2556f5a7e4661670890b4f8156b1d46a7b..f9bafb446be11885a85a10a7b74e0802e689d004 100644 --- a/changelog.md +++ b/changelog.md @@ -2,6 +2,10 @@ All notable changes to this project will be documented in this file. +## [0.16] - 2021-07-13 +- Add GWS Direct/Indirect graphs + related changes +- Improve request logging for easier debugging + ## [0.15] - 2021-05-17 - [POL1-433] Only provision aggregate panels for NRENs if LAG interfaces are present. diff --git a/setup.py b/setup.py index 47b079424ac889549eb2f03be9e24b71f98d8df5..f4245e35f135384ed9269beaf3a3238f129f0e0e 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup( name='brian-dashboard-manager', - version="0.15", + version="0.16", author='GEANT', author_email='swd@geant.org', description='', diff --git a/test/test_gws_direct.py b/test/test_gws_direct.py new file mode 100644 index 0000000000000000000000000000000000000000..688db385a1a0d1371876168d4f46b4066ed5cb5b --- /dev/null +++ b/test/test_gws_direct.py @@ -0,0 +1,133 @@ +import responses +import json +from brian_dashboard_manager.templating.gws import generate_gws +from brian_dashboard_manager.inventory_provider.interfaces import \ + get_gws_direct + + +TEST_DATA = [ + { + "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": "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" + } + ] + } +] + + +@responses.activate +def test_gws(data_config, mocker, client): + + def get_callback(request): + return 200, {}, json.dumps(TEST_DATA) + + responses.add_callback( + method=responses.GET, + url=f"{data_config['inventory_provider']}/poller/gws/direct", + callback=get_callback) + + gws_data = get_gws_direct(data_config['inventory_provider']) + + dashboards = list(generate_gws(gws_data, 'testdatasource')) + + assert len(dashboards) == 2 + + assert dashboards[0]['title'] == 'GWS Direct - Cogent' + assert len(dashboards[0]['panels']) == 3 + + assert dashboards[1]['title'] == 'GWS Direct - Telia' + assert len(dashboards[1]['panels']) == 1 diff --git a/test/test_gws_indirect.py b/test/test_gws_indirect.py new file mode 100644 index 0000000000000000000000000000000000000000..9edd611152bbd469f5ba3deec6a38e4069ed86e4 --- /dev/null +++ b/test/test_gws_indirect.py @@ -0,0 +1,102 @@ +import responses +import json +from brian_dashboard_manager.templating.gws import generate_indirect +from brian_dashboard_manager.inventory_provider.interfaces import \ + get_gws_indirect + + +TEST_DATA = [ + { + "id": 712361, + "name": "FCCN-AP3-IAS", + "customer": "FCCN", + "speed": 107374182400, + "pop": "PORTO", + "hostname": "rt1.por.pt.geant.net", + "interface": "ae10.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": 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": 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": 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" + } +] + + +@responses.activate +def test_gws(data_config, mocker, client): + + def get_callback(request): + return 200, {}, json.dumps(TEST_DATA) + + responses.add_callback( + method=responses.GET, + url=f"{data_config['inventory_provider']}/poller/gws/indirect", + callback=get_callback) + + gws_data = get_gws_indirect(data_config['inventory_provider']) + + dashboards = list(generate_indirect(gws_data, 'testdatasource')) + + assert len(dashboards) == 3 + + assert dashboards[0]['title'] == 'GWS Indirect - FCCN' + assert len(dashboards[0]['panels']) == 3 + + assert dashboards[1]['title'] == 'GWS Indirect - IUCC' + assert len(dashboards[1]['panels']) == 2 + + assert dashboards[2]['title'] == 'GWS Indirect - ROEDUNET' + assert len(dashboards[2]['panels']) == 1 diff --git a/test/test_update.py b/test/test_update.py index 0512ebcebc934133fb3f53fadcc2ad46f0b990e0..55050de6be23493d7b201cdecb1dfaa0f36ad556 100644 --- a/test/test_update.py +++ b/test/test_update.py @@ -460,6 +460,14 @@ def test_provision(data_config, mocker, client): _mocked_get_dashboard_definitions = mocker.patch( 'brian_dashboard_manager.grafana.provision.get_dashboard_definitions') + _mocked_gws = mocker.patch( + 'brian_dashboard_manager.grafana.provision.get_gws_direct') + _mocked_gws.return_value = [] + + _mocked_gws_indirect = mocker.patch( + 'brian_dashboard_manager.grafana.provision.get_gws_indirect') + _mocked_gws_indirect.return_value = [] + UID = 1 ID = 1 VERSION = 1