diff --git a/config/interpolate_funcs.go b/config/interpolate_funcs.go index d36bc65ea..87bfa99df 100644 --- a/config/interpolate_funcs.go +++ b/config/interpolate_funcs.go @@ -17,6 +17,7 @@ import ( "strings" "github.com/apparentlymart/go-cidr/cidr" + "github.com/hashicorp/go-uuid" "github.com/hashicorp/hil/ast" "github.com/mitchellh/go-homedir" ) @@ -42,6 +43,7 @@ func Funcs() map[string]ast.Function { "length": interpolationFuncLength(), "lower": interpolationFuncLower(), "md5": interpolationFuncMd5(), + "uuid": interpolationFuncUUID(), "replace": interpolationFuncReplace(), "sha1": interpolationFuncSha1(), "sha256": interpolationFuncSha256(), @@ -682,3 +684,13 @@ func interpolationFuncBase64Sha256() ast.Function { }, } } + +func interpolationFuncUUID() ast.Function { + return ast.Function{ + ArgTypes: []ast.Type{}, + ReturnType: ast.TypeString, + Callback: func(args []interface{}) (interface{}, error) { + return uuid.GenerateUUID() + }, + } +} diff --git a/config/interpolate_funcs_test.go b/config/interpolate_funcs_test.go index 2a2981b76..93fe16665 100644 --- a/config/interpolate_funcs_test.go +++ b/config/interpolate_funcs_test.go @@ -945,6 +945,28 @@ func TestInterpolateFuncMd5(t *testing.T) { }) } +func TestInterpolateFuncUUID(t *testing.T) { + results := make(map[string]bool) + + for i := 0; i < 100; i++ { + ast, err := hil.Parse("${uuid()}") + if err != nil { + t.Fatalf("err: %s", err) + } + + out, _, err := hil.Eval(ast, langEvalConfig(nil)) + if err != nil { + t.Fatalf("err: %s", err) + } + + if results[out.(string)] { + t.Fatalf("Got unexpected duplicate uuid: %s", out) + } + + results[out.(string)] = true + } +} + type testFunctionConfig struct { Cases []testFunctionCase Vars map[string]ast.Variable diff --git a/website/source/docs/configuration/interpolation.html.md b/website/source/docs/configuration/interpolation.html.md index 2f6dacde1..c1be98548 100644 --- a/website/source/docs/configuration/interpolation.html.md +++ b/website/source/docs/configuration/interpolation.html.md @@ -198,6 +198,8 @@ The supported built-in functions are: * `upper(string)` - Returns a copy of the string with all Unicode letters mapped to their upper case. + * `uuid()` - Returns a UUID string in RFC 4122 v4 format. This string will change with every invocation of the function, so in order to prevent diffs on every plan & apply, it must be used with the [`ignore_changes`](/docs/configuration/resources.html#ignore-changes) lifecycle attribute. + ## Templates Long strings can be managed using templates. [Templates](/docs/providers/template/index.html) are [resources](/docs/configuration/resources.html) defined by a filename and some variables to use during interpolation. They have a computed `rendered` attribute containing the result. diff --git a/website/source/docs/configuration/resources.html.md b/website/source/docs/configuration/resources.html.md index 11fb9a9c5..07cde03a6 100644 --- a/website/source/docs/configuration/resources.html.md +++ b/website/source/docs/configuration/resources.html.md @@ -68,6 +68,8 @@ The `lifecycle` block allows the following keys to be set: destruction of a given resource. When this is set to `true`, any plan that includes a destroy of this resource will return an error message. + + * `ignore_changes` (list of strings) - Customizes how diffs are evaluated for resources, allowing individual attributes to be ignored through changes. As an example, this can be used to ignore dynamic changes to the