From 6571451a5725b7466eaffe22e55b84dcc613fdca Mon Sep 17 00:00:00 2001 From: Stephanie Hingtgen Date: Tue, 19 Nov 2024 05:32:05 -0700 Subject: [PATCH] K8s: dashboards: fix conversion (#96648) --- .../apis/dashboard/v0alpha1/register.go | 23 ++++++++++++++++--- .../apis/dashboard/v1alpha1/register.go | 23 ++++++++++++++++--- .../apis/dashboard/v2alpha1/register.go | 23 ++++++++++++++++--- pkg/storage/unified/apistore/store.go | 15 +++++++++--- 4 files changed, 72 insertions(+), 12 deletions(-) diff --git a/pkg/registry/apis/dashboard/v0alpha1/register.go b/pkg/registry/apis/dashboard/v0alpha1/register.go index e6b5e1f9bd9..804d5e4e02d 100644 --- a/pkg/registry/apis/dashboard/v0alpha1/register.go +++ b/pkg/registry/apis/dashboard/v0alpha1/register.go @@ -12,6 +12,7 @@ import ( "k8s.io/kube-openapi/pkg/common" "k8s.io/kube-openapi/pkg/spec3" + dashboardinternal "github.com/grafana/grafana/pkg/apis/dashboard" dashboardv0alpha1 "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" @@ -114,14 +115,30 @@ func (b *DashboardsAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver return err } + defaultOpts, err := optsGetter.GetRESTOptions(b.legacy.Resource.GroupResource(), &dashboardinternal.Dashboard{}) + if err != nil { + return err + } + storageOpts := apistore.StorageOptions{ + InternalConversion: (func(b []byte, desiredObj runtime.Object) (runtime.Object, error) { + internal := &dashboardinternal.Dashboard{} + obj, _, err := defaultOpts.StorageConfig.Config.Codec.Decode(b, nil, internal) + if err != nil { + return nil, err + } + + err = scheme.Convert(obj, desiredObj, nil) + return desiredObj, err + }), + } + // Split dashboards when they are large var largeObjects apistore.LargeObjectSupport if b.legacy.Features.IsEnabledGlobally(featuremgmt.FlagUnifiedStorageBigObjectsSupport) { largeObjects = dashboard.NewDashboardLargeObjectSupport(scheme) - opts.StorageOptions(dash.GroupResource(), apistore.StorageOptions{ - LargeObjectSupport: largeObjects, - }) + storageOpts.LargeObjectSupport = largeObjects } + opts.StorageOptions(dash.GroupResource(), storageOpts) storage := map[string]rest.Storage{} storage[dash.StoragePath()] = legacyStore diff --git a/pkg/registry/apis/dashboard/v1alpha1/register.go b/pkg/registry/apis/dashboard/v1alpha1/register.go index 74b0d08c684..0744ba56573 100644 --- a/pkg/registry/apis/dashboard/v1alpha1/register.go +++ b/pkg/registry/apis/dashboard/v1alpha1/register.go @@ -10,6 +10,7 @@ import ( "k8s.io/kube-openapi/pkg/common" "k8s.io/kube-openapi/pkg/spec3" + dashboardinternal "github.com/grafana/grafana/pkg/apis/dashboard" dashboardv1alpha1 "github.com/grafana/grafana/pkg/apis/dashboard/v1alpha1" grafanaregistry "github.com/grafana/grafana/pkg/apiserver/registry/generic" grafanarest "github.com/grafana/grafana/pkg/apiserver/rest" @@ -112,14 +113,30 @@ func (b *DashboardsAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver return err } + defaultOpts, err := optsGetter.GetRESTOptions(b.legacy.Resource.GroupResource(), &dashboardinternal.Dashboard{}) + if err != nil { + return err + } + storageOpts := apistore.StorageOptions{ + InternalConversion: (func(b []byte, desiredObj runtime.Object) (runtime.Object, error) { + internal := &dashboardinternal.Dashboard{} + obj, _, err := defaultOpts.StorageConfig.Config.Codec.Decode(b, nil, internal) + if err != nil { + return nil, err + } + + err = scheme.Convert(obj, desiredObj, nil) + return desiredObj, err + }), + } + // Split dashboards when they are large var largeObjects apistore.LargeObjectSupport if b.legacy.Features.IsEnabledGlobally(featuremgmt.FlagUnifiedStorageBigObjectsSupport) { largeObjects = dashboard.NewDashboardLargeObjectSupport(scheme) - opts.StorageOptions(dash.GroupResource(), apistore.StorageOptions{ - LargeObjectSupport: largeObjects, - }) + storageOpts.LargeObjectSupport = largeObjects } + opts.StorageOptions(dash.GroupResource(), storageOpts) storage := map[string]rest.Storage{} storage[dash.StoragePath()] = legacyStore diff --git a/pkg/registry/apis/dashboard/v2alpha1/register.go b/pkg/registry/apis/dashboard/v2alpha1/register.go index 6195651cb0e..0484201f79c 100644 --- a/pkg/registry/apis/dashboard/v2alpha1/register.go +++ b/pkg/registry/apis/dashboard/v2alpha1/register.go @@ -10,6 +10,7 @@ import ( "k8s.io/kube-openapi/pkg/common" "k8s.io/kube-openapi/pkg/spec3" + dashboardinternal "github.com/grafana/grafana/pkg/apis/dashboard" dashboardv2alpha1 "github.com/grafana/grafana/pkg/apis/dashboard/v2alpha1" grafanaregistry "github.com/grafana/grafana/pkg/apiserver/registry/generic" grafanarest "github.com/grafana/grafana/pkg/apiserver/rest" @@ -112,14 +113,30 @@ func (b *DashboardsAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver return err } + defaultOpts, err := optsGetter.GetRESTOptions(b.legacy.Resource.GroupResource(), &dashboardinternal.Dashboard{}) + if err != nil { + return err + } + storageOpts := apistore.StorageOptions{ + InternalConversion: (func(b []byte, desiredObj runtime.Object) (runtime.Object, error) { + internal := &dashboardinternal.Dashboard{} + obj, _, err := defaultOpts.StorageConfig.Config.Codec.Decode(b, nil, internal) + if err != nil { + return nil, err + } + + err = scheme.Convert(obj, desiredObj, nil) + return desiredObj, err + }), + } + // Split dashboards when they are large var largeObjects apistore.LargeObjectSupport if b.legacy.Features.IsEnabledGlobally(featuremgmt.FlagUnifiedStorageBigObjectsSupport) { largeObjects = dashboard.NewDashboardLargeObjectSupport(scheme) - opts.StorageOptions(dash.GroupResource(), apistore.StorageOptions{ - LargeObjectSupport: largeObjects, - }) + storageOpts.LargeObjectSupport = largeObjects } + opts.StorageOptions(dash.GroupResource(), storageOpts) storage := map[string]rest.Storage{} storage[dash.StoragePath()] = legacyStore diff --git a/pkg/storage/unified/apistore/store.go b/pkg/storage/unified/apistore/store.go index 8b19007dd8b..a33b602cdc1 100644 --- a/pkg/storage/unified/apistore/store.go +++ b/pkg/storage/unified/apistore/store.go @@ -44,6 +44,7 @@ var _ storage.Interface = (*Storage)(nil) // Optional settings that apply to a single resource type StorageOptions struct { LargeObjectSupport LargeObjectSupport + InternalConversion func([]byte, runtime.Object) (runtime.Object, error) } // Storage implements storage.Interface and storage resources as JSON files on disk. @@ -132,6 +133,14 @@ func (s *Storage) Versioner() storage.Versioner { return s.versioner } +func (s *Storage) convertToObject(data []byte, obj runtime.Object) (runtime.Object, error) { + if s.opts.InternalConversion != nil { + return s.opts.InternalConversion(data, obj) + } + obj, _, err := s.codec.Decode(data, nil, obj) + return obj, err +} + // Create adds a new object at a key unless it already exists. 'ttl' is time-to-live // in seconds (0 means forever). If no error is returned and out is not nil, out will be // set to the read value from database. @@ -310,7 +319,7 @@ func (s *Storage) Get(ctx context.Context, key string, opts storage.GetOptions, return resource.GetError(rsp.Error) } - _, _, err = s.codec.Decode(rsp.Value, nil, objPtr) + _, err = s.convertToObject(rsp.Value, objPtr) if err != nil { return err } @@ -360,7 +369,7 @@ func (s *Storage) GetList(ctx context.Context, key string, opts storage.ListOpti } for _, item := range rsp.Items { - obj, _, err := s.codec.Decode(item.Value, nil, s.newFunc()) + obj, err := s.convertToObject(item.Value, s.newFunc()) if err != nil { return err } @@ -461,7 +470,7 @@ func (s *Storage) GuaranteedUpdate( existingObj = s.newFunc() if len(rsp.Value) > 0 { created = false - _, _, err = s.codec.Decode(rsp.Value, nil, existingObj) + _, err = s.convertToObject(rsp.Value, existingObj) if err != nil { return err }