hclfuncs

package module
v0.8.0 Latest Latest
Warning

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

Go to latest
Published: May 17, 2024 License: MPL-2.0 Imports: 34 Imported by: 2

README

HCL Funcs

This library is a facade that combines all built-in functions provided by HashiCorp Packer and some functions from HashiCorp Terraform.

All copied functions are copied from Terraform and Packer's latest MPL 2.0 license version, all referenced functions are based on MPL 2.0 or MIT license.

Goroutine-local env function

env function is different than the Packer version, we provided a goroutine-local cache so the caller can set different environment variables for different goroutines, this is very handy when you allow users to set different environment variables for a specified HCL block, like this example. Please check out this unit test for details.

Documentation

Overview

Copy from https://github.com/opentofu/opentofu/blob/v1.7.1/internal/lang/funcs/datetime.go

Copy from https://github.com/opentofu/opentofu/blob/v1.7.1/internal/lang/funcs/sensitive.go

Index

Constants

This section is empty.

Variables

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) (ret cty.Value, err error) {
		result := cty.True
		for it := args[0].ElementIterator(); it.Next(); {
			_, v := it.Element()
			if !v.IsKnown() {
				return cty.UnknownVal(cty.Bool), nil
			}
			if v.IsNull() {
				return cty.False, nil
			}
			result = result.And(v)
			if result.False() {
				return cty.False, nil
			}
		}
		return result, nil
	},
})

AllTrueFunc constructs a function that returns true if all elements of the list are true. If the list is empty, return true.

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) (ret cty.Value, err error) {
		result := cty.False
		var hasUnknown bool
		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
	},
})

AnyTrueFunc constructs a function that returns true if any element of the list is true. If the list is empty, return false.

View Source
var CidrContainsFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{
			Name: "containing_prefix",
			Type: cty.String,
		},
		{
			Name: "contained_ip_or_prefix",
			Type: cty.String,
		},
	},
	Type: function.StaticReturnType(cty.Bool),
	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
		prefix := args[0].AsString()
		addr := args[1].AsString()

		_, containing, err := ipaddr.ParseCIDR(prefix)
		if err != nil {
			return cty.UnknownVal(cty.Bool), err
		}

		startIP := ipaddr.ParseIP(addr)
		var endIP ipaddr.IP

		if startIP == nil {
			_, contained, err := ipaddr.ParseCIDR(addr)

			if err != nil {
				return cty.UnknownVal(cty.Bool), fmt.Errorf("invalid IP address or prefix: %s", addr)
			}

			startIP, endIP = cidr.AddressRange(contained)
		}

		if (startIP.To4() == nil) != (containing.IP.To4() == nil) {
			return cty.UnknownVal(cty.Bool), fmt.Errorf("address family mismatch: %s vs. %s", prefix, addr)
		}

		result := containing.Contains(startIP)

		if endIP != nil {
			result = result && containing.Contains(endIP)
		}

		return cty.BoolVal(result), nil
	},
})

CidrContainsFunc constructs a function that checks whether a given IP address is within a given IP network address prefix.

View Source
var ComplimentFunction = function.New(&function.Spec{
	Description: "Return the compliment of list1 and all otherLists.",
	Params: []function.Parameter{
		{
			Name:             "list1",
			Description:      "the first list, will return all elements that in this list but not in any of other lists.",
			Type:             cty.Set(cty.DynamicPseudoType),
			AllowDynamicType: true,
		},
	},
	VarParam: &function.Parameter{
		Name:             "otherList",
		Description:      "other_list",
		Type:             cty.Set(cty.DynamicPseudoType),
		AllowDynamicType: true,
	},
	Type:         setOperationReturnType,
	RefineResult: refineNonNull,
	Impl: setOperationImpl(func(s1, s2 cty.ValueSet) cty.ValueSet {
		return s1.Subtract(s2)
	}, false),
})
View Source
var ConsulFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{
			Name: "key",
			Type: cty.String,
		},
	},
	Type: function.StaticReturnType(cty.String),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		key := args[0].AsString()
		val, err := commontpl.Consul(key)

		return cty.StringVal(val), err
	},
})

ConsulFunc constructs a function that retrieves KV secrets from HC vault

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),
	RefineResult: refineNotNull,
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		str := args[0].AsString()
		suffix := args[1].AsString()

		if strings.HasSuffix(str, suffix) {
			return cty.True, nil
		}

		return cty.False, nil
	},
})

EndsWithFunc constructs a function that checks if a string ends with a specific suffix using strings.HasSuffix Copy from https://github.com/opentofu/opentofu/blob/v1.7.1/internal/lang/funcs/string.go

View Source
var EnvFunction = function.New(&function.Spec{
	Description: "Read environment variable, return empty string if the variable is not set.",
	Params: []function.Parameter{
		{
			Name:         "key",
			Description:  "Environment variable name",
			Type:         cty.String,
			AllowUnknown: true,
			AllowMarked:  true,
		},
	},
	Type: function.StaticReturnType(cty.String),
	RefineResult: func(builder *cty.RefinementBuilder) *cty.RefinementBuilder {
		return builder.NotNull()
	},
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		key := args[0]
		if !key.IsKnown() {
			return cty.UnknownVal(cty.String), nil
		}
		envKey := key.AsString()
		localEnv := GoroutineLocalEnv.Get()
		if localEnv != nil {
			if env, ok := localEnv[envKey]; ok {
				return cty.StringVal(env), nil
			}
		}
		env := os.Getenv(envKey)
		return cty.StringVal(env), nil
	},
})
View Source
var GoroutineLocalEnv = routine.NewThreadLocal[map[string]string]()
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) (ret cty.Value, err error) {
		if !(args[0].Type().IsListType() || args[0].Type().IsTupleType()) {
			return cty.NilVal, errors.New("argument must be a list or tuple")
		}

		if !args[0].IsKnown() {
			return cty.UnknownVal(cty.Number), nil
		}

		if args[0].LengthInt() == 0 {
			return cty.NilVal, errors.New("cannot search an empty list")
		}

		for it := args[0].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 constructs a function that finds the element index for a given value in a list.

View Source
var InitTime time.Time

InitTime is the UTC time when this package was initialized. It is used as the timestamp for all configuration templates so that they match for a single build.

View Source
var IsSensitiveFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{
			Name:             "value",
			Type:             cty.DynamicPseudoType,
			AllowUnknown:     true,
			AllowNull:        true,
			AllowMarked:      true,
			AllowDynamicType: true,
		},
	},
	Type: func(args []cty.Value) (cty.Type, error) {
		return cty.Bool, nil
	},
	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
		return cty.BoolVal(args[0].HasMark(marks.Sensitive)), nil
	},
})

IsSensitiveFunc returns whether or not the value is sensitive.

View Source
var LegacyIsotimeFunc = function.New(&function.Spec{
	Params: []function.Parameter{},
	VarParam: &function.Parameter{
		Name: "format",
		Type: cty.String,
	},
	Type: function.StaticReturnType(cty.String),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		if len(args) > 1 {
			return cty.StringVal(""), fmt.Errorf("too many values, 1 needed: %v", args)
		} else if len(args) == 0 {
			return cty.StringVal(InitTime.Format(time.RFC3339)), nil
		}
		format := args[0].AsString()
		return cty.StringVal(InitTime.Format(format)), nil
	},
})

LegacyIsotimeFunc constructs a function that returns a string representation of the current date and time using golang's datetime formatting.

View Source
var LegacyStrftimeFunc = function.New(&function.Spec{
	Params: []function.Parameter{},
	VarParam: &function.Parameter{
		Name: "format",
		Type: cty.String,
	},
	Type: function.StaticReturnType(cty.String),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		if len(args) > 1 {
			return cty.StringVal(""), fmt.Errorf("too many values, 1 needed: %v", args)
		} else if len(args) == 0 {
			return cty.StringVal(InitTime.Format(time.RFC3339)), nil
		}
		format := args[0].AsString()
		return cty.StringVal(strftime.Format(format, InitTime)), nil
	},
})

LegacyStrftimeFunc constructs a function that returns a string representation of the current date and time using golang's strftime datetime formatting.

View Source
var LengthFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{
			Name:             "value",
			Type:             cty.DynamicPseudoType,
			AllowDynamicType: true,
			AllowUnknown:     true,
		},
	},
	Type: func(args []cty.Value) (cty.Type, error) {
		collTy := args[0].Type()
		switch {
		case collTy == cty.String || collTy.IsTupleType() || collTy.IsObjectType() || collTy.IsListType() || collTy.IsMapType() || collTy.IsSetType() || collTy == cty.DynamicPseudoType:
			return cty.Number, nil
		default:
			return cty.Number, errors.New("argument must be a string, a collection type, or a structural type")
		}
	},
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		coll := args[0]
		collTy := args[0].Type()
		switch {
		case collTy == cty.DynamicPseudoType:
			return cty.UnknownVal(cty.Number), nil
		case collTy.IsTupleType():
			l := len(collTy.TupleElementTypes())
			return cty.NumberIntVal(int64(l)), nil
		case collTy.IsObjectType():
			l := len(collTy.AttributeTypes())
			return cty.NumberIntVal(int64(l)), nil
		case collTy == cty.String:

			return stdlib.Strlen(coll)
		case collTy.IsListType() || collTy.IsSetType() || collTy.IsMapType():
			return coll.Length(), nil
		default:

			return cty.UnknownVal(cty.Number), errors.New("impossible value type for length(...)")
		}
	},
})
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) {
		ty, _ := convert.UnifyUnsafe([]cty.Type{args[1].Type(), args[2].Type()})
		if ty == cty.NilType {
			return cty.NilType, errors.New("keys and searchset must be of the same type")
		}

		return args[0].Type(), nil
	},
	RefineResult: refineNotNull,
	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
		if !args[0].IsKnown() {
			return cty.UnknownVal(cty.List(retType.ElementType())), nil
		}

		if args[0].LengthInt() != args[1].LengthInt() {
			return cty.ListValEmpty(retType.ElementType()), errors.New("length of keys and values should be equal")
		}

		output := make([]cty.Value, 0)
		values := args[0]

		ty, _ := convert.UnifyUnsafe([]cty.Type{args[1].Type(), args[2].Type()})
		keys, _ := convert.Convert(args[1], ty)
		searchset, _ := convert.Convert(args[2], ty)

		if searchset.LengthInt() == 0 {
			return cty.ListValEmpty(retType.ElementType()), nil
		}

		if !values.IsWhollyKnown() || !keys.IsWhollyKnown() {
			return cty.UnknownVal(retType), nil
		}

		i := 0
		for it := keys.ElementIterator(); it.Next(); {
			_, key := it.Element()
			for iter := searchset.ElementIterator(); iter.Next(); {
				_, search := iter.Element()
				eq, err := stdlib.Equal(key, search)
				if err != nil {
					return cty.NilVal, err
				}
				if !eq.IsKnown() {
					return cty.ListValEmpty(retType.ElementType()), nil
				}
				if eq.True() {
					v := values.Index(cty.NumberIntVal(int64(i)))
					output = append(output, v)
					break
				}
			}
			i++
		}

		if len(output) == 0 {
			return cty.ListValEmpty(retType.ElementType()), nil
		}
		return cty.ListVal(output), nil
	},
})

MatchkeysFunc constructs a function that constructs a new list by taking a subset of elements from one list whose indexes match the corresponding indexes of values in another list. Copy from https://github.com/opentofu/opentofu/blob/v1.7.1/internal/lang/funcs/collection.go

View Source
var NonsensitiveFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{
			Name:             "value",
			Type:             cty.DynamicPseudoType,
			AllowUnknown:     true,
			AllowNull:        true,
			AllowMarked:      true,
			AllowDynamicType: true,
		},
	},
	Type: func(args []cty.Value) (cty.Type, error) {

		return args[0].Type(), nil
	},
	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
		v, m := args[0].Unmark()
		delete(m, marks.Sensitive)
		return v.WithMarks(m), nil
	},
})

NonsensitiveFunc takes a sensitive value and returns the same value without the sensitive marking, effectively exposing the value.

View Source
var SensitiveFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{
			Name:             "value",
			Type:             cty.DynamicPseudoType,
			AllowUnknown:     true,
			AllowNull:        true,
			AllowMarked:      true,
			AllowDynamicType: true,
		},
	},
	Type: func(args []cty.Value) (cty.Type, error) {

		return args[0].Type(), nil
	},
	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
		val, _ := args[0].Unmark()
		return val.Mark(marks.Sensitive), nil
	},
})

SensitiveFunc returns a value identical to its argument except that OpenTofu will consider it to be sensitive.

View Source
var StartsWithFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{
			Name:         "str",
			Type:         cty.String,
			AllowUnknown: true,
		},
		{
			Name: "prefix",
			Type: cty.String,
		},
	},
	Type:         function.StaticReturnType(cty.Bool),
	RefineResult: refineNotNull,
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		prefix := args[1].AsString()

		if !args[0].IsKnown() {

			if prefix == "" {

				return cty.True, nil
			}
			if knownPrefix := args[0].Range().StringPrefix(); knownPrefix != "" {
				if strings.HasPrefix(knownPrefix, prefix) {
					return cty.True, nil
				}
				if len(knownPrefix) >= len(prefix) {

					return cty.False, nil
				}
			}
			return cty.UnknownVal(cty.Bool), nil
		}

		str := args[0].AsString()

		if strings.HasPrefix(str, prefix) {
			return cty.True, nil
		}

		return cty.False, nil
	},
})

StartsWithFunc constructs a function that checks if a string starts with a specific prefix using strings.HasPrefix Copy from https://github.com/opentofu/opentofu/blob/v1.7.1/internal/lang/funcs/string.go

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) (ret cty.Value, err error) {
		str := args[0].AsString()
		substr := args[1].AsString()

		if strings.Contains(str, substr) {
			return cty.True, nil
		}

		return cty.False, nil
	},
})

StrContainsFunc searches a given string for another given substring, if found the function returns true, otherwise returns false. Copy from https://github.com/opentofu/opentofu/blob/v1.7.1/internal/lang/funcs/string.go

View Source
var SumFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{
			Name: "list",
			Type: cty.DynamicPseudoType,
		},
	},
	Type:         function.StaticReturnType(cty.Number),
	RefineResult: refineNotNull,
	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {

		if !args[0].CanIterateElements() {
			return cty.NilVal, function.NewArgErrorf(0, "cannot sum noniterable")
		}

		if args[0].LengthInt() == 0 {
			return cty.NilVal, function.NewArgErrorf(0, "cannot sum an empty list")
		}

		arg := args[0].AsValueSlice()
		ty := args[0].Type()

		if !ty.IsListType() && !ty.IsSetType() && !ty.IsTupleType() {
			return cty.NilVal, function.NewArgErrorf(0, fmt.Sprintf("argument must be list, set, or tuple. Received %s", ty.FriendlyName()))
		}

		if !args[0].IsWhollyKnown() {
			return cty.UnknownVal(cty.Number), nil
		}

		defer func() {
			if r := recover(); r != nil {
				if _, ok := r.(big.ErrNaN); ok {
					ret = cty.NilVal
					err = fmt.Errorf("can't compute sum of opposing infinities")
				} else {

					panic(r)
				}
			}
		}()

		s := arg[0]
		if s.IsNull() {
			return cty.NilVal, function.NewArgErrorf(0, "argument must be list, set, or tuple of number values")
		}
		s, err = convert.Convert(s, cty.Number)
		if err != nil {
			return cty.NilVal, function.NewArgErrorf(0, "argument must be list, set, or tuple of number values")
		}
		for _, v := range arg[1:] {
			if v.IsNull() {
				return cty.NilVal, function.NewArgErrorf(0, "argument must be list, set, or tuple of number values")
			}
			v, err = convert.Convert(v, cty.Number)
			if err != nil {
				return cty.NilVal, function.NewArgErrorf(0, "argument must be list, set, or tuple of number values")
			}
			s = s.Add(v)
		}

		return s, nil
	},
})

SumFunc constructs a function that returns the sum of all numbers provided in a list Copy from https://github.com/opentofu/opentofu/blob/v1.7.1/internal/lang/funcs/collection.go

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),
	RefineResult: refineNotNull,
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		encoding, err := ianaindex.IANA.Encoding(args[1].AsString())
		if err != nil || encoding == nil {
			return cty.UnknownVal(cty.String), function.NewArgErrorf(1, "%q is not a supported IANA encoding name or alias in this OpenTofu version", args[1].AsString())
		}

		encName, err := ianaindex.IANA.Name(encoding)
		if err != nil {
			encName = args[1].AsString()
		}

		s := args[0].AsString()
		sDec, err := base64.StdEncoding.DecodeString(s)
		if err != nil {
			switch err := err.(type) {
			case base64.CorruptInputError:
				return cty.UnknownVal(cty.String), function.NewArgErrorf(0, "the given value is has an invalid base64 symbol at offset %d", int(err))
			default:
				return cty.UnknownVal(cty.String), function.NewArgErrorf(0, "invalid source string: %w", err)
			}

		}

		decoder := encoding.NewDecoder()
		decoded, err := decoder.Bytes(sDec)
		if err != nil || bytes.ContainsRune(decoded, '�') {
			return cty.UnknownVal(cty.String), function.NewArgErrorf(0, "the given string contains symbols that are not defined for %s", encName)
		}

		return cty.StringVal(string(decoded)), nil
	},
})

TextDecodeBase64Func constructs a function that decodes a base64 sequence to a target encoding. Copy from https://github.com/opentofu/opentofu/blob/v1.7.1/internal/lang/funcs/encoding.go

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),
	RefineResult: refineNotNull,
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		encoding, err := ianaindex.IANA.Encoding(args[1].AsString())
		if err != nil || encoding == nil {
			return cty.UnknownVal(cty.String), function.NewArgErrorf(1, "%q is not a supported IANA encoding name or alias in this OpenTofu version", args[1].AsString())
		}

		encName, err := ianaindex.IANA.Name(encoding)
		if err != nil {
			encName = args[1].AsString()
		}

		encoder := encoding.NewEncoder()
		encodedInput, err := encoder.Bytes([]byte(args[0].AsString()))
		if err != nil {

			return cty.UnknownVal(cty.String), function.NewArgErrorf(0, "the given string contains characters that cannot be represented in %s", encName)
		}

		return cty.StringVal(base64.StdEncoding.EncodeToString(encodedInput)), nil
	},
})

TextEncodeBase64Func constructs a function that encodes a string to a target encoding and then to a base64 sequence. Copy from https://github.com/opentofu/opentofu/blob/v1.7.1/internal/lang/funcs/encoding.go

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),
	RefineResult: refineNotNull,
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		tsA, err := parseTimestamp(args[0].AsString())
		if err != nil {
			return cty.UnknownVal(cty.String), function.NewArgError(0, err)
		}
		tsB, err := parseTimestamp(args[1].AsString())
		if err != nil {
			return cty.UnknownVal(cty.String), function.NewArgError(1, err)
		}

		switch {
		case tsA.Equal(tsB):
			return cty.NumberIntVal(0), nil
		case tsA.Before(tsB):
			return cty.NumberIntVal(-1), nil
		default:

			return cty.NumberIntVal(1), nil
		}
	},
})

TimeCmpFunc is a function that compares two timestamps.

View Source
var TimestampFunc = 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.Now().UTC().Format(time.RFC3339)), nil
	},
})

TimestampFunc constructs a function that returns a string representation of the current date and time.

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))),
	RefineResult: refineNotNull,
	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
		inputMap := args[0]
		if !inputMap.IsWhollyKnown() {
			return cty.UnknownVal(retType), nil
		}

		outputMap := make(map[string]cty.Value)
		tmpMap := make(map[string][]string)

		for it := inputMap.ElementIterator(); it.Next(); {
			inKey, inVal := it.Element()
			for iter := inVal.ElementIterator(); iter.Next(); {
				_, val := iter.Element()
				if !val.Type().Equals(cty.String) {
					return cty.MapValEmpty(cty.List(cty.String)), errors.New("input must be a map of lists of strings")
				}

				outKey := val.AsString()
				if _, ok := tmpMap[outKey]; !ok {
					tmpMap[outKey] = make([]string, 0)
				}
				outVal := tmpMap[outKey]
				outVal = append(outVal, inKey.AsString())
				sort.Strings(outVal)
				tmpMap[outKey] = outVal
			}
		}

		for outKey, outVal := range tmpMap {
			values := make([]cty.Value, 0)
			for _, v := range outVal {
				values = append(values, cty.StringVal(v))
			}
			outputMap[outKey] = cty.ListVal(values)
		}

		if len(outputMap) == 0 {
			return cty.MapValEmpty(cty.List(cty.String)), nil
		}

		return cty.MapVal(outputMap), nil
	},
})

TransposeFunc constructs a function that takes a map of lists of strings and swaps the keys and values to produce a new map of lists of strings. Copy from https://github.com/opentofu/opentofu/blob/v1.7.1/internal/lang/funcs/collection.go

View Source
var TypeFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{
			Name:             "value",
			Type:             cty.DynamicPseudoType,
			AllowDynamicType: true,
			AllowUnknown:     true,
			AllowNull:        true,
		},
	},
	Type: function.StaticReturnType(TypeType),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		givenType := args[0].Type()
		return cty.CapsuleVal(TypeType, &givenType).Mark(TypeType), nil
	},
})

TypeFunc returns an encapsulated value containing its argument's type. This value is marked to allow us to limit the use of this function at the moment to only a few supported use cases.

View Source
var TypeType = cty.Capsule("type", reflect.TypeOf(cty.Type{}))
View Source
var URLDecodeFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{
			Name: "str",
			Type: cty.String,
		},
	},
	Type:         function.StaticReturnType(cty.String),
	RefineResult: refineNotNull,
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		query, err := url.QueryUnescape(args[0].AsString())
		if err != nil {
			return cty.UnknownVal(cty.String), fmt.Errorf("failed to decode URL '%s': %v", query, err)
		}

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

URLDecodeFunc constructs a function that applies URL decoding to a given encoded string. Copy from https://github.com/opentofu/opentofu/blob/v1.7.1/internal/lang/funcs/encoding.go

View Source
var URLEncodeFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{
			Name: "str",
			Type: cty.String,
		},
	},
	Type:         function.StaticReturnType(cty.String),
	RefineResult: refineNotNull,
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		return cty.StringVal(url.QueryEscape(args[0].AsString())), nil
	},
})

URLEncodeFunc constructs a function that applies URL encoding to a given string. Copy from https://github.com/opentofu/opentofu/blob/v1.7.1/internal/lang/funcs/encoding.go

View Source
var UUIDFunc = function.New(&function.Spec{
	Params:       []function.Parameter{},
	Type:         function.StaticReturnType(cty.String),
	RefineResult: refineNotNull,
	Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
		result, err := uuid.GenerateUUID()
		if err != nil {
			return cty.UnknownVal(cty.String), err
		}
		return cty.StringVal(result), nil
	},
})

Copy from https://github.com/opentofu/opentofu/blob/v1.7.1/internal/lang/funcs/crypto.go

View Source
var VaultFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{
			Name: "path",
			Type: cty.String,
		},
		{
			Name: "key",
			Type: cty.String,
		},
	},
	Type: function.StaticReturnType(cty.String),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		path := args[0].AsString()
		key := args[1].AsString()

		val, err := commontpl.Vault(path, key)

		return cty.StringVal(val), err
	},
})

VaultFunc constructs a function that retrieves KV secrets from HC vault

View Source
var YAML2JsonFunc = 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")
		}
		return cty.String, nil
	},
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		json, err := yaml2json.Convert([]byte(args[0].AsString()))
		if err != nil {
			return cty.NilVal, err
		}
		return cty.StringVal(string(json)), nil
	},
})

Functions

func Functions added in v0.2.0

func Functions(baseDir string) map[string]function.Function

func MakeToFunc

func MakeToFunc(wantTy cty.Type) function.Function

func Type

func Type(input []cty.Value) (cty.Value, error)

Types

This section is empty.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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