apache-airflow-providers-google 10.7.0rc1__py3-none-any.whl → 10.8.0__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 +10 -6
- airflow/providers/google/cloud/_internal_client/secret_manager_client.py +4 -1
- airflow/providers/google/cloud/example_dags/example_cloud_sql_query.py +31 -34
- airflow/providers/google/cloud/hooks/automl.py +11 -9
- airflow/providers/google/cloud/hooks/bigquery.py +30 -36
- airflow/providers/google/cloud/hooks/bigquery_dts.py +5 -3
- airflow/providers/google/cloud/hooks/bigtable.py +11 -8
- airflow/providers/google/cloud/hooks/cloud_batch.py +5 -3
- airflow/providers/google/cloud/hooks/cloud_build.py +6 -4
- airflow/providers/google/cloud/hooks/cloud_composer.py +14 -10
- airflow/providers/google/cloud/hooks/cloud_memorystore.py +5 -3
- airflow/providers/google/cloud/hooks/cloud_run.py +5 -3
- airflow/providers/google/cloud/hooks/cloud_sql.py +11 -14
- airflow/providers/google/cloud/hooks/cloud_storage_transfer_service.py +8 -6
- airflow/providers/google/cloud/hooks/compute.py +5 -3
- airflow/providers/google/cloud/hooks/compute_ssh.py +1 -1
- airflow/providers/google/cloud/hooks/datacatalog.py +5 -3
- airflow/providers/google/cloud/hooks/dataflow.py +8 -11
- airflow/providers/google/cloud/hooks/dataform.py +4 -2
- airflow/providers/google/cloud/hooks/datafusion.py +24 -6
- airflow/providers/google/cloud/hooks/dataplex.py +75 -6
- airflow/providers/google/cloud/hooks/dataproc.py +9 -7
- airflow/providers/google/cloud/hooks/dataproc_metastore.py +8 -6
- airflow/providers/google/cloud/hooks/dlp.py +139 -137
- airflow/providers/google/cloud/hooks/gcs.py +15 -20
- airflow/providers/google/cloud/hooks/kms.py +4 -2
- airflow/providers/google/cloud/hooks/kubernetes_engine.py +34 -34
- airflow/providers/google/cloud/hooks/looker.py +4 -1
- airflow/providers/google/cloud/hooks/mlengine.py +8 -6
- airflow/providers/google/cloud/hooks/natural_language.py +4 -2
- airflow/providers/google/cloud/hooks/os_login.py +9 -7
- airflow/providers/google/cloud/hooks/pubsub.py +13 -11
- airflow/providers/google/cloud/hooks/spanner.py +7 -5
- airflow/providers/google/cloud/hooks/speech_to_text.py +4 -2
- airflow/providers/google/cloud/hooks/stackdriver.py +6 -5
- airflow/providers/google/cloud/hooks/tasks.py +5 -3
- airflow/providers/google/cloud/hooks/text_to_speech.py +4 -2
- airflow/providers/google/cloud/hooks/vertex_ai/auto_ml.py +7 -5
- airflow/providers/google/cloud/hooks/vertex_ai/batch_prediction_job.py +6 -4
- airflow/providers/google/cloud/hooks/vertex_ai/custom_job.py +11 -9
- airflow/providers/google/cloud/hooks/vertex_ai/dataset.py +12 -10
- airflow/providers/google/cloud/hooks/vertex_ai/endpoint_service.py +8 -6
- airflow/providers/google/cloud/hooks/vertex_ai/hyperparameter_tuning_job.py +6 -4
- airflow/providers/google/cloud/hooks/vertex_ai/model_service.py +7 -5
- airflow/providers/google/cloud/hooks/video_intelligence.py +5 -3
- airflow/providers/google/cloud/hooks/vision.py +5 -3
- airflow/providers/google/cloud/hooks/workflows.py +8 -6
- airflow/providers/google/cloud/links/bigquery.py +1 -1
- airflow/providers/google/cloud/links/bigquery_dts.py +1 -1
- airflow/providers/google/cloud/links/cloud_functions.py +1 -1
- airflow/providers/google/cloud/links/cloud_memorystore.py +1 -1
- airflow/providers/google/cloud/links/cloud_sql.py +1 -1
- airflow/providers/google/cloud/links/cloud_tasks.py +1 -1
- airflow/providers/google/cloud/links/compute.py +1 -1
- airflow/providers/google/cloud/links/datacatalog.py +1 -1
- airflow/providers/google/cloud/links/dataflow.py +1 -1
- airflow/providers/google/cloud/links/dataform.py +1 -1
- airflow/providers/google/cloud/links/pubsub.py +1 -1
- airflow/providers/google/cloud/links/spanner.py +1 -1
- airflow/providers/google/cloud/links/stackdriver.py +1 -1
- airflow/providers/google/cloud/links/workflows.py +2 -2
- airflow/providers/google/cloud/log/gcs_task_handler.py +5 -7
- airflow/providers/google/cloud/log/stackdriver_task_handler.py +8 -4
- airflow/providers/google/cloud/operators/automl.py +2 -1
- airflow/providers/google/cloud/operators/bigquery.py +6 -2
- airflow/providers/google/cloud/operators/bigquery_dts.py +2 -1
- airflow/providers/google/cloud/operators/bigtable.py +5 -3
- airflow/providers/google/cloud/operators/cloud_batch.py +6 -3
- airflow/providers/google/cloud/operators/cloud_build.py +2 -1
- airflow/providers/google/cloud/operators/cloud_composer.py +3 -2
- airflow/providers/google/cloud/operators/cloud_memorystore.py +3 -2
- airflow/providers/google/cloud/operators/cloud_run.py +3 -2
- airflow/providers/google/cloud/operators/cloud_sql.py +157 -152
- airflow/providers/google/cloud/operators/compute.py +59 -61
- airflow/providers/google/cloud/operators/datacatalog.py +3 -2
- airflow/providers/google/cloud/operators/dataflow.py +3 -1
- airflow/providers/google/cloud/operators/dataform.py +2 -1
- airflow/providers/google/cloud/operators/datafusion.py +1 -1
- airflow/providers/google/cloud/operators/dataplex.py +110 -8
- airflow/providers/google/cloud/operators/dataproc.py +39 -18
- airflow/providers/google/cloud/operators/dataproc_metastore.py +2 -1
- airflow/providers/google/cloud/operators/dlp.py +3 -2
- airflow/providers/google/cloud/operators/functions.py +46 -46
- airflow/providers/google/cloud/operators/gcs.py +4 -6
- airflow/providers/google/cloud/operators/kubernetes_engine.py +2 -1
- airflow/providers/google/cloud/operators/natural_language.py +3 -2
- airflow/providers/google/cloud/operators/pubsub.py +2 -1
- airflow/providers/google/cloud/operators/speech_to_text.py +3 -2
- airflow/providers/google/cloud/operators/stackdriver.py +2 -1
- airflow/providers/google/cloud/operators/tasks.py +3 -2
- airflow/providers/google/cloud/operators/text_to_speech.py +3 -2
- airflow/providers/google/cloud/operators/translate_speech.py +2 -1
- airflow/providers/google/cloud/operators/vertex_ai/auto_ml.py +2 -1
- airflow/providers/google/cloud/operators/vertex_ai/batch_prediction_job.py +3 -2
- airflow/providers/google/cloud/operators/vertex_ai/custom_job.py +2 -1
- airflow/providers/google/cloud/operators/vertex_ai/dataset.py +3 -2
- airflow/providers/google/cloud/operators/vertex_ai/endpoint_service.py +4 -4
- airflow/providers/google/cloud/operators/vertex_ai/hyperparameter_tuning_job.py +3 -2
- airflow/providers/google/cloud/operators/vertex_ai/model_service.py +2 -1
- airflow/providers/google/cloud/operators/video_intelligence.py +2 -1
- airflow/providers/google/cloud/operators/vision.py +3 -2
- airflow/providers/google/cloud/operators/workflows.py +7 -5
- airflow/providers/google/cloud/secrets/secret_manager.py +2 -2
- airflow/providers/google/cloud/sensors/bigquery_dts.py +2 -1
- airflow/providers/google/cloud/sensors/dataplex.py +2 -1
- airflow/providers/google/cloud/sensors/dataproc_metastore.py +2 -2
- airflow/providers/google/cloud/sensors/gcs.py +2 -1
- airflow/providers/google/cloud/sensors/workflows.py +2 -1
- airflow/providers/google/cloud/transfers/azure_fileshare_to_gcs.py +24 -10
- airflow/providers/google/cloud/transfers/bigquery_to_gcs.py +2 -1
- airflow/providers/google/cloud/transfers/bigquery_to_mssql.py +2 -1
- airflow/providers/google/cloud/transfers/bigquery_to_mysql.py +1 -4
- airflow/providers/google/cloud/transfers/bigquery_to_postgres.py +1 -4
- airflow/providers/google/cloud/transfers/bigquery_to_sql.py +1 -1
- airflow/providers/google/cloud/transfers/calendar_to_gcs.py +4 -2
- airflow/providers/google/cloud/transfers/cassandra_to_gcs.py +1 -3
- airflow/providers/google/cloud/transfers/facebook_ads_to_gcs.py +2 -2
- airflow/providers/google/cloud/transfers/gcs_to_bigquery.py +2 -1
- airflow/providers/google/cloud/transfers/presto_to_gcs.py +5 -4
- airflow/providers/google/cloud/transfers/sql_to_gcs.py +1 -1
- airflow/providers/google/cloud/transfers/trino_to_gcs.py +5 -4
- airflow/providers/google/cloud/triggers/bigquery.py +30 -36
- airflow/providers/google/cloud/triggers/bigquery_dts.py +9 -10
- airflow/providers/google/cloud/triggers/cloud_batch.py +6 -8
- airflow/providers/google/cloud/triggers/cloud_build.py +5 -6
- airflow/providers/google/cloud/triggers/cloud_run.py +4 -3
- airflow/providers/google/cloud/triggers/cloud_sql.py +10 -10
- airflow/providers/google/cloud/triggers/cloud_storage_transfer_service.py +1 -1
- airflow/providers/google/cloud/triggers/dataflow.py +5 -6
- airflow/providers/google/cloud/triggers/datafusion.py +5 -6
- airflow/providers/google/cloud/triggers/dataplex.py +110 -0
- airflow/providers/google/cloud/triggers/dataproc.py +18 -20
- airflow/providers/google/cloud/triggers/kubernetes_engine.py +14 -13
- airflow/providers/google/cloud/triggers/mlengine.py +5 -5
- airflow/providers/google/cloud/triggers/pubsub.py +2 -2
- airflow/providers/google/cloud/utils/bigquery_get_data.py +6 -3
- airflow/providers/google/cloud/utils/credentials_provider.py +1 -1
- airflow/providers/google/cloud/utils/field_validator.py +13 -13
- airflow/providers/google/cloud/utils/mlengine_operator_utils.py +5 -3
- airflow/providers/google/cloud/utils/mlengine_prediction_summary.py +1 -1
- airflow/providers/google/common/hooks/base_google.py +10 -2
- airflow/providers/google/common/links/storage.py +1 -1
- airflow/providers/google/common/utils/id_token_credentials.py +4 -1
- airflow/providers/google/get_provider_info.py +5 -0
- airflow/providers/google/marketing_platform/hooks/campaign_manager.py +4 -2
- airflow/providers/google/marketing_platform/sensors/display_video.py +6 -3
- airflow/providers/google/suite/hooks/calendar.py +4 -2
- {apache_airflow_providers_google-10.7.0rc1.dist-info → apache_airflow_providers_google-10.8.0.dist-info}/METADATA +8 -8
- {apache_airflow_providers_google-10.7.0rc1.dist-info → apache_airflow_providers_google-10.8.0.dist-info}/RECORD +155 -173
- {apache_airflow_providers_google-10.7.0rc1.dist-info → apache_airflow_providers_google-10.8.0.dist-info}/WHEEL +1 -1
- airflow/providers/google/ads/_vendor/__init__.py +0 -16
- airflow/providers/google/ads/_vendor/googleads/__init__.py +0 -16
- airflow/providers/google/ads/_vendor/googleads/interceptors/__init__.py +0 -16
- airflow/providers/google/ads/_vendor/googleads/v12/__init__.py +0 -16
- airflow/providers/google/ads/_vendor/googleads/v12/common/__init__.py +0 -16
- airflow/providers/google/ads/_vendor/googleads/v12/common/types/__init__.py +0 -16
- airflow/providers/google/ads/_vendor/googleads/v12/enums/__init__.py +0 -16
- airflow/providers/google/ads/_vendor/googleads/v12/enums/types/__init__.py +0 -16
- airflow/providers/google/ads/_vendor/googleads/v12/errors/__init__.py +0 -16
- airflow/providers/google/ads/_vendor/googleads/v12/errors/types/__init__.py +0 -16
- airflow/providers/google/ads/_vendor/googleads/v12/resources/__init__.py +0 -16
- airflow/providers/google/ads/_vendor/googleads/v12/resources/types/__init__.py +0 -16
- airflow/providers/google/ads/_vendor/googleads/v12/services/__init__.py +0 -16
- airflow/providers/google/ads/_vendor/googleads/v12/services/services/__init__.py +0 -16
- airflow/providers/google/ads/_vendor/googleads/v12/services/services/customer_service/__init__.py +0 -16
- airflow/providers/google/ads/_vendor/googleads/v12/services/services/customer_service/transports/__init__.py +0 -16
- airflow/providers/google/ads/_vendor/googleads/v12/services/services/google_ads_service/__init__.py +0 -16
- airflow/providers/google/ads/_vendor/googleads/v12/services/services/google_ads_service/transports/__init__.py +0 -16
- airflow/providers/google/ads/_vendor/googleads/v12/services/types/__init__.py +0 -16
- {apache_airflow_providers_google-10.7.0rc1.dist-info → apache_airflow_providers_google-10.8.0.dist-info}/LICENSE +0 -0
- {apache_airflow_providers_google-10.7.0rc1.dist-info → apache_airflow_providers_google-10.8.0.dist-info}/NOTICE +0 -0
- {apache_airflow_providers_google-10.7.0rc1.dist-info → apache_airflow_providers_google-10.8.0.dist-info}/entry_points.txt +0 -0
- {apache_airflow_providers_google-10.7.0rc1.dist-info → apache_airflow_providers_google-10.8.0.dist-info}/top_level.txt +0 -0
@@ -75,8 +75,8 @@ class BigQueryInsertJobTrigger(BaseTrigger):
|
|
75
75
|
"""Gets current job execution status and yields a TriggerEvent."""
|
76
76
|
"""Gets current job execution status and yields a TriggerEvent."""
|
77
77
|
hook = self._get_async_hook()
|
78
|
-
|
79
|
-
|
78
|
+
try:
|
79
|
+
while True:
|
80
80
|
job_status = await hook.get_job_status(job_id=self.job_id, project_id=self.project_id)
|
81
81
|
if job_status == "success":
|
82
82
|
yield TriggerEvent(
|
@@ -95,10 +95,9 @@ class BigQueryInsertJobTrigger(BaseTrigger):
|
|
95
95
|
"Bigquery job status is %s. Sleeping for %s seconds.", job_status, self.poll_interval
|
96
96
|
)
|
97
97
|
await asyncio.sleep(self.poll_interval)
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
return
|
98
|
+
except Exception as e:
|
99
|
+
self.log.exception("Exception occurred while checking for query completion")
|
100
|
+
yield TriggerEvent({"status": "error", "message": str(e)})
|
102
101
|
|
103
102
|
def _get_async_hook(self) -> BigQueryAsyncHook:
|
104
103
|
return BigQueryAsyncHook(gcp_conn_id=self.conn_id)
|
@@ -124,8 +123,8 @@ class BigQueryCheckTrigger(BigQueryInsertJobTrigger):
|
|
124
123
|
async def run(self) -> AsyncIterator[TriggerEvent]: # type: ignore[override]
|
125
124
|
"""Gets current job execution status and yields a TriggerEvent."""
|
126
125
|
hook = self._get_async_hook()
|
127
|
-
|
128
|
-
|
126
|
+
try:
|
127
|
+
while True:
|
129
128
|
# Poll for job execution status
|
130
129
|
job_status = await hook.get_job_status(job_id=self.job_id, project_id=self.project_id)
|
131
130
|
if job_status == "success":
|
@@ -160,10 +159,9 @@ class BigQueryCheckTrigger(BigQueryInsertJobTrigger):
|
|
160
159
|
"Bigquery job status is %s. Sleeping for %s seconds.", job_status, self.poll_interval
|
161
160
|
)
|
162
161
|
await asyncio.sleep(self.poll_interval)
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
return
|
162
|
+
except Exception as e:
|
163
|
+
self.log.exception("Exception occurred while checking for query completion")
|
164
|
+
yield TriggerEvent({"status": "error", "message": str(e)})
|
167
165
|
|
168
166
|
|
169
167
|
class BigQueryGetDataTrigger(BigQueryInsertJobTrigger):
|
@@ -196,8 +194,8 @@ class BigQueryGetDataTrigger(BigQueryInsertJobTrigger):
|
|
196
194
|
async def run(self) -> AsyncIterator[TriggerEvent]: # type: ignore[override]
|
197
195
|
"""Gets current job execution status and yields a TriggerEvent with response data."""
|
198
196
|
hook = self._get_async_hook()
|
199
|
-
|
200
|
-
|
197
|
+
try:
|
198
|
+
while True:
|
201
199
|
# Poll for job execution status
|
202
200
|
job_status = await hook.get_job_status(job_id=self.job_id, project_id=self.project_id)
|
203
201
|
if job_status == "success":
|
@@ -220,10 +218,9 @@ class BigQueryGetDataTrigger(BigQueryInsertJobTrigger):
|
|
220
218
|
"Bigquery job status is %s. Sleeping for %s seconds.", job_status, self.poll_interval
|
221
219
|
)
|
222
220
|
await asyncio.sleep(self.poll_interval)
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
return
|
221
|
+
except Exception as e:
|
222
|
+
self.log.exception("Exception occurred while checking for query completion")
|
223
|
+
yield TriggerEvent({"status": "error", "message": str(e)})
|
227
224
|
|
228
225
|
|
229
226
|
class BigQueryIntervalCheckTrigger(BigQueryInsertJobTrigger):
|
@@ -302,8 +299,8 @@ class BigQueryIntervalCheckTrigger(BigQueryInsertJobTrigger):
|
|
302
299
|
async def run(self) -> AsyncIterator[TriggerEvent]: # type: ignore[override]
|
303
300
|
"""Gets current job execution status and yields a TriggerEvent."""
|
304
301
|
hook = self._get_async_hook()
|
305
|
-
|
306
|
-
|
302
|
+
try:
|
303
|
+
while True:
|
307
304
|
first_job_response_from_hook = await hook.get_job_status(
|
308
305
|
job_id=self.first_job_id, project_id=self.project_id
|
309
306
|
)
|
@@ -365,10 +362,9 @@ class BigQueryIntervalCheckTrigger(BigQueryInsertJobTrigger):
|
|
365
362
|
)
|
366
363
|
return
|
367
364
|
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
return
|
365
|
+
except Exception as e:
|
366
|
+
self.log.exception("Exception occurred while checking for query completion")
|
367
|
+
yield TriggerEvent({"status": "error", "message": str(e)})
|
372
368
|
|
373
369
|
|
374
370
|
class BigQueryValueCheckTrigger(BigQueryInsertJobTrigger):
|
@@ -430,8 +426,8 @@ class BigQueryValueCheckTrigger(BigQueryInsertJobTrigger):
|
|
430
426
|
async def run(self) -> AsyncIterator[TriggerEvent]: # type: ignore[override]
|
431
427
|
"""Gets current job execution status and yields a TriggerEvent."""
|
432
428
|
hook = self._get_async_hook()
|
433
|
-
|
434
|
-
|
429
|
+
try:
|
430
|
+
while True:
|
435
431
|
# Poll for job execution status
|
436
432
|
response_from_hook = await hook.get_job_status(job_id=self.job_id, project_id=self.project_id)
|
437
433
|
if response_from_hook == "success":
|
@@ -448,10 +444,9 @@ class BigQueryValueCheckTrigger(BigQueryInsertJobTrigger):
|
|
448
444
|
else:
|
449
445
|
yield TriggerEvent({"status": "error", "message": response_from_hook, "records": None})
|
450
446
|
return
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
return
|
447
|
+
except Exception as e:
|
448
|
+
self.log.exception("Exception occurred while checking for query completion")
|
449
|
+
yield TriggerEvent({"status": "error", "message": str(e)})
|
455
450
|
|
456
451
|
|
457
452
|
class BigQueryTableExistenceTrigger(BaseTrigger):
|
@@ -501,8 +496,8 @@ class BigQueryTableExistenceTrigger(BaseTrigger):
|
|
501
496
|
|
502
497
|
async def run(self) -> AsyncIterator[TriggerEvent]: # type: ignore[override]
|
503
498
|
"""Will run until the table exists in the Google Big Query."""
|
504
|
-
|
505
|
-
|
499
|
+
try:
|
500
|
+
while True:
|
506
501
|
hook = self._get_async_hook()
|
507
502
|
response = await self._table_exists(
|
508
503
|
hook=hook, dataset=self.dataset_id, table_id=self.table_id, project_id=self.project_id
|
@@ -511,10 +506,9 @@ class BigQueryTableExistenceTrigger(BaseTrigger):
|
|
511
506
|
yield TriggerEvent({"status": "success", "message": "success"})
|
512
507
|
return
|
513
508
|
await asyncio.sleep(self.poll_interval)
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
return
|
509
|
+
except Exception as e:
|
510
|
+
self.log.exception("Exception occurred while checking for Table existence")
|
511
|
+
yield TriggerEvent({"status": "error", "message": str(e)})
|
518
512
|
|
519
513
|
async def _table_exists(
|
520
514
|
self, hook: BigQueryTableAsyncHook, dataset: str, table_id: str, project_id: str
|
@@ -83,8 +83,8 @@ class BigQueryDataTransferRunTrigger(BaseTrigger):
|
|
83
83
|
async def run(self) -> AsyncIterator[TriggerEvent]:
|
84
84
|
"""If the Transfer Run is in a terminal state, then yield TriggerEvent object."""
|
85
85
|
hook = self._get_async_hook()
|
86
|
-
|
87
|
-
|
86
|
+
try:
|
87
|
+
while True:
|
88
88
|
transfer_run: TransferRun = await hook.get_transfer_run(
|
89
89
|
project_id=self.project_id,
|
90
90
|
config_id=self.config_id,
|
@@ -129,14 +129,13 @@ class BigQueryDataTransferRunTrigger(BaseTrigger):
|
|
129
129
|
self.log.info("Job is still working...")
|
130
130
|
self.log.info("Waiting for %s seconds", self.poll_interval)
|
131
131
|
await asyncio.sleep(self.poll_interval)
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
return
|
132
|
+
except Exception as e:
|
133
|
+
yield TriggerEvent(
|
134
|
+
{
|
135
|
+
"status": "failed",
|
136
|
+
"message": f"Trigger failed with exception: {e}",
|
137
|
+
}
|
138
|
+
)
|
140
139
|
|
141
140
|
def _get_async_hook(self) -> AsyncBiqQueryDataTransferServiceHook:
|
142
141
|
return AsyncBiqQueryDataTransferServiceHook(
|
@@ -92,9 +92,8 @@ class CloudBatchJobFinishedTrigger(BaseTrigger):
|
|
92
92
|
"""
|
93
93
|
timeout = self.timeout
|
94
94
|
hook = self._get_async_hook()
|
95
|
-
|
96
|
-
|
97
|
-
try:
|
95
|
+
try:
|
96
|
+
while timeout is None or timeout > 0:
|
98
97
|
job: Job = await hook.get_batch_job(job_name=self.job_name)
|
99
98
|
|
100
99
|
status: JobStatus.State = job.status.state
|
@@ -134,10 +133,10 @@ class CloudBatchJobFinishedTrigger(BaseTrigger):
|
|
134
133
|
if timeout is None or timeout > 0:
|
135
134
|
await asyncio.sleep(self.polling_period_seconds)
|
136
135
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
136
|
+
except Exception as e:
|
137
|
+
self.log.exception("Exception occurred while checking for job completion.")
|
138
|
+
yield TriggerEvent({"status": "error", "message": str(e)})
|
139
|
+
return
|
141
140
|
|
142
141
|
self.log.exception(f"Job with name [{self.job_name}] timed out")
|
143
142
|
yield TriggerEvent(
|
@@ -147,7 +146,6 @@ class CloudBatchJobFinishedTrigger(BaseTrigger):
|
|
147
146
|
"message": f"Batch job with name {self.job_name} timed out",
|
148
147
|
}
|
149
148
|
)
|
150
|
-
return
|
151
149
|
|
152
150
|
def _get_async_hook(self) -> CloudBatchAsyncHook:
|
153
151
|
return CloudBatchAsyncHook(
|
@@ -78,8 +78,8 @@ class CloudBuildCreateBuildTrigger(BaseTrigger):
|
|
78
78
|
async def run(self) -> AsyncIterator[TriggerEvent]: # type: ignore[override]
|
79
79
|
"""Gets current build execution status and yields a TriggerEvent."""
|
80
80
|
hook = self._get_async_hook()
|
81
|
-
|
82
|
-
|
81
|
+
try:
|
82
|
+
while True:
|
83
83
|
# Poll for job execution status
|
84
84
|
cloud_build_instance = await hook.get_cloud_build(
|
85
85
|
id_=self.id_,
|
@@ -119,10 +119,9 @@ class CloudBuildCreateBuildTrigger(BaseTrigger):
|
|
119
119
|
)
|
120
120
|
return
|
121
121
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
return
|
122
|
+
except Exception as e:
|
123
|
+
self.log.exception("Exception occurred while checking for Cloud Build completion")
|
124
|
+
yield TriggerEvent({"status": "error", "message": str(e)})
|
126
125
|
|
127
126
|
def _get_async_hook(self) -> CloudBuildAsyncHook:
|
128
127
|
return CloudBuildAsyncHook(gcp_conn_id=self.gcp_conn_id)
|
@@ -18,14 +18,15 @@ from __future__ import annotations
|
|
18
18
|
|
19
19
|
import asyncio
|
20
20
|
from enum import Enum
|
21
|
-
from typing import Any, AsyncIterator, Sequence
|
22
|
-
|
23
|
-
from google.longrunning import operations_pb2
|
21
|
+
from typing import TYPE_CHECKING, Any, AsyncIterator, Sequence
|
24
22
|
|
25
23
|
from airflow.exceptions import AirflowException
|
26
24
|
from airflow.providers.google.cloud.hooks.cloud_run import CloudRunAsyncHook
|
27
25
|
from airflow.triggers.base import BaseTrigger, TriggerEvent
|
28
26
|
|
27
|
+
if TYPE_CHECKING:
|
28
|
+
from google.longrunning import operations_pb2
|
29
|
+
|
29
30
|
DEFAULT_BATCH_LOCATION = "us-central1"
|
30
31
|
|
31
32
|
|
@@ -64,8 +64,8 @@ class CloudSQLExportTrigger(BaseTrigger):
|
|
64
64
|
)
|
65
65
|
|
66
66
|
async def run(self):
|
67
|
-
|
68
|
-
|
67
|
+
try:
|
68
|
+
while True:
|
69
69
|
operation = await self.hook.get_operation(
|
70
70
|
project_id=self.project_id, operation_name=self.operation_name
|
71
71
|
)
|
@@ -93,11 +93,11 @@ class CloudSQLExportTrigger(BaseTrigger):
|
|
93
93
|
self.poke_interval,
|
94
94
|
)
|
95
95
|
await asyncio.sleep(self.poke_interval)
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
96
|
+
except Exception as e:
|
97
|
+
self.log.exception("Exception occurred while checking operation status.")
|
98
|
+
yield TriggerEvent(
|
99
|
+
{
|
100
|
+
"status": "failed",
|
101
|
+
"message": str(e),
|
102
|
+
}
|
103
|
+
)
|
@@ -97,7 +97,7 @@ class CloudStorageTransferServiceCreateJobsTrigger(BaseTrigger):
|
|
97
97
|
)
|
98
98
|
return
|
99
99
|
except (GoogleAPIError, AirflowException) as ex:
|
100
|
-
yield TriggerEvent(
|
100
|
+
yield TriggerEvent({"status": "error", "message": str(ex)})
|
101
101
|
return
|
102
102
|
|
103
103
|
jobs_total = len(self.job_names)
|
@@ -92,8 +92,8 @@ class TemplateJobStartTrigger(BaseTrigger):
|
|
92
92
|
amount of time stored in self.poll_sleep variable.
|
93
93
|
"""
|
94
94
|
hook = self._get_async_hook()
|
95
|
-
|
96
|
-
|
95
|
+
try:
|
96
|
+
while True:
|
97
97
|
status = await hook.get_job_status(
|
98
98
|
project_id=self.project_id,
|
99
99
|
job_id=self.job_id,
|
@@ -129,10 +129,9 @@ class TemplateJobStartTrigger(BaseTrigger):
|
|
129
129
|
self.log.info("Current job status is: %s", status)
|
130
130
|
self.log.info("Sleeping for %s seconds.", self.poll_sleep)
|
131
131
|
await asyncio.sleep(self.poll_sleep)
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
return
|
132
|
+
except Exception as e:
|
133
|
+
self.log.exception("Exception occurred while checking for job completion.")
|
134
|
+
yield TriggerEvent({"status": "error", "message": str(e)})
|
136
135
|
|
137
136
|
def _get_async_hook(self) -> AsyncDataflowHook:
|
138
137
|
return AsyncDataflowHook(
|
@@ -83,8 +83,8 @@ class DataFusionStartPipelineTrigger(BaseTrigger):
|
|
83
83
|
async def run(self) -> AsyncIterator[TriggerEvent]: # type: ignore[override]
|
84
84
|
"""Gets current pipeline status and yields a TriggerEvent."""
|
85
85
|
hook = self._get_async_hook()
|
86
|
-
|
87
|
-
|
86
|
+
try:
|
87
|
+
while True:
|
88
88
|
# Poll for job execution status
|
89
89
|
response_from_hook = await hook.get_pipeline_status(
|
90
90
|
success_states=self.success_states,
|
@@ -109,10 +109,9 @@ class DataFusionStartPipelineTrigger(BaseTrigger):
|
|
109
109
|
else:
|
110
110
|
yield TriggerEvent({"status": "error", "message": response_from_hook})
|
111
111
|
return
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
return
|
112
|
+
except Exception as e:
|
113
|
+
self.log.exception("Exception occurred while checking for pipeline state")
|
114
|
+
yield TriggerEvent({"status": "error", "message": str(e)})
|
116
115
|
|
117
116
|
def _get_async_hook(self) -> DataFusionAsyncHook:
|
118
117
|
return DataFusionAsyncHook(
|
@@ -0,0 +1,110 @@
|
|
1
|
+
#
|
2
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
3
|
+
# or more contributor license agreements. See the NOTICE file
|
4
|
+
# distributed with this work for additional information
|
5
|
+
# regarding copyright ownership. The ASF licenses this file
|
6
|
+
# to you under the Apache License, Version 2.0 (the
|
7
|
+
# "License"); you may not use this file except in compliance
|
8
|
+
# with the License. You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing,
|
13
|
+
# software distributed under the License is distributed on an
|
14
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15
|
+
# KIND, either express or implied. See the License for the
|
16
|
+
# specific language governing permissions and limitations
|
17
|
+
# under the License.
|
18
|
+
"""This module contains Google Dataplex triggers."""
|
19
|
+
from __future__ import annotations
|
20
|
+
|
21
|
+
import asyncio
|
22
|
+
from typing import AsyncIterator, Sequence
|
23
|
+
|
24
|
+
from google.cloud.dataplex_v1.types import DataScanJob
|
25
|
+
|
26
|
+
from airflow.providers.google.cloud.hooks.dataplex import DataplexAsyncHook
|
27
|
+
from airflow.triggers.base import BaseTrigger, TriggerEvent
|
28
|
+
|
29
|
+
|
30
|
+
class DataplexDataQualityJobTrigger(BaseTrigger):
|
31
|
+
"""
|
32
|
+
DataplexDataQualityJobTrigger runs on the trigger worker and waits for the job to be `SUCCEEDED` state.
|
33
|
+
|
34
|
+
:param job_id: Optional. The ID of a Dataplex job.
|
35
|
+
:param data_scan_id: Required. DataScan identifier.
|
36
|
+
:param project_id: Google Cloud Project where the job is running.
|
37
|
+
:param region: The ID of the Google Cloud region that the job belongs to.
|
38
|
+
:param gcp_conn_id: Optional, the connection ID used to connect to Google Cloud Platform.
|
39
|
+
:param impersonation_chain: Optional service account to impersonate using short-term
|
40
|
+
credentials, or chained list of accounts required to get the access_token
|
41
|
+
of the last account in the list, which will be impersonated in the request.
|
42
|
+
If set as a string, the account must grant the originating account
|
43
|
+
the Service Account Token Creator IAM role.
|
44
|
+
If set as a sequence, the identities from the list must grant
|
45
|
+
Service Account Token Creator IAM role to the directly preceding identity, with first
|
46
|
+
account from the list granting this role to the originating account (templated).
|
47
|
+
:param polling_interval_seconds: polling period in seconds to check for the status.
|
48
|
+
"""
|
49
|
+
|
50
|
+
def __init__(
|
51
|
+
self,
|
52
|
+
job_id: str | None,
|
53
|
+
data_scan_id: str,
|
54
|
+
project_id: str | None,
|
55
|
+
region: str,
|
56
|
+
gcp_conn_id: str = "google_cloud_default",
|
57
|
+
polling_interval_seconds: int = 10,
|
58
|
+
impersonation_chain: str | Sequence[str] | None = None,
|
59
|
+
**kwargs,
|
60
|
+
):
|
61
|
+
|
62
|
+
super().__init__(**kwargs)
|
63
|
+
self.job_id = job_id
|
64
|
+
self.data_scan_id = data_scan_id
|
65
|
+
self.project_id = project_id
|
66
|
+
self.region = region
|
67
|
+
self.gcp_conn_id = gcp_conn_id
|
68
|
+
self.polling_interval_seconds = polling_interval_seconds
|
69
|
+
self.impersonation_chain = impersonation_chain
|
70
|
+
|
71
|
+
def serialize(self):
|
72
|
+
return (
|
73
|
+
"airflow.providers.google.cloud.triggers.dataplex.DataplexDataQualityJobTrigger",
|
74
|
+
{
|
75
|
+
"job_id": self.job_id,
|
76
|
+
"data_scan_id": self.data_scan_id,
|
77
|
+
"project_id": self.project_id,
|
78
|
+
"region": self.region,
|
79
|
+
"gcp_conn_id": self.gcp_conn_id,
|
80
|
+
"impersonation_chain": self.impersonation_chain,
|
81
|
+
"polling_interval_seconds": self.polling_interval_seconds,
|
82
|
+
},
|
83
|
+
)
|
84
|
+
|
85
|
+
async def run(self) -> AsyncIterator[TriggerEvent]:
|
86
|
+
hook = DataplexAsyncHook(
|
87
|
+
gcp_conn_id=self.gcp_conn_id,
|
88
|
+
impersonation_chain=self.impersonation_chain,
|
89
|
+
)
|
90
|
+
while True:
|
91
|
+
job = await hook.get_data_scan_job(
|
92
|
+
project_id=self.project_id,
|
93
|
+
region=self.region,
|
94
|
+
job_id=self.job_id,
|
95
|
+
data_scan_id=self.data_scan_id,
|
96
|
+
)
|
97
|
+
state = job.state
|
98
|
+
if state in (DataScanJob.State.FAILED, DataScanJob.State.SUCCEEDED, DataScanJob.State.CANCELLED):
|
99
|
+
break
|
100
|
+
self.log.info(
|
101
|
+
"Current state is: %s, sleeping for %s seconds.",
|
102
|
+
DataScanJob.State(state).name,
|
103
|
+
self.polling_interval_seconds,
|
104
|
+
)
|
105
|
+
await asyncio.sleep(self.polling_interval_seconds)
|
106
|
+
yield TriggerEvent({"job_id": self.job_id, "job_state": state, "job": self._convert_to_dict(job)})
|
107
|
+
|
108
|
+
def _convert_to_dict(self, job: DataScanJob) -> dict:
|
109
|
+
"""Returns a representation of a DataScanJob instance as a dict."""
|
110
|
+
return DataScanJob.to_dict(job)
|
@@ -263,8 +263,8 @@ class DataprocDeleteClusterTrigger(DataprocBaseTrigger):
|
|
263
263
|
|
264
264
|
async def run(self) -> AsyncIterator[TriggerEvent]:
|
265
265
|
"""Wait until cluster is deleted completely."""
|
266
|
-
|
267
|
-
|
266
|
+
try:
|
267
|
+
while self.end_time > time.time():
|
268
268
|
cluster = await self.get_async_hook().get_cluster(
|
269
269
|
region=self.region, # type: ignore[arg-type]
|
270
270
|
cluster_name=self.cluster_name,
|
@@ -277,13 +277,12 @@ class DataprocDeleteClusterTrigger(DataprocBaseTrigger):
|
|
277
277
|
self.polling_interval_seconds,
|
278
278
|
)
|
279
279
|
await asyncio.sleep(self.polling_interval_seconds)
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
yield TriggerEvent({"status": "error", "message": "Timeout"})
|
280
|
+
except NotFound:
|
281
|
+
yield TriggerEvent({"status": "success", "message": ""})
|
282
|
+
except Exception as e:
|
283
|
+
yield TriggerEvent({"status": "error", "message": str(e)})
|
284
|
+
else:
|
285
|
+
yield TriggerEvent({"status": "error", "message": "Timeout"})
|
287
286
|
|
288
287
|
|
289
288
|
class DataprocWorkflowTrigger(DataprocBaseTrigger):
|
@@ -312,8 +311,8 @@ class DataprocWorkflowTrigger(DataprocBaseTrigger):
|
|
312
311
|
|
313
312
|
async def run(self) -> AsyncIterator[TriggerEvent]:
|
314
313
|
hook = self.get_async_hook()
|
315
|
-
|
316
|
-
|
314
|
+
try:
|
315
|
+
while True:
|
317
316
|
operation = await hook.get_operation(region=self.region, operation_name=self.name)
|
318
317
|
if operation.done:
|
319
318
|
if operation.error.message:
|
@@ -338,12 +337,11 @@ class DataprocWorkflowTrigger(DataprocBaseTrigger):
|
|
338
337
|
else:
|
339
338
|
self.log.info("Sleeping for %s seconds.", self.polling_interval_seconds)
|
340
339
|
await asyncio.sleep(self.polling_interval_seconds)
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
return
|
340
|
+
except Exception as e:
|
341
|
+
self.log.exception("Exception occurred while checking operation status.")
|
342
|
+
yield TriggerEvent(
|
343
|
+
{
|
344
|
+
"status": "failed",
|
345
|
+
"message": str(e),
|
346
|
+
}
|
347
|
+
)
|
@@ -19,8 +19,7 @@ from __future__ import annotations
|
|
19
19
|
|
20
20
|
import asyncio
|
21
21
|
import warnings
|
22
|
-
from
|
23
|
-
from typing import Any, AsyncIterator, Sequence
|
22
|
+
from typing import TYPE_CHECKING, Any, AsyncIterator, Sequence
|
24
23
|
|
25
24
|
from google.cloud.container_v1.types import Operation
|
26
25
|
|
@@ -35,6 +34,9 @@ except ImportError:
|
|
35
34
|
from airflow.providers.google.cloud.hooks.kubernetes_engine import GKEAsyncHook, GKEPodAsyncHook
|
36
35
|
from airflow.triggers.base import BaseTrigger, TriggerEvent
|
37
36
|
|
37
|
+
if TYPE_CHECKING:
|
38
|
+
from datetime import datetime
|
39
|
+
|
38
40
|
|
39
41
|
class GKEStartPodTrigger(KubernetesPodTrigger):
|
40
42
|
"""
|
@@ -182,8 +184,8 @@ class GKEOperationTrigger(BaseTrigger):
|
|
182
184
|
async def run(self) -> AsyncIterator[TriggerEvent]: # type: ignore[override]
|
183
185
|
"""Gets operation status and yields corresponding event."""
|
184
186
|
hook = self._get_hook()
|
185
|
-
|
186
|
-
|
187
|
+
try:
|
188
|
+
while True:
|
187
189
|
operation = await hook.get_operation(
|
188
190
|
operation_name=self.operation_name,
|
189
191
|
project_id=self.project_id,
|
@@ -212,15 +214,14 @@ class GKEOperationTrigger(BaseTrigger):
|
|
212
214
|
}
|
213
215
|
)
|
214
216
|
return
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
return
|
217
|
+
except Exception as e:
|
218
|
+
self.log.exception("Exception occurred while checking operation status")
|
219
|
+
yield TriggerEvent(
|
220
|
+
{
|
221
|
+
"status": "error",
|
222
|
+
"message": str(e),
|
223
|
+
}
|
224
|
+
)
|
224
225
|
|
225
226
|
def _get_hook(self) -> GKEAsyncHook:
|
226
227
|
if self._hook is None:
|
@@ -91,8 +91,8 @@ class MLEngineStartTrainingJobTrigger(BaseTrigger):
|
|
91
91
|
async def run(self) -> AsyncIterator[TriggerEvent]: # type: ignore[override]
|
92
92
|
"""Gets current job execution status and yields a TriggerEvent."""
|
93
93
|
hook = self._get_async_hook()
|
94
|
-
|
95
|
-
|
94
|
+
try:
|
95
|
+
while True:
|
96
96
|
# Poll for job execution status
|
97
97
|
response_from_hook = await hook.get_job_status(job_id=self.job_id, project_id=self.project_id)
|
98
98
|
if response_from_hook == "success":
|
@@ -110,9 +110,9 @@ class MLEngineStartTrainingJobTrigger(BaseTrigger):
|
|
110
110
|
else:
|
111
111
|
yield TriggerEvent({"status": "error", "message": response_from_hook})
|
112
112
|
|
113
|
-
|
114
|
-
|
115
|
-
|
113
|
+
except Exception as e:
|
114
|
+
self.log.exception("Exception occurred while checking for query completion")
|
115
|
+
yield TriggerEvent({"status": "error", "message": str(e)})
|
116
116
|
|
117
117
|
def _get_async_hook(self) -> MLEngineAsyncHook:
|
118
118
|
return MLEngineAsyncHook(
|
@@ -20,12 +20,12 @@ from __future__ import annotations
|
|
20
20
|
import asyncio
|
21
21
|
from typing import TYPE_CHECKING, Any, AsyncIterator, Callable, Sequence
|
22
22
|
|
23
|
-
from google.cloud.pubsub_v1.types import ReceivedMessage
|
24
|
-
|
25
23
|
from airflow.providers.google.cloud.hooks.pubsub import PubSubAsyncHook
|
26
24
|
from airflow.triggers.base import BaseTrigger, TriggerEvent
|
27
25
|
|
28
26
|
if TYPE_CHECKING:
|
27
|
+
from google.cloud.pubsub_v1.types import ReceivedMessage
|
28
|
+
|
29
29
|
from airflow.utils.context import Context
|
30
30
|
|
31
31
|
|
@@ -16,12 +16,15 @@
|
|
16
16
|
# under the License.
|
17
17
|
from __future__ import annotations
|
18
18
|
|
19
|
-
from
|
20
|
-
from logging import Logger
|
19
|
+
from typing import TYPE_CHECKING
|
21
20
|
|
22
21
|
from google.cloud.bigquery.table import Row, RowIterator
|
23
22
|
|
24
|
-
|
23
|
+
if TYPE_CHECKING:
|
24
|
+
from collections.abc import Iterator
|
25
|
+
from logging import Logger
|
26
|
+
|
27
|
+
from airflow.providers.google.cloud.hooks.bigquery import BigQueryHook
|
25
28
|
|
26
29
|
|
27
30
|
def bigquery_get_data(
|