|
5 | 5 | import java.util.Arrays;
|
6 | 6 | import java.util.Collections;
|
7 | 7 | import java.util.HashMap;
|
| 8 | +import java.util.LinkedHashMap; |
8 | 9 | import java.util.List;
|
9 | 10 | import java.util.Map;
|
10 | 11 | import java.util.Map.Entry;
|
|
25 | 26 | import io.javaoperatorsdk.operator.api.reconciler.Context;
|
26 | 27 | import io.javaoperatorsdk.operator.processing.LoggingUtils;
|
27 | 28 |
|
| 29 | +import com.github.difflib.DiffUtils; |
| 30 | +import com.github.difflib.UnifiedDiffUtils; |
| 31 | + |
28 | 32 | /**
|
29 | 33 | * Matches the actual state on the server vs the desired state. Based on the managedFields of SSA.
|
30 | 34 | *
|
@@ -103,20 +107,66 @@ public boolean matches(R actual, R desired, Context<?> context) {
|
103 | 107 |
|
104 | 108 | removeIrrelevantValues(desiredMap);
|
105 | 109 |
|
106 |
| - if (LoggingUtils.isNotSensitiveResource(desired)) { |
107 |
| - logDiff(prunedActual, desiredMap, objectMapper); |
| 110 | + var matches = prunedActual.equals(desiredMap); |
| 111 | + |
| 112 | + if (!matches && log.isDebugEnabled() && LoggingUtils.isNotSensitiveResource(desired)) { |
| 113 | + var diff = getDiff(prunedActual, desiredMap, objectMapper); |
| 114 | + log.debug( |
| 115 | + "Diff between actual and desired state for resource: {} with name: {} in namespace: {} is: \n{}", |
| 116 | + actual.getKind(), actual.getMetadata().getName(), actual.getMetadata().getNamespace(), |
| 117 | + diff); |
108 | 118 | }
|
109 | 119 |
|
110 |
| - return prunedActual.equals(desiredMap); |
| 120 | + return matches; |
111 | 121 | }
|
112 | 122 |
|
113 |
| - private void logDiff(Map<String, Object> prunedActualMap, Map<String, Object> desiredMap, |
| 123 | + private String getDiff(Map<String, Object> prunedActualMap, Map<String, Object> desiredMap, |
114 | 124 | KubernetesSerialization serialization) {
|
115 |
| - if (log.isDebugEnabled()) { |
116 |
| - var actualYaml = serialization.asYaml(prunedActualMap); |
117 |
| - var desiredYaml = serialization.asYaml(desiredMap); |
118 |
| - log.debug("Pruned actual yaml: \n {} \n desired yaml: \n {} ", actualYaml, desiredYaml); |
| 125 | + var actualYaml = serialization.asYaml(sortMap(prunedActualMap)); |
| 126 | + var desiredYaml = serialization.asYaml(sortMap(desiredMap)); |
| 127 | + if (log.isTraceEnabled()) { |
| 128 | + log.trace("Pruned actual resource: \n {} \ndesired resource: \n {} ", actualYaml, |
| 129 | + desiredYaml); |
| 130 | + } |
| 131 | + |
| 132 | + var patch = DiffUtils.diff(actualYaml.lines().toList(), desiredYaml.lines().toList()); |
| 133 | + List<String> unifiedDiff = |
| 134 | + UnifiedDiffUtils.generateUnifiedDiff("", "", actualYaml.lines().toList(), patch, 1); |
| 135 | + return String.join("\n", unifiedDiff); |
| 136 | + } |
| 137 | + |
| 138 | + @SuppressWarnings("unchecked") |
| 139 | + Map<String, Object> sortMap(Map<String, Object> map) { |
| 140 | + List<String> sortedKeys = new ArrayList<>(map.keySet()); |
| 141 | + Collections.sort(sortedKeys); |
| 142 | + |
| 143 | + Map<String, Object> sortedMap = new LinkedHashMap<>(); |
| 144 | + for (String key : sortedKeys) { |
| 145 | + Object value = map.get(key); |
| 146 | + if (value instanceof Map) { |
| 147 | + sortedMap.put(key, sortMap((Map<String, Object>) value)); |
| 148 | + } else if (value instanceof List) { |
| 149 | + sortedMap.put(key, sortListItems((List<Object>) value)); |
| 150 | + } else { |
| 151 | + sortedMap.put(key, value); |
| 152 | + } |
| 153 | + } |
| 154 | + return sortedMap; |
| 155 | + } |
| 156 | + |
| 157 | + @SuppressWarnings("unchecked") |
| 158 | + List<Object> sortListItems(List<Object> list) { |
| 159 | + List<Object> sortedList = new ArrayList<>(); |
| 160 | + for (Object item : list) { |
| 161 | + if (item instanceof Map) { |
| 162 | + sortedList.add(sortMap((Map<String, Object>) item)); |
| 163 | + } else if (item instanceof List) { |
| 164 | + sortedList.add(sortListItems((List<Object>) item)); |
| 165 | + } else { |
| 166 | + sortedList.add(item); |
| 167 | + } |
119 | 168 | }
|
| 169 | + return sortedList; |
120 | 170 | }
|
121 | 171 |
|
122 | 172 | /**
|
|
0 commit comments