|
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;
|
|
13 | 14 | import java.util.SortedMap;
|
14 | 15 | import java.util.TreeMap;
|
15 | 16 |
|
| 17 | +import org.assertj.core.util.diff.DiffUtils; |
16 | 18 | import org.slf4j.Logger;
|
17 | 19 | import org.slf4j.LoggerFactory;
|
18 | 20 |
|
@@ -104,19 +106,63 @@ public boolean matches(R actual, R desired, Context<?> context) {
|
104 | 106 | removeIrrelevantValues(desiredMap);
|
105 | 107 |
|
106 | 108 | if (LoggingUtils.isNotSensitiveResource(desired)) {
|
107 |
| - logDiff(prunedActual, desiredMap, objectMapper); |
| 109 | + var diff = getDiff(prunedActual, desiredMap, objectMapper); |
| 110 | + if (diff != null) { |
| 111 | + log.debug("Diff between actual and desired state for resource: {} with name: {} in namespace: {} is: \n{}", |
| 112 | + actual.getKind(), actual.getMetadata().getName(), actual.getMetadata().getNamespace(), diff); |
| 113 | + } |
108 | 114 | }
|
109 | 115 |
|
110 | 116 | return prunedActual.equals(desiredMap);
|
111 | 117 | }
|
112 | 118 |
|
113 |
| - private void logDiff(Map<String, Object> prunedActualMap, Map<String, Object> desiredMap, |
114 |
| - KubernetesSerialization serialization) { |
| 119 | + private String getDiff(Map<String, Object> prunedActualMap, Map<String, Object> desiredMap, |
| 120 | + KubernetesSerialization serialization) { |
115 | 121 | 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); |
| 122 | + var actualLines = serialization.asYaml(sortMap(prunedActualMap)).lines().toList(); |
| 123 | + var desiredLines = serialization.asYaml(sortMap(desiredMap)).lines().toList(); |
| 124 | + |
| 125 | + var patch = DiffUtils.diff(actualLines, desiredLines); |
| 126 | + List<String> unifiedDiff = DiffUtils.generateUnifiedDiff("", "", actualLines, patch, 0); |
| 127 | + return unifiedDiff.isEmpty() ? null : String.join("\n", unifiedDiff); |
| 128 | + } |
| 129 | + return null; |
| 130 | + } |
| 131 | + |
| 132 | + @SuppressWarnings("unchecked") |
| 133 | + private Map<String, Object> sortMap(Map<String, Object> map) { |
| 134 | + List<String> sortedKeys = new ArrayList<>(map.keySet()); |
| 135 | + Collections.sort(sortedKeys); |
| 136 | + |
| 137 | + Map<String, Object> sortedMap = new LinkedHashMap<>(); |
| 138 | + for (String key : sortedKeys) { |
| 139 | + Object value = map.get(key); |
| 140 | + if (value instanceof Map) { |
| 141 | + Map<String, Object> nestedMap = (Map<String, Object>) value; |
| 142 | + sortedMap.put(key, sortMap(nestedMap)); |
| 143 | + } else if (value instanceof List) { |
| 144 | + sortedMap.put(key, sortList((List<?>) value)); |
| 145 | + } else { |
| 146 | + sortedMap.put(key, value); |
| 147 | + } |
| 148 | + } |
| 149 | + return sortedMap; |
| 150 | + } |
| 151 | + |
| 152 | + @SuppressWarnings("unchecked") |
| 153 | + private List<?> sortList(List<?> list) { |
| 154 | + List<Object> sortedList = new ArrayList<>(); |
| 155 | + for (Object item : list) { |
| 156 | + if (item instanceof Map) { |
| 157 | + Map<String, Object> mapItem = (Map<String, Object>) item; |
| 158 | + sortedList.add(sortMap(mapItem)); |
| 159 | + } else if (item instanceof List) { |
| 160 | + sortedList.add(sortList((List<?>) item)); |
| 161 | + } else { |
| 162 | + sortedList.add(item); |
| 163 | + } |
119 | 164 | }
|
| 165 | + return sortedList; |
120 | 166 | }
|
121 | 167 |
|
122 | 168 | /**
|
|
0 commit comments