From ad9dbce832cec9b2929f05e1879b4658a021d114 Mon Sep 17 00:00:00 2001 From: Daniel Lipovetsky Date: Tue, 18 Jun 2024 10:47:04 -0700 Subject: [PATCH 1/2] test: Verify that empty namespace label key will not return a match --- pkg/controllers/namespacesync/controller.go | 7 --- pkg/controllers/namespacesync/label.go | 10 ++++ pkg/controllers/namespacesync/label_test.go | 59 +++++++++++++++++++++ 3 files changed, 69 insertions(+), 7 deletions(-) create mode 100644 pkg/controllers/namespacesync/label.go create mode 100644 pkg/controllers/namespacesync/label_test.go diff --git a/pkg/controllers/namespacesync/controller.go b/pkg/controllers/namespacesync/controller.go index a331f282b..7080dc95a 100644 --- a/pkg/controllers/namespacesync/controller.go +++ b/pkg/controllers/namespacesync/controller.go @@ -32,13 +32,6 @@ type Reconciler struct { TargetNamespaceFilter func(ns *corev1.Namespace) bool } -var NamespaceHasLabelKey = func(key string) func(ns *corev1.Namespace) bool { - return func(ns *corev1.Namespace) bool { - _, ok := ns.GetLabels()[key] - return ok - } -} - func (r *Reconciler) SetupWithManager( ctx context.Context, mgr ctrl.Manager, diff --git a/pkg/controllers/namespacesync/label.go b/pkg/controllers/namespacesync/label.go new file mode 100644 index 000000000..9dc9d8bd7 --- /dev/null +++ b/pkg/controllers/namespacesync/label.go @@ -0,0 +1,10 @@ +package namespacesync + +import corev1 "k8s.io/api/core/v1" + +var NamespaceHasLabelKey = func(key string) func(ns *corev1.Namespace) bool { + return func(ns *corev1.Namespace) bool { + _, ok := ns.GetLabels()[key] + return ok + } +} diff --git a/pkg/controllers/namespacesync/label_test.go b/pkg/controllers/namespacesync/label_test.go new file mode 100644 index 000000000..0c57807c2 --- /dev/null +++ b/pkg/controllers/namespacesync/label_test.go @@ -0,0 +1,59 @@ +package namespacesync + +import ( + "testing" + + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestNamespaceHasLabelKey(t *testing.T) { + tests := []struct { + name string + key string + ns *corev1.Namespace + want bool + }{ + { + name: "match a labeled namespace", + key: "testkey", + ns: &corev1.Namespace{ + ObjectMeta: v1.ObjectMeta{ + Name: "test", + Labels: map[string]string{ + "testkey": "", + }, + }, + }, + want: true, + }, + { + name: "do not match if label key is not found", + key: "testkey", + ns: &corev1.Namespace{ + ObjectMeta: v1.ObjectMeta{ + Name: "test", + }, + }, + want: false, + }, + { + name: "do not match if label key is empty string", + key: "", + ns: &corev1.Namespace{ + ObjectMeta: v1.ObjectMeta{ + Name: "test", + }, + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fn := NamespaceHasLabelKey(tt.key) + if got := fn(tt.ns); got != tt.want { + t.Fatalf("got %t, want %t", got, tt.want) + } + }) + } +} From 7cabebf58d4999156d51404d3b59c74f9f325fd3 Mon Sep 17 00:00:00 2001 From: Daniel Lipovetsky Date: Tue, 18 Jun 2024 11:03:55 -0700 Subject: [PATCH 2/2] fix: List no resources when source namespace is empty string Previously, the controller listed resources in all namespaces when the source namespace was an empty string. --- pkg/controllers/namespacesync/controller.go | 6 +++++ .../namespacesync/controller_test.go | 23 +++++++++++++++++++ pkg/controllers/namespacesync/label.go | 2 ++ pkg/controllers/namespacesync/label_test.go | 2 ++ 4 files changed, 33 insertions(+) diff --git a/pkg/controllers/namespacesync/controller.go b/pkg/controllers/namespacesync/controller.go index 7080dc95a..448a5fef2 100644 --- a/pkg/controllers/namespacesync/controller.go +++ b/pkg/controllers/namespacesync/controller.go @@ -150,6 +150,12 @@ func (r *Reconciler) listSourceClusterClasses( []clusterv1.ClusterClass, error, ) { + // Handle the empty string explicitly, because listing resources with an empty + // string namespace returns resources in all namespaces. + if r.SourceClusterClassNamespace == "" { + return nil, nil + } + ccl := &clusterv1.ClusterClassList{} err := r.Client.List(ctx, ccl, client.InNamespace(r.SourceClusterClassNamespace)) if err != nil { diff --git a/pkg/controllers/namespacesync/controller_test.go b/pkg/controllers/namespacesync/controller_test.go index d9db1a5cb..93ee0dcc8 100644 --- a/pkg/controllers/namespacesync/controller_test.go +++ b/pkg/controllers/namespacesync/controller_test.go @@ -73,6 +73,29 @@ func TestReconcileNewClusterClass(t *testing.T) { } } +func TestSourceClusterClassNamespaceEmpty(t *testing.T) { + g := NewWithT(t) + + _, cleanup, err := createUniqueClusterClassAndTemplates( + sourceClusterClassNamespace, + ) + g.Expect(err).ToNot(HaveOccurred()) + defer func() { + g.Expect(cleanup()).To(Succeed()) + }() + + // This test initializes its own reconciler, instead of using the one created + // in suite_test.go, in order to configure the source namespace. + r := Reconciler{ + Client: env.Client, + SourceClusterClassNamespace: "", + } + + ns, err := r.listSourceClusterClasses(ctx) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(ns).To(BeEmpty()) +} + func verifyClusterClassAndTemplates( cli client.Reader, name, diff --git a/pkg/controllers/namespacesync/label.go b/pkg/controllers/namespacesync/label.go index 9dc9d8bd7..b0bf3aae9 100644 --- a/pkg/controllers/namespacesync/label.go +++ b/pkg/controllers/namespacesync/label.go @@ -1,3 +1,5 @@ +// Copyright 2024 Nutanix. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 package namespacesync import corev1 "k8s.io/api/core/v1" diff --git a/pkg/controllers/namespacesync/label_test.go b/pkg/controllers/namespacesync/label_test.go index 0c57807c2..d274687ba 100644 --- a/pkg/controllers/namespacesync/label_test.go +++ b/pkg/controllers/namespacesync/label_test.go @@ -1,3 +1,5 @@ +// Copyright 2024 Nutanix. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 package namespacesync import (