Skip to content

Commit 5feca7f

Browse files
authored
fix: Namespace Sync controller should list no resources when source namespace is empty string (#725)
**What problem does this PR solve?**: Previously, the controller listed resources in all namespaces when the source namespace was an empty string. Now, it lists no resources. The PR adds a test verifying the above. It also adds a test that verifies that an the controller will not match any namespaces when the target namespace label key is an empty string. **Which issue(s) this PR fixes**: Fixes # **How Has This Been Tested?**: <!-- Please describe the tests that you ran to verify your changes. Provide output from the tests and any manual steps needed to replicate the tests. --> **Special notes for your reviewer**: <!-- Use this to provide any additional information to the reviewers. This may include: - Best way to review the PR. - Where the author wants the most review attention on. - etc. -->
1 parent 0a74124 commit 5feca7f

File tree

4 files changed

+102
-7
lines changed

4 files changed

+102
-7
lines changed

pkg/controllers/namespacesync/controller.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,6 @@ type Reconciler struct {
3232
TargetNamespaceFilter func(ns *corev1.Namespace) bool
3333
}
3434

35-
var NamespaceHasLabelKey = func(key string) func(ns *corev1.Namespace) bool {
36-
return func(ns *corev1.Namespace) bool {
37-
_, ok := ns.GetLabels()[key]
38-
return ok
39-
}
40-
}
41-
4235
func (r *Reconciler) SetupWithManager(
4336
ctx context.Context,
4437
mgr ctrl.Manager,
@@ -157,6 +150,12 @@ func (r *Reconciler) listSourceClusterClasses(
157150
[]clusterv1.ClusterClass,
158151
error,
159152
) {
153+
// Handle the empty string explicitly, because listing resources with an empty
154+
// string namespace returns resources in all namespaces.
155+
if r.SourceClusterClassNamespace == "" {
156+
return nil, nil
157+
}
158+
160159
ccl := &clusterv1.ClusterClassList{}
161160
err := r.Client.List(ctx, ccl, client.InNamespace(r.SourceClusterClassNamespace))
162161
if err != nil {

pkg/controllers/namespacesync/controller_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,29 @@ func TestReconcileNewClusterClass(t *testing.T) {
7373
}
7474
}
7575

76+
func TestSourceClusterClassNamespaceEmpty(t *testing.T) {
77+
g := NewWithT(t)
78+
79+
_, cleanup, err := createUniqueClusterClassAndTemplates(
80+
sourceClusterClassNamespace,
81+
)
82+
g.Expect(err).ToNot(HaveOccurred())
83+
defer func() {
84+
g.Expect(cleanup()).To(Succeed())
85+
}()
86+
87+
// This test initializes its own reconciler, instead of using the one created
88+
// in suite_test.go, in order to configure the source namespace.
89+
r := Reconciler{
90+
Client: env.Client,
91+
SourceClusterClassNamespace: "",
92+
}
93+
94+
ns, err := r.listSourceClusterClasses(ctx)
95+
g.Expect(err).ToNot(HaveOccurred())
96+
g.Expect(ns).To(BeEmpty())
97+
}
98+
7699
func verifyClusterClassAndTemplates(
77100
cli client.Reader,
78101
name,
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright 2024 Nutanix. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
package namespacesync
4+
5+
import corev1 "k8s.io/api/core/v1"
6+
7+
var NamespaceHasLabelKey = func(key string) func(ns *corev1.Namespace) bool {
8+
return func(ns *corev1.Namespace) bool {
9+
_, ok := ns.GetLabels()[key]
10+
return ok
11+
}
12+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright 2024 Nutanix. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
package namespacesync
4+
5+
import (
6+
"testing"
7+
8+
corev1 "k8s.io/api/core/v1"
9+
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10+
)
11+
12+
func TestNamespaceHasLabelKey(t *testing.T) {
13+
tests := []struct {
14+
name string
15+
key string
16+
ns *corev1.Namespace
17+
want bool
18+
}{
19+
{
20+
name: "match a labeled namespace",
21+
key: "testkey",
22+
ns: &corev1.Namespace{
23+
ObjectMeta: v1.ObjectMeta{
24+
Name: "test",
25+
Labels: map[string]string{
26+
"testkey": "",
27+
},
28+
},
29+
},
30+
want: true,
31+
},
32+
{
33+
name: "do not match if label key is not found",
34+
key: "testkey",
35+
ns: &corev1.Namespace{
36+
ObjectMeta: v1.ObjectMeta{
37+
Name: "test",
38+
},
39+
},
40+
want: false,
41+
},
42+
{
43+
name: "do not match if label key is empty string",
44+
key: "",
45+
ns: &corev1.Namespace{
46+
ObjectMeta: v1.ObjectMeta{
47+
Name: "test",
48+
},
49+
},
50+
want: false,
51+
},
52+
}
53+
for _, tt := range tests {
54+
t.Run(tt.name, func(t *testing.T) {
55+
fn := NamespaceHasLabelKey(tt.key)
56+
if got := fn(tt.ns); got != tt.want {
57+
t.Fatalf("got %t, want %t", got, tt.want)
58+
}
59+
})
60+
}
61+
}

0 commit comments

Comments
 (0)