diff --git a/go.mod b/go.mod index 4b65095e..daa35abd 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/K-Phoen/dark go 1.19 require ( - github.com/K-Phoen/grabana v0.21.13 + github.com/K-Phoen/grabana v0.21.14 github.com/K-Phoen/sdk v0.12.0 github.com/go-logr/logr v1.2.3 github.com/onsi/ginkgo v1.16.5 diff --git a/go.sum b/go.sum index ce967224..3c64734c 100644 --- a/go.sum +++ b/go.sum @@ -38,8 +38,8 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/K-Phoen/grabana v0.21.13 h1:JtvwhZonUOmOfSyNe16pG+5eJ723kZDX9E9vQ3jUzYY= -github.com/K-Phoen/grabana v0.21.13/go.mod h1:HDl99djdna5Auu7RcOgxE64HnvQ9UBIpqc+A2A5XnL8= +github.com/K-Phoen/grabana v0.21.14 h1:sosOZQ5APT4s08F6amqLEbv7b+//7YFyzSdWazIQPsQ= +github.com/K-Phoen/grabana v0.21.14/go.mod h1:HDl99djdna5Auu7RcOgxE64HnvQ9UBIpqc+A2A5XnL8= github.com/K-Phoen/sdk v0.12.0 h1:+0QqHoDZbO6zetFMggM3zKF48GKRu744Ycc9w4oyY0E= github.com/K-Phoen/sdk v0.12.0/go.mod h1:wp7qXARaIhCYktmoOjRZ+TDMlek5nbayC+waN7vigxI= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= diff --git a/internal/pkg/converter/dashboardlink.go b/internal/pkg/converter/dashboardlink.go new file mode 100644 index 00000000..c189ee70 --- /dev/null +++ b/internal/pkg/converter/dashboardlink.go @@ -0,0 +1,26 @@ +package converter + +import ( + grabana "github.com/K-Phoen/grabana/decoder" + "github.com/K-Phoen/sdk" +) + +func (converter *JSON) convertDashboardLink(link sdk.Link) *grabana.DashboardInternalLink { + extLink := &grabana.DashboardInternalLink{ + Title: link.Title, + Tags: link.Tags, + IncludeVariableValues: link.IncludeVars, + } + + if link.AsDropdown != nil { + extLink.AsDropdown = *link.AsDropdown + } + if link.TargetBlank != nil { + extLink.OpenInNewTab = *link.TargetBlank + } + if link.KeepTime != nil { + extLink.IncludeTimeRange = *link.KeepTime + } + + return extLink +} diff --git a/internal/pkg/converter/dashboardlink_test.go b/internal/pkg/converter/dashboardlink_test.go new file mode 100644 index 00000000..115fc263 --- /dev/null +++ b/internal/pkg/converter/dashboardlink_test.go @@ -0,0 +1,32 @@ +package converter + +import ( + "testing" + + "github.com/K-Phoen/sdk" + "github.com/stretchr/testify/require" + "go.uber.org/zap" +) + +func TestConvertDashboardLink(t *testing.T) { + req := require.New(t) + + externalLink := sdk.Link{ + Title: "joe", + Tags: []string{"my-service"}, + Type: "dashboards", + IncludeVars: true, + AsDropdown: boolPtr(true), + KeepTime: boolPtr(true), + TargetBlank: boolPtr(true), + } + converter := NewJSON(zap.NewNop()) + link := converter.convertDashboardLink(externalLink) + + req.Equal("joe", link.Title) + req.ElementsMatch([]string{"my-service"}, link.Tags) + req.True(link.OpenInNewTab) + req.True(link.IncludeTimeRange) + req.True(link.AsDropdown) + req.True(link.IncludeVariableValues) +} diff --git a/internal/pkg/converter/externallink.go b/internal/pkg/converter/externallink.go index ec606056..36cf26d3 100644 --- a/internal/pkg/converter/externallink.go +++ b/internal/pkg/converter/externallink.go @@ -6,23 +6,7 @@ import ( "go.uber.org/zap" ) -func (converter *JSON) convertExternalLinks(links []sdk.Link, dashboard *grabana.DashboardModel) { - for _, link := range links { - extLink := converter.convertExternalLink(link) - if extLink == nil { - continue - } - - dashboard.ExternalLinks = append(dashboard.ExternalLinks, *extLink) - } -} - func (converter *JSON) convertExternalLink(link sdk.Link) *grabana.DashboardExternalLink { - if link.Type != "link" { - converter.logger.Warn("unhandled link type: skipped", zap.String("type", link.Type), zap.String("title", link.Title)) - return nil - } - if link.URL == nil || *link.URL == "" { converter.logger.Warn("link URL empty: skipped", zap.String("title", link.Title)) return nil diff --git a/internal/pkg/converter/externallink_test.go b/internal/pkg/converter/externallink_test.go index 6971e7bd..fcad1ebc 100644 --- a/internal/pkg/converter/externallink_test.go +++ b/internal/pkg/converter/externallink_test.go @@ -3,7 +3,6 @@ package converter import ( "testing" - grabana "github.com/K-Phoen/grabana/decoder" "github.com/K-Phoen/sdk" "github.com/stretchr/testify/require" "go.uber.org/zap" @@ -22,18 +21,8 @@ func TestConvertExternalLink(t *testing.T) { Tooltip: strPtr("description"), URL: strPtr("http://lala"), } - dashLink := sdk.Link{ - Title: "not link", - } - converter := NewJSON(zap.NewNop()) - - dashboard := &grabana.DashboardModel{} - converter.convertExternalLinks([]sdk.Link{externalLink, dashLink}, dashboard) - - req.Len(dashboard.ExternalLinks, 1) - - link := dashboard.ExternalLinks[0] + link := converter.convertExternalLink(externalLink) req.Equal("joe", link.Title) req.Equal("description", link.Description) diff --git a/internal/pkg/converter/json.go b/internal/pkg/converter/json.go index 96277517..d9905ca2 100644 --- a/internal/pkg/converter/json.go +++ b/internal/pkg/converter/json.go @@ -119,12 +119,35 @@ func (converter *JSON) parseInput(input io.Reader) (*grabana.DashboardModel, err converter.convertGeneralSettings(board, dashboard) converter.convertVariables(board.Templating.List, dashboard) converter.convertAnnotations(board.Annotations.List, dashboard) - converter.convertExternalLinks(board.Links, dashboard) + converter.convertLinks(board.Links, dashboard) converter.convertPanels(board.Panels, dashboard) return dashboard, nil } +func (converter *JSON) convertLinks(links []sdk.Link, dashboard *grabana.DashboardModel) { + for _, link := range links { + switch link.Type { + case "link": + extLink := converter.convertExternalLink(link) + if extLink == nil { + continue + } + + dashboard.ExternalLinks = append(dashboard.ExternalLinks, *extLink) + case "dashboards": + dashLink := converter.convertDashboardLink(link) + if dashLink == nil { + continue + } + + dashboard.DashboardLinks = append(dashboard.DashboardLinks, *dashLink) + default: + converter.logger.Warn("unhandled link type: skipped", zap.String("type", link.Type), zap.String("title", link.Title)) + } + } +} + func (converter *JSON) convertGeneralSettings(board *sdk.Board, dashboard *grabana.DashboardModel) { dashboard.Title = board.Title dashboard.SharedCrosshair = board.SharedCrosshair diff --git a/internal/pkg/converter/json_test.go b/internal/pkg/converter/json_test.go index bd193422..9a631bdb 100644 --- a/internal/pkg/converter/json_test.go +++ b/internal/pkg/converter/json_test.go @@ -93,6 +93,34 @@ func TestConvertGeneralSettings(t *testing.T) { req.True(dashboard.SharedCrosshair) } +func TestConvertLinks(t *testing.T) { + req := require.New(t) + + links := []sdk.Link{ + { + Title: "ext link", + Type: "link", + URL: strPtr("https://foo"), + }, + { + Title: "dash link", + Type: "dashboards", + Tags: []string{"foo"}, + }, + { + Title: "some link", + Type: "unknown", + }, + } + + converter := NewJSON(zap.NewNop()) + dashboard := &grabana.DashboardModel{} + converter.convertLinks(links, dashboard) + + req.Equal(1, len(dashboard.DashboardLinks)) + req.Equal(1, len(dashboard.ExternalLinks)) +} + func strPtr(input string) *string { return &input } diff --git a/vendor/github.com/K-Phoen/grabana/Makefile b/vendor/github.com/K-Phoen/grabana/Makefile index eebd656e..789937a3 100644 --- a/vendor/github.com/K-Phoen/grabana/Makefile +++ b/vendor/github.com/K-Phoen/grabana/Makefile @@ -8,7 +8,7 @@ endif .PHONY: lint lint: - docker run --rm -v $(shell pwd):/app -w /app golangci/golangci-lint:v1.43.0 golangci-lint run -c .golangci.yaml + docker run --rm -v $(shell pwd):/app -w /app golangci/golangci-lint:v1.51.1 golangci-lint run -c .golangci.yaml .PHONY: tests tests: diff --git a/vendor/github.com/K-Phoen/grabana/README.md b/vendor/github.com/K-Phoen/grabana/README.md index d58ad3d3..bcc36f83 100644 --- a/vendor/github.com/K-Phoen/grabana/README.md +++ b/vendor/github.com/K-Phoen/grabana/README.md @@ -98,7 +98,7 @@ rows: Dashboard creation (or [automatically as a Kubernetes Resource, using DARK](https://github.com/K-Phoen/dark)): ```go -content, err := ioutil.ReadFile("dashboard.yaml") +content, err := os.ReadFile("dashboard.yaml") if err != nil { fmt.Fprintf(os.Stderr, "Could not read file: %s\n", err) os.Exit(1) diff --git a/vendor/github.com/K-Phoen/grabana/client.go b/vendor/github.com/K-Phoen/grabana/client.go index 2569e1c7..fc15332c 100644 --- a/vendor/github.com/K-Phoen/grabana/client.go +++ b/vendor/github.com/K-Phoen/grabana/client.go @@ -6,7 +6,6 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "net/http" ) @@ -61,7 +60,7 @@ func (client *Client) modifyRequest(request *http.Request) { } func (client Client) httpError(resp *http.Response) error { - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { return err } diff --git a/vendor/github.com/K-Phoen/grabana/dashboard/dashboard.go b/vendor/github.com/K-Phoen/grabana/dashboard/dashboard.go index b1767ef8..58eb3acb 100644 --- a/vendor/github.com/K-Phoen/grabana/dashboard/dashboard.go +++ b/vendor/github.com/K-Phoen/grabana/dashboard/dashboard.go @@ -213,8 +213,8 @@ func VariableAsDatasource(name string, options ...datasource.Option) Option { } } -// ExternalLinks adds a dashboard-level link. -// See https://grafana.com/docs/grafana/latest/linking/dashboard-links/ +// ExternalLinks adds a dashboard-level external links. +// See https://grafana.com/docs/grafana/latest/dashboards/build-dashboards/manage-dashboard-links/#add-a-url-link-to-a-dashboard func ExternalLinks(links ...ExternalLink) Option { return func(builder *Builder) error { for _, link := range links { @@ -225,6 +225,18 @@ func ExternalLinks(links ...ExternalLink) Option { } } +// DashboardLinks adds a dashboard-level links to other dashboards. +// See https://grafana.com/docs/grafana/latest/dashboards/build-dashboards/manage-dashboard-links/#dashboard-links +func DashboardLinks(links ...DashboardLink) Option { + return func(builder *Builder) error { + for _, link := range links { + builder.board.Links = append(builder.board.Links, link.asSdk()) + } + + return nil + } +} + // Row adds a row to the dashboard. func Row(title string, options ...row.Option) Option { return func(builder *Builder) error { diff --git a/vendor/github.com/K-Phoen/grabana/dashboard/link.go b/vendor/github.com/K-Phoen/grabana/dashboard/link.go index 8e0ac767..292c3579 100644 --- a/vendor/github.com/K-Phoen/grabana/dashboard/link.go +++ b/vendor/github.com/K-Phoen/grabana/dashboard/link.go @@ -15,7 +15,7 @@ const ( ) // ExternalLink describes dashboard-level external link. -// See https://grafana.com/docs/grafana/latest/linking/dashboard-links/ +// See https://grafana.com/docs/grafana/latest/dashboards/build-dashboards/manage-dashboard-links/#add-a-url-link-to-a-dashboard type ExternalLink struct { Title string Description string @@ -46,3 +46,27 @@ func (link ExternalLink) asSdk() sdk.Link { Type: "link", } } + +// DashboardLink describes dashboard-level links to other dashboards. +// See https://grafana.com/docs/grafana/latest/dashboards/build-dashboards/manage-dashboard-links/#dashboard-links +type DashboardLink struct { + Title string + Tags []string + + AsDropdown bool + IncludeTimeRange bool + IncludeVariableValues bool + OpenInNewTab bool +} + +func (link DashboardLink) asSdk() sdk.Link { + return sdk.Link{ + Title: link.Title, + Tags: link.Tags, + AsDropdown: &link.AsDropdown, + IncludeVars: link.IncludeVariableValues, + KeepTime: &link.IncludeTimeRange, + TargetBlank: &link.OpenInNewTab, + Type: "dashboards", + } +} diff --git a/vendor/github.com/K-Phoen/grabana/decoder/dashboard.go b/vendor/github.com/K-Phoen/grabana/decoder/dashboard.go index a80f3f20..71d25c36 100644 --- a/vendor/github.com/K-Phoen/grabana/decoder/dashboard.go +++ b/vendor/github.com/K-Phoen/grabana/decoder/dashboard.go @@ -25,6 +25,7 @@ type DashboardModel struct { TagsAnnotation []dashboard.TagAnnotation `yaml:"tags_annotations,omitempty"` Variables []DashboardVariable `yaml:",omitempty"` ExternalLinks []DashboardExternalLink `yaml:"external_links,omitempty"` + DashboardLinks []DashboardInternalLink `yaml:"dashboard_links,omitempty"` Rows []DashboardRow } @@ -52,6 +53,10 @@ func (d *DashboardModel) ToBuilder() (dashboard.Builder, error) { opts = append(opts, dashboard.ExternalLinks(externalLink.toModel())) } + for _, dashboardLink := range d.DashboardLinks { + opts = append(opts, dashboard.DashboardLinks(dashboardLink.toModel())) + } + if d.AutoRefresh != "" { opts = append(opts, dashboard.AutoRefresh(d.AutoRefresh)) } diff --git a/vendor/github.com/K-Phoen/grabana/decoder/dashboardlink.go b/vendor/github.com/K-Phoen/grabana/decoder/dashboardlink.go new file mode 100644 index 00000000..e752ea76 --- /dev/null +++ b/vendor/github.com/K-Phoen/grabana/decoder/dashboardlink.go @@ -0,0 +1,25 @@ +package decoder + +import ( + "github.com/K-Phoen/grabana/dashboard" +) + +type DashboardInternalLink struct { + Title string `yaml:"title"` + Tags []string `yaml:"tags"` + AsDropdown bool `yaml:"as_dropdown,omitempty"` + IncludeTimeRange bool `yaml:"include_time_range,omitempty"` + IncludeVariableValues bool `yaml:"include_variable_values,omitempty"` + OpenInNewTab bool `yaml:"open_in_new_tab,omitempty"` +} + +func (l DashboardInternalLink) toModel() dashboard.DashboardLink { + return dashboard.DashboardLink{ + Title: l.Title, + Tags: l.Tags, + AsDropdown: l.AsDropdown, + IncludeTimeRange: l.IncludeTimeRange, + IncludeVariableValues: l.IncludeVariableValues, + OpenInNewTab: l.OpenInNewTab, + } +} diff --git a/vendor/github.com/K-Phoen/grabana/decoder/row.go b/vendor/github.com/K-Phoen/grabana/decoder/row.go index 2184dbc9..0fb551a0 100644 --- a/vendor/github.com/K-Phoen/grabana/decoder/row.go +++ b/vendor/github.com/K-Phoen/grabana/decoder/row.go @@ -7,10 +7,11 @@ import ( // DashboardRow represents a dashboard row. type DashboardRow struct { - Name string - Repeat string `yaml:"repeat_for,omitempty"` - Collapse bool `yaml:",omitempty"` - Panels []DashboardPanel + Name string + Repeat string `yaml:"repeat_for,omitempty"` + Collapse bool `yaml:",omitempty"` + HideTitle bool `yaml:"hide_title,omitempty"` + Panels []DashboardPanel } func (r DashboardRow) toOption() (dashboard.Option, error) { @@ -22,6 +23,9 @@ func (r DashboardRow) toOption() (dashboard.Option, error) { if r.Collapse { opts = append(opts, row.Collapse()) } + if r.HideTitle { + opts = append(opts, row.HideTitle()) + } for _, panel := range r.Panels { opt, err := panel.toOption() diff --git a/vendor/modules.txt b/vendor/modules.txt index 0dc09933..b3b063fd 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,4 +1,4 @@ -# github.com/K-Phoen/grabana v0.21.13 +# github.com/K-Phoen/grabana v0.21.14 ## explicit; go 1.19 github.com/K-Phoen/grabana github.com/K-Phoen/grabana/alert