Skip to content

Commit 3e01689

Browse files
author
Rahul Sharma
committed
allow cidr sizes to be configurable
1 parent fd878a5 commit 3e01689

File tree

8 files changed

+94
-7
lines changed

8 files changed

+94
-7
lines changed

api/v1alpha2/linodevpc_types.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ type LinodeVPCSpec struct {
4242
// supplied then the credentials of the controller will be used.
4343
// +optional
4444
CredentialsRef *corev1.SecretReference `json:"credentialsRef,omitempty"`
45+
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
46+
// +optional
47+
// +kubebuilder:validation:MinLength=2
48+
// +kubebuilder:validation:MaxLength=4
49+
// +kubebuilder:default="/52"
50+
IPv6Range string `json:"ipv6Range,omitempty"`
4551
}
4652

4753
// VPCSubnetCreateOptions defines subnet options
@@ -55,6 +61,11 @@ type VPCSubnetCreateOptions struct {
5561
// SubnetID is subnet id for the subnet
5662
// +optional
5763
SubnetID int `json:"subnetID,omitempty"`
64+
// +optional
65+
// +kubebuilder:validation:MinLength=2
66+
// +kubebuilder:validation:MaxLength=4
67+
// +kubebuilder:default="/56"
68+
IPv6Range string `json:"ipv6Range,omitempty"`
5869
}
5970

6071
// LinodeVPCStatus defines the observed state of LinodeVPC

config/crd/bases/infrastructure.cluster.x-k8s.io_linodevpcs.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ spec:
6767
x-kubernetes-map-type: atomic
6868
description:
6969
type: string
70+
ipv6Range:
71+
default: /52
72+
maxLength: 4
73+
minLength: 2
74+
type: string
75+
x-kubernetes-validations:
76+
- message: Value is immutable
77+
rule: self == oldSelf
7078
region:
7179
type: string
7280
x-kubernetes-validations:
@@ -78,6 +86,11 @@ spec:
7886
properties:
7987
ipv4:
8088
type: string
89+
ipv6Range:
90+
default: /56
91+
maxLength: 4
92+
minLength: 2
93+
type: string
8194
label:
8295
maxLength: 63
8396
minLength: 3

docs/src/reference/out.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,6 +1060,7 @@ _Appears in:_
10601060
| `region` _string_ | | | |
10611061
| `subnets` _[VPCSubnetCreateOptions](#vpcsubnetcreateoptions) array_ | | | |
10621062
| `credentialsRef` _[SecretReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#secretreference-v1-core)_ | CredentialsRef is a reference to a Secret that contains the credentials to use for provisioning this VPC. If not<br />supplied then the credentials of the controller will be used. | | |
1063+
| `ipv6Range` _string_ | | /52 | MaxLength: 4 <br />MinLength: 2 <br /> |
10631064

10641065

10651066
#### LinodeVPCStatus
@@ -1217,5 +1218,6 @@ _Appears in:_
12171218
| `label` _string_ | | | MaxLength: 63 <br />MinLength: 3 <br /> |
12181219
| `ipv4` _string_ | | | |
12191220
| `subnetID` _integer_ | SubnetID is subnet id for the subnet | | |
1221+
| `ipv6Range` _string_ | | /56 | MaxLength: 4 <br />MinLength: 2 <br /> |
12201222

12211223

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,3 +152,5 @@ require (
152152
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
153153
sigs.k8s.io/yaml v1.4.0 // indirect
154154
)
155+
156+
replace github.com/linode/linodego => github.com/rahulait/linodego v1.50.1-0.20250708032219-cf7181d2963f

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
177177
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
178178
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
179179
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
180-
github.com/linode/linodego v1.52.2 h1:N9ozU27To1LMSrDd8WvJZ5STSz1eGYdyLnxhAR/dIZg=
181-
github.com/linode/linodego v1.52.2/go.mod h1:bI949fZaVchjWyKIA08hNyvAcV6BAS+PM2op3p7PAWA=
182180
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
183181
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
184182
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
@@ -223,6 +221,8 @@ github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2
223221
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
224222
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
225223
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
224+
github.com/rahulait/linodego v1.50.1-0.20250708032219-cf7181d2963f h1:16z+vd4lkTN/jDfZB5KpG0j2MM+Q6m/ZAb0EugSFuPU=
225+
github.com/rahulait/linodego v1.50.1-0.20250708032219-cf7181d2963f/go.mod h1:bI949fZaVchjWyKIA08hNyvAcV6BAS+PM2op3p7PAWA=
226226
github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
227227
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
228228
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=

internal/controller/linodemachine_controller_helpers.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,13 @@ func getVPCInterfaceConfig(ctx context.Context, machineScope *scope.MachineScope
500500
IPv4: &linodego.VPCIPv4{
501501
NAT1To1: ptr.To("any"),
502502
},
503+
IPv6: &linodego.InstanceConfigInterfaceCreateOptionsIPv6{
504+
Ranges: []linodego.InstanceConfigInterfaceCreateOptionsIPv6Range{
505+
{
506+
Range: ptr.To("/64"),
507+
},
508+
},
509+
},
503510
}, nil
504511
}
505512

internal/controller/linodevpc_controller_helpers.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,15 +93,28 @@ func updateVPCSpecSubnets(vpcScope *scope.VPCScope, vpc *linodego.VPC) {
9393

9494
func linodeVPCSpecToVPCCreateConfig(vpcSpec infrav1alpha2.LinodeVPCSpec) *linodego.VPCCreateOptions {
9595
subnets := make([]linodego.VPCSubnetCreateOptions, len(vpcSpec.Subnets))
96+
vpcIPv6 := []linodego.VPCCreateOptionsIPv6{
97+
{
98+
Range: &vpcSpec.IPv6Range,
99+
},
100+
}
101+
96102
for idx, subnet := range vpcSpec.Subnets {
97103
subnets[idx] = linodego.VPCSubnetCreateOptions{
98104
Label: subnet.Label,
99105
IPv4: subnet.IPv4,
106+
IPv6: []linodego.VPCSubnetCreateOptionsIPv6{
107+
{
108+
Range: &subnet.IPv6Range,
109+
},
110+
},
100111
}
101112
}
113+
102114
return &linodego.VPCCreateOptions{
103115
Description: vpcSpec.Description,
104116
Region: vpcSpec.Region,
105117
Subnets: subnets,
118+
IPv6: vpcIPv6,
106119
}
107120
}

internal/webhook/v1alpha2/linodevpc_webhook.go

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"net/netip"
2424
"regexp"
2525
"slices"
26+
"strconv"
2627
"strings"
2728

2829
"go4.org/netipx"
@@ -146,7 +147,11 @@ func (r *linodeVPCValidator) ValidateDelete(ctx context.Context, obj runtime.Obj
146147

147148
func (r *linodeVPCValidator) validateLinodeVPCSpec(ctx context.Context, linodeclient clients.LinodeClient, spec infrav1alpha2.LinodeVPCSpec, skipAPIValidation bool) field.ErrorList {
148149
// TODO: instrument with tracing, might need refactor to preserve readibility
149-
var errs field.ErrorList
150+
var (
151+
errs field.ErrorList
152+
ipv6Range = spec.IPv6Range
153+
ipv6RangePath = field.NewPath("spec").Child("ipv6Range")
154+
)
150155

151156
if !skipAPIValidation {
152157
if err := validateRegion(ctx, linodeclient, spec.Region, field.NewPath("spec").Child("region"), LinodeVPCCapability); err != nil {
@@ -157,6 +162,12 @@ func (r *linodeVPCValidator) validateLinodeVPCSpec(ctx context.Context, linodecl
157162
errs = slices.Concat(errs, err)
158163
}
159164

165+
// Validate VPC IPv6 Range
166+
rangeErr := validateIPv6Range(ipv6Range, ipv6RangePath)
167+
if rangeErr != nil {
168+
errs = append(errs, rangeErr)
169+
}
170+
160171
if len(errs) == 0 {
161172
return nil
162173
}
@@ -173,10 +184,12 @@ func (r *linodeVPCValidator) validateLinodeVPCSubnets(spec infrav1alpha2.LinodeV
173184

174185
for i, subnet := range spec.Subnets {
175186
var (
176-
label = subnet.Label
177-
labelPath = field.NewPath("spec").Child("Subnets").Index(i).Child("Label")
178-
ip = subnet.IPv4
179-
ipPath = field.NewPath("spec").Child("Subnets").Index(i).Child("IPv4")
187+
label = subnet.Label
188+
labelPath = field.NewPath("spec").Child("Subnets").Index(i).Child("Label")
189+
ip = subnet.IPv4
190+
ipPath = field.NewPath("spec").Child("Subnets").Index(i).Child("IPv4")
191+
ipv6Range = subnet.IPv6Range
192+
ipv6RangePath = field.NewPath("spec").Child("Subnets").Index(i).Child("IPv6Range")
180193
)
181194

182195
// Validate Subnet Label
@@ -202,6 +215,12 @@ func (r *linodeVPCValidator) validateLinodeVPCSubnets(spec infrav1alpha2.LinodeV
202215
if cidrs, err = builder.IPSet(); err != nil {
203216
return append(field.ErrorList{}, field.InternalError(ipPath, fmt.Errorf("build ip set: %w", err)))
204217
}
218+
219+
// Validate Subnet IPv6 Range
220+
rangeErr := validateIPv6Range(ipv6Range, ipv6RangePath)
221+
if rangeErr != nil {
222+
errs = append(errs, rangeErr)
223+
}
205224
}
206225

207226
if len(errs) == 0 {
@@ -282,3 +301,23 @@ func validateSubnetIPv4CIDR(cidr string, path *field.Path) (*netipx.IPSet, *fiel
282301
}
283302
return set, nil
284303
}
304+
305+
func validateIPv6Range(ipv6Range string, path *field.Path) *field.Error {
306+
var errs = []error{
307+
errors.New("IPv6 range must start with /. Example: /64"),
308+
errors.New("IPv6 range doesn't contain a valid number after /"),
309+
errors.New("IPv6 range must be between /0 and /128"),
310+
}
311+
if !strings.HasPrefix(ipv6Range, "/") {
312+
return field.Invalid(path, ipv6Range, errs[0].Error())
313+
}
314+
numStr := strings.TrimPrefix(ipv6Range, "/")
315+
num, err := strconv.Atoi(numStr)
316+
if err != nil {
317+
return field.Invalid(path, ipv6Range, errs[1].Error())
318+
}
319+
if num < 0 || num > 128 {
320+
return field.Invalid(path, ipv6Range, errs[2].Error())
321+
}
322+
return nil
323+
}

0 commit comments

Comments
 (0)