@@ -3,7 +3,8 @@ package plugin
33import (
44 "context"
55 "encoding/json"
6- "regexp"
6+ "fmt"
7+ "reflect"
78 "strconv"
89 "strings"
910
@@ -16,6 +17,11 @@ type GrafanaApi struct {
1617 grafanaClient * sdk.Client
1718}
1819
20+ type DashboardWithCustomFields struct {
21+ sdk.Board
22+ SyncOrigin string `json:"syncOrigin"`
23+ }
24+
1925// NewGrafanaApi creates a new GrafanaApi instance
2026func NewGrafanaApi (grafanaURL string , apiToken string ) GrafanaApi {
2127 client , _ := sdk .NewClient (grafanaURL , apiToken , sdk .DefaultHTTPClient )
@@ -31,20 +37,21 @@ func (grafanaApi GrafanaApi) SearchDashboardsWithTag(tag string) ([]sdk.FoundBoa
3137 return foundDashboards , err
3238}
3339
34- // GetRawDashboardByID return Dashboard by the given UID as raw byte object
35- func (grafanaApi GrafanaApi ) GetRawDashboardByID (uid string ) ([]byte , sdk.BoardProperties , error ) {
36- rawDashboard , props , err := grafanaApi .grafanaClient .GetRawDashboardByUID (context .Background (), uid )
37- return rawDashboard , props , err
38- }
39-
40- // GetDashboardObjectByID return Dashboard by the given UID as object
41- func (grafanaApi GrafanaApi ) GetDashboardObjectByID (uid string ) (sdk.Board , sdk.BoardProperties , error ) {
42- dashboardObject , props , err := grafanaApi .grafanaClient .GetDashboardByUID (context .Background (), uid )
43- return dashboardObject , props , err
40+ // GetDashboardObjectByUID return Dashboard by the given UID as object
41+ func (grafanaApi GrafanaApi ) GetDashboardObjectByUID (uid string ) (sdk.Board , sdk.BoardProperties ) {
42+ dashboardObject , dashboardProperties , err := grafanaApi .grafanaClient .GetDashboardByUID (context .Background (), uid )
43+ if err != nil {
44+ dashboardNotFound := strings .Contains (err .Error (), "Dashboard not found" )
45+ if ! dashboardNotFound {
46+ log .DefaultLogger .Error ("get dashboard object error" , "error" , err .Error ())
47+ }
48+ return sdk.Board {}, sdk.BoardProperties {}
49+ }
50+ return dashboardObject , dashboardProperties
4451}
4552
4653// CreateOrUpdateDashboardObjectByID create or update the Dashboard with the given dashboard object
47- func (grafanaApi GrafanaApi ) CreateOrUpdateDashboardObjectByID (rawDashboard []byte , folderId int , message string ) ( sdk.StatusMessage ) {
54+ func (grafanaApi GrafanaApi ) CreateOrUpdateDashboardObjectByID (rawDashboard []byte , folderId int , message string ) sdk.StatusMessage {
4855 statusMessage , err := grafanaApi .grafanaClient .SetRawDashboardWithParam (context .Background (), sdk.RawBoardRequest {
4956 Dashboard : rawDashboard ,
5057 Parameters : sdk.SetDashboardParams {
@@ -85,70 +92,41 @@ func (grafanaApi GrafanaApi) GetOrCreateFolderID(folderName string) int {
8592}
8693
8794// getDashboardObjectFromRawDashboard get the dashboard object from a raw dashboard json
88- func getDashboardObjectFromRawDashboard (rawDashboard []byte ) sdk. Board {
89- var dashboard sdk. Board
90- err := json .Unmarshal (rawDashboard , & dashboard )
95+ func getDashboardObjectFromRawDashboard (rawDashboard []byte ) DashboardWithCustomFields {
96+ var dashboardWCF DashboardWithCustomFields
97+ err := json .Unmarshal (rawDashboard , & dashboardWCF )
9198 if err != nil {
9299 log .DefaultLogger .Error ("unmarshal raw dashboard error" , "error" , err .Error ())
93100 }
94- return dashboard
95- }
96-
97- // getLatestVersionsFromDashboardById get the latest version information of a dashboard by id
98- func (grafanaApi GrafanaApi ) getLatestVersionsFromDashboardById (dashboardId int ) int {
99- versionResponse , err := grafanaApi .grafanaClient .GetAllDashboardVersions (context .Background (), dashboardId , 1 )
100- if err != nil {
101- log .DefaultLogger .Error ("get dashboard versions error" , "error" , err .Error ())
102- }
103-
104- // get version message
105- latestVersion := versionResponse .Versions [0 ]
106- re := regexp .MustCompile (`[-]?\d[\d,]*[\.]?[\d]*` )
107- idFromVersionMessage := re .FindString (latestVersion .Message )
108- log .DefaultLogger .Debug ("latest ID in version message" , "version" , idFromVersionMessage )
109-
110- id , err := strconv .ParseUint (idFromVersionMessage , 10 , 32 )
111- if err != nil {
112- log .DefaultLogger .Error ("parsing integer error" , "error" , err .Error ())
113- }
114- return int (id )
115- }
116-
117- // parseGetDashboardError
118- func (grafanaApi GrafanaApi ) parseGetDashboardError (error error , gitBoardID int , grafanaBoardID int ) int {
119- var grafanaDashboardVersionMessageId int
120-
121- if error == nil {
122- // get version message ID
123- grafanaDashboardVersionMessageId = grafanaApi .getLatestVersionsFromDashboardById (grafanaBoardID )
124- } else {
125- containsNoDashboard := strings .Contains (error .Error (), "Dashboard not found" )
126- if containsNoDashboard {
127- // set message ID from GitHub Board
128- grafanaDashboardVersionMessageId = gitBoardID
129- } else {
130- log .DefaultLogger .Error ("get dashboard object error" , "error" , error .Error ())
131- }
132- }
133-
134- return grafanaDashboardVersionMessageId
101+ return dashboardWCF
135102}
136103
137- // CreateDashboardObjects set a Dashboard with the given raw dashboard object
138- func (grafanaApi GrafanaApi ) CreateDashboardObjects (fileMap map [string ]map [string ][]byte ) {
104+ // CreateOrUpdateDashboard set a Dashboard with the given raw dashboard object
105+ func (grafanaApi GrafanaApi ) CreateOrUpdateDashboard (fileMap map [string ]map [string ][]byte , currentCommitId string ) {
106+ // for each folder
139107 for dashboardDir , dashboardFile := range fileMap {
108+ // get Grafana folder ID or create if not exists
140109 folderID := grafanaApi .GetOrCreateFolderID (dashboardDir )
141- for dashboardName , rawDashboard := range dashboardFile {
142- gitDashboardObject := getDashboardObjectFromRawDashboard (rawDashboard )
143- // get grafana dashboard to compare version with git dashboard
144- grafanaDashboardObject , _ , err := grafanaApi .GetDashboardObjectByID (gitDashboardObject .UID )
145- grafanaDashboardVersionMessageId := grafanaApi .parseGetDashboardError (err , int (gitDashboardObject .ID ), int (grafanaDashboardObject .ID ))
146-
147- if grafanaDashboardVersionMessageId != int (gitDashboardObject .Version ) {
148- grafanaApi .CreateOrUpdateDashboardObjectByID (rawDashboard , folderID , "Synchronized from Version " + strconv .Itoa (int (gitDashboardObject .Version )))
149- log .DefaultLogger .Debug ("Dashboard created" , "name" , dashboardName )
110+ // for each dashboard within folder
111+ for gitDashboardName , gitRawDashboard := range dashboardFile {
112+ // get dashboards from Git and Grafana for comparison
113+ gitDashboardExtended := getDashboardObjectFromRawDashboard (gitRawDashboard )
114+ grafanaDashboard , _ := grafanaApi .GetDashboardObjectByUID (gitDashboardExtended .UID )
115+
116+ syncOrigin := gitDashboardExtended .SyncOrigin
117+
118+ // 'Version' and 'Dashboard ID' need to be set equal, as they are fundamentally different because of import mechanisms
119+ grafanaDashboard .Version = gitDashboardExtended .Version
120+ grafanaDashboard .ID = gitDashboardExtended .ID
121+ // 'SyncOrigin' need to be set, because custom fields are lost through the import
122+ grafanaDashboardExtended := DashboardWithCustomFields {grafanaDashboard , gitDashboardExtended .SyncOrigin }
123+
124+ if ! reflect .DeepEqual (grafanaDashboardExtended , gitDashboardExtended ) {
125+ versionMessage := fmt .Sprintf ("[SYNC] Synchronized dashboard. Version '%s' from origin '%s' (commit %s)." , strconv .Itoa (int (gitDashboardExtended .Version )), syncOrigin , currentCommitId )
126+ grafanaApi .CreateOrUpdateDashboardObjectByID (gitRawDashboard , folderID , versionMessage )
127+ log .DefaultLogger .Debug ("Dashboard created" , "name" , gitDashboardName )
150128 } else {
151- log .DefaultLogger .Info ("Dashboard already up-to-date" , "name" , dashboardName )
129+ log .DefaultLogger .Debug ("Dashboard already up-to-date" , "name" , gitDashboardName )
152130 }
153131 }
154132 }
0 commit comments