support generic response

This commit is contained in:
Ryan McKinley
2026-01-12 18:08:56 +03:00
parent b7269073b2
commit e25d09ff3e
5 changed files with 48 additions and 10 deletions
+7 -4
View File
@@ -30,6 +30,7 @@ import (
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/apiserver/builder"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/storage/unified/apistore"
"github.com/grafana/grafana/pkg/tsdb/grafana-testdata-datasource/kinds"
)
@@ -89,10 +90,6 @@ func RegisterAPIService(
return nil, fmt.Errorf("plugin client is not a PluginClient: %T", pluginClient)
}
if pluginJSON.ID != "grafana-testdata-datasource" {
continue // FOR TESTING! codec currently picks the first registered apiVersion :cry:
}
builder, err = NewDataSourceAPIBuilder(
pluginJSON,
client,
@@ -223,6 +220,12 @@ func (b *DataSourceAPIBuilder) AllowedV0Alpha1Resources() []string {
}
func (b *DataSourceAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, opts builder.APIGroupOptions) error {
opts.StorageOptsRegister(b.datasourceResourceInfo.GroupResource(), apistore.StorageOptions{
EnableFolderSupport: false,
Scheme: opts.Scheme, // allows for generic Type applied to multiple groups
})
storage := map[string]rest.Storage{}
// Register the raw datasource connection
+36 -5
View File
@@ -3,8 +3,10 @@ package apistore
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"time"
"github.com/dustin/go-humanize"
@@ -138,8 +140,7 @@ func (s *Storage) prepareObjectForStorage(ctx context.Context, newObject runtime
return v, err
}
err = s.codec.Encode(newObject, &v.raw)
if err == nil {
if err = s.encode(newObject, &v.raw); err == nil {
err = s.handleLargeResources(ctx, obj, &v.raw)
}
return v, err
@@ -233,8 +234,7 @@ func (s *Storage) prepareObjectForUpdate(ctx context.Context, updateObject runti
obj.SetAnnotation(utils.AnnoKeyUpdatedTimestamp, previous.GetAnnotation(utils.AnnoKeyUpdatedTimestamp))
}
err = s.codec.Encode(updateObject, &v.raw)
if err == nil {
if s.encode(updateObject, &v.raw); err == nil {
err = s.handleLargeResources(ctx, obj, &v.raw)
}
return v, err
@@ -268,7 +268,38 @@ func (s *Storage) handleLargeResources(ctx context.Context, obj utils.GrafanaMet
}
// Now encode the smaller version
return s.codec.Encode(orig, buf)
return s.encode(orig, buf)
}
return nil
}
func (s *Storage) encode(obj runtime.Object, w io.Writer) error {
// The standard encoder is fine when only one type maps to a group
if s.opts.Scheme == nil {
return s.codec.Encode(obj, w)
}
// Ensure group+version+kind are configured
info := obj.GetObjectKind()
gvk := info.GroupVersionKind()
if gvk.Group == "" || gvk.Kind == "" || gvk.Version == "" {
gvks, _, err := s.opts.Scheme.ObjectKinds(obj)
if err != nil {
return fmt.Errorf("unable to encode object %w", err)
}
for _, v := range gvks {
if v.Group != s.gr.Group {
continue // skip values not in this group
}
gvk.Group = v.Group
gvk.Kind = v.Kind
if gvk.Version == "" {
gvk.Version = v.Version
}
info.SetGroupVersionKind(gvk)
break
}
}
return json.NewEncoder(w).Encode(obj)
}
@@ -33,9 +33,11 @@ func TestPrepareObjectForStorage(t *testing.T) {
node, err := snowflake.NewNode(rand.Int64N(1024))
require.NoError(t, err)
s := &Storage{
gr: dashv1.DashboardResourceInfo.GroupResource(),
codec: apitesting.TestCodec(rtcodecs, dashv1.DashboardResourceInfo.GroupVersion()),
snowflake: node,
opts: StorageOptions{
Scheme: rtscheme,
EnableFolderSupport: true,
LargeObjectSupport: nil,
MaximumNameLength: 100,
+2
View File
@@ -57,6 +57,8 @@ type DefaultPermissionSetter = func(ctx context.Context, key *resourcepb.Resourc
// Optional settings that apply to a single resource
type StorageOptions struct {
Scheme *runtime.Scheme
// ????: should we constrain this to only dashboards for now?
// Not yet clear if this is a good general solution, or just a stop-gap
LargeObjectSupport LargeObjectSupport
+1 -1
View File
@@ -37,7 +37,7 @@ func TestIntegrationTestDatasource(t *testing.T) {
grafanarest.Mode0, // Legacy only
// grafanarest.Mode2, // write both, read legacy
// grafanarest.Mode3, // write both, read unified
// grafanarest.Mode5, // Unified only
grafanarest.Mode5, // Unified only
} {
t.Run(fmt.Sprintf("testdata (mode:%d)", mode), func(t *testing.T) {
ctx := context.Background()