@@ -29,6 +29,7 @@ import (
2929 corev1 "k8s.io/api/core/v1"
3030 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3131 "k8s.io/apimachinery/pkg/types"
32+ "k8s.io/utils/ptr"
3233 "sigs.k8s.io/controller-runtime/pkg/client"
3334
3435 infrav1alpha2 "github.com/linode/cluster-api-provider-linode/api/v1alpha2"
@@ -60,6 +61,9 @@ func TestValidateLinodeVPC(t *testing.T) {
6061 ErrorSubnetRangeNotPrivate = "spec.Subnets[0].IPv4: Invalid value: \" 9.9.9.0/24\" : range must belong to a private address space as defined in RFC1918"
6162 ErrorSubnetRange = "spec.Subnets[0].IPv4: Invalid value: \" IPv4 CIDR\" : must be IPv4 range in CIDR canonical form"
6263 ErrorSubnetRangeNotIPv4 = "spec.Subnets[0].IPv4: Invalid value: \" 10.9.9.9/8\" : must be IPv4 range in CIDR canonical form"
64+ ErrorIPv6RangeInvalid = "spec.IPv6Range[0].Range: Invalid value: \" 48\" : IPv6 range must be either 'auto' or start with /. Example: /52"
65+ ErrorIPv6RangeInvalidChars = "spec.IPv6Range[0].Range: Invalid value: \" /a48\" : IPv6 range doesn't contain a valid number after /"
66+ ErrorIPv6RangeOutOfRange = "spec.IPv6Range[0].Range: Invalid value: \" /130\" : IPv6 range must be between /0 and /128"
6367 validator = & linodeVPCValidator {}
6468 )
6569
@@ -89,6 +93,40 @@ func TestValidateLinodeVPC(t *testing.T) {
8993 require .Empty (t , errs )
9094 }),
9195 ),
96+ Path (
97+ Call ("valid ipv6 ranges in vpc" , func (ctx context.Context , mck Mock ) {
98+ region := region
99+ region .Capabilities = slices .Clone (capabilities )
100+ mck .LinodeClient .EXPECT ().GetRegion (gomock .Any (), gomock .Any ()).Return (& region , nil ).AnyTimes ()
101+ }),
102+ Result ("success" , func (ctx context.Context , mck Mock ) {
103+ vpc := vpc
104+ vpc .Spec .IPv6Range = []infrav1alpha2.VPCCreateOptionsIPv6 {
105+ {Range : ptr .To ("/48" )},
106+ {Range : ptr .To ("/52" )},
107+ {Range : ptr .To ("auto" )},
108+ }
109+ errs := validator .validateLinodeVPCSpec (ctx , mck .LinodeClient , vpc .Spec , SkipAPIValidation )
110+ require .Empty (t , errs )
111+ }),
112+ ),
113+ Path (
114+ Call ("valid ipv6 ranges in subnets" , func (ctx context.Context , mck Mock ) {
115+ region := region
116+ region .Capabilities = slices .Clone (capabilities )
117+ mck .LinodeClient .EXPECT ().GetRegion (gomock .Any (), gomock .Any ()).Return (& region , nil ).AnyTimes ()
118+ }),
119+ Result ("success" , func (ctx context.Context , mck Mock ) {
120+ vpc := vpc
121+ vpc .Spec .Subnets = []infrav1alpha2.VPCSubnetCreateOptions {
122+ {Label : "foo" , IPv4 : "10.0.0.0/24" , IPv6Range : []infrav1alpha2.VPCSubnetCreateOptionsIPv6 {{Range : ptr .To ("/52" )}}},
123+ {Label : "bar" , IPv4 : "10.0.1.0/24" , IPv6Range : []infrav1alpha2.VPCSubnetCreateOptionsIPv6 {{Range : ptr .To ("/64" )}}},
124+ {Label : "buzz" , IPv4 : "10.0.2.0/24" , IPv6Range : []infrav1alpha2.VPCSubnetCreateOptionsIPv6 {{Range : ptr .To ("auto" )}}},
125+ }
126+ errs := validator .validateLinodeVPCSpec (ctx , mck .LinodeClient , vpc .Spec , SkipAPIValidation )
127+ require .Empty (t , errs )
128+ }),
129+ ),
92130 ),
93131 OneOf (
94132 Path (
@@ -115,6 +153,39 @@ func TestValidateLinodeVPC(t *testing.T) {
115153 }
116154 })),
117155 ),
156+ OneOf (
157+ Path (
158+ Call ("invalid ipv6 range" , func (ctx context.Context , mck Mock ) {
159+ region := region
160+ region .Capabilities = slices .Clone (capabilities )
161+ mck .LinodeClient .EXPECT ().GetRegion (gomock .Any (), gomock .Any ()).Return (& region , nil ).AnyTimes ()
162+ }),
163+ Result ("error" , func (ctx context.Context , mck Mock ) {
164+ vpc := vpc
165+ vpc .Spec .IPv6Range = []infrav1alpha2.VPCCreateOptionsIPv6 {
166+ {Range : ptr .To ("48" )},
167+ }
168+ errs := validator .validateLinodeVPCSpec (ctx , mck .LinodeClient , vpc .Spec , SkipAPIValidation )
169+ for _ , err := range errs {
170+ assert .ErrorContains (t , err , ErrorIPv6RangeInvalid )
171+ }
172+ vpc .Spec .IPv6Range = []infrav1alpha2.VPCCreateOptionsIPv6 {
173+ {Range : ptr .To ("/a48" )},
174+ }
175+ errs = validator .validateLinodeVPCSpec (ctx , mck .LinodeClient , vpc .Spec , SkipAPIValidation )
176+ for _ , err := range errs {
177+ assert .ErrorContains (t , err , ErrorIPv6RangeInvalidChars )
178+ }
179+ vpc .Spec .IPv6Range = []infrav1alpha2.VPCCreateOptionsIPv6 {
180+ {Range : ptr .To ("/130" )},
181+ }
182+ errs = validator .validateLinodeVPCSpec (ctx , mck .LinodeClient , vpc .Spec , SkipAPIValidation )
183+ for _ , err := range errs {
184+ assert .ErrorContains (t , err , ErrorIPv6RangeOutOfRange )
185+ }
186+ }),
187+ ),
188+ ),
118189 OneOf (
119190 Path (
120191 Call ("no subnet label" , func (ctx context.Context , mck Mock ) {
@@ -269,6 +340,21 @@ func TestValidateLinodeVPC(t *testing.T) {
269340 }
270341 }),
271342 ),
343+ Path (
344+ Call ("subnet ipv6 range is incorrect" , func (ctx context.Context , mck Mock ) {
345+ region := region
346+ region .Capabilities = slices .Clone (capabilities )
347+ mck .LinodeClient .EXPECT ().GetRegion (gomock .Any (), gomock .Any ()).Return (& region , nil ).AnyTimes ()
348+ }),
349+ Result ("error" , func (ctx context.Context , mck Mock ) {
350+ vpc := vpc
351+ vpc .Spec .Subnets = []infrav1alpha2.VPCSubnetCreateOptions {{Label : "foo" , IPv4 : "10.0.0.0/8" , IPv6Range : []infrav1alpha2.VPCSubnetCreateOptionsIPv6 {{Range : ptr .To ("" )}}}}
352+ errs := validator .validateLinodeVPCSpec (ctx , mck .LinodeClient , vpc .Spec , SkipAPIValidation )
353+ for _ , err := range errs {
354+ require .Error (t , err )
355+ }
356+ }),
357+ ),
272358 ),
273359 )
274360}
0 commit comments