Skip to content

Commit 620018c

Browse files
oilbeaterclaude
andcommitted
fix: use targeted patch in calcSubnetStatusIP to prevent U2O status overwrite
calcSubnetStatusIP previously used subnet.Status.Bytes() which serialized the entire SubnetStatus and patched all fields to etcd. This caused a race condition where handleUpdateSubnetStatus could overwrite U2OInterconnectionVPC with stale data from its informer cache, leading to flaky e2e test failures in "should support underlay to overlay subnet interconnection". The race condition occurs when: 1. handleAddOrUpdateSubnet sets U2OInterconnectionVPC and patches status 2. handleUpdateSubnetStatus retries (from IP inconsistency requeue), reads stale cache without U2OInterconnectionVPC, and calcSubnetStatusIP overwrites all status fields including U2OInterconnectionVPC="" Fix by using a targeted JSON merge patch that only includes the 8 IP-related fields, leaving non-IP fields like U2OInterconnectionVPC untouched. Signed-off-by: Mengxin Liu <liumengxinfly@gmail.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 53b0946 commit 620018c

File tree

1 file changed

+24
-1
lines changed

1 file changed

+24
-1
lines changed

pkg/controller/subnet_status.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,30 @@ func (c *Controller) calcSubnetStatusIP(subnet *kubeovnv1.Subnet) (*kubeovnv1.Su
242242
subnet.Status.V6UsingIPRange = v6UsingIPStr
243243
subnet.Status.V4AvailableIPRange = v4AvailableIPStr
244244
subnet.Status.V6AvailableIPRange = v6AvailableIPStr
245-
bytes, err := subnet.Status.Bytes()
245+
246+
// Use a targeted patch with only IP-related fields to avoid overwriting
247+
// non-IP status fields (e.g., U2OInterconnectionVPC) set by other handlers.
248+
ipStatusPatch := struct {
249+
Status struct {
250+
V4AvailableIPs float64 `json:"v4availableIPs"`
251+
V4AvailableIPRange string `json:"v4availableIPrange"`
252+
V4UsingIPs float64 `json:"v4usingIPs"`
253+
V4UsingIPRange string `json:"v4usingIPrange"`
254+
V6AvailableIPs float64 `json:"v6availableIPs"`
255+
V6AvailableIPRange string `json:"v6availableIPrange"`
256+
V6UsingIPs float64 `json:"v6usingIPs"`
257+
V6UsingIPRange string `json:"v6usingIPrange"`
258+
} `json:"status"`
259+
}{}
260+
ipStatusPatch.Status.V4AvailableIPs = v4availableIPs
261+
ipStatusPatch.Status.V4AvailableIPRange = v4AvailableIPStr
262+
ipStatusPatch.Status.V4UsingIPs = v4UsingIPs
263+
ipStatusPatch.Status.V4UsingIPRange = v4UsingIPStr
264+
ipStatusPatch.Status.V6AvailableIPs = v6availableIPs
265+
ipStatusPatch.Status.V6AvailableIPRange = v6AvailableIPStr
266+
ipStatusPatch.Status.V6UsingIPs = v6UsingIPs
267+
ipStatusPatch.Status.V6UsingIPRange = v6UsingIPStr
268+
bytes, err := json.Marshal(ipStatusPatch)
246269
if err != nil {
247270
klog.Error(err)
248271
return nil, err

0 commit comments

Comments
 (0)