/
dashboard.go
353 lines (282 loc) · 9.66 KB
/
dashboard.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
package dashboard
import (
// We're not using it for security stuff, so it's fine.
//nolint:gosec
"crypto/sha1"
"encoding/hex"
"encoding/json"
"github.com/K-Phoen/grabana/alert"
"github.com/K-Phoen/grabana/row"
"github.com/K-Phoen/grabana/variable/constant"
"github.com/K-Phoen/grabana/variable/custom"
"github.com/K-Phoen/grabana/variable/datasource"
"github.com/K-Phoen/grabana/variable/interval"
"github.com/K-Phoen/grabana/variable/query"
"github.com/K-Phoen/grabana/variable/text"
"github.com/K-Phoen/sdk"
)
// TagAnnotation describes an annotation represented as a Tag.
// See https://grafana.com/docs/grafana/latest/reference/annotations/#query-by-tag
type TagAnnotation struct {
Name string
Datasource string
IconColor string `yaml:"color"`
Tags []string `yaml:",flow"`
}
// Option represents an option that can be used to configure a
// dashboard.
type Option func(dashboard *Builder) error
// TimezoneOption represents a possible value for the dashboard's timezone
// configuration.
type TimezoneOption string
// DefaultTimezone sets the dashboard's timezone to the default one used by
// Grafana.
const DefaultTimezone TimezoneOption = ""
// UTC sets the dashboard's timezone to UTC.
const UTC TimezoneOption = "utc"
// Browser sets the dashboard's timezone to the browser's one.
const Browser TimezoneOption = "browser"
// Builder is the main builder used to configure dashboards.
type Builder struct {
board *sdk.Board
alerts []*alert.Alert
}
// New creates a new dashboard builder.
func New(title string, options ...Option) (Builder, error) {
board := sdk.NewBoard(title)
board.ID = 0
builder := &Builder{board: board}
for _, opt := range append(defaults(), options...) {
if err := opt(builder); err != nil {
return *builder, err
}
}
return *builder, nil
}
func defaults() []Option {
return []Option{
defaultTimePicker(),
Timezone(DefaultTimezone),
Time("now-3h", "now"),
SharedCrossHair(),
}
}
func defaultTimePicker() Option {
return func(builder *Builder) error {
builder.board.Timepicker = sdk.Timepicker{
RefreshIntervals: []string{"5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"},
TimeOptions: []string{"5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"},
}
return nil
}
}
// MarshalJSON implements the encoding/json.Marshaler interface.
//
// This method can be used to render the dashboard as JSON
// which your configuration management tool of choice can then feed into
// Grafana's dashboard via its provisioning support.
// See https://grafana.com/docs/grafana/latest/administration/provisioning/#dashboards
func (builder *Builder) MarshalJSON() ([]byte, error) {
return json.Marshal(builder.board)
}
// MarshalIndentJSON renders the dashboard as indented JSON
// which your configuration management tool of choice can then feed into
// Grafana's dashboard via its provisioning support.
// See https://grafana.com/docs/grafana/latest/administration/provisioning/#dashboards
func (builder *Builder) MarshalIndentJSON() ([]byte, error) {
return json.MarshalIndent(builder.board, "", " ")
}
// Alerts returns all the alerts defined in this dashboard.
func (builder *Builder) Alerts() []*alert.Alert {
return builder.alerts
}
// Internal.
func (builder *Builder) Internal() *sdk.Board {
return builder.board
}
// VariableAsConst adds a templated variable, defined as a set of constant
// values.
// See https://grafana.com/docs/grafana/latest/reference/templating/#variable-types
func VariableAsConst(name string, options ...constant.Option) Option {
return func(builder *Builder) error {
templatedVar := constant.New(name, options...)
builder.board.Templating.List = append(builder.board.Templating.List, templatedVar.Builder)
return nil
}
}
// ID sets the ID used by the dashboard.
func ID(id uint) Option {
return func(builder *Builder) error {
builder.board.ID = id
return nil
}
}
// UID sets the UID used by the dashboard.
func UID(uid string) Option {
return func(builder *Builder) error {
validUID := uid
if len(uid) > 40 {
// We're not using it for security stuff, so it's fine.
//nolint:gosec
sha := sha1.Sum([]byte(uid))
validUID = hex.EncodeToString(sha[:])
}
builder.board.UID = validUID
return nil
}
}
// Slug sets the Slug used by the dashboard.
func Slug(slug string) Option {
return func(builder *Builder) error {
builder.board.Slug = slug
return nil
}
}
// VariableAsCustom adds a templated variable, defined as a set of custom
// values.
// See https://grafana.com/docs/grafana/latest/reference/templating/#variable-types
func VariableAsCustom(name string, options ...custom.Option) Option {
return func(builder *Builder) error {
templatedVar := custom.New(name, options...)
builder.board.Templating.List = append(builder.board.Templating.List, templatedVar.Builder)
return nil
}
}
// VariableAsInterval adds a templated variable, defined as an interval.
// See https://grafana.com/docs/grafana/latest/reference/templating/#variable-types
func VariableAsInterval(name string, options ...interval.Option) Option {
return func(builder *Builder) error {
templatedVar := interval.New(name, options...)
builder.board.Templating.List = append(builder.board.Templating.List, templatedVar.Builder)
return nil
}
}
// VariableAsQuery adds a templated variable, defined as a query.
// See https://grafana.com/docs/grafana/latest/reference/templating/#variable-types
func VariableAsQuery(name string, options ...query.Option) Option {
return func(builder *Builder) error {
templatedVar := query.New(name, options...)
builder.board.Templating.List = append(builder.board.Templating.List, templatedVar.Builder)
return nil
}
}
// VariableAsDatasource adds a templated variable, defined as a datasource.
// See https://grafana.com/docs/grafana/latest/variables/variable-types/add-data-source-variable/
func VariableAsDatasource(name string, options ...datasource.Option) Option {
return func(builder *Builder) error {
templatedVar := datasource.New(name, options...)
builder.board.Templating.List = append(builder.board.Templating.List, templatedVar.Builder)
return nil
}
}
// VariableAsText adds a templated variable, defined as a free text input.
// See https://grafana.com/docs/grafana/latest/dashboards/variables/add-template-variables/#add-a-text-box-variable
func VariableAsText(name string, options ...text.Option) Option {
return func(builder *Builder) error {
templatedVar := text.New(name, options...)
builder.board.Templating.List = append(builder.board.Templating.List, templatedVar.Builder)
return nil
}
}
// 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 {
builder.board.Links = append(builder.board.Links, link.asSdk())
}
return nil
}
}
// 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 { //nolint:revive
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 {
r, err := row.New(builder.board, title, options...)
if err != nil {
return err
}
builder.alerts = append(builder.alerts, r.Alerts()...)
return nil
}
}
// TagsAnnotation adds a new source of annotation for the dashboard.
func TagsAnnotation(annotation TagAnnotation) Option {
return func(builder *Builder) error {
builder.board.Annotations.List = append(builder.board.Annotations.List, sdk.Annotation{
Name: annotation.Name,
Datasource: &sdk.DatasourceRef{LegacyName: annotation.Datasource},
IconColor: annotation.IconColor,
Enable: true,
Tags: annotation.Tags,
Type: "tags",
})
return nil
}
}
// Editable marks the dashboard as editable.
func Editable() Option {
return func(builder *Builder) error {
builder.board.Editable = true
return nil
}
}
// ReadOnly marks the dashboard as non-editable.
func ReadOnly() Option {
return func(builder *Builder) error {
builder.board.Editable = false
return nil
}
}
// SharedCrossHair configures the graph tooltip to be shared across panels.
func SharedCrossHair() Option {
return func(builder *Builder) error {
builder.board.SharedCrosshair = true
return nil
}
}
// DefaultTooltip configures the graph tooltip NOT to be shared across panels.
func DefaultTooltip() Option {
return func(builder *Builder) error {
builder.board.SharedCrosshair = false
return nil
}
}
// Tags adds the given set of tags to the dashboard.
func Tags(tags []string) Option {
return func(builder *Builder) error {
builder.board.Tags = tags
return nil
}
}
// AutoRefresh defines the auto-refresh interval for the dashboard.
func AutoRefresh(interval string) Option {
return func(builder *Builder) error {
builder.board.Refresh = &sdk.BoolString{Flag: true, Value: interval}
return nil
}
}
// Time defines the default time range for the dashboard, e.g. from "now-6h" to
// "now".
func Time(from, to string) Option {
return func(builder *Builder) error {
builder.board.Time = sdk.Time{From: from, To: to}
return nil
}
}
// Timezone defines the default timezone for the dashboard, e.g. "utc".
func Timezone(timezone TimezoneOption) Option {
return func(builder *Builder) error {
builder.board.Timezone = string(timezone)
return nil
}
}