K8s: handle multiple versions of the same group in standalone mode (#93199)

This commit is contained in:
Charandas
2024-09-23 19:07:52 -07:00
committed by GitHub
parent e699348d39
commit db97da3465
15 changed files with 91 additions and 164 deletions

View File

@ -4,10 +4,8 @@ import (
"context" "context"
"fmt" "fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/registry/rest"
@ -72,29 +70,22 @@ func (t *NotificationsAPIBuilder) InstallSchema(scheme *runtime.Scheme) error {
return scheme.SetVersionPriority(notificationsModels.SchemeGroupVersion) return scheme.SetVersionPriority(notificationsModels.SchemeGroupVersion)
} }
func (t *NotificationsAPIBuilder) GetAPIGroupInfo( func (t *NotificationsAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter, dualWriteBuilder grafanarest.DualWriteBuilder) error {
scheme *runtime.Scheme,
codecs serializer.CodecFactory,
optsGetter generic.RESTOptionsGetter,
dualWriteBuilder grafanarest.DualWriteBuilder,
) (*genericapiserver.APIGroupInfo, error) {
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(notificationsModels.GROUP, scheme, metav1.ParameterCodec, codecs)
intervals, err := timeInterval.NewStorage(t.ng.Api.MuteTimings, t.namespacer, scheme, optsGetter, dualWriteBuilder) intervals, err := timeInterval.NewStorage(t.ng.Api.MuteTimings, t.namespacer, scheme, optsGetter, dualWriteBuilder)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to initialize time-interval storage: %w", err) return fmt.Errorf("failed to initialize time-interval storage: %w", err)
} }
recvStorage, err := receiver.NewStorage(t.ng.Api.ReceiverService, t.namespacer, scheme, optsGetter, dualWriteBuilder, t.ng.Api.ReceiverService) recvStorage, err := receiver.NewStorage(t.ng.Api.ReceiverService, t.namespacer, scheme, optsGetter, dualWriteBuilder, t.ng.Api.ReceiverService)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to initialize receiver storage: %w", err) return fmt.Errorf("failed to initialize receiver storage: %w", err)
} }
apiGroupInfo.VersionedResourcesStorageMap[notificationsModels.VERSION] = map[string]rest.Storage{ apiGroupInfo.VersionedResourcesStorageMap[notificationsModels.VERSION] = map[string]rest.Storage{
notificationsModels.TimeIntervalResourceInfo.StoragePath(): intervals, notificationsModels.TimeIntervalResourceInfo.StoragePath(): intervals,
notificationsModels.ReceiverResourceInfo.StoragePath(): recvStorage, notificationsModels.ReceiverResourceInfo.StoragePath(): recvStorage,
} }
return &apiGroupInfo, nil return nil
} }
func (t *NotificationsAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions { func (t *NotificationsAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions {

View File

@ -1,6 +1,16 @@
package dashboard package dashboard
import ( import (
"github.com/prometheus/client_golang/prometheus"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/registry/rest"
genericapiserver "k8s.io/apiserver/pkg/server"
"k8s.io/kube-openapi/pkg/common"
"k8s.io/kube-openapi/pkg/spec3"
dashboard "github.com/grafana/grafana/pkg/apis/dashboard/v0alpha1" dashboard "github.com/grafana/grafana/pkg/apis/dashboard/v0alpha1"
grafanaregistry "github.com/grafana/grafana/pkg/apiserver/registry/generic" grafanaregistry "github.com/grafana/grafana/pkg/apiserver/registry/generic"
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest" grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
@ -18,16 +28,6 @@ import (
"github.com/grafana/grafana/pkg/storage/legacysql" "github.com/grafana/grafana/pkg/storage/legacysql"
"github.com/grafana/grafana/pkg/storage/unified/apistore" "github.com/grafana/grafana/pkg/storage/unified/apistore"
"github.com/grafana/grafana/pkg/storage/unified/resource" "github.com/grafana/grafana/pkg/storage/unified/resource"
"github.com/prometheus/client_golang/prometheus"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/registry/rest"
genericapiserver "k8s.io/apiserver/pkg/server"
common "k8s.io/kube-openapi/pkg/common"
"k8s.io/kube-openapi/pkg/spec3"
) )
var ( var (
@ -124,18 +124,11 @@ func (b *DashboardsAPIBuilder) InstallSchema(scheme *runtime.Scheme) error {
return scheme.SetVersionPriority(resourceInfo.GroupVersion()) return scheme.SetVersionPriority(resourceInfo.GroupVersion())
} }
func (b *DashboardsAPIBuilder) GetAPIGroupInfo( func (b *DashboardsAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter, dualWriteBuilder grafanarest.DualWriteBuilder) error {
scheme *runtime.Scheme,
codecs serializer.CodecFactory, // pointer?
optsGetter generic.RESTOptionsGetter,
dualWriteBuilder grafanarest.DualWriteBuilder,
) (*genericapiserver.APIGroupInfo, error) {
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(dashboard.GROUP, scheme, metav1.ParameterCodec, codecs)
dash := b.legacy.resource dash := b.legacy.resource
legacyStore, err := b.legacy.newStore(scheme, optsGetter) legacyStore, err := b.legacy.newStore(scheme, optsGetter)
if err != nil { if err != nil {
return nil, err return err
} }
storage := map[string]rest.Storage{} storage := map[string]rest.Storage{}
@ -149,23 +142,23 @@ func (b *DashboardsAPIBuilder) GetAPIGroupInfo(
if optsGetter != nil && dualWriteBuilder != nil { if optsGetter != nil && dualWriteBuilder != nil {
store, err := newStorage(scheme) store, err := newStorage(scheme)
if err != nil { if err != nil {
return nil, err return err
} }
options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: grafanaregistry.GetAttrs} options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: grafanaregistry.GetAttrs}
if err := store.CompleteWithOptions(options); err != nil { if err := store.CompleteWithOptions(options); err != nil {
return nil, err return err
} }
storage[dash.StoragePath()], err = dualWriteBuilder(dash.GroupResource(), legacyStore, store) storage[dash.StoragePath()], err = dualWriteBuilder(dash.GroupResource(), legacyStore, store)
if err != nil { if err != nil {
return nil, err return err
} }
} }
// Register the DTO endpoint that will consolidate all dashboard bits // Register the DTO endpoint that will consolidate all dashboard bits
storage[dash.StoragePath("dto")], err = newDTOConnector(storage[dash.StoragePath()], b) storage[dash.StoragePath("dto")], err = newDTOConnector(storage[dash.StoragePath()], b)
if err != nil { if err != nil {
return nil, err return err
} }
// Expose read only library panels // Expose read only library panels
@ -174,7 +167,7 @@ func (b *DashboardsAPIBuilder) GetAPIGroupInfo(
} }
apiGroupInfo.VersionedResourcesStorageMap[dashboard.VERSION] = storage apiGroupInfo.VersionedResourcesStorageMap[dashboard.VERSION] = storage
return &apiGroupInfo, nil return nil
} }
func (b *DashboardsAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions { func (b *DashboardsAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions {

View File

@ -11,7 +11,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/registry/rest"
@ -120,13 +119,7 @@ func (b *SnapshotsAPIBuilder) InstallSchema(scheme *runtime.Scheme) error {
return scheme.SetVersionPriority(gv) return scheme.SetVersionPriority(gv)
} }
func (b *SnapshotsAPIBuilder) GetAPIGroupInfo( func (b *SnapshotsAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, _ *runtime.Scheme, _ generic.RESTOptionsGetter, _ grafanarest.DualWriteBuilder) error {
scheme *runtime.Scheme,
codecs serializer.CodecFactory, // pointer?
optsGetter generic.RESTOptionsGetter,
_ grafanarest.DualWriteBuilder,
) (*genericapiserver.APIGroupInfo, error) {
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(dashboardsnapshot.GROUP, scheme, metav1.ParameterCodec, codecs)
storage := map[string]rest.Storage{} storage := map[string]rest.Storage{}
legacyStore := &legacyStorage{ legacyStore := &legacyStorage{
@ -147,7 +140,7 @@ func (b *SnapshotsAPIBuilder) GetAPIGroupInfo(
} }
apiGroupInfo.VersionedResourcesStorageMap[dashboardsnapshot.VERSION] = storage apiGroupInfo.VersionedResourcesStorageMap[dashboardsnapshot.VERSION] = storage
return &apiGroupInfo, nil return nil
} }
func (b *SnapshotsAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions { func (b *SnapshotsAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions {

View File

@ -24,7 +24,6 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/registry/rest"
genericapiserver "k8s.io/apiserver/pkg/server" genericapiserver "k8s.io/apiserver/pkg/server"
@ -200,12 +199,7 @@ func resourceFromPluginID(pluginID string) (utils.ResourceInfo, error) {
return datasource.GenericConnectionResourceInfo.WithGroupAndShortName(group, pluginID+"-connection"), nil return datasource.GenericConnectionResourceInfo.WithGroupAndShortName(group, pluginID+"-connection"), nil
} }
func (b *DataSourceAPIBuilder) GetAPIGroupInfo( func (b *DataSourceAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, _ *runtime.Scheme, _ generic.RESTOptionsGetter, _ grafanarest.DualWriteBuilder) error {
scheme *runtime.Scheme,
codecs serializer.CodecFactory, // pointer?
_ generic.RESTOptionsGetter,
_ grafanarest.DualWriteBuilder,
) (*genericapiserver.APIGroupInfo, error) {
storage := map[string]rest.Storage{} storage := map[string]rest.Storage{}
conn := b.connectionResourceInfo conn := b.connectionResourceInfo
@ -228,13 +222,8 @@ func (b *DataSourceAPIBuilder) GetAPIGroupInfo(
// Register hardcoded query schemas // Register hardcoded query schemas
err := queryschema.RegisterQueryTypes(b.queryTypes, storage) err := queryschema.RegisterQueryTypes(b.queryTypes, storage)
// Create the group info
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(
conn.GroupResource().Group, scheme,
metav1.ParameterCodec, codecs)
apiGroupInfo.VersionedResourcesStorageMap[conn.GroupVersion().Version] = storage apiGroupInfo.VersionedResourcesStorageMap[conn.GroupVersion().Version] = storage
return &apiGroupInfo, err return err
} }
func (b *DataSourceAPIBuilder) getPluginContext(ctx context.Context, uid string) (backend.PluginContext, error) { func (b *DataSourceAPIBuilder) getPluginContext(ctx context.Context, uid string) (backend.PluginContext, error) {

View File

@ -4,7 +4,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/registry/rest"
@ -82,14 +81,7 @@ func (b *FeatureFlagAPIBuilder) InstallSchema(scheme *runtime.Scheme) error {
return scheme.SetVersionPriority(gv) return scheme.SetVersionPriority(gv)
} }
func (b *FeatureFlagAPIBuilder) GetAPIGroupInfo( func (b *FeatureFlagAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, _ *runtime.Scheme, _ generic.RESTOptionsGetter, _ grafanarest.DualWriteBuilder) error {
scheme *runtime.Scheme,
codecs serializer.CodecFactory, // pointer?
_ generic.RESTOptionsGetter,
_ grafanarest.DualWriteBuilder,
) (*genericapiserver.APIGroupInfo, error) {
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(v0alpha1.GROUP, scheme, metav1.ParameterCodec, codecs)
featureStore := NewFeaturesStorage() featureStore := NewFeaturesStorage()
toggleStore := NewTogglesStorage(b.features) toggleStore := NewTogglesStorage(b.features)
@ -98,7 +90,7 @@ func (b *FeatureFlagAPIBuilder) GetAPIGroupInfo(
storage[toggleStore.resource.StoragePath()] = toggleStore storage[toggleStore.resource.StoragePath()] = toggleStore
apiGroupInfo.VersionedResourcesStorageMap[v0alpha1.VERSION] = storage apiGroupInfo.VersionedResourcesStorageMap[v0alpha1.VERSION] = storage
return &apiGroupInfo, nil return nil
} }
func (b *FeatureFlagAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions { func (b *FeatureFlagAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions {

View File

@ -7,7 +7,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/registry/rest"
@ -95,14 +94,7 @@ func (b *FolderAPIBuilder) InstallSchema(scheme *runtime.Scheme) error {
return scheme.SetVersionPriority(b.gv) return scheme.SetVersionPriority(b.gv)
} }
func (b *FolderAPIBuilder) GetAPIGroupInfo( func (b *FolderAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter, dualWriteBuilder grafanarest.DualWriteBuilder) error {
scheme *runtime.Scheme,
codecs serializer.CodecFactory, // pointer?
optsGetter generic.RESTOptionsGetter,
dualWriteBuilder grafanarest.DualWriteBuilder,
) (*genericapiserver.APIGroupInfo, error) {
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(v0alpha1.GROUP, scheme, metav1.ParameterCodec, codecs)
legacyStore := &legacyStorage{ legacyStore := &legacyStorage{
service: b.folderSvc, service: b.folderSvc,
namespacer: b.namespacer, namespacer: b.namespacer,
@ -119,16 +111,16 @@ func (b *FolderAPIBuilder) GetAPIGroupInfo(
if optsGetter != nil && dualWriteBuilder != nil { if optsGetter != nil && dualWriteBuilder != nil {
store, err := newStorage(scheme, optsGetter, legacyStore) store, err := newStorage(scheme, optsGetter, legacyStore)
if err != nil { if err != nil {
return nil, err return err
} }
storage[resourceInfo.StoragePath()], err = dualWriteBuilder(resourceInfo.GroupResource(), legacyStore, store) storage[resourceInfo.StoragePath()], err = dualWriteBuilder(resourceInfo.GroupResource(), legacyStore, store)
if err != nil { if err != nil {
return nil, err return err
} }
} }
apiGroupInfo.VersionedResourcesStorageMap[v0alpha1.VERSION] = storage apiGroupInfo.VersionedResourcesStorageMap[v0alpha1.VERSION] = storage
return &apiGroupInfo, nil return nil
} }
func (b *FolderAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions { func (b *FolderAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions {

View File

@ -6,7 +6,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/registry/rest"
@ -101,13 +100,7 @@ func (b *IdentityAccessManagementAPIBuilder) InstallSchema(scheme *runtime.Schem
return scheme.SetVersionPriority(iamv0.SchemeGroupVersion) return scheme.SetVersionPriority(iamv0.SchemeGroupVersion)
} }
func (b *IdentityAccessManagementAPIBuilder) GetAPIGroupInfo( func (b *IdentityAccessManagementAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, _ *runtime.Scheme, _ generic.RESTOptionsGetter, _ grafanarest.DualWriteBuilder) error {
scheme *runtime.Scheme,
codecs serializer.CodecFactory, // pointer?
optsGetter generic.RESTOptionsGetter,
dualWriteBuilder grafanarest.DualWriteBuilder,
) (*genericapiserver.APIGroupInfo, error) {
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(iamv0.GROUP, scheme, metav1.ParameterCodec, codecs)
storage := map[string]rest.Storage{} storage := map[string]rest.Storage{}
teamResource := iamv0.TeamResourceInfo teamResource := iamv0.TeamResourceInfo
@ -134,7 +127,7 @@ func (b *IdentityAccessManagementAPIBuilder) GetAPIGroupInfo(
storage["display"] = user.NewLegacyDisplayREST(b.store) storage["display"] = user.NewLegacyDisplayREST(b.store)
apiGroupInfo.VersionedResourcesStorageMap[iamv0.VERSION] = storage apiGroupInfo.VersionedResourcesStorageMap[iamv0.VERSION] = storage
return &apiGroupInfo, nil return nil
} }
func (b *IdentityAccessManagementAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions { func (b *IdentityAccessManagementAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions {

View File

@ -4,7 +4,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/registry/rest"
@ -66,19 +65,12 @@ func (b *PeakQAPIBuilder) InstallSchema(scheme *runtime.Scheme) error {
return scheme.SetVersionPriority(gv) return scheme.SetVersionPriority(gv)
} }
func (b *PeakQAPIBuilder) GetAPIGroupInfo( func (b *PeakQAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter, _ grafanarest.DualWriteBuilder) error {
scheme *runtime.Scheme,
codecs serializer.CodecFactory,
optsGetter generic.RESTOptionsGetter,
_ grafanarest.DualWriteBuilder,
) (*genericapiserver.APIGroupInfo, error) {
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(peakq.GROUP, scheme, metav1.ParameterCodec, codecs)
resourceInfo := peakq.QueryTemplateResourceInfo resourceInfo := peakq.QueryTemplateResourceInfo
storage := map[string]rest.Storage{} storage := map[string]rest.Storage{}
peakqStorage, err := newStorage(scheme, optsGetter) peakqStorage, err := newStorage(scheme, optsGetter)
if err != nil { if err != nil {
return nil, err return err
} }
storage[resourceInfo.StoragePath()] = peakqStorage storage[resourceInfo.StoragePath()] = peakqStorage
storage[resourceInfo.StoragePath("render")] = &renderREST{ storage[resourceInfo.StoragePath("render")] = &renderREST{
@ -86,7 +78,7 @@ func (b *PeakQAPIBuilder) GetAPIGroupInfo(
} }
apiGroupInfo.VersionedResourcesStorageMap[peakq.VERSION] = storage apiGroupInfo.VersionedResourcesStorageMap[peakq.VERSION] = storage
return &apiGroupInfo, nil return nil
} }
func (b *PeakQAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions { func (b *PeakQAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions {

View File

@ -7,12 +7,11 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/registry/rest"
genericapiserver "k8s.io/apiserver/pkg/server" genericapiserver "k8s.io/apiserver/pkg/server"
common "k8s.io/kube-openapi/pkg/common" "k8s.io/kube-openapi/pkg/common"
playlist "github.com/grafana/grafana/apps/playlist/apis/playlist/v0alpha1" playlist "github.com/grafana/grafana/apps/playlist/apis/playlist/v0alpha1"
"github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/apimachinery/utils"
@ -79,13 +78,7 @@ func (b *PlaylistAPIBuilder) InstallSchema(scheme *runtime.Scheme) error {
return scheme.SetVersionPriority(b.gv) return scheme.SetVersionPriority(b.gv)
} }
func (b *PlaylistAPIBuilder) GetAPIGroupInfo( func (b *PlaylistAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter, dualWriteBuilder grafanarest.DualWriteBuilder) error {
scheme *runtime.Scheme,
codecs serializer.CodecFactory, // pointer?
optsGetter generic.RESTOptionsGetter,
dualWriteBuilder grafanarest.DualWriteBuilder,
) (*genericapiserver.APIGroupInfo, error) {
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(playlist.PlaylistKind().Group(), scheme, metav1.ParameterCodec, codecs)
storage := map[string]rest.Storage{} storage := map[string]rest.Storage{}
gvr := schema.GroupVersionResource{ gvr := schema.GroupVersionResource{
@ -127,17 +120,18 @@ func (b *PlaylistAPIBuilder) GetAPIGroupInfo(
if optsGetter != nil && dualWriteBuilder != nil { if optsGetter != nil && dualWriteBuilder != nil {
store, err := newStorage(scheme, optsGetter, legacyStore) store, err := newStorage(scheme, optsGetter, legacyStore)
if err != nil { if err != nil {
return nil, err return err
} }
dualWriter, err := dualWriteBuilder(gvr.GroupResource(), legacyStore, store) dualWriter, err := dualWriteBuilder(gvr.GroupResource(), legacyStore, store)
if err != nil { if err != nil {
return nil, err return err
} }
storage[gvr.Resource] = dualWriter storage[gvr.Resource] = dualWriter
} }
apiGroupInfo.VersionedResourcesStorageMap[gvr.Version] = storage apiGroupInfo.VersionedResourcesStorageMap[gvr.Version] = storage
return &apiGroupInfo, nil return nil
} }
func (b *PlaylistAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions { func (b *PlaylistAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions {

View File

@ -7,7 +7,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/registry/rest"
@ -139,14 +138,8 @@ func (b *QueryAPIBuilder) InstallSchema(scheme *runtime.Scheme) error {
return scheme.SetVersionPriority(query.SchemeGroupVersion) return scheme.SetVersionPriority(query.SchemeGroupVersion)
} }
func (b *QueryAPIBuilder) GetAPIGroupInfo( func (b *QueryAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, _ *runtime.Scheme, _ generic.RESTOptionsGetter, _ grafanarest.DualWriteBuilder) error {
scheme *runtime.Scheme,
codecs serializer.CodecFactory, // pointer?
optsGetter generic.RESTOptionsGetter,
_ grafanarest.DualWriteBuilder,
) (*genericapiserver.APIGroupInfo, error) {
gv := query.SchemeGroupVersion gv := query.SchemeGroupVersion
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(gv.Group, scheme, metav1.ParameterCodec, codecs)
storage := map[string]rest.Storage{} storage := map[string]rest.Storage{}
@ -166,7 +159,7 @@ func (b *QueryAPIBuilder) GetAPIGroupInfo(
err := queryschema.RegisterQueryTypes(b.queryTypes, storage) err := queryschema.RegisterQueryTypes(b.queryTypes, storage)
apiGroupInfo.VersionedResourcesStorageMap[gv.Version] = storage apiGroupInfo.VersionedResourcesStorageMap[gv.Version] = storage
return &apiGroupInfo, err return err
} }
func (b *QueryAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions { func (b *QueryAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions {

View File

@ -3,10 +3,8 @@ package scope
import ( import (
"fmt" "fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/registry/rest"
@ -113,14 +111,7 @@ func (b *ScopeAPIBuilder) InstallSchema(scheme *runtime.Scheme) error {
return scheme.SetVersionPriority(scope.SchemeGroupVersion) return scheme.SetVersionPriority(scope.SchemeGroupVersion)
} }
func (b *ScopeAPIBuilder) GetAPIGroupInfo( func (b *ScopeAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter, _ grafanarest.DualWriteBuilder) error {
scheme *runtime.Scheme,
codecs serializer.CodecFactory,
optsGetter generic.RESTOptionsGetter,
_ grafanarest.DualWriteBuilder,
) (*genericapiserver.APIGroupInfo, error) {
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(scope.GROUP, scheme, metav1.ParameterCodec, codecs)
scopeResourceInfo := scope.ScopeResourceInfo scopeResourceInfo := scope.ScopeResourceInfo
scopeDashboardResourceInfo := scope.ScopeDashboardBindingResourceInfo scopeDashboardResourceInfo := scope.ScopeDashboardBindingResourceInfo
scopeNodeResourceInfo := scope.ScopeNodeResourceInfo scopeNodeResourceInfo := scope.ScopeNodeResourceInfo
@ -129,20 +120,20 @@ func (b *ScopeAPIBuilder) GetAPIGroupInfo(
scopeStorage, err := newScopeStorage(scheme, optsGetter) scopeStorage, err := newScopeStorage(scheme, optsGetter)
if err != nil { if err != nil {
return nil, err return err
} }
storage[scopeResourceInfo.StoragePath()] = scopeStorage storage[scopeResourceInfo.StoragePath()] = scopeStorage
scopeDashboardStorage, scopedDashboardStatusStorage, err := newScopeDashboardBindingStorage(scheme, optsGetter) scopeDashboardStorage, scopedDashboardStatusStorage, err := newScopeDashboardBindingStorage(scheme, optsGetter)
if err != nil { if err != nil {
return nil, err return err
} }
storage[scopeDashboardResourceInfo.StoragePath()] = scopeDashboardStorage storage[scopeDashboardResourceInfo.StoragePath()] = scopeDashboardStorage
storage[scopeDashboardResourceInfo.StoragePath()+"/status"] = scopedDashboardStatusStorage storage[scopeDashboardResourceInfo.StoragePath()+"/status"] = scopedDashboardStatusStorage
scopeNodeStorage, err := newScopeNodeStorage(scheme, optsGetter) scopeNodeStorage, err := newScopeNodeStorage(scheme, optsGetter)
if err != nil { if err != nil {
return nil, err return err
} }
storage[scopeNodeResourceInfo.StoragePath()] = scopeNodeStorage storage[scopeNodeResourceInfo.StoragePath()] = scopeNodeStorage
@ -157,7 +148,7 @@ func (b *ScopeAPIBuilder) GetAPIGroupInfo(
storage["scope_dashboard_bindings"] = &findScopeDashboardsREST{scopeDashboardStorage: scopeDashboardStorage} storage["scope_dashboard_bindings"] = &findScopeDashboardsREST{scopeDashboardStorage: scopeDashboardStorage}
apiGroupInfo.VersionedResourcesStorageMap[scope.VERSION] = storage apiGroupInfo.VersionedResourcesStorageMap[scope.VERSION] = storage
return &apiGroupInfo, nil return nil
} }
func (b *ScopeAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions { func (b *ScopeAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions {

View File

@ -4,7 +4,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/registry/rest"
@ -71,23 +70,16 @@ func (b *ServiceAPIBuilder) InstallSchema(scheme *runtime.Scheme) error {
return scheme.SetVersionPriority(gv) return scheme.SetVersionPriority(gv)
} }
func (b *ServiceAPIBuilder) GetAPIGroupInfo( func (b *ServiceAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter, _ grafanarest.DualWriteBuilder) error {
scheme *runtime.Scheme,
codecs serializer.CodecFactory,
optsGetter generic.RESTOptionsGetter,
_ grafanarest.DualWriteBuilder,
) (*genericapiserver.APIGroupInfo, error) {
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(service.GROUP, scheme, metav1.ParameterCodec, codecs)
resourceInfo := service.ExternalNameResourceInfo resourceInfo := service.ExternalNameResourceInfo
storage := map[string]rest.Storage{} storage := map[string]rest.Storage{}
serviceStorage, err := newStorage(scheme, optsGetter) serviceStorage, err := newStorage(scheme, optsGetter)
if err != nil { if err != nil {
return nil, err return err
} }
storage[resourceInfo.StoragePath()] = serviceStorage storage[resourceInfo.StoragePath()] = serviceStorage
apiGroupInfo.VersionedResourcesStorageMap[service.VERSION] = storage apiGroupInfo.VersionedResourcesStorageMap[service.VERSION] = storage
return &apiGroupInfo, nil return nil
} }
func (b *ServiceAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions { func (b *ServiceAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions {

View File

@ -284,19 +284,21 @@ func CreateAggregatorServer(config *Config, delegateAPIServer genericapiserver.D
return nil return nil
}) })
serviceAPIGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(servicev0alpha1.GROUP, aggregatorscheme.Scheme, metav1.ParameterCodec, aggregatorscheme.Codecs)
for _, b := range config.Builders { for _, b := range config.Builders {
serviceAPIGroupInfo, err := b.GetAPIGroupInfo( err := b.UpdateAPIGroupInfo(
&serviceAPIGroupInfo,
aggregatorscheme.Scheme, aggregatorscheme.Scheme,
aggregatorscheme.Codecs,
aggregatorConfig.GenericConfig.RESTOptionsGetter, aggregatorConfig.GenericConfig.RESTOptionsGetter,
nil, // no dual writer nil, // no dual writer
) )
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := aggregatorServer.GenericAPIServer.InstallAPIGroup(serviceAPIGroupInfo); err != nil { }
return nil, err
} if err := aggregatorServer.GenericAPIServer.InstallAPIGroup(&serviceAPIGroupInfo); err != nil {
return nil, err
} }
return aggregatorServer, nil return aggregatorServer, nil

View File

@ -5,7 +5,6 @@ import (
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/generic"
genericapiserver "k8s.io/apiserver/pkg/server" genericapiserver "k8s.io/apiserver/pkg/server"
@ -24,13 +23,19 @@ type APIGroupBuilder interface {
// Add the kinds to the server scheme // Add the kinds to the server scheme
InstallSchema(scheme *runtime.Scheme) error InstallSchema(scheme *runtime.Scheme) error
// Build the group+version behavior // UpdateAPIGroupInfo used to be a getter until we ran into the issue
GetAPIGroupInfo( // where separate API Group Info for the same group (different versions) aren't handled well by
// the InstallAPIGroup facility of genericapiserver. Also, we can only ever call InstallAPIGroup
// once on the genericapiserver per group, or we run into double registration startup errors.
//
// The caller should share the apiGroupInfo passed into this function across builder versions of the same group.
// UpdateAPIGroupInfo builds the group+version behavior updating the passed in apiGroupInfo in place
UpdateAPIGroupInfo(
apiGroupInfo *genericapiserver.APIGroupInfo,
scheme *runtime.Scheme, scheme *runtime.Scheme,
codecs serializer.CodecFactory,
optsGetter generic.RESTOptionsGetter, optsGetter generic.RESTOptionsGetter,
dualWrite grafanarest.DualWriteBuilder, dualWriteBuilder grafanarest.DualWriteBuilder,
) (*genericapiserver.APIGroupInfo, error) ) error
// Get OpenAPI definitions // Get OpenAPI definitions
GetOpenAPIDefinitions() common.GetOpenAPIDefinitions GetOpenAPIDefinitions() common.GetOpenAPIDefinitions

View File

@ -210,18 +210,33 @@ func InstallAPIs(
} }
} }
// NOTE: we build a map structure by version only for the purposes of InstallAPIGroup
// in other places, working with a flat []APIGroupBuilder list is much nicer
buildersGroupMap := make(map[string][]APIGroupBuilder, 0)
for _, b := range builders { for _, b := range builders {
g, err := b.GetAPIGroupInfo(scheme, codecs, optsGetter, dualWrite) group := b.GetGroupVersion().Group
if err != nil { if _, ok := buildersGroupMap[group]; !ok {
return err buildersGroupMap[group] = make([]APIGroupBuilder, 0)
} }
if g == nil || len(g.PrioritizedVersions) < 1 { buildersGroupMap[group] = append(buildersGroupMap[group], b)
continue }
for group, buildersForGroup := range buildersGroupMap {
g := genericapiserver.NewDefaultAPIGroupInfo(group, scheme, metav1.ParameterCodec, codecs)
for _, b := range buildersForGroup {
if err := b.UpdateAPIGroupInfo(&g, scheme, optsGetter, dualWrite); err != nil {
return err
}
if len(g.PrioritizedVersions) < 1 {
continue
}
} }
err = server.InstallAPIGroup(g)
err := server.InstallAPIGroup(&g)
if err != nil { if err != nil {
return err return err
} }
} }
return nil return nil
} }