mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Schemas: Generate CRDs for core kinds (#62641)
Co-authored-by: sam boyer <sdboyer@grafana.com>
This commit is contained in:
parent
b95eda045a
commit
e70d623f90
19
go.mod
19
go.mod
@ -7,10 +7,6 @@ go 1.19
|
||||
// Also, use our fork with fixes for unimplemented methods (required for Go 1.16).
|
||||
replace github.com/denisenkom/go-mssqldb => github.com/grafana/go-mssqldb v0.0.0-20210326084033-d0ce3c521036
|
||||
|
||||
// Override k8s.io/client-go outdated dependency, which is an indirect dependency of grafana/loki.
|
||||
// It's also present on grafana/loki's go.mod so we'll need till it gets updated.
|
||||
replace k8s.io/client-go => k8s.io/client-go v0.25.0
|
||||
|
||||
replace github.com/russellhaering/goxmldsig@v1.1.0 => github.com/russellhaering/goxmldsig v1.1.1
|
||||
|
||||
// Avoid using v2.0.0+incompatible Redigo used by dependencies as the latest maintained branch of Redigo is v1.
|
||||
@ -24,6 +20,17 @@ replace github.com/docker/docker => github.com/moby/moby v0.7.3-0.20190826074503
|
||||
// contains openapi encoder fixes. remove ASAP
|
||||
replace cuelang.org/go => github.com/sdboyer/cue v0.5.0-beta.2.0.20221218111347-341999f48bdb
|
||||
|
||||
// For some insane reason, client-go seems to have a broken v12.0.0 tag on it that forces us to
|
||||
// hoist a replace statement.
|
||||
replace k8s.io/client-go => k8s.io/client-go v0.25.3
|
||||
|
||||
require (
|
||||
k8s.io/api v0.25.3 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.25.3
|
||||
k8s.io/apimachinery v0.25.3
|
||||
k8s.io/client-go v12.0.0+incompatible
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go/storage v1.28.1
|
||||
cuelang.org/go v0.5.0-beta.2
|
||||
@ -257,7 +264,6 @@ require (
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.11.2
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.11.2
|
||||
gocloud.dev v0.25.0
|
||||
k8s.io/client-go v12.0.0+incompatible // gets replaced with v0.25.0
|
||||
)
|
||||
|
||||
require (
|
||||
@ -268,7 +274,6 @@ require (
|
||||
github.com/grafana/thema v0.0.0-20230122235053-b4b6714dd1c9
|
||||
github.com/hmarr/codeowners v1.1.1
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f
|
||||
k8s.io/apimachinery v0.25.3
|
||||
)
|
||||
|
||||
require (
|
||||
@ -296,6 +301,7 @@ require (
|
||||
github.com/emicklei/go-restful/v3 v3.8.0 // indirect
|
||||
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v0.6.7 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/google/gnostic v0.5.7-v3refs // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
@ -333,7 +339,6 @@ require (
|
||||
golang.org/x/term v0.3.0 // indirect
|
||||
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
k8s.io/api v0.25.3 // indirect
|
||||
k8s.io/klog/v2 v2.80.0 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 // indirect
|
||||
k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect
|
||||
|
14
go.sum
14
go.sum
@ -770,8 +770,9 @@ github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUork
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
|
||||
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/fsouza/fake-gcs-server v1.7.0/go.mod h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7RHGAyAK3EP2EsNk=
|
||||
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
|
||||
github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
|
||||
@ -1839,6 +1840,7 @@ github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||
github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU=
|
||||
github.com/onsi/ginkgo/v2 v2.1.6 h1:Fx2POJZfKRQcM1pH49qSZiYeu319wji004qX+GDovrU=
|
||||
github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
|
||||
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
@ -1850,6 +1852,7 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y
|
||||
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
|
||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
|
||||
github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo=
|
||||
github.com/onsi/gomega v1.24.0 h1:+0glovB9Jd6z3VR+ScSwQqXVTIfJcGA9UBM8yzQxhqg=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
@ -2856,6 +2859,7 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
|
||||
@ -3180,9 +3184,10 @@ k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ=
|
||||
k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8=
|
||||
k8s.io/api v0.21.1/go.mod h1:FstGROTmsSHBarKc8bylzXih8BLNYTiS3TZcsoEDg2s=
|
||||
k8s.io/api v0.22.1/go.mod h1:bh13rkTp3F1XEaLGykbyRD2QaTTzPm0e/BMd8ptFONY=
|
||||
k8s.io/api v0.25.0/go.mod h1:ttceV1GyV1i1rnmvzT3BST08N6nGt+dudGrquzVQWPk=
|
||||
k8s.io/api v0.25.3 h1:Q1v5UFfYe87vi5H7NU0p4RXC26PPMT8KOpr1TLQbCMQ=
|
||||
k8s.io/api v0.25.3/go.mod h1:o42gKscFrEVjHdQnyRenACrMtbuJsVdP+WVjqejfzmI=
|
||||
k8s.io/apiextensions-apiserver v0.25.3 h1:bfI4KS31w2f9WM1KLGwnwuVlW3RSRPuIsfNF/3HzR0k=
|
||||
k8s.io/apiextensions-apiserver v0.25.3/go.mod h1:ZJqwpCkxIx9itilmZek7JgfUAM0dnTsA48I4krPqRmo=
|
||||
k8s.io/apimachinery v0.0.0-20190809020650-423f5d784010/go.mod h1:Waf/xTS2FGRrgXCkO5FP3XxTOWh0qLf2QhL1qFZZ/R8=
|
||||
k8s.io/apimachinery v0.17.5/go.mod h1:ioIo1G/a+uONV7Tv+ZmCbMG1/a3kVw5YcDdncd8ugQ0=
|
||||
k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
|
||||
@ -3190,14 +3195,13 @@ k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRp
|
||||
k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc=
|
||||
k8s.io/apimachinery v0.21.1/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY=
|
||||
k8s.io/apimachinery v0.22.1/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0=
|
||||
k8s.io/apimachinery v0.25.0/go.mod h1:qMx9eAk0sZQGsXGu86fab8tZdffHbwUfsvzqKn4mfB0=
|
||||
k8s.io/apimachinery v0.25.3 h1:7o9ium4uyUOM76t6aunP0nZuex7gDf8VGwkR5RcJnQc=
|
||||
k8s.io/apimachinery v0.25.3/go.mod h1:jaF9C/iPNM1FuLl7Zuy5b9v+n35HGSh6AQ4HYRkCqwo=
|
||||
k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU=
|
||||
k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM=
|
||||
k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q=
|
||||
k8s.io/client-go v0.25.0 h1:CVWIaCETLMBNiTUta3d5nzRbXvY5Hy9Dpl+VvREpu5E=
|
||||
k8s.io/client-go v0.25.0/go.mod h1:lxykvypVfKilxhTklov0wz1FoaUZ8X4EwbhS6rpRfN8=
|
||||
k8s.io/client-go v0.25.3 h1:oB4Dyl8d6UbfDHD8Bv8evKylzs3BXzzufLiO27xuPs0=
|
||||
k8s.io/client-go v0.25.3/go.mod h1:t39LPczAIMwycjcXkVc+CB+PZV69jQuNx4um5ORDjQA=
|
||||
k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk=
|
||||
k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI=
|
||||
k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM=
|
||||
|
@ -6,6 +6,8 @@ name: "Dashboard"
|
||||
maturity: "experimental"
|
||||
description: "A Grafana dashboard."
|
||||
|
||||
crd: dummySchema: true
|
||||
|
||||
lineage: seqs: [
|
||||
{
|
||||
schemas: [
|
||||
|
@ -42,6 +42,9 @@ func main() {
|
||||
codegen.BaseCoreRegistryJenny(filepath.Join("pkg", "registry", "corekind"), kindsys.GoCoreKindParentPath),
|
||||
codegen.LatestMajorsOrXJenny(kindsys.TSCoreKindParentPath, codegen.TSTypesJenny{}),
|
||||
codegen.TSVeneerIndexJenny(filepath.Join("packages", "grafana-schema", "src")),
|
||||
codegen.CRDTypesJenny(kindsys.GoCoreKindParentPath),
|
||||
codegen.YamlCRDJenny(kindsys.GoCoreKindParentPath),
|
||||
codegen.CRDKindRegistryJenny(filepath.Join("pkg", "registry", "corecrd")),
|
||||
codegen.DocsJenny(filepath.Join("docs", "sources", "developers", "kinds", "core")),
|
||||
)
|
||||
|
||||
|
@ -34,21 +34,27 @@ func ForLatestSchema(k kindsys.Kind) SchemaForGen {
|
||||
// file.
|
||||
func SlashHeaderMapper(maingen string) codejen.FileMapper {
|
||||
return func(f codejen.File) (codejen.File, error) {
|
||||
var leader string
|
||||
// Never inject on certain filetypes, it's never valid
|
||||
switch filepath.Ext(f.RelativePath) {
|
||||
case ".json", ".yml", ".yaml", ".md":
|
||||
case ".json", ".md":
|
||||
return f, nil
|
||||
case ".yml", ".yaml":
|
||||
leader = "#"
|
||||
default:
|
||||
buf := new(bytes.Buffer)
|
||||
if err := tmpls.Lookup("gen_header.tmpl").Execute(buf, tvars_gen_header{
|
||||
MainGenerator: maingen,
|
||||
Using: f.From,
|
||||
}); err != nil {
|
||||
return codejen.File{}, fmt.Errorf("failed executing gen header template: %w", err)
|
||||
}
|
||||
fmt.Fprint(buf, string(f.Data))
|
||||
f.Data = buf.Bytes()
|
||||
leader = "//"
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
if err := tmpls.Lookup("gen_header.tmpl").Execute(buf, tvars_gen_header{
|
||||
MainGenerator: maingen,
|
||||
Using: f.From,
|
||||
Leader: leader,
|
||||
}); err != nil {
|
||||
return codejen.File{}, fmt.Errorf("failed executing gen header template: %w", err)
|
||||
}
|
||||
fmt.Fprint(buf, string(f.Data))
|
||||
f.Data = buf.Bytes()
|
||||
return f, nil
|
||||
}
|
||||
}
|
||||
|
@ -33,11 +33,21 @@ func (gen *genBaseRegistry) JennyName() string {
|
||||
}
|
||||
|
||||
func (gen *genBaseRegistry) 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("kind_registry.tmpl").Execute(buf, tvars_kind_registry{
|
||||
PackageName: filepath.Base(gen.path),
|
||||
KindPackagePrefix: filepath.ToSlash(filepath.Join("github.com/grafana/grafana", gen.kindrelroot)),
|
||||
Kinds: kinds,
|
||||
Kinds: cores,
|
||||
}); err != nil {
|
||||
return nil, fmt.Errorf("failed executing kind registry template: %w", err)
|
||||
}
|
||||
|
61
pkg/codegen/jenny_crd_reg.go
Normal file
61
pkg/codegen/jenny_crd_reg.go
Normal file
@ -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
|
||||
}
|
51
pkg/codegen/jenny_crd_types.go
Normal file
51
pkg/codegen/jenny_crd_types.go
Normal file
@ -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
|
||||
}
|
214
pkg/codegen/jenny_crd_yaml.go
Normal file
214
pkg/codegen/jenny_crd_yaml.go
Normal file
@ -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))
|
||||
}
|
@ -8,7 +8,7 @@ import (
|
||||
"github.com/grafana/thema/encoding/openapi"
|
||||
)
|
||||
|
||||
// GoTypesJenny creates a [OneToOne] that produces Go types for the provided
|
||||
// GoTypesJenny is a [OneToOne] that produces Go types for the provided
|
||||
// [thema.Schema].
|
||||
type GoTypesJenny struct {
|
||||
ApplyFuncs []dstutil.ApplyFunc
|
||||
|
@ -36,12 +36,12 @@ type (
|
||||
MainGenerator string
|
||||
Using []codejen.NamedJenny
|
||||
From string
|
||||
Leader string
|
||||
}
|
||||
tvars_kind_registry struct {
|
||||
// Header tvars_autogen_header
|
||||
PackageName string
|
||||
KindPackagePrefix string
|
||||
Kinds []kindsys.Kind
|
||||
Kinds []kindsys.Core
|
||||
}
|
||||
tvars_coremodel_imports struct {
|
||||
PackageName string
|
||||
|
66
pkg/codegen/tmpl/core_crd_registry.tmpl
Normal file
66
pkg/codegen/tmpl/core_crd_registry.tmpl
Normal file
@ -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
|
||||
}
|
25
pkg/codegen/tmpl/core_crd_types.tmpl
Normal file
25
pkg/codegen/tmpl/core_crd_types.tmpl
Normal file
@ -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.
|
||||
|
||||
|
36
pkg/kinds/dashboard/crd/dashboard.crd.yml
Normal file
36
pkg/kinds/dashboard/crd/dashboard.crd.yml
Normal file
@ -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
|
34
pkg/kinds/dashboard/crd/dashboard_crd_gen.go
Normal file
34
pkg/kinds/dashboard/crd/dashboard_crd_gen.go
Normal file
@ -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]
|
||||
}
|
120
pkg/kinds/librarypanel/crd/librarypanel.crd.yml
Normal file
120
pkg/kinds/librarypanel/crd/librarypanel.crd.yml
Normal file
@ -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
|
34
pkg/kinds/librarypanel/crd/librarypanel_crd_gen.go
Normal file
34
pkg/kinds/librarypanel/crd/librarypanel_crd_gen.go
Normal file
@ -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]
|
||||
}
|
82
pkg/kinds/playlist/crd/playlist.crd.yml
Normal file
82
pkg/kinds/playlist/crd/playlist.crd.yml
Normal file
@ -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
|
34
pkg/kinds/playlist/crd/playlist_crd_gen.go
Normal file
34
pkg/kinds/playlist/crd/playlist_crd_gen.go
Normal file
@ -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]
|
||||
}
|
56
pkg/kinds/preferences/crd/preferences.crd.yml
Normal file
56
pkg/kinds/preferences/crd/preferences.crd.yml
Normal file
@ -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
|
34
pkg/kinds/preferences/crd/preferences_crd_gen.go
Normal file
34
pkg/kinds/preferences/crd/preferences_crd_gen.go
Normal file
@ -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]
|
||||
}
|
56
pkg/kinds/publicdashboard/crd/publicdashboard.crd.yml
Normal file
56
pkg/kinds/publicdashboard/crd/publicdashboard.crd.yml
Normal file
@ -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
|
34
pkg/kinds/publicdashboard/crd/publicdashboard_crd_gen.go
Normal file
34
pkg/kinds/publicdashboard/crd/publicdashboard_crd_gen.go
Normal file
@ -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]
|
||||
}
|
94
pkg/kinds/serviceaccount/crd/serviceaccount.crd.yml
Normal file
94
pkg/kinds/serviceaccount/crd/serviceaccount.crd.yml
Normal file
@ -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
|
34
pkg/kinds/serviceaccount/crd/serviceaccount_crd_gen.go
Normal file
34
pkg/kinds/serviceaccount/crd/serviceaccount_crd_gen.go
Normal file
@ -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]
|
||||
}
|
77
pkg/kinds/team/crd/team.crd.yml
Normal file
77
pkg/kinds/team/crd/team.crd.yml
Normal file
@ -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
|
34
pkg/kinds/team/crd/team_crd_gen.go
Normal file
34
pkg/kinds/team/crd/team_crd_gen.go
Normal file
@ -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]
|
||||
}
|
154
pkg/kindsys/k8ssys/crd.go
Normal file
154
pkg/kindsys/k8ssys/crd.go
Normal file
@ -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
|
||||
}
|
@ -100,6 +100,28 @@ Core: S=close({
|
||||
|
||||
lineage: { name: S.machineName }
|
||||
lineageIsGroup: false
|
||||
|
||||
// crd contains properties specific to converting this kind to a Kubernetes CRD.
|
||||
crd: {
|
||||
// group is used as the CRD group name in the GVK.
|
||||
group: "\(S.machineName).core.grafana.com"
|
||||
|
||||
// scope determines whether resources of this kind exist globally ("Cluster") or
|
||||
// within Kubernetes namespaces.
|
||||
scope: "Cluster" | *"Namespaced"
|
||||
|
||||
// dummySchema determines whether a dummy OpenAPI schema - where the schema is
|
||||
// simply an empty, open object - should be generated for the kind.
|
||||
//
|
||||
// It is a goal that this option eventually be force dto false. Only set to
|
||||
// true when Grafana's code generators produce OpenAPI that is rejected by
|
||||
// Kubernetes' CRD validation.
|
||||
dummySchema: bool | *false
|
||||
|
||||
// deepCopy determines whether a generic implementation of copying should be
|
||||
// generated, or a passthrough call to a Go function.
|
||||
// deepCopy: *"generic" | "passthrough"
|
||||
}
|
||||
})
|
||||
|
||||
nonEmptyString: string & strings.MinRunes(1)
|
||||
|
@ -23,6 +23,11 @@ type CommonProperties struct {
|
||||
type CoreProperties struct {
|
||||
CommonProperties
|
||||
CurrentVersion thema.SyntacticVersion `json:"currentVersion"`
|
||||
CRD struct {
|
||||
Group string `json:"group"`
|
||||
Scope string `json:"scope"`
|
||||
DummySchema bool `json:"dummySchema"`
|
||||
} `json:"crd"`
|
||||
}
|
||||
|
||||
func (m CoreProperties) _private() {}
|
||||
|
@ -117,6 +117,11 @@
|
||||
"apikey": {
|
||||
"category": "core",
|
||||
"codeowners": [],
|
||||
"crd": {
|
||||
"dummySchema": false,
|
||||
"group": "",
|
||||
"scope": ""
|
||||
},
|
||||
"currentVersion": [
|
||||
0,
|
||||
0
|
||||
@ -279,6 +284,11 @@
|
||||
"grafana/plugins-platform-frontend",
|
||||
"grafana/user-essentials"
|
||||
],
|
||||
"crd": {
|
||||
"dummySchema": true,
|
||||
"group": "dashboard.core.grafana.com",
|
||||
"scope": "Namespaced"
|
||||
},
|
||||
"currentVersion": [
|
||||
0,
|
||||
0
|
||||
@ -369,6 +379,11 @@
|
||||
"datasource": {
|
||||
"category": "core",
|
||||
"codeowners": [],
|
||||
"crd": {
|
||||
"dummySchema": false,
|
||||
"group": "",
|
||||
"scope": ""
|
||||
},
|
||||
"currentVersion": [
|
||||
0,
|
||||
0
|
||||
@ -478,6 +493,11 @@
|
||||
"folder": {
|
||||
"category": "core",
|
||||
"codeowners": [],
|
||||
"crd": {
|
||||
"dummySchema": false,
|
||||
"group": "",
|
||||
"scope": ""
|
||||
},
|
||||
"currentVersion": [
|
||||
0,
|
||||
0
|
||||
@ -816,6 +836,11 @@
|
||||
"grafana/plugins-platform-frontend",
|
||||
"grafana/user-essentials"
|
||||
],
|
||||
"crd": {
|
||||
"dummySchema": false,
|
||||
"group": "librarypanel.core.grafana.com",
|
||||
"scope": "Namespaced"
|
||||
},
|
||||
"currentVersion": [
|
||||
0,
|
||||
0
|
||||
@ -1181,6 +1206,11 @@
|
||||
"grafana/plugins-platform-frontend",
|
||||
"grafana/user-essentials"
|
||||
],
|
||||
"crd": {
|
||||
"dummySchema": false,
|
||||
"group": "playlist.core.grafana.com",
|
||||
"scope": "Namespaced"
|
||||
},
|
||||
"currentVersion": [
|
||||
0,
|
||||
0
|
||||
@ -1252,6 +1282,11 @@
|
||||
"grafana/plugins-platform-frontend",
|
||||
"grafana/user-essentials"
|
||||
],
|
||||
"crd": {
|
||||
"dummySchema": false,
|
||||
"group": "preferences.core.grafana.com",
|
||||
"scope": "Namespaced"
|
||||
},
|
||||
"currentVersion": [
|
||||
0,
|
||||
0
|
||||
@ -1323,6 +1358,11 @@
|
||||
"grafana/plugins-platform-frontend",
|
||||
"grafana/user-essentials"
|
||||
],
|
||||
"crd": {
|
||||
"dummySchema": false,
|
||||
"group": "publicdashboard.core.grafana.com",
|
||||
"scope": "Namespaced"
|
||||
},
|
||||
"currentVersion": [
|
||||
0,
|
||||
0
|
||||
@ -1345,6 +1385,11 @@
|
||||
"query": {
|
||||
"category": "core",
|
||||
"codeowners": [],
|
||||
"crd": {
|
||||
"dummySchema": false,
|
||||
"group": "",
|
||||
"scope": ""
|
||||
},
|
||||
"currentVersion": [
|
||||
0,
|
||||
0
|
||||
@ -1366,6 +1411,11 @@
|
||||
"queryhistory": {
|
||||
"category": "core",
|
||||
"codeowners": [],
|
||||
"crd": {
|
||||
"dummySchema": false,
|
||||
"group": "",
|
||||
"scope": ""
|
||||
},
|
||||
"currentVersion": [
|
||||
0,
|
||||
0
|
||||
@ -1392,6 +1442,11 @@
|
||||
"grafana/plugins-platform-frontend",
|
||||
"grafana/user-essentials"
|
||||
],
|
||||
"crd": {
|
||||
"dummySchema": false,
|
||||
"group": "serviceaccount.core.grafana.com",
|
||||
"scope": "Namespaced"
|
||||
},
|
||||
"currentVersion": [
|
||||
0,
|
||||
0
|
||||
@ -1513,6 +1568,11 @@
|
||||
"grafana/plugins-platform-frontend",
|
||||
"grafana/user-essentials"
|
||||
],
|
||||
"crd": {
|
||||
"dummySchema": false,
|
||||
"group": "team.core.grafana.com",
|
||||
"scope": "Namespaced"
|
||||
},
|
||||
"currentVersion": [
|
||||
0,
|
||||
0
|
||||
@ -1651,6 +1711,11 @@
|
||||
"thumb": {
|
||||
"category": "core",
|
||||
"codeowners": [],
|
||||
"crd": {
|
||||
"dummySchema": false,
|
||||
"group": "",
|
||||
"scope": ""
|
||||
},
|
||||
"currentVersion": [
|
||||
0,
|
||||
0
|
||||
@ -1694,6 +1759,11 @@
|
||||
"user": {
|
||||
"category": "core",
|
||||
"codeowners": [],
|
||||
"crd": {
|
||||
"dummySchema": false,
|
||||
"group": "",
|
||||
"scope": ""
|
||||
},
|
||||
"currentVersion": [
|
||||
0,
|
||||
0
|
||||
|
26
pkg/registry/corecrd/registry.go
Normal file
26
pkg/registry/corecrd/registry.go
Normal file
@ -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
|
||||
}
|
231
pkg/registry/corecrd/registry_gen.go
Normal file
231
pkg/registry/corecrd/registry_gen.go
Normal file
@ -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
Block a user