Skip to content
This repository has been archived by the owner on Dec 15, 2022. It is now read-only.

Generate controllers and terraformed interface methods on CRDs #26

Merged
merged 3 commits into from
Aug 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
75 changes: 75 additions & 0 deletions pkg/pipeline/controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
Copyright 2021 The Crossplane Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package pipeline

import (
"os"
"path/filepath"
"strings"

"github.com/muvaf/typewriter/pkg/wrapper"
"github.com/pkg/errors"

"github.com/crossplane-contrib/terrajet/pkg/pipeline/templates"
)

// NewControllerGenerator returns a new ControllerGenerator.
func NewControllerGenerator(controllerGroupDir, rootModulePath, group, providerConfigBuilderPath string) *ControllerGenerator {
return &ControllerGenerator{
Group: group,
ControllerGroupDir: controllerGroupDir,
RootModulePath: rootModulePath,
ProviderConfigBuilderPath: providerConfigBuilderPath,
}
}

// ControllerGenerator generates controller setup functions.
type ControllerGenerator struct {
Group string
ControllerGroupDir string
RootModulePath string
ProviderConfigBuilderPath string
}

// Generate writes controller setup functions.
func (tg *ControllerGenerator) Generate(version, kind string) error {
groupPkgPath := filepath.Join(tg.RootModulePath, "apis", strings.ToLower(strings.Split(tg.Group, ".")[0]), strings.ToLower(version))
kindPkgPath := filepath.Join(groupPkgPath, strings.ToLower(kind))

controllerPkgPath := filepath.Join(tg.RootModulePath, "internal", "controller", strings.ToLower(strings.Split(tg.Group, ".")[0]), strings.ToLower(kind))
ctrlFile := wrapper.NewFile(controllerPkgPath, version, templates.ControllerTemplate,
wrapper.WithGenStatement(GenStatement),
wrapper.WithHeaderPath("hack/boilerplate.go.txt"), // todo
wrapper.LinterEnabled(),
)

vars := map[string]interface{}{
"Package": strings.ToLower(kind),
"CRD": map[string]string{
"APIVersion": version,
"Kind": kind,
},
"TypePackageAlias": ctrlFile.Imports.UsePackage(kindPkgPath),
"ProviderConfigBuilderPackageAlias": ctrlFile.Imports.UsePackage(tg.ProviderConfigBuilderPath),
}

filePath := filepath.Join(tg.ControllerGroupDir, strings.ToLower(kind), "zz_controller.go")
return errors.Wrap(
ctrlFile.Write(filePath, vars, os.ModePerm),
"cannot write controller file",
)
}
19 changes: 19 additions & 0 deletions pkg/pipeline/templates/controller.go.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{{ .Header }}

{{ .GenStatement }}

package {{ .Package }}

import (
ctrl "sigs.k8s.io/controller-runtime"

"github.com/crossplane-contrib/terrajet/pkg/terraform"
"github.com/crossplane/crossplane-runtime/pkg/logging"

{{ .Imports }}
)

// Setup adds a controller that reconciles {{ .CRD.Kind }} managed resources.
func Setup(mgr ctrl.Manager, l logging.Logger) error {
return terraform.SetupController(mgr, l, &{{ .TypePackageAlias }}{{ .CRD.Kind }}{}, {{ .TypePackageAlias }}{{ .CRD.Kind }}GroupVersionKind, {{ .ProviderConfigBuilderPackageAlias }}ProviderConfigBuilder)
}
9 changes: 9 additions & 0 deletions pkg/pipeline/templates/embed.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,12 @@ var CRDTypesTemplate string
// GroupVersionInfoTemplate is populated with group and version information.
//go:embed groupversion_info.go.tmpl
var GroupVersionInfoTemplate string

// TerraformedTemplate is populated with conversion methods implementing
// Terraformed interface on CRD structs.
//go:embed terraformed.go.tmpl
var TerraformedTemplate string

// ControllerTemplate is populated with controller setup functions.
//go:embed controller.go.tmpl
var ControllerTemplate string
2 changes: 1 addition & 1 deletion pkg/pipeline/templates/groupversion_info.go.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ var (

// AddToScheme adds the types in this group-version to the given scheme.
AddToScheme = SchemeBuilder.AddToScheme
)
)
37 changes: 37 additions & 0 deletions pkg/pipeline/templates/terraformed.go.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{{ .Header }}

{{ .GenStatement }}

package {{ .CRD.APIVersion }}

import "github.com/crossplane-contrib/terrajet/pkg/conversion"

// GetTerraformResourceType returns Terraform resource type for this {{ .CRD.Kind }}
func (mg *{{ .CRD.Kind }}) GetTerraformResourceType() string {
turkenh marked this conversation as resolved.
Show resolved Hide resolved
return "{{ .Terraform.ResourceType }}"
}

// GetTerraformResourceIdField returns Terraform identifier field for this {{ .CRD.Kind }}
func (tr *{{ .CRD.Kind }}) GetTerraformResourceIdField() string {
return "{{ .Terraform.IdentifierField }}"
}

// GetObservation of this {{ .CRD.Kind }}
func (tr *{{ .CRD.Kind }}) GetObservation() ([]byte, error) {
return conversion.TFParser.Marshal(tr.Status.AtProvider)
}

// SetObservation for this {{ .CRD.Kind }}
func (tr *{{ .CRD.Kind }}) SetObservation(data []byte) error {
return conversion.TFParser.Unmarshal(data, &tr.Status.AtProvider)
}

// GetParameters of this {{ .CRD.Kind }}
func (tr *{{ .CRD.Kind }}) GetParameters() ([]byte, error) {
return conversion.TFParser.Marshal(tr.Spec.ForProvider)
}

// SetParameters for this {{ .CRD.Kind }}
func (tr *{{ .CRD.Kind }}) SetParameters(data []byte) error {
return conversion.TFParser.Unmarshal(data, &tr.Spec.ForProvider)
}
77 changes: 77 additions & 0 deletions pkg/pipeline/terraformed.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
Copyright 2021 The Crossplane Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package pipeline

import (
"os"
"path/filepath"
"strings"

"github.com/muvaf/typewriter/pkg/wrapper"
"github.com/pkg/errors"

"github.com/crossplane-contrib/terrajet/pkg/pipeline/templates"
)

// NewTerraformedGenerator returns a new TerraformedGenerator.
func NewTerraformedGenerator(groupDir, rootModulePath, group string) *TerraformedGenerator {
return &TerraformedGenerator{
GroupDir: groupDir,
RootModulePath: rootModulePath,
Group: group,
}
}

// TerraformedGenerator generates conversion methods implementing Terraformed
// interface on CRD structs.
type TerraformedGenerator struct {
GroupDir string
RootModulePath string
Group string
}

// Generate writes generated Terraformed interface functions
func (tg *TerraformedGenerator) Generate(version, kind, terraformResourceType, terraformIDField string) error {
vars := map[string]interface{}{
"CRD": map[string]string{
"APIVersion": version,
"Kind": kind,
},
"Terraform": map[string]string{
// TODO(hasan): This identifier is used to generate external name.
// However, external-name generation is not as straightforward as
// just finding out the identifier field since Terraform uses
// more complex logic like combining multiple fields etc.
// I'll revisit this with
// https://github.com/crossplane-contrib/terrajet/issues/11
"IdentifierField": terraformIDField,
"ResourceType": terraformResourceType,
},
}

pkgPath := filepath.Join(tg.RootModulePath, "apis", strings.ToLower(strings.Split(tg.Group, ".")[0]), strings.ToLower(version), strings.ToLower(kind))
trFile := wrapper.NewFile(pkgPath, version, templates.TerraformedTemplate,
wrapper.WithGenStatement(GenStatement),
wrapper.WithHeaderPath("hack/boilerplate.go.txt"), // todo
wrapper.LinterEnabled(),
)
filePath := filepath.Join(tg.GroupDir, strings.ToLower(version), strings.ToLower(kind), "zz_generated.terraformed.go")
return errors.Wrap(
trFile.Write(filePath, vars, os.ModePerm),
"cannot write terraformed conversion methods file",
)
}