@@ -33,6 +33,7 @@ type Container struct {
33
33
index int
34
34
inheritedEnv map [string ]string
35
35
configMaps map [string ]* corev1.ConfigMap
36
+ secrets map [string ]* corev1.Secret
36
37
}
37
38
38
39
func NewContainer (client client.Reader , ctx context.Context , logger logr.Logger , namespace string , pod * corev1.Pod , index int ) (Container , error ) {
@@ -42,22 +43,17 @@ func NewContainer(client client.Reader, ctx context.Context, logger logr.Logger,
42
43
container := & pod .Spec .Containers [index ]
43
44
44
45
configMaps := make (map [string ]* corev1.ConfigMap )
46
+ secrets := make (map [string ]* corev1.Secret )
45
47
inheritedEnv := make (map [string ]string )
46
48
for _ , envsFrom := range container .EnvFrom {
47
49
if envsFrom .ConfigMapRef != nil {
48
- prefix := envsFrom .Prefix
49
- name := envsFrom .ConfigMapRef .Name
50
- if cm , err := getOrLoadResource (client , ctx , namespace , configMaps , name ); err == nil {
51
- for k , v := range cm .Data {
52
- // Safely overwrite the value, last one from EnvFrom wins in Kubernetes, with the direct value
53
- // from the container itself taking precedence
54
- inheritedEnv [prefix + k ] = v
55
- }
56
- } else if envsFrom .ConfigMapRef .Optional == nil || ! * envsFrom .ConfigMapRef .Optional {
57
- return Container {}, fmt .Errorf ("failed to load environment variables: %w" , err )
50
+ if err := loadAllEnvVars (client , ctx , namespace , configMaps , envsFrom .ConfigMapRef .Name , envsFrom .Prefix , envsFrom .ConfigMapRef .Optional , inheritedEnv ); err != nil {
51
+ return Container {}, err
58
52
}
59
53
} else if envsFrom .SecretRef != nil {
60
- logger .V (2 ).Info ("ignoring SecretRef in EnvFrom" , "container" , container .Name , "secret" , envsFrom .SecretRef .Name )
54
+ if err := loadAllEnvVars (client , ctx , namespace , secrets , envsFrom .SecretRef .Name , envsFrom .Prefix , envsFrom .SecretRef .Optional , inheritedEnv ); err != nil {
55
+ return Container {}, err
56
+ }
61
57
}
62
58
}
63
59
@@ -73,39 +69,10 @@ func NewContainer(client client.Reader, ctx context.Context, logger logr.Logger,
73
69
index : index ,
74
70
inheritedEnv : inheritedEnv ,
75
71
configMaps : configMaps ,
72
+ secrets : secrets ,
76
73
}, nil
77
74
}
78
75
79
- func getOrLoadResource [T any , PT interface {
80
- client.Object
81
- * T
82
- }](client client.Reader , ctx context.Context , namespace string , cache map [string ]* T , name string ) (* T , error ) {
83
- var obj T
84
- if cached , ok := cache [name ]; ok {
85
- if cached != nil {
86
- return cached , nil
87
- } else {
88
- return nil , fmt .Errorf ("failed to get %s %s/%s" , reflect .TypeOf (obj ).Name (), namespace , name )
89
- }
90
- }
91
-
92
- if client == nil || ctx == nil {
93
- // Cache error value
94
- cache [name ] = nil
95
- return nil , fmt .Errorf ("client or context is nil, cannot load %s %s/%s" , reflect .TypeOf (obj ).Name (), namespace , name )
96
- }
97
-
98
- err := client .Get (ctx , types.NamespacedName {Namespace : namespace , Name : name }, PT (& obj ))
99
- if err != nil {
100
- // Cache error value
101
- cache [name ] = nil
102
- return nil , fmt .Errorf ("failed to get %s %s/%s: %w" , reflect .TypeOf (obj ).Name (), namespace , name , err )
103
- }
104
-
105
- cache [name ] = & obj
106
- return & obj , nil
107
- }
108
-
109
76
func (c * Container ) validate (pod * corev1.Pod , envsToBeValidated ... string ) error {
110
77
// Try if the value is resolvable
111
78
for _ , envToBeValidated := range envsToBeValidated {
@@ -169,21 +136,9 @@ func (c *Container) getOrMakeEnvVar(pod *corev1.Pod, name string) (corev1.EnvVar
169
136
func (c * Container ) resolveEnvVar (envVar corev1.EnvVar ) (corev1.EnvVar , error ) {
170
137
if envVar .Value == "" && envVar .ValueFrom != nil {
171
138
if envVar .ValueFrom .ConfigMapKeyRef != nil {
172
- configMapName := envVar .ValueFrom .ConfigMapKeyRef .Name
173
- configMapKey := envVar .ValueFrom .ConfigMapKeyRef .Key
174
- if cm , err := getOrLoadResource (c .client , c .ctx , c .namespace , c .configMaps , configMapName ); err == nil {
175
- if value , ok := cm .Data [configMapKey ]; ok {
176
- return corev1.EnvVar {Name : envVar .Name , Value : value }, nil
177
- } else if envVar .ValueFrom .ConfigMapKeyRef .Optional == nil || ! * envVar .ValueFrom .ConfigMapKeyRef .Optional {
178
- return corev1.EnvVar {}, fmt .Errorf ("failed to resolve environment variable %s, key %s not found in ConfigMap %s/%s" , envVar .Name , configMapKey , c .namespace , configMapName )
179
- } else {
180
- return corev1.EnvVar {Name : envVar .Name , Value : "" }, nil
181
- }
182
- } else if envVar .ValueFrom .ConfigMapKeyRef .Optional == nil || ! * envVar .ValueFrom .ConfigMapKeyRef .Optional {
183
- return corev1.EnvVar {}, fmt .Errorf ("failed to resolve environment variable %s: %w" , envVar .Name , err )
184
- } else {
185
- return corev1.EnvVar {Name : envVar .Name , Value : "" }, nil
186
- }
139
+ return loadEnvVar (c .client , c .ctx , c .namespace , c .configMaps , envVar .Name , envVar .ValueFrom .ConfigMapKeyRef .Name , envVar .ValueFrom .ConfigMapKeyRef .Key , envVar .ValueFrom .ConfigMapKeyRef .Optional )
140
+ } else if envVar .ValueFrom .SecretKeyRef != nil {
141
+ return loadEnvVar (c .client , c .ctx , c .namespace , c .secrets , envVar .Name , envVar .ValueFrom .SecretKeyRef .Name , envVar .ValueFrom .SecretKeyRef .Key , envVar .ValueFrom .SecretKeyRef .Optional )
187
142
} else {
188
143
v := reflect .ValueOf (* envVar .ValueFrom )
189
144
for i := 0 ; i < v .NumField (); i ++ {
@@ -197,6 +152,98 @@ func (c *Container) resolveEnvVar(envVar corev1.EnvVar) (corev1.EnvVar, error) {
197
152
return envVar , nil
198
153
}
199
154
155
+ func getOrLoadResource [T any , PT interface {
156
+ client.Object
157
+ * T
158
+ }](client client.Reader , ctx context.Context , namespace string , cache map [string ]* T , name string ) (* T , error ) {
159
+ var obj T
160
+ if cached , ok := cache [name ]; ok {
161
+ if cached != nil {
162
+ return cached , nil
163
+ } else {
164
+ return nil , fmt .Errorf ("failed to get %s %s/%s" , reflect .TypeOf (obj ).Name (), namespace , name )
165
+ }
166
+ }
167
+
168
+ if client == nil || ctx == nil {
169
+ // Cache error value
170
+ cache [name ] = nil
171
+ return nil , fmt .Errorf ("client or context is nil, cannot load %s %s/%s" , reflect .TypeOf (obj ).Name (), namespace , name )
172
+ }
173
+
174
+ err := client .Get (ctx , types.NamespacedName {Namespace : namespace , Name : name }, PT (& obj ))
175
+ if err != nil {
176
+ // Cache error value
177
+ cache [name ] = nil
178
+ return nil , fmt .Errorf ("failed to get %s %s/%s: %w" , reflect .TypeOf (obj ).Name (), namespace , name , err )
179
+ }
180
+
181
+ cache [name ] = & obj
182
+ return & obj , nil
183
+ }
184
+
185
+ func loadAllEnvVars [T any , PT interface {
186
+ client.Object
187
+ * T
188
+ }](client client.Reader , ctx context.Context , namespace string , cache map [string ]* T , name string , prefix string , optional * bool , inheritedEnv map [string ]string ) error {
189
+ if obj , err := getOrLoadResource [T , PT ](client , ctx , namespace , cache , name ); err == nil {
190
+ return fillEnvVars (obj , prefix , inheritedEnv )
191
+ } else if optional == nil || ! * optional {
192
+ return fmt .Errorf ("failed to load environment variables: %w" , err )
193
+ } else {
194
+ return nil
195
+ }
196
+ }
197
+
198
+ func loadEnvVar [T any , PT interface {
199
+ client.Object
200
+ * T
201
+ }](client client.Reader , ctx context.Context , namespace string , cache map [string ]* T , variable string , name string , key string , optional * bool ) (corev1.EnvVar , error ) {
202
+ if resource , err := getOrLoadResource [T , PT ](client , ctx , namespace , cache , name ); err == nil {
203
+ if value , ok := getResourceValue (resource , key ); ok {
204
+ return corev1.EnvVar {Name : variable , Value : value }, nil
205
+ } else if optional == nil || ! * optional {
206
+ return corev1.EnvVar {}, fmt .Errorf ("failed to resolve environment variable %s, key %s not found in %s %s/%s" , variable , key , reflect .TypeOf (* resource ).Name (), namespace , name )
207
+ } else {
208
+ return corev1.EnvVar {Name : variable , Value : "" }, nil
209
+ }
210
+ } else if optional == nil || ! * optional {
211
+ return corev1.EnvVar {}, fmt .Errorf ("failed to resolve environment variable %s: %w" , variable , err )
212
+ } else {
213
+ return corev1.EnvVar {Name : variable , Value : "" }, nil
214
+ }
215
+ }
216
+
217
+ func fillEnvVars (obj any , prefix string , inheritedEnv map [string ]string ) error {
218
+ switch o := obj .(type ) {
219
+ case * corev1.ConfigMap :
220
+ for k , v := range o .Data {
221
+ inheritedEnv [prefix + k ] = v
222
+ }
223
+ return nil
224
+ case * corev1.Secret :
225
+ for k , v := range o .Data {
226
+ inheritedEnv [prefix + k ] = string (v )
227
+ }
228
+ return nil
229
+ default :
230
+ return fmt .Errorf ("unsupported type %T" , obj )
231
+ }
232
+ }
233
+
234
+ func getResourceValue (obj interface {}, key string ) (string , bool ) {
235
+ switch o := obj .(type ) {
236
+ case * corev1.ConfigMap :
237
+ val , ok := o .Data [key ]
238
+ return val , ok
239
+ case * corev1.Secret :
240
+ val , ok := o .Data [key ]
241
+ return string (val ), ok
242
+ default :
243
+ return "" , false
244
+ }
245
+ }
246
+
200
247
func existsEnvVarInEnv (env []corev1.EnvVar , name string ) bool {
201
248
for i := range env {
202
249
if env [i ].Name == name {
0 commit comments