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