package sdk /* Copyright 2016 Alexander I.Grafov Copyright 2016-2019 The Grafana SDK authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ॐ तारे तुत्तारे तुरे स्व */ import ( "encoding/json" "errors" ) // Each panel may be one of these types. const ( CustomType panelType = iota DashlistType GraphType TableType TextType PluginlistType AlertlistType SinglestatType StatType RowType BarGaugeType HeatmapType ) const MixedSource = "-- Mixed --" type ( // Panel represents panels of different types defined in Grafana. Panel struct { CommonPanel // Should be initialized only one type of panels. // OfType field defines which of types below will be used. *GraphPanel *TablePanel *TextPanel *SinglestatPanel *StatPanel *DashlistPanel *PluginlistPanel *RowPanel *AlertlistPanel *BarGaugePanel *HeatmapPanel *CustomPanel } panelType int8 CommonPanel struct { Datasource *string `json:"datasource,omitempty"` // metrics Editable bool `json:"editable"` Error bool `json:"error"` GridPos struct { H *int `json:"h,omitempty"` W *int `json:"w,omitempty"` X *int `json:"x,omitempty"` Y *int `json:"y,omitempty"` } `json:"gridPos,omitempty"` Height interface{} `json:"height,omitempty"` // general HideTimeOverride *bool `json:"hideTimeOverride,omitempty"` ID uint `json:"id"` IsNew bool `json:"isNew"` Links []Link `json:"links,omitempty"` // general MinSpan *float32 `json:"minSpan,omitempty"` // templating options OfType panelType `json:"-"` // it required for defining type of the panel Renderer *string `json:"renderer,omitempty"` // display styles Repeat *string `json:"repeat,omitempty"` // templating options // RepeatIteration *int64 `json:"repeatIteration,omitempty"` RepeatPanelID *uint `json:"repeatPanelId,omitempty"` ScopedVars map[string]struct { Selected bool `json:"selected"` Text string `json:"text"` Value string `json:"value"` } `json:"scopedVars,omitempty"` Span float32 `json:"span"` // general Title string `json:"title"` // general Description *string `json:"description,omitempty"` // general Transparent bool `json:"transparent"` Type string `json:"type"` Alert *Alert `json:"alert,omitempty"` } AlertEvaluator struct { Params []float64 `json:"params,omitempty"` Type string `json:"type,omitempty"` } AlertOperator struct { Type string `json:"type,omitempty"` } AlertQuery struct { Params []string `json:"params,omitempty"` } AlertReducer struct { Params []string `json:"params,omitempty"` Type string `json:"type,omitempty"` } AlertCondition struct { Evaluator AlertEvaluator `json:"evaluator,omitempty"` Operator AlertOperator `json:"operator,omitempty"` Query AlertQuery `json:"query,omitempty"` Reducer AlertReducer `json:"reducer,omitempty"` Type string `json:"type,omitempty"` } Alert struct { AlertRuleTags map[string]string `json:"alertRuleTags,omitempty"` Conditions []AlertCondition `json:"conditions,omitempty"` ExecutionErrorState string `json:"executionErrorState,omitempty"` Frequency string `json:"frequency,omitempty"` Handler int `json:"handler,omitempty"` Name string `json:"name,omitempty"` NoDataState string `json:"noDataState,omitempty"` Notifications []AlertNotification `json:"notifications,omitempty"` Message string `json:"message,omitempty"` For string `json:"for,omitempty"` } GraphPanel struct { AliasColors interface{} `json:"aliasColors"` // XXX Bars bool `json:"bars"` DashLength *uint `json:"dashLength,omitempty"` Dashes *bool `json:"dashes,omitempty"` Decimals *uint `json:"decimals,omitempty"` Fill int `json:"fill"` // Grid grid `json:"grid"` obsoleted in 4.1 by xaxis and yaxis Legend Legend `json:"legend,omitempty"` LeftYAxisLabel *string `json:"leftYAxisLabel,omitempty"` Lines bool `json:"lines"` Linewidth uint `json:"linewidth"` NullPointMode string `json:"nullPointMode"` Percentage bool `json:"percentage"` Pointradius float32 `json:"pointradius"` Points bool `json:"points"` RightYAxisLabel *string `json:"rightYAxisLabel,omitempty"` SeriesOverrides []SeriesOverride `json:"seriesOverrides,omitempty"` SpaceLength *uint `json:"spaceLength,omitempty"` Stack bool `json:"stack"` SteppedLine bool `json:"steppedLine"` Targets []Target `json:"targets,omitempty"` Thresholds []Threshold `json:"thresholds,omitempty"` TimeFrom *string `json:"timeFrom,omitempty"` TimeShift *string `json:"timeShift,omitempty"` Tooltip Tooltip `json:"tooltip"` XAxis bool `json:"x-axis,omitempty"` YAxis bool `json:"y-axis,omitempty"` YFormats []string `json:"y_formats,omitempty"` Xaxis Axis `json:"xaxis"` // was added in Grafana 4.x? Yaxes []Axis `json:"yaxes"` // was added in Grafana 4.x? } FieldConfig struct { Defaults struct { Unit string `json:"unit"` Threshold struct { Mode string `json:"mode"` Steps []struct { Color string `json:"color"` Value string `json:"value"` } `json:"steps"` } `json:"threshold"` } `json:"defaults"` } Options struct { Orientation string `json:"orientation"` TextMode string `json:"textMode"` ColorMode string `json:"colorMode"` GraphMode string `json:"graphMode"` JustifyMode string `json:"justifyMode"` DisplayMode string `json:"displayMode"` Content string `json:"content"` Mode string `json:"mode"` ReduceOptions struct { Values bool `json:"values"` Fields string `json:"fields"` Calcs []string `json:"calcs"` } `json:"reduceOptions"` } Threshold struct { // the alert threshold value, we do not omitempty, since 0 is a valid // threshold Value float32 `json:"value"` // critical, warning, ok, custom ColorMode string `json:"colorMode,omitempty"` // gt or lt Op string `json:"op,omitempty"` Fill bool `json:"fill"` Line bool `json:"line"` // hexadecimal color (e.g. #629e51, only when ColorMode is "custom") FillColor string `json:"fillColor,omitempty"` // hexadecimal color (e.g. #629e51, only when ColorMode is "custom") LineColor string `json:"lineColor,omitempty"` // left or right Yaxis string `json:"yaxis,omitempty"` } Tooltip struct { Shared bool `json:"shared"` ValueType string `json:"value_type"` MsResolution bool `json:"msResolution,omitempty"` // was added in Grafana 3.x Sort int `json:"sort,omitempty"` } TablePanel struct { Columns []Column `json:"columns"` Sort *Sort `json:"sort,omitempty"` Styles []ColumnStyle `json:"styles"` Transform string `json:"transform"` Targets []Target `json:"targets,omitempty"` Scroll bool `json:"scroll"` // from grafana 3.x } TextPanel struct { Content string `json:"content"` Mode string `json:"mode"` PageSize uint `json:"pageSize"` Scroll bool `json:"scroll"` ShowHeader bool `json:"showHeader"` Sort Sort `json:"sort"` Styles []ColumnStyle `json:"styles"` FieldConfig FieldConfig `json:"fieldConfig"` Options struct { Content string `json:"content"` Mode string `json:"mode"` } `json:"options"` } SinglestatPanel struct { Colors []string `json:"colors"` ColorValue bool `json:"colorValue"` ColorBackground bool `json:"colorBackground"` Decimals int `json:"decimals"` Format string `json:"format"` Gauge Gauge `json:"gauge,omitempty"` MappingType *uint `json:"mappingType,omitempty"` MappingTypes []*MapType `json:"mappingTypes,omitempty"` MaxDataPoints *IntString `json:"maxDataPoints,omitempty"` NullPointMode string `json:"nullPointMode"` Postfix *string `json:"postfix,omitempty"` PostfixFontSize *string `json:"postfixFontSize,omitempty"` Prefix *string `json:"prefix,omitempty"` PrefixFontSize *string `json:"prefixFontSize,omitempty"` RangeMaps []*RangeMap `json:"rangeMaps,omitempty"` SparkLine SparkLine `json:"sparkline,omitempty"` Targets []Target `json:"targets,omitempty"` Thresholds string `json:"thresholds"` ValueFontSize string `json:"valueFontSize"` ValueMaps []ValueMap `json:"valueMaps"` ValueName string `json:"valueName"` } StatPanel struct { Colors []string `json:"colors"` ColorValue bool `json:"colorValue"` ColorBackground bool `json:"colorBackground"` Decimals int `json:"decimals"` Format string `json:"format"` Gauge Gauge `json:"gauge,omitempty"` MappingType *uint `json:"mappingType,omitempty"` MappingTypes []*MapType `json:"mappingTypes,omitempty"` MaxDataPoints *IntString `json:"maxDataPoints,omitempty"` NullPointMode string `json:"nullPointMode"` Postfix *string `json:"postfix,omitempty"` PostfixFontSize *string `json:"postfixFontSize,omitempty"` Prefix *string `json:"prefix,omitempty"` PrefixFontSize *string `json:"prefixFontSize,omitempty"` RangeMaps []*RangeMap `json:"rangeMaps,omitempty"` SparkLine SparkLine `json:"sparkline,omitempty"` Targets []Target `json:"targets,omitempty"` Thresholds string `json:"thresholds"` ValueFontSize string `json:"valueFontSize"` ValueMaps []ValueMap `json:"valueMaps"` ValueName string `json:"valueName"` Options Options `json:"options"` } DashlistPanel struct { Mode string `json:"mode"` Query string `json:"query"` Tags []string `json:"tags"` FolderID int `json:"folderId"` Limit int `json:"limit"` Headings bool `json:"headings"` Recent bool `json:"recent"` Search bool `json:"search"` Starred bool `json:"starred"` } PluginlistPanel struct { Limit int `json:"limit,omitempty"` } AlertlistPanel struct { OnlyAlertsOnDashboard bool `json:"onlyAlertsOnDashboard"` Show string `json:"show"` SortOrder int `json:"sortOrder"` Limit int `json:"limit"` StateFilter []string `json:"stateFilter"` NameFilter string `json:"nameFilter,omitempty"` DashboardTags []string `json:"dashboardTags,omitempty"` } BarGaugePanel struct { Options Options `json:"options"` Targets []Target `json:"targets,omitempty"` FieldConfig FieldConfig `json:"fieldConfig"` } RowPanel struct { Panels []Panel `json:"panels"` Collapsed bool `json:"collapsed"` } HeatmapPanel struct { Cards struct { CardPadding *float64 `json:"cardPadding"` CardRound *float64 `json:"cardRound"` } `json:"cards"` Color struct { CardColor string `json:"cardColor"` ColorScale string `json:"colorScale"` ColorScheme string `json:"colorScheme"` Exponent float64 `json:"exponent"` Min *float64 `json:"min,omitempty"` Max *float64 `json:"max,omitempty"` Mode string `json:"mode"` } `json:"color"` DataFormat string `json:"dataFormat"` HideZeroBuckets bool `json:"hideZeroBuckets"` HighlightCards bool `json:"highlightCards"` Legend struct { Show bool `json:"show"` } `json:"legend"` ReverseYBuckets bool `json:"reverseYBuckets"` Targets []Target `json:"targets,omitempty"` Tooltip struct { Show bool `json:"show"` ShowHistogram bool `json:"showHistogram"` } `json:"tooltip"` TooltipDecimals int `json:"tooltipDecimals"` XAxis struct { Show bool `json:"show"` } `json:"xAxis"` XBucketNumber *float64 `json:"xBucketNumber"` XBucketSize *string `json:"xBucketSize"` YAxis struct { Decimals *int `json:"decimals"` Format string `json:"format"` LogBase int `json:"logBase"` Show bool `json:"show"` Max *string `json:"max"` Min *string `json:"min"` SplitFactor *float64 `json:"splitFactor"` } `json:"yAxis"` YBucketBound string `json:"yBucketBound"` YBucketNumber *float64 `json:"yBucketNumber"` YBucketSize *float64 `json:"yBucketSize"` } CustomPanel map[string]interface{} ) // for a graph panel type ( // TODO look at schema versions carefully // grid was obsoleted by xaxis and yaxes grid struct { //nolint: unused,deadcode LeftLogBase *int `json:"leftLogBase"` LeftMax *int `json:"leftMax"` LeftMin *int `json:"leftMin"` RightLogBase *int `json:"rightLogBase"` RightMax *int `json:"rightMax"` RightMin *int `json:"rightMin"` Threshold1 *float64 `json:"threshold1"` Threshold1Color string `json:"threshold1Color"` Threshold2 *float64 `json:"threshold2"` Threshold2Color string `json:"threshold2Color"` ThresholdLine bool `json:"thresholdLine"` } xaxis struct { //nolint:unused,deadcode Mode string `json:"mode"` Name interface{} `json:"name"` // TODO what is this? Show bool `json:"show"` Values *[]string `json:"values,omitempty"` } Axis struct { Format string `json:"format"` LogBase int `json:"logBase"` Decimals int `json:"decimals,omitempty"` Max *FloatString `json:"max,omitempty"` Min *FloatString `json:"min,omitempty"` Show bool `json:"show"` Label string `json:"label,omitempty"` } SeriesOverride struct { Alias string `json:"alias"` Bars *bool `json:"bars,omitempty"` Color *string `json:"color,omitempty"` Dashes *bool `json:"dashes,omitempty"` Fill *int `json:"fill,omitempty"` FillBelowTo *string `json:"fillBelowTo,omitempty"` Legend *bool `json:"legend,omitempty"` Lines *bool `json:"lines,omitempty"` LineWidth *int `json:"linewidth,omitempty"` Stack *BoolString `json:"stack,omitempty"` Transform *string `json:"transform,omitempty"` YAxis *int `json:"yaxis,omitempty"` ZIndex *int `json:"zindex,omitempty"` NullPointMode *string `json:"nullPointMode,omitempty"` } Sort struct { Col int `json:"col"` Desc bool `json:"desc"` } Legend struct { AlignAsTable bool `json:"alignAsTable"` Avg bool `json:"avg"` Current bool `json:"current"` HideEmpty bool `json:"hideEmpty"` HideZero bool `json:"hideZero"` Max bool `json:"max"` Min bool `json:"min"` RightSide bool `json:"rightSide"` Show bool `json:"show"` SideWidth *uint `json:"sideWidth,omitempty"` Total bool `json:"total"` Values bool `json:"values"` } ) // for a table type ( Column struct { TextType string `json:"text"` Value string `json:"value"` } ColumnStyle struct { Alias *string `json:"alias"` DateFormat *string `json:"dateFormat,omitempty"` Pattern string `json:"pattern"` Type string `json:"type"` ColorMode *string `json:"colorMode,omitempty"` Colors *[]string `json:"colors,omitempty"` Decimals *uint `json:"decimals,omitempty"` Thresholds *[]string `json:"thresholds,omitempty"` Unit *string `json:"unit,omitempty"` MappingType int `json:"mappingType,omitempty"` ValueMaps []ValueMap `json:"valueMaps,omitempty"` Link bool `json:"link,omitempty"` LinkTooltip *string `json:"linkTooltip,omitempty"` LinkUrl *string `json:"linkUrl,omitempty"` LinkTargetBlank bool `json:"linkTargetBlank,omitempty"` } ) // for a stat type ( ValueMap struct { Op string `json:"op"` TextType string `json:"text"` Value string `json:"value"` } Gauge struct { MaxValue float32 `json:"maxValue"` MinValue float32 `json:"minValue"` Show bool `json:"show"` ThresholdLabels bool `json:"thresholdLabels"` ThresholdMarkers bool `json:"thresholdMarkers"` } SparkLine struct { FillColor *string `json:"fillColor,omitempty"` Full bool `json:"full,omitempty"` LineColor *string `json:"lineColor,omitempty"` Show bool `json:"show,omitempty"` YMin *float64 `json:"ymin,omitempty"` YMax *float64 `json:"ymax,omitempty"` } ) // for an any panel type Target struct { RefID string `json:"refId"` Datasource string `json:"datasource,omitempty"` Hide bool `json:"hide,omitempty"` // For PostgreSQL Table string `json:"table,omitempty"` TimeColumn string `json:"timeColumn,omitempty"` MetricColumn string `json:"metricColumn,omitempty"` RawSql string `json:"rawSql,omitempty"` Select [][]struct { Params []string `json:"params,omitempty"` Type string `json:"type,omitempty"` } `json:"select,omitempty"` Where []struct { Type string `json:"type,omitempty"` Name string `json:"name,omitempty"` Params []string `json:"params,omitempty"` Datatype string `json:"datatype,omitempty"` } `json:"where,omitempty"` Group []struct { Type string `json:"type,omitempty"` Params []string `json:"params,omitempty"` } `json:"group,omitempty"` // For Prometheus Expr string `json:"expr,omitempty"` IntervalFactor int `json:"intervalFactor,omitempty"` Interval string `json:"interval,omitempty"` Step int `json:"step,omitempty"` LegendFormat string `json:"legendFormat,omitempty"` Instant bool `json:"instant,omitempty"` Format string `json:"format,omitempty"` // For InfluxDB Measurement string `json:"measurement,omitempty"` // For Elasticsearch DsType *string `json:"dsType,omitempty"` Metrics []struct { ID string `json:"id"` Field string `json:"field"` Type string `json:"type"` } `json:"metrics,omitempty"` Query string `json:"query,omitempty"` Alias string `json:"alias,omitempty"` RawQuery bool `json:"rawQuery,omitempty"` TimeField string `json:"timeField,omitempty"` BucketAggs []struct { ID string `json:"id"` Field string `json:"field"` Type string `json:"type"` Settings struct { Interval string `json:"interval,omitempty"` MinDocCount interface{} `json:"min_doc_count"` Order string `json:"order,omitempty"` OrderBy string `json:"orderBy,omitempty"` Size string `json:"size,omitempty"` } `json:"settings"` } `json:"bucketAggs,omitempty"` // For Graphite Target string `json:"target,omitempty"` // For CloudWatch Namespace string `json:"namespace,omitempty"` MetricName string `json:"metricName,omitempty"` Statistics []string `json:"statistics,omitempty"` Dimensions map[string]string `json:"dimensions,omitempty"` Period string `json:"period,omitempty"` Region string `json:"region,omitempty"` // For the Stackdriver data source. Find out more information at // https:/grafana.com/docs/grafana/v6.0/features/datasources/stackdriver/ ProjectName string `json:"projectName,omitempty"` AlignOptions []StackdriverAlignOptions `json:"alignOptions,omitempty"` AliasBy string `json:"aliasBy,omitempty"` MetricType string `json:"metricType,omitempty"` MetricKind string `json:"metricKind,omitempty"` Filters []string `json:"filters,omitempty"` AlignmentPeriod string `json:"alignmentPeriod,omitempty"` CrossSeriesReducer string `json:"crossSeriesReducer,omitempty"` PerSeriesAligner string `json:"perSeriesAligner,omitempty"` ValueType string `json:"valueType,omitempty"` GroupBys []string `json:"groupBys,omitempty"` } // StackdriverAlignOptions defines the list of alignment options shown in // Grafana during query configuration. type StackdriverAlignOptions struct { Expanded bool `json:"expanded"` Label string `json:"label"` Options []StackdriverAlignOption `json:"options"` } // StackdriverAlignOption defines a single alignment option shown in Grafana // during query configuration. type StackdriverAlignOption struct { Label string `json:"label"` MetricKinds []string `json:"metricKinds"` Text string `json:"text"` Value string `json:"value"` ValueTypes []string `json:"valueTypes"` } type MapType struct { Name *string `json:"name,omitempty"` Value *int `json:"value,omitempty"` } type RangeMap struct { From *string `json:"from,omitempty"` Text *string `json:"text,omitempty"` To *string `json:"to,omitempty"` } // NewDashlist initializes panel with a dashlist panel. func NewDashlist(title string) *Panel { if title == "" { title = "Panel Title" } render := "flot" return &Panel{ CommonPanel: CommonPanel{ OfType: DashlistType, Title: title, Type: "dashlist", Renderer: &render, IsNew: true}, DashlistPanel: &DashlistPanel{}} } // NewGraph initializes panel with a graph panel. func NewGraph(title string) *Panel { if title == "" { title = "Panel Title" } render := "flot" return &Panel{ CommonPanel: CommonPanel{ OfType: GraphType, Title: title, Type: "graph", Renderer: &render, Span: 12, IsNew: true}, GraphPanel: &GraphPanel{ NullPointMode: "connected", Pointradius: 5, XAxis: true, YAxis: true, }} } // NewTable initializes panel with a table panel. func NewTable(title string) *Panel { if title == "" { title = "Panel Title" } render := "flot" return &Panel{ CommonPanel: CommonPanel{ OfType: TableType, Title: title, Type: "table", Renderer: &render, IsNew: true}, TablePanel: &TablePanel{}} } // NewText initializes panel with a text panel. func NewText(title string) *Panel { if title == "" { title = "Panel Title" } render := "flot" return &Panel{ CommonPanel: CommonPanel{ OfType: TextType, Title: title, Type: "text", Renderer: &render, IsNew: true}, TextPanel: &TextPanel{}} } // NewSinglestat initializes panel with a singlestat panel. func NewSinglestat(title string) *Panel { if title == "" { title = "Panel Title" } render := "flot" return &Panel{ CommonPanel: CommonPanel{ OfType: SinglestatType, Title: title, Type: "singlestat", Renderer: &render, IsNew: true}, SinglestatPanel: &SinglestatPanel{}} } // NewStat initializes panel with a stat panel. func NewStat(title string) *Panel { if title == "" { title = "Panel Title" } render := "flot" return &Panel{ CommonPanel: CommonPanel{ OfType: StatType, Title: title, Type: "stat", Renderer: &render, IsNew: true}, StatPanel: &StatPanel{}} } // NewPluginlist initializes panel with a stat panel. func NewPluginlist(title string) *Panel { if title == "" { title = "Panel Title" } render := "flot" return &Panel{ CommonPanel: CommonPanel{ OfType: PluginlistType, Title: title, Type: "pluginlist", Renderer: &render, IsNew: true}, PluginlistPanel: &PluginlistPanel{}} } func NewAlertlist(title string) *Panel { if title == "" { title = "Panel Title" } render := "flot" return &Panel{ CommonPanel: CommonPanel{ OfType: AlertlistType, Title: title, Type: "alertlist", Renderer: &render, IsNew: true}, AlertlistPanel: &AlertlistPanel{}} } func NewHeatmap(title string) *Panel { if title == "" { title = "Panel Title" } render := "flot" return &Panel{ CommonPanel: CommonPanel{ OfType: HeatmapType, Title: title, Type: "heatmap", Renderer: &render, IsNew: true}, HeatmapPanel: &HeatmapPanel{}} } // NewCustom initializes panel with a stat panel. func NewCustom(title string) *Panel { if title == "" { title = "Panel Title" } render := "flot" return &Panel{ CommonPanel: CommonPanel{ OfType: CustomType, Title: title, Type: "singlestat", Renderer: &render, IsNew: true}, CustomPanel: &CustomPanel{}} } // ResetTargets delete all targets defined for a panel. func (p *Panel) ResetTargets() { switch p.OfType { case GraphType: p.GraphPanel.Targets = nil case SinglestatType: p.SinglestatPanel.Targets = nil case StatType: p.StatPanel.Targets = nil case TableType: p.TablePanel.Targets = nil case BarGaugeType: p.BarGaugePanel.Targets = nil case HeatmapType: p.HeatmapPanel.Targets = nil } } // AddTarget adds a new target as defined in the argument // but with refId letter incremented. Value of refID from // the argument will be used only if no target with such // value already exists. func (p *Panel) AddTarget(t *Target) { switch p.OfType { case GraphType: p.GraphPanel.Targets = append(p.GraphPanel.Targets, *t) case SinglestatType: p.SinglestatPanel.Targets = append(p.SinglestatPanel.Targets, *t) case StatType: p.StatPanel.Targets = append(p.StatPanel.Targets, *t) case TableType: p.TablePanel.Targets = append(p.TablePanel.Targets, *t) case HeatmapType: p.HeatmapPanel.Targets = append(p.HeatmapPanel.Targets, *t) } // TODO check for existing refID } // SetTarget updates a target if target with such refId exists // or creates a new one. func (p *Panel) SetTarget(t *Target) { setTarget := func(t *Target, targets *[]Target) { for i, target := range *targets { if t.RefID == target.RefID { (*targets)[i] = *t return } } (*targets) = append((*targets), *t) } switch p.OfType { case GraphType: setTarget(t, &p.GraphPanel.Targets) case SinglestatType: setTarget(t, &p.SinglestatPanel.Targets) case StatType: setTarget(t, &p.StatPanel.Targets) case TableType: setTarget(t, &p.TablePanel.Targets) case HeatmapType: setTarget(t, &p.HeatmapPanel.Targets) } } // MapDatasources on all existing targets for the panel. func (p *Panel) RepeatDatasourcesForEachTarget(dsNames ...string) { repeatDS := func(dsNames []string, targets *[]Target) { var refID = "A" originalTargets := *targets cleanedTargets := make([]Target, 0, len(originalTargets)*len(dsNames)) *targets = cleanedTargets for _, target := range originalTargets { for _, ds := range dsNames { newTarget := target newTarget.RefID = refID newTarget.Datasource = ds refID = incRefID(refID) *targets = append(*targets, newTarget) } } } switch p.OfType { case GraphType: repeatDS(dsNames, &p.GraphPanel.Targets) case SinglestatType: repeatDS(dsNames, &p.SinglestatPanel.Targets) case StatType: repeatDS(dsNames, &p.StatPanel.Targets) case TableType: repeatDS(dsNames, &p.TablePanel.Targets) case HeatmapType: repeatDS(dsNames, &p.HeatmapPanel.Targets) } } // RepeatTargetsForDatasources repeats all existing targets for a panel // for all provided in the argument datasources. Existing datasources of // targets are ignored. func (p *Panel) RepeatTargetsForDatasources(dsNames ...string) { repeatTarget := func(dsNames []string, targets *[]Target) { var lastRefID string lenTargets := len(*targets) for i, name := range dsNames { if i < lenTargets { (*targets)[i].Datasource = name lastRefID = (*targets)[i].RefID } else { newTarget := (*targets)[i%lenTargets] lastRefID = incRefID(lastRefID) newTarget.RefID = lastRefID newTarget.Datasource = name *targets = append(*targets, newTarget) } } } switch p.OfType { case GraphType: repeatTarget(dsNames, &p.GraphPanel.Targets) case SinglestatType: repeatTarget(dsNames, &p.SinglestatPanel.Targets) case StatType: repeatTarget(dsNames, &p.StatPanel.Targets) case TableType: repeatTarget(dsNames, &p.TablePanel.Targets) case HeatmapType: repeatTarget(dsNames, &p.HeatmapPanel.Targets) } } // GetTargets is iterate over all panel targets. It just returns nil if // no targets defined for panel of concrete type. func (p *Panel) GetTargets() *[]Target { switch p.OfType { case GraphType: return &p.GraphPanel.Targets case SinglestatType: return &p.SinglestatPanel.Targets case StatType: return &p.StatPanel.Targets case TableType: return &p.TablePanel.Targets case BarGaugeType: return &p.BarGaugePanel.Targets case HeatmapType: return &p.HeatmapPanel.Targets default: return nil } } type probePanel struct { CommonPanel // json.RawMessage } func (p *Panel) UnmarshalJSON(b []byte) (err error) { var probe probePanel if err = json.Unmarshal(b, &probe); err == nil { p.CommonPanel = probe.CommonPanel switch probe.Type { case "graph": var graph GraphPanel p.OfType = GraphType if err = json.Unmarshal(b, &graph); err == nil { p.GraphPanel = &graph } case "table": var table TablePanel p.OfType = TableType if err = json.Unmarshal(b, &table); err == nil { p.TablePanel = &table } case "text": var text TextPanel p.OfType = TextType if err = json.Unmarshal(b, &text); err == nil { p.TextPanel = &text } case "singlestat": var singlestat SinglestatPanel p.OfType = SinglestatType if err = json.Unmarshal(b, &singlestat); err == nil { p.SinglestatPanel = &singlestat } case "stat": var stat StatPanel p.OfType = StatType if err = json.Unmarshal(b, &stat); err == nil { p.StatPanel = &stat } case "dashlist": var dashlist DashlistPanel p.OfType = DashlistType if err = json.Unmarshal(b, &dashlist); err == nil { p.DashlistPanel = &dashlist } case "bargauge": var bargauge BarGaugePanel p.OfType = BarGaugeType if err = json.Unmarshal(b, &bargauge); err == nil { p.BarGaugePanel = &bargauge } case "heatmap": var heatmap HeatmapPanel p.OfType = HeatmapType if err = json.Unmarshal(b, &heatmap); err == nil { p.HeatmapPanel = &heatmap } case "row": var rowpanel RowPanel p.OfType = RowType if err = json.Unmarshal(b, &rowpanel); err == nil { p.RowPanel = &rowpanel } default: var custom = make(CustomPanel) p.OfType = CustomType if err = json.Unmarshal(b, &custom); err == nil { p.CustomPanel = &custom } } } return } func (p *Panel) MarshalJSON() ([]byte, error) { switch p.OfType { case GraphType: var outGraph = struct { CommonPanel GraphPanel }{p.CommonPanel, *p.GraphPanel} return json.Marshal(outGraph) case TableType: var outTable = struct { CommonPanel TablePanel }{p.CommonPanel, *p.TablePanel} return json.Marshal(outTable) case TextType: var outText = struct { CommonPanel TextPanel }{p.CommonPanel, *p.TextPanel} return json.Marshal(outText) case SinglestatType: var outSinglestat = struct { CommonPanel SinglestatPanel }{p.CommonPanel, *p.SinglestatPanel} return json.Marshal(outSinglestat) case StatType: var outSinglestat = struct { CommonPanel StatPanel }{p.CommonPanel, *p.StatPanel} return json.Marshal(outSinglestat) case DashlistType: var outDashlist = struct { CommonPanel DashlistPanel }{p.CommonPanel, *p.DashlistPanel} return json.Marshal(outDashlist) case BarGaugeType: var outBarGauge = struct { CommonPanel BarGaugePanel }{p.CommonPanel, *p.BarGaugePanel} return json.Marshal(outBarGauge) case PluginlistType: var outPluginlist = struct { CommonPanel PluginlistPanel }{p.CommonPanel, *p.PluginlistPanel} return json.Marshal(outPluginlist) case AlertlistType: var outAlertlist = struct { CommonPanel AlertlistPanel }{p.CommonPanel, *p.AlertlistPanel} return json.Marshal(outAlertlist) case RowType: var outRow = struct { CommonPanel RowPanel }{p.CommonPanel, *p.RowPanel} return json.Marshal(outRow) case HeatmapType: var outHeatmap = struct { CommonPanel HeatmapPanel }{p.CommonPanel, *p.HeatmapPanel} return json.Marshal(outHeatmap) case CustomType: var outCustom = struct { CommonPanel CustomPanel }{p.CommonPanel, *p.CustomPanel} return json.Marshal(outCustom) } return nil, errors.New("can't marshal unknown panel type") } func incRefID(refID string) string { firstLetter := refID[0] ordinal := int(firstLetter) ordinal++ return string(rune(ordinal)) }