Dashboards: Only expose LibraryPanels and search on v0 (not v1+v2) (#103335)

This commit is contained in:
Ryan McKinley
2025-04-03 20:24:12 +03:00
committed by GitHub
parent 224139e9d0
commit 04fb9f534e
15 changed files with 6323 additions and 63 deletions
+14 -25
View File
@@ -5,7 +5,6 @@ import (
"errors"
"fmt"
"maps"
"path"
"github.com/prometheus/client_golang/prometheus"
apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -197,7 +196,7 @@ func (b *DashboardsAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver
// v0alpha1
if err := b.storageForVersion(apiGroupInfo, opts, largeObjects,
v0alpha1.DashboardResourceInfo,
v0alpha1.LibraryPanelResourceInfo,
&v0alpha1.LibraryPanelResourceInfo,
func(obj runtime.Object, access *internal.DashboardAccess) (v runtime.Object, err error) {
dto := &v0alpha1.DashboardWithAccessInfo{}
dash, ok := obj.(*v0alpha1.Dashboard)
@@ -215,7 +214,7 @@ func (b *DashboardsAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver
// v1alpha1
if err := b.storageForVersion(apiGroupInfo, opts, largeObjects,
v1alpha1.DashboardResourceInfo,
v1alpha1.LibraryPanelResourceInfo,
nil, // do not register library panel
func(obj runtime.Object, access *internal.DashboardAccess) (v runtime.Object, err error) {
dto := &v1alpha1.DashboardWithAccessInfo{}
dash, ok := obj.(*v1alpha1.Dashboard)
@@ -233,7 +232,7 @@ func (b *DashboardsAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver
// v2alpha1
if err := b.storageForVersion(apiGroupInfo, opts, largeObjects,
v2alpha1.DashboardResourceInfo,
v2alpha1.LibraryPanelResourceInfo,
nil, // do not register library panel
func(obj runtime.Object, access *internal.DashboardAccess) (v runtime.Object, err error) {
dto := &v2alpha1.DashboardWithAccessInfo{}
dash, ok := obj.(*v2alpha1.Dashboard)
@@ -256,7 +255,7 @@ func (b *DashboardsAPIBuilder) storageForVersion(
opts builder.APIGroupOptions,
largeObjects apistore.LargeObjectSupport,
dashboards utils.ResourceInfo,
libraryPanels utils.ResourceInfo,
libraryPanels *utils.ResourceInfo,
newDTOFunc dtoBuilder,
) error {
// Register the versioned storage
@@ -294,9 +293,11 @@ func (b *DashboardsAPIBuilder) storageForVersion(
}
// Expose read only library panels
storage[libraryPanels.StoragePath()] = &LibraryPanelStore{
Access: b.legacy.Access,
ResourceInfo: libraryPanels,
if libraryPanels != nil {
storage[libraryPanels.StoragePath()] = &LibraryPanelStore{
Access: b.legacy.Access,
ResourceInfo: *libraryPanels,
}
}
return nil
@@ -312,27 +313,15 @@ func (b *DashboardsAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefiniti
}
func (b *DashboardsAPIBuilder) PostProcessOpenAPI(oas *spec3.OpenAPI) (*spec3.OpenAPI, error) {
// The plugin description
oas.Info.Description = "Grafana dashboards as resources"
for _, gv := range b.GetGroupVersions() {
version := gv.Version
// Hide cluster-scoped resources
root := path.Join("/apis/", v0alpha1.GROUP, version)
delete(oas.Paths.Paths, path.Join(root, "dashboards"))
delete(oas.Paths.Paths, path.Join(root, "watch", "dashboards"))
if version == v0alpha1.VERSION {
sub := oas.Paths.Paths[path.Join(root, "search", "{name}")]
oas.Paths.Paths[path.Join(root, "search")] = sub
delete(oas.Paths.Paths, path.Join(root, "search", "{name}"))
}
}
return oas, nil
}
func (b *DashboardsAPIBuilder) GetAPIRoutes() *builder.APIRoutes {
func (b *DashboardsAPIBuilder) GetAPIRoutes(gv schema.GroupVersion) *builder.APIRoutes {
if gv.Version != v0alpha1.VERSION {
return nil // Only show the custom routes for v0
}
defs := b.GetOpenAPIDefinitions()(func(path string) spec.Ref { return spec.Ref{} })
return b.search.GetAPIRoutes(defs)
}
@@ -34,8 +34,11 @@ import (
"github.com/grafana/grafana/pkg/web"
)
var _ builder.APIGroupBuilder = (*SnapshotsAPIBuilder)(nil)
var _ builder.OpenAPIPostProcessor = (*SnapshotsAPIBuilder)(nil)
var (
_ builder.APIGroupBuilder = (*SnapshotsAPIBuilder)(nil)
_ builder.OpenAPIPostProcessor = (*SnapshotsAPIBuilder)(nil)
_ builder.APIGroupRouteProvider = (*SnapshotsAPIBuilder)(nil)
)
var resourceInfo = dashboardsnapshot.DashboardSnapshotResourceInfo
@@ -146,7 +149,7 @@ func (b *SnapshotsAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitio
}
// Register additional routes with the server
func (b *SnapshotsAPIBuilder) GetAPIRoutes() *builder.APIRoutes {
func (b *SnapshotsAPIBuilder) GetAPIRoutes(gv schema.GroupVersion) *builder.APIRoutes {
prefix := dashboardsnapshot.DashboardSnapshotResourceInfo.GroupResource().Resource
defs := dashboardsnapshot.GetOpenAPIDefinitions(func(path string) spec.Ref { return spec.Ref{} })
createCmd := defs["github.com/grafana/grafana/apps/dashboard/pkg/apissnapshot/v0alpha1.DashboardCreateCommand"].Schema
@@ -347,8 +350,5 @@ func (b *SnapshotsAPIBuilder) PostProcessOpenAPI(oas *spec3.OpenAPI) (*spec3.Ope
sub.Get.Description = "Read the full dashboard body"
}
// Hide the invalid endpoint to list all snapshots for all orgs
delete(oas.Paths.Paths, "/apis/dashboardsnapshot.grafana.app/v0alpha1/dashboardsnapshots")
return oas, nil
}
-3
View File
@@ -260,9 +260,6 @@ func (b *DataSourceAPIBuilder) PostProcessOpenAPI(oas *spec3.OpenAPI) (*spec3.Op
// The root api URL
root := "/apis/" + b.connectionResourceInfo.GroupVersion().String() + "/"
// Hide the ability to list all connections across tenants
delete(oas.Paths.Paths, root+b.connectionResourceInfo.GroupResource().Resource)
// Add queries to the request properties
// Add queries to the request properties
err := queryschema.AddQueriesToOpenAPI(queryschema.OASQueryOptions{
+2 -1
View File
@@ -21,6 +21,7 @@ import (
)
var _ builder.APIGroupBuilder = (*FeatureFlagAPIBuilder)(nil)
var _ builder.APIGroupRouteProvider = (*FeatureFlagAPIBuilder)(nil)
var gv = v0alpha1.SchemeGroupVersion
@@ -100,7 +101,7 @@ func (b *FeatureFlagAPIBuilder) GetAuthorizer() authorizer.Authorizer {
}
// Register additional routes with the server
func (b *FeatureFlagAPIBuilder) GetAPIRoutes() *builder.APIRoutes {
func (b *FeatureFlagAPIBuilder) GetAPIRoutes(gv schema.GroupVersion) *builder.APIRoutes {
defs := v0alpha1.GetOpenAPIDefinitions(func(path string) spec.Ref { return spec.Ref{} })
stateSchema := defs["github.com/grafana/grafana/pkg/apis/featuretoggle/v0alpha1.ResolvedToggleState"].Schema
-8
View File
@@ -197,15 +197,7 @@ func (b *FolderAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions
}
func (b *FolderAPIBuilder) PostProcessOpenAPI(oas *spec3.OpenAPI) (*spec3.OpenAPI, error) {
// The plugin description
oas.Info.Description = "Grafana folders"
// The root api URL
root := "/apis/" + b.GetGroupVersion().String() + "/"
// Hide the ability to list or watch across all tenants
delete(oas.Paths.Paths, root+v0alpha1.FolderResourceInfo.GroupResource().Resource)
return oas, nil
}
+2 -1
View File
@@ -30,6 +30,7 @@ import (
)
var _ builder.APIGroupBuilder = (*IdentityAccessManagementAPIBuilder)(nil)
var _ builder.APIGroupRouteProvider = (*IdentityAccessManagementAPIBuilder)(nil)
// This is used just so wire has something unique to return
type IdentityAccessManagementAPIBuilder struct {
@@ -182,7 +183,7 @@ func (b *IdentityAccessManagementAPIBuilder) PostProcessOpenAPI(oas *spec3.OpenA
return oas, nil
}
func (b *IdentityAccessManagementAPIBuilder) GetAPIRoutes() *builder.APIRoutes {
func (b *IdentityAccessManagementAPIBuilder) GetAPIRoutes(gv schema.GroupVersion) *builder.APIRoutes {
defs := b.GetOpenAPIDefinitions()(func(path string) spec.Ref { return spec.Ref{} })
return b.display.GetAPIRoutes(defs)
}
+2 -1
View File
@@ -7,6 +7,7 @@ import (
"time"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kube-openapi/pkg/spec3"
"k8s.io/kube-openapi/pkg/validation/spec"
@@ -19,7 +20,7 @@ import (
// TODO: Move the specific logic to the connector so that we don't have logic all over the place.
// GetAPIRoutes implements the direct HTTP handlers that bypass k8s
func (b *APIBuilder) GetAPIRoutes() *builder.APIRoutes {
func (b *APIBuilder) GetAPIRoutes(gv schema.GroupVersion) *builder.APIRoutes {
return &builder.APIRoutes{
Namespace: []builder.APIRouteHandler{
{
+3 -9
View File
@@ -29,10 +29,9 @@ import (
)
var (
_ builder.APIGroupBuilder = (*SecretAPIBuilder)(nil)
_ builder.APIGroupMutation = (*SecretAPIBuilder)(nil)
_ builder.APIGroupValidation = (*SecretAPIBuilder)(nil)
_ builder.APIGroupRouteProvider = (*SecretAPIBuilder)(nil)
_ builder.APIGroupBuilder = (*SecretAPIBuilder)(nil)
_ builder.APIGroupMutation = (*SecretAPIBuilder)(nil)
_ builder.APIGroupValidation = (*SecretAPIBuilder)(nil)
)
type SecretAPIBuilder struct {
@@ -156,11 +155,6 @@ func (b *SecretAPIBuilder) GetAuthorizer() authorizer.Authorizer {
return authsvc.NewResourceAuthorizer(b.accessClient)
}
// Register additional routes with the server.
func (b *SecretAPIBuilder) GetAPIRoutes() *builder.APIRoutes {
return nil
}
// Validate is called in `Create`, `Update` and `Delete` REST funcs, if the body calls the argument `rest.ValidateObjectFunc`.
func (b *SecretAPIBuilder) Validate(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error {
obj := a.GetObject()
+1 -1
View File
@@ -64,7 +64,7 @@ type APIGroupValidation interface {
type APIGroupRouteProvider interface {
// Support direct HTTP routes from an APIGroup
GetAPIRoutes() *APIRoutes
GetAPIRoutes(gv schema.GroupVersion) *APIRoutes
}
type APIGroupPostStartHookProvider interface {
+1 -1
View File
@@ -125,7 +125,7 @@ func getOpenAPIPostProcessor(version string, builders []APIGroupBuilder) func(*s
// Optionally include raw http handlers
provider, ok := b.(APIGroupRouteProvider)
if ok && provider != nil {
routes := provider.GetAPIRoutes()
routes := provider.GetAPIRoutes(gv)
if routes != nil {
for _, route := range routes.Root {
copy.Paths.Paths[prefix+route.Path] = &spec3.Path{
@@ -23,12 +23,12 @@ func GetCustomRoutesHandler(delegateHandler http.Handler, restConfig *restclient
continue
}
routes := provider.GetAPIRoutes()
if routes == nil {
continue
}
for _, gv := range GetGroupVersions(builder) {
routes := provider.GetAPIRoutes(gv)
if routes == nil {
continue
}
prefix := "/apis/" + gv.String()
// Root handlers
@@ -1311,8 +1311,7 @@
}
}
}
},
"/apis/dashboard.grafana.app/v0alpha1/search": null
}
},
"components": {
"schemas": {
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+6
View File
@@ -62,6 +62,12 @@ func TestIntegrationOpenAPIs(t *testing.T) {
var groups = []schema.GroupVersion{{
Group: "dashboard.grafana.app",
Version: "v0alpha1",
}, {
Group: "dashboard.grafana.app",
Version: "v1alpha1",
}, {
Group: "dashboard.grafana.app",
Version: "v2alpha1",
}, {
Group: "folder.grafana.app",
Version: "v0alpha1",