Skip to content

Commit

Permalink
Merge pull request #134 from juztas/DevUniqueID
Browse files Browse the repository at this point in the history
Use unique UID for Grafana dashboards (Separate development from prod)
  • Loading branch information
juztas authored Oct 11, 2024
2 parents 128ea33 + d8522e6 commit 96b33b3
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 44 deletions.
6 changes: 6 additions & 0 deletions autogole-api/packaging/files/etc/rtmon.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ workdir: '/srv/'
grafana_host: 'https://autogole-grafana.nrp-nautilus.io'
grafana_api_key: 'REPLACE_ME'
grafana_folder: 'Real Time Mon'
# FOR DEVELOPMEENT ONLY
# Enable grafana_dev parameter (can be any string, and will be used as name to create directory inside Grafana)
# Additionally - all dashboards will have this added to name.
# Grafana itself update's/inserts dashboards based on uid (and if this is not used, it can easily update production dashboards)
# grafana_dev: 'Justas-Dev'


# Template path and tags. If tag updated - it will force update all templates
template_path: '/etc/rtmon/templates'
Expand Down
73 changes: 39 additions & 34 deletions autogole-api/src/python/RTMon/worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ def submit_exe(self, filename, fout):
return
# 4. Submit to Grafana (Check if folder exists, if not create it)
folderName = self.config.get('grafana_folder', 'Real Time Mon')
devname = self.config.get('grafana_dev', None)
if devname:
folderName = f'{folderName} - {devname}'
folderInfo = self.g_createFolder(folderName)
template['folderId'] = folderInfo['id']
template['overwrite'] = True
Expand All @@ -84,48 +87,50 @@ def delete_exe(self, filename, fout):
"""Delete Action Execution"""
self.logger.info('Delete Execution: %s, %s', filename, fout)
# Delete the dashboard and template from Grafana
for dashbName, dashbVals in self.dashboards.items():
present = True
for key in ['referenceUUID', 'orchestrator', 'submission']:
if fout.get(key, '') not in dashbVals['tags']:
present = False
if present:
self.logger.info('Deleting Dashboard: %s', dashbName)
self.g_deleteDashboard(dashbName)
filename = f'{self.config.get("workdir", "/srv")}/{filename}'
if os.path.exists(filename):
os.remove(filename)
break
# Delete the action from External API
self.e_submitExternalAPI(fout, 'delete')
for grafDir, dirVals in self.dashboards.items():
for dashbName, dashbVals in dirVals.items():
present = True
for key in ['referenceUUID', 'orchestrator', 'submission']:
if fout.get(key, '') not in dashbVals.get('tags', []):
present = False
if present:
self.logger.info('Deleting Dashboard: %s', dashbName)
self.g_deleteDashboard(dashbName)
filename = f'{self.config.get("workdir", "/srv")}/{filename}'
if os.path.exists(filename):
os.remove(filename)
break
# Delete the action from External API
self.e_submitExternalAPI(fout, 'delete')

def running_exe(self, filename, fout):
"""Running Action Execution"""
self.logger.debug('Running Execution: %s, %s', filename, fout)
# Check external record to track info of device
self.e_submitExternalAPI(fout, 'running')
for dashbName, dashbVals in self.dashboards.items():
present = True
for key in ['referenceUUID', 'orchestrator', 'submission']:
if fout.get(key, '') not in dashbVals['tags']:
present = False
if present:
# Check that version is the same, in case of new release,
# we need to update the dashboard with new template_tag
if self.config['template_tag'] in dashbVals['tags']:
self.logger.info('Dashboard is present in Grafana: %s', dashbName)
# Check if we need to re-issue ping test
tmpOut = self.sr_submit_ping(instance=fout.get('instance', {}), manifest=fout.get('manifest', {}))
if tmpOut and fout.get('dashbInfo', {}):
fout['ping'] = tmpOut
self.g_submitAnnotation(sitermOut=tmpOut, dashbInfo=fout["dashbInfo"])
for grafDir, dirVals in self.dashboards.items():
for dashbName, dashbVals in dirVals.items():
present = True
for key in ['referenceUUID', 'orchestrator', 'submission']:
if fout.get(key, '') not in dashbVals.get('tags', []):
present = False
if present:
# Check that version is the same, in case of new release,
# we need to update the dashboard with new template_tag
if self.config['template_tag'] in dashbVals['tags']:
self.logger.info('Dashboard is present in Grafana: %s', dashbName)
# Check if we need to re-issue ping test
tmpOut = self.sr_submit_ping(instance=fout.get('instance', {}), manifest=fout.get('manifest', {}))
if tmpOut and fout.get('dashbInfo', {}):
fout['ping'] = tmpOut
self.g_submitAnnotation(sitermOut=tmpOut, dashbInfo=fout["dashbInfo"])
self._updateState(filename, fout)
return
# Need to update the dashboard with new template_tag
self.logger.info('Dashboard is present in Grafana, but with old version: %s', dashbName)
fout['state'] = 'delete'
self._updateState(filename, fout)
return
# Need to update the dashboard with new template_tag
self.logger.info('Dashboard is present in Grafana, but with old version: %s', dashbName)
fout['state'] = 'delete'
self._updateState(filename, fout)
return
# If we reach here - means the dashboard is not present in Grafana
self.logger.info('Dashboard is not present in Grafana: %s', fout)
fout.setdefault('retries', 0)
Expand Down
11 changes: 11 additions & 0 deletions autogole-api/src/python/RTMonLibs/GeneralLibs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,21 @@
import os
import json
import time
import uuid
import hashlib
import requests
from yaml import safe_load as yload
from yaml import safe_dump as ydump

def getUUID(inputstr):
"""Generate UUID from Input Str"""
hashObject = hashlib.sha256(inputstr.encode('utf-8'))
hashHex = hashObject.hexdigest()
customUUID = str(uuid.UUID(hashHex[:32]))
# Grafana allows max 40 chars for UUID
return customUUID[:40]


def loadFileJson(filename, logger):
"""Load File"""
with open(filename, 'rb') as fd:
Expand Down
19 changes: 11 additions & 8 deletions autogole-api/src/python/RTMonLibs/GrafanaAPI.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,21 @@ def g_getDashboards(self):
while failures < 3:
try:
for item in self.grafanaapi.search.search_dashboards():
self.dashboards[item['title']] = item
folderTitle = item.get('folderTitle', '')
if folderTitle:
self.dashboards.setdefault(folderTitle, {})
self.dashboards[folderTitle][item['title']] = item
return
except Exception as ex:
failures += 1
self.logger.error(f"Failed to get dashboards: {ex}")
time.sleep(1)
raise Exception("Failed to get dashboards after 3 retries")

def g_getDashboardByTitle(self, title):
"""Get dashboard by Title"""
if title in self.dashboards:
return self.dashboards[title]
def g_getDashboardByTitle(self, title, folderTitle):
"""Get dashboard by Title inside folder"""
if folderTitle in self.dashboards and title in self.dashboards[folderTitle]:
return self.dashboards[folderTitle][title]
return {}

def g_getDataSources(self):
Expand Down Expand Up @@ -81,13 +84,13 @@ def g_addNewDashboard(self, dashbJson):
time.sleep(1)
raise Exception(f"Failed to create dashboard {dashbJson} after 3 retries")

def g_deleteDashboard(self, title):
def g_deleteDashboard(self, title, folderTitle):
"""Delete dashboard"""
if title in self.dashboards:
if folderTitle in self.dashboards and title in self.dashboards[folderTitle]:
failures = 0
while failures < 3:
try:
return self.grafanaapi.dashboard.delete_dashboard(self.dashboards[title]['uid'])
return self.grafanaapi.dashboard.delete_dashboard(self.dashboards[folderTitle][title]['uid'])
except Exception as ex:
failures += 1
self.logger.error(f"Failed to delete dashboard {title}: {ex}")
Expand Down
6 changes: 4 additions & 2 deletions autogole-api/src/python/RTMonLibs/Template.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""Grafana Template Generation"""
import copy
import os.path
from RTMonLibs.GeneralLibs import loadJson, dumpJson, dumpYaml, escape
from RTMonLibs.GeneralLibs import loadJson, dumpJson, dumpYaml, escape, getUUID

def _processName(name):
"""Process Name for Mermaid and replace all special chars with _"""
Expand Down Expand Up @@ -402,12 +402,14 @@ def t_createDashboard(self, *args, **kwargs):
out = self._t_loadTemplate("dashboard.json")
# Update title;
title = f'{args[0]["alias"]}|Flow: {args[0]["intents"][0]["id"]}|{args[0]["timestamp"]}'
if self.config.get('grafana_dev', None):
title += f" ({self.config['grafana_dev']})"
out["title"] = title
for key in ['referenceUUID', 'orchestrator', 'submission']:
if key in kwargs:
out['tags'].append(kwargs[key])
out['tags'].append(self.config['template_tag'])
out["uid"] = args[0]["intents"][0]["id"]
out["uid"] = getUUID(title)
return out

def t_createHostFlow(self, *args):
Expand Down

0 comments on commit 96b33b3

Please sign in to comment.