Skip to content

Commit de49a38

Browse files
committed
Support SubnetIPReservations with reservedIPs
Signed-off-by: Yanjun Zhou <yanjun.zhou@broadcom.com>
1 parent 6f7ddad commit de49a38

23 files changed

+1048
-146
lines changed

build/yaml/crd/vpc/crd.nsx.vmware.com_subnetipreservations.yaml

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,20 +59,37 @@ spec:
5959
minimum: 1
6060
type: integer
6161
x-kubernetes-validations:
62-
- message: NumberOfIPs is immutable
62+
- message: numberOfIPs is immutable
6363
rule: self == oldSelf
64+
reservedIPs:
65+
description: |-
66+
ReservedIPs represents array of Reserved IPs. It can can contain IP addresses,
67+
IP Address range and CIDRs.
68+
Supported formats include: ["192.168.1.1", "192.168.1.3-192.168.1.100", "192.168.2.0/28"]
69+
items:
70+
type: string
71+
minItems: 1
72+
type: array
6473
subnet:
6574
description: |-
6675
Subnet specifies the Subnet to reserve IPs from.
6776
The Subnet needs to have static IP allocation activated.
6877
type: string
6978
x-kubernetes-validations:
70-
- message: Subnet is immutable
79+
- message: subnet is immutable
7180
rule: self == oldSelf
7281
required:
73-
- numberOfIPs
7482
- subnet
7583
type: object
84+
x-kubernetes-validations:
85+
- message: Only one of numberOfIPs or reservedIPs can be specified
86+
rule: '!has(self.numberOfIPs) || !has(self.reservedIPs)'
87+
- message: One of numberOfIPs or reservedIPs must be specified
88+
rule: has(self.numberOfIPs) || has(self.reservedIPs)
89+
- message: reservedIPs cannot be unset once set
90+
rule: '!has(oldSelf.reservedIPs) || has(self.reservedIPs)'
91+
- message: numberOfIPs cannot be unset once set
92+
rule: '!has(oldSelf.numberOfIPs) || has(self.numberOfIPs)'
7693
status:
7794
description: SubnetIPReservationStatus defines the observed state of SubnetIPReservation
7895
properties:
@@ -110,7 +127,7 @@ spec:
110127
ips:
111128
description: |-
112129
List of reserved IPs.
113-
Supported formats include: ["192.168.1.1", "192.168.1.3-192.168.1.100"]
130+
Supported formats include: ["192.168.1.1", "192.168.1.3-192.168.1.100", "192.168.2.0/28"]
114131
items:
115132
type: string
116133
type: array

docs/ref/apis/vpc.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ _Appears in:_
141141
| `AutoSnatEnabled` | |
142142
| `ExternalIPBlocksConfigured` | |
143143
| `DeletionFailed` | |
144+
| `UpdateFailed` | |
144145

145146

146147
#### ConnectivityState
@@ -850,7 +851,8 @@ _Appears in:_
850851
| Field | Description | Default | Validation |
851852
| --- | --- | --- | --- |
852853
| `subnet` _string_ | Subnet specifies the Subnet to reserve IPs from.<br />The Subnet needs to have static IP allocation activated. | | Required: \{\} <br /> |
853-
| `numberOfIPs` _integer_ | NumberOfIPs defines number of IPs requested to be reserved. | | Maximum: 100 <br />Minimum: 1 <br />Required: \{\} <br /> |
854+
| `numberOfIPs` _integer_ | NumberOfIPs defines number of IPs requested to be reserved. | | Maximum: 100 <br />Minimum: 1 <br /> |
855+
| `reservedIPs` _string array_ | ReservedIPs represents array of Reserved IPs. It can can contain IP addresses,<br />IP Address range and CIDRs.<br />Supported formats include: ["192.168.1.1", "192.168.1.3-192.168.1.100", "192.168.2.0/28"] | | MinItems: 1 <br /> |
854856

855857

856858
#### SubnetIPReservationStatus
@@ -867,7 +869,7 @@ _Appears in:_
867869
| Field | Description | Default | Validation |
868870
| --- | --- | --- | --- |
869871
| `conditions` _[Condition](#condition) array_ | Conditions described if the SubnetIPReservation is configured on NSX or not.<br />Condition type "" | | |
870-
| `ips` _string array_ | List of reserved IPs.<br />Supported formats include: ["192.168.1.1", "192.168.1.3-192.168.1.100"] | | |
872+
| `ips` _string array_ | List of reserved IPs.<br />Supported formats include: ["192.168.1.1", "192.168.1.3-192.168.1.100", "192.168.2.0/28"] | | |
871873

872874

873875
#### SubnetInfo

go.mod

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ require (
3232
github.com/vmware/govmomi v0.27.4
3333
github.com/vmware/vsphere-automation-sdk-go/lib v0.7.0
3434
github.com/vmware/vsphere-automation-sdk-go/runtime v0.7.0
35-
github.com/vmware/vsphere-automation-sdk-go/services/nsxt v0.0.0-20251214130913-3e87ca3a7aed
36-
github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp v0.0.0-20251214130913-3e87ca3a7aed
35+
github.com/vmware/vsphere-automation-sdk-go/services/nsxt v0.0.0-20260310075027-d32fca6a7b22
36+
github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp v0.0.0-20260310075027-d32fca6a7b22
3737
go.uber.org/automaxprocs v1.5.3
3838
go.uber.org/zap v1.26.0
3939
golang.org/x/crypto v0.47.0
@@ -47,7 +47,6 @@ require (
4747
k8s.io/code-generator v0.31.0
4848
k8s.io/utils v0.0.0-20260108192941-914a6e750570
4949
sigs.k8s.io/controller-runtime v0.19.0
50-
sigs.k8s.io/gateway-api v1.5.0
5150
)
5251

5352
require (
@@ -79,6 +78,8 @@ require (
7978
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
8079
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
8180
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
81+
github.com/onsi/ginkgo/v2 v2.28.0 // indirect
82+
github.com/onsi/gomega v1.39.1 // indirect
8283
github.com/pkg/errors v0.9.1 // indirect
8384
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
8485
github.com/prometheus/client_model v0.6.1 // indirect
@@ -91,13 +92,13 @@ require (
9192
go.yaml.in/yaml/v2 v2.4.3 // indirect
9293
go.yaml.in/yaml/v3 v3.0.4 // indirect
9394
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc // indirect
94-
golang.org/x/mod v0.31.0 // indirect
95+
golang.org/x/mod v0.32.0 // indirect
9596
golang.org/x/net v0.49.0 // indirect
9697
golang.org/x/oauth2 v0.34.0 // indirect
9798
golang.org/x/sys v0.40.0 // indirect
9899
golang.org/x/term v0.39.0 // indirect
99100
golang.org/x/text v0.33.0 // indirect
100-
golang.org/x/tools v0.40.0 // indirect
101+
golang.org/x/tools v0.41.0 // indirect
101102
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
102103
google.golang.org/protobuf v1.36.11 // indirect
103104
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect

go.sum

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX
6565
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
6666
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
6767
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
68-
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
69-
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
68+
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 h1:z2ogiKUYzX5Is6zr/vP9vJGqPwcdqsWjOt+V8J7+bTc=
69+
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
7070
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
7171
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
7272
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -159,10 +159,10 @@ github.com/vmware/vsphere-automation-sdk-go/lib v0.7.0 h1:pT+oqJ8FD5eUBQkl+e7LZw
159159
github.com/vmware/vsphere-automation-sdk-go/lib v0.7.0/go.mod h1:f3+6YVZpNcK2pYyiQ94BoHWmjMj9BnYav0vNFuTiDVM=
160160
github.com/vmware/vsphere-automation-sdk-go/runtime v0.7.0 h1:pSBxa9Agh6bgW8Hr0A1eQxuwnxGTnuAVox8iQb023hg=
161161
github.com/vmware/vsphere-automation-sdk-go/runtime v0.7.0/go.mod h1:qdzEFm2iK3dvlmm99EYYNxs70HbzuiHyENFD24Ps8fQ=
162-
github.com/vmware/vsphere-automation-sdk-go/services/nsxt v0.0.0-20251214130913-3e87ca3a7aed h1:i0PpOk/+vFa48FJMIhOqMSi2koIKvKwm/t1K4xccuLA=
163-
github.com/vmware/vsphere-automation-sdk-go/services/nsxt v0.0.0-20251214130913-3e87ca3a7aed/go.mod h1:C3JVOHRVLrGBQ8kTWAiGYlRz5UQC5qAcTdt3tvA+5P0=
164-
github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp v0.0.0-20251214130913-3e87ca3a7aed h1:X1Adxoq1388wnuWK5fvEvxpEhcgRzhUe5L6vKeSEofU=
165-
github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp v0.0.0-20251214130913-3e87ca3a7aed/go.mod h1:ugk9I4YM62SSAox57l5NAVBCRIkPQ1RNLb3URxyTADc=
162+
github.com/vmware/vsphere-automation-sdk-go/services/nsxt v0.0.0-20260310075027-d32fca6a7b22 h1:yDMJj+UG0u9aDdC0Q1byw8QEjfPd8gm7QKB2mo2oU1I=
163+
github.com/vmware/vsphere-automation-sdk-go/services/nsxt v0.0.0-20260310075027-d32fca6a7b22/go.mod h1:C3JVOHRVLrGBQ8kTWAiGYlRz5UQC5qAcTdt3tvA+5P0=
164+
github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp v0.0.0-20260310075027-d32fca6a7b22 h1:SKbUc9p+LFUwtPvjk9WCwrjstN6NpewgPx4eWSIZq+k=
165+
github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp v0.0.0-20260310075027-d32fca6a7b22/go.mod h1:ugk9I4YM62SSAox57l5NAVBCRIkPQ1RNLb3URxyTADc=
166166
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
167167
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
168168
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -193,8 +193,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
193193
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
194194
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
195195
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
196-
golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI=
197-
golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg=
196+
golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
197+
golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=
198198
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
199199
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
200200
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -255,8 +255,8 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY
255255
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
256256
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
257257
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
258-
golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
259-
golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
258+
golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc=
259+
golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg=
260260
golang.org/x/tools/go/expect v0.1.0-deprecated h1:jY2C5HGYR5lqex3gEniOQL0r7Dq5+VGVgY1nudX5lXY=
261261
golang.org/x/tools/go/expect v0.1.0-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY=
262262
golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM=
@@ -304,8 +304,6 @@ k8s.io/utils v0.0.0-20260108192941-914a6e750570 h1:JT4W8lsdrGENg9W+YwwdLJxklIuKW
304304
k8s.io/utils v0.0.0-20260108192941-914a6e750570/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
305305
sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q=
306306
sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4=
307-
sigs.k8s.io/gateway-api v1.5.0 h1:duoo14Ky/fJXpjpmyMISE2RTBGnfCg8zICfTYLTnBJA=
308-
sigs.k8s.io/gateway-api v1.5.0/go.mod h1:GvCETiaMAlLym5CovLxGjS0NysqFk3+Yuq3/rh6QL2o=
309307
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
310308
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
311309
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=

pkg/apis/vpc/v1alpha1/subnetipreservation_types.go

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,28 @@ import (
88
)
99

1010
// SubnetIPReservationSpec defines the desired state of SubnetIPReservation
11+
// +kubebuilder:validation:XValidation:rule="!has(self.numberOfIPs) || !has(self.reservedIPs)",message="Only one of numberOfIPs or reservedIPs can be specified"
12+
// +kubebuilder:validation:XValidation:rule="has(self.numberOfIPs) || has(self.reservedIPs)",message="One of numberOfIPs or reservedIPs must be specified"
13+
// +kubebuilder:validation:XValidation:rule="!has(oldSelf.reservedIPs) || has(self.reservedIPs)",message="reservedIPs cannot be unset once set"
14+
// +kubebuilder:validation:XValidation:rule="!has(oldSelf.numberOfIPs) || has(self.numberOfIPs)",message="numberOfIPs cannot be unset once set"
1115
type SubnetIPReservationSpec struct {
1216
// Subnet specifies the Subnet to reserve IPs from.
1317
// The Subnet needs to have static IP allocation activated.
1418
// +kubebuilder:validation:Required
15-
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Subnet is immutable"
19+
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="subnet is immutable"
1620
Subnet string `json:"subnet"`
1721

1822
// NumberOfIPs defines number of IPs requested to be reserved.
19-
// +kubebuilder:validation:Required
20-
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="NumberOfIPs is immutable"
23+
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="numberOfIPs is immutable"
2124
// +kubebuilder:validation:Maximum:=100
2225
// +kubebuilder:validation:Minimum:=1
23-
NumberOfIPs int `json:"numberOfIPs"`
26+
NumberOfIPs int `json:"numberOfIPs,omitempty"`
27+
28+
// ReservedIPs represents array of Reserved IPs. It can can contain IP addresses,
29+
// IP Address range and CIDRs.
30+
// Supported formats include: ["192.168.1.1", "192.168.1.3-192.168.1.100", "192.168.2.0/28"]
31+
// +kubebuilder:validation:MinItems=1
32+
ReservedIPs []string `json:"reservedIPs,omitempty"`
2433
}
2534

2635
// SubnetIPReservationStatus defines the observed state of SubnetIPReservation
@@ -29,7 +38,7 @@ type SubnetIPReservationStatus struct {
2938
// Condition type ""
3039
Conditions []Condition `json:"conditions,omitempty"`
3140
// List of reserved IPs.
32-
// Supported formats include: ["192.168.1.1", "192.168.1.3-192.168.1.100"]
41+
// Supported formats include: ["192.168.1.1", "192.168.1.3-192.168.1.100", "192.168.2.0/28"]
3342
IPs []string `json:"ips,omitempty"`
3443
}
3544

pkg/apis/vpc/v1alpha1/zz_generated.deepcopy.go

Lines changed: 6 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/controllers/subnetipreservation/subnetipreservation_controller.go

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,64 @@ type Reconciler struct {
4343
IPReservationService *subnetipreservation.IPReservationService
4444
SubnetService servicecommon.SubnetServiceProvider
4545
StatusUpdater common.StatusUpdater
46+
restoreMode bool
4647
}
4748

4849
func (r *Reconciler) RestoreReconcile() error {
50+
// Only resotre IPReservation if Subnet StaticIPReservation is supported
51+
if !r.IPReservationService.NSXClient.NSXCheckVersion(nsx.StaticIPReservation) {
52+
return nil
53+
}
54+
restoreList, err := r.getRestoreList()
55+
if err != nil {
56+
err = fmt.Errorf("failed to get SubnetIPReservation restore list: %w", err)
57+
return err
58+
}
59+
var errorList []error
60+
r.restoreMode = true
61+
for _, key := range restoreList {
62+
result, err := r.Reconcile(context.Background(), ctrl.Request{NamespacedName: key})
63+
if result.Requeue || err != nil {
64+
errorList = append(errorList, fmt.Errorf("failed to restore SubnetIPReservation %s, error: %w", key, err))
65+
}
66+
}
67+
if len(errorList) > 0 {
68+
return fmt.Errorf("errors found in SubnetIPReservation restore: %v", errorList)
69+
}
4970
return nil
5071
}
5172

73+
func (r *Reconciler) getRestoreList() ([]types.NamespacedName, error) {
74+
restoreList := []types.NamespacedName{}
75+
subnetIPReservationList := &v1alpha1.SubnetIPReservationList{}
76+
if err := r.Client.List(context.TODO(), subnetIPReservationList); err != nil {
77+
return restoreList, err
78+
}
79+
for _, ipReservation := range subnetIPReservationList.Items {
80+
// Skip the SubnetIPReservation which is not created
81+
if len(ipReservation.Status.IPs) == 0 {
82+
continue
83+
}
84+
var reservedIPs []string
85+
// Search for both dynamic and static ipreservation store for the NSX IPReservation
86+
dynamicIPReservations := r.IPReservationService.DynamicIPReservationStore.GetByIndex(servicecommon.TagScopeSubnetIPReservationCRUID, string(ipReservation.UID))
87+
if len(dynamicIPReservations) > 0 {
88+
reservedIPs = dynamicIPReservations[0].Ips
89+
} else {
90+
staticIPReservations := r.IPReservationService.StaticIPReservationStore.GetByIndex(servicecommon.TagScopeSubnetIPReservationCRUID, string(ipReservation.UID))
91+
if len(staticIPReservations) > 0 {
92+
reservedIPs = staticIPReservations[0].ReservedIps
93+
}
94+
}
95+
// Skip the SubnetIPReservation if the existing reserved ip is the same as CR status
96+
if reflect.DeepEqual(reservedIPs, ipReservation.Status.IPs) {
97+
continue
98+
}
99+
restoreList = append(restoreList, types.NamespacedName{Namespace: ipReservation.Namespace, Name: ipReservation.Name})
100+
}
101+
return restoreList, nil
102+
}
103+
52104
func NewReconciler(mgr ctrl.Manager, ipReservationService *subnetipreservation.IPReservationService, subnetService servicecommon.SubnetServiceProvider) *Reconciler {
53105
recorder := mgr.GetEventRecorderFor("subnetipreservation-controller")
54106
// Create the SubnetIPReservation Reconciler with the necessary services and configuration
@@ -195,14 +247,14 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
195247
}
196248

197249
// Create or update SubnetIPReservation
198-
nsxIPReservation, err := r.IPReservationService.GetOrCreateSubnetIPReservation(ipReservationCR, *nsxSubnet.Path)
250+
ips, err := r.IPReservationService.CreateOrUpdateSubnetIPReservation(ipReservationCR, *nsxSubnet.Path, r.restoreMode)
199251
if err != nil {
200252
log.Error(err, "Failed to get or create NSX SubnetIPReservations")
201253
r.StatusUpdater.UpdateFail(ctx, ipReservationCR, err, "Failed to get or create NSX SubnetIPReservations", setReadyStatusFalse)
202254
return common.ResultRequeue, nil
203255
}
204256

205-
ipReservationCR.Status.IPs = nsxIPReservation.Ips
257+
ipReservationCR.Status.IPs = ips
206258
// Update SubnetIPReservation with ready condition
207259
r.StatusUpdater.UpdateSuccess(ctx, ipReservationCR, setReadyStatusTrue)
208260
return common.ResultNormal, nil

0 commit comments

Comments
 (0)