Skip to content

Commit a1470d4

Browse files
authored
fix: Namespacesync controller should reconcile an updated namespace (#775)
**What problem does this PR solve?**: The namespacesync controller did not reconcile a namespace when it was updated. We anticipated namespaces to meet the criteria for "target namespace" when they were created. We also wanted to avoid reconciling namespaces unnecessarily. This PR makes the controller reconcile an updated namespace, if the answer to question "is this a target namespace," has changed. It also adds an integration test (which fails without the subsequent fix commit). **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 b65cb36 commit a1470d4

File tree

4 files changed

+51
-9
lines changed

4 files changed

+51
-9
lines changed

cmd/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ func main() {
173173
Client: mgr.GetClient(),
174174
UnstructuredCachingClient: unstructuredCachingClient,
175175
SourceClusterClassNamespace: namespacesyncOptions.SourceNamespace,
176-
TargetNamespaceFilter: namespacesync.NamespaceHasLabelKey(namespacesyncOptions.TargetNamespaceLabelKey),
176+
IsTargetNamespace: namespacesync.NamespaceHasLabelKey(namespacesyncOptions.TargetNamespaceLabelKey),
177177
}).SetupWithManager(
178178
signalCtx,
179179
mgr,

pkg/controllers/namespacesync/controller.go

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,17 @@ type Reconciler struct {
2828
// SourceClusterClassNamespace is the namespace from which ClusterClasses are copied.
2929
SourceClusterClassNamespace string
3030

31-
// TargetNamespaceFilter determines whether ClusterClasses should be copied to a given namespace.
32-
TargetNamespaceFilter func(ns *corev1.Namespace) bool
31+
// IsTargetNamespace determines whether ClusterClasses should be copied to a given namespace.
32+
IsTargetNamespace func(ns *corev1.Namespace) bool
3333
}
3434

3535
func (r *Reconciler) SetupWithManager(
3636
ctx context.Context,
3737
mgr ctrl.Manager,
3838
options controller.Options,
3939
) error {
40-
if r.TargetNamespaceFilter == nil {
41-
return fmt.Errorf("target Namespace filter is nil")
40+
if r.IsTargetNamespace == nil {
41+
return fmt.Errorf("define IsTargetNamespace function to use controller")
4242
}
4343

4444
err := ctrl.NewControllerManagedBy(mgr).
@@ -52,12 +52,22 @@ func (r *Reconciler) SetupWithManager(
5252
if !ok {
5353
return false
5454
}
55-
return r.TargetNamespaceFilter(ns)
55+
return r.IsTargetNamespace(ns)
5656
},
5757
UpdateFunc: func(e event.UpdateEvent) bool {
5858
// Called when an object is already in the cache, and it is either updated,
5959
// or fetched as part of a re-list (aka re-sync).
60-
return false
60+
nsOld, ok := e.ObjectOld.(*corev1.Namespace)
61+
if !ok {
62+
return false
63+
}
64+
nsNew, ok := e.ObjectNew.(*corev1.Namespace)
65+
if !ok {
66+
return false
67+
}
68+
// Only reconcile the namespace if the answer to the question "Is this a
69+
// target namespace?" changed from no to yes.
70+
return !r.IsTargetNamespace(nsOld) && r.IsTargetNamespace(nsNew)
6171
},
6272
DeleteFunc: func(e event.DeleteEvent) bool {
6373
// Ignore deletes.
@@ -93,7 +103,7 @@ func (r *Reconciler) clusterClassToNamespaces(ctx context.Context, o client.Obje
93103
rs := []ctrl.Request{}
94104
for i := range namespaceList.Items {
95105
ns := &namespaceList.Items[i]
96-
if r.TargetNamespaceFilter(ns) {
106+
if r.IsTargetNamespace(ns) {
97107
rs = append(rs,
98108
ctrl.Request{
99109
NamespacedName: client.ObjectKeyFromObject(ns),

pkg/controllers/namespacesync/controller_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,38 @@ import (
1717
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/internal/test/builder"
1818
)
1919

20+
func TestReconcileExistingNamespaceWithUpdatedLabels(t *testing.T) {
21+
g := NewWithT(t)
22+
timeout := 5 * time.Second
23+
24+
sourceClusterClassName, cleanup, err := createUniqueClusterClassAndTemplates(
25+
sourceClusterClassNamespace,
26+
)
27+
g.Expect(err).ToNot(HaveOccurred())
28+
defer func() {
29+
g.Expect(cleanup()).To(Succeed())
30+
}()
31+
32+
// Create namespace without label
33+
targetNamespace, err := env.CreateNamespace(ctx, "target", map[string]string{})
34+
g.Expect(err).ToNot(HaveOccurred())
35+
36+
// Label the namespace
37+
targetNamespace.Labels[targetNamespaceLabelKey] = ""
38+
err = env.Update(ctx, targetNamespace)
39+
g.Expect(err).ToNot(HaveOccurred())
40+
41+
g.Eventually(func() error {
42+
return verifyClusterClassAndTemplates(
43+
env.Client,
44+
sourceClusterClassName,
45+
targetNamespace.Name,
46+
)
47+
},
48+
timeout,
49+
).Should(Succeed())
50+
}
51+
2052
func TestReconcileNewNamespaces(t *testing.T) {
2153
g := NewWithT(t)
2254
timeout := 5 * time.Second

pkg/controllers/namespacesync/suite_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func TestMain(m *testing.M) {
5858
Client: mgr.GetClient(),
5959
UnstructuredCachingClient: unstructuredCachingClient,
6060
SourceClusterClassNamespace: sourceClusterClassNamespace,
61-
TargetNamespaceFilter: NamespaceHasLabelKey(targetNamespaceLabelKey),
61+
IsTargetNamespace: NamespaceHasLabelKey(targetNamespaceLabelKey),
6262
}).SetupWithManager(ctx, mgr, controller.Options{MaxConcurrentReconciles: 1}); err != nil {
6363
panic(fmt.Sprintf("unable to create reconciler: %v", err))
6464
}

0 commit comments

Comments
 (0)