github.com/terraform-linters/tflint@v0.51.2-0.20240520175844-3750771571b6/terraform/lang/functions.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package lang 5 6 import ( 7 "github.com/hashicorp/hcl/v2/ext/tryfunc" 8 ctyyaml "github.com/zclconf/go-cty-yaml" 9 "github.com/zclconf/go-cty/cty" 10 "github.com/zclconf/go-cty/cty/function" 11 "github.com/zclconf/go-cty/cty/function/stdlib" 12 13 "github.com/terraform-linters/tflint/terraform/lang/funcs" 14 "github.com/terraform-linters/tflint/terraform/lang/funcs/terraform" 15 ) 16 17 var impureFunctions = []string{ 18 "bcrypt", 19 "timestamp", 20 "uuid", 21 } 22 23 // Functions returns the set of functions that should be used to when evaluating 24 // expressions in the receiving scope. 25 func (s *Scope) Functions() map[string]function.Function { 26 s.funcsLock.Lock() 27 if s.funcs == nil { 28 // Some of our functions are just directly the cty stdlib functions. 29 // Others are implemented in the subdirectory "funcs" here in this 30 // repository. New functions should generally start out their lives 31 // in the "funcs" directory and potentially graduate to cty stdlib 32 // later if the functionality seems to be something domain-agnostic 33 // that would be useful to all applications using cty functions. 34 35 coreFuncs := map[string]function.Function{ 36 "abs": stdlib.AbsoluteFunc, 37 "abspath": funcs.AbsPathFunc, 38 "alltrue": funcs.AllTrueFunc, 39 "anytrue": funcs.AnyTrueFunc, 40 "basename": funcs.BasenameFunc, 41 "base64decode": funcs.Base64DecodeFunc, 42 "base64encode": funcs.Base64EncodeFunc, 43 "base64gzip": funcs.Base64GzipFunc, 44 "base64sha256": funcs.Base64Sha256Func, 45 "base64sha512": funcs.Base64Sha512Func, 46 "bcrypt": funcs.BcryptFunc, 47 "can": tryfunc.CanFunc, 48 "ceil": stdlib.CeilFunc, 49 "chomp": stdlib.ChompFunc, 50 "cidrhost": funcs.CidrHostFunc, 51 "cidrnetmask": funcs.CidrNetmaskFunc, 52 "cidrsubnet": funcs.CidrSubnetFunc, 53 "cidrsubnets": funcs.CidrSubnetsFunc, 54 "coalesce": funcs.CoalesceFunc, 55 "coalescelist": stdlib.CoalesceListFunc, 56 "compact": stdlib.CompactFunc, 57 "concat": stdlib.ConcatFunc, 58 "contains": stdlib.ContainsFunc, 59 "csvdecode": stdlib.CSVDecodeFunc, 60 "dirname": funcs.DirnameFunc, 61 "distinct": stdlib.DistinctFunc, 62 "element": stdlib.ElementFunc, 63 "endswith": funcs.EndsWithFunc, 64 "chunklist": stdlib.ChunklistFunc, 65 "file": funcs.MakeFileFunc(s.BaseDir, false), 66 "fileexists": funcs.MakeFileExistsFunc(s.BaseDir), 67 "fileset": funcs.MakeFileSetFunc(s.BaseDir), 68 "filebase64": funcs.MakeFileFunc(s.BaseDir, true), 69 "filebase64sha256": funcs.MakeFileBase64Sha256Func(s.BaseDir), 70 "filebase64sha512": funcs.MakeFileBase64Sha512Func(s.BaseDir), 71 "filemd5": funcs.MakeFileMd5Func(s.BaseDir), 72 "filesha1": funcs.MakeFileSha1Func(s.BaseDir), 73 "filesha256": funcs.MakeFileSha256Func(s.BaseDir), 74 "filesha512": funcs.MakeFileSha512Func(s.BaseDir), 75 "flatten": stdlib.FlattenFunc, 76 "floor": stdlib.FloorFunc, 77 "format": stdlib.FormatFunc, 78 "formatdate": stdlib.FormatDateFunc, 79 "formatlist": stdlib.FormatListFunc, 80 "indent": stdlib.IndentFunc, 81 "index": funcs.IndexFunc, // stdlib.IndexFunc is not compatible 82 "join": stdlib.JoinFunc, 83 "jsondecode": stdlib.JSONDecodeFunc, 84 "jsonencode": stdlib.JSONEncodeFunc, 85 "keys": stdlib.KeysFunc, 86 "length": funcs.LengthFunc, 87 "list": funcs.ListFunc, 88 "log": stdlib.LogFunc, 89 "lookup": funcs.LookupFunc, 90 "lower": stdlib.LowerFunc, 91 "map": funcs.MapFunc, 92 "matchkeys": funcs.MatchkeysFunc, 93 "max": stdlib.MaxFunc, 94 "md5": funcs.Md5Func, 95 "merge": stdlib.MergeFunc, 96 "min": stdlib.MinFunc, 97 "one": funcs.OneFunc, 98 "parseint": stdlib.ParseIntFunc, 99 "pathexpand": funcs.PathExpandFunc, 100 "plantimestamp": funcs.PlantimestampFunc, 101 "pow": stdlib.PowFunc, 102 "range": stdlib.RangeFunc, 103 "regex": stdlib.RegexFunc, 104 "regexall": stdlib.RegexAllFunc, 105 "replace": funcs.ReplaceFunc, 106 "reverse": stdlib.ReverseListFunc, 107 "rsadecrypt": funcs.RsaDecryptFunc, 108 "sensitive": funcs.SensitiveFunc, 109 "nonsensitive": funcs.NonsensitiveFunc, 110 "issensitive": funcs.IssensitiveFunc, 111 "setintersection": stdlib.SetIntersectionFunc, 112 "setproduct": stdlib.SetProductFunc, 113 "setsubtract": stdlib.SetSubtractFunc, 114 "setunion": stdlib.SetUnionFunc, 115 "sha1": funcs.Sha1Func, 116 "sha256": funcs.Sha256Func, 117 "sha512": funcs.Sha512Func, 118 "signum": stdlib.SignumFunc, 119 "slice": stdlib.SliceFunc, 120 "sort": stdlib.SortFunc, 121 "split": stdlib.SplitFunc, 122 "startswith": funcs.StartsWithFunc, 123 "strcontains": funcs.StrContainsFunc, 124 "strrev": stdlib.ReverseFunc, 125 "substr": stdlib.SubstrFunc, 126 "sum": funcs.SumFunc, 127 "textdecodebase64": funcs.TextDecodeBase64Func, 128 "textencodebase64": funcs.TextEncodeBase64Func, 129 "timestamp": funcs.TimestampFunc, 130 "timeadd": stdlib.TimeAddFunc, 131 "timecmp": funcs.TimeCmpFunc, 132 "title": stdlib.TitleFunc, 133 "tostring": funcs.MakeToFunc(cty.String), 134 "tonumber": funcs.MakeToFunc(cty.Number), 135 "tobool": funcs.MakeToFunc(cty.Bool), 136 "toset": funcs.MakeToFunc(cty.Set(cty.DynamicPseudoType)), 137 "tolist": funcs.MakeToFunc(cty.List(cty.DynamicPseudoType)), 138 "tomap": funcs.MakeToFunc(cty.Map(cty.DynamicPseudoType)), 139 "transpose": funcs.TransposeFunc, 140 "trim": stdlib.TrimFunc, 141 "trimprefix": stdlib.TrimPrefixFunc, 142 "trimspace": stdlib.TrimSpaceFunc, 143 "trimsuffix": stdlib.TrimSuffixFunc, 144 "try": tryfunc.TryFunc, 145 "upper": stdlib.UpperFunc, 146 "urlencode": funcs.URLEncodeFunc, 147 "uuid": funcs.UUIDFunc, 148 "uuidv5": funcs.UUIDV5Func, 149 "values": stdlib.ValuesFunc, 150 "yamldecode": ctyyaml.YAMLDecodeFunc, 151 "yamlencode": ctyyaml.YAMLEncodeFunc, 152 "zipmap": stdlib.ZipmapFunc, 153 } 154 155 coreFuncs["templatefile"] = funcs.MakeTemplateFileFunc(s.BaseDir, func() map[string]function.Function { 156 // The templatefile function prevents recursive calls to itself 157 // by copying this map and overwriting the "templatefile" and 158 // "core:templatefile" entries. 159 return s.funcs 160 }) 161 162 if s.PureOnly { 163 // Force our few impure functions to return unknown so that we 164 // can defer evaluating them until a later pass. 165 for _, name := range impureFunctions { 166 coreFuncs[name] = function.Unpredictable(s.funcs[name]) 167 } 168 } 169 170 // All of the built-in functions are also available under the "core::" 171 // namespace, to distinguish from the "provider::" and "module::" 172 // namespaces that can serve as external extension points. 173 s.funcs = make(map[string]function.Function, len(coreFuncs)*2) 174 for name, fn := range coreFuncs { 175 s.funcs[name] = fn 176 s.funcs["core::"+name] = fn 177 } 178 179 // Built-in Terraform provider-defined functions are typically obtained dynamically, 180 // but given that they are built-ins, they are provided just like regular functions. 181 s.funcs["provider::terraform::encode_tfvars"] = terraform.EncodeTfvarsFunc 182 s.funcs["provider::terraform::decode_tfvars"] = terraform.DecodeTfvarsFunc 183 s.funcs["provider::terraform::encode_expr"] = terraform.EncodeExprFunc 184 } 185 s.funcsLock.Unlock() 186 187 return s.funcs 188 } 189 190 // NewMockFunction creates a mock function that returns a dynamic value. 191 // This is primarily used to replace provider-defined functions. 192 func NewMockFunction(call *FunctionCall) function.Function { 193 params := make([]function.Parameter, call.ArgsCount) 194 for idx := 0; idx < call.ArgsCount; idx++ { 195 params[idx] = function.Parameter{ 196 Type: cty.DynamicPseudoType, 197 AllowNull: true, 198 AllowUnknown: true, 199 AllowDynamicType: true, 200 AllowMarked: true, 201 } 202 } 203 204 return function.New(&function.Spec{ 205 Params: params, 206 Type: function.StaticReturnType(cty.DynamicPseudoType), 207 Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { 208 return cty.DynamicVal, nil 209 }, 210 }) 211 }