K8s: Add basic query service (#80325)
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
// +k8s:deepcopy-gen=package
|
||||
// +k8s:openapi-gen=true
|
||||
// +k8s:defaulter-gen=TypeMeta
|
||||
// +groupName=query.grafana.app
|
||||
|
||||
package v0alpha1
|
||||
@@ -0,0 +1,211 @@
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// Generic query request with shared time across all values
|
||||
// Copied from: https://github.com/grafana/grafana/blob/main/pkg/api/dtos/models.go#L62
|
||||
type GenericQueryRequest struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
// From Start time in epoch timestamps in milliseconds or relative using Grafana time units.
|
||||
// example: now-1h
|
||||
From string `json:"from,omitempty"`
|
||||
|
||||
// To End time in epoch timestamps in milliseconds or relative using Grafana time units.
|
||||
// example: now
|
||||
To string `json:"to,omitempty"`
|
||||
|
||||
// queries.refId – Specifies an identifier of the query. Is optional and default to “A”.
|
||||
// queries.datasourceId – Specifies the data source to be queried. Each query in the request must have an unique datasourceId.
|
||||
// queries.maxDataPoints - Species maximum amount of data points that dashboard panel can render. Is optional and default to 100.
|
||||
// queries.intervalMs - Specifies the time interval in milliseconds of time series. Is optional and defaults to 1000.
|
||||
// required: true
|
||||
// example: [ { "refId": "A", "intervalMs": 86400000, "maxDataPoints": 1092, "datasource":{ "uid":"PD8C576611E62080A" }, "rawSql": "SELECT 1 as valueOne, 2 as valueTwo", "format": "table" } ]
|
||||
Queries []GenericDataQuery `json:"queries"`
|
||||
|
||||
// required: false
|
||||
Debug bool `json:"debug,omitempty"`
|
||||
}
|
||||
|
||||
type DataSourceRef struct {
|
||||
// The datasource plugin type
|
||||
Type string `json:"type"`
|
||||
|
||||
// Datasource UID
|
||||
UID string `json:"uid"`
|
||||
}
|
||||
|
||||
// GenericDataQuery is a replacement for `dtos.MetricRequest` that provides more explicit types
|
||||
type GenericDataQuery struct {
|
||||
// RefID is the unique identifier of the query, set by the frontend call.
|
||||
RefID string `json:"refId"`
|
||||
|
||||
// TimeRange represents the query range
|
||||
// NOTE: unlike generic /ds/query, we can now send explicit time values in each query
|
||||
TimeRange *TimeRange `json:"timeRange,omitempty"`
|
||||
|
||||
// The datasource
|
||||
Datasource *DataSourceRef `json:"datasource,omitempty"`
|
||||
|
||||
// Deprecated -- use datasource ref instead
|
||||
DatasourceId int64 `json:"datasourceId,omitempty"`
|
||||
|
||||
// QueryType is an optional identifier for the type of query.
|
||||
// It can be used to distinguish different types of queries.
|
||||
QueryType string `json:"queryType,omitempty"`
|
||||
|
||||
// MaxDataPoints is the maximum number of data points that should be returned from a time series query.
|
||||
MaxDataPoints int64 `json:"maxDataPoints,omitempty"`
|
||||
|
||||
// Interval is the suggested duration between time points in a time series query.
|
||||
IntervalMS float64 `json:"intervalMs,omitempty"`
|
||||
|
||||
// true if query is disabled (ie should not be returned to the dashboard)
|
||||
// Note this does not always imply that the query should not be executed since
|
||||
// the results from a hidden query may be used as the input to other queries (SSE etc)
|
||||
Hide bool `json:"hide,omitempty"`
|
||||
|
||||
// Additional Properties (that live at the root)
|
||||
props map[string]any `json:"-"`
|
||||
}
|
||||
|
||||
// TimeRange represents a time range for a query and is a property of DataQuery.
|
||||
type TimeRange struct {
|
||||
// From is the start time of the query.
|
||||
From string `json:"from"`
|
||||
|
||||
// To is the end time of the query.
|
||||
To string `json:"to"`
|
||||
}
|
||||
|
||||
func (g *GenericDataQuery) AdditionalProperties() map[string]any {
|
||||
if g.props == nil {
|
||||
g.props = make(map[string]any)
|
||||
}
|
||||
return g.props
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (g *GenericDataQuery) DeepCopyInto(out *GenericDataQuery) {
|
||||
*out = *g
|
||||
if g.props != nil {
|
||||
out.props = runtime.DeepCopyJSON(g.props)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericDataQuery.
|
||||
func (g *GenericDataQuery) DeepCopy() *GenericDataQuery {
|
||||
if g == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(GenericDataQuery)
|
||||
g.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// MarshalJSON ensures that the unstructured object produces proper
|
||||
// JSON when passed to Go's standard JSON library.
|
||||
func (g GenericDataQuery) MarshalJSON() ([]byte, error) {
|
||||
vals := map[string]any{}
|
||||
if g.props != nil {
|
||||
for k, v := range g.props {
|
||||
vals[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
vals["refId"] = g.RefID
|
||||
if g.Datasource.Type != "" || g.Datasource.UID != "" {
|
||||
vals["datasource"] = g.Datasource
|
||||
}
|
||||
if g.DatasourceId > 0 {
|
||||
vals["datasourceId"] = g.DatasourceId
|
||||
}
|
||||
if g.IntervalMS > 0 {
|
||||
vals["intervalMs"] = g.IntervalMS
|
||||
}
|
||||
if g.MaxDataPoints > 0 {
|
||||
vals["maxDataPoints"] = g.MaxDataPoints
|
||||
}
|
||||
return json.Marshal(vals)
|
||||
}
|
||||
|
||||
// UnmarshalJSON ensures that the unstructured object properly decodes
|
||||
// JSON when passed to Go's standard JSON library.
|
||||
func (g *GenericDataQuery) UnmarshalJSON(b []byte) error {
|
||||
vals := map[string]any{}
|
||||
err := json.Unmarshal(b, &vals)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key := "refId"
|
||||
v, ok := vals[key]
|
||||
if ok {
|
||||
g.RefID, ok = v.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected string refid (got: %t)", v)
|
||||
}
|
||||
delete(vals, key)
|
||||
}
|
||||
|
||||
key = "datasource"
|
||||
v, ok = vals[key]
|
||||
if ok {
|
||||
wrap, ok := v.(map[string]any)
|
||||
if ok {
|
||||
g.Datasource = &DataSourceRef{}
|
||||
g.Datasource.Type, _ = wrap["type"].(string)
|
||||
g.Datasource.UID, _ = wrap["uid"].(string)
|
||||
delete(vals, key)
|
||||
} else {
|
||||
// Old old queries may arrive with just the name
|
||||
name, ok := v.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected datasource as object (got: %t)", v)
|
||||
}
|
||||
g.Datasource = &DataSourceRef{}
|
||||
g.Datasource.UID = name // Not great, but the lookup function will try its best to resolve
|
||||
delete(vals, key)
|
||||
}
|
||||
}
|
||||
|
||||
key = "intervalMs"
|
||||
v, ok = vals[key]
|
||||
if ok {
|
||||
g.IntervalMS, ok = v.(float64)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected intervalMs as float (got: %t)", v)
|
||||
}
|
||||
delete(vals, key)
|
||||
}
|
||||
|
||||
key = "maxDataPoints"
|
||||
v, ok = vals[key]
|
||||
if ok {
|
||||
count, ok := v.(float64)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected maxDataPoints as number (got: %t)", v)
|
||||
}
|
||||
g.MaxDataPoints = int64(count)
|
||||
delete(vals, key)
|
||||
}
|
||||
|
||||
key = "datasourceId"
|
||||
v, ok = vals[key]
|
||||
if ok {
|
||||
count, ok := v.(float64)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected datasourceId as number (got: %t)", v)
|
||||
}
|
||||
g.DatasourceId = int64(count)
|
||||
delete(vals, key)
|
||||
}
|
||||
|
||||
g.props = vals
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package v0alpha1_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apis/query/v0alpha1"
|
||||
)
|
||||
|
||||
func TestParseQueriesIntoQueryDataRequest(t *testing.T) {
|
||||
request := []byte(`{
|
||||
"queries": [
|
||||
{
|
||||
"refId": "A",
|
||||
"datasource": {
|
||||
"type": "grafana-googlesheets-datasource",
|
||||
"uid": "b1808c48-9fc9-4045-82d7-081781f8a553"
|
||||
},
|
||||
"cacheDurationSeconds": 300,
|
||||
"spreadsheet": "spreadsheetID",
|
||||
"datasourceId": 4,
|
||||
"intervalMs": 30000,
|
||||
"maxDataPoints": 794
|
||||
},
|
||||
{
|
||||
"refId": "Z",
|
||||
"datasource": "old",
|
||||
"maxDataPoints": 10,
|
||||
"timeRange": {
|
||||
"from": "100",
|
||||
"to": "200"
|
||||
}
|
||||
}
|
||||
],
|
||||
"from": "1692624667389",
|
||||
"to": "1692646267389"
|
||||
}`)
|
||||
|
||||
req := &v0alpha1.GenericQueryRequest{}
|
||||
err := json.Unmarshal(request, req)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, req.Queries, 2)
|
||||
require.Equal(t, "b1808c48-9fc9-4045-82d7-081781f8a553", req.Queries[0].Datasource.UID)
|
||||
require.Equal(t, "spreadsheetID", req.Queries[0].AdditionalProperties()["spreadsheet"])
|
||||
|
||||
// Write the query (with additional spreadsheetID) to JSON
|
||||
out, err := json.MarshalIndent(req.Queries[0], "", " ")
|
||||
require.NoError(t, err)
|
||||
|
||||
// And read it back with standard JSON marshal functions
|
||||
query := &v0alpha1.GenericDataQuery{}
|
||||
err = json.Unmarshal(out, query)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "spreadsheetID", query.AdditionalProperties()["spreadsheet"])
|
||||
|
||||
// The second query has an explicit time range, and legacy datasource name
|
||||
out, err = json.MarshalIndent(req.Queries[1], "", " ")
|
||||
require.NoError(t, err)
|
||||
// fmt.Printf("%s\n", string(out))
|
||||
require.JSONEq(t, `{
|
||||
"datasource": {
|
||||
"type": "", ` /* NOTE! this implies legacy naming */ +`
|
||||
"uid": "old"
|
||||
},
|
||||
"maxDataPoints": 10,
|
||||
"refId": "Z",
|
||||
"timeRange": {
|
||||
"from": "100",
|
||||
"to": "200"
|
||||
}
|
||||
}`, string(out))
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
common "github.com/grafana/grafana/pkg/apis/common/v0alpha1"
|
||||
)
|
||||
|
||||
const (
|
||||
GROUP = "query.grafana.app"
|
||||
VERSION = "v0alpha1"
|
||||
APIVERSION = GROUP + "/" + VERSION
|
||||
)
|
||||
|
||||
var DataSourceApiServerResourceInfo = common.NewResourceInfo(GROUP, VERSION,
|
||||
"datasourceapiservers", "datasourceapiserver", "DataSourceApiServer",
|
||||
func() runtime.Object { return &DataSourceApiServer{} },
|
||||
func() runtime.Object { return &DataSourceApiServerList{} },
|
||||
)
|
||||
|
||||
var (
|
||||
// SchemeGroupVersion is group version used to register these objects
|
||||
SchemeGroupVersion = schema.GroupVersion{Group: GROUP, Version: VERSION}
|
||||
)
|
||||
@@ -0,0 +1,64 @@
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
openapi "k8s.io/kube-openapi/pkg/common"
|
||||
spec "k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
// Wraps backend.QueryDataResponse, however it includes TypeMeta and implements runtime.Object
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type QueryDataResponse struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
// Backend wrapper (external dependency)
|
||||
backend.QueryDataResponse
|
||||
}
|
||||
|
||||
// Expose backend DataResponse in OpenAPI (yes this still requires some serious love!)
|
||||
func (r QueryDataResponse) OpenAPIDefinition() openapi.OpenAPIDefinition {
|
||||
return openapi.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"object"},
|
||||
AdditionalProperties: &spec.SchemaOrBool{Allows: true},
|
||||
},
|
||||
VendorExtensible: spec.VendorExtensible{
|
||||
Extensions: map[string]interface{}{
|
||||
"x-kubernetes-preserve-unknown-fields": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalJSON writes the results as json
|
||||
func (r QueryDataResponse) MarshalJSON() ([]byte, error) {
|
||||
return r.QueryDataResponse.MarshalJSON()
|
||||
}
|
||||
|
||||
// UnmarshalJSON will read JSON into a QueryDataResponse
|
||||
func (r *QueryDataResponse) UnmarshalJSON(b []byte) error {
|
||||
return r.QueryDataResponse.UnmarshalJSON(b)
|
||||
}
|
||||
|
||||
func (r *QueryDataResponse) DeepCopy() *QueryDataResponse {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// /!\ The most dumb approach, but OK for now...
|
||||
// likely best to move DeepCopy into SDK
|
||||
out := &QueryDataResponse{}
|
||||
body, _ := json.Marshal(r.QueryDataResponse)
|
||||
_ = json.Unmarshal(body, &out.QueryDataResponse)
|
||||
return out
|
||||
}
|
||||
|
||||
func (r *QueryDataResponse) DeepCopyInto(out *QueryDataResponse) {
|
||||
clone := r.DeepCopy()
|
||||
*out = *clone
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// The query runner interface
|
||||
type QueryRunner interface {
|
||||
// Runs the query as the user in context
|
||||
ExecuteQueryData(ctx context.Context,
|
||||
// The k8s group for the datasource (pluginId)
|
||||
datasource schema.GroupVersion,
|
||||
|
||||
// The datasource name/uid
|
||||
name string,
|
||||
|
||||
// The raw backend query objects
|
||||
query []GenericDataQuery,
|
||||
) (*backend.QueryDataResponse, error)
|
||||
}
|
||||
|
||||
type DataSourceApiServerRegistry interface {
|
||||
// Get the group and preferred version for a plugin
|
||||
GetDatasourceGroupVersion(pluginId string) (schema.GroupVersion, error)
|
||||
|
||||
// Get the list of available datasource api servers
|
||||
// The values will be managed though API discovery/reconciliation
|
||||
GetDatasourceApiServers(ctx context.Context) (*DataSourceApiServerList, error)
|
||||
}
|
||||
|
||||
// The data source resource is a reflection of the individual datasource instances
|
||||
// that are exposed in the groups: {datasource}.datasource.grafana.app
|
||||
// The status is updated periodically.
|
||||
// The name is the plugin id
|
||||
//
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type DataSourceApiServer struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
// The display name
|
||||
Title string `json:"title"`
|
||||
|
||||
// Describe the plugin
|
||||
Description string `json:"description,omitempty"`
|
||||
|
||||
// The group + preferred version
|
||||
GroupVersion string `json:"groupVersion"`
|
||||
|
||||
// Possible alternative plugin IDs
|
||||
AliasIDs []string `json:"aliasIDs,omitempty"`
|
||||
}
|
||||
|
||||
// List of datasource plugins
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type DataSourceApiServerList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
|
||||
Items []DataSourceApiServer `json:"items,omitempty"`
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
//go:build !ignore_autogenerated
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
// Code generated by deepcopy-gen. DO NOT EDIT.
|
||||
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DataSourceApiServer) DeepCopyInto(out *DataSourceApiServer) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
if in.AliasIDs != nil {
|
||||
in, out := &in.AliasIDs, &out.AliasIDs
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataSourceApiServer.
|
||||
func (in *DataSourceApiServer) DeepCopy() *DataSourceApiServer {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DataSourceApiServer)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *DataSourceApiServer) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DataSourceApiServerList) DeepCopyInto(out *DataSourceApiServerList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]DataSourceApiServer, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataSourceApiServerList.
|
||||
func (in *DataSourceApiServerList) DeepCopy() *DataSourceApiServerList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DataSourceApiServerList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *DataSourceApiServerList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DataSourceRef) DeepCopyInto(out *DataSourceRef) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataSourceRef.
|
||||
func (in *DataSourceRef) DeepCopy() *DataSourceRef {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DataSourceRef)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *GenericQueryRequest) DeepCopyInto(out *GenericQueryRequest) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if in.Queries != nil {
|
||||
in, out := &in.Queries, &out.Queries
|
||||
*out = make([]GenericDataQuery, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericQueryRequest.
|
||||
func (in *GenericQueryRequest) DeepCopy() *GenericQueryRequest {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(GenericQueryRequest)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *QueryDataResponse) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TimeRange) DeepCopyInto(out *TimeRange) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TimeRange.
|
||||
func (in *TimeRange) DeepCopy() *TimeRange {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(TimeRange)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
//go:build !ignore_autogenerated
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
// Code generated by defaulter-gen. DO NOT EDIT.
|
||||
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// RegisterDefaults adds defaulters functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
// All generated defaulters are covering - they call all nested defaulters.
|
||||
func RegisterDefaults(scheme *runtime.Scheme) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
//go:build !ignore_autogenerated
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
// Code generated by openapi-gen. DO NOT EDIT.
|
||||
|
||||
// This file was autogenerated by openapi-gen. Do not edit it manually!
|
||||
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
common "k8s.io/kube-openapi/pkg/common"
|
||||
spec "k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition {
|
||||
return map[string]common.OpenAPIDefinition{
|
||||
"github.com/grafana/grafana/pkg/apis/query/v0alpha1.DataSourceApiServer": schema_pkg_apis_query_v0alpha1_DataSourceApiServer(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/query/v0alpha1.DataSourceApiServerList": schema_pkg_apis_query_v0alpha1_DataSourceApiServerList(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/query/v0alpha1.DataSourceRef": schema_pkg_apis_query_v0alpha1_DataSourceRef(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/query/v0alpha1.GenericDataQuery": schema_pkg_apis_query_v0alpha1_GenericDataQuery(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/query/v0alpha1.GenericQueryRequest": schema_pkg_apis_query_v0alpha1_GenericQueryRequest(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/query/v0alpha1.QueryDataResponse": QueryDataResponse{}.OpenAPIDefinition(),
|
||||
"github.com/grafana/grafana/pkg/apis/query/v0alpha1.TimeRange": schema_pkg_apis_query_v0alpha1_TimeRange(ref),
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_query_v0alpha1_DataSourceApiServer(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The data source resource is a reflection of the individual datasource instances that are exposed in the groups: {datasource}.datasource.grafana.app The status is updated periodically. The name is the plugin id",
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"kind": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"apiVersion": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"metadata": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"),
|
||||
},
|
||||
},
|
||||
"title": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The display name",
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"description": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Describe the plugin",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"groupVersion": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The group + preferred version",
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"aliasIDs": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Possible alternative plugin IDs",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"title", "groupVersion"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_query_v0alpha1_DataSourceApiServerList(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "List of datasource plugins",
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"kind": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"apiVersion": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"metadata": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"),
|
||||
},
|
||||
},
|
||||
"items": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/pkg/apis/query/v0alpha1.DataSourceApiServer"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"github.com/grafana/grafana/pkg/apis/query/v0alpha1.DataSourceApiServer", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_query_v0alpha1_DataSourceRef(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"type": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The datasource plugin type",
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"uid": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Datasource UID",
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"type", "uid"},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_query_v0alpha1_GenericDataQuery(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "GenericDataQuery is a replacement for `dtos.MetricRequest` that provides more explicit types",
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"refId": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "RefID is the unique identifier of the query, set by the frontend call.",
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"timeRange": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "TimeRange represents the query range NOTE: unlike generic /ds/query, we can now send explicit time values in each query",
|
||||
Ref: ref("github.com/grafana/grafana/pkg/apis/query/v0alpha1.TimeRange"),
|
||||
},
|
||||
},
|
||||
"datasource": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The datasource",
|
||||
Ref: ref("github.com/grafana/grafana/pkg/apis/query/v0alpha1.DataSourceRef"),
|
||||
},
|
||||
},
|
||||
"datasourceId": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Deprecated -- use datasource ref instead",
|
||||
Type: []string{"integer"},
|
||||
Format: "int64",
|
||||
},
|
||||
},
|
||||
"queryType": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "QueryType is an optional identifier for the type of query. It can be used to distinguish different types of queries.",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"maxDataPoints": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "MaxDataPoints is the maximum number of data points that should be returned from a time series query.",
|
||||
Type: []string{"integer"},
|
||||
Format: "int64",
|
||||
},
|
||||
},
|
||||
"intervalMs": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Interval is the suggested duration between time points in a time series query.",
|
||||
Type: []string{"number"},
|
||||
Format: "double",
|
||||
},
|
||||
},
|
||||
"hide": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "true if query is disabled (ie should not be returned to the dashboard) Note this does not always imply that the query should not be executed since the results from a hidden query may be used as the input to other queries (SSE etc)",
|
||||
Type: []string{"boolean"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"refId"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"github.com/grafana/grafana/pkg/apis/query/v0alpha1.DataSourceRef", "github.com/grafana/grafana/pkg/apis/query/v0alpha1.TimeRange"},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_query_v0alpha1_GenericQueryRequest(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Generic query request with shared time across all values Copied from: https://github.com/grafana/grafana/blob/main/pkg/api/dtos/models.go#L62",
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"kind": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"apiVersion": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"from": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "From Start time in epoch timestamps in milliseconds or relative using Grafana time units. example: now-1h",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"to": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "To End time in epoch timestamps in milliseconds or relative using Grafana time units. example: now",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"queries": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "queries.refId – Specifies an identifier of the query. Is optional and default to “A”. queries.datasourceId – Specifies the data source to be queried. Each query in the request must have an unique datasourceId. queries.maxDataPoints - Species maximum amount of data points that dashboard panel can render. Is optional and default to 100. queries.intervalMs - Specifies the time interval in milliseconds of time series. Is optional and defaults to 1000. required: true example: [ { \"refId\": \"A\", \"intervalMs\": 86400000, \"maxDataPoints\": 1092, \"datasource\":{ \"uid\":\"PD8C576611E62080A\" }, \"rawSql\": \"SELECT 1 as valueOne, 2 as valueTwo\", \"format\": \"table\" } ]",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Ref: ref("github.com/grafana/grafana/pkg/apis/query/v0alpha1.GenericDataQuery"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"debug": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "required: false",
|
||||
Type: []string{"boolean"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"queries"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"github.com/grafana/grafana/pkg/apis/query/v0alpha1.GenericDataQuery"},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_query_v0alpha1_TimeRange(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "TimeRange represents a time range for a query and is a property of DataQuery.",
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"from": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "From is the start time of the query.",
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"to": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "To is the end time of the query.",
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"from", "to"},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/query/v0alpha1,DataSourceApiServer,AliasIDs
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/pkg/apis/query/v0alpha1,GenericQueryRequest,Queries
|
||||
API rule violation: names_match,github.com/grafana/grafana/pkg/apis/query/v0alpha1,GenericDataQuery,IntervalMS
|
||||
API rule violation: names_match,github.com/grafana/grafana/pkg/apis/query/v0alpha1,GenericDataQuery,RefID
|
||||
API rule violation: names_match,github.com/grafana/grafana/pkg/apis/query/v0alpha1,QueryDataResponse,QueryDataResponse
|
||||
Reference in New Issue
Block a user