From 915e100942bc779a6a65b91cf7b5ff551adb79eb Mon Sep 17 00:00:00 2001 From: Bjarke Madsen <bjarke.madsen@geant.org> Date: Mon, 25 Jan 2021 17:57:54 +0100 Subject: [PATCH] Implement dashboard provisioning --- brian_dashboard_manager/grafana/dashboard.py | 94 ++++++++++++++++++-- 1 file changed, 87 insertions(+), 7 deletions(-) diff --git a/brian_dashboard_manager/grafana/dashboard.py b/brian_dashboard_manager/grafana/dashboard.py index 5b59a0b..394895f 100644 --- a/brian_dashboard_manager/grafana/dashboard.py +++ b/brian_dashboard_manager/grafana/dashboard.py @@ -1,21 +1,101 @@ import logging +import os +import json from typing import Dict + +from requests.models import HTTPError from brian_dashboard_manager.grafana.utils.request import TokenRequest logger = logging.getLogger(__name__) -def provision_dashboard(request: TokenRequest, dashboard: Dict): - del dashboard['uid'] - del dashboard['id'] - del dashboard['version'] +# Returns dictionary for each dashboard JSON definition in supplied directory +def get_dashboard_definitions(dir=None): # pragma: no cover + dashboard_dir = dir or os.path.join( + os.path.dirname(__file__), '../../dashboards/') + for (dirpath, _, filenames) in os.walk(dashboard_dir): + for file in filenames: + if file.endswith('.json'): + filename = os.path.join(dirpath, file) + dashboard = json.load(open(filename, 'r')) + yield dashboard + + +# Deletes a single dashboard for the organization the API token is registered to. +def _delete_dashboard(request: TokenRequest, uid: int): + try: + r = request.delete(f'api/dashboards/uid/{uid}') + if r and 'deleted' in r.get('message', ''): + return r + except HTTPError as e: + logger.error( + f'Error when deleting dashboard with UID #{uid}: {e.response.text}') + return None + + +# Deletes all dashboards for the organization the API token is registered to. +def delete_dashboards(request: TokenRequest): + r = request.get('api/search') + if r and len(r) > 0: + for dash in r: + _delete_dashboard(request, dash['uid']) + return True + + +# Searches Grafana for a dashboard matching the title of the provided dashboard. +def _search_dashboard(request: TokenRequest, dashboard: Dict): + try: + r = request.get('api/search', params={ + 'query': f'{dashboard["title"]}' + }) + if r and isinstance(r, list): + if len(r) >= 1: + for dash in r: + if dash['title'] == dashboard['title']: + return _get_dashboard(request, dash['uid']) + return None + except HTTPError: + return None + + +# Fetches dashboard with given UID for the token's organization. +def _get_dashboard(request: TokenRequest, uid: int): + + try: + r = request.get(f'api/dashboards/uid/{uid}') + except HTTPError: + return None + return r + + +# Creates or updates (if exists) given dashboard for the token's organization. +# supplied dashboards are JSON blobs exported from GUI with a UID. +def create_dashboard(request: TokenRequest, dashboard: Dict): + + existing_dashboard = None + if dashboard.get('uid') is not None: + existing_dashboard = _get_dashboard(request, uid=dashboard['uid']) + else: + existing_dashboard = _search_dashboard(request, dashboard) + + if existing_dashboard: + dashboard['uid'] = existing_dashboard['dashboard']['uid'] + dashboard['id'] = existing_dashboard['dashboard']['id'] + dashboard['version'] = existing_dashboard['dashboard']['version'] + else: + # We are creating a new dashboard, delete ID if it exists. + del dashboard['id'] payload = { 'dashboard': dashboard, 'overwrite': False } try: + logger.info( + f'{"Updating" if existing_dashboard else "Provisioning"} dashboard: {dashboard["title"]}') r = request.post('api/dashboards/db', json=payload) - except Exception as e: - logger.error(f'Error when provisioning dashboard: ' + e.response.text) - return True + return r + except HTTPError as e: + logger.error( + f'Error when provisioning dashboard {dashboard["title"]}: {e.response.text}') + return None -- GitLab