2023-03-02 15:37:05 -05:00
// Copyright (c) HashiCorp, Inc.
2023-08-10 18:53:29 -04:00
// SPDX-License-Identifier: BUSL-1.1
2023-03-02 15:37:05 -05:00
Hcl2 input variables, local variables and functions (#8588)
Mainly redefine or reused what Terraform did.
* allow to used `variables`, `variable` and `local` blocks
* import the following functions and their docs from Terraform: abs, abspath, basename, base64decode, base64encode, bcrypt, can, ceil, chomp, chunklist, cidrhost, cidrnetmask, cidrsubnet, cidrsubnets, coalesce, coalescelist, compact, concat, contains, convert, csvdecode, dirname, distinct, element, file, fileexists, fileset, flatten, floor, format, formatdate, formatlist, indent, index, join, jsondecode, jsonencode, keys, length, log, lookup, lower, max, md5, merge, min, parseint, pathexpand, pow, range, reverse, rsadecrypt, setintersection, setproduct, setunion, sha1, sha256, sha512, signum, slice, sort, split, strrev, substr, timestamp, timeadd, title, trim, trimprefix, trimspace, trimsuffix, try, upper, urlencode, uuidv4, uuidv5, values, yamldecode, yamlencode, zipmap.
2020-02-06 05:49:21 -05:00
package hcl2template
import (
2024-05-30 08:24:46 -04:00
"bytes"
"encoding/base64"
Hcl2 input variables, local variables and functions (#8588)
Mainly redefine or reused what Terraform did.
* allow to used `variables`, `variable` and `local` blocks
* import the following functions and their docs from Terraform: abs, abspath, basename, base64decode, base64encode, bcrypt, can, ceil, chomp, chunklist, cidrhost, cidrnetmask, cidrsubnet, cidrsubnets, coalesce, coalescelist, compact, concat, contains, convert, csvdecode, dirname, distinct, element, file, fileexists, fileset, flatten, floor, format, formatdate, formatlist, indent, index, join, jsondecode, jsonencode, keys, length, log, lookup, lower, max, md5, merge, min, parseint, pathexpand, pow, range, reverse, rsadecrypt, setintersection, setproduct, setunion, sha1, sha256, sha512, signum, slice, sort, split, strrev, substr, timestamp, timeadd, title, trim, trimprefix, trimspace, trimsuffix, try, upper, urlencode, uuidv4, uuidv5, values, yamldecode, yamlencode, zipmap.
2020-02-06 05:49:21 -05:00
"github.com/hashicorp/go-cty-funcs/cidr"
2020-09-30 05:59:00 -04:00
"github.com/hashicorp/go-cty-funcs/collection"
Hcl2 input variables, local variables and functions (#8588)
Mainly redefine or reused what Terraform did.
* allow to used `variables`, `variable` and `local` blocks
* import the following functions and their docs from Terraform: abs, abspath, basename, base64decode, base64encode, bcrypt, can, ceil, chomp, chunklist, cidrhost, cidrnetmask, cidrsubnet, cidrsubnets, coalesce, coalescelist, compact, concat, contains, convert, csvdecode, dirname, distinct, element, file, fileexists, fileset, flatten, floor, format, formatdate, formatlist, indent, index, join, jsondecode, jsonencode, keys, length, log, lookup, lower, max, md5, merge, min, parseint, pathexpand, pow, range, reverse, rsadecrypt, setintersection, setproduct, setunion, sha1, sha256, sha512, signum, slice, sort, split, strrev, substr, timestamp, timeadd, title, trim, trimprefix, trimspace, trimsuffix, try, upper, urlencode, uuidv4, uuidv5, values, yamldecode, yamlencode, zipmap.
2020-02-06 05:49:21 -05:00
"github.com/hashicorp/go-cty-funcs/crypto"
"github.com/hashicorp/go-cty-funcs/encoding"
"github.com/hashicorp/go-cty-funcs/filesystem"
"github.com/hashicorp/go-cty-funcs/uuid"
"github.com/hashicorp/hcl/v2/ext/tryfunc"
"github.com/hashicorp/hcl/v2/ext/typeexpr"
pkrfunction "github.com/hashicorp/packer/hcl2template/function"
ctyyaml "github.com/zclconf/go-cty-yaml"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/function"
"github.com/zclconf/go-cty/cty/function/stdlib"
2024-05-30 08:24:46 -04:00
"golang.org/x/text/encoding/ianaindex"
Hcl2 input variables, local variables and functions (#8588)
Mainly redefine or reused what Terraform did.
* allow to used `variables`, `variable` and `local` blocks
* import the following functions and their docs from Terraform: abs, abspath, basename, base64decode, base64encode, bcrypt, can, ceil, chomp, chunklist, cidrhost, cidrnetmask, cidrsubnet, cidrsubnets, coalesce, coalescelist, compact, concat, contains, convert, csvdecode, dirname, distinct, element, file, fileexists, fileset, flatten, floor, format, formatdate, formatlist, indent, index, join, jsondecode, jsonencode, keys, length, log, lookup, lower, max, md5, merge, min, parseint, pathexpand, pow, range, reverse, rsadecrypt, setintersection, setproduct, setunion, sha1, sha256, sha512, signum, slice, sort, split, strrev, substr, timestamp, timeadd, title, trim, trimprefix, trimspace, trimsuffix, try, upper, urlencode, uuidv4, uuidv5, values, yamldecode, yamlencode, zipmap.
2020-02-06 05:49:21 -05:00
)
// Functions returns the set of functions that should be used to when
// evaluating expressions in the receiving scope.
//
// basedir is used with file functions and allows a user to reference a file
// using local path. Usually basedir is the directory in which the config file
// is located
func Functions ( basedir string ) map [ string ] function . Function {
funcs := map [ string ] function . Function {
2024-12-20 10:48:13 -05:00
"abs" : stdlib . AbsoluteFunc ,
"abspath" : filesystem . AbsPathFunc ,
"alltrue" : pkrfunction . AllTrue ,
"anytrue" : pkrfunction . AnyTrue ,
"aws_secretsmanager" : pkrfunction . AWSSecret ,
"aws_secretsmanager_raw" : pkrfunction . AWSSecretRaw ,
"basename" : filesystem . BasenameFunc ,
"base64decode" : encoding . Base64DecodeFunc ,
"base64encode" : encoding . Base64EncodeFunc ,
"base64gzip" : pkrfunction . Base64GzipFunc ,
"bcrypt" : crypto . BcryptFunc ,
"can" : tryfunc . CanFunc ,
"ceil" : stdlib . CeilFunc ,
"chomp" : stdlib . ChompFunc ,
"chunklist" : stdlib . ChunklistFunc ,
"cidrhost" : cidr . HostFunc ,
"cidrnetmask" : cidr . NetmaskFunc ,
"cidrsubnet" : cidr . SubnetFunc ,
"cidrsubnets" : cidr . SubnetsFunc ,
"coalesce" : collection . CoalesceFunc ,
"coalescelist" : stdlib . CoalesceListFunc ,
"compact" : stdlib . CompactFunc ,
"concat" : stdlib . ConcatFunc ,
"consul_key" : pkrfunction . ConsulFunc ,
"contains" : stdlib . ContainsFunc ,
"convert" : typeexpr . ConvertFunc ,
"csvdecode" : stdlib . CSVDecodeFunc ,
"dirname" : filesystem . DirnameFunc ,
"distinct" : stdlib . DistinctFunc ,
"element" : stdlib . ElementFunc ,
2025-04-14 11:49:36 -04:00
"endswith" : pkrfunction . EndsWithFunc ,
2024-12-20 10:48:13 -05:00
"file" : filesystem . MakeFileFunc ( basedir , false ) ,
2025-04-24 13:24:07 -04:00
"filebase64" : pkrfunction . Filebase64 ,
2024-12-20 10:48:13 -05:00
"fileexists" : filesystem . MakeFileExistsFunc ( basedir ) ,
"fileset" : filesystem . MakeFileSetFunc ( basedir ) ,
"flatten" : stdlib . FlattenFunc ,
"floor" : stdlib . FloorFunc ,
"format" : stdlib . FormatFunc ,
"formatdate" : stdlib . FormatDateFunc ,
"formatlist" : stdlib . FormatListFunc ,
"indent" : stdlib . IndentFunc ,
"index" : pkrfunction . IndexFunc , // stdlib.IndexFunc is not compatible
"join" : stdlib . JoinFunc ,
"jsondecode" : stdlib . JSONDecodeFunc ,
"jsonencode" : stdlib . JSONEncodeFunc ,
"keys" : stdlib . KeysFunc ,
"legacy_isotime" : pkrfunction . LegacyIsotimeFunc ,
"legacy_strftime" : pkrfunction . LegacyStrftimeFunc ,
"length" : pkrfunction . LengthFunc ,
"log" : stdlib . LogFunc ,
"lookup" : stdlib . LookupFunc ,
"lower" : stdlib . LowerFunc ,
"max" : stdlib . MaxFunc ,
"md5" : crypto . Md5Func ,
"merge" : stdlib . MergeFunc ,
"min" : stdlib . MinFunc ,
"parseint" : stdlib . ParseIntFunc ,
"pathexpand" : filesystem . PathExpandFunc ,
"pow" : stdlib . PowFunc ,
"range" : stdlib . RangeFunc ,
"reverse" : stdlib . ReverseListFunc ,
"replace" : stdlib . ReplaceFunc ,
"regex" : stdlib . RegexFunc ,
"regexall" : stdlib . RegexAllFunc ,
"regex_replace" : stdlib . RegexReplaceFunc ,
"rsadecrypt" : crypto . RsaDecryptFunc ,
"setintersection" : stdlib . SetIntersectionFunc ,
"setproduct" : stdlib . SetProductFunc ,
"setunion" : stdlib . SetUnionFunc ,
"sha1" : crypto . Sha1Func ,
"sha256" : crypto . Sha256Func ,
"sha512" : crypto . Sha512Func ,
"signum" : stdlib . SignumFunc ,
"slice" : stdlib . SliceFunc ,
"sort" : stdlib . SortFunc ,
"split" : stdlib . SplitFunc ,
2025-04-14 11:49:36 -04:00
"startswith" : pkrfunction . StartsWithFunc ,
2024-12-20 10:48:13 -05:00
"strcontains" : pkrfunction . StrContains ,
"strrev" : stdlib . ReverseFunc ,
"substr" : stdlib . SubstrFunc ,
2025-04-14 11:49:36 -04:00
"sum" : pkrfunction . SumFunc ,
2024-12-20 10:48:13 -05:00
"textdecodebase64" : TextDecodeBase64Func ,
"textencodebase64" : TextEncodeBase64Func ,
"timestamp" : pkrfunction . TimestampFunc ,
"timeadd" : stdlib . TimeAddFunc ,
"title" : stdlib . TitleFunc ,
"trim" : stdlib . TrimFunc ,
"trimprefix" : stdlib . TrimPrefixFunc ,
"trimspace" : stdlib . TrimSpaceFunc ,
"trimsuffix" : stdlib . TrimSuffixFunc ,
"try" : tryfunc . TryFunc ,
"upper" : stdlib . UpperFunc ,
"urlencode" : encoding . URLEncodeFunc ,
"uuidv4" : uuid . V4Func ,
"uuidv5" : uuid . V5Func ,
"values" : stdlib . ValuesFunc ,
"vault" : pkrfunction . VaultFunc ,
"yamldecode" : ctyyaml . YAMLDecodeFunc ,
"yamlencode" : ctyyaml . YAMLEncodeFunc ,
"zipmap" : stdlib . ZipmapFunc ,
Hcl2 input variables, local variables and functions (#8588)
Mainly redefine or reused what Terraform did.
* allow to used `variables`, `variable` and `local` blocks
* import the following functions and their docs from Terraform: abs, abspath, basename, base64decode, base64encode, bcrypt, can, ceil, chomp, chunklist, cidrhost, cidrnetmask, cidrsubnet, cidrsubnets, coalesce, coalescelist, compact, concat, contains, convert, csvdecode, dirname, distinct, element, file, fileexists, fileset, flatten, floor, format, formatdate, formatlist, indent, index, join, jsondecode, jsonencode, keys, length, log, lookup, lower, max, md5, merge, min, parseint, pathexpand, pow, range, reverse, rsadecrypt, setintersection, setproduct, setunion, sha1, sha256, sha512, signum, slice, sort, split, strrev, substr, timestamp, timeadd, title, trim, trimprefix, trimspace, trimsuffix, try, upper, urlencode, uuidv4, uuidv5, values, yamldecode, yamlencode, zipmap.
2020-02-06 05:49:21 -05:00
}
2021-03-23 07:02:05 -04:00
funcs [ "templatefile" ] = pkrfunction . MakeTemplateFileFunc ( basedir , func ( ) map [ string ] function . Function {
// The templatefile function prevents recursive calls to itself
// by copying this map and overwriting the "templatefile" entry.
return funcs
} )
Hcl2 input variables, local variables and functions (#8588)
Mainly redefine or reused what Terraform did.
* allow to used `variables`, `variable` and `local` blocks
* import the following functions and their docs from Terraform: abs, abspath, basename, base64decode, base64encode, bcrypt, can, ceil, chomp, chunklist, cidrhost, cidrnetmask, cidrsubnet, cidrsubnets, coalesce, coalescelist, compact, concat, contains, convert, csvdecode, dirname, distinct, element, file, fileexists, fileset, flatten, floor, format, formatdate, formatlist, indent, index, join, jsondecode, jsonencode, keys, length, log, lookup, lower, max, md5, merge, min, parseint, pathexpand, pow, range, reverse, rsadecrypt, setintersection, setproduct, setunion, sha1, sha256, sha512, signum, slice, sort, split, strrev, substr, timestamp, timeadd, title, trim, trimprefix, trimspace, trimsuffix, try, upper, urlencode, uuidv4, uuidv5, values, yamldecode, yamlencode, zipmap.
2020-02-06 05:49:21 -05:00
return funcs
}
2024-05-30 08:24:46 -04:00
// TextEncodeBase64Func constructs a function that encodes a string to a target encoding and then to a base64 sequence.
var TextEncodeBase64Func = function . New ( & function . Spec {
Params : [ ] function . Parameter {
{
Name : "string" ,
Type : cty . String ,
} ,
{
Name : "encoding" ,
Type : cty . String ,
} ,
} ,
Description : "Encodes the input string (UTF-8) to the destination encoding. The output is base64 to account for cty limiting strings to NFC normalised UTF-8 strings." ,
Type : function . StaticReturnType ( cty . String ) ,
RefineResult : func ( rb * cty . RefinementBuilder ) * cty . RefinementBuilder { return rb . NotNull ( ) } ,
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" , args [ 1 ] . AsString ( ) )
}
encName , err := ianaindex . IANA . Name ( encoding )
if err != nil { // would be weird, since we just read this encoding out
encName = args [ 1 ] . AsString ( )
}
encoder := encoding . NewEncoder ( )
encodedInput , err := encoder . Bytes ( [ ] byte ( args [ 0 ] . AsString ( ) ) )
if err != nil {
// The string representations of "err" disclose implementation
// details of the underlying library, and the main error we might
// like to return a special message for is unexported as
// golang.org/x/text/encoding/internal.RepertoireError, so this
// is just a generic error message for now.
//
// We also don't include the string itself in the message because
// it can typically be very large, contain newline characters,
// etc.
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
} ,
} )
// TextDecodeBase64Func constructs a function that decodes a base64 sequence from the source encoding to UTF-8.
var TextDecodeBase64Func = function . New ( & function . Spec {
Params : [ ] function . Parameter {
{
Name : "source" ,
Type : cty . String ,
} ,
{
Name : "encoding" ,
Type : cty . String ,
} ,
} ,
Type : function . StaticReturnType ( cty . String ) ,
Description : "Encodes the input base64 blob from an encoding to utf-8. The input is base64 to account for cty limiting strings to NFC normalised UTF-8 strings." ,
RefineResult : func ( rb * cty . RefinementBuilder ) * cty . RefinementBuilder { return rb . NotNull ( ) } ,
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" , args [ 1 ] . AsString ( ) )
}
encName , err := ianaindex . IANA . Name ( encoding )
if err != nil { // would be weird, since we just read this encoding out
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 , '<27> ' ) {
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
} ,
} )