diff --git a/.gitignore b/.gitignore index e2a3e9346c070336a189a33c39c09130942da8fe..01699bf8df9e74459303584f5390d95e6ad0d10e 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ htmlcov dist docs/build .coverage* +bom.json # logs *.log diff --git a/Jenkinsfile b/Jenkinsfile index bd5177efe9649b374c8215df5aa560d2a6e68f3d..47f5288712ff8b913af6bed3786427322fee8a52 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -7,6 +7,6 @@ library 'SWDPipeline' // python_test_versions (list of python versions, resolving to docker tags, to test against) String name = 'brian-dashboard-manager' List<String> extraRecipients = ['bjarke@nordu.net', 'erik.reid@geant.org', 'sam.roberts@geant.org', 'pelle.koster@geant.org'] -List<String> pythonTestVersions = ['3.6', '3.11'] +List<String> pythonTestVersions = ['3.11'] SimplePythonBuild(name, extraRecipients, pythonTestVersions) diff --git a/brian_dashboard_manager/dashboards/region_eap.json b/brian_dashboard_manager/dashboards/region_eap.json index 8897ba6bd2e33aab8e7a60f19bafd502f7b9b9fb..42efd783752b9990e18d189ec998fb988e243516 100644 --- a/brian_dashboard_manager/dashboards/region_eap.json +++ b/brian_dashboard_manager/dashboards/region_eap.json @@ -90,6 +90,7 @@ "schemaVersion": 26, "style": "dark", "tags": [ + "customers" ], "templating": { "list": [] diff --git a/brian_dashboard_manager/grafana/provision.py b/brian_dashboard_manager/grafana/provision.py index 6cfafec124540725db385d03e084b2caea418c42..941346e117cb20d4af35fd950b59eb130ec06e21 100644 --- a/brian_dashboard_manager/grafana/provision.py +++ b/brian_dashboard_manager/grafana/provision.py @@ -942,7 +942,12 @@ def provision(config): """ start = time.time() - all_orgs = _provision_orgs(config) + try: + all_orgs = _provision_orgs(config) + except Exception: + logger.exception('Error when provisioning orgs') + return + request = AdminRequest(**config) try: # needed for older versions of grafana (<11.0) @@ -961,9 +966,13 @@ def provision(config): return None orgs = list(filter(lambda t: t[1] is not None, [(org, _find_org_config(org)) for org in all_orgs])) - interfaces = get_interfaces(config['inventory_provider']) - services = fetch_services(config['reporting_provider']) - regions = get_nren_regions(config['inventory_provider']) + try: + interfaces = get_interfaces(config['inventory_provider']) + services = fetch_services(config['reporting_provider']) + regions = get_nren_regions(config['inventory_provider']) + except Exception: + logger.exception('Error when fetching interfaces:') + return for org, org_config in orgs: _provision_org(config, org, org_config, interfaces, services, regions) diff --git a/brian_dashboard_manager/inventory_provider/interfaces.py b/brian_dashboard_manager/inventory_provider/interfaces.py index c342817842d6ad70c766ef90dd4381f162ea9473..df6ba6559b4900b1105d059117255a9d3cb08486 100644 --- a/brian_dashboard_manager/inventory_provider/interfaces.py +++ b/brian_dashboard_manager/inventory_provider/interfaces.py @@ -322,7 +322,7 @@ def _get_ip_info(host): return prev try: - r = requests.get(f'{host}/data/interfaces') + r = requests.get(f'{host}/data/interfaces', timeout=5) r.raise_for_status() interfaces = r.json() except HTTPError: @@ -341,7 +341,7 @@ def get_interfaces(host): :return: A list of interfaces with IP information added, if present. """ - r = requests.get(f'{host}/poller/interfaces') + r = requests.get(f'{host}/poller/interfaces', timeout=5) try: r.raise_for_status() interfaces = r.json() @@ -415,7 +415,7 @@ def get_gws_direct(host): :return: GWS direct data """ - r = requests.get(f'{host}/poller/gws/direct') + r = requests.get(f'{host}/poller/gws/direct', timeout=5) try: r.raise_for_status() interfaces = r.json() @@ -435,7 +435,7 @@ def get_gws_indirect(host): :return: GWS Indirect data """ try: - r = requests.get(f'{host}/poller/gws/indirect') + r = requests.get(f'{host}/poller/gws/indirect', timeout=5) r.raise_for_status() interfaces = r.json() except HTTPError: @@ -452,7 +452,7 @@ def get_eumetsat_multicast_subscriptions(host): :return: EUMETSAT multicast subscriptions """ try: - r = requests.get(f'{host}/poller/eumetsat-multicast') + r = requests.get(f'{host}/poller/eumetsat-multicast', timeout=5) r.raise_for_status() data = r.json() except HTTPError: diff --git a/brian_dashboard_manager/routes/update.py b/brian_dashboard_manager/routes/update.py index 5c81c011f400dde670fa7551a54571f71dfe7999..c5cd92368286154eaee415c5165b7376325707fb 100644 --- a/brian_dashboard_manager/routes/update.py +++ b/brian_dashboard_manager/routes/update.py @@ -38,7 +38,7 @@ def provision_maybe(): and the timestamp of the last provisioning, respectively. """ - global provision_state + global provision_state # noqa: F824 now = datetime.datetime.now(datetime.timezone.utc) timestamp = provision_state['time'] diff --git a/brian_dashboard_manager/templating/helpers.py b/brian_dashboard_manager/templating/helpers.py index e3f58ac01649a948830268f28eaf933fe23a5374..649179452a6de94805496aa2f00a9eda9d396fd0 100644 --- a/brian_dashboard_manager/templating/helpers.py +++ b/brian_dashboard_manager/templating/helpers.py @@ -24,6 +24,18 @@ PANEL_WIDTH = 24 logger = logging.getLogger(__file__) +def endpoint_sort_key(endpoint): + # sort by equipment/port if exists, otherwise host/interface + if 'equipment' in endpoint: + equipment = endpoint['equipment'] + port = endpoint['port'] + return equipment, port + else: + hostname = endpoint['hostname'] + interface = endpoint['interface'] + return hostname, interface + + def num_generator(start=30): """ Generator for numbers starting from the value of `start` @@ -223,7 +235,7 @@ def get_re_peer_interface_data(interfaces): def get_service_aggregate_targets(services): for service in services: - _interfaces = service.get('endpoints') + _interfaces = sorted(service.get('endpoints', []), key=endpoint_sort_key) name = service.get('name') sid = service.get('sid') scid = service.get('scid') @@ -309,7 +321,7 @@ def get_nren_interface_data(services, interfaces, excluded_dashboards, region_cu dashboard['AGGREGATES'].append(target) for service in services: - _interfaces = service.get('endpoints') + _interfaces = sorted(service.get('endpoints', []), key=endpoint_sort_key) name = service.get('name') sid = service.get('sid') scid = service.get('scid') @@ -450,7 +462,7 @@ def get_service_data(service_type, services, interfaces, excluded_dashboards): }) for service in services: - _interfaces = service.get('endpoints') + _interfaces = sorted(service.get('endpoints', []), key=endpoint_sort_key) name = service.get('name') sid = service.get('sid') scid = service.get('scid') diff --git a/changelog.md b/changelog.md index 6110d8663e866c95215c3300ed245c53614e5738..946c263da51b3fe1e296af14c221c9e95affa1f5 100644 --- a/changelog.md +++ b/changelog.md @@ -2,6 +2,10 @@ All notable changes to this project will be documented in this file. +## [0.79] - 2025-05-30 +- POL1-898: Unify logic for selecting interface between poller-udf and brian-dashboard-manager +- Add EAP Nren dashboard to NREN Access dropdown + ## [0.78] - 2025-02-06 - Add Router VLANs dropdown for staff - Add VLAN dashboard skeleton diff --git a/docker-setup/Dockerfile b/docker-setup/Dockerfile deleted file mode 100644 index 2fc46ac50f52de38a61aa9a60c55d96f7dea76c9..0000000000000000000000000000000000000000 --- a/docker-setup/Dockerfile +++ /dev/null @@ -1,30 +0,0 @@ -FROM alpine:3.8 - -# Build arguments -## The database user name -ARG DBUSER -## The user's password -ARG DBPASS -## The database name -ARG DBNAME - - -# Forward the args to the container -ENV DBUSER=${DBUSER} -ENV DBPASS=${DBPASS} -ENV DBNAME=${DBNAME} - -ENV PGDATA "/var/lib/postgresql" - -RUN apk update && \ - apk add postgresql postgresql-contrib - -RUN mkdir -p /run/postgresql && chmod a+w /run/postgresql - -ADD entrypoint.sh /entrypoint.sh -RUN chmod +x /entrypoint.sh -USER postgres - -VOLUME $PGDATA -CMD ["/entrypoint.sh"] -EXPOSE 5432 diff --git a/setup.py b/setup.py index 9662590526bd6c11dcfdd548da29f63a9755e67d..45bd43677c7784d951e7d6d845faafbf581e9bbf 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup( name='brian-dashboard-manager', - version="0.78", + version="0.79", author='GEANT', author_email='swd@geant.org', description='', diff --git a/tox.ini b/tox.ini index 3d311c9638bc099a522e82a04acc1d90be9a4ebe..65321cbc6d912821ddfc42a3acb3db3e5a826bd0 100644 --- a/tox.ini +++ b/tox.ini @@ -10,12 +10,15 @@ concurrency = multiprocessing,thread [testenv] deps = + pytest-xdist pytest-cov flake8 + cyclonedx-py -r requirements.txt commands = coverage erase - pytest --cov brian_dashboard_manager --cov-fail-under=75 --cov-report html --cov-report xml --cov-report term -p no:checkdocs + pytest -n auto --cov brian_dashboard_manager --cov-fail-under=75 --cov-report html --cov-report xml --cov-report term -p no:checkdocs flake8 sphinx-build -M html docs/source docs/build + cyclonedx-py environment --output-format json -o bom.json