merge main
This commit is contained in:
@@ -38,29 +38,3 @@ var DataSourceResourceInfo = utils.NewResourceInfo(GROUP, VERSION,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
var ConnectionResourceInfo = utils.NewResourceInfo(GROUP, VERSION,
|
||||
"connections", "connection", "DataSourceConnection",
|
||||
func() runtime.Object { return &DataSourceConnection{} },
|
||||
func() runtime.Object { return &DataSourceConnectionList{} },
|
||||
utils.TableColumns{
|
||||
Definition: []metav1.TableColumnDefinition{
|
||||
{Name: "Name", Type: "string", Format: "name"},
|
||||
{Name: "Title", Type: "string", Format: "string", Description: "The datasource title"},
|
||||
{Name: "APIVersion", Type: "string", Format: "string", Description: "API Version"},
|
||||
{Name: "Created At", Type: "date"},
|
||||
},
|
||||
Reader: func(obj any) ([]interface{}, error) {
|
||||
m, ok := obj.(*DataSourceConnection)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected connection")
|
||||
}
|
||||
return []interface{}{
|
||||
m.Name,
|
||||
m.Title,
|
||||
m.APIVersion,
|
||||
m.CreationTimestamp.UTC().Format(time.RFC3339),
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
@@ -6,26 +6,6 @@ import (
|
||||
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
|
||||
)
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type DataSourceConnection struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
// The display name
|
||||
Title string `json:"title"`
|
||||
|
||||
// Optional description for the data source (does not exist yet)
|
||||
Description string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type DataSourceConnectionList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
|
||||
Items []DataSourceConnection `json:"items"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type HealthCheckResult struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
secretv0alpha1 "github.com/grafana/grafana/pkg/apis/secret/v0alpha1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
secretv0alpha1 "github.com/grafana/grafana/pkg/apis/secret/v0alpha1"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
@@ -46,65 +47,6 @@ func (in *DataSource) DeepCopyObject() runtime.Object {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DataSourceConnection) DeepCopyInto(out *DataSourceConnection) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataSourceConnection.
|
||||
func (in *DataSourceConnection) DeepCopy() *DataSourceConnection {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DataSourceConnection)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *DataSourceConnection) 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 *DataSourceConnectionList) DeepCopyInto(out *DataSourceConnectionList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]DataSourceConnection, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataSourceConnectionList.
|
||||
func (in *DataSourceConnectionList) DeepCopy() *DataSourceConnectionList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DataSourceConnectionList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *DataSourceConnectionList) 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 *DataSourceList) DeepCopyInto(out *DataSourceList) {
|
||||
*out = *in
|
||||
|
||||
@@ -7,6 +7,28 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// Connection to a datasource instance
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type DataSourceConnection struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
// The display name
|
||||
Title string `json:"title"`
|
||||
|
||||
// Optional description for the data source (does not exist yet)
|
||||
Description string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// List of all datasource instances across all datasource apiservers
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type DataSourceConnectionList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
|
||||
Items []DataSourceConnection `json:"items"`
|
||||
}
|
||||
|
||||
type DataSourceApiServerRegistry interface {
|
||||
// Get the group and preferred version for a plugin
|
||||
GetDatasourceGroupVersion(pluginId string) (schema.GroupVersion, error)
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package v0alpha1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
@@ -13,6 +17,32 @@ const (
|
||||
APIVERSION = GROUP + "/" + VERSION
|
||||
)
|
||||
|
||||
var ConnectionResourceInfo = utils.NewResourceInfo(GROUP, VERSION,
|
||||
"connections", "connection", "DataSourceConnection",
|
||||
func() runtime.Object { return &DataSourceConnection{} },
|
||||
func() runtime.Object { return &DataSourceConnectionList{} },
|
||||
utils.TableColumns{
|
||||
Definition: []metav1.TableColumnDefinition{
|
||||
{Name: "Name", Type: "string", Format: "name"},
|
||||
{Name: "Title", Type: "string", Format: "string", Description: "The datasource title"},
|
||||
{Name: "APIVersion", Type: "string", Format: "string", Description: "API Version"},
|
||||
{Name: "Created At", Type: "date"},
|
||||
},
|
||||
Reader: func(obj any) ([]interface{}, error) {
|
||||
m, ok := obj.(*DataSourceConnection)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected connection")
|
||||
}
|
||||
return []interface{}{
|
||||
m.Name,
|
||||
m.Title,
|
||||
m.APIVersion,
|
||||
m.CreationTimestamp.UTC().Format(time.RFC3339),
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
var DataSourceApiServerResourceInfo = utils.NewResourceInfo(GROUP, VERSION,
|
||||
"datasourceapiservers", "datasourceapiserver", "DataSourceApiServer",
|
||||
func() runtime.Object { return &DataSourceApiServer{} },
|
||||
|
||||
@@ -75,6 +75,65 @@ func (in *DataSourceApiServerList) DeepCopyObject() runtime.Object {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DataSourceConnection) DeepCopyInto(out *DataSourceConnection) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataSourceConnection.
|
||||
func (in *DataSourceConnection) DeepCopy() *DataSourceConnection {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DataSourceConnection)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *DataSourceConnection) 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 *DataSourceConnectionList) DeepCopyInto(out *DataSourceConnectionList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]DataSourceConnection, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataSourceConnectionList.
|
||||
func (in *DataSourceConnectionList) DeepCopy() *DataSourceConnectionList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DataSourceConnectionList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *DataSourceConnectionList) 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 *QueryDataRequest) DeepCopyInto(out *QueryDataRequest) {
|
||||
*out = *in
|
||||
|
||||
@@ -14,12 +14,14 @@ import (
|
||||
|
||||
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.QueryDataRequest": schema_pkg_apis_query_v0alpha1_QueryDataRequest(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/query/v0alpha1.QueryDataResponse": schema_pkg_apis_query_v0alpha1_QueryDataResponse(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/query/v0alpha1.QueryTypeDefinition": schema_pkg_apis_query_v0alpha1_QueryTypeDefinition(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/query/v0alpha1.QueryTypeDefinitionList": schema_pkg_apis_query_v0alpha1_QueryTypeDefinitionList(ref),
|
||||
"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.DataSourceConnection": schema_pkg_apis_query_v0alpha1_DataSourceConnection(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/query/v0alpha1.DataSourceConnectionList": schema_pkg_apis_query_v0alpha1_DataSourceConnectionList(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/query/v0alpha1.QueryDataRequest": schema_pkg_apis_query_v0alpha1_QueryDataRequest(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/query/v0alpha1.QueryDataResponse": schema_pkg_apis_query_v0alpha1_QueryDataResponse(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/query/v0alpha1.QueryTypeDefinition": schema_pkg_apis_query_v0alpha1_QueryTypeDefinition(ref),
|
||||
"github.com/grafana/grafana/pkg/apis/query/v0alpha1.QueryTypeDefinitionList": schema_pkg_apis_query_v0alpha1_QueryTypeDefinitionList(ref),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,6 +148,106 @@ func schema_pkg_apis_query_v0alpha1_DataSourceApiServerList(ref common.Reference
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_query_v0alpha1_DataSourceConnection(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Connection to a datasource instance",
|
||||
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: "Optional description for the data source (does not exist yet)",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"title"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_query_v0alpha1_DataSourceConnectionList(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "List of all datasource instances across all datasource apiservers",
|
||||
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.DataSourceConnection"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"items"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"github.com/grafana/grafana/pkg/apis/query/v0alpha1.DataSourceConnection", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_query_v0alpha1_QueryDataRequest(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
|
||||
@@ -25,7 +25,7 @@ func (b *DataSourceAPIBuilder) GetAuthorizer() authorizer.Authorizer {
|
||||
uidScope := datasources.ScopeProvider.GetResourceScopeUID(attr.GetName())
|
||||
|
||||
// Must have query access to see a connection
|
||||
if attr.GetResource() == b.connectionResourceInfo.GroupResource().Resource {
|
||||
if attr.GetResource() == b.datasourceResourceInfo.GroupResource().Resource {
|
||||
scopes := []string{}
|
||||
if attr.GetName() != "" {
|
||||
scopes = []string{uidScope}
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
package datasource
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/internalversion"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
_ rest.Scoper = (*connectionAccess)(nil)
|
||||
_ rest.SingularNameProvider = (*connectionAccess)(nil)
|
||||
_ rest.Getter = (*connectionAccess)(nil)
|
||||
_ rest.Lister = (*connectionAccess)(nil)
|
||||
_ rest.Storage = (*connectionAccess)(nil)
|
||||
)
|
||||
|
||||
type connectionAccess struct {
|
||||
resourceInfo utils.ResourceInfo
|
||||
tableConverter rest.TableConvertor
|
||||
datasources PluginDatasourceProvider
|
||||
}
|
||||
|
||||
func (s *connectionAccess) New() runtime.Object {
|
||||
return s.resourceInfo.NewFunc()
|
||||
}
|
||||
|
||||
func (s *connectionAccess) Destroy() {}
|
||||
|
||||
func (s *connectionAccess) NamespaceScoped() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *connectionAccess) GetSingularName() string {
|
||||
return s.resourceInfo.GetSingularName()
|
||||
}
|
||||
|
||||
func (s *connectionAccess) ShortNames() []string {
|
||||
return s.resourceInfo.GetShortNames()
|
||||
}
|
||||
|
||||
func (s *connectionAccess) NewList() runtime.Object {
|
||||
return s.resourceInfo.NewListFunc()
|
||||
}
|
||||
|
||||
func (s *connectionAccess) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) {
|
||||
return s.tableConverter.ConvertToTable(ctx, object, tableOptions)
|
||||
}
|
||||
|
||||
func (s *connectionAccess) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
|
||||
return s.datasources.GetConnection(ctx, name)
|
||||
}
|
||||
|
||||
func (s *connectionAccess) List(ctx context.Context, options *internalversion.ListOptions) (runtime.Object, error) {
|
||||
return s.datasources.ListConnections(ctx)
|
||||
}
|
||||
@@ -10,7 +10,8 @@ import (
|
||||
"github.com/grafana/authlib/types"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
"github.com/grafana/grafana/pkg/apis/datasource/v0alpha1"
|
||||
secret "github.com/grafana/grafana/pkg/apis/secret/v0alpha1"
|
||||
datasourceV0 "github.com/grafana/grafana/pkg/apis/datasource/v0alpha1"
|
||||
secretV0 "github.com/grafana/grafana/pkg/apis/secret/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
||||
gapiutil "github.com/grafana/grafana/pkg/services/apiserver/utils"
|
||||
@@ -23,31 +24,8 @@ type converter struct {
|
||||
dstype string // the expected pluginId
|
||||
}
|
||||
|
||||
func asConnection(ds *datasources.DataSource, ns string) (*v0alpha1.DataSourceConnection, error) {
|
||||
v := &v0alpha1.DataSourceConnection{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: ds.UID,
|
||||
Namespace: ns,
|
||||
CreationTimestamp: metav1.NewTime(ds.Created),
|
||||
ResourceVersion: fmt.Sprintf("%d", ds.Updated.UnixMilli()),
|
||||
Generation: int64(ds.Version),
|
||||
},
|
||||
Title: ds.Name,
|
||||
}
|
||||
v.UID = gapiutil.CalculateClusterWideUID(v) // indicates if the value changed on the server
|
||||
meta, err := utils.MetaAccessor(v)
|
||||
if err != nil {
|
||||
meta.SetUpdatedTimestamp(&ds.Updated)
|
||||
}
|
||||
return v, err
|
||||
}
|
||||
|
||||
func (r *converter) asConnection(ds *datasources.DataSource) (*v0alpha1.DataSourceConnection, error) {
|
||||
return asConnection(ds, r.mapper(ds.OrgID))
|
||||
}
|
||||
|
||||
func (r *converter) asDataSource(ds *datasources.DataSource) (*v0alpha1.DataSource, error) {
|
||||
cfg := &v0alpha1.DataSource{
|
||||
func (r *converter) asDataSource(ds *datasources.DataSource) (*datasourceV0.DataSource, error) {
|
||||
cfg := &datasourceV0.DataSource{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: ds.UID,
|
||||
Namespace: r.mapper(ds.OrgID),
|
||||
@@ -55,7 +33,7 @@ func (r *converter) asDataSource(ds *datasources.DataSource) (*v0alpha1.DataSour
|
||||
ResourceVersion: fmt.Sprintf("%d", ds.Updated.UnixMilli()),
|
||||
Generation: int64(ds.Version),
|
||||
},
|
||||
Spec: v0alpha1.DataSourceSpec{
|
||||
Spec: datasourceV0.DataSourceSpec{
|
||||
Title: ds.Name,
|
||||
Access: v0alpha1.DsAccess(ds.Access),
|
||||
URL: ds.URL,
|
||||
@@ -85,9 +63,9 @@ func (r *converter) asDataSource(ds *datasources.DataSource) (*v0alpha1.DataSour
|
||||
}
|
||||
|
||||
if ds.SecureJsonData != nil {
|
||||
cfg.Secure = make(secret.InlineSecureValues)
|
||||
cfg.Secure = make(secretV0.InlineSecureValues)
|
||||
for k := range ds.SecureJsonData {
|
||||
cfg.Secure[k] = secret.InlineSecureValue{
|
||||
cfg.Secure[k] = secretV0.InlineSecureValue{
|
||||
UID: "????", // ????
|
||||
}
|
||||
}
|
||||
@@ -96,7 +74,7 @@ func (r *converter) asDataSource(ds *datasources.DataSource) (*v0alpha1.DataSour
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func (r *converter) toAddCommand(ds *v0alpha1.DataSource) (*datasources.AddDataSourceCommand, error) {
|
||||
func (r *converter) toAddCommand(ds *datasourceV0.DataSource) (*datasources.AddDataSourceCommand, error) {
|
||||
if r.group != "" && !strings.HasPrefix(ds.APIVersion, r.group) {
|
||||
return nil, fmt.Errorf("expecting APIGroup: %s", r.group)
|
||||
}
|
||||
@@ -131,7 +109,7 @@ func (r *converter) toAddCommand(ds *v0alpha1.DataSource) (*datasources.AddDataS
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
func (r *converter) toUpdateCommand(ds *v0alpha1.DataSource) (*datasources.UpdateDataSourceCommand, error) {
|
||||
func (r *converter) toUpdateCommand(ds *datasourceV0.DataSource) (*datasources.UpdateDataSourceCommand, error) {
|
||||
if r.group != "" && !strings.HasPrefix(ds.APIVersion, r.group) {
|
||||
return nil, fmt.Errorf("expecting APIGroup: %s", r.group)
|
||||
}
|
||||
@@ -167,7 +145,7 @@ func (r *converter) toUpdateCommand(ds *v0alpha1.DataSource) (*datasources.Updat
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
func toSecureJsonData(ds *v0alpha1.DataSource) map[string]string {
|
||||
func toSecureJsonData(ds *datasourceV0.DataSource) map[string]string {
|
||||
if ds == nil || len(ds.Secure) < 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"github.com/grafana/authlib/types"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/apis/datasource/v0alpha1"
|
||||
datasourceV0 "github.com/grafana/grafana/pkg/apis/datasource/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
@@ -18,23 +18,17 @@ import (
|
||||
// Authorization checks will happen within each function, and the user in ctx will
|
||||
// limit which namespace/tenant/org we are talking to
|
||||
type PluginDatasourceProvider interface {
|
||||
// Get gets a specific datasource (that the user in context can see)
|
||||
GetConnection(ctx context.Context, uid string) (*v0alpha1.DataSourceConnection, error)
|
||||
|
||||
// List lists all data sources the user in context can see
|
||||
ListConnections(ctx context.Context) (*v0alpha1.DataSourceConnectionList, error)
|
||||
|
||||
// Get a single datasurce
|
||||
GetDataSource(ctx context.Context, uid string) (*v0alpha1.DataSource, error)
|
||||
GetDataSource(ctx context.Context, uid string) (*datasourceV0.DataSource, error)
|
||||
|
||||
// List all datasources
|
||||
ListDataSource(ctx context.Context) (*v0alpha1.DataSourceList, error)
|
||||
ListDataSource(ctx context.Context) (*datasourceV0.DataSourceList, error)
|
||||
|
||||
// Create a data source
|
||||
CreateDataSource(ctx context.Context, ds *v0alpha1.DataSource) (*v0alpha1.DataSource, error)
|
||||
CreateDataSource(ctx context.Context, ds *datasourceV0.DataSource) (*datasourceV0.DataSource, error)
|
||||
|
||||
// Update a data source
|
||||
UpdateDataSource(ctx context.Context, ds *v0alpha1.DataSource) (*v0alpha1.DataSource, error)
|
||||
UpdateDataSource(ctx context.Context, ds *datasourceV0.DataSource) (*datasourceV0.DataSource, error)
|
||||
|
||||
// Delete datasurce
|
||||
Delete(ctx context.Context, uid string) error
|
||||
@@ -102,42 +96,6 @@ var (
|
||||
_ ScopedPluginDatasourceProvider = (*cachingDatasourceProvider)(nil)
|
||||
)
|
||||
|
||||
func (q *scopedDatasourceProvider) GetConnection(ctx context.Context, uid string) (*v0alpha1.DataSourceConnection, error) {
|
||||
user, err := identity.GetRequester(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ds, err := q.dsCache.GetDatasourceByUID(ctx, uid, user, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return q.converter.asConnection(ds)
|
||||
}
|
||||
|
||||
func (q *scopedDatasourceProvider) ListConnections(ctx context.Context) (*v0alpha1.DataSourceConnectionList, error) {
|
||||
info, err := request.NamespaceInfoFrom(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dss, err := q.dsService.GetDataSourcesByType(ctx, &datasources.GetDataSourcesByTypeQuery{
|
||||
OrgID: info.OrgID,
|
||||
Type: q.plugin.ID,
|
||||
AliasIDs: q.plugin.AliasIDs,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := &v0alpha1.DataSourceConnectionList{
|
||||
Items: []v0alpha1.DataSourceConnection{},
|
||||
}
|
||||
for _, ds := range dss {
|
||||
v, _ := q.converter.asConnection(ds)
|
||||
result.Items = append(result.Items, *v)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (q *scopedDatasourceProvider) GetInstanceSettings(ctx context.Context, uid string) (*backend.DataSourceInstanceSettings, error) {
|
||||
if q.contextProvider == nil {
|
||||
return nil, fmt.Errorf("missing contextProvider")
|
||||
@@ -146,7 +104,7 @@ func (q *scopedDatasourceProvider) GetInstanceSettings(ctx context.Context, uid
|
||||
}
|
||||
|
||||
// CreateDataSource implements PluginDatasourceProvider.
|
||||
func (q *scopedDatasourceProvider) CreateDataSource(ctx context.Context, ds *v0alpha1.DataSource) (*v0alpha1.DataSource, error) {
|
||||
func (q *scopedDatasourceProvider) CreateDataSource(ctx context.Context, ds *datasourceV0.DataSource) (*datasourceV0.DataSource, error) {
|
||||
cmd, err := q.converter.toAddCommand(ds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -159,7 +117,7 @@ func (q *scopedDatasourceProvider) CreateDataSource(ctx context.Context, ds *v0a
|
||||
}
|
||||
|
||||
// UpdateDataSource implements PluginDatasourceProvider.
|
||||
func (q *scopedDatasourceProvider) UpdateDataSource(ctx context.Context, ds *v0alpha1.DataSource) (*v0alpha1.DataSource, error) {
|
||||
func (q *scopedDatasourceProvider) UpdateDataSource(ctx context.Context, ds *datasourceV0.DataSource) (*datasourceV0.DataSource, error) {
|
||||
cmd, err := q.converter.toUpdateCommand(ds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -193,7 +151,7 @@ func (q *scopedDatasourceProvider) Delete(ctx context.Context, uid string) error
|
||||
}
|
||||
|
||||
// GetDataSource implements PluginDatasourceProvider.
|
||||
func (q *scopedDatasourceProvider) GetDataSource(ctx context.Context, uid string) (*v0alpha1.DataSource, error) {
|
||||
func (q *scopedDatasourceProvider) GetDataSource(ctx context.Context, uid string) (*datasourceV0.DataSource, error) {
|
||||
user, err := identity.GetRequester(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -206,7 +164,7 @@ func (q *scopedDatasourceProvider) GetDataSource(ctx context.Context, uid string
|
||||
}
|
||||
|
||||
// ListDataSource implements PluginDatasourceProvider.
|
||||
func (q *scopedDatasourceProvider) ListDataSource(ctx context.Context) (*v0alpha1.DataSourceList, error) {
|
||||
func (q *scopedDatasourceProvider) ListDataSource(ctx context.Context) (*datasourceV0.DataSourceList, error) {
|
||||
info, err := request.NamespaceInfoFrom(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -220,8 +178,8 @@ func (q *scopedDatasourceProvider) ListDataSource(ctx context.Context) (*v0alpha
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := &v0alpha1.DataSourceList{
|
||||
Items: []v0alpha1.DataSource{},
|
||||
result := &datasourceV0.DataSourceList{
|
||||
Items: []datasourceV0.DataSource{},
|
||||
}
|
||||
for _, ds := range dss {
|
||||
v, _ := q.converter.asDataSource(ds)
|
||||
|
||||
@@ -3,12 +3,8 @@ package datasource
|
||||
import (
|
||||
"context"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
"github.com/grafana/grafana/pkg/apis/datasource/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
@@ -49,10 +45,6 @@ type Querier interface {
|
||||
Health(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error)
|
||||
// Resource gets a resource plugin.
|
||||
Resource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error
|
||||
// Datasource gets all data source plugins (with elevated permissions).
|
||||
Datasource(ctx context.Context, name string) (*v0alpha1.DataSourceConnection, error)
|
||||
// Datasources lists all data sources (with elevated permissions).
|
||||
Datasources(ctx context.Context) (*v0alpha1.DataSourceConnectionList, error)
|
||||
}
|
||||
|
||||
type DefaultQuerier struct {
|
||||
@@ -102,47 +94,3 @@ func (q *DefaultQuerier) Health(ctx context.Context, query *backend.CheckHealthR
|
||||
}
|
||||
return q.pluginClient.CheckHealth(ctx, query)
|
||||
}
|
||||
|
||||
func (q *DefaultQuerier) Datasource(ctx context.Context, name string) (*v0alpha1.DataSourceConnection, error) {
|
||||
info, err := request.NamespaceInfoFrom(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user, err := identity.GetRequester(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ds, err := q.dsCache.GetDatasourceByUID(ctx, name, user, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return asConnection(ds, info.Value)
|
||||
}
|
||||
|
||||
func (q *DefaultQuerier) Datasources(ctx context.Context) (*v0alpha1.DataSourceConnectionList, error) {
|
||||
info, err := request.NamespaceInfoFrom(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ds, err := q.dsService.GetDataSourcesByType(ctx, &datasources.GetDataSourcesByTypeQuery{
|
||||
OrgID: info.OrgID,
|
||||
Type: q.pluginJSON.ID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return asConnectionList(q.connectionResourceInfo.TypeMeta(), ds, info.Value)
|
||||
}
|
||||
|
||||
func asConnectionList(typeMeta metav1.TypeMeta, dss []*datasources.DataSource, ns string) (*v0alpha1.DataSourceConnectionList, error) {
|
||||
result := &v0alpha1.DataSourceConnectionList{
|
||||
Items: []v0alpha1.DataSourceConnection{},
|
||||
}
|
||||
for _, ds := range dss {
|
||||
v, _ := asConnection(ds, ns)
|
||||
result.Items = append(result.Items, *v)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ import (
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
datasource "github.com/grafana/grafana/pkg/apis/datasource/v0alpha1"
|
||||
query "github.com/grafana/grafana/pkg/apis/query/v0alpha1"
|
||||
datasourceV0 "github.com/grafana/grafana/pkg/apis/datasource/v0alpha1"
|
||||
queryV0 "github.com/grafana/grafana/pkg/apis/query/v0alpha1"
|
||||
grafanaregistry "github.com/grafana/grafana/pkg/apiserver/registry/generic"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
@@ -36,7 +36,6 @@ var _ builder.APIGroupBuilder = (*DataSourceAPIBuilder)(nil)
|
||||
|
||||
// DataSourceAPIBuilder is used just so wire has something unique to return
|
||||
type DataSourceAPIBuilder struct {
|
||||
connectionResourceInfo utils.ResourceInfo
|
||||
datasourceResourceInfo utils.ResourceInfo
|
||||
|
||||
pluginJSON plugins.JSONData
|
||||
@@ -44,7 +43,7 @@ type DataSourceAPIBuilder struct {
|
||||
datasources PluginDatasourceProvider
|
||||
contextProvider PluginContextWrapper
|
||||
accessControl accesscontrol.AccessControl
|
||||
queryTypes *query.QueryTypeDefinitionList
|
||||
queryTypes *queryV0.QueryTypeDefinitionList
|
||||
log log.Logger
|
||||
}
|
||||
|
||||
@@ -122,8 +121,7 @@ func NewDataSourceAPIBuilder(
|
||||
}
|
||||
|
||||
builder := &DataSourceAPIBuilder{
|
||||
connectionResourceInfo: datasource.ConnectionResourceInfo.WithGroupAndShortName(group, plugin.ID+"-connection"),
|
||||
datasourceResourceInfo: datasource.DataSourceResourceInfo.WithGroupAndShortName(group, plugin.ID),
|
||||
datasourceResourceInfo: datasourceV0.DataSourceResourceInfo.WithGroupAndShortName(group, plugin.ID),
|
||||
pluginJSON: plugin,
|
||||
client: client,
|
||||
datasources: datasources,
|
||||
@@ -139,7 +137,7 @@ func NewDataSourceAPIBuilder(
|
||||
}
|
||||
|
||||
// TODO -- somehow get the list from the plugin -- not hardcoded
|
||||
func getHardcodedQueryTypes(group string) (*query.QueryTypeDefinitionList, error) {
|
||||
func getHardcodedQueryTypes(group string) (*queryV0.QueryTypeDefinitionList, error) {
|
||||
var err error
|
||||
var raw json.RawMessage
|
||||
switch group {
|
||||
@@ -152,7 +150,7 @@ func getHardcodedQueryTypes(group string) (*query.QueryTypeDefinitionList, error
|
||||
return nil, err
|
||||
}
|
||||
if raw != nil {
|
||||
types := &query.QueryTypeDefinitionList{}
|
||||
types := &queryV0.QueryTypeDefinitionList{}
|
||||
err = json.Unmarshal(raw, types)
|
||||
return types, err
|
||||
}
|
||||
@@ -160,29 +158,27 @@ func getHardcodedQueryTypes(group string) (*query.QueryTypeDefinitionList, error
|
||||
}
|
||||
|
||||
func (b *DataSourceAPIBuilder) GetGroupVersion() schema.GroupVersion {
|
||||
return b.connectionResourceInfo.GroupVersion()
|
||||
return b.datasourceResourceInfo.GroupVersion()
|
||||
}
|
||||
|
||||
func addKnownTypes(scheme *runtime.Scheme, gv schema.GroupVersion) {
|
||||
scheme.AddKnownTypes(gv,
|
||||
&datasource.DataSourceConnection{},
|
||||
&datasource.DataSourceConnectionList{},
|
||||
&datasource.DataSource{},
|
||||
&datasource.DataSourceList{},
|
||||
&datasource.HealthCheckResult{},
|
||||
&datasourceV0.DataSource{}, // or AddKnownTypeWithName?
|
||||
&datasourceV0.DataSourceList{},
|
||||
&datasourceV0.HealthCheckResult{},
|
||||
&unstructured.Unstructured{},
|
||||
|
||||
// Query handler
|
||||
&query.QueryDataRequest{},
|
||||
&query.QueryDataResponse{},
|
||||
&query.QueryTypeDefinition{},
|
||||
&query.QueryTypeDefinitionList{},
|
||||
&queryV0.QueryDataRequest{},
|
||||
&queryV0.QueryDataResponse{},
|
||||
&queryV0.QueryTypeDefinition{},
|
||||
&queryV0.QueryTypeDefinitionList{},
|
||||
&metav1.Status{},
|
||||
)
|
||||
}
|
||||
|
||||
func (b *DataSourceAPIBuilder) InstallSchema(scheme *runtime.Scheme) error {
|
||||
gv := b.connectionResourceInfo.GroupVersion()
|
||||
gv := b.datasourceResourceInfo.GroupVersion()
|
||||
addKnownTypes(scheme, gv)
|
||||
|
||||
// Link this version to the internal representation.
|
||||
@@ -223,22 +219,15 @@ func (b *DataSourceAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver
|
||||
return err
|
||||
}
|
||||
|
||||
// Register the "connection" view for a datasource (no access to raw settings)
|
||||
conn := b.connectionResourceInfo
|
||||
storage[conn.StoragePath()] = &connectionAccess{
|
||||
datasources: b.datasources,
|
||||
resourceInfo: conn,
|
||||
tableConverter: conn.TableConverter(),
|
||||
}
|
||||
storage[conn.StoragePath("query")] = &subQueryREST{builder: b}
|
||||
storage[conn.StoragePath("health")] = &subHealthREST{builder: b}
|
||||
storage[ds.StoragePath("query")] = &subQueryREST{builder: b}
|
||||
storage[ds.StoragePath("health")] = &subHealthREST{builder: b}
|
||||
|
||||
// TODO! only setup this endpoint if it is implemented
|
||||
storage[conn.StoragePath("resource")] = &subResourceREST{builder: b}
|
||||
storage[ds.StoragePath("resource")] = &subResourceREST{builder: b}
|
||||
|
||||
// Frontend proxy
|
||||
if len(b.pluginJSON.Routes) > 0 {
|
||||
storage[conn.StoragePath("proxy")] = &subProxyREST{pluginJSON: b.pluginJSON}
|
||||
storage[ds.StoragePath("proxy")] = &subProxyREST{pluginJSON: b.pluginJSON}
|
||||
}
|
||||
|
||||
// Register hardcoded query schemas
|
||||
@@ -249,7 +238,7 @@ func (b *DataSourceAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver
|
||||
|
||||
registerQueryConvert(b.client, b.contextProvider, storage)
|
||||
|
||||
apiGroupInfo.VersionedResourcesStorageMap[conn.GroupVersion().Version] = storage
|
||||
apiGroupInfo.VersionedResourcesStorageMap[ds.GroupVersion().Version] = storage
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -263,8 +252,8 @@ func (b *DataSourceAPIBuilder) getPluginContext(ctx context.Context, uid string)
|
||||
|
||||
func (b *DataSourceAPIBuilder) GetOpenAPIDefinitions() openapi.GetOpenAPIDefinitions {
|
||||
return func(ref openapi.ReferenceCallback) map[string]openapi.OpenAPIDefinition {
|
||||
defs := query.GetOpenAPIDefinitions(ref) // required when running standalone
|
||||
for k, v := range datasource.GetOpenAPIDefinitions(ref) {
|
||||
defs := queryV0.GetOpenAPIDefinitions(ref) // required when running standalone
|
||||
for k, v := range datasourceV0.GetOpenAPIDefinitions(ref) {
|
||||
defs[k] = v
|
||||
}
|
||||
return defs
|
||||
@@ -276,7 +265,7 @@ func (b *DataSourceAPIBuilder) PostProcessOpenAPI(oas *spec3.OpenAPI) (*spec3.Op
|
||||
oas.Info.Description = b.pluginJSON.Info.Description
|
||||
|
||||
// The root api URL
|
||||
root := "/apis/" + b.connectionResourceInfo.GroupVersion().String() + "/"
|
||||
root := "/apis/" + b.datasourceResourceInfo.GroupVersion().String() + "/"
|
||||
|
||||
// Add queries to the request properties
|
||||
// Add queries to the request properties
|
||||
|
||||
@@ -6,18 +6,16 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
data "github.com/grafana/grafana-plugin-sdk-go/experimental/apis/data/v0alpha1"
|
||||
query "github.com/grafana/grafana/pkg/apis/query/v0alpha1"
|
||||
query_headers "github.com/grafana/grafana/pkg/registry/apis/query"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
|
||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
)
|
||||
|
||||
type subQueryREST struct {
|
||||
@@ -58,15 +56,8 @@ func (r *subQueryREST) Connect(ctx context.Context, name string, opts runtime.Ob
|
||||
|
||||
if err != nil {
|
||||
if errors.Is(err, datasources.ErrDataSourceNotFound) {
|
||||
return nil, k8serrors.NewNotFound(
|
||||
schema.GroupResource{
|
||||
Group: r.builder.connectionResourceInfo.GroupResource().Group,
|
||||
Resource: r.builder.connectionResourceInfo.GroupResource().Resource,
|
||||
},
|
||||
name,
|
||||
)
|
||||
return nil, r.builder.datasourceResourceInfo.NewNotFound(name)
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana/pkg/apis/datasource/v0alpha1"
|
||||
queryV0 "github.com/grafana/grafana/pkg/apis/query/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
@@ -147,12 +148,12 @@ func (m mockDatasources) ListDataSource(ctx context.Context) (*v0alpha1.DataSour
|
||||
}
|
||||
|
||||
// Get gets a specific datasource (that the user in context can see)
|
||||
func (m mockDatasources) GetConnection(ctx context.Context, uid string) (*v0alpha1.DataSourceConnection, error) {
|
||||
func (m mockDatasources) GetConnection(ctx context.Context, uid string) (*queryV0.DataSourceConnection, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// List lists all data sources the user in context can see
|
||||
func (m mockDatasources) ListConnections(ctx context.Context) (*v0alpha1.DataSourceConnectionList, error) {
|
||||
func (m mockDatasources) ListConnections(ctx context.Context) (*queryV0.DataSourceConnectionList, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/internalversion"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
|
||||
authlib "github.com/grafana/authlib/types"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
query "github.com/grafana/grafana/pkg/apis/query/v0alpha1"
|
||||
queryV0 "github.com/grafana/grafana/pkg/apis/query/v0alpha1"
|
||||
gapiutil "github.com/grafana/grafana/pkg/services/apiserver/utils"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
)
|
||||
|
||||
var (
|
||||
_ rest.Scoper = (*connectionAccess)(nil)
|
||||
_ rest.SingularNameProvider = (*connectionAccess)(nil)
|
||||
_ rest.Getter = (*connectionAccess)(nil)
|
||||
_ rest.Lister = (*connectionAccess)(nil)
|
||||
_ rest.Storage = (*connectionAccess)(nil)
|
||||
)
|
||||
|
||||
type DataSourceConnectionProvider interface {
|
||||
// Get gets a specific datasource (that the user in context can see)
|
||||
GetConnection(ctx context.Context, namespace string, name string) (*queryV0.DataSourceConnection, error)
|
||||
|
||||
// List lists all data sources the user in context can see
|
||||
ListConnections(ctx context.Context, namespace string) (*queryV0.DataSourceConnectionList, error)
|
||||
}
|
||||
|
||||
type connectionAccess struct {
|
||||
tableConverter rest.TableConvertor
|
||||
connections DataSourceConnectionProvider
|
||||
}
|
||||
|
||||
func (s *connectionAccess) New() runtime.Object {
|
||||
return query.ConnectionResourceInfo.NewFunc()
|
||||
}
|
||||
|
||||
func (s *connectionAccess) Destroy() {}
|
||||
|
||||
func (s *connectionAccess) NamespaceScoped() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *connectionAccess) GetSingularName() string {
|
||||
return query.ConnectionResourceInfo.GetSingularName()
|
||||
}
|
||||
|
||||
func (s *connectionAccess) ShortNames() []string {
|
||||
return query.ConnectionResourceInfo.GetShortNames()
|
||||
}
|
||||
|
||||
func (s *connectionAccess) NewList() runtime.Object {
|
||||
return query.ConnectionResourceInfo.NewListFunc()
|
||||
}
|
||||
|
||||
func (s *connectionAccess) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) {
|
||||
if s.tableConverter == nil {
|
||||
s.tableConverter = query.ConnectionResourceInfo.TableConverter()
|
||||
}
|
||||
return s.tableConverter.ConvertToTable(ctx, object, tableOptions)
|
||||
}
|
||||
|
||||
func (s *connectionAccess) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
|
||||
return s.connections.GetConnection(ctx, request.NamespaceValue(ctx), name)
|
||||
}
|
||||
|
||||
func (s *connectionAccess) List(ctx context.Context, options *internalversion.ListOptions) (runtime.Object, error) {
|
||||
return s.connections.ListConnections(ctx, request.NamespaceValue(ctx))
|
||||
}
|
||||
|
||||
type connectionsProvider struct {
|
||||
dsService datasources.DataSourceService
|
||||
}
|
||||
|
||||
func (q *connectionsProvider) GetConnection(ctx context.Context, namespace string, name string) (*queryV0.DataSourceConnection, error) {
|
||||
info, err := authlib.ParseNamespace(namespace)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ds, err := q.dsService.GetDataSource(ctx, &datasources.GetDataSourceQuery{
|
||||
UID: name,
|
||||
OrgID: info.OrgID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO... access control?
|
||||
|
||||
return asConnection(ds, namespace)
|
||||
}
|
||||
|
||||
func (q *connectionsProvider) ListConnections(ctx context.Context, namespace string) (*queryV0.DataSourceConnectionList, error) {
|
||||
info, err := authlib.ParseNamespace(namespace)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dss, err := q.dsService.GetDataSources(ctx, &datasources.GetDataSourcesQuery{
|
||||
OrgID: info.OrgID,
|
||||
DataSourceLimit: 10000,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := &queryV0.DataSourceConnectionList{
|
||||
Items: []queryV0.DataSourceConnection{},
|
||||
}
|
||||
for _, ds := range dss {
|
||||
// TODO, access control!
|
||||
v, _ := asConnection(ds, namespace)
|
||||
result.Items = append(result.Items, *v)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func asConnection(ds *datasources.DataSource, ns string) (*queryV0.DataSourceConnection, error) {
|
||||
v := &queryV0.DataSourceConnection{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: ds.UID,
|
||||
Namespace: ns,
|
||||
CreationTimestamp: metav1.NewTime(ds.Created),
|
||||
ResourceVersion: fmt.Sprintf("%d", ds.Updated.UnixMilli()),
|
||||
Generation: int64(ds.Version),
|
||||
},
|
||||
Title: ds.Name,
|
||||
}
|
||||
v.UID = gapiutil.CalculateClusterWideUID(v) // indicates if the value changed on the server
|
||||
meta, err := utils.MetaAccessor(v)
|
||||
if err != nil {
|
||||
meta.SetUpdatedTimestamp(&ds.Updated)
|
||||
}
|
||||
return v, err
|
||||
}
|
||||
@@ -47,6 +47,7 @@ type QueryAPIBuilder struct {
|
||||
metrics *metrics.ExprMetrics
|
||||
parser *queryParser
|
||||
clientSupplier clientapi.DataSourceClientSupplier
|
||||
connections DataSourceConnectionProvider
|
||||
registry query.DataSourceApiServerRegistry
|
||||
converter *expr.ResultConverter
|
||||
queryTypes *query.QueryTypeDefinitionList
|
||||
@@ -56,6 +57,7 @@ func NewQueryAPIBuilder(features featuremgmt.FeatureToggles,
|
||||
clientSupplier clientapi.DataSourceClientSupplier,
|
||||
ar authorizer.Authorizer,
|
||||
registry query.DataSourceApiServerRegistry,
|
||||
connections DataSourceConnectionProvider,
|
||||
legacy service.LegacyDataSourceLookup,
|
||||
registerer prometheus.Registerer,
|
||||
tracer tracing.Tracer,
|
||||
@@ -88,6 +90,7 @@ func NewQueryAPIBuilder(features featuremgmt.FeatureToggles,
|
||||
tracer: tracer,
|
||||
features: features,
|
||||
queryTypes: queryTypes,
|
||||
connections: connections,
|
||||
converter: &expr.ResultConverter{
|
||||
Features: features,
|
||||
Tracer: tracer,
|
||||
@@ -132,7 +135,7 @@ func RegisterAPIService(features featuremgmt.FeatureToggles,
|
||||
},
|
||||
ar,
|
||||
client.NewDataSourceRegistryFromStore(pluginStore, dataSourcesService),
|
||||
legacy, registerer, tracer,
|
||||
&connectionsProvider{dsService: dataSourcesService}, legacy, registerer, tracer,
|
||||
)
|
||||
apiregistration.RegisterAPI(builder)
|
||||
return builder, err
|
||||
@@ -146,6 +149,8 @@ func addKnownTypes(scheme *runtime.Scheme, gv schema.GroupVersion) {
|
||||
scheme.AddKnownTypes(gv,
|
||||
&query.DataSourceApiServer{},
|
||||
&query.DataSourceApiServerList{},
|
||||
&query.DataSourceConnection{},
|
||||
&query.DataSourceConnectionList{},
|
||||
&query.QueryDataRequest{},
|
||||
&query.QueryDataResponse{},
|
||||
&query.QueryTypeDefinition{},
|
||||
@@ -168,6 +173,12 @@ func (b *QueryAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIG
|
||||
|
||||
storage := map[string]rest.Storage{}
|
||||
|
||||
// Get a list of all datasource instances
|
||||
// Eventually this would be backed either by search or reconciler pattern
|
||||
storage[query.ConnectionResourceInfo.StoragePath()] = &connectionAccess{
|
||||
connections: b.connections,
|
||||
}
|
||||
|
||||
plugins := newPluginsStorage(b.registry)
|
||||
storage[plugins.resourceInfo.StoragePath()] = plugins
|
||||
if !b.features.IsEnabledGlobally(featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs) {
|
||||
|
||||
@@ -119,8 +119,29 @@ func getOpenAPIPostProcessor(version string, builders []APIGroupBuilder) func(*s
|
||||
|
||||
// Remove the growing list of kinds
|
||||
for k, v := range copy.Components.Schemas {
|
||||
if strings.HasPrefix(k, "io.k8s.apimachinery.pkg.apis.meta.v1") && v.Extensions != nil {
|
||||
if v.Extensions == nil {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(k, "io.k8s.apimachinery.pkg.apis.meta.v1") {
|
||||
delete(v.Extensions, "x-kubernetes-group-version-kind") // a growing list of everything
|
||||
continue
|
||||
}
|
||||
|
||||
// Remove the internal annotations
|
||||
val, ok := v.Extensions["x-kubernetes-group-version-kind"]
|
||||
if ok {
|
||||
gvks, ok := val.([]any)
|
||||
if ok {
|
||||
keep := make([]map[string]any, 0, len(gvks))
|
||||
for _, val := range gvks {
|
||||
gvk, ok := val.(map[string]any)
|
||||
if ok && gvk["version"] == "__internal" {
|
||||
continue
|
||||
}
|
||||
keep = append(keep, gvk)
|
||||
}
|
||||
v.Extensions["x-kubernetes-group-version-kind"] = keep
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user