import responses import json import re from brian_dashboard_manager.grafana.provision import provision_folder, \ provision DEFAULT_REQUEST_HEADERS = { "Content-type": "application/json", "Accept": ["application/json"] } TEST_INTERFACES = [ { "router": "srx2.ch.office.geant.net", "name": "ge-0/0/8", "bundle": [], "bundle-parents": [], "description": "PHY CUSTOMER GEANT CORPORATE SRF000001 | GEANT Corporate to MX1.LON - Via Vodafone", # noqa: E501 "circuits": [ { "id": 679232, "name": "GEANT CORPORATE TO MX1.LON - VIA VODAFONE", "type": "GEANT IP", "status": "non-monitored" } ], "snmp-index": 523, "dashboards": [ "NREN", "RE_CUST" ], "dashboard_info": { "name": "GEANT", "interface_type": "PHYSICAL" }, "ipv4": [], "ipv6": [] }, { "router": "srx2.ch.office.geant.net", "name": "ge-0/0/8.10", "bundle": [], "bundle-parents": [], "description": "SRV_GLOBAL CUSTOMER GEANT #GEANT_CORPORATE-ViaVodafone | GEANT Corporate to mx1.lon - Via Vodafone ", # noqa: E501 "circuits": [ { "id": 679360, "name": "GEANT_CORPORATE-VIAVODAFONE", "type": "GEANT IP", "status": "non-monitored" } ], "snmp-index": 543, "dashboards": [ "NREN", "RE_CUST" ], "dashboard_info": { "name": "GEANT", "interface_type": "LOGICAL" }, "ipv4": [ "62.40.127.131/31" ], "ipv6": [ "2001:798:99:1::ca/126" ] }, { "router": "srx2.ch.office.geant.net", "name": "ge-0/0/8.11", "bundle": [], "bundle-parents": [], "description": "SRV_GLOBAL CUSTOMER GEANT #GEANT_CORPORATE_ViaVodafone-VRF | GEANT Corporate to mx1.lon - Via Vodafone - for VRF", # noqa: E501 "circuits": [ { "id": 712144, "name": "GEANT_CORPORATE_VIAVODAFONE-VRF", "type": "GEANT IP", "status": "non-monitored" } ], "snmp-index": 545, "dashboards": [ "NREN", "RE_CUST" ], "dashboard_info": { "name": "GEANT", "interface_type": "LOGICAL" }, "ipv4": [ "10.101.0.6/30" ], "ipv6": [] }, { "router": "srx2.ch.office.geant.net", "name": "ge-0/0/8.12", "bundle": [], "bundle-parents": [], "description": "SRV_GLOBAL CUSTOMER GEANT #GEANT_CORPORATE_ViaVodafone-VRF-TEST | GEANT Corporate to mx1.lon - Via Vodafone - DASHBOARD BGP TEST VLAN", # noqa: E501 "circuits": [ { "id": 678920, "name": "GEANT_CORPORATE_VIAVODAFONE-VRF-TEST (DO NOT OPEN A TICKET)", # noqa: E501 "type": "GEANT IP", "status": "non-monitored" } ], "snmp-index": 522, "dashboards": [ "NREN", "RE_CUST" ], "dashboard_info": { "name": "GEANT", "interface_type": "LOGICAL" }, "ipv4": [ "62.40.127.141/31" ], "ipv6": [] }, { "router": "srx2.ch.office.geant.net", "name": "ge-0/0/8.996", "bundle": [], "bundle-parents": [], "description": "SRV_GLOBAL CUSTOMER GEANT #GEANT_OPERATIONS_LabConnectivity | GEANT MX1.LON Infinera VRF to Operations Lab", # noqa: E501 "circuits": [ { "id": 678999, "name": "GEANT_OPERATIONS_LABCONNECTIVITY", "type": "GEANT IP", "status": "non-monitored" } ], "snmp-index": 554, "dashboards": [ "NREN", "RE_CUST" ], "dashboard_info": { "name": "GEANT", "interface_type": "LOGICAL" }, "ipv4": [ "10.1.1.1/30" ], "ipv6": [] }, { "router": "mx1.ams.nl.geant.net", "name": "xe-0/0/0", "bundle": [ "ae16" ], "bundle-parents": [], "description": "PHY CUSTOMER KIAE P_AE16 SRF9915671 |", "circuits": [], "snmp-index": 588, "dashboards": [ "NREN", "RE_CUST" ], "dashboard_info": { "name": "KIAE", "interface_type": "PHYSICAL" }, "ipv4": [], "ipv6": [] }, { "router": "mx1.ams.nl.geant.net", "name": "xe-0/0/1", "bundle": [ "ae14" ], "bundle-parents": [], "description": "PHY CUSTOMER SWITCH P_AE14 SRF18008 |", "circuits": [], "snmp-index": 589, "dashboards": [ "NREN", "RE_CUST" ], "dashboard_info": { "name": "SWITCH", "interface_type": "PHYSICAL" }, "ipv4": [], "ipv6": [] }, { "router": "mx1.ams.nl.geant.net", "name": "ge-0/2/1.0", "bundle": [], "bundle-parents": [], "description": "SRV_L2CIRCUIT INFRASTRUCTURE GEANT GEANT #AMS-ZAG OPENFLOW |", # noqa: E501 "circuits": [], "snmp-index": 687, "dashboards": [ "L2_CIRCUIT" ], "dashboard_info": { "name": "GEANT", "interface_type": "LOGICAL" }, "ipv4": [], "ipv6": [] }, { "router": "mx1.ams.nl.geant.net", "name": "ge-0/2/2.0", "bundle": [], "bundle-parents": [], "description": "SRV_L2CIRCUIT INFRASTRUCTURE GEANT GEANT #AMS-VIE OPENFLOW |", # noqa: E501 "circuits": [], "snmp-index": 711, "dashboards": [ "L2_CIRCUIT" ], "dashboard_info": { "name": "GEANT", "interface_type": "LOGICAL" }, "ipv4": [], "ipv6": [] }, { "router": "mx1.ams.nl.geant.net", "name": "ge-0/2/4.0", "bundle": [], "bundle-parents": [], "description": "SRV_L2CIRCUIT INFRASTRUCTURE GEANT GEANT #AMS-FRA OPENFLOW |", # noqa: E501 "circuits": [], "snmp-index": 718, "dashboards": [ "L2_CIRCUIT" ], "dashboard_info": { "name": "GEANT", "interface_type": "LOGICAL" }, "ipv4": [], "ipv6": [] } ] NREN_INTERFACES = [ { "router": "mx1.dub2.ie.geant.net", "name": "xe-0/0/0", "bundle": [ "ae10" ], "bundle-parents": [], "description": "PHY CUSTOMER HEANET P_AE10 SRF9948758 | HEANET-AP2-LL3", # noqa: E501 "circuits": [], "snmp-index": 554, "dashboards": [ "NREN", "RE_CUST" ], "dashboard_info": { "name": "HEANET", "interface_type": "PHYSICAL" }, "ipv4": [], "ipv6": [] }, { "router": "mx1.dub2.ie.geant.net", "name": "xe-1/0/1", "bundle": [ "ae10" ], "bundle-parents": [], "description": "PHY CUSTOMER HEANET P_AE10 SRF0000001 | HEANET-AP2-LL2", # noqa: E501 "circuits": [], "snmp-index": 527, "dashboards": [ "NREN", "RE_CUST" ], "dashboard_info": { "name": "HEANET", "interface_type": "PHYSICAL" }, "ipv4": [], "ipv6": [] }, { "router": "mx1.dub2.ie.geant.net", "name": "xe-1/1/0", "bundle": [ "ae10" ], "bundle-parents": [], "description": "PHY CUSTOMER HEANET P_AE10 SRF9925903 | HEANET-AP2-LL1", # noqa: E501 "circuits": [], "snmp-index": 528, "dashboards": [ "NREN", "RE_CUST" ], "dashboard_info": { "name": "HEANET", "interface_type": "PHYSICAL" }, "ipv4": [], "ipv6": [] }, { "router": "mx1.dub2.ie.geant.net", "name": "ae10", "bundle": [], "bundle-parents": [ "xe-0/0/0", "xe-1/0/1", "xe-1/1/0" ], "description": "LAG CUSTOMER HEANET SRF9925909 | HEANET-AP2-LAG", "circuits": [], "snmp-index": 596, "dashboards": [ "NREN", "RE_CUST" ], "dashboard_info": { "name": "HEANET", "interface_type": "AGGREGATE" }, "ipv4": [], "ipv6": [] }, { "router": "mx1.dub2.ie.geant.net", "name": "ae10.12", "bundle": [], "bundle-parents": [ "xe-0/0/0", "xe-1/0/1", "xe-1/1/0" ], "description": "SRV_GLOBAL CUSTOMER HEANET #HEANET-AP2 | ASN1213 | ", "circuits": [ { "id": 662976, "name": "HEANET-AP2", "type": "GEANT IP", "status": "operational" } ], "snmp-index": 713, "dashboards": [ "NREN", "RE_CUST" ], "dashboard_info": { "name": "HEANET", "interface_type": "LOGICAL" }, "ipv4": [ "62.40.125.13/30" ], "ipv6": [ "2001:0798:0018:10aa::15/126" ] }, { "router": "mx1.dub2.ie.geant.net", "name": "ae10.30", "bundle": [], "bundle-parents": [ "xe-0/0/0", "xe-1/0/1", "xe-1/1/0" ], "description": "SRV_MDVPN CUSTOMER HEANET AP2 #HEANET-BGP-LU-CoC-1 |", # noqa: E501 "circuits": [ { "id": 663160, "name": "HEANET-BGP-LU-COC-1", "type": "MD-VPN (NATIVE)", "status": "operational" } ], "snmp-index": 712, "dashboards": [ "MDVPN_CUSTOMERS", "NREN" ], "dashboard_info": { "name": "HEANET", "interface_type": "LOGICAL" }, "ipv4": [ "62.40.102.36/31" ], "ipv6": [] }, { "router": "mx1.dub2.ie.geant.net", "name": "ae10.333", "bundle": [], "bundle-parents": [ "xe-0/0/0", "xe-1/0/1", "xe-1/1/0" ], "description": "SRV_IAS CUSTOMER HEANET #HEANET-AP2-IAS IASPS | ASN1213 ", # noqa: E501 "circuits": [ { "id": 663214, "name": "HEANET-AP2-IAS", "type": "GEANT PEERING", "status": "operational" } ], "snmp-index": 658, "dashboards": [ "IAS_CUSTOMER", "NREN" ], "dashboard_info": { "name": "HEANET", "interface_type": "LOGICAL" }, "ipv4": [ "83.97.88.77/30" ], "ipv6": [ "2001:798:1::61/126" ] }, { "router": "mx1.dub2.ie.geant.net", "name": "ae10.1214", "bundle": [], "bundle-parents": [ "xe-0/0/0", "xe-1/0/1", "xe-1/1/0" ], "description": "SRV_L2CIRCUIT CUSTOMER HEANET GEANT #ams-dub2-HEANET-RARE-21061 |", # noqa: E501 "circuits": [ { "id": 713335, "name": "AMS-DUB2-HEANET-RARE-21061", "type": "GEANT PLUS", "status": "non-monitored" } ], "snmp-index": 790, "dashboards": [ "L2_CIRCUIT" ], "dashboard_info": { "name": "HEANET", "interface_type": "LOGICAL" }, "ipv4": [], "ipv6": [] } ] def generate_folder(data): return { "id": 555, "uid": data['uid'], "title": data['title'], "url": f"/dashboards/f/{data['uid']}/{data['title'].lower()}", "hasAcl": False, "canSave": True, "canEdit": True, "canAdmin": True, "createdBy": "Anonymous", "created": "2021-02-23T15:33:46Z", "updatedBy": "Anonymous", "updated": "2021-02-23T15:33:46Z", "version": 1 } @responses.activate def test_provision_folder(data_config, mocker): dashboards = { 'NREN': { 'tag': ['customers'], 'folder_name': 'NREN Access', 'interfaces': [iface for iface in TEST_INTERFACES if 'NREN' in iface['dashboards']] # noqa: E501 }, 'RE_CUST': { 'tag': 'RE_CUST', 'folder_name': 'RE Customer', 'interfaces': [iface for iface in TEST_INTERFACES if 'RE_CUST' in iface['dashboards']] # noqa: E501 }, } # just return a generated folder _mocked_find_folder = mocker.patch( 'brian_dashboard_manager.grafana.provision.find_folder') _mocked_find_folder.return_value = generate_folder( {'uid': 'testfolderuid', 'title': 'testfolder'}) def create_dashboard(request, dashboard, folder_id=None): return dashboard mocker.patch( 'brian_dashboard_manager.grafana.provision.create_dashboard', create_dashboard) excluded_dashboards = [] nren_result = provision_folder(None, 'testfolder', dashboards['NREN'], 'testdatasource', excluded_dashboards) assert len(nren_result) == 3 assert nren_result[0]['title'] == 'GEANT' assert nren_result[1]['title'] == 'KIAE' assert nren_result[2]['title'] == 'SWITCH' excluded_dashboards = ['SWITCH'] nren_excluded = provision_folder(None, 'testfolder', dashboards['NREN'], 'testdatasource', excluded_dashboards) assert len(nren_excluded) == 2 assert nren_excluded[0]['title'] == 'GEANT' assert nren_excluded[1]['title'] == 'KIAE' cust_result = provision_folder(None, 'testfolder', dashboards['RE_CUST'], 'testdatasource', ['GEANT']) assert len(cust_result) == 2 assert cust_result[0]['title'] == 'KIAE' assert cust_result[1]['title'] == 'SWITCH' @responses.activate def test_provision(data_config, mocker, client): def get_callback(request): return 200, {}, json.dumps(NREN_INTERFACES) responses.add_callback( method=responses.GET, url=f"{data_config['inventory_provider']}/poller/interfaces", callback=get_callback) responses.add_callback( method=responses.GET, url=f"{data_config['inventory_provider']}/data/interfaces", callback=get_callback) def folder_get(request): return 200, {}, json.dumps([]) responses.add_callback( method=responses.GET, url=f"http://{data_config['hostname']}/api/folders", callback=folder_get) def folder_delete(request): return 200, {}, json.dumps({"message": "Deleted folder"}) responses.add_callback( method=responses.DELETE, url=re.compile(f"http://{data_config['hostname']}/api/folders"), callback=folder_delete, ) def folder_post(request): data = json.loads(request.body) return 200, {}, json.dumps(generate_folder(data)) responses.add_callback( method=responses.POST, url=f"http://{data_config['hostname']}/api/folders", callback=folder_post) def home_dashboard(request): return 200, {}, json.dumps([]) responses.add_callback( method=responses.GET, url=f"http://{data_config['hostname']}/api/search?query=Home", callback=home_dashboard) TEST_DATASOURCE = [{ "name": "brian-influx-datasource", "type": "influxdb", "access": "proxy", "url": "http://test-brian-datasource.geant.org:8086", "database": "test-db", "basicAuth": False, "isDefault": True, "readOnly": False }] def datasources(request): return 200, {}, json.dumps(TEST_DATASOURCE) responses.add_callback( method=responses.GET, url=f"http://{data_config['hostname']}/api/datasources", callback=datasources) def createdashboard(request): return 200, {}, json.dumps({'id': 666}) responses.add_callback( method=responses.POST, url=f"http://{data_config['hostname']}/api/dashboards/db", callback=createdashboard) def preferences(request): return 200, {}, json.dumps({'message': 'Preferences updated'}) responses.add_callback( method=responses.PUT, url=f"http://{data_config['hostname']}/api/org/preferences", callback=preferences) def homedashboard(request): return 404, {}, '' responses.add_callback( method=responses.GET, url=f"http://{data_config['hostname']}/api/dashboards/uid/home", callback=homedashboard) PROVISIONED_ORGANIZATION = { 'name': data_config['organizations'][0], 'id': 0 } EXISTING_ORGS = [{**org, 'id': i + 1} for i, org in enumerate(data_config['organizations'][1:])] _mocked_get_organizations = mocker.patch( 'brian_dashboard_manager.grafana.provision.get_organizations') # all organizations are provisioned except the first one. _mocked_get_organizations.return_value = EXISTING_ORGS.copy() _mocked_create_organization = mocker.patch( 'brian_dashboard_manager.grafana.provision.create_organization') # spoof creating first organization _mocked_create_organization.return_value = PROVISIONED_ORGANIZATION _mocked_delete_expired_api_tokens = mocker.patch( 'brian_dashboard_manager.grafana.provision.delete_expired_api_tokens') # we dont care about this, , tested separately _mocked_delete_expired_api_tokens.return_value = None _mocked_create_api_token = mocker.patch( 'brian_dashboard_manager.grafana.provision.create_api_token') _mocked_create_api_token.return_value = { 'key': 'testtoken', 'id': 0} # api token _mocked_create_datasource = mocker.patch( 'brian_dashboard_manager.grafana.provision.create_datasource') # we dont care about this, just mark it created _mocked_create_datasource.return_value = True _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 TITLE = 'testdashboard' dashboard = {'id': ID, 'uid': UID, 'title': TITLE, 'version': VERSION} _mocked_get_dashboard_definitions.return_value = [ dashboard # test dashboard ] _mocked_create_dashboard = mocker.patch( 'brian_dashboard_manager.grafana.provision.create_dashboard') # we dont care about this, just mark it created # we dont care about this, tested separately _mocked_create_dashboard.return_value = {'id': 666} _mocked_delete_api_token = mocker.patch( 'brian_dashboard_manager.grafana.provision.delete_api_token') # we dont care about this, tested separately _mocked_delete_api_token.return_value = None provision(data_config)