functions

package
v1.19.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 29, 2026 License: Apache-2.0 Imports: 38 Imported by: 0

Documentation

Overview

* Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. * * This product includes software developed at Datadog (https://www.datadoghq.com) Copyright 2024 Datadog, Inc.

* Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. * * This product includes software developed at Datadog (https://www.datadoghq.com) Copyright 2024 Datadog, Inc.

* Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. * * This product includes software developed at Datadog (https://www.datadoghq.com) Copyright 2024 Datadog, Inc.

* Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. * * This product includes software developed at Datadog (https://www.datadoghq.com) Copyright 2024 Datadog, Inc.

* Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. * * This product includes software developed at Datadog (https://www.datadoghq.com) Copyright 2024 Datadog, Inc.

* Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. * * This product includes software developed at Datadog (https://www.datadoghq.com) Copyright 2024 Datadog, Inc.

* Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. * * This product includes software developed at Datadog (https://www.datadoghq.com) Copyright 2024 Datadog, Inc.

* Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. * * This product includes software developed at Datadog (https://www.datadoghq.com) Copyright 2024 Datadog, Inc.

* Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. * * This product includes software developed at Datadog (https://www.datadoghq.com) Copyright 2024 Datadog, Inc.

* Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. * * This product includes software developed at Datadog (https://www.datadoghq.com) Copyright 2024 Datadog, Inc.

* Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. * * This product includes software developed at Datadog (https://www.datadoghq.com) Copyright 2024 Datadog, Inc.

* Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. * * This product includes software developed at Datadog (https://www.datadoghq.com) Copyright 2024 Datadog, Inc.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ToSetFunc - https://developer.hashicorp.com/terraform/language/functions/toset
	ToSetFunc = collectionConvertFunc(collectionKindSet)
	// ToListFunc - https://developer.hashicorp.com/terraform/language/functions/tolist
	ToListFunc = collectionConvertFunc(collectionKindList)
	// ToMapFunc - https://developer.hashicorp.com/terraform/language/functions/tomap
	ToMapFunc = collectionConvertFunc(collectionKindMap)
)
View Source
var (
	Md5Func          = hashHexFunc(md5.New)
	Sha1Func         = hashHexFunc(sha1.New)
	Sha256Func       = hashHexFunc(sha256.New)
	Sha512Func       = hashHexFunc(sha512.New)
	Base64Sha256Func = hashBase64Func(sha256.New)
	Base64Sha512Func = hashBase64Func(sha512.New)
)
View Source
var AbsPathFunc = function.New(&function.Spec{
	Params: []function.Parameter{{Name: "path", Type: cty.String}},
	Type:   function.StaticReturnType(cty.String),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		abs, err := filepath.Abs(args[0].AsString())
		if err != nil {
			return cty.NilVal, err
		}
		return cty.StringVal(filepath.ToSlash(abs)), nil
	},
})
View Source
var AllTrueFunc = function.New(&function.Spec{
	Params: []function.Parameter{{
		Name: "list",
		Type: cty.List(cty.Bool),
	}},
	Type: function.StaticReturnType(cty.Bool),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		hasUnknown := false
		for it := args[0].ElementIterator(); it.Next(); {
			_, v := it.Element()
			if !v.IsKnown() {
				hasUnknown = true
				continue
			}
			if v.IsNull() || v.False() {
				return cty.False, nil
			}
		}
		if hasUnknown {
			return cty.UnknownVal(cty.Bool), nil
		}
		return cty.True, nil
	},
})
View Source
var AnyTrueFunc = function.New(&function.Spec{
	Params: []function.Parameter{{
		Name: "list",
		Type: cty.List(cty.Bool),
	}},
	Type: function.StaticReturnType(cty.Bool),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		result := cty.False
		hasUnknown := false
		for it := args[0].ElementIterator(); it.Next(); {
			_, v := it.Element()
			if !v.IsKnown() {
				hasUnknown = true
				continue
			}
			if v.IsNull() {
				continue
			}
			result = result.Or(v)
			if result.True() {
				return cty.True, nil
			}
		}
		if hasUnknown {
			return cty.UnknownVal(cty.Bool), nil
		}
		return result, nil
	},
})
View Source
var Base64DecodeFunc = function.New(&function.Spec{
	Params: []function.Parameter{{
		Name: "str",
		Type: cty.String,
	}},
	Type: function.StaticReturnType(cty.String),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		s := args[0].AsString()
		decoded, err := base64.StdEncoding.DecodeString(s)
		if err != nil {
			decoded, err = base64.RawStdEncoding.DecodeString(s)
			if err != nil {
				return cty.NilVal, function.NewArgErrorf(0, "invalid base64: %s", err)
			}
		}
		if !utf8.Valid(decoded) {
			return cty.NilVal, function.NewArgErrorf(0, "the result of decoding the provided string is not valid UTF-8")
		}
		return cty.StringVal(string(decoded)), nil
	},
})
View Source
var Base64EncodeFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{
			Name:             "val",
			Type:             cty.DynamicPseudoType,
			AllowDynamicType: true,
			AllowNull:        true,
		},
	},
	Type: function.StaticReturnType(cty.String),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		val := args[0]
		if !val.IsWhollyKnown() {

			return cty.UnknownVal(retType), nil
		}

		if val.IsNull() {
			return cty.StringVal("null"), nil
		}

		encoded := base64.StdEncoding.EncodeToString([]byte(val.AsString()))

		return cty.StringVal(encoded), nil
	},
})

Base64EncodeFunc - https://www.terraform.io/docs/language/functions/base64encode.html

View Source
var Base64GzipFunc = function.New(&function.Spec{
	Params: []function.Parameter{{Name: "str", Type: cty.String}},
	Type:   function.StaticReturnType(cty.String),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		var buf bytes.Buffer
		gz := gzip.NewWriter(&buf)
		gz.ModTime = time.Unix(0, 0)
		if _, err := gz.Write([]byte(args[0].AsString())); err != nil {
			return cty.NilVal, err
		}
		if err := gz.Flush(); err != nil {
			return cty.NilVal, err
		}
		if err := gz.Close(); err != nil {
			return cty.NilVal, err
		}
		return cty.StringVal(base64.StdEncoding.EncodeToString(buf.Bytes())), nil
	},
})
View Source
var BasenameFunc = function.New(&function.Spec{
	Params: []function.Parameter{{Name: "path", Type: cty.String}},
	Type:   function.StaticReturnType(cty.String),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		return cty.StringVal(filepath.Base(args[0].AsString())), nil
	},
})
View Source
var CidrHostFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{Name: "prefix", Type: cty.String},
		{Name: "hostnum", Type: cty.Number},
	},
	Type: function.StaticReturnType(cty.String),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		prefix, err := parsePrefix(args[0].AsString())
		if err != nil {
			return cty.NilVal, err
		}
		var hostNum big.Int
		if err := gocty.FromCtyValue(args[1], &hostNum); err != nil {
			return cty.NilVal, function.NewArgError(1, err)
		}
		addr, err := cidrHost(prefix, &hostNum)
		if err != nil {
			return cty.NilVal, err
		}
		return cty.StringVal(addr.String()), nil
	},
})
View Source
var CidrNetmaskFunc = function.New(&function.Spec{
	Params: []function.Parameter{{
		Name: "prefix",
		Type: cty.String,
	}},
	Type: function.StaticReturnType(cty.String),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		prefix, err := parsePrefix(args[0].AsString())
		if err != nil {
			return cty.NilVal, err
		}
		if !prefix.Addr().Is4() {
			return cty.NilVal, function.NewArgErrorf(0, "cidrnetmask only supports IPv4")
		}
		mask := net.CIDRMask(prefix.Bits(), prefix.Addr().BitLen())
		return cty.StringVal(net.IP(mask).String()), nil
	},
})
View Source
var CidrSubnetFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{Name: "prefix", Type: cty.String},
		{Name: "newbits", Type: cty.Number},
		{Name: "netnum", Type: cty.Number},
	},
	Type: function.StaticReturnType(cty.String),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		prefix, err := parsePrefix(args[0].AsString())
		if err != nil {
			return cty.NilVal, err
		}
		var newbits int
		var netnum big.Int
		if err := gocty.FromCtyValue(args[1], &newbits); err != nil {
			return cty.NilVal, function.NewArgError(1, err)
		}
		if err := gocty.FromCtyValue(args[2], &netnum); err != nil {
			return cty.NilVal, function.NewArgError(2, err)
		}
		out, err := cidrSubnet(prefix, newbits, &netnum)
		if err != nil {
			return cty.NilVal, err
		}
		return cty.StringVal(out.String()), nil
	},
})
View Source
var CidrSubnetsFunc = function.New(&function.Spec{
	Params: []function.Parameter{{
		Name: "prefix",
		Type: cty.String,
	}},
	VarParam: &function.Parameter{
		Name: "newbits",
		Type: cty.Number,
	},
	Type: function.StaticReturnType(cty.List(cty.String)),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		prefix, err := parsePrefix(args[0].AsString())
		if err != nil {
			return cty.NilVal, err
		}
		if len(args) == 1 {
			return cty.ListValEmpty(cty.String), nil
		}
		newbits := make([]int, len(args)-1)
		for i, arg := range args[1:] {
			if err := gocty.FromCtyValue(arg, &newbits[i]); err != nil {
				return cty.NilVal, function.NewArgError(i+1, err)
			}
		}
		subs, err := cidrSubnets(prefix, newbits)
		if err != nil {
			return cty.NilVal, err
		}
		vals := make([]cty.Value, len(subs))
		for i, sub := range subs {
			vals[i] = cty.StringVal(sub)
		}
		return cty.ListVal(vals), nil
	},
})
View Source
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) (cty.Type, error) {
		argTypes := make([]cty.Type, len(args))
		for i, val := range args {
			argTypes[i] = val.Type()
		}
		retType, _ := ctyconvert.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) (cty.Value, error) {
		for _, argVal := range args {
			converted, err := ctyconvert.Convert(argVal, retType)
			if err != nil {
				return cty.NilVal, err
			}
			if !converted.IsKnown() {
				return cty.UnknownVal(retType), nil
			}
			if converted.IsNull() {
				continue
			}
			if retType == cty.String && converted.RawEquals(cty.StringVal("")) {
				continue
			}
			return converted, nil
		}
		return cty.NilVal, errors.New("no non-null, non-empty-string arguments")
	},
})

CoalesceFunc matches Terraform: first non-null, non-empty-string argument.

View Source
var DirnameFunc = function.New(&function.Spec{
	Params: []function.Parameter{{Name: "path", Type: cty.String}},
	Type:   function.StaticReturnType(cty.String),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		return cty.StringVal(filepath.Dir(args[0].AsString())), nil
	},
})
View Source
var EndsWithFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{Name: "str", Type: cty.String},
		{Name: "suffix", Type: cty.String},
	},
	Type: function.StaticReturnType(cty.Bool),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		return cty.BoolVal(strings.HasSuffix(args[0].AsString(), args[1].AsString())), nil
	},
})
View Source
var IndexFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{Name: "list", Type: cty.DynamicPseudoType},
		{Name: "value", Type: cty.DynamicPseudoType},
	},
	Type: function.StaticReturnType(cty.Number),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		list := args[0]
		if !list.Type().IsListType() && !list.Type().IsTupleType() {
			return cty.NilVal, errors.New("argument must be a list or tuple")
		}
		if !list.IsKnown() {
			return cty.UnknownVal(cty.Number), nil
		}
		if list.LengthInt() == 0 {
			return cty.NilVal, errors.New("cannot search an empty list")
		}
		for it := list.ElementIterator(); it.Next(); {
			i, v := it.Element()
			eq, err := stdlib.Equal(v, args[1])
			if err != nil {
				return cty.NilVal, err
			}
			if !eq.IsKnown() {
				return cty.UnknownVal(cty.Number), nil
			}
			if eq.True() {
				return i, nil
			}
		}
		return cty.NilVal, errors.New("item not found")
	},
})

IndexFunc matches Terraform: first index of value in a list or tuple.

View Source
var LengthFunc = function.New(&function.Spec{
	Params: []function.Parameter{{
		Name:             "value",
		Type:             cty.DynamicPseudoType,
		AllowDynamicType: true,
		AllowUnknown:     true,
		AllowMarked:      true,
	}},
	Type: function.StaticReturnType(cty.Number),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		val := args[0]
		ty := val.Type()
		switch {
		case ty == cty.String:
			return stdlib.Strlen(val)
		case ty.IsObjectType():
			if !val.IsKnown() {
				return cty.UnknownVal(cty.Number), nil
			}
			return cty.NumberIntVal(int64(len(ty.AttributeTypes()))), nil
		default:
			return stdlib.Length(val)
		}
	},
})

LengthFunc matches Terraform: strings, collections, and objects.

View Source
var LookupFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{
			Name:         "inputMap",
			Type:         cty.DynamicPseudoType,
			AllowMarked:  true,
			AllowUnknown: true,
		},
		{
			Name:         "key",
			Type:         cty.String,
			AllowMarked:  true,
			AllowUnknown: true,
		},
	},
	VarParam: &function.Parameter{
		Name:             "default",
		Type:             cty.DynamicPseudoType,
		AllowUnknown:     true,
		AllowDynamicType: true,
		AllowNull:        true,
		AllowMarked:      true,
	},
	Type: func(args []cty.Value) (cty.Type, error) {
		if len(args) > 3 {
			return cty.NilType, fmt.Errorf("lookup() takes two or three arguments, got %d", len(args))
		}
		ty := args[0].Type()
		switch {
		case ty.IsObjectType():
			if !args[1].IsKnown() {
				return cty.DynamicPseudoType, nil
			}
			keyVal, _ := args[1].Unmark()
			key := keyVal.AsString()
			if ty.HasAttribute(key) {
				return args[0].GetAttr(key).Type(), nil
			}
			if len(args) == 3 {
				return args[2].Type(), nil
			}
			return cty.DynamicPseudoType, function.NewArgErrorf(0, "the given object has no attribute %q", key)
		case ty.IsMapType():
			if len(args) == 3 {
				if _, err := ctyconvert.Convert(args[2], ty.ElementType()); err != nil {
					return cty.NilType, function.NewArgErrorf(2, "the default value must have the same type as the map elements")
				}
			}
			return ty.ElementType(), nil
		default:
			return cty.NilType, function.NewArgErrorf(0, "lookup() requires a map as the first argument")
		}
	},
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		mapVar, mapMarks := args[0].Unmark()
		keyVal, keyMarks := args[1].Unmark()

		if !mapVar.IsKnown() || !keyVal.IsKnown() {
			return cty.UnknownVal(retType).WithMarks(mapMarks, keyMarks), nil
		}

		lookupKey := keyVal.AsString()
		found := cty.NilVal
		switch {
		case mapVar.Type().IsObjectType() && mapVar.Type().HasAttribute(lookupKey):
			found = mapVar.GetAttr(lookupKey)
		case mapVar.Type().IsMapType() && mapVar.HasIndex(cty.StringVal(lookupKey)) == cty.True:
			found = mapVar.Index(cty.StringVal(lookupKey))
		}
		if found != cty.NilVal {
			return found.WithMarks(mapMarks, keyMarks), nil
		}
		if len(args) == 3 {
			defaultVal, err := ctyconvert.Convert(args[2], retType)
			if err != nil {
				return cty.NilVal, err
			}
			return defaultVal.WithMarks(mapMarks, keyMarks), nil
		}
		return cty.NilVal, fmt.Errorf("lookup failed to find key %s", lookupKey)
	},
})

LookupFunc matches Terraform: optional default, maps and objects.

View Source
var MatchkeysFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{Name: "values", Type: cty.List(cty.DynamicPseudoType)},
		{Name: "keys", Type: cty.List(cty.DynamicPseudoType)},
		{Name: "searchset", Type: cty.List(cty.DynamicPseudoType)},
	},
	Type: func(args []cty.Value) (cty.Type, error) {
		if ty, _ := ctyconvert.UnifyUnsafe([]cty.Type{args[1].Type(), args[2].Type()}); ty == cty.NilType {
			return cty.NilType, errors.New("keys and searchset must be of the same type")
		}
		return args[0].Type(), nil
	},
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		values, keys, searchset := args[0], args[1], args[2]
		if !values.IsKnown() || !keys.IsKnown() || !searchset.IsKnown() {
			return cty.UnknownVal(retType), nil
		}
		if values.LengthInt() != keys.LengthInt() {
			return cty.NilVal, errors.New("length of keys and values should be equal")
		}
		if searchset.LengthInt() == 0 {
			return cty.ListValEmpty(retType.ElementType()), nil
		}
		if !values.IsWhollyKnown() || !keys.IsWhollyKnown() {
			return cty.UnknownVal(retType), nil
		}
		var out []cty.Value
		i := 0
		for it := keys.ElementIterator(); it.Next(); {
			_, key := it.Element()
			for sit := searchset.ElementIterator(); sit.Next(); {
				_, search := sit.Element()
				eq, err := stdlib.Equal(key, search)
				if err != nil {
					return cty.NilVal, err
				}
				if !eq.IsKnown() {
					return cty.UnknownVal(retType), nil
				}
				if eq.True() {
					out = append(out, values.Index(cty.NumberIntVal(int64(i))))
					break
				}
			}
			i++
		}
		if len(out) == 0 {
			return cty.ListValEmpty(retType.ElementType()), nil
		}
		return cty.ListVal(out), nil
	},
})
View Source
var OneFunc = function.New(&function.Spec{
	Params: []function.Parameter{{
		Name: "list",
		Type: cty.DynamicPseudoType,
	}},
	Type: func(args []cty.Value) (cty.Type, error) {
		ty := args[0].Type()
		switch {
		case ty.IsListType(), ty.IsSetType():
			return ty.ElementType(), nil
		case ty.IsTupleType():
			etys := ty.TupleElementTypes()
			switch len(etys) {
			case 0:
				return cty.DynamicPseudoType, nil
			case 1:
				return etys[0], nil
			}
		}
		return cty.NilType, function.NewArgErrorf(0, "must be a list, set, or tuple value with either zero or one elements")
	},
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		val := args[0]
		if !val.IsKnown() {
			return cty.UnknownVal(retType), nil
		}
		length := val.Length()
		if !length.IsKnown() {
			return cty.UnknownVal(retType), nil
		}
		var n int
		if err := gocty.FromCtyValue(length, &n); err != nil {
			return cty.NilVal, err
		}
		switch n {
		case 0:
			return cty.NullVal(retType), nil
		case 1:
			for it := val.ElementIterator(); it.Next(); {
				_, elem := it.Element()
				return elem, nil
			}
		}
		return cty.NilVal, function.NewArgErrorf(0, "must be a list, set, or tuple value with either zero or one elements")
	},
})
View Source
var PathExpandFunc = function.New(&function.Spec{
	Params: []function.Parameter{{Name: "path", Type: cty.String}},
	Type:   function.StaticReturnType(cty.String),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		p := args[0].AsString()
		if p == "~" || strings.HasPrefix(p, "~/") || strings.HasPrefix(p, `~\`) {
			home, err := os.UserHomeDir()
			if err != nil {
				return cty.NilVal, err
			}
			if p == "~" {
				return cty.StringVal(home), nil
			}
			return cty.StringVal(filepath.Join(home, p[2:])), nil
		}
		return cty.StringVal(p), nil
	},
})
View Source
var ReplaceFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{Name: "str", Type: cty.String},
		{Name: "substr", Type: cty.String},
		{Name: "replace", Type: cty.String},
	},
	Type: function.StaticReturnType(cty.String),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		substr := args[1].AsString()
		if len(substr) > 1 && strings.HasPrefix(substr, "/") && strings.HasSuffix(substr, "/") {
			pattern := cty.StringVal(substr[1 : len(substr)-1])
			return stdlib.RegexReplace(args[0], pattern, args[2])
		}
		return stdlib.Replace(args[0], args[1], args[2])
	},
})

ReplaceFunc matches Terraform: /pattern/ is a regular expression.

View Source
var StartsWithFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{Name: "str", Type: cty.String},
		{Name: "prefix", Type: cty.String},
	},
	Type: function.StaticReturnType(cty.Bool),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		return cty.BoolVal(strings.HasPrefix(args[0].AsString(), args[1].AsString())), nil
	},
})
View Source
var StrContainsFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{Name: "str", Type: cty.String},
		{Name: "substr", Type: cty.String},
	},
	Type: function.StaticReturnType(cty.Bool),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		return cty.BoolVal(strings.Contains(args[0].AsString(), args[1].AsString())), nil
	},
})
View Source
var SumFunc = function.New(&function.Spec{
	Params: []function.Parameter{{
		Name: "list",
		Type: cty.DynamicPseudoType,
	}},
	Type: function.StaticReturnType(cty.Number),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		list := args[0]
		ty := list.Type()
		if !ty.IsListType() && !ty.IsSetType() && !ty.IsTupleType() {
			return cty.NilVal, function.NewArgErrorf(0, "argument must be list, set, or tuple")
		}
		if !list.IsWhollyKnown() {
			return cty.UnknownVal(cty.Number), nil
		}
		if list.LengthInt() == 0 {
			return cty.NilVal, function.NewArgErrorf(0, "cannot sum an empty list")
		}
		elems := list.AsValueSlice()
		total, err := ctyconvert.Convert(elems[0], cty.Number)
		if err != nil || total.IsNull() {
			return cty.NilVal, function.NewArgErrorf(0, "argument must be list, set, or tuple of number values")
		}
		for _, elem := range elems[1:] {
			n, convErr := ctyconvert.Convert(elem, cty.Number)
			if convErr != nil || n.IsNull() {
				return cty.NilVal, function.NewArgErrorf(0, "argument must be list, set, or tuple of number values")
			}
			total = total.Add(n)
		}
		return total, nil
	},
})
View Source
var TerraformFuncs = func() map[string]function.Function {
	funcs := map[string]function.Function{
		"abs":              stdlib.AbsoluteFunc,
		"abspath":          AbsPathFunc,
		"alltrue":          AllTrueFunc,
		"anytrue":          AnyTrueFunc,
		"base64decode":     Base64DecodeFunc,
		"base64encode":     Base64EncodeFunc,
		"base64gzip":       Base64GzipFunc,
		"base64sha256":     Base64Sha256Func,
		"base64sha512":     Base64Sha512Func,
		"basename":         BasenameFunc,
		"can":              tryfunc.CanFunc,
		"cidrhost":         CidrHostFunc,
		"cidrnetmask":      CidrNetmaskFunc,
		"cidrsubnet":       CidrSubnetFunc,
		"cidrsubnets":      CidrSubnetsFunc,
		"ceil":             stdlib.CeilFunc,
		"chomp":            stdlib.ChompFunc,
		"coalesce":         CoalesceFunc,
		"coalescelist":     stdlib.CoalesceListFunc,
		"compact":          stdlib.CompactFunc,
		"concat":           stdlib.ConcatFunc,
		"contains":         stdlib.ContainsFunc,
		"csvdecode":        stdlib.CSVDecodeFunc,
		"dirname":          DirnameFunc,
		"distinct":         stdlib.DistinctFunc,
		"endswith":         EndsWithFunc,
		"element":          stdlib.ElementFunc,
		"chunklist":        stdlib.ChunklistFunc,
		"flatten":          stdlib.FlattenFunc,
		"floor":            stdlib.FloorFunc,
		"format":           stdlib.FormatFunc,
		"formatdate":       stdlib.FormatDateFunc,
		"formatlist":       stdlib.FormatListFunc,
		"indent":           stdlib.IndentFunc,
		"index":            IndexFunc,
		"join":             stdlib.JoinFunc,
		"jsondecode":       stdlib.JSONDecodeFunc,
		"jsonencode":       stdlib.JSONEncodeFunc,
		"keys":             stdlib.KeysFunc,
		"length":           LengthFunc,
		"log":              stdlib.LogFunc,
		"lookup":           LookupFunc,
		"lower":            stdlib.LowerFunc,
		"matchkeys":        MatchkeysFunc,
		"max":              stdlib.MaxFunc,
		"md5":              Md5Func,
		"merge":            stdlib.MergeFunc,
		"min":              stdlib.MinFunc,
		"one":              OneFunc,
		"parseint":         stdlib.ParseIntFunc,
		"pathexpand":       PathExpandFunc,
		"pow":              stdlib.PowFunc,
		"range":            stdlib.RangeFunc,
		"regex":            stdlib.RegexFunc,
		"regexall":         stdlib.RegexAllFunc,
		"replace":          ReplaceFunc,
		"reverse":          stdlib.ReverseListFunc,
		"setintersection":  stdlib.SetIntersectionFunc,
		"setproduct":       stdlib.SetProductFunc,
		"setsubtract":      stdlib.SetSubtractFunc,
		"setunion":         stdlib.SetUnionFunc,
		"sha1":             Sha1Func,
		"sha256":           Sha256Func,
		"sha512":           Sha512Func,
		"signum":           stdlib.SignumFunc,
		"slice":            stdlib.SliceFunc,
		"sort":             stdlib.SortFunc,
		"split":            stdlib.SplitFunc,
		"startswith":       StartsWithFunc,
		"strcontains":      StrContainsFunc,
		"strrev":           stdlib.ReverseFunc,
		"substr":           stdlib.SubstrFunc,
		"sum":              SumFunc,
		"textdecodebase64": TextDecodeBase64Func,
		"textencodebase64": TextEncodeBase64Func,
		"timeadd":          stdlib.TimeAddFunc,
		"timecmp":          TimeCmpFunc,
		"title":            stdlib.TitleFunc,
		"tobool":           stdlib.MakeToFunc(cty.Bool),
		"tolist":           ToListFunc,
		"tomap":            ToMapFunc,
		"tonumber":         stdlib.MakeToFunc(cty.Number),
		"toset":            ToSetFunc,
		"tostring":         stdlib.MakeToFunc(cty.String),
		"transpose":        TransposeFunc,
		"trim":             stdlib.TrimFunc,
		"trimprefix":       stdlib.TrimPrefixFunc,
		"trimspace":        stdlib.TrimSpaceFunc,
		"trimsuffix":       stdlib.TrimSuffixFunc,
		"try":              tryfunc.TryFunc,
		"upper":            stdlib.UpperFunc,
		"urlencode":        URLEncodeFunc,
		"uuidv5":           UUIDV5Func,
		"values":           stdlib.ValuesFunc,
		"yamldecode":       ctyyaml.YAMLDecodeFunc,
		"yamlencode":       ctyyaml.YAMLEncodeFunc,
		"zipmap":           stdlib.ZipmapFunc,
	}
	funcs["templatestring"] = makeTemplateStringFunc(func() map[string]function.Function {
		return funcs
	})
	return funcs
}()

TerraformFuncs contains all functions, overriding any conflicting built-ins it should create a file in this package and add/change this function key here

View Source
var TextDecodeBase64Func = function.New(&function.Spec{
	Params: []function.Parameter{
		{Name: "source", Type: cty.String},
		{Name: "encoding", Type: cty.String},
	},
	Type: function.StaticReturnType(cty.String),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		enc, err := ianaindex.IANA.Encoding(args[1].AsString())
		if err != nil || enc == nil {
			return cty.NilVal, function.NewArgErrorf(1, "%q is not a supported IANA encoding name", args[1].AsString())
		}
		raw, err := base64.StdEncoding.DecodeString(args[0].AsString())
		if err != nil {
			return cty.NilVal, function.NewArgErrorf(0, "invalid base64: %s", err)
		}
		decoded, err := enc.NewDecoder().Bytes(raw)
		if err != nil {
			return cty.NilVal, function.NewArgErrorf(0, "the given string contains symbols that are not defined for %s", args[1].AsString())
		}
		return cty.StringVal(string(decoded)), nil
	},
})
View Source
var TextEncodeBase64Func = function.New(&function.Spec{
	Params: []function.Parameter{
		{Name: "string", Type: cty.String},
		{Name: "encoding", Type: cty.String},
	},
	Type: function.StaticReturnType(cty.String),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		enc, err := ianaindex.IANA.Encoding(args[1].AsString())
		if err != nil || enc == nil {
			return cty.NilVal, function.NewArgErrorf(1, "%q is not a supported IANA encoding name", args[1].AsString())
		}
		encoded, err := enc.NewEncoder().Bytes([]byte(args[0].AsString()))
		if err != nil {
			return cty.NilVal, function.NewArgErrorf(0, "the given string cannot be represented in %s", args[1].AsString())
		}
		return cty.StringVal(base64.StdEncoding.EncodeToString(encoded)), nil
	},
})
View Source
var TimeCmpFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{Name: "timestamp_a", Type: cty.String},
		{Name: "timestamp_b", Type: cty.String},
	},
	Type: function.StaticReturnType(cty.Number),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		a, err := time.Parse(time.RFC3339, args[0].AsString())
		if err != nil {
			return cty.NilVal, function.NewArgErrorf(0, "not a valid RFC3339 timestamp: %s", args[0].AsString())
		}
		b, err := time.Parse(time.RFC3339, args[1].AsString())
		if err != nil {
			return cty.NilVal, function.NewArgErrorf(1, "not a valid RFC3339 timestamp: %s", args[1].AsString())
		}
		switch {
		case a.Equal(b):
			return cty.NumberIntVal(0), nil
		case a.Before(b):
			return cty.NumberIntVal(-1), nil
		default:
			return cty.NumberIntVal(1), nil
		}
	},
})
View Source
var TransposeFunc = function.New(&function.Spec{
	Params: []function.Parameter{{
		Name: "values",
		Type: cty.Map(cty.List(cty.String)),
	}},
	Type: function.StaticReturnType(cty.Map(cty.List(cty.String))),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		input := args[0]
		if !input.IsWhollyKnown() {
			return cty.UnknownVal(retType), nil
		}
		tmp := make(map[string][]string)
		for it := input.ElementIterator(); it.Next(); {
			inKey, inVal := it.Element()
			if inVal.IsNull() {
				return cty.NilVal, errors.New("input must not contain null list")
			}
			for vit := inVal.ElementIterator(); vit.Next(); {
				_, val := vit.Element()
				if val.IsNull() {
					return cty.NilVal, errors.New("input list must not contain null string")
				}
				outKey := val.AsString()
				tmp[outKey] = append(tmp[outKey], inKey.AsString())
			}
		}
		if len(tmp) == 0 {
			return cty.MapValEmpty(cty.List(cty.String)), nil
		}
		out := make(map[string]cty.Value, len(tmp))
		for k, vs := range tmp {
			sort.Strings(vs)
			elems := make([]cty.Value, len(vs))
			for i, v := range vs {
				elems[i] = cty.StringVal(v)
			}
			out[k] = cty.ListVal(elems)
		}
		return cty.MapVal(out), nil
	},
})
View Source
var URLEncodeFunc = function.New(&function.Spec{
	Params: []function.Parameter{{
		Name: "str",
		Type: cty.String,
	}},
	Type: function.StaticReturnType(cty.String),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		return cty.StringVal(url.QueryEscape(args[0].AsString())), nil
	},
})
View Source
var UUIDV5Func = function.New(&function.Spec{
	Params: []function.Parameter{
		{Name: "namespace", Type: cty.String},
		{Name: "name", Type: cty.String},
	},
	Type: function.StaticReturnType(cty.String),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		ns, err := uuidNamespace(args[0].AsString())
		if err != nil {
			return cty.NilVal, function.NewArgError(0, err)
		}
		return cty.StringVal(uuid.NewSHA1(ns, []byte(args[1].AsString())).String()), nil
	},
})

Functions

func ContextVariables added in v1.15.0

func ContextVariables(moduleDir, rootDir string) map[string]cty.Value

func EvalFuncs added in v1.15.0

func EvalFuncs(baseDir string, fsys vfs.FS) map[string]function.Function

EvalFuncs returns TerraformFuncs plus filesystem functions rooted at baseDir. When fsys is nil and baseDir is empty the static map is returned unchanged.

func EvalFuncsWithRoot added in v1.15.0

func EvalFuncsWithRoot(baseDir, rootDir string, fsys vfs.FS) map[string]function.Function

func MakeAbsPathFunc added in v1.15.0

func MakeAbsPathFunc(baseDir string) function.Function

Types

type ScanFS added in v1.19.0

type ScanFS struct {
	vfs.FS
	// contains filtered or unexported fields
}

ScanFS serves the filesystem functions of one scan. The files a scan reads do not change under it, so each path's symlinks are resolved once instead of on every call that confines a path to its module.

func NewScanFS added in v1.19.0

func NewScanFS(fsys vfs.FS) *ScanFS
func (s *ScanFS) EvalSymlinks(path string) (string, error)

EvalSymlinks is filepath.EvalSymlinks, remembered for the life of the scan.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL