github.com/adrian-bl/terraform@v0.7.0-rc2.0.20160705220747-de0a34fc3517/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  	"errors"
    11  	"fmt"
    12  	"io/ioutil"
    13  	"net"
    14  	"regexp"
    15  	"sort"
    16  	"strconv"
    17  	"strings"
    18  
    19  	"github.com/apparentlymart/go-cidr/cidr"
    20  	"github.com/hashicorp/go-uuid"
    21  	"github.com/hashicorp/hil"
    22  	"github.com/hashicorp/hil/ast"
    23  	"github.com/mitchellh/go-homedir"
    24  )
    25  
    26  // stringSliceToVariableValue converts a string slice into the value
    27  // required to be returned from interpolation functions which return
    28  // TypeList.
    29  func stringSliceToVariableValue(values []string) []ast.Variable {
    30  	output := make([]ast.Variable, len(values))
    31  	for index, value := range values {
    32  		output[index] = ast.Variable{
    33  			Type:  ast.TypeString,
    34  			Value: value,
    35  		}
    36  	}
    37  	return output
    38  }
    39  
    40  func listVariableValueToStringSlice(values []ast.Variable) ([]string, error) {
    41  	output := make([]string, len(values))
    42  	for index, value := range values {
    43  		if value.Type != ast.TypeString {
    44  			return []string{}, fmt.Errorf("list has non-string element (%T)", value.Type.String())
    45  		}
    46  		output[index] = value.Value.(string)
    47  	}
    48  	return output, nil
    49  }
    50  
    51  // Funcs is the mapping of built-in functions for configuration.
    52  func Funcs() map[string]ast.Function {
    53  	return map[string]ast.Function{
    54  		"base64decode": interpolationFuncBase64Decode(),
    55  		"base64encode": interpolationFuncBase64Encode(),
    56  		"base64sha256": interpolationFuncBase64Sha256(),
    57  		"cidrhost":     interpolationFuncCidrHost(),
    58  		"cidrnetmask":  interpolationFuncCidrNetmask(),
    59  		"cidrsubnet":   interpolationFuncCidrSubnet(),
    60  		"coalesce":     interpolationFuncCoalesce(),
    61  		"compact":      interpolationFuncCompact(),
    62  		"concat":       interpolationFuncConcat(),
    63  		"distinct":     interpolationFuncDistinct(),
    64  		"element":      interpolationFuncElement(),
    65  		"file":         interpolationFuncFile(),
    66  		"format":       interpolationFuncFormat(),
    67  		"formatlist":   interpolationFuncFormatList(),
    68  		"index":        interpolationFuncIndex(),
    69  		"join":         interpolationFuncJoin(),
    70  		"jsonencode":   interpolationFuncJSONEncode(),
    71  		"length":       interpolationFuncLength(),
    72  		"lower":        interpolationFuncLower(),
    73  		"md5":          interpolationFuncMd5(),
    74  		"uuid":         interpolationFuncUUID(),
    75  		"replace":      interpolationFuncReplace(),
    76  		"sha1":         interpolationFuncSha1(),
    77  		"sha256":       interpolationFuncSha256(),
    78  		"signum":       interpolationFuncSignum(),
    79  		"sort":         interpolationFuncSort(),
    80  		"split":        interpolationFuncSplit(),
    81  		"trimspace":    interpolationFuncTrimSpace(),
    82  		"upper":        interpolationFuncUpper(),
    83  	}
    84  }
    85  
    86  // interpolationFuncCompact strips a list of multi-variable values
    87  // (e.g. as returned by "split") of any empty strings.
    88  func interpolationFuncCompact() ast.Function {
    89  	return ast.Function{
    90  		ArgTypes:   []ast.Type{ast.TypeList},
    91  		ReturnType: ast.TypeList,
    92  		Variadic:   false,
    93  		Callback: func(args []interface{}) (interface{}, error) {
    94  			inputList := args[0].([]ast.Variable)
    95  
    96  			var outputList []string
    97  			for _, val := range inputList {
    98  				if strVal, ok := val.Value.(string); ok {
    99  					if strVal == "" {
   100  						continue
   101  					}
   102  
   103  					outputList = append(outputList, strVal)
   104  				}
   105  			}
   106  			return stringSliceToVariableValue(outputList), nil
   107  		},
   108  	}
   109  }
   110  
   111  // interpolationFuncCidrHost implements the "cidrhost" function that
   112  // fills in the host part of a CIDR range address to create a single
   113  // host address
   114  func interpolationFuncCidrHost() ast.Function {
   115  	return ast.Function{
   116  		ArgTypes: []ast.Type{
   117  			ast.TypeString, // starting CIDR mask
   118  			ast.TypeInt,    // host number to insert
   119  		},
   120  		ReturnType: ast.TypeString,
   121  		Variadic:   false,
   122  		Callback: func(args []interface{}) (interface{}, error) {
   123  			hostNum := args[1].(int)
   124  			_, network, err := net.ParseCIDR(args[0].(string))
   125  			if err != nil {
   126  				return nil, fmt.Errorf("invalid CIDR expression: %s", err)
   127  			}
   128  
   129  			ip, err := cidr.Host(network, hostNum)
   130  			if err != nil {
   131  				return nil, err
   132  			}
   133  
   134  			return ip.String(), nil
   135  		},
   136  	}
   137  }
   138  
   139  // interpolationFuncCidrNetmask implements the "cidrnetmask" function
   140  // that returns the subnet mask in IP address notation.
   141  func interpolationFuncCidrNetmask() ast.Function {
   142  	return ast.Function{
   143  		ArgTypes: []ast.Type{
   144  			ast.TypeString, // CIDR mask
   145  		},
   146  		ReturnType: ast.TypeString,
   147  		Variadic:   false,
   148  		Callback: func(args []interface{}) (interface{}, error) {
   149  			_, network, err := net.ParseCIDR(args[0].(string))
   150  			if err != nil {
   151  				return nil, fmt.Errorf("invalid CIDR expression: %s", err)
   152  			}
   153  
   154  			return net.IP(network.Mask).String(), nil
   155  		},
   156  	}
   157  }
   158  
   159  // interpolationFuncCidrSubnet implements the "cidrsubnet" function that
   160  // adds an additional subnet of the given length onto an existing
   161  // IP block expressed in CIDR notation.
   162  func interpolationFuncCidrSubnet() ast.Function {
   163  	return ast.Function{
   164  		ArgTypes: []ast.Type{
   165  			ast.TypeString, // starting CIDR mask
   166  			ast.TypeInt,    // number of bits to extend the prefix
   167  			ast.TypeInt,    // network number to append to the prefix
   168  		},
   169  		ReturnType: ast.TypeString,
   170  		Variadic:   false,
   171  		Callback: func(args []interface{}) (interface{}, error) {
   172  			extraBits := args[1].(int)
   173  			subnetNum := args[2].(int)
   174  			_, network, err := net.ParseCIDR(args[0].(string))
   175  			if err != nil {
   176  				return nil, fmt.Errorf("invalid CIDR expression: %s", err)
   177  			}
   178  
   179  			// For portability with 32-bit systems where the subnet number
   180  			// will be a 32-bit int, we only allow extension of 32 bits in
   181  			// one call even if we're running on a 64-bit machine.
   182  			// (Of course, this is significant only for IPv6.)
   183  			if extraBits > 32 {
   184  				return nil, fmt.Errorf("may not extend prefix by more than 32 bits")
   185  			}
   186  
   187  			newNetwork, err := cidr.Subnet(network, extraBits, subnetNum)
   188  			if err != nil {
   189  				return nil, err
   190  			}
   191  
   192  			return newNetwork.String(), nil
   193  		},
   194  	}
   195  }
   196  
   197  // interpolationFuncCoalesce implements the "coalesce" function that
   198  // returns the first non null / empty string from the provided input
   199  func interpolationFuncCoalesce() ast.Function {
   200  	return ast.Function{
   201  		ArgTypes:     []ast.Type{ast.TypeString},
   202  		ReturnType:   ast.TypeString,
   203  		Variadic:     true,
   204  		VariadicType: ast.TypeString,
   205  		Callback: func(args []interface{}) (interface{}, error) {
   206  			if len(args) < 2 {
   207  				return nil, fmt.Errorf("must provide at least two arguments")
   208  			}
   209  			for _, arg := range args {
   210  				argument := arg.(string)
   211  
   212  				if argument != "" {
   213  					return argument, nil
   214  				}
   215  			}
   216  			return "", nil
   217  		},
   218  	}
   219  }
   220  
   221  // interpolationFuncConcat implements the "concat" function that
   222  // concatenates multiple strings. This isn't actually necessary anymore
   223  // since our language supports string concat natively, but for backwards
   224  // compat we do this.
   225  func interpolationFuncConcat() ast.Function {
   226  	return ast.Function{
   227  		ArgTypes:     []ast.Type{ast.TypeAny},
   228  		ReturnType:   ast.TypeList,
   229  		Variadic:     true,
   230  		VariadicType: ast.TypeAny,
   231  		Callback: func(args []interface{}) (interface{}, error) {
   232  			var finalListElements []string
   233  
   234  			for _, arg := range args {
   235  				// Append strings for backward compatibility
   236  				if argument, ok := arg.(string); ok {
   237  					finalListElements = append(finalListElements, argument)
   238  					continue
   239  				}
   240  
   241  				// Otherwise variables
   242  				if argument, ok := arg.([]ast.Variable); ok {
   243  					for _, element := range argument {
   244  						t := element.Type
   245  						switch t {
   246  						case ast.TypeString:
   247  							finalListElements = append(finalListElements, element.Value.(string))
   248  						default:
   249  							return nil, fmt.Errorf("concat() does not support lists of %s", t.Printable())
   250  						}
   251  					}
   252  					continue
   253  				}
   254  
   255  				return nil, fmt.Errorf("arguments to concat() must be a string or list of strings")
   256  			}
   257  
   258  			return stringSliceToVariableValue(finalListElements), nil
   259  		},
   260  	}
   261  }
   262  
   263  // interpolationFuncFile implements the "file" function that allows
   264  // loading contents from a file.
   265  func interpolationFuncFile() ast.Function {
   266  	return ast.Function{
   267  		ArgTypes:   []ast.Type{ast.TypeString},
   268  		ReturnType: ast.TypeString,
   269  		Callback: func(args []interface{}) (interface{}, error) {
   270  			path, err := homedir.Expand(args[0].(string))
   271  			if err != nil {
   272  				return "", err
   273  			}
   274  			data, err := ioutil.ReadFile(path)
   275  			if err != nil {
   276  				return "", err
   277  			}
   278  
   279  			return string(data), nil
   280  		},
   281  	}
   282  }
   283  
   284  // interpolationFuncFormat implements the "format" function that does
   285  // string formatting.
   286  func interpolationFuncFormat() ast.Function {
   287  	return ast.Function{
   288  		ArgTypes:     []ast.Type{ast.TypeString},
   289  		Variadic:     true,
   290  		VariadicType: ast.TypeAny,
   291  		ReturnType:   ast.TypeString,
   292  		Callback: func(args []interface{}) (interface{}, error) {
   293  			format := args[0].(string)
   294  			return fmt.Sprintf(format, args[1:]...), nil
   295  		},
   296  	}
   297  }
   298  
   299  // interpolationFuncFormatList implements the "formatlist" function that does
   300  // string formatting on lists.
   301  func interpolationFuncFormatList() ast.Function {
   302  	return ast.Function{
   303  		ArgTypes:     []ast.Type{ast.TypeAny},
   304  		Variadic:     true,
   305  		VariadicType: ast.TypeAny,
   306  		ReturnType:   ast.TypeList,
   307  		Callback: func(args []interface{}) (interface{}, error) {
   308  			// Make a copy of the variadic part of args
   309  			// to avoid modifying the original.
   310  			varargs := make([]interface{}, len(args)-1)
   311  			copy(varargs, args[1:])
   312  
   313  			// Convert arguments that are lists into slices.
   314  			// Confirm along the way that all lists have the same length (n).
   315  			var n int
   316  			for i := 1; i < len(args); i++ {
   317  				s, ok := args[i].([]ast.Variable)
   318  				if !ok {
   319  					continue
   320  				}
   321  
   322  				parts, err := listVariableValueToStringSlice(s)
   323  				if err != nil {
   324  					return nil, err
   325  				}
   326  
   327  				// otherwise the list is sent down to be indexed
   328  				varargs[i-1] = parts
   329  
   330  				// Check length
   331  				if n == 0 {
   332  					// first list we've seen
   333  					n = len(parts)
   334  					continue
   335  				}
   336  				if n != len(parts) {
   337  					return nil, fmt.Errorf("format: mismatched list lengths: %d != %d", n, len(parts))
   338  				}
   339  			}
   340  
   341  			if n == 0 {
   342  				return nil, errors.New("no lists in arguments to formatlist")
   343  			}
   344  
   345  			// Do the formatting.
   346  			format := args[0].(string)
   347  
   348  			// Generate a list of formatted strings.
   349  			list := make([]string, n)
   350  			fmtargs := make([]interface{}, len(varargs))
   351  			for i := 0; i < n; i++ {
   352  				for j, arg := range varargs {
   353  					switch arg := arg.(type) {
   354  					default:
   355  						fmtargs[j] = arg
   356  					case []string:
   357  						fmtargs[j] = arg[i]
   358  					}
   359  				}
   360  				list[i] = fmt.Sprintf(format, fmtargs...)
   361  			}
   362  			return stringSliceToVariableValue(list), nil
   363  		},
   364  	}
   365  }
   366  
   367  // interpolationFuncIndex implements the "index" function that allows one to
   368  // find the index of a specific element in a list
   369  func interpolationFuncIndex() ast.Function {
   370  	return ast.Function{
   371  		ArgTypes:   []ast.Type{ast.TypeList, ast.TypeString},
   372  		ReturnType: ast.TypeInt,
   373  		Callback: func(args []interface{}) (interface{}, error) {
   374  			haystack := args[0].([]ast.Variable)
   375  			needle := args[1].(string)
   376  			for index, element := range haystack {
   377  				if needle == element.Value {
   378  					return index, nil
   379  				}
   380  			}
   381  			return nil, fmt.Errorf("Could not find '%s' in '%s'", needle, haystack)
   382  		},
   383  	}
   384  }
   385  
   386  // interpolationFuncDistinct implements the "distinct" function that
   387  // removes duplicate elements from a list.
   388  func interpolationFuncDistinct() ast.Function {
   389  	return ast.Function{
   390  		ArgTypes:     []ast.Type{ast.TypeList},
   391  		ReturnType:   ast.TypeList,
   392  		Variadic:     true,
   393  		VariadicType: ast.TypeList,
   394  		Callback: func(args []interface{}) (interface{}, error) {
   395  			var list []string
   396  
   397  			if len(args) != 1 {
   398  				return nil, fmt.Errorf("distinct() excepts only one argument.")
   399  			}
   400  
   401  			if argument, ok := args[0].([]ast.Variable); ok {
   402  				for _, element := range argument {
   403  					list = appendIfMissing(list, element.Value.(string))
   404  				}
   405  			}
   406  
   407  			return stringSliceToVariableValue(list), nil
   408  		},
   409  	}
   410  }
   411  
   412  // helper function to add an element to a list, if it does not already exsit
   413  func appendIfMissing(slice []string, element string) []string {
   414  	for _, ele := range slice {
   415  		if ele == element {
   416  			return slice
   417  		}
   418  	}
   419  	return append(slice, element)
   420  }
   421  
   422  // interpolationFuncJoin implements the "join" function that allows
   423  // multi-variable values to be joined by some character.
   424  func interpolationFuncJoin() ast.Function {
   425  	return ast.Function{
   426  		ArgTypes:     []ast.Type{ast.TypeString},
   427  		Variadic:     true,
   428  		VariadicType: ast.TypeList,
   429  		ReturnType:   ast.TypeString,
   430  		Callback: func(args []interface{}) (interface{}, error) {
   431  			var list []string
   432  
   433  			if len(args) < 2 {
   434  				return nil, fmt.Errorf("not enough arguments to join()")
   435  			}
   436  
   437  			for _, arg := range args[1:] {
   438  				if parts, ok := arg.(ast.Variable); ok {
   439  					for _, part := range parts.Value.([]ast.Variable) {
   440  						list = append(list, part.Value.(string))
   441  					}
   442  				}
   443  				if parts, ok := arg.([]ast.Variable); ok {
   444  					for _, part := range parts {
   445  						list = append(list, part.Value.(string))
   446  					}
   447  				}
   448  			}
   449  
   450  			return strings.Join(list, args[0].(string)), nil
   451  		},
   452  	}
   453  }
   454  
   455  // interpolationFuncJSONEncode implements the "jsonencode" function that encodes
   456  // a string, list, or map as its JSON representation. For now, values in the
   457  // list or map may only be strings.
   458  func interpolationFuncJSONEncode() ast.Function {
   459  	return ast.Function{
   460  		ArgTypes:   []ast.Type{ast.TypeAny},
   461  		ReturnType: ast.TypeString,
   462  		Callback: func(args []interface{}) (interface{}, error) {
   463  			var toEncode interface{}
   464  
   465  			switch typedArg := args[0].(type) {
   466  			case string:
   467  				toEncode = typedArg
   468  
   469  			case []ast.Variable:
   470  				// We preallocate the list here. Note that it's important that in
   471  				// the length 0 case, we have an empty list rather than nil, as
   472  				// they encode differently.
   473  				// XXX It would be nice to support arbitrarily nested data here. Is
   474  				// there an inverse of hil.InterfaceToVariable?
   475  				strings := make([]string, len(typedArg))
   476  
   477  				for i, v := range typedArg {
   478  					if v.Type != ast.TypeString {
   479  						return "", fmt.Errorf("list elements must be strings")
   480  					}
   481  					strings[i] = v.Value.(string)
   482  				}
   483  				toEncode = strings
   484  
   485  			case map[string]ast.Variable:
   486  				// XXX It would be nice to support arbitrarily nested data here. Is
   487  				// there an inverse of hil.InterfaceToVariable?
   488  				stringMap := make(map[string]string)
   489  				for k, v := range typedArg {
   490  					if v.Type != ast.TypeString {
   491  						return "", fmt.Errorf("map values must be strings")
   492  					}
   493  					stringMap[k] = v.Value.(string)
   494  				}
   495  				toEncode = stringMap
   496  
   497  			default:
   498  				return "", fmt.Errorf("unknown type for JSON encoding: %T", args[0])
   499  			}
   500  
   501  			jEnc, err := json.Marshal(toEncode)
   502  			if err != nil {
   503  				return "", fmt.Errorf("failed to encode JSON data '%s'", toEncode)
   504  			}
   505  			return string(jEnc), nil
   506  		},
   507  	}
   508  }
   509  
   510  // interpolationFuncReplace implements the "replace" function that does
   511  // string replacement.
   512  func interpolationFuncReplace() ast.Function {
   513  	return ast.Function{
   514  		ArgTypes:   []ast.Type{ast.TypeString, ast.TypeString, ast.TypeString},
   515  		ReturnType: ast.TypeString,
   516  		Callback: func(args []interface{}) (interface{}, error) {
   517  			s := args[0].(string)
   518  			search := args[1].(string)
   519  			replace := args[2].(string)
   520  
   521  			// We search/replace using a regexp if the string is surrounded
   522  			// in forward slashes.
   523  			if len(search) > 1 && search[0] == '/' && search[len(search)-1] == '/' {
   524  				re, err := regexp.Compile(search[1 : len(search)-1])
   525  				if err != nil {
   526  					return nil, err
   527  				}
   528  
   529  				return re.ReplaceAllString(s, replace), nil
   530  			}
   531  
   532  			return strings.Replace(s, search, replace, -1), nil
   533  		},
   534  	}
   535  }
   536  
   537  func interpolationFuncLength() ast.Function {
   538  	return ast.Function{
   539  		ArgTypes:   []ast.Type{ast.TypeAny},
   540  		ReturnType: ast.TypeInt,
   541  		Variadic:   false,
   542  		Callback: func(args []interface{}) (interface{}, error) {
   543  			subject := args[0]
   544  
   545  			switch typedSubject := subject.(type) {
   546  			case string:
   547  				return len(typedSubject), nil
   548  			case []ast.Variable:
   549  				return len(typedSubject), nil
   550  			}
   551  
   552  			return 0, fmt.Errorf("arguments to length() must be a string or list")
   553  		},
   554  	}
   555  }
   556  
   557  func interpolationFuncSignum() ast.Function {
   558  	return ast.Function{
   559  		ArgTypes:   []ast.Type{ast.TypeInt},
   560  		ReturnType: ast.TypeInt,
   561  		Variadic:   false,
   562  		Callback: func(args []interface{}) (interface{}, error) {
   563  			num := args[0].(int)
   564  			switch {
   565  			case num < 0:
   566  				return -1, nil
   567  			case num > 0:
   568  				return +1, nil
   569  			default:
   570  				return 0, nil
   571  			}
   572  		},
   573  	}
   574  }
   575  
   576  // interpolationFuncSort sorts a list of a strings lexographically
   577  func interpolationFuncSort() ast.Function {
   578  	return ast.Function{
   579  		ArgTypes:   []ast.Type{ast.TypeList},
   580  		ReturnType: ast.TypeList,
   581  		Variadic:   false,
   582  		Callback: func(args []interface{}) (interface{}, error) {
   583  			inputList := args[0].([]ast.Variable)
   584  
   585  			// Ensure that all the list members are strings and
   586  			// create a string slice from them
   587  			members := make([]string, len(inputList))
   588  			for i, val := range inputList {
   589  				if val.Type != ast.TypeString {
   590  					return nil, fmt.Errorf(
   591  						"sort() may only be used with lists of strings - %s at index %d",
   592  						val.Type.String(), i)
   593  				}
   594  
   595  				members[i] = val.Value.(string)
   596  			}
   597  
   598  			sort.Strings(members)
   599  			return stringSliceToVariableValue(members), nil
   600  		},
   601  	}
   602  }
   603  
   604  // interpolationFuncSplit implements the "split" function that allows
   605  // strings to split into multi-variable values
   606  func interpolationFuncSplit() ast.Function {
   607  	return ast.Function{
   608  		ArgTypes:   []ast.Type{ast.TypeString, ast.TypeString},
   609  		ReturnType: ast.TypeList,
   610  		Callback: func(args []interface{}) (interface{}, error) {
   611  			sep := args[0].(string)
   612  			s := args[1].(string)
   613  			elements := strings.Split(s, sep)
   614  			return stringSliceToVariableValue(elements), nil
   615  		},
   616  	}
   617  }
   618  
   619  // interpolationFuncLookup implements the "lookup" function that allows
   620  // dynamic lookups of map types within a Terraform configuration.
   621  func interpolationFuncLookup(vs map[string]ast.Variable) ast.Function {
   622  	return ast.Function{
   623  		ArgTypes:     []ast.Type{ast.TypeMap, ast.TypeString},
   624  		ReturnType:   ast.TypeString,
   625  		Variadic:     true,
   626  		VariadicType: ast.TypeString,
   627  		Callback: func(args []interface{}) (interface{}, error) {
   628  			defaultValue := ""
   629  			defaultValueSet := false
   630  			if len(args) > 2 {
   631  				defaultValue = args[2].(string)
   632  				defaultValueSet = true
   633  			}
   634  			if len(args) > 3 {
   635  				return "", fmt.Errorf("lookup() takes no more than three arguments")
   636  			}
   637  			index := args[1].(string)
   638  			mapVar := args[0].(map[string]ast.Variable)
   639  
   640  			v, ok := mapVar[index]
   641  			if !ok {
   642  				if defaultValueSet {
   643  					return defaultValue, nil
   644  				} else {
   645  					return "", fmt.Errorf(
   646  						"lookup failed to find '%s'",
   647  						args[1].(string))
   648  				}
   649  			}
   650  			if v.Type != ast.TypeString {
   651  				return "", fmt.Errorf(
   652  					"lookup for '%s' has bad type %s",
   653  					args[1].(string), v.Type)
   654  			}
   655  
   656  			return v.Value.(string), nil
   657  		},
   658  	}
   659  }
   660  
   661  // interpolationFuncElement implements the "element" function that allows
   662  // a specific index to be looked up in a multi-variable value. Note that this will
   663  // wrap if the index is larger than the number of elements in the multi-variable value.
   664  func interpolationFuncElement() ast.Function {
   665  	return ast.Function{
   666  		ArgTypes:   []ast.Type{ast.TypeList, ast.TypeString},
   667  		ReturnType: ast.TypeString,
   668  		Callback: func(args []interface{}) (interface{}, error) {
   669  			list := args[0].([]ast.Variable)
   670  			if len(list) == 0 {
   671  				return nil, fmt.Errorf("element() may not be used with an empty list")
   672  			}
   673  
   674  			index, err := strconv.Atoi(args[1].(string))
   675  			if err != nil || index < 0 {
   676  				return "", fmt.Errorf(
   677  					"invalid number for index, got %s", args[1])
   678  			}
   679  
   680  			resolvedIndex := index % len(list)
   681  
   682  			v := list[resolvedIndex].Value
   683  			return v, nil
   684  		},
   685  	}
   686  }
   687  
   688  // interpolationFuncKeys implements the "keys" function that yields a list of
   689  // keys of map types within a Terraform configuration.
   690  func interpolationFuncKeys(vs map[string]ast.Variable) ast.Function {
   691  	return ast.Function{
   692  		ArgTypes:   []ast.Type{ast.TypeMap},
   693  		ReturnType: ast.TypeList,
   694  		Callback: func(args []interface{}) (interface{}, error) {
   695  			mapVar := args[0].(map[string]ast.Variable)
   696  			keys := make([]string, 0)
   697  
   698  			for k, _ := range mapVar {
   699  				keys = append(keys, k)
   700  			}
   701  
   702  			sort.Strings(keys)
   703  
   704  			//Keys are guaranteed to be strings
   705  			return stringSliceToVariableValue(keys), nil
   706  		},
   707  	}
   708  }
   709  
   710  // interpolationFuncValues implements the "values" function that yields a list of
   711  // keys of map types within a Terraform configuration.
   712  func interpolationFuncValues(vs map[string]ast.Variable) ast.Function {
   713  	return ast.Function{
   714  		ArgTypes:   []ast.Type{ast.TypeMap},
   715  		ReturnType: ast.TypeList,
   716  		Callback: func(args []interface{}) (interface{}, error) {
   717  			mapVar := args[0].(map[string]ast.Variable)
   718  			keys := make([]string, 0)
   719  
   720  			for k, _ := range mapVar {
   721  				keys = append(keys, k)
   722  			}
   723  
   724  			sort.Strings(keys)
   725  
   726  			values := make([]string, len(keys))
   727  			for index, key := range keys {
   728  				if value, ok := mapVar[key].Value.(string); ok {
   729  					values[index] = value
   730  				} else {
   731  					return "", fmt.Errorf("values(): %q has element with bad type %s",
   732  						key, mapVar[key].Type)
   733  				}
   734  			}
   735  
   736  			variable, err := hil.InterfaceToVariable(values)
   737  			if err != nil {
   738  				return nil, err
   739  			}
   740  
   741  			return variable.Value, nil
   742  		},
   743  	}
   744  }
   745  
   746  // interpolationFuncBase64Encode implements the "base64encode" function that
   747  // allows Base64 encoding.
   748  func interpolationFuncBase64Encode() ast.Function {
   749  	return ast.Function{
   750  		ArgTypes:   []ast.Type{ast.TypeString},
   751  		ReturnType: ast.TypeString,
   752  		Callback: func(args []interface{}) (interface{}, error) {
   753  			s := args[0].(string)
   754  			return base64.StdEncoding.EncodeToString([]byte(s)), nil
   755  		},
   756  	}
   757  }
   758  
   759  // interpolationFuncBase64Decode implements the "base64decode" function that
   760  // allows Base64 decoding.
   761  func interpolationFuncBase64Decode() ast.Function {
   762  	return ast.Function{
   763  		ArgTypes:   []ast.Type{ast.TypeString},
   764  		ReturnType: ast.TypeString,
   765  		Callback: func(args []interface{}) (interface{}, error) {
   766  			s := args[0].(string)
   767  			sDec, err := base64.StdEncoding.DecodeString(s)
   768  			if err != nil {
   769  				return "", fmt.Errorf("failed to decode base64 data '%s'", s)
   770  			}
   771  			return string(sDec), nil
   772  		},
   773  	}
   774  }
   775  
   776  // interpolationFuncLower implements the "lower" function that does
   777  // string lower casing.
   778  func interpolationFuncLower() ast.Function {
   779  	return ast.Function{
   780  		ArgTypes:   []ast.Type{ast.TypeString},
   781  		ReturnType: ast.TypeString,
   782  		Callback: func(args []interface{}) (interface{}, error) {
   783  			toLower := args[0].(string)
   784  			return strings.ToLower(toLower), nil
   785  		},
   786  	}
   787  }
   788  
   789  func interpolationFuncMd5() ast.Function {
   790  	return ast.Function{
   791  		ArgTypes:   []ast.Type{ast.TypeString},
   792  		ReturnType: ast.TypeString,
   793  		Callback: func(args []interface{}) (interface{}, error) {
   794  			s := args[0].(string)
   795  			h := md5.New()
   796  			h.Write([]byte(s))
   797  			hash := hex.EncodeToString(h.Sum(nil))
   798  			return hash, nil
   799  		},
   800  	}
   801  }
   802  
   803  // interpolationFuncUpper implements the "upper" function that does
   804  // string upper casing.
   805  func interpolationFuncUpper() ast.Function {
   806  	return ast.Function{
   807  		ArgTypes:   []ast.Type{ast.TypeString},
   808  		ReturnType: ast.TypeString,
   809  		Callback: func(args []interface{}) (interface{}, error) {
   810  			toUpper := args[0].(string)
   811  			return strings.ToUpper(toUpper), nil
   812  		},
   813  	}
   814  }
   815  
   816  func interpolationFuncSha1() ast.Function {
   817  	return ast.Function{
   818  		ArgTypes:   []ast.Type{ast.TypeString},
   819  		ReturnType: ast.TypeString,
   820  		Callback: func(args []interface{}) (interface{}, error) {
   821  			s := args[0].(string)
   822  			h := sha1.New()
   823  			h.Write([]byte(s))
   824  			hash := hex.EncodeToString(h.Sum(nil))
   825  			return hash, nil
   826  		},
   827  	}
   828  }
   829  
   830  // hexadecimal representation of sha256 sum
   831  func interpolationFuncSha256() ast.Function {
   832  	return ast.Function{
   833  		ArgTypes:   []ast.Type{ast.TypeString},
   834  		ReturnType: ast.TypeString,
   835  		Callback: func(args []interface{}) (interface{}, error) {
   836  			s := args[0].(string)
   837  			h := sha256.New()
   838  			h.Write([]byte(s))
   839  			hash := hex.EncodeToString(h.Sum(nil))
   840  			return hash, nil
   841  		},
   842  	}
   843  }
   844  
   845  func interpolationFuncTrimSpace() ast.Function {
   846  	return ast.Function{
   847  		ArgTypes:   []ast.Type{ast.TypeString},
   848  		ReturnType: ast.TypeString,
   849  		Callback: func(args []interface{}) (interface{}, error) {
   850  			trimSpace := args[0].(string)
   851  			return strings.TrimSpace(trimSpace), nil
   852  		},
   853  	}
   854  }
   855  
   856  func interpolationFuncBase64Sha256() ast.Function {
   857  	return ast.Function{
   858  		ArgTypes:   []ast.Type{ast.TypeString},
   859  		ReturnType: ast.TypeString,
   860  		Callback: func(args []interface{}) (interface{}, error) {
   861  			s := args[0].(string)
   862  			h := sha256.New()
   863  			h.Write([]byte(s))
   864  			shaSum := h.Sum(nil)
   865  			encoded := base64.StdEncoding.EncodeToString(shaSum[:])
   866  			return encoded, nil
   867  		},
   868  	}
   869  }
   870  
   871  func interpolationFuncUUID() ast.Function {
   872  	return ast.Function{
   873  		ArgTypes:   []ast.Type{},
   874  		ReturnType: ast.TypeString,
   875  		Callback: func(args []interface{}) (interface{}, error) {
   876  			return uuid.GenerateUUID()
   877  		},
   878  	}
   879  }