File: dashboard.go

package info (click to toggle)
golang-github-circonus-labs-circonus-gometrics 2.3.1-4
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 824 kB
  • sloc: makefile: 2
file content (400 lines) | stat: -rw-r--r-- 17,093 bytes parent folder | download | duplicates (2)
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
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
// Copyright 2016 Circonus, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Dashboard API support - Fetch, Create, Update, Delete, and Search
// See: https://login.circonus.com/resources/api/calls/dashboard

package api

import (
	"encoding/json"
	"fmt"
	"net/url"
	"regexp"

	"github.com/circonus-labs/circonus-gometrics/api/config"
)

// DashboardGridLayout defines layout
type DashboardGridLayout struct {
	Height uint `json:"height"`
	Width  uint `json:"width"`
}

// DashboardAccessConfig defines access config
type DashboardAccessConfig struct {
	BlackDash           bool   `json:"black_dash"`
	Enabled             bool   `json:"enabled"`
	Fullscreen          bool   `json:"fullscreen"`
	FullscreenHideTitle bool   `json:"fullscreen_hide_title"`
	Nickname            string `json:"nickname"`
	ScaleText           bool   `json:"scale_text"`
	SharedID            string `json:"shared_id"`
	TextSize            uint   `json:"text_size"`
}

// DashboardOptions defines options
type DashboardOptions struct {
	AccessConfigs       []DashboardAccessConfig `json:"access_configs"`
	FullscreenHideTitle bool                    `json:"fullscreen_hide_title"`
	HideGrid            bool                    `json:"hide_grid"`
	Linkages            [][]string              `json:"linkages"`
	ScaleText           bool                    `json:"scale_text"`
	TextSize            uint                    `json:"text_size"`
}

// ChartTextWidgetDatapoint defines datapoints for charts
type ChartTextWidgetDatapoint struct {
	AccountID    string `json:"account_id,omitempty"`     // metric cluster, metric
	CheckID      uint   `json:"_check_id,omitempty"`      // metric
	ClusterID    uint   `json:"cluster_id,omitempty"`     // metric cluster
	ClusterTitle string `json:"_cluster_title,omitempty"` // metric cluster
	Label        string `json:"label,omitempty"`          // metric
	Label2       string `json:"_label,omitempty"`         // metric cluster
	Metric       string `json:"metric,omitempty"`         // metric
	MetricType   string `json:"_metric_type,omitempty"`   // metric
	NumericOnly  bool   `json:"numeric_only,omitempty"`   // metric cluster
}

// ChartWidgetDefinitionLegend defines chart widget definition legend
type ChartWidgetDefinitionLegend struct {
	Show bool   `json:"show,omitempty"`
	Type string `json:"type,omitempty"`
}

// ChartWidgetWedgeLabels defines chart widget wedge labels
type ChartWidgetWedgeLabels struct {
	OnChart  bool `json:"on_chart,omitempty"`
	ToolTips bool `json:"tooltips,omitempty"`
}

// ChartWidgetWedgeValues defines chart widget wedge values
type ChartWidgetWedgeValues struct {
	Angle string `json:"angle,omitempty"`
	Color string `json:"color,omitempty"`
	Show  bool   `json:"show,omitempty"`
}

// ChartWidgtDefinition defines chart widget definition
type ChartWidgtDefinition struct {
	Datasource        string                      `json:"datasource,omitempty"`
	Derive            string                      `json:"derive,omitempty"`
	DisableAutoformat bool                        `json:"disable_autoformat,omitempty"`
	Formula           string                      `json:"formula,omitempty"`
	Legend            ChartWidgetDefinitionLegend `json:"legend,omitempty"`
	Period            uint                        `json:"period,omitempty"`
	PopOnHover        bool                        `json:"pop_onhover,omitempty"`
	WedgeLabels       ChartWidgetWedgeLabels      `json:"wedge_labels,omitempty"`
	WedgeValues       ChartWidgetWedgeValues      `json:"wedge_values,omitempty"`
}

// ForecastGaugeWidgetThresholds defines forecast widget thresholds
type ForecastGaugeWidgetThresholds struct {
	Colors []string `json:"colors,omitempty"` // forecasts, gauges
	Flip   bool     `json:"flip,omitempty"`   // gauges
	Values []string `json:"values,omitempty"` // forecasts, gauges
}

// StatusWidgetAgentStatusSettings defines agent status settings
type StatusWidgetAgentStatusSettings struct {
	Search         string `json:"search,omitempty"`
	ShowAgentTypes string `json:"show_agent_types,omitempty"`
	ShowContact    bool   `json:"show_contact,omitempty"`
	ShowFeeds      bool   `json:"show_feeds,omitempty"`
	ShowSetup      bool   `json:"show_setup,omitempty"`
	ShowSkew       bool   `json:"show_skew,omitempty"`
	ShowUpdates    bool   `json:"show_updates,omitempty"`
}

// StatusWidgetHostStatusSettings defines host status settings
type StatusWidgetHostStatusSettings struct {
	LayoutStyle  string   `json:"layout_style,omitempty"`
	Search       string   `json:"search,omitempty"`
	SortBy       string   `json:"sort_by,omitempty"`
	TagFilterSet []string `json:"tag_filter_set,omitempty"`
}

// DashboardWidgetSettings defines settings specific to widget
// Note: optional attributes which are structs need to be pointers so they will be omitted
type DashboardWidgetSettings struct {
	AccountID           string                           `json:"account_id,omitempty"`            // alerts, clusters, gauges, graphs, lists, status
	Acknowledged        string                           `json:"acknowledged,omitempty"`          // alerts
	AgentStatusSettings *StatusWidgetAgentStatusSettings `json:"agent_status_settings,omitempty"` // status
	Algorithm           string                           `json:"algorithm,omitempty"`             // clusters
	Autoformat          bool                             `json:"autoformat,omitempty"`            // text
	BodyFormat          string                           `json:"body_format,omitempty"`           // text
	ChartType           string                           `json:"chart_type,omitempty"`            // charts
	CheckUUID           string                           `json:"check_uuid,omitempty"`            // gauges
	Cleared             string                           `json:"cleared,omitempty"`               // alerts
	ClusterID           uint                             `json:"cluster_id,omitempty"`            // clusters
	ClusterName         string                           `json:"cluster_name,omitempty"`          // clusters
	ContactGroups       []uint                           `json:"contact_groups,omitempty"`        // alerts
	ContentType         string                           `json:"content_type,omitempty"`          // status
	Datapoints          []ChartTextWidgetDatapoint       `json:"datapoints,omitempty"`            // charts, text
	DateWindow          string                           `json:"date_window,omitempty"`           // graphs
	Definition          *ChartWidgtDefinition            `json:"definition,omitempty"`            // charts
	Dependents          string                           `json:"dependents,omitempty"`            // alerts
	DisableAutoformat   bool                             `json:"disable_autoformat,omitempty"`    // gauges
	Display             string                           `json:"display,omitempty"`               // alerts
	Format              string                           `json:"format,omitempty"`                // forecasts
	Formula             string                           `json:"formula,omitempty"`               // gauges
	GraphUUID           string                           `json:"graph_id,omitempty"`              // graphs
	HideXAxis           bool                             `json:"hide_xaxis,omitempty"`            // graphs
	HideYAxis           bool                             `json:"hide_yaxis,omitempty"`            // graphs
	HostStatusSettings  *StatusWidgetHostStatusSettings  `json:"host_status_settings,omitempty"`  // status
	KeyInline           bool                             `json:"key_inline,omitempty"`            // graphs
	KeyLoc              string                           `json:"key_loc,omitempty"`               // graphs
	KeySize             uint                             `json:"key_size,omitempty"`              // graphs
	KeyWrap             bool                             `json:"key_wrap,omitempty"`              // graphs
	Label               string                           `json:"label,omitempty"`                 // graphs
	Layout              string                           `json:"layout,omitempty"`                // clusters
	Limit               uint                             `json:"limit,omitempty"`                 // lists
	Maintenance         string                           `json:"maintenance,omitempty"`           // alerts
	Markup              string                           `json:"markup,omitempty"`                // html
	MetricDisplayName   string                           `json:"metric_display_name,omitempty"`   // gauges
	MetricName          string                           `json:"metric_name,omitempty"`           // gauges
	MinAge              string                           `json:"min_age,omitempty"`               // alerts
	OffHours            []uint                           `json:"off_hours,omitempty"`             // alerts
	OverlaySetID        string                           `json:"overlay_set_id,omitempty"`        // graphs
	Period              uint                             `json:"period,omitempty"`                // gauges, text, graphs
	RangeHigh           int                              `json:"range_high,omitempty"`            // gauges
	RangeLow            int                              `json:"range_low,omitempty"`             // gauges
	Realtime            bool                             `json:"realtime,omitempty"`              // graphs
	ResourceLimit       string                           `json:"resource_limit,omitempty"`        // forecasts
	ResourceUsage       string                           `json:"resource_usage,omitempty"`        // forecasts
	Search              string                           `json:"search,omitempty"`                // alerts, lists
	Severity            string                           `json:"severity,omitempty"`              // alerts
	ShowFlags           bool                             `json:"show_flags,omitempty"`            // graphs
	Size                string                           `json:"size,omitempty"`                  // clusters
	TagFilterSet        []string                         `json:"tag_filter_set,omitempty"`        // alerts
	Threshold           float32                          `json:"threshold,omitempty"`             // clusters
	Thresholds          *ForecastGaugeWidgetThresholds   `json:"thresholds,omitempty"`            // forecasts, gauges
	TimeWindow          string                           `json:"time_window,omitempty"`           // alerts
	Title               string                           `json:"title,omitempty"`                 // alerts, charts, forecasts, gauges, html
	TitleFormat         string                           `json:"title_format,omitempty"`          // text
	Trend               string                           `json:"trend,omitempty"`                 // forecasts
	Type                string                           `json:"type,omitempty"`                  // gauges, lists
	UseDefault          bool                             `json:"use_default,omitempty"`           // text
	ValueType           string                           `json:"value_type,omitempty"`            // gauges, text
	WeekDays            []string                         `json:"weekdays,omitempty"`              // alerts
}

// DashboardWidget defines widget
type DashboardWidget struct {
	Active   bool                    `json:"active"`
	Height   uint                    `json:"height"`
	Name     string                  `json:"name"`
	Origin   string                  `json:"origin"`
	Settings DashboardWidgetSettings `json:"settings"`
	Type     string                  `json:"type"`
	WidgetID string                  `json:"widget_id"`
	Width    uint                    `json:"width"`
}

// Dashboard defines a dashboard. See https://login.circonus.com/resources/api/calls/dashboard for more information.
type Dashboard struct {
	AccountDefault bool                `json:"account_default"`
	Active         bool                `json:"_active,omitempty"`
	CID            string              `json:"_cid,omitempty"`
	Created        uint                `json:"_created,omitempty"`
	CreatedBy      string              `json:"_created_by,omitempty"`
	GridLayout     DashboardGridLayout `json:"grid_layout"`
	LastModified   uint                `json:"_last_modified,omitempty"`
	Options        DashboardOptions    `json:"options"`
	Shared         bool                `json:"shared"`
	Title          string              `json:"title"`
	UUID           string              `json:"_dashboard_uuid,omitempty"`
	Widgets        []DashboardWidget   `json:"widgets"`
}

// NewDashboard returns a new Dashboard (with defaults, if applicable)
func NewDashboard() *Dashboard {
	return &Dashboard{}
}

// FetchDashboard retrieves dashboard with passed cid.
func (a *API) FetchDashboard(cid CIDType) (*Dashboard, error) {
	if cid == nil || *cid == "" {
		return nil, fmt.Errorf("Invalid dashboard CID [none]")
	}

	dashboardCID := string(*cid)

	matched, err := regexp.MatchString(config.DashboardCIDRegex, dashboardCID)
	if err != nil {
		return nil, err
	}
	if !matched {
		return nil, fmt.Errorf("Invalid dashboard CID [%s]", dashboardCID)
	}

	result, err := a.Get(string(*cid))
	if err != nil {
		return nil, err
	}

	if a.Debug {
		a.Log.Printf("[DEBUG] fetch dashboard, received JSON: %s", string(result))
	}

	dashboard := new(Dashboard)
	if err := json.Unmarshal(result, dashboard); err != nil {
		return nil, err
	}

	return dashboard, nil
}

// FetchDashboards retrieves all dashboards available to the API Token.
func (a *API) FetchDashboards() (*[]Dashboard, error) {
	result, err := a.Get(config.DashboardPrefix)
	if err != nil {
		return nil, err
	}

	var dashboards []Dashboard
	if err := json.Unmarshal(result, &dashboards); err != nil {
		return nil, err
	}

	return &dashboards, nil
}

// UpdateDashboard updates passed dashboard.
func (a *API) UpdateDashboard(cfg *Dashboard) (*Dashboard, error) {
	if cfg == nil {
		return nil, fmt.Errorf("Invalid dashboard config [nil]")
	}

	dashboardCID := string(cfg.CID)

	matched, err := regexp.MatchString(config.DashboardCIDRegex, dashboardCID)
	if err != nil {
		return nil, err
	}
	if !matched {
		return nil, fmt.Errorf("Invalid dashboard CID [%s]", dashboardCID)
	}

	jsonCfg, err := json.Marshal(cfg)
	if err != nil {
		return nil, err
	}

	if a.Debug {
		a.Log.Printf("[DEBUG] update dashboard, sending JSON: %s", string(jsonCfg))
	}

	result, err := a.Put(dashboardCID, jsonCfg)
	if err != nil {
		return nil, err
	}

	dashboard := &Dashboard{}
	if err := json.Unmarshal(result, dashboard); err != nil {
		return nil, err
	}

	return dashboard, nil
}

// CreateDashboard creates a new dashboard.
func (a *API) CreateDashboard(cfg *Dashboard) (*Dashboard, error) {
	if cfg == nil {
		return nil, fmt.Errorf("Invalid dashboard config [nil]")
	}

	jsonCfg, err := json.Marshal(cfg)
	if err != nil {
		return nil, err
	}

	if a.Debug {
		a.Log.Printf("[DEBUG] create dashboard, sending JSON: %s", string(jsonCfg))
	}

	result, err := a.Post(config.DashboardPrefix, jsonCfg)
	if err != nil {
		return nil, err
	}

	dashboard := &Dashboard{}
	if err := json.Unmarshal(result, dashboard); err != nil {
		return nil, err
	}

	return dashboard, nil
}

// DeleteDashboard deletes passed dashboard.
func (a *API) DeleteDashboard(cfg *Dashboard) (bool, error) {
	if cfg == nil {
		return false, fmt.Errorf("Invalid dashboard config [nil]")
	}
	return a.DeleteDashboardByCID(CIDType(&cfg.CID))
}

// DeleteDashboardByCID deletes dashboard with passed cid.
func (a *API) DeleteDashboardByCID(cid CIDType) (bool, error) {
	if cid == nil || *cid == "" {
		return false, fmt.Errorf("Invalid dashboard CID [none]")
	}

	dashboardCID := string(*cid)

	matched, err := regexp.MatchString(config.DashboardCIDRegex, dashboardCID)
	if err != nil {
		return false, err
	}
	if !matched {
		return false, fmt.Errorf("Invalid dashboard CID [%s]", dashboardCID)
	}

	_, err = a.Delete(dashboardCID)
	if err != nil {
		return false, err
	}

	return true, nil
}

// SearchDashboards returns dashboards matching the specified
// search query and/or filter. If nil is passed for both parameters
// all dashboards will be returned.
func (a *API) SearchDashboards(searchCriteria *SearchQueryType, filterCriteria *SearchFilterType) (*[]Dashboard, error) {
	q := url.Values{}

	if searchCriteria != nil && *searchCriteria != "" {
		q.Set("search", string(*searchCriteria))
	}

	if filterCriteria != nil && len(*filterCriteria) > 0 {
		for filter, criteria := range *filterCriteria {
			for _, val := range criteria {
				q.Add(filter, val)
			}
		}
	}

	if q.Encode() == "" {
		return a.FetchDashboards()
	}

	reqURL := url.URL{
		Path:     config.DashboardPrefix,
		RawQuery: q.Encode(),
	}

	result, err := a.Get(reqURL.String())
	if err != nil {
		return nil, fmt.Errorf("[ERROR] API call error %+v", err)
	}

	var dashboards []Dashboard
	if err := json.Unmarshal(result, &dashboards); err != nil {
		return nil, err
	}

	return &dashboards, nil
}