From 1db873f6f46365a5e78cfa7e4a29bdfcc155a979 Mon Sep 17 00:00:00 2001
From: Ian Wienand <iwienand@redhat.com>
Date: Wed, 29 Jun 2022 14:25:08 +1000
Subject: [PATCH] Use fixed datasource UID

As described inline, datasources now have a UID.  Set this to a fixed
hash of the URL to make dashboards which refer to datasources
explicitly portable.

Change-Id: I53e2aec7f635e8ce8793abb5755eccd2e6b3e4c5
---
 grafana_dashboards/grafana/datasource.py | 39 ++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/grafana_dashboards/grafana/datasource.py b/grafana_dashboards/grafana/datasource.py
index d6edcca..894bfe7 100644
--- a/grafana_dashboards/grafana/datasource.py
+++ b/grafana_dashboards/grafana/datasource.py
@@ -12,12 +12,16 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
+import logging
+import hashlib
 import json
 
 from requests import exceptions
 
 from grafana_dashboards.grafana import utils
 
+LOG = logging.getLogger(__name__)
+
 
 class Datasource(object):
 
@@ -39,6 +43,41 @@ class Datasource(object):
         if self.is_datasource(name):
             raise Exception('datasource[%s] already exists' % name)
 
+        # Always create this datasource with an fixed UID (*not* id)
+        # that is consistent across installations by hashing the
+        # name/url.  A story why:
+        #
+        # Since ~ Grafana 8.3 or so datasources got a UID and all
+        # metrics now refer to their datasource by UID.
+        #
+        # Grafana can make "exportable" dashboards that replace the
+        # datasource UID with a variable (read about that at [1]).
+        # This is what we want ... the only problem is you can not
+        # automatically import such a dashboard -- it is a UI driven
+        # process where when clicking on "import" you end up in a
+        # wizard where you select the datasource and behind the scenes
+        # it goes and fills in the variables for you before saving the
+        # dashboard.  You can search around the forums and github
+        # issues for where people are discussing this; the short story
+        # is that this happens in the UI via an undocumented
+        # api/dashboards/import call which upstream so far (June 2022)
+        # have no plans to export [2].
+        #
+        # So, by fixing the UID here, we ensure that dashboards are
+        # portable within the "grafyaml" ecosystem.  i.e. if you used
+        # grafyaml to setup the datasource, be that in testing,
+        # locally or in production, you'll have a consistent
+        # datasource UID and your dashboards will work when imported
+        # to any other.
+        #
+        # [1] https://grafana.com/docs/grafana/latest/dashboards/export-import/
+        # [2] https://github.com/grafana/grafana/ \
+        #       issues/9812#issuecomment-343216975
+        data['uid'] = hashlib.sha256(
+            data['url'].encode('utf-8')).hexdigest()[0:10]
+        LOG.debug('Setting UID of datasource %s to %s' %
+                  (data['url'], data['uid']))
+
         res = self.session.post(
             self.url, data=json.dumps(data))