diff options
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/config/interpolate_funcs.go')
-rw-r--r-- | vendor/github.com/hashicorp/terraform/config/interpolate_funcs.go | 429 |
1 files changed, 364 insertions, 65 deletions
diff --git a/vendor/github.com/hashicorp/terraform/config/interpolate_funcs.go b/vendor/github.com/hashicorp/terraform/config/interpolate_funcs.go index a298cf2..421edb0 100644 --- a/vendor/github.com/hashicorp/terraform/config/interpolate_funcs.go +++ b/vendor/github.com/hashicorp/terraform/config/interpolate_funcs.go | |||
@@ -1,17 +1,23 @@ | |||
1 | package config | 1 | package config |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "bytes" | ||
5 | "compress/gzip" | ||
4 | "crypto/md5" | 6 | "crypto/md5" |
7 | "crypto/rsa" | ||
5 | "crypto/sha1" | 8 | "crypto/sha1" |
6 | "crypto/sha256" | 9 | "crypto/sha256" |
7 | "crypto/sha512" | 10 | "crypto/sha512" |
11 | "crypto/x509" | ||
8 | "encoding/base64" | 12 | "encoding/base64" |
9 | "encoding/hex" | 13 | "encoding/hex" |
10 | "encoding/json" | 14 | "encoding/json" |
15 | "encoding/pem" | ||
11 | "fmt" | 16 | "fmt" |
12 | "io/ioutil" | 17 | "io/ioutil" |
13 | "math" | 18 | "math" |
14 | "net" | 19 | "net" |
20 | "net/url" | ||
15 | "path/filepath" | 21 | "path/filepath" |
16 | "regexp" | 22 | "regexp" |
17 | "sort" | 23 | "sort" |
@@ -55,59 +61,74 @@ func listVariableValueToStringSlice(values []ast.Variable) ([]string, error) { | |||
55 | // Funcs is the mapping of built-in functions for configuration. | 61 | // Funcs is the mapping of built-in functions for configuration. |
56 | func Funcs() map[string]ast.Function { | 62 | func Funcs() map[string]ast.Function { |
57 | return map[string]ast.Function{ | 63 | return map[string]ast.Function{ |
58 | "basename": interpolationFuncBasename(), | 64 | "abs": interpolationFuncAbs(), |
59 | "base64decode": interpolationFuncBase64Decode(), | 65 | "basename": interpolationFuncBasename(), |
60 | "base64encode": interpolationFuncBase64Encode(), | 66 | "base64decode": interpolationFuncBase64Decode(), |
61 | "base64sha256": interpolationFuncBase64Sha256(), | 67 | "base64encode": interpolationFuncBase64Encode(), |
62 | "base64sha512": interpolationFuncBase64Sha512(), | 68 | "base64gzip": interpolationFuncBase64Gzip(), |
63 | "bcrypt": interpolationFuncBcrypt(), | 69 | "base64sha256": interpolationFuncBase64Sha256(), |
64 | "ceil": interpolationFuncCeil(), | 70 | "base64sha512": interpolationFuncBase64Sha512(), |
65 | "chomp": interpolationFuncChomp(), | 71 | "bcrypt": interpolationFuncBcrypt(), |
66 | "cidrhost": interpolationFuncCidrHost(), | 72 | "ceil": interpolationFuncCeil(), |
67 | "cidrnetmask": interpolationFuncCidrNetmask(), | 73 | "chomp": interpolationFuncChomp(), |
68 | "cidrsubnet": interpolationFuncCidrSubnet(), | 74 | "cidrhost": interpolationFuncCidrHost(), |
69 | "coalesce": interpolationFuncCoalesce(), | 75 | "cidrnetmask": interpolationFuncCidrNetmask(), |
70 | "coalescelist": interpolationFuncCoalesceList(), | 76 | "cidrsubnet": interpolationFuncCidrSubnet(), |
71 | "compact": interpolationFuncCompact(), | 77 | "coalesce": interpolationFuncCoalesce(), |
72 | "concat": interpolationFuncConcat(), | 78 | "coalescelist": interpolationFuncCoalesceList(), |
73 | "contains": interpolationFuncContains(), | 79 | "compact": interpolationFuncCompact(), |
74 | "dirname": interpolationFuncDirname(), | 80 | "concat": interpolationFuncConcat(), |
75 | "distinct": interpolationFuncDistinct(), | 81 | "contains": interpolationFuncContains(), |
76 | "element": interpolationFuncElement(), | 82 | "dirname": interpolationFuncDirname(), |
77 | "file": interpolationFuncFile(), | 83 | "distinct": interpolationFuncDistinct(), |
78 | "matchkeys": interpolationFuncMatchKeys(), | 84 | "element": interpolationFuncElement(), |
79 | "floor": interpolationFuncFloor(), | 85 | "chunklist": interpolationFuncChunklist(), |
80 | "format": interpolationFuncFormat(), | 86 | "file": interpolationFuncFile(), |
81 | "formatlist": interpolationFuncFormatList(), | 87 | "filebase64sha256": interpolationFuncMakeFileHash(interpolationFuncBase64Sha256()), |
82 | "index": interpolationFuncIndex(), | 88 | "filebase64sha512": interpolationFuncMakeFileHash(interpolationFuncBase64Sha512()), |
83 | "join": interpolationFuncJoin(), | 89 | "filemd5": interpolationFuncMakeFileHash(interpolationFuncMd5()), |
84 | "jsonencode": interpolationFuncJSONEncode(), | 90 | "filesha1": interpolationFuncMakeFileHash(interpolationFuncSha1()), |
85 | "length": interpolationFuncLength(), | 91 | "filesha256": interpolationFuncMakeFileHash(interpolationFuncSha256()), |
86 | "list": interpolationFuncList(), | 92 | "filesha512": interpolationFuncMakeFileHash(interpolationFuncSha512()), |
87 | "log": interpolationFuncLog(), | 93 | "matchkeys": interpolationFuncMatchKeys(), |
88 | "lower": interpolationFuncLower(), | 94 | "flatten": interpolationFuncFlatten(), |
89 | "map": interpolationFuncMap(), | 95 | "floor": interpolationFuncFloor(), |
90 | "max": interpolationFuncMax(), | 96 | "format": interpolationFuncFormat(), |
91 | "md5": interpolationFuncMd5(), | 97 | "formatlist": interpolationFuncFormatList(), |
92 | "merge": interpolationFuncMerge(), | 98 | "indent": interpolationFuncIndent(), |
93 | "min": interpolationFuncMin(), | 99 | "index": interpolationFuncIndex(), |
94 | "pathexpand": interpolationFuncPathExpand(), | 100 | "join": interpolationFuncJoin(), |
95 | "pow": interpolationFuncPow(), | 101 | "jsonencode": interpolationFuncJSONEncode(), |
96 | "uuid": interpolationFuncUUID(), | 102 | "length": interpolationFuncLength(), |
97 | "replace": interpolationFuncReplace(), | 103 | "list": interpolationFuncList(), |
98 | "sha1": interpolationFuncSha1(), | 104 | "log": interpolationFuncLog(), |
99 | "sha256": interpolationFuncSha256(), | 105 | "lower": interpolationFuncLower(), |
100 | "sha512": interpolationFuncSha512(), | 106 | "map": interpolationFuncMap(), |
101 | "signum": interpolationFuncSignum(), | 107 | "max": interpolationFuncMax(), |
102 | "slice": interpolationFuncSlice(), | 108 | "md5": interpolationFuncMd5(), |
103 | "sort": interpolationFuncSort(), | 109 | "merge": interpolationFuncMerge(), |
104 | "split": interpolationFuncSplit(), | 110 | "min": interpolationFuncMin(), |
105 | "substr": interpolationFuncSubstr(), | 111 | "pathexpand": interpolationFuncPathExpand(), |
106 | "timestamp": interpolationFuncTimestamp(), | 112 | "pow": interpolationFuncPow(), |
107 | "title": interpolationFuncTitle(), | 113 | "uuid": interpolationFuncUUID(), |
108 | "trimspace": interpolationFuncTrimSpace(), | 114 | "replace": interpolationFuncReplace(), |
109 | "upper": interpolationFuncUpper(), | 115 | "rsadecrypt": interpolationFuncRsaDecrypt(), |
110 | "zipmap": interpolationFuncZipMap(), | 116 | "sha1": interpolationFuncSha1(), |
117 | "sha256": interpolationFuncSha256(), | ||
118 | "sha512": interpolationFuncSha512(), | ||
119 | "signum": interpolationFuncSignum(), | ||
120 | "slice": interpolationFuncSlice(), | ||
121 | "sort": interpolationFuncSort(), | ||
122 | "split": interpolationFuncSplit(), | ||
123 | "substr": interpolationFuncSubstr(), | ||
124 | "timestamp": interpolationFuncTimestamp(), | ||
125 | "timeadd": interpolationFuncTimeAdd(), | ||
126 | "title": interpolationFuncTitle(), | ||
127 | "transpose": interpolationFuncTranspose(), | ||
128 | "trimspace": interpolationFuncTrimSpace(), | ||
129 | "upper": interpolationFuncUpper(), | ||
130 | "urlencode": interpolationFuncURLEncode(), | ||
131 | "zipmap": interpolationFuncZipMap(), | ||
111 | } | 132 | } |
112 | } | 133 | } |
113 | 134 | ||
@@ -669,6 +690,21 @@ func interpolationFuncFormatList() ast.Function { | |||
669 | } | 690 | } |
670 | } | 691 | } |
671 | 692 | ||
693 | // interpolationFuncIndent indents a multi-line string with the | ||
694 | // specified number of spaces | ||
695 | func interpolationFuncIndent() ast.Function { | ||
696 | return ast.Function{ | ||
697 | ArgTypes: []ast.Type{ast.TypeInt, ast.TypeString}, | ||
698 | ReturnType: ast.TypeString, | ||
699 | Callback: func(args []interface{}) (interface{}, error) { | ||
700 | spaces := args[0].(int) | ||
701 | data := args[1].(string) | ||
702 | pad := strings.Repeat(" ", spaces) | ||
703 | return strings.Replace(data, "\n", "\n"+pad, -1), nil | ||
704 | }, | ||
705 | } | ||
706 | } | ||
707 | |||
672 | // interpolationFuncIndex implements the "index" function that allows one to | 708 | // interpolationFuncIndex implements the "index" function that allows one to |
673 | // find the index of a specific element in a list | 709 | // find the index of a specific element in a list |
674 | func interpolationFuncIndex() ast.Function { | 710 | func interpolationFuncIndex() ast.Function { |
@@ -823,8 +859,7 @@ func interpolationFuncJoin() ast.Function { | |||
823 | } | 859 | } |
824 | 860 | ||
825 | // interpolationFuncJSONEncode implements the "jsonencode" function that encodes | 861 | // interpolationFuncJSONEncode implements the "jsonencode" function that encodes |
826 | // a string, list, or map as its JSON representation. For now, values in the | 862 | // a string, list, or map as its JSON representation. |
827 | // list or map may only be strings. | ||
828 | func interpolationFuncJSONEncode() ast.Function { | 863 | func interpolationFuncJSONEncode() ast.Function { |
829 | return ast.Function{ | 864 | return ast.Function{ |
830 | ArgTypes: []ast.Type{ast.TypeAny}, | 865 | ArgTypes: []ast.Type{ast.TypeAny}, |
@@ -837,28 +872,36 @@ func interpolationFuncJSONEncode() ast.Function { | |||
837 | toEncode = typedArg | 872 | toEncode = typedArg |
838 | 873 | ||
839 | case []ast.Variable: | 874 | case []ast.Variable: |
840 | // We preallocate the list here. Note that it's important that in | ||
841 | // the length 0 case, we have an empty list rather than nil, as | ||
842 | // they encode differently. | ||
843 | // XXX It would be nice to support arbitrarily nested data here. Is | ||
844 | // there an inverse of hil.InterfaceToVariable? | ||
845 | strings := make([]string, len(typedArg)) | 875 | strings := make([]string, len(typedArg)) |
846 | 876 | ||
847 | for i, v := range typedArg { | 877 | for i, v := range typedArg { |
848 | if v.Type != ast.TypeString { | 878 | if v.Type != ast.TypeString { |
849 | return "", fmt.Errorf("list elements must be strings") | 879 | variable, _ := hil.InterfaceToVariable(typedArg) |
880 | toEncode, _ = hil.VariableToInterface(variable) | ||
881 | |||
882 | jEnc, err := json.Marshal(toEncode) | ||
883 | if err != nil { | ||
884 | return "", fmt.Errorf("failed to encode JSON data '%s'", toEncode) | ||
885 | } | ||
886 | return string(jEnc), nil | ||
887 | |||
850 | } | 888 | } |
851 | strings[i] = v.Value.(string) | 889 | strings[i] = v.Value.(string) |
852 | } | 890 | } |
853 | toEncode = strings | 891 | toEncode = strings |
854 | 892 | ||
855 | case map[string]ast.Variable: | 893 | case map[string]ast.Variable: |
856 | // XXX It would be nice to support arbitrarily nested data here. Is | ||
857 | // there an inverse of hil.InterfaceToVariable? | ||
858 | stringMap := make(map[string]string) | 894 | stringMap := make(map[string]string) |
859 | for k, v := range typedArg { | 895 | for k, v := range typedArg { |
860 | if v.Type != ast.TypeString { | 896 | if v.Type != ast.TypeString { |
861 | return "", fmt.Errorf("map values must be strings") | 897 | variable, _ := hil.InterfaceToVariable(typedArg) |
898 | toEncode, _ = hil.VariableToInterface(variable) | ||
899 | |||
900 | jEnc, err := json.Marshal(toEncode) | ||
901 | if err != nil { | ||
902 | return "", fmt.Errorf("failed to encode JSON data '%s'", toEncode) | ||
903 | } | ||
904 | return string(jEnc), nil | ||
862 | } | 905 | } |
863 | stringMap[k] = v.Value.(string) | 906 | stringMap[k] = v.Value.(string) |
864 | } | 907 | } |
@@ -1098,6 +1141,56 @@ func interpolationFuncElement() ast.Function { | |||
1098 | } | 1141 | } |
1099 | } | 1142 | } |
1100 | 1143 | ||
1144 | // returns the `list` items chunked by `size`. | ||
1145 | func interpolationFuncChunklist() ast.Function { | ||
1146 | return ast.Function{ | ||
1147 | ArgTypes: []ast.Type{ | ||
1148 | ast.TypeList, // inputList | ||
1149 | ast.TypeInt, // size | ||
1150 | }, | ||
1151 | ReturnType: ast.TypeList, | ||
1152 | Callback: func(args []interface{}) (interface{}, error) { | ||
1153 | output := make([]ast.Variable, 0) | ||
1154 | |||
1155 | values, _ := args[0].([]ast.Variable) | ||
1156 | size, _ := args[1].(int) | ||
1157 | |||
1158 | // errors if size is negative | ||
1159 | if size < 0 { | ||
1160 | return nil, fmt.Errorf("The size argument must be positive") | ||
1161 | } | ||
1162 | |||
1163 | // if size is 0, returns a list made of the initial list | ||
1164 | if size == 0 { | ||
1165 | output = append(output, ast.Variable{ | ||
1166 | Type: ast.TypeList, | ||
1167 | Value: values, | ||
1168 | }) | ||
1169 | return output, nil | ||
1170 | } | ||
1171 | |||
1172 | variables := make([]ast.Variable, 0) | ||
1173 | chunk := ast.Variable{ | ||
1174 | Type: ast.TypeList, | ||
1175 | Value: variables, | ||
1176 | } | ||
1177 | l := len(values) | ||
1178 | for i, v := range values { | ||
1179 | variables = append(variables, v) | ||
1180 | |||
1181 | // Chunk when index isn't 0, or when reaching the values's length | ||
1182 | if (i+1)%size == 0 || (i+1) == l { | ||
1183 | chunk.Value = variables | ||
1184 | output = append(output, chunk) | ||
1185 | variables = make([]ast.Variable, 0) | ||
1186 | } | ||
1187 | } | ||
1188 | |||
1189 | return output, nil | ||
1190 | }, | ||
1191 | } | ||
1192 | } | ||
1193 | |||
1101 | // interpolationFuncKeys implements the "keys" function that yields a list of | 1194 | // interpolationFuncKeys implements the "keys" function that yields a list of |
1102 | // keys of map types within a Terraform configuration. | 1195 | // keys of map types within a Terraform configuration. |
1103 | func interpolationFuncKeys(vs map[string]ast.Variable) ast.Function { | 1196 | func interpolationFuncKeys(vs map[string]ast.Variable) ast.Function { |
@@ -1197,6 +1290,32 @@ func interpolationFuncBase64Decode() ast.Function { | |||
1197 | } | 1290 | } |
1198 | } | 1291 | } |
1199 | 1292 | ||
1293 | // interpolationFuncBase64Gzip implements the "gzip" function that allows gzip | ||
1294 | // compression encoding the result using base64 | ||
1295 | func interpolationFuncBase64Gzip() ast.Function { | ||
1296 | return ast.Function{ | ||
1297 | ArgTypes: []ast.Type{ast.TypeString}, | ||
1298 | ReturnType: ast.TypeString, | ||
1299 | Callback: func(args []interface{}) (interface{}, error) { | ||
1300 | s := args[0].(string) | ||
1301 | |||
1302 | var b bytes.Buffer | ||
1303 | gz := gzip.NewWriter(&b) | ||
1304 | if _, err := gz.Write([]byte(s)); err != nil { | ||
1305 | return "", fmt.Errorf("failed to write gzip raw data: '%s'", s) | ||
1306 | } | ||
1307 | if err := gz.Flush(); err != nil { | ||
1308 | return "", fmt.Errorf("failed to flush gzip writer: '%s'", s) | ||
1309 | } | ||
1310 | if err := gz.Close(); err != nil { | ||
1311 | return "", fmt.Errorf("failed to close gzip writer: '%s'", s) | ||
1312 | } | ||
1313 | |||
1314 | return base64.StdEncoding.EncodeToString(b.Bytes()), nil | ||
1315 | }, | ||
1316 | } | ||
1317 | } | ||
1318 | |||
1200 | // interpolationFuncLower implements the "lower" function that does | 1319 | // interpolationFuncLower implements the "lower" function that does |
1201 | // string lower casing. | 1320 | // string lower casing. |
1202 | func interpolationFuncLower() ast.Function { | 1321 | func interpolationFuncLower() ast.Function { |
@@ -1396,6 +1515,29 @@ func interpolationFuncTimestamp() ast.Function { | |||
1396 | } | 1515 | } |
1397 | } | 1516 | } |
1398 | 1517 | ||
1518 | func interpolationFuncTimeAdd() ast.Function { | ||
1519 | return ast.Function{ | ||
1520 | ArgTypes: []ast.Type{ | ||
1521 | ast.TypeString, // input timestamp string in RFC3339 format | ||
1522 | ast.TypeString, // duration to add to input timestamp that should be parsable by time.ParseDuration | ||
1523 | }, | ||
1524 | ReturnType: ast.TypeString, | ||
1525 | Callback: func(args []interface{}) (interface{}, error) { | ||
1526 | |||
1527 | ts, err := time.Parse(time.RFC3339, args[0].(string)) | ||
1528 | if err != nil { | ||
1529 | return nil, err | ||
1530 | } | ||
1531 | duration, err := time.ParseDuration(args[1].(string)) | ||
1532 | if err != nil { | ||
1533 | return nil, err | ||
1534 | } | ||
1535 | |||
1536 | return ts.Add(duration).Format(time.RFC3339), nil | ||
1537 | }, | ||
1538 | } | ||
1539 | } | ||
1540 | |||
1399 | // interpolationFuncTitle implements the "title" function that returns a copy of the | 1541 | // interpolationFuncTitle implements the "title" function that returns a copy of the |
1400 | // string in which first characters of all the words are capitalized. | 1542 | // string in which first characters of all the words are capitalized. |
1401 | func interpolationFuncTitle() ast.Function { | 1543 | func interpolationFuncTitle() ast.Function { |
@@ -1441,7 +1583,7 @@ func interpolationFuncSubstr() ast.Function { | |||
1441 | return nil, fmt.Errorf("length should be a non-negative integer") | 1583 | return nil, fmt.Errorf("length should be a non-negative integer") |
1442 | } | 1584 | } |
1443 | 1585 | ||
1444 | if offset > len(str) { | 1586 | if offset > len(str) || offset < 0 { |
1445 | return nil, fmt.Errorf("offset cannot be larger than the length of the string") | 1587 | return nil, fmt.Errorf("offset cannot be larger than the length of the string") |
1446 | } | 1588 | } |
1447 | 1589 | ||
@@ -1453,3 +1595,160 @@ func interpolationFuncSubstr() ast.Function { | |||
1453 | }, | 1595 | }, |
1454 | } | 1596 | } |
1455 | } | 1597 | } |
1598 | |||
1599 | // Flatten until it's not ast.TypeList | ||
1600 | func flattener(finalList []ast.Variable, flattenList []ast.Variable) []ast.Variable { | ||
1601 | for _, val := range flattenList { | ||
1602 | if val.Type == ast.TypeList { | ||
1603 | finalList = flattener(finalList, val.Value.([]ast.Variable)) | ||
1604 | } else { | ||
1605 | finalList = append(finalList, val) | ||
1606 | } | ||
1607 | } | ||
1608 | return finalList | ||
1609 | } | ||
1610 | |||
1611 | // Flatten to single list | ||
1612 | func interpolationFuncFlatten() ast.Function { | ||
1613 | return ast.Function{ | ||
1614 | ArgTypes: []ast.Type{ast.TypeList}, | ||
1615 | ReturnType: ast.TypeList, | ||
1616 | Variadic: false, | ||
1617 | Callback: func(args []interface{}) (interface{}, error) { | ||
1618 | inputList := args[0].([]ast.Variable) | ||
1619 | |||
1620 | var outputList []ast.Variable | ||
1621 | return flattener(outputList, inputList), nil | ||
1622 | }, | ||
1623 | } | ||
1624 | } | ||
1625 | |||
1626 | func interpolationFuncURLEncode() ast.Function { | ||
1627 | return ast.Function{ | ||
1628 | ArgTypes: []ast.Type{ast.TypeString}, | ||
1629 | ReturnType: ast.TypeString, | ||
1630 | Callback: func(args []interface{}) (interface{}, error) { | ||
1631 | s := args[0].(string) | ||
1632 | return url.QueryEscape(s), nil | ||
1633 | }, | ||
1634 | } | ||
1635 | } | ||
1636 | |||
1637 | // interpolationFuncTranspose implements the "transpose" function | ||
1638 | // that converts a map (string,list) to a map (string,list) where | ||
1639 | // the unique values of the original lists become the keys of the | ||
1640 | // new map and the keys of the original map become values for the | ||
1641 | // corresponding new keys. | ||
1642 | func interpolationFuncTranspose() ast.Function { | ||
1643 | return ast.Function{ | ||
1644 | ArgTypes: []ast.Type{ast.TypeMap}, | ||
1645 | ReturnType: ast.TypeMap, | ||
1646 | Callback: func(args []interface{}) (interface{}, error) { | ||
1647 | |||
1648 | inputMap := args[0].(map[string]ast.Variable) | ||
1649 | outputMap := make(map[string]ast.Variable) | ||
1650 | tmpMap := make(map[string][]string) | ||
1651 | |||
1652 | for inKey, inVal := range inputMap { | ||
1653 | if inVal.Type != ast.TypeList { | ||
1654 | return nil, fmt.Errorf("transpose requires a map of lists of strings") | ||
1655 | } | ||
1656 | values := inVal.Value.([]ast.Variable) | ||
1657 | for _, listVal := range values { | ||
1658 | if listVal.Type != ast.TypeString { | ||
1659 | return nil, fmt.Errorf("transpose requires the given map values to be lists of strings") | ||
1660 | } | ||
1661 | outKey := listVal.Value.(string) | ||
1662 | if _, ok := tmpMap[outKey]; !ok { | ||
1663 | tmpMap[outKey] = make([]string, 0) | ||
1664 | } | ||
1665 | outVal := tmpMap[outKey] | ||
1666 | outVal = append(outVal, inKey) | ||
1667 | sort.Strings(outVal) | ||
1668 | tmpMap[outKey] = outVal | ||
1669 | } | ||
1670 | } | ||
1671 | |||
1672 | for outKey, outVal := range tmpMap { | ||
1673 | values := make([]ast.Variable, 0) | ||
1674 | for _, v := range outVal { | ||
1675 | values = append(values, ast.Variable{Type: ast.TypeString, Value: v}) | ||
1676 | } | ||
1677 | outputMap[outKey] = ast.Variable{Type: ast.TypeList, Value: values} | ||
1678 | } | ||
1679 | return outputMap, nil | ||
1680 | }, | ||
1681 | } | ||
1682 | } | ||
1683 | |||
1684 | // interpolationFuncAbs returns the absolute value of a given float. | ||
1685 | func interpolationFuncAbs() ast.Function { | ||
1686 | return ast.Function{ | ||
1687 | ArgTypes: []ast.Type{ast.TypeFloat}, | ||
1688 | ReturnType: ast.TypeFloat, | ||
1689 | Callback: func(args []interface{}) (interface{}, error) { | ||
1690 | return math.Abs(args[0].(float64)), nil | ||
1691 | }, | ||
1692 | } | ||
1693 | } | ||
1694 | |||
1695 | // interpolationFuncRsaDecrypt implements the "rsadecrypt" function that does | ||
1696 | // RSA decryption. | ||
1697 | func interpolationFuncRsaDecrypt() ast.Function { | ||
1698 | return ast.Function{ | ||
1699 | ArgTypes: []ast.Type{ast.TypeString, ast.TypeString}, | ||
1700 | ReturnType: ast.TypeString, | ||
1701 | Callback: func(args []interface{}) (interface{}, error) { | ||
1702 | s := args[0].(string) | ||
1703 | key := args[1].(string) | ||
1704 | |||
1705 | b, err := base64.StdEncoding.DecodeString(s) | ||
1706 | if err != nil { | ||
1707 | return "", fmt.Errorf("Failed to decode input %q: cipher text must be base64-encoded", s) | ||
1708 | } | ||
1709 | |||
1710 | block, _ := pem.Decode([]byte(key)) | ||
1711 | if block == nil { | ||
1712 | return "", fmt.Errorf("Failed to read key %q: no key found", key) | ||
1713 | } | ||
1714 | if block.Headers["Proc-Type"] == "4,ENCRYPTED" { | ||
1715 | return "", fmt.Errorf( | ||
1716 | "Failed to read key %q: password protected keys are\n"+ | ||
1717 | "not supported. Please decrypt the key prior to use.", key) | ||
1718 | } | ||
1719 | |||
1720 | x509Key, err := x509.ParsePKCS1PrivateKey(block.Bytes) | ||
1721 | if err != nil { | ||
1722 | return "", err | ||
1723 | } | ||
1724 | |||
1725 | out, err := rsa.DecryptPKCS1v15(nil, x509Key, b) | ||
1726 | if err != nil { | ||
1727 | return "", err | ||
1728 | } | ||
1729 | |||
1730 | return string(out), nil | ||
1731 | }, | ||
1732 | } | ||
1733 | } | ||
1734 | |||
1735 | // interpolationFuncMakeFileHash constructs a function that hashes the contents | ||
1736 | // of a file by combining the implementations of the file(...) function and | ||
1737 | // a given other function that is assumed to take a single string argument and | ||
1738 | // return a hash value. | ||
1739 | func interpolationFuncMakeFileHash(hashFunc ast.Function) ast.Function { | ||
1740 | fileFunc := interpolationFuncFile() | ||
1741 | |||
1742 | return ast.Function{ | ||
1743 | ArgTypes: []ast.Type{ast.TypeString}, | ||
1744 | ReturnType: ast.TypeString, | ||
1745 | Callback: func(args []interface{}) (interface{}, error) { | ||
1746 | filename := args[0].(string) | ||
1747 | contents, err := fileFunc.Callback([]interface{}{filename}) | ||
1748 | if err != nil { | ||
1749 | return nil, err | ||
1750 | } | ||
1751 | return hashFunc.Callback([]interface{}{contents}) | ||
1752 | }, | ||
1753 | } | ||
1754 | } | ||