Skip to content

Commit

Permalink
Add config.NewExternalNameFrom that makes the existing ExternalName c…
Browse files Browse the repository at this point in the history
…onfigurations

reusable via compositions.

- Format the doc comments for the config.TemplatedStringAsIdentifier function.

Signed-off-by: Alper Rifat Ulucinar <[email protected]>
  • Loading branch information
ulucinar committed Feb 13, 2024
1 parent a57975b commit 47cb5c5
Showing 1 changed file with 108 additions and 11 deletions.
119 changes: 108 additions & 11 deletions pkg/config/externalname.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,34 +70,38 @@ func ParameterAsIdentifier(param string) ExternalName {
// TemplatedStringAsIdentifier accepts a template as the shape of the Terraform
// ID and lets you provide a field path for the argument you're using as external
// name. The available variables you can use in the template are as follows:
// parameters: A tree of parameters that you'd normally see in a Terraform HCL
//
// file. You can use TF registry documentation of given resource to
// see what's available.
// parameters: A tree of parameters that you'd normally see in a Terraform HCL
// file. You can use TF registry documentation of given resource to
// see what's available.
//
// setup.configuration: The Terraform configuration object of the provider. You can
//
// take a look at the TF registry provider configuration object
// to see what's available. Not to be confused with ProviderConfig
// custom resource of the Crossplane provider.
// take a look at the TF registry provider configuration object
// to see what's available. Not to be confused with ProviderConfig
// custom resource of the Crossplane provider.
//
// setup.client_metadata: The Terraform client metadata available for the provider,
//
// such as the AWS account ID for the AWS provider.
// such as the AWS account ID for the AWS provider.
//
// external_name: The value of external name annotation of the custom resource.
//
// It is required to use this as part of the template.
// It is required to use this as part of the template.
//
// The following template functions are available:
//
// ToLower: Converts the contents of the pipeline to lower-case
//
// ToUpper: Converts the contents of the pipeline to upper-case
//
// Please note that it's currently *not* possible to use
// the template functions on the .external_name template variable.
// Example usages:
//
// TemplatedStringAsIdentifier("index_name", "/subscriptions/{{ .setup.configuration.subscription }}/{{ .external_name }}")
//
// TemplatedStringAsIdentifier("index_name", "/resource/{{ .external_name }}/static")
//
// TemplatedStringAsIdentifier("index_name", "{{ .parameters.cluster_id }}:{{ .parameters.node_id }}:{{ .external_name }}")
//
// TemplatedStringAsIdentifier("", "arn:aws:network-firewall:{{ .setup.configuration.region }}:{{ .setup.client_metadata.account_id }}:{{ .parameters.type | ToLower }}-rulegroup/{{ .external_name }}")
func TemplatedStringAsIdentifier(nameFieldPath, tmpl string) ExternalName {
t, err := template.New("getid").Funcs(template.FuncMap{
Expand Down Expand Up @@ -205,3 +209,96 @@ func GetExternalNameFromTemplated(tmpl, val string) (string, error) { //nolint:g
}
return "", errors.Errorf("unhandled case with template %s and value %s", tmpl, val)
}

// ExternalNameFrom is an ExternalName configuration which uses a parent
// configuration as its base and modifies any of the GetIDFn,
// GetExternalNameFn or SetIdentifierArgumentsFn. This enables us to reuse
// the existing ExternalName configurations with modifications in their
// behaviors via compositions.
type ExternalNameFrom struct {
ExternalName
getIDFn func(GetIDFn, context.Context, string, map[string]any, map[string]any) (string, error)
getExternalNameFn func(GetExternalNameFn, map[string]any) (string, error)
setIdentifierArgumentFn func(SetIdentifierArgumentsFn, map[string]any, string)
}

// ExternalNameFromOption is an option that modifies the behavior of an
// ExternalNameFrom external-name configuration.
type ExternalNameFromOption func(from *ExternalNameFrom)

// WithGetIDFn sets the GetIDFn for the ExternalNameFrom configuration.
// The function parameter fn receives the parent ExternalName's GetIDFn, and
// implementations may invoke the parent's GetIDFn via this
// parameter. For the description of the rest of the parameters and return
// values, please see the documentation of GetIDFn.
func WithGetIDFn(fn func(fn GetIDFn, ctx context.Context, externalName string, parameters map[string]any, terraformProviderConfig map[string]any) (string, error)) ExternalNameFromOption {
return func(ec *ExternalNameFrom) {
ec.getIDFn = fn
}
}

// WithGetExternalNameFn sets the GetExternalNameFn for the ExternalNameFrom
// configuration. The function parameter fn receives the parent ExternalName's
// GetExternalNameFn, and implementations may invoke the parent's
// GetExternalNameFn via this parameter. For the description of the rest
// of the parameters and return values, please see the documentation of
// GetExternalNameFn.
func WithGetExternalNameFn(fn func(fn GetExternalNameFn, tfstate map[string]any) (string, error)) ExternalNameFromOption {
return func(ec *ExternalNameFrom) {
ec.getExternalNameFn = fn
}
}

// WithSetIdentifierArgumentsFn sets the SetIdentifierArgumentsFn for the
// ExternalNameFrom configuration. The function parameter fn receives the
// parent ExternalName's SetIdentifierArgumentsFn, and implementations may
// invoke the parent's SetIdentifierArgumentsFn via this
// parameter. For the description of the rest of the parameters and return
// values, please see the documentation of SetIdentifierArgumentsFn.
func WithSetIdentifierArgumentsFn(fn func(fn SetIdentifierArgumentsFn, base map[string]any, externalName string)) ExternalNameFromOption {
return func(ec *ExternalNameFrom) {
ec.setIdentifierArgumentFn = fn
}
}

// NewExternalNameFrom initializes a new ExternalNameFrom with the given parent
// and with the given options. An example configuration that uses a
// TemplatedStringAsIdentifier as its parent (base) and sets a default value
// for the external-name if the external-name is yet not populated is as
// follows:
//
// config.NewExternalNameFrom(config.TemplatedStringAsIdentifier("", "{{ .parameters.type }}/{{ .setup.client_metadata.account_id }}/{{ .external_name }}"),
//
// config.WithGetIDFn(func(fn config.GetIDFn, ctx context.Context, externalName string, parameters map[string]any, terraformProviderConfig map[string]any) (string, error) {
// if externalName == "" {
// externalName = "some random string"
// }
// return fn(ctx, externalName, parameters, terraformProviderConfig)
// }))
func NewExternalNameFrom(parent ExternalName, opts ...ExternalNameFromOption) ExternalName {
ec := &ExternalNameFrom{}
for _, o := range opts {
o(ec)
}

ec.ExternalName.GetIDFn = func(ctx context.Context, externalName string, parameters map[string]any, terraformProviderConfig map[string]any) (string, error) {
if ec.getIDFn == nil {
return parent.GetIDFn(ctx, externalName, parameters, terraformProviderConfig)
}
return ec.getIDFn(parent.GetIDFn, ctx, externalName, parameters, terraformProviderConfig)
}
ec.ExternalName.GetExternalNameFn = func(tfstate map[string]any) (string, error) {
if ec.getExternalNameFn == nil {
return parent.GetExternalNameFn(tfstate)
}
return ec.getExternalNameFn(parent.GetExternalNameFn, tfstate)
}
ec.ExternalName.SetIdentifierArgumentFn = func(base map[string]any, externalName string) {
if ec.setIdentifierArgumentFn == nil {
parent.SetIdentifierArgumentFn(base, externalName)
return
}
ec.setIdentifierArgumentFn(parent.SetIdentifierArgumentFn, base, externalName)
}
return ec.ExternalName
}

0 comments on commit 47cb5c5

Please sign in to comment.