mirror of https://github.com/grafana/grafana
Schemas: Generate CRDs for core kinds (#62641)
Co-authored-by: sam boyer <sdboyer@grafana.com>pull/62715/head
parent
b95eda045a
commit
e70d623f90
@ -0,0 +1,61 @@ |
||||
package codegen |
||||
|
||||
import ( |
||||
"bytes" |
||||
"fmt" |
||||
"path/filepath" |
||||
|
||||
"github.com/grafana/codejen" |
||||
"github.com/grafana/grafana/pkg/kindsys" |
||||
) |
||||
|
||||
// CRDKindRegistryJenny generates a static registry of the CRD representations
|
||||
// of core Grafana kinds, layered on top of the publicly consumable generated
|
||||
// registry in pkg/corekinds.
|
||||
//
|
||||
// Path should be the relative path to the directory that will contain the
|
||||
// generated registry.
|
||||
func CRDKindRegistryJenny(path string) ManyToOne { |
||||
return &crdregjenny{ |
||||
path: path, |
||||
} |
||||
} |
||||
|
||||
type crdregjenny struct { |
||||
path string |
||||
} |
||||
|
||||
func (j *crdregjenny) JennyName() string { |
||||
return "CRDKindRegistryJenny" |
||||
} |
||||
|
||||
func (j *crdregjenny) Generate(kinds ...kindsys.Kind) (*codejen.File, error) { |
||||
cores := make([]kindsys.Core, 0, len(kinds)) |
||||
for _, d := range kinds { |
||||
if corekind, is := d.(kindsys.Core); is { |
||||
cores = append(cores, corekind) |
||||
} |
||||
} |
||||
if len(cores) == 0 { |
||||
return nil, nil |
||||
} |
||||
|
||||
buf := new(bytes.Buffer) |
||||
if err := tmpls.Lookup("core_crd_registry.tmpl").Execute(buf, tvars_kind_registry{ |
||||
PackageName: "corecrd", |
||||
KindPackagePrefix: filepath.ToSlash(filepath.Join("github.com/grafana/grafana", kindsys.GoCoreKindParentPath)), |
||||
Kinds: cores, |
||||
}); err != nil { |
||||
return nil, fmt.Errorf("failed executing core crd registry template: %w", err) |
||||
} |
||||
|
||||
b, err := postprocessGoFile(genGoFile{ |
||||
path: j.path, |
||||
in: buf.Bytes(), |
||||
}) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return codejen.NewFile(filepath.Join(j.path, "registry_gen.go"), b, j), nil |
||||
} |
@ -0,0 +1,51 @@ |
||||
package codegen |
||||
|
||||
import ( |
||||
"bytes" |
||||
"fmt" |
||||
"path/filepath" |
||||
|
||||
"github.com/grafana/codejen" |
||||
"github.com/grafana/grafana/pkg/kindsys" |
||||
) |
||||
|
||||
// CRDTypesJenny generates the OpenAPI CRD representation for a core
|
||||
// structured kind that is expected by Kubernetes controller machinery.
|
||||
func CRDTypesJenny(path string) OneToOne { |
||||
return crdTypesJenny{ |
||||
parentpath: path, |
||||
} |
||||
} |
||||
|
||||
type crdTypesJenny struct { |
||||
parentpath string |
||||
} |
||||
|
||||
func (j crdTypesJenny) JennyName() string { |
||||
return "CRDTypesJenny" |
||||
} |
||||
|
||||
func (j crdTypesJenny) Generate(kind kindsys.Kind) (*codejen.File, error) { |
||||
_, isCore := kind.(kindsys.Core) |
||||
_, isCustom := kind.(kindsys.Core) |
||||
if !(isCore || isCustom) { |
||||
return nil, nil |
||||
} |
||||
|
||||
buf := new(bytes.Buffer) |
||||
if err := tmpls.Lookup("core_crd_types.tmpl").Execute(buf, kind); err != nil { |
||||
return nil, fmt.Errorf("failed executing crd types template: %w", err) |
||||
} |
||||
|
||||
name := kind.Props().Common().MachineName |
||||
path := filepath.Join(j.parentpath, name, "crd", name+"_crd_gen.go") |
||||
b, err := postprocessGoFile(genGoFile{ |
||||
path: path, |
||||
in: buf.Bytes(), |
||||
}) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return codejen.NewFile(path, b, j), nil |
||||
} |
@ -0,0 +1,214 @@ |
||||
package codegen |
||||
|
||||
import ( |
||||
"bytes" |
||||
"fmt" |
||||
"path/filepath" |
||||
|
||||
"cuelang.org/go/cue" |
||||
"cuelang.org/go/cue/ast" |
||||
"cuelang.org/go/encoding/openapi" |
||||
cueyaml "cuelang.org/go/pkg/encoding/yaml" |
||||
"github.com/grafana/codejen" |
||||
"github.com/grafana/grafana/pkg/kindsys" |
||||
"github.com/grafana/grafana/pkg/kindsys/k8ssys" |
||||
"github.com/grafana/thema" |
||||
goyaml "gopkg.in/yaml.v3" |
||||
) |
||||
|
||||
// TODO this jenny is quite sloppy, having been quickly adapted from app-sdk. It needs love
|
||||
|
||||
// YamlCRDJenny generates a representation of a core structured kind in YAML CRD form.
|
||||
func YamlCRDJenny(path string) OneToOne { |
||||
return yamlCRDJenny{ |
||||
parentpath: path, |
||||
} |
||||
} |
||||
|
||||
type yamlCRDJenny struct { |
||||
parentpath string |
||||
} |
||||
|
||||
func (yamlCRDJenny) JennyName() string { |
||||
return "YamlCRDJenny" |
||||
} |
||||
|
||||
func (j yamlCRDJenny) Generate(k kindsys.Kind) (*codejen.File, error) { |
||||
kind, is := k.(kindsys.Core) |
||||
if !is { |
||||
return nil, nil |
||||
} |
||||
|
||||
props := kind.Def().Properties |
||||
lin := kind.Lineage() |
||||
|
||||
// We need to go through every schema, as they all have to be defined in the CRD
|
||||
sch, err := lin.Schema(thema.SV(0, 0)) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
resource := customResourceDefinition{ |
||||
APIVersion: "apiextensions.k8s.io/v1", |
||||
Kind: "CustomResourceDefinition", |
||||
Metadata: customResourceDefinitionMetadata{ |
||||
Name: fmt.Sprintf("%s.%s", props.PluralMachineName, props.CRD.Group), |
||||
}, |
||||
Spec: k8ssys.CustomResourceDefinitionSpec{ |
||||
Group: props.CRD.Group, |
||||
Scope: props.CRD.Scope, |
||||
Names: k8ssys.CustomResourceDefinitionSpecNames{ |
||||
Kind: props.Name, |
||||
Plural: props.PluralMachineName, |
||||
}, |
||||
Versions: make([]k8ssys.CustomResourceDefinitionSpecVersion, 0), |
||||
}, |
||||
} |
||||
latest := lin.Latest().Version() |
||||
|
||||
for sch != nil { |
||||
oapi, err := generateOpenAPI(sch, props) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
vstr := versionString(sch.Version()) |
||||
if props.Maturity.Less(kindsys.MaturityStable) { |
||||
vstr = "v0-0alpha1" |
||||
} |
||||
|
||||
ver, err := valueToCRDSpecVersion(oapi, vstr, sch.Version() == latest) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
if props.CRD.DummySchema { |
||||
ver.Schema = map[string]any{ |
||||
"openAPIV3Schema": map[string]any{ |
||||
"type": "object", |
||||
"properties": map[string]any{ |
||||
"spec": map[string]any{ |
||||
"type": "object", |
||||
"x-kubernetes-preserve-unknown-fields": true, |
||||
}, |
||||
}, |
||||
"required": []any{ |
||||
"spec", |
||||
}, |
||||
}, |
||||
} |
||||
} |
||||
|
||||
resource.Spec.Versions = append(resource.Spec.Versions, ver) |
||||
sch = sch.Successor() |
||||
} |
||||
contents, err := goyaml.Marshal(resource) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
if props.CRD.DummySchema { |
||||
// Add a comment header for those with dummy schema
|
||||
b := new(bytes.Buffer) |
||||
fmt.Fprintf(b, "# This CRD is generated with an empty schema body because Grafana's\n# code generators currently produce OpenAPI that Kubernetes will not\n# accept, despite being valid.\n\n%s", string(contents)) |
||||
contents = b.Bytes() |
||||
} |
||||
|
||||
return codejen.NewFile(filepath.Join(j.parentpath, props.MachineName, "crd", props.MachineName+".crd.yml"), contents, j), nil |
||||
} |
||||
|
||||
// customResourceDefinition differs from k8ssys.CustomResourceDefinition in that it doesn't use the metav1
|
||||
// TypeMeta and ObjectMeta, as those do not contain YAML tags and get improperly serialized to YAML.
|
||||
// Since we don't need to use it with the kubernetes go-client, we don't need the extra functionality attached.
|
||||
//
|
||||
//nolint:lll
|
||||
type customResourceDefinition struct { |
||||
Kind string `json:"kind,omitempty" yaml:"kind,omitempty" protobuf:"bytes,1,opt,name=kind"` |
||||
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty" protobuf:"bytes,2,opt,name=apiVersion"` |
||||
Metadata customResourceDefinitionMetadata `json:"metadata,omitempty" yaml:"metadata,omitempty"` |
||||
Spec k8ssys.CustomResourceDefinitionSpec `json:"spec"` |
||||
} |
||||
|
||||
type customResourceDefinitionMetadata struct { |
||||
Name string `json:"name,omitempty" yaml:"name" protobuf:"bytes,1,opt,name=name"` |
||||
// TODO: other fields as necessary for codegen
|
||||
} |
||||
|
||||
type cueOpenAPIEncoded struct { |
||||
Components cueOpenAPIEncodedComponents `json:"components"` |
||||
} |
||||
|
||||
type cueOpenAPIEncodedComponents struct { |
||||
Schemas map[string]any `json:"schemas"` |
||||
} |
||||
|
||||
func valueToCRDSpecVersion(str string, name string, stored bool) (k8ssys.CustomResourceDefinitionSpecVersion, error) { |
||||
// Decode the bytes back into an object where we can trim the openAPI clutter out
|
||||
// and grab just the schema as a map[string]any (which is what k8s wants)
|
||||
back := cueOpenAPIEncoded{} |
||||
err := goyaml.Unmarshal([]byte(str), &back) |
||||
if err != nil { |
||||
return k8ssys.CustomResourceDefinitionSpecVersion{}, err |
||||
} |
||||
if len(back.Components.Schemas) != 1 { |
||||
// There should only be one schema here...
|
||||
// TODO: this may change with subresources--but subresources should have defined names
|
||||
return k8ssys.CustomResourceDefinitionSpecVersion{}, fmt.Errorf("version %s has multiple schemas", name) |
||||
} |
||||
var def map[string]any |
||||
for _, v := range back.Components.Schemas { |
||||
ok := false |
||||
def, ok = v.(map[string]any) |
||||
if !ok { |
||||
return k8ssys.CustomResourceDefinitionSpecVersion{}, |
||||
fmt.Errorf("error generating openapi schema - generated schema has invalid type") |
||||
} |
||||
} |
||||
|
||||
return k8ssys.CustomResourceDefinitionSpecVersion{ |
||||
Name: name, |
||||
Served: true, |
||||
Storage: stored, |
||||
Schema: map[string]any{ |
||||
"openAPIV3Schema": map[string]any{ |
||||
"properties": map[string]any{ |
||||
"spec": def, |
||||
}, |
||||
"required": []any{ |
||||
"spec", |
||||
}, |
||||
"type": "object", |
||||
}, |
||||
}, |
||||
}, nil |
||||
} |
||||
|
||||
func versionString(version thema.SyntacticVersion) string { |
||||
return fmt.Sprintf("v%d-%d", version[0], version[1]) |
||||
} |
||||
|
||||
// Hoisting this out of thema until we resolve the proper approach there
|
||||
func generateOpenAPI(sch thema.Schema, props kindsys.CoreProperties) (string, error) { |
||||
ctx := sch.Underlying().Context() |
||||
v := ctx.CompileString(fmt.Sprintf("#%s: _", props.Name)) |
||||
defpath := cue.MakePath(cue.Def(props.Name)) |
||||
defsch := v.FillPath(defpath, sch.Underlying()) |
||||
|
||||
cfg := &openapi.Config{ |
||||
NameFunc: func(v cue.Value, path cue.Path) string { |
||||
if path.String() == defpath.String() { |
||||
return props.Name |
||||
} |
||||
return "" |
||||
}, |
||||
Info: ast.NewStruct( // doesn't matter, we're throwing it away
|
||||
"title", ast.NewString(props.Name), |
||||
"version", ast.NewString("0.0"), |
||||
), |
||||
} |
||||
|
||||
f, err := openapi.Generate(defsch, cfg) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
return cueyaml.Marshal(sch.Lineage().Runtime().Context().BuildFile(f)) |
||||
} |
@ -0,0 +1,66 @@ |
||||
package {{ .PackageName }} |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"fmt" |
||||
|
||||
{{range .Kinds }} |
||||
{{ .Props.MachineName }} "{{ $.KindPackagePrefix }}/{{ .Props.MachineName }}/crd"{{end}} |
||||
"github.com/grafana/grafana/pkg/kindsys" |
||||
"github.com/grafana/grafana/pkg/kindsys/k8ssys" |
||||
"github.com/grafana/grafana/pkg/registry/corekind" |
||||
"gopkg.in/yaml.v3" |
||||
) |
||||
|
||||
// Registry is a list of all of Grafana's core structured kinds, wrapped in a |
||||
// standard [k8ssys.CRD] interface that makes them usable for interactions |
||||
// with certain Kubernetes controller and apimachinery libraries. |
||||
// |
||||
// There are two access methods: individually via literal named methods, or as |
||||
// a slice returned from All() method. |
||||
// |
||||
// Prefer the individual named methods for use cases where the particular kind(s) |
||||
// that are needed are known to the caller. Prefer All() when performing operations |
||||
// generically across all kinds. |
||||
type Registry struct { |
||||
all [{{ len .Kinds }}]k8ssys.Kind |
||||
} |
||||
|
||||
{{range $i, $k := .Kinds }} |
||||
// {{ .Props.Name }} returns the [k8ssys.Kind] instance for the {{ .Props.Name }} kind. |
||||
func (r *Registry) {{ .Props.Name }}() k8ssys.Kind { |
||||
return r.all[{{ $i }}] |
||||
} |
||||
{{end}} |
||||
|
||||
func doNewRegistry(breg *corekind.Base) *Registry { |
||||
var err error |
||||
var b []byte |
||||
var kk k8ssys.Kind |
||||
reg := &Registry{} |
||||
|
||||
{{range $i, $k := .Kinds }} |
||||
kk = k8ssys.Kind{ |
||||
GrafanaKind: breg.{{ $k.Props.Name }}(), |
||||
Object: &{{ $k.Props.MachineName }}.{{ $k.Props.Name }}{}, |
||||
ObjectList: &{{ $k.Props.MachineName }}.{{ $k.Props.Name }}List{}, |
||||
} |
||||
// TODO Having the committed form on disk in YAML is worth doing this for now...but fix this silliness |
||||
map{{ $i }} := make(map[string]any) |
||||
err = yaml.Unmarshal({{ $k.Props.MachineName }}.CRDYaml, map{{ $i }}) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("generated CRD YAML for {{ $k.Props.Name }} failed to unmarshal: %s", err)) |
||||
} |
||||
b, err = json.Marshal(map{{ $i }}) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("could not re-marshal CRD JSON for {{ $k.Props.Name }}: %s", err)) |
||||
} |
||||
err = json.Unmarshal(b, &kk.Schema) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("could not unmarshal CRD JSON for {{ $k.Props.Name }}: %s", err)) |
||||
} |
||||
reg.all[{{ $i }}] = kk |
||||
{{end}} |
||||
|
||||
return reg |
||||
} |
@ -0,0 +1,25 @@ |
||||
package crd |
||||
|
||||
import ( |
||||
_ "embed" |
||||
|
||||
"github.com/grafana/grafana/pkg/kinds/{{ .Props.MachineName }}" |
||||
"github.com/grafana/grafana/pkg/kindsys/k8ssys" |
||||
) |
||||
|
||||
// The CRD YAML representation of the {{ .Props.Name }} kind. |
||||
// |
||||
//go:embed {{ .Props.MachineName }}.crd.yml |
||||
var CRDYaml []byte |
||||
|
||||
// {{ .Props.Name }} is the Go CRD representation of a single {{ .Props.Name }} object. |
||||
// It implements [runtime.Object], and is used in k8s scheme construction. |
||||
type {{ .Props.Name }} struct { |
||||
k8ssys.Base[{{ .Props.MachineName }}.{{ .Props.Name }}] |
||||
} |
||||
|
||||
// {{ .Props.Name }}List is the Go CRD representation of a list {{ .Props.Name }} objects. |
||||
// It implements [runtime.Object], and is used in k8s scheme construction. |
||||
type {{ .Props.Name }}List struct { |
||||
k8ssys.ListBase[{{ .Props.MachineName }}.{{ .Props.Name }}] |
||||
} |
@ -1,11 +1,11 @@ |
||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT. |
||||
// |
||||
// Generated by: |
||||
// {{ .MainGenerator }} |
||||
// Using jennies: |
||||
{{ .Leader }} Code generated - EDITING IS FUTILE. DO NOT EDIT. |
||||
{{ .Leader }} |
||||
{{ .Leader }} Generated by: |
||||
{{ .Leader }} {{ .MainGenerator }} |
||||
{{ .Leader }} Using jennies: |
||||
{{- range .Using }} |
||||
// {{ .JennyName }} |
||||
{{ $.Leader }} {{ .JennyName }} |
||||
{{- end }} |
||||
// |
||||
// Run 'make gen-cue' from repository root to regenerate. |
||||
{{ .Leader }} |
||||
{{ .Leader }} Run 'make gen-cue' from repository root to regenerate. |
||||
|
||||
|
@ -0,0 +1,36 @@ |
||||
# Code generated - EDITING IS FUTILE. DO NOT EDIT. |
||||
# |
||||
# Generated by: |
||||
# kinds/gen.go |
||||
# Using jennies: |
||||
# YamlCRDJenny |
||||
# |
||||
# Run 'make gen-cue' from repository root to regenerate. |
||||
|
||||
# This CRD is generated with an empty schema body because Grafana's |
||||
# code generators currently produce OpenAPI that Kubernetes will not |
||||
# accept, despite being valid. |
||||
|
||||
kind: CustomResourceDefinition |
||||
apiVersion: apiextensions.k8s.io/v1 |
||||
metadata: |
||||
name: dashboards.dashboard.core.grafana.com |
||||
spec: |
||||
group: dashboard.core.grafana.com |
||||
versions: |
||||
- name: v0-0alpha1 |
||||
served: true |
||||
storage: true |
||||
schema: |
||||
openAPIV3Schema: |
||||
properties: |
||||
spec: |
||||
type: object |
||||
x-kubernetes-preserve-unknown-fields: true |
||||
required: |
||||
- spec |
||||
type: object |
||||
names: |
||||
kind: Dashboard |
||||
plural: dashboards |
||||
scope: Namespaced |
@ -0,0 +1,34 @@ |
||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||
//
|
||||
// Generated by:
|
||||
// kinds/gen.go
|
||||
// Using jennies:
|
||||
// CRDTypesJenny
|
||||
//
|
||||
// Run 'make gen-cue' from repository root to regenerate.
|
||||
|
||||
package crd |
||||
|
||||
import ( |
||||
_ "embed" |
||||
|
||||
"github.com/grafana/grafana/pkg/kinds/dashboard" |
||||
"github.com/grafana/grafana/pkg/kindsys/k8ssys" |
||||
) |
||||
|
||||
// The CRD YAML representation of the Dashboard kind.
|
||||
//
|
||||
//go:embed dashboard.crd.yml
|
||||
var CRDYaml []byte |
||||
|
||||
// Dashboard is the Go CRD representation of a single Dashboard object.
|
||||
// It implements [runtime.Object], and is used in k8s scheme construction.
|
||||
type Dashboard struct { |
||||
k8ssys.Base[dashboard.Dashboard] |
||||
} |
||||
|
||||
// DashboardList is the Go CRD representation of a list Dashboard objects.
|
||||
// It implements [runtime.Object], and is used in k8s scheme construction.
|
||||
type DashboardList struct { |
||||
k8ssys.ListBase[dashboard.Dashboard] |
||||
} |
@ -0,0 +1,120 @@ |
||||
# Code generated - EDITING IS FUTILE. DO NOT EDIT. |
||||
# |
||||
# Generated by: |
||||
# kinds/gen.go |
||||
# Using jennies: |
||||
# YamlCRDJenny |
||||
# |
||||
# Run 'make gen-cue' from repository root to regenerate. |
||||
|
||||
kind: CustomResourceDefinition |
||||
apiVersion: apiextensions.k8s.io/v1 |
||||
metadata: |
||||
name: librarypanels.librarypanel.core.grafana.com |
||||
spec: |
||||
group: librarypanel.core.grafana.com |
||||
versions: |
||||
- name: v0-0alpha1 |
||||
served: true |
||||
storage: true |
||||
schema: |
||||
openAPIV3Schema: |
||||
properties: |
||||
spec: |
||||
properties: |
||||
description: |
||||
description: Panel description |
||||
type: string |
||||
folderUid: |
||||
description: Folder UID |
||||
type: string |
||||
meta: |
||||
description: Object storage metadata |
||||
properties: |
||||
connectedDashboards: |
||||
format: int64 |
||||
type: integer |
||||
created: |
||||
type: string |
||||
createdBy: |
||||
properties: |
||||
avatarUrl: |
||||
type: string |
||||
id: |
||||
format: int64 |
||||
type: integer |
||||
name: |
||||
type: string |
||||
required: |
||||
- id |
||||
- name |
||||
- avatarUrl |
||||
type: object |
||||
folderName: |
||||
type: string |
||||
folderUid: |
||||
type: string |
||||
updated: |
||||
type: string |
||||
updatedBy: |
||||
properties: |
||||
avatarUrl: |
||||
type: string |
||||
id: |
||||
format: int64 |
||||
type: integer |
||||
name: |
||||
type: string |
||||
required: |
||||
- id |
||||
- name |
||||
- avatarUrl |
||||
type: object |
||||
required: |
||||
- folderName |
||||
- folderUid |
||||
- connectedDashboards |
||||
- created |
||||
- updated |
||||
- createdBy |
||||
- updatedBy |
||||
type: object |
||||
model: |
||||
description: |- |
||||
TODO: should be the same panel schema defined in dashboard |
||||
Typescript: Omit<Panel, 'gridPos' | 'id' | 'libraryPanel'>; |
||||
type: object |
||||
name: |
||||
description: Panel name (also saved in the model) |
||||
minLength: 1 |
||||
type: string |
||||
schemaVersion: |
||||
description: Dashboard version when this was saved (zero if unknown) |
||||
maximum: 65535 |
||||
minimum: 0 |
||||
type: integer |
||||
type: |
||||
description: The panel type (from inside the model) |
||||
minLength: 1 |
||||
type: string |
||||
uid: |
||||
description: Library element UID |
||||
type: string |
||||
version: |
||||
description: panel version, incremented each time the dashboard is updated. |
||||
format: int64 |
||||
type: integer |
||||
required: |
||||
- uid |
||||
- name |
||||
- type |
||||
- version |
||||
- model |
||||
type: object |
||||
required: |
||||
- spec |
||||
type: object |
||||
names: |
||||
kind: LibraryPanel |
||||
plural: librarypanels |
||||
scope: Namespaced |
@ -0,0 +1,34 @@ |
||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||
//
|
||||
// Generated by:
|
||||
// kinds/gen.go
|
||||
// Using jennies:
|
||||
// CRDTypesJenny
|
||||
//
|
||||
// Run 'make gen-cue' from repository root to regenerate.
|
||||
|
||||
package crd |
||||
|
||||
import ( |
||||
_ "embed" |
||||
|
||||
"github.com/grafana/grafana/pkg/kinds/librarypanel" |
||||
"github.com/grafana/grafana/pkg/kindsys/k8ssys" |
||||
) |
||||
|
||||
// The CRD YAML representation of the LibraryPanel kind.
|
||||
//
|
||||
//go:embed librarypanel.crd.yml
|
||||
var CRDYaml []byte |
||||
|
||||
// LibraryPanel is the Go CRD representation of a single LibraryPanel object.
|
||||
// It implements [runtime.Object], and is used in k8s scheme construction.
|
||||
type LibraryPanel struct { |
||||
k8ssys.Base[librarypanel.LibraryPanel] |
||||
} |
||||
|
||||
// LibraryPanelList is the Go CRD representation of a list LibraryPanel objects.
|
||||
// It implements [runtime.Object], and is used in k8s scheme construction.
|
||||
type LibraryPanelList struct { |
||||
k8ssys.ListBase[librarypanel.LibraryPanel] |
||||
} |
@ -0,0 +1,82 @@ |
||||
# Code generated - EDITING IS FUTILE. DO NOT EDIT. |
||||
# |
||||
# Generated by: |
||||
# kinds/gen.go |
||||
# Using jennies: |
||||
# YamlCRDJenny |
||||
# |
||||
# Run 'make gen-cue' from repository root to regenerate. |
||||
|
||||
kind: CustomResourceDefinition |
||||
apiVersion: apiextensions.k8s.io/v1 |
||||
metadata: |
||||
name: playlists.playlist.core.grafana.com |
||||
spec: |
||||
group: playlist.core.grafana.com |
||||
versions: |
||||
- name: v0-0alpha1 |
||||
served: true |
||||
storage: true |
||||
schema: |
||||
openAPIV3Schema: |
||||
properties: |
||||
spec: |
||||
properties: |
||||
interval: |
||||
default: 5m |
||||
description: |- |
||||
Interval sets the time between switching views in a playlist. |
||||
FIXME: Is this based on a standardized format or what options are available? Can datemath be used? |
||||
type: string |
||||
items: |
||||
description: |- |
||||
The ordered list of items that the playlist will iterate over. |
||||
FIXME! This should not be optional, but changing it makes the godegen awkward |
||||
items: |
||||
properties: |
||||
title: |
||||
description: Title is an unused property -- it will be removed in the future |
||||
type: string |
||||
type: |
||||
description: Type of the item. |
||||
enum: |
||||
- dashboard_by_uid |
||||
- dashboard_by_id |
||||
- dashboard_by_tag |
||||
type: string |
||||
value: |
||||
description: |- |
||||
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 |
||||
type: string |
||||
required: |
||||
- type |
||||
- value |
||||
type: object |
||||
type: array |
||||
name: |
||||
description: Name of the playlist. |
||||
type: string |
||||
uid: |
||||
description: |- |
||||
Unique playlist identifier. Generated on creation, either by the |
||||
creator of the playlist of by the application. |
||||
type: string |
||||
required: |
||||
- uid |
||||
- name |
||||
- interval |
||||
type: object |
||||
required: |
||||
- spec |
||||
type: object |
||||
names: |
||||
kind: Playlist |
||||
plural: playlists |
||||
scope: Namespaced |
@ -0,0 +1,34 @@ |
||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||
//
|
||||
// Generated by:
|
||||
// kinds/gen.go
|
||||
// Using jennies:
|
||||
// CRDTypesJenny
|
||||
//
|
||||
// Run 'make gen-cue' from repository root to regenerate.
|
||||
|
||||
package crd |
||||
|
||||
import ( |
||||
_ "embed" |
||||
|
||||
"github.com/grafana/grafana/pkg/kinds/playlist" |
||||
"github.com/grafana/grafana/pkg/kindsys/k8ssys" |
||||
) |
||||
|
||||
// The CRD YAML representation of the Playlist kind.
|
||||
//
|
||||
//go:embed playlist.crd.yml
|
||||
var CRDYaml []byte |
||||
|
||||
// Playlist is the Go CRD representation of a single Playlist object.
|
||||
// It implements [runtime.Object], and is used in k8s scheme construction.
|
||||
type Playlist struct { |
||||
k8ssys.Base[playlist.Playlist] |
||||
} |
||||
|
||||
// PlaylistList is the Go CRD representation of a list Playlist objects.
|
||||
// It implements [runtime.Object], and is used in k8s scheme construction.
|
||||
type PlaylistList struct { |
||||
k8ssys.ListBase[playlist.Playlist] |
||||
} |
@ -0,0 +1,56 @@ |
||||
# Code generated - EDITING IS FUTILE. DO NOT EDIT. |
||||
# |
||||
# Generated by: |
||||
# kinds/gen.go |
||||
# Using jennies: |
||||
# YamlCRDJenny |
||||
# |
||||
# Run 'make gen-cue' from repository root to regenerate. |
||||
|
||||
kind: CustomResourceDefinition |
||||
apiVersion: apiextensions.k8s.io/v1 |
||||
metadata: |
||||
name: preferencess.preferences.core.grafana.com |
||||
spec: |
||||
group: preferences.core.grafana.com |
||||
versions: |
||||
- name: v0-0alpha1 |
||||
served: true |
||||
storage: true |
||||
schema: |
||||
openAPIV3Schema: |
||||
properties: |
||||
spec: |
||||
properties: |
||||
homeDashboardUID: |
||||
description: UID for the home dashboard |
||||
type: string |
||||
language: |
||||
description: Selected language (beta) |
||||
type: string |
||||
queryHistory: |
||||
description: Explore query history preferences |
||||
properties: |
||||
homeTab: |
||||
description: 'one of: '''' | ''query'' | ''starred'';' |
||||
type: string |
||||
type: object |
||||
theme: |
||||
description: light, dark, empty is default |
||||
type: string |
||||
timezone: |
||||
description: |- |
||||
The timezone selection |
||||
TODO: this should use the timezone defined in common |
||||
type: string |
||||
weekStart: |
||||
description: day of the week (sunday, monday, etc) |
||||
type: string |
||||
type: object |
||||
required: |
||||
- spec |
||||
type: object |
||||
names: |
||||
kind: Preferences |
||||
plural: preferencess |
||||
scope: Namespaced |
@ -0,0 +1,34 @@ |
||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||
//
|
||||
// Generated by:
|
||||
// kinds/gen.go
|
||||
// Using jennies:
|
||||
// CRDTypesJenny
|
||||
//
|
||||
// Run 'make gen-cue' from repository root to regenerate.
|
||||
|
||||
package crd |
||||
|
||||
import ( |
||||
_ "embed" |
||||
|
||||
"github.com/grafana/grafana/pkg/kinds/preferences" |
||||
"github.com/grafana/grafana/pkg/kindsys/k8ssys" |
||||
) |
||||
|
||||
// The CRD YAML representation of the Preferences kind.
|
||||
//
|
||||
//go:embed preferences.crd.yml
|
||||
var CRDYaml []byte |
||||
|
||||
// Preferences is the Go CRD representation of a single Preferences object.
|
||||
// It implements [runtime.Object], and is used in k8s scheme construction.
|
||||
type Preferences struct { |
||||
k8ssys.Base[preferences.Preferences] |
||||
} |
||||
|
||||
// PreferencesList is the Go CRD representation of a list Preferences objects.
|
||||
// It implements [runtime.Object], and is used in k8s scheme construction.
|
||||
type PreferencesList struct { |
||||
k8ssys.ListBase[preferences.Preferences] |
||||
} |
@ -0,0 +1,56 @@ |
||||
# Code generated - EDITING IS FUTILE. DO NOT EDIT. |
||||
# |
||||
# Generated by: |
||||
# kinds/gen.go |
||||
# Using jennies: |
||||
# YamlCRDJenny |
||||
# |
||||
# Run 'make gen-cue' from repository root to regenerate. |
||||
|
||||
kind: CustomResourceDefinition |
||||
apiVersion: apiextensions.k8s.io/v1 |
||||
metadata: |
||||
name: publicdashboards.publicdashboard.core.grafana.com |
||||
spec: |
||||
group: publicdashboard.core.grafana.com |
||||
versions: |
||||
- name: v0-0alpha1 |
||||
served: true |
||||
storage: true |
||||
schema: |
||||
openAPIV3Schema: |
||||
properties: |
||||
spec: |
||||
properties: |
||||
accessToken: |
||||
description: Unique public access token |
||||
type: string |
||||
annotationsEnabled: |
||||
description: Flag that indicates if annotations are enabled |
||||
type: boolean |
||||
dashboardUid: |
||||
description: Dashboard unique identifier referenced by this public dashboard |
||||
type: string |
||||
isEnabled: |
||||
description: Flag that indicates if the public dashboard is enabled |
||||
type: boolean |
||||
timeSelectionEnabled: |
||||
description: Flag that indicates if the time range picker is enabled |
||||
type: boolean |
||||
uid: |
||||
description: Unique public dashboard identifier |
||||
type: string |
||||
required: |
||||
- uid |
||||
- dashboardUid |
||||
- isEnabled |
||||
- annotationsEnabled |
||||
- timeSelectionEnabled |
||||
type: object |
||||
required: |
||||
- spec |
||||
type: object |
||||
names: |
||||
kind: PublicDashboard |
||||
plural: publicdashboards |
||||
scope: Namespaced |
@ -0,0 +1,34 @@ |
||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||
//
|
||||
// Generated by:
|
||||
// kinds/gen.go
|
||||
// Using jennies:
|
||||
// CRDTypesJenny
|
||||
//
|
||||
// Run 'make gen-cue' from repository root to regenerate.
|
||||
|
||||
package crd |
||||
|
||||
import ( |
||||
_ "embed" |
||||
|
||||
"github.com/grafana/grafana/pkg/kinds/publicdashboard" |
||||
"github.com/grafana/grafana/pkg/kindsys/k8ssys" |
||||
) |
||||
|
||||
// The CRD YAML representation of the PublicDashboard kind.
|
||||
//
|
||||
//go:embed publicdashboard.crd.yml
|
||||
var CRDYaml []byte |
||||
|
||||
// PublicDashboard is the Go CRD representation of a single PublicDashboard object.
|
||||
// It implements [runtime.Object], and is used in k8s scheme construction.
|
||||
type PublicDashboard struct { |
||||
k8ssys.Base[publicdashboard.PublicDashboard] |
||||
} |
||||
|
||||
// PublicDashboardList is the Go CRD representation of a list PublicDashboard objects.
|
||||
// It implements [runtime.Object], and is used in k8s scheme construction.
|
||||
type PublicDashboardList struct { |
||||
k8ssys.ListBase[publicdashboard.PublicDashboard] |
||||
} |
@ -0,0 +1,94 @@ |
||||
# Code generated - EDITING IS FUTILE. DO NOT EDIT. |
||||
# |
||||
# Generated by: |
||||
# kinds/gen.go |
||||
# Using jennies: |
||||
# YamlCRDJenny |
||||
# |
||||
# Run 'make gen-cue' from repository root to regenerate. |
||||
|
||||
kind: CustomResourceDefinition |
||||
apiVersion: apiextensions.k8s.io/v1 |
||||
metadata: |
||||
name: serviceaccounts.serviceaccount.core.grafana.com |
||||
spec: |
||||
group: serviceaccount.core.grafana.com |
||||
versions: |
||||
- name: v0-0alpha1 |
||||
served: true |
||||
storage: true |
||||
schema: |
||||
openAPIV3Schema: |
||||
properties: |
||||
spec: |
||||
properties: |
||||
accessControl: |
||||
additionalProperties: |
||||
type: boolean |
||||
description: AccessControl metadata associated with a given resource. |
||||
type: object |
||||
avatarUrl: |
||||
description: |- |
||||
AvatarUrl is the service account's avatar URL. It allows the frontend to display a picture in front |
||||
of the service account. |
||||
type: string |
||||
created: |
||||
description: Created indicates when the service account was created. |
||||
format: int64 |
||||
type: integer |
||||
id: |
||||
description: ID is the unique identifier of the service account in the database. |
||||
format: int64 |
||||
type: integer |
||||
isDisabled: |
||||
description: IsDisabled indicates if the service account is disabled. |
||||
type: boolean |
||||
login: |
||||
description: Login of the service account. |
||||
type: string |
||||
name: |
||||
description: Name of the service account. |
||||
type: string |
||||
orgId: |
||||
description: OrgId is the ID of an organisation the service account belongs to. |
||||
format: int64 |
||||
type: integer |
||||
role: |
||||
description: Role is the Grafana organization role of the service account which can be 'Viewer', 'Editor', 'Admin'. |
||||
enum: |
||||
- Admin |
||||
- Editor |
||||
- Viewer |
||||
type: string |
||||
teams: |
||||
description: Teams is a list of teams the service account belongs to. |
||||
items: |
||||
type: string |
||||
type: array |
||||
tokens: |
||||
description: |- |
||||
Tokens is the number of active tokens for the service account. |
||||
Tokens are used to authenticate the service account against Grafana. |
||||
format: int64 |
||||
type: integer |
||||
updated: |
||||
description: Updated indicates when the service account was updated. |
||||
format: int64 |
||||
type: integer |
||||
required: |
||||
- id |
||||
- orgId |
||||
- name |
||||
- login |
||||
- isDisabled |
||||
- role |
||||
- tokens |
||||
- avatarUrl |
||||
type: object |
||||
required: |
||||
- spec |
||||
type: object |
||||
names: |
||||
kind: ServiceAccount |
||||
plural: serviceaccounts |
||||
scope: Namespaced |
@ -0,0 +1,34 @@ |
||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||
//
|
||||
// Generated by:
|
||||
// kinds/gen.go
|
||||
// Using jennies:
|
||||
// CRDTypesJenny
|
||||
//
|
||||
// Run 'make gen-cue' from repository root to regenerate.
|
||||
|
||||
package crd |
||||
|
||||
import ( |
||||
_ "embed" |
||||
|
||||
"github.com/grafana/grafana/pkg/kinds/serviceaccount" |
||||
"github.com/grafana/grafana/pkg/kindsys/k8ssys" |
||||
) |
||||
|
||||
// The CRD YAML representation of the ServiceAccount kind.
|
||||
//
|
||||
//go:embed serviceaccount.crd.yml
|
||||
var CRDYaml []byte |
||||
|
||||
// ServiceAccount is the Go CRD representation of a single ServiceAccount object.
|
||||
// It implements [runtime.Object], and is used in k8s scheme construction.
|
||||
type ServiceAccount struct { |
||||
k8ssys.Base[serviceaccount.ServiceAccount] |
||||
} |
||||
|
||||
// ServiceAccountList is the Go CRD representation of a list ServiceAccount objects.
|
||||
// It implements [runtime.Object], and is used in k8s scheme construction.
|
||||
type ServiceAccountList struct { |
||||
k8ssys.ListBase[serviceaccount.ServiceAccount] |
||||
} |
@ -0,0 +1,77 @@ |
||||
# Code generated - EDITING IS FUTILE. DO NOT EDIT. |
||||
# |
||||
# Generated by: |
||||
# kinds/gen.go |
||||
# Using jennies: |
||||
# YamlCRDJenny |
||||
# |
||||
# Run 'make gen-cue' from repository root to regenerate. |
||||
|
||||
kind: CustomResourceDefinition |
||||
apiVersion: apiextensions.k8s.io/v1 |
||||
metadata: |
||||
name: teams.team.core.grafana.com |
||||
spec: |
||||
group: team.core.grafana.com |
||||
versions: |
||||
- name: v0-0alpha1 |
||||
served: true |
||||
storage: true |
||||
schema: |
||||
openAPIV3Schema: |
||||
properties: |
||||
spec: |
||||
properties: |
||||
accessControl: |
||||
additionalProperties: |
||||
type: boolean |
||||
description: AccessControl metadata associated with a given resource. |
||||
type: object |
||||
avatarUrl: |
||||
description: AvatarUrl is the team's avatar URL. |
||||
type: string |
||||
created: |
||||
description: Created indicates when the team was created. |
||||
format: int64 |
||||
type: integer |
||||
email: |
||||
description: Email of the team. |
||||
type: string |
||||
memberCount: |
||||
description: MemberCount is the number of the team members. |
||||
format: int64 |
||||
type: integer |
||||
name: |
||||
description: Name of the team. |
||||
type: string |
||||
orgId: |
||||
description: OrgId is the ID of an organisation the team belongs to. |
||||
format: int64 |
||||
type: integer |
||||
permission: |
||||
description: TODO - it seems it's a team_member.permission, unlikely it should belong to the team kind |
||||
enum: |
||||
- 0 |
||||
- 1 |
||||
- 2 |
||||
- 4 |
||||
type: integer |
||||
updated: |
||||
description: Updated indicates when the team was updated. |
||||
format: int64 |
||||
type: integer |
||||
required: |
||||
- orgId |
||||
- name |
||||
- memberCount |
||||
- permission |
||||
- created |
||||
- updated |
||||
type: object |
||||
required: |
||||
- spec |
||||
type: object |
||||
names: |
||||
kind: Team |
||||
plural: teams |
||||
scope: Namespaced |
@ -0,0 +1,34 @@ |
||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||
//
|
||||
// Generated by:
|
||||
// kinds/gen.go
|
||||
// Using jennies:
|
||||
// CRDTypesJenny
|
||||
//
|
||||
// Run 'make gen-cue' from repository root to regenerate.
|
||||
|
||||
package crd |
||||
|
||||
import ( |
||||
_ "embed" |
||||
|
||||
"github.com/grafana/grafana/pkg/kinds/team" |
||||
"github.com/grafana/grafana/pkg/kindsys/k8ssys" |
||||
) |
||||
|
||||
// The CRD YAML representation of the Team kind.
|
||||
//
|
||||
//go:embed team.crd.yml
|
||||
var CRDYaml []byte |
||||
|
||||
// Team is the Go CRD representation of a single Team object.
|
||||
// It implements [runtime.Object], and is used in k8s scheme construction.
|
||||
type Team struct { |
||||
k8ssys.Base[team.Team] |
||||
} |
||||
|
||||
// TeamList is the Go CRD representation of a list Team objects.
|
||||
// It implements [runtime.Object], and is used in k8s scheme construction.
|
||||
type TeamList struct { |
||||
k8ssys.ListBase[team.Team] |
||||
} |
@ -0,0 +1,154 @@ |
||||
package k8ssys |
||||
|
||||
import ( |
||||
"fmt" |
||||
"reflect" |
||||
|
||||
"github.com/grafana/grafana/pkg/kindsys" |
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" |
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
||||
"k8s.io/apimachinery/pkg/runtime" |
||||
k8schema "k8s.io/apimachinery/pkg/runtime/schema" |
||||
) |
||||
|
||||
type Kind struct { |
||||
GrafanaKind kindsys.Kind |
||||
Object runtime.Object // singular type
|
||||
ObjectList runtime.Object // list type
|
||||
Schema apiextensionsv1.CustomResourceDefinition |
||||
} |
||||
|
||||
// TODO this could probably be done in CUE/framework
|
||||
func (crd Kind) GVK() k8schema.GroupVersionKind { |
||||
// TODO custom structured
|
||||
props := crd.GrafanaKind.Props().(kindsys.CoreProperties) |
||||
gvk := k8schema.GroupVersionKind{ |
||||
Group: fmt.Sprintf("%s.core.grafana.com", props.MachineName), |
||||
Kind: props.Name, |
||||
} |
||||
if props.Maturity.Less(kindsys.MaturityStable) { |
||||
gvk.Version = "v0-0alpha1" |
||||
} else { |
||||
gvk.Version = fmt.Sprintf("v%d-%d", props.CurrentVersion[0], props.CurrentVersion[1]) |
||||
} |
||||
|
||||
return gvk |
||||
} |
||||
|
||||
// CustomResourceDefinitionList is the kubernetes-API-compliant representation of a list of CustomResourceDefinitions
|
||||
type CustomResourceDefinitionList struct { |
||||
ListBase[CustomResourceDefinition] |
||||
} |
||||
|
||||
// CustomResourceDefinition is the kubernetes-API-compliant representation of a Custom Resource Definition
|
||||
type CustomResourceDefinition struct { |
||||
metav1.TypeMeta `json:",inline" yaml:",inline"` |
||||
metav1.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"` |
||||
Spec CustomResourceDefinitionSpec `json:"spec"` |
||||
} |
||||
|
||||
// DeepCopyObject implements runtime.Object.
|
||||
func (crd *CustomResourceDefinition) DeepCopyObject() runtime.Object { |
||||
return DeepCopyObject(crd) |
||||
} |
||||
|
||||
// CustomResourceDefinitionSpec is the body or spec of a kubernetes Custom Resource Definition
|
||||
type CustomResourceDefinitionSpec struct { |
||||
Group string `json:"group" yaml:"group"` |
||||
Versions []CustomResourceDefinitionSpecVersion `json:"versions" yaml:"versions"` |
||||
Names CustomResourceDefinitionSpecNames `json:"names" yaml:"names"` |
||||
Scope string `json:"scope" yaml:"scope"` |
||||
} |
||||
|
||||
// CustomResourceDefinitionSpecVersion is the representation of a specific version of a CRD, as part of the overall spec
|
||||
type CustomResourceDefinitionSpecVersion struct { |
||||
Name string `json:"name" yaml:"name"` |
||||
Served bool `json:"served" yaml:"served"` |
||||
Storage bool `json:"storage" yaml:"storage"` |
||||
Schema map[string]any `json:"schema" yaml:"schema"` |
||||
Subresources map[string]any `json:"subresources,omitempty" yaml:"subresources,omitempty"` |
||||
} |
||||
|
||||
// CustomResourceDefinitionSpecNames is the struct representing the names (kind and plural) of a kubernetes CRD
|
||||
type CustomResourceDefinitionSpecNames struct { |
||||
Kind string `json:"kind" yaml:"kind"` |
||||
Plural string `json:"plural" yaml:"plural"` |
||||
} |
||||
|
||||
// Base is a struct which describes a basic CRD, and implements runtime.Object.
|
||||
// SpecType should be the struct that represents the spec in the definition.
|
||||
// It cannot be used on its own, as the name of the CRD in kubernetes must exactly match the name of struct.
|
||||
// Instead, this struct can be used as a component of a new named struct, for examples:
|
||||
//
|
||||
// type MyCustomResource struct {
|
||||
// crd.Base[MyCustomResourceSpec]
|
||||
// }
|
||||
type Base[SpecType any] struct { |
||||
metav1.TypeMeta `json:",inline"` |
||||
metav1.ObjectMeta `json:"metadata,omitempty"` |
||||
Spec SpecType `json:"spec"` |
||||
} |
||||
|
||||
// DeepCopyObject is implemented for Base so it will implement runtime.Object.
|
||||
// DeepCopyObject here just calls crd.DeepCopyObject on itself.
|
||||
func (b *Base[T]) DeepCopyObject() runtime.Object { |
||||
return DeepCopyObject(b) |
||||
} |
||||
|
||||
// ListBase is a struct which describes a list of CRDs, and implements runtime.Object.
|
||||
// ItemType should be the CRD type being listed (NOT the model).
|
||||
// It cannot be used on its own, as the struct name must exactly match `<name of kubernetes CRD>List`.
|
||||
// Instead, this struct can be used as a component of a new named struct, for examples:
|
||||
//
|
||||
// type MyCustomResourceList struct {
|
||||
// crd.Base[MyCustomResource]
|
||||
// }
|
||||
type ListBase[ItemType any] struct { |
||||
metav1.TypeMeta `json:",inline"` |
||||
metav1.ListMeta `json:"metadata"` |
||||
Items []ItemType `json:"items"` |
||||
} |
||||
|
||||
// DeepCopyObject is implemented for Base so it will implement runtime.Object.
|
||||
// DeepCopyObject here just calls crd.DeepCopyObject on itself.
|
||||
func (b *ListBase[T]) DeepCopyObject() runtime.Object { |
||||
return DeepCopyObject(b) |
||||
} |
||||
|
||||
// BaseStatus extends Base by including a Status subresource.
|
||||
// This should be used if your kubernetes CRD includes the status subresource and you want to be able to view/modify it.
|
||||
// Usage is identical to Base
|
||||
type BaseStatus[SpecType, StatusType any] struct { |
||||
metav1.TypeMeta `json:",inline"` |
||||
metav1.ObjectMeta `json:"metadata,omitempty"` |
||||
Spec SpecType `json:"spec"` |
||||
Status StatusType `json:"status"` |
||||
} |
||||
|
||||
// DeepCopyObject is implemented for Base so it will implement runtime.Object.
|
||||
// DeepCopyObject here just calls crd.DeepCopyObject on itself.
|
||||
func (b *BaseStatus[T, S]) DeepCopyObject() runtime.Object { |
||||
return DeepCopyObject(b) |
||||
} |
||||
|
||||
// DeepCopyObject is an implementation of the receiver method required for implementing runtime.Object.
|
||||
// It should be used in your own runtime.Object implementations if you do not wish to implement custom behavior.
|
||||
// Example:
|
||||
//
|
||||
// func (c *CustomObject) DeepCopyObject() runtime.Object {
|
||||
// return crd.DeepCopyObject(c)
|
||||
// }
|
||||
func DeepCopyObject(in any) runtime.Object { |
||||
val := reflect.ValueOf(in).Elem() |
||||
|
||||
cpy := reflect.New(val.Type()) |
||||
cpy.Elem().Set(val) |
||||
|
||||
// Using the <obj>, <ok> for the type conversion ensures that it doesn't panic if it can't be converted
|
||||
if obj, ok := cpy.Interface().(runtime.Object); ok { |
||||
return obj |
||||
} |
||||
|
||||
// TODO: better return than nil?
|
||||
return nil |
||||
} |
@ -0,0 +1,26 @@ |
||||
package corecrd |
||||
|
||||
import ( |
||||
"github.com/grafana/grafana/pkg/kindsys/k8ssys" |
||||
"github.com/grafana/grafana/pkg/registry/corekind" |
||||
"github.com/grafana/thema" |
||||
) |
||||
|
||||
// New constructs a new [Registry].
|
||||
//
|
||||
// All calling code within grafana/grafana is expected to use Grafana's
|
||||
// singleton [thema.Runtime], returned from [cuectx.GrafanaThemaRuntime]. If nil
|
||||
// is passed, the singleton will be used.
|
||||
func New(rt *thema.Runtime) *Registry { |
||||
breg := corekind.NewBase(rt) |
||||
return doNewRegistry(breg) |
||||
} |
||||
|
||||
// All returns a slice of all core Grafana CRDs in the registry.
|
||||
//
|
||||
// The returned slice is guaranteed to be alphabetically sorted by kind name.
|
||||
func (r *Registry) All() []k8ssys.Kind { |
||||
all := make([]k8ssys.Kind, len(r.all)) |
||||
copy(all, r.all[:]) |
||||
return all |
||||
} |
@ -0,0 +1,231 @@ |
||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||
//
|
||||
// Generated by:
|
||||
// kinds/gen.go
|
||||
// Using jennies:
|
||||
// CRDKindRegistryJenny
|
||||
//
|
||||
// Run 'make gen-cue' from repository root to regenerate.
|
||||
|
||||
package corecrd |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"fmt" |
||||
|
||||
dashboard "github.com/grafana/grafana/pkg/kinds/dashboard/crd" |
||||
librarypanel "github.com/grafana/grafana/pkg/kinds/librarypanel/crd" |
||||
playlist "github.com/grafana/grafana/pkg/kinds/playlist/crd" |
||||
preferences "github.com/grafana/grafana/pkg/kinds/preferences/crd" |
||||
publicdashboard "github.com/grafana/grafana/pkg/kinds/publicdashboard/crd" |
||||
serviceaccount "github.com/grafana/grafana/pkg/kinds/serviceaccount/crd" |
||||
team "github.com/grafana/grafana/pkg/kinds/team/crd" |
||||
"github.com/grafana/grafana/pkg/kindsys/k8ssys" |
||||
"github.com/grafana/grafana/pkg/registry/corekind" |
||||
"gopkg.in/yaml.v3" |
||||
) |
||||
|
||||
// Registry is a list of all of Grafana's core structured kinds, wrapped in a
|
||||
// standard [k8ssys.CRD] interface that makes them usable for interactions
|
||||
// with certain Kubernetes controller and apimachinery libraries.
|
||||
//
|
||||
// There are two access methods: individually via literal named methods, or as
|
||||
// a slice returned from All() method.
|
||||
//
|
||||
// Prefer the individual named methods for use cases where the particular kind(s)
|
||||
// that are needed are known to the caller. Prefer All() when performing operations
|
||||
// generically across all kinds.
|
||||
type Registry struct { |
||||
all [7]k8ssys.Kind |
||||
} |
||||
|
||||
// Dashboard returns the [k8ssys.Kind] instance for the Dashboard kind.
|
||||
func (r *Registry) Dashboard() k8ssys.Kind { |
||||
return r.all[0] |
||||
} |
||||
|
||||
// LibraryPanel returns the [k8ssys.Kind] instance for the LibraryPanel kind.
|
||||
func (r *Registry) LibraryPanel() k8ssys.Kind { |
||||
return r.all[1] |
||||
} |
||||
|
||||
// Playlist returns the [k8ssys.Kind] instance for the Playlist kind.
|
||||
func (r *Registry) Playlist() k8ssys.Kind { |
||||
return r.all[2] |
||||
} |
||||
|
||||
// Preferences returns the [k8ssys.Kind] instance for the Preferences kind.
|
||||
func (r *Registry) Preferences() k8ssys.Kind { |
||||
return r.all[3] |
||||
} |
||||
|
||||
// PublicDashboard returns the [k8ssys.Kind] instance for the PublicDashboard kind.
|
||||
func (r *Registry) PublicDashboard() k8ssys.Kind { |
||||
return r.all[4] |
||||
} |
||||
|
||||
// ServiceAccount returns the [k8ssys.Kind] instance for the ServiceAccount kind.
|
||||
func (r *Registry) ServiceAccount() k8ssys.Kind { |
||||
return r.all[5] |
||||
} |
||||
|
||||
// Team returns the [k8ssys.Kind] instance for the Team kind.
|
||||
func (r *Registry) Team() k8ssys.Kind { |
||||
return r.all[6] |
||||
} |
||||
|
||||
func doNewRegistry(breg *corekind.Base) *Registry { |
||||
var err error |
||||
var b []byte |
||||
var kk k8ssys.Kind |
||||
reg := &Registry{} |
||||
|
||||
kk = k8ssys.Kind{ |
||||
GrafanaKind: breg.Dashboard(), |
||||
Object: &dashboard.Dashboard{}, |
||||
ObjectList: &dashboard.DashboardList{}, |
||||
} |
||||
// TODO Having the committed form on disk in YAML is worth doing this for now...but fix this silliness
|
||||
map0 := make(map[string]any) |
||||
err = yaml.Unmarshal(dashboard.CRDYaml, map0) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("generated CRD YAML for Dashboard failed to unmarshal: %s", err)) |
||||
} |
||||
b, err = json.Marshal(map0) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("could not re-marshal CRD JSON for Dashboard: %s", err)) |
||||
} |
||||
err = json.Unmarshal(b, &kk.Schema) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("could not unmarshal CRD JSON for Dashboard: %s", err)) |
||||
} |
||||
reg.all[0] = kk |
||||
|
||||
kk = k8ssys.Kind{ |
||||
GrafanaKind: breg.LibraryPanel(), |
||||
Object: &librarypanel.LibraryPanel{}, |
||||
ObjectList: &librarypanel.LibraryPanelList{}, |
||||
} |
||||
// TODO Having the committed form on disk in YAML is worth doing this for now...but fix this silliness
|
||||
map1 := make(map[string]any) |
||||
err = yaml.Unmarshal(librarypanel.CRDYaml, map1) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("generated CRD YAML for LibraryPanel failed to unmarshal: %s", err)) |
||||
} |
||||
b, err = json.Marshal(map1) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("could not re-marshal CRD JSON for LibraryPanel: %s", err)) |
||||
} |
||||
err = json.Unmarshal(b, &kk.Schema) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("could not unmarshal CRD JSON for LibraryPanel: %s", err)) |
||||
} |
||||
reg.all[1] = kk |
||||
|
||||
kk = k8ssys.Kind{ |
||||
GrafanaKind: breg.Playlist(), |
||||
Object: &playlist.Playlist{}, |
||||
ObjectList: &playlist.PlaylistList{}, |
||||
} |
||||
// TODO Having the committed form on disk in YAML is worth doing this for now...but fix this silliness
|
||||
map2 := make(map[string]any) |
||||
err = yaml.Unmarshal(playlist.CRDYaml, map2) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("generated CRD YAML for Playlist failed to unmarshal: %s", err)) |
||||
} |
||||
b, err = json.Marshal(map2) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("could not re-marshal CRD JSON for Playlist: %s", err)) |
||||
} |
||||
err = json.Unmarshal(b, &kk.Schema) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("could not unmarshal CRD JSON for Playlist: %s", err)) |
||||
} |
||||
reg.all[2] = kk |
||||
|
||||
kk = k8ssys.Kind{ |
||||
GrafanaKind: breg.Preferences(), |
||||
Object: &preferences.Preferences{}, |
||||
ObjectList: &preferences.PreferencesList{}, |
||||
} |
||||
// TODO Having the committed form on disk in YAML is worth doing this for now...but fix this silliness
|
||||
map3 := make(map[string]any) |
||||
err = yaml.Unmarshal(preferences.CRDYaml, map3) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("generated CRD YAML for Preferences failed to unmarshal: %s", err)) |
||||
} |
||||
b, err = json.Marshal(map3) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("could not re-marshal CRD JSON for Preferences: %s", err)) |
||||
} |
||||
err = json.Unmarshal(b, &kk.Schema) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("could not unmarshal CRD JSON for Preferences: %s", err)) |
||||
} |
||||
reg.all[3] = kk |
||||
|
||||
kk = k8ssys.Kind{ |
||||
GrafanaKind: breg.PublicDashboard(), |
||||
Object: &publicdashboard.PublicDashboard{}, |
||||
ObjectList: &publicdashboard.PublicDashboardList{}, |
||||
} |
||||
// TODO Having the committed form on disk in YAML is worth doing this for now...but fix this silliness
|
||||
map4 := make(map[string]any) |
||||
err = yaml.Unmarshal(publicdashboard.CRDYaml, map4) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("generated CRD YAML for PublicDashboard failed to unmarshal: %s", err)) |
||||
} |
||||
b, err = json.Marshal(map4) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("could not re-marshal CRD JSON for PublicDashboard: %s", err)) |
||||
} |
||||
err = json.Unmarshal(b, &kk.Schema) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("could not unmarshal CRD JSON for PublicDashboard: %s", err)) |
||||
} |
||||
reg.all[4] = kk |
||||
|
||||
kk = k8ssys.Kind{ |
||||
GrafanaKind: breg.ServiceAccount(), |
||||
Object: &serviceaccount.ServiceAccount{}, |
||||
ObjectList: &serviceaccount.ServiceAccountList{}, |
||||
} |
||||
// TODO Having the committed form on disk in YAML is worth doing this for now...but fix this silliness
|
||||
map5 := make(map[string]any) |
||||
err = yaml.Unmarshal(serviceaccount.CRDYaml, map5) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("generated CRD YAML for ServiceAccount failed to unmarshal: %s", err)) |
||||
} |
||||
b, err = json.Marshal(map5) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("could not re-marshal CRD JSON for ServiceAccount: %s", err)) |
||||
} |
||||
err = json.Unmarshal(b, &kk.Schema) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("could not unmarshal CRD JSON for ServiceAccount: %s", err)) |
||||
} |
||||
reg.all[5] = kk |
||||
|
||||
kk = k8ssys.Kind{ |
||||
GrafanaKind: breg.Team(), |
||||
Object: &team.Team{}, |
||||
ObjectList: &team.TeamList{}, |
||||
} |
||||
// TODO Having the committed form on disk in YAML is worth doing this for now...but fix this silliness
|
||||
map6 := make(map[string]any) |
||||
err = yaml.Unmarshal(team.CRDYaml, map6) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("generated CRD YAML for Team failed to unmarshal: %s", err)) |
||||
} |
||||
b, err = json.Marshal(map6) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("could not re-marshal CRD JSON for Team: %s", err)) |
||||
} |
||||
err = json.Unmarshal(b, &kk.Schema) |
||||
if err != nil { |
||||
panic(fmt.Sprintf("could not unmarshal CRD JSON for Team: %s", err)) |
||||
} |
||||
reg.all[6] = kk |
||||
|
||||
return reg |
||||
} |
Loading…
Reference in new issue