apache-airflow-providers-google 15.1.0rc1__py3-none-any.whl → 19.3.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/3rd-party-licenses/NOTICE +2 -12
- airflow/providers/google/__init__.py +3 -3
- airflow/providers/google/ads/hooks/ads.py +39 -6
- airflow/providers/google/ads/operators/ads.py +2 -2
- airflow/providers/google/ads/transfers/ads_to_gcs.py +2 -2
- airflow/providers/google/assets/gcs.py +1 -11
- airflow/providers/google/cloud/bundles/__init__.py +16 -0
- airflow/providers/google/cloud/bundles/gcs.py +161 -0
- airflow/providers/google/cloud/hooks/alloy_db.py +1 -1
- airflow/providers/google/cloud/hooks/bigquery.py +176 -293
- airflow/providers/google/cloud/hooks/cloud_batch.py +1 -1
- airflow/providers/google/cloud/hooks/cloud_build.py +1 -1
- airflow/providers/google/cloud/hooks/cloud_composer.py +288 -15
- airflow/providers/google/cloud/hooks/cloud_logging.py +109 -0
- airflow/providers/google/cloud/hooks/cloud_memorystore.py +1 -1
- airflow/providers/google/cloud/hooks/cloud_run.py +18 -10
- airflow/providers/google/cloud/hooks/cloud_sql.py +102 -23
- airflow/providers/google/cloud/hooks/cloud_storage_transfer_service.py +29 -7
- airflow/providers/google/cloud/hooks/compute.py +1 -1
- airflow/providers/google/cloud/hooks/compute_ssh.py +6 -2
- airflow/providers/google/cloud/hooks/datacatalog.py +10 -1
- airflow/providers/google/cloud/hooks/dataflow.py +72 -95
- airflow/providers/google/cloud/hooks/dataform.py +1 -1
- airflow/providers/google/cloud/hooks/datafusion.py +21 -19
- airflow/providers/google/cloud/hooks/dataplex.py +2 -2
- airflow/providers/google/cloud/hooks/dataprep.py +1 -1
- airflow/providers/google/cloud/hooks/dataproc.py +73 -72
- airflow/providers/google/cloud/hooks/dataproc_metastore.py +1 -1
- airflow/providers/google/cloud/hooks/dlp.py +1 -1
- airflow/providers/google/cloud/hooks/functions.py +1 -1
- airflow/providers/google/cloud/hooks/gcs.py +112 -15
- airflow/providers/google/cloud/hooks/gdm.py +1 -1
- airflow/providers/google/cloud/hooks/gen_ai.py +196 -0
- airflow/providers/google/cloud/hooks/kubernetes_engine.py +3 -3
- airflow/providers/google/cloud/hooks/looker.py +6 -2
- airflow/providers/google/cloud/hooks/managed_kafka.py +1 -1
- airflow/providers/google/cloud/hooks/mlengine.py +4 -3
- airflow/providers/google/cloud/hooks/pubsub.py +3 -0
- airflow/providers/google/cloud/hooks/secret_manager.py +102 -10
- airflow/providers/google/cloud/hooks/spanner.py +74 -9
- airflow/providers/google/cloud/hooks/stackdriver.py +11 -9
- airflow/providers/google/cloud/hooks/tasks.py +1 -1
- airflow/providers/google/cloud/hooks/translate.py +2 -2
- airflow/providers/google/cloud/hooks/vertex_ai/auto_ml.py +2 -210
- airflow/providers/google/cloud/hooks/vertex_ai/batch_prediction_job.py +3 -3
- airflow/providers/google/cloud/hooks/vertex_ai/custom_job.py +28 -2
- airflow/providers/google/cloud/hooks/vertex_ai/experiment_service.py +202 -0
- airflow/providers/google/cloud/hooks/vertex_ai/feature_store.py +308 -8
- airflow/providers/google/cloud/hooks/vertex_ai/generative_model.py +79 -75
- airflow/providers/google/cloud/hooks/vertex_ai/hyperparameter_tuning_job.py +1 -1
- airflow/providers/google/cloud/hooks/vertex_ai/model_service.py +1 -1
- airflow/providers/google/cloud/hooks/vertex_ai/pipeline_job.py +1 -1
- airflow/providers/google/cloud/hooks/vertex_ai/ray.py +223 -0
- airflow/providers/google/cloud/hooks/vision.py +3 -3
- airflow/providers/google/cloud/hooks/workflows.py +1 -1
- airflow/providers/google/cloud/links/alloy_db.py +0 -46
- airflow/providers/google/cloud/links/base.py +77 -13
- airflow/providers/google/cloud/links/bigquery.py +0 -47
- airflow/providers/google/cloud/links/bigquery_dts.py +0 -20
- airflow/providers/google/cloud/links/bigtable.py +0 -48
- airflow/providers/google/cloud/links/cloud_build.py +0 -73
- airflow/providers/google/cloud/links/cloud_functions.py +0 -33
- airflow/providers/google/cloud/links/cloud_memorystore.py +0 -58
- airflow/providers/google/cloud/links/{life_sciences.py → cloud_run.py} +5 -27
- airflow/providers/google/cloud/links/cloud_sql.py +0 -33
- airflow/providers/google/cloud/links/cloud_storage_transfer.py +17 -44
- airflow/providers/google/cloud/links/cloud_tasks.py +7 -26
- airflow/providers/google/cloud/links/compute.py +0 -58
- airflow/providers/google/cloud/links/data_loss_prevention.py +0 -169
- airflow/providers/google/cloud/links/datacatalog.py +23 -54
- airflow/providers/google/cloud/links/dataflow.py +0 -34
- airflow/providers/google/cloud/links/dataform.py +0 -64
- airflow/providers/google/cloud/links/datafusion.py +1 -96
- airflow/providers/google/cloud/links/dataplex.py +0 -154
- airflow/providers/google/cloud/links/dataprep.py +0 -24
- airflow/providers/google/cloud/links/dataproc.py +11 -95
- airflow/providers/google/cloud/links/datastore.py +0 -31
- airflow/providers/google/cloud/links/kubernetes_engine.py +9 -60
- airflow/providers/google/cloud/links/managed_kafka.py +0 -70
- airflow/providers/google/cloud/links/mlengine.py +0 -70
- airflow/providers/google/cloud/links/pubsub.py +0 -32
- airflow/providers/google/cloud/links/spanner.py +0 -33
- airflow/providers/google/cloud/links/stackdriver.py +0 -30
- airflow/providers/google/cloud/links/translate.py +17 -187
- airflow/providers/google/cloud/links/vertex_ai.py +28 -195
- airflow/providers/google/cloud/links/workflows.py +0 -52
- airflow/providers/google/cloud/log/gcs_task_handler.py +58 -22
- airflow/providers/google/cloud/log/stackdriver_task_handler.py +9 -6
- airflow/providers/google/cloud/openlineage/CloudStorageTransferJobFacet.json +68 -0
- airflow/providers/google/cloud/openlineage/CloudStorageTransferRunFacet.json +60 -0
- airflow/providers/google/cloud/openlineage/DataFusionRunFacet.json +32 -0
- airflow/providers/google/cloud/openlineage/facets.py +102 -1
- airflow/providers/google/cloud/openlineage/mixins.py +10 -8
- airflow/providers/google/cloud/openlineage/utils.py +15 -1
- airflow/providers/google/cloud/operators/alloy_db.py +71 -56
- airflow/providers/google/cloud/operators/bigquery.py +73 -636
- airflow/providers/google/cloud/operators/bigquery_dts.py +4 -6
- airflow/providers/google/cloud/operators/bigtable.py +37 -8
- airflow/providers/google/cloud/operators/cloud_base.py +21 -1
- airflow/providers/google/cloud/operators/cloud_batch.py +3 -3
- airflow/providers/google/cloud/operators/cloud_build.py +76 -33
- airflow/providers/google/cloud/operators/cloud_composer.py +129 -41
- airflow/providers/google/cloud/operators/cloud_logging_sink.py +341 -0
- airflow/providers/google/cloud/operators/cloud_memorystore.py +69 -43
- airflow/providers/google/cloud/operators/cloud_run.py +24 -6
- airflow/providers/google/cloud/operators/cloud_sql.py +8 -17
- airflow/providers/google/cloud/operators/cloud_storage_transfer_service.py +93 -12
- airflow/providers/google/cloud/operators/compute.py +9 -41
- airflow/providers/google/cloud/operators/datacatalog.py +157 -21
- airflow/providers/google/cloud/operators/dataflow.py +40 -16
- airflow/providers/google/cloud/operators/dataform.py +15 -5
- airflow/providers/google/cloud/operators/datafusion.py +42 -21
- airflow/providers/google/cloud/operators/dataplex.py +194 -110
- airflow/providers/google/cloud/operators/dataprep.py +1 -5
- airflow/providers/google/cloud/operators/dataproc.py +80 -36
- airflow/providers/google/cloud/operators/dataproc_metastore.py +97 -89
- airflow/providers/google/cloud/operators/datastore.py +23 -7
- airflow/providers/google/cloud/operators/dlp.py +6 -29
- airflow/providers/google/cloud/operators/functions.py +17 -8
- airflow/providers/google/cloud/operators/gcs.py +12 -9
- airflow/providers/google/cloud/operators/gen_ai.py +389 -0
- airflow/providers/google/cloud/operators/kubernetes_engine.py +62 -100
- airflow/providers/google/cloud/operators/looker.py +2 -2
- airflow/providers/google/cloud/operators/managed_kafka.py +108 -53
- airflow/providers/google/cloud/operators/natural_language.py +1 -1
- airflow/providers/google/cloud/operators/pubsub.py +68 -15
- airflow/providers/google/cloud/operators/spanner.py +26 -13
- airflow/providers/google/cloud/operators/speech_to_text.py +2 -3
- airflow/providers/google/cloud/operators/stackdriver.py +1 -9
- airflow/providers/google/cloud/operators/tasks.py +1 -12
- airflow/providers/google/cloud/operators/text_to_speech.py +2 -3
- airflow/providers/google/cloud/operators/translate.py +41 -17
- airflow/providers/google/cloud/operators/translate_speech.py +2 -3
- airflow/providers/google/cloud/operators/vertex_ai/auto_ml.py +39 -19
- airflow/providers/google/cloud/operators/vertex_ai/batch_prediction_job.py +30 -10
- airflow/providers/google/cloud/operators/vertex_ai/custom_job.py +55 -27
- airflow/providers/google/cloud/operators/vertex_ai/dataset.py +70 -8
- airflow/providers/google/cloud/operators/vertex_ai/endpoint_service.py +43 -9
- airflow/providers/google/cloud/operators/vertex_ai/experiment_service.py +435 -0
- airflow/providers/google/cloud/operators/vertex_ai/feature_store.py +532 -1
- airflow/providers/google/cloud/operators/vertex_ai/generative_model.py +135 -115
- airflow/providers/google/cloud/operators/vertex_ai/hyperparameter_tuning_job.py +12 -10
- airflow/providers/google/cloud/operators/vertex_ai/model_service.py +57 -11
- airflow/providers/google/cloud/operators/vertex_ai/pipeline_job.py +31 -8
- airflow/providers/google/cloud/operators/vertex_ai/ray.py +393 -0
- airflow/providers/google/cloud/operators/video_intelligence.py +1 -1
- airflow/providers/google/cloud/operators/vision.py +2 -2
- airflow/providers/google/cloud/operators/workflows.py +18 -15
- airflow/providers/google/cloud/secrets/secret_manager.py +3 -2
- airflow/providers/google/cloud/sensors/bigquery.py +3 -3
- airflow/providers/google/cloud/sensors/bigquery_dts.py +2 -3
- airflow/providers/google/cloud/sensors/bigtable.py +11 -4
- airflow/providers/google/cloud/sensors/cloud_composer.py +533 -30
- airflow/providers/google/cloud/sensors/cloud_storage_transfer_service.py +2 -3
- airflow/providers/google/cloud/sensors/dataflow.py +26 -10
- airflow/providers/google/cloud/sensors/dataform.py +2 -3
- airflow/providers/google/cloud/sensors/datafusion.py +4 -5
- airflow/providers/google/cloud/sensors/dataplex.py +2 -3
- airflow/providers/google/cloud/sensors/dataprep.py +2 -2
- airflow/providers/google/cloud/sensors/dataproc.py +2 -3
- airflow/providers/google/cloud/sensors/dataproc_metastore.py +2 -3
- airflow/providers/google/cloud/sensors/gcs.py +4 -5
- airflow/providers/google/cloud/sensors/looker.py +2 -3
- airflow/providers/google/cloud/sensors/pubsub.py +4 -5
- airflow/providers/google/cloud/sensors/tasks.py +2 -2
- airflow/providers/google/cloud/sensors/vertex_ai/feature_store.py +2 -3
- airflow/providers/google/cloud/sensors/workflows.py +2 -3
- airflow/providers/google/cloud/transfers/adls_to_gcs.py +1 -1
- airflow/providers/google/cloud/transfers/azure_blob_to_gcs.py +2 -2
- airflow/providers/google/cloud/transfers/azure_fileshare_to_gcs.py +4 -3
- airflow/providers/google/cloud/transfers/bigquery_to_bigquery.py +11 -8
- airflow/providers/google/cloud/transfers/bigquery_to_gcs.py +10 -5
- airflow/providers/google/cloud/transfers/bigquery_to_mssql.py +7 -3
- airflow/providers/google/cloud/transfers/bigquery_to_mysql.py +12 -1
- airflow/providers/google/cloud/transfers/bigquery_to_postgres.py +24 -10
- airflow/providers/google/cloud/transfers/bigquery_to_sql.py +104 -5
- airflow/providers/google/cloud/transfers/calendar_to_gcs.py +1 -1
- airflow/providers/google/cloud/transfers/cassandra_to_gcs.py +3 -3
- airflow/providers/google/cloud/transfers/facebook_ads_to_gcs.py +4 -4
- airflow/providers/google/cloud/transfers/gcs_to_bigquery.py +21 -13
- airflow/providers/google/cloud/transfers/gcs_to_gcs.py +4 -3
- airflow/providers/google/cloud/transfers/gcs_to_local.py +6 -4
- airflow/providers/google/cloud/transfers/gcs_to_sftp.py +11 -5
- airflow/providers/google/cloud/transfers/gdrive_to_gcs.py +6 -2
- airflow/providers/google/cloud/transfers/gdrive_to_local.py +2 -2
- airflow/providers/google/cloud/transfers/http_to_gcs.py +193 -0
- airflow/providers/google/cloud/transfers/local_to_gcs.py +2 -2
- airflow/providers/google/cloud/transfers/mssql_to_gcs.py +1 -1
- airflow/providers/google/cloud/transfers/oracle_to_gcs.py +36 -11
- airflow/providers/google/cloud/transfers/postgres_to_gcs.py +42 -9
- airflow/providers/google/cloud/transfers/s3_to_gcs.py +13 -7
- airflow/providers/google/cloud/transfers/salesforce_to_gcs.py +2 -2
- airflow/providers/google/cloud/transfers/sftp_to_gcs.py +14 -5
- airflow/providers/google/cloud/transfers/sheets_to_gcs.py +3 -3
- airflow/providers/google/cloud/transfers/sql_to_gcs.py +10 -10
- airflow/providers/google/cloud/triggers/bigquery.py +76 -35
- airflow/providers/google/cloud/triggers/cloud_build.py +1 -1
- airflow/providers/google/cloud/triggers/cloud_composer.py +303 -47
- airflow/providers/google/cloud/triggers/cloud_run.py +3 -3
- airflow/providers/google/cloud/triggers/cloud_storage_transfer_service.py +92 -2
- airflow/providers/google/cloud/triggers/dataflow.py +122 -0
- airflow/providers/google/cloud/triggers/datafusion.py +1 -1
- airflow/providers/google/cloud/triggers/dataplex.py +14 -2
- airflow/providers/google/cloud/triggers/dataproc.py +123 -53
- airflow/providers/google/cloud/triggers/kubernetes_engine.py +47 -28
- airflow/providers/google/cloud/triggers/mlengine.py +1 -1
- airflow/providers/google/cloud/triggers/pubsub.py +15 -19
- airflow/providers/google/cloud/triggers/vertex_ai.py +1 -1
- airflow/providers/google/cloud/utils/bigquery_get_data.py +1 -1
- airflow/providers/google/cloud/utils/credentials_provider.py +2 -2
- airflow/providers/google/cloud/utils/field_sanitizer.py +1 -1
- airflow/providers/google/cloud/utils/field_validator.py +2 -3
- airflow/providers/google/common/auth_backend/google_openid.py +4 -4
- airflow/providers/google/common/deprecated.py +2 -1
- airflow/providers/google/common/hooks/base_google.py +27 -9
- airflow/providers/google/common/hooks/operation_helpers.py +1 -1
- airflow/providers/google/common/links/storage.py +0 -22
- airflow/providers/google/common/utils/get_secret.py +31 -0
- airflow/providers/google/common/utils/id_token_credentials.py +3 -4
- airflow/providers/google/firebase/hooks/firestore.py +1 -1
- airflow/providers/google/firebase/operators/firestore.py +3 -3
- airflow/providers/google/get_provider_info.py +56 -52
- airflow/providers/google/go_module_utils.py +35 -3
- airflow/providers/google/leveldb/hooks/leveldb.py +27 -2
- airflow/providers/google/leveldb/operators/leveldb.py +2 -2
- airflow/providers/google/marketing_platform/hooks/campaign_manager.py +1 -1
- airflow/providers/google/marketing_platform/hooks/display_video.py +3 -109
- airflow/providers/google/marketing_platform/hooks/search_ads.py +1 -1
- airflow/providers/google/marketing_platform/links/analytics_admin.py +5 -14
- airflow/providers/google/marketing_platform/operators/analytics_admin.py +2 -3
- airflow/providers/google/marketing_platform/operators/campaign_manager.py +6 -6
- airflow/providers/google/marketing_platform/operators/display_video.py +28 -489
- airflow/providers/google/marketing_platform/operators/search_ads.py +2 -2
- airflow/providers/google/marketing_platform/sensors/campaign_manager.py +2 -2
- airflow/providers/google/marketing_platform/sensors/display_video.py +3 -64
- airflow/providers/google/suite/hooks/calendar.py +2 -2
- airflow/providers/google/suite/hooks/sheets.py +16 -2
- airflow/providers/google/suite/operators/sheets.py +8 -3
- airflow/providers/google/suite/sensors/drive.py +2 -2
- airflow/providers/google/suite/transfers/gcs_to_gdrive.py +3 -3
- airflow/providers/google/suite/transfers/gcs_to_sheets.py +1 -1
- airflow/providers/google/suite/transfers/local_to_drive.py +3 -3
- airflow/providers/google/suite/transfers/sql_to_sheets.py +5 -4
- airflow/providers/google/version_compat.py +15 -1
- {apache_airflow_providers_google-15.1.0rc1.dist-info → apache_airflow_providers_google-19.3.0.dist-info}/METADATA +90 -46
- apache_airflow_providers_google-19.3.0.dist-info/RECORD +331 -0
- apache_airflow_providers_google-19.3.0.dist-info/licenses/NOTICE +5 -0
- airflow/providers/google/cloud/hooks/automl.py +0 -673
- airflow/providers/google/cloud/hooks/life_sciences.py +0 -159
- airflow/providers/google/cloud/links/automl.py +0 -193
- airflow/providers/google/cloud/operators/automl.py +0 -1362
- airflow/providers/google/cloud/operators/life_sciences.py +0 -119
- airflow/providers/google/cloud/operators/mlengine.py +0 -112
- apache_airflow_providers_google-15.1.0rc1.dist-info/RECORD +0 -321
- {apache_airflow_providers_google-15.1.0rc1.dist-info → apache_airflow_providers_google-19.3.0.dist-info}/WHEEL +0 -0
- {apache_airflow_providers_google-15.1.0rc1.dist-info → apache_airflow_providers_google-19.3.0.dist-info}/entry_points.txt +0 -0
- {airflow/providers/google → apache_airflow_providers_google-19.3.0.dist-info/licenses}/LICENSE +0 -0
|
@@ -18,12 +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
|
|
|
27
|
+
from aiohttp import ClientSession
|
|
25
28
|
from google.api_core.client_options import ClientOptions
|
|
26
29
|
from google.api_core.gapic_v1.method import DEFAULT, _MethodDefault
|
|
30
|
+
from google.auth.transport.requests import AuthorizedSession, Request
|
|
27
31
|
from google.cloud.orchestration.airflow.service_v1 import (
|
|
28
32
|
EnvironmentsAsyncClient,
|
|
29
33
|
EnvironmentsClient,
|
|
@@ -31,9 +35,9 @@ from google.cloud.orchestration.airflow.service_v1 import (
|
|
|
31
35
|
PollAirflowCommandResponse,
|
|
32
36
|
)
|
|
33
37
|
|
|
34
|
-
from airflow.
|
|
38
|
+
from airflow.providers.common.compat.sdk import AirflowException
|
|
35
39
|
from airflow.providers.google.common.consts import CLIENT_INFO
|
|
36
|
-
from airflow.providers.google.common.hooks.base_google import GoogleBaseHook
|
|
40
|
+
from airflow.providers.google.common.hooks.base_google import GoogleBaseAsyncHook, GoogleBaseHook
|
|
37
41
|
|
|
38
42
|
if TYPE_CHECKING:
|
|
39
43
|
from google.api_core.operation import Operation
|
|
@@ -76,6 +80,34 @@ class CloudComposerHook(GoogleBaseHook, OperationHelper):
|
|
|
76
80
|
client_options=self.client_options,
|
|
77
81
|
)
|
|
78
82
|
|
|
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
|
|
110
|
+
|
|
79
111
|
def get_operation(self, operation_name):
|
|
80
112
|
return self.get_environment_client().transport.operations_client.get_operation(name=operation_name)
|
|
81
113
|
|
|
@@ -408,20 +440,160 @@ class CloudComposerHook(GoogleBaseHook, OperationHelper):
|
|
|
408
440
|
self.log.info("Waiting for result...")
|
|
409
441
|
time.sleep(poll_interval)
|
|
410
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
|
+
)
|
|
411
469
|
|
|
412
|
-
|
|
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.
|
|
484
|
+
|
|
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):
|
|
413
546
|
"""Hook for Google Cloud Composer async APIs."""
|
|
414
547
|
|
|
548
|
+
sync_hook_class = CloudComposerHook
|
|
549
|
+
|
|
415
550
|
client_options = ClientOptions(api_endpoint="composer.googleapis.com:443")
|
|
416
551
|
|
|
417
|
-
def get_environment_client(self) -> EnvironmentsAsyncClient:
|
|
552
|
+
async def get_environment_client(self) -> EnvironmentsAsyncClient:
|
|
418
553
|
"""Retrieve client library object that allow access Environments service."""
|
|
554
|
+
sync_hook = await self.get_sync_hook()
|
|
419
555
|
return EnvironmentsAsyncClient(
|
|
420
|
-
credentials=
|
|
556
|
+
credentials=sync_hook.get_credentials(),
|
|
421
557
|
client_info=CLIENT_INFO,
|
|
422
558
|
client_options=self.client_options,
|
|
423
559
|
)
|
|
424
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
|
+
|
|
425
597
|
def get_environment_name(self, project_id, region, environment_id):
|
|
426
598
|
return f"projects/{project_id}/locations/{region}/environments/{environment_id}"
|
|
427
599
|
|
|
@@ -429,9 +601,8 @@ class CloudComposerAsyncHook(GoogleBaseHook):
|
|
|
429
601
|
return f"projects/{project_id}/locations/{region}"
|
|
430
602
|
|
|
431
603
|
async def get_operation(self, operation_name):
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
)
|
|
604
|
+
client = await self.get_environment_client()
|
|
605
|
+
return await client.transport.operations_client.get_operation(name=operation_name)
|
|
435
606
|
|
|
436
607
|
@GoogleBaseHook.fallback_to_default_project_id
|
|
437
608
|
async def create_environment(
|
|
@@ -454,7 +625,7 @@ class CloudComposerAsyncHook(GoogleBaseHook):
|
|
|
454
625
|
:param timeout: The timeout for this request.
|
|
455
626
|
:param metadata: Strings which should be sent along with the request as metadata.
|
|
456
627
|
"""
|
|
457
|
-
client = self.get_environment_client()
|
|
628
|
+
client = await self.get_environment_client()
|
|
458
629
|
return await client.create_environment(
|
|
459
630
|
request={"parent": self.get_parent(project_id, region), "environment": environment},
|
|
460
631
|
retry=retry,
|
|
@@ -482,7 +653,7 @@ class CloudComposerAsyncHook(GoogleBaseHook):
|
|
|
482
653
|
:param timeout: The timeout for this request.
|
|
483
654
|
:param metadata: Strings which should be sent along with the request as metadata.
|
|
484
655
|
"""
|
|
485
|
-
client = self.get_environment_client()
|
|
656
|
+
client = await self.get_environment_client()
|
|
486
657
|
name = self.get_environment_name(project_id, region, environment_id)
|
|
487
658
|
return await client.delete_environment(
|
|
488
659
|
request={"name": name}, retry=retry, timeout=timeout, metadata=metadata
|
|
@@ -518,7 +689,7 @@ class CloudComposerAsyncHook(GoogleBaseHook):
|
|
|
518
689
|
:param timeout: The timeout for this request.
|
|
519
690
|
:param metadata: Strings which should be sent along with the request as metadata.
|
|
520
691
|
"""
|
|
521
|
-
client = self.get_environment_client()
|
|
692
|
+
client = await self.get_environment_client()
|
|
522
693
|
name = self.get_environment_name(project_id, region, environment_id)
|
|
523
694
|
|
|
524
695
|
return await client.update_environment(
|
|
@@ -528,6 +699,35 @@ class CloudComposerAsyncHook(GoogleBaseHook):
|
|
|
528
699
|
metadata=metadata,
|
|
529
700
|
)
|
|
530
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
|
+
|
|
531
731
|
@GoogleBaseHook.fallback_to_default_project_id
|
|
532
732
|
async def execute_airflow_command(
|
|
533
733
|
self,
|
|
@@ -556,7 +756,7 @@ class CloudComposerAsyncHook(GoogleBaseHook):
|
|
|
556
756
|
:param timeout: The timeout for this request.
|
|
557
757
|
:param metadata: Strings which should be sent along with the request as metadata.
|
|
558
758
|
"""
|
|
559
|
-
client = self.get_environment_client()
|
|
759
|
+
client = await self.get_environment_client()
|
|
560
760
|
|
|
561
761
|
return await client.execute_airflow_command(
|
|
562
762
|
request={
|
|
@@ -598,7 +798,7 @@ class CloudComposerAsyncHook(GoogleBaseHook):
|
|
|
598
798
|
:param timeout: The timeout for this request.
|
|
599
799
|
:param metadata: Strings which should be sent along with the request as metadata.
|
|
600
800
|
"""
|
|
601
|
-
client = self.get_environment_client()
|
|
801
|
+
client = await self.get_environment_client()
|
|
602
802
|
|
|
603
803
|
return await client.poll_airflow_command(
|
|
604
804
|
request={
|
|
@@ -642,9 +842,82 @@ class CloudComposerAsyncHook(GoogleBaseHook):
|
|
|
642
842
|
self.log.exception("Exception occurred while polling CMD result")
|
|
643
843
|
raise AirflowException(ex)
|
|
644
844
|
|
|
645
|
-
|
|
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
|
+
|
|
646
851
|
if result_dict["output_end"]:
|
|
647
852
|
return result_dict
|
|
648
853
|
|
|
649
854
|
self.log.info("Sleeping for %s seconds.", poll_interval)
|
|
650
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
|
|
@@ -0,0 +1,109 @@
|
|
|
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
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
from collections.abc import Sequence
|
|
21
|
+
from typing import TYPE_CHECKING
|
|
22
|
+
|
|
23
|
+
from google.cloud.logging_v2.services.config_service_v2 import ConfigServiceV2Client
|
|
24
|
+
from google.cloud.logging_v2.types import (
|
|
25
|
+
CreateSinkRequest,
|
|
26
|
+
DeleteSinkRequest,
|
|
27
|
+
GetSinkRequest,
|
|
28
|
+
ListSinksRequest,
|
|
29
|
+
LogSink,
|
|
30
|
+
UpdateSinkRequest,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
from airflow.providers.google.common.consts import CLIENT_INFO
|
|
34
|
+
from airflow.providers.google.common.hooks.base_google import PROVIDE_PROJECT_ID, GoogleBaseHook
|
|
35
|
+
|
|
36
|
+
if TYPE_CHECKING:
|
|
37
|
+
from google.protobuf.field_mask_pb2 import FieldMask
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class CloudLoggingHook(GoogleBaseHook):
|
|
41
|
+
"""
|
|
42
|
+
Hook for Google Cloud Logging Log Sinks API.
|
|
43
|
+
|
|
44
|
+
:param gcp_conn_id: The connection ID to use when fetching connection info.
|
|
45
|
+
:param impersonation_chain: Optional service account to impersonate.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
def __init__(
|
|
49
|
+
self,
|
|
50
|
+
gcp_conn_id: str = "google_cloud_default",
|
|
51
|
+
impersonation_chain: str | Sequence[str] | None = None,
|
|
52
|
+
**kwargs,
|
|
53
|
+
) -> None:
|
|
54
|
+
super().__init__(gcp_conn_id=gcp_conn_id, impersonation_chain=impersonation_chain, **kwargs)
|
|
55
|
+
self._client: ConfigServiceV2Client | None = None
|
|
56
|
+
|
|
57
|
+
def get_conn(self) -> ConfigServiceV2Client:
|
|
58
|
+
"""Return the Google Cloud Logging Config client."""
|
|
59
|
+
if not self._client:
|
|
60
|
+
self._client = ConfigServiceV2Client(credentials=self.get_credentials(), client_info=CLIENT_INFO)
|
|
61
|
+
return self._client
|
|
62
|
+
|
|
63
|
+
def get_parent(self, project_id):
|
|
64
|
+
return f"projects/{project_id}"
|
|
65
|
+
|
|
66
|
+
@GoogleBaseHook.fallback_to_default_project_id
|
|
67
|
+
def create_sink(
|
|
68
|
+
self, sink: LogSink | dict, unique_writer_identity: bool = True, project_id: str = PROVIDE_PROJECT_ID
|
|
69
|
+
) -> LogSink:
|
|
70
|
+
if isinstance(sink, dict):
|
|
71
|
+
sink = LogSink(**sink)
|
|
72
|
+
request = CreateSinkRequest(
|
|
73
|
+
parent=self.get_parent(project_id), sink=sink, unique_writer_identity=unique_writer_identity
|
|
74
|
+
)
|
|
75
|
+
return self.get_conn().create_sink(request=request)
|
|
76
|
+
|
|
77
|
+
@GoogleBaseHook.fallback_to_default_project_id
|
|
78
|
+
def get_sink(self, sink_name: str, project_id: str = PROVIDE_PROJECT_ID) -> LogSink:
|
|
79
|
+
request = GetSinkRequest(sink_name=f"projects/{project_id}/sinks/{sink_name}")
|
|
80
|
+
return self.get_conn().get_sink(request=request)
|
|
81
|
+
|
|
82
|
+
@GoogleBaseHook.fallback_to_default_project_id
|
|
83
|
+
def list_sinks(self, page_size: int | None = None, project_id: str = PROVIDE_PROJECT_ID) -> list[LogSink]:
|
|
84
|
+
request = ListSinksRequest(parent=self.get_parent(project_id), page_size=page_size)
|
|
85
|
+
return list(self.get_conn().list_sinks(request=request))
|
|
86
|
+
|
|
87
|
+
@GoogleBaseHook.fallback_to_default_project_id
|
|
88
|
+
def delete_sink(self, sink_name: str, project_id: str = PROVIDE_PROJECT_ID) -> None:
|
|
89
|
+
request = DeleteSinkRequest(sink_name=f"projects/{project_id}/sinks/{sink_name}")
|
|
90
|
+
self.get_conn().delete_sink(request=request)
|
|
91
|
+
|
|
92
|
+
@GoogleBaseHook.fallback_to_default_project_id
|
|
93
|
+
def update_sink(
|
|
94
|
+
self,
|
|
95
|
+
sink_name: str,
|
|
96
|
+
sink: LogSink | dict,
|
|
97
|
+
unique_writer_identity: bool,
|
|
98
|
+
update_mask: FieldMask | dict,
|
|
99
|
+
project_id: str = PROVIDE_PROJECT_ID,
|
|
100
|
+
) -> LogSink:
|
|
101
|
+
if isinstance(sink, dict):
|
|
102
|
+
sink = LogSink(**sink)
|
|
103
|
+
request = UpdateSinkRequest(
|
|
104
|
+
sink_name=f"projects/{project_id}/sinks/{sink_name}",
|
|
105
|
+
sink=sink,
|
|
106
|
+
unique_writer_identity=unique_writer_identity,
|
|
107
|
+
update_mask=update_mask,
|
|
108
|
+
)
|
|
109
|
+
return self.get_conn().update_sink(request=request)
|
|
@@ -45,7 +45,7 @@ from google.cloud.redis_v1 import (
|
|
|
45
45
|
)
|
|
46
46
|
|
|
47
47
|
from airflow import version
|
|
48
|
-
from airflow.
|
|
48
|
+
from airflow.providers.common.compat.sdk import AirflowException
|
|
49
49
|
from airflow.providers.google.common.hooks.base_google import PROVIDE_PROJECT_ID, GoogleBaseHook
|
|
50
50
|
|
|
51
51
|
if TYPE_CHECKING:
|
|
@@ -38,11 +38,15 @@ from google.cloud.run_v2 import (
|
|
|
38
38
|
ServicesClient,
|
|
39
39
|
UpdateJobRequest,
|
|
40
40
|
)
|
|
41
|
-
from google.longrunning import operations_pb2
|
|
41
|
+
from google.longrunning import operations_pb2
|
|
42
42
|
|
|
43
|
-
from airflow.
|
|
43
|
+
from airflow.providers.common.compat.sdk import AirflowException
|
|
44
44
|
from airflow.providers.google.common.consts import CLIENT_INFO
|
|
45
|
-
from airflow.providers.google.common.hooks.base_google import
|
|
45
|
+
from airflow.providers.google.common.hooks.base_google import (
|
|
46
|
+
PROVIDE_PROJECT_ID,
|
|
47
|
+
GoogleBaseAsyncHook,
|
|
48
|
+
GoogleBaseHook,
|
|
49
|
+
)
|
|
46
50
|
|
|
47
51
|
if TYPE_CHECKING:
|
|
48
52
|
from google.api_core import operation
|
|
@@ -159,7 +163,7 @@ class CloudRunHook(GoogleBaseHook):
|
|
|
159
163
|
return list(itertools.islice(jobs, limit))
|
|
160
164
|
|
|
161
165
|
|
|
162
|
-
class CloudRunAsyncHook(
|
|
166
|
+
class CloudRunAsyncHook(GoogleBaseAsyncHook):
|
|
163
167
|
"""
|
|
164
168
|
Async hook for the Google Cloud Run service.
|
|
165
169
|
|
|
@@ -174,6 +178,8 @@ class CloudRunAsyncHook(GoogleBaseHook):
|
|
|
174
178
|
account from the list granting this role to the originating account.
|
|
175
179
|
"""
|
|
176
180
|
|
|
181
|
+
sync_hook_class = CloudRunHook
|
|
182
|
+
|
|
177
183
|
def __init__(
|
|
178
184
|
self,
|
|
179
185
|
gcp_conn_id: str = "google_cloud_default",
|
|
@@ -183,16 +189,16 @@ class CloudRunAsyncHook(GoogleBaseHook):
|
|
|
183
189
|
self._client: JobsAsyncClient | None = None
|
|
184
190
|
super().__init__(gcp_conn_id=gcp_conn_id, impersonation_chain=impersonation_chain, **kwargs)
|
|
185
191
|
|
|
186
|
-
def get_conn(self):
|
|
192
|
+
async def get_conn(self):
|
|
187
193
|
if self._client is None:
|
|
188
|
-
|
|
194
|
+
sync_hook = await self.get_sync_hook()
|
|
195
|
+
self._client = JobsAsyncClient(credentials=sync_hook.get_credentials(), client_info=CLIENT_INFO)
|
|
189
196
|
|
|
190
197
|
return self._client
|
|
191
198
|
|
|
192
199
|
async def get_operation(self, operation_name: str) -> operations_pb2.Operation:
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
)
|
|
200
|
+
conn = await self.get_conn()
|
|
201
|
+
return await conn.get_operation(operations_pb2.GetOperationRequest(name=operation_name), timeout=120)
|
|
196
202
|
|
|
197
203
|
|
|
198
204
|
class CloudRunServiceHook(GoogleBaseHook):
|
|
@@ -258,7 +264,7 @@ class CloudRunServiceHook(GoogleBaseHook):
|
|
|
258
264
|
return operation.result()
|
|
259
265
|
|
|
260
266
|
|
|
261
|
-
class CloudRunServiceAsyncHook(
|
|
267
|
+
class CloudRunServiceAsyncHook(GoogleBaseAsyncHook):
|
|
262
268
|
"""
|
|
263
269
|
Async hook for the Google Cloud Run services.
|
|
264
270
|
|
|
@@ -273,6 +279,8 @@ class CloudRunServiceAsyncHook(GoogleBaseHook):
|
|
|
273
279
|
account from the list granting this role to the originating account.
|
|
274
280
|
"""
|
|
275
281
|
|
|
282
|
+
sync_hook_class = CloudRunServiceHook
|
|
283
|
+
|
|
276
284
|
def __init__(
|
|
277
285
|
self,
|
|
278
286
|
gcp_conn_id: str = "google_cloud_default",
|