2
2
3
3
import java .util .List ;
4
4
import java .util .Map ;
5
+ import java .util .Objects ;
5
6
import java .util .Optional ;
6
7
7
8
import io .fabric8 .kubernetes .api .model .Container ;
9
+ import io .fabric8 .kubernetes .api .model .EnvVar ;
8
10
import io .fabric8 .kubernetes .api .model .GenericKubernetesResource ;
9
11
import io .fabric8 .kubernetes .api .model .PodTemplateSpec ;
10
12
import io .fabric8 .kubernetes .api .model .Quantity ;
11
13
import io .fabric8 .kubernetes .api .model .ResourceRequirements ;
12
14
13
15
/**
14
- * Sanitizes the {@link ResourceRequirements} in the containers of a pair of {@link PodTemplateSpec}
15
- * instances.
16
+ * Sanitizes the {@link ResourceRequirements} and the {@link EnvVar} in the containers of a pair of
17
+ * {@link PodTemplateSpec} instances.
16
18
*
17
19
* <p>When the sanitizer finds a mismatch in the structure of the given templates, before it gets to
18
- * the nested resource limits and requests , it returns early without fixing the actual map. This is
19
- * an optimization because the given templates will anyway differ at this point. This means we do
20
- * not have to attempt to sanitize the resources for these use cases, since there will anyway be an
21
- * update of the K8s resource.
20
+ * the nested fields , it returns early without fixing the actual map. This is an optimization
21
+ * because the given templates will anyway differ at this point. This means we do not have to
22
+ * attempt to sanitize the fields for these use cases, since there will anyway be an update of the
23
+ * K8s resource.
22
24
*
23
25
* <p>The algorithm traverses the whole template structure because we need the actual and desired
24
- * {@link Quantity} instances to compare their numerical amount . Using the {@link
26
+ * {@link Quantity} and {@link EnvVar} instances . Using the {@link
25
27
* GenericKubernetesResource#get(Map, Object...)} shortcut would need to create new instances just
26
28
* for the sanitization check.
27
29
*/
28
- class ResourceRequirementsSanitizer {
30
+ class PodTemplateSpecSanitizer {
29
31
30
- static void sanitizeResourceRequirements (
32
+ static void sanitizePodTemplateSpec (
31
33
final Map <String , Object > actualMap ,
32
34
final PodTemplateSpec actualTemplate ,
33
35
final PodTemplateSpec desiredTemplate ) {
@@ -37,31 +39,37 @@ static void sanitizeResourceRequirements(
37
39
if (actualTemplate .getSpec () == null || desiredTemplate .getSpec () == null ) {
38
40
return ;
39
41
}
40
- sanitizeResourceRequirements (
42
+ sanitizePodTemplateSpec (
41
43
actualMap ,
42
44
actualTemplate .getSpec ().getInitContainers (),
43
45
desiredTemplate .getSpec ().getInitContainers (),
44
46
"initContainers" );
45
- sanitizeResourceRequirements (
47
+ sanitizePodTemplateSpec (
46
48
actualMap ,
47
49
actualTemplate .getSpec ().getContainers (),
48
50
desiredTemplate .getSpec ().getContainers (),
49
51
"containers" );
50
52
}
51
53
52
- private static void sanitizeResourceRequirements (
54
+ private static void sanitizePodTemplateSpec (
53
55
final Map <String , Object > actualMap ,
54
56
final List <Container > actualContainers ,
55
57
final List <Container > desiredContainers ,
56
58
final String containerPath ) {
57
59
int containers = desiredContainers .size ();
58
60
if (containers == actualContainers .size ()) {
59
61
for (int containerIndex = 0 ; containerIndex < containers ; containerIndex ++) {
60
- var desiredContainer = desiredContainers .get (containerIndex );
61
- var actualContainer = actualContainers .get (containerIndex );
62
+ final var desiredContainer = desiredContainers .get (containerIndex );
63
+ final var actualContainer = actualContainers .get (containerIndex );
62
64
if (!desiredContainer .getName ().equals (actualContainer .getName ())) {
63
65
return ;
64
66
}
67
+ sanitizeEnvVars (
68
+ actualMap ,
69
+ actualContainer .getEnv (),
70
+ desiredContainer .getEnv (),
71
+ containerPath ,
72
+ containerIndex );
65
73
sanitizeResourceRequirements (
66
74
actualMap ,
67
75
actualContainer .getResources (),
@@ -121,7 +129,7 @@ private static void sanitizeQuantities(
121
129
m ->
122
130
actualResource .forEach (
123
131
(key , actualQuantity ) -> {
124
- var desiredQuantity = desiredResource .get (key );
132
+ final var desiredQuantity = desiredResource .get (key );
125
133
if (desiredQuantity == null ) {
126
134
return ;
127
135
}
@@ -138,4 +146,53 @@ private static void sanitizeQuantities(
138
146
}
139
147
}));
140
148
}
149
+
150
+ @ SuppressWarnings ("unchecked" )
151
+ private static void sanitizeEnvVars (
152
+ final Map <String , Object > actualMap ,
153
+ final List <EnvVar > actualEnvVars ,
154
+ final List <EnvVar > desiredEnvVars ,
155
+ final String containerPath ,
156
+ final int containerIndex ) {
157
+ if (desiredEnvVars .isEmpty () || actualEnvVars .isEmpty ()) {
158
+ return ;
159
+ }
160
+ Optional .ofNullable (
161
+ GenericKubernetesResource .get (
162
+ actualMap , "spec" , "template" , "spec" , containerPath , containerIndex , "env" ))
163
+ .map (List .class ::cast )
164
+ .ifPresent (
165
+ envVars ->
166
+ actualEnvVars .forEach (
167
+ actualEnvVar -> {
168
+ final var actualEnvVarName = actualEnvVar .getName ();
169
+ final var actualEnvVarValue = actualEnvVar .getValue ();
170
+ // check if the actual EnvVar value string is not null or the desired EnvVar
171
+ // already contains the same EnvVar name with a non empty EnvVar value
172
+ final var isDesiredEnvVarEmpty =
173
+ hasEnvVarNoEmptyValue (actualEnvVarName , desiredEnvVars );
174
+ if (actualEnvVarValue != null || isDesiredEnvVarEmpty ) {
175
+ return ;
176
+ }
177
+ envVars .stream ()
178
+ .filter (
179
+ envVar ->
180
+ ((Map <String , String >) envVar )
181
+ .get ("name" )
182
+ .equals (actualEnvVarName ))
183
+ // add the actual EnvVar value with an empty string to prevent a
184
+ // resource update
185
+ .forEach (envVar -> ((Map <String , String >) envVar ).put ("value" , "" ));
186
+ }));
187
+ }
188
+
189
+ private static boolean hasEnvVarNoEmptyValue (
190
+ final String envVarName , final List <EnvVar > envVars ) {
191
+ return envVars .stream ()
192
+ .anyMatch (
193
+ envVar ->
194
+ Objects .equals (envVarName , envVar .getName ())
195
+ && envVar .getValue () != null
196
+ && !envVar .getValue ().isEmpty ());
197
+ }
141
198
}
0 commit comments