7
7
from airflow .utils .decorators import apply_defaults
8
8
from airflow .operators import BaseOperator
9
9
10
- from .utils import to_kubernetes_valid_name , set_yaml_path_value
10
+ from .utils import to_kubernetes_valid_name , set_yaml_path_value , get_yaml_path_value
11
11
from .job_runner import JobRunner
12
12
from .threaded_kubernetes_resource_watchers import (
13
13
ThreadedKubernetesResourcesWatcher ,
@@ -39,6 +39,7 @@ def __init__(
39
39
image : str = None ,
40
40
namespace : str = None ,
41
41
name : str = None ,
42
+ envs : dict = None ,
42
43
job_yaml = None ,
43
44
job_yaml_filepath = None ,
44
45
delete_policy : str = "IfSucceeded" ,
@@ -65,6 +66,8 @@ def __init__(
65
66
image {str} -- The image to use in the pod. (default: None)
66
67
namespace {str} -- The namespace to execute in. (default: None)
67
68
name {str} -- Override automatic name creation for the job. (default: None)
69
+ envs {dict} -= A collection of environment variables that will be added to all
70
+ containers.
68
71
job_yaml {dict|string} -- The job to execute as a yaml description. (default: None)
69
72
If None, will use a default job yaml command. In this case you must provide an
70
73
image.
@@ -98,9 +101,7 @@ def __init__(
98
101
), "job_yaml is None, and an image was not defined. Unknown image to execute."
99
102
100
103
# use or load
101
- job_yaml = job_yaml or self .read_job_yaml (
102
- job_yaml_filepath or JOB_YAML_DEFAULT_FILE
103
- )
104
+ job_yaml = job_yaml or self .read_job_yaml (job_yaml_filepath or JOB_YAML_DEFAULT_FILE )
104
105
105
106
assert job_yaml is not None and (
106
107
isinstance (job_yaml , (dict , str ))
@@ -112,12 +113,15 @@ def __init__(
112
113
"ifsucceeded" ,
113
114
], "the delete_policy must be one of: Never, Always, IfSucceeded"
114
115
116
+ assert envs is None or isinstance (envs , dict ), "The env collection must be a dict or None"
117
+
115
118
# override/replace properties
116
119
self .name = name
117
120
self .namespace = namespace
118
121
self .command = command
119
122
self .arguments = arguments
120
123
self .image = image
124
+ self .envs = envs
121
125
122
126
# kubernetes config properties.
123
127
self .job_yaml = job_yaml
@@ -211,13 +215,9 @@ def log_job_result(
211
215
self .log .error (f"Job Failed ({ pod_count } pods), last pod/job status:" )
212
216
213
217
# log proper resource error
214
- def log_resource_error (
215
- resource_watcher : ThreadedKubernetesResourcesWatcher ,
216
- ):
218
+ def log_resource_error (resource_watcher : ThreadedKubernetesResourcesWatcher ,):
217
219
log_method = (
218
- self .log .error
219
- if resource_watcher .status == "Failed"
220
- else self .log .info
220
+ self .log .error if resource_watcher .status == "Failed" else self .log .info
221
221
)
222
222
log_method (
223
223
"FINAL STATUS: "
@@ -268,15 +268,19 @@ def set_if_not_none(path_names: list, value):
268
268
269
269
set_if_not_none (["metadata" , "name" ], self .name )
270
270
set_if_not_none (["metadata" , "namespace" ], self .namespace )
271
- set_if_not_none (
272
- ["spec" , "template" , "spec" , "containers" , 0 , "command" ], self .command
273
- )
274
- set_if_not_none (
275
- ["spec" , "template" , "spec" , "containers" , 0 , "args" ], self .arguments
276
- )
277
- set_if_not_none (
278
- ["spec" , "template" , "spec" , "containers" , 0 , "image" ], self .image
279
- )
271
+ set_if_not_none (["spec" , "template" , "spec" , "containers" , 0 , "command" ], self .command )
272
+ set_if_not_none (["spec" , "template" , "spec" , "containers" , 0 , "args" ], self .arguments )
273
+ set_if_not_none (["spec" , "template" , "spec" , "containers" , 0 , "image" ], self .image )
274
+
275
+ containers = get_yaml_path_value (self .job_yaml , ["spec" , "template" , "spec" , "containers" ])
276
+
277
+ if self .envs is not None and len (self .envs .keys ()) > 0 :
278
+ for container in containers :
279
+ if "env" not in container :
280
+ container ["env" ] = []
281
+
282
+ for env_name in self .envs .keys ():
283
+ container ["env" ].append ({"name" : env_name , "value" : self .envs [env_name ]})
280
284
281
285
# call parent.
282
286
return super ().pre_execute (context )
@@ -295,9 +299,7 @@ def execute(self, context):
295
299
296
300
# Executing the job
297
301
(job_watcher , namespace_watcher ) = self .job_runner .execute_job (
298
- self .job_yaml ,
299
- start_timeout = self .startup_timeout_seconds ,
300
- read_logs = self .get_logs ,
302
+ self .job_yaml , start_timeout = self .startup_timeout_seconds , read_logs = self .get_logs ,
301
303
)
302
304
303
305
self .__waiting_for_job_execution = False
@@ -333,8 +335,7 @@ def on_kill(self):
333
335
self .log .info ("Job deleted." )
334
336
except Exception :
335
337
self .log .error (
336
- "Failed to delete an aborted/killed"
337
- + " job! The job may still be executing."
338
+ "Failed to delete an aborted/killed" + " job! The job may still be executing."
338
339
)
339
340
340
341
return super ().on_kill ()
0 commit comments