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