apache-airflow-providers-google 14.0.0__py3-none-any.whl → 19.1.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 (278) hide show
  1. airflow/providers/google/3rd-party-licenses/LICENSES.txt +14 -0
  2. airflow/providers/google/3rd-party-licenses/NOTICE +5 -0
  3. airflow/providers/google/__init__.py +3 -3
  4. airflow/providers/google/_vendor/__init__.py +0 -0
  5. airflow/providers/google/_vendor/json_merge_patch.py +91 -0
  6. airflow/providers/google/ads/hooks/ads.py +52 -43
  7. airflow/providers/google/ads/operators/ads.py +2 -2
  8. airflow/providers/google/ads/transfers/ads_to_gcs.py +3 -19
  9. airflow/providers/google/assets/gcs.py +1 -11
  10. airflow/providers/google/cloud/_internal_client/secret_manager_client.py +3 -2
  11. airflow/providers/google/cloud/bundles/gcs.py +161 -0
  12. airflow/providers/google/cloud/hooks/alloy_db.py +2 -3
  13. airflow/providers/google/cloud/hooks/bigquery.py +195 -318
  14. airflow/providers/google/cloud/hooks/bigquery_dts.py +8 -8
  15. airflow/providers/google/cloud/hooks/bigtable.py +3 -2
  16. airflow/providers/google/cloud/hooks/cloud_batch.py +8 -9
  17. airflow/providers/google/cloud/hooks/cloud_build.py +6 -65
  18. airflow/providers/google/cloud/hooks/cloud_composer.py +292 -24
  19. airflow/providers/google/cloud/hooks/cloud_logging.py +109 -0
  20. airflow/providers/google/cloud/hooks/cloud_memorystore.py +4 -3
  21. airflow/providers/google/cloud/hooks/cloud_run.py +20 -11
  22. airflow/providers/google/cloud/hooks/cloud_sql.py +136 -64
  23. airflow/providers/google/cloud/hooks/cloud_storage_transfer_service.py +35 -15
  24. airflow/providers/google/cloud/hooks/compute.py +7 -6
  25. airflow/providers/google/cloud/hooks/compute_ssh.py +7 -4
  26. airflow/providers/google/cloud/hooks/datacatalog.py +12 -3
  27. airflow/providers/google/cloud/hooks/dataflow.py +87 -242
  28. airflow/providers/google/cloud/hooks/dataform.py +9 -14
  29. airflow/providers/google/cloud/hooks/datafusion.py +7 -9
  30. airflow/providers/google/cloud/hooks/dataplex.py +13 -12
  31. airflow/providers/google/cloud/hooks/dataprep.py +2 -2
  32. airflow/providers/google/cloud/hooks/dataproc.py +76 -74
  33. airflow/providers/google/cloud/hooks/dataproc_metastore.py +4 -3
  34. airflow/providers/google/cloud/hooks/dlp.py +5 -4
  35. airflow/providers/google/cloud/hooks/gcs.py +144 -33
  36. airflow/providers/google/cloud/hooks/gen_ai.py +196 -0
  37. airflow/providers/google/cloud/hooks/kms.py +3 -2
  38. airflow/providers/google/cloud/hooks/kubernetes_engine.py +22 -17
  39. airflow/providers/google/cloud/hooks/looker.py +6 -1
  40. airflow/providers/google/cloud/hooks/managed_kafka.py +227 -3
  41. airflow/providers/google/cloud/hooks/mlengine.py +7 -8
  42. airflow/providers/google/cloud/hooks/natural_language.py +3 -2
  43. airflow/providers/google/cloud/hooks/os_login.py +3 -2
  44. airflow/providers/google/cloud/hooks/pubsub.py +6 -6
  45. airflow/providers/google/cloud/hooks/secret_manager.py +105 -12
  46. airflow/providers/google/cloud/hooks/spanner.py +75 -10
  47. airflow/providers/google/cloud/hooks/speech_to_text.py +3 -2
  48. airflow/providers/google/cloud/hooks/stackdriver.py +18 -18
  49. airflow/providers/google/cloud/hooks/tasks.py +4 -3
  50. airflow/providers/google/cloud/hooks/text_to_speech.py +3 -2
  51. airflow/providers/google/cloud/hooks/translate.py +8 -17
  52. airflow/providers/google/cloud/hooks/vertex_ai/auto_ml.py +8 -222
  53. airflow/providers/google/cloud/hooks/vertex_ai/batch_prediction_job.py +9 -15
  54. airflow/providers/google/cloud/hooks/vertex_ai/custom_job.py +33 -283
  55. airflow/providers/google/cloud/hooks/vertex_ai/dataset.py +5 -12
  56. airflow/providers/google/cloud/hooks/vertex_ai/endpoint_service.py +6 -12
  57. airflow/providers/google/cloud/hooks/vertex_ai/experiment_service.py +202 -0
  58. airflow/providers/google/cloud/hooks/vertex_ai/feature_store.py +311 -10
  59. airflow/providers/google/cloud/hooks/vertex_ai/generative_model.py +79 -75
  60. airflow/providers/google/cloud/hooks/vertex_ai/hyperparameter_tuning_job.py +7 -13
  61. airflow/providers/google/cloud/hooks/vertex_ai/model_service.py +8 -12
  62. airflow/providers/google/cloud/hooks/vertex_ai/pipeline_job.py +6 -12
  63. airflow/providers/google/cloud/hooks/vertex_ai/prediction_service.py +3 -2
  64. airflow/providers/google/cloud/hooks/vertex_ai/ray.py +223 -0
  65. airflow/providers/google/cloud/hooks/video_intelligence.py +3 -2
  66. airflow/providers/google/cloud/hooks/vision.py +7 -7
  67. airflow/providers/google/cloud/hooks/workflows.py +4 -3
  68. airflow/providers/google/cloud/links/alloy_db.py +0 -46
  69. airflow/providers/google/cloud/links/base.py +77 -7
  70. airflow/providers/google/cloud/links/bigquery.py +0 -47
  71. airflow/providers/google/cloud/links/bigquery_dts.py +0 -20
  72. airflow/providers/google/cloud/links/bigtable.py +0 -48
  73. airflow/providers/google/cloud/links/cloud_build.py +0 -73
  74. airflow/providers/google/cloud/links/cloud_functions.py +0 -33
  75. airflow/providers/google/cloud/links/cloud_memorystore.py +0 -58
  76. airflow/providers/google/cloud/links/{life_sciences.py → cloud_run.py} +5 -27
  77. airflow/providers/google/cloud/links/cloud_sql.py +0 -33
  78. airflow/providers/google/cloud/links/cloud_storage_transfer.py +17 -46
  79. airflow/providers/google/cloud/links/cloud_tasks.py +7 -26
  80. airflow/providers/google/cloud/links/compute.py +0 -58
  81. airflow/providers/google/cloud/links/data_loss_prevention.py +0 -169
  82. airflow/providers/google/cloud/links/datacatalog.py +23 -54
  83. airflow/providers/google/cloud/links/dataflow.py +0 -34
  84. airflow/providers/google/cloud/links/dataform.py +0 -64
  85. airflow/providers/google/cloud/links/datafusion.py +1 -90
  86. airflow/providers/google/cloud/links/dataplex.py +0 -154
  87. airflow/providers/google/cloud/links/dataprep.py +0 -24
  88. airflow/providers/google/cloud/links/dataproc.py +11 -89
  89. airflow/providers/google/cloud/links/datastore.py +0 -31
  90. airflow/providers/google/cloud/links/kubernetes_engine.py +11 -61
  91. airflow/providers/google/cloud/links/managed_kafka.py +11 -51
  92. airflow/providers/google/cloud/links/mlengine.py +0 -70
  93. airflow/providers/google/cloud/links/pubsub.py +0 -32
  94. airflow/providers/google/cloud/links/spanner.py +0 -33
  95. airflow/providers/google/cloud/links/stackdriver.py +0 -30
  96. airflow/providers/google/cloud/links/translate.py +17 -187
  97. airflow/providers/google/cloud/links/vertex_ai.py +28 -195
  98. airflow/providers/google/cloud/links/workflows.py +0 -52
  99. airflow/providers/google/cloud/log/gcs_task_handler.py +166 -118
  100. airflow/providers/google/cloud/log/stackdriver_task_handler.py +14 -9
  101. airflow/providers/google/cloud/openlineage/CloudStorageTransferJobFacet.json +68 -0
  102. airflow/providers/google/cloud/openlineage/CloudStorageTransferRunFacet.json +60 -0
  103. airflow/providers/google/cloud/openlineage/DataFusionRunFacet.json +32 -0
  104. airflow/providers/google/cloud/openlineage/facets.py +141 -40
  105. airflow/providers/google/cloud/openlineage/mixins.py +14 -13
  106. airflow/providers/google/cloud/openlineage/utils.py +19 -3
  107. airflow/providers/google/cloud/operators/alloy_db.py +76 -61
  108. airflow/providers/google/cloud/operators/bigquery.py +104 -667
  109. airflow/providers/google/cloud/operators/bigquery_dts.py +12 -12
  110. airflow/providers/google/cloud/operators/bigtable.py +38 -7
  111. airflow/providers/google/cloud/operators/cloud_base.py +22 -1
  112. airflow/providers/google/cloud/operators/cloud_batch.py +18 -18
  113. airflow/providers/google/cloud/operators/cloud_build.py +80 -36
  114. airflow/providers/google/cloud/operators/cloud_composer.py +157 -71
  115. airflow/providers/google/cloud/operators/cloud_logging_sink.py +341 -0
  116. airflow/providers/google/cloud/operators/cloud_memorystore.py +74 -46
  117. airflow/providers/google/cloud/operators/cloud_run.py +39 -20
  118. airflow/providers/google/cloud/operators/cloud_sql.py +46 -61
  119. airflow/providers/google/cloud/operators/cloud_storage_transfer_service.py +92 -14
  120. airflow/providers/google/cloud/operators/compute.py +18 -50
  121. airflow/providers/google/cloud/operators/datacatalog.py +167 -29
  122. airflow/providers/google/cloud/operators/dataflow.py +38 -15
  123. airflow/providers/google/cloud/operators/dataform.py +19 -7
  124. airflow/providers/google/cloud/operators/datafusion.py +43 -43
  125. airflow/providers/google/cloud/operators/dataplex.py +212 -126
  126. airflow/providers/google/cloud/operators/dataprep.py +1 -5
  127. airflow/providers/google/cloud/operators/dataproc.py +134 -207
  128. airflow/providers/google/cloud/operators/dataproc_metastore.py +102 -84
  129. airflow/providers/google/cloud/operators/datastore.py +22 -6
  130. airflow/providers/google/cloud/operators/dlp.py +24 -45
  131. airflow/providers/google/cloud/operators/functions.py +21 -14
  132. airflow/providers/google/cloud/operators/gcs.py +15 -12
  133. airflow/providers/google/cloud/operators/gen_ai.py +389 -0
  134. airflow/providers/google/cloud/operators/kubernetes_engine.py +115 -106
  135. airflow/providers/google/cloud/operators/looker.py +1 -1
  136. airflow/providers/google/cloud/operators/managed_kafka.py +362 -40
  137. airflow/providers/google/cloud/operators/natural_language.py +5 -3
  138. airflow/providers/google/cloud/operators/pubsub.py +69 -21
  139. airflow/providers/google/cloud/operators/spanner.py +53 -45
  140. airflow/providers/google/cloud/operators/speech_to_text.py +5 -4
  141. airflow/providers/google/cloud/operators/stackdriver.py +5 -11
  142. airflow/providers/google/cloud/operators/tasks.py +6 -15
  143. airflow/providers/google/cloud/operators/text_to_speech.py +4 -3
  144. airflow/providers/google/cloud/operators/translate.py +46 -20
  145. airflow/providers/google/cloud/operators/translate_speech.py +4 -3
  146. airflow/providers/google/cloud/operators/vertex_ai/auto_ml.py +44 -34
  147. airflow/providers/google/cloud/operators/vertex_ai/batch_prediction_job.py +34 -12
  148. airflow/providers/google/cloud/operators/vertex_ai/custom_job.py +62 -53
  149. airflow/providers/google/cloud/operators/vertex_ai/dataset.py +75 -11
  150. airflow/providers/google/cloud/operators/vertex_ai/endpoint_service.py +48 -12
  151. airflow/providers/google/cloud/operators/vertex_ai/experiment_service.py +435 -0
  152. airflow/providers/google/cloud/operators/vertex_ai/feature_store.py +532 -1
  153. airflow/providers/google/cloud/operators/vertex_ai/generative_model.py +135 -116
  154. airflow/providers/google/cloud/operators/vertex_ai/hyperparameter_tuning_job.py +16 -12
  155. airflow/providers/google/cloud/operators/vertex_ai/model_service.py +62 -14
  156. airflow/providers/google/cloud/operators/vertex_ai/pipeline_job.py +35 -10
  157. airflow/providers/google/cloud/operators/vertex_ai/ray.py +393 -0
  158. airflow/providers/google/cloud/operators/video_intelligence.py +5 -3
  159. airflow/providers/google/cloud/operators/vision.py +7 -5
  160. airflow/providers/google/cloud/operators/workflows.py +24 -19
  161. airflow/providers/google/cloud/secrets/secret_manager.py +2 -1
  162. airflow/providers/google/cloud/sensors/bigquery.py +2 -2
  163. airflow/providers/google/cloud/sensors/bigquery_dts.py +6 -4
  164. airflow/providers/google/cloud/sensors/bigtable.py +14 -6
  165. airflow/providers/google/cloud/sensors/cloud_composer.py +535 -33
  166. airflow/providers/google/cloud/sensors/cloud_storage_transfer_service.py +6 -5
  167. airflow/providers/google/cloud/sensors/dataflow.py +27 -10
  168. airflow/providers/google/cloud/sensors/dataform.py +2 -2
  169. airflow/providers/google/cloud/sensors/datafusion.py +4 -4
  170. airflow/providers/google/cloud/sensors/dataplex.py +7 -5
  171. airflow/providers/google/cloud/sensors/dataprep.py +2 -2
  172. airflow/providers/google/cloud/sensors/dataproc.py +10 -9
  173. airflow/providers/google/cloud/sensors/dataproc_metastore.py +4 -3
  174. airflow/providers/google/cloud/sensors/gcs.py +22 -21
  175. airflow/providers/google/cloud/sensors/looker.py +5 -5
  176. airflow/providers/google/cloud/sensors/pubsub.py +20 -20
  177. airflow/providers/google/cloud/sensors/tasks.py +2 -2
  178. airflow/providers/google/cloud/sensors/vertex_ai/feature_store.py +2 -2
  179. airflow/providers/google/cloud/sensors/workflows.py +6 -4
  180. airflow/providers/google/cloud/transfers/adls_to_gcs.py +1 -1
  181. airflow/providers/google/cloud/transfers/azure_blob_to_gcs.py +2 -2
  182. airflow/providers/google/cloud/transfers/azure_fileshare_to_gcs.py +2 -2
  183. airflow/providers/google/cloud/transfers/bigquery_to_bigquery.py +11 -8
  184. airflow/providers/google/cloud/transfers/bigquery_to_gcs.py +14 -13
  185. airflow/providers/google/cloud/transfers/bigquery_to_mssql.py +7 -3
  186. airflow/providers/google/cloud/transfers/bigquery_to_mysql.py +12 -1
  187. airflow/providers/google/cloud/transfers/bigquery_to_postgres.py +24 -10
  188. airflow/providers/google/cloud/transfers/bigquery_to_sql.py +104 -5
  189. airflow/providers/google/cloud/transfers/calendar_to_gcs.py +1 -1
  190. airflow/providers/google/cloud/transfers/cassandra_to_gcs.py +18 -22
  191. airflow/providers/google/cloud/transfers/facebook_ads_to_gcs.py +4 -5
  192. airflow/providers/google/cloud/transfers/gcs_to_bigquery.py +45 -38
  193. airflow/providers/google/cloud/transfers/gcs_to_gcs.py +2 -2
  194. airflow/providers/google/cloud/transfers/gcs_to_local.py +5 -3
  195. airflow/providers/google/cloud/transfers/gcs_to_sftp.py +10 -4
  196. airflow/providers/google/cloud/transfers/gdrive_to_gcs.py +6 -2
  197. airflow/providers/google/cloud/transfers/gdrive_to_local.py +2 -2
  198. airflow/providers/google/cloud/transfers/http_to_gcs.py +193 -0
  199. airflow/providers/google/cloud/transfers/local_to_gcs.py +2 -2
  200. airflow/providers/google/cloud/transfers/mssql_to_gcs.py +1 -1
  201. airflow/providers/google/cloud/transfers/oracle_to_gcs.py +36 -11
  202. airflow/providers/google/cloud/transfers/postgres_to_gcs.py +44 -12
  203. airflow/providers/google/cloud/transfers/s3_to_gcs.py +12 -6
  204. airflow/providers/google/cloud/transfers/salesforce_to_gcs.py +2 -2
  205. airflow/providers/google/cloud/transfers/sftp_to_gcs.py +36 -14
  206. airflow/providers/google/cloud/transfers/sheets_to_gcs.py +3 -3
  207. airflow/providers/google/cloud/transfers/sql_to_gcs.py +10 -10
  208. airflow/providers/google/cloud/triggers/bigquery.py +75 -34
  209. airflow/providers/google/cloud/triggers/bigquery_dts.py +2 -1
  210. airflow/providers/google/cloud/triggers/cloud_batch.py +2 -1
  211. airflow/providers/google/cloud/triggers/cloud_build.py +3 -2
  212. airflow/providers/google/cloud/triggers/cloud_composer.py +303 -47
  213. airflow/providers/google/cloud/triggers/cloud_run.py +2 -2
  214. airflow/providers/google/cloud/triggers/cloud_storage_transfer_service.py +96 -5
  215. airflow/providers/google/cloud/triggers/dataflow.py +125 -2
  216. airflow/providers/google/cloud/triggers/datafusion.py +1 -1
  217. airflow/providers/google/cloud/triggers/dataplex.py +16 -3
  218. airflow/providers/google/cloud/triggers/dataproc.py +124 -53
  219. airflow/providers/google/cloud/triggers/kubernetes_engine.py +46 -28
  220. airflow/providers/google/cloud/triggers/mlengine.py +1 -1
  221. airflow/providers/google/cloud/triggers/pubsub.py +17 -20
  222. airflow/providers/google/cloud/triggers/vertex_ai.py +8 -7
  223. airflow/providers/google/cloud/utils/bigquery.py +5 -7
  224. airflow/providers/google/cloud/utils/bigquery_get_data.py +1 -1
  225. airflow/providers/google/cloud/utils/credentials_provider.py +4 -3
  226. airflow/providers/google/cloud/utils/dataform.py +1 -1
  227. airflow/providers/google/cloud/utils/external_token_supplier.py +0 -1
  228. airflow/providers/google/cloud/utils/field_validator.py +1 -2
  229. airflow/providers/google/cloud/utils/validators.py +43 -0
  230. airflow/providers/google/common/auth_backend/google_openid.py +26 -9
  231. airflow/providers/google/common/consts.py +2 -1
  232. airflow/providers/google/common/deprecated.py +2 -1
  233. airflow/providers/google/common/hooks/base_google.py +40 -43
  234. airflow/providers/google/common/hooks/operation_helpers.py +78 -0
  235. airflow/providers/google/common/links/storage.py +0 -22
  236. airflow/providers/google/common/utils/get_secret.py +31 -0
  237. airflow/providers/google/common/utils/id_token_credentials.py +4 -5
  238. airflow/providers/google/firebase/operators/firestore.py +2 -2
  239. airflow/providers/google/get_provider_info.py +61 -216
  240. airflow/providers/google/go_module_utils.py +35 -3
  241. airflow/providers/google/leveldb/hooks/leveldb.py +30 -6
  242. airflow/providers/google/leveldb/operators/leveldb.py +2 -2
  243. airflow/providers/google/marketing_platform/hooks/analytics_admin.py +3 -2
  244. airflow/providers/google/marketing_platform/hooks/display_video.py +3 -109
  245. airflow/providers/google/marketing_platform/hooks/search_ads.py +1 -1
  246. airflow/providers/google/marketing_platform/links/analytics_admin.py +4 -5
  247. airflow/providers/google/marketing_platform/operators/analytics_admin.py +7 -6
  248. airflow/providers/google/marketing_platform/operators/campaign_manager.py +5 -5
  249. airflow/providers/google/marketing_platform/operators/display_video.py +28 -489
  250. airflow/providers/google/marketing_platform/operators/search_ads.py +2 -2
  251. airflow/providers/google/marketing_platform/sensors/campaign_manager.py +2 -2
  252. airflow/providers/google/marketing_platform/sensors/display_video.py +4 -64
  253. airflow/providers/google/suite/hooks/calendar.py +1 -1
  254. airflow/providers/google/suite/hooks/drive.py +2 -2
  255. airflow/providers/google/suite/hooks/sheets.py +15 -1
  256. airflow/providers/google/suite/operators/sheets.py +8 -3
  257. airflow/providers/google/suite/sensors/drive.py +2 -2
  258. airflow/providers/google/suite/transfers/gcs_to_gdrive.py +2 -2
  259. airflow/providers/google/suite/transfers/gcs_to_sheets.py +1 -1
  260. airflow/providers/google/suite/transfers/local_to_drive.py +3 -3
  261. airflow/providers/google/suite/transfers/sql_to_sheets.py +5 -4
  262. airflow/providers/google/version_compat.py +15 -1
  263. {apache_airflow_providers_google-14.0.0.dist-info → apache_airflow_providers_google-19.1.0rc1.dist-info}/METADATA +117 -72
  264. apache_airflow_providers_google-19.1.0rc1.dist-info/RECORD +331 -0
  265. {apache_airflow_providers_google-14.0.0.dist-info → apache_airflow_providers_google-19.1.0rc1.dist-info}/WHEEL +1 -1
  266. apache_airflow_providers_google-19.1.0rc1.dist-info/licenses/NOTICE +5 -0
  267. airflow/providers/google/cloud/example_dags/example_cloud_task.py +0 -54
  268. airflow/providers/google/cloud/hooks/automl.py +0 -679
  269. airflow/providers/google/cloud/hooks/life_sciences.py +0 -159
  270. airflow/providers/google/cloud/links/automl.py +0 -193
  271. airflow/providers/google/cloud/operators/automl.py +0 -1360
  272. airflow/providers/google/cloud/operators/life_sciences.py +0 -119
  273. airflow/providers/google/cloud/operators/mlengine.py +0 -1515
  274. airflow/providers/google/cloud/utils/mlengine_operator_utils.py +0 -273
  275. apache_airflow_providers_google-14.0.0.dist-info/RECORD +0 -318
  276. /airflow/providers/google/cloud/{example_dags → bundles}/__init__.py +0 -0
  277. {apache_airflow_providers_google-14.0.0.dist-info → apache_airflow_providers_google-19.1.0rc1.dist-info}/entry_points.txt +0 -0
  278. {airflow/providers/google → apache_airflow_providers_google-19.1.0rc1.dist-info/licenses}/LICENSE +0 -0
@@ -23,12 +23,6 @@ from collections.abc import Sequence
23
23
  from copy import copy
24
24
  from typing import TYPE_CHECKING
25
25
 
26
- from airflow.providers.google.common.consts import CLIENT_INFO
27
- from airflow.providers.google.common.hooks.base_google import (
28
- PROVIDE_PROJECT_ID,
29
- GoogleBaseAsyncHook,
30
- GoogleBaseHook,
31
- )
32
26
  from google.api_core.gapic_v1.method import DEFAULT, _MethodDefault
33
27
  from google.cloud.bigquery_datatransfer_v1 import DataTransferServiceAsyncClient, DataTransferServiceClient
34
28
  from google.cloud.bigquery_datatransfer_v1.types import (
@@ -37,11 +31,17 @@ from google.cloud.bigquery_datatransfer_v1.types import (
37
31
  TransferRun,
38
32
  )
39
33
 
40
- if TYPE_CHECKING:
41
- from googleapiclient.discovery import Resource
34
+ from airflow.providers.google.common.consts import CLIENT_INFO
35
+ from airflow.providers.google.common.hooks.base_google import (
36
+ PROVIDE_PROJECT_ID,
37
+ GoogleBaseAsyncHook,
38
+ GoogleBaseHook,
39
+ )
42
40
 
41
+ if TYPE_CHECKING:
43
42
  from google.api_core.retry import Retry
44
43
  from google.api_core.retry_async import AsyncRetry
44
+ from googleapiclient.discovery import Resource
45
45
 
46
46
 
47
47
  def get_object_id(obj: dict) -> str:
@@ -22,13 +22,14 @@ from __future__ import annotations
22
22
  from collections.abc import Sequence
23
23
  from typing import TYPE_CHECKING
24
24
 
25
- from airflow.providers.google.common.consts import CLIENT_INFO
26
- from airflow.providers.google.common.hooks.base_google import GoogleBaseHook
27
25
  from google.cloud.bigtable import Client, enums
28
26
  from google.cloud.bigtable.cluster import Cluster
29
27
  from google.cloud.bigtable.instance import Instance
30
28
  from google.cloud.bigtable.table import ClusterState, Table
31
29
 
30
+ from airflow.providers.google.common.consts import CLIENT_INFO
31
+ from airflow.providers.google.common.hooks.base_google import GoogleBaseHook
32
+
32
33
  if TYPE_CHECKING:
33
34
  import enum
34
35
 
@@ -23,9 +23,6 @@ import time
23
23
  from collections.abc import Iterable, Sequence
24
24
  from typing import TYPE_CHECKING
25
25
 
26
- from airflow.exceptions import AirflowException
27
- from airflow.providers.google.common.consts import CLIENT_INFO
28
- from airflow.providers.google.common.hooks.base_google import PROVIDE_PROJECT_ID, GoogleBaseHook
29
26
  from google.cloud.batch import ListJobsRequest, ListTasksRequest
30
27
  from google.cloud.batch_v1 import (
31
28
  BatchServiceAsyncClient,
@@ -36,6 +33,10 @@ from google.cloud.batch_v1 import (
36
33
  Task,
37
34
  )
38
35
 
36
+ from airflow.exceptions import AirflowException
37
+ from airflow.providers.google.common.consts import CLIENT_INFO
38
+ from airflow.providers.google.common.hooks.base_google import PROVIDE_PROJECT_ID, GoogleBaseHook
39
+
39
40
  if TYPE_CHECKING:
40
41
  from google.api_core import operation
41
42
  from google.cloud.batch_v1.services.batch_service import pagers
@@ -146,20 +147,18 @@ class CloudBatchHook(GoogleBaseHook):
146
147
  status: JobStatus.State = job.status.state
147
148
  if status == JobStatus.State.SUCCEEDED:
148
149
  return job
149
- elif status == JobStatus.State.FAILED:
150
+ if status == JobStatus.State.FAILED:
150
151
  message = (
151
152
  "Unexpected error in the operation: "
152
153
  "Batch job with name {job_name} has failed its execution."
153
154
  )
154
155
  raise AirflowException(message)
155
- elif status == JobStatus.State.DELETION_IN_PROGRESS:
156
+ if status == JobStatus.State.DELETION_IN_PROGRESS:
156
157
  message = (
157
- "Unexpected error in the operation: "
158
- "Batch job with name {job_name} is being deleted."
158
+ "Unexpected error in the operation: Batch job with name {job_name} is being deleted."
159
159
  )
160
160
  raise AirflowException(message)
161
- else:
162
- time.sleep(polling_period_seconds)
161
+ time.sleep(polling_period_seconds)
163
162
  except Exception as e:
164
163
  self.log.exception("Exception occurred while checking for job completion.")
165
164
  raise e
@@ -22,15 +22,16 @@ from __future__ import annotations
22
22
  from collections.abc import Sequence
23
23
  from typing import TYPE_CHECKING
24
24
 
25
- from airflow.exceptions import AirflowException, AirflowProviderDeprecationWarning
26
- from airflow.providers.google.common.consts import CLIENT_INFO
27
- from airflow.providers.google.common.deprecated import deprecated
28
- from airflow.providers.google.common.hooks.base_google import PROVIDE_PROJECT_ID, GoogleBaseHook
29
25
  from google.api_core.client_options import ClientOptions
30
26
  from google.api_core.exceptions import AlreadyExists
31
27
  from google.api_core.gapic_v1.method import DEFAULT, _MethodDefault
32
28
  from google.cloud.devtools.cloudbuild_v1 import CloudBuildAsyncClient, CloudBuildClient, GetBuildRequest
33
29
 
30
+ from airflow.exceptions import AirflowException
31
+ from airflow.providers.google.common.consts import CLIENT_INFO
32
+ from airflow.providers.google.common.hooks.base_google import PROVIDE_PROJECT_ID, GoogleBaseHook
33
+ from airflow.providers.google.common.hooks.operation_helpers import OperationHelper
34
+
34
35
  if TYPE_CHECKING:
35
36
  from google.api_core.operation import Operation
36
37
  from google.api_core.retry import Retry
@@ -41,7 +42,7 @@ if TYPE_CHECKING:
41
42
  TIME_TO_SLEEP_IN_SECONDS = 5
42
43
 
43
44
 
44
- class CloudBuildHook(GoogleBaseHook):
45
+ class CloudBuildHook(GoogleBaseHook, OperationHelper):
45
46
  """
46
47
  Hook for the Google Cloud Build Service.
47
48
 
@@ -79,14 +80,6 @@ class CloudBuildHook(GoogleBaseHook):
79
80
  except Exception:
80
81
  raise AirflowException("Could not retrieve Build ID from Operation.")
81
82
 
82
- def wait_for_operation(self, operation: Operation, timeout: float | None = None):
83
- """Wait for long-lasting operation to complete."""
84
- try:
85
- return operation.result(timeout=timeout)
86
- except Exception:
87
- error = operation.exception(timeout=timeout)
88
- raise AirflowException(error)
89
-
90
83
  def get_conn(self, location: str = "global") -> CloudBuildClient:
91
84
  """
92
85
  Retrieve the connection to Google Cloud Build.
@@ -184,58 +177,6 @@ class CloudBuildHook(GoogleBaseHook):
184
177
 
185
178
  return operation, id_
186
179
 
187
- @GoogleBaseHook.fallback_to_default_project_id
188
- @deprecated(
189
- planned_removal_date="March 01, 2025",
190
- use_instead="create_build_without_waiting_for_result",
191
- category=AirflowProviderDeprecationWarning,
192
- )
193
- def create_build(
194
- self,
195
- build: dict | Build,
196
- project_id: str = PROVIDE_PROJECT_ID,
197
- wait: bool = True,
198
- retry: Retry | _MethodDefault = DEFAULT,
199
- timeout: float | None = None,
200
- metadata: Sequence[tuple[str, str]] = (),
201
- ) -> Build:
202
- """
203
- Start a build with the specified configuration.
204
-
205
- :param build: The build resource to create. If a dict is provided, it must be of the same form
206
- as the protobuf message `google.cloud.devtools.cloudbuild_v1.types.Build`
207
- :param project_id: Optional, Google Cloud Project project_id where the function belongs.
208
- If set to None or missing, the default project_id from the GCP connection is used.
209
- :param wait: Optional, wait for operation to finish.
210
- :param retry: Optional, a retry object used to retry requests. If `None` is specified, requests
211
- will not be retried.
212
- :param timeout: Optional, the amount of time, in seconds, to wait for the request to complete.
213
- Note that if `retry` is specified, the timeout applies to each individual attempt.
214
- :param metadata: Optional, additional metadata that is provided to the method.
215
-
216
- """
217
- client = self.get_conn()
218
-
219
- self.log.info("Start creating build...")
220
-
221
- operation = client.create_build(
222
- request={"project_id": project_id, "build": build},
223
- retry=retry,
224
- timeout=timeout,
225
- metadata=metadata,
226
- )
227
-
228
- id_ = self._get_build_id_from_operation(operation)
229
-
230
- if not wait:
231
- return self.get_build(id_=id_, project_id=project_id)
232
-
233
- operation.result()
234
-
235
- self.log.info("Build has been created: %s.", id_)
236
-
237
- return self.get_build(id_=id_, project_id=project_id)
238
-
239
180
  @GoogleBaseHook.fallback_to_default_project_id
240
181
  def create_build_trigger(
241
182
  self,
@@ -18,15 +18,16 @@
18
18
  from __future__ import annotations
19
19
 
20
20
  import asyncio
21
+ import json
21
22
  import time
22
23
  from collections.abc import MutableSequence, Sequence
23
- from typing import TYPE_CHECKING
24
+ from typing import TYPE_CHECKING, Any
25
+ from urllib.parse import urlencode, urljoin
24
26
 
25
- from airflow.exceptions import AirflowException
26
- from airflow.providers.google.common.consts import CLIENT_INFO
27
- from airflow.providers.google.common.hooks.base_google import GoogleBaseHook
27
+ from aiohttp import ClientSession
28
28
  from google.api_core.client_options import ClientOptions
29
29
  from google.api_core.gapic_v1.method import DEFAULT, _MethodDefault
30
+ from google.auth.transport.requests import AuthorizedSession, Request
30
31
  from google.cloud.orchestration.airflow.service_v1 import (
31
32
  EnvironmentsAsyncClient,
32
33
  EnvironmentsClient,
@@ -34,6 +35,10 @@ from google.cloud.orchestration.airflow.service_v1 import (
34
35
  PollAirflowCommandResponse,
35
36
  )
36
37
 
38
+ from airflow.exceptions import AirflowException
39
+ from airflow.providers.google.common.consts import CLIENT_INFO
40
+ from airflow.providers.google.common.hooks.base_google import GoogleBaseAsyncHook, GoogleBaseHook
41
+
37
42
  if TYPE_CHECKING:
38
43
  from google.api_core.operation import Operation
39
44
  from google.api_core.operation_async import AsyncOperation
@@ -51,8 +56,10 @@ if TYPE_CHECKING:
51
56
  )
52
57
  from google.protobuf.field_mask_pb2 import FieldMask
53
58
 
59
+ from airflow.providers.google.common.hooks.operation_helpers import OperationHelper
60
+
54
61
 
55
- class CloudComposerHook(GoogleBaseHook):
62
+ class CloudComposerHook(GoogleBaseHook, OperationHelper):
56
63
  """Hook for Google Cloud Composer APIs."""
57
64
 
58
65
  client_options = ClientOptions(api_endpoint="composer.googleapis.com:443")
@@ -73,13 +80,33 @@ class CloudComposerHook(GoogleBaseHook):
73
80
  client_options=self.client_options,
74
81
  )
75
82
 
76
- def wait_for_operation(self, operation: Operation, timeout: float | None = None):
77
- """Wait for long-lasting operation to complete."""
78
- try:
79
- return operation.result(timeout=timeout)
80
- except Exception:
81
- error = operation.exception(timeout=timeout)
82
- raise AirflowException(error)
83
+ def make_composer_airflow_api_request(
84
+ self,
85
+ method: str,
86
+ airflow_uri: str,
87
+ path: str,
88
+ data: Any | None = None,
89
+ timeout: float | None = None,
90
+ ):
91
+ """
92
+ Make a request to Cloud Composer environment's web server.
93
+
94
+ :param method: The request method to use ('GET', 'OPTIONS', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE').
95
+ :param airflow_uri: The URI of the Apache Airflow Web UI hosted within this environment.
96
+ :param path: The path to send the request.
97
+ :param data: Dictionary, list of tuples, bytes, or file-like object to send in the body of the request.
98
+ :param timeout: The timeout for this request.
99
+ """
100
+ authed_session = AuthorizedSession(self.get_credentials())
101
+
102
+ resp = authed_session.request(
103
+ method=method,
104
+ url=urljoin(airflow_uri, path),
105
+ data=data,
106
+ headers={"Content-Type": "application/json"},
107
+ timeout=timeout,
108
+ )
109
+ return resp
83
110
 
84
111
  def get_operation(self, operation_name):
85
112
  return self.get_environment_client().transport.operations_client.get_operation(name=operation_name)
@@ -413,20 +440,160 @@ class CloudComposerHook(GoogleBaseHook):
413
440
  self.log.info("Waiting for result...")
414
441
  time.sleep(poll_interval)
415
442
 
443
+ def trigger_dag_run(
444
+ self,
445
+ composer_airflow_uri: str,
446
+ composer_dag_id: str,
447
+ composer_dag_conf: dict | None = None,
448
+ timeout: float | None = None,
449
+ ) -> dict:
450
+ """
451
+ Trigger DAG run for provided Apache Airflow Web UI hosted within Composer environment.
452
+
453
+ :param composer_airflow_uri: The URI of the Apache Airflow Web UI hosted within Composer environment.
454
+ :param composer_dag_id: The ID of DAG which will be triggered.
455
+ :param composer_dag_conf: Configuration parameters for the DAG run.
456
+ :param timeout: The timeout for this request.
457
+ """
458
+ response = self.make_composer_airflow_api_request(
459
+ method="POST",
460
+ airflow_uri=composer_airflow_uri,
461
+ path=f"/api/v1/dags/{composer_dag_id}/dagRuns",
462
+ data=json.dumps(
463
+ {
464
+ "conf": composer_dag_conf or {},
465
+ }
466
+ ),
467
+ timeout=timeout,
468
+ )
469
+
470
+ if response.status_code != 200:
471
+ self.log.error(response.text)
472
+ response.raise_for_status()
473
+
474
+ return response.json()
475
+
476
+ def get_dag_runs(
477
+ self,
478
+ composer_airflow_uri: str,
479
+ composer_dag_id: str,
480
+ timeout: float | None = None,
481
+ ) -> dict:
482
+ """
483
+ Get the list of dag runs for provided DAG.
416
484
 
417
- class CloudComposerAsyncHook(GoogleBaseHook):
485
+ :param composer_airflow_uri: The URI of the Apache Airflow Web UI hosted within Composer environment.
486
+ :param composer_dag_id: The ID of DAG.
487
+ :param timeout: The timeout for this request.
488
+ """
489
+ response = self.make_composer_airflow_api_request(
490
+ method="GET",
491
+ airflow_uri=composer_airflow_uri,
492
+ path=f"/api/v1/dags/{composer_dag_id}/dagRuns",
493
+ timeout=timeout,
494
+ )
495
+
496
+ if response.status_code != 200:
497
+ self.log.error(
498
+ "Failed to get DAG runs for dag_id=%s from %s (status=%s): %s",
499
+ composer_dag_id,
500
+ composer_airflow_uri,
501
+ response.status_code,
502
+ response.text,
503
+ )
504
+ response.raise_for_status()
505
+
506
+ return response.json()
507
+
508
+ def get_task_instances(
509
+ self,
510
+ composer_airflow_uri: str,
511
+ composer_dag_id: str,
512
+ query_parameters: dict | None = None,
513
+ timeout: float | None = None,
514
+ ) -> dict:
515
+ """
516
+ Get the list of task instances for provided DAG.
517
+
518
+ :param composer_airflow_uri: The URI of the Apache Airflow Web UI hosted within Composer environment.
519
+ :param composer_dag_id: The ID of DAG.
520
+ :query_parameters: Query parameters for this request.
521
+ :param timeout: The timeout for this request.
522
+ """
523
+ query_string = f"?{urlencode(query_parameters)}" if query_parameters else ""
524
+
525
+ response = self.make_composer_airflow_api_request(
526
+ method="GET",
527
+ airflow_uri=composer_airflow_uri,
528
+ path=f"/api/v1/dags/{composer_dag_id}/dagRuns/~/taskInstances{query_string}",
529
+ timeout=timeout,
530
+ )
531
+
532
+ if response.status_code != 200:
533
+ self.log.error(
534
+ "Failed to get task instances for dag_id=%s from %s (status=%s): %s",
535
+ composer_dag_id,
536
+ composer_airflow_uri,
537
+ response.status_code,
538
+ response.text,
539
+ )
540
+ response.raise_for_status()
541
+
542
+ return response.json()
543
+
544
+
545
+ class CloudComposerAsyncHook(GoogleBaseAsyncHook):
418
546
  """Hook for Google Cloud Composer async APIs."""
419
547
 
548
+ sync_hook_class = CloudComposerHook
549
+
420
550
  client_options = ClientOptions(api_endpoint="composer.googleapis.com:443")
421
551
 
422
- def get_environment_client(self) -> EnvironmentsAsyncClient:
552
+ async def get_environment_client(self) -> EnvironmentsAsyncClient:
423
553
  """Retrieve client library object that allow access Environments service."""
554
+ sync_hook = await self.get_sync_hook()
424
555
  return EnvironmentsAsyncClient(
425
- credentials=self.get_credentials(),
556
+ credentials=sync_hook.get_credentials(),
426
557
  client_info=CLIENT_INFO,
427
558
  client_options=self.client_options,
428
559
  )
429
560
 
561
+ async def make_composer_airflow_api_request(
562
+ self,
563
+ method: str,
564
+ airflow_uri: str,
565
+ path: str,
566
+ data: Any | None = None,
567
+ timeout: float | None = None,
568
+ ):
569
+ """
570
+ Make a request to Cloud Composer environment's web server.
571
+
572
+ :param method: The request method to use ('GET', 'OPTIONS', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE').
573
+ :param airflow_uri: The URI of the Apache Airflow Web UI hosted within this environment.
574
+ :param path: The path to send the request.
575
+ :param data: Dictionary, list of tuples, bytes, or file-like object to send in the body of the request.
576
+ :param timeout: The timeout for this request.
577
+ """
578
+ sync_hook = await self.get_sync_hook()
579
+ credentials = sync_hook.get_credentials()
580
+
581
+ if not credentials.valid:
582
+ credentials.refresh(Request())
583
+
584
+ async with ClientSession() as session:
585
+ async with session.request(
586
+ method=method,
587
+ url=urljoin(airflow_uri, path),
588
+ data=data,
589
+ headers={
590
+ "Content-Type": "application/json",
591
+ "Authorization": f"Bearer {credentials.token}",
592
+ },
593
+ timeout=timeout,
594
+ ) as response:
595
+ return await response.json(), response.status
596
+
430
597
  def get_environment_name(self, project_id, region, environment_id):
431
598
  return f"projects/{project_id}/locations/{region}/environments/{environment_id}"
432
599
 
@@ -434,9 +601,8 @@ class CloudComposerAsyncHook(GoogleBaseHook):
434
601
  return f"projects/{project_id}/locations/{region}"
435
602
 
436
603
  async def get_operation(self, operation_name):
437
- return await self.get_environment_client().transport.operations_client.get_operation(
438
- name=operation_name
439
- )
604
+ client = await self.get_environment_client()
605
+ return await client.transport.operations_client.get_operation(name=operation_name)
440
606
 
441
607
  @GoogleBaseHook.fallback_to_default_project_id
442
608
  async def create_environment(
@@ -459,7 +625,7 @@ class CloudComposerAsyncHook(GoogleBaseHook):
459
625
  :param timeout: The timeout for this request.
460
626
  :param metadata: Strings which should be sent along with the request as metadata.
461
627
  """
462
- client = self.get_environment_client()
628
+ client = await self.get_environment_client()
463
629
  return await client.create_environment(
464
630
  request={"parent": self.get_parent(project_id, region), "environment": environment},
465
631
  retry=retry,
@@ -487,7 +653,7 @@ class CloudComposerAsyncHook(GoogleBaseHook):
487
653
  :param timeout: The timeout for this request.
488
654
  :param metadata: Strings which should be sent along with the request as metadata.
489
655
  """
490
- client = self.get_environment_client()
656
+ client = await self.get_environment_client()
491
657
  name = self.get_environment_name(project_id, region, environment_id)
492
658
  return await client.delete_environment(
493
659
  request={"name": name}, retry=retry, timeout=timeout, metadata=metadata
@@ -523,7 +689,7 @@ class CloudComposerAsyncHook(GoogleBaseHook):
523
689
  :param timeout: The timeout for this request.
524
690
  :param metadata: Strings which should be sent along with the request as metadata.
525
691
  """
526
- client = self.get_environment_client()
692
+ client = await self.get_environment_client()
527
693
  name = self.get_environment_name(project_id, region, environment_id)
528
694
 
529
695
  return await client.update_environment(
@@ -533,6 +699,35 @@ class CloudComposerAsyncHook(GoogleBaseHook):
533
699
  metadata=metadata,
534
700
  )
535
701
 
702
+ @GoogleBaseHook.fallback_to_default_project_id
703
+ async def get_environment(
704
+ self,
705
+ project_id: str,
706
+ region: str,
707
+ environment_id: str,
708
+ retry: AsyncRetry | _MethodDefault = DEFAULT,
709
+ timeout: float | None = None,
710
+ metadata: Sequence[tuple[str, str]] = (),
711
+ ) -> Environment:
712
+ """
713
+ Get an existing environment.
714
+
715
+ :param project_id: Required. The ID of the Google Cloud project that the service belongs to.
716
+ :param region: Required. The ID of the Google Cloud region that the service belongs to.
717
+ :param environment_id: Required. The ID of the Google Cloud environment that the service belongs to.
718
+ :param retry: Designation of what errors, if any, should be retried.
719
+ :param timeout: The timeout for this request.
720
+ :param metadata: Strings which should be sent along with the request as metadata.
721
+ """
722
+ client = await self.get_environment_client()
723
+
724
+ return await client.get_environment(
725
+ request={"name": self.get_environment_name(project_id, region, environment_id)},
726
+ retry=retry,
727
+ timeout=timeout,
728
+ metadata=metadata,
729
+ )
730
+
536
731
  @GoogleBaseHook.fallback_to_default_project_id
537
732
  async def execute_airflow_command(
538
733
  self,
@@ -561,7 +756,7 @@ class CloudComposerAsyncHook(GoogleBaseHook):
561
756
  :param timeout: The timeout for this request.
562
757
  :param metadata: Strings which should be sent along with the request as metadata.
563
758
  """
564
- client = self.get_environment_client()
759
+ client = await self.get_environment_client()
565
760
 
566
761
  return await client.execute_airflow_command(
567
762
  request={
@@ -603,7 +798,7 @@ class CloudComposerAsyncHook(GoogleBaseHook):
603
798
  :param timeout: The timeout for this request.
604
799
  :param metadata: Strings which should be sent along with the request as metadata.
605
800
  """
606
- client = self.get_environment_client()
801
+ client = await self.get_environment_client()
607
802
 
608
803
  return await client.poll_airflow_command(
609
804
  request={
@@ -647,9 +842,82 @@ class CloudComposerAsyncHook(GoogleBaseHook):
647
842
  self.log.exception("Exception occurred while polling CMD result")
648
843
  raise AirflowException(ex)
649
844
 
650
- result_dict = PollAirflowCommandResponse.to_dict(result)
845
+ try:
846
+ result_dict = PollAirflowCommandResponse.to_dict(result)
847
+ except Exception as ex:
848
+ self.log.exception("Exception occurred while transforming PollAirflowCommandResponse")
849
+ raise AirflowException(ex)
850
+
651
851
  if result_dict["output_end"]:
652
852
  return result_dict
653
853
 
654
854
  self.log.info("Sleeping for %s seconds.", poll_interval)
655
855
  await asyncio.sleep(poll_interval)
856
+
857
+ async def get_dag_runs(
858
+ self,
859
+ composer_airflow_uri: str,
860
+ composer_dag_id: str,
861
+ timeout: float | None = None,
862
+ ) -> dict:
863
+ """
864
+ Get the list of dag runs for provided DAG.
865
+
866
+ :param composer_airflow_uri: The URI of the Apache Airflow Web UI hosted within Composer environment.
867
+ :param composer_dag_id: The ID of DAG.
868
+ :param timeout: The timeout for this request.
869
+ """
870
+ response_body, response_status_code = await self.make_composer_airflow_api_request(
871
+ method="GET",
872
+ airflow_uri=composer_airflow_uri,
873
+ path=f"/api/v1/dags/{composer_dag_id}/dagRuns",
874
+ timeout=timeout,
875
+ )
876
+
877
+ if response_status_code != 200:
878
+ self.log.error(
879
+ "Failed to get DAG runs for dag_id=%s from %s (status=%s): %s",
880
+ composer_dag_id,
881
+ composer_airflow_uri,
882
+ response_status_code,
883
+ response_body["title"],
884
+ )
885
+ raise AirflowException(response_body["title"])
886
+
887
+ return response_body
888
+
889
+ async def get_task_instances(
890
+ self,
891
+ composer_airflow_uri: str,
892
+ composer_dag_id: str,
893
+ query_parameters: dict | None = None,
894
+ timeout: float | None = None,
895
+ ) -> dict:
896
+ """
897
+ Get the list of task instances for provided DAG.
898
+
899
+ :param composer_airflow_uri: The URI of the Apache Airflow Web UI hosted within Composer environment.
900
+ :param composer_dag_id: The ID of DAG.
901
+ :query_parameters: Query parameters for this request.
902
+ :param timeout: The timeout for this request.
903
+ """
904
+ query_string = f"?{urlencode(query_parameters)}" if query_parameters else ""
905
+
906
+ response_body, response_status_code = await self.make_composer_airflow_api_request(
907
+ method="GET",
908
+ airflow_uri=composer_airflow_uri,
909
+ path=f"/api/v1/dags/{composer_dag_id}/dagRuns/~/taskInstances{query_string}",
910
+ timeout=timeout,
911
+ )
912
+
913
+ if response_status_code != 200:
914
+ self.log.error(
915
+ "Failed to get task instances for dag_id=%s from %s (status=%s): %s",
916
+ composer_dag_id,
917
+ composer_airflow_uri,
918
+ response_status_code,
919
+ response_body["title"],
920
+ )
921
+ raise AirflowException(response_body["title"])
922
+
923
+ return response_body