10
10
import io .fabric8 .kubernetes .api .model .ManagedFieldsEntry ;
11
11
import io .javaoperatorsdk .operator .api .reconciler .Context ;
12
12
13
+ import com .fasterxml .jackson .core .JsonProcessingException ;
13
14
import com .fasterxml .jackson .core .type .TypeReference ;
14
15
import com .fasterxml .jackson .databind .ObjectMapper ;
15
16
16
17
public class SSABasedGenericKubernetesResourceMatcher <R extends HasMetadata > {
17
18
19
+ @ SuppressWarnings ("rawtypes" )
20
+ private static final SSABasedGenericKubernetesResourceMatcher INSTANCE =
21
+ new SSABasedGenericKubernetesResourceMatcher <>();
22
+
23
+ @ SuppressWarnings ("unchecked" )
24
+ public static <L extends HasMetadata > SSABasedGenericKubernetesResourceMatcher <L > getInstance () {
25
+ return INSTANCE ;
26
+ }
27
+
28
+ private static final TypeReference <HashMap <String , Object >> typeRef = new TypeReference <>() {};
29
+
18
30
private static final String F_PREFIX = "f:" ;
19
31
private static final String K_PREFIX = "k:" ;
20
-
21
- public static final String METADATA_LABELS = "/metadata/labels" ;
22
- public static final String METADATA_ANNOTATIONS = "/metadata/annotations" ;
32
+ public static final String METADATA_KEY = "metadata" ;
23
33
24
34
private static final Logger log =
25
35
LoggerFactory .getLogger (SSABasedGenericKubernetesResourceMatcher .class );
26
36
37
+ // todo list orders should be irrelevant, change lists to sets?
38
+ // todo owner reference removal?
27
39
public boolean matches (R actual , R desired , Context <?> context ) {
28
40
29
41
var optionalManagedFieldsEntry =
@@ -33,20 +45,35 @@ public boolean matches(R actual, R desired, Context<?> context) {
33
45
if (optionalManagedFieldsEntry .isEmpty ()) {
34
46
return false ;
35
47
}
48
+
36
49
var managedFieldsEntry = optionalManagedFieldsEntry .orElseThrow ();
37
50
38
51
var objectMapper =
39
52
context .getControllerConfiguration ().getConfigurationService ().getObjectMapper ();
40
53
41
- TypeReference <HashMap <String , Object >> typeRef = new TypeReference <>() {};
42
54
var actualMap = objectMapper .convertValue (actual , typeRef );
43
55
var desiredMap = objectMapper .convertValue (desired , typeRef );
44
56
45
57
var prunedActual = new HashMap <String , Object >();
46
58
pruneActualAccordingManagedFields (prunedActual , actualMap ,
47
59
managedFieldsEntry .getFieldsV1 ().getAdditionalProperties (), objectMapper );
60
+ removeIrrelevantValues (desiredMap );
61
+
62
+ log .trace ("Pruned actual: \n {} \n desired: \n {} " , prunedActual , desiredMap );
63
+
64
+ return prunedActual .equals (desiredMap );
65
+ }
66
+
67
+ private void removeIrrelevantValues (HashMap <String , Object > desiredMap ) {
68
+ var metadata = (Map <String , Object >) desiredMap .get (METADATA_KEY );
69
+ metadata .remove ("name" );
70
+ metadata .remove ("namespace" );
71
+ if (metadata .isEmpty ()) {
72
+ desiredMap .remove (METADATA_KEY );
73
+ }
74
+ desiredMap .remove ("kind" );
75
+ desiredMap .remove ("apiVersion" );
48
76
49
- return actualMap .equals (desiredMap );
50
77
}
51
78
52
79
private void pruneActualAccordingManagedFields (Map <String , Object > result ,
@@ -71,9 +98,6 @@ private void pruneActualAccordingManagedFields(Map<String, Object> result,
71
98
pruneActualAccordingManagedFields (emptyResMapValue , actualListEntry ,
72
99
(Map <String , Object >) listEntry .getValue (), objectMapper );
73
100
}
74
-
75
- // todo handle lists
76
- return ;
77
101
} else {
78
102
var emptyMapValue = new HashMap <String , Object >();
79
103
result .put (targetKey , emptyMapValue );
@@ -87,16 +111,36 @@ private void pruneActualAccordingManagedFields(Map<String, Object> result,
87
111
} else {
88
112
result .put (targetKey , actualMap .get (targetKey ));
89
113
}
114
+ } else {
115
+ if (!"." .equals (key )) {
116
+ throw new IllegalStateException ("Key: " + key + " has no prefix: " + F_PREFIX );
117
+ }
90
118
}
91
119
}
92
120
93
121
}
94
122
95
- private Map <String , Object > selectListEntryBasedOnKey (String key , List <Map <String , Object >> value ,
123
+ private Map <String , Object > selectListEntryBasedOnKey (String key ,
124
+ List <Map <String , Object >> values ,
96
125
ObjectMapper objectMapper ) {
97
- // objectMapper.
126
+ try {
127
+ Map <String , Object > ids = objectMapper .readValue (key , typeRef );
128
+ var possibleTargets =
129
+ values .stream ().filter (v -> v .entrySet ().containsAll (ids .entrySet ()))
130
+ .collect (Collectors .toList ());
131
+ if (possibleTargets .isEmpty ()) {
132
+ throw new IllegalStateException (
133
+ "Cannot find list element for key:" + key + ", in map: " + values );
134
+ }
135
+ if (possibleTargets .size () > 1 ) {
136
+ throw new IllegalStateException (
137
+ "More targets found in list element for key:" + key + ", in map: " + values );
138
+ }
98
139
99
- return null ;
140
+ return possibleTargets .get (0 );
141
+ } catch (JsonProcessingException e ) {
142
+ throw new IllegalStateException (e );
143
+ }
100
144
}
101
145
102
146
0 commit comments