From 10c16799c063f7d12dffd466512a9ee4d6cb507c Mon Sep 17 00:00:00 2001 From: Alper Rifat Ulucinar Date: Tue, 9 Jan 2024 15:35:45 +0300 Subject: [PATCH] Generate a standalone "zz_generated.terraformed.go" file for each resource - Each resource will now have its own resource.Terraformed interface implementation file. - The per-group "zz_generated_terraformed.go" is now split into per-resource "zz_generated.terraformed.go" files. - This helps while generating multiple versions for the CRDs. Signed-off-by: Alper Rifat Ulucinar --- pkg/pipeline/templates/terraformed.go.tmpl | 213 ++++++++++----------- pkg/pipeline/terraformed.go | 59 +++--- 2 files changed, 134 insertions(+), 138 deletions(-) diff --git a/pkg/pipeline/templates/terraformed.go.tmpl b/pkg/pipeline/templates/terraformed.go.tmpl index 4681e523..49ee620b 100644 --- a/pkg/pipeline/templates/terraformed.go.tmpl +++ b/pkg/pipeline/templates/terraformed.go.tmpl @@ -16,125 +16,124 @@ import ( "github.com/crossplane/upjet/pkg/resource/json" {{ .Imports }} ) -{{ range .Resources }} - // GetTerraformResourceType returns Terraform resource type for this {{ .CRD.Kind }} - func (mg *{{ .CRD.Kind }}) GetTerraformResourceType() string { - return "{{ .Terraform.ResourceType }}" - } - // GetConnectionDetailsMapping for this {{ .CRD.Kind }} - func (tr *{{ .CRD.Kind }}) GetConnectionDetailsMapping() map[string]string { - {{- if .Sensitive.Fields }} - return map[string]string{ {{range $k, $v := .Sensitive.Fields}}"{{ $k }}": "{{ $v}}", {{end}} } - {{- else }} - return nil - {{- end }} +// GetTerraformResourceType returns Terraform resource type for this {{ .CRD.Kind }} +func (mg *{{ .CRD.Kind }}) GetTerraformResourceType() string { + return "{{ .Terraform.ResourceType }}" +} + +// GetConnectionDetailsMapping for this {{ .CRD.Kind }} +func (tr *{{ .CRD.Kind }}) GetConnectionDetailsMapping() map[string]string { + {{- if .Sensitive.Fields }} + return map[string]string{ {{range $k, $v := .Sensitive.Fields}}"{{ $k }}": "{{ $v}}", {{end}} } + {{- else }} + return nil + {{- end }} +} + +// GetObservation of this {{ .CRD.Kind }} +func (tr *{{ .CRD.Kind }}) GetObservation() (map[string]any, error) { + o, err := json.TFParser.Marshal(tr.Status.AtProvider) + if err != nil { + return nil, err } - - // GetObservation of this {{ .CRD.Kind }} - func (tr *{{ .CRD.Kind }}) GetObservation() (map[string]any, error) { - o, err := json.TFParser.Marshal(tr.Status.AtProvider) - if err != nil { - return nil, err - } - base := map[string]any{} - return base, json.TFParser.Unmarshal(o, &base) + base := map[string]any{} + return base, json.TFParser.Unmarshal(o, &base) +} + +// SetObservation for this {{ .CRD.Kind }} +func (tr *{{ .CRD.Kind }}) SetObservation(obs map[string]any) error { + p, err := json.TFParser.Marshal(obs) + if err != nil { + return err } + return json.TFParser.Unmarshal(p, &tr.Status.AtProvider) +} - // SetObservation for this {{ .CRD.Kind }} - func (tr *{{ .CRD.Kind }}) SetObservation(obs map[string]any) error { - p, err := json.TFParser.Marshal(obs) - if err != nil { - return err - } - return json.TFParser.Unmarshal(p, &tr.Status.AtProvider) +// GetID returns ID of underlying Terraform resource of this {{ .CRD.Kind }} +func (tr *{{ .CRD.Kind }}) GetID() string { + if tr.Status.AtProvider.ID == nil { + return "" } - - // GetID returns ID of underlying Terraform resource of this {{ .CRD.Kind }} - func (tr *{{ .CRD.Kind }}) GetID() string { - if tr.Status.AtProvider.ID == nil { - return "" - } - return *tr.Status.AtProvider.ID + return *tr.Status.AtProvider.ID +} + +// GetParameters of this {{ .CRD.Kind }} +func (tr *{{ .CRD.Kind }}) GetParameters() (map[string]any, error) { + p, err := json.TFParser.Marshal(tr.Spec.ForProvider) + if err != nil { + return nil, err } - - // GetParameters of this {{ .CRD.Kind }} - func (tr *{{ .CRD.Kind }}) GetParameters() (map[string]any, error) { - p, err := json.TFParser.Marshal(tr.Spec.ForProvider) - if err != nil { - return nil, err - } - base := map[string]any{} - return base, json.TFParser.Unmarshal(p, &base) + base := map[string]any{} + return base, json.TFParser.Unmarshal(p, &base) +} + +// SetParameters for this {{ .CRD.Kind }} +func (tr *{{ .CRD.Kind }}) SetParameters(params map[string]any) error { + p, err := json.TFParser.Marshal(params) + if err != nil { + return err } - - // SetParameters for this {{ .CRD.Kind }} - func (tr *{{ .CRD.Kind }}) SetParameters(params map[string]any) error { - p, err := json.TFParser.Marshal(params) - if err != nil { - return err - } - return json.TFParser.Unmarshal(p, &tr.Spec.ForProvider) + return json.TFParser.Unmarshal(p, &tr.Spec.ForProvider) +} + +// GetInitParameters of this {{ .CRD.Kind }} +func (tr *{{ .CRD.Kind }}) GetInitParameters() (map[string]any, error) { + p, err := json.TFParser.Marshal(tr.Spec.InitProvider) + if err != nil { + return nil, err } - - // GetInitParameters of this {{ .CRD.Kind }} - func (tr *{{ .CRD.Kind }}) GetInitParameters() (map[string]any, error) { - p, err := json.TFParser.Marshal(tr.Spec.InitProvider) - if err != nil { - return nil, err - } - base := map[string]any{} - return base, json.TFParser.Unmarshal(p, &base) + base := map[string]any{} + return base, json.TFParser.Unmarshal(p, &base) +} + +// GetInitParameters of this {{ .CRD.Kind }} +func (tr *{{ .CRD.Kind }}) GetMergedParameters(shouldMergeInitProvider bool) (map[string]any, error) { + params, err := tr.GetParameters() + if err != nil { + return nil, errors.Wrapf(err, "cannot get parameters for resource '%q'", tr.GetName()) } - - // GetInitParameters of this {{ .CRD.Kind }} - func (tr *{{ .CRD.Kind }}) GetMergedParameters(shouldMergeInitProvider bool) (map[string]any, error) { - params, err := tr.GetParameters() - if err != nil { - return nil, errors.Wrapf(err, "cannot get parameters for resource '%q'", tr.GetName()) - } - if !shouldMergeInitProvider { - return params, nil - } - - initParams, err := tr.GetInitParameters() - if err != nil { - return nil, errors.Wrapf(err, "cannot get init parameters for resource '%q'", tr.GetName()) - } - - // Note(lsviben): mergo.WithSliceDeepCopy is needed to merge the - // slices from the initProvider to forProvider. As it also sets - // overwrite to true, we need to set it back to false, we don't - // want to overwrite the forProvider fields with the initProvider - // fields. - err = mergo.Merge(¶ms, initParams, mergo.WithSliceDeepCopy, func(c *mergo.Config) { - c.Overwrite = false - }) - if err != nil { - return nil, errors.Wrapf(err, "cannot merge spec.initProvider and spec.forProvider parameters for resource '%q'", tr.GetName()) - } - + if !shouldMergeInitProvider { return params, nil } - // LateInitialize this {{ .CRD.Kind }} using its observed tfState. - // returns True if there are any spec changes for the resource. - func (tr *{{ .CRD.Kind }}) LateInitialize(attrs []byte) (bool, error) { - params := &{{ .CRD.ParametersTypeName }}{} - if err := json.TFParser.Unmarshal(attrs, params); err != nil { - return false, errors.Wrap(err, "failed to unmarshal Terraform state parameters for late-initialization") - } - opts := []resource.GenericLateInitializerOption{resource.WithZeroValueJSONOmitEmptyFilter(resource.CNameWildcard)} - {{ range .LateInitializer.IgnoredFields -}} - opts = append(opts, resource.WithNameFilter("{{ . }}")) - {{ end }} - - li := resource.NewGenericLateInitializer(opts...) - return li.LateInitialize(&tr.Spec.ForProvider, params) + initParams, err := tr.GetInitParameters() + if err != nil { + return nil, errors.Wrapf(err, "cannot get init parameters for resource '%q'", tr.GetName()) } - // GetTerraformSchemaVersion returns the associated Terraform schema version - func (tr *{{ .CRD.Kind }}) GetTerraformSchemaVersion() int { - return {{ .Terraform.SchemaVersion }} + // Note(lsviben): mergo.WithSliceDeepCopy is needed to merge the + // slices from the initProvider to forProvider. As it also sets + // overwrite to true, we need to set it back to false, we don't + // want to overwrite the forProvider fields with the initProvider + // fields. + err = mergo.Merge(¶ms, initParams, mergo.WithSliceDeepCopy, func(c *mergo.Config) { + c.Overwrite = false + }) + if err != nil { + return nil, errors.Wrapf(err, "cannot merge spec.initProvider and spec.forProvider parameters for resource '%q'", tr.GetName()) + } + + return params, nil +} + +// LateInitialize this {{ .CRD.Kind }} using its observed tfState. +// returns True if there are any spec changes for the resource. +func (tr *{{ .CRD.Kind }}) LateInitialize(attrs []byte) (bool, error) { + params := &{{ .CRD.ParametersTypeName }}{} + if err := json.TFParser.Unmarshal(attrs, params); err != nil { + return false, errors.Wrap(err, "failed to unmarshal Terraform state parameters for late-initialization") } -{{ end }} + opts := []resource.GenericLateInitializerOption{resource.WithZeroValueJSONOmitEmptyFilter(resource.CNameWildcard)} + {{ range .LateInitializer.IgnoredFields -}} + opts = append(opts, resource.WithNameFilter("{{ . }}")) + {{ end }} + + li := resource.NewGenericLateInitializer(opts...) + return li.LateInitialize(&tr.Spec.ForProvider, params) +} + +// GetTerraformSchemaVersion returns the associated Terraform schema version +func (tr *{{ .CRD.Kind }}) GetTerraformSchemaVersion() int { + return {{ .Terraform.SchemaVersion }} +} diff --git a/pkg/pipeline/terraformed.go b/pkg/pipeline/terraformed.go index fea56e6a..e588c00e 100644 --- a/pkg/pipeline/terraformed.go +++ b/pkg/pipeline/terraformed.go @@ -5,6 +5,7 @@ package pipeline import ( + "fmt" "go/types" "os" "path/filepath" @@ -36,38 +37,34 @@ type TerraformedGenerator struct { // Generate writes generated Terraformed interface functions func (tg *TerraformedGenerator) Generate(cfgs []*terraformedInput, apiVersion string) error { - trFile := wrapper.NewFile(tg.pkg.Path(), tg.pkg.Name(), templates.TerraformedTemplate, - wrapper.WithGenStatement(GenStatement), - wrapper.WithHeaderPath(tg.LicenseHeaderPath), - ) - filePath := filepath.Join(tg.LocalDirectoryPath, "zz_generated_terraformed.go") - vars := map[string]any{ - "APIVersion": apiVersion, - } - resources := make([]map[string]any, len(cfgs)) - index := 0 for _, cfg := range cfgs { - resources[index] = map[string]any{ - "CRD": map[string]string{ - "Kind": cfg.Kind, - "ParametersTypeName": cfg.ParametersTypeName, - }, - "Terraform": map[string]any{ - "ResourceType": cfg.Name, - "SchemaVersion": cfg.TerraformResource.SchemaVersion, - }, - "Sensitive": map[string]any{ - "Fields": cfg.Sensitive.GetFieldPaths(), - }, - "LateInitializer": map[string]any{ - "IgnoredFields": cfg.LateInitializer.GetIgnoredCanonicalFields(), - }, + trFile := wrapper.NewFile(tg.pkg.Path(), tg.pkg.Name(), templates.TerraformedTemplate, + wrapper.WithGenStatement(GenStatement), + wrapper.WithHeaderPath(tg.LicenseHeaderPath), + ) + filePath := filepath.Join(tg.LocalDirectoryPath, fmt.Sprintf("zz_%s_terraformed.go", strings.ToLower(cfg.Kind))) + + vars := map[string]any{ + "APIVersion": apiVersion, + } + vars["CRD"] = map[string]string{ + "Kind": cfg.Kind, + "ParametersTypeName": cfg.ParametersTypeName, + } + vars["Terraform"] = map[string]any{ + "ResourceType": cfg.Name, + "SchemaVersion": cfg.TerraformResource.SchemaVersion, + } + vars["Sensitive"] = map[string]any{ + "Fields": cfg.Sensitive.GetFieldPaths(), + } + vars["LateInitializer"] = map[string]any{ + "IgnoredFields": cfg.LateInitializer.GetIgnoredCanonicalFields(), + } + + if err := trFile.Write(filePath, vars, os.ModePerm); err != nil { + return errors.Wrapf(err, "cannot write the Terraformed interface implementation file %s", filePath) } - index++ } - vars["Resources"] = resources - return errors.Wrap( - trFile.Write(filePath, vars, os.ModePerm), - "cannot write terraformed conversion methods file", - ) + return nil }