apache-airflow-providers-google 10.16.0rc1__py3-none-any.whl → 10.17.0rc1__py3-none-any.whl
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.
- airflow/providers/google/__init__.py +1 -1
- airflow/providers/google/ads/hooks/ads.py +5 -4
- airflow/providers/google/ads/operators/ads.py +1 -0
- airflow/providers/google/cloud/example_dags/example_cloud_sql_query.py +1 -0
- airflow/providers/google/cloud/example_dags/example_cloud_task.py +1 -0
- airflow/providers/google/cloud/example_dags/example_facebook_ads_to_gcs.py +1 -0
- airflow/providers/google/cloud/example_dags/example_looker.py +1 -0
- airflow/providers/google/cloud/example_dags/example_presto_to_gcs.py +1 -0
- airflow/providers/google/cloud/example_dags/example_salesforce_to_gcs.py +1 -0
- airflow/providers/google/cloud/fs/gcs.py +1 -2
- airflow/providers/google/cloud/hooks/automl.py +1 -0
- airflow/providers/google/cloud/hooks/bigquery.py +87 -24
- airflow/providers/google/cloud/hooks/bigquery_dts.py +1 -0
- airflow/providers/google/cloud/hooks/bigtable.py +1 -0
- airflow/providers/google/cloud/hooks/cloud_build.py +1 -0
- airflow/providers/google/cloud/hooks/cloud_memorystore.py +1 -0
- airflow/providers/google/cloud/hooks/cloud_sql.py +1 -0
- airflow/providers/google/cloud/hooks/cloud_storage_transfer_service.py +9 -4
- airflow/providers/google/cloud/hooks/compute.py +1 -0
- airflow/providers/google/cloud/hooks/compute_ssh.py +2 -2
- airflow/providers/google/cloud/hooks/dataflow.py +6 -5
- airflow/providers/google/cloud/hooks/datafusion.py +1 -0
- airflow/providers/google/cloud/hooks/datapipeline.py +1 -0
- airflow/providers/google/cloud/hooks/dataplex.py +1 -0
- airflow/providers/google/cloud/hooks/dataprep.py +1 -0
- airflow/providers/google/cloud/hooks/dataproc.py +3 -2
- airflow/providers/google/cloud/hooks/dataproc_metastore.py +1 -0
- airflow/providers/google/cloud/hooks/datastore.py +1 -0
- airflow/providers/google/cloud/hooks/dlp.py +1 -0
- airflow/providers/google/cloud/hooks/functions.py +1 -0
- airflow/providers/google/cloud/hooks/gcs.py +12 -5
- airflow/providers/google/cloud/hooks/kms.py +1 -0
- airflow/providers/google/cloud/hooks/kubernetes_engine.py +178 -300
- airflow/providers/google/cloud/hooks/life_sciences.py +1 -0
- airflow/providers/google/cloud/hooks/looker.py +1 -0
- airflow/providers/google/cloud/hooks/mlengine.py +1 -0
- airflow/providers/google/cloud/hooks/natural_language.py +1 -0
- airflow/providers/google/cloud/hooks/os_login.py +1 -0
- airflow/providers/google/cloud/hooks/pubsub.py +1 -0
- airflow/providers/google/cloud/hooks/secret_manager.py +1 -0
- airflow/providers/google/cloud/hooks/spanner.py +1 -0
- airflow/providers/google/cloud/hooks/speech_to_text.py +1 -0
- airflow/providers/google/cloud/hooks/stackdriver.py +1 -0
- airflow/providers/google/cloud/hooks/text_to_speech.py +1 -0
- airflow/providers/google/cloud/hooks/translate.py +1 -0
- airflow/providers/google/cloud/hooks/vertex_ai/auto_ml.py +1 -0
- airflow/providers/google/cloud/hooks/vertex_ai/batch_prediction_job.py +255 -3
- airflow/providers/google/cloud/hooks/vertex_ai/custom_job.py +1 -0
- airflow/providers/google/cloud/hooks/vertex_ai/dataset.py +1 -0
- airflow/providers/google/cloud/hooks/vertex_ai/endpoint_service.py +1 -0
- airflow/providers/google/cloud/hooks/vertex_ai/generative_model.py +197 -0
- airflow/providers/google/cloud/hooks/vertex_ai/hyperparameter_tuning_job.py +9 -9
- airflow/providers/google/cloud/hooks/vertex_ai/pipeline_job.py +231 -12
- airflow/providers/google/cloud/hooks/video_intelligence.py +1 -0
- airflow/providers/google/cloud/hooks/vision.py +1 -0
- airflow/providers/google/cloud/links/automl.py +1 -0
- airflow/providers/google/cloud/links/bigquery.py +1 -0
- airflow/providers/google/cloud/links/bigquery_dts.py +1 -0
- airflow/providers/google/cloud/links/cloud_memorystore.py +1 -0
- airflow/providers/google/cloud/links/cloud_sql.py +1 -0
- airflow/providers/google/cloud/links/cloud_tasks.py +1 -0
- airflow/providers/google/cloud/links/compute.py +1 -0
- airflow/providers/google/cloud/links/datacatalog.py +1 -0
- airflow/providers/google/cloud/links/dataflow.py +1 -0
- airflow/providers/google/cloud/links/dataform.py +1 -0
- airflow/providers/google/cloud/links/datafusion.py +1 -0
- airflow/providers/google/cloud/links/dataplex.py +1 -0
- airflow/providers/google/cloud/links/dataproc.py +1 -0
- airflow/providers/google/cloud/links/kubernetes_engine.py +28 -0
- airflow/providers/google/cloud/links/mlengine.py +1 -0
- airflow/providers/google/cloud/links/pubsub.py +1 -0
- airflow/providers/google/cloud/links/spanner.py +1 -0
- airflow/providers/google/cloud/links/stackdriver.py +1 -0
- airflow/providers/google/cloud/links/workflows.py +1 -0
- airflow/providers/google/cloud/log/stackdriver_task_handler.py +18 -4
- airflow/providers/google/cloud/operators/automl.py +1 -0
- airflow/providers/google/cloud/operators/bigquery.py +21 -0
- airflow/providers/google/cloud/operators/bigquery_dts.py +1 -0
- airflow/providers/google/cloud/operators/bigtable.py +1 -0
- airflow/providers/google/cloud/operators/cloud_base.py +1 -0
- airflow/providers/google/cloud/operators/cloud_build.py +1 -0
- airflow/providers/google/cloud/operators/cloud_memorystore.py +1 -0
- airflow/providers/google/cloud/operators/cloud_sql.py +1 -0
- airflow/providers/google/cloud/operators/cloud_storage_transfer_service.py +11 -5
- airflow/providers/google/cloud/operators/compute.py +1 -0
- airflow/providers/google/cloud/operators/dataflow.py +1 -0
- airflow/providers/google/cloud/operators/datafusion.py +1 -0
- airflow/providers/google/cloud/operators/datapipeline.py +1 -0
- airflow/providers/google/cloud/operators/dataprep.py +1 -0
- airflow/providers/google/cloud/operators/dataproc.py +3 -2
- airflow/providers/google/cloud/operators/dataproc_metastore.py +1 -0
- airflow/providers/google/cloud/operators/datastore.py +1 -0
- airflow/providers/google/cloud/operators/functions.py +1 -0
- airflow/providers/google/cloud/operators/gcs.py +1 -0
- airflow/providers/google/cloud/operators/kubernetes_engine.py +600 -4
- airflow/providers/google/cloud/operators/life_sciences.py +1 -0
- airflow/providers/google/cloud/operators/looker.py +1 -0
- airflow/providers/google/cloud/operators/mlengine.py +283 -259
- airflow/providers/google/cloud/operators/natural_language.py +1 -0
- airflow/providers/google/cloud/operators/pubsub.py +1 -0
- airflow/providers/google/cloud/operators/spanner.py +1 -0
- airflow/providers/google/cloud/operators/speech_to_text.py +1 -0
- airflow/providers/google/cloud/operators/text_to_speech.py +1 -0
- airflow/providers/google/cloud/operators/translate.py +1 -0
- airflow/providers/google/cloud/operators/translate_speech.py +1 -0
- airflow/providers/google/cloud/operators/vertex_ai/auto_ml.py +14 -7
- airflow/providers/google/cloud/operators/vertex_ai/batch_prediction_job.py +67 -13
- airflow/providers/google/cloud/operators/vertex_ai/custom_job.py +26 -8
- airflow/providers/google/cloud/operators/vertex_ai/dataset.py +1 -0
- airflow/providers/google/cloud/operators/vertex_ai/generative_model.py +306 -0
- airflow/providers/google/cloud/operators/vertex_ai/hyperparameter_tuning_job.py +29 -48
- airflow/providers/google/cloud/operators/vertex_ai/pipeline_job.py +52 -17
- airflow/providers/google/cloud/operators/video_intelligence.py +1 -0
- airflow/providers/google/cloud/operators/vision.py +1 -0
- airflow/providers/google/cloud/secrets/secret_manager.py +1 -0
- airflow/providers/google/cloud/sensors/bigquery.py +1 -0
- airflow/providers/google/cloud/sensors/bigquery_dts.py +1 -0
- airflow/providers/google/cloud/sensors/bigtable.py +1 -0
- airflow/providers/google/cloud/sensors/cloud_storage_transfer_service.py +1 -0
- airflow/providers/google/cloud/sensors/dataflow.py +1 -0
- airflow/providers/google/cloud/sensors/dataform.py +1 -0
- airflow/providers/google/cloud/sensors/datafusion.py +1 -0
- airflow/providers/google/cloud/sensors/dataplex.py +1 -0
- airflow/providers/google/cloud/sensors/dataprep.py +1 -0
- airflow/providers/google/cloud/sensors/dataproc.py +1 -0
- airflow/providers/google/cloud/sensors/gcs.py +1 -0
- airflow/providers/google/cloud/sensors/looker.py +1 -0
- airflow/providers/google/cloud/sensors/pubsub.py +1 -0
- airflow/providers/google/cloud/sensors/tasks.py +1 -0
- airflow/providers/google/cloud/transfers/bigquery_to_bigquery.py +1 -0
- airflow/providers/google/cloud/transfers/bigquery_to_gcs.py +1 -0
- airflow/providers/google/cloud/transfers/bigquery_to_mssql.py +1 -0
- airflow/providers/google/cloud/transfers/bigquery_to_mysql.py +1 -0
- airflow/providers/google/cloud/transfers/bigquery_to_postgres.py +1 -0
- airflow/providers/google/cloud/transfers/bigquery_to_sql.py +1 -0
- airflow/providers/google/cloud/transfers/facebook_ads_to_gcs.py +1 -0
- airflow/providers/google/cloud/transfers/gcs_to_bigquery.py +3 -2
- airflow/providers/google/cloud/transfers/gcs_to_gcs.py +1 -0
- airflow/providers/google/cloud/transfers/gcs_to_sftp.py +1 -0
- airflow/providers/google/cloud/transfers/local_to_gcs.py +1 -0
- airflow/providers/google/cloud/transfers/mssql_to_gcs.py +1 -0
- airflow/providers/google/cloud/transfers/mysql_to_gcs.py +1 -0
- airflow/providers/google/cloud/transfers/postgres_to_gcs.py +19 -1
- airflow/providers/google/cloud/transfers/s3_to_gcs.py +3 -5
- airflow/providers/google/cloud/transfers/sftp_to_gcs.py +1 -0
- airflow/providers/google/cloud/transfers/sql_to_gcs.py +4 -2
- airflow/providers/google/cloud/triggers/bigquery.py +4 -3
- airflow/providers/google/cloud/triggers/cloud_batch.py +1 -1
- airflow/providers/google/cloud/triggers/cloud_run.py +1 -0
- airflow/providers/google/cloud/triggers/cloud_sql.py +2 -0
- airflow/providers/google/cloud/triggers/cloud_storage_transfer_service.py +14 -2
- airflow/providers/google/cloud/triggers/dataplex.py +1 -0
- airflow/providers/google/cloud/triggers/dataproc.py +1 -0
- airflow/providers/google/cloud/triggers/kubernetes_engine.py +72 -2
- airflow/providers/google/cloud/triggers/mlengine.py +2 -0
- airflow/providers/google/cloud/triggers/pubsub.py +3 -3
- airflow/providers/google/cloud/triggers/vertex_ai.py +107 -15
- airflow/providers/google/cloud/utils/field_sanitizer.py +2 -1
- airflow/providers/google/cloud/utils/field_validator.py +1 -0
- airflow/providers/google/cloud/utils/helpers.py +1 -0
- airflow/providers/google/cloud/utils/mlengine_operator_utils.py +1 -0
- airflow/providers/google/cloud/utils/mlengine_prediction_summary.py +1 -0
- airflow/providers/google/cloud/utils/openlineage.py +1 -0
- airflow/providers/google/common/auth_backend/google_openid.py +1 -0
- airflow/providers/google/common/hooks/base_google.py +2 -1
- airflow/providers/google/common/hooks/discovery_api.py +1 -0
- airflow/providers/google/common/links/storage.py +1 -0
- airflow/providers/google/common/utils/id_token_credentials.py +1 -0
- airflow/providers/google/firebase/hooks/firestore.py +1 -0
- airflow/providers/google/get_provider_info.py +9 -3
- airflow/providers/google/go_module_utils.py +1 -0
- airflow/providers/google/leveldb/hooks/leveldb.py +8 -7
- airflow/providers/google/marketing_platform/example_dags/example_display_video.py +1 -0
- airflow/providers/google/marketing_platform/hooks/analytics_admin.py +1 -0
- airflow/providers/google/marketing_platform/hooks/campaign_manager.py +1 -0
- airflow/providers/google/marketing_platform/hooks/display_video.py +1 -0
- airflow/providers/google/marketing_platform/hooks/search_ads.py +1 -0
- airflow/providers/google/marketing_platform/operators/analytics.py +1 -0
- airflow/providers/google/marketing_platform/operators/analytics_admin.py +4 -2
- airflow/providers/google/marketing_platform/operators/campaign_manager.py +1 -0
- airflow/providers/google/marketing_platform/operators/display_video.py +1 -0
- airflow/providers/google/marketing_platform/operators/search_ads.py +1 -0
- airflow/providers/google/marketing_platform/sensors/campaign_manager.py +1 -0
- airflow/providers/google/marketing_platform/sensors/display_video.py +2 -1
- airflow/providers/google/marketing_platform/sensors/search_ads.py +1 -0
- airflow/providers/google/suite/hooks/calendar.py +1 -0
- airflow/providers/google/suite/hooks/drive.py +1 -0
- airflow/providers/google/suite/hooks/sheets.py +1 -0
- airflow/providers/google/suite/sensors/drive.py +1 -0
- airflow/providers/google/suite/transfers/gcs_to_gdrive.py +7 -0
- airflow/providers/google/suite/transfers/gcs_to_sheets.py +4 -1
- airflow/providers/google/suite/transfers/local_to_drive.py +1 -0
- {apache_airflow_providers_google-10.16.0rc1.dist-info → apache_airflow_providers_google-10.17.0rc1.dist-info}/METADATA +22 -17
- {apache_airflow_providers_google-10.16.0rc1.dist-info → apache_airflow_providers_google-10.17.0rc1.dist-info}/RECORD +196 -194
- {apache_airflow_providers_google-10.16.0rc1.dist-info → apache_airflow_providers_google-10.17.0rc1.dist-info}/WHEEL +0 -0
- {apache_airflow_providers_google-10.16.0rc1.dist-info → apache_airflow_providers_google-10.17.0rc1.dist-info}/entry_points.txt +0 -0
@@ -16,6 +16,7 @@
|
|
16
16
|
# specific language governing permissions and limitations
|
17
17
|
# under the License.
|
18
18
|
"""This module contains a Google Cloud Storage hook."""
|
19
|
+
|
19
20
|
from __future__ import annotations
|
20
21
|
|
21
22
|
import functools
|
@@ -279,8 +280,7 @@ class GCSHook(GoogleBaseHook):
|
|
279
280
|
timeout: int | None = DEFAULT_TIMEOUT,
|
280
281
|
num_max_attempts: int | None = 1,
|
281
282
|
user_project: str | None = None,
|
282
|
-
) -> bytes:
|
283
|
-
...
|
283
|
+
) -> bytes: ...
|
284
284
|
|
285
285
|
@overload
|
286
286
|
def download(
|
@@ -292,8 +292,7 @@ class GCSHook(GoogleBaseHook):
|
|
292
292
|
timeout: int | None = DEFAULT_TIMEOUT,
|
293
293
|
num_max_attempts: int | None = 1,
|
294
294
|
user_project: str | None = None,
|
295
|
-
) -> str:
|
296
|
-
...
|
295
|
+
) -> str: ...
|
297
296
|
|
298
297
|
def download(
|
299
298
|
self,
|
@@ -1338,7 +1337,15 @@ class GCSHook(GoogleBaseHook):
|
|
1338
1337
|
for current_name in names_to_check:
|
1339
1338
|
source_blob = source_names_index[current_name]
|
1340
1339
|
destination_blob = destination_names_index[current_name]
|
1341
|
-
# If
|
1340
|
+
# If either object is CMEK-protected, use the Cloud Storage Objects Get API to retrieve them
|
1341
|
+
# so that the crc32c is included
|
1342
|
+
if source_blob.kms_key_name:
|
1343
|
+
source_blob = source_bucket.get_blob(source_blob.name, generation=source_blob.generation)
|
1344
|
+
if destination_blob.kms_key_name:
|
1345
|
+
destination_blob = destination_bucket.get_blob(
|
1346
|
+
destination_blob.name, generation=destination_blob.generation
|
1347
|
+
)
|
1348
|
+
# if the objects are different, save it
|
1342
1349
|
if source_blob.crc32c != destination_blob.crc32c:
|
1343
1350
|
to_rewrite_blobs.add(source_blob)
|
1344
1351
|
|
@@ -16,12 +16,12 @@
|
|
16
16
|
# specific language governing permissions and limitations
|
17
17
|
# under the License.
|
18
18
|
"""This module contains a Google Kubernetes Engine Hook."""
|
19
|
+
|
19
20
|
from __future__ import annotations
|
20
21
|
|
21
22
|
import contextlib
|
22
23
|
import json
|
23
24
|
import time
|
24
|
-
from functools import cached_property
|
25
25
|
from typing import TYPE_CHECKING, Sequence
|
26
26
|
|
27
27
|
from deprecated import deprecated
|
@@ -37,13 +37,11 @@ from kubernetes import client, utils
|
|
37
37
|
from kubernetes.client.models import V1Deployment
|
38
38
|
from kubernetes_asyncio import client as async_client
|
39
39
|
from kubernetes_asyncio.config.kube_config import FileOrData
|
40
|
-
from urllib3.exceptions import HTTPError
|
41
40
|
|
42
41
|
from airflow import version
|
43
42
|
from airflow.exceptions import AirflowException, AirflowProviderDeprecationWarning
|
44
|
-
from airflow.providers.cncf.kubernetes.hooks.kubernetes import KubernetesHook
|
43
|
+
from airflow.providers.cncf.kubernetes.hooks.kubernetes import AsyncKubernetesHook, KubernetesHook
|
45
44
|
from airflow.providers.cncf.kubernetes.kube_client import _enable_tcp_keepalive
|
46
|
-
from airflow.providers.cncf.kubernetes.utils.pod_manager import PodOperatorHookProtocol
|
47
45
|
from airflow.providers.google.common.consts import CLIENT_INFO
|
48
46
|
from airflow.providers.google.common.hooks.base_google import (
|
49
47
|
PROVIDE_PROJECT_ID,
|
@@ -53,13 +51,58 @@ from airflow.providers.google.common.hooks.base_google import (
|
|
53
51
|
|
54
52
|
if TYPE_CHECKING:
|
55
53
|
import google.auth.credentials
|
56
|
-
from gcloud.aio.auth import Token
|
57
54
|
from google.api_core.retry import Retry
|
58
|
-
from kubernetes_asyncio.client.models import V1Pod
|
59
55
|
|
60
56
|
OPERATIONAL_POLL_INTERVAL = 15
|
61
57
|
|
62
58
|
|
59
|
+
class GKEClusterConnection:
|
60
|
+
"""Helper for establishing connection to GKE cluster."""
|
61
|
+
|
62
|
+
def __init__(
|
63
|
+
self,
|
64
|
+
cluster_url: str,
|
65
|
+
ssl_ca_cert: str,
|
66
|
+
credentials: google.auth.credentials.Credentials,
|
67
|
+
enable_tcp_keepalive: bool = False,
|
68
|
+
):
|
69
|
+
self._cluster_url = cluster_url
|
70
|
+
self._ssl_ca_cert = ssl_ca_cert
|
71
|
+
self._credentials = credentials
|
72
|
+
self.enable_tcp_keepalive = enable_tcp_keepalive
|
73
|
+
|
74
|
+
def get_conn(self) -> client.ApiClient:
|
75
|
+
configuration = self._get_config()
|
76
|
+
configuration.refresh_api_key_hook = self._refresh_api_key_hook
|
77
|
+
if self.enable_tcp_keepalive:
|
78
|
+
_enable_tcp_keepalive()
|
79
|
+
return client.ApiClient(configuration)
|
80
|
+
|
81
|
+
def _refresh_api_key_hook(self, configuration: client.configuration.Configuration):
|
82
|
+
configuration.api_key = {"authorization": self._get_token(self._credentials)}
|
83
|
+
|
84
|
+
def _get_config(self) -> client.configuration.Configuration:
|
85
|
+
configuration = client.Configuration(
|
86
|
+
host=self._cluster_url,
|
87
|
+
api_key_prefix={"authorization": "Bearer"},
|
88
|
+
api_key={"authorization": self._get_token(self._credentials)},
|
89
|
+
)
|
90
|
+
configuration.ssl_ca_cert = FileOrData(
|
91
|
+
{
|
92
|
+
"certificate-authority-data": self._ssl_ca_cert,
|
93
|
+
},
|
94
|
+
file_key_name="certificate-authority",
|
95
|
+
).as_file()
|
96
|
+
return configuration
|
97
|
+
|
98
|
+
@staticmethod
|
99
|
+
def _get_token(creds: google.auth.credentials.Credentials) -> str:
|
100
|
+
if creds.token is None or creds.expired:
|
101
|
+
auth_req = google_requests.Request()
|
102
|
+
creds.refresh(auth_req)
|
103
|
+
return creds.token
|
104
|
+
|
105
|
+
|
63
106
|
class GKEHook(GoogleBaseHook):
|
64
107
|
"""Google Kubernetes Engine cluster APIs.
|
65
108
|
|
@@ -329,96 +372,6 @@ class GKEHook(GoogleBaseHook):
|
|
329
372
|
return False
|
330
373
|
|
331
374
|
|
332
|
-
class GKEDeploymentHook(GoogleBaseHook, KubernetesHook):
|
333
|
-
"""Google Kubernetes Engine Deployment APIs."""
|
334
|
-
|
335
|
-
def __init__(
|
336
|
-
self,
|
337
|
-
cluster_url: str,
|
338
|
-
ssl_ca_cert: str,
|
339
|
-
*args,
|
340
|
-
**kwargs,
|
341
|
-
):
|
342
|
-
super().__init__(*args, **kwargs)
|
343
|
-
self._cluster_url = cluster_url
|
344
|
-
self._ssl_ca_cert = ssl_ca_cert
|
345
|
-
|
346
|
-
@cached_property
|
347
|
-
def api_client(self) -> client.ApiClient:
|
348
|
-
return self.get_conn()
|
349
|
-
|
350
|
-
@cached_property
|
351
|
-
def core_v1_client(self) -> client.CoreV1Api:
|
352
|
-
return client.CoreV1Api(self.api_client)
|
353
|
-
|
354
|
-
@cached_property
|
355
|
-
def batch_v1_client(self) -> client.BatchV1Api:
|
356
|
-
return client.BatchV1Api(self.api_client)
|
357
|
-
|
358
|
-
@cached_property
|
359
|
-
def apps_v1_client(self) -> client.AppsV1Api:
|
360
|
-
return client.AppsV1Api(api_client=self.api_client)
|
361
|
-
|
362
|
-
def get_conn(self) -> client.ApiClient:
|
363
|
-
configuration = self._get_config()
|
364
|
-
configuration.refresh_api_key_hook = self._refresh_api_key_hook
|
365
|
-
return client.ApiClient(configuration)
|
366
|
-
|
367
|
-
def _refresh_api_key_hook(self, configuration: client.configuration.Configuration):
|
368
|
-
configuration.api_key = {"authorization": self._get_token(self.get_credentials())}
|
369
|
-
|
370
|
-
def _get_config(self) -> client.configuration.Configuration:
|
371
|
-
configuration = client.Configuration(
|
372
|
-
host=self._cluster_url,
|
373
|
-
api_key_prefix={"authorization": "Bearer"},
|
374
|
-
api_key={"authorization": self._get_token(self.get_credentials())},
|
375
|
-
)
|
376
|
-
configuration.ssl_ca_cert = FileOrData(
|
377
|
-
{
|
378
|
-
"certificate-authority-data": self._ssl_ca_cert,
|
379
|
-
},
|
380
|
-
file_key_name="certificate-authority",
|
381
|
-
).as_file()
|
382
|
-
return configuration
|
383
|
-
|
384
|
-
@staticmethod
|
385
|
-
def _get_token(creds: google.auth.credentials.Credentials) -> str:
|
386
|
-
if creds.token is None or creds.expired:
|
387
|
-
auth_req = google_requests.Request()
|
388
|
-
creds.refresh(auth_req)
|
389
|
-
return creds.token
|
390
|
-
|
391
|
-
def check_kueue_deployment_running(self, name, namespace):
|
392
|
-
timeout = 300
|
393
|
-
polling_period_seconds = 2
|
394
|
-
|
395
|
-
while timeout is None or timeout > 0:
|
396
|
-
try:
|
397
|
-
deployment = self.get_deployment_status(name=name, namespace=namespace)
|
398
|
-
deployment_status = V1Deployment.to_dict(deployment)["status"]
|
399
|
-
replicas = deployment_status["replicas"]
|
400
|
-
ready_replicas = deployment_status["ready_replicas"]
|
401
|
-
unavailable_replicas = deployment_status["unavailable_replicas"]
|
402
|
-
if (
|
403
|
-
replicas is not None
|
404
|
-
and ready_replicas is not None
|
405
|
-
and unavailable_replicas is None
|
406
|
-
and replicas == ready_replicas
|
407
|
-
):
|
408
|
-
return
|
409
|
-
else:
|
410
|
-
self.log.info("Waiting until Deployment will be ready...")
|
411
|
-
time.sleep(polling_period_seconds)
|
412
|
-
except Exception as e:
|
413
|
-
self.log.exception("Exception occurred while checking for Deployment status.")
|
414
|
-
raise e
|
415
|
-
|
416
|
-
if timeout is not None:
|
417
|
-
timeout -= polling_period_seconds
|
418
|
-
|
419
|
-
raise AirflowException("Deployment timed out")
|
420
|
-
|
421
|
-
|
422
375
|
class GKEAsyncHook(GoogleBaseAsyncHook):
|
423
376
|
"""Asynchronous client of GKE."""
|
424
377
|
|
@@ -466,89 +419,64 @@ class GKEAsyncHook(GoogleBaseAsyncHook):
|
|
466
419
|
)
|
467
420
|
|
468
421
|
|
469
|
-
class
|
470
|
-
"""
|
422
|
+
class GKEKubernetesHook(GoogleBaseHook, KubernetesHook):
|
423
|
+
"""GKE authenticated hook for standard Kubernetes API.
|
424
|
+
|
425
|
+
This hook provides full set of the standard Kubernetes API provided by the KubernetesHook,
|
426
|
+
and at the same time it provides a GKE authentication, so it makes it possible to KubernetesHook
|
427
|
+
functionality against GKE clusters.
|
428
|
+
"""
|
471
429
|
|
472
430
|
def __init__(
|
473
431
|
self,
|
474
432
|
cluster_url: str,
|
475
433
|
ssl_ca_cert: str,
|
476
|
-
|
477
|
-
|
478
|
-
impersonation_chain: str | Sequence[str] | None = None,
|
434
|
+
enable_tcp_keepalive: bool = False,
|
435
|
+
*args,
|
479
436
|
**kwargs,
|
480
437
|
):
|
481
|
-
super().__init__(
|
482
|
-
gcp_conn_id=gcp_conn_id,
|
483
|
-
impersonation_chain=impersonation_chain,
|
484
|
-
**kwargs,
|
485
|
-
)
|
438
|
+
super().__init__(*args, **kwargs)
|
486
439
|
self._cluster_url = cluster_url
|
487
440
|
self._ssl_ca_cert = ssl_ca_cert
|
488
|
-
self.
|
489
|
-
|
490
|
-
@cached_property
|
491
|
-
def api_client(self) -> client.ApiClient:
|
492
|
-
return self.get_conn()
|
493
|
-
|
494
|
-
@cached_property
|
495
|
-
def core_v1_client(self) -> client.CoreV1Api:
|
496
|
-
return client.CoreV1Api(self.api_client)
|
497
|
-
|
498
|
-
@property
|
499
|
-
def is_in_cluster(self) -> bool:
|
500
|
-
return False
|
501
|
-
|
502
|
-
def get_namespace(self):
|
503
|
-
"""Get the namespace configured by the Airflow connection."""
|
504
|
-
|
505
|
-
def _get_namespace(self):
|
506
|
-
"""For compatibility with KubernetesHook. Deprecated; do not use."""
|
507
|
-
|
508
|
-
def get_xcom_sidecar_container_image(self):
|
509
|
-
"""Get the xcom sidecar image defined in the connection.
|
510
|
-
|
511
|
-
Implemented for compatibility with KubernetesHook.
|
512
|
-
"""
|
513
|
-
|
514
|
-
def get_xcom_sidecar_container_resources(self):
|
515
|
-
"""Get the xcom sidecar resources defined in the connection.
|
516
|
-
|
517
|
-
Implemented for compatibility with KubernetesHook.
|
518
|
-
"""
|
441
|
+
self.enable_tcp_keepalive = enable_tcp_keepalive
|
519
442
|
|
520
443
|
def get_conn(self) -> client.ApiClient:
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
444
|
+
return GKEClusterConnection(
|
445
|
+
cluster_url=self._cluster_url,
|
446
|
+
ssl_ca_cert=self._ssl_ca_cert,
|
447
|
+
credentials=self.get_credentials(),
|
448
|
+
enable_tcp_keepalive=self.enable_tcp_keepalive,
|
449
|
+
).get_conn()
|
526
450
|
|
527
|
-
|
451
|
+
def check_kueue_deployment_running(self, name, namespace):
|
452
|
+
timeout = 300
|
453
|
+
polling_period_seconds = 2
|
528
454
|
|
529
|
-
|
530
|
-
|
455
|
+
while timeout is None or timeout > 0:
|
456
|
+
try:
|
457
|
+
deployment = self.get_deployment_status(name=name, namespace=namespace)
|
458
|
+
deployment_status = V1Deployment.to_dict(deployment)["status"]
|
459
|
+
replicas = deployment_status["replicas"]
|
460
|
+
ready_replicas = deployment_status["ready_replicas"]
|
461
|
+
unavailable_replicas = deployment_status["unavailable_replicas"]
|
462
|
+
if (
|
463
|
+
replicas is not None
|
464
|
+
and ready_replicas is not None
|
465
|
+
and unavailable_replicas is None
|
466
|
+
and replicas == ready_replicas
|
467
|
+
):
|
468
|
+
return
|
469
|
+
else:
|
470
|
+
self.log.info("Waiting until Deployment will be ready...")
|
471
|
+
time.sleep(polling_period_seconds)
|
472
|
+
except Exception as e:
|
473
|
+
self.log.exception("Exception occurred while checking for Deployment status.")
|
474
|
+
raise e
|
531
475
|
|
532
|
-
|
533
|
-
|
534
|
-
host=self._cluster_url,
|
535
|
-
api_key_prefix={"authorization": "Bearer"},
|
536
|
-
api_key={"authorization": self._get_token(self.get_credentials())},
|
537
|
-
)
|
538
|
-
configuration.ssl_ca_cert = FileOrData(
|
539
|
-
{
|
540
|
-
"certificate-authority-data": self._ssl_ca_cert,
|
541
|
-
},
|
542
|
-
file_key_name="certificate-authority",
|
543
|
-
).as_file()
|
544
|
-
return configuration
|
476
|
+
if timeout is not None:
|
477
|
+
timeout -= polling_period_seconds
|
545
478
|
|
546
|
-
|
547
|
-
def _get_token(creds: google.auth.credentials.Credentials) -> str:
|
548
|
-
if creds.token is None or creds.expired:
|
549
|
-
auth_req = google_requests.Request()
|
550
|
-
creds.refresh(auth_req)
|
551
|
-
return creds.token
|
479
|
+
raise AirflowException("Deployment timed out")
|
552
480
|
|
553
481
|
def apply_from_yaml_file(
|
554
482
|
self,
|
@@ -558,7 +486,7 @@ class GKEPodHook(GoogleBaseHook, PodOperatorHookProtocol):
|
|
558
486
|
namespace: str = "default",
|
559
487
|
):
|
560
488
|
"""
|
561
|
-
Perform an action from a yaml file
|
489
|
+
Perform an action from a yaml file.
|
562
490
|
|
563
491
|
:param yaml_file: Contains the path to yaml file.
|
564
492
|
:param yaml_objects: List of YAML objects; used instead of reading the yaml_file.
|
@@ -576,82 +504,16 @@ class GKEPodHook(GoogleBaseHook, PodOperatorHookProtocol):
|
|
576
504
|
namespace=namespace,
|
577
505
|
)
|
578
506
|
|
579
|
-
def get_pod(self, name: str, namespace: str) -> V1Pod:
|
580
|
-
"""Get a pod object.
|
581
|
-
|
582
|
-
:param name: Name of the pod.
|
583
|
-
:param namespace: Name of the pod's namespace.
|
584
|
-
"""
|
585
|
-
return self.core_v1_client.read_namespaced_pod(
|
586
|
-
name=name,
|
587
|
-
namespace=namespace,
|
588
|
-
)
|
589
|
-
|
590
|
-
|
591
|
-
class GKEJobHook(GoogleBaseHook, KubernetesHook):
|
592
|
-
"""Google Kubernetes Engine Job APIs."""
|
593
|
-
|
594
|
-
def __init__(
|
595
|
-
self,
|
596
|
-
cluster_url: str,
|
597
|
-
ssl_ca_cert: str,
|
598
|
-
*args,
|
599
|
-
**kwargs,
|
600
|
-
):
|
601
|
-
super().__init__(*args, **kwargs)
|
602
|
-
self._cluster_url = cluster_url
|
603
|
-
self._ssl_ca_cert = ssl_ca_cert
|
604
|
-
|
605
|
-
@cached_property
|
606
|
-
def api_client(self) -> client.ApiClient:
|
607
|
-
return self.get_conn()
|
608
|
-
|
609
|
-
@cached_property
|
610
|
-
def core_v1_client(self) -> client.CoreV1Api:
|
611
|
-
return client.CoreV1Api(self.api_client)
|
612
|
-
|
613
|
-
@cached_property
|
614
|
-
def batch_v1_client(self) -> client.BatchV1Api:
|
615
|
-
return client.BatchV1Api(self.api_client)
|
616
|
-
|
617
|
-
def get_conn(self) -> client.ApiClient:
|
618
|
-
configuration = self._get_config()
|
619
|
-
configuration.refresh_api_key_hook = self._refresh_api_key_hook
|
620
|
-
return client.ApiClient(configuration)
|
621
|
-
|
622
|
-
def _refresh_api_key_hook(self, configuration: client.configuration.Configuration):
|
623
|
-
configuration.api_key = {"authorization": self._get_token(self.get_credentials())}
|
624
|
-
|
625
|
-
def _get_config(self) -> client.configuration.Configuration:
|
626
|
-
configuration = client.Configuration(
|
627
|
-
host=self._cluster_url,
|
628
|
-
api_key_prefix={"authorization": "Bearer"},
|
629
|
-
api_key={"authorization": self._get_token(self.get_credentials())},
|
630
|
-
)
|
631
|
-
configuration.ssl_ca_cert = FileOrData(
|
632
|
-
{
|
633
|
-
"certificate-authority-data": self._ssl_ca_cert,
|
634
|
-
},
|
635
|
-
file_key_name="certificate-authority",
|
636
|
-
).as_file()
|
637
|
-
return configuration
|
638
|
-
|
639
|
-
@staticmethod
|
640
|
-
def _get_token(creds: google.auth.credentials.Credentials) -> str:
|
641
|
-
if creds.token is None or creds.expired:
|
642
|
-
auth_req = google_requests.Request()
|
643
|
-
creds.refresh(auth_req)
|
644
|
-
return creds.token
|
645
|
-
|
646
507
|
|
647
|
-
class
|
648
|
-
"""
|
508
|
+
class GKEKubernetesAsyncHook(GoogleBaseAsyncHook, AsyncKubernetesHook):
|
509
|
+
"""Async GKE authenticated hook for standard Kubernetes API.
|
649
510
|
|
650
|
-
|
651
|
-
|
511
|
+
This hook provides full set of the standard Kubernetes API provided by the AsyncKubernetesHook,
|
512
|
+
and at the same time it provides a GKE authentication, so it makes it possible to KubernetesHook
|
513
|
+
functionality against GKE clusters.
|
652
514
|
"""
|
653
515
|
|
654
|
-
sync_hook_class =
|
516
|
+
sync_hook_class = GKEKubernetesHook
|
655
517
|
scopes = ["https://www.googleapis.com/auth/cloud-platform"]
|
656
518
|
|
657
519
|
def __init__(
|
@@ -660,10 +522,12 @@ class GKEPodAsyncHook(GoogleBaseAsyncHook):
|
|
660
522
|
ssl_ca_cert: str,
|
661
523
|
gcp_conn_id: str = "google_cloud_default",
|
662
524
|
impersonation_chain: str | Sequence[str] | None = None,
|
525
|
+
enable_tcp_keepalive: bool = True,
|
663
526
|
**kwargs,
|
664
527
|
) -> None:
|
665
528
|
self._cluster_url = cluster_url
|
666
529
|
self._ssl_ca_cert = ssl_ca_cert
|
530
|
+
self.enable_tcp_keepalive = enable_tcp_keepalive
|
667
531
|
super().__init__(
|
668
532
|
cluster_url=cluster_url,
|
669
533
|
ssl_ca_cert=ssl_ca_cert,
|
@@ -673,17 +537,18 @@ class GKEPodAsyncHook(GoogleBaseAsyncHook):
|
|
673
537
|
)
|
674
538
|
|
675
539
|
@contextlib.asynccontextmanager
|
676
|
-
async def get_conn(self
|
540
|
+
async def get_conn(self) -> async_client.ApiClient: # type: ignore[override]
|
677
541
|
kube_client = None
|
678
542
|
try:
|
679
|
-
kube_client = await self._load_config(
|
543
|
+
kube_client = await self._load_config()
|
680
544
|
yield kube_client
|
681
545
|
finally:
|
682
546
|
if kube_client is not None:
|
683
547
|
await kube_client.close()
|
684
548
|
|
685
|
-
async def _load_config(self
|
549
|
+
async def _load_config(self) -> async_client.ApiClient:
|
686
550
|
configuration = self._get_config()
|
551
|
+
token = await self.get_token()
|
687
552
|
access_token = await token.get()
|
688
553
|
return async_client.ApiClient(
|
689
554
|
configuration,
|
@@ -703,66 +568,79 @@ class GKEPodAsyncHook(GoogleBaseAsyncHook):
|
|
703
568
|
)
|
704
569
|
return configuration
|
705
570
|
|
706
|
-
async def get_pod(self, name: str, namespace: str) -> V1Pod:
|
707
|
-
"""Get a pod object.
|
708
571
|
|
709
|
-
|
710
|
-
|
711
|
-
""
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
)
|
719
|
-
return pod
|
572
|
+
@deprecated(
|
573
|
+
reason=(
|
574
|
+
"The `GKEDeploymentHook` class is deprecated and will be removed after 01.10.2024, please use "
|
575
|
+
"`GKEKubernetesHook` instead."
|
576
|
+
),
|
577
|
+
category=AirflowProviderDeprecationWarning,
|
578
|
+
)
|
579
|
+
class GKEDeploymentHook(GKEKubernetesHook):
|
580
|
+
"""Google Kubernetes Engine Deployment APIs."""
|
720
581
|
|
721
|
-
async def delete_pod(self, name: str, namespace: str):
|
722
|
-
"""Delete a pod.
|
723
582
|
|
724
|
-
|
725
|
-
|
726
|
-
""
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
:
|
750
|
-
:
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
583
|
+
@deprecated(
|
584
|
+
reason=(
|
585
|
+
"The `GKECustomResourceHook` class is deprecated and will be removed after 01.10.2024, please use "
|
586
|
+
"`GKEKubernetesHook` instead."
|
587
|
+
),
|
588
|
+
category=AirflowProviderDeprecationWarning,
|
589
|
+
)
|
590
|
+
class GKECustomResourceHook(GKEKubernetesHook):
|
591
|
+
"""Google Kubernetes Engine Custom Resource APIs."""
|
592
|
+
|
593
|
+
|
594
|
+
@deprecated(
|
595
|
+
reason=(
|
596
|
+
"The `GKEPodHook` class is deprecated and will be removed after 01.10.2024, please use "
|
597
|
+
"`GKEKubernetesHook` instead."
|
598
|
+
),
|
599
|
+
category=AirflowProviderDeprecationWarning,
|
600
|
+
)
|
601
|
+
class GKEPodHook(GKEKubernetesHook):
|
602
|
+
"""Google Kubernetes Engine pod APIs."""
|
603
|
+
|
604
|
+
def __init__(
|
605
|
+
self,
|
606
|
+
cluster_url: str,
|
607
|
+
ssl_ca_cert: str,
|
608
|
+
disable_tcp_keepalive: bool | None = None,
|
609
|
+
gcp_conn_id: str = "google_cloud_default",
|
610
|
+
impersonation_chain: str | Sequence[str] | None = None,
|
611
|
+
**kwargs,
|
612
|
+
):
|
613
|
+
super().__init__(
|
614
|
+
gcp_conn_id=gcp_conn_id,
|
615
|
+
impersonation_chain=impersonation_chain,
|
616
|
+
cluster_url=cluster_url,
|
617
|
+
ssl_ca_cert=ssl_ca_cert,
|
618
|
+
**kwargs,
|
619
|
+
)
|
620
|
+
self.enable_tcp_keepalive = not bool(disable_tcp_keepalive)
|
621
|
+
|
622
|
+
|
623
|
+
@deprecated(
|
624
|
+
reason=(
|
625
|
+
"The `GKEJobHook` class is deprecated and will be removed after 01.10.2024, please use "
|
626
|
+
"`GKEKubernetesHook` instead."
|
627
|
+
),
|
628
|
+
category=AirflowProviderDeprecationWarning,
|
629
|
+
)
|
630
|
+
class GKEJobHook(GKEKubernetesHook):
|
631
|
+
"""Google Kubernetes Engine Job APIs."""
|
632
|
+
|
633
|
+
|
634
|
+
@deprecated(
|
635
|
+
reason=(
|
636
|
+
"The `GKEPodAsyncHook` class is deprecated and will be removed after 01.10.2024, please use "
|
637
|
+
"`GKEKubernetesAsyncHook` instead."
|
638
|
+
),
|
639
|
+
category=AirflowProviderDeprecationWarning,
|
640
|
+
)
|
641
|
+
class GKEPodAsyncHook(GKEKubernetesAsyncHook):
|
642
|
+
"""Google Kubernetes Engine pods APIs asynchronously.
|
643
|
+
|
644
|
+
:param cluster_url: The URL pointed to the cluster.
|
645
|
+
:param ssl_ca_cert: SSL certificate used for authentication to the pod.
|
646
|
+
"""
|