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.
Files changed (196) hide show
  1. airflow/providers/google/__init__.py +1 -1
  2. airflow/providers/google/ads/hooks/ads.py +5 -4
  3. airflow/providers/google/ads/operators/ads.py +1 -0
  4. airflow/providers/google/cloud/example_dags/example_cloud_sql_query.py +1 -0
  5. airflow/providers/google/cloud/example_dags/example_cloud_task.py +1 -0
  6. airflow/providers/google/cloud/example_dags/example_facebook_ads_to_gcs.py +1 -0
  7. airflow/providers/google/cloud/example_dags/example_looker.py +1 -0
  8. airflow/providers/google/cloud/example_dags/example_presto_to_gcs.py +1 -0
  9. airflow/providers/google/cloud/example_dags/example_salesforce_to_gcs.py +1 -0
  10. airflow/providers/google/cloud/fs/gcs.py +1 -2
  11. airflow/providers/google/cloud/hooks/automl.py +1 -0
  12. airflow/providers/google/cloud/hooks/bigquery.py +87 -24
  13. airflow/providers/google/cloud/hooks/bigquery_dts.py +1 -0
  14. airflow/providers/google/cloud/hooks/bigtable.py +1 -0
  15. airflow/providers/google/cloud/hooks/cloud_build.py +1 -0
  16. airflow/providers/google/cloud/hooks/cloud_memorystore.py +1 -0
  17. airflow/providers/google/cloud/hooks/cloud_sql.py +1 -0
  18. airflow/providers/google/cloud/hooks/cloud_storage_transfer_service.py +9 -4
  19. airflow/providers/google/cloud/hooks/compute.py +1 -0
  20. airflow/providers/google/cloud/hooks/compute_ssh.py +2 -2
  21. airflow/providers/google/cloud/hooks/dataflow.py +6 -5
  22. airflow/providers/google/cloud/hooks/datafusion.py +1 -0
  23. airflow/providers/google/cloud/hooks/datapipeline.py +1 -0
  24. airflow/providers/google/cloud/hooks/dataplex.py +1 -0
  25. airflow/providers/google/cloud/hooks/dataprep.py +1 -0
  26. airflow/providers/google/cloud/hooks/dataproc.py +3 -2
  27. airflow/providers/google/cloud/hooks/dataproc_metastore.py +1 -0
  28. airflow/providers/google/cloud/hooks/datastore.py +1 -0
  29. airflow/providers/google/cloud/hooks/dlp.py +1 -0
  30. airflow/providers/google/cloud/hooks/functions.py +1 -0
  31. airflow/providers/google/cloud/hooks/gcs.py +12 -5
  32. airflow/providers/google/cloud/hooks/kms.py +1 -0
  33. airflow/providers/google/cloud/hooks/kubernetes_engine.py +178 -300
  34. airflow/providers/google/cloud/hooks/life_sciences.py +1 -0
  35. airflow/providers/google/cloud/hooks/looker.py +1 -0
  36. airflow/providers/google/cloud/hooks/mlengine.py +1 -0
  37. airflow/providers/google/cloud/hooks/natural_language.py +1 -0
  38. airflow/providers/google/cloud/hooks/os_login.py +1 -0
  39. airflow/providers/google/cloud/hooks/pubsub.py +1 -0
  40. airflow/providers/google/cloud/hooks/secret_manager.py +1 -0
  41. airflow/providers/google/cloud/hooks/spanner.py +1 -0
  42. airflow/providers/google/cloud/hooks/speech_to_text.py +1 -0
  43. airflow/providers/google/cloud/hooks/stackdriver.py +1 -0
  44. airflow/providers/google/cloud/hooks/text_to_speech.py +1 -0
  45. airflow/providers/google/cloud/hooks/translate.py +1 -0
  46. airflow/providers/google/cloud/hooks/vertex_ai/auto_ml.py +1 -0
  47. airflow/providers/google/cloud/hooks/vertex_ai/batch_prediction_job.py +255 -3
  48. airflow/providers/google/cloud/hooks/vertex_ai/custom_job.py +1 -0
  49. airflow/providers/google/cloud/hooks/vertex_ai/dataset.py +1 -0
  50. airflow/providers/google/cloud/hooks/vertex_ai/endpoint_service.py +1 -0
  51. airflow/providers/google/cloud/hooks/vertex_ai/generative_model.py +197 -0
  52. airflow/providers/google/cloud/hooks/vertex_ai/hyperparameter_tuning_job.py +9 -9
  53. airflow/providers/google/cloud/hooks/vertex_ai/pipeline_job.py +231 -12
  54. airflow/providers/google/cloud/hooks/video_intelligence.py +1 -0
  55. airflow/providers/google/cloud/hooks/vision.py +1 -0
  56. airflow/providers/google/cloud/links/automl.py +1 -0
  57. airflow/providers/google/cloud/links/bigquery.py +1 -0
  58. airflow/providers/google/cloud/links/bigquery_dts.py +1 -0
  59. airflow/providers/google/cloud/links/cloud_memorystore.py +1 -0
  60. airflow/providers/google/cloud/links/cloud_sql.py +1 -0
  61. airflow/providers/google/cloud/links/cloud_tasks.py +1 -0
  62. airflow/providers/google/cloud/links/compute.py +1 -0
  63. airflow/providers/google/cloud/links/datacatalog.py +1 -0
  64. airflow/providers/google/cloud/links/dataflow.py +1 -0
  65. airflow/providers/google/cloud/links/dataform.py +1 -0
  66. airflow/providers/google/cloud/links/datafusion.py +1 -0
  67. airflow/providers/google/cloud/links/dataplex.py +1 -0
  68. airflow/providers/google/cloud/links/dataproc.py +1 -0
  69. airflow/providers/google/cloud/links/kubernetes_engine.py +28 -0
  70. airflow/providers/google/cloud/links/mlengine.py +1 -0
  71. airflow/providers/google/cloud/links/pubsub.py +1 -0
  72. airflow/providers/google/cloud/links/spanner.py +1 -0
  73. airflow/providers/google/cloud/links/stackdriver.py +1 -0
  74. airflow/providers/google/cloud/links/workflows.py +1 -0
  75. airflow/providers/google/cloud/log/stackdriver_task_handler.py +18 -4
  76. airflow/providers/google/cloud/operators/automl.py +1 -0
  77. airflow/providers/google/cloud/operators/bigquery.py +21 -0
  78. airflow/providers/google/cloud/operators/bigquery_dts.py +1 -0
  79. airflow/providers/google/cloud/operators/bigtable.py +1 -0
  80. airflow/providers/google/cloud/operators/cloud_base.py +1 -0
  81. airflow/providers/google/cloud/operators/cloud_build.py +1 -0
  82. airflow/providers/google/cloud/operators/cloud_memorystore.py +1 -0
  83. airflow/providers/google/cloud/operators/cloud_sql.py +1 -0
  84. airflow/providers/google/cloud/operators/cloud_storage_transfer_service.py +11 -5
  85. airflow/providers/google/cloud/operators/compute.py +1 -0
  86. airflow/providers/google/cloud/operators/dataflow.py +1 -0
  87. airflow/providers/google/cloud/operators/datafusion.py +1 -0
  88. airflow/providers/google/cloud/operators/datapipeline.py +1 -0
  89. airflow/providers/google/cloud/operators/dataprep.py +1 -0
  90. airflow/providers/google/cloud/operators/dataproc.py +3 -2
  91. airflow/providers/google/cloud/operators/dataproc_metastore.py +1 -0
  92. airflow/providers/google/cloud/operators/datastore.py +1 -0
  93. airflow/providers/google/cloud/operators/functions.py +1 -0
  94. airflow/providers/google/cloud/operators/gcs.py +1 -0
  95. airflow/providers/google/cloud/operators/kubernetes_engine.py +600 -4
  96. airflow/providers/google/cloud/operators/life_sciences.py +1 -0
  97. airflow/providers/google/cloud/operators/looker.py +1 -0
  98. airflow/providers/google/cloud/operators/mlengine.py +283 -259
  99. airflow/providers/google/cloud/operators/natural_language.py +1 -0
  100. airflow/providers/google/cloud/operators/pubsub.py +1 -0
  101. airflow/providers/google/cloud/operators/spanner.py +1 -0
  102. airflow/providers/google/cloud/operators/speech_to_text.py +1 -0
  103. airflow/providers/google/cloud/operators/text_to_speech.py +1 -0
  104. airflow/providers/google/cloud/operators/translate.py +1 -0
  105. airflow/providers/google/cloud/operators/translate_speech.py +1 -0
  106. airflow/providers/google/cloud/operators/vertex_ai/auto_ml.py +14 -7
  107. airflow/providers/google/cloud/operators/vertex_ai/batch_prediction_job.py +67 -13
  108. airflow/providers/google/cloud/operators/vertex_ai/custom_job.py +26 -8
  109. airflow/providers/google/cloud/operators/vertex_ai/dataset.py +1 -0
  110. airflow/providers/google/cloud/operators/vertex_ai/generative_model.py +306 -0
  111. airflow/providers/google/cloud/operators/vertex_ai/hyperparameter_tuning_job.py +29 -48
  112. airflow/providers/google/cloud/operators/vertex_ai/pipeline_job.py +52 -17
  113. airflow/providers/google/cloud/operators/video_intelligence.py +1 -0
  114. airflow/providers/google/cloud/operators/vision.py +1 -0
  115. airflow/providers/google/cloud/secrets/secret_manager.py +1 -0
  116. airflow/providers/google/cloud/sensors/bigquery.py +1 -0
  117. airflow/providers/google/cloud/sensors/bigquery_dts.py +1 -0
  118. airflow/providers/google/cloud/sensors/bigtable.py +1 -0
  119. airflow/providers/google/cloud/sensors/cloud_storage_transfer_service.py +1 -0
  120. airflow/providers/google/cloud/sensors/dataflow.py +1 -0
  121. airflow/providers/google/cloud/sensors/dataform.py +1 -0
  122. airflow/providers/google/cloud/sensors/datafusion.py +1 -0
  123. airflow/providers/google/cloud/sensors/dataplex.py +1 -0
  124. airflow/providers/google/cloud/sensors/dataprep.py +1 -0
  125. airflow/providers/google/cloud/sensors/dataproc.py +1 -0
  126. airflow/providers/google/cloud/sensors/gcs.py +1 -0
  127. airflow/providers/google/cloud/sensors/looker.py +1 -0
  128. airflow/providers/google/cloud/sensors/pubsub.py +1 -0
  129. airflow/providers/google/cloud/sensors/tasks.py +1 -0
  130. airflow/providers/google/cloud/transfers/bigquery_to_bigquery.py +1 -0
  131. airflow/providers/google/cloud/transfers/bigquery_to_gcs.py +1 -0
  132. airflow/providers/google/cloud/transfers/bigquery_to_mssql.py +1 -0
  133. airflow/providers/google/cloud/transfers/bigquery_to_mysql.py +1 -0
  134. airflow/providers/google/cloud/transfers/bigquery_to_postgres.py +1 -0
  135. airflow/providers/google/cloud/transfers/bigquery_to_sql.py +1 -0
  136. airflow/providers/google/cloud/transfers/facebook_ads_to_gcs.py +1 -0
  137. airflow/providers/google/cloud/transfers/gcs_to_bigquery.py +3 -2
  138. airflow/providers/google/cloud/transfers/gcs_to_gcs.py +1 -0
  139. airflow/providers/google/cloud/transfers/gcs_to_sftp.py +1 -0
  140. airflow/providers/google/cloud/transfers/local_to_gcs.py +1 -0
  141. airflow/providers/google/cloud/transfers/mssql_to_gcs.py +1 -0
  142. airflow/providers/google/cloud/transfers/mysql_to_gcs.py +1 -0
  143. airflow/providers/google/cloud/transfers/postgres_to_gcs.py +19 -1
  144. airflow/providers/google/cloud/transfers/s3_to_gcs.py +3 -5
  145. airflow/providers/google/cloud/transfers/sftp_to_gcs.py +1 -0
  146. airflow/providers/google/cloud/transfers/sql_to_gcs.py +4 -2
  147. airflow/providers/google/cloud/triggers/bigquery.py +4 -3
  148. airflow/providers/google/cloud/triggers/cloud_batch.py +1 -1
  149. airflow/providers/google/cloud/triggers/cloud_run.py +1 -0
  150. airflow/providers/google/cloud/triggers/cloud_sql.py +2 -0
  151. airflow/providers/google/cloud/triggers/cloud_storage_transfer_service.py +14 -2
  152. airflow/providers/google/cloud/triggers/dataplex.py +1 -0
  153. airflow/providers/google/cloud/triggers/dataproc.py +1 -0
  154. airflow/providers/google/cloud/triggers/kubernetes_engine.py +72 -2
  155. airflow/providers/google/cloud/triggers/mlengine.py +2 -0
  156. airflow/providers/google/cloud/triggers/pubsub.py +3 -3
  157. airflow/providers/google/cloud/triggers/vertex_ai.py +107 -15
  158. airflow/providers/google/cloud/utils/field_sanitizer.py +2 -1
  159. airflow/providers/google/cloud/utils/field_validator.py +1 -0
  160. airflow/providers/google/cloud/utils/helpers.py +1 -0
  161. airflow/providers/google/cloud/utils/mlengine_operator_utils.py +1 -0
  162. airflow/providers/google/cloud/utils/mlengine_prediction_summary.py +1 -0
  163. airflow/providers/google/cloud/utils/openlineage.py +1 -0
  164. airflow/providers/google/common/auth_backend/google_openid.py +1 -0
  165. airflow/providers/google/common/hooks/base_google.py +2 -1
  166. airflow/providers/google/common/hooks/discovery_api.py +1 -0
  167. airflow/providers/google/common/links/storage.py +1 -0
  168. airflow/providers/google/common/utils/id_token_credentials.py +1 -0
  169. airflow/providers/google/firebase/hooks/firestore.py +1 -0
  170. airflow/providers/google/get_provider_info.py +9 -3
  171. airflow/providers/google/go_module_utils.py +1 -0
  172. airflow/providers/google/leveldb/hooks/leveldb.py +8 -7
  173. airflow/providers/google/marketing_platform/example_dags/example_display_video.py +1 -0
  174. airflow/providers/google/marketing_platform/hooks/analytics_admin.py +1 -0
  175. airflow/providers/google/marketing_platform/hooks/campaign_manager.py +1 -0
  176. airflow/providers/google/marketing_platform/hooks/display_video.py +1 -0
  177. airflow/providers/google/marketing_platform/hooks/search_ads.py +1 -0
  178. airflow/providers/google/marketing_platform/operators/analytics.py +1 -0
  179. airflow/providers/google/marketing_platform/operators/analytics_admin.py +4 -2
  180. airflow/providers/google/marketing_platform/operators/campaign_manager.py +1 -0
  181. airflow/providers/google/marketing_platform/operators/display_video.py +1 -0
  182. airflow/providers/google/marketing_platform/operators/search_ads.py +1 -0
  183. airflow/providers/google/marketing_platform/sensors/campaign_manager.py +1 -0
  184. airflow/providers/google/marketing_platform/sensors/display_video.py +2 -1
  185. airflow/providers/google/marketing_platform/sensors/search_ads.py +1 -0
  186. airflow/providers/google/suite/hooks/calendar.py +1 -0
  187. airflow/providers/google/suite/hooks/drive.py +1 -0
  188. airflow/providers/google/suite/hooks/sheets.py +1 -0
  189. airflow/providers/google/suite/sensors/drive.py +1 -0
  190. airflow/providers/google/suite/transfers/gcs_to_gdrive.py +7 -0
  191. airflow/providers/google/suite/transfers/gcs_to_sheets.py +4 -1
  192. airflow/providers/google/suite/transfers/local_to_drive.py +1 -0
  193. {apache_airflow_providers_google-10.16.0rc1.dist-info → apache_airflow_providers_google-10.17.0rc1.dist-info}/METADATA +22 -17
  194. {apache_airflow_providers_google-10.16.0rc1.dist-info → apache_airflow_providers_google-10.17.0rc1.dist-info}/RECORD +196 -194
  195. {apache_airflow_providers_google-10.16.0rc1.dist-info → apache_airflow_providers_google-10.17.0rc1.dist-info}/WHEEL +0 -0
  196. {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 the objects are different, save it
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,6 +16,7 @@
16
16
  # specific language governing permissions and limitations
17
17
  # under the License.
18
18
  """This module contains a Google Cloud KMS hook."""
19
+
19
20
  from __future__ import annotations
20
21
 
21
22
  import base64
@@ -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 GKEPodHook(GoogleBaseHook, PodOperatorHookProtocol):
470
- """Google Kubernetes Engine pod APIs."""
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
- disable_tcp_keepalive: bool | None = None,
477
- gcp_conn_id: str = "google_cloud_default",
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.disable_tcp_keepalive = disable_tcp_keepalive
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
- configuration = self._get_config()
522
- configuration.refresh_api_key_hook = self._refresh_api_key_hook
523
-
524
- if self.disable_tcp_keepalive is not True:
525
- _enable_tcp_keepalive()
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
- return client.ApiClient(configuration)
451
+ def check_kueue_deployment_running(self, name, namespace):
452
+ timeout = 300
453
+ polling_period_seconds = 2
528
454
 
529
- def _refresh_api_key_hook(self, configuration: client.configuration.Configuration):
530
- configuration.api_key = {"authorization": self._get_token(self.get_credentials())}
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
- def _get_config(self) -> client.configuration.Configuration:
533
- configuration = client.Configuration(
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
- @staticmethod
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 on a Pod.
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 GKEPodAsyncHook(GoogleBaseAsyncHook):
648
- """Google Kubernetes Engine pods APIs asynchronously.
508
+ class GKEKubernetesAsyncHook(GoogleBaseAsyncHook, AsyncKubernetesHook):
509
+ """Async GKE authenticated hook for standard Kubernetes API.
649
510
 
650
- :param cluster_url: The URL pointed to the cluster.
651
- :param ssl_ca_cert: SSL certificate used for authentication to the pod.
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 = GKEPodHook
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, token: Token) -> async_client.ApiClient: # type: ignore[override]
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(token)
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, token: Token) -> async_client.ApiClient:
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
- :param name: Name of the pod.
710
- :param namespace: Name of the pod's namespace.
711
- """
712
- token = await self.get_token()
713
- async with self.get_conn(token) as connection:
714
- v1_api = async_client.CoreV1Api(connection)
715
- pod: V1Pod = await v1_api.read_namespaced_pod(
716
- name=name,
717
- namespace=namespace,
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
- :param name: Name of the pod.
725
- :param namespace: Name of the pod's namespace.
726
- """
727
- token = await self.get_token()
728
- async with self.get_conn(token) as connection:
729
- try:
730
- v1_api = async_client.CoreV1Api(connection)
731
- await v1_api.delete_namespaced_pod(
732
- name=name,
733
- namespace=namespace,
734
- body=client.V1DeleteOptions(),
735
- )
736
- except async_client.ApiException as e:
737
- # If the pod is already deleted
738
- if e.status != 404:
739
- raise
740
-
741
- async def read_logs(self, name: str, namespace: str):
742
- """Read logs inside the pod while starting containers inside.
743
-
744
- All the logs will be outputted with its timestamp to track the logs
745
- after the execution of the pod is completed. The method is used for
746
- async output of the logs only in the pod failed it execution or the task
747
- was cancelled by the user.
748
-
749
- :param name: Name of the pod.
750
- :param namespace: Name of the pod's namespace.
751
- """
752
- token = await self.get_token()
753
- async with self.get_conn(token) as connection:
754
- try:
755
- v1_api = async_client.CoreV1Api(connection)
756
- logs = await v1_api.read_namespaced_pod_log(
757
- name=name,
758
- namespace=namespace,
759
- follow=False,
760
- timestamps=True,
761
- )
762
- logs = logs.splitlines()
763
- for line in logs:
764
- self.log.info("Container logs from %s", line)
765
- return logs
766
- except HTTPError:
767
- self.log.exception("There was an error reading the kubernetes API.")
768
- raise
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
+ """
@@ -16,6 +16,7 @@
16
16
  # specific language governing permissions and limitations
17
17
  # under the License.
18
18
  """Hook for Google Cloud Life Sciences service."""
19
+
19
20
  from __future__ import annotations
20
21
 
21
22
  import time
@@ -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 Looker hook."""
19
+
19
20
  from __future__ import annotations
20
21
 
21
22
  import json
@@ -16,6 +16,7 @@
16
16
  # specific language governing permissions and limitations
17
17
  # under the License.
18
18
  """This module contains a Google ML Engine Hook."""
19
+
19
20
  from __future__ import annotations
20
21
 
21
22
  import contextlib
@@ -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 Natural Language Hook."""
19
+
19
20
  from __future__ import annotations
20
21
 
21
22
  from typing import TYPE_CHECKING, Sequence