The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/pkg/registry/apis/playlist/register.go

160 lines
4.9 KiB

package playlist
import (
"fmt"
"strings"
"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/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"
playlist "github.com/grafana/grafana/pkg/apis/playlist/v0alpha1"
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"
playlistsvc "github.com/grafana/grafana/pkg/services/playlist"
"github.com/grafana/grafana/pkg/setting"
)
var _ grafanaapiserver.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 grafanaapiserver.APIRegistrar,
cfg *setting.Cfg,
) *PlaylistAPIBuilder {
builder := &PlaylistAPIBuilder{
service: p,
namespacer: request.GetNamespaceMapper(cfg),
gv: playlist.PlaylistResourceInfo.GroupVersion(),
}
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,
})
gvk := playlist.PlaylistResourceInfo.GroupVersionKind()
// Add playlist thing
_ = scheme.AddFieldLabelConversionFunc(gvk,
runtime.FieldLabelConversionFunc(
func(label, value string) (string, string, error) {
if strings.HasPrefix(label, "grafana.app/") {
return label, value, nil
}
switch label {
case "metadata.name":
return label, value, nil
case "metadata.namespace":
return label, value, nil
default:
return "", "", fmt.Errorf("%q is not a known field selector: only %q, %q", label, "metadata.name", "metadata.namespace")
}
},
),
)
// 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) GetAPIGroupInfo(
scheme *runtime.Scheme,
codecs serializer.CodecFactory, // pointer?
optsGetter generic.RESTOptionsGetter,
) (*genericapiserver.APIGroupInfo, error) {
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(playlist.GROUP, scheme, metav1.ParameterCodec, codecs)
storage := map[string]rest.Storage{}
resource := playlist.PlaylistResourceInfo
legacyStore := &legacyStorage{
service: b.service,
namespacer: b.namespacer,
}
legacyStore.tableConverter = utils.NewTableConverter(
resource.GroupResource(),
[]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 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[resource.StoragePath()] = 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[resource.StoragePath()] = grafanarest.NewDualWriter(legacyStore, store)
}
apiGroupInfo.VersionedResourcesStorageMap[playlist.VERSION] = storage
return &apiGroupInfo, nil
}
func (b *PlaylistAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions {
return playlist.GetOpenAPIDefinitions
}
func (b *PlaylistAPIBuilder) GetAPIRoutes() *grafanaapiserver.APIRoutes {
return nil // no custom API routes
}
func (b *PlaylistAPIBuilder) GetAuthorizer() authorizer.Authorizer {
return nil // default authorizer is fine
}