diff --git a/pkg/config/resource.go b/pkg/config/resource.go index 528d7f78..025fbb01 100644 --- a/pkg/config/resource.go +++ b/pkg/config/resource.go @@ -18,13 +18,18 @@ package config import ( "context" + "fmt" + "strings" "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/util/json" "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/crossplane/crossplane-runtime/pkg/fieldpath" "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" + xpresource "github.com/crossplane/crossplane-runtime/pkg/resource" ) // SetIdentifierArgumentsFn sets the name of the resource in Terraform attributes map, @@ -198,8 +203,62 @@ type OperationTimeouts struct { Delete time.Duration } -// InitializerFn returns the Initializer with a client. -type InitializerFn func(client client.Client) managed.Initializer +// NewInitializerFn returns the Initializer with a client. +type NewInitializerFn func(client client.Client) managed.Initializer + +// TagInitializer returns a tagger to use default tag initializer. +var TagInitializer NewInitializerFn = func(client client.Client) managed.Initializer { + return NewTagger(client, "tags") +} + +// Tagger implements the Initialize function to set external tags +type Tagger struct { + kube client.Client + fieldName string +} + +// NewTagger returns a Tagger object. +func NewTagger(kube client.Client, fieldName string) *Tagger { + return &Tagger{kube: kube, fieldName: fieldName} +} + +// Initialize is a custom initializer for setting external tags +func (t *Tagger) Initialize(ctx context.Context, mg xpresource.Managed) error { + kind := strings.ToLower(mg.GetObjectKind().GroupVersionKind().GroupKind().String()) + name := mg.GetName() + providerConfig := "" + mg.GetProviderConfigReference() + switch { + case mg.GetProviderConfigReference() != nil && mg.GetProviderConfigReference().Name != "": + providerConfig = mg.GetProviderConfigReference().Name + case mg.GetProviderReference() != nil && mg.GetProviderReference().Name != "": + providerConfig = mg.GetProviderReference().Name + } + tags := map[string]*string{ + "crossplane-kind": &kind, + "crossplane-name": &name, + "crossplane-providerconfig": &providerConfig, + } + + paved, err := fieldpath.PaveObject(mg) + if err != nil { + return err + } + if err := paved.SetValue(fmt.Sprintf("spec.forProvider.%s", t.fieldName), tags); err != nil { + return err + } + pavedByte, err := paved.MarshalJSON() + if err != nil { + return err + } + if err := json.Unmarshal(pavedByte, mg); err != nil { + return err + } + if err := t.kube.Update(ctx, mg); err != nil { + return err + } + return nil +} // Resource is the set of information that you can override at different steps // of the code generation pipeline. @@ -229,7 +288,7 @@ type Resource struct { // databases. UseAsync bool - Initializers []InitializerFn + InitializerFns []NewInitializerFn // OperationTimeouts allows configuring resource operation timeouts. OperationTimeouts OperationTimeouts diff --git a/pkg/pipeline/controller.go b/pkg/pipeline/controller.go index 26338bb4..0fada37c 100644 --- a/pkg/pipeline/controller.go +++ b/pkg/pipeline/controller.go @@ -63,7 +63,7 @@ func (cg *ControllerGenerator) Generate(cfg *config.Resource, typesPkgPath strin "TypePackageAlias": ctrlFile.Imports.UsePackage(typesPkgPath), "UseAsync": cfg.UseAsync, "ResourceType": cfg.Name, - "Initializers": cfg.Initializers, + "Initializers": cfg.InitializerFns, } filePath := filepath.Join(cg.ControllerGroupDir, strings.ToLower(cfg.Kind), "zz_controller.go") diff --git a/pkg/pipeline/templates/controller.go.tmpl b/pkg/pipeline/templates/controller.go.tmpl index 5ae44ac1..76fec306 100644 --- a/pkg/pipeline/templates/controller.go.tmpl +++ b/pkg/pipeline/templates/controller.go.tmpl @@ -26,12 +26,15 @@ import ( // Setup adds a controller that reconciles {{ .CRD.Kind }} managed resources. func Setup(mgr ctrl.Manager, l logging.Logger, rl workqueue.RateLimiter, s terraform.SetupFn, ws *terraform.WorkspaceStore, cfg *tjconfig.Provider, concurrency int) error { name := managed.ControllerName({{ .TypePackageAlias }}{{ .CRD.Kind }}_GroupVersionKind.String()) - {{- if .Initializers }} var initializers managed.InitializerChain - for _, i := range cfg.Resources["{{ .ResourceType }}"].Initializers { + {{- if .Initializers }} + for _, i := range cfg.Resources["{{ .ResourceType }}"].InitializerFns { initializers = append(initializers,i(mgr.GetClient())) - } - {{- end}} + } + {{- end}} + {{- if not .DisableNameInitializer }} + initializers = append(initializers, managed.NewNameAsExternalName(mgr.GetClient())) + {{- end}} r := managed.NewReconciler(mgr, xpresource.ManagedKind({{ .TypePackageAlias }}{{ .CRD.Kind }}_GroupVersionKind), managed.WithExternalConnecter(tjcontroller.NewConnector(mgr.GetClient(), ws, s, cfg.Resources["{{ .ResourceType }}"], @@ -43,13 +46,7 @@ func Setup(mgr ctrl.Manager, l logging.Logger, rl workqueue.RateLimiter, s terra managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))), managed.WithFinalizer(terraform.NewWorkspaceFinalizer(ws, xpresource.NewAPIFinalizer(mgr.GetClient(), managed.FinalizerName))), managed.WithTimeout(3*time.Minute), - {{- if .Initializers }} managed.WithInitializers(initializers), - {{else}} - {{- if .DisableNameInitializer }} - managed.WithInitializers(), - {{- end}} - {{- end}} ) return ctrl.NewControllerManagedBy(mgr).