@@ -40,14 +40,18 @@ func objectSpecSetter(object client.Object) controllerutil.MutateFn {
4040 return nil
4141}
4242
43+ const (
44+ managedKeysAnnotation = "gateway.nginx.org/internal-managed-annotation-keys"
45+ )
46+
4347func deploymentSpecSetter (
4448 deployment * appsv1.Deployment ,
4549 spec appsv1.DeploymentSpec ,
4650 objectMeta metav1.ObjectMeta ,
4751) controllerutil.MutateFn {
4852 return func () error {
4953 deployment .Labels = objectMeta .Labels
50- deployment .Annotations = objectMeta .Annotations
54+ deployment .Annotations = mergeAnnotations ( deployment . Annotations , objectMeta .Annotations , managedKeysAnnotation )
5155 deployment .Spec = spec
5256 return nil
5357 }
@@ -73,7 +77,7 @@ func daemonSetSpecSetter(
7377) controllerutil.MutateFn {
7478 return func () error {
7579 daemonSet .Labels = objectMeta .Labels
76- daemonSet .Annotations = objectMeta .Annotations
80+ daemonSet .Annotations = mergeAnnotations ( daemonSet . Annotations , objectMeta .Annotations , managedKeysAnnotation )
7781 daemonSet .Spec = spec
7882 return nil
7983 }
@@ -85,54 +89,8 @@ func serviceSpecSetter(
8589 objectMeta metav1.ObjectMeta ,
8690) controllerutil.MutateFn {
8791 return func () error {
88- const managedKeysAnnotation = "gateway.nginx.org/internal-managed-annotation-keys"
89-
90- // Track which annotation keys NGF currently manages
91- currentManagedKeys := make (map [string ]bool )
92- for k := range objectMeta .Annotations {
93- currentManagedKeys [k ] = true
94- }
95-
96- // Get previously managed keys from existing service
97- var previousManagedKeys map [string ]bool
98- if prevKeysStr , ok := service .Annotations [managedKeysAnnotation ]; ok {
99- previousManagedKeys = make (map [string ]bool )
100- for _ , k := range strings .Split (prevKeysStr , "," ) {
101- if k != "" {
102- previousManagedKeys [k ] = true
103- }
104- }
105- }
106-
107- // Start with existing annotations (preserves external controller annotations)
108- mergedAnnotations := make (map [string ]string )
109- for k , v := range service .Annotations {
110- // Skip the internal tracking annotation
111- if k == managedKeysAnnotation {
112- continue
113- }
114- // Remove annotations that NGF previously managed but no longer wants
115- if previousManagedKeys != nil && previousManagedKeys [k ] && ! currentManagedKeys [k ] {
116- continue // Remove this annotation
117- }
118- mergedAnnotations [k ] = v
119- }
120-
121- // Apply NGF-managed annotations (take precedence)
122- maps .Copy (mergedAnnotations , objectMeta .Annotations )
123-
124- // Store current managed keys for next reconciliation
125- if len (currentManagedKeys ) > 0 {
126- var managedKeysList []string
127- for k := range currentManagedKeys {
128- managedKeysList = append (managedKeysList , k )
129- }
130- slices .Sort (managedKeysList ) // Sort for deterministic output
131- mergedAnnotations [managedKeysAnnotation ] = strings .Join (managedKeysList , "," )
132- }
133-
13492 service .Labels = objectMeta .Labels
135- service .Annotations = mergedAnnotations
93+ service .Annotations = mergeAnnotations ( service . Annotations , objectMeta . Annotations , managedKeysAnnotation )
13694 service .Spec = spec
13795 return nil
13896 }
@@ -210,3 +168,54 @@ func roleBindingSpecSetter(
210168 return nil
211169 }
212170}
171+
172+ func mergeAnnotations (existing , desired map [string ]string , trackingKey string ) map [string ]string {
173+ desiredKeys := make (map [string ]struct {}, len (desired ))
174+ for key := range desired {
175+ desiredKeys [key ] = struct {}{}
176+ }
177+
178+ previousKeys := make (map [string ]struct {}, len (existing ))
179+ if existing != nil {
180+ if prev , ok := existing [trackingKey ]; ok {
181+ for splitKey := range strings .SplitSeq (prev , "," ) {
182+ if splitKey != "" {
183+ previousKeys [splitKey ] = struct {}{}
184+ }
185+ }
186+ }
187+ }
188+
189+ annotations := make (map [string ]string )
190+
191+ // Start with existing annotations (preserves external controller annotations)
192+ for key , value := range existing {
193+ if key == trackingKey {
194+ continue
195+ }
196+
197+ // if this key was previously managed and is no longer desired, drop it
198+ if _ , wasManaged := previousKeys [key ]; wasManaged {
199+ if _ , stillDesired := desiredKeys [key ]; ! stillDesired {
200+ continue
201+ }
202+ }
203+
204+ annotations [key ] = value
205+ }
206+
207+ // Apply desired annotations (NGF-managed wins)
208+ maps .Copy (annotations , desired )
209+
210+ // Store current managed keys
211+ if len (desiredKeys ) > 0 {
212+ keys := make ([]string , 0 , len (desiredKeys ))
213+ for key := range desiredKeys {
214+ keys = append (keys , key )
215+ }
216+ slices .Sort (keys )
217+ annotations [trackingKey ] = strings .Join (keys , "," )
218+ }
219+
220+ return annotations
221+ }
0 commit comments