This is an automated email from the ASF dual-hosted git repository.

gyfora pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/flink-kubernetes-operator.git


The following commit(s) were added to refs/heads/main by this push:
     new 24b0d998 [FLINK-39509][flink-kubernetes-webhook] Fix mutating webhook 
producing spurious object modifications on no-op patches
24b0d998 is described below

commit 24b0d998278b8ce8a579927ea292b9f4eb1b5a60
Author: Dennis-Mircea Ciupitu <[email protected]>
AuthorDate: Tue Apr 21 16:20:55 2026 +0300

    [FLINK-39509][flink-kubernetes-webhook] Fix mutating webhook producing 
spurious object modifications on no-op patches
---
 .../operator/admission/mutator/FlinkMutator.java   | 28 ++++++++++++++++++----
 1 file changed, 24 insertions(+), 4 deletions(-)

diff --git 
a/flink-kubernetes-webhook/src/main/java/org/apache/flink/kubernetes/operator/admission/mutator/FlinkMutator.java
 
b/flink-kubernetes-webhook/src/main/java/org/apache/flink/kubernetes/operator/admission/mutator/FlinkMutator.java
index 28199614..f9d4f878 100644
--- 
a/flink-kubernetes-webhook/src/main/java/org/apache/flink/kubernetes/operator/admission/mutator/FlinkMutator.java
+++ 
b/flink-kubernetes-webhook/src/main/java/org/apache/flink/kubernetes/operator/admission/mutator/FlinkMutator.java
@@ -66,9 +66,10 @@ public class FlinkMutator implements Mutator<HasMetadata> {
         return resource;
     }
 
-    private FlinkSessionJob mutateSessionJob(HasMetadata resource) {
+    private HasMetadata mutateSessionJob(HasMetadata resource) {
         try {
             var sessionJob = mapper.convertValue(resource, 
FlinkSessionJob.class);
+            var originalSessionJob = mapper.valueToTree(sessionJob);
             var namespace = sessionJob.getMetadata().getNamespace();
             var deploymentName = sessionJob.getSpec().getDeploymentName();
             var key = Cache.namespaceKeyFunc(namespace, deploymentName);
@@ -78,31 +79,50 @@ public class FlinkMutator implements Mutator<HasMetadata> {
             for (FlinkResourceMutator mutator : mutators) {
                 sessionJob = mutator.mutateSessionJob(sessionJob, 
Optional.ofNullable(deployment));
             }
-
+            // Return the original resource if no mutation was applied to avoid
+            // the serialization round-trip producing a different object, 
which causes
+            // kubectl to inconsistently omit the "(no change)" suffix on 
patch responses
+            if (originalSessionJob.equals(mapper.valueToTree(sessionJob))) {
+                return resource;
+            }
             return sessionJob;
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
     }
 
-    private FlinkDeployment mutateDeployment(HasMetadata resource) {
+    private HasMetadata mutateDeployment(HasMetadata resource) {
         try {
             var flinkDeployment = mapper.convertValue(resource, 
FlinkDeployment.class);
+            var originalFlinkDeployment = mapper.valueToTree(flinkDeployment);
             for (FlinkResourceMutator mutator : mutators) {
                 flinkDeployment = mutator.mutateDeployment(flinkDeployment);
             }
+            // Return the original resource if no mutation was applied to avoid
+            // the serialization round-trip producing a different object, 
which causes
+            // kubectl to inconsistently omit the "(no change)" suffix on 
patch responses
+            if 
(originalFlinkDeployment.equals(mapper.valueToTree(flinkDeployment))) {
+                return resource;
+            }
             return flinkDeployment;
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
     }
 
-    private FlinkStateSnapshot mutateStateSnapshot(HasMetadata resource) {
+    private HasMetadata mutateStateSnapshot(HasMetadata resource) {
         try {
             var snapshot = mapper.convertValue(resource, 
FlinkStateSnapshot.class);
+            var originalSnapshot = mapper.valueToTree(snapshot);
             for (var mutator : mutators) {
                 snapshot = mutator.mutateStateSnapshot(snapshot);
             }
+            // Return the original resource if no mutation was applied to avoid
+            // the serialization round-trip producing a different object, 
which causes
+            // kubectl to inconsistently omit the "(no change)" suffix on 
patch responses
+            if (originalSnapshot.equals(mapper.valueToTree(snapshot))) {
+                return resource;
+            }
             return snapshot;
         } catch (Exception e) {
             throw new RuntimeException(e);

Reply via email to