apache-airflow-providers-google 10.16.0rc1__py3-none-any.whl → 10.17.0rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- airflow/providers/google/__init__.py +1 -1
- airflow/providers/google/ads/hooks/ads.py +5 -4
- airflow/providers/google/ads/operators/ads.py +1 -0
- airflow/providers/google/cloud/example_dags/example_cloud_sql_query.py +1 -0
- airflow/providers/google/cloud/example_dags/example_cloud_task.py +1 -0
- airflow/providers/google/cloud/example_dags/example_facebook_ads_to_gcs.py +1 -0
- airflow/providers/google/cloud/example_dags/example_looker.py +1 -0
- airflow/providers/google/cloud/example_dags/example_presto_to_gcs.py +1 -0
- airflow/providers/google/cloud/example_dags/example_salesforce_to_gcs.py +1 -0
- airflow/providers/google/cloud/fs/gcs.py +1 -2
- airflow/providers/google/cloud/hooks/automl.py +1 -0
- airflow/providers/google/cloud/hooks/bigquery.py +87 -24
- airflow/providers/google/cloud/hooks/bigquery_dts.py +1 -0
- airflow/providers/google/cloud/hooks/bigtable.py +1 -0
- airflow/providers/google/cloud/hooks/cloud_build.py +1 -0
- airflow/providers/google/cloud/hooks/cloud_memorystore.py +1 -0
- airflow/providers/google/cloud/hooks/cloud_sql.py +1 -0
- airflow/providers/google/cloud/hooks/cloud_storage_transfer_service.py +9 -4
- airflow/providers/google/cloud/hooks/compute.py +1 -0
- airflow/providers/google/cloud/hooks/compute_ssh.py +2 -2
- airflow/providers/google/cloud/hooks/dataflow.py +6 -5
- airflow/providers/google/cloud/hooks/datafusion.py +1 -0
- airflow/providers/google/cloud/hooks/datapipeline.py +1 -0
- airflow/providers/google/cloud/hooks/dataplex.py +1 -0
- airflow/providers/google/cloud/hooks/dataprep.py +1 -0
- airflow/providers/google/cloud/hooks/dataproc.py +3 -2
- airflow/providers/google/cloud/hooks/dataproc_metastore.py +1 -0
- airflow/providers/google/cloud/hooks/datastore.py +1 -0
- airflow/providers/google/cloud/hooks/dlp.py +1 -0
- airflow/providers/google/cloud/hooks/functions.py +1 -0
- airflow/providers/google/cloud/hooks/gcs.py +12 -5
- airflow/providers/google/cloud/hooks/kms.py +1 -0
- airflow/providers/google/cloud/hooks/kubernetes_engine.py +178 -300
- airflow/providers/google/cloud/hooks/life_sciences.py +1 -0
- airflow/providers/google/cloud/hooks/looker.py +1 -0
- airflow/providers/google/cloud/hooks/mlengine.py +1 -0
- airflow/providers/google/cloud/hooks/natural_language.py +1 -0
- airflow/providers/google/cloud/hooks/os_login.py +1 -0
- airflow/providers/google/cloud/hooks/pubsub.py +1 -0
- airflow/providers/google/cloud/hooks/secret_manager.py +1 -0
- airflow/providers/google/cloud/hooks/spanner.py +1 -0
- airflow/providers/google/cloud/hooks/speech_to_text.py +1 -0
- airflow/providers/google/cloud/hooks/stackdriver.py +1 -0
- airflow/providers/google/cloud/hooks/text_to_speech.py +1 -0
- airflow/providers/google/cloud/hooks/translate.py +1 -0
- airflow/providers/google/cloud/hooks/vertex_ai/auto_ml.py +1 -0
- airflow/providers/google/cloud/hooks/vertex_ai/batch_prediction_job.py +255 -3
- airflow/providers/google/cloud/hooks/vertex_ai/custom_job.py +1 -0
- airflow/providers/google/cloud/hooks/vertex_ai/dataset.py +1 -0
- airflow/providers/google/cloud/hooks/vertex_ai/endpoint_service.py +1 -0
- airflow/providers/google/cloud/hooks/vertex_ai/generative_model.py +197 -0
- airflow/providers/google/cloud/hooks/vertex_ai/hyperparameter_tuning_job.py +9 -9
- airflow/providers/google/cloud/hooks/vertex_ai/pipeline_job.py +231 -12
- airflow/providers/google/cloud/hooks/video_intelligence.py +1 -0
- airflow/providers/google/cloud/hooks/vision.py +1 -0
- airflow/providers/google/cloud/links/automl.py +1 -0
- airflow/providers/google/cloud/links/bigquery.py +1 -0
- airflow/providers/google/cloud/links/bigquery_dts.py +1 -0
- airflow/providers/google/cloud/links/cloud_memorystore.py +1 -0
- airflow/providers/google/cloud/links/cloud_sql.py +1 -0
- airflow/providers/google/cloud/links/cloud_tasks.py +1 -0
- airflow/providers/google/cloud/links/compute.py +1 -0
- airflow/providers/google/cloud/links/datacatalog.py +1 -0
- airflow/providers/google/cloud/links/dataflow.py +1 -0
- airflow/providers/google/cloud/links/dataform.py +1 -0
- airflow/providers/google/cloud/links/datafusion.py +1 -0
- airflow/providers/google/cloud/links/dataplex.py +1 -0
- airflow/providers/google/cloud/links/dataproc.py +1 -0
- airflow/providers/google/cloud/links/kubernetes_engine.py +28 -0
- airflow/providers/google/cloud/links/mlengine.py +1 -0
- airflow/providers/google/cloud/links/pubsub.py +1 -0
- airflow/providers/google/cloud/links/spanner.py +1 -0
- airflow/providers/google/cloud/links/stackdriver.py +1 -0
- airflow/providers/google/cloud/links/workflows.py +1 -0
- airflow/providers/google/cloud/log/stackdriver_task_handler.py +18 -4
- airflow/providers/google/cloud/operators/automl.py +1 -0
- airflow/providers/google/cloud/operators/bigquery.py +21 -0
- airflow/providers/google/cloud/operators/bigquery_dts.py +1 -0
- airflow/providers/google/cloud/operators/bigtable.py +1 -0
- airflow/providers/google/cloud/operators/cloud_base.py +1 -0
- airflow/providers/google/cloud/operators/cloud_build.py +1 -0
- airflow/providers/google/cloud/operators/cloud_memorystore.py +1 -0
- airflow/providers/google/cloud/operators/cloud_sql.py +1 -0
- airflow/providers/google/cloud/operators/cloud_storage_transfer_service.py +11 -5
- airflow/providers/google/cloud/operators/compute.py +1 -0
- airflow/providers/google/cloud/operators/dataflow.py +1 -0
- airflow/providers/google/cloud/operators/datafusion.py +1 -0
- airflow/providers/google/cloud/operators/datapipeline.py +1 -0
- airflow/providers/google/cloud/operators/dataprep.py +1 -0
- airflow/providers/google/cloud/operators/dataproc.py +3 -2
- airflow/providers/google/cloud/operators/dataproc_metastore.py +1 -0
- airflow/providers/google/cloud/operators/datastore.py +1 -0
- airflow/providers/google/cloud/operators/functions.py +1 -0
- airflow/providers/google/cloud/operators/gcs.py +1 -0
- airflow/providers/google/cloud/operators/kubernetes_engine.py +600 -4
- airflow/providers/google/cloud/operators/life_sciences.py +1 -0
- airflow/providers/google/cloud/operators/looker.py +1 -0
- airflow/providers/google/cloud/operators/mlengine.py +283 -259
- airflow/providers/google/cloud/operators/natural_language.py +1 -0
- airflow/providers/google/cloud/operators/pubsub.py +1 -0
- airflow/providers/google/cloud/operators/spanner.py +1 -0
- airflow/providers/google/cloud/operators/speech_to_text.py +1 -0
- airflow/providers/google/cloud/operators/text_to_speech.py +1 -0
- airflow/providers/google/cloud/operators/translate.py +1 -0
- airflow/providers/google/cloud/operators/translate_speech.py +1 -0
- airflow/providers/google/cloud/operators/vertex_ai/auto_ml.py +14 -7
- airflow/providers/google/cloud/operators/vertex_ai/batch_prediction_job.py +67 -13
- airflow/providers/google/cloud/operators/vertex_ai/custom_job.py +26 -8
- airflow/providers/google/cloud/operators/vertex_ai/dataset.py +1 -0
- airflow/providers/google/cloud/operators/vertex_ai/generative_model.py +306 -0
- airflow/providers/google/cloud/operators/vertex_ai/hyperparameter_tuning_job.py +29 -48
- airflow/providers/google/cloud/operators/vertex_ai/pipeline_job.py +52 -17
- airflow/providers/google/cloud/operators/video_intelligence.py +1 -0
- airflow/providers/google/cloud/operators/vision.py +1 -0
- airflow/providers/google/cloud/secrets/secret_manager.py +1 -0
- airflow/providers/google/cloud/sensors/bigquery.py +1 -0
- airflow/providers/google/cloud/sensors/bigquery_dts.py +1 -0
- airflow/providers/google/cloud/sensors/bigtable.py +1 -0
- airflow/providers/google/cloud/sensors/cloud_storage_transfer_service.py +1 -0
- airflow/providers/google/cloud/sensors/dataflow.py +1 -0
- airflow/providers/google/cloud/sensors/dataform.py +1 -0
- airflow/providers/google/cloud/sensors/datafusion.py +1 -0
- airflow/providers/google/cloud/sensors/dataplex.py +1 -0
- airflow/providers/google/cloud/sensors/dataprep.py +1 -0
- airflow/providers/google/cloud/sensors/dataproc.py +1 -0
- airflow/providers/google/cloud/sensors/gcs.py +1 -0
- airflow/providers/google/cloud/sensors/looker.py +1 -0
- airflow/providers/google/cloud/sensors/pubsub.py +1 -0
- airflow/providers/google/cloud/sensors/tasks.py +1 -0
- airflow/providers/google/cloud/transfers/bigquery_to_bigquery.py +1 -0
- airflow/providers/google/cloud/transfers/bigquery_to_gcs.py +1 -0
- airflow/providers/google/cloud/transfers/bigquery_to_mssql.py +1 -0
- airflow/providers/google/cloud/transfers/bigquery_to_mysql.py +1 -0
- airflow/providers/google/cloud/transfers/bigquery_to_postgres.py +1 -0
- airflow/providers/google/cloud/transfers/bigquery_to_sql.py +1 -0
- airflow/providers/google/cloud/transfers/facebook_ads_to_gcs.py +1 -0
- airflow/providers/google/cloud/transfers/gcs_to_bigquery.py +3 -2
- airflow/providers/google/cloud/transfers/gcs_to_gcs.py +1 -0
- airflow/providers/google/cloud/transfers/gcs_to_sftp.py +1 -0
- airflow/providers/google/cloud/transfers/local_to_gcs.py +1 -0
- airflow/providers/google/cloud/transfers/mssql_to_gcs.py +1 -0
- airflow/providers/google/cloud/transfers/mysql_to_gcs.py +1 -0
- airflow/providers/google/cloud/transfers/postgres_to_gcs.py +19 -1
- airflow/providers/google/cloud/transfers/s3_to_gcs.py +3 -5
- airflow/providers/google/cloud/transfers/sftp_to_gcs.py +1 -0
- airflow/providers/google/cloud/transfers/sql_to_gcs.py +4 -2
- airflow/providers/google/cloud/triggers/bigquery.py +4 -3
- airflow/providers/google/cloud/triggers/cloud_batch.py +1 -1
- airflow/providers/google/cloud/triggers/cloud_run.py +1 -0
- airflow/providers/google/cloud/triggers/cloud_sql.py +2 -0
- airflow/providers/google/cloud/triggers/cloud_storage_transfer_service.py +14 -2
- airflow/providers/google/cloud/triggers/dataplex.py +1 -0
- airflow/providers/google/cloud/triggers/dataproc.py +1 -0
- airflow/providers/google/cloud/triggers/kubernetes_engine.py +72 -2
- airflow/providers/google/cloud/triggers/mlengine.py +2 -0
- airflow/providers/google/cloud/triggers/pubsub.py +3 -3
- airflow/providers/google/cloud/triggers/vertex_ai.py +107 -15
- airflow/providers/google/cloud/utils/field_sanitizer.py +2 -1
- airflow/providers/google/cloud/utils/field_validator.py +1 -0
- airflow/providers/google/cloud/utils/helpers.py +1 -0
- airflow/providers/google/cloud/utils/mlengine_operator_utils.py +1 -0
- airflow/providers/google/cloud/utils/mlengine_prediction_summary.py +1 -0
- airflow/providers/google/cloud/utils/openlineage.py +1 -0
- airflow/providers/google/common/auth_backend/google_openid.py +1 -0
- airflow/providers/google/common/hooks/base_google.py +2 -1
- airflow/providers/google/common/hooks/discovery_api.py +1 -0
- airflow/providers/google/common/links/storage.py +1 -0
- airflow/providers/google/common/utils/id_token_credentials.py +1 -0
- airflow/providers/google/firebase/hooks/firestore.py +1 -0
- airflow/providers/google/get_provider_info.py +9 -3
- airflow/providers/google/go_module_utils.py +1 -0
- airflow/providers/google/leveldb/hooks/leveldb.py +8 -7
- airflow/providers/google/marketing_platform/example_dags/example_display_video.py +1 -0
- airflow/providers/google/marketing_platform/hooks/analytics_admin.py +1 -0
- airflow/providers/google/marketing_platform/hooks/campaign_manager.py +1 -0
- airflow/providers/google/marketing_platform/hooks/display_video.py +1 -0
- airflow/providers/google/marketing_platform/hooks/search_ads.py +1 -0
- airflow/providers/google/marketing_platform/operators/analytics.py +1 -0
- airflow/providers/google/marketing_platform/operators/analytics_admin.py +4 -2
- airflow/providers/google/marketing_platform/operators/campaign_manager.py +1 -0
- airflow/providers/google/marketing_platform/operators/display_video.py +1 -0
- airflow/providers/google/marketing_platform/operators/search_ads.py +1 -0
- airflow/providers/google/marketing_platform/sensors/campaign_manager.py +1 -0
- airflow/providers/google/marketing_platform/sensors/display_video.py +2 -1
- airflow/providers/google/marketing_platform/sensors/search_ads.py +1 -0
- airflow/providers/google/suite/hooks/calendar.py +1 -0
- airflow/providers/google/suite/hooks/drive.py +1 -0
- airflow/providers/google/suite/hooks/sheets.py +1 -0
- airflow/providers/google/suite/sensors/drive.py +1 -0
- airflow/providers/google/suite/transfers/gcs_to_gdrive.py +7 -0
- airflow/providers/google/suite/transfers/gcs_to_sheets.py +4 -1
- airflow/providers/google/suite/transfers/local_to_drive.py +1 -0
- {apache_airflow_providers_google-10.16.0rc1.dist-info → apache_airflow_providers_google-10.17.0rc1.dist-info}/METADATA +22 -17
- {apache_airflow_providers_google-10.16.0rc1.dist-info → apache_airflow_providers_google-10.17.0rc1.dist-info}/RECORD +196 -194
- {apache_airflow_providers_google-10.16.0rc1.dist-info → apache_airflow_providers_google-10.17.0rc1.dist-info}/WHEEL +0 -0
- {apache_airflow_providers_google-10.16.0rc1.dist-info → apache_airflow_providers_google-10.17.0rc1.dist-info}/entry_points.txt +0 -0
@@ -16,6 +16,7 @@
|
|
16
16
|
# specific language governing permissions and limitations
|
17
17
|
# under the License.
|
18
18
|
"""This module contains Google BigQuery to PostgreSQL operator."""
|
19
|
+
|
19
20
|
from __future__ import annotations
|
20
21
|
|
21
22
|
from airflow.providers.google.cloud.transfers.bigquery_to_sql import BigQueryToSqlBaseOperator
|
@@ -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 to BigQuery operator."""
|
19
|
+
|
19
20
|
from __future__ import annotations
|
20
21
|
|
21
22
|
import json
|
@@ -467,7 +468,7 @@ class GCSToBigQueryOperator(BaseOperator):
|
|
467
468
|
impersonation_chain=self.impersonation_chain,
|
468
469
|
)
|
469
470
|
if self.max_id_key:
|
470
|
-
self.log.info(
|
471
|
+
self.log.info("Selecting the MAX value from BigQuery column %r...", self.max_id_key)
|
471
472
|
select_command = (
|
472
473
|
f"SELECT MAX({self.max_id_key}) AS max_value "
|
473
474
|
f"FROM {self.destination_project_dataset_table}"
|
@@ -713,7 +714,7 @@ class GCSToBigQueryOperator(BaseOperator):
|
|
713
714
|
if k not in src_fmt_configs and k in valid_configs:
|
714
715
|
src_fmt_configs[k] = v
|
715
716
|
|
716
|
-
for k
|
717
|
+
for k in src_fmt_configs:
|
717
718
|
if k not in valid_configs:
|
718
719
|
raise ValueError(f"{k} is not a valid src_fmt_configs for type {source_format}.")
|
719
720
|
|
@@ -16,6 +16,7 @@
|
|
16
16
|
# specific language governing permissions and limitations
|
17
17
|
# under the License.
|
18
18
|
"""PostgreSQL to GCS operator."""
|
19
|
+
|
19
20
|
from __future__ import annotations
|
20
21
|
|
21
22
|
import datetime
|
@@ -25,6 +26,7 @@ import uuid
|
|
25
26
|
from decimal import Decimal
|
26
27
|
|
27
28
|
import pendulum
|
29
|
+
from slugify import slugify
|
28
30
|
|
29
31
|
from airflow.providers.google.cloud.transfers.sql_to_gcs import BaseSQLToGCSOperator
|
30
32
|
from airflow.providers.postgres.hooks.postgres import PostgresHook
|
@@ -112,7 +114,23 @@ class PostgresToGCSOperator(BaseSQLToGCSOperator):
|
|
112
114
|
self.cursor_itersize = cursor_itersize
|
113
115
|
|
114
116
|
def _unique_name(self):
|
115
|
-
|
117
|
+
"""
|
118
|
+
Generate a non-deterministic UUID for the cursor name using the task_id and dag_id.
|
119
|
+
|
120
|
+
Ensures the resulting name fits within the maximum length allowed for an identifier in Postgres.
|
121
|
+
"""
|
122
|
+
if self.use_server_side_cursor:
|
123
|
+
separator = "__"
|
124
|
+
random_sufix = str(uuid.uuid4())
|
125
|
+
available_length = 63 - len(random_sufix) - (len(separator) * 2)
|
126
|
+
return separator.join(
|
127
|
+
(
|
128
|
+
slugify(self.dag_id, allow_unicode=False, max_length=available_length // 2),
|
129
|
+
slugify(self.task_id, allow_unicode=False, max_length=available_length // 2),
|
130
|
+
random_sufix,
|
131
|
+
)
|
132
|
+
)
|
133
|
+
return None
|
116
134
|
|
117
135
|
def query(self):
|
118
136
|
"""Query Postgres and returns a cursor to the results."""
|
@@ -269,6 +269,7 @@ class S3ToGCSOperator(S3ListOperator):
|
|
269
269
|
self.defer(
|
270
270
|
trigger=CloudStorageTransferServiceCreateJobsTrigger(
|
271
271
|
project_id=gcs_hook.project_id,
|
272
|
+
gcp_conn_id=self.gcp_conn_id,
|
272
273
|
job_names=job_names,
|
273
274
|
poll_interval=self.poll_interval,
|
274
275
|
),
|
@@ -319,14 +320,11 @@ class S3ToGCSOperator(S3ListOperator):
|
|
319
320
|
body[TRANSFER_SPEC][OBJECT_CONDITIONS][INCLUDE_PREFIXES] = files_chunk
|
320
321
|
job = transfer_hook.create_transfer_job(body=body)
|
321
322
|
|
322
|
-
s
|
323
|
-
self.log.info(f"Submitted job {job['name']} to transfer {len(files_chunk)} file{s}")
|
323
|
+
self.log.info("Submitted job %s to transfer %s file(s).", job["name"], len(files_chunk))
|
324
324
|
job_names.append(job["name"])
|
325
325
|
|
326
326
|
if len(files) > chunk_size:
|
327
|
-
|
328
|
-
fs = "s" if len(files) > 1 else ""
|
329
|
-
self.log.info(f"Overall submitted {len(job_names)} job{js} to transfer {len(files)} file{fs}")
|
327
|
+
self.log.info("Overall submitted %s job(s) to transfer %s file(s).", len(job_names), len(files))
|
330
328
|
|
331
329
|
return job_names
|
332
330
|
|
@@ -16,6 +16,7 @@
|
|
16
16
|
# specific language governing permissions and limitations
|
17
17
|
# under the License.
|
18
18
|
"""Base operator for SQL to GCS operators."""
|
19
|
+
|
19
20
|
from __future__ import annotations
|
20
21
|
|
21
22
|
import abc
|
@@ -153,9 +154,10 @@ class BaseSQLToGCSOperator(BaseOperator):
|
|
153
154
|
def execute(self, context: Context):
|
154
155
|
if self.partition_columns:
|
155
156
|
self.log.info(
|
156
|
-
|
157
|
+
"Found partition columns: %s. "
|
157
158
|
"Assuming the SQL statement is properly sorted by these columns in "
|
158
|
-
"ascending or descending order."
|
159
|
+
"ascending or descending order.",
|
160
|
+
",".join(self.partition_columns),
|
159
161
|
)
|
160
162
|
|
161
163
|
self.log.info("Executing query")
|
@@ -160,7 +160,6 @@ class BigQueryCheckTrigger(BigQueryInsertJobTrigger):
|
|
160
160
|
"records": None,
|
161
161
|
}
|
162
162
|
)
|
163
|
-
return
|
164
163
|
else:
|
165
164
|
# Extract only first record from the query results
|
166
165
|
first_record = records.pop(0)
|
@@ -171,7 +170,7 @@ class BigQueryCheckTrigger(BigQueryInsertJobTrigger):
|
|
171
170
|
"records": first_record,
|
172
171
|
}
|
173
172
|
)
|
174
|
-
|
173
|
+
return
|
175
174
|
elif job_status["status"] == "error":
|
176
175
|
yield TriggerEvent({"status": "error", "message": job_status["message"]})
|
177
176
|
return
|
@@ -681,7 +680,9 @@ class BigQueryTablePartitionExistenceTrigger(BigQueryTableExistenceTrigger):
|
|
681
680
|
await asyncio.sleep(self.poll_interval)
|
682
681
|
|
683
682
|
else:
|
684
|
-
job_id = await hook.create_job_for_partition_get(
|
683
|
+
job_id = await hook.create_job_for_partition_get(
|
684
|
+
self.dataset_id, table_id=self.table_id, project_id=self.project_id
|
685
|
+
)
|
685
686
|
self.log.info("Sleeping for %s seconds.", self.poll_interval)
|
686
687
|
await asyncio.sleep(self.poll_interval)
|
687
688
|
|
@@ -140,7 +140,7 @@ class CloudBatchJobFinishedTrigger(BaseTrigger):
|
|
140
140
|
yield TriggerEvent({"status": "error", "message": str(e)})
|
141
141
|
return
|
142
142
|
|
143
|
-
self.log.exception(
|
143
|
+
self.log.exception("Job with name [%s] timed out", self.job_name)
|
144
144
|
yield TriggerEvent(
|
145
145
|
{
|
146
146
|
"job_name": self.job_name,
|
@@ -16,6 +16,7 @@
|
|
16
16
|
# specific language governing permissions and limitations
|
17
17
|
# under the License.
|
18
18
|
"""This module contains Google Cloud SQL triggers."""
|
19
|
+
|
19
20
|
from __future__ import annotations
|
20
21
|
|
21
22
|
import asyncio
|
@@ -79,6 +80,7 @@ class CloudSQLExportTrigger(BaseTrigger):
|
|
79
80
|
}
|
80
81
|
)
|
81
82
|
return
|
83
|
+
|
82
84
|
yield TriggerEvent(
|
83
85
|
{
|
84
86
|
"operation_name": operation["name"],
|
@@ -37,11 +37,19 @@ class CloudStorageTransferServiceCreateJobsTrigger(BaseTrigger):
|
|
37
37
|
:param job_names: List of transfer jobs names.
|
38
38
|
:param project_id: GCP project id.
|
39
39
|
:param poll_interval: Interval in seconds between polls.
|
40
|
+
:param gcp_conn_id: The connection ID used to connect to Google Cloud.
|
40
41
|
"""
|
41
42
|
|
42
|
-
def __init__(
|
43
|
+
def __init__(
|
44
|
+
self,
|
45
|
+
job_names: list[str],
|
46
|
+
project_id: str | None = None,
|
47
|
+
poll_interval: int = 10,
|
48
|
+
gcp_conn_id: str = "google_cloud_default",
|
49
|
+
) -> None:
|
43
50
|
super().__init__()
|
44
51
|
self.project_id = project_id
|
52
|
+
self.gcp_conn_id = gcp_conn_id
|
45
53
|
self.job_names = job_names
|
46
54
|
self.poll_interval = poll_interval
|
47
55
|
|
@@ -53,6 +61,7 @@ class CloudStorageTransferServiceCreateJobsTrigger(BaseTrigger):
|
|
53
61
|
"project_id": self.project_id,
|
54
62
|
"job_names": self.job_names,
|
55
63
|
"poll_interval": self.poll_interval,
|
64
|
+
"gcp_conn_id": self.gcp_conn_id,
|
56
65
|
},
|
57
66
|
)
|
58
67
|
|
@@ -117,4 +126,7 @@ class CloudStorageTransferServiceCreateJobsTrigger(BaseTrigger):
|
|
117
126
|
await asyncio.sleep(self.poll_interval)
|
118
127
|
|
119
128
|
def get_async_hook(self) -> CloudDataTransferServiceAsyncHook:
|
120
|
-
return CloudDataTransferServiceAsyncHook(
|
129
|
+
return CloudDataTransferServiceAsyncHook(
|
130
|
+
project_id=self.project_id,
|
131
|
+
gcp_conn_id=self.gcp_conn_id,
|
132
|
+
)
|
@@ -27,12 +27,18 @@ from google.cloud.container_v1.types import Operation
|
|
27
27
|
from airflow.exceptions import AirflowProviderDeprecationWarning
|
28
28
|
from airflow.providers.cncf.kubernetes.triggers.pod import KubernetesPodTrigger
|
29
29
|
from airflow.providers.cncf.kubernetes.utils.pod_manager import OnFinishAction
|
30
|
-
from airflow.providers.google.cloud.hooks.kubernetes_engine import
|
30
|
+
from airflow.providers.google.cloud.hooks.kubernetes_engine import (
|
31
|
+
GKEAsyncHook,
|
32
|
+
GKEKubernetesAsyncHook,
|
33
|
+
GKEPodAsyncHook,
|
34
|
+
)
|
31
35
|
from airflow.triggers.base import BaseTrigger, TriggerEvent
|
32
36
|
|
33
37
|
if TYPE_CHECKING:
|
34
38
|
from datetime import datetime
|
35
39
|
|
40
|
+
from kubernetes_asyncio.client import V1Job
|
41
|
+
|
36
42
|
|
37
43
|
class GKEStartPodTrigger(KubernetesPodTrigger):
|
38
44
|
"""
|
@@ -147,6 +153,7 @@ class GKEStartPodTrigger(KubernetesPodTrigger):
|
|
147
153
|
ssl_ca_cert=self._ssl_ca_cert,
|
148
154
|
gcp_conn_id=self.gcp_conn_id,
|
149
155
|
impersonation_chain=self.impersonation_chain,
|
156
|
+
enable_tcp_keepalive=True,
|
150
157
|
)
|
151
158
|
|
152
159
|
|
@@ -211,7 +218,6 @@ class GKEOperationTrigger(BaseTrigger):
|
|
211
218
|
self.log.info("Operation is still running.")
|
212
219
|
self.log.info("Sleeping for %ss...", self.poll_interval)
|
213
220
|
await asyncio.sleep(self.poll_interval)
|
214
|
-
|
215
221
|
else:
|
216
222
|
yield TriggerEvent(
|
217
223
|
{
|
@@ -237,3 +243,67 @@ class GKEOperationTrigger(BaseTrigger):
|
|
237
243
|
impersonation_chain=self.impersonation_chain,
|
238
244
|
)
|
239
245
|
return self._hook
|
246
|
+
|
247
|
+
|
248
|
+
class GKEJobTrigger(BaseTrigger):
|
249
|
+
"""GKEJobTrigger run on the trigger worker to check the state of Job."""
|
250
|
+
|
251
|
+
def __init__(
|
252
|
+
self,
|
253
|
+
cluster_url: str,
|
254
|
+
ssl_ca_cert: str,
|
255
|
+
job_name: str,
|
256
|
+
job_namespace: str,
|
257
|
+
gcp_conn_id: str = "google_cloud_default",
|
258
|
+
poll_interval: float = 2,
|
259
|
+
impersonation_chain: str | Sequence[str] | None = None,
|
260
|
+
) -> None:
|
261
|
+
super().__init__()
|
262
|
+
self.cluster_url = cluster_url
|
263
|
+
self.ssl_ca_cert = ssl_ca_cert
|
264
|
+
self.job_name = job_name
|
265
|
+
self.job_namespace = job_namespace
|
266
|
+
self.gcp_conn_id = gcp_conn_id
|
267
|
+
self.poll_interval = poll_interval
|
268
|
+
self.impersonation_chain = impersonation_chain
|
269
|
+
|
270
|
+
def serialize(self) -> tuple[str, dict[str, Any]]:
|
271
|
+
"""Serialize KubernetesCreateJobTrigger arguments and classpath."""
|
272
|
+
return (
|
273
|
+
"airflow.providers.google.cloud.triggers.kubernetes_engine.GKEJobTrigger",
|
274
|
+
{
|
275
|
+
"cluster_url": self.cluster_url,
|
276
|
+
"ssl_ca_cert": self.ssl_ca_cert,
|
277
|
+
"job_name": self.job_name,
|
278
|
+
"job_namespace": self.job_namespace,
|
279
|
+
"gcp_conn_id": self.gcp_conn_id,
|
280
|
+
"poll_interval": self.poll_interval,
|
281
|
+
"impersonation_chain": self.impersonation_chain,
|
282
|
+
},
|
283
|
+
)
|
284
|
+
|
285
|
+
async def run(self) -> AsyncIterator[TriggerEvent]: # type: ignore[override]
|
286
|
+
"""Get current job status and yield a TriggerEvent."""
|
287
|
+
job: V1Job = await self.hook.wait_until_job_complete(name=self.job_name, namespace=self.job_namespace)
|
288
|
+
job_dict = job.to_dict()
|
289
|
+
error_message = self.hook.is_job_failed(job=job)
|
290
|
+
status = "error" if error_message else "success"
|
291
|
+
message = f"Job failed with error: {error_message}" if error_message else "Job completed successfully"
|
292
|
+
yield TriggerEvent(
|
293
|
+
{
|
294
|
+
"name": job.metadata.name,
|
295
|
+
"namespace": job.metadata.namespace,
|
296
|
+
"status": status,
|
297
|
+
"message": message,
|
298
|
+
"job": job_dict,
|
299
|
+
}
|
300
|
+
)
|
301
|
+
|
302
|
+
@cached_property
|
303
|
+
def hook(self) -> GKEKubernetesAsyncHook:
|
304
|
+
return GKEKubernetesAsyncHook(
|
305
|
+
cluster_url=self.cluster_url,
|
306
|
+
ssl_ca_cert=self.ssl_ca_cert,
|
307
|
+
gcp_conn_id=self.gcp_conn_id,
|
308
|
+
impersonation_chain=self.impersonation_chain,
|
309
|
+
)
|
@@ -103,12 +103,14 @@ class MLEngineStartTrainingJobTrigger(BaseTrigger):
|
|
103
103
|
"message": "Job completed",
|
104
104
|
}
|
105
105
|
)
|
106
|
+
return
|
106
107
|
elif response_from_hook == "pending":
|
107
108
|
self.log.info("Job is still running...")
|
108
109
|
self.log.info("Sleeping for %s seconds.", self.poll_interval)
|
109
110
|
await asyncio.sleep(self.poll_interval)
|
110
111
|
else:
|
111
112
|
yield TriggerEvent({"status": "error", "message": response_from_hook})
|
113
|
+
return
|
112
114
|
|
113
115
|
except Exception as e:
|
114
116
|
self.log.exception("Exception occurred while checking for query completion")
|
@@ -15,6 +15,7 @@
|
|
15
15
|
# specific language governing permissions and limitations
|
16
16
|
# under the License.
|
17
17
|
"""This module contains Google Cloud Pubsub triggers."""
|
18
|
+
|
18
19
|
from __future__ import annotations
|
19
20
|
|
20
21
|
import asyncio
|
@@ -101,9 +102,8 @@ class PubsubPullTrigger(BaseTrigger):
|
|
101
102
|
if pulled_messages:
|
102
103
|
if self.ack_messages:
|
103
104
|
await self.message_acknowledgement(pulled_messages)
|
104
|
-
|
105
|
-
|
106
|
-
yield TriggerEvent({"status": "success", "message": pulled_messages})
|
105
|
+
yield TriggerEvent({"status": "success", "message": pulled_messages})
|
106
|
+
return
|
107
107
|
else:
|
108
108
|
pulled_messages = await self.hook.pull(
|
109
109
|
project_id=self.project_id,
|