mirror of
https://github.com/grafana/grafana.git
synced 2025-12-21 20:24:41 +08:00
Compare commits
1 Commits
KD/lazy-lo
...
register-d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
72eec4e995 |
@@ -7,6 +7,7 @@ import (
|
|||||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/registry/apis/query/queryschema"
|
"github.com/grafana/grafana/pkg/registry/apis/query/queryschema"
|
||||||
|
"github.com/grafana/grafana/pkg/services/apiserver/builder"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (b *DataSourceAPIBuilder) PostProcessOpenAPI(oas *spec3.OpenAPI) (*spec3.OpenAPI, error) {
|
func (b *DataSourceAPIBuilder) PostProcessOpenAPI(oas *spec3.OpenAPI) (*spec3.OpenAPI, error) {
|
||||||
@@ -70,5 +71,15 @@ func (b *DataSourceAPIBuilder) PostProcessOpenAPI(oas *spec3.OpenAPI) (*spec3.Op
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mark all alias APIServers as deprecated
|
||||||
|
if b.isAlias {
|
||||||
|
oas.Info.Description = "Deprecated. Please use: " + b.pluginJSON.ID
|
||||||
|
for _, p := range oas.Paths.Paths {
|
||||||
|
for _, op := range builder.GetPathOperations(p) {
|
||||||
|
op.Deprecated = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return oas, nil
|
return oas, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ var (
|
|||||||
// DataSourceAPIBuilder is used just so wire has something unique to return
|
// DataSourceAPIBuilder is used just so wire has something unique to return
|
||||||
type DataSourceAPIBuilder struct {
|
type DataSourceAPIBuilder struct {
|
||||||
datasourceResourceInfo utils.ResourceInfo
|
datasourceResourceInfo utils.ResourceInfo
|
||||||
|
isAlias bool // The datasourceResourceInfo group is an alias and the API should be deprecated
|
||||||
|
|
||||||
pluginJSON plugins.JSONData
|
pluginJSON plugins.JSONData
|
||||||
client PluginClient // will only ever be called with the same plugin id!
|
client PluginClient // will only ever be called with the same plugin id!
|
||||||
@@ -58,10 +59,17 @@ func RegisterAPIService(
|
|||||||
pluginSources sources.Registry,
|
pluginSources sources.Registry,
|
||||||
) (*DataSourceAPIBuilder, error) {
|
) (*DataSourceAPIBuilder, error) {
|
||||||
//nolint:staticcheck // not yet migrated to OpenFeature
|
//nolint:staticcheck // not yet migrated to OpenFeature
|
||||||
if !features.IsEnabledGlobally(featuremgmt.FlagQueryServiceWithConnections) && !features.IsEnabledGlobally(featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs) {
|
useQueryService := !features.IsEnabledGlobally(featuremgmt.FlagQueryServiceWithConnections)
|
||||||
|
|
||||||
|
//nolint:staticcheck // not yet migrated to OpenFeature
|
||||||
|
experimental := features.IsEnabledGlobally(featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs)
|
||||||
|
if !experimental && !useQueryService {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Include CRUD when running local dev mode
|
||||||
|
configCrudUseNewApis := experimental
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
var builder *DataSourceAPIBuilder
|
var builder *DataSourceAPIBuilder
|
||||||
|
|
||||||
@@ -84,13 +92,25 @@ func RegisterAPIService(
|
|||||||
accessControl,
|
accessControl,
|
||||||
//nolint:staticcheck // not yet migrated to OpenFeature
|
//nolint:staticcheck // not yet migrated to OpenFeature
|
||||||
features.IsEnabledGlobally(featuremgmt.FlagDatasourceQueryTypes),
|
features.IsEnabledGlobally(featuremgmt.FlagDatasourceQueryTypes),
|
||||||
false,
|
configCrudUseNewApis, // register the CRUD endpoints
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The group is a calculated FQDN (eg testdata.datasource.grafana.app)
|
||||||
|
// and should be replaced with with the raw plugin ID
|
||||||
|
aliasIDs := append(pluginJSON.AliasIDs, builder.datasourceResourceInfo.GroupResource().Group)
|
||||||
|
builder.datasourceResourceInfo = builder.datasourceResourceInfo.WithGroupAndShortName(pluginJSON.ID, "")
|
||||||
apiRegistrar.RegisterAPI(builder)
|
apiRegistrar.RegisterAPI(builder)
|
||||||
|
|
||||||
|
// Register a deprecated copy with the previous routes
|
||||||
|
for _, aliasId := range aliasIDs {
|
||||||
|
copy := *builder
|
||||||
|
copy.isAlias = true
|
||||||
|
copy.datasourceResourceInfo = builder.datasourceResourceInfo.WithGroupAndShortName(aliasId, "")
|
||||||
|
apiRegistrar.RegisterAPI(©)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return builder, nil // only used for wire
|
return builder, nil // only used for wire
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"maps"
|
"maps"
|
||||||
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@@ -217,11 +218,9 @@ func getOpenAPIPostProcessor(version string, builders []APIGroupBuilder, gvs []s
|
|||||||
parent := copy.Paths.Paths[path[:idx+6]]
|
parent := copy.Paths.Paths[path[:idx+6]]
|
||||||
if parent != nil && parent.Get != nil {
|
if parent != nil && parent.Get != nil {
|
||||||
for _, op := range GetPathOperations(spec) {
|
for _, op := range GetPathOperations(spec) {
|
||||||
if op != nil && op.Extensions != nil {
|
action, ok := op.Extensions.GetString("x-kubernetes-action")
|
||||||
action, ok := op.Extensions.GetString("x-kubernetes-action")
|
if ok && action == "connect" {
|
||||||
if ok && action == "connect" {
|
op.Tags = parent.Get.Tags
|
||||||
op.Tags = parent.Get.Tags
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -234,15 +233,32 @@ func getOpenAPIPostProcessor(version string, builders []APIGroupBuilder, gvs []s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPathOperations(path *spec3.Path) []*spec3.Operation {
|
// GetPathOperations returns the set of non-nil operations defined on a path
|
||||||
return []*spec3.Operation{
|
func GetPathOperations(path *spec3.Path) map[string]*spec3.Operation {
|
||||||
path.Get,
|
ops := make(map[string]*spec3.Operation)
|
||||||
path.Head,
|
if path.Get != nil {
|
||||||
path.Delete,
|
ops[http.MethodGet] = path.Get
|
||||||
path.Patch,
|
|
||||||
path.Post,
|
|
||||||
path.Put,
|
|
||||||
path.Trace,
|
|
||||||
path.Options,
|
|
||||||
}
|
}
|
||||||
|
if path.Head != nil {
|
||||||
|
ops[http.MethodHead] = path.Head
|
||||||
|
}
|
||||||
|
if path.Delete != nil {
|
||||||
|
ops[http.MethodDelete] = path.Delete
|
||||||
|
}
|
||||||
|
if path.Post != nil {
|
||||||
|
ops[http.MethodPost] = path.Post
|
||||||
|
}
|
||||||
|
if path.Put != nil {
|
||||||
|
ops[http.MethodPut] = path.Put
|
||||||
|
}
|
||||||
|
if path.Patch != nil {
|
||||||
|
ops[http.MethodPatch] = path.Patch
|
||||||
|
}
|
||||||
|
if path.Trace != nil {
|
||||||
|
ops[http.MethodTrace] = path.Trace
|
||||||
|
}
|
||||||
|
if path.Options != nil {
|
||||||
|
ops[http.MethodOptions] = path.Options
|
||||||
|
}
|
||||||
|
return ops
|
||||||
}
|
}
|
||||||
|
|||||||
76
pkg/services/apiserver/builder/openapi_test.go
Normal file
76
pkg/services/apiserver/builder/openapi_test.go
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
package builder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"k8s.io/kube-openapi/pkg/spec3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestOpenAPI_GetPathOperations(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
input *spec3.Path
|
||||||
|
expect []string // the methods we should see
|
||||||
|
exclude []string // the methods we should never see
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "some operations",
|
||||||
|
input: &spec3.Path{
|
||||||
|
PathProps: spec3.PathProps{
|
||||||
|
Get: &spec3.Operation{OperationProps: spec3.OperationProps{Summary: "get"}},
|
||||||
|
Post: &spec3.Operation{OperationProps: spec3.OperationProps{Summary: "post"}},
|
||||||
|
Delete: &spec3.Operation{OperationProps: spec3.OperationProps{Summary: "delete"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expect: []string{"GET", "POST", "DELETE"},
|
||||||
|
exclude: []string{"PUT", "PATCH", "OPTIONS", "HEAD", "TRACE"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "all operations",
|
||||||
|
input: &spec3.Path{
|
||||||
|
PathProps: spec3.PathProps{
|
||||||
|
Get: &spec3.Operation{OperationProps: spec3.OperationProps{Summary: "get"}},
|
||||||
|
Post: &spec3.Operation{OperationProps: spec3.OperationProps{Summary: "post"}},
|
||||||
|
Delete: &spec3.Operation{OperationProps: spec3.OperationProps{Summary: "delete"}},
|
||||||
|
Put: &spec3.Operation{OperationProps: spec3.OperationProps{Summary: "put"}},
|
||||||
|
Patch: &spec3.Operation{OperationProps: spec3.OperationProps{Summary: "patch"}},
|
||||||
|
Options: &spec3.Operation{OperationProps: spec3.OperationProps{Summary: "options"}},
|
||||||
|
Head: &spec3.Operation{OperationProps: spec3.OperationProps{Summary: "head"}},
|
||||||
|
Trace: &spec3.Operation{OperationProps: spec3.OperationProps{Summary: "trace"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expect: []string{"GET", "POST", "DELETE", "PUT", "PATCH", "OPTIONS", "HEAD", "TRACE"},
|
||||||
|
exclude: []string{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range testCases {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
expect := make(map[string]bool)
|
||||||
|
for _, k := range tt.expect {
|
||||||
|
expect[k] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, op := range GetPathOperations(tt.input) {
|
||||||
|
require.NotNil(t, op)
|
||||||
|
require.Equal(t, strings.ToLower(k), op.Summary)
|
||||||
|
|
||||||
|
if !expect[k] {
|
||||||
|
if slices.Contains(tt.expect, k) {
|
||||||
|
require.Fail(t, "method returned multiple times", k)
|
||||||
|
} else {
|
||||||
|
require.Fail(t, "unexpected method", k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete(expect, k)
|
||||||
|
require.NotContains(t, tt.exclude, k, "exclude")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(expect) > 0 {
|
||||||
|
require.Fail(t, "missing expected method", expect)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user