github.com/hugorut/terraform@v1.1.3/src/lang/functions.go (about)

     1  package lang
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hashicorp/hcl/v2/ext/tryfunc"
     7  	ctyyaml "github.com/zclconf/go-cty-yaml"
     8  	"github.com/zclconf/go-cty/cty"
     9  	"github.com/zclconf/go-cty/cty/function"
    10  	"github.com/zclconf/go-cty/cty/function/stdlib"
    11  
    12  	"github.com/hugorut/terraform/src/experiments"
    13  	"github.com/hugorut/terraform/src/lang/funcs"
    14  )
    15  
    16  var impureFunctions = []string{
    17  	"bcrypt",
    18  	"timestamp",
    19  	"uuid",
    20  }
    21  
    22  // Functions returns the set of functions that should be used to when evaluating
    23  // expressions in the receiving scope.
    24  func (s *Scope) Functions() map[string]function.Function {
    25  	s.funcsLock.Lock()
    26  	if s.funcs == nil {
    27  		// Some of our functions are just directly the cty stdlib functions.
    28  		// Others are implemented in the subdirectory "funcs" here in this
    29  		// repository. New functions should generally start out their lives
    30  		// in the "funcs" directory and potentially graduate to cty stdlib
    31  		// later if the functionality seems to be something domain-agnostic
    32  		// that would be useful to all applications using cty functions.
    33  
    34  		s.funcs = map[string]function.Function{
    35  			"abs":              stdlib.AbsoluteFunc,
    36  			"abspath":          funcs.AbsPathFunc,
    37  			"alltrue":          funcs.AllTrueFunc,
    38  			"anytrue":          funcs.AnyTrueFunc,
    39  			"basename":         funcs.BasenameFunc,
    40  			"base64decode":     funcs.Base64DecodeFunc,
    41  			"base64encode":     funcs.Base64EncodeFunc,
    42  			"base64gzip":       funcs.Base64GzipFunc,
    43  			"base64sha256":     funcs.Base64Sha256Func,
    44  			"base64sha512":     funcs.Base64Sha512Func,
    45  			"bcrypt":           funcs.BcryptFunc,
    46  			"can":              tryfunc.CanFunc,
    47  			"ceil":             stdlib.CeilFunc,
    48  			"chomp":            stdlib.ChompFunc,
    49  			"cidrhost":         funcs.CidrHostFunc,
    50  			"cidrnetmask":      funcs.CidrNetmaskFunc,
    51  			"cidrsubnet":       funcs.CidrSubnetFunc,
    52  			"cidrsubnets":      funcs.CidrSubnetsFunc,
    53  			"coalesce":         funcs.CoalesceFunc,
    54  			"coalescelist":     stdlib.CoalesceListFunc,
    55  			"compact":          stdlib.CompactFunc,
    56  			"concat":           stdlib.ConcatFunc,
    57  			"contains":         stdlib.ContainsFunc,
    58  			"csvdecode":        stdlib.CSVDecodeFunc,
    59  			"defaults":         s.experimentalFunction(experiments.ModuleVariableOptionalAttrs, funcs.DefaultsFunc),
    60  			"dirname":          funcs.DirnameFunc,
    61  			"distinct":         stdlib.DistinctFunc,
    62  			"element":          stdlib.ElementFunc,
    63  			"chunklist":        stdlib.ChunklistFunc,
    64  			"file":             funcs.MakeFileFunc(s.BaseDir, false),
    65  			"fileexists":       funcs.MakeFileExistsFunc(s.BaseDir),
    66  			"fileset":          funcs.MakeFileSetFunc(s.BaseDir),
    67  			"filebase64":       funcs.MakeFileFunc(s.BaseDir, true),
    68  			"filebase64sha256": funcs.MakeFileBase64Sha256Func(s.BaseDir),
    69  			"filebase64sha512": funcs.MakeFileBase64Sha512Func(s.BaseDir),
    70  			"filemd5":          funcs.MakeFileMd5Func(s.BaseDir),
    71  			"filesha1":         funcs.MakeFileSha1Func(s.BaseDir),
    72  			"filesha256":       funcs.MakeFileSha256Func(s.BaseDir),
    73  			"filesha512":       funcs.MakeFileSha512Func(s.BaseDir),
    74  			"flatten":          stdlib.FlattenFunc,
    75  			"floor":            stdlib.FloorFunc,
    76  			"format":           stdlib.FormatFunc,
    77  			"formatdate":       stdlib.FormatDateFunc,
    78  			"formatlist":       stdlib.FormatListFunc,
    79  			"indent":           stdlib.IndentFunc,
    80  			"index":            funcs.IndexFunc, // stdlib.IndexFunc is not compatible
    81  			"join":             stdlib.JoinFunc,
    82  			"jsondecode":       stdlib.JSONDecodeFunc,
    83  			"jsonencode":       stdlib.JSONEncodeFunc,
    84  			"keys":             stdlib.KeysFunc,
    85  			"length":           funcs.LengthFunc,
    86  			"list":             funcs.ListFunc,
    87  			"log":              stdlib.LogFunc,
    88  			"lookup":           funcs.LookupFunc,
    89  			"lower":            stdlib.LowerFunc,
    90  			"map":              funcs.MapFunc,
    91  			"matchkeys":        funcs.MatchkeysFunc,
    92  			"max":              stdlib.MaxFunc,
    93  			"md5":              funcs.Md5Func,
    94  			"merge":            stdlib.MergeFunc,
    95  			"min":              stdlib.MinFunc,
    96  			"one":              funcs.OneFunc,
    97  			"parseint":         stdlib.ParseIntFunc,
    98  			"pathexpand":       funcs.PathExpandFunc,
    99  			"pow":              stdlib.PowFunc,
   100  			"range":            stdlib.RangeFunc,
   101  			"regex":            stdlib.RegexFunc,
   102  			"regexall":         stdlib.RegexAllFunc,
   103  			"replace":          funcs.ReplaceFunc,
   104  			"reverse":          stdlib.ReverseListFunc,
   105  			"rsadecrypt":       funcs.RsaDecryptFunc,
   106  			"sensitive":        funcs.SensitiveFunc,
   107  			"nonsensitive":     funcs.NonsensitiveFunc,
   108  			"setintersection":  stdlib.SetIntersectionFunc,
   109  			"setproduct":       stdlib.SetProductFunc,
   110  			"setsubtract":      stdlib.SetSubtractFunc,
   111  			"setunion":         stdlib.SetUnionFunc,
   112  			"sha1":             funcs.Sha1Func,
   113  			"sha256":           funcs.Sha256Func,
   114  			"sha512":           funcs.Sha512Func,
   115  			"signum":           stdlib.SignumFunc,
   116  			"slice":            stdlib.SliceFunc,
   117  			"sort":             stdlib.SortFunc,
   118  			"split":            stdlib.SplitFunc,
   119  			"strrev":           stdlib.ReverseFunc,
   120  			"substr":           stdlib.SubstrFunc,
   121  			"sum":              funcs.SumFunc,
   122  			"textdecodebase64": funcs.TextDecodeBase64Func,
   123  			"textencodebase64": funcs.TextEncodeBase64Func,
   124  			"timestamp":        funcs.TimestampFunc,
   125  			"timeadd":          stdlib.TimeAddFunc,
   126  			"title":            stdlib.TitleFunc,
   127  			"tostring":         funcs.MakeToFunc(cty.String),
   128  			"tonumber":         funcs.MakeToFunc(cty.Number),
   129  			"tobool":           funcs.MakeToFunc(cty.Bool),
   130  			"toset":            funcs.MakeToFunc(cty.Set(cty.DynamicPseudoType)),
   131  			"tolist":           funcs.MakeToFunc(cty.List(cty.DynamicPseudoType)),
   132  			"tomap":            funcs.MakeToFunc(cty.Map(cty.DynamicPseudoType)),
   133  			"transpose":        funcs.TransposeFunc,
   134  			"trim":             stdlib.TrimFunc,
   135  			"trimprefix":       stdlib.TrimPrefixFunc,
   136  			"trimspace":        stdlib.TrimSpaceFunc,
   137  			"trimsuffix":       stdlib.TrimSuffixFunc,
   138  			"try":              tryfunc.TryFunc,
   139  			"upper":            stdlib.UpperFunc,
   140  			"urlencode":        funcs.URLEncodeFunc,
   141  			"uuid":             funcs.UUIDFunc,
   142  			"uuidv5":           funcs.UUIDV5Func,
   143  			"values":           stdlib.ValuesFunc,
   144  			"yamldecode":       ctyyaml.YAMLDecodeFunc,
   145  			"yamlencode":       ctyyaml.YAMLEncodeFunc,
   146  			"zipmap":           stdlib.ZipmapFunc,
   147  		}
   148  
   149  		s.funcs["templatefile"] = funcs.MakeTemplateFileFunc(s.BaseDir, func() map[string]function.Function {
   150  			// The templatefile function prevents recursive calls to itself
   151  			// by copying this map and overwriting the "templatefile" entry.
   152  			return s.funcs
   153  		})
   154  
   155  		if s.ConsoleMode {
   156  			// The type function is only available in terraform console.
   157  			s.funcs["type"] = funcs.TypeFunc
   158  		}
   159  
   160  		if s.PureOnly {
   161  			// Force our few impure functions to return unknown so that we
   162  			// can defer evaluating them until a later pass.
   163  			for _, name := range impureFunctions {
   164  				s.funcs[name] = function.Unpredictable(s.funcs[name])
   165  			}
   166  		}
   167  	}
   168  	s.funcsLock.Unlock()
   169  
   170  	return s.funcs
   171  }
   172  
   173  // experimentalFunction checks whether the given experiment is enabled for
   174  // the recieving scope. If so, it will return the given function verbatim.
   175  // If not, it will return a placeholder function that just returns an
   176  // error explaining that the function requires the experiment to be enabled.
   177  func (s *Scope) experimentalFunction(experiment experiments.Experiment, fn function.Function) function.Function {
   178  	if s.activeExperiments.Has(experiment) {
   179  		return fn
   180  	}
   181  
   182  	err := fmt.Errorf(
   183  		"this function is experimental and available only when the experiment keyword %s is enabled for the current module",
   184  		experiment.Keyword(),
   185  	)
   186  
   187  	return function.New(&function.Spec{
   188  		Params:   fn.Params(),
   189  		VarParam: fn.VarParam(),
   190  		Type: func(args []cty.Value) (cty.Type, error) {
   191  			return cty.DynamicPseudoType, err
   192  		},
   193  		Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
   194  			// It would be weird to get here because the Type function always
   195  			// fails, but we'll return an error here too anyway just to be
   196  			// robust.
   197  			return cty.DynamicVal, err
   198  		},
   199  	})
   200  }