Skip to content

Commit e4d2b28

Browse files
committed
[node_allocator] Add stale annotation cleanup.
To only execute it once, run for default network NodeAllocator only, since it is always created. Signed-off-by: Nadia Pinaeva <[email protected]>
1 parent 0bbfdd8 commit e4d2b28

File tree

3 files changed

+72
-1
lines changed

3 files changed

+72
-1
lines changed

go-controller/pkg/clustermanager/node/node_allocator.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ func (na *NodeAllocator) Init() error {
7171
if !na.hasNodeSubnetAllocation() {
7272
return nil
7373
}
74+
na.CleanupStaleAnnotation()
7475

7576
clusterSubnets := na.netInfo.Subnets()
7677

@@ -96,6 +97,31 @@ func (na *NodeAllocator) Init() error {
9697
return nil
9798
}
9899

100+
// CleanupStaleAnnotation cleans up the stale annotations on all nodes.
101+
// If an error occurs, it logs the error and continues to the next node.
102+
func (na *NodeAllocator) CleanupStaleAnnotation() {
103+
// only cleanup once with the default network NodeAllocator
104+
if !na.netInfo.IsDefault() {
105+
return
106+
}
107+
existingNodes, err := na.nodeLister.List(labels.Everything())
108+
if err != nil {
109+
klog.Errorf("Error in retrieving the nodes: %v", err)
110+
return
111+
}
112+
113+
for _, node := range existingNodes {
114+
if _, ok := node.Annotations[util.OVNNodeGRLRPAddrs]; !ok {
115+
continue
116+
}
117+
// to cleanup an annotation, set it to nil
118+
if err = na.kube.SetAnnotationsOnNode(node.Name, map[string]interface{}{util.OVNNodeGRLRPAddrs: nil}); err != nil {
119+
klog.Warningf("Failed to clear node %s annotation %s: %v",
120+
node.Name, util.OVNNodeGRLRPAddrs, err)
121+
}
122+
}
123+
}
124+
99125
func (na *NodeAllocator) hasHybridOverlayAllocation() bool {
100126
// When config.HybridOverlay.ClusterSubnets is empty, assume the subnet allocation will be managed by an external component.
101127
return config.HybridOverlay.Enabled && !na.netInfo.IsSecondary() && len(config.HybridOverlay.ClusterSubnets) > 0

go-controller/pkg/clustermanager/node/node_allocator_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package node
22

33
import (
4+
"context"
45
"fmt"
56
"net"
67
"reflect"
@@ -10,11 +11,13 @@ import (
1011

1112
corev1 "k8s.io/api/core/v1"
1213
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14+
"k8s.io/client-go/kubernetes/fake"
1315
"k8s.io/client-go/listers/core/v1"
1416
"k8s.io/client-go/tools/cache"
1517

1618
ovncnitypes "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/cni/types"
1719
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/config"
20+
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/kube"
1821
ovntest "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/testing"
1922
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/types"
2023
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/util"
@@ -288,6 +291,7 @@ func TestController_allocateNodeSubnets(t *testing.T) {
288291
na := &NodeAllocator{
289292
netInfo: netInfo,
290293
clusterSubnetAllocator: NewSubnetAllocator(),
294+
nodeLister: newFakeNodeLister([]*corev1.Node{}),
291295
}
292296

293297
if err := na.Init(); err != nil {
@@ -403,3 +407,44 @@ func newFakeNodeLister(nodes []*corev1.Node) v1.NodeLister {
403407
}
404408
return v1.NewNodeLister(indexer)
405409
}
410+
411+
func TestController_CleanupStaleAnnotation(t *testing.T) {
412+
// create a node with an annotation that shouldn't be changed and one that should be cleaned up.
413+
newNode := &corev1.Node{
414+
ObjectMeta: metav1.ObjectMeta{
415+
Name: "node1",
416+
Annotations: map[string]string{"leave-me": "value", util.OVNNodeGRLRPAddrs: "remove-me"},
417+
},
418+
}
419+
fakeClient := fake.NewClientset(newNode)
420+
kube := &kube.Kube{
421+
KClient: fakeClient,
422+
}
423+
424+
netInfo, err := util.NewNetInfo(
425+
&ovncnitypes.NetConf{
426+
NetConf: cnitypes.NetConf{Name: types.DefaultNetworkName},
427+
},
428+
)
429+
if err != nil {
430+
t.Fatal(err)
431+
}
432+
433+
na := &NodeAllocator{
434+
nodeLister: newFakeNodeLister([]*corev1.Node{newNode}),
435+
kube: kube,
436+
netInfo: netInfo,
437+
}
438+
na.CleanupStaleAnnotation()
439+
nodes, err := fakeClient.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{})
440+
if err != nil {
441+
t.Fatal(err)
442+
}
443+
if len(nodes.Items) != 1 {
444+
t.Fatalf("Expected 1 node, got %d", len(nodes.Items))
445+
}
446+
// check that unrelated annotation is not changed, and stale one is cleaned up
447+
if !reflect.DeepEqual(nodes.Items[0].Annotations, map[string]string{"leave-me": "value"}) {
448+
t.Fatalf("Expected annotation %s to be cleaned up, got %v", util.OVNNodeGRLRPAddrs, nodes.Items[0].Annotations)
449+
}
450+
}

go-controller/pkg/util/node_annotations.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ const (
8585
// \"l2-network\":{\"ipv4\":\"100.65.0.4/16\",\"ipv6\":\"fd99::4/64\"},
8686
// \"l3-network\":{\"ipv4\":\"100.65.0.4/16\",\"ipv6\":\"fd99::4/64\"}
8787
// }",
88-
// TODO add cleanup code
88+
// deprecated, only used for cleanup
8989
OVNNodeGRLRPAddrs = "k8s.ovn.org/node-gateway-router-lrp-ifaddrs"
9090

9191
// OvnNodeMasqCIDR is the CIDR form representation of the masquerade subnet that is currently configured on this node (i.e. 169.254.169.0/29)

0 commit comments

Comments
 (0)