apache-airflow-providers-amazon 8.27.0rc1__py3-none-any.whl → 8.28.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/amazon/__init__.py +3 -3
- airflow/providers/amazon/aws/hooks/batch_client.py +3 -0
- airflow/providers/amazon/aws/hooks/rds.py +2 -2
- airflow/providers/amazon/aws/operators/batch.py +8 -0
- airflow/providers/amazon/aws/operators/emr.py +23 -23
- airflow/providers/amazon/aws/operators/redshift_cluster.py +67 -51
- airflow/providers/amazon/aws/operators/redshift_data.py +3 -3
- airflow/providers/amazon/aws/operators/sagemaker.py +4 -15
- airflow/providers/amazon/aws/sensors/athena.py +2 -6
- airflow/providers/amazon/aws/sensors/batch.py +7 -33
- airflow/providers/amazon/aws/sensors/bedrock.py +1 -4
- airflow/providers/amazon/aws/sensors/cloud_formation.py +2 -11
- airflow/providers/amazon/aws/sensors/comprehend.py +1 -7
- airflow/providers/amazon/aws/sensors/dms.py +5 -11
- airflow/providers/amazon/aws/sensors/ec2.py +2 -6
- airflow/providers/amazon/aws/sensors/ecs.py +4 -6
- airflow/providers/amazon/aws/sensors/eks.py +5 -7
- airflow/providers/amazon/aws/sensors/emr.py +9 -36
- airflow/providers/amazon/aws/sensors/glacier.py +2 -6
- airflow/providers/amazon/aws/sensors/glue.py +0 -9
- airflow/providers/amazon/aws/sensors/glue_catalog_partition.py +2 -6
- airflow/providers/amazon/aws/sensors/glue_crawler.py +2 -6
- airflow/providers/amazon/aws/sensors/kinesis_analytics.py +1 -4
- airflow/providers/amazon/aws/sensors/lambda_function.py +4 -6
- airflow/providers/amazon/aws/sensors/opensearch_serverless.py +1 -4
- airflow/providers/amazon/aws/sensors/quicksight.py +2 -5
- airflow/providers/amazon/aws/sensors/redshift_cluster.py +2 -6
- airflow/providers/amazon/aws/sensors/s3.py +3 -14
- airflow/providers/amazon/aws/sensors/sagemaker.py +4 -6
- airflow/providers/amazon/aws/sensors/sqs.py +3 -11
- airflow/providers/amazon/aws/sensors/step_function.py +2 -6
- airflow/providers/amazon/aws/transfers/dynamodb_to_s3.py +41 -10
- airflow/providers/amazon/aws/triggers/eks.py +2 -4
- airflow/providers/amazon/aws/triggers/sagemaker.py +9 -1
- airflow/providers/amazon/aws/utils/task_log_fetcher.py +12 -0
- airflow/providers/amazon/get_provider_info.py +3 -2
- {apache_airflow_providers_amazon-8.27.0rc1.dist-info → apache_airflow_providers_amazon-8.28.0.dist-info}/METADATA +12 -12
- {apache_airflow_providers_amazon-8.27.0rc1.dist-info → apache_airflow_providers_amazon-8.28.0.dist-info}/RECORD +40 -40
- {apache_airflow_providers_amazon-8.27.0rc1.dist-info → apache_airflow_providers_amazon-8.28.0.dist-info}/WHEEL +0 -0
- {apache_airflow_providers_amazon-8.27.0rc1.dist-info → apache_airflow_providers_amazon-8.28.0.dist-info}/entry_points.txt +0 -0
@@ -29,11 +29,11 @@ from airflow import __version__ as airflow_version
|
|
29
29
|
|
30
30
|
__all__ = ["__version__"]
|
31
31
|
|
32
|
-
__version__ = "8.
|
32
|
+
__version__ = "8.28.0"
|
33
33
|
|
34
34
|
if packaging.version.parse(packaging.version.parse(airflow_version).base_version) < packaging.version.parse(
|
35
|
-
"2.
|
35
|
+
"2.8.0"
|
36
36
|
):
|
37
37
|
raise RuntimeError(
|
38
|
-
f"The package `apache-airflow-providers-amazon:{__version__}` needs Apache Airflow 2.
|
38
|
+
f"The package `apache-airflow-providers-amazon:{__version__}` needs Apache Airflow 2.8.0+"
|
39
39
|
)
|
@@ -103,6 +103,7 @@ class BatchProtocol(Protocol):
|
|
103
103
|
parameters: dict,
|
104
104
|
containerOverrides: dict,
|
105
105
|
ecsPropertiesOverride: dict,
|
106
|
+
eksPropertiesOverride: dict,
|
106
107
|
tags: dict,
|
107
108
|
) -> dict:
|
108
109
|
"""
|
@@ -122,6 +123,8 @@ class BatchProtocol(Protocol):
|
|
122
123
|
|
123
124
|
:param ecsPropertiesOverride: the same parameter that boto3 will receive
|
124
125
|
|
126
|
+
:param eksPropertiesOverride: the same parameter that boto3 will receive
|
127
|
+
|
125
128
|
:param tags: the same parameter that boto3 will receive
|
126
129
|
|
127
130
|
:return: an API response
|
@@ -155,7 +155,7 @@ class RdsHook(AwsGenericHook["RDSClient"]):
|
|
155
155
|
try:
|
156
156
|
response = self.conn.describe_export_tasks(ExportTaskIdentifier=export_task_id)
|
157
157
|
except self.conn.exceptions.ClientError as e:
|
158
|
-
if e.response["Error"]["Code"]
|
158
|
+
if e.response["Error"]["Code"] in ("ExportTaskNotFound", "ExportTaskNotFoundFault"):
|
159
159
|
raise AirflowNotFoundException(e)
|
160
160
|
raise e
|
161
161
|
return response["ExportTasks"][0]["Status"].lower()
|
@@ -196,7 +196,7 @@ class RdsHook(AwsGenericHook["RDSClient"]):
|
|
196
196
|
try:
|
197
197
|
response = self.conn.describe_event_subscriptions(SubscriptionName=subscription_name)
|
198
198
|
except self.conn.exceptions.ClientError as e:
|
199
|
-
if e.response["Error"]["Code"]
|
199
|
+
if e.response["Error"]["Code"] in ("SubscriptionNotFoundFault", "SubscriptionNotFound"):
|
200
200
|
raise AirflowNotFoundException(e)
|
201
201
|
raise e
|
202
202
|
return response["EventSubscriptionsList"][0]["Status"].lower()
|
@@ -68,6 +68,7 @@ class BatchOperator(BaseOperator):
|
|
68
68
|
:param overrides: DEPRECATED, use container_overrides instead with the same value.
|
69
69
|
:param container_overrides: the `containerOverrides` parameter for boto3 (templated)
|
70
70
|
:param ecs_properties_override: the `ecsPropertiesOverride` parameter for boto3 (templated)
|
71
|
+
:param eks_properties_override: the `eksPropertiesOverride` parameter for boto3 (templated)
|
71
72
|
:param node_overrides: the `nodeOverrides` parameter for boto3 (templated)
|
72
73
|
:param share_identifier: The share identifier for the job. Don't specify this parameter if the job queue
|
73
74
|
doesn't have a scheduling policy.
|
@@ -116,6 +117,7 @@ class BatchOperator(BaseOperator):
|
|
116
117
|
"container_overrides",
|
117
118
|
"array_properties",
|
118
119
|
"ecs_properties_override",
|
120
|
+
"eks_properties_override",
|
119
121
|
"node_overrides",
|
120
122
|
"parameters",
|
121
123
|
"retry_strategy",
|
@@ -129,6 +131,7 @@ class BatchOperator(BaseOperator):
|
|
129
131
|
"container_overrides": "json",
|
130
132
|
"parameters": "json",
|
131
133
|
"ecs_properties_override": "json",
|
134
|
+
"eks_properties_override": "json",
|
132
135
|
"node_overrides": "json",
|
133
136
|
"retry_strategy": "json",
|
134
137
|
}
|
@@ -166,6 +169,7 @@ class BatchOperator(BaseOperator):
|
|
166
169
|
container_overrides: dict | None = None,
|
167
170
|
array_properties: dict | None = None,
|
168
171
|
ecs_properties_override: dict | None = None,
|
172
|
+
eks_properties_override: dict | None = None,
|
169
173
|
node_overrides: dict | None = None,
|
170
174
|
share_identifier: str | None = None,
|
171
175
|
scheduling_priority_override: int | None = None,
|
@@ -208,6 +212,7 @@ class BatchOperator(BaseOperator):
|
|
208
212
|
)
|
209
213
|
|
210
214
|
self.ecs_properties_override = ecs_properties_override
|
215
|
+
self.eks_properties_override = eks_properties_override
|
211
216
|
self.node_overrides = node_overrides
|
212
217
|
self.share_identifier = share_identifier
|
213
218
|
self.scheduling_priority_override = scheduling_priority_override
|
@@ -307,6 +312,8 @@ class BatchOperator(BaseOperator):
|
|
307
312
|
self.log.info("AWS Batch job - array properties: %s", self.array_properties)
|
308
313
|
if self.ecs_properties_override:
|
309
314
|
self.log.info("AWS Batch job - ECS properties: %s", self.ecs_properties_override)
|
315
|
+
if self.eks_properties_override:
|
316
|
+
self.log.info("AWS Batch job - EKS properties: %s", self.eks_properties_override)
|
310
317
|
if self.node_overrides:
|
311
318
|
self.log.info("AWS Batch job - node properties: %s", self.node_overrides)
|
312
319
|
|
@@ -319,6 +326,7 @@ class BatchOperator(BaseOperator):
|
|
319
326
|
"tags": self.tags,
|
320
327
|
"containerOverrides": self.container_overrides,
|
321
328
|
"ecsPropertiesOverride": self.ecs_properties_override,
|
329
|
+
"eksPropertiesOverride": self.eks_properties_override,
|
322
330
|
"nodeOverrides": self.node_overrides,
|
323
331
|
"retryStrategy": self.retry_strategy,
|
324
332
|
"shareIdentifier": self.share_identifier,
|
@@ -1382,30 +1382,30 @@ class EmrServerlessStartJobOperator(BaseOperator):
|
|
1382
1382
|
|
1383
1383
|
self.persist_links(context)
|
1384
1384
|
|
1385
|
-
if self.deferrable:
|
1386
|
-
self.defer(
|
1387
|
-
trigger=EmrServerlessStartJobTrigger(
|
1388
|
-
application_id=self.application_id,
|
1389
|
-
job_id=self.job_id,
|
1390
|
-
waiter_delay=self.waiter_delay,
|
1391
|
-
waiter_max_attempts=self.waiter_max_attempts,
|
1392
|
-
aws_conn_id=self.aws_conn_id,
|
1393
|
-
),
|
1394
|
-
method_name="execute_complete",
|
1395
|
-
timeout=timedelta(seconds=self.waiter_max_attempts * self.waiter_delay),
|
1396
|
-
)
|
1397
|
-
|
1398
1385
|
if self.wait_for_completion:
|
1399
|
-
|
1400
|
-
|
1401
|
-
|
1402
|
-
|
1403
|
-
|
1404
|
-
|
1405
|
-
|
1406
|
-
|
1407
|
-
|
1408
|
-
|
1386
|
+
if self.deferrable:
|
1387
|
+
self.defer(
|
1388
|
+
trigger=EmrServerlessStartJobTrigger(
|
1389
|
+
application_id=self.application_id,
|
1390
|
+
job_id=self.job_id,
|
1391
|
+
waiter_delay=self.waiter_delay,
|
1392
|
+
waiter_max_attempts=self.waiter_max_attempts,
|
1393
|
+
aws_conn_id=self.aws_conn_id,
|
1394
|
+
),
|
1395
|
+
method_name="execute_complete",
|
1396
|
+
timeout=timedelta(seconds=self.waiter_max_attempts * self.waiter_delay),
|
1397
|
+
)
|
1398
|
+
else:
|
1399
|
+
waiter = self.hook.get_waiter("serverless_job_completed")
|
1400
|
+
wait(
|
1401
|
+
waiter=waiter,
|
1402
|
+
waiter_max_attempts=self.waiter_max_attempts,
|
1403
|
+
waiter_delay=self.waiter_delay,
|
1404
|
+
args={"applicationId": self.application_id, "jobRunId": self.job_id},
|
1405
|
+
failure_message="Serverless Job failed",
|
1406
|
+
status_message="Serverless Job status is",
|
1407
|
+
status_args=["jobRun.state", "jobRun.stateDetails"],
|
1408
|
+
)
|
1409
1409
|
|
1410
1410
|
return self.job_id
|
1411
1411
|
|
@@ -32,6 +32,7 @@ from airflow.providers.amazon.aws.triggers.redshift_cluster import (
|
|
32
32
|
RedshiftResumeClusterTrigger,
|
33
33
|
)
|
34
34
|
from airflow.providers.amazon.aws.utils import validate_execute_complete_event
|
35
|
+
from airflow.utils.helpers import prune_dict
|
35
36
|
|
36
37
|
if TYPE_CHECKING:
|
37
38
|
from airflow.utils.context import Context
|
@@ -507,8 +508,8 @@ class RedshiftResumeClusterOperator(BaseOperator):
|
|
507
508
|
aws_conn_id: str | None = "aws_default",
|
508
509
|
wait_for_completion: bool = False,
|
509
510
|
deferrable: bool = conf.getboolean("operators", "default_deferrable", fallback=False),
|
510
|
-
poll_interval: int =
|
511
|
-
max_attempts: int =
|
511
|
+
poll_interval: int = 30,
|
512
|
+
max_attempts: int = 30,
|
512
513
|
**kwargs,
|
513
514
|
):
|
514
515
|
super().__init__(**kwargs)
|
@@ -542,38 +543,38 @@ class RedshiftResumeClusterOperator(BaseOperator):
|
|
542
543
|
else:
|
543
544
|
raise error
|
544
545
|
|
545
|
-
if self.
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
546
|
+
if self.wait_for_completion:
|
547
|
+
if self.deferrable:
|
548
|
+
cluster_state = redshift_hook.cluster_status(cluster_identifier=self.cluster_identifier)
|
549
|
+
if cluster_state == "available":
|
550
|
+
self.log.info("Resumed cluster successfully")
|
551
|
+
elif cluster_state == "deleting":
|
552
|
+
raise AirflowException(
|
553
|
+
"Unable to resume cluster since cluster is currently in status: %s", cluster_state
|
554
|
+
)
|
555
|
+
else:
|
556
|
+
self.defer(
|
557
|
+
trigger=RedshiftResumeClusterTrigger(
|
558
|
+
cluster_identifier=self.cluster_identifier,
|
559
|
+
waiter_delay=self.poll_interval,
|
560
|
+
waiter_max_attempts=self.max_attempts,
|
561
|
+
aws_conn_id=self.aws_conn_id,
|
562
|
+
),
|
563
|
+
method_name="execute_complete",
|
564
|
+
# timeout is set to ensure that if a trigger dies, the timeout does not restart
|
565
|
+
# 60 seconds is added to allow the trigger to exit gracefully (i.e. yield TriggerEvent)
|
566
|
+
timeout=timedelta(seconds=self.max_attempts * self.poll_interval + 60),
|
567
|
+
)
|
553
568
|
else:
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
method_name="execute_complete",
|
562
|
-
# timeout is set to ensure that if a trigger dies, the timeout does not restart
|
563
|
-
# 60 seconds is added to allow the trigger to exit gracefully (i.e. yield TriggerEvent)
|
564
|
-
timeout=timedelta(seconds=self.max_attempts * self.poll_interval + 60),
|
569
|
+
waiter = redshift_hook.get_waiter("cluster_resumed")
|
570
|
+
waiter.wait(
|
571
|
+
ClusterIdentifier=self.cluster_identifier,
|
572
|
+
WaiterConfig={
|
573
|
+
"Delay": self.poll_interval,
|
574
|
+
"MaxAttempts": self.max_attempts,
|
575
|
+
},
|
565
576
|
)
|
566
577
|
|
567
|
-
if self.wait_for_completion:
|
568
|
-
waiter = redshift_hook.get_waiter("cluster_resumed")
|
569
|
-
waiter.wait(
|
570
|
-
ClusterIdentifier=self.cluster_identifier,
|
571
|
-
WaiterConfig={
|
572
|
-
"Delay": self.poll_interval,
|
573
|
-
"MaxAttempts": self.max_attempts,
|
574
|
-
},
|
575
|
-
)
|
576
|
-
|
577
578
|
def execute_complete(self, context: Context, event: dict[str, Any] | None = None) -> None:
|
578
579
|
event = validate_execute_complete_event(event)
|
579
580
|
|
@@ -596,6 +597,7 @@ class RedshiftPauseClusterOperator(BaseOperator):
|
|
596
597
|
running Airflow in a distributed manner and aws_conn_id is None or
|
597
598
|
empty, then default boto3 configuration would be used (and must be
|
598
599
|
maintained on each worker node).
|
600
|
+
:param wait_for_completion: If True, waits for the cluster to be paused. (default: False)
|
599
601
|
:param deferrable: Run operator in the deferrable mode
|
600
602
|
:param poll_interval: Time (in seconds) to wait between two consecutive calls to check cluster state
|
601
603
|
:param max_attempts: Maximum number of attempts to poll the cluster
|
@@ -610,14 +612,16 @@ class RedshiftPauseClusterOperator(BaseOperator):
|
|
610
612
|
*,
|
611
613
|
cluster_identifier: str,
|
612
614
|
aws_conn_id: str | None = "aws_default",
|
615
|
+
wait_for_completion: bool = False,
|
613
616
|
deferrable: bool = conf.getboolean("operators", "default_deferrable", fallback=False),
|
614
|
-
poll_interval: int =
|
615
|
-
max_attempts: int =
|
617
|
+
poll_interval: int = 30,
|
618
|
+
max_attempts: int = 30,
|
616
619
|
**kwargs,
|
617
620
|
):
|
618
621
|
super().__init__(**kwargs)
|
619
622
|
self.cluster_identifier = cluster_identifier
|
620
623
|
self.aws_conn_id = aws_conn_id
|
624
|
+
self.wait_for_completion = wait_for_completion
|
621
625
|
self.deferrable = deferrable
|
622
626
|
self.max_attempts = max_attempts
|
623
627
|
self.poll_interval = poll_interval
|
@@ -643,26 +647,38 @@ class RedshiftPauseClusterOperator(BaseOperator):
|
|
643
647
|
time.sleep(self._attempt_interval)
|
644
648
|
else:
|
645
649
|
raise error
|
646
|
-
if self.
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
650
|
+
if self.wait_for_completion:
|
651
|
+
if self.deferrable:
|
652
|
+
cluster_state = redshift_hook.cluster_status(cluster_identifier=self.cluster_identifier)
|
653
|
+
if cluster_state == "paused":
|
654
|
+
self.log.info("Paused cluster successfully")
|
655
|
+
elif cluster_state == "deleting":
|
656
|
+
raise AirflowException(
|
657
|
+
f"Unable to pause cluster since cluster is currently in status: {cluster_state}"
|
658
|
+
)
|
659
|
+
else:
|
660
|
+
self.defer(
|
661
|
+
trigger=RedshiftPauseClusterTrigger(
|
662
|
+
cluster_identifier=self.cluster_identifier,
|
663
|
+
waiter_delay=self.poll_interval,
|
664
|
+
waiter_max_attempts=self.max_attempts,
|
665
|
+
aws_conn_id=self.aws_conn_id,
|
666
|
+
),
|
667
|
+
method_name="execute_complete",
|
668
|
+
# timeout is set to ensure that if a trigger dies, the timeout does not restart
|
669
|
+
# 60 seconds is added to allow the trigger to exit gracefully (i.e. yield TriggerEvent)
|
670
|
+
timeout=timedelta(seconds=self.max_attempts * self.poll_interval + 60),
|
671
|
+
)
|
654
672
|
else:
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
673
|
+
waiter = redshift_hook.get_waiter("cluster_paused")
|
674
|
+
waiter.wait(
|
675
|
+
ClusterIdentifier=self.cluster_identifier,
|
676
|
+
WaiterConfig=prune_dict(
|
677
|
+
{
|
678
|
+
"Delay": self.poll_interval,
|
679
|
+
"MaxAttempts": self.max_attempts,
|
680
|
+
}
|
661
681
|
),
|
662
|
-
method_name="execute_complete",
|
663
|
-
# timeout is set to ensure that if a trigger dies, the timeout does not restart
|
664
|
-
# 60 seconds is added to allow the trigger to exit gracefully (i.e. yield TriggerEvent)
|
665
|
-
timeout=timedelta(seconds=self.max_attempts * self.poll_interval + 60),
|
666
682
|
)
|
667
683
|
|
668
684
|
def execute_complete(self, context: Context, event: dict[str, Any] | None = None) -> None:
|
@@ -127,8 +127,8 @@ class RedshiftDataOperator(AwsBaseOperator[RedshiftDataHook]):
|
|
127
127
|
|
128
128
|
# Set wait_for_completion to False so that it waits for the status in the deferred task.
|
129
129
|
wait_for_completion = self.wait_for_completion
|
130
|
-
if self.deferrable
|
131
|
-
|
130
|
+
if self.deferrable:
|
131
|
+
wait_for_completion = False
|
132
132
|
|
133
133
|
self.statement_id = self.hook.execute_query(
|
134
134
|
database=self.database,
|
@@ -144,7 +144,7 @@ class RedshiftDataOperator(AwsBaseOperator[RedshiftDataHook]):
|
|
144
144
|
poll_interval=self.poll_interval,
|
145
145
|
)
|
146
146
|
|
147
|
-
if self.deferrable:
|
147
|
+
if self.deferrable and self.wait_for_completion:
|
148
148
|
is_finished = self.hook.check_query_is_finished(self.statement_id)
|
149
149
|
if not is_finished:
|
150
150
|
self.defer(
|
@@ -36,7 +36,6 @@ from airflow.providers.amazon.aws.hooks.sagemaker import (
|
|
36
36
|
)
|
37
37
|
from airflow.providers.amazon.aws.triggers.sagemaker import (
|
38
38
|
SageMakerPipelineTrigger,
|
39
|
-
SageMakerTrainingPrintLogTrigger,
|
40
39
|
SageMakerTrigger,
|
41
40
|
)
|
42
41
|
from airflow.providers.amazon.aws.utils import trim_none_values, validate_execute_complete_event
|
@@ -1195,25 +1194,15 @@ class SageMakerTrainingOperator(SageMakerBaseOperator):
|
|
1195
1194
|
if self.max_ingestion_time:
|
1196
1195
|
timeout = datetime.timedelta(seconds=self.max_ingestion_time)
|
1197
1196
|
|
1198
|
-
|
1199
|
-
|
1200
|
-
trigger
|
1201
|
-
job_name=self.config["TrainingJobName"],
|
1202
|
-
poke_interval=self.check_interval,
|
1203
|
-
aws_conn_id=self.aws_conn_id,
|
1204
|
-
)
|
1205
|
-
else:
|
1206
|
-
trigger = SageMakerTrigger(
|
1197
|
+
self.defer(
|
1198
|
+
timeout=timeout,
|
1199
|
+
trigger=SageMakerTrigger(
|
1207
1200
|
job_name=self.config["TrainingJobName"],
|
1208
1201
|
job_type="Training",
|
1209
1202
|
poke_interval=self.check_interval,
|
1210
1203
|
max_attempts=self.max_attempts,
|
1211
1204
|
aws_conn_id=self.aws_conn_id,
|
1212
|
-
)
|
1213
|
-
|
1214
|
-
self.defer(
|
1215
|
-
timeout=timeout,
|
1216
|
-
trigger=trigger,
|
1205
|
+
),
|
1217
1206
|
method_name="execute_complete",
|
1218
1207
|
)
|
1219
1208
|
|
@@ -25,7 +25,7 @@ from airflow.providers.amazon.aws.utils.mixins import aws_template_fields
|
|
25
25
|
if TYPE_CHECKING:
|
26
26
|
from airflow.utils.context import Context
|
27
27
|
|
28
|
-
from airflow.exceptions import AirflowException
|
28
|
+
from airflow.exceptions import AirflowException
|
29
29
|
from airflow.providers.amazon.aws.hooks.athena import AthenaHook
|
30
30
|
|
31
31
|
|
@@ -88,11 +88,7 @@ class AthenaSensor(AwsBaseSensor[AthenaHook]):
|
|
88
88
|
state = self.hook.poll_query_status(self.query_execution_id, self.max_retries, self.sleep_time)
|
89
89
|
|
90
90
|
if state in self.FAILURE_STATES:
|
91
|
-
|
92
|
-
message = "Athena sensor failed"
|
93
|
-
if self.soft_fail:
|
94
|
-
raise AirflowSkipException(message)
|
95
|
-
raise AirflowException(message)
|
91
|
+
raise AirflowException("Athena sensor failed")
|
96
92
|
|
97
93
|
if state in self.INTERMEDIATE_STATES:
|
98
94
|
return False
|
@@ -86,18 +86,7 @@ class BatchSensor(BaseSensorOperator):
|
|
86
86
|
if state in BatchClientHook.INTERMEDIATE_STATES:
|
87
87
|
return False
|
88
88
|
|
89
|
-
|
90
|
-
# TODO: remove this if block when min_airflow_version is set to higher than 2.7.1
|
91
|
-
message = f"Batch sensor failed. AWS Batch job status: {state}"
|
92
|
-
if self.soft_fail:
|
93
|
-
raise AirflowSkipException(message)
|
94
|
-
raise AirflowException(message)
|
95
|
-
|
96
|
-
# TODO: remove this if block when min_airflow_version is set to higher than 2.7.1
|
97
|
-
message = f"Batch sensor failed. Unknown AWS Batch job status: {state}"
|
98
|
-
if self.soft_fail:
|
99
|
-
raise AirflowSkipException(message)
|
100
|
-
raise AirflowException(message)
|
89
|
+
raise AirflowException(f"Batch sensor failed. AWS Batch job status: {state}")
|
101
90
|
|
102
91
|
def execute(self, context: Context) -> None:
|
103
92
|
if not self.deferrable:
|
@@ -127,12 +116,7 @@ class BatchSensor(BaseSensorOperator):
|
|
127
116
|
Relies on trigger to throw an exception, otherwise it assumes execution was successful.
|
128
117
|
"""
|
129
118
|
if event["status"] != "success":
|
130
|
-
|
131
|
-
# TODO: remove this if-else block when min_airflow_version is set to higher than the version that
|
132
|
-
# changed in https://github.com/apache/airflow/pull/33424 is released (2.7.1)
|
133
|
-
if self.soft_fail:
|
134
|
-
raise AirflowSkipException(message)
|
135
|
-
raise AirflowException(message)
|
119
|
+
raise AirflowException(f"Error while running job: {event}")
|
136
120
|
job_id = event["job_id"]
|
137
121
|
self.log.info("Batch Job %s complete", job_id)
|
138
122
|
|
@@ -198,11 +182,7 @@ class BatchComputeEnvironmentSensor(BaseSensorOperator):
|
|
198
182
|
)
|
199
183
|
|
200
184
|
if not response["computeEnvironments"]:
|
201
|
-
|
202
|
-
# TODO: remove this if block when min_airflow_version is set to higher than 2.7.1
|
203
|
-
if self.soft_fail:
|
204
|
-
raise AirflowSkipException(message)
|
205
|
-
raise AirflowException(message)
|
185
|
+
raise AirflowException(f"AWS Batch compute environment {self.compute_environment} not found")
|
206
186
|
|
207
187
|
status = response["computeEnvironments"][0]["status"]
|
208
188
|
|
@@ -212,11 +192,9 @@ class BatchComputeEnvironmentSensor(BaseSensorOperator):
|
|
212
192
|
if status in BatchClientHook.COMPUTE_ENVIRONMENT_INTERMEDIATE_STATUS:
|
213
193
|
return False
|
214
194
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
raise AirflowSkipException(message)
|
219
|
-
raise AirflowException(message)
|
195
|
+
raise AirflowException(
|
196
|
+
f"AWS Batch compute environment failed. AWS Batch compute environment status: {status}"
|
197
|
+
)
|
220
198
|
|
221
199
|
|
222
200
|
class BatchJobQueueSensor(BaseSensorOperator):
|
@@ -276,11 +254,7 @@ class BatchJobQueueSensor(BaseSensorOperator):
|
|
276
254
|
if self.treat_non_existing_as_deleted:
|
277
255
|
return True
|
278
256
|
else:
|
279
|
-
|
280
|
-
message = f"AWS Batch job queue {self.job_queue} not found"
|
281
|
-
if self.soft_fail:
|
282
|
-
raise AirflowSkipException(message)
|
283
|
-
raise AirflowException(message)
|
257
|
+
raise AirflowException(f"AWS Batch job queue {self.job_queue} not found")
|
284
258
|
|
285
259
|
status = response["jobQueues"][0]["status"]
|
286
260
|
|
@@ -21,7 +21,7 @@ import abc
|
|
21
21
|
from typing import TYPE_CHECKING, Any, Sequence, TypeVar
|
22
22
|
|
23
23
|
from airflow.configuration import conf
|
24
|
-
from airflow.exceptions import AirflowException
|
24
|
+
from airflow.exceptions import AirflowException
|
25
25
|
from airflow.providers.amazon.aws.hooks.bedrock import BedrockAgentHook, BedrockHook
|
26
26
|
from airflow.providers.amazon.aws.sensors.base_aws import AwsBaseSensor
|
27
27
|
from airflow.providers.amazon.aws.triggers.bedrock import (
|
@@ -76,9 +76,6 @@ class BedrockBaseSensor(AwsBaseSensor[_GenericBedrockHook]):
|
|
76
76
|
def poke(self, context: Context, **kwargs) -> bool:
|
77
77
|
state = self.get_state()
|
78
78
|
if state in self.FAILURE_STATES:
|
79
|
-
# TODO: remove this if block when min_airflow_version is set to higher than 2.7.1
|
80
|
-
if self.soft_fail:
|
81
|
-
raise AirflowSkipException(self.FAILURE_MESSAGE)
|
82
79
|
raise AirflowException(self.FAILURE_MESSAGE)
|
83
80
|
|
84
81
|
return state not in self.INTERMEDIATE_STATES
|
@@ -27,7 +27,6 @@ from airflow.providers.amazon.aws.utils.mixins import aws_template_fields
|
|
27
27
|
if TYPE_CHECKING:
|
28
28
|
from airflow.utils.context import Context
|
29
29
|
|
30
|
-
from airflow.exceptions import AirflowSkipException
|
31
30
|
from airflow.providers.amazon.aws.hooks.cloud_formation import CloudFormationHook
|
32
31
|
|
33
32
|
|
@@ -67,11 +66,7 @@ class CloudFormationCreateStackSensor(AwsBaseSensor[CloudFormationHook]):
|
|
67
66
|
if stack_status in ("CREATE_IN_PROGRESS", None):
|
68
67
|
return False
|
69
68
|
|
70
|
-
|
71
|
-
message = f"Stack {self.stack_name} in bad state: {stack_status}"
|
72
|
-
if self.soft_fail:
|
73
|
-
raise AirflowSkipException(message)
|
74
|
-
raise ValueError(message)
|
69
|
+
raise ValueError(f"Stack {self.stack_name} in bad state: {stack_status}")
|
75
70
|
|
76
71
|
|
77
72
|
class CloudFormationDeleteStackSensor(AwsBaseSensor[CloudFormationHook]):
|
@@ -119,8 +114,4 @@ class CloudFormationDeleteStackSensor(AwsBaseSensor[CloudFormationHook]):
|
|
119
114
|
if stack_status == "DELETE_IN_PROGRESS":
|
120
115
|
return False
|
121
116
|
|
122
|
-
|
123
|
-
message = f"Stack {self.stack_name} in bad state: {stack_status}"
|
124
|
-
if self.soft_fail:
|
125
|
-
raise AirflowSkipException(message)
|
126
|
-
raise ValueError(message)
|
117
|
+
raise ValueError(f"Stack {self.stack_name} in bad state: {stack_status}")
|
@@ -20,7 +20,7 @@ import abc
|
|
20
20
|
from typing import TYPE_CHECKING, Any, Sequence
|
21
21
|
|
22
22
|
from airflow.configuration import conf
|
23
|
-
from airflow.exceptions import AirflowException
|
23
|
+
from airflow.exceptions import AirflowException
|
24
24
|
from airflow.providers.amazon.aws.hooks.comprehend import ComprehendHook
|
25
25
|
from airflow.providers.amazon.aws.sensors.base_aws import AwsBaseSensor
|
26
26
|
from airflow.providers.amazon.aws.triggers.comprehend import (
|
@@ -71,9 +71,6 @@ class ComprehendBaseSensor(AwsBaseSensor[ComprehendHook]):
|
|
71
71
|
def poke(self, context: Context, **kwargs) -> bool:
|
72
72
|
state = self.get_state()
|
73
73
|
if state in self.FAILURE_STATES:
|
74
|
-
# TODO: remove this if block when min_airflow_version is set to higher than 2.7.1
|
75
|
-
if self.soft_fail:
|
76
|
-
raise AirflowSkipException(self.FAILURE_MESSAGE)
|
77
74
|
raise AirflowException(self.FAILURE_MESSAGE)
|
78
75
|
|
79
76
|
return state not in self.INTERMEDIATE_STATES
|
@@ -241,9 +238,6 @@ class ComprehendCreateDocumentClassifierCompletedSensor(AwsBaseSensor[Comprehend
|
|
241
238
|
)
|
242
239
|
|
243
240
|
if status in self.FAILURE_STATES:
|
244
|
-
# TODO: remove this if block when min_airflow_version is set to higher than 2.7.1
|
245
|
-
if self.soft_fail:
|
246
|
-
raise AirflowSkipException(self.FAILURE_MESSAGE)
|
247
241
|
raise AirflowException(self.FAILURE_MESSAGE)
|
248
242
|
|
249
243
|
if status in self.SUCCESS_STATES:
|
@@ -21,7 +21,7 @@ from typing import TYPE_CHECKING, Iterable, Sequence
|
|
21
21
|
|
22
22
|
from deprecated import deprecated
|
23
23
|
|
24
|
-
from airflow.exceptions import AirflowException, AirflowProviderDeprecationWarning
|
24
|
+
from airflow.exceptions import AirflowException, AirflowProviderDeprecationWarning
|
25
25
|
from airflow.providers.amazon.aws.hooks.dms import DmsHook
|
26
26
|
from airflow.providers.amazon.aws.sensors.base_aws import AwsBaseSensor
|
27
27
|
from airflow.providers.amazon.aws.utils.mixins import aws_template_fields
|
@@ -75,11 +75,9 @@ class DmsTaskBaseSensor(AwsBaseSensor[DmsHook]):
|
|
75
75
|
|
76
76
|
def poke(self, context: Context):
|
77
77
|
if not (status := self.hook.get_task_status(self.replication_task_arn)):
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
raise AirflowSkipException(message)
|
82
|
-
raise AirflowException(message)
|
78
|
+
raise AirflowException(
|
79
|
+
f"Failed to read task status, task with ARN {self.replication_task_arn} not found"
|
80
|
+
)
|
83
81
|
|
84
82
|
self.log.info("DMS Replication task (%s) has status: %s", self.replication_task_arn, status)
|
85
83
|
|
@@ -87,11 +85,7 @@ class DmsTaskBaseSensor(AwsBaseSensor[DmsHook]):
|
|
87
85
|
return True
|
88
86
|
|
89
87
|
if status in self.termination_statuses:
|
90
|
-
|
91
|
-
message = f"Unexpected status: {status}"
|
92
|
-
if self.soft_fail:
|
93
|
-
raise AirflowSkipException(message)
|
94
|
-
raise AirflowException(message)
|
88
|
+
raise AirflowException(f"Unexpected status: {status}")
|
95
89
|
|
96
90
|
return False
|
97
91
|
|
@@ -21,7 +21,7 @@ from functools import cached_property
|
|
21
21
|
from typing import TYPE_CHECKING, Any, Sequence
|
22
22
|
|
23
23
|
from airflow.configuration import conf
|
24
|
-
from airflow.exceptions import AirflowException
|
24
|
+
from airflow.exceptions import AirflowException
|
25
25
|
from airflow.providers.amazon.aws.hooks.ec2 import EC2Hook
|
26
26
|
from airflow.providers.amazon.aws.triggers.ec2 import EC2StateSensorTrigger
|
27
27
|
from airflow.providers.amazon.aws.utils import validate_execute_complete_event
|
@@ -97,8 +97,4 @@ class EC2InstanceStateSensor(BaseSensorOperator):
|
|
97
97
|
event = validate_execute_complete_event(event)
|
98
98
|
|
99
99
|
if event["status"] != "success":
|
100
|
-
|
101
|
-
message = f"Error: {event}"
|
102
|
-
if self.soft_fail:
|
103
|
-
raise AirflowSkipException(message)
|
104
|
-
raise AirflowException(message)
|
100
|
+
raise AirflowException(f"Error: {event}")
|
@@ -19,7 +19,7 @@ from __future__ import annotations
|
|
19
19
|
from functools import cached_property
|
20
20
|
from typing import TYPE_CHECKING, Sequence
|
21
21
|
|
22
|
-
from airflow.exceptions import AirflowException
|
22
|
+
from airflow.exceptions import AirflowException
|
23
23
|
from airflow.providers.amazon.aws.hooks.ecs import (
|
24
24
|
EcsClusterStates,
|
25
25
|
EcsHook,
|
@@ -37,11 +37,9 @@ if TYPE_CHECKING:
|
|
37
37
|
|
38
38
|
def _check_failed(current_state, target_state, failure_states, soft_fail: bool) -> None:
|
39
39
|
if (current_state != target_state) and (current_state in failure_states):
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
raise AirflowSkipException(message)
|
44
|
-
raise AirflowException(message)
|
40
|
+
raise AirflowException(
|
41
|
+
f"Terminal state reached. Current state: {current_state}, Expected state: {target_state}"
|
42
|
+
)
|
45
43
|
|
46
44
|
|
47
45
|
class EcsBaseSensor(AwsBaseSensor[EcsHook]):
|