github.com/nathanielks/terraform@v0.6.1-0.20170509030759-13e1a62319dc/config/interpolate_funcs.go (about)

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