Skip to content

Commit b65cb36

Browse files
authored
fix: Copy ClusterClasses and Templates without their owner references (#776)
**What problem does this PR solve?**: Objects are garbage-collected if owners are not in the target namespace. Unfortunately, the envtest-based integration tests missed this, because envtest does not have garbage collection. I'd like an e2e test to create a cluster in a separate namespace, but that might in a future PR. **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 9cfc05f commit b65cb36

File tree

1 file changed

+34
-6
lines changed
  • pkg/controllers/namespacesync

1 file changed

+34
-6
lines changed

pkg/controllers/namespacesync/copy.go

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"fmt"
99

1010
corev1 "k8s.io/api/core/v1"
11+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1112
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
1213
"sigs.k8s.io/controller-runtime/pkg/client"
1314
)
@@ -19,9 +20,7 @@ func copyClusterClassAndTemplates(
1920
source *clusterv1.ClusterClass,
2021
namespace string,
2122
) error {
22-
target := source.DeepCopy()
23-
target.SetNamespace(namespace)
24-
target.SetResourceVersion("")
23+
target := copyObjectForCreate(source, source.Name, namespace)
2524

2625
if err := walkReferences(ctx, target, func(ctx context.Context, ref *corev1.ObjectReference) error {
2726
// Get referenced Template
@@ -31,9 +30,7 @@ func copyClusterClassAndTemplates(
3130
}
3231

3332
// Copy Template to target namespace
34-
targetTemplate := sourceTemplate.DeepCopy()
35-
targetTemplate.SetNamespace(namespace)
36-
targetTemplate.SetResourceVersion("")
33+
targetTemplate := copyObjectForCreate(sourceTemplate, sourceTemplate.GetName(), namespace)
3734

3835
if err := w.Create(ctx, targetTemplate); err != nil {
3936
return fmt.Errorf(
@@ -63,3 +60,34 @@ func copyClusterClassAndTemplates(
6360
}
6461
return nil
6562
}
63+
64+
// copyObjectForCreate copies the object, updating the name and namespace,
65+
// and preserving only labels and annotations metadata.
66+
func copyObjectForCreate[T client.Object](src T, name, namespace string) T {
67+
dst := src.DeepCopyObject().(T)
68+
69+
dst.SetName(name)
70+
dst.SetNamespace(namespace)
71+
72+
// Zero out ManagedFields (clients will set them)
73+
dst.SetManagedFields(nil)
74+
// Zero out OwnerReferences (object is garbage-collected if
75+
// owners are not in the target namespace)
76+
dst.SetOwnerReferences(nil)
77+
78+
// Zero out fields that are ignored by the API server on create
79+
dst.SetCreationTimestamp(metav1.Time{})
80+
dst.SetDeletionGracePeriodSeconds(nil)
81+
dst.SetDeletionTimestamp(nil)
82+
dst.SetFinalizers(nil)
83+
dst.SetGenerateName("")
84+
dst.SetGeneration(0)
85+
dst.SetLabels(nil)
86+
dst.SetManagedFields(nil)
87+
dst.SetOwnerReferences(nil)
88+
dst.SetResourceVersion("")
89+
dst.SetSelfLink("")
90+
dst.SetUID("")
91+
92+
return dst
93+
}

0 commit comments

Comments
 (0)