Documentation
¶
Index ¶
- Variables
- func Coalesce(args ...cty.Value) (cty.Value, error)
- func File(baseDir string, path cty.Value) (cty.Value, error)
- func FileBase64(baseDir string, path cty.Value) (cty.Value, error)
- func FileExists(baseDir string, path cty.Value) (cty.Value, error)
- func FileSet(baseDir string, path, pattern cty.Value) (cty.Value, error)
- func LogArgs(logger zerolog.Logger) function.Function
- func MakeFileBase64Sha256Func(baseDir string) function.Function
- func MakeFileBase64Sha512Func(baseDir string) function.Function
- func MakeFileExistsFunc(baseDir string) function.Function
- func MakeFileFunc(baseDir string, encBase64 bool) function.Function
- func MakeFileMd5Func(baseDir string) function.Function
- func MakeFileSetFunc(baseDir string) function.Function
- func MakeFileSha1Func(baseDir string) function.Function
- func MakeFileSha256Func(baseDir string) function.Function
- func MakeFileSha512Func(baseDir string) function.Function
- func MakeTemplateFileFunc(baseDir string, funcsCb func() map[string]function.Function) function.Function
- func MakeToFunc(wantTy cty.Type) function.Function
- func TimeAdd(timestamp cty.Value, duration cty.Value) (cty.Value, error)
- func Timestamp() (cty.Value, error)
Constants ¶
This section is empty.
Variables ¶
var CoalesceFunc = function.New(&function.Spec{ Params: []function.Parameter{}, VarParam: &function.Parameter{ Name: "vals", Type: cty.DynamicPseudoType, AllowUnknown: true, AllowDynamicType: true, AllowNull: true, }, Type: func(args []cty.Value) (ret cty.Type, err error) { argTypes := make([]cty.Type, len(args)) for i, val := range args { argTypes[i] = val.Type() } retType, _ := convert.UnifyUnsafe(argTypes) if retType == cty.NilType { return cty.NilType, errors.New("all arguments must have the same type") } return retType, nil }, Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { for _, argVal := range args { argVal, _ = convert.Convert(argVal, retType) if !argVal.IsKnown() { return cty.UnknownVal(retType), nil } if argVal.IsNull() { continue } if retType == cty.String && argVal.RawEquals(cty.StringVal("")) { continue } return argVal, nil } return cty.NilVal, errors.New("no non-null, non-empty-string arguments") }, })
CoalesceFunc constructs a function that takes any number of arguments and returns the first one that isn't empty. This function was copied from go-cty stdlib and modified so that it returns the first *non-empty* non-null element from a sequence, instead of merely the first non-null.
var FormatDateFunc = function.New(&function.Spec{ Description: stdlib.FormatDateFunc.Description(), Params: stdlib.FormatDateFunc.Params(), Type: function.StaticReturnType(cty.String), RefineResult: refineNonNull, Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { val, err := stdlib.FormatDateFunc.Call(args) var argsError function.ArgError if errors.As(err, &argsError) { if argsError.Index == 1 { args[1] = cty.StringVal(time.Now().UTC().Format(time.RFC3339)) val, err = stdlib.FormatDateFunc.Call(args) if err == nil { return val, nil } } } if err != nil { return cty.StringVal(time.Now().UTC().Format(time.RFC3339)), nil } return val, nil }, })
FormatDateFunc is a wrapper around the stdlib.FormatDateFunc function that returns the current date if the input date is invalid. This is useful in cases where the date is invalid because of mocking/incomplete data because C3X cannot infer the values from the IaC.
var JSONDecodeFunc = function.New(&function.Spec{ Description: `Parses the given string as JSON and returns a value corresponding to what the JSON document describes.`, Params: []function.Parameter{ { Name: "str", Type: cty.String, }, }, Type: func(args []cty.Value) (cty.Type, error) { str := args[0] if !str.IsKnown() { return cty.DynamicPseudoType, nil } val := str.AsString() if strings.HasSuffix(val, "-mock") || strings.Contains(val, mock.Identifier) { return cty.Object(map[string]cty.Type{ "foo": cty.String, }), nil } return json.ImpliedType([]byte(val)) }, Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { val := args[0].AsString() if strings.HasSuffix(val, "-mock") || strings.Contains(val, mock.Identifier) { return cty.ObjectVal(map[string]cty.Value{ "foo": cty.StringVal("bar"), }), nil } return json.Unmarshal([]byte(val), retType) }, })
JSONDecodeFunc is a C3X specific version of the json.JSONDecodeFunc which handles C3X mocked return values. If the argument passed to JSONDecodeFunc is a C3X mock (e.g. a string with value mock-value) then we return a mocked object that can be used in the HCL evaluation loop. This means we get less unwanted nil values when evaluating HCL files. This is especially important when evaluating Terragrunt HCL files as unexpected nils cause program termination.
var MergeFunc = function.New(&function.Spec{ Description: `Merges all of the elements from the given maps into a single map, or the attributes from given objects into a single object.`, Params: []function.Parameter{}, VarParam: &function.Parameter{ Name: "maps", Type: cty.DynamicPseudoType, AllowUnknown: true, AllowDynamicType: true, AllowNull: true, AllowMarked: true, }, Type: func(args []cty.Value) (cty.Type, error) { if len(args) == 0 { return cty.EmptyObject, nil } attrs := map[string]cty.Type{} first := cty.NilType matching := true attrsKnown := true for i, arg := range args { ty := arg.Type() arg, _ = arg.Unmark() switch { case ty.IsObjectType() && !arg.IsNull(): for attr, aty := range ty.AttributeTypes() { attrs[attr] = aty } case ty.IsMapType(): switch { case arg.IsNull(): case arg.IsKnown(): ety := arg.Type().ElementType() for it := arg.ElementIterator(); it.Next(); { attr, _ := it.Element() attrs[attr.AsString()] = ety } default: attrsKnown = false } } if i == 0 { first = arg.Type() continue } if !ty.Equals(first) && matching { matching = false } } if matching { return first, nil } if !attrsKnown { return cty.DynamicPseudoType, nil } return cty.Object(attrs), nil }, RefineResult: refineNonNull, Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { outputMap := make(map[string]cty.Value) var markses []cty.ValueMarks // remember any marked maps/objects we find for _, arg := range args { if arg.IsNull() || !arg.CanIterateElements() { continue } arg, argMarks := arg.Unmark() if len(argMarks) > 0 { markses = append(markses, argMarks) } for it := arg.ElementIterator(); it.Next(); { k, v := it.Element() outputMap[k.AsString()] = v } } switch { case retType.IsMapType(): if len(outputMap) == 0 { return cty.MapValEmpty(retType.ElementType()).WithMarks(markses...), nil } return cty.MapVal(outputMap).WithMarks(markses...), nil case retType.IsObjectType(), retType.Equals(cty.DynamicPseudoType): return cty.ObjectVal(outputMap).WithMarks(markses...), nil default: panic(fmt.Sprintf("unexpected return type: %#v", retType)) } }, })
MergeFunc is a C3X specific version of collection.MergeFunc which handles C3X mocked return values. If the argument contains a C3X mock string then we ignore it in the merge.
var MockTimestampFunc = function.New(&function.Spec{ Params: []function.Parameter{}, Type: function.StaticReturnType(cty.String), Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { return cty.StringVal(time.Date(2023, 3, 14, 15, 9, 29, 0, time.UTC).UTC().Format(time.RFC3339)), nil }, })
MockTimestampFunc constructs a function that returns a string representation of a static timestamp. We keep this as a static value so that it is deterministic when generating cost estimates.
var PrintArgs = function.New(&function.Spec{ Params: []function.Parameter{ { Name: "name", Type: cty.String, }, { Name: "v", Type: cty.DynamicPseudoType, AllowNull: true, AllowUnknown: true, AllowMarked: true, AllowDynamicType: true, }, }, Type: func(args []cty.Value) (cty.Type, error) { return args[1].Type(), nil }, Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { fmt.Printf("terraform print %q:%s\n", args[0].AsString(), string(valueToBytes(args[1]))) return args[1], nil }, })
PrintArgs prints any number of args to the std out using fmt. This can be used for debugging variables/inputs at points in the Terraform evaluation. Example usage:
c3xprint("test", 50)
will print:
"terraform print "test":cty.IntVal(50)
PrintArgs will return any args passed unaltered so that the args are still safe to use in the evaluation context. e.g:
locals {
test = c3xprint("a")
}
will still have `local.test` == "a" if used by other Terraform attributes/blocks. This allows debugging to unalter the Terraform evaluation and not cause unwanted consequences.
var TimeAddFunc = function.New(&function.Spec{ Params: []function.Parameter{ { Name: "timestamp", Type: cty.String, }, { Name: "duration", Type: cty.String, }, }, Type: function.StaticReturnType(cty.String), Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { ts, err := time.Parse(time.RFC3339, args[0].AsString()) if err != nil { return cty.UnknownVal(cty.String), err } duration, err := time.ParseDuration(args[1].AsString()) if err != nil { return cty.UnknownVal(cty.String), err } return cty.StringVal(ts.Add(duration).Format(time.RFC3339)), nil }, })
TimeAddFunc constructs a function that adds a duration to a timestamp, returning a new timestamp.
var YAMLDecodeFunc = function.New(&function.Spec{ Params: []function.Parameter{ { Name: "src", Type: cty.String, }, }, Type: func(args []cty.Value) (cty.Type, error) { if !args[0].IsKnown() { return cty.DynamicPseudoType, nil } if args[0].IsNull() { return cty.NilType, function.NewArgErrorf(0, "YAML source code cannot be null") } val := args[0].AsString() if strings.HasSuffix(val, "-mock") || strings.Contains(val, mock.Identifier) { return cty.Object(map[string]cty.Type{ "foo": cty.String, }), nil } return yaml.Standard.ImpliedType([]byte(val)) }, Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { val := args[0].AsString() if strings.HasSuffix(val, "-mock") || strings.Contains(val, mock.Identifier) { return cty.ObjectVal(map[string]cty.Value{ "foo": cty.StringVal("bar"), }), nil } return yaml.Standard.Unmarshal([]byte(val), retType) }, })
YAMLDecodeFunc is a C3X specific version of the yaml.YAMLDecodeFunc which handles C3X mocked return values. If the argument passed to YAMLDecodeFunc is a C3X mock (e.g. a string with value mock-value) then we return a mocked object that can be used in the HCL evaluation loop. This means we get less unwanted nil values when evaluating HCL files. This is especially important when evaluating Terragrunt HCL files as unexpected nils cause program termination.
Functions ¶
func File ¶
File reads the contents of the file at the given path.
The file must contain valid UTF-8 bytes, or this function will return an error.
The underlying function implementation works relative to a particular base directory, so this wrapper takes a base directory string and uses it to construct the underlying function before calling it.
func FileBase64 ¶
FileBase64 reads the contents of the file at the given path.
The bytes from the file are encoded as base64 before returning.
The underlying function implementation works relative to a particular base directory, so this wrapper takes a base directory string and uses it to construct the underlying function before calling it.
func FileExists ¶
FileExists determines whether a file exists at the given path.
The underlying function implementation works relative to a particular base directory, so this wrapper takes a base directory string and uses it to construct the underlying function before calling it.
func FileSet ¶
FileSet enumerates a set of files given a glob pattern
The underlying function implementation works relative to a particular base directory, so this wrapper takes a base directory string and uses it to construct the underlying function before calling it.
func LogArgs ¶
LogArgs is identical to PrintArgs but writes the arguments to the C3X log. This is useful to understand arguments as they change in the module evaluation. As the arguments will be printed next to log entries that correspond to the program runtime. e.g:
root_block_device {
volume_size = c3xlog("test", "foo")
}
will log:
time="2022-12-06T10:27:40Z" level=debug enable_cloud_org=false ... attribute_name=volume_size provider=terraform_dir block_name=root_block_device. sync_usage=false msg="fetching attribute value" time="2022-12-06T10:27:40Z" level=debug ... msg="terraform print "test":cty.StringVal(\"foo\")"
func MakeFileBase64Sha256Func ¶
MakeFileBase64Sha256Func constructs a function that is like Base64Sha256Func but reads the contents of a file rather than hashing a given literal string.
func MakeFileBase64Sha512Func ¶
MakeFileBase64Sha512Func constructs a function that is like Base64Sha512Func but reads the contents of a file rather than hashing a given literal string.
func MakeFileExistsFunc ¶
MakeFileExistsFunc constructs a function that takes a path and determines whether a file exists at that path
func MakeFileMd5Func ¶
MakeFileMd5Func constructs a function that is like Md5Func but reads the contents of a file rather than hashing a given literal string.
func MakeFileSetFunc ¶
MakeFileSetFunc constructs a function that takes a glob pattern and enumerates a file set from that pattern
func MakeFileSha1Func ¶
MakeFileSha1Func constructs a function that is like Sha1Func but reads the contents of a file rather than hashing a given literal string.
func MakeFileSha256Func ¶
MakeFileSha256Func constructs a function that is like Sha256Func but reads the contents of a file rather than hashing a given literal string.
func MakeFileSha512Func ¶
MakeFileSha512Func constructs a function that is like Sha512Func but reads the contents of a file rather than hashing a given literal string.
func MakeTemplateFileFunc ¶
func MakeTemplateFileFunc(baseDir string, funcsCb func() map[string]function.Function) function.Function
MakeTemplateFileFunc constructs a function that takes a file path and an arbitrary object of named values and attempts to render the referenced file as a template using HCL template syntax.
The template itself may recursively call other functions so a callback must be provided to get access to those functions. The template cannot, however, access any variables defined in the scope: it is restricted only to those variables provided in the second function argument, to ensure that all dependencies on other graph nodes can be seen before executing this function.
As a special exception, a referenced template file may not recursively call the templatefile function, since that would risk the same file being included into itself indefinitely.
func MakeToFunc ¶
Adapted from https://github.com/zclconf/go-cty/blob/ea922e7a95ba2be57897697117f318670e066d22/cty/function/stdlib/conversion.go to handle C3X mock values.
MakeToFunc constructs a "to..." function, like "tostring", which converts its argument to a specific type or type kind.
The given type wantTy can be any type constraint that cty's "convert" package would accept. In particular, this means that you can pass cty.List(cty.DynamicPseudoType) to mean "list of any single type", which will then cause cty to attempt to unify all of the element types when given a tuple.
func TimeAdd ¶
TimeAdd adds a duration to a timestamp, returning a new timestamp.
In the Terraform language, timestamps are conventionally represented as strings using RFC 3339 "Date and Time format" syntax. Timeadd requires the timestamp argument to be a string conforming to this syntax.
`duration` is a string representation of a time difference, consisting of sequences of number and unit pairs, like `"1.5h"` or `1h30m`. The accepted units are `ns`, `us` (or `µs`), `"ms"`, `"s"`, `"m"`, and `"h"`. The first number may be negative to indicate a negative duration, like `"-2h5m"`.
The result is a string, also in RFC 3339 format, representing the result of adding the given direction to the given timestamp.
Types ¶
This section is empty.