add grafana package & temporary debug checks
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Tom Neuber 2024-02-15 01:12:57 +01:00
parent 1247fc3fcb
commit 2d08f75545
Signed by: tom
GPG key ID: F17EFE4272D89FF6
9 changed files with 373 additions and 0 deletions

60
pkg/grafana/dashboard.go Normal file
View file

@ -0,0 +1,60 @@
package grafana
import (
"context"
"encoding/json"
"fmt"
"net/url"
"time"
)
type DashboardVersion struct {
ID uint `json:"id"`
DashboardID uint `json:"dashboardId"`
ParentVersion uint `json:"parentVersion"`
RestoredFrom uint `json:"restoredFrom"`
Version uint `json:"version"`
Created time.Time `json:"created"`
CreatedBy string `json:"createdBy"`
Message string `json:"message"`
}
func queryParams(params ...QueryParam) url.Values {
u := url.URL{}
q := u.Query()
for _, p := range params {
p(&q)
}
return q
}
func (c *Client) GetDashboardVersionsByDashboardID(ctx context.Context, dashboardID uint, params ...QueryParam) ([]DashboardVersion, error) {
var (
raw []byte
code int
err error
)
if raw, code, err = c.get(ctx, fmt.Sprintf("api/dashboards/id/%d/versions", dashboardID), queryParams(params...)); err != nil {
return nil, err
}
if code != 200 {
return nil, fmt.Errorf("HTTP error %d: returns %s", code, raw)
}
var versions []DashboardVersion
err = json.Unmarshal(raw, &versions)
return versions, err
}
func (c *Client) SearchDashboards(ctx context.Context, query string, starred bool, tags ...string) ([]FoundBoard, error) {
params := []SearchParam{
SearchType(SearchTypeDashboard),
SearchQuery(query),
SearchStarred(starred),
}
for _, tag := range tags {
params = append(params, SearchTag(tag))
}
return c.Search(ctx, params...)
}

80
pkg/grafana/requests.go Normal file
View file

@ -0,0 +1,80 @@
package grafana
import (
"bytes"
"context"
"fmt"
"io"
"net/http"
"net/url"
"path"
"strings"
)
var DefaultHTTPClient = http.DefaultClient
type Client struct {
baseURL string
key string
basicAuth bool
client *http.Client
}
func NewClient(apiURL, authString string, client *http.Client) (*Client, error) {
basicAuth := strings.Contains(authString, ":")
baseURL, err := url.Parse(apiURL)
if err != nil {
return nil, err
}
var key string
if len(authString) > 0 {
if !basicAuth {
key = fmt.Sprintf("Bearer %s", authString)
} else {
parts := strings.SplitN(authString, ":", 2)
baseURL.User = url.UserPassword(parts[0], parts[1])
}
}
return &Client{
baseURL: baseURL.String(),
basicAuth: basicAuth,
key: key,
client: client,
}, nil
}
func (c *Client) doRequest(ctx context.Context, method, query string, params url.Values, buf io.Reader) ([]byte, int, error) {
u, _ := url.Parse(c.baseURL)
u.Path = path.Join(u.Path, query)
if params != nil {
u.RawQuery = params.Encode()
}
req, err := http.NewRequest(method, u.String(), buf)
if err != nil {
return nil, 0, err
}
req = req.WithContext(ctx)
if !c.basicAuth && len(c.key) > 0 {
req.Header.Set("Authorization", c.key)
}
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
req.Header.Set("User-Agent", "grafana-backuper")
resp, err := c.client.Do(req)
if err != nil {
return nil, 0, err
}
data, err := io.ReadAll(resp.Body)
resp.Body.Close()
return data, resp.StatusCode, err
}
func (c *Client) get(ctx context.Context, query string, params url.Values) ([]byte, int, error) {
return c.doRequest(ctx, "GET", query, params, nil)
}
func (c *Client) post(ctx context.Context, query string, params url.Values, body []byte) ([]byte, int, error) {
return c.doRequest(ctx, "POST", query, params, bytes.NewBuffer(body))
}

89
pkg/grafana/search.go Normal file
View file

@ -0,0 +1,89 @@
package grafana
import (
"context"
"encoding/json"
"fmt"
"net/url"
"strconv"
)
const (
SearchTypeFolder SearchParamType = "dash-folder"
SearchTypeDashboard SearchParamType = "dash-db"
)
type FoundBoard struct {
ID uint `json:"id"`
UID string `json:"uid"`
Title string `json:"title"`
URI string `json:"uri"`
URL string `json:"url"`
Slug string `json:"slug"`
Type string `json:"type"`
Tags []string `json:"tags"`
IsStarred bool `json:"isStarred"`
FolderID int `json:"folderId"`
FolderUID string `json:"folderUid"`
FolderTitle string `json:"folderTitle"`
FolderURL string `json:"folderUrl"`
}
type (
// SearchParam is a type for specifying Search params.
SearchParam func(*url.Values)
// SearchParamType is a type accepted by SearchType func.
SearchParamType string
// QueryParam is a type for specifying arbitrary API parameters
QueryParam func(*url.Values)
)
func (c *Client) Search(ctx context.Context, params ...SearchParam) ([]FoundBoard, error) {
var (
raw []byte
boards []FoundBoard
code int
err error
)
u := url.URL{}
q := u.Query()
for _, p := range params {
p(&q)
}
if raw, code, err = c.get(ctx, "api/search", q); err != nil {
return nil, err
}
if code != 200 {
return nil, fmt.Errorf("HTTP error %d: returns %s", code, raw)
}
err = json.Unmarshal(raw, &boards)
return boards, err
}
func SearchQuery(query string) SearchParam {
return func(v *url.Values) {
if query != "" {
v.Set("query", query)
}
}
}
func SearchStarred(starred bool) SearchParam {
return func(v *url.Values) {
v.Set("starred", strconv.FormatBool(starred))
}
}
func SearchTag(tag string) SearchParam {
return func(v *url.Values) {
if tag != "" {
v.Add("tag", tag)
}
}
}
func SearchType(searchType SearchParamType) SearchParam {
return func(v *url.Values) {
v.Set("type", string(searchType))
}
}