From db97da3465082c3173fdbfc152a4b21f78f2d45a Mon Sep 17 00:00:00 2001 From: Charandas <542168+charandas@users.noreply.github.com> Date: Mon, 23 Sep 2024 19:07:52 -0700 Subject: [PATCH] K8s: handle multiple versions of the same group in standalone mode (#93199) --- .../apis/alerting/notifications/register.go | 17 ++------ pkg/registry/apis/dashboard/register.go | 41 ++++++++----------- .../apis/dashboardsnapshot/register.go | 11 +---- pkg/registry/apis/datasource/register.go | 15 +------ pkg/registry/apis/featuretoggle/register.go | 12 +----- pkg/registry/apis/folders/register.go | 16 ++------ pkg/registry/apis/iam/register.go | 11 +---- pkg/registry/apis/peakq/register.go | 14 ++----- pkg/registry/apis/playlist/register.go | 18 +++----- pkg/registry/apis/query/register.go | 11 +---- pkg/registry/apis/scope/register.go | 19 +++------ pkg/registry/apis/service/register.go | 14 ++----- .../apiserver/aggregator/aggregator.go | 12 +++--- pkg/services/apiserver/builder/common.go | 17 +++++--- pkg/services/apiserver/builder/helper.go | 27 +++++++++--- 15 files changed, 91 insertions(+), 164 deletions(-) diff --git a/pkg/registry/apis/alerting/notifications/register.go b/pkg/registry/apis/alerting/notifications/register.go index db0c85ddea3..be565852adc 100644 --- a/pkg/registry/apis/alerting/notifications/register.go +++ b/pkg/registry/apis/alerting/notifications/register.go @@ -4,10 +4,8 @@ import ( "context" "fmt" - 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/authorization/authorizer" "k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/rest" @@ -72,29 +70,22 @@ func (t *NotificationsAPIBuilder) InstallSchema(scheme *runtime.Scheme) error { return scheme.SetVersionPriority(notificationsModels.SchemeGroupVersion) } -func (t *NotificationsAPIBuilder) GetAPIGroupInfo( - scheme *runtime.Scheme, - codecs serializer.CodecFactory, - optsGetter generic.RESTOptionsGetter, - dualWriteBuilder grafanarest.DualWriteBuilder, -) (*genericapiserver.APIGroupInfo, error) { - apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(notificationsModels.GROUP, scheme, metav1.ParameterCodec, codecs) - +func (t *NotificationsAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter, dualWriteBuilder grafanarest.DualWriteBuilder) error { intervals, err := timeInterval.NewStorage(t.ng.Api.MuteTimings, t.namespacer, scheme, optsGetter, dualWriteBuilder) 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) 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{ notificationsModels.TimeIntervalResourceInfo.StoragePath(): intervals, notificationsModels.ReceiverResourceInfo.StoragePath(): recvStorage, } - return &apiGroupInfo, nil + return nil } func (t *NotificationsAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions { diff --git a/pkg/registry/apis/dashboard/register.go b/pkg/registry/apis/dashboard/register.go index 2bd040fa69a..10a5826a392 100644 --- a/pkg/registry/apis/dashboard/register.go +++ b/pkg/registry/apis/dashboard/register.go @@ -1,6 +1,16 @@ package dashboard 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" grafanaregistry "github.com/grafana/grafana/pkg/apiserver/registry/generic" 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/unified/apistore" "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 ( @@ -124,18 +124,11 @@ func (b *DashboardsAPIBuilder) InstallSchema(scheme *runtime.Scheme) error { return scheme.SetVersionPriority(resourceInfo.GroupVersion()) } -func (b *DashboardsAPIBuilder) GetAPIGroupInfo( - 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) - +func (b *DashboardsAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter, dualWriteBuilder grafanarest.DualWriteBuilder) error { dash := b.legacy.resource legacyStore, err := b.legacy.newStore(scheme, optsGetter) if err != nil { - return nil, err + return err } storage := map[string]rest.Storage{} @@ -149,23 +142,23 @@ func (b *DashboardsAPIBuilder) GetAPIGroupInfo( if optsGetter != nil && dualWriteBuilder != nil { store, err := newStorage(scheme) if err != nil { - return nil, err + return err } options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: grafanaregistry.GetAttrs} if err := store.CompleteWithOptions(options); err != nil { - return nil, err + return err } storage[dash.StoragePath()], err = dualWriteBuilder(dash.GroupResource(), legacyStore, store) if err != nil { - return nil, err + return err } } // Register the DTO endpoint that will consolidate all dashboard bits storage[dash.StoragePath("dto")], err = newDTOConnector(storage[dash.StoragePath()], b) if err != nil { - return nil, err + return err } // Expose read only library panels @@ -174,7 +167,7 @@ func (b *DashboardsAPIBuilder) GetAPIGroupInfo( } apiGroupInfo.VersionedResourcesStorageMap[dashboard.VERSION] = storage - return &apiGroupInfo, nil + return nil } func (b *DashboardsAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions { diff --git a/pkg/registry/apis/dashboardsnapshot/register.go b/pkg/registry/apis/dashboardsnapshot/register.go index d5c9c557e62..a8bc461a3c0 100644 --- a/pkg/registry/apis/dashboardsnapshot/register.go +++ b/pkg/registry/apis/dashboardsnapshot/register.go @@ -11,7 +11,6 @@ import ( 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/authorization/authorizer" "k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/rest" @@ -120,13 +119,7 @@ func (b *SnapshotsAPIBuilder) InstallSchema(scheme *runtime.Scheme) error { return scheme.SetVersionPriority(gv) } -func (b *SnapshotsAPIBuilder) GetAPIGroupInfo( - scheme *runtime.Scheme, - codecs serializer.CodecFactory, // pointer? - optsGetter generic.RESTOptionsGetter, - _ grafanarest.DualWriteBuilder, -) (*genericapiserver.APIGroupInfo, error) { - apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(dashboardsnapshot.GROUP, scheme, metav1.ParameterCodec, codecs) +func (b *SnapshotsAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, _ *runtime.Scheme, _ generic.RESTOptionsGetter, _ grafanarest.DualWriteBuilder) error { storage := map[string]rest.Storage{} legacyStore := &legacyStorage{ @@ -147,7 +140,7 @@ func (b *SnapshotsAPIBuilder) GetAPIGroupInfo( } apiGroupInfo.VersionedResourcesStorageMap[dashboardsnapshot.VERSION] = storage - return &apiGroupInfo, nil + return nil } func (b *SnapshotsAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions { diff --git a/pkg/registry/apis/datasource/register.go b/pkg/registry/apis/datasource/register.go index 120a8e9acb0..638bb52ac7d 100644 --- a/pkg/registry/apis/datasource/register.go +++ b/pkg/registry/apis/datasource/register.go @@ -24,7 +24,6 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "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" @@ -200,12 +199,7 @@ func resourceFromPluginID(pluginID string) (utils.ResourceInfo, error) { return datasource.GenericConnectionResourceInfo.WithGroupAndShortName(group, pluginID+"-connection"), nil } -func (b *DataSourceAPIBuilder) GetAPIGroupInfo( - scheme *runtime.Scheme, - codecs serializer.CodecFactory, // pointer? - _ generic.RESTOptionsGetter, - _ grafanarest.DualWriteBuilder, -) (*genericapiserver.APIGroupInfo, error) { +func (b *DataSourceAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, _ *runtime.Scheme, _ generic.RESTOptionsGetter, _ grafanarest.DualWriteBuilder) error { storage := map[string]rest.Storage{} conn := b.connectionResourceInfo @@ -228,13 +222,8 @@ func (b *DataSourceAPIBuilder) GetAPIGroupInfo( // Register hardcoded query schemas 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 - return &apiGroupInfo, err + return err } func (b *DataSourceAPIBuilder) getPluginContext(ctx context.Context, uid string) (backend.PluginContext, error) { diff --git a/pkg/registry/apis/featuretoggle/register.go b/pkg/registry/apis/featuretoggle/register.go index 598fea25a38..52cbb6d7a65 100644 --- a/pkg/registry/apis/featuretoggle/register.go +++ b/pkg/registry/apis/featuretoggle/register.go @@ -4,7 +4,6 @@ import ( 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/authorization/authorizer" "k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/rest" @@ -82,14 +81,7 @@ func (b *FeatureFlagAPIBuilder) InstallSchema(scheme *runtime.Scheme) error { return scheme.SetVersionPriority(gv) } -func (b *FeatureFlagAPIBuilder) GetAPIGroupInfo( - scheme *runtime.Scheme, - codecs serializer.CodecFactory, // pointer? - _ generic.RESTOptionsGetter, - _ grafanarest.DualWriteBuilder, -) (*genericapiserver.APIGroupInfo, error) { - apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(v0alpha1.GROUP, scheme, metav1.ParameterCodec, codecs) - +func (b *FeatureFlagAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, _ *runtime.Scheme, _ generic.RESTOptionsGetter, _ grafanarest.DualWriteBuilder) error { featureStore := NewFeaturesStorage() toggleStore := NewTogglesStorage(b.features) @@ -98,7 +90,7 @@ func (b *FeatureFlagAPIBuilder) GetAPIGroupInfo( storage[toggleStore.resource.StoragePath()] = toggleStore apiGroupInfo.VersionedResourcesStorageMap[v0alpha1.VERSION] = storage - return &apiGroupInfo, nil + return nil } func (b *FeatureFlagAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions { diff --git a/pkg/registry/apis/folders/register.go b/pkg/registry/apis/folders/register.go index fc7056d02be..60c6a278ece 100644 --- a/pkg/registry/apis/folders/register.go +++ b/pkg/registry/apis/folders/register.go @@ -7,7 +7,6 @@ import ( 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/authorization/authorizer" "k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/rest" @@ -95,14 +94,7 @@ func (b *FolderAPIBuilder) InstallSchema(scheme *runtime.Scheme) error { return scheme.SetVersionPriority(b.gv) } -func (b *FolderAPIBuilder) GetAPIGroupInfo( - 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) - +func (b *FolderAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter, dualWriteBuilder grafanarest.DualWriteBuilder) error { legacyStore := &legacyStorage{ service: b.folderSvc, namespacer: b.namespacer, @@ -119,16 +111,16 @@ func (b *FolderAPIBuilder) GetAPIGroupInfo( if optsGetter != nil && dualWriteBuilder != nil { store, err := newStorage(scheme, optsGetter, legacyStore) if err != nil { - return nil, err + return err } storage[resourceInfo.StoragePath()], err = dualWriteBuilder(resourceInfo.GroupResource(), legacyStore, store) if err != nil { - return nil, err + return err } } apiGroupInfo.VersionedResourcesStorageMap[v0alpha1.VERSION] = storage - return &apiGroupInfo, nil + return nil } func (b *FolderAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions { diff --git a/pkg/registry/apis/iam/register.go b/pkg/registry/apis/iam/register.go index ff6d89b48b7..61af0057284 100644 --- a/pkg/registry/apis/iam/register.go +++ b/pkg/registry/apis/iam/register.go @@ -6,7 +6,6 @@ import ( 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/authorization/authorizer" "k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/rest" @@ -101,13 +100,7 @@ func (b *IdentityAccessManagementAPIBuilder) InstallSchema(scheme *runtime.Schem return scheme.SetVersionPriority(iamv0.SchemeGroupVersion) } -func (b *IdentityAccessManagementAPIBuilder) GetAPIGroupInfo( - 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) +func (b *IdentityAccessManagementAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, _ *runtime.Scheme, _ generic.RESTOptionsGetter, _ grafanarest.DualWriteBuilder) error { storage := map[string]rest.Storage{} teamResource := iamv0.TeamResourceInfo @@ -134,7 +127,7 @@ func (b *IdentityAccessManagementAPIBuilder) GetAPIGroupInfo( storage["display"] = user.NewLegacyDisplayREST(b.store) apiGroupInfo.VersionedResourcesStorageMap[iamv0.VERSION] = storage - return &apiGroupInfo, nil + return nil } func (b *IdentityAccessManagementAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions { diff --git a/pkg/registry/apis/peakq/register.go b/pkg/registry/apis/peakq/register.go index 240078c5aa1..31f41d8c379 100644 --- a/pkg/registry/apis/peakq/register.go +++ b/pkg/registry/apis/peakq/register.go @@ -4,7 +4,6 @@ import ( 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/authorization/authorizer" "k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/rest" @@ -66,19 +65,12 @@ func (b *PeakQAPIBuilder) InstallSchema(scheme *runtime.Scheme) error { return scheme.SetVersionPriority(gv) } -func (b *PeakQAPIBuilder) GetAPIGroupInfo( - scheme *runtime.Scheme, - codecs serializer.CodecFactory, - optsGetter generic.RESTOptionsGetter, - _ grafanarest.DualWriteBuilder, -) (*genericapiserver.APIGroupInfo, error) { - apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(peakq.GROUP, scheme, metav1.ParameterCodec, codecs) - +func (b *PeakQAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter, _ grafanarest.DualWriteBuilder) error { resourceInfo := peakq.QueryTemplateResourceInfo storage := map[string]rest.Storage{} peakqStorage, err := newStorage(scheme, optsGetter) if err != nil { - return nil, err + return err } storage[resourceInfo.StoragePath()] = peakqStorage storage[resourceInfo.StoragePath("render")] = &renderREST{ @@ -86,7 +78,7 @@ func (b *PeakQAPIBuilder) GetAPIGroupInfo( } apiGroupInfo.VersionedResourcesStorageMap[peakq.VERSION] = storage - return &apiGroupInfo, nil + return nil } func (b *PeakQAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions { diff --git a/pkg/registry/apis/playlist/register.go b/pkg/registry/apis/playlist/register.go index 4f58a75840f..dc1e3e5ea4d 100644 --- a/pkg/registry/apis/playlist/register.go +++ b/pkg/registry/apis/playlist/register.go @@ -7,12 +7,11 @@ import ( 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/authorization/authorizer" "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/common" playlist "github.com/grafana/grafana/apps/playlist/apis/playlist/v0alpha1" "github.com/grafana/grafana/pkg/apimachinery/utils" @@ -79,13 +78,7 @@ func (b *PlaylistAPIBuilder) InstallSchema(scheme *runtime.Scheme) error { return scheme.SetVersionPriority(b.gv) } -func (b *PlaylistAPIBuilder) GetAPIGroupInfo( - 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) +func (b *PlaylistAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter, dualWriteBuilder grafanarest.DualWriteBuilder) error { storage := map[string]rest.Storage{} gvr := schema.GroupVersionResource{ @@ -127,17 +120,18 @@ func (b *PlaylistAPIBuilder) GetAPIGroupInfo( if optsGetter != nil && dualWriteBuilder != nil { store, err := newStorage(scheme, optsGetter, legacyStore) if err != nil { - return nil, err + return err } dualWriter, err := dualWriteBuilder(gvr.GroupResource(), legacyStore, store) if err != nil { - return nil, err + return err } storage[gvr.Resource] = dualWriter } + apiGroupInfo.VersionedResourcesStorageMap[gvr.Version] = storage - return &apiGroupInfo, nil + return nil } func (b *PlaylistAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions { diff --git a/pkg/registry/apis/query/register.go b/pkg/registry/apis/query/register.go index d20b01f3a5e..fdd8388b961 100644 --- a/pkg/registry/apis/query/register.go +++ b/pkg/registry/apis/query/register.go @@ -7,7 +7,6 @@ import ( 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/authorization/authorizer" "k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/rest" @@ -139,14 +138,8 @@ func (b *QueryAPIBuilder) InstallSchema(scheme *runtime.Scheme) error { return scheme.SetVersionPriority(query.SchemeGroupVersion) } -func (b *QueryAPIBuilder) GetAPIGroupInfo( - scheme *runtime.Scheme, - codecs serializer.CodecFactory, // pointer? - optsGetter generic.RESTOptionsGetter, - _ grafanarest.DualWriteBuilder, -) (*genericapiserver.APIGroupInfo, error) { +func (b *QueryAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, _ *runtime.Scheme, _ generic.RESTOptionsGetter, _ grafanarest.DualWriteBuilder) error { gv := query.SchemeGroupVersion - apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(gv.Group, scheme, metav1.ParameterCodec, codecs) storage := map[string]rest.Storage{} @@ -166,7 +159,7 @@ func (b *QueryAPIBuilder) GetAPIGroupInfo( err := queryschema.RegisterQueryTypes(b.queryTypes, storage) apiGroupInfo.VersionedResourcesStorageMap[gv.Version] = storage - return &apiGroupInfo, err + return err } func (b *QueryAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions { diff --git a/pkg/registry/apis/scope/register.go b/pkg/registry/apis/scope/register.go index 0d1c37d6809..b41c1bea43b 100644 --- a/pkg/registry/apis/scope/register.go +++ b/pkg/registry/apis/scope/register.go @@ -3,10 +3,8 @@ package scope import ( "fmt" - 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/authorization/authorizer" "k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/rest" @@ -113,14 +111,7 @@ func (b *ScopeAPIBuilder) InstallSchema(scheme *runtime.Scheme) error { return scheme.SetVersionPriority(scope.SchemeGroupVersion) } -func (b *ScopeAPIBuilder) GetAPIGroupInfo( - scheme *runtime.Scheme, - codecs serializer.CodecFactory, - optsGetter generic.RESTOptionsGetter, - _ grafanarest.DualWriteBuilder, -) (*genericapiserver.APIGroupInfo, error) { - apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(scope.GROUP, scheme, metav1.ParameterCodec, codecs) - +func (b *ScopeAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter, _ grafanarest.DualWriteBuilder) error { scopeResourceInfo := scope.ScopeResourceInfo scopeDashboardResourceInfo := scope.ScopeDashboardBindingResourceInfo scopeNodeResourceInfo := scope.ScopeNodeResourceInfo @@ -129,20 +120,20 @@ func (b *ScopeAPIBuilder) GetAPIGroupInfo( scopeStorage, err := newScopeStorage(scheme, optsGetter) if err != nil { - return nil, err + return err } storage[scopeResourceInfo.StoragePath()] = scopeStorage scopeDashboardStorage, scopedDashboardStatusStorage, err := newScopeDashboardBindingStorage(scheme, optsGetter) if err != nil { - return nil, err + return err } storage[scopeDashboardResourceInfo.StoragePath()] = scopeDashboardStorage storage[scopeDashboardResourceInfo.StoragePath()+"/status"] = scopedDashboardStatusStorage scopeNodeStorage, err := newScopeNodeStorage(scheme, optsGetter) if err != nil { - return nil, err + return err } storage[scopeNodeResourceInfo.StoragePath()] = scopeNodeStorage @@ -157,7 +148,7 @@ func (b *ScopeAPIBuilder) GetAPIGroupInfo( storage["scope_dashboard_bindings"] = &findScopeDashboardsREST{scopeDashboardStorage: scopeDashboardStorage} apiGroupInfo.VersionedResourcesStorageMap[scope.VERSION] = storage - return &apiGroupInfo, nil + return nil } func (b *ScopeAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions { diff --git a/pkg/registry/apis/service/register.go b/pkg/registry/apis/service/register.go index 23a7bf89f3c..17763fa64e9 100644 --- a/pkg/registry/apis/service/register.go +++ b/pkg/registry/apis/service/register.go @@ -4,7 +4,6 @@ import ( 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/authorization/authorizer" "k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/rest" @@ -71,23 +70,16 @@ func (b *ServiceAPIBuilder) InstallSchema(scheme *runtime.Scheme) error { return scheme.SetVersionPriority(gv) } -func (b *ServiceAPIBuilder) GetAPIGroupInfo( - scheme *runtime.Scheme, - codecs serializer.CodecFactory, - optsGetter generic.RESTOptionsGetter, - _ grafanarest.DualWriteBuilder, -) (*genericapiserver.APIGroupInfo, error) { - apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(service.GROUP, scheme, metav1.ParameterCodec, codecs) - +func (b *ServiceAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter, _ grafanarest.DualWriteBuilder) error { resourceInfo := service.ExternalNameResourceInfo storage := map[string]rest.Storage{} serviceStorage, err := newStorage(scheme, optsGetter) if err != nil { - return nil, err + return err } storage[resourceInfo.StoragePath()] = serviceStorage apiGroupInfo.VersionedResourcesStorageMap[service.VERSION] = storage - return &apiGroupInfo, nil + return nil } func (b *ServiceAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions { diff --git a/pkg/services/apiserver/aggregator/aggregator.go b/pkg/services/apiserver/aggregator/aggregator.go index 44078245990..c5eb66498c7 100644 --- a/pkg/services/apiserver/aggregator/aggregator.go +++ b/pkg/services/apiserver/aggregator/aggregator.go @@ -284,19 +284,21 @@ func CreateAggregatorServer(config *Config, delegateAPIServer genericapiserver.D return nil }) + serviceAPIGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(servicev0alpha1.GROUP, aggregatorscheme.Scheme, metav1.ParameterCodec, aggregatorscheme.Codecs) for _, b := range config.Builders { - serviceAPIGroupInfo, err := b.GetAPIGroupInfo( + err := b.UpdateAPIGroupInfo( + &serviceAPIGroupInfo, aggregatorscheme.Scheme, - aggregatorscheme.Codecs, aggregatorConfig.GenericConfig.RESTOptionsGetter, nil, // no dual writer ) if err != nil { 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 diff --git a/pkg/services/apiserver/builder/common.go b/pkg/services/apiserver/builder/common.go index 0a576ec5b20..746ee55e2c1 100644 --- a/pkg/services/apiserver/builder/common.go +++ b/pkg/services/apiserver/builder/common.go @@ -5,7 +5,6 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/registry/generic" genericapiserver "k8s.io/apiserver/pkg/server" @@ -24,13 +23,19 @@ type APIGroupBuilder interface { // Add the kinds to the server scheme InstallSchema(scheme *runtime.Scheme) error - // Build the group+version behavior - GetAPIGroupInfo( + // UpdateAPIGroupInfo used to be a getter until we ran into the issue + // 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, - codecs serializer.CodecFactory, optsGetter generic.RESTOptionsGetter, - dualWrite grafanarest.DualWriteBuilder, - ) (*genericapiserver.APIGroupInfo, error) + dualWriteBuilder grafanarest.DualWriteBuilder, + ) error // Get OpenAPI definitions GetOpenAPIDefinitions() common.GetOpenAPIDefinitions diff --git a/pkg/services/apiserver/builder/helper.go b/pkg/services/apiserver/builder/helper.go index bcee690864f..a088be374db 100644 --- a/pkg/services/apiserver/builder/helper.go +++ b/pkg/services/apiserver/builder/helper.go @@ -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 { - g, err := b.GetAPIGroupInfo(scheme, codecs, optsGetter, dualWrite) - if err != nil { - return err + group := b.GetGroupVersion().Group + if _, ok := buildersGroupMap[group]; !ok { + buildersGroupMap[group] = make([]APIGroupBuilder, 0) } - if g == nil || len(g.PrioritizedVersions) < 1 { - continue + buildersGroupMap[group] = append(buildersGroupMap[group], b) + } + + 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 { return err } } + return nil }