github.com/trawler/terraform@v0.10.8-0.20171106022149-4b1c7a1d9b48/config/interpolate_funcs.go (about)

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