From 2245bce7cb91b8331e6e621efbfc6ee6b7618014 Mon Sep 17 00:00:00 2001 From: Jean Chen Date: Fri, 26 Jun 2026 15:20:15 -0400 Subject: [PATCH] clustermanager: re-evaluate egress IPs when cloud egress IP config changes When cloud-network-config-controller updates the cloud.network.openshift.io/egress-ipconfig annotation (e.g., adding an IPv6 subnet that was initially missing because the AWS subnet's IPv6 CIDR block was not yet in 'associated' state), the node update handler returned early without re-triggering egress IP assignment. Add CloudEgressIPConfigAnnotationChanged() and include it in the early-return guard so that addEgressNode() is called whenever the annotation changes, allowing previously-unassigned IPv6 egress IPs to be reconsidered. Signed-off-by: Jean Chen Co-authored-by: Cursor --- .../pkg/clustermanager/egressip_event_handler.go | 14 ++++++++++++-- go-controller/pkg/util/node_annotations.go | 8 ++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/go-controller/pkg/clustermanager/egressip_event_handler.go b/go-controller/pkg/clustermanager/egressip_event_handler.go index 1368ba3d5b..ae830cffb6 100644 --- a/go-controller/pkg/clustermanager/egressip_event_handler.go +++ b/go-controller/pkg/clustermanager/egressip_event_handler.go @@ -128,6 +128,7 @@ func (h *egressIPClusterControllerEventHandler) UpdateResource(oldObj, newObj in isNewReady := h.eIPC.isEgressNodeReady(newNode) isNewReachable := h.eIPC.isEgressNodeReachable(newNode) isHostCIDRsAltered := util.NodeHostCIDRsAnnotationChanged(oldNode, newNode) + isCloudEgressIPConfigAltered := util.CloudEgressIPConfigAnnotationChanged(oldNode, newNode) h.eIPC.setNodeEgressReady(newNode.Name, isNewReady) if !oldHadEgressLabel && newHasEgressLabel { klog.Infof("Node: %s has been labeled, adding it for egress assignment", newNode.Name) @@ -142,7 +143,7 @@ func (h *egressIPClusterControllerEventHandler) UpdateResource(oldObj, newObj in } return nil } - if isOldReady == isNewReady && !isHostCIDRsAltered { + if isOldReady == isNewReady && !isHostCIDRsAltered && !isCloudEgressIPConfigAltered { return nil } if !isNewReady { @@ -151,7 +152,16 @@ func (h *egressIPClusterControllerEventHandler) UpdateResource(oldObj, newObj in return err } } else if isNewReady && isNewReachable { - klog.Infof("Node: %s is ready and reachable, adding it for egress assignment", newNode.Name) + if isCloudEgressIPConfigAltered { + // When cloud-network-config-controller updates the egress IP config + // annotation (e.g., adding an IPv6 subnet that was previously missing + // because the subnet's IPv6 CIDR was not yet in "associated" state), + // the node's egress IP capacity may have changed. Log this explicitly + // so operators can correlate annotation changes with re-assignments. + klog.Infof("Node: %s cloud egress IP config annotation changed, re-evaluating egress IP assignments", newNode.Name) + } else { + klog.Infof("Node: %s is ready and reachable, adding it for egress assignment", newNode.Name) + } h.eIPC.setNodeEgressReachable(newNode.Name, isNewReachable) if err := h.eIPC.addEgressNode(newNode.Name); err != nil { return err diff --git a/go-controller/pkg/util/node_annotations.go b/go-controller/pkg/util/node_annotations.go index 83e9c0a02e..fb9b4b0412 100644 --- a/go-controller/pkg/util/node_annotations.go +++ b/go-controller/pkg/util/node_annotations.go @@ -886,6 +886,14 @@ func NodeHostCIDRsAnnotationChanged(oldNode, newNode *corev1.Node) bool { return oldNode.Annotations[OVNNodeHostCIDRs] != newNode.Annotations[OVNNodeHostCIDRs] } +// CloudEgressIPConfigAnnotationChanged returns true if the cloud egress IP +// configuration annotation changed between oldNode and newNode. This annotation +// is managed by cloud-network-config-controller and carries the IPv4/IPv6 +// subnets and capacity for egress IP assignment on cloud platforms. +func CloudEgressIPConfigAnnotationChanged(oldNode, newNode *corev1.Node) bool { + return oldNode.Annotations[cloudEgressIPConfigAnnotationKey] != newNode.Annotations[cloudEgressIPConfigAnnotationKey] +} + // ParseNodeHostCIDRs returns the parsed host CIDRS living on a node func ParseNodeHostCIDRs(node *corev1.Node) (sets.Set[string], error) { addrAnnotation, ok := node.Annotations[OVNNodeHostCIDRs]