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