Skip to content

Instantly share code, notes, and snippets.

@omarismail
Last active September 22, 2023 06:52
Show Gist options
  • Save omarismail/3ac59bb34aed5bfadb7ccdf729738000 to your computer and use it in GitHub Desktop.
Save omarismail/3ac59bb34aed5bfadb7ccdf729738000 to your computer and use it in GitHub Desktop.
provider-functions-features

As a Terraform User

See below for the Provider Author side.

Provider Functions Syntax

  • A function will accept any number of arguments, as defined by the provider function
  • A function will have a result and error/diagnostic handling
  • The function syntax will maintain the top level namespace to allow for future extensibility
  • Each provider will have its own namespace, that of the provider name.
  • The built-in functions will have their own namespace

Pure Functions

  • Functions will be treated as pure functions, and will not have any side effects
  • Functions will not have access to provider configuration
  • Functions results will always be consistent given the same input.

terraform validate

  • Functions are called whenever the config is evaluated.
  • Misconfigurations of functions will be detected during terraform validate

Usable in the Terraform Console

  • Functions can be used in terraform console

As a Provider Author

  • Defining a function will feel very similar to defining a resource or data source in the framework
  • There will be a schema and a way to define it, with the arguments and the result.

Here is sample code:

// Prototype example code. This design has not been finalized.
type ExampleFunction struct{}

func (f ExampleFunction) Metadata(ctx context.Context, req function.MetadataRequest, resp *function.MetadataResponse) {
	resp.Name = "iso8061"
}

func (f ExampleFunction) Definition(ctx context.Context, req function.DefinitionRequest, resp *function.DefinitionResponse) {
	resp.Arguments = []function.Argument{
		function.StringArgument{
			DisplayName: "rfc3339",
			Description: "RFC3339 timestamp to be converted",
		},
	}
	resp.Description = "Converts a RFC3339 timestamp string to ISO8601"
	resp.Result = function.StringResult{
		Description: "ISO8601 timestamp",
	}
}

func (f ExampleFunction) Run(ctx context.Context, req function.RunRequest, resp *function.RunResponse) {
	var arg types.String

	resp.Diagnostics.Append(req.Arguments.GetArgument(ctx, 0, &arg)...)

	if resp.Diagnostics.HasError() {
		return
	}

	if arg.IsNull() || arg.IsUnknown() {

	resp.Diagnostics.Append(resp.Result.Set(ctx, /* ... */)...)
}
@l-with
Copy link

l-with commented Sep 18, 2023

In many cases the go function is already implemented. In this case there could be a very generic approach using go reflection with the little assumption that the go function has the type
func (par1 type1, par2 type2, ...) (structType, error)
which for instance is the case for the arn function
func Parse(arn string) (ARN, error)
If not, a small wrapper function can be implemented.

If the field names are accepted as sufficient only the name for the function and descriptions for the input parameters need to be coded (just a sketch):

import (
	"github.com/aws/aws-sdk-go/aws/arn"
)

type providerFuncArgument struct {
	argName string
	argType reflect.Kind
}
type providerFunc struct {
	function  any
	name      string
	arguments []providerFuncArgument
}

var pf = providerFunc{
	function: arn.Parse,
	name:     "parse_arn",
	arguments: []providerFuncArgument{
		{
			argName: "arn",
			argType: reflect.String,
		},
	},
}

everything else can be coded by reflection in the framework.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment