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