From 2acd1c1d048ef9962f7475d977426312771bebae Mon Sep 17 00:00:00 2001 From: Juan Mesa Date: Tue, 14 May 2019 22:34:04 +0200 Subject: [PATCH 01/10] Add search folder by UID --- folder.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/folder.go b/folder.go index 55613c6..1f3e7e1 100644 --- a/folder.go +++ b/folder.go @@ -57,6 +57,27 @@ func (c *Client) Folder(id int64) (*Folder, error) { return folder, err } +func (c *Client) FolderByUID(uid string) (*Folder, error) { + folder := &Folder{} + req, err := c.newRequest("GET", fmt.Sprintf("/api/folders/%s", uid), nil, nil) + if err != nil { + return folder, err + } + resp, err := c.Do(req) + if err != nil { + return folder, err + } + if resp.StatusCode != 200 { + return folder, errors.New(resp.Status) + } + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return folder, err + } + err = json.Unmarshal(data, &folder) + return folder, err +} + func (c *Client) NewFolder(title string) (Folder, error) { folder := Folder{} dataMap := map[string]string{ From 7c083a46076f9357791b0bf1dccaf96ebea16628 Mon Sep 17 00:00:00 2001 From: Juan Mesa Date: Sun, 19 May 2019 10:25:11 +0200 Subject: [PATCH 02/10] Add support to create folder with custom UID --- folder.go | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/folder.go b/folder.go index 1f3e7e1..d572f1a 100644 --- a/folder.go +++ b/folder.go @@ -78,6 +78,38 @@ func (c *Client) FolderByUID(uid string) (*Folder, error) { return folder, err } +// NewFolderWithUID allows to create a new folder by specifying a custom +// UID. It is duplicated in order to maintain compatibility with existent tools +func (c *Client) NewFolderWithUID(title, uid string) (Folder, error) { + folder := Folder{} + dataMap := map[string]string{ + "title": title, + "uid": uid, + } + data, err := json.Marshal(dataMap) + req, err := c.newRequest("POST", "/api/folders", nil, bytes.NewBuffer(data)) + if err != nil { + return folder, err + } + resp, err := c.Do(req) + if err != nil { + return folder, err + } + if resp.StatusCode != 200 { + data, _ = ioutil.ReadAll(resp.Body) + return folder, fmt.Errorf("status: %s body: %s", resp.Status, data) + } + data, err = ioutil.ReadAll(resp.Body) + if err != nil { + return folder, err + } + err = json.Unmarshal(data, &folder) + if err != nil { + return folder, err + } + return folder, err +} + func (c *Client) NewFolder(title string) (Folder, error) { folder := Folder{} dataMap := map[string]string{ From 1281bda6b4359d5fafd5599d5e27871cf0306bed Mon Sep 17 00:00:00 2001 From: Juan Mesa Date: Sun, 19 May 2019 19:45:50 +0200 Subject: [PATCH 03/10] Change DeleteDashboard method to accept uid --- dashboard.go | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/dashboard.go b/dashboard.go index 2d6418f..4bea620 100644 --- a/dashboard.go +++ b/dashboard.go @@ -31,6 +31,10 @@ type Dashboard struct { Overwrite bool `json:overwrite` } +type DashboardDeleteResponse struct { + Title string `json:title` +} + // Deprecated: use NewDashboard instead func (c *Client) SaveDashboard(model map[string]interface{}, overwrite bool) (*DashboardSaveResponse, error) { wrapper := map[string]interface{}{ @@ -122,20 +126,29 @@ func (c *Client) Dashboard(slug string) (*Dashboard, error) { return result, err } -func (c *Client) DeleteDashboard(slug string) error { - path := fmt.Sprintf("/api/dashboards/db/%s", slug) +// DeleteDashboard deletes a grafana dashoboard +func (c *Client) DeleteDashboard(uid string) (string, error) { + deleted := &DashboardDeleteResponse{} + path := fmt.Sprintf("/api/dashboards/uid/%s", uid) req, err := c.newRequest("DELETE", path, nil, nil) if err != nil { - return err + return "", err } resp, err := c.Do(req) if err != nil { - return err + return "", err } if resp.StatusCode != 200 { - return errors.New(resp.Status) + return "", errors.New(resp.Status) } - - return nil + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + err = json.Unmarshal(data, &deleted) + if err != nil { + return "", err + } + return deleted.Title, nil } From 40db85ea9bcb6cf1b86e8b47bd3c64f28fd7a254 Mon Sep 17 00:00:00 2001 From: Juan Mesa Date: Sun, 19 May 2019 20:12:09 +0200 Subject: [PATCH 04/10] Add GetDashboard find a dashboard by UID, valid from Grafana 5+ --- dashboard.go | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/dashboard.go b/dashboard.go index 4bea620..212afaa 100644 --- a/dashboard.go +++ b/dashboard.go @@ -16,10 +16,12 @@ type DashboardMeta struct { Folder int64 `json:"folderId"` } +// DashboardSaveResponse grafana response for create dashboard type DashboardSaveResponse struct { Slug string `json:"slug"` - Id int64 `json:"id"` - Uid string `json:"uid"` + ID int64 `json:"id"` + UID string `json:"uid"` + URL string `json:"url"` Status string `json:"status"` Version int64 `json:"version"` } @@ -31,6 +33,7 @@ type Dashboard struct { Overwrite bool `json:overwrite` } +// DashboardDeleteResponse grafana response for delete dashboard type DashboardDeleteResponse struct { Title string `json:title` } @@ -97,6 +100,37 @@ func (c *Client) NewDashboard(dashboard Dashboard) (*DashboardSaveResponse, erro return result, err } +// GetDashboard get a dashboard by UID +func (c *Client) GetDashboard(uid string) (*Dashboard, error) { + path := fmt.Sprintf("/api/dashboards/uid/%s", uid) + req, err := c.newRequest("GET", path, nil, nil) + if err != nil { + return nil, err + } + + resp, err := c.Do(req) + if err != nil { + return nil, err + } + if resp.StatusCode != 200 { + return nil, errors.New(resp.Status) + } + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + result := &Dashboard{} + err = json.Unmarshal(data, &result) + result.Folder = result.Meta.Folder + if os.Getenv("GF_LOG") != "" { + log.Printf("got back dashboard response %s", data) + } + return result, err +} + +// Deprecated: use GetDashboard instead func (c *Client) Dashboard(slug string) (*Dashboard, error) { path := fmt.Sprintf("/api/dashboards/db/%s", slug) req, err := c.newRequest("GET", path, nil, nil) From 2eeb9c880e314d5e90baa46e45882c809dadce07 Mon Sep 17 00:00:00 2001 From: Juan Mesa Date: Sun, 19 May 2019 20:32:39 +0200 Subject: [PATCH 05/10] Update DashboardMeta struct --- dashboard.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dashboard.go b/dashboard.go index 212afaa..056eff6 100644 --- a/dashboard.go +++ b/dashboard.go @@ -11,9 +11,10 @@ import ( ) type DashboardMeta struct { - IsStarred bool `json:"isStarred"` - Slug string `json:"slug"` - Folder int64 `json:"folderId"` + IsStarred bool `json:"isStarred"` + Slug string `json:"slug"` + Folder int64 `json:"folderId"` + FolderTitle string `json:"folderTitle"` } // DashboardSaveResponse grafana response for create dashboard From c8bf5a3262363e3723e6adbace0b7373d4f29fb9 Mon Sep 17 00:00:00 2001 From: Juan Mesa Date: Sat, 25 May 2019 14:40:13 +0200 Subject: [PATCH 06/10] Add SearchFolder method --- folder.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/folder.go b/folder.go index d572f1a..3d789d0 100644 --- a/folder.go +++ b/folder.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "io/ioutil" + "net/url" ) type Folder struct { @@ -57,6 +58,34 @@ func (c *Client) Folder(id int64) (*Folder, error) { return folder, err } +// SearchFolder search an object in Grafana +func (c *Client) SearchFolder(query string) ([]Folder, error) { + folders := make([]Folder, 0) + path := "/api/search" + + params := url.Values{} + params.Add("type", "dash-folder") + params.Add("query", query) + + req, err := c.newRequest("GET", path, params, nil) + if err != nil { + return folders, err + } + resp, err := c.Do(req) + if err != nil { + return folders, err + } + if resp.StatusCode != 200 { + return folders, errors.New(resp.Status) + } + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return folders, err + } + err = json.Unmarshal(data, &folders) + return folders, err +} + func (c *Client) FolderByUID(uid string) (*Folder, error) { folder := &Folder{} req, err := c.newRequest("GET", fmt.Sprintf("/api/folders/%s", uid), nil, nil) From 33b08899448f4ba1dd8657a341c0ea4d0e9ad04e Mon Sep 17 00:00:00 2001 From: Juan Mesa Date: Sat, 25 May 2019 15:44:30 +0200 Subject: [PATCH 07/10] Add SearchDashboard method --- dashboard.go | 32 ++++++++++++++++++++++++++++++++ folder.go | 2 +- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/dashboard.go b/dashboard.go index 056eff6..b1aacc4 100644 --- a/dashboard.go +++ b/dashboard.go @@ -7,7 +7,9 @@ import ( "fmt" "io/ioutil" "log" + "net/url" "os" + "strings" ) type DashboardMeta struct { @@ -101,6 +103,36 @@ func (c *Client) NewDashboard(dashboard Dashboard) (*DashboardSaveResponse, erro return result, err } +// SearchDashboard search a dashboard in Grafana +func (c *Client) SearchDashboard(query string, tags []string, folderIds []string) ([]Dashboard, error) { + dashboards := make([]Dashboard, 0) + path := "/api/search" + + params := url.Values{} + params.Add("type", "dash-db") + params.Add("query", query) + params.Add("tags", strings.Join(tags, ",")) + params.Add("folderIds", strings.Join(folderIds, ",")) + + req, err := c.newRequest("GET", path, params, nil) + if err != nil { + return dashboards, err + } + resp, err := c.Do(req) + if err != nil { + return dashboards, err + } + if resp.StatusCode != 200 { + return dashboards, errors.New(resp.Status) + } + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return dashboards, err + } + err = json.Unmarshal(data, &dashboards) + return dashboards, err +} + // GetDashboard get a dashboard by UID func (c *Client) GetDashboard(uid string) (*Dashboard, error) { path := fmt.Sprintf("/api/dashboards/uid/%s", uid) diff --git a/folder.go b/folder.go index 3d789d0..30f2f5c 100644 --- a/folder.go +++ b/folder.go @@ -58,7 +58,7 @@ func (c *Client) Folder(id int64) (*Folder, error) { return folder, err } -// SearchFolder search an object in Grafana +// SearchFolder search a folder in Grafana func (c *Client) SearchFolder(query string) ([]Folder, error) { folders := make([]Folder, 0) path := "/api/search" From 42bb6449f9ca7f6eb779f01bf4639e45d1ec58f6 Mon Sep 17 00:00:00 2001 From: Juan Mesa Date: Sat, 25 May 2019 15:57:12 +0200 Subject: [PATCH 08/10] Allow search folder only by name and/or folder ID --- dashboard.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/dashboard.go b/dashboard.go index b1aacc4..b35c039 100644 --- a/dashboard.go +++ b/dashboard.go @@ -9,7 +9,6 @@ import ( "log" "net/url" "os" - "strings" ) type DashboardMeta struct { @@ -104,15 +103,14 @@ func (c *Client) NewDashboard(dashboard Dashboard) (*DashboardSaveResponse, erro } // SearchDashboard search a dashboard in Grafana -func (c *Client) SearchDashboard(query string, tags []string, folderIds []string) ([]Dashboard, error) { +func (c *Client) SearchDashboard(query string, folderID string) ([]Dashboard, error) { dashboards := make([]Dashboard, 0) path := "/api/search" params := url.Values{} params.Add("type", "dash-db") params.Add("query", query) - params.Add("tags", strings.Join(tags, ",")) - params.Add("folderIds", strings.Join(folderIds, ",")) + params.Add("folderIds", folderID) req, err := c.newRequest("GET", path, params, nil) if err != nil { From 400fe0d57ab61f3551bd5c2b885b424c467e2c3d Mon Sep 17 00:00:00 2001 From: Juan Mesa Date: Sat, 25 May 2019 16:16:39 +0200 Subject: [PATCH 09/10] Add debug when dashboard is returned --- dashboard.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dashboard.go b/dashboard.go index b35c039..016e608 100644 --- a/dashboard.go +++ b/dashboard.go @@ -127,7 +127,9 @@ func (c *Client) SearchDashboard(query string, folderID string) ([]Dashboard, er if err != nil { return dashboards, err } + err = json.Unmarshal(data, &dashboards) + log.Printf("got back dashboard response %s", data) return dashboards, err } From 05cae1ba109a888e9244928ea2ec6cbe959ce6b5 Mon Sep 17 00:00:00 2001 From: Juan Mesa Date: Sat, 25 May 2019 16:51:47 +0200 Subject: [PATCH 10/10] Add struct type for Dashboards returned by search API --- dashboard.go | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/dashboard.go b/dashboard.go index 016e608..a6863b3 100644 --- a/dashboard.go +++ b/dashboard.go @@ -35,6 +35,19 @@ type Dashboard struct { Overwrite bool `json:overwrite` } +// Dashboards represent json returned by search API +type Dashboards struct { + ID int64 `json:"id"` + UID string `json:"uid"` + Title string `json:"title"` + URI string `json:"uri"` + URL string `json:"url"` + Starred bool `json:"isStarred"` + FolderID int64 `json:"folderId"` + FolderUID string `json:"folderUid"` + FolderTitle string `json:"folderTitle"` +} + // DashboardDeleteResponse grafana response for delete dashboard type DashboardDeleteResponse struct { Title string `json:title` @@ -103,8 +116,8 @@ func (c *Client) NewDashboard(dashboard Dashboard) (*DashboardSaveResponse, erro } // SearchDashboard search a dashboard in Grafana -func (c *Client) SearchDashboard(query string, folderID string) ([]Dashboard, error) { - dashboards := make([]Dashboard, 0) +func (c *Client) SearchDashboard(query string, folderID string) ([]Dashboards, error) { + dashboards := make([]Dashboards, 0) path := "/api/search" params := url.Values{} @@ -129,7 +142,7 @@ func (c *Client) SearchDashboard(query string, folderID string) ([]Dashboard, er } err = json.Unmarshal(data, &dashboards) - log.Printf("got back dashboard response %s", data) + return dashboards, err }