From 384f5ccdc6be681cb8298d2a1690f052031db64b Mon Sep 17 00:00:00 2001 From: Todd Treece <360020+toddtreece@users.noreply.github.com> Date: Wed, 1 Nov 2023 09:44:04 -0400 Subject: [PATCH] Playlist: Add internal API version (#77318) --- pkg/api/playlist.go | 12 +- .../playlist/{v0alpha1 => }/conversions.go | 2 +- .../{v0alpha1 => }/conversions_test.go | 2 +- pkg/apis/playlist/doc.go | 4 + .../playlist/{v0alpha1 => }/legacy_storage.go | 2 +- pkg/apis/playlist/register.go | 118 ++++++++++++ pkg/apis/playlist/{v0alpha1 => }/storage.go | 2 +- pkg/apis/playlist/types.go | 65 +++++++ pkg/apis/playlist/v0alpha1/register.go | 53 +----- .../v0alpha1/zz_generated.conversion.go | 170 ++++++++++++++++++ .../v0alpha1/zz_generated.deepcopy.go | 16 +- .../v0alpha1/zz_generated.defaults.go | 33 ++++ pkg/apis/playlist/zz_generated.deepcopy.go | 123 +++++++++++++ pkg/apis/wireset.go | 2 + pkg/registry/apis/apis.go | 2 + pkg/services/grafana-apiserver/service.go | 3 + .../grafana-apiserver/storage/file/file.go | 12 +- 17 files changed, 553 insertions(+), 68 deletions(-) rename pkg/apis/playlist/{v0alpha1 => }/conversions.go (99%) rename pkg/apis/playlist/{v0alpha1 => }/conversions_test.go (98%) create mode 100644 pkg/apis/playlist/doc.go rename pkg/apis/playlist/{v0alpha1 => }/legacy_storage.go (99%) create mode 100644 pkg/apis/playlist/register.go rename pkg/apis/playlist/{v0alpha1 => }/storage.go (98%) create mode 100644 pkg/apis/playlist/types.go create mode 100644 pkg/apis/playlist/v0alpha1/zz_generated.conversion.go create mode 100644 pkg/apis/playlist/v0alpha1/zz_generated.defaults.go create mode 100644 pkg/apis/playlist/zz_generated.deepcopy.go diff --git a/pkg/api/playlist.go b/pkg/api/playlist.go index 65c1605a13f..30be0e3b550 100644 --- a/pkg/api/playlist.go +++ b/pkg/api/playlist.go @@ -12,7 +12,7 @@ import ( "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/apis/playlist/v0alpha1" + internalplaylist "github.com/grafana/grafana/pkg/apis/playlist" "github.com/grafana/grafana/pkg/middleware" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" "github.com/grafana/grafana/pkg/services/featuremgmt" @@ -49,8 +49,8 @@ func (hs *HTTPServer) registerPlaylistAPI(apiRoute routing.RouteRegister) { if hs.Features.IsEnabled(featuremgmt.FlagKubernetesPlaylistsAPI) { namespacer := request.GetNamespaceMapper(hs.Cfg) gvr := schema.GroupVersionResource{ - Group: v0alpha1.GroupName, - Version: v0alpha1.VersionID, + Group: internalplaylist.GroupName, + Version: internalplaylist.VersionID, Resource: "playlists", } @@ -88,7 +88,7 @@ func (hs *HTTPServer) registerPlaylistAPI(apiRoute routing.RouteRegister) { query := strings.ToUpper(c.Query("query")) playlists := []playlist.Playlist{} for _, item := range out.Items { - p := v0alpha1.UnstructuredToLegacyPlaylist(item) + p := internalplaylist.UnstructuredToLegacyPlaylist(item) if p == nil { continue } @@ -111,7 +111,7 @@ func (hs *HTTPServer) registerPlaylistAPI(apiRoute routing.RouteRegister) { errorWriter(c, err) return } - c.JSON(http.StatusOK, v0alpha1.UnstructuredToLegacyPlaylistDTO(*out)) + c.JSON(http.StatusOK, internalplaylist.UnstructuredToLegacyPlaylistDTO(*out)) }} handler.GetPlaylistItems = []web.Handler{func(c *contextmodel.ReqContext) { @@ -125,7 +125,7 @@ func (hs *HTTPServer) registerPlaylistAPI(apiRoute routing.RouteRegister) { errorWriter(c, err) return } - c.JSON(http.StatusOK, v0alpha1.UnstructuredToLegacyPlaylistDTO(*out).Items) + c.JSON(http.StatusOK, internalplaylist.UnstructuredToLegacyPlaylistDTO(*out).Items) }} } diff --git a/pkg/apis/playlist/v0alpha1/conversions.go b/pkg/apis/playlist/conversions.go similarity index 99% rename from pkg/apis/playlist/v0alpha1/conversions.go rename to pkg/apis/playlist/conversions.go index 121eb491458..bbe77f689fa 100644 --- a/pkg/apis/playlist/v0alpha1/conversions.go +++ b/pkg/apis/playlist/conversions.go @@ -1,4 +1,4 @@ -package v0alpha1 +package playlist import ( "encoding/json" diff --git a/pkg/apis/playlist/v0alpha1/conversions_test.go b/pkg/apis/playlist/conversions_test.go similarity index 98% rename from pkg/apis/playlist/v0alpha1/conversions_test.go rename to pkg/apis/playlist/conversions_test.go index 1c64a1ec082..f2d12e5dace 100644 --- a/pkg/apis/playlist/v0alpha1/conversions_test.go +++ b/pkg/apis/playlist/conversions_test.go @@ -1,4 +1,4 @@ -package v0alpha1 +package playlist import ( "encoding/json" diff --git a/pkg/apis/playlist/doc.go b/pkg/apis/playlist/doc.go new file mode 100644 index 00000000000..f4eff4cd63a --- /dev/null +++ b/pkg/apis/playlist/doc.go @@ -0,0 +1,4 @@ +// +k8s:deepcopy-gen=package +// +groupName=playlist.grafana.app + +package playlist // import "github.com/grafana/grafana/pkg/apis/playlist" diff --git a/pkg/apis/playlist/v0alpha1/legacy_storage.go b/pkg/apis/playlist/legacy_storage.go similarity index 99% rename from pkg/apis/playlist/v0alpha1/legacy_storage.go rename to pkg/apis/playlist/legacy_storage.go index e504d37b62e..dab3ce7f813 100644 --- a/pkg/apis/playlist/v0alpha1/legacy_storage.go +++ b/pkg/apis/playlist/legacy_storage.go @@ -1,4 +1,4 @@ -package v0alpha1 +package playlist import ( "context" diff --git a/pkg/apis/playlist/register.go b/pkg/apis/playlist/register.go new file mode 100644 index 00000000000..1658447dec2 --- /dev/null +++ b/pkg/apis/playlist/register.go @@ -0,0 +1,118 @@ +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/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" + + grafanaapiserver "github.com/grafana/grafana/pkg/services/grafana-apiserver" + "github.com/grafana/grafana/pkg/services/grafana-apiserver/endpoints/request" + grafanarest "github.com/grafana/grafana/pkg/services/grafana-apiserver/rest" + "github.com/grafana/grafana/pkg/services/grafana-apiserver/utils" + "github.com/grafana/grafana/pkg/services/playlist" + "github.com/grafana/grafana/pkg/setting" +) + +// GroupName is the group name for this API. +const GroupName = "playlist.grafana.app" +const VersionID = runtime.APIVersionInternal + +var _ grafanaapiserver.APIGroupBuilder = (*PlaylistAPIBuilder)(nil) + +// This is used just so wire has something unique to return +type PlaylistAPIBuilder struct { + service playlist.Service + namespacer request.NamespaceMapper + gv schema.GroupVersion +} + +func RegisterAPIService(p playlist.Service, + apiregistration grafanaapiserver.APIRegistrar, + cfg *setting.Cfg, +) *PlaylistAPIBuilder { + builder := &PlaylistAPIBuilder{ + service: p, + namespacer: request.GetNamespaceMapper(cfg), + gv: schema.GroupVersion{Group: GroupName, Version: VersionID}, + } + apiregistration.RegisterAPI(builder) + return builder +} + +func (b *PlaylistAPIBuilder) GetGroupVersion() schema.GroupVersion { + return b.gv +} + +func (b *PlaylistAPIBuilder) InstallSchema(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(b.gv, + &Playlist{}, + &PlaylistList{}, + ) + return nil +} + +func (b *PlaylistAPIBuilder) GetAPIGroupInfo( + scheme *runtime.Scheme, + codecs serializer.CodecFactory, // pointer? + optsGetter generic.RESTOptionsGetter, +) (*genericapiserver.APIGroupInfo, error) { + apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(GroupName, scheme, metav1.ParameterCodec, codecs) + storage := map[string]rest.Storage{} + + legacyStore := &legacyStorage{ + service: b.service, + namespacer: b.namespacer, + DefaultQualifiedResource: b.gv.WithResource("playlists").GroupResource(), + SingularQualifiedResource: b.gv.WithResource("playlist").GroupResource(), + } + legacyStore.tableConverter = utils.NewTableConverter( + legacyStore.DefaultQualifiedResource, + []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"}, + }, + func(obj runtime.Object) ([]interface{}, error) { + m, ok := obj.(*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["playlists"] = legacyStore + + // enable dual writes if a RESTOptionsGetter is provided + if optsGetter != nil { + store, err := newStorage(scheme, optsGetter, legacyStore) + if err != nil { + return nil, err + } + storage["playlists"] = grafanarest.NewDualWriter(legacyStore, store) + } + + apiGroupInfo.VersionedResourcesStorageMap["v0alpha1"] = storage + return &apiGroupInfo, nil +} + +func (b *PlaylistAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions { + return nil // no custom OpenAPI definitions +} + +func (b *PlaylistAPIBuilder) GetAPIRoutes() *grafanaapiserver.APIRoutes { + return nil // no custom API routes +} diff --git a/pkg/apis/playlist/v0alpha1/storage.go b/pkg/apis/playlist/storage.go similarity index 98% rename from pkg/apis/playlist/v0alpha1/storage.go rename to pkg/apis/playlist/storage.go index d9934841468..d5d80e18b55 100644 --- a/pkg/apis/playlist/v0alpha1/storage.go +++ b/pkg/apis/playlist/storage.go @@ -1,4 +1,4 @@ -package v0alpha1 +package playlist import ( "k8s.io/apimachinery/pkg/runtime" diff --git a/pkg/apis/playlist/types.go b/pkg/apis/playlist/types.go new file mode 100644 index 00000000000..c7c8647086a --- /dev/null +++ b/pkg/apis/playlist/types.go @@ -0,0 +1,65 @@ +package playlist + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type Playlist struct { + metav1.TypeMeta `json:",inline"` + // Standard object's metadata + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec Spec `json:"spec,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type PlaylistList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + Items []Playlist `json:"items,omitempty"` +} + +// Spec defines model for Spec. +type Spec struct { + // Name of the playlist. + Title string `json:"title"` + + // Interval sets the time between switching views in a playlist. + Interval string `json:"interval"` + + // The ordered list of items that the playlist will iterate over. + Items []Item `json:"items,omitempty"` +} + +// Defines values for ItemType. +const ( + ItemTypeDashboardByTag ItemType = "dashboard_by_tag" + ItemTypeDashboardByUid ItemType = "dashboard_by_uid" + + // deprecated -- should use UID + ItemTypeDashboardById ItemType = "dashboard_by_id" +) + +// Item defines model for Item. +type Item struct { + // Type of the item. + Type ItemType `json:"type"` + + // Value depends on type and describes the playlist item. + // + // - dashboard_by_id: The value is an internal numerical identifier set by Grafana. This + // is not portable as the numerical identifier is non-deterministic between different instances. + // Will be replaced by dashboard_by_uid in the future. (deprecated) + // - dashboard_by_tag: The value is a tag which is set on any number of dashboards. All + // dashboards behind the tag will be added to the playlist. + // - dashboard_by_uid: The value is the dashboard UID + Value string `json:"value"` +} + +// Type of the item. +type ItemType string diff --git a/pkg/apis/playlist/v0alpha1/register.go b/pkg/apis/playlist/v0alpha1/register.go index 520f7b5c2d1..cc803ce8fbe 100644 --- a/pkg/apis/playlist/v0alpha1/register.go +++ b/pkg/apis/playlist/v0alpha1/register.go @@ -1,22 +1,16 @@ package v0alpha1 import ( - "fmt" - "time" - 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" grafanaapiserver "github.com/grafana/grafana/pkg/services/grafana-apiserver" "github.com/grafana/grafana/pkg/services/grafana-apiserver/endpoints/request" - grafanarest "github.com/grafana/grafana/pkg/services/grafana-apiserver/rest" - "github.com/grafana/grafana/pkg/services/grafana-apiserver/utils" "github.com/grafana/grafana/pkg/services/playlist" "github.com/grafana/grafana/pkg/setting" ) @@ -56,6 +50,9 @@ func (b *PlaylistAPIBuilder) InstallSchema(scheme *runtime.Scheme) error { &Playlist{}, &PlaylistList{}, ) + if err := RegisterConversions(scheme); err != nil { + return err + } metav1.AddToGroupVersion(scheme, b.gv) return scheme.SetVersionPriority(b.gv) } @@ -65,49 +62,7 @@ func (b *PlaylistAPIBuilder) GetAPIGroupInfo( codecs serializer.CodecFactory, // pointer? optsGetter generic.RESTOptionsGetter, ) (*genericapiserver.APIGroupInfo, error) { - apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(GroupName, scheme, metav1.ParameterCodec, codecs) - storage := map[string]rest.Storage{} - - legacyStore := &legacyStorage{ - service: b.service, - namespacer: b.namespacer, - DefaultQualifiedResource: b.gv.WithResource("playlists").GroupResource(), - SingularQualifiedResource: b.gv.WithResource("playlist").GroupResource(), - } - legacyStore.tableConverter = utils.NewTableConverter( - legacyStore.DefaultQualifiedResource, - []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"}, - }, - func(obj runtime.Object) ([]interface{}, error) { - m, ok := obj.(*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["playlists"] = legacyStore - - // enable dual writes if a RESTOptionsGetter is provided - if optsGetter != nil { - store, err := newStorage(scheme, optsGetter, legacyStore) - if err != nil { - return nil, err - } - storage["playlists"] = grafanarest.NewDualWriter(legacyStore, store) - } - - apiGroupInfo.VersionedResourcesStorageMap[VersionID] = storage - return &apiGroupInfo, nil + return nil, nil } func (b *PlaylistAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions { diff --git a/pkg/apis/playlist/v0alpha1/zz_generated.conversion.go b/pkg/apis/playlist/v0alpha1/zz_generated.conversion.go new file mode 100644 index 00000000000..d89fef079e0 --- /dev/null +++ b/pkg/apis/playlist/v0alpha1/zz_generated.conversion.go @@ -0,0 +1,170 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by conversion-gen. DO NOT EDIT. + +package v0alpha1 + +import ( + unsafe "unsafe" + + playlist "github.com/grafana/grafana/pkg/apis/playlist" + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*Item)(nil), (*playlist.Item)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v0alpha1_Item_To_playlist_Item(a.(*Item), b.(*playlist.Item), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*playlist.Item)(nil), (*Item)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_playlist_Item_To_v0alpha1_Item(a.(*playlist.Item), b.(*Item), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*Playlist)(nil), (*playlist.Playlist)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v0alpha1_Playlist_To_playlist_Playlist(a.(*Playlist), b.(*playlist.Playlist), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*playlist.Playlist)(nil), (*Playlist)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_playlist_Playlist_To_v0alpha1_Playlist(a.(*playlist.Playlist), b.(*Playlist), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*PlaylistList)(nil), (*playlist.PlaylistList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v0alpha1_PlaylistList_To_playlist_PlaylistList(a.(*PlaylistList), b.(*playlist.PlaylistList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*playlist.PlaylistList)(nil), (*PlaylistList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_playlist_PlaylistList_To_v0alpha1_PlaylistList(a.(*playlist.PlaylistList), b.(*PlaylistList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*Spec)(nil), (*playlist.Spec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v0alpha1_Spec_To_playlist_Spec(a.(*Spec), b.(*playlist.Spec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*playlist.Spec)(nil), (*Spec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_playlist_Spec_To_v0alpha1_Spec(a.(*playlist.Spec), b.(*Spec), scope) + }); err != nil { + return err + } + return nil +} + +func autoConvert_v0alpha1_Item_To_playlist_Item(in *Item, out *playlist.Item, s conversion.Scope) error { + out.Type = playlist.ItemType(in.Type) + out.Value = in.Value + return nil +} + +// Convert_v0alpha1_Item_To_playlist_Item is an autogenerated conversion function. +func Convert_v0alpha1_Item_To_playlist_Item(in *Item, out *playlist.Item, s conversion.Scope) error { + return autoConvert_v0alpha1_Item_To_playlist_Item(in, out, s) +} + +func autoConvert_playlist_Item_To_v0alpha1_Item(in *playlist.Item, out *Item, s conversion.Scope) error { + out.Type = ItemType(in.Type) + out.Value = in.Value + return nil +} + +// Convert_playlist_Item_To_v0alpha1_Item is an autogenerated conversion function. +func Convert_playlist_Item_To_v0alpha1_Item(in *playlist.Item, out *Item, s conversion.Scope) error { + return autoConvert_playlist_Item_To_v0alpha1_Item(in, out, s) +} + +func autoConvert_v0alpha1_Playlist_To_playlist_Playlist(in *Playlist, out *playlist.Playlist, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v0alpha1_Spec_To_playlist_Spec(&in.Spec, &out.Spec, s); err != nil { + return err + } + return nil +} + +// Convert_v0alpha1_Playlist_To_playlist_Playlist is an autogenerated conversion function. +func Convert_v0alpha1_Playlist_To_playlist_Playlist(in *Playlist, out *playlist.Playlist, s conversion.Scope) error { + return autoConvert_v0alpha1_Playlist_To_playlist_Playlist(in, out, s) +} + +func autoConvert_playlist_Playlist_To_v0alpha1_Playlist(in *playlist.Playlist, out *Playlist, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_playlist_Spec_To_v0alpha1_Spec(&in.Spec, &out.Spec, s); err != nil { + return err + } + return nil +} + +// Convert_playlist_Playlist_To_v0alpha1_Playlist is an autogenerated conversion function. +func Convert_playlist_Playlist_To_v0alpha1_Playlist(in *playlist.Playlist, out *Playlist, s conversion.Scope) error { + return autoConvert_playlist_Playlist_To_v0alpha1_Playlist(in, out, s) +} + +func autoConvert_v0alpha1_PlaylistList_To_playlist_PlaylistList(in *PlaylistList, out *playlist.PlaylistList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]playlist.Playlist)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_v0alpha1_PlaylistList_To_playlist_PlaylistList is an autogenerated conversion function. +func Convert_v0alpha1_PlaylistList_To_playlist_PlaylistList(in *PlaylistList, out *playlist.PlaylistList, s conversion.Scope) error { + return autoConvert_v0alpha1_PlaylistList_To_playlist_PlaylistList(in, out, s) +} + +func autoConvert_playlist_PlaylistList_To_v0alpha1_PlaylistList(in *playlist.PlaylistList, out *PlaylistList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]Playlist)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_playlist_PlaylistList_To_v0alpha1_PlaylistList is an autogenerated conversion function. +func Convert_playlist_PlaylistList_To_v0alpha1_PlaylistList(in *playlist.PlaylistList, out *PlaylistList, s conversion.Scope) error { + return autoConvert_playlist_PlaylistList_To_v0alpha1_PlaylistList(in, out, s) +} + +func autoConvert_v0alpha1_Spec_To_playlist_Spec(in *Spec, out *playlist.Spec, s conversion.Scope) error { + out.Title = in.Title + out.Interval = in.Interval + out.Items = *(*[]playlist.Item)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_v0alpha1_Spec_To_playlist_Spec is an autogenerated conversion function. +func Convert_v0alpha1_Spec_To_playlist_Spec(in *Spec, out *playlist.Spec, s conversion.Scope) error { + return autoConvert_v0alpha1_Spec_To_playlist_Spec(in, out, s) +} + +func autoConvert_playlist_Spec_To_v0alpha1_Spec(in *playlist.Spec, out *Spec, s conversion.Scope) error { + out.Title = in.Title + out.Interval = in.Interval + out.Items = *(*[]Item)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_playlist_Spec_To_v0alpha1_Spec is an autogenerated conversion function. +func Convert_playlist_Spec_To_v0alpha1_Spec(in *playlist.Spec, out *Spec, s conversion.Scope) error { + return autoConvert_playlist_Spec_To_v0alpha1_Spec(in, out, s) +} diff --git a/pkg/apis/playlist/v0alpha1/zz_generated.deepcopy.go b/pkg/apis/playlist/v0alpha1/zz_generated.deepcopy.go index 74637ae2fb4..022f71d9be8 100644 --- a/pkg/apis/playlist/v0alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/playlist/v0alpha1/zz_generated.deepcopy.go @@ -1,7 +1,21 @@ //go:build !ignore_autogenerated // +build !ignore_autogenerated -// SPDX-License-Identifier: AGPL-3.0-only +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ // Code generated by deepcopy-gen. DO NOT EDIT. diff --git a/pkg/apis/playlist/v0alpha1/zz_generated.defaults.go b/pkg/apis/playlist/v0alpha1/zz_generated.defaults.go new file mode 100644 index 00000000000..ff019bc6019 --- /dev/null +++ b/pkg/apis/playlist/v0alpha1/zz_generated.defaults.go @@ -0,0 +1,33 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v0alpha1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + return nil +} diff --git a/pkg/apis/playlist/zz_generated.deepcopy.go b/pkg/apis/playlist/zz_generated.deepcopy.go new file mode 100644 index 00000000000..87997bf7079 --- /dev/null +++ b/pkg/apis/playlist/zz_generated.deepcopy.go @@ -0,0 +1,123 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package playlist + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Item) DeepCopyInto(out *Item) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Item. +func (in *Item) DeepCopy() *Item { + if in == nil { + return nil + } + out := new(Item) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Playlist) DeepCopyInto(out *Playlist) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Playlist. +func (in *Playlist) DeepCopy() *Playlist { + if in == nil { + return nil + } + out := new(Playlist) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Playlist) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PlaylistList) DeepCopyInto(out *PlaylistList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Playlist, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PlaylistList. +func (in *PlaylistList) DeepCopy() *PlaylistList { + if in == nil { + return nil + } + out := new(PlaylistList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PlaylistList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Spec) DeepCopyInto(out *Spec) { + *out = *in + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Item, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Spec. +func (in *Spec) DeepCopy() *Spec { + if in == nil { + return nil + } + out := new(Spec) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/apis/wireset.go b/pkg/apis/wireset.go index 30b3cbe489c..dd7465bf7e5 100644 --- a/pkg/apis/wireset.go +++ b/pkg/apis/wireset.go @@ -4,12 +4,14 @@ import ( "github.com/google/wire" examplev0alpha1 "github.com/grafana/grafana/pkg/apis/example/v0alpha1" + "github.com/grafana/grafana/pkg/apis/playlist" playlistsv0alpha1 "github.com/grafana/grafana/pkg/apis/playlist/v0alpha1" ) // WireSet is the list of all services // NOTE: you must also register the service in: pkg/registry/apis/apis.go var WireSet = wire.NewSet( + playlist.RegisterAPIService, playlistsv0alpha1.RegisterAPIService, examplev0alpha1.RegisterAPIService, ) diff --git a/pkg/registry/apis/apis.go b/pkg/registry/apis/apis.go index 546b75f5fa8..300d6778f9c 100644 --- a/pkg/registry/apis/apis.go +++ b/pkg/registry/apis/apis.go @@ -4,6 +4,7 @@ import ( "context" examplev0alpha1 "github.com/grafana/grafana/pkg/apis/example/v0alpha1" + "github.com/grafana/grafana/pkg/apis/playlist" playlistsv0alpha1 "github.com/grafana/grafana/pkg/apis/playlist/v0alpha1" "github.com/grafana/grafana/pkg/registry" ) @@ -17,6 +18,7 @@ type Service struct{} // ProvideService is an entry point for each service that will force initialization // and give each builder the chance to register itself with the main server func ProvideService( + _ *playlist.PlaylistAPIBuilder, _ *playlistsv0alpha1.PlaylistAPIBuilder, _ *examplev0alpha1.TestingAPIBuilder, ) *Service { diff --git a/pkg/services/grafana-apiserver/service.go b/pkg/services/grafana-apiserver/service.go index 5193b9c89ef..21eec399f8c 100644 --- a/pkg/services/grafana-apiserver/service.go +++ b/pkg/services/grafana-apiserver/service.go @@ -307,6 +307,9 @@ func (s *service) start(ctx context.Context) error { if err != nil { return err } + if g == nil { + continue + } err = server.InstallAPIGroup(g) if err != nil { return err diff --git a/pkg/services/grafana-apiserver/storage/file/file.go b/pkg/services/grafana-apiserver/storage/file/file.go index d04dea3365a..6b43207e6ce 100644 --- a/pkg/services/grafana-apiserver/storage/file/file.go +++ b/pkg/services/grafana-apiserver/storage/file/file.go @@ -287,7 +287,10 @@ func (s *Storage) Watch(ctx context.Context, key string, opts storage.ListOption // match 'opts.ResourceVersion' according 'opts.ResourceVersionMatch'. func (s *Storage) Get(ctx context.Context, key string, opts storage.GetOptions, objPtr runtime.Object) error { filename := s.filePath(key) - if !exists(filename) { + obj, err := readFile(s.codec, filename, func() runtime.Object { + return objPtr + }) + if err != nil { if opts.IgnoreNotFound { return runtime.SetZeroValue(objPtr) } @@ -298,13 +301,6 @@ func (s *Storage) Get(ctx context.Context, key string, opts storage.GetOptions, return storage.NewKeyNotFoundError(key, int64(rv)) } - obj, err := readFile(s.codec, filename, func() runtime.Object { - return objPtr - }) - if err != nil { - return err - } - currentVersion, err := s.Versioner().ObjectResourceVersion(obj) if err != nil { return err