Skip to content

Commit e51ae7c

Browse files
committed
Import functions from Terraform
* copy pasted the missing funcs & tests from github.com/hashicorp/terraform/lang/funcs/ 39e609 * forced github.com/bmatcuk/doublestar to use v1.1.5 so that TestFileSet passes; v1.2 had a different behavior. * renamed terraform's ReverseFunc to ReverseListFunc
1 parent c282fd1 commit e51ae7c

24 files changed

+5380
-7
lines changed

cty/function/stdlib/cidr.go

+217
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
package stdlib
2+
import (
3+
"fmt"
4+
"net"
5+
6+
"github.com/apparentlymart/go-cidr/cidr"
7+
"github.com/zclconf/go-cty/cty"
8+
"github.com/zclconf/go-cty/cty/function"
9+
"github.com/zclconf/go-cty/cty/gocty"
10+
)
11+
12+
// CidrHostFunc contructs a function that calculates a full host IP address
13+
// within a given IP network address prefix.
14+
var CidrHostFunc = function.New(&function.Spec{
15+
Params: []function.Parameter{
16+
{
17+
Name: "prefix",
18+
Type: cty.String,
19+
},
20+
{
21+
Name: "hostnum",
22+
Type: cty.Number,
23+
},
24+
},
25+
Type: function.StaticReturnType(cty.String),
26+
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
27+
var hostNum int
28+
if err := gocty.FromCtyValue(args[1], &hostNum); err != nil {
29+
return cty.UnknownVal(cty.String), err
30+
}
31+
_, network, err := net.ParseCIDR(args[0].AsString())
32+
if err != nil {
33+
return cty.UnknownVal(cty.String), fmt.Errorf("invalid CIDR expression: %s", err)
34+
}
35+
36+
ip, err := cidr.Host(network, hostNum)
37+
if err != nil {
38+
return cty.UnknownVal(cty.String), err
39+
}
40+
41+
return cty.StringVal(ip.String()), nil
42+
},
43+
})
44+
45+
// CidrNetmaskFunc contructs a function that converts an IPv4 address prefix given
46+
// in CIDR notation into a subnet mask address.
47+
var CidrNetmaskFunc = function.New(&function.Spec{
48+
Params: []function.Parameter{
49+
{
50+
Name: "prefix",
51+
Type: cty.String,
52+
},
53+
},
54+
Type: function.StaticReturnType(cty.String),
55+
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
56+
_, network, err := net.ParseCIDR(args[0].AsString())
57+
if err != nil {
58+
return cty.UnknownVal(cty.String), fmt.Errorf("invalid CIDR expression: %s", err)
59+
}
60+
61+
return cty.StringVal(net.IP(network.Mask).String()), nil
62+
},
63+
})
64+
65+
// CidrSubnetFunc contructs a function that calculates a subnet address within
66+
// a given IP network address prefix.
67+
var CidrSubnetFunc = function.New(&function.Spec{
68+
Params: []function.Parameter{
69+
{
70+
Name: "prefix",
71+
Type: cty.String,
72+
},
73+
{
74+
Name: "newbits",
75+
Type: cty.Number,
76+
},
77+
{
78+
Name: "netnum",
79+
Type: cty.Number,
80+
},
81+
},
82+
Type: function.StaticReturnType(cty.String),
83+
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
84+
var newbits int
85+
if err := gocty.FromCtyValue(args[1], &newbits); err != nil {
86+
return cty.UnknownVal(cty.String), err
87+
}
88+
var netnum int
89+
if err := gocty.FromCtyValue(args[2], &netnum); err != nil {
90+
return cty.UnknownVal(cty.String), err
91+
}
92+
93+
_, network, err := net.ParseCIDR(args[0].AsString())
94+
if err != nil {
95+
return cty.UnknownVal(cty.String), fmt.Errorf("invalid CIDR expression: %s", err)
96+
}
97+
98+
// For portability with 32-bit systems where the subnet number
99+
// will be a 32-bit int, we only allow extension of 32 bits in
100+
// one call even if we're running on a 64-bit machine.
101+
// (Of course, this is significant only for IPv6.)
102+
if newbits > 32 {
103+
return cty.UnknownVal(cty.String), fmt.Errorf("may not extend prefix by more than 32 bits")
104+
}
105+
106+
newNetwork, err := cidr.Subnet(network, newbits, netnum)
107+
if err != nil {
108+
return cty.UnknownVal(cty.String), err
109+
}
110+
111+
return cty.StringVal(newNetwork.String()), nil
112+
},
113+
})
114+
115+
// CidrSubnetsFunc is similar to CidrSubnetFunc but calculates many consecutive
116+
// subnet addresses at once, rather than just a single subnet extension.
117+
var CidrSubnetsFunc = function.New(&function.Spec{
118+
Params: []function.Parameter{
119+
{
120+
Name: "prefix",
121+
Type: cty.String,
122+
},
123+
},
124+
VarParam: &function.Parameter{
125+
Name: "newbits",
126+
Type: cty.Number,
127+
},
128+
Type: function.StaticReturnType(cty.List(cty.String)),
129+
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
130+
_, network, err := net.ParseCIDR(args[0].AsString())
131+
if err != nil {
132+
return cty.UnknownVal(cty.String), function.NewArgErrorf(0, "invalid CIDR expression: %s", err)
133+
}
134+
startPrefixLen, _ := network.Mask.Size()
135+
136+
prefixLengthArgs := args[1:]
137+
if len(prefixLengthArgs) == 0 {
138+
return cty.ListValEmpty(cty.String), nil
139+
}
140+
141+
var firstLength int
142+
if err := gocty.FromCtyValue(prefixLengthArgs[0], &firstLength); err != nil {
143+
return cty.UnknownVal(cty.String), function.NewArgError(1, err)
144+
}
145+
firstLength += startPrefixLen
146+
147+
retVals := make([]cty.Value, len(prefixLengthArgs))
148+
149+
current, _ := cidr.PreviousSubnet(network, firstLength)
150+
for i, lengthArg := range prefixLengthArgs {
151+
var length int
152+
if err := gocty.FromCtyValue(lengthArg, &length); err != nil {
153+
return cty.UnknownVal(cty.String), function.NewArgError(i+1, err)
154+
}
155+
156+
if length < 1 {
157+
return cty.UnknownVal(cty.String), function.NewArgErrorf(i+1, "must extend prefix by at least one bit")
158+
}
159+
// For portability with 32-bit systems where the subnet number
160+
// will be a 32-bit int, we only allow extension of 32 bits in
161+
// one call even if we're running on a 64-bit machine.
162+
// (Of course, this is significant only for IPv6.)
163+
if length > 32 {
164+
return cty.UnknownVal(cty.String), function.NewArgErrorf(i+1, "may not extend prefix by more than 32 bits")
165+
}
166+
length += startPrefixLen
167+
if length > (len(network.IP) * 8) {
168+
protocol := "IP"
169+
switch len(network.IP) * 8 {
170+
case 32:
171+
protocol = "IPv4"
172+
case 128:
173+
protocol = "IPv6"
174+
}
175+
return cty.UnknownVal(cty.String), function.NewArgErrorf(i+1, "would extend prefix to %d bits, which is too long for an %s address", length, protocol)
176+
}
177+
178+
next, rollover := cidr.NextSubnet(current, length)
179+
if rollover || !network.Contains(next.IP) {
180+
// If we run out of suffix bits in the base CIDR prefix then
181+
// NextSubnet will start incrementing the prefix bits, which
182+
// we don't allow because it would then allocate addresses
183+
// outside of the caller's given prefix.
184+
return cty.UnknownVal(cty.String), function.NewArgErrorf(i+1, "not enough remaining address space for a subnet with a prefix of %d bits after %s", length, current.String())
185+
}
186+
187+
current = next
188+
retVals[i] = cty.StringVal(current.String())
189+
}
190+
191+
return cty.ListVal(retVals), nil
192+
},
193+
})
194+
195+
// CidrHost calculates a full host IP address within a given IP network address prefix.
196+
func CidrHost(prefix, hostnum cty.Value) (cty.Value, error) {
197+
return CidrHostFunc.Call([]cty.Value{prefix, hostnum})
198+
}
199+
200+
// CidrNetmask converts an IPv4 address prefix given in CIDR notation into a subnet mask address.
201+
func CidrNetmask(prefix cty.Value) (cty.Value, error) {
202+
return CidrNetmaskFunc.Call([]cty.Value{prefix})
203+
}
204+
205+
// CidrSubnet calculates a subnet address within a given IP network address prefix.
206+
func CidrSubnet(prefix, newbits, netnum cty.Value) (cty.Value, error) {
207+
return CidrSubnetFunc.Call([]cty.Value{prefix, newbits, netnum})
208+
}
209+
210+
// CidrSubnets calculates a sequence of consecutive subnet prefixes that may
211+
// be of different prefix lengths under a common base prefix.
212+
func CidrSubnets(prefix cty.Value, newbits ...cty.Value) (cty.Value, error) {
213+
args := make([]cty.Value, len(newbits)+1)
214+
args[0] = prefix
215+
copy(args[1:], newbits)
216+
return CidrSubnetsFunc.Call(args)
217+
}

0 commit comments

Comments
 (0)