Expressions: Create json schema for query types (#84032)
This commit is contained in:
@@ -26,7 +26,7 @@ func (s *Service) handleCsvContentScenario(ctx context.Context, req *backend.Que
|
||||
return nil, fmt.Errorf("failed to parse query json: %v", err)
|
||||
}
|
||||
|
||||
csvContent := model.CSVContent
|
||||
csvContent := model.CsvContent
|
||||
if len(csvContent) == 0 {
|
||||
return backend.NewQueryDataResponse(), nil
|
||||
}
|
||||
@@ -63,7 +63,7 @@ func (s *Service) handleCsvFileScenario(ctx context.Context, req *backend.QueryD
|
||||
return nil, fmt.Errorf("failed to parse query json %v", err)
|
||||
}
|
||||
|
||||
fileName := model.CSVFileName
|
||||
fileName := model.CsvFileName
|
||||
|
||||
if len(fileName) == 0 {
|
||||
continue
|
||||
|
||||
@@ -1,211 +0,0 @@
|
||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||
//
|
||||
// Generated by:
|
||||
// public/app/plugins/gen.go
|
||||
// Using jennies:
|
||||
// PluginGoTypesJenny
|
||||
//
|
||||
// Run 'make gen-cue' from repository root to regenerate.
|
||||
|
||||
package dataquery
|
||||
|
||||
// Defines values for NodesQueryType.
|
||||
const (
|
||||
NodesQueryTypeFeatureShowcase NodesQueryType = "feature_showcase"
|
||||
NodesQueryTypeRandom NodesQueryType = "random"
|
||||
NodesQueryTypeRandomEdges NodesQueryType = "random edges"
|
||||
NodesQueryTypeResponseMedium NodesQueryType = "response_medium"
|
||||
NodesQueryTypeResponseSmall NodesQueryType = "response_small"
|
||||
)
|
||||
|
||||
// Defines values for StreamingQueryType.
|
||||
const (
|
||||
StreamingQueryTypeFetch StreamingQueryType = "fetch"
|
||||
StreamingQueryTypeLogs StreamingQueryType = "logs"
|
||||
StreamingQueryTypeSignal StreamingQueryType = "signal"
|
||||
StreamingQueryTypeTraces StreamingQueryType = "traces"
|
||||
)
|
||||
|
||||
// Defines values for TestDataDataQueryErrorType.
|
||||
const (
|
||||
TestDataDataQueryErrorTypeFrontendException TestDataDataQueryErrorType = "frontend_exception"
|
||||
TestDataDataQueryErrorTypeFrontendObservable TestDataDataQueryErrorType = "frontend_observable"
|
||||
TestDataDataQueryErrorTypeServerPanic TestDataDataQueryErrorType = "server_panic"
|
||||
)
|
||||
|
||||
// Defines values for TestDataQueryType.
|
||||
const (
|
||||
TestDataQueryTypeAnnotations TestDataQueryType = "annotations"
|
||||
TestDataQueryTypeArrow TestDataQueryType = "arrow"
|
||||
TestDataQueryTypeCsvContent TestDataQueryType = "csv_content"
|
||||
TestDataQueryTypeCsvFile TestDataQueryType = "csv_file"
|
||||
TestDataQueryTypeCsvMetricValues TestDataQueryType = "csv_metric_values"
|
||||
TestDataQueryTypeDatapointsOutsideRange TestDataQueryType = "datapoints_outside_range"
|
||||
TestDataQueryTypeExponentialHeatmapBucketData TestDataQueryType = "exponential_heatmap_bucket_data"
|
||||
TestDataQueryTypeFlameGraph TestDataQueryType = "flame_graph"
|
||||
TestDataQueryTypeGrafanaApi TestDataQueryType = "grafana_api"
|
||||
TestDataQueryTypeLinearHeatmapBucketData TestDataQueryType = "linear_heatmap_bucket_data"
|
||||
TestDataQueryTypeLive TestDataQueryType = "live"
|
||||
TestDataQueryTypeLogs TestDataQueryType = "logs"
|
||||
TestDataQueryTypeManualEntry TestDataQueryType = "manual_entry"
|
||||
TestDataQueryTypeNoDataPoints TestDataQueryType = "no_data_points"
|
||||
TestDataQueryTypeNodeGraph TestDataQueryType = "node_graph"
|
||||
TestDataQueryTypePredictableCsvWave TestDataQueryType = "predictable_csv_wave"
|
||||
TestDataQueryTypePredictablePulse TestDataQueryType = "predictable_pulse"
|
||||
TestDataQueryTypeRandomWalk TestDataQueryType = "random_walk"
|
||||
TestDataQueryTypeRandomWalkTable TestDataQueryType = "random_walk_table"
|
||||
TestDataQueryTypeRandomWalkWithError TestDataQueryType = "random_walk_with_error"
|
||||
TestDataQueryTypeRawFrame TestDataQueryType = "raw_frame"
|
||||
TestDataQueryTypeServerError500 TestDataQueryType = "server_error_500"
|
||||
TestDataQueryTypeSimulation TestDataQueryType = "simulation"
|
||||
TestDataQueryTypeSlowQuery TestDataQueryType = "slow_query"
|
||||
TestDataQueryTypeStreamingClient TestDataQueryType = "streaming_client"
|
||||
TestDataQueryTypeTableStatic TestDataQueryType = "table_static"
|
||||
TestDataQueryTypeTrace TestDataQueryType = "trace"
|
||||
TestDataQueryTypeUsa TestDataQueryType = "usa"
|
||||
TestDataQueryTypeVariablesQuery TestDataQueryType = "variables-query"
|
||||
)
|
||||
|
||||
// CSVWave defines model for CSVWave.
|
||||
type CSVWave struct {
|
||||
Labels *string `json:"labels,omitempty"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
TimeStep *int64 `json:"timeStep,omitempty"`
|
||||
ValuesCSV *string `json:"valuesCSV,omitempty"`
|
||||
}
|
||||
|
||||
// These are the common properties available to all queries in all datasources.
|
||||
// Specific implementations will *extend* this interface, adding the required
|
||||
// properties for the given context.
|
||||
type DataQuery struct {
|
||||
// For mixed data sources the selected datasource is on the query level.
|
||||
// For non mixed scenarios this is undefined.
|
||||
// TODO find a better way to do this ^ that's friendly to schema
|
||||
// TODO this shouldn't be unknown but DataSourceRef | null
|
||||
Datasource *any `json:"datasource,omitempty"`
|
||||
|
||||
// If hide is set to true, Grafana will filter out the response(s) associated with this query before returning it to the panel.
|
||||
Hide *bool `json:"hide,omitempty"`
|
||||
|
||||
// Specify the query flavor
|
||||
// TODO make this required and give it a default
|
||||
QueryType *string `json:"queryType,omitempty"`
|
||||
|
||||
// A unique identifier for the query within the list of targets.
|
||||
// In server side expressions, the refId is used as a variable name to identify results.
|
||||
// By default, the UI will assign A->Z; however setting meaningful names may be useful.
|
||||
RefId string `json:"refId"`
|
||||
}
|
||||
|
||||
// NodesQuery defines model for NodesQuery.
|
||||
type NodesQuery struct {
|
||||
Count *int64 `json:"count,omitempty"`
|
||||
Seed *int64 `json:"seed,omitempty"`
|
||||
Type *NodesQueryType `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
// NodesQueryType defines model for NodesQuery.Type.
|
||||
type NodesQueryType string
|
||||
|
||||
// PulseWaveQuery defines model for PulseWaveQuery.
|
||||
type PulseWaveQuery struct {
|
||||
OffCount *int64 `json:"offCount,omitempty"`
|
||||
OffValue *float64 `json:"offValue,omitempty"`
|
||||
OnCount *int64 `json:"onCount,omitempty"`
|
||||
OnValue *float64 `json:"onValue,omitempty"`
|
||||
TimeStep *int64 `json:"timeStep,omitempty"`
|
||||
}
|
||||
|
||||
// TODO: Should this live here given it's not used in the dataquery?
|
||||
type Scenario struct {
|
||||
Description *string `json:"description,omitempty"`
|
||||
HideAliasField *bool `json:"hideAliasField,omitempty"`
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
StringInput string `json:"stringInput"`
|
||||
}
|
||||
|
||||
// SimulationQuery defines model for SimulationQuery.
|
||||
type SimulationQuery struct {
|
||||
Config map[string]any `json:"config,omitempty"`
|
||||
Key struct {
|
||||
Tick float64 `json:"tick"`
|
||||
Type string `json:"type"`
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
} `json:"key"`
|
||||
Last *bool `json:"last,omitempty"`
|
||||
Stream *bool `json:"stream,omitempty"`
|
||||
}
|
||||
|
||||
// StreamingQuery defines model for StreamingQuery.
|
||||
type StreamingQuery struct {
|
||||
Bands *int32 `json:"bands,omitempty"`
|
||||
Noise int32 `json:"noise"`
|
||||
Speed int32 `json:"speed"`
|
||||
Spread int32 `json:"spread"`
|
||||
Type StreamingQueryType `json:"type"`
|
||||
Url *string `json:"url,omitempty"`
|
||||
}
|
||||
|
||||
// StreamingQueryType defines model for StreamingQuery.Type.
|
||||
type StreamingQueryType string
|
||||
|
||||
// TestDataDataQuery defines model for TestDataDataQuery.
|
||||
type TestDataDataQuery struct {
|
||||
Alias *string `json:"alias,omitempty"`
|
||||
Channel *string `json:"channel,omitempty"`
|
||||
CsvContent *string `json:"csvContent,omitempty"`
|
||||
CsvFileName *string `json:"csvFileName,omitempty"`
|
||||
CsvWave []CSVWave `json:"csvWave,omitempty"`
|
||||
|
||||
// For mixed data sources the selected datasource is on the query level.
|
||||
// For non mixed scenarios this is undefined.
|
||||
// TODO find a better way to do this ^ that's friendly to schema
|
||||
// TODO this shouldn't be unknown but DataSourceRef | null
|
||||
Datasource *any `json:"datasource,omitempty"`
|
||||
|
||||
// Drop percentage (the chance we will lose a point 0-100)
|
||||
DropPercent *float64 `json:"dropPercent,omitempty"`
|
||||
ErrorType *TestDataDataQueryErrorType `json:"errorType,omitempty"`
|
||||
FlamegraphDiff *bool `json:"flamegraphDiff,omitempty"`
|
||||
|
||||
// If hide is set to true, Grafana will filter out the response(s) associated with this query before returning it to the panel.
|
||||
Hide *bool `json:"hide,omitempty"`
|
||||
Labels *string `json:"labels,omitempty"`
|
||||
LevelColumn *bool `json:"levelColumn,omitempty"`
|
||||
Lines *int64 `json:"lines,omitempty"`
|
||||
Nodes *NodesQuery `json:"nodes,omitempty"`
|
||||
Points [][]any `json:"points,omitempty"`
|
||||
PulseWave *PulseWaveQuery `json:"pulseWave,omitempty"`
|
||||
|
||||
// Specify the query flavor
|
||||
// TODO make this required and give it a default
|
||||
QueryType *string `json:"queryType,omitempty"`
|
||||
RawFrameContent *string `json:"rawFrameContent,omitempty"`
|
||||
|
||||
// A unique identifier for the query within the list of targets.
|
||||
// In server side expressions, the refId is used as a variable name to identify results.
|
||||
// By default, the UI will assign A->Z; however setting meaningful names may be useful.
|
||||
RefId *string `json:"refId,omitempty"`
|
||||
ScenarioId *TestDataQueryType `json:"scenarioId,omitempty"`
|
||||
SeriesCount *int32 `json:"seriesCount,omitempty"`
|
||||
Sim *SimulationQuery `json:"sim,omitempty"`
|
||||
SpanCount *int32 `json:"spanCount,omitempty"`
|
||||
Stream *StreamingQuery `json:"stream,omitempty"`
|
||||
StringInput *string `json:"stringInput,omitempty"`
|
||||
Usa *USAQuery `json:"usa,omitempty"`
|
||||
}
|
||||
|
||||
// TestDataDataQueryErrorType defines model for TestDataDataQuery.ErrorType.
|
||||
type TestDataDataQueryErrorType string
|
||||
|
||||
// TestDataQueryType defines model for TestDataQueryType.
|
||||
type TestDataQueryType string
|
||||
|
||||
// USAQuery defines model for USAQuery.
|
||||
type USAQuery struct {
|
||||
Fields []string `json:"fields,omitempty"`
|
||||
Mode *string `json:"mode,omitempty"`
|
||||
Period *string `json:"period,omitempty"`
|
||||
States []string `json:"states,omitempty"`
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
package kinds
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// NodesQueryType defines model for NodesQuery.Type.
|
||||
// +enum
|
||||
type NodesQueryType string
|
||||
|
||||
const (
|
||||
NodesQueryTypeRandom NodesQueryType = "random"
|
||||
NodesQueryTypeRandomEdges NodesQueryType = "random edges"
|
||||
NodesQueryTypeResponseMedium NodesQueryType = "response_medium"
|
||||
NodesQueryTypeResponseSmall NodesQueryType = "response_small"
|
||||
NodesQueryTypeFeatureShowcase NodesQueryType = "feature_showcase"
|
||||
)
|
||||
|
||||
// StreamingQueryType defines model for StreamingQuery.Type.
|
||||
// +enum
|
||||
type StreamingQueryType string
|
||||
|
||||
const (
|
||||
StreamingQueryTypeFetch StreamingQueryType = "fetch"
|
||||
StreamingQueryTypeLogs StreamingQueryType = "logs"
|
||||
StreamingQueryTypeSignal StreamingQueryType = "signal"
|
||||
StreamingQueryTypeTraces StreamingQueryType = "traces"
|
||||
)
|
||||
|
||||
// ErrorType defines model for TestDataQuery.ErrorType.
|
||||
// +enum
|
||||
type ErrorType string
|
||||
|
||||
const (
|
||||
ErrorTypeFrontendException ErrorType = "frontend_exception"
|
||||
ErrorTypeFrontendObservable ErrorType = "frontend_observable"
|
||||
ErrorTypeServerPanic ErrorType = "server_panic"
|
||||
)
|
||||
|
||||
// TestDataQueryType defines model for TestDataQueryType.
|
||||
// +enum
|
||||
type TestDataQueryType string
|
||||
|
||||
// Defines values for TestDataQueryType.
|
||||
const (
|
||||
TestDataQueryTypeAnnotations TestDataQueryType = "annotations"
|
||||
TestDataQueryTypeArrow TestDataQueryType = "arrow"
|
||||
TestDataQueryTypeCsvContent TestDataQueryType = "csv_content"
|
||||
TestDataQueryTypeCsvFile TestDataQueryType = "csv_file"
|
||||
TestDataQueryTypeCsvMetricValues TestDataQueryType = "csv_metric_values"
|
||||
TestDataQueryTypeDatapointsOutsideRange TestDataQueryType = "datapoints_outside_range"
|
||||
TestDataQueryTypeExponentialHeatmapBucketData TestDataQueryType = "exponential_heatmap_bucket_data"
|
||||
TestDataQueryTypeFlameGraph TestDataQueryType = "flame_graph"
|
||||
TestDataQueryTypeGrafanaApi TestDataQueryType = "grafana_api"
|
||||
TestDataQueryTypeLinearHeatmapBucketData TestDataQueryType = "linear_heatmap_bucket_data"
|
||||
TestDataQueryTypeLive TestDataQueryType = "live"
|
||||
TestDataQueryTypeLogs TestDataQueryType = "logs"
|
||||
TestDataQueryTypeManualEntry TestDataQueryType = "manual_entry"
|
||||
TestDataQueryTypeNoDataPoints TestDataQueryType = "no_data_points"
|
||||
TestDataQueryTypeNodeGraph TestDataQueryType = "node_graph"
|
||||
TestDataQueryTypePredictableCsvWave TestDataQueryType = "predictable_csv_wave"
|
||||
TestDataQueryTypePredictablePulse TestDataQueryType = "predictable_pulse"
|
||||
TestDataQueryTypeRandomWalk TestDataQueryType = "random_walk"
|
||||
TestDataQueryTypeRandomWalkTable TestDataQueryType = "random_walk_table"
|
||||
TestDataQueryTypeRandomWalkWithError TestDataQueryType = "random_walk_with_error"
|
||||
TestDataQueryTypeRawFrame TestDataQueryType = "raw_frame"
|
||||
TestDataQueryTypeServerError500 TestDataQueryType = "server_error_500"
|
||||
TestDataQueryTypeSimulation TestDataQueryType = "simulation"
|
||||
TestDataQueryTypeSlowQuery TestDataQueryType = "slow_query"
|
||||
TestDataQueryTypeStreamingClient TestDataQueryType = "streaming_client"
|
||||
TestDataQueryTypeTableStatic TestDataQueryType = "table_static"
|
||||
TestDataQueryTypeTrace TestDataQueryType = "trace"
|
||||
TestDataQueryTypeUsa TestDataQueryType = "usa"
|
||||
TestDataQueryTypeVariablesQuery TestDataQueryType = "variables-query"
|
||||
)
|
||||
|
||||
// TestDataQuery defines model for TestDataQuery.
|
||||
type TestDataQuery struct {
|
||||
ScenarioId TestDataQueryType `json:"scenarioId,omitempty"`
|
||||
Alias string `json:"alias,omitempty"`
|
||||
Labels string `json:"labels,omitempty"`
|
||||
|
||||
// common parameter used by many query types
|
||||
StringInput string `json:"stringInput,omitempty"`
|
||||
|
||||
CsvContent string `json:"csvContent,omitempty"`
|
||||
CsvFileName string `json:"csvFileName,omitempty"`
|
||||
CsvWave []CSVWave `json:"csvWave,omitempty"`
|
||||
|
||||
// Used for live query
|
||||
Channel string `json:"channel,omitempty"`
|
||||
|
||||
// Drop percentage (the chance we will lose a point 0-100)
|
||||
DropPercent float64 `json:"dropPercent,omitempty"`
|
||||
ErrorType ErrorType `json:"errorType,omitempty"`
|
||||
FlamegraphDiff bool `json:"flamegraphDiff,omitempty"`
|
||||
LevelColumn bool `json:"levelColumn,omitempty"`
|
||||
StartValue float64 `json:"startValue,omitempty"`
|
||||
Spread float64 `json:"spread,omitempty"`
|
||||
Noise float64 `json:"noise,omitempty"`
|
||||
Min *float64 `json:"min,omitempty"`
|
||||
Max *float64 `json:"max,omitempty"`
|
||||
WithNil bool `json:"withNil,omitempty"`
|
||||
Lines int64 `json:"lines,omitempty"`
|
||||
Points [][]any `json:"points,omitempty"`
|
||||
RawFrameContent string `json:"rawFrameContent,omitempty"`
|
||||
SeriesCount int `json:"seriesCount,omitempty"`
|
||||
SpanCount int `json:"spanCount,omitempty"`
|
||||
|
||||
Nodes *NodesQuery `json:"nodes,omitempty"`
|
||||
PulseWave *PulseWaveQuery `json:"pulseWave,omitempty"`
|
||||
Sim *SimulationQuery `json:"sim,omitempty"`
|
||||
Stream *StreamingQuery `json:"stream,omitempty"`
|
||||
Usa *USAQuery `json:"usa,omitempty"`
|
||||
}
|
||||
|
||||
// CSVWave defines model for CSVWave.
|
||||
type CSVWave struct {
|
||||
TimeStep int64 `json:"timeStep,omitempty"`
|
||||
ValuesCSV string `json:"valuesCSV,omitempty"`
|
||||
Labels string `json:"labels,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
}
|
||||
|
||||
// NodesQuery defines model for NodesQuery.
|
||||
type NodesQuery struct {
|
||||
Count int64 `json:"count,omitempty"`
|
||||
Seed int64 `json:"seed,omitempty"`
|
||||
Type NodesQueryType `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
// PulseWaveQuery defines model for PulseWaveQuery.
|
||||
type PulseWaveQuery struct {
|
||||
OffCount int64 `json:"offCount,omitempty"`
|
||||
OffValue float64 `json:"offValue,omitempty"`
|
||||
OnCount int64 `json:"onCount,omitempty"`
|
||||
OnValue float64 `json:"onValue,omitempty"`
|
||||
TimeStep int64 `json:"timeStep,omitempty"`
|
||||
}
|
||||
|
||||
// SimulationQuery defines model for SimulationQuery.
|
||||
type SimulationQuery struct {
|
||||
Config map[string]any `json:"config,omitempty"`
|
||||
Key struct {
|
||||
Tick float64 `json:"tick"`
|
||||
Type string `json:"type"`
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
} `json:"key"`
|
||||
Last bool `json:"last,omitempty"`
|
||||
Stream bool `json:"stream,omitempty"`
|
||||
}
|
||||
|
||||
// StreamingQuery defines model for StreamingQuery.
|
||||
type StreamingQuery struct {
|
||||
Bands int32 `json:"bands,omitempty"`
|
||||
Noise float64 `json:"noise"`
|
||||
Speed float64 `json:"speed"`
|
||||
Spread float64 `json:"spread"`
|
||||
Type StreamingQueryType `json:"type"`
|
||||
Url string `json:"url,omitempty"`
|
||||
}
|
||||
|
||||
// USAQuery defines model for USAQuery.
|
||||
type USAQuery struct {
|
||||
Fields []string `json:"fields,omitempty"`
|
||||
Mode string `json:"mode,omitempty"`
|
||||
Period string `json:"period,omitempty"`
|
||||
States []string `json:"states,omitempty"`
|
||||
}
|
||||
|
||||
//go:embed query.types.json
|
||||
var f embed.FS
|
||||
|
||||
// QueryTypeDefinitionsJSON returns the query type definitions
|
||||
func QueryTypeDefinitionsJSON() (json.RawMessage, error) {
|
||||
return f.ReadFile("query.types.json")
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"type": "table",
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"datasource": {
|
||||
"type": "grafana-testdata-datasource",
|
||||
"uid": "TheUID"
|
||||
},
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "B",
|
||||
"datasource": {
|
||||
"type": "grafana-testdata-datasource",
|
||||
"uid": "TheUID"
|
||||
},
|
||||
"pulseWave": {
|
||||
"offCount": 20,
|
||||
"offValue": 1.23,
|
||||
"onCount": 10,
|
||||
"onValue": 4.56,
|
||||
"timeStep": 1000
|
||||
},
|
||||
"scenarioId": "predictable_pulse"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,411 @@
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"targets",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"targets": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"description": "TestDataQuery defines model for TestDataQuery.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"alias": {
|
||||
"type": "string"
|
||||
},
|
||||
"channel": {
|
||||
"description": "Used for live query",
|
||||
"type": "string"
|
||||
},
|
||||
"csvContent": {
|
||||
"type": "string"
|
||||
},
|
||||
"csvFileName": {
|
||||
"type": "string"
|
||||
},
|
||||
"csvWave": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"description": "CSVWave defines model for CSVWave.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"labels": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"timeStep": {
|
||||
"type": "integer"
|
||||
},
|
||||
"valuesCSV": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"datasource": {
|
||||
"description": "The datasource",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"description": "The datasource plugin type",
|
||||
"type": "string",
|
||||
"pattern": "^grafana-testdata-datasource$|^testdata$"
|
||||
},
|
||||
"uid": {
|
||||
"description": "Datasource UID",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"dropPercent": {
|
||||
"description": "Drop percentage (the chance we will lose a point 0-100)",
|
||||
"type": "number"
|
||||
},
|
||||
"errorType": {
|
||||
"description": "Possible enum values:\n - `\"frontend_exception\"` \n - `\"frontend_observable\"` \n - `\"server_panic\"` ",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"frontend_exception",
|
||||
"frontend_observable",
|
||||
"server_panic"
|
||||
],
|
||||
"x-enum-description": {}
|
||||
},
|
||||
"flamegraphDiff": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"hide": {
|
||||
"description": "true if query is disabled (ie should not be returned to the dashboard)\nNOTE: this does not always imply that the query should not be executed since\nthe results from a hidden query may be used as the input to other queries (SSE etc)",
|
||||
"type": "boolean"
|
||||
},
|
||||
"intervalMs": {
|
||||
"description": "Interval is the suggested duration between time points in a time series query.\nNOTE: the values for intervalMs is not saved in the query model. It is typically calculated\nfrom the interval required to fill a pixels in the visualization",
|
||||
"type": "number"
|
||||
},
|
||||
"labels": {
|
||||
"type": "string"
|
||||
},
|
||||
"levelColumn": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"lines": {
|
||||
"type": "integer"
|
||||
},
|
||||
"max": {
|
||||
"type": "number"
|
||||
},
|
||||
"maxDataPoints": {
|
||||
"description": "MaxDataPoints is the maximum number of data points that should be returned from a time series query.\nNOTE: the values for maxDataPoints is not saved in the query model. It is typically calculated\nfrom the number of pixels visible in a visualization",
|
||||
"type": "integer"
|
||||
},
|
||||
"min": {
|
||||
"type": "number"
|
||||
},
|
||||
"nodes": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"count": {
|
||||
"type": "integer"
|
||||
},
|
||||
"seed": {
|
||||
"type": "integer"
|
||||
},
|
||||
"type": {
|
||||
"description": "Possible enum values:\n - `\"random\"` \n - `\"random edges\"` \n - `\"response_medium\"` \n - `\"response_small\"` \n - `\"feature_showcase\"` ",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"random",
|
||||
"random edges",
|
||||
"response_medium",
|
||||
"response_small",
|
||||
"feature_showcase"
|
||||
],
|
||||
"x-enum-description": {}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"noise": {
|
||||
"type": "number"
|
||||
},
|
||||
"points": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"pulseWave": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"offCount": {
|
||||
"type": "integer"
|
||||
},
|
||||
"offValue": {
|
||||
"type": "number"
|
||||
},
|
||||
"onCount": {
|
||||
"type": "integer"
|
||||
},
|
||||
"onValue": {
|
||||
"type": "number"
|
||||
},
|
||||
"timeStep": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"queryType": {
|
||||
"description": "QueryType is an optional identifier for the type of query.\nIt can be used to distinguish different types of queries.",
|
||||
"type": "string"
|
||||
},
|
||||
"rawFrameContent": {
|
||||
"type": "string"
|
||||
},
|
||||
"refId": {
|
||||
"description": "RefID is the unique identifier of the query, set by the frontend call.",
|
||||
"type": "string"
|
||||
},
|
||||
"resultAssertions": {
|
||||
"description": "Optionally define expected query result behavior",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"typeVersion"
|
||||
],
|
||||
"properties": {
|
||||
"maxFrames": {
|
||||
"description": "Maximum frame count",
|
||||
"type": "integer"
|
||||
},
|
||||
"type": {
|
||||
"description": "Type asserts that the frame matches a known type structure.\n\n\nPossible enum values:\n - `\"\"` \n - `\"timeseries-wide\"` \n - `\"timeseries-long\"` \n - `\"timeseries-many\"` \n - `\"timeseries-multi\"` \n - `\"directory-listing\"` \n - `\"table\"` \n - `\"numeric-wide\"` \n - `\"numeric-multi\"` \n - `\"numeric-long\"` \n - `\"log-lines\"` ",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"",
|
||||
"timeseries-wide",
|
||||
"timeseries-long",
|
||||
"timeseries-many",
|
||||
"timeseries-multi",
|
||||
"directory-listing",
|
||||
"table",
|
||||
"numeric-wide",
|
||||
"numeric-multi",
|
||||
"numeric-long",
|
||||
"log-lines"
|
||||
],
|
||||
"x-enum-description": {}
|
||||
},
|
||||
"typeVersion": {
|
||||
"description": "TypeVersion is the version of the Type property. Versions greater than 0.0 correspond to the dataplane\ncontract documentation https://grafana.github.io/dataplane/contract/.",
|
||||
"type": "array",
|
||||
"maxItems": 2,
|
||||
"minItems": 2,
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"scenarioId": {
|
||||
"description": "Possible enum values:\n - `\"annotations\"` \n - `\"arrow\"` \n - `\"csv_content\"` \n - `\"csv_file\"` \n - `\"csv_metric_values\"` \n - `\"datapoints_outside_range\"` \n - `\"exponential_heatmap_bucket_data\"` \n - `\"flame_graph\"` \n - `\"grafana_api\"` \n - `\"linear_heatmap_bucket_data\"` \n - `\"live\"` \n - `\"logs\"` \n - `\"manual_entry\"` \n - `\"no_data_points\"` \n - `\"node_graph\"` \n - `\"predictable_csv_wave\"` \n - `\"predictable_pulse\"` \n - `\"random_walk\"` \n - `\"random_walk_table\"` \n - `\"random_walk_with_error\"` \n - `\"raw_frame\"` \n - `\"server_error_500\"` \n - `\"simulation\"` \n - `\"slow_query\"` \n - `\"streaming_client\"` \n - `\"table_static\"` \n - `\"trace\"` \n - `\"usa\"` \n - `\"variables-query\"` ",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"annotations",
|
||||
"arrow",
|
||||
"csv_content",
|
||||
"csv_file",
|
||||
"csv_metric_values",
|
||||
"datapoints_outside_range",
|
||||
"exponential_heatmap_bucket_data",
|
||||
"flame_graph",
|
||||
"grafana_api",
|
||||
"linear_heatmap_bucket_data",
|
||||
"live",
|
||||
"logs",
|
||||
"manual_entry",
|
||||
"no_data_points",
|
||||
"node_graph",
|
||||
"predictable_csv_wave",
|
||||
"predictable_pulse",
|
||||
"random_walk",
|
||||
"random_walk_table",
|
||||
"random_walk_with_error",
|
||||
"raw_frame",
|
||||
"server_error_500",
|
||||
"simulation",
|
||||
"slow_query",
|
||||
"streaming_client",
|
||||
"table_static",
|
||||
"trace",
|
||||
"usa",
|
||||
"variables-query"
|
||||
],
|
||||
"x-enum-description": {}
|
||||
},
|
||||
"seriesCount": {
|
||||
"type": "integer"
|
||||
},
|
||||
"sim": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"key"
|
||||
],
|
||||
"properties": {
|
||||
"config": {
|
||||
"type": "object"
|
||||
},
|
||||
"key": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"tick",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"tick": {
|
||||
"type": "number"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"uid": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"last": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"stream": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"spanCount": {
|
||||
"type": "integer"
|
||||
},
|
||||
"spread": {
|
||||
"type": "number"
|
||||
},
|
||||
"startValue": {
|
||||
"type": "number"
|
||||
},
|
||||
"stream": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"noise",
|
||||
"speed",
|
||||
"spread",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"bands": {
|
||||
"type": "integer"
|
||||
},
|
||||
"noise": {
|
||||
"type": "number"
|
||||
},
|
||||
"speed": {
|
||||
"type": "number"
|
||||
},
|
||||
"spread": {
|
||||
"type": "number"
|
||||
},
|
||||
"type": {
|
||||
"description": "Possible enum values:\n - `\"fetch\"` \n - `\"logs\"` \n - `\"signal\"` \n - `\"traces\"` ",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"fetch",
|
||||
"logs",
|
||||
"signal",
|
||||
"traces"
|
||||
],
|
||||
"x-enum-description": {}
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"stringInput": {
|
||||
"description": "common parameter used by many query types",
|
||||
"type": "string"
|
||||
},
|
||||
"timeRange": {
|
||||
"description": "TimeRange represents the query range\nNOTE: unlike generic /ds/query, we can now send explicit time values in each query\nNOTE: the values for timeRange are not saved in a dashboard, they are constructed on the fly",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"from",
|
||||
"to"
|
||||
],
|
||||
"properties": {
|
||||
"from": {
|
||||
"description": "From is the start time of the query.",
|
||||
"type": "string",
|
||||
"default": "now-6h",
|
||||
"examples": [
|
||||
"now-1h"
|
||||
]
|
||||
},
|
||||
"to": {
|
||||
"description": "To is the end time of the query.",
|
||||
"type": "string",
|
||||
"default": "now",
|
||||
"examples": [
|
||||
"now"
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"usa": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"fields": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"mode": {
|
||||
"type": "string"
|
||||
},
|
||||
"period": {
|
||||
"type": "string"
|
||||
},
|
||||
"states": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"withNil": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"$schema": "https://json-schema.org/draft-04/schema#"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"description": "the panel type",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": true,
|
||||
"$schema": "https://json-schema.org/draft-04/schema#"
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"from": "now-1h",
|
||||
"to": "now",
|
||||
"queries": [
|
||||
{
|
||||
"refId": "A",
|
||||
"maxDataPoints": 1000,
|
||||
"intervalMs": 5,
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "B",
|
||||
"maxDataPoints": 1000,
|
||||
"intervalMs": 5,
|
||||
"pulseWave": {
|
||||
"offCount": 20,
|
||||
"offValue": 1.23,
|
||||
"onCount": 10,
|
||||
"onValue": 4.56,
|
||||
"timeStep": 1000
|
||||
},
|
||||
"scenarioId": "predictable_pulse"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,421 @@
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"queries"
|
||||
],
|
||||
"properties": {
|
||||
"$schema": {
|
||||
"description": "helper",
|
||||
"type": "string"
|
||||
},
|
||||
"debug": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"from": {
|
||||
"description": "From Start time in epoch timestamps in milliseconds or relative using Grafana time units.",
|
||||
"type": "string"
|
||||
},
|
||||
"queries": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"description": "TestDataQuery defines model for TestDataQuery.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"alias": {
|
||||
"type": "string"
|
||||
},
|
||||
"channel": {
|
||||
"description": "Used for live query",
|
||||
"type": "string"
|
||||
},
|
||||
"csvContent": {
|
||||
"type": "string"
|
||||
},
|
||||
"csvFileName": {
|
||||
"type": "string"
|
||||
},
|
||||
"csvWave": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"description": "CSVWave defines model for CSVWave.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"labels": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"timeStep": {
|
||||
"type": "integer"
|
||||
},
|
||||
"valuesCSV": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"datasource": {
|
||||
"description": "The datasource",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"description": "The datasource plugin type",
|
||||
"type": "string",
|
||||
"pattern": "^grafana-testdata-datasource$|^testdata$"
|
||||
},
|
||||
"uid": {
|
||||
"description": "Datasource UID",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"dropPercent": {
|
||||
"description": "Drop percentage (the chance we will lose a point 0-100)",
|
||||
"type": "number"
|
||||
},
|
||||
"errorType": {
|
||||
"description": "Possible enum values:\n - `\"frontend_exception\"` \n - `\"frontend_observable\"` \n - `\"server_panic\"` ",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"frontend_exception",
|
||||
"frontend_observable",
|
||||
"server_panic"
|
||||
],
|
||||
"x-enum-description": {}
|
||||
},
|
||||
"flamegraphDiff": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"hide": {
|
||||
"description": "true if query is disabled (ie should not be returned to the dashboard)\nNOTE: this does not always imply that the query should not be executed since\nthe results from a hidden query may be used as the input to other queries (SSE etc)",
|
||||
"type": "boolean"
|
||||
},
|
||||
"intervalMs": {
|
||||
"description": "Interval is the suggested duration between time points in a time series query.\nNOTE: the values for intervalMs is not saved in the query model. It is typically calculated\nfrom the interval required to fill a pixels in the visualization",
|
||||
"type": "number"
|
||||
},
|
||||
"labels": {
|
||||
"type": "string"
|
||||
},
|
||||
"levelColumn": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"lines": {
|
||||
"type": "integer"
|
||||
},
|
||||
"max": {
|
||||
"type": "number"
|
||||
},
|
||||
"maxDataPoints": {
|
||||
"description": "MaxDataPoints is the maximum number of data points that should be returned from a time series query.\nNOTE: the values for maxDataPoints is not saved in the query model. It is typically calculated\nfrom the number of pixels visible in a visualization",
|
||||
"type": "integer"
|
||||
},
|
||||
"min": {
|
||||
"type": "number"
|
||||
},
|
||||
"nodes": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"count": {
|
||||
"type": "integer"
|
||||
},
|
||||
"seed": {
|
||||
"type": "integer"
|
||||
},
|
||||
"type": {
|
||||
"description": "Possible enum values:\n - `\"random\"` \n - `\"random edges\"` \n - `\"response_medium\"` \n - `\"response_small\"` \n - `\"feature_showcase\"` ",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"random",
|
||||
"random edges",
|
||||
"response_medium",
|
||||
"response_small",
|
||||
"feature_showcase"
|
||||
],
|
||||
"x-enum-description": {}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"noise": {
|
||||
"type": "number"
|
||||
},
|
||||
"points": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"pulseWave": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"offCount": {
|
||||
"type": "integer"
|
||||
},
|
||||
"offValue": {
|
||||
"type": "number"
|
||||
},
|
||||
"onCount": {
|
||||
"type": "integer"
|
||||
},
|
||||
"onValue": {
|
||||
"type": "number"
|
||||
},
|
||||
"timeStep": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"queryType": {
|
||||
"description": "QueryType is an optional identifier for the type of query.\nIt can be used to distinguish different types of queries.",
|
||||
"type": "string"
|
||||
},
|
||||
"rawFrameContent": {
|
||||
"type": "string"
|
||||
},
|
||||
"refId": {
|
||||
"description": "RefID is the unique identifier of the query, set by the frontend call.",
|
||||
"type": "string"
|
||||
},
|
||||
"resultAssertions": {
|
||||
"description": "Optionally define expected query result behavior",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"typeVersion"
|
||||
],
|
||||
"properties": {
|
||||
"maxFrames": {
|
||||
"description": "Maximum frame count",
|
||||
"type": "integer"
|
||||
},
|
||||
"type": {
|
||||
"description": "Type asserts that the frame matches a known type structure.\n\n\nPossible enum values:\n - `\"\"` \n - `\"timeseries-wide\"` \n - `\"timeseries-long\"` \n - `\"timeseries-many\"` \n - `\"timeseries-multi\"` \n - `\"directory-listing\"` \n - `\"table\"` \n - `\"numeric-wide\"` \n - `\"numeric-multi\"` \n - `\"numeric-long\"` \n - `\"log-lines\"` ",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"",
|
||||
"timeseries-wide",
|
||||
"timeseries-long",
|
||||
"timeseries-many",
|
||||
"timeseries-multi",
|
||||
"directory-listing",
|
||||
"table",
|
||||
"numeric-wide",
|
||||
"numeric-multi",
|
||||
"numeric-long",
|
||||
"log-lines"
|
||||
],
|
||||
"x-enum-description": {}
|
||||
},
|
||||
"typeVersion": {
|
||||
"description": "TypeVersion is the version of the Type property. Versions greater than 0.0 correspond to the dataplane\ncontract documentation https://grafana.github.io/dataplane/contract/.",
|
||||
"type": "array",
|
||||
"maxItems": 2,
|
||||
"minItems": 2,
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"scenarioId": {
|
||||
"description": "Possible enum values:\n - `\"annotations\"` \n - `\"arrow\"` \n - `\"csv_content\"` \n - `\"csv_file\"` \n - `\"csv_metric_values\"` \n - `\"datapoints_outside_range\"` \n - `\"exponential_heatmap_bucket_data\"` \n - `\"flame_graph\"` \n - `\"grafana_api\"` \n - `\"linear_heatmap_bucket_data\"` \n - `\"live\"` \n - `\"logs\"` \n - `\"manual_entry\"` \n - `\"no_data_points\"` \n - `\"node_graph\"` \n - `\"predictable_csv_wave\"` \n - `\"predictable_pulse\"` \n - `\"random_walk\"` \n - `\"random_walk_table\"` \n - `\"random_walk_with_error\"` \n - `\"raw_frame\"` \n - `\"server_error_500\"` \n - `\"simulation\"` \n - `\"slow_query\"` \n - `\"streaming_client\"` \n - `\"table_static\"` \n - `\"trace\"` \n - `\"usa\"` \n - `\"variables-query\"` ",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"annotations",
|
||||
"arrow",
|
||||
"csv_content",
|
||||
"csv_file",
|
||||
"csv_metric_values",
|
||||
"datapoints_outside_range",
|
||||
"exponential_heatmap_bucket_data",
|
||||
"flame_graph",
|
||||
"grafana_api",
|
||||
"linear_heatmap_bucket_data",
|
||||
"live",
|
||||
"logs",
|
||||
"manual_entry",
|
||||
"no_data_points",
|
||||
"node_graph",
|
||||
"predictable_csv_wave",
|
||||
"predictable_pulse",
|
||||
"random_walk",
|
||||
"random_walk_table",
|
||||
"random_walk_with_error",
|
||||
"raw_frame",
|
||||
"server_error_500",
|
||||
"simulation",
|
||||
"slow_query",
|
||||
"streaming_client",
|
||||
"table_static",
|
||||
"trace",
|
||||
"usa",
|
||||
"variables-query"
|
||||
],
|
||||
"x-enum-description": {}
|
||||
},
|
||||
"seriesCount": {
|
||||
"type": "integer"
|
||||
},
|
||||
"sim": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"key"
|
||||
],
|
||||
"properties": {
|
||||
"config": {
|
||||
"type": "object"
|
||||
},
|
||||
"key": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"tick",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"tick": {
|
||||
"type": "number"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"uid": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"last": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"stream": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"spanCount": {
|
||||
"type": "integer"
|
||||
},
|
||||
"spread": {
|
||||
"type": "number"
|
||||
},
|
||||
"startValue": {
|
||||
"type": "number"
|
||||
},
|
||||
"stream": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"noise",
|
||||
"speed",
|
||||
"spread",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"bands": {
|
||||
"type": "integer"
|
||||
},
|
||||
"noise": {
|
||||
"type": "number"
|
||||
},
|
||||
"speed": {
|
||||
"type": "number"
|
||||
},
|
||||
"spread": {
|
||||
"type": "number"
|
||||
},
|
||||
"type": {
|
||||
"description": "Possible enum values:\n - `\"fetch\"` \n - `\"logs\"` \n - `\"signal\"` \n - `\"traces\"` ",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"fetch",
|
||||
"logs",
|
||||
"signal",
|
||||
"traces"
|
||||
],
|
||||
"x-enum-description": {}
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"stringInput": {
|
||||
"description": "common parameter used by many query types",
|
||||
"type": "string"
|
||||
},
|
||||
"timeRange": {
|
||||
"description": "TimeRange represents the query range\nNOTE: unlike generic /ds/query, we can now send explicit time values in each query\nNOTE: the values for timeRange are not saved in a dashboard, they are constructed on the fly",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"from",
|
||||
"to"
|
||||
],
|
||||
"properties": {
|
||||
"from": {
|
||||
"description": "From is the start time of the query.",
|
||||
"type": "string",
|
||||
"default": "now-6h",
|
||||
"examples": [
|
||||
"now-1h"
|
||||
]
|
||||
},
|
||||
"to": {
|
||||
"description": "To is the end time of the query.",
|
||||
"type": "string",
|
||||
"default": "now",
|
||||
"examples": [
|
||||
"now"
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"usa": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"fields": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"mode": {
|
||||
"type": "string"
|
||||
},
|
||||
"period": {
|
||||
"type": "string"
|
||||
},
|
||||
"states": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"withNil": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"$schema": "https://json-schema.org/draft-04/schema#"
|
||||
}
|
||||
},
|
||||
"to": {
|
||||
"description": "To end time in epoch timestamps in milliseconds or relative using Grafana time units.",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"$schema": "https://json-schema.org/draft-04/schema#"
|
||||
}
|
||||
@@ -0,0 +1,325 @@
|
||||
{
|
||||
"kind": "QueryTypeDefinitionList",
|
||||
"apiVersion": "query.grafana.app/v0alpha1",
|
||||
"metadata": {
|
||||
"resourceVersion": "1709261615323"
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"metadata": {
|
||||
"name": "default",
|
||||
"resourceVersion": "1711119846950",
|
||||
"creationTimestamp": "2024-03-01T02:53:35Z"
|
||||
},
|
||||
"spec": {
|
||||
"schema": {
|
||||
"$schema": "https://json-schema.org/draft-04/schema",
|
||||
"additionalProperties": false,
|
||||
"description": "TestDataQuery defines model for TestDataQuery.",
|
||||
"properties": {
|
||||
"alias": {
|
||||
"type": "string"
|
||||
},
|
||||
"channel": {
|
||||
"description": "Used for live query",
|
||||
"type": "string"
|
||||
},
|
||||
"csvContent": {
|
||||
"type": "string"
|
||||
},
|
||||
"csvFileName": {
|
||||
"type": "string"
|
||||
},
|
||||
"csvWave": {
|
||||
"items": {
|
||||
"additionalProperties": false,
|
||||
"description": "CSVWave defines model for CSVWave.",
|
||||
"properties": {
|
||||
"labels": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"timeStep": {
|
||||
"type": "integer"
|
||||
},
|
||||
"valuesCSV": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"dropPercent": {
|
||||
"description": "Drop percentage (the chance we will lose a point 0-100)",
|
||||
"type": "number"
|
||||
},
|
||||
"errorType": {
|
||||
"description": "Possible enum values:\n - `\"frontend_exception\"` \n - `\"frontend_observable\"` \n - `\"server_panic\"` ",
|
||||
"enum": [
|
||||
"frontend_exception",
|
||||
"frontend_observable",
|
||||
"server_panic"
|
||||
],
|
||||
"type": "string",
|
||||
"x-enum-description": {}
|
||||
},
|
||||
"flamegraphDiff": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"labels": {
|
||||
"type": "string"
|
||||
},
|
||||
"levelColumn": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"lines": {
|
||||
"type": "integer"
|
||||
},
|
||||
"max": {
|
||||
"type": "number"
|
||||
},
|
||||
"min": {
|
||||
"type": "number"
|
||||
},
|
||||
"nodes": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"count": {
|
||||
"type": "integer"
|
||||
},
|
||||
"seed": {
|
||||
"type": "integer"
|
||||
},
|
||||
"type": {
|
||||
"description": "Possible enum values:\n - `\"random\"` \n - `\"random edges\"` \n - `\"response_medium\"` \n - `\"response_small\"` \n - `\"feature_showcase\"` ",
|
||||
"enum": [
|
||||
"random",
|
||||
"random edges",
|
||||
"response_medium",
|
||||
"response_small",
|
||||
"feature_showcase"
|
||||
],
|
||||
"type": "string",
|
||||
"x-enum-description": {}
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"noise": {
|
||||
"type": "number"
|
||||
},
|
||||
"points": {
|
||||
"items": {
|
||||
"type": "array"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"pulseWave": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"offCount": {
|
||||
"type": "integer"
|
||||
},
|
||||
"offValue": {
|
||||
"type": "number"
|
||||
},
|
||||
"onCount": {
|
||||
"type": "integer"
|
||||
},
|
||||
"onValue": {
|
||||
"type": "number"
|
||||
},
|
||||
"timeStep": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"rawFrameContent": {
|
||||
"type": "string"
|
||||
},
|
||||
"scenarioId": {
|
||||
"description": "Possible enum values:\n - `\"annotations\"` \n - `\"arrow\"` \n - `\"csv_content\"` \n - `\"csv_file\"` \n - `\"csv_metric_values\"` \n - `\"datapoints_outside_range\"` \n - `\"exponential_heatmap_bucket_data\"` \n - `\"flame_graph\"` \n - `\"grafana_api\"` \n - `\"linear_heatmap_bucket_data\"` \n - `\"live\"` \n - `\"logs\"` \n - `\"manual_entry\"` \n - `\"no_data_points\"` \n - `\"node_graph\"` \n - `\"predictable_csv_wave\"` \n - `\"predictable_pulse\"` \n - `\"random_walk\"` \n - `\"random_walk_table\"` \n - `\"random_walk_with_error\"` \n - `\"raw_frame\"` \n - `\"server_error_500\"` \n - `\"simulation\"` \n - `\"slow_query\"` \n - `\"streaming_client\"` \n - `\"table_static\"` \n - `\"trace\"` \n - `\"usa\"` \n - `\"variables-query\"` ",
|
||||
"enum": [
|
||||
"annotations",
|
||||
"arrow",
|
||||
"csv_content",
|
||||
"csv_file",
|
||||
"csv_metric_values",
|
||||
"datapoints_outside_range",
|
||||
"exponential_heatmap_bucket_data",
|
||||
"flame_graph",
|
||||
"grafana_api",
|
||||
"linear_heatmap_bucket_data",
|
||||
"live",
|
||||
"logs",
|
||||
"manual_entry",
|
||||
"no_data_points",
|
||||
"node_graph",
|
||||
"predictable_csv_wave",
|
||||
"predictable_pulse",
|
||||
"random_walk",
|
||||
"random_walk_table",
|
||||
"random_walk_with_error",
|
||||
"raw_frame",
|
||||
"server_error_500",
|
||||
"simulation",
|
||||
"slow_query",
|
||||
"streaming_client",
|
||||
"table_static",
|
||||
"trace",
|
||||
"usa",
|
||||
"variables-query"
|
||||
],
|
||||
"type": "string",
|
||||
"x-enum-description": {}
|
||||
},
|
||||
"seriesCount": {
|
||||
"type": "integer"
|
||||
},
|
||||
"sim": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"config": {
|
||||
"type": "object"
|
||||
},
|
||||
"key": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"tick": {
|
||||
"type": "number"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"uid": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"tick",
|
||||
"type"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"last": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"stream": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"key"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"spanCount": {
|
||||
"type": "integer"
|
||||
},
|
||||
"spread": {
|
||||
"type": "number"
|
||||
},
|
||||
"startValue": {
|
||||
"type": "number"
|
||||
},
|
||||
"stream": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"bands": {
|
||||
"type": "integer"
|
||||
},
|
||||
"noise": {
|
||||
"type": "number"
|
||||
},
|
||||
"speed": {
|
||||
"type": "number"
|
||||
},
|
||||
"spread": {
|
||||
"type": "number"
|
||||
},
|
||||
"type": {
|
||||
"description": "Possible enum values:\n - `\"fetch\"` \n - `\"logs\"` \n - `\"signal\"` \n - `\"traces\"` ",
|
||||
"enum": [
|
||||
"fetch",
|
||||
"logs",
|
||||
"signal",
|
||||
"traces"
|
||||
],
|
||||
"type": "string",
|
||||
"x-enum-description": {}
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"noise",
|
||||
"speed",
|
||||
"spread",
|
||||
"type"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"stringInput": {
|
||||
"description": "common parameter used by many query types",
|
||||
"type": "string"
|
||||
},
|
||||
"usa": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"fields": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"mode": {
|
||||
"type": "string"
|
||||
},
|
||||
"period": {
|
||||
"type": "string"
|
||||
},
|
||||
"states": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"withNil": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"name": "simple random walk",
|
||||
"saveModel": {
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "pulse wave example",
|
||||
"saveModel": {
|
||||
"pulseWave": {
|
||||
"offCount": 20,
|
||||
"offValue": 1.23,
|
||||
"onCount": 10,
|
||||
"onValue": 4.56,
|
||||
"timeStep": 1000
|
||||
},
|
||||
"scenarioId": "predictable_pulse"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package kinds
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
data "github.com/grafana/grafana-plugin-sdk-go/experimental/apis/data/v0alpha1"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/experimental/schemabuilder"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestQueryTypeDefinitions(t *testing.T) {
|
||||
builder, err := schemabuilder.NewSchemaBuilder(
|
||||
schemabuilder.BuilderOptions{
|
||||
PluginID: []string{"grafana-testdata-datasource", "testdata"},
|
||||
ScanCode: []schemabuilder.CodePaths{{
|
||||
BasePackage: "github.com/grafana/grafana/pkg/tsdb/grafana-testdata-datasource/kinds",
|
||||
CodePath: "./",
|
||||
}},
|
||||
Enums: []reflect.Type{
|
||||
reflect.TypeOf(NodesQueryTypeRandom), // pick an example value (not the root)
|
||||
reflect.TypeOf(StreamingQueryTypeFetch), // pick an example value (not the root)
|
||||
reflect.TypeOf(ErrorTypeServerPanic), // pick an example value (not the root)
|
||||
reflect.TypeOf(TestDataQueryTypeAnnotations), // pick an example value (not the root)
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
err = builder.AddQueries(
|
||||
schemabuilder.QueryTypeInfo{
|
||||
Name: "default",
|
||||
GoType: reflect.TypeOf(&TestDataQuery{}),
|
||||
Examples: []data.QueryExample{
|
||||
{
|
||||
Name: "simple random walk",
|
||||
SaveModel: data.AsUnstructured(
|
||||
TestDataQuery{
|
||||
ScenarioId: TestDataQueryTypeRandomWalk,
|
||||
},
|
||||
),
|
||||
},
|
||||
{
|
||||
Name: "pulse wave example",
|
||||
SaveModel: data.AsUnstructured(
|
||||
TestDataQuery{
|
||||
ScenarioId: TestDataQueryTypePredictablePulse,
|
||||
PulseWave: &PulseWaveQuery{
|
||||
TimeStep: int64(1000),
|
||||
OnCount: 10,
|
||||
OffCount: 20,
|
||||
OffValue: 1.23, // should be any (rather json any)
|
||||
OnValue: 4.56, // should be any
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
require.NoError(t, err)
|
||||
builder.UpdateQueryDefinition(t, "./")
|
||||
}
|
||||
@@ -10,6 +10,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
||||
|
||||
"github.com/grafana/grafana/pkg/tsdb/grafana-testdata-datasource/kinds"
|
||||
)
|
||||
|
||||
func (s *Service) registerRoutes() *http.ServeMux {
|
||||
@@ -46,12 +48,12 @@ func (s *Service) getScenariosHandler(rw http.ResponseWriter, req *http.Request)
|
||||
|
||||
scenarioIds := make([]string, 0)
|
||||
for id := range s.scenarios {
|
||||
scenarioIds = append(scenarioIds, id)
|
||||
scenarioIds = append(scenarioIds, string(id))
|
||||
}
|
||||
sort.Strings(scenarioIds)
|
||||
|
||||
for _, scenarioID := range scenarioIds {
|
||||
scenario := s.scenarios[scenarioID]
|
||||
scenario := s.scenarios[kinds.TestDataQueryType(scenarioID)]
|
||||
result = append(result, map[string]any{
|
||||
"id": scenario.ID,
|
||||
"name": scenario.Name,
|
||||
|
||||
@@ -17,42 +17,13 @@ import (
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
const (
|
||||
randomWalkQuery queryType = "random_walk"
|
||||
randomWalkSlowQuery queryType = "slow_query"
|
||||
randomWalkWithErrorQuery queryType = "random_walk_with_error"
|
||||
randomWalkTableQuery queryType = "random_walk_table"
|
||||
exponentialHeatmapBucketDataQuery queryType = "exponential_heatmap_bucket_data"
|
||||
linearHeatmapBucketDataQuery queryType = "linear_heatmap_bucket_data"
|
||||
noDataPointsQuery queryType = "no_data_points"
|
||||
datapointsOutsideRangeQuery queryType = "datapoints_outside_range"
|
||||
csvMetricValuesQuery queryType = "csv_metric_values"
|
||||
predictablePulseQuery queryType = "predictable_pulse"
|
||||
predictableCSVWaveQuery queryType = "predictable_csv_wave"
|
||||
streamingClientQuery queryType = "streaming_client"
|
||||
simulation queryType = "simulation"
|
||||
usaQueryKey queryType = "usa"
|
||||
liveQuery queryType = "live"
|
||||
grafanaAPIQuery queryType = "grafana_api"
|
||||
arrowQuery queryType = "arrow"
|
||||
annotationsQuery queryType = "annotations"
|
||||
tableStaticQuery queryType = "table_static"
|
||||
serverError500Query queryType = "server_error_500"
|
||||
logsQuery queryType = "logs"
|
||||
nodeGraphQuery queryType = "node_graph"
|
||||
flameGraphQuery queryType = "flame_graph"
|
||||
rawFrameQuery queryType = "raw_frame"
|
||||
csvFileQueryType queryType = "csv_file"
|
||||
csvContentQueryType queryType = "csv_content"
|
||||
traceType queryType = "trace"
|
||||
"github.com/grafana/grafana/pkg/tsdb/grafana-testdata-datasource/kinds"
|
||||
)
|
||||
|
||||
type queryType string
|
||||
|
||||
type Scenario struct {
|
||||
ID string `json:"id"`
|
||||
ID kinds.TestDataQueryType `json:"id"`
|
||||
|
||||
Name string `json:"name"`
|
||||
StringInput string `json:"stringInput"`
|
||||
Description string `json:"description"`
|
||||
@@ -61,25 +32,25 @@ type Scenario struct {
|
||||
|
||||
func (s *Service) registerScenarios() {
|
||||
s.registerScenario(&Scenario{
|
||||
ID: string(exponentialHeatmapBucketDataQuery),
|
||||
ID: kinds.TestDataQueryTypeExponentialHeatmapBucketData,
|
||||
Name: "Exponential heatmap bucket data",
|
||||
handler: s.handleExponentialHeatmapBucketDataScenario,
|
||||
})
|
||||
|
||||
s.registerScenario(&Scenario{
|
||||
ID: string(linearHeatmapBucketDataQuery),
|
||||
ID: kinds.TestDataQueryTypeLinearHeatmapBucketData,
|
||||
Name: "Linear heatmap bucket data",
|
||||
handler: s.handleLinearHeatmapBucketDataScenario,
|
||||
})
|
||||
|
||||
s.registerScenario(&Scenario{
|
||||
ID: string(randomWalkQuery),
|
||||
ID: kinds.TestDataQueryTypeRandomWalk,
|
||||
Name: "Random Walk",
|
||||
handler: s.handleRandomWalkScenario,
|
||||
})
|
||||
|
||||
s.registerScenario(&Scenario{
|
||||
ID: string(predictablePulseQuery),
|
||||
ID: kinds.TestDataQueryTypePredictablePulse,
|
||||
Name: "Predictable Pulse",
|
||||
handler: s.handlePredictablePulseScenario,
|
||||
Description: `Predictable Pulse returns a pulse wave where there is a datapoint every timeStepSeconds.
|
||||
@@ -89,100 +60,100 @@ Timestamps will line up evenly on timeStepSeconds (For example, 60 seconds means
|
||||
})
|
||||
|
||||
s.registerScenario(&Scenario{
|
||||
ID: string(predictableCSVWaveQuery),
|
||||
ID: kinds.TestDataQueryTypePredictableCsvWave,
|
||||
Name: "Predictable CSV Wave",
|
||||
handler: s.handlePredictableCSVWaveScenario,
|
||||
})
|
||||
|
||||
s.registerScenario(&Scenario{
|
||||
ID: string(randomWalkTableQuery),
|
||||
ID: kinds.TestDataQueryTypeRandomWalkTable,
|
||||
Name: "Random Walk Table",
|
||||
handler: s.handleRandomWalkTableScenario,
|
||||
})
|
||||
|
||||
s.registerScenario(&Scenario{
|
||||
ID: string(randomWalkSlowQuery),
|
||||
ID: kinds.TestDataQueryTypeSlowQuery,
|
||||
Name: "Slow Query",
|
||||
StringInput: "5s",
|
||||
handler: s.handleRandomWalkSlowScenario,
|
||||
})
|
||||
|
||||
s.registerScenario(&Scenario{
|
||||
ID: string(noDataPointsQuery),
|
||||
ID: kinds.TestDataQueryTypeNoDataPoints,
|
||||
Name: "No Data Points",
|
||||
handler: s.handleClientSideScenario,
|
||||
})
|
||||
|
||||
s.registerScenario(&Scenario{
|
||||
ID: string(datapointsOutsideRangeQuery),
|
||||
ID: kinds.TestDataQueryTypeDatapointsOutsideRange,
|
||||
Name: "Datapoints Outside Range",
|
||||
handler: s.handleDatapointsOutsideRangeScenario,
|
||||
})
|
||||
|
||||
s.registerScenario(&Scenario{
|
||||
ID: string(csvMetricValuesQuery),
|
||||
ID: kinds.TestDataQueryTypeCsvMetricValues,
|
||||
Name: "CSV Metric Values",
|
||||
StringInput: "1,20,90,30,5,0",
|
||||
handler: s.handleCSVMetricValuesScenario,
|
||||
})
|
||||
|
||||
s.registerScenario(&Scenario{
|
||||
ID: string(streamingClientQuery),
|
||||
ID: kinds.TestDataQueryTypeStreamingClient,
|
||||
Name: "Streaming Client",
|
||||
handler: s.handleClientSideScenario,
|
||||
})
|
||||
|
||||
s.registerScenario(&Scenario{
|
||||
ID: string(liveQuery),
|
||||
ID: kinds.TestDataQueryTypeLive,
|
||||
Name: "Grafana Live",
|
||||
handler: s.handleClientSideScenario,
|
||||
})
|
||||
|
||||
s.registerScenario(&Scenario{
|
||||
ID: string(simulation),
|
||||
ID: kinds.TestDataQueryTypeSimulation,
|
||||
Name: "Simulation",
|
||||
handler: s.sims.QueryData,
|
||||
})
|
||||
|
||||
s.registerScenario(&Scenario{
|
||||
ID: string(usaQueryKey),
|
||||
ID: kinds.TestDataQueryTypeUsa,
|
||||
Name: "USA generated data",
|
||||
handler: s.handleUSAScenario,
|
||||
})
|
||||
|
||||
s.registerScenario(&Scenario{
|
||||
ID: string(grafanaAPIQuery),
|
||||
ID: kinds.TestDataQueryTypeGrafanaApi,
|
||||
Name: "Grafana API",
|
||||
handler: s.handleClientSideScenario,
|
||||
})
|
||||
|
||||
s.registerScenario(&Scenario{
|
||||
ID: string(arrowQuery),
|
||||
ID: kinds.TestDataQueryTypeArrow,
|
||||
Name: "Load Apache Arrow Data",
|
||||
handler: s.handleArrowScenario,
|
||||
})
|
||||
|
||||
s.registerScenario(&Scenario{
|
||||
ID: string(annotationsQuery),
|
||||
ID: kinds.TestDataQueryTypeAnnotations,
|
||||
Name: "Annotations",
|
||||
handler: s.handleClientSideScenario,
|
||||
})
|
||||
|
||||
s.registerScenario(&Scenario{
|
||||
ID: string(tableStaticQuery),
|
||||
ID: kinds.TestDataQueryTypeTableStatic,
|
||||
Name: "Table Static",
|
||||
handler: s.handleTableStaticScenario,
|
||||
})
|
||||
|
||||
s.registerScenario(&Scenario{
|
||||
ID: string(randomWalkWithErrorQuery),
|
||||
ID: kinds.TestDataQueryTypeRandomWalkWithError,
|
||||
Name: "Random Walk (with error)",
|
||||
handler: s.handleRandomWalkWithErrorScenario,
|
||||
})
|
||||
|
||||
s.registerScenario(&Scenario{
|
||||
// Is no longer strictly a _server_ error scenario, but ID is kept for legacy :)
|
||||
ID: string(serverError500Query),
|
||||
ID: kinds.TestDataQueryTypeServerError500,
|
||||
Name: "Conditional Error",
|
||||
handler: s.handleServerError500Scenario,
|
||||
StringInput: "1,20,90,30,5,0",
|
||||
@@ -190,40 +161,40 @@ Timestamps will line up evenly on timeStepSeconds (For example, 60 seconds means
|
||||
})
|
||||
|
||||
s.registerScenario(&Scenario{
|
||||
ID: string(logsQuery),
|
||||
ID: kinds.TestDataQueryTypeLogs,
|
||||
Name: "Logs",
|
||||
handler: s.handleLogsScenario,
|
||||
})
|
||||
|
||||
s.registerScenario(&Scenario{
|
||||
ID: string(nodeGraphQuery),
|
||||
ID: kinds.TestDataQueryTypeNodeGraph,
|
||||
Name: "Node Graph",
|
||||
})
|
||||
|
||||
s.registerScenario(&Scenario{
|
||||
ID: string(flameGraphQuery),
|
||||
ID: kinds.TestDataQueryTypeFlameGraph,
|
||||
Name: "Flame Graph",
|
||||
})
|
||||
|
||||
s.registerScenario(&Scenario{
|
||||
ID: string(rawFrameQuery),
|
||||
ID: kinds.TestDataQueryTypeRawFrame,
|
||||
Name: "Raw Frames",
|
||||
})
|
||||
|
||||
s.registerScenario(&Scenario{
|
||||
ID: string(csvFileQueryType),
|
||||
ID: kinds.TestDataQueryTypeCsvFile,
|
||||
Name: "CSV File",
|
||||
handler: s.handleCsvFileScenario,
|
||||
})
|
||||
|
||||
s.registerScenario(&Scenario{
|
||||
ID: string(csvContentQueryType),
|
||||
ID: kinds.TestDataQueryTypeCsvContent,
|
||||
Name: "CSV Content",
|
||||
handler: s.handleCsvContentScenario,
|
||||
})
|
||||
|
||||
s.registerScenario(&Scenario{
|
||||
ID: string(traceType),
|
||||
ID: kinds.TestDataQueryTypeTrace,
|
||||
Name: "Trace",
|
||||
})
|
||||
|
||||
@@ -232,14 +203,14 @@ Timestamps will line up evenly on timeStepSeconds (For example, 60 seconds means
|
||||
|
||||
func (s *Service) registerScenario(scenario *Scenario) {
|
||||
s.scenarios[scenario.ID] = scenario
|
||||
s.queryMux.HandleFunc(scenario.ID, instrumentScenarioHandler(s.logger, scenario.ID, scenario.handler))
|
||||
s.queryMux.HandleFunc(string(scenario.ID), instrumentScenarioHandler(s.logger, scenario.ID, scenario.handler))
|
||||
}
|
||||
|
||||
func instrumentScenarioHandler(logger log.Logger, scenario string, fn backend.QueryDataHandlerFunc) backend.QueryDataHandlerFunc {
|
||||
func instrumentScenarioHandler(logger log.Logger, scenario kinds.TestDataQueryType, fn backend.QueryDataHandlerFunc) backend.QueryDataHandlerFunc {
|
||||
return backend.QueryDataHandlerFunc(func(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
|
||||
ctx, span := tracing.DefaultTracer().Start(ctx, "testdatasource.queryData",
|
||||
trace.WithAttributes(
|
||||
attribute.String("scenario", scenario),
|
||||
attribute.String("scenario", string(scenario)),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
@@ -250,52 +221,18 @@ func instrumentScenarioHandler(logger log.Logger, scenario string, fn backend.Qu
|
||||
})
|
||||
}
|
||||
|
||||
type JSONModel struct {
|
||||
ScenarioID string `json:"scenarioId"`
|
||||
SeriesCount int `json:"seriesCount"`
|
||||
StringInput string `json:"stringInput"`
|
||||
Lines int64 `json:"lines"`
|
||||
IncludeLevelColumn bool `json:"includeLevelColumn"`
|
||||
StartValue float64 `json:"startValue"`
|
||||
Spread float64 `json:"spread"`
|
||||
Noise float64 `json:"noise"`
|
||||
Drop float64 `json:"drop"`
|
||||
Min *float64 `json:"min,omitempty"`
|
||||
Max *float64 `json:"max,omitempty"`
|
||||
Labels string `json:"labels"`
|
||||
WithNil bool `json:"withNil"`
|
||||
PulseWave pulseWave `json:"pulseWave"`
|
||||
Alias string `json:"alias"`
|
||||
// Cannot specify a type for csvWave since legacy queries
|
||||
// does not follow the same format as the new ones (and there is no migration).
|
||||
CSVWave any `json:"csvWave"`
|
||||
CSVContent string `json:"csvContent"`
|
||||
CSVFileName string `json:"csvFileName"`
|
||||
DropPercent float64 `json:"dropPercent"`
|
||||
}
|
||||
|
||||
type pulseWave struct {
|
||||
TimeStep int64 `json:"timeStep"`
|
||||
OnCount int64 `json:"onCount"`
|
||||
OffCount int64 `json:"offCount"`
|
||||
OnValue any `json:"onValue"`
|
||||
OffValue any `json:"offValue"`
|
||||
}
|
||||
|
||||
func GetJSONModel(j json.RawMessage) (JSONModel, error) {
|
||||
model := JSONModel{
|
||||
func GetJSONModel(j json.RawMessage) (kinds.TestDataQuery, error) {
|
||||
model := kinds.TestDataQuery{
|
||||
// Default values
|
||||
ScenarioID: string(randomWalkQuery),
|
||||
ScenarioId: kinds.TestDataQueryTypeRandomWalk,
|
||||
SeriesCount: 1,
|
||||
Lines: 10,
|
||||
StartValue: rand.Float64() * 100,
|
||||
Spread: 1,
|
||||
}
|
||||
if len(j) > 0 {
|
||||
err := json.Unmarshal(j, &model)
|
||||
if err != nil {
|
||||
return JSONModel{}, err
|
||||
}
|
||||
// csvWave has saved values that are single values, not arrays
|
||||
_ = json.Unmarshal(j, &model)
|
||||
}
|
||||
return model, nil
|
||||
}
|
||||
@@ -303,7 +240,7 @@ func GetJSONModel(j json.RawMessage) (JSONModel, error) {
|
||||
// handleFallbackScenario handles the scenario where queryType is not set and fallbacks to scenarioId.
|
||||
func (s *Service) handleFallbackScenario(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
|
||||
ctxLogger := s.logger.FromContext(ctx)
|
||||
scenarioQueries := map[string][]backend.DataQuery{}
|
||||
scenarioQueries := map[kinds.TestDataQueryType][]backend.DataQuery{}
|
||||
|
||||
for _, q := range req.Queries {
|
||||
model, err := GetJSONModel(q.JSON)
|
||||
@@ -312,7 +249,7 @@ func (s *Service) handleFallbackScenario(ctx context.Context, req *backend.Query
|
||||
continue
|
||||
}
|
||||
|
||||
scenarioID := model.ScenarioID
|
||||
scenarioID := model.ScenarioId
|
||||
if _, exist := s.scenarios[scenarioID]; exist {
|
||||
if _, ok := scenarioQueries[scenarioID]; !ok {
|
||||
scenarioQueries[scenarioID] = []backend.DataQuery{}
|
||||
@@ -654,7 +591,7 @@ func (s *Service) handleLogsScenario(ctx context.Context, req *backend.QueryData
|
||||
}
|
||||
|
||||
lines := model.Lines
|
||||
includeLevelColumn := model.IncludeLevelColumn
|
||||
includeLevelColumn := model.LevelColumn
|
||||
|
||||
logLevelGenerator := newRandomStringProvider([]string{
|
||||
"emerg",
|
||||
@@ -726,14 +663,14 @@ func (s *Service) handleLogsScenario(ctx context.Context, req *backend.QueryData
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func RandomWalk(query backend.DataQuery, model JSONModel, index int) *data.Frame {
|
||||
func RandomWalk(query backend.DataQuery, model kinds.TestDataQuery, index int) *data.Frame {
|
||||
rand := rand.New(rand.NewSource(time.Now().UnixNano() + int64(index)))
|
||||
timeWalkerMs := query.TimeRange.From.UnixNano() / int64(time.Millisecond)
|
||||
to := query.TimeRange.To.UnixNano() / int64(time.Millisecond)
|
||||
startValue := model.StartValue
|
||||
spread := model.Spread
|
||||
noise := model.Noise
|
||||
drop := model.Drop / 100.0 // value is 0-100
|
||||
drop := model.DropPercent / 100.0 // value is 0-100
|
||||
|
||||
min := float64(0)
|
||||
hasMin := false
|
||||
@@ -795,7 +732,7 @@ func RandomWalk(query backend.DataQuery, model JSONModel, index int) *data.Frame
|
||||
return frame
|
||||
}
|
||||
|
||||
func randomWalkTable(query backend.DataQuery, model JSONModel) *data.Frame {
|
||||
func randomWalkTable(query backend.DataQuery, model kinds.TestDataQuery) *data.Frame {
|
||||
rand := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
timeWalkerMs := query.TimeRange.From.UnixNano() / int64(time.Millisecond)
|
||||
to := query.TimeRange.To.UnixNano() / int64(time.Millisecond)
|
||||
@@ -868,23 +805,8 @@ func randomWalkTable(query backend.DataQuery, model JSONModel) *data.Frame {
|
||||
return frame
|
||||
}
|
||||
|
||||
type pCSVOptions struct {
|
||||
TimeStep int64 `json:"timeStep"`
|
||||
ValuesCSV string `json:"valuesCSV"`
|
||||
Labels string `json:"labels"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func predictableCSVWave(query backend.DataQuery, model JSONModel) ([]*data.Frame, error) {
|
||||
queries := []pCSVOptions{}
|
||||
input, err := json.Marshal(model.CSVWave)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = json.Unmarshal(input, &queries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
func predictableCSVWave(query backend.DataQuery, model kinds.TestDataQuery) ([]*data.Frame, error) {
|
||||
queries := model.CsvWave
|
||||
|
||||
frames := make([]*data.Frame, 0, len(queries))
|
||||
|
||||
@@ -972,7 +894,7 @@ func predictableSeries(timeRange backend.TimeRange, timeStep, length int64, getV
|
||||
}, nil
|
||||
}
|
||||
|
||||
func predictablePulse(query backend.DataQuery, model JSONModel) (*data.Frame, error) {
|
||||
func predictablePulse(query backend.DataQuery, model kinds.TestDataQuery) (*data.Frame, error) {
|
||||
// Process Input
|
||||
var timeStep int64
|
||||
var onCount int64
|
||||
@@ -1042,7 +964,7 @@ func randomHeatmapData(query backend.DataQuery, fnBucketGen func(index int) floa
|
||||
return frame
|
||||
}
|
||||
|
||||
func doArrowQuery(query backend.DataQuery, model JSONModel) (*data.Frame, error) {
|
||||
func doArrowQuery(query backend.DataQuery, model kinds.TestDataQuery) (*data.Frame, error) {
|
||||
encoded := model.StringInput
|
||||
if encoded == "" {
|
||||
return nil, nil
|
||||
@@ -1054,7 +976,7 @@ func doArrowQuery(query backend.DataQuery, model JSONModel) (*data.Frame, error)
|
||||
return data.UnmarshalArrowFrame(arrow)
|
||||
}
|
||||
|
||||
func newSeriesForQuery(query backend.DataQuery, model JSONModel, index int) *data.Frame {
|
||||
func newSeriesForQuery(query backend.DataQuery, model kinds.TestDataQuery, index int) *data.Frame {
|
||||
alias := model.Alias
|
||||
suffix := ""
|
||||
|
||||
@@ -1082,7 +1004,7 @@ func newSeriesForQuery(query backend.DataQuery, model JSONModel, index int) *dat
|
||||
*
|
||||
* '{job="foo", instance="bar"} => {job: "foo", instance: "bar"}`
|
||||
*/
|
||||
func parseLabels(model JSONModel, seriesIndex int) data.Labels {
|
||||
func parseLabels(model kinds.TestDataQuery, seriesIndex int) data.Labels {
|
||||
return parseLabelsString(model.Labels, seriesIndex)
|
||||
}
|
||||
|
||||
@@ -1110,7 +1032,7 @@ func parseLabelsString(labelText string, seriesIndex int) data.Labels {
|
||||
return tags
|
||||
}
|
||||
|
||||
func frameNameForQuery(query backend.DataQuery, model JSONModel, index int) string {
|
||||
func frameNameForQuery(query backend.DataQuery, model kinds.TestDataQuery, index int) string {
|
||||
name := model.Alias
|
||||
suffix := ""
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ import (
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/tsdb/grafana-testdata-datasource/kinds"
|
||||
)
|
||||
|
||||
func TestTestdataScenarios(t *testing.T) {
|
||||
@@ -184,32 +186,32 @@ func TestParseLabels(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
model JSONModel
|
||||
model kinds.TestDataQuery
|
||||
expected data.Labels
|
||||
}{
|
||||
{
|
||||
name: "wrapped in {} and quoted value ",
|
||||
model: JSONModel{Labels: `{job="foo", instance="bar"}`},
|
||||
model: kinds.TestDataQuery{Labels: `{job="foo", instance="bar"}`},
|
||||
expected: expectedTags,
|
||||
},
|
||||
{
|
||||
name: "comma-separated non-quoted",
|
||||
model: JSONModel{Labels: `job=foo, instance=bar`},
|
||||
model: kinds.TestDataQuery{Labels: `job=foo, instance=bar`},
|
||||
expected: expectedTags,
|
||||
},
|
||||
{
|
||||
name: "comma-separated quoted",
|
||||
model: JSONModel{Labels: `job="foo"", instance="bar"`},
|
||||
model: kinds.TestDataQuery{Labels: `job="foo"", instance="bar"`},
|
||||
expected: expectedTags,
|
||||
},
|
||||
{
|
||||
name: "comma-separated with spaces, non quoted",
|
||||
model: JSONModel{Labels: `job = foo,instance = bar`},
|
||||
model: kinds.TestDataQuery{Labels: `job = foo,instance = bar`},
|
||||
expected: expectedTags,
|
||||
},
|
||||
{
|
||||
name: "expands $seriesIndex",
|
||||
model: JSONModel{Labels: `job=series-$seriesIndex,instance=bar`},
|
||||
model: kinds.TestDataQuery{Labels: `job=series-$seriesIndex,instance=bar`},
|
||||
expected: data.Labels{
|
||||
"job": fmt.Sprintf("series-%d", seriesIndex),
|
||||
"instance": "bar",
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||
|
||||
"github.com/grafana/grafana/pkg/tsdb/grafana-testdata-datasource/kinds"
|
||||
"github.com/grafana/grafana/pkg/tsdb/grafana-testdata-datasource/sims"
|
||||
)
|
||||
|
||||
@@ -19,7 +20,7 @@ import (
|
||||
func ProvideService() *Service {
|
||||
s := &Service{
|
||||
queryMux: datasource.NewQueryTypeMux(),
|
||||
scenarios: map[string]*Scenario{},
|
||||
scenarios: map[kinds.TestDataQueryType]*Scenario{},
|
||||
frame: data.NewFrame("testdata",
|
||||
data.NewField("Time", nil, make([]time.Time, 1)),
|
||||
data.NewField("Value", nil, make([]float64, 1)),
|
||||
@@ -48,7 +49,7 @@ func ProvideService() *Service {
|
||||
|
||||
type Service struct {
|
||||
logger log.Logger
|
||||
scenarios map[string]*Scenario
|
||||
scenarios map[kinds.TestDataQueryType]*Scenario
|
||||
frame *data.Frame
|
||||
labelFrame *data.Frame
|
||||
queryMux *datasource.QueryTypeMux
|
||||
|
||||
Reference in New Issue
Block a user