github.com/gettyimages/terraform@v0.7.6-0.20161219132226-dc052c5707a3/config/interpolate_funcs.go (about)

     1  package config
     2  
     3  import (
     4  	"crypto/md5"
     5  	"crypto/sha1"
     6  	"crypto/sha256"
     7  	"encoding/base64"
     8  	"encoding/hex"
     9  	"encoding/json"
    10  	"fmt"
    11  	"io/ioutil"
    12  	"math"
    13  	"net"
    14  	"regexp"
    15  	"sort"
    16  	"strconv"
    17  	"strings"
    18  	"time"
    19  
    20  	"github.com/apparentlymart/go-cidr/cidr"
    21  	"github.com/hashicorp/go-uuid"
    22  	"github.com/hashicorp/hil"
    23  	"github.com/hashicorp/hil/ast"
    24  	"github.com/mitchellh/go-homedir"
    25  )
    26  
    27  // stringSliceToVariableValue converts a string slice into the value
    28  // required to be returned from interpolation functions which return
    29  // TypeList.
    30  func stringSliceToVariableValue(values []string) []ast.Variable {
    31  	output := make([]ast.Variable, len(values))
    32  	for index, value := range values {
    33  		output[index] = ast.Variable{
    34  			Type:  ast.TypeString,
    35  			Value: value,
    36  		}
    37  	}
    38  	return output
    39  }
    40  
    41  func listVariableValueToStringSlice(values []ast.Variable) ([]string, error) {
    42  	output := make([]string, len(values))
    43  	for index, value := range values {
    44  		if value.Type != ast.TypeString {
    45  			return []string{}, fmt.Errorf("list has non-string element (%T)", value.Type.String())
    46  		}
    47  		output[index] = value.Value.(string)
    48  	}
    49  	return output, nil
    50  }
    51  
    52  // Funcs is the mapping of built-in functions for configuration.
    53  func Funcs() map[string]ast.Function {
    54  	return map[string]ast.Function{
    55  		"base64decode": interpolationFuncBase64Decode(),
    56  		"base64encode": interpolationFuncBase64Encode(),
    57  		"base64sha256": interpolationFuncBase64Sha256(),
    58  		"ceil":         interpolationFuncCeil(),
    59  		"cidrhost":     interpolationFuncCidrHost(),
    60  		"cidrnetmask":  interpolationFuncCidrNetmask(),
    61  		"cidrsubnet":   interpolationFuncCidrSubnet(),
    62  		"coalesce":     interpolationFuncCoalesce(),
    63  		"compact":      interpolationFuncCompact(),
    64  		"concat":       interpolationFuncConcat(),
    65  		"distinct":     interpolationFuncDistinct(),
    66  		"element":      interpolationFuncElement(),
    67  		"file":         interpolationFuncFile(),
    68  		"floor":        interpolationFuncFloor(),
    69  		"format":       interpolationFuncFormat(),
    70  		"formatlist":   interpolationFuncFormatList(),
    71  		"index":        interpolationFuncIndex(),
    72  		"join":         interpolationFuncJoin(),
    73  		"jsonencode":   interpolationFuncJSONEncode(),
    74  		"length":       interpolationFuncLength(),
    75  		"list":         interpolationFuncList(),
    76  		"lower":        interpolationFuncLower(),
    77  		"map":          interpolationFuncMap(),
    78  		"max":          interpolationFuncMax(),
    79  		"md5":          interpolationFuncMd5(),
    80  		"merge":        interpolationFuncMerge(),
    81  		"min":          interpolationFuncMin(),
    82  		"uuid":         interpolationFuncUUID(),
    83  		"replace":      interpolationFuncReplace(),
    84  		"sha1":         interpolationFuncSha1(),
    85  		"sha256":       interpolationFuncSha256(),
    86  		"signum":       interpolationFuncSignum(),
    87  		"sort":         interpolationFuncSort(),
    88  		"split":        interpolationFuncSplit(),
    89  		"timestamp":    interpolationFuncTimestamp(),
    90  		"title":        interpolationFuncTitle(),
    91  		"trimspace":    interpolationFuncTrimSpace(),
    92  		"upper":        interpolationFuncUpper(),
    93  		"zipmap":       interpolationFuncZipMap(),
    94  	}
    95  }
    96  
    97  // interpolationFuncList creates a list from the parameters passed
    98  // to it.
    99  func interpolationFuncList() ast.Function {
   100  	return ast.Function{
   101  		ArgTypes:     []ast.Type{},
   102  		ReturnType:   ast.TypeList,
   103  		Variadic:     true,
   104  		VariadicType: ast.TypeAny,
   105  		Callback: func(args []interface{}) (interface{}, error) {
   106  			var outputList []ast.Variable
   107  
   108  			for i, val := range args {
   109  				switch v := val.(type) {
   110  				case string:
   111  					outputList = append(outputList, ast.Variable{Type: ast.TypeString, Value: v})
   112  				case []ast.Variable:
   113  					outputList = append(outputList, ast.Variable{Type: ast.TypeList, Value: v})
   114  				case map[string]ast.Variable:
   115  					outputList = append(outputList, ast.Variable{Type: ast.TypeMap, Value: v})
   116  				default:
   117  					return nil, fmt.Errorf("unexpected type %T for argument %d in list", v, i)
   118  				}
   119  			}
   120  
   121  			// we don't support heterogeneous types, so make sure all types match the first
   122  			if len(outputList) > 0 {
   123  				firstType := outputList[0].Type
   124  				for i, v := range outputList[1:] {
   125  					if v.Type != firstType {
   126  						return nil, fmt.Errorf("unexpected type %s for argument %d in list", v.Type, i+1)
   127  					}
   128  				}
   129  			}
   130  
   131  			return outputList, nil
   132  		},
   133  	}
   134  }
   135  
   136  // interpolationFuncMap creates a map from the parameters passed
   137  // to it.
   138  func interpolationFuncMap() ast.Function {
   139  	return ast.Function{
   140  		ArgTypes:     []ast.Type{},
   141  		ReturnType:   ast.TypeMap,
   142  		Variadic:     true,
   143  		VariadicType: ast.TypeAny,
   144  		Callback: func(args []interface{}) (interface{}, error) {
   145  			outputMap := make(map[string]ast.Variable)
   146  
   147  			if len(args)%2 != 0 {
   148  				return nil, fmt.Errorf("requires an even number of arguments, got %d", len(args))
   149  			}
   150  
   151  			var firstType *ast.Type
   152  			for i := 0; i < len(args); i += 2 {
   153  				key, ok := args[i].(string)
   154  				if !ok {
   155  					return nil, fmt.Errorf("argument %d represents a key, so it must be a string", i+1)
   156  				}
   157  				val := args[i+1]
   158  				variable, err := hil.InterfaceToVariable(val)
   159  				if err != nil {
   160  					return nil, err
   161  				}
   162  				// Enforce map type homogeneity
   163  				if firstType == nil {
   164  					firstType = &variable.Type
   165  				} else if variable.Type != *firstType {
   166  					return nil, fmt.Errorf("all map values must have the same type, got %s then %s", firstType.Printable(), variable.Type.Printable())
   167  				}
   168  				// Check for duplicate keys
   169  				if _, ok := outputMap[key]; ok {
   170  					return nil, fmt.Errorf("argument %d is a duplicate key: %q", i+1, key)
   171  				}
   172  				outputMap[key] = variable
   173  			}
   174  
   175  			return outputMap, nil
   176  		},
   177  	}
   178  }
   179  
   180  // interpolationFuncCompact strips a list of multi-variable values
   181  // (e.g. as returned by "split") of any empty strings.
   182  func interpolationFuncCompact() ast.Function {
   183  	return ast.Function{
   184  		ArgTypes:   []ast.Type{ast.TypeList},
   185  		ReturnType: ast.TypeList,
   186  		Variadic:   false,
   187  		Callback: func(args []interface{}) (interface{}, error) {
   188  			inputList := args[0].([]ast.Variable)
   189  
   190  			var outputList []string
   191  			for _, val := range inputList {
   192  				strVal, ok := val.Value.(string)
   193  				if !ok {
   194  					return nil, fmt.Errorf(
   195  						"compact() may only be used with flat lists, this list contains elements of %s",
   196  						val.Type.Printable())
   197  				}
   198  				if strVal == "" {
   199  					continue
   200  				}
   201  
   202  				outputList = append(outputList, strVal)
   203  			}
   204  			return stringSliceToVariableValue(outputList), nil
   205  		},
   206  	}
   207  }
   208  
   209  // interpolationFuncCidrHost implements the "cidrhost" function that
   210  // fills in the host part of a CIDR range address to create a single
   211  // host address
   212  func interpolationFuncCidrHost() ast.Function {
   213  	return ast.Function{
   214  		ArgTypes: []ast.Type{
   215  			ast.TypeString, // starting CIDR mask
   216  			ast.TypeInt,    // host number to insert
   217  		},
   218  		ReturnType: ast.TypeString,
   219  		Variadic:   false,
   220  		Callback: func(args []interface{}) (interface{}, error) {
   221  			hostNum := args[1].(int)
   222  			_, network, err := net.ParseCIDR(args[0].(string))
   223  			if err != nil {
   224  				return nil, fmt.Errorf("invalid CIDR expression: %s", err)
   225  			}
   226  
   227  			ip, err := cidr.Host(network, hostNum)
   228  			if err != nil {
   229  				return nil, err
   230  			}
   231  
   232  			return ip.String(), nil
   233  		},
   234  	}
   235  }
   236  
   237  // interpolationFuncCidrNetmask implements the "cidrnetmask" function
   238  // that returns the subnet mask in IP address notation.
   239  func interpolationFuncCidrNetmask() ast.Function {
   240  	return ast.Function{
   241  		ArgTypes: []ast.Type{
   242  			ast.TypeString, // CIDR mask
   243  		},
   244  		ReturnType: ast.TypeString,
   245  		Variadic:   false,
   246  		Callback: func(args []interface{}) (interface{}, error) {
   247  			_, network, err := net.ParseCIDR(args[0].(string))
   248  			if err != nil {
   249  				return nil, fmt.Errorf("invalid CIDR expression: %s", err)
   250  			}
   251  
   252  			return net.IP(network.Mask).String(), nil
   253  		},
   254  	}
   255  }
   256  
   257  // interpolationFuncCidrSubnet implements the "cidrsubnet" function that
   258  // adds an additional subnet of the given length onto an existing
   259  // IP block expressed in CIDR notation.
   260  func interpolationFuncCidrSubnet() ast.Function {
   261  	return ast.Function{
   262  		ArgTypes: []ast.Type{
   263  			ast.TypeString, // starting CIDR mask
   264  			ast.TypeInt,    // number of bits to extend the prefix
   265  			ast.TypeInt,    // network number to append to the prefix
   266  		},
   267  		ReturnType: ast.TypeString,
   268  		Variadic:   false,
   269  		Callback: func(args []interface{}) (interface{}, error) {
   270  			extraBits := args[1].(int)
   271  			subnetNum := args[2].(int)
   272  			_, network, err := net.ParseCIDR(args[0].(string))
   273  			if err != nil {
   274  				return nil, fmt.Errorf("invalid CIDR expression: %s", err)
   275  			}
   276  
   277  			// For portability with 32-bit systems where the subnet number
   278  			// will be a 32-bit int, we only allow extension of 32 bits in
   279  			// one call even if we're running on a 64-bit machine.
   280  			// (Of course, this is significant only for IPv6.)
   281  			if extraBits > 32 {
   282  				return nil, fmt.Errorf("may not extend prefix by more than 32 bits")
   283  			}
   284  
   285  			newNetwork, err := cidr.Subnet(network, extraBits, subnetNum)
   286  			if err != nil {
   287  				return nil, err
   288  			}
   289  
   290  			return newNetwork.String(), nil
   291  		},
   292  	}
   293  }
   294  
   295  // interpolationFuncCoalesce implements the "coalesce" function that
   296  // returns the first non null / empty string from the provided input
   297  func interpolationFuncCoalesce() ast.Function {
   298  	return ast.Function{
   299  		ArgTypes:     []ast.Type{ast.TypeString},
   300  		ReturnType:   ast.TypeString,
   301  		Variadic:     true,
   302  		VariadicType: ast.TypeString,
   303  		Callback: func(args []interface{}) (interface{}, error) {
   304  			if len(args) < 2 {
   305  				return nil, fmt.Errorf("must provide at least two arguments")
   306  			}
   307  			for _, arg := range args {
   308  				argument := arg.(string)
   309  
   310  				if argument != "" {
   311  					return argument, nil
   312  				}
   313  			}
   314  			return "", nil
   315  		},
   316  	}
   317  }
   318  
   319  // interpolationFuncConcat implements the "concat" function that concatenates
   320  // multiple lists.
   321  func interpolationFuncConcat() ast.Function {
   322  	return ast.Function{
   323  		ArgTypes:     []ast.Type{ast.TypeList},
   324  		ReturnType:   ast.TypeList,
   325  		Variadic:     true,
   326  		VariadicType: ast.TypeList,
   327  		Callback: func(args []interface{}) (interface{}, error) {
   328  			var outputList []ast.Variable
   329  
   330  			for _, arg := range args {
   331  				for _, v := range arg.([]ast.Variable) {
   332  					switch v.Type {
   333  					case ast.TypeString:
   334  						outputList = append(outputList, v)
   335  					case ast.TypeList:
   336  						outputList = append(outputList, v)
   337  					case ast.TypeMap:
   338  						outputList = append(outputList, v)
   339  					default:
   340  						return nil, fmt.Errorf("concat() does not support lists of %s", v.Type.Printable())
   341  					}
   342  				}
   343  			}
   344  
   345  			// we don't support heterogeneous types, so make sure all types match the first
   346  			if len(outputList) > 0 {
   347  				firstType := outputList[0].Type
   348  				for _, v := range outputList[1:] {
   349  					if v.Type != firstType {
   350  						return nil, fmt.Errorf("unexpected %s in list of %s", v.Type.Printable(), firstType.Printable())
   351  					}
   352  				}
   353  			}
   354  
   355  			return outputList, nil
   356  		},
   357  	}
   358  }
   359  
   360  // interpolationFuncFile implements the "file" function that allows
   361  // loading contents from a file.
   362  func interpolationFuncFile() ast.Function {
   363  	return ast.Function{
   364  		ArgTypes:   []ast.Type{ast.TypeString},
   365  		ReturnType: ast.TypeString,
   366  		Callback: func(args []interface{}) (interface{}, error) {
   367  			path, err := homedir.Expand(args[0].(string))
   368  			if err != nil {
   369  				return "", err
   370  			}
   371  			data, err := ioutil.ReadFile(path)
   372  			if err != nil {
   373  				return "", err
   374  			}
   375  
   376  			return string(data), nil
   377  		},
   378  	}
   379  }
   380  
   381  // interpolationFuncFormat implements the "format" function that does
   382  // string formatting.
   383  func interpolationFuncFormat() ast.Function {
   384  	return ast.Function{
   385  		ArgTypes:     []ast.Type{ast.TypeString},
   386  		Variadic:     true,
   387  		VariadicType: ast.TypeAny,
   388  		ReturnType:   ast.TypeString,
   389  		Callback: func(args []interface{}) (interface{}, error) {
   390  			format := args[0].(string)
   391  			return fmt.Sprintf(format, args[1:]...), nil
   392  		},
   393  	}
   394  }
   395  
   396  // interpolationFuncMax returns the maximum of the numeric arguments
   397  func interpolationFuncMax() ast.Function {
   398  	return ast.Function{
   399  		ArgTypes:     []ast.Type{ast.TypeFloat},
   400  		ReturnType:   ast.TypeFloat,
   401  		Variadic:     true,
   402  		VariadicType: ast.TypeFloat,
   403  		Callback: func(args []interface{}) (interface{}, error) {
   404  			max := args[0].(float64)
   405  
   406  			for i := 1; i < len(args); i++ {
   407  				max = math.Max(max, args[i].(float64))
   408  			}
   409  
   410  			return max, nil
   411  		},
   412  	}
   413  }
   414  
   415  // interpolationFuncMin returns the minimum of the numeric arguments
   416  func interpolationFuncMin() ast.Function {
   417  	return ast.Function{
   418  		ArgTypes:     []ast.Type{ast.TypeFloat},
   419  		ReturnType:   ast.TypeFloat,
   420  		Variadic:     true,
   421  		VariadicType: ast.TypeFloat,
   422  		Callback: func(args []interface{}) (interface{}, error) {
   423  			min := args[0].(float64)
   424  
   425  			for i := 1; i < len(args); i++ {
   426  				min = math.Min(min, args[i].(float64))
   427  			}
   428  
   429  			return min, nil
   430  		},
   431  	}
   432  }
   433  
   434  // interpolationFuncCeil returns the the least integer value greater than or equal to the argument
   435  func interpolationFuncCeil() ast.Function {
   436  	return ast.Function{
   437  		ArgTypes:   []ast.Type{ast.TypeFloat},
   438  		ReturnType: ast.TypeInt,
   439  		Callback: func(args []interface{}) (interface{}, error) {
   440  			return int(math.Ceil(args[0].(float64))), nil
   441  		},
   442  	}
   443  }
   444  
   445  // interpolationFuncFloorreturns returns the greatest integer value less than or equal to the argument
   446  func interpolationFuncFloor() ast.Function {
   447  	return ast.Function{
   448  		ArgTypes:   []ast.Type{ast.TypeFloat},
   449  		ReturnType: ast.TypeInt,
   450  		Callback: func(args []interface{}) (interface{}, error) {
   451  			return int(math.Floor(args[0].(float64))), nil
   452  		},
   453  	}
   454  }
   455  
   456  func interpolationFuncZipMap() ast.Function {
   457  	return ast.Function{
   458  		ArgTypes: []ast.Type{
   459  			ast.TypeList, // Keys
   460  			ast.TypeList, // Values
   461  		},
   462  		ReturnType: ast.TypeMap,
   463  		Callback: func(args []interface{}) (interface{}, error) {
   464  			keys := args[0].([]ast.Variable)
   465  			values := args[1].([]ast.Variable)
   466  
   467  			if len(keys) != len(values) {
   468  				return nil, fmt.Errorf("count of keys (%d) does not match count of values (%d)",
   469  					len(keys), len(values))
   470  			}
   471  
   472  			for i, val := range keys {
   473  				if val.Type != ast.TypeString {
   474  					return nil, fmt.Errorf("keys must be strings. value at position %d is %s",
   475  						i, val.Type.Printable())
   476  				}
   477  			}
   478  
   479  			result := map[string]ast.Variable{}
   480  			for i := 0; i < len(keys); i++ {
   481  				result[keys[i].Value.(string)] = values[i]
   482  			}
   483  
   484  			return result, nil
   485  		},
   486  	}
   487  }
   488  
   489  // interpolationFuncFormatList implements the "formatlist" function that does
   490  // string formatting on lists.
   491  func interpolationFuncFormatList() ast.Function {
   492  	return ast.Function{
   493  		ArgTypes:     []ast.Type{ast.TypeAny},
   494  		Variadic:     true,
   495  		VariadicType: ast.TypeAny,
   496  		ReturnType:   ast.TypeList,
   497  		Callback: func(args []interface{}) (interface{}, error) {
   498  			// Make a copy of the variadic part of args
   499  			// to avoid modifying the original.
   500  			varargs := make([]interface{}, len(args)-1)
   501  			copy(varargs, args[1:])
   502  
   503  			// Verify we have some arguments
   504  			if len(varargs) == 0 {
   505  				return nil, fmt.Errorf("no arguments to formatlist")
   506  			}
   507  
   508  			// Convert arguments that are lists into slices.
   509  			// Confirm along the way that all lists have the same length (n).
   510  			var n int
   511  			listSeen := false
   512  			for i := 1; i < len(args); i++ {
   513  				s, ok := args[i].([]ast.Variable)
   514  				if !ok {
   515  					continue
   516  				}
   517  
   518  				// Mark that we've seen at least one list
   519  				listSeen = true
   520  
   521  				// Convert the ast.Variable to a slice of strings
   522  				parts, err := listVariableValueToStringSlice(s)
   523  				if err != nil {
   524  					return nil, err
   525  				}
   526  
   527  				// otherwise the list is sent down to be indexed
   528  				varargs[i-1] = parts
   529  
   530  				// Check length
   531  				if n == 0 {
   532  					// first list we've seen
   533  					n = len(parts)
   534  					continue
   535  				}
   536  				if n != len(parts) {
   537  					return nil, fmt.Errorf("format: mismatched list lengths: %d != %d", n, len(parts))
   538  				}
   539  			}
   540  
   541  			// If we didn't see a list this is an error because we
   542  			// can't determine the return value length.
   543  			if !listSeen {
   544  				return nil, fmt.Errorf(
   545  					"formatlist requires at least one list argument")
   546  			}
   547  
   548  			// Do the formatting.
   549  			format := args[0].(string)
   550  
   551  			// Generate a list of formatted strings.
   552  			list := make([]string, n)
   553  			fmtargs := make([]interface{}, len(varargs))
   554  			for i := 0; i < n; i++ {
   555  				for j, arg := range varargs {
   556  					switch arg := arg.(type) {
   557  					default:
   558  						fmtargs[j] = arg
   559  					case []string:
   560  						fmtargs[j] = arg[i]
   561  					}
   562  				}
   563  				list[i] = fmt.Sprintf(format, fmtargs...)
   564  			}
   565  			return stringSliceToVariableValue(list), nil
   566  		},
   567  	}
   568  }
   569  
   570  // interpolationFuncIndex implements the "index" function that allows one to
   571  // find the index of a specific element in a list
   572  func interpolationFuncIndex() ast.Function {
   573  	return ast.Function{
   574  		ArgTypes:   []ast.Type{ast.TypeList, ast.TypeString},
   575  		ReturnType: ast.TypeInt,
   576  		Callback: func(args []interface{}) (interface{}, error) {
   577  			haystack := args[0].([]ast.Variable)
   578  			needle := args[1].(string)
   579  			for index, element := range haystack {
   580  				if needle == element.Value {
   581  					return index, nil
   582  				}
   583  			}
   584  			return nil, fmt.Errorf("Could not find '%s' in '%s'", needle, haystack)
   585  		},
   586  	}
   587  }
   588  
   589  // interpolationFuncDistinct implements the "distinct" function that
   590  // removes duplicate elements from a list.
   591  func interpolationFuncDistinct() ast.Function {
   592  	return ast.Function{
   593  		ArgTypes:     []ast.Type{ast.TypeList},
   594  		ReturnType:   ast.TypeList,
   595  		Variadic:     true,
   596  		VariadicType: ast.TypeList,
   597  		Callback: func(args []interface{}) (interface{}, error) {
   598  			var list []string
   599  
   600  			if len(args) != 1 {
   601  				return nil, fmt.Errorf("accepts only one argument.")
   602  			}
   603  
   604  			if argument, ok := args[0].([]ast.Variable); ok {
   605  				for _, element := range argument {
   606  					if element.Type != ast.TypeString {
   607  						return nil, fmt.Errorf(
   608  							"only works for flat lists, this list contains elements of %s",
   609  							element.Type.Printable())
   610  					}
   611  					list = appendIfMissing(list, element.Value.(string))
   612  				}
   613  			}
   614  
   615  			return stringSliceToVariableValue(list), nil
   616  		},
   617  	}
   618  }
   619  
   620  // helper function to add an element to a list, if it does not already exsit
   621  func appendIfMissing(slice []string, element string) []string {
   622  	for _, ele := range slice {
   623  		if ele == element {
   624  			return slice
   625  		}
   626  	}
   627  	return append(slice, element)
   628  }
   629  
   630  // interpolationFuncJoin implements the "join" function that allows
   631  // multi-variable values to be joined by some character.
   632  func interpolationFuncJoin() ast.Function {
   633  	return ast.Function{
   634  		ArgTypes:     []ast.Type{ast.TypeString},
   635  		Variadic:     true,
   636  		VariadicType: ast.TypeList,
   637  		ReturnType:   ast.TypeString,
   638  		Callback: func(args []interface{}) (interface{}, error) {
   639  			var list []string
   640  
   641  			if len(args) < 2 {
   642  				return nil, fmt.Errorf("not enough arguments to join()")
   643  			}
   644  
   645  			for _, arg := range args[1:] {
   646  				for _, part := range arg.([]ast.Variable) {
   647  					if part.Type != ast.TypeString {
   648  						return nil, fmt.Errorf(
   649  							"only works on flat lists, this list contains elements of %s",
   650  							part.Type.Printable())
   651  					}
   652  					list = append(list, part.Value.(string))
   653  				}
   654  			}
   655  
   656  			return strings.Join(list, args[0].(string)), nil
   657  		},
   658  	}
   659  }
   660  
   661  // interpolationFuncJSONEncode implements the "jsonencode" function that encodes
   662  // a string, list, or map as its JSON representation. For now, values in the
   663  // list or map may only be strings.
   664  func interpolationFuncJSONEncode() ast.Function {
   665  	return ast.Function{
   666  		ArgTypes:   []ast.Type{ast.TypeAny},
   667  		ReturnType: ast.TypeString,
   668  		Callback: func(args []interface{}) (interface{}, error) {
   669  			var toEncode interface{}
   670  
   671  			switch typedArg := args[0].(type) {
   672  			case string:
   673  				toEncode = typedArg
   674  
   675  			case []ast.Variable:
   676  				// We preallocate the list here. Note that it's important that in
   677  				// the length 0 case, we have an empty list rather than nil, as
   678  				// they encode differently.
   679  				// XXX It would be nice to support arbitrarily nested data here. Is
   680  				// there an inverse of hil.InterfaceToVariable?
   681  				strings := make([]string, len(typedArg))
   682  
   683  				for i, v := range typedArg {
   684  					if v.Type != ast.TypeString {
   685  						return "", fmt.Errorf("list elements must be strings")
   686  					}
   687  					strings[i] = v.Value.(string)
   688  				}
   689  				toEncode = strings
   690  
   691  			case map[string]ast.Variable:
   692  				// XXX It would be nice to support arbitrarily nested data here. Is
   693  				// there an inverse of hil.InterfaceToVariable?
   694  				stringMap := make(map[string]string)
   695  				for k, v := range typedArg {
   696  					if v.Type != ast.TypeString {
   697  						return "", fmt.Errorf("map values must be strings")
   698  					}
   699  					stringMap[k] = v.Value.(string)
   700  				}
   701  				toEncode = stringMap
   702  
   703  			default:
   704  				return "", fmt.Errorf("unknown type for JSON encoding: %T", args[0])
   705  			}
   706  
   707  			jEnc, err := json.Marshal(toEncode)
   708  			if err != nil {
   709  				return "", fmt.Errorf("failed to encode JSON data '%s'", toEncode)
   710  			}
   711  			return string(jEnc), nil
   712  		},
   713  	}
   714  }
   715  
   716  // interpolationFuncReplace implements the "replace" function that does
   717  // string replacement.
   718  func interpolationFuncReplace() ast.Function {
   719  	return ast.Function{
   720  		ArgTypes:   []ast.Type{ast.TypeString, ast.TypeString, ast.TypeString},
   721  		ReturnType: ast.TypeString,
   722  		Callback: func(args []interface{}) (interface{}, error) {
   723  			s := args[0].(string)
   724  			search := args[1].(string)
   725  			replace := args[2].(string)
   726  
   727  			// We search/replace using a regexp if the string is surrounded
   728  			// in forward slashes.
   729  			if len(search) > 1 && search[0] == '/' && search[len(search)-1] == '/' {
   730  				re, err := regexp.Compile(search[1 : len(search)-1])
   731  				if err != nil {
   732  					return nil, err
   733  				}
   734  
   735  				return re.ReplaceAllString(s, replace), nil
   736  			}
   737  
   738  			return strings.Replace(s, search, replace, -1), nil
   739  		},
   740  	}
   741  }
   742  
   743  func interpolationFuncLength() ast.Function {
   744  	return ast.Function{
   745  		ArgTypes:   []ast.Type{ast.TypeAny},
   746  		ReturnType: ast.TypeInt,
   747  		Variadic:   false,
   748  		Callback: func(args []interface{}) (interface{}, error) {
   749  			subject := args[0]
   750  
   751  			switch typedSubject := subject.(type) {
   752  			case string:
   753  				return len(typedSubject), nil
   754  			case []ast.Variable:
   755  				return len(typedSubject), nil
   756  			case map[string]ast.Variable:
   757  				return len(typedSubject), nil
   758  			}
   759  
   760  			return 0, fmt.Errorf("arguments to length() must be a string, list, or map")
   761  		},
   762  	}
   763  }
   764  
   765  func interpolationFuncSignum() ast.Function {
   766  	return ast.Function{
   767  		ArgTypes:   []ast.Type{ast.TypeInt},
   768  		ReturnType: ast.TypeInt,
   769  		Variadic:   false,
   770  		Callback: func(args []interface{}) (interface{}, error) {
   771  			num := args[0].(int)
   772  			switch {
   773  			case num < 0:
   774  				return -1, nil
   775  			case num > 0:
   776  				return +1, nil
   777  			default:
   778  				return 0, nil
   779  			}
   780  		},
   781  	}
   782  }
   783  
   784  // interpolationFuncSort sorts a list of a strings lexographically
   785  func interpolationFuncSort() ast.Function {
   786  	return ast.Function{
   787  		ArgTypes:   []ast.Type{ast.TypeList},
   788  		ReturnType: ast.TypeList,
   789  		Variadic:   false,
   790  		Callback: func(args []interface{}) (interface{}, error) {
   791  			inputList := args[0].([]ast.Variable)
   792  
   793  			// Ensure that all the list members are strings and
   794  			// create a string slice from them
   795  			members := make([]string, len(inputList))
   796  			for i, val := range inputList {
   797  				if val.Type != ast.TypeString {
   798  					return nil, fmt.Errorf(
   799  						"sort() may only be used with lists of strings - %s at index %d",
   800  						val.Type.String(), i)
   801  				}
   802  
   803  				members[i] = val.Value.(string)
   804  			}
   805  
   806  			sort.Strings(members)
   807  			return stringSliceToVariableValue(members), nil
   808  		},
   809  	}
   810  }
   811  
   812  // interpolationFuncSplit implements the "split" function that allows
   813  // strings to split into multi-variable values
   814  func interpolationFuncSplit() ast.Function {
   815  	return ast.Function{
   816  		ArgTypes:   []ast.Type{ast.TypeString, ast.TypeString},
   817  		ReturnType: ast.TypeList,
   818  		Callback: func(args []interface{}) (interface{}, error) {
   819  			sep := args[0].(string)
   820  			s := args[1].(string)
   821  			elements := strings.Split(s, sep)
   822  			return stringSliceToVariableValue(elements), nil
   823  		},
   824  	}
   825  }
   826  
   827  // interpolationFuncLookup implements the "lookup" function that allows
   828  // dynamic lookups of map types within a Terraform configuration.
   829  func interpolationFuncLookup(vs map[string]ast.Variable) ast.Function {
   830  	return ast.Function{
   831  		ArgTypes:     []ast.Type{ast.TypeMap, ast.TypeString},
   832  		ReturnType:   ast.TypeString,
   833  		Variadic:     true,
   834  		VariadicType: ast.TypeString,
   835  		Callback: func(args []interface{}) (interface{}, error) {
   836  			defaultValue := ""
   837  			defaultValueSet := false
   838  			if len(args) > 2 {
   839  				defaultValue = args[2].(string)
   840  				defaultValueSet = true
   841  			}
   842  			if len(args) > 3 {
   843  				return "", fmt.Errorf("lookup() takes no more than three arguments")
   844  			}
   845  			index := args[1].(string)
   846  			mapVar := args[0].(map[string]ast.Variable)
   847  
   848  			v, ok := mapVar[index]
   849  			if !ok {
   850  				if defaultValueSet {
   851  					return defaultValue, nil
   852  				} else {
   853  					return "", fmt.Errorf(
   854  						"lookup failed to find '%s'",
   855  						args[1].(string))
   856  				}
   857  			}
   858  			if v.Type != ast.TypeString {
   859  				return nil, fmt.Errorf(
   860  					"lookup() may only be used with flat maps, this map contains elements of %s",
   861  					v.Type.Printable())
   862  			}
   863  
   864  			return v.Value.(string), nil
   865  		},
   866  	}
   867  }
   868  
   869  // interpolationFuncElement implements the "element" function that allows
   870  // a specific index to be looked up in a multi-variable value. Note that this will
   871  // wrap if the index is larger than the number of elements in the multi-variable value.
   872  func interpolationFuncElement() ast.Function {
   873  	return ast.Function{
   874  		ArgTypes:   []ast.Type{ast.TypeList, ast.TypeString},
   875  		ReturnType: ast.TypeString,
   876  		Callback: func(args []interface{}) (interface{}, error) {
   877  			list := args[0].([]ast.Variable)
   878  			if len(list) == 0 {
   879  				return nil, fmt.Errorf("element() may not be used with an empty list")
   880  			}
   881  
   882  			index, err := strconv.Atoi(args[1].(string))
   883  			if err != nil || index < 0 {
   884  				return "", fmt.Errorf(
   885  					"invalid number for index, got %s", args[1])
   886  			}
   887  
   888  			resolvedIndex := index % len(list)
   889  
   890  			v := list[resolvedIndex]
   891  			if v.Type != ast.TypeString {
   892  				return nil, fmt.Errorf(
   893  					"element() may only be used with flat lists, this list contains elements of %s",
   894  					v.Type.Printable())
   895  			}
   896  			return v.Value, nil
   897  		},
   898  	}
   899  }
   900  
   901  // interpolationFuncKeys implements the "keys" function that yields a list of
   902  // keys of map types within a Terraform configuration.
   903  func interpolationFuncKeys(vs map[string]ast.Variable) ast.Function {
   904  	return ast.Function{
   905  		ArgTypes:   []ast.Type{ast.TypeMap},
   906  		ReturnType: ast.TypeList,
   907  		Callback: func(args []interface{}) (interface{}, error) {
   908  			mapVar := args[0].(map[string]ast.Variable)
   909  			keys := make([]string, 0)
   910  
   911  			for k, _ := range mapVar {
   912  				keys = append(keys, k)
   913  			}
   914  
   915  			sort.Strings(keys)
   916  
   917  			// Keys are guaranteed to be strings
   918  			return stringSliceToVariableValue(keys), nil
   919  		},
   920  	}
   921  }
   922  
   923  // interpolationFuncValues implements the "values" function that yields a list of
   924  // keys of map types within a Terraform configuration.
   925  func interpolationFuncValues(vs map[string]ast.Variable) ast.Function {
   926  	return ast.Function{
   927  		ArgTypes:   []ast.Type{ast.TypeMap},
   928  		ReturnType: ast.TypeList,
   929  		Callback: func(args []interface{}) (interface{}, error) {
   930  			mapVar := args[0].(map[string]ast.Variable)
   931  			keys := make([]string, 0)
   932  
   933  			for k, _ := range mapVar {
   934  				keys = append(keys, k)
   935  			}
   936  
   937  			sort.Strings(keys)
   938  
   939  			values := make([]string, len(keys))
   940  			for index, key := range keys {
   941  				if value, ok := mapVar[key].Value.(string); ok {
   942  					values[index] = value
   943  				} else {
   944  					return "", fmt.Errorf("values(): %q has element with bad type %s",
   945  						key, mapVar[key].Type)
   946  				}
   947  			}
   948  
   949  			variable, err := hil.InterfaceToVariable(values)
   950  			if err != nil {
   951  				return nil, err
   952  			}
   953  
   954  			return variable.Value, nil
   955  		},
   956  	}
   957  }
   958  
   959  // interpolationFuncBase64Encode implements the "base64encode" function that
   960  // allows Base64 encoding.
   961  func interpolationFuncBase64Encode() ast.Function {
   962  	return ast.Function{
   963  		ArgTypes:   []ast.Type{ast.TypeString},
   964  		ReturnType: ast.TypeString,
   965  		Callback: func(args []interface{}) (interface{}, error) {
   966  			s := args[0].(string)
   967  			return base64.StdEncoding.EncodeToString([]byte(s)), nil
   968  		},
   969  	}
   970  }
   971  
   972  // interpolationFuncBase64Decode implements the "base64decode" function that
   973  // allows Base64 decoding.
   974  func interpolationFuncBase64Decode() ast.Function {
   975  	return ast.Function{
   976  		ArgTypes:   []ast.Type{ast.TypeString},
   977  		ReturnType: ast.TypeString,
   978  		Callback: func(args []interface{}) (interface{}, error) {
   979  			s := args[0].(string)
   980  			sDec, err := base64.StdEncoding.DecodeString(s)
   981  			if err != nil {
   982  				return "", fmt.Errorf("failed to decode base64 data '%s'", s)
   983  			}
   984  			return string(sDec), nil
   985  		},
   986  	}
   987  }
   988  
   989  // interpolationFuncLower implements the "lower" function that does
   990  // string lower casing.
   991  func interpolationFuncLower() ast.Function {
   992  	return ast.Function{
   993  		ArgTypes:   []ast.Type{ast.TypeString},
   994  		ReturnType: ast.TypeString,
   995  		Callback: func(args []interface{}) (interface{}, error) {
   996  			toLower := args[0].(string)
   997  			return strings.ToLower(toLower), nil
   998  		},
   999  	}
  1000  }
  1001  
  1002  func interpolationFuncMd5() ast.Function {
  1003  	return ast.Function{
  1004  		ArgTypes:   []ast.Type{ast.TypeString},
  1005  		ReturnType: ast.TypeString,
  1006  		Callback: func(args []interface{}) (interface{}, error) {
  1007  			s := args[0].(string)
  1008  			h := md5.New()
  1009  			h.Write([]byte(s))
  1010  			hash := hex.EncodeToString(h.Sum(nil))
  1011  			return hash, nil
  1012  		},
  1013  	}
  1014  }
  1015  
  1016  func interpolationFuncMerge() ast.Function {
  1017  	return ast.Function{
  1018  		ArgTypes:     []ast.Type{ast.TypeMap},
  1019  		ReturnType:   ast.TypeMap,
  1020  		Variadic:     true,
  1021  		VariadicType: ast.TypeMap,
  1022  		Callback: func(args []interface{}) (interface{}, error) {
  1023  			outputMap := make(map[string]ast.Variable)
  1024  
  1025  			for _, arg := range args {
  1026  				for k, v := range arg.(map[string]ast.Variable) {
  1027  					outputMap[k] = v
  1028  				}
  1029  			}
  1030  
  1031  			return outputMap, nil
  1032  		},
  1033  	}
  1034  }
  1035  
  1036  // interpolationFuncUpper implements the "upper" function that does
  1037  // string upper casing.
  1038  func interpolationFuncUpper() ast.Function {
  1039  	return ast.Function{
  1040  		ArgTypes:   []ast.Type{ast.TypeString},
  1041  		ReturnType: ast.TypeString,
  1042  		Callback: func(args []interface{}) (interface{}, error) {
  1043  			toUpper := args[0].(string)
  1044  			return strings.ToUpper(toUpper), nil
  1045  		},
  1046  	}
  1047  }
  1048  
  1049  func interpolationFuncSha1() ast.Function {
  1050  	return ast.Function{
  1051  		ArgTypes:   []ast.Type{ast.TypeString},
  1052  		ReturnType: ast.TypeString,
  1053  		Callback: func(args []interface{}) (interface{}, error) {
  1054  			s := args[0].(string)
  1055  			h := sha1.New()
  1056  			h.Write([]byte(s))
  1057  			hash := hex.EncodeToString(h.Sum(nil))
  1058  			return hash, nil
  1059  		},
  1060  	}
  1061  }
  1062  
  1063  // hexadecimal representation of sha256 sum
  1064  func interpolationFuncSha256() ast.Function {
  1065  	return ast.Function{
  1066  		ArgTypes:   []ast.Type{ast.TypeString},
  1067  		ReturnType: ast.TypeString,
  1068  		Callback: func(args []interface{}) (interface{}, error) {
  1069  			s := args[0].(string)
  1070  			h := sha256.New()
  1071  			h.Write([]byte(s))
  1072  			hash := hex.EncodeToString(h.Sum(nil))
  1073  			return hash, nil
  1074  		},
  1075  	}
  1076  }
  1077  
  1078  func interpolationFuncTrimSpace() ast.Function {
  1079  	return ast.Function{
  1080  		ArgTypes:   []ast.Type{ast.TypeString},
  1081  		ReturnType: ast.TypeString,
  1082  		Callback: func(args []interface{}) (interface{}, error) {
  1083  			trimSpace := args[0].(string)
  1084  			return strings.TrimSpace(trimSpace), nil
  1085  		},
  1086  	}
  1087  }
  1088  
  1089  func interpolationFuncBase64Sha256() ast.Function {
  1090  	return ast.Function{
  1091  		ArgTypes:   []ast.Type{ast.TypeString},
  1092  		ReturnType: ast.TypeString,
  1093  		Callback: func(args []interface{}) (interface{}, error) {
  1094  			s := args[0].(string)
  1095  			h := sha256.New()
  1096  			h.Write([]byte(s))
  1097  			shaSum := h.Sum(nil)
  1098  			encoded := base64.StdEncoding.EncodeToString(shaSum[:])
  1099  			return encoded, nil
  1100  		},
  1101  	}
  1102  }
  1103  
  1104  func interpolationFuncUUID() ast.Function {
  1105  	return ast.Function{
  1106  		ArgTypes:   []ast.Type{},
  1107  		ReturnType: ast.TypeString,
  1108  		Callback: func(args []interface{}) (interface{}, error) {
  1109  			return uuid.GenerateUUID()
  1110  		},
  1111  	}
  1112  }
  1113  
  1114  // interpolationFuncTimestamp
  1115  func interpolationFuncTimestamp() ast.Function {
  1116  	return ast.Function{
  1117  		ArgTypes:   []ast.Type{},
  1118  		ReturnType: ast.TypeString,
  1119  		Callback: func(args []interface{}) (interface{}, error) {
  1120  			return time.Now().UTC().Format(time.RFC3339), nil
  1121  		},
  1122  	}
  1123  }
  1124  
  1125  // interpolationFuncTitle implements the "title" function that returns a copy of the
  1126  // string in which first characters of all the words are capitalized.
  1127  func interpolationFuncTitle() ast.Function {
  1128  	return ast.Function{
  1129  		ArgTypes:   []ast.Type{ast.TypeString},
  1130  		ReturnType: ast.TypeString,
  1131  		Callback: func(args []interface{}) (interface{}, error) {
  1132  			toTitle := args[0].(string)
  1133  			return strings.Title(toTitle), nil
  1134  		},
  1135  	}
  1136  }