Skip to content

Commit

Permalink
Merge pull request crossplane#326 from ulucinar/isolate-terraformed-i…
Browse files Browse the repository at this point in the history
…mplementations

Generate a standalone "zz_generated.terraformed.go" file for each resource
  • Loading branch information
ulucinar authored Jan 23, 2024
2 parents ed4e0de + 10c1679 commit 87fae5e
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 138 deletions.
213 changes: 106 additions & 107 deletions pkg/pipeline/templates/terraformed.go.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -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(&params, 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(&params, 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 }}
}
59 changes: 28 additions & 31 deletions pkg/pipeline/terraformed.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package pipeline

import (
"fmt"
"go/types"
"os"
"path/filepath"
Expand Down Expand Up @@ -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
}

0 comments on commit 87fae5e

Please sign in to comment.