From 39827e453f5f038fb75137f5418c81b5d54f56da Mon Sep 17 00:00:00 2001 From: Charandas Batra Date: Thu, 26 Dec 2024 13:04:04 -0800 Subject: [PATCH 1/4] update from main --- cmd/grafana-app-sdk/project.go | 15 ++- codegen/cuekind/generators.go | 17 +++ codegen/jennies/app.go | 2 +- codegen/jennies/grafana-app.go | 59 ++++++++++ codegen/jennies/operator.go | 2 +- codegen/templates/app/app.tmpl | 2 +- .../templates/app/grafana-app-watcher.tmpl | 89 +++++++++++++++ codegen/templates/app/grafana-app.tmpl | 101 ++++++++++++++++++ codegen/templates/templates.go | 23 ++-- 9 files changed, 300 insertions(+), 10 deletions(-) create mode 100644 codegen/jennies/grafana-app.go create mode 100644 codegen/templates/app/grafana-app-watcher.tmpl create mode 100644 codegen/templates/app/grafana-app.tmpl diff --git a/cmd/grafana-app-sdk/project.go b/cmd/grafana-app-sdk/project.go index e80f743c..a95468b6 100644 --- a/cmd/grafana-app-sdk/project.go +++ b/cmd/grafana-app-sdk/project.go @@ -381,7 +381,8 @@ func projectAddComponent(cmd *cobra.Command, args []string) error { where are one or more of: backend frontend - operator`) + operator + grafanaApp`) os.Exit(1) } @@ -482,6 +483,17 @@ func projectAddComponent(cmd *cobra.Command, args []string) error { fmt.Printf("%s\n", err.Error()) os.Exit(1) } + case "grafanaApp": + switch format { + case FormatCUE: + err = addComponentGrafanaApp(path, generator.(*codegen.Generator[codegen.Kind]), selectors, kindGrouping == kindGroupingKind) + default: + return fmt.Errorf("unknown kind format '%s'", format) + } + if err != nil { + fmt.Printf("%s\n", err.Error()) + os.Exit(1) + } default: return fmt.Errorf("unknown component %s", component) } @@ -497,6 +509,7 @@ type anyGenerator interface { *codegen.Generator[codegen.Kind] } +<<<<<<< HEAD //nolint:revive func addComponentOperator[G anyGenerator](projectRootPath string, generator G, selectors []string, groupKinds bool, confirmOverwrite bool) error { // Get the repo from the go.mod file diff --git a/codegen/cuekind/generators.go b/codegen/cuekind/generators.go index 65842cdf..36dc42e5 100644 --- a/codegen/cuekind/generators.go +++ b/codegen/cuekind/generators.go @@ -112,6 +112,23 @@ func AppGenerator(projectRepo, codegenPath string, groupKinds bool) *codejen.Jen return g } +func GrafanaAppGenerator(projectRepo, codegenPath, apisPath string, groupKinds bool) *codejen.JennyList[codegen.Kind] { + parts := strings.Split(projectRepo, "/") + if len(parts) == 0 { + parts = []string{""} + } + g := codejen.JennyListWithNamer[codegen.Kind](namerFunc) + g.Append( + jennies.WatcherJenny(projectRepo, codegenPath, !groupKinds), + &jennies.GrafanaAppGenerator{ + ProjectRepo: projectRepo, + ProjectName: parts[len(parts)-1], + APIsPath: apisPath, + }, + ) + return g +} + func PostResourceGenerationGenerator(projectRepo, goGenPath string, groupKinds bool) *codejen.JennyList[codegen.Kind] { g := codejen.JennyListWithNamer[codegen.Kind](namerFunc) g.Append(&jennies.OpenAPI{ diff --git a/codegen/jennies/app.go b/codegen/jennies/app.go index cf07e446..c5cdf959 100644 --- a/codegen/jennies/app.go +++ b/codegen/jennies/app.go @@ -44,7 +44,7 @@ func (a *AppGenerator) Generate(kinds ...codegen.Kind) (*codejen.File, error) { } b := bytes.Buffer{} - err := templates.WriteAppGoFile(tmd, &b) + err := templates.WriteAppGoFile(tmd, &b, templates.TemplateApp) if err != nil { return nil, err } diff --git a/codegen/jennies/grafana-app.go b/codegen/jennies/grafana-app.go new file mode 100644 index 00000000..789f53de --- /dev/null +++ b/codegen/jennies/grafana-app.go @@ -0,0 +1,59 @@ +package jennies + +import ( + "bytes" + "go/format" + "path" + + "github.com/grafana/codejen" + + "github.com/grafana/grafana-app-sdk/codegen" + "github.com/grafana/grafana-app-sdk/codegen/templates" +) + +type GrafanaAppGenerator struct { + ProjectRepo string + ProjectName string + APIsPath string +} + +func (*GrafanaAppGenerator) JennyName() string { + return "GrafanaApp" +} + +func (a *GrafanaAppGenerator) Generate(kinds ...codegen.Kind) (*codejen.File, error) { + tmd := templates.AppMetadata{ + Repo: a.ProjectRepo, + ProjectName: a.ProjectName, + APIsPath: a.APIsPath, + PackageName: "app", + WatcherPackage: "watchers", + Resources: make([]templates.AppMetadataKind, 0), + } + + for _, kind := range kinds { + if kind.Properties().APIResource == nil { + continue + } + vers := make([]string, len(kind.Versions())) + for i, ver := range kind.Versions() { + vers[i] = ver.Version + } + tmd.Resources = append(tmd.Resources, templates.AppMetadataKind{ + KindProperties: kind.Properties(), + Versions: vers, + }) + } + + b := bytes.Buffer{} + err := templates.WriteAppGoFile(tmd, &b, templates.TemplateGrafanaApp) + if err != nil { + return nil, err + } + formatted, err := format.Source(b.Bytes()) + if err != nil { + return nil, err + } + // TODO: do inside codegen_path/package_name (apps/playlist) + return codejen.NewFile(path.Join(tmd.CodegenPath, "pkg/app/app.go"), formatted, a), nil +} diff --git a/codegen/jennies/operator.go b/codegen/jennies/operator.go index 30187473..dd8b22eb 100644 --- a/codegen/jennies/operator.go +++ b/codegen/jennies/operator.go @@ -46,7 +46,7 @@ func (w *watcherJenny) Generate(kind codegen.Kind) (*codejen.File, error) { Version: ver, KindPackage: GetGeneratedPath(w.groupByKind, kind, ver), KindsAreGrouped: !w.groupByKind, - }, &b) + }, &b, templates.TemplateWatcher) if err != nil { return nil, err } diff --git a/codegen/templates/app/app.tmpl b/codegen/templates/app/app.tmpl index 0a35e856..f42303c8 100644 --- a/codegen/templates/app/app.tmpl +++ b/codegen/templates/app/app.tmpl @@ -51,4 +51,4 @@ func New(cfg app.Config) (app.App, error) { // Validate the capabilities against the provided manifest to make sure there isn't a mismatch err = a.ValidateManifest(cfg.ManifestData) return a, err -} \ No newline at end of file +} diff --git a/codegen/templates/app/grafana-app-watcher.tmpl b/codegen/templates/app/grafana-app-watcher.tmpl new file mode 100644 index 00000000..017767d5 --- /dev/null +++ b/codegen/templates/app/grafana-app-watcher.tmpl @@ -0,0 +1,89 @@ +package {{.PackageName}} + +import ( + "context" + "fmt" + + "github.com/grafana/grafana-app-sdk/logging" + "github.com/grafana/grafana-app-sdk/operator" + "github.com/grafana/grafana-app-sdk/resource" + "go.opentelemetry.io/otel" + + {{ if ne .Version "" }}{{.MachineName}} "{{.Repo}}/{{.CodegenPath}}{{ if not .KindsAreGrouped }}/resource{{end}}/{{.KindPackage}}" + {{ else }}"{{.Repo}}/{{.CodegenPath}}/resource/{{.MachineName}}"{{ end }} +) + +var _ operator.ResourceWatcher = &{{.Kind}}Watcher{} + +type {{.Kind}}Watcher struct {} + +func New{{.Kind}}Watcher() (*{{.Kind}}Watcher, error) { + return &{{.Kind}}Watcher{}, nil +} + +// Add handles add events for {{.MachineName}}.{{.Kind}} resources. +func (s *{{.Kind}}Watcher) Add(ctx context.Context, rObj resource.Object) error { + ctx, span := otel.GetTracerProvider().Tracer("watcher").Start(ctx, "watcher-add") + defer span.End() + object, ok := rObj.(*{{.MachineName}}.{{.Kind}}) + if !ok { + return fmt.Errorf("provided object is not of type *{{.MachineName}}.{{.Kind}} (name=%s, namespace=%s, kind=%s)", + rObj.GetStaticMetadata().Name, rObj.GetStaticMetadata().Namespace, rObj.GetStaticMetadata().Kind) + } + + // TODO + logging.FromContext(ctx).Debug("Added resource", "name", object.GetStaticMetadata().Identifier().Name) + return nil +} + +// Update handles update events for {{.MachineName}}.{{.Kind}} resources. +func (s *{{.Kind}}Watcher) Update(ctx context.Context, rOld resource.Object, rNew resource.Object) error { + ctx, span := otel.GetTracerProvider().Tracer("watcher").Start(ctx, "watcher-update") + defer span.End() + oldObject, ok := rOld.(*{{.MachineName}}.{{.Kind}}) + if !ok { + return fmt.Errorf("provided object is not of type *{{.MachineName}}.{{.Kind}} (name=%s, namespace=%s, kind=%s)", + rOld.GetStaticMetadata().Name, rOld.GetStaticMetadata().Namespace, rOld.GetStaticMetadata().Kind) + } + + _, ok = rNew.(*{{.MachineName}}.{{.Kind}}) + if !ok { + return fmt.Errorf("provided object is not of type *{{.MachineName}}.{{.Kind}} (name=%s, namespace=%s, kind=%s)", + rNew.GetStaticMetadata().Name, rNew.GetStaticMetadata().Namespace, rNew.GetStaticMetadata().Kind) + } + + // TODO + logging.FromContext(ctx).Debug("Updated resource", "name", oldObject.GetStaticMetadata().Identifier().Name) + return nil +} + +// Delete handles delete events for {{.MachineName}}.{{.Kind}} resources. +func (s *{{.Kind}}Watcher) Delete(ctx context.Context, rObj resource.Object) error { + ctx, span := otel.GetTracerProvider().Tracer("watcher").Start(ctx, "watcher-delete") + defer span.End() + object, ok := rObj.(*{{.MachineName}}.{{.Kind}}) + if !ok { + return fmt.Errorf("provided object is not of type *{{.MachineName}}.{{.Kind}} (name=%s, namespace=%s, kind=%s)", + rObj.GetStaticMetadata().Name, rObj.GetStaticMetadata().Namespace, rObj.GetStaticMetadata().Kind) + } + + // TODO + logging.FromContext(ctx).Debug("Deleted resource", "name", object.GetStaticMetadata().Identifier().Name) + return nil +} + +// Sync is not a standard resource.Watcher function, but is used when wrapping this watcher in an operator.OpinionatedWatcher. +// It handles resources which MAY have been updated during an outage period where the watcher was not able to consume events. +func (s *{{.Kind}}Watcher) Sync(ctx context.Context, rObj resource.Object) error { + ctx, span := otel.GetTracerProvider().Tracer("watcher").Start(ctx, "watcher-sync") + defer span.End() + object, ok := rObj.(*{{.MachineName}}.{{.Kind}}) + if !ok { + return fmt.Errorf("provided object is not of type *{{.MachineName}}.{{.Kind}} (name=%s, namespace=%s, kind=%s)", + rObj.GetStaticMetadata().Name, rObj.GetStaticMetadata().Namespace, rObj.GetStaticMetadata().Kind) + } + + // TODO + logging.FromContext(ctx).Debug("Possible resource update", "name", object.GetStaticMetadata().Identifier().Name) + return nil +} diff --git a/codegen/templates/app/grafana-app.tmpl b/codegen/templates/app/grafana-app.tmpl new file mode 100644 index 00000000..45a530a0 --- /dev/null +++ b/codegen/templates/app/grafana-app.tmpl @@ -0,0 +1,101 @@ +package {{.PackageName}} + +import ( + "context" + "errors" + "fmt" + "reflect" + + "github.com/grafana/grafana-app-sdk/app" + "github.com/grafana/grafana-app-sdk/logging" + "github.com/grafana/grafana-app-sdk/resource" + "github.com/grafana/grafana-app-sdk/simple" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/klog/v2" + + {{ range $key, $val := .GVToKindAll }}{{ $.ToPackageNameVariable ($key.String) }} "{{$.Repo}}/{{$.APIsPath}}/{{ $.ToPackageName $key.Group }}/{{ $.ToPackageName $key.Version }}" + {{end}} + {{ if ne .WatcherPackage "" }}"{{$.Repo}}/pkg/{{.WatcherPackage}}"{{end}} +) + +type {{.ProjectName | .ToUpper}}Config struct { + EnableWatchers bool +} + +func New(cfg app.Config) (app.App, error) { + {{.ProjectName}}Config, ok := cfg.SpecificConfig.(*{{.ProjectName | .ToUpper}}Config) + if !ok { + return nil, errors.New("could not load project's specific config, type assertion failed: type of SpecificConfig=" + reflect.TypeOf(cfg.SpecificConfig).Name()) + } + + managedKinds := make([]simple.AppManagedKind, 0) + {{ $pn := .ProjectName }} + {{ $wp := .WatcherPackage }} + + {{ range $key, $val := .GVToKindCurrent }}{{ range $val }} + { + managedKind := simple.AppManagedKind{ + Kind: {{$.ToPackageNameVariable ($key.String)}}.{{.Kind}}Kind(), + Mutator: &simple.Mutator{ + MutateFunc: func(ctx context.Context, req *app.AdmissionRequest) (*app.MutatingResponse, error) { + // modify req.Object if needed + return &app.MutatingResponse{ + UpdatedObject: req.Object, + }, nil + }, + }, + Validator: &simple.Validator{ + ValidateFunc: func(ctx context.Context, req *app.AdmissionRequest) error { + // do something here if needed + return nil + }, + }, + } + managedKinds = append(managedKinds, managedKind) + if {{$pn}}Config.EnableWatchers { + {{ $p := $wp }}{{.MachineName}}Watcher, err := {{if ne $p ""}}{{$p}}.{{end}}New{{.Kind}}Watcher() + if err != nil { + return nil, fmt.Errorf("unable to create {{.Kind}}Watcher: %w", err) + }{{ if eq $key.Version .Current }} + managedKind.Watcher = {{.MachineName}}Watcher{{ end }} + } + {{ end }}{{ end }} + } + + config := simple.AppConfig{ + Name: "{{.ProjectName}}", + KubeConfig: cfg.KubeConfig, + InformerConfig: simple.AppInformerConfig{ + ErrorHandler: func(ctx context.Context, err error) { + // FIXME: add your own error handling here + klog.ErrorS(err, "Informer processing error") + }, + }, + ManagedKinds: managedKinds, + } + + // Create the App + a, err := simple.NewApp(config) + if err != nil { + return nil, err + } + + // Validate the capabilities against the provided manifest to make sure there isn't a mismatch + err = a.ValidateManifest(cfg.ManifestData) + if err != nil { + return nil, err + } + return a, nil +} + +func GetKinds() map[schema.GroupVersion]resource.Kind { + {{ range $key, $val := .GVToKindAll }}{{ range $val }} + gv := schema.GroupVersion{ + Group: {{ $.ToPackageNameVariable ($key.String) }}.{{.Kind}}Kind().Group(), + Version: {{ $.ToPackageNameVariable ($key.String) }}.{{.Kind}}Kind().Version(), + } + return map[schema.GroupVersion]resource.Kind{ + gv: {{ $.ToPackageNameVariable ($key.String) }}.{{.Kind}}Kind(), + } + {{end}}{{ end }} +} diff --git a/codegen/templates/templates.go b/codegen/templates/templates.go index be34f573..b07e0506 100644 --- a/codegen/templates/templates.go +++ b/codegen/templates/templates.go @@ -9,6 +9,9 @@ import ( "strings" "text/template" + "golang.org/x/text/cases" + "golang.org/x/text/language" + "k8s.io/apimachinery/pkg/runtime/schema" "github.com/grafana/grafana-app-sdk/app" @@ -33,8 +36,10 @@ var ( templateBackendPluginModelsHandler, _ = template.ParseFS(templates, "plugin/handler_models.tmpl") templateBackendMain, _ = template.ParseFS(templates, "plugin/main.tmpl") - templateWatcher, _ = template.ParseFS(templates, "app/watcher.tmpl") - templateApp, _ = template.ParseFS(templates, "app/app.tmpl") + TemplateWatcher, _ = template.ParseFS(templates, "app/watcher.tmpl") + TemplateApp, _ = template.ParseFS(templates, "app/app.tmpl") + TemplateGrafanaAppWatcher, _ = template.ParseFS(templates, "app/grafana-app-watcher.tmpl") + TemplateGrafanaApp, _ = template.ParseFS(templates, "app/grafana-app.tmpl") templateOperatorKubeconfig, _ = template.ParseFS(templates, "operator/kubeconfig.tmpl") templateOperatorMain, _ = template.ParseFS(templates, "operator/main.tmpl") @@ -321,8 +326,8 @@ func (WatcherMetadata) ToPackageName(input string) string { return ToPackageName(input) } -func WriteWatcher(metadata WatcherMetadata, out io.Writer) error { - return templateWatcher.Execute(out, metadata) +func WriteWatcher(metadata WatcherMetadata, out io.Writer, tmpl *template.Template) error { + return tmpl.Execute(out, metadata) } func WriteOperatorKubeConfig(out io.Writer) error { @@ -418,6 +423,7 @@ type AppMetadata struct { ProjectName string Repo string CodegenPath string + APIsPath string // only used by grafanaApp component WatcherPackage string KindsAreGrouped bool Resources []AppMetadataKind @@ -434,6 +440,11 @@ type extendedAppMetadata struct { GVToKindCurrent map[schema.GroupVersion][]codegen.KindProperties } +func (AppMetadata) ToUpper(input string) string { + caser := cases.Title(language.English) + return caser.String(input) +} + func (AppMetadata) ToPackageName(input string) string { return ToPackageName(input) } @@ -442,7 +453,7 @@ func (AppMetadata) ToPackageNameVariable(input string) string { return strings.ReplaceAll(ToPackageName(input), "_", "") } -func WriteAppGoFile(metadata AppMetadata, out io.Writer) error { +func WriteAppGoFile(metadata AppMetadata, out io.Writer, tmpl *template.Template) error { md := extendedAppMetadata{ AppMetadata: metadata, GVToKindAll: make(map[schema.GroupVersion][]codegen.KindProperties), @@ -466,7 +477,7 @@ func WriteAppGoFile(metadata AppMetadata, out io.Writer) error { md.GVToKindAll[gv] = l } } - return templateApp.Execute(out, md) + return tmpl.Execute(out, md) } type ConstantsMetadata struct { From a2eb732291b289190f341352e27bab55bc683e75 Mon Sep 17 00:00:00 2001 From: Charandas Batra Date: Thu, 26 Dec 2024 13:08:43 -0800 Subject: [PATCH 2/4] back to building --- cmd/grafana-app-sdk/project.go | 42 +++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/cmd/grafana-app-sdk/project.go b/cmd/grafana-app-sdk/project.go index a95468b6..5379e125 100644 --- a/cmd/grafana-app-sdk/project.go +++ b/cmd/grafana-app-sdk/project.go @@ -509,7 +509,6 @@ type anyGenerator interface { *codegen.Generator[codegen.Kind] } -<<<<<<< HEAD //nolint:revive func addComponentOperator[G anyGenerator](projectRootPath string, generator G, selectors []string, groupKinds bool, confirmOverwrite bool) error { // Get the repo from the go.mod file @@ -558,6 +557,47 @@ func addComponentOperator[G anyGenerator](projectRootPath string, generator G, s return nil } +// +// Grafana App +// + +func addComponentGrafanaApp[G anyGenerator](projectRootPath string, generator G, selectors []string, groupKinds bool) error { + // Get the repo from the go.mod file + repo, err := getGoModule(filepath.Join(projectRootPath, "go.mod")) + if err != nil { + return err + } + var files codejen.Files + switch cast := any(generator).(type) { + case *codegen.Generator[codegen.Kind]: + appFiles, err := cast.Generate(cuekind.GrafanaAppGenerator(repo, ".", "pkg/apis", groupKinds), selectors...) + if err != nil { + return err + } + files = append(files, appFiles...) + default: + return fmt.Errorf("unknown generator type: %T", cast) + } + if err = checkAndMakePath("pkg"); err != nil { + return err + } + for _, f := range files { + err = writeFile(filepath.Join(projectRootPath, f.RelativePath), f.Data) + if err != nil { + return err + } + } + dockerfile, err := templates.ReadFile("templates/operator_Dockerfile.tmpl") + if err != nil { + return err + } + err = writeFile(filepath.Join(projectRootPath, "cmd", "operator", "Dockerfile"), dockerfile) + if err != nil { + return err + } + return nil +} + // // Backend plugin // From 9217ccd0a43db2cd8fdd5541dc6b6249d74910b6 Mon Sep 17 00:00:00 2001 From: Charandas Batra Date: Wed, 8 Jan 2025 14:32:50 -0800 Subject: [PATCH 3/4] make update-workspace --- go.mod | 2 +- go.sum | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index f3a21ccc..eaa6c743 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,7 @@ require ( go.opentelemetry.io/otel/sdk v1.33.0 go.opentelemetry.io/otel/trace v1.33.0 golang.org/x/sync v0.10.0 + golang.org/x/text v0.21.0 gomodules.xyz/jsonpatch/v2 v2.4.0 google.golang.org/grpc v1.69.0 gopkg.in/yaml.v3 v3.0.1 @@ -97,7 +98,6 @@ require ( golang.org/x/oauth2 v0.24.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/term v0.27.0 // indirect - golang.org/x/text v0.21.0 // indirect golang.org/x/time v0.7.0 // indirect golang.org/x/tools v0.28.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 // indirect diff --git a/go.sum b/go.sum index 194f4585..bca77ff0 100644 --- a/go.sum +++ b/go.sum @@ -203,6 +203,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= From 3d4cca8658a878bd8015b09f5a11b42bd56d74de Mon Sep 17 00:00:00 2001 From: Charandas Batra Date: Fri, 10 Jan 2025 11:32:47 -0800 Subject: [PATCH 4/4] boilerplate for reconciler --- codegen/jennies/grafana-app.go | 48 +++++++++++++++++-- codegen/jennies/manifest.go | 1 + ...tcher.tmpl => grafana-app-reconciler.tmpl} | 0 codegen/templates/app/grafana-app.tmpl | 1 + codegen/templates/templates.go | 25 +++++----- 5 files changed, 60 insertions(+), 15 deletions(-) rename codegen/templates/app/{grafana-app-watcher.tmpl => grafana-app-reconciler.tmpl} (100%) diff --git a/codegen/jennies/grafana-app.go b/codegen/jennies/grafana-app.go index 789f53de..6dfccd99 100644 --- a/codegen/jennies/grafana-app.go +++ b/codegen/jennies/grafana-app.go @@ -32,9 +32,6 @@ func (a *GrafanaAppGenerator) Generate(kinds ...codegen.Kind) (*codejen.File, er } for _, kind := range kinds { - if kind.Properties().APIResource == nil { - continue - } vers := make([]string, len(kind.Versions())) for i, ver := range kind.Versions() { vers[i] = ver.Version @@ -57,3 +54,48 @@ func (a *GrafanaAppGenerator) Generate(kinds ...codegen.Kind) (*codejen.File, er // TODO: do inside codegen_path/package_name (apps/playlist) return codejen.NewFile(path.Join(tmd.CodegenPath, "pkg/app/app.go"), formatted, a), nil } + +type GrafanaAppReconcilerGenerator struct { + ProjectRepo string + ProjectName string + APIsPath string +} + +func (*GrafanaAppReconcilerGenerator) JennyName() string { + return "GrafanaApp" +} + +func (a *GrafanaAppReconcilerGenerator) Generate(kinds ...codegen.Kind) (*codejen.File, error) { + tmd := templates.AppMetadata{ + Repo: a.ProjectRepo, + ProjectName: a.ProjectName, + APIsPath: a.APIsPath, + PackageName: "app", + ReconcilerPackage: "reconcilers", + Resources: make([]templates.AppMetadataKind, 0), + } + + for _, kind := range kinds { + vers := make([]string, len(kind.Versions())) + for i, ver := range kind.Versions() { + vers[i] = ver.Version + } + tmd.Resources = append(tmd.Resources, templates.AppMetadataKind{ + KindProperties: kind.Properties(), + Versions: vers, + }) + } + + b := bytes.Buffer{} + err := templates.WriteAppGoFile(tmd, &b, templates.TemplateGrafanaAppReconciler) + if err != nil { + return nil, err + } + formatted, err := format.Source(b.Bytes()) + if err != nil { + return nil, err + } + // TODO: do inside codegen_path/package_name (apps/playlist) + // pkg/reconcilers/reconciler_.go + return codejen.NewFile(path.Join(tmd.CodegenPath, "pkg/reconcilers/reconciler.go"), formatted, a), nil +} diff --git a/codegen/jennies/manifest.go b/codegen/jennies/manifest.go index 7d5d44fc..c21a94fe 100644 --- a/codegen/jennies/manifest.go +++ b/codegen/jennies/manifest.go @@ -146,6 +146,7 @@ func buildManifestData(m codegen.AppManifest) (*app.ManifestData, error) { mver := app.ManifestKindVersion{ Name: version.Version, } + if len(version.Mutation.Operations) > 0 { operations, err := sanitizeAdmissionOperations(version.Mutation.Operations) if err != nil { diff --git a/codegen/templates/app/grafana-app-watcher.tmpl b/codegen/templates/app/grafana-app-reconciler.tmpl similarity index 100% rename from codegen/templates/app/grafana-app-watcher.tmpl rename to codegen/templates/app/grafana-app-reconciler.tmpl diff --git a/codegen/templates/app/grafana-app.tmpl b/codegen/templates/app/grafana-app.tmpl index 45a530a0..d1cb37f9 100644 --- a/codegen/templates/app/grafana-app.tmpl +++ b/codegen/templates/app/grafana-app.tmpl @@ -1,3 +1,4 @@ +{{- /*gotype: github.com/grafana/grafana-app-sdk/codegen/templates.AppMetadata */ -}} package {{.PackageName}} import ( diff --git a/codegen/templates/templates.go b/codegen/templates/templates.go index b07e0506..ea011dfa 100644 --- a/codegen/templates/templates.go +++ b/codegen/templates/templates.go @@ -36,10 +36,10 @@ var ( templateBackendPluginModelsHandler, _ = template.ParseFS(templates, "plugin/handler_models.tmpl") templateBackendMain, _ = template.ParseFS(templates, "plugin/main.tmpl") - TemplateWatcher, _ = template.ParseFS(templates, "app/watcher.tmpl") - TemplateApp, _ = template.ParseFS(templates, "app/app.tmpl") - TemplateGrafanaAppWatcher, _ = template.ParseFS(templates, "app/grafana-app-watcher.tmpl") - TemplateGrafanaApp, _ = template.ParseFS(templates, "app/grafana-app.tmpl") + TemplateWatcher, _ = template.ParseFS(templates, "app/watcher.tmpl") + TemplateApp, _ = template.ParseFS(templates, "app/app.tmpl") + TemplateGrafanaAppReconciler, _ = template.ParseFS(templates, "app/grafana-app-reconciler.tmpl") + TemplateGrafanaApp, _ = template.ParseFS(templates, "app/grafana-app.tmpl") templateOperatorKubeconfig, _ = template.ParseFS(templates, "operator/kubeconfig.tmpl") templateOperatorMain, _ = template.ParseFS(templates, "operator/main.tmpl") @@ -419,14 +419,15 @@ func WriteManifestGoFile(metadata ManifestGoFileMetadata, out io.Writer) error { } type AppMetadata struct { - PackageName string - ProjectName string - Repo string - CodegenPath string - APIsPath string // only used by grafanaApp component - WatcherPackage string - KindsAreGrouped bool - Resources []AppMetadataKind + PackageName string + ProjectName string + Repo string + CodegenPath string + APIsPath string // only used by grafanaApp component + ReconcilerPackage string + WatcherPackage string + KindsAreGrouped bool + Resources []AppMetadataKind } type AppMetadataKind struct {