Skip to content

Commit 092473a

Browse files
authored
feat: don't alter well-known labels and annotations (#1170)
* feat: don't touch well-known labels and annotations These are reserved for kubernetes own usage and should not be altered by users. Apply the same logic alreayd used for PVC to all resources managed by this controller for both labels and annotations. * refactor: use map range for all map copying
1 parent 9baf10e commit 092473a

2 files changed

Lines changed: 98 additions & 29 deletions

File tree

internal/controller/amaltheasession_controller_test.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,68 @@ var _ = Describe("AmaltheaSession Controller", func() {
161161
})
162162
Expect(err).NotTo(HaveOccurred())
163163
})
164+
165+
It("should not touch well known labels/annotations", func(ctx SpecContext) {
166+
// Run reconcile once to start
167+
controllerReconciler := newReconciler()
168+
_, err := controllerReconciler.Reconcile(ctx, reconcile.Request{
169+
NamespacedName: typeNamespacedName,
170+
})
171+
Expect(err).NotTo(HaveOccurred())
172+
173+
// Adding new labels and annotations
174+
newLabels := map[string]string{
175+
"renku.io/test": "newLabel",
176+
"app.kubernetes.io/created-by": "other-manager",
177+
"app.kubernetes.io/name": "other-name",
178+
}
179+
expectedLabels := map[string]string{
180+
"renku.io/test": "newLabel",
181+
"app.kubernetes.io/created-by": "controller-manager",
182+
"app.kubernetes.io/name": "AmaltheaSession",
183+
}
184+
185+
// Adding well-known annotations to simulate the system doing it
186+
// These annotations are reserved and shall not be set/modified
187+
// by other components
188+
newAnnotations := map[string]string{
189+
"renku.io/test": "newAnnotation",
190+
"applyset.kubernetes.io/additional-namespaces": "namespace1,namespace2",
191+
"kube-scheduler-simulator.sigs.k8s.io/selected-node": "testnode",
192+
}
193+
expectedAnnotations := map[string]string{
194+
"renku.io/test": "newAnnotation",
195+
"applyset.kubernetes.io/additional-namespaces": "namespace1,namespace2",
196+
"kube-scheduler-simulator.sigs.k8s.io/selected-node": "testnode",
197+
}
198+
199+
newSession0 := amaltheasession.DeepCopy()
200+
newSession0.Spec.Template.Metadata.Labels = newLabels
201+
newSession0.Spec.Template.Metadata.Annotations = newAnnotations
202+
newSession0.Spec.ReconcileStrategy = amaltheadevv1alpha1.Always
203+
err = k8sClient.Patch(ctx, newSession0, client.MergeFrom(amaltheasession))
204+
Expect(err).NotTo(HaveOccurred())
205+
_, err = controllerReconciler.Reconcile(ctx, reconcile.Request{
206+
NamespacedName: typeNamespacedName,
207+
})
208+
Expect(err).NotTo(HaveOccurred())
209+
childrenMetadataCheck(ctx, k8sClient, typeNamespacedName, expectedLabels, expectedAnnotations, false)
210+
211+
// Altering well-known annotations should fail
212+
newAnnotations = map[string]string{
213+
"applyset.kubernetes.io/additional-namespaces": "namespace3,namespace4",
214+
"kube-scheduler-simulator.sigs.k8s.io/selected-node": "other-node",
215+
}
216+
217+
newSession0.Spec.Template.Metadata.Annotations = newAnnotations
218+
err = k8sClient.Patch(ctx, newSession0, client.MergeFrom(amaltheasession))
219+
Expect(err).NotTo(HaveOccurred())
220+
_, err = controllerReconciler.Reconcile(ctx, reconcile.Request{
221+
NamespacedName: typeNamespacedName,
222+
})
223+
Expect(err).NotTo(HaveOccurred())
224+
childrenMetadataCheck(ctx, k8sClient, typeNamespacedName, expectedLabels, expectedAnnotations, false)
225+
})
164226
})
165227

166228
Context("When reconciling a resource without ingress", func() {

internal/controller/children.go

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,30 @@ func isFailedOrHibernated(as *amaltheadevv1alpha1.AmaltheaSession) bool {
7070
as.Status.State == amaltheadevv1alpha1.Hibernated
7171
}
7272

73+
// Returns a map ensuring that the labels/annotations desired do not
74+
// overwrite well-known values.
75+
// Reference: https://kubernetes.io/docs/reference/labels-annotations-taints/
76+
func cleanWellKnown(current map[string]string, desired map[string]string) map[string]string {
77+
preserved := map[string]string{}
78+
for key, value := range current {
79+
domain, _, _ := strings.Cut(key, "/")
80+
if domain == "kubernetes.io" || domain == "k8s.io" || strings.HasSuffix(domain, ".kubernetes.io") ||
81+
strings.HasSuffix(domain, ".k8s.io") {
82+
preserved[key] = value
83+
}
84+
}
85+
86+
clean := map[string]string{}
87+
for key, value := range desired {
88+
clean[key] = value
89+
}
90+
91+
for key, value := range preserved {
92+
clean[key] = value
93+
}
94+
return clean
95+
}
96+
7397
func (c ChildResource[T]) Reconcile(ctx context.Context, clnt client.Client, cr *amaltheadevv1alpha1.AmaltheaSession) ChildResourceUpdate[T] { //nolint:gocyclo
7498
logger := log.FromContext(ctx)
7599
if c.Current == nil {
@@ -102,8 +126,8 @@ func (c ChildResource[T]) Reconcile(ctx context.Context, clnt client.Client, cr
102126
fallthrough
103127
case amaltheadevv1alpha1.Always:
104128
current.Spec = desired.Spec
105-
current.Labels = desired.Labels
106-
current.Annotations = desired.Annotations
129+
current.Labels = cleanWellKnown(current.Labels, desired.Labels)
130+
current.Annotations = cleanWellKnown(current.Annotations, desired.Annotations)
107131
default:
108132
return fmt.Errorf("attempting to reconcile ingress with unknown strategy %s", strategy)
109133
}
@@ -160,8 +184,8 @@ func (c ChildResource[T]) Reconcile(ctx context.Context, clnt client.Client, cr
160184
current.Spec.Template.Spec.InitContainers = desired.Spec.Template.Spec.InitContainers
161185
current.Spec.Template.Spec.Volumes = desired.Spec.Template.Spec.Volumes
162186
current.Spec.Selector = desired.Spec.Selector
163-
current.Labels = desired.Labels
164-
current.Annotations = desired.Annotations
187+
current.Labels = cleanWellKnown(current.Labels, desired.Labels)
188+
current.Annotations = cleanWellKnown(current.Annotations, desired.Annotations)
165189
current.Spec.Template.Labels = desired.Spec.Template.Labels
166190
current.Spec.Template.Annotations = desired.Spec.Template.Annotations
167191
default:
@@ -197,25 +221,8 @@ func (c ChildResource[T]) Reconcile(ctx context.Context, clnt client.Client, cr
197221
// NOTE: If the desired storage class is nil then the current spec contains the name for the default storage class
198222
current.Spec.StorageClassName = desired.Spec.StorageClassName
199223
}
200-
// Do not touch reserved labels and annotations
201-
// Reference: https://kubernetes.io/docs/reference/labels-annotations-taints/
202-
// TODO: handle labels
203-
current.Labels = desired.Labels
204-
preservedAnnotations := map[string]string{}
205-
for key := range current.Annotations {
206-
domain, _, _ := strings.Cut(key, "/")
207-
if domain == "kubernetes.io" || domain == "k8s.io" || strings.HasSuffix(domain, ".kubernetes.io") ||
208-
strings.HasSuffix(domain, ".k8s.io") {
209-
preservedAnnotations[key] = current.Annotations[key]
210-
}
211-
}
212-
current.Annotations = desired.Annotations
213-
if current.Annotations == nil {
214-
current.Annotations = map[string]string{}
215-
}
216-
for key := range preservedAnnotations {
217-
current.Annotations[key] = preservedAnnotations[key]
218-
}
224+
current.Labels = cleanWellKnown(current.Labels, desired.Labels)
225+
current.Annotations = cleanWellKnown(current.Annotations, desired.Annotations)
219226
default:
220227
return fmt.Errorf("attempting to reconcile PVC with unknown strategy %s", strategy)
221228
}
@@ -246,8 +253,8 @@ func (c ChildResource[T]) Reconcile(ctx context.Context, clnt client.Client, cr
246253
case amaltheadevv1alpha1.Always:
247254
current.Spec.Ports = desired.Spec.Ports
248255
current.Spec.Selector = desired.Spec.Selector
249-
current.Labels = desired.Labels
250-
current.Annotations = desired.Annotations
256+
current.Labels = cleanWellKnown(current.Labels, desired.Labels)
257+
current.Annotations = cleanWellKnown(current.Annotations, desired.Annotations)
251258
default:
252259
return fmt.Errorf("attempting to reconcile service with unknown strategy %s", strategy)
253260
}
@@ -293,8 +300,8 @@ func (c ChildResource[T]) Reconcile(ctx context.Context, clnt client.Client, cr
293300
}
294301
current.Data = desired.Data
295302
current.StringData = preservedStringData
296-
current.Labels = desired.Labels
297-
current.Annotations = desired.Annotations
303+
current.Labels = cleanWellKnown(current.Labels, desired.Labels)
304+
current.Annotations = cleanWellKnown(current.Annotations, desired.Annotations)
298305
default:
299306
return fmt.Errorf("attempting to reconcile secret with unknown strategy %s", strategy)
300307
}
@@ -362,8 +369,8 @@ func (c ChildResource[T]) Reconcile(ctx context.Context, clnt client.Client, cr
362369
current.Spec.Template.Spec.Containers = desired.Spec.Template.Spec.Containers
363370
current.Spec.Template.Spec.InitContainers = desired.Spec.Template.Spec.InitContainers
364371
current.Spec.Template.Spec.Volumes = desired.Spec.Template.Spec.Volumes
365-
current.Labels = desired.Labels
366-
current.Annotations = desired.Annotations
372+
current.Labels = cleanWellKnown(current.Labels, desired.Labels)
373+
current.Annotations = cleanWellKnown(current.Annotations, desired.Annotations)
367374
current.Spec.Template.Annotations = desired.Spec.Template.Annotations
368375
default:
369376
return fmt.Errorf("attempting to reconcile batchjob with unknown strategy %s", strategy)

0 commit comments

Comments
 (0)