wip: add datasources collection resource kind definition, register it to the API

This commit is contained in:
Dafydd
2025-12-01 15:02:00 +00:00
parent 0275939762
commit d71474246c
21 changed files with 1128 additions and 20 deletions
+1 -1
View File
@@ -7,4 +7,4 @@ generate: install-app-sdk update-app-sdk
--gogenpath=./pkg/apis \
--grouping=group \
--genoperatorstate=false \
--defencoding=none
--defencoding=none
@@ -0,0 +1,35 @@
package preferences
datasourcestacksV1alpha1: {
kind: "Datasources"
pluralName: "Datasource"
scope: "Namespaced"
schema: {
spec: {
template: TemplateSpec
modes: [...Mode]
}
}
}
TemplateSpec: {
[string]: DataSourceTemplateSpec
}
DataSourceTemplateSpec: {
group: string // type
name: string // variable name / display name
}
Mode: {
name: string
uid: string
definition: ModeSpec
}
ModeSpec: [string]: DataSourceRef
DataSourceRef: {
name: string // grafana data source uid
}
+4 -3
View File
@@ -6,12 +6,13 @@ manifest: {
versions: {
"v1alpha1": {
codegen: {
ts: {enabled: false}
ts: {enabled: true}
go: {enabled: true}
}
kinds: [
starsV1alpha1,
datasourcestacksV1alpha1
]
}
},
}
}
}
@@ -0,0 +1,80 @@
package v1alpha1
import (
"context"
"github.com/grafana/grafana-app-sdk/resource"
)
type DatasourcesClient struct {
client *resource.TypedClient[*Datasources, *DatasourcesList]
}
func NewDatasourcesClient(client resource.Client) *DatasourcesClient {
return &DatasourcesClient{
client: resource.NewTypedClient[*Datasources, *DatasourcesList](client, DatasourcesKind()),
}
}
func NewDatasourcesClientFromGenerator(generator resource.ClientGenerator) (*DatasourcesClient, error) {
c, err := generator.ClientFor(DatasourcesKind())
if err != nil {
return nil, err
}
return NewDatasourcesClient(c), nil
}
func (c *DatasourcesClient) Get(ctx context.Context, identifier resource.Identifier) (*Datasources, error) {
return c.client.Get(ctx, identifier)
}
func (c *DatasourcesClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*DatasourcesList, error) {
return c.client.List(ctx, namespace, opts)
}
func (c *DatasourcesClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*DatasourcesList, error) {
resp, err := c.client.List(ctx, namespace, resource.ListOptions{
ResourceVersion: opts.ResourceVersion,
Limit: opts.Limit,
LabelFilters: opts.LabelFilters,
FieldSelectors: opts.FieldSelectors,
})
if err != nil {
return nil, err
}
for resp.GetContinue() != "" {
page, err := c.client.List(ctx, namespace, resource.ListOptions{
Continue: resp.GetContinue(),
ResourceVersion: opts.ResourceVersion,
Limit: opts.Limit,
LabelFilters: opts.LabelFilters,
FieldSelectors: opts.FieldSelectors,
})
if err != nil {
return nil, err
}
resp.SetContinue(page.GetContinue())
resp.SetResourceVersion(page.GetResourceVersion())
resp.SetItems(append(resp.GetItems(), page.GetItems()...))
}
return resp, nil
}
func (c *DatasourcesClient) Create(ctx context.Context, obj *Datasources, opts resource.CreateOptions) (*Datasources, error) {
// Make sure apiVersion and kind are set
obj.APIVersion = GroupVersion.Identifier()
obj.Kind = DatasourcesKind().Kind()
return c.client.Create(ctx, obj, opts)
}
func (c *DatasourcesClient) Update(ctx context.Context, obj *Datasources, opts resource.UpdateOptions) (*Datasources, error) {
return c.client.Update(ctx, obj, opts)
}
func (c *DatasourcesClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*Datasources, error) {
return c.client.Patch(ctx, identifier, req, opts)
}
func (c *DatasourcesClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
return c.client.Delete(ctx, identifier, opts)
}
@@ -0,0 +1,28 @@
//
// Code generated by grafana-app-sdk. DO NOT EDIT.
//
package v1alpha1
import (
"encoding/json"
"io"
"github.com/grafana/grafana-app-sdk/resource"
)
// DatasourcesJSONCodec is an implementation of resource.Codec for kubernetes JSON encoding
type DatasourcesJSONCodec struct{}
// Read reads JSON-encoded bytes from `reader` and unmarshals them into `into`
func (*DatasourcesJSONCodec) Read(reader io.Reader, into resource.Object) error {
return json.NewDecoder(reader).Decode(into)
}
// Write writes JSON-encoded bytes into `writer` marshaled from `from`
func (*DatasourcesJSONCodec) Write(writer io.Writer, from resource.Object) error {
return json.NewEncoder(writer).Encode(from)
}
// Interface compliance checks
var _ resource.Codec = &DatasourcesJSONCodec{}
@@ -0,0 +1,31 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
package v1alpha1
import (
time "time"
)
// metadata contains embedded CommonMetadata and can be extended with custom string fields
// TODO: use CommonMetadata instead of redefining here; currently needs to be defined here
// without external reference as using the CommonMetadata reference breaks thema codegen.
type DatasourcesMetadata struct {
UpdateTimestamp time.Time `json:"updateTimestamp"`
CreatedBy string `json:"createdBy"`
Uid string `json:"uid"`
CreationTimestamp time.Time `json:"creationTimestamp"`
DeletionTimestamp *time.Time `json:"deletionTimestamp,omitempty"`
Finalizers []string `json:"finalizers"`
ResourceVersion string `json:"resourceVersion"`
Generation int64 `json:"generation"`
UpdatedBy string `json:"updatedBy"`
Labels map[string]string `json:"labels"`
}
// NewDatasourcesMetadata creates a new DatasourcesMetadata object.
func NewDatasourcesMetadata() *DatasourcesMetadata {
return &DatasourcesMetadata{
Finalizers: []string{},
Labels: map[string]string{},
}
}
@@ -0,0 +1,293 @@
//
// Code generated by grafana-app-sdk. DO NOT EDIT.
//
package v1alpha1
import (
"fmt"
"github.com/grafana/grafana-app-sdk/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"time"
)
// +k8s:openapi-gen=true
type Datasources struct {
metav1.TypeMeta `json:",inline" yaml:",inline"`
metav1.ObjectMeta `json:"metadata" yaml:"metadata"`
// Spec is the spec of the Datasources
Spec DatasourcesSpec `json:"spec" yaml:"spec"`
}
func (o *Datasources) GetSpec() any {
return o.Spec
}
func (o *Datasources) SetSpec(spec any) error {
cast, ok := spec.(DatasourcesSpec)
if !ok {
return fmt.Errorf("cannot set spec type %#v, not of type Spec", spec)
}
o.Spec = cast
return nil
}
func (o *Datasources) GetSubresources() map[string]any {
return map[string]any{}
}
func (o *Datasources) GetSubresource(name string) (any, bool) {
switch name {
default:
return nil, false
}
}
func (o *Datasources) SetSubresource(name string, value any) error {
switch name {
default:
return fmt.Errorf("subresource '%s' does not exist", name)
}
}
func (o *Datasources) GetStaticMetadata() resource.StaticMetadata {
gvk := o.GroupVersionKind()
return resource.StaticMetadata{
Name: o.ObjectMeta.Name,
Namespace: o.ObjectMeta.Namespace,
Group: gvk.Group,
Version: gvk.Version,
Kind: gvk.Kind,
}
}
func (o *Datasources) SetStaticMetadata(metadata resource.StaticMetadata) {
o.Name = metadata.Name
o.Namespace = metadata.Namespace
o.SetGroupVersionKind(schema.GroupVersionKind{
Group: metadata.Group,
Version: metadata.Version,
Kind: metadata.Kind,
})
}
func (o *Datasources) GetCommonMetadata() resource.CommonMetadata {
dt := o.DeletionTimestamp
var deletionTimestamp *time.Time
if dt != nil {
deletionTimestamp = &dt.Time
}
// Legacy ExtraFields support
extraFields := make(map[string]any)
if o.Annotations != nil {
extraFields["annotations"] = o.Annotations
}
if o.ManagedFields != nil {
extraFields["managedFields"] = o.ManagedFields
}
if o.OwnerReferences != nil {
extraFields["ownerReferences"] = o.OwnerReferences
}
return resource.CommonMetadata{
UID: string(o.UID),
ResourceVersion: o.ResourceVersion,
Generation: o.Generation,
Labels: o.Labels,
CreationTimestamp: o.CreationTimestamp.Time,
DeletionTimestamp: deletionTimestamp,
Finalizers: o.Finalizers,
UpdateTimestamp: o.GetUpdateTimestamp(),
CreatedBy: o.GetCreatedBy(),
UpdatedBy: o.GetUpdatedBy(),
ExtraFields: extraFields,
}
}
func (o *Datasources) SetCommonMetadata(metadata resource.CommonMetadata) {
o.UID = types.UID(metadata.UID)
o.ResourceVersion = metadata.ResourceVersion
o.Generation = metadata.Generation
o.Labels = metadata.Labels
o.CreationTimestamp = metav1.NewTime(metadata.CreationTimestamp)
if metadata.DeletionTimestamp != nil {
dt := metav1.NewTime(*metadata.DeletionTimestamp)
o.DeletionTimestamp = &dt
} else {
o.DeletionTimestamp = nil
}
o.Finalizers = metadata.Finalizers
if o.Annotations == nil {
o.Annotations = make(map[string]string)
}
if !metadata.UpdateTimestamp.IsZero() {
o.SetUpdateTimestamp(metadata.UpdateTimestamp)
}
if metadata.CreatedBy != "" {
o.SetCreatedBy(metadata.CreatedBy)
}
if metadata.UpdatedBy != "" {
o.SetUpdatedBy(metadata.UpdatedBy)
}
// Legacy support for setting Annotations, ManagedFields, and OwnerReferences via ExtraFields
if metadata.ExtraFields != nil {
if annotations, ok := metadata.ExtraFields["annotations"]; ok {
if cast, ok := annotations.(map[string]string); ok {
o.Annotations = cast
}
}
if managedFields, ok := metadata.ExtraFields["managedFields"]; ok {
if cast, ok := managedFields.([]metav1.ManagedFieldsEntry); ok {
o.ManagedFields = cast
}
}
if ownerReferences, ok := metadata.ExtraFields["ownerReferences"]; ok {
if cast, ok := ownerReferences.([]metav1.OwnerReference); ok {
o.OwnerReferences = cast
}
}
}
}
func (o *Datasources) GetCreatedBy() string {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
return o.ObjectMeta.Annotations["grafana.com/createdBy"]
}
func (o *Datasources) SetCreatedBy(createdBy string) {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
o.ObjectMeta.Annotations["grafana.com/createdBy"] = createdBy
}
func (o *Datasources) GetUpdateTimestamp() time.Time {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
parsed, _ := time.Parse(time.RFC3339, o.ObjectMeta.Annotations["grafana.com/updateTimestamp"])
return parsed
}
func (o *Datasources) SetUpdateTimestamp(updateTimestamp time.Time) {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
o.ObjectMeta.Annotations["grafana.com/updateTimestamp"] = updateTimestamp.Format(time.RFC3339)
}
func (o *Datasources) GetUpdatedBy() string {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
return o.ObjectMeta.Annotations["grafana.com/updatedBy"]
}
func (o *Datasources) SetUpdatedBy(updatedBy string) {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
o.ObjectMeta.Annotations["grafana.com/updatedBy"] = updatedBy
}
func (o *Datasources) Copy() resource.Object {
return resource.CopyObject(o)
}
func (o *Datasources) DeepCopyObject() runtime.Object {
return o.Copy()
}
func (o *Datasources) DeepCopy() *Datasources {
cpy := &Datasources{}
o.DeepCopyInto(cpy)
return cpy
}
func (o *Datasources) DeepCopyInto(dst *Datasources) {
dst.TypeMeta.APIVersion = o.TypeMeta.APIVersion
dst.TypeMeta.Kind = o.TypeMeta.Kind
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
o.Spec.DeepCopyInto(&dst.Spec)
}
// Interface compliance compile-time check
var _ resource.Object = &Datasources{}
// +k8s:openapi-gen=true
type DatasourcesList struct {
metav1.TypeMeta `json:",inline" yaml:",inline"`
metav1.ListMeta `json:"metadata" yaml:"metadata"`
Items []Datasources `json:"items" yaml:"items"`
}
func (o *DatasourcesList) DeepCopyObject() runtime.Object {
return o.Copy()
}
func (o *DatasourcesList) Copy() resource.ListObject {
cpy := &DatasourcesList{
TypeMeta: o.TypeMeta,
Items: make([]Datasources, len(o.Items)),
}
o.ListMeta.DeepCopyInto(&cpy.ListMeta)
for i := 0; i < len(o.Items); i++ {
if item, ok := o.Items[i].Copy().(*Datasources); ok {
cpy.Items[i] = *item
}
}
return cpy
}
func (o *DatasourcesList) GetItems() []resource.Object {
items := make([]resource.Object, len(o.Items))
for i := 0; i < len(o.Items); i++ {
items[i] = &o.Items[i]
}
return items
}
func (o *DatasourcesList) SetItems(items []resource.Object) {
o.Items = make([]Datasources, len(items))
for i := 0; i < len(items); i++ {
o.Items[i] = *items[i].(*Datasources)
}
}
func (o *DatasourcesList) DeepCopy() *DatasourcesList {
cpy := &DatasourcesList{}
o.DeepCopyInto(cpy)
return cpy
}
func (o *DatasourcesList) DeepCopyInto(dst *DatasourcesList) {
resource.CopyObjectInto(dst, o)
}
// Interface compliance compile-time check
var _ resource.ListObject = &DatasourcesList{}
// Copy methods for all subresource types
// DeepCopy creates a full deep copy of Spec
func (s *DatasourcesSpec) DeepCopy() *DatasourcesSpec {
cpy := &DatasourcesSpec{}
s.DeepCopyInto(cpy)
return cpy
}
// DeepCopyInto deep copies Spec into another Spec object
func (s *DatasourcesSpec) DeepCopyInto(dst *DatasourcesSpec) {
resource.CopyObjectInto(dst, s)
}
@@ -0,0 +1,34 @@
//
// Code generated by grafana-app-sdk. DO NOT EDIT.
//
package v1alpha1
import (
"github.com/grafana/grafana-app-sdk/resource"
)
// schema is unexported to prevent accidental overwrites
var (
schemaDatasources = resource.NewSimpleSchema("collections.grafana.app", "v1alpha1", &Datasources{}, &DatasourcesList{}, resource.WithKind("Datasources"),
resource.WithPlural("datasource"), resource.WithScope(resource.NamespacedScope))
kindDatasources = resource.Kind{
Schema: schemaDatasources,
Codecs: map[resource.KindEncoding]resource.Codec{
resource.KindEncodingJSON: &DatasourcesJSONCodec{},
},
}
)
// Kind returns a resource.Kind for this Schema with a JSON codec
func DatasourcesKind() resource.Kind {
return kindDatasources
}
// Schema returns a resource.SimpleSchema representation of Datasources
func DatasourcesSchema() *resource.SimpleSchema {
return schemaDatasources
}
// Interface compliance checks
var _ resource.Schema = kindDatasources
@@ -0,0 +1,58 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
package v1alpha1
// +k8s:openapi-gen=true
type DatasourcesTemplateSpec map[string]DatasourcesDataSourceTemplateSpec
// +k8s:openapi-gen=true
type DatasourcesDataSourceTemplateSpec struct {
// type
Group string `json:"group"`
// variable name / display name
Name string `json:"name"`
}
// NewDatasourcesDataSourceTemplateSpec creates a new DatasourcesDataSourceTemplateSpec object.
func NewDatasourcesDataSourceTemplateSpec() *DatasourcesDataSourceTemplateSpec {
return &DatasourcesDataSourceTemplateSpec{}
}
// +k8s:openapi-gen=true
type DatasourcesMode struct {
Name string `json:"name"`
Uid string `json:"uid"`
Definition DatasourcesModeSpec `json:"definition"`
}
// NewDatasourcesMode creates a new DatasourcesMode object.
func NewDatasourcesMode() *DatasourcesMode {
return &DatasourcesMode{}
}
// +k8s:openapi-gen=true
type DatasourcesModeSpec map[string]DatasourcesDataSourceRef
// +k8s:openapi-gen=true
type DatasourcesDataSourceRef struct {
// grafana data source uid
Name string `json:"name"`
}
// NewDatasourcesDataSourceRef creates a new DatasourcesDataSourceRef object.
func NewDatasourcesDataSourceRef() *DatasourcesDataSourceRef {
return &DatasourcesDataSourceRef{}
}
// +k8s:openapi-gen=true
type DatasourcesSpec struct {
Template DatasourcesTemplateSpec `json:"template"`
Modes []DatasourcesMode `json:"modes"`
}
// NewDatasourcesSpec creates a new DatasourcesSpec object.
func NewDatasourcesSpec() *DatasourcesSpec {
return &DatasourcesSpec{
Modes: []DatasourcesMode{},
}
}
@@ -32,6 +32,19 @@ var StarsResourceInfo = utils.NewResourceInfo(APIGroup, APIVersion,
},
)
var DatasourcesResourceInfo = utils.NewResourceInfo(APIGroup, APIVersion,
"datasources", "datasource", "Datasources",
func() runtime.Object { return &Datasources{} },
func() runtime.Object { return &DatasourcesList{} },
utils.TableColumns{
Definition: []metav1.TableColumnDefinition{
{Name: "Name", Type: "string", Format: "name"},
{Name: "Created At", Type: "date"},
},
// TODO: Reader?
},
)
var (
SchemeBuilder runtime.SchemeBuilder
localSchemeBuilder = &SchemeBuilder
@@ -48,6 +61,8 @@ func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(schemeGroupVersion,
&Stars{},
&StarsList{},
&Datasources{},
&DatasourcesList{},
)
metav1.AddToGroupVersion(scheme, schemeGroupVersion)
return nil
@@ -14,10 +14,241 @@ import (
func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition {
return map[string]common.OpenAPIDefinition{
"github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1.Stars": schema_pkg_apis_collections_v1alpha1_Stars(ref),
"github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1.StarsList": schema_pkg_apis_collections_v1alpha1_StarsList(ref),
"github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1.StarsResource": schema_pkg_apis_collections_v1alpha1_StarsResource(ref),
"github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1.StarsSpec": schema_pkg_apis_collections_v1alpha1_StarsSpec(ref),
"github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1.Datasources": schema_pkg_apis_collections_v1alpha1_Datasources(ref),
"github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1.DatasourcesDataSourceRef": schema_pkg_apis_collections_v1alpha1_DatasourcesDataSourceRef(ref),
"github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1.DatasourcesDataSourceTemplateSpec": schema_pkg_apis_collections_v1alpha1_DatasourcesDataSourceTemplateSpec(ref),
"github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1.DatasourcesList": schema_pkg_apis_collections_v1alpha1_DatasourcesList(ref),
"github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1.DatasourcesMode": schema_pkg_apis_collections_v1alpha1_DatasourcesMode(ref),
"github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1.DatasourcesSpec": schema_pkg_apis_collections_v1alpha1_DatasourcesSpec(ref),
"github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1.Stars": schema_pkg_apis_collections_v1alpha1_Stars(ref),
"github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1.StarsList": schema_pkg_apis_collections_v1alpha1_StarsList(ref),
"github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1.StarsResource": schema_pkg_apis_collections_v1alpha1_StarsResource(ref),
"github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1.StarsSpec": schema_pkg_apis_collections_v1alpha1_StarsSpec(ref),
}
}
func schema_pkg_apis_collections_v1alpha1_Datasources(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"kind": {
SchemaProps: spec.SchemaProps{
Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
Type: []string{"string"},
Format: "",
},
},
"apiVersion": {
SchemaProps: spec.SchemaProps{
Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
Type: []string{"string"},
Format: "",
},
},
"metadata": {
SchemaProps: spec.SchemaProps{
Default: map[string]interface{}{},
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"),
},
},
"spec": {
SchemaProps: spec.SchemaProps{
Description: "Spec is the spec of the Datasources",
Default: map[string]interface{}{},
Ref: ref("github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1.DatasourcesSpec"),
},
},
},
Required: []string{"metadata", "spec"},
},
},
Dependencies: []string{
"github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1.DatasourcesSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
}
}
func schema_pkg_apis_collections_v1alpha1_DatasourcesDataSourceRef(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"name": {
SchemaProps: spec.SchemaProps{
Description: "grafana data source uid",
Default: "",
Type: []string{"string"},
Format: "",
},
},
},
Required: []string{"name"},
},
},
}
}
func schema_pkg_apis_collections_v1alpha1_DatasourcesDataSourceTemplateSpec(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"group": {
SchemaProps: spec.SchemaProps{
Description: "type",
Default: "",
Type: []string{"string"},
Format: "",
},
},
"name": {
SchemaProps: spec.SchemaProps{
Description: "variable name / display name",
Default: "",
Type: []string{"string"},
Format: "",
},
},
},
Required: []string{"group", "name"},
},
},
}
}
func schema_pkg_apis_collections_v1alpha1_DatasourcesList(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"kind": {
SchemaProps: spec.SchemaProps{
Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
Type: []string{"string"},
Format: "",
},
},
"apiVersion": {
SchemaProps: spec.SchemaProps{
Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
Type: []string{"string"},
Format: "",
},
},
"metadata": {
SchemaProps: spec.SchemaProps{
Default: map[string]interface{}{},
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"),
},
},
"items": {
SchemaProps: spec.SchemaProps{
Type: []string{"array"},
Items: &spec.SchemaOrArray{
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Default: map[string]interface{}{},
Ref: ref("github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1.Datasources"),
},
},
},
},
},
},
Required: []string{"metadata", "items"},
},
},
Dependencies: []string{
"github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1.Datasources", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"},
}
}
func schema_pkg_apis_collections_v1alpha1_DatasourcesMode(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"name": {
SchemaProps: spec.SchemaProps{
Default: "",
Type: []string{"string"},
Format: "",
},
},
"uid": {
SchemaProps: spec.SchemaProps{
Default: "",
Type: []string{"string"},
Format: "",
},
},
"definition": {
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
AdditionalProperties: &spec.SchemaOrBool{
Allows: true,
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Default: map[string]interface{}{},
Ref: ref("github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1.DatasourcesDataSourceRef"),
},
},
},
},
},
},
Required: []string{"name", "uid", "definition"},
},
},
Dependencies: []string{
"github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1.DatasourcesDataSourceRef"},
}
}
func schema_pkg_apis_collections_v1alpha1_DatasourcesSpec(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"template": {
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
AdditionalProperties: &spec.SchemaOrBool{
Allows: true,
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Default: map[string]interface{}{},
Ref: ref("github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1.DatasourcesDataSourceTemplateSpec"),
},
},
},
},
},
"modes": {
SchemaProps: spec.SchemaProps{
Type: []string{"array"},
Items: &spec.SchemaOrArray{
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Default: map[string]interface{}{},
Ref: ref("github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1.DatasourcesMode"),
},
},
},
},
},
},
Required: []string{"template", "modes"},
},
},
Dependencies: []string{
"github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1.DatasourcesDataSourceTemplateSpec", "github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1.DatasourcesMode"},
}
}
@@ -1,2 +1,4 @@
API rule violation: list_type_missing,github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1,DatasourcesSpec,Modes
API rule violation: list_type_missing,github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1,StarsSpec,Resource
API rule violation: streaming_list_type_json_tags,github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1,DatasourcesList,ListMeta
API rule violation: streaming_list_type_json_tags,github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1,StarsList,ListMeta
+19 -7
View File
@@ -10,19 +10,22 @@ import (
"fmt"
"strings"
"github.com/grafana/grafana-app-sdk/app"
"github.com/grafana/grafana-app-sdk/resource"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/kube-openapi/pkg/spec3"
"k8s.io/kube-openapi/pkg/validation/spec"
"github.com/grafana/grafana-app-sdk/app"
"github.com/grafana/grafana-app-sdk/resource"
"github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1"
v1alpha1 "github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1"
)
var (
rawSchemaStarsv1alpha1 = []byte(`{"Resource":{"additionalProperties":false,"properties":{"group":{"type":"string"},"kind":{"type":"string"},"names":{"description":"The set of resources\n+listType=set","items":{"type":"string"},"type":"array"}},"required":["group","kind","names"],"type":"object"},"Stars":{"properties":{"spec":{"$ref":"#/components/schemas/spec"}},"required":["spec"]},"spec":{"additionalProperties":false,"properties":{"resource":{"items":{"$ref":"#/components/schemas/Resource"},"type":"array"}},"required":["resource"],"type":"object"}}`)
versionSchemaStarsv1alpha1 app.VersionSchema
_ = json.Unmarshal(rawSchemaStarsv1alpha1, &versionSchemaStarsv1alpha1)
rawSchemaStarsv1alpha1 = []byte(`{"Resource":{"additionalProperties":false,"properties":{"group":{"type":"string"},"kind":{"type":"string"},"names":{"description":"The set of resources\n+listType=set","items":{"type":"string"},"type":"array"}},"required":["group","kind","names"],"type":"object"},"Stars":{"properties":{"spec":{"$ref":"#/components/schemas/spec"}},"required":["spec"]},"spec":{"additionalProperties":false,"properties":{"resource":{"items":{"$ref":"#/components/schemas/Resource"},"type":"array"}},"required":["resource"],"type":"object"}}`)
versionSchemaStarsv1alpha1 app.VersionSchema
_ = json.Unmarshal(rawSchemaStarsv1alpha1, &versionSchemaStarsv1alpha1)
rawSchemaDatasourcesv1alpha1 = []byte(`{"DataSourceRef":{"additionalProperties":false,"properties":{"name":{"description":"grafana data source uid","type":"string"}},"required":["name"],"type":"object"},"DataSourceTemplateSpec":{"additionalProperties":false,"properties":{"group":{"description":"type","type":"string"},"name":{"description":"variable name / display name","type":"string"}},"required":["group","name"],"type":"object"},"Datasources":{"properties":{"spec":{"$ref":"#/components/schemas/spec"}},"required":["spec"]},"Mode":{"additionalProperties":false,"properties":{"definition":{"$ref":"#/components/schemas/ModeSpec"},"name":{"type":"string"},"uid":{"type":"string"}},"required":["name","uid","definition"],"type":"object"},"ModeSpec":{"additionalProperties":{"$ref":"#/components/schemas/DataSourceRef"},"type":"object"},"TemplateSpec":{"additionalProperties":{"$ref":"#/components/schemas/DataSourceTemplateSpec"},"type":"object"},"spec":{"additionalProperties":false,"properties":{"modes":{"items":{"$ref":"#/components/schemas/Mode"},"type":"array"},"template":{"$ref":"#/components/schemas/TemplateSpec"}},"required":["template","modes"],"type":"object"}}`)
versionSchemaDatasourcesv1alpha1 app.VersionSchema
_ = json.Unmarshal(rawSchemaDatasourcesv1alpha1, &versionSchemaDatasourcesv1alpha1)
)
var appManifestData = app.ManifestData{
@@ -49,6 +52,14 @@ var appManifestData = app.ManifestData{
},
Schema: &versionSchemaStarsv1alpha1,
},
{
Kind: "Datasources",
Plural: "Datasource",
Scope: "Namespaced",
Conversion: false,
Schema: &versionSchemaDatasourcesv1alpha1,
},
},
Routes: app.ManifestVersionRoutes{
Namespaced: map[string]spec3.PathProps{},
@@ -68,7 +79,8 @@ func RemoteManifest() app.Manifest {
}
var kindVersionToGoType = map[string]resource.Kind{
"Stars/v1alpha1": v1alpha1.StarsKind(),
"Stars/v1alpha1": v1alpha1.StarsKind(),
"Datasources/v1alpha1": v1alpha1.DatasourcesKind(),
}
// ManifestGoTypeAssociator returns the associated resource.Kind instance for a given Kind and Version, if one exists.
@@ -0,0 +1,47 @@
/*
* This file was generated by grafana-app-sdk. DO NOT EDIT.
*/
import { Spec } from './types.spec.gen';
export interface Metadata {
name: string;
namespace: string;
generateName?: string;
selfLink?: string;
uid?: string;
resourceVersion?: string;
generation?: number;
creationTimestamp?: string;
deletionTimestamp?: string;
deletionGracePeriodSeconds?: number;
labels?: Record<string, string>;
annotations?: Record<string, string>;
ownerReferences?: OwnerReference[];
finalizers?: string[];
managedFields?: ManagedFieldsEntry[];
}
export interface OwnerReference {
apiVersion: string;
kind: string;
name: string;
uid: string;
controller?: boolean;
blockOwnerDeletion?: boolean;
}
export interface ManagedFieldsEntry {
manager?: string;
operation?: string;
apiVersion?: string;
time?: string;
fieldsType?: string;
subresource?: string;
}
export interface Datasources {
kind: string;
apiVersion: string;
metadata: Metadata;
spec: Spec;
}
@@ -0,0 +1,30 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
// metadata contains embedded CommonMetadata and can be extended with custom string fields
// TODO: use CommonMetadata instead of redefining here; currently needs to be defined here
// without external reference as using the CommonMetadata reference breaks thema codegen.
export interface Metadata {
updateTimestamp: string;
createdBy: string;
uid: string;
creationTimestamp: string;
deletionTimestamp?: string;
finalizers: string[];
resourceVersion: string;
generation: number;
updatedBy: string;
labels: Record<string, string>;
}
export const defaultMetadata = (): Metadata => ({
updateTimestamp: "",
createdBy: "",
uid: "",
creationTimestamp: "",
finalizers: [],
resourceVersion: "",
generation: 0,
updatedBy: "",
labels: {},
});
@@ -0,0 +1,53 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
export type TemplateSpec = Record<string, DataSourceTemplateSpec>;
export const defaultTemplateSpec = (): TemplateSpec => ({});
export interface DataSourceTemplateSpec {
// type
group: string;
// variable name / display name
name: string;
}
export const defaultDataSourceTemplateSpec = (): DataSourceTemplateSpec => ({
group: "",
name: "",
});
export interface Mode {
name: string;
uid: string;
definition: ModeSpec;
}
export const defaultMode = (): Mode => ({
name: "",
uid: "",
definition: defaultModeSpec(),
});
export type ModeSpec = Record<string, DataSourceRef>;
export const defaultModeSpec = (): ModeSpec => ({});
export interface DataSourceRef {
// grafana data source uid
name: string;
}
export const defaultDataSourceRef = (): DataSourceRef => ({
name: "",
});
export interface Spec {
template: TemplateSpec;
modes: Mode[];
}
export const defaultSpec = (): Spec => ({
template: defaultTemplateSpec(),
modes: [],
});
@@ -0,0 +1,47 @@
/*
* This file was generated by grafana-app-sdk. DO NOT EDIT.
*/
import { Spec } from './types.spec.gen';
export interface Metadata {
name: string;
namespace: string;
generateName?: string;
selfLink?: string;
uid?: string;
resourceVersion?: string;
generation?: number;
creationTimestamp?: string;
deletionTimestamp?: string;
deletionGracePeriodSeconds?: number;
labels?: Record<string, string>;
annotations?: Record<string, string>;
ownerReferences?: OwnerReference[];
finalizers?: string[];
managedFields?: ManagedFieldsEntry[];
}
export interface OwnerReference {
apiVersion: string;
kind: string;
name: string;
uid: string;
controller?: boolean;
blockOwnerDeletion?: boolean;
}
export interface ManagedFieldsEntry {
manager?: string;
operation?: string;
apiVersion?: string;
time?: string;
fieldsType?: string;
subresource?: string;
}
export interface Stars {
kind: string;
apiVersion: string;
metadata: Metadata;
spec: Spec;
}
@@ -0,0 +1,30 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
// metadata contains embedded CommonMetadata and can be extended with custom string fields
// TODO: use CommonMetadata instead of redefining here; currently needs to be defined here
// without external reference as using the CommonMetadata reference breaks thema codegen.
export interface Metadata {
updateTimestamp: string;
createdBy: string;
uid: string;
creationTimestamp: string;
deletionTimestamp?: string;
finalizers: string[];
resourceVersion: string;
generation: number;
updatedBy: string;
labels: Record<string, string>;
}
export const defaultMetadata = (): Metadata => ({
updateTimestamp: "",
createdBy: "",
uid: "",
creationTimestamp: "",
finalizers: [],
resourceVersion: "",
generation: 0,
updatedBy: "",
labels: {},
});
@@ -0,0 +1,24 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
export interface Resource {
group: string;
kind: string;
// The set of resources
// +listType=set
names: string[];
}
export const defaultResource = (): Resource => ({
group: "",
kind: "",
names: [],
});
export interface Spec {
resource: Resource[];
}
export const defaultSpec = (): Spec => ({
resource: [],
});
@@ -0,0 +1,47 @@
package collections
import (
"context"
authlib "github.com/grafana/authlib/types"
collections "github.com/grafana/grafana/apps/collections/pkg/apis/collections/v1alpha1"
"github.com/grafana/grafana/pkg/apimachinery/identity"
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
"k8s.io/apimachinery/pkg/apis/meta/internalversion"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)
var _ grafanarest.Storage = (*datasourceStorage)(nil)
type datasourceStorage struct {
grafanarest.Storage
}
// When using list, we really just want to get the value for the single user
func (s *datasourceStorage) List(ctx context.Context, options *internalversion.ListOptions) (runtime.Object, error) {
user, err := identity.GetRequester(ctx)
if err != nil {
return nil, err
}
switch user.GetIdentityType() {
case authlib.TypeAnonymous:
return s.NewList(), nil
// Get the single user stars
case authlib.TypeUser:
datasources := &collections.DatasourcesList{}
obj, _ := s.Get(ctx, "user-"+user.GetIdentifier(), &v1.GetOptions{})
if obj != nil {
d, ok := obj.(*collections.Datasources)
if ok {
datasources.Items = []collections.Datasources{*d}
}
}
return datasources, nil
default:
return s.Storage.List(ctx, options)
}
}
+15 -5
View File
@@ -94,21 +94,31 @@ func (b *APIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupI
storage := map[string]rest.Storage{}
// Configure Stars Dual writer
resource := collections.StarsResourceInfo
starsResource := collections.StarsResourceInfo
var stars grafanarest.Storage
stars, err := grafanaregistry.NewRegistryStore(opts.Scheme, resource, opts.OptsGetter)
stars, err := grafanaregistry.NewRegistryStore(opts.Scheme, starsResource, opts.OptsGetter)
if err != nil {
return err
}
stars = &starStorage{Storage: stars} // wrap List so we only return one value
if b.legacyStars != nil && opts.DualWriteBuilder != nil {
stars, err = opts.DualWriteBuilder(resource.GroupResource(), b.legacyStars, stars)
stars, err = opts.DualWriteBuilder(starsResource.GroupResource(), b.legacyStars, stars)
if err != nil {
return err
}
}
storage[resource.StoragePath()] = stars
storage[resource.StoragePath("update")] = &starsREST{store: stars}
storage[starsResource.StoragePath()] = stars
storage[starsResource.StoragePath("update")] = &starsREST{store: stars}
// Configure Datasources dual writer
datasourcesResource := collections.DatasourcesResourceInfo
var datasources grafanarest.Storage
datasources, err = grafanaregistry.NewRegistryStore(opts.Scheme, datasourcesResource, opts.OptsGetter)
if err != nil {
return err
}
datasources = &datasourceStorage{Storage: datasources} // wrap List so we only return one value
storage[datasourcesResource.StoragePath()] = datasources
apiGroupInfo.VersionedResourcesStorageMap[collections.APIVersion] = storage
return nil