Playlist: Migrate to App SDK (#95691)

This commit is contained in:
Todd Treece
2024-11-04 14:18:49 -05:00
committed by GitHub
parent 4452d0932a
commit 517a1bef08
25 changed files with 465 additions and 255 deletions
+2 -2
View File
@@ -9,12 +9,12 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic"
"github.com/grafana/grafana/apps/playlist/apis/playlist/v0alpha1"
"github.com/grafana/grafana/apps/playlist/pkg/apis/playlist/v0alpha1"
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/middleware"
internalplaylist "github.com/grafana/grafana/pkg/registry/apis/playlist"
internalplaylist "github.com/grafana/grafana/pkg/registry/apps/playlist"
grafanaapiserver "github.com/grafana/grafana/pkg/services/apiserver"
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
-2
View File
@@ -9,7 +9,6 @@ import (
"github.com/grafana/grafana/pkg/registry/apis/folders"
"github.com/grafana/grafana/pkg/registry/apis/iam"
"github.com/grafana/grafana/pkg/registry/apis/peakq"
"github.com/grafana/grafana/pkg/registry/apis/playlist"
"github.com/grafana/grafana/pkg/registry/apis/query"
"github.com/grafana/grafana/pkg/registry/apis/scope"
"github.com/grafana/grafana/pkg/registry/apis/search"
@@ -21,7 +20,6 @@ type Service struct{}
// and give each builder the chance to register itself with the main server
func ProvideRegistryServiceSink(
_ *dashboard.DashboardsAPIBuilder,
_ *playlist.PlaylistAPIBuilder,
_ *dashboardsnapshot.SnapshotsAPIBuilder,
_ *featuretoggle.FeatureFlagAPIBuilder,
_ *datasource.DataSourceAPIBuilder,
-150
View File
@@ -1,150 +0,0 @@
package playlist
import (
"fmt"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/apiserver/pkg/registry/rest"
genericapiserver "k8s.io/apiserver/pkg/server"
"k8s.io/kube-openapi/pkg/common"
"github.com/prometheus/client_golang/prometheus"
playlist "github.com/grafana/grafana/apps/playlist/apis/playlist/v0alpha1"
"github.com/grafana/grafana/pkg/apimachinery/utils"
"github.com/grafana/grafana/pkg/infra/kvstore"
"github.com/grafana/grafana/pkg/services/apiserver/builder"
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
playlistsvc "github.com/grafana/grafana/pkg/services/playlist"
"github.com/grafana/grafana/pkg/setting"
)
var _ builder.APIGroupBuilder = (*PlaylistAPIBuilder)(nil)
// This is used just so wire has something unique to return
type PlaylistAPIBuilder struct {
service playlistsvc.Service
namespacer request.NamespaceMapper
gv schema.GroupVersion
}
func RegisterAPIService(p playlistsvc.Service,
apiregistration builder.APIRegistrar,
cfg *setting.Cfg,
kvStore kvstore.KVStore,
registerer prometheus.Registerer,
) *PlaylistAPIBuilder {
builder := &PlaylistAPIBuilder{
service: p,
namespacer: request.GetNamespaceMapper(cfg),
gv: schema.GroupVersion{Group: playlist.PlaylistKind().Group(), Version: playlist.PlaylistKind().Version()},
}
apiregistration.RegisterAPI(builder)
return builder
}
func (b *PlaylistAPIBuilder) GetGroupVersion() schema.GroupVersion {
return b.gv
}
func addKnownTypes(scheme *runtime.Scheme, gv schema.GroupVersion) {
scheme.AddKnownTypes(gv,
&playlist.Playlist{},
&playlist.PlaylistList{},
)
}
func (b *PlaylistAPIBuilder) InstallSchema(scheme *runtime.Scheme) error {
addKnownTypes(scheme, b.gv)
// Link this version to the internal representation.
// This is used for server-side-apply (PATCH), and avoids the error:
// "no kind is registered for the type"
addKnownTypes(scheme, schema.GroupVersion{
Group: b.gv.Group,
Version: runtime.APIVersionInternal,
})
// If multiple versions exist, then register conversions from zz_generated.conversion.go
// if err := playlist.RegisterConversions(scheme); err != nil {
// return err
// }
metav1.AddToGroupVersion(scheme, b.gv)
return scheme.SetVersionPriority(b.gv)
}
func (b *PlaylistAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, opts builder.APIGroupOptions) error {
scheme := opts.Scheme
optsGetter := opts.OptsGetter
dualWriteBuilder := opts.DualWriteBuilder
storage := map[string]rest.Storage{}
gvr := schema.GroupVersionResource{
Group: playlist.PlaylistKind().Group(),
Version: playlist.PlaylistKind().Version(),
Resource: playlist.PlaylistKind().Plural(),
}
legacyStore := &legacyStorage{
service: b.service,
namespacer: b.namespacer,
}
legacyStore.tableConverter = utils.NewTableConverter(
gvr.GroupResource(),
utils.TableColumns{
Definition: []metav1.TableColumnDefinition{
{Name: "Name", Type: "string", Format: "name"},
{Name: "Title", Type: "string", Format: "string", Description: "The playlist name"},
{Name: "Interval", Type: "string", Format: "string", Description: "How often the playlist will update"},
{Name: "Created At", Type: "date"},
},
Reader: func(obj any) ([]interface{}, error) {
m, ok := obj.(*playlist.Playlist)
if !ok {
return nil, fmt.Errorf("expected playlist")
}
return []interface{}{
m.Name,
m.Spec.Title,
m.Spec.Interval,
m.CreationTimestamp.UTC().Format(time.RFC3339),
}, nil
},
},
)
storage[gvr.Resource] = legacyStore
// enable dual writes if a RESTOptionsGetter is provided
if optsGetter != nil && dualWriteBuilder != nil {
store, err := newStorage(scheme, optsGetter, legacyStore)
if err != nil {
return err
}
dualWriter, err := dualWriteBuilder(gvr.GroupResource(), legacyStore, store)
if err != nil {
return err
}
storage[gvr.Resource] = dualWriter
}
apiGroupInfo.VersionedResourcesStorageMap[gvr.Version] = storage
return nil
}
func (b *PlaylistAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions {
return playlist.GetOpenAPIDefinitions
}
func (b *PlaylistAPIBuilder) GetAPIRoutes() *builder.APIRoutes {
return nil // no custom API routes
}
func (b *PlaylistAPIBuilder) GetAuthorizer() authorizer.Authorizer {
return nil // default authorizer is fine
}
-31
View File
@@ -1,31 +0,0 @@
package playlist
import (
"strings"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/registry/generic"
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
playlist "github.com/grafana/grafana/apps/playlist/apis/playlist/v0alpha1"
"github.com/grafana/grafana/pkg/apimachinery/utils"
grafanaregistry "github.com/grafana/grafana/pkg/apiserver/registry/generic"
)
func newStorage(scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter, legacy *legacyStorage) (*genericregistry.Store, error) {
kind := playlist.PlaylistKind()
singular := strings.ToLower(kind.Kind()) // ???
resourceInfo := utils.NewResourceInfo(
kind.Group(), kind.Version(),
kind.GroupVersionResource().Resource, singular,
kind.Kind(),
func() runtime.Object {
return kind.ZeroValue()
},
func() runtime.Object {
return kind.ZeroListValue()
},
utils.TableColumns{}, // will use default columns... TODO? legacy.tableConverter.,
)
return grafanaregistry.NewRegistryStore(scheme, resourceInfo, optsGetter)
}
-2
View File
@@ -11,7 +11,6 @@ import (
"github.com/grafana/grafana/pkg/registry/apis/folders"
"github.com/grafana/grafana/pkg/registry/apis/iam"
"github.com/grafana/grafana/pkg/registry/apis/peakq"
"github.com/grafana/grafana/pkg/registry/apis/playlist"
"github.com/grafana/grafana/pkg/registry/apis/query"
"github.com/grafana/grafana/pkg/registry/apis/scope"
"github.com/grafana/grafana/pkg/registry/apis/search"
@@ -28,7 +27,6 @@ var WireSet = wire.NewSet(
datasource.ProvideDefaultPluginConfigs,
// Each must be added here *and* in the ServiceSink above
playlist.RegisterAPIService,
dashboard.RegisterAPIService,
dashboardsnapshot.RegisterAPIService,
featuretoggle.RegisterAPIService,
+3 -1
View File
@@ -4,6 +4,7 @@ import (
"context"
"github.com/grafana/grafana/pkg/registry"
"github.com/grafana/grafana/pkg/registry/apps/playlist"
"github.com/grafana/grafana/pkg/services/apiserver"
"github.com/grafana/grafana/pkg/services/apiserver/builder"
"github.com/grafana/grafana/pkg/services/apiserver/builder/runner"
@@ -22,6 +23,7 @@ type Service struct {
func ProvideRegistryServiceSink(
registrar builder.APIRegistrar,
restConfigProvider apiserver.RestConfigProvider,
playlistAppProvider *playlist.PlaylistAppProvider,
) (*Service, error) {
cfgWrapper := func(ctx context.Context) *rest.Config {
cfg := restConfigProvider.GetRestConfig(ctx)
@@ -36,7 +38,7 @@ func ProvideRegistryServiceSink(
RestConfigGetter: cfgWrapper,
APIRegistrar: registrar,
}
runner, err := runner.NewAPIGroupRunner(cfg)
runner, err := runner.NewAPIGroupRunner(cfg, playlistAppProvider)
if err != nil {
return nil, err
}
@@ -10,7 +10,7 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/types"
playlist "github.com/grafana/grafana/apps/playlist/apis/playlist/v0alpha1"
playlist "github.com/grafana/grafana/apps/playlist/pkg/apis/playlist/v0alpha1"
"github.com/grafana/grafana/pkg/apimachinery/utils"
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
gapiutil "github.com/grafana/grafana/pkg/services/apiserver/utils"
@@ -13,7 +13,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apiserver/pkg/registry/rest"
playlist "github.com/grafana/grafana/apps/playlist/apis/playlist/v0alpha1"
playlist "github.com/grafana/grafana/apps/playlist/pkg/apis/playlist/v0alpha1"
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
playlistsvc "github.com/grafana/grafana/pkg/services/playlist"
)
+88
View File
@@ -0,0 +1,88 @@
package playlist
import (
"fmt"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"github.com/grafana/grafana-app-sdk/app"
"github.com/grafana/grafana-app-sdk/simple"
"github.com/grafana/grafana/apps/playlist/pkg/apis"
playlistv0alpha1 "github.com/grafana/grafana/apps/playlist/pkg/apis/playlist/v0alpha1"
playlistapp "github.com/grafana/grafana/apps/playlist/pkg/app"
"github.com/grafana/grafana/pkg/apimachinery/utils"
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
"github.com/grafana/grafana/pkg/services/apiserver/builder/runner"
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
"github.com/grafana/grafana/pkg/services/featuremgmt"
playlistsvc "github.com/grafana/grafana/pkg/services/playlist"
"github.com/grafana/grafana/pkg/setting"
)
type PlaylistAppProvider struct {
app.Provider
cfg *setting.Cfg
service playlistsvc.Service
}
func RegisterApp(
p playlistsvc.Service,
cfg *setting.Cfg,
features featuremgmt.FeatureToggles,
) *PlaylistAppProvider {
provider := &PlaylistAppProvider{
cfg: cfg,
service: p,
}
appCfg := &runner.AppBuilderConfig{
OpenAPIDefGetter: playlistv0alpha1.GetOpenAPIDefinitions,
LegacyStorageGetter: provider.legacyStorageGetter,
ManagedKinds: playlistapp.GetKinds(),
CustomConfig: any(&playlistapp.PlaylistConfig{
EnableWatchers: features.IsEnabledGlobally(featuremgmt.FlagPlaylistsWatcher),
}),
}
provider.Provider = simple.NewAppProvider(apis.LocalManifest(), appCfg, playlistapp.New)
return provider
}
func (p *PlaylistAppProvider) legacyStorageGetter(requested schema.GroupVersionResource) grafanarest.LegacyStorage {
gvr := schema.GroupVersionResource{
Group: playlistv0alpha1.PlaylistKind().Group(),
Version: playlistv0alpha1.PlaylistKind().Version(),
Resource: playlistv0alpha1.PlaylistKind().Plural(),
}
if requested.String() != gvr.String() {
return nil
}
legacyStore := &legacyStorage{
service: p.service,
namespacer: request.GetNamespaceMapper(p.cfg),
}
legacyStore.tableConverter = utils.NewTableConverter(
gvr.GroupResource(),
utils.TableColumns{
Definition: []metav1.TableColumnDefinition{
{Name: "Name", Type: "string", Format: "name"},
{Name: "Title", Type: "string", Format: "string", Description: "The playlist name"},
{Name: "Interval", Type: "string", Format: "string", Description: "How often the playlist will update"},
{Name: "Created At", Type: "date"},
},
Reader: func(obj any) ([]interface{}, error) {
m, ok := obj.(*playlistv0alpha1.Playlist)
if !ok {
return nil, fmt.Errorf("expected playlist")
}
return []interface{}{
m.Name,
m.Spec.Title,
m.Spec.Interval,
m.CreationTimestamp.UTC().Format(time.RFC3339),
}, nil
},
},
)
return legacyStore
}
+3
View File
@@ -2,8 +2,11 @@ package appregistry
import (
"github.com/google/wire"
"github.com/grafana/grafana/pkg/registry/apps/playlist"
)
var WireSet = wire.NewSet(
ProvideRegistryServiceSink,
playlist.RegisterApp,
)