github.com/medzin/terraform@v0.11.11/config/interpolate_funcs.go (about)

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