apache-airflow-providers-cncf-kubernetes 8.0.1rc1__tar.gz → 8.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/PKG-INFO +9 -8
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/README.rst +4 -4
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/__init__.py +1 -1
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/backcompat/backwards_compat_converters.py +1 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/executors/kubernetes_executor.py +1 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/get_provider_info.py +6 -2
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/hooks/kubernetes.py +149 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/k8s_model.py +1 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/kube_client.py +1 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/kubernetes_helper_functions.py +1 -1
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/operators/custom_object_launcher.py +4 -3
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/operators/job.py +239 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/operators/kubernetes_pod.py +1 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/operators/pod.py +35 -16
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/operators/resource.py +47 -13
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/operators/spark_kubernetes.py +27 -3
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/pod_generator.py +3 -1
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/pod_generator_deprecated.py +1 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/pod_launcher_deprecated.py +1 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/python_kubernetes_script.py +1 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/secret.py +1 -0
- apache_airflow_providers_cncf_kubernetes-8.1.0/airflow/providers/cncf/kubernetes/triggers/job.py +101 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/triggers/kubernetes_pod.py +1 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/triggers/pod.py +11 -3
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/utils/pod_manager.py +2 -1
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/utils/xcom_sidecar.py +1 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/pyproject.toml +5 -4
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/LICENSE +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/backcompat/__init__.py +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/callbacks.py +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/decorators/__init__.py +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/decorators/kubernetes.py +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/executors/__init__.py +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/executors/kubernetes_executor_types.py +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/executors/kubernetes_executor_utils.py +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/executors/local_kubernetes_executor.py +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/hooks/__init__.py +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/kube_config.py +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/kubernetes_executor_templates/__init__.py +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/kubernetes_executor_templates/basic_template.yaml +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/operators/__init__.py +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/pod_template_file_examples/__init__.py +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/pod_template_file_examples/dags_in_image_template.yaml +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/pod_template_file_examples/dags_in_volume_template.yaml +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/pod_template_file_examples/git_sync_template.yaml +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/python_kubernetes_script.jinja2 +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/resource_convert/__init__.py +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/resource_convert/configmap.py +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/resource_convert/env_variable.py +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/resource_convert/secret.py +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/sensors/__init__.py +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/sensors/spark_kubernetes.py +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/template_rendering.py +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/triggers/__init__.py +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/utils/__init__.py +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/utils/delete_from.py +0 -0
- {apache_airflow_providers_cncf_kubernetes-8.0.1rc1 → apache_airflow_providers_cncf_kubernetes-8.1.0}/airflow/providers/cncf/kubernetes/utils/k8s_resource_iterator.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: apache-airflow-providers-cncf-kubernetes
|
|
3
|
-
Version: 8.0
|
|
3
|
+
Version: 8.1.0
|
|
4
4
|
Summary: Provider package apache-airflow-providers-cncf-kubernetes for Apache Airflow
|
|
5
5
|
Keywords: airflow-provider,cncf.kubernetes,airflow,integration
|
|
6
6
|
Author-email: Apache Software Foundation <dev@airflow.apache.org>
|
|
@@ -19,17 +19,18 @@ Classifier: Programming Language :: Python :: 3.8
|
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.9
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.10
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
23
|
Classifier: Topic :: System :: Monitoring
|
|
23
24
|
Requires-Dist: aiofiles>=23.2.0
|
|
24
|
-
Requires-Dist: apache-airflow>=2.6.0
|
|
25
|
+
Requires-Dist: apache-airflow>=2.6.0
|
|
25
26
|
Requires-Dist: asgiref>=3.5.2
|
|
26
27
|
Requires-Dist: cryptography>=2.0.0
|
|
27
28
|
Requires-Dist: google-re2>=1.0
|
|
28
29
|
Requires-Dist: kubernetes>=28.1.0,<=29.0.0
|
|
29
30
|
Requires-Dist: kubernetes_asyncio>=28.1.0,<=29.0.0
|
|
30
31
|
Project-URL: Bug Tracker, https://github.com/apache/airflow/issues
|
|
31
|
-
Project-URL: Changelog, https://airflow.apache.org/docs/apache-airflow-providers-cncf-kubernetes/8.0
|
|
32
|
-
Project-URL: Documentation, https://airflow.apache.org/docs/apache-airflow-providers-cncf-kubernetes/8.0
|
|
32
|
+
Project-URL: Changelog, https://airflow.apache.org/docs/apache-airflow-providers-cncf-kubernetes/8.1.0/changelog.html
|
|
33
|
+
Project-URL: Documentation, https://airflow.apache.org/docs/apache-airflow-providers-cncf-kubernetes/8.1.0
|
|
33
34
|
Project-URL: Slack Chat, https://s.apache.org/airflow-slack
|
|
34
35
|
Project-URL: Source Code, https://github.com/apache/airflow
|
|
35
36
|
Project-URL: Twitter, https://twitter.com/ApacheAirflow
|
|
@@ -79,7 +80,7 @@ Project-URL: YouTube, https://www.youtube.com/channel/UCSXwxpWZQ7XZ1WL3wqevChA/
|
|
|
79
80
|
|
|
80
81
|
Package ``apache-airflow-providers-cncf-kubernetes``
|
|
81
82
|
|
|
82
|
-
Release: ``8.
|
|
83
|
+
Release: ``8.1.0``
|
|
83
84
|
|
|
84
85
|
|
|
85
86
|
`Kubernetes <https://kubernetes.io/>`__
|
|
@@ -92,7 +93,7 @@ This is a provider package for ``cncf.kubernetes`` provider. All classes for thi
|
|
|
92
93
|
are in ``airflow.providers.cncf.kubernetes`` python package.
|
|
93
94
|
|
|
94
95
|
You can find package information and changelog for the provider
|
|
95
|
-
in the `documentation <https://airflow.apache.org/docs/apache-airflow-providers-cncf-kubernetes/8.0
|
|
96
|
+
in the `documentation <https://airflow.apache.org/docs/apache-airflow-providers-cncf-kubernetes/8.1.0/>`_.
|
|
96
97
|
|
|
97
98
|
Installation
|
|
98
99
|
------------
|
|
@@ -101,7 +102,7 @@ You can install this package on top of an existing Airflow 2 installation (see `
|
|
|
101
102
|
for the minimum Airflow version supported) via
|
|
102
103
|
``pip install apache-airflow-providers-cncf-kubernetes``
|
|
103
104
|
|
|
104
|
-
The package supports the following python versions: 3.8,3.9,3.10,3.11
|
|
105
|
+
The package supports the following python versions: 3.8,3.9,3.10,3.11,3.12
|
|
105
106
|
|
|
106
107
|
Requirements
|
|
107
108
|
------------
|
|
@@ -119,4 +120,4 @@ PIP package Version required
|
|
|
119
120
|
====================== =====================
|
|
120
121
|
|
|
121
122
|
The changelog for the provider package can be found in the
|
|
122
|
-
`changelog <https://airflow.apache.org/docs/apache-airflow-providers-cncf-kubernetes/8.0
|
|
123
|
+
`changelog <https://airflow.apache.org/docs/apache-airflow-providers-cncf-kubernetes/8.1.0/changelog.html>`_.
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
|
|
43
43
|
Package ``apache-airflow-providers-cncf-kubernetes``
|
|
44
44
|
|
|
45
|
-
Release: ``8.
|
|
45
|
+
Release: ``8.1.0``
|
|
46
46
|
|
|
47
47
|
|
|
48
48
|
`Kubernetes <https://kubernetes.io/>`__
|
|
@@ -55,7 +55,7 @@ This is a provider package for ``cncf.kubernetes`` provider. All classes for thi
|
|
|
55
55
|
are in ``airflow.providers.cncf.kubernetes`` python package.
|
|
56
56
|
|
|
57
57
|
You can find package information and changelog for the provider
|
|
58
|
-
in the `documentation <https://airflow.apache.org/docs/apache-airflow-providers-cncf-kubernetes/8.0
|
|
58
|
+
in the `documentation <https://airflow.apache.org/docs/apache-airflow-providers-cncf-kubernetes/8.1.0/>`_.
|
|
59
59
|
|
|
60
60
|
Installation
|
|
61
61
|
------------
|
|
@@ -64,7 +64,7 @@ You can install this package on top of an existing Airflow 2 installation (see `
|
|
|
64
64
|
for the minimum Airflow version supported) via
|
|
65
65
|
``pip install apache-airflow-providers-cncf-kubernetes``
|
|
66
66
|
|
|
67
|
-
The package supports the following python versions: 3.8,3.9,3.10,3.11
|
|
67
|
+
The package supports the following python versions: 3.8,3.9,3.10,3.11,3.12
|
|
68
68
|
|
|
69
69
|
Requirements
|
|
70
70
|
------------
|
|
@@ -82,4 +82,4 @@ PIP package Version required
|
|
|
82
82
|
====================== =====================
|
|
83
83
|
|
|
84
84
|
The changelog for the provider package can be found in the
|
|
85
|
-
`changelog <https://airflow.apache.org/docs/apache-airflow-providers-cncf-kubernetes/8.0
|
|
85
|
+
`changelog <https://airflow.apache.org/docs/apache-airflow-providers-cncf-kubernetes/8.1.0/changelog.html>`_.
|
|
@@ -28,8 +28,9 @@ def get_provider_info():
|
|
|
28
28
|
"name": "Kubernetes",
|
|
29
29
|
"description": "`Kubernetes <https://kubernetes.io/>`__\n",
|
|
30
30
|
"state": "ready",
|
|
31
|
-
"source-date-epoch":
|
|
31
|
+
"source-date-epoch": 1712665231,
|
|
32
32
|
"versions": [
|
|
33
|
+
"8.1.0",
|
|
33
34
|
"8.0.1",
|
|
34
35
|
"8.0.0",
|
|
35
36
|
"7.14.0",
|
|
@@ -135,7 +136,10 @@ def get_provider_info():
|
|
|
135
136
|
"triggers": [
|
|
136
137
|
{
|
|
137
138
|
"integration-name": "Kubernetes",
|
|
138
|
-
"python-modules": [
|
|
139
|
+
"python-modules": [
|
|
140
|
+
"airflow.providers.cncf.kubernetes.triggers.pod",
|
|
141
|
+
"airflow.providers.cncf.kubernetes.triggers.job",
|
|
142
|
+
],
|
|
139
143
|
}
|
|
140
144
|
],
|
|
141
145
|
"connection-types": [
|
|
@@ -16,10 +16,12 @@
|
|
|
16
16
|
# under the License.
|
|
17
17
|
from __future__ import annotations
|
|
18
18
|
|
|
19
|
+
import asyncio
|
|
19
20
|
import contextlib
|
|
20
21
|
import json
|
|
21
22
|
import tempfile
|
|
22
23
|
from functools import cached_property
|
|
24
|
+
from time import sleep
|
|
23
25
|
from typing import TYPE_CHECKING, Any, Generator
|
|
24
26
|
|
|
25
27
|
import aiofiles
|
|
@@ -37,10 +39,18 @@ from airflow.providers.cncf.kubernetes.utils.pod_manager import PodOperatorHookP
|
|
|
37
39
|
from airflow.utils import yaml
|
|
38
40
|
|
|
39
41
|
if TYPE_CHECKING:
|
|
42
|
+
from kubernetes.client import V1JobList
|
|
40
43
|
from kubernetes.client.models import V1Deployment, V1Job, V1Pod
|
|
41
44
|
|
|
42
45
|
LOADING_KUBE_CONFIG_FILE_RESOURCE = "Loading Kubernetes configuration file kube_config from {}..."
|
|
43
46
|
|
|
47
|
+
JOB_FINAL_STATUS_CONDITION_TYPES = {
|
|
48
|
+
"Complete",
|
|
49
|
+
"Failed",
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
JOB_STATUS_CONDITION_TYPES = JOB_FINAL_STATUS_CONDITION_TYPES | {"Suspended"}
|
|
53
|
+
|
|
44
54
|
|
|
45
55
|
def _load_body_to_dict(body: str) -> dict:
|
|
46
56
|
try:
|
|
@@ -502,6 +512,114 @@ class KubernetesHook(BaseHook, PodOperatorHookProtocol):
|
|
|
502
512
|
raise e
|
|
503
513
|
return resp
|
|
504
514
|
|
|
515
|
+
def get_job(self, job_name: str, namespace: str) -> V1Job:
|
|
516
|
+
"""Get Job of specified name and namespace.
|
|
517
|
+
|
|
518
|
+
:param job_name: Name of Job to fetch.
|
|
519
|
+
:param namespace: Namespace of the Job.
|
|
520
|
+
:return: Job object
|
|
521
|
+
"""
|
|
522
|
+
return self.batch_v1_client.read_namespaced_job(name=job_name, namespace=namespace, pretty=True)
|
|
523
|
+
|
|
524
|
+
def get_job_status(self, job_name: str, namespace: str) -> V1Job:
|
|
525
|
+
"""Get job with status of specified name and namespace.
|
|
526
|
+
|
|
527
|
+
:param job_name: Name of Job to fetch.
|
|
528
|
+
:param namespace: Namespace of the Job.
|
|
529
|
+
:return: Job object
|
|
530
|
+
"""
|
|
531
|
+
return self.batch_v1_client.read_namespaced_job_status(
|
|
532
|
+
name=job_name, namespace=namespace, pretty=True
|
|
533
|
+
)
|
|
534
|
+
|
|
535
|
+
def wait_until_job_complete(self, job_name: str, namespace: str, job_poll_interval: float = 10) -> V1Job:
|
|
536
|
+
"""Block job of specified name and namespace until it is complete or failed.
|
|
537
|
+
|
|
538
|
+
:param job_name: Name of Job to fetch.
|
|
539
|
+
:param namespace: Namespace of the Job.
|
|
540
|
+
:param job_poll_interval: Interval in seconds between polling the job status
|
|
541
|
+
:return: Job object
|
|
542
|
+
"""
|
|
543
|
+
while True:
|
|
544
|
+
self.log.info("Requesting status for the job '%s' ", job_name)
|
|
545
|
+
job: V1Job = self.get_job_status(job_name=job_name, namespace=namespace)
|
|
546
|
+
if self.is_job_complete(job=job):
|
|
547
|
+
return job
|
|
548
|
+
self.log.info("The job '%s' is incomplete. Sleeping for %i sec.", job_name, job_poll_interval)
|
|
549
|
+
sleep(job_poll_interval)
|
|
550
|
+
|
|
551
|
+
def list_jobs_all_namespaces(self) -> V1JobList:
|
|
552
|
+
"""Get list of Jobs from all namespaces.
|
|
553
|
+
|
|
554
|
+
:return: V1JobList object
|
|
555
|
+
"""
|
|
556
|
+
return self.batch_v1_client.list_job_for_all_namespaces(pretty=True)
|
|
557
|
+
|
|
558
|
+
def list_jobs_from_namespace(self, namespace: str) -> V1JobList:
|
|
559
|
+
"""Get list of Jobs from dedicated namespace.
|
|
560
|
+
|
|
561
|
+
:param namespace: Namespace of the Job.
|
|
562
|
+
:return: V1JobList object
|
|
563
|
+
"""
|
|
564
|
+
return self.batch_v1_client.list_namespaced_job(namespace=namespace, pretty=True)
|
|
565
|
+
|
|
566
|
+
def is_job_complete(self, job: V1Job) -> bool:
|
|
567
|
+
"""Check whether the given job is complete (with success or fail).
|
|
568
|
+
|
|
569
|
+
:return: Boolean indicating that the given job is complete.
|
|
570
|
+
"""
|
|
571
|
+
if status := job.status:
|
|
572
|
+
if conditions := status.conditions:
|
|
573
|
+
if final_condition_types := list(
|
|
574
|
+
c for c in conditions if c.type in JOB_FINAL_STATUS_CONDITION_TYPES and c.status
|
|
575
|
+
):
|
|
576
|
+
s = "s" if len(final_condition_types) > 1 else ""
|
|
577
|
+
self.log.info(
|
|
578
|
+
"The job '%s' state%s: %s",
|
|
579
|
+
job.metadata.name,
|
|
580
|
+
s,
|
|
581
|
+
", ".join(f"{c.type} at {c.last_transition_time}" for c in final_condition_types),
|
|
582
|
+
)
|
|
583
|
+
return True
|
|
584
|
+
return False
|
|
585
|
+
|
|
586
|
+
@staticmethod
|
|
587
|
+
def is_job_failed(job: V1Job) -> str | bool:
|
|
588
|
+
"""Check whether the given job is failed.
|
|
589
|
+
|
|
590
|
+
:return: Error message if the job is failed, and False otherwise.
|
|
591
|
+
"""
|
|
592
|
+
if status := job.status:
|
|
593
|
+
conditions = status.conditions or []
|
|
594
|
+
if fail_condition := next((c for c in conditions if c.type == "Failed" and c.status), None):
|
|
595
|
+
return fail_condition.reason
|
|
596
|
+
return False
|
|
597
|
+
|
|
598
|
+
@staticmethod
|
|
599
|
+
def is_job_successful(job: V1Job) -> str | bool:
|
|
600
|
+
"""Check whether the given job is completed successfully..
|
|
601
|
+
|
|
602
|
+
:return: Error message if the job is failed, and False otherwise.
|
|
603
|
+
"""
|
|
604
|
+
if status := job.status:
|
|
605
|
+
conditions = status.conditions or []
|
|
606
|
+
return bool(next((c for c in conditions if c.type == "Complete" and c.status), None))
|
|
607
|
+
return False
|
|
608
|
+
|
|
609
|
+
def patch_namespaced_job(self, job_name: str, namespace: str, body: object) -> V1Job:
|
|
610
|
+
"""
|
|
611
|
+
Update the specified Job.
|
|
612
|
+
|
|
613
|
+
:param job_name: name of the Job
|
|
614
|
+
:param namespace: the namespace to run within kubernetes
|
|
615
|
+
:param body: json object with parameters for update
|
|
616
|
+
"""
|
|
617
|
+
return self.batch_v1_client.patch_namespaced_job(
|
|
618
|
+
name=job_name,
|
|
619
|
+
namespace=namespace,
|
|
620
|
+
body=body,
|
|
621
|
+
)
|
|
622
|
+
|
|
505
623
|
|
|
506
624
|
def _get_bool(val) -> bool | None:
|
|
507
625
|
"""Convert val to bool if can be done with certainty; if we cannot infer intention we return None."""
|
|
@@ -667,3 +785,34 @@ class AsyncKubernetesHook(KubernetesHook):
|
|
|
667
785
|
except HTTPError:
|
|
668
786
|
self.log.exception("There was an error reading the kubernetes API.")
|
|
669
787
|
raise
|
|
788
|
+
|
|
789
|
+
async def get_job_status(self, name: str, namespace: str) -> V1Job:
|
|
790
|
+
"""
|
|
791
|
+
Get job's status object.
|
|
792
|
+
|
|
793
|
+
:param name: Name of the pod.
|
|
794
|
+
:param namespace: Name of the pod's namespace.
|
|
795
|
+
"""
|
|
796
|
+
async with self.get_conn() as connection:
|
|
797
|
+
v1_api = async_client.BatchV1Api(connection)
|
|
798
|
+
job: V1Job = await v1_api.read_namespaced_job_status(
|
|
799
|
+
name=name,
|
|
800
|
+
namespace=namespace,
|
|
801
|
+
)
|
|
802
|
+
return job
|
|
803
|
+
|
|
804
|
+
async def wait_until_job_complete(self, name: str, namespace: str, poll_interval: float = 10) -> V1Job:
|
|
805
|
+
"""Block job of specified name and namespace until it is complete or failed.
|
|
806
|
+
|
|
807
|
+
:param name: Name of Job to fetch.
|
|
808
|
+
:param namespace: Namespace of the Job.
|
|
809
|
+
:param poll_interval: Interval in seconds between polling the job status
|
|
810
|
+
:return: Job object
|
|
811
|
+
"""
|
|
812
|
+
while True:
|
|
813
|
+
self.log.info("Requesting status for the job '%s' ", name)
|
|
814
|
+
job: V1Job = await self.get_job_status(name=name, namespace=namespace)
|
|
815
|
+
if self.is_job_complete(job=job):
|
|
816
|
+
return job
|
|
817
|
+
self.log.info("The job '%s' is incomplete. Sleeping for %i sec.", name, poll_interval)
|
|
818
|
+
await asyncio.sleep(poll_interval)
|
|
@@ -104,7 +104,7 @@ def create_unique_id(
|
|
|
104
104
|
name += task_id
|
|
105
105
|
base_name = slugify(name, lowercase=True)[:max_length].strip(".-")
|
|
106
106
|
if unique:
|
|
107
|
-
return
|
|
107
|
+
return add_unique_suffix(name=base_name, rand_len=8, max_len=max_length)
|
|
108
108
|
else:
|
|
109
109
|
return base_name
|
|
110
110
|
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
# specific language governing permissions and limitations
|
|
16
16
|
# under the License.
|
|
17
17
|
"""Launches Custom object."""
|
|
18
|
+
|
|
18
19
|
from __future__ import annotations
|
|
19
20
|
|
|
20
21
|
import time
|
|
@@ -59,9 +60,9 @@ class SparkJobSpec:
|
|
|
59
60
|
if self.spec.get("dynamicAllocation", {}).get("enabled"):
|
|
60
61
|
if not all(
|
|
61
62
|
[
|
|
62
|
-
self.spec["dynamicAllocation"]
|
|
63
|
-
self.spec["dynamicAllocation"]
|
|
64
|
-
self.spec["dynamicAllocation"]
|
|
63
|
+
self.spec["dynamicAllocation"].get("initialExecutors"),
|
|
64
|
+
self.spec["dynamicAllocation"].get("minExecutors"),
|
|
65
|
+
self.spec["dynamicAllocation"].get("maxExecutors"),
|
|
65
66
|
]
|
|
66
67
|
):
|
|
67
68
|
raise AirflowException("Make sure initial/min/max value for dynamic allocation is passed")
|