apache-airflow-providers-amazon 9.8.0rc1__py3-none-any.whl → 9.9.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/amazon/__init__.py +1 -1
- airflow/providers/amazon/aws/executors/aws_lambda/__init__.py +21 -0
- airflow/providers/amazon/aws/executors/aws_lambda/docker/Dockerfile +107 -0
- airflow/providers/amazon/aws/executors/aws_lambda/docker/__init__.py +16 -0
- airflow/providers/amazon/aws/executors/aws_lambda/docker/app.py +129 -0
- airflow/providers/amazon/aws/executors/aws_lambda/lambda_executor.py +479 -0
- airflow/providers/amazon/aws/executors/aws_lambda/utils.py +70 -0
- airflow/providers/amazon/aws/executors/ecs/ecs_executor.py +1 -1
- airflow/providers/amazon/aws/executors/ecs/ecs_executor_config.py +4 -8
- airflow/providers/amazon/aws/hooks/base_aws.py +20 -4
- airflow/providers/amazon/aws/hooks/eks.py +14 -5
- airflow/providers/amazon/aws/hooks/s3.py +101 -34
- airflow/providers/amazon/aws/hooks/sns.py +10 -1
- airflow/providers/amazon/aws/log/cloudwatch_task_handler.py +12 -5
- airflow/providers/amazon/aws/operators/batch.py +1 -2
- airflow/providers/amazon/aws/operators/cloud_formation.py +0 -2
- airflow/providers/amazon/aws/operators/comprehend.py +0 -2
- airflow/providers/amazon/aws/operators/dms.py +0 -2
- airflow/providers/amazon/aws/operators/ecs.py +1 -1
- airflow/providers/amazon/aws/operators/eks.py +13 -0
- airflow/providers/amazon/aws/operators/emr.py +4 -4
- airflow/providers/amazon/aws/operators/glue.py +0 -6
- airflow/providers/amazon/aws/operators/rds.py +0 -4
- airflow/providers/amazon/aws/operators/redshift_cluster.py +90 -63
- airflow/providers/amazon/aws/operators/sns.py +15 -1
- airflow/providers/amazon/aws/sensors/redshift_cluster.py +13 -10
- airflow/providers/amazon/get_provider_info.py +68 -0
- {apache_airflow_providers_amazon-9.8.0rc1.dist-info → apache_airflow_providers_amazon-9.9.0rc1.dist-info}/METADATA +15 -19
- {apache_airflow_providers_amazon-9.8.0rc1.dist-info → apache_airflow_providers_amazon-9.9.0rc1.dist-info}/RECORD +31 -25
- {apache_airflow_providers_amazon-9.8.0rc1.dist-info → apache_airflow_providers_amazon-9.9.0rc1.dist-info}/WHEEL +0 -0
- {apache_airflow_providers_amazon-9.8.0rc1.dist-info → apache_airflow_providers_amazon-9.9.0rc1.dist-info}/entry_points.txt +0 -0
@@ -193,6 +193,7 @@ class S3Hook(AwsBaseHook):
|
|
193
193
|
) -> None:
|
194
194
|
kwargs["client_type"] = "s3"
|
195
195
|
kwargs["aws_conn_id"] = aws_conn_id
|
196
|
+
self._requester_pays = kwargs.pop("requester_pays", False)
|
196
197
|
|
197
198
|
if transfer_config_args and not isinstance(transfer_config_args, dict):
|
198
199
|
raise TypeError(f"transfer_config_args expected dict, got {type(transfer_config_args).__name__}.")
|
@@ -409,12 +410,15 @@ class S3Hook(AwsBaseHook):
|
|
409
410
|
}
|
410
411
|
|
411
412
|
paginator = self.get_conn().get_paginator("list_objects_v2")
|
412
|
-
|
413
|
-
Bucket
|
414
|
-
Prefix
|
415
|
-
Delimiter
|
416
|
-
PaginationConfig
|
417
|
-
|
413
|
+
params = {
|
414
|
+
"Bucket": bucket_name,
|
415
|
+
"Prefix": prefix,
|
416
|
+
"Delimiter": delimiter,
|
417
|
+
"PaginationConfig": config,
|
418
|
+
}
|
419
|
+
if self._requester_pays:
|
420
|
+
params["RequestPayer"] = "requester"
|
421
|
+
response = paginator.paginate(**params)
|
418
422
|
|
419
423
|
prefixes: list[str] = []
|
420
424
|
for page in response:
|
@@ -437,7 +441,13 @@ class S3Hook(AwsBaseHook):
|
|
437
441
|
"""
|
438
442
|
head_object_val: dict[str, Any] | None = None
|
439
443
|
try:
|
440
|
-
|
444
|
+
params = {
|
445
|
+
"Bucket": bucket_name,
|
446
|
+
"Key": key,
|
447
|
+
}
|
448
|
+
if self._requester_pays:
|
449
|
+
params["RequestPayer"] = "requester"
|
450
|
+
head_object_val = await client.head_object(**params)
|
441
451
|
return head_object_val
|
442
452
|
except ClientError as e:
|
443
453
|
if e.response["ResponseMetadata"]["HTTPStatusCode"] == 404:
|
@@ -472,12 +482,15 @@ class S3Hook(AwsBaseHook):
|
|
472
482
|
}
|
473
483
|
|
474
484
|
paginator = client.get_paginator("list_objects_v2")
|
475
|
-
|
476
|
-
Bucket
|
477
|
-
Prefix
|
478
|
-
Delimiter
|
479
|
-
PaginationConfig
|
480
|
-
|
485
|
+
params = {
|
486
|
+
"Bucket": bucket_name,
|
487
|
+
"Prefix": prefix,
|
488
|
+
"Delimiter": delimiter,
|
489
|
+
"PaginationConfig": config,
|
490
|
+
}
|
491
|
+
if self._requester_pays:
|
492
|
+
params["RequestPayer"] = "requester"
|
493
|
+
response = paginator.paginate(**params)
|
481
494
|
|
482
495
|
prefixes = []
|
483
496
|
async for page in response:
|
@@ -501,7 +514,14 @@ class S3Hook(AwsBaseHook):
|
|
501
514
|
prefix = re.split(r"[\[\*\?]", key, 1)[0] if key else ""
|
502
515
|
delimiter = ""
|
503
516
|
paginator = client.get_paginator("list_objects_v2")
|
504
|
-
|
517
|
+
params = {
|
518
|
+
"Bucket": bucket_name,
|
519
|
+
"Prefix": prefix,
|
520
|
+
"Delimiter": delimiter,
|
521
|
+
}
|
522
|
+
if self._requester_pays:
|
523
|
+
params["RequestPayer"] = "requester"
|
524
|
+
response = paginator.paginate(**params)
|
505
525
|
async for page in response:
|
506
526
|
if "Contents" in page:
|
507
527
|
for row in page["Contents"]:
|
@@ -622,14 +642,21 @@ class S3Hook(AwsBaseHook):
|
|
622
642
|
prefix = re.split(r"[\[*?]", key, 1)[0]
|
623
643
|
|
624
644
|
paginator = client.get_paginator("list_objects_v2")
|
625
|
-
|
645
|
+
params = {
|
646
|
+
"Bucket": bucket,
|
647
|
+
"Prefix": prefix,
|
648
|
+
"Delimiter": delimiter,
|
649
|
+
}
|
650
|
+
if self._requester_pays:
|
651
|
+
params["RequestPayer"] = "requester"
|
652
|
+
response = paginator.paginate(**params)
|
626
653
|
async for page in response:
|
627
654
|
if "Contents" in page:
|
628
655
|
keys.extend(k for k in page["Contents"] if isinstance(k.get("Size"), (int, float)))
|
629
656
|
return keys
|
630
657
|
|
631
|
-
@staticmethod
|
632
658
|
async def _list_keys_async(
|
659
|
+
self,
|
633
660
|
client: AioBaseClient,
|
634
661
|
bucket_name: str | None = None,
|
635
662
|
prefix: str | None = None,
|
@@ -655,12 +682,15 @@ class S3Hook(AwsBaseHook):
|
|
655
682
|
}
|
656
683
|
|
657
684
|
paginator = client.get_paginator("list_objects_v2")
|
658
|
-
|
659
|
-
Bucket
|
660
|
-
Prefix
|
661
|
-
Delimiter
|
662
|
-
PaginationConfig
|
663
|
-
|
685
|
+
params = {
|
686
|
+
"Bucket": bucket_name,
|
687
|
+
"Prefix": prefix,
|
688
|
+
"Delimiter": delimiter,
|
689
|
+
"PaginationConfig": config,
|
690
|
+
}
|
691
|
+
if self._requester_pays:
|
692
|
+
params["RequestPayer"] = "requester"
|
693
|
+
response = paginator.paginate(**params)
|
664
694
|
|
665
695
|
keys = []
|
666
696
|
async for page in response:
|
@@ -863,13 +893,16 @@ class S3Hook(AwsBaseHook):
|
|
863
893
|
}
|
864
894
|
|
865
895
|
paginator = self.get_conn().get_paginator("list_objects_v2")
|
866
|
-
|
867
|
-
Bucket
|
868
|
-
Prefix
|
869
|
-
Delimiter
|
870
|
-
PaginationConfig
|
871
|
-
StartAfter
|
872
|
-
|
896
|
+
params = {
|
897
|
+
"Bucket": bucket_name,
|
898
|
+
"Prefix": _prefix,
|
899
|
+
"Delimiter": delimiter,
|
900
|
+
"PaginationConfig": config,
|
901
|
+
"StartAfter": start_after_key,
|
902
|
+
}
|
903
|
+
if self._requester_pays:
|
904
|
+
params["RequestPayer"] = "requester"
|
905
|
+
response = paginator.paginate(**params)
|
873
906
|
|
874
907
|
keys: list[str] = []
|
875
908
|
for page in response:
|
@@ -909,7 +942,14 @@ class S3Hook(AwsBaseHook):
|
|
909
942
|
}
|
910
943
|
|
911
944
|
paginator = self.get_conn().get_paginator("list_objects_v2")
|
912
|
-
|
945
|
+
params = {
|
946
|
+
"Bucket": bucket_name,
|
947
|
+
"Prefix": prefix,
|
948
|
+
"PaginationConfig": config,
|
949
|
+
}
|
950
|
+
if self._requester_pays:
|
951
|
+
params["RequestPayer"] = "requester"
|
952
|
+
response = paginator.paginate(**params)
|
913
953
|
|
914
954
|
files = []
|
915
955
|
for page in response:
|
@@ -931,7 +971,13 @@ class S3Hook(AwsBaseHook):
|
|
931
971
|
:return: metadata of an object
|
932
972
|
"""
|
933
973
|
try:
|
934
|
-
|
974
|
+
params = {
|
975
|
+
"Bucket": bucket_name,
|
976
|
+
"Key": key,
|
977
|
+
}
|
978
|
+
if self._requester_pays:
|
979
|
+
params["RequestPayer"] = "requester"
|
980
|
+
return self.get_conn().head_object(**params)
|
935
981
|
except ClientError as e:
|
936
982
|
if e.response["ResponseMetadata"]["HTTPStatusCode"] == 404:
|
937
983
|
return None
|
@@ -975,8 +1021,11 @@ class S3Hook(AwsBaseHook):
|
|
975
1021
|
if arg_name in S3Transfer.ALLOWED_DOWNLOAD_ARGS
|
976
1022
|
}
|
977
1023
|
|
1024
|
+
params = sanitize_extra_args()
|
1025
|
+
if self._requester_pays:
|
1026
|
+
params["RequestPayer"] = "requester"
|
978
1027
|
obj = self.resource.Object(bucket_name, key)
|
979
|
-
obj.load(**
|
1028
|
+
obj.load(**params)
|
980
1029
|
return obj
|
981
1030
|
|
982
1031
|
@unify_bucket_name_and_key
|
@@ -1022,11 +1071,14 @@ class S3Hook(AwsBaseHook):
|
|
1022
1071
|
"""
|
1023
1072
|
expression = expression or "SELECT * FROM S3Object"
|
1024
1073
|
expression_type = expression_type or "SQL"
|
1074
|
+
extra_args = {}
|
1025
1075
|
|
1026
1076
|
if input_serialization is None:
|
1027
1077
|
input_serialization = {"CSV": {}}
|
1028
1078
|
if output_serialization is None:
|
1029
1079
|
output_serialization = {"CSV": {}}
|
1080
|
+
if self._requester_pays:
|
1081
|
+
extra_args["RequestPayer"] = "requester"
|
1030
1082
|
|
1031
1083
|
response = self.get_conn().select_object_content(
|
1032
1084
|
Bucket=bucket_name,
|
@@ -1035,6 +1087,7 @@ class S3Hook(AwsBaseHook):
|
|
1035
1087
|
ExpressionType=expression_type,
|
1036
1088
|
InputSerialization=input_serialization,
|
1037
1089
|
OutputSerialization=output_serialization,
|
1090
|
+
ExtraArgs=extra_args,
|
1038
1091
|
)
|
1039
1092
|
|
1040
1093
|
return b"".join(
|
@@ -1124,6 +1177,8 @@ class S3Hook(AwsBaseHook):
|
|
1124
1177
|
filename = filename_gz
|
1125
1178
|
if acl_policy:
|
1126
1179
|
extra_args["ACL"] = acl_policy
|
1180
|
+
if self._requester_pays:
|
1181
|
+
extra_args["RequestPayer"] = "requester"
|
1127
1182
|
|
1128
1183
|
client = self.get_conn()
|
1129
1184
|
client.upload_file(
|
@@ -1270,6 +1325,8 @@ class S3Hook(AwsBaseHook):
|
|
1270
1325
|
extra_args["ServerSideEncryption"] = "AES256"
|
1271
1326
|
if acl_policy:
|
1272
1327
|
extra_args["ACL"] = acl_policy
|
1328
|
+
if self._requester_pays:
|
1329
|
+
extra_args["RequestPayer"] = "requester"
|
1273
1330
|
|
1274
1331
|
client = self.get_conn()
|
1275
1332
|
client.upload_fileobj(
|
@@ -1330,6 +1387,8 @@ class S3Hook(AwsBaseHook):
|
|
1330
1387
|
kwargs["ACL"] = acl_policy
|
1331
1388
|
if meta_data_directive:
|
1332
1389
|
kwargs["MetadataDirective"] = meta_data_directive
|
1390
|
+
if self._requester_pays:
|
1391
|
+
kwargs["RequestPayer"] = "requester"
|
1333
1392
|
|
1334
1393
|
dest_bucket_name, dest_bucket_key = self.get_s3_bucket_key(
|
1335
1394
|
dest_bucket_name, dest_bucket_key, "dest_bucket_name", "dest_bucket_key"
|
@@ -1412,12 +1471,17 @@ class S3Hook(AwsBaseHook):
|
|
1412
1471
|
keys = [keys]
|
1413
1472
|
|
1414
1473
|
s3 = self.get_conn()
|
1474
|
+
extra_kwargs = {}
|
1475
|
+
if self._requester_pays:
|
1476
|
+
extra_kwargs["RequestPayer"] = "requester"
|
1415
1477
|
|
1416
1478
|
# We can only send a maximum of 1000 keys per request.
|
1417
1479
|
# For details see:
|
1418
1480
|
# https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.delete_objects
|
1419
1481
|
for chunk in chunks(keys, chunk_size=1000):
|
1420
|
-
response = s3.delete_objects(
|
1482
|
+
response = s3.delete_objects(
|
1483
|
+
Bucket=bucket, Delete={"Objects": [{"Key": k} for k in chunk]}, **extra_kwargs
|
1484
|
+
)
|
1421
1485
|
deleted_keys = [x["Key"] for x in response.get("Deleted", [])]
|
1422
1486
|
self.log.info("Deleted: %s", deleted_keys)
|
1423
1487
|
if "Errors" in response:
|
@@ -1496,9 +1560,12 @@ class S3Hook(AwsBaseHook):
|
|
1496
1560
|
file = NamedTemporaryFile(dir=local_path, prefix="airflow_tmp_", delete=False) # type: ignore
|
1497
1561
|
|
1498
1562
|
with file:
|
1563
|
+
extra_args = {**self.extra_args}
|
1564
|
+
if self._requester_pays:
|
1565
|
+
extra_args["RequestPayer"] = "requester"
|
1499
1566
|
s3_obj.download_fileobj(
|
1500
1567
|
file,
|
1501
|
-
ExtraArgs=
|
1568
|
+
ExtraArgs=extra_args,
|
1502
1569
|
Config=self.transfer_config,
|
1503
1570
|
)
|
1504
1571
|
get_hook_lineage_collector().add_input_asset(
|
@@ -60,6 +60,8 @@ class SnsHook(AwsBaseHook):
|
|
60
60
|
message: str,
|
61
61
|
subject: str | None = None,
|
62
62
|
message_attributes: dict | None = None,
|
63
|
+
message_deduplication_id: str | None = None,
|
64
|
+
message_group_id: str | None = None,
|
63
65
|
):
|
64
66
|
"""
|
65
67
|
Publish a message to a SNS topic or an endpoint.
|
@@ -77,7 +79,10 @@ class SnsHook(AwsBaseHook):
|
|
77
79
|
- str = String
|
78
80
|
- int, float = Number
|
79
81
|
- iterable = String.Array
|
80
|
-
|
82
|
+
:param message_deduplication_id: Every message must have a unique message_deduplication_id.
|
83
|
+
This parameter applies only to FIFO (first-in-first-out) topics.
|
84
|
+
:param message_group_id: Tag that specifies that a message belongs to a specific message group.
|
85
|
+
This parameter applies only to FIFO (first-in-first-out) topics.
|
81
86
|
"""
|
82
87
|
publish_kwargs: dict[str, str | dict] = {
|
83
88
|
"TargetArn": target_arn,
|
@@ -88,6 +93,10 @@ class SnsHook(AwsBaseHook):
|
|
88
93
|
# Construct args this way because boto3 distinguishes from missing args and those set to None
|
89
94
|
if subject:
|
90
95
|
publish_kwargs["Subject"] = subject
|
96
|
+
if message_deduplication_id:
|
97
|
+
publish_kwargs["MessageDeduplicationId"] = message_deduplication_id
|
98
|
+
if message_group_id:
|
99
|
+
publish_kwargs["MessageGroupId"] = message_group_id
|
91
100
|
if message_attributes:
|
92
101
|
publish_kwargs["MessageAttributes"] = {
|
93
102
|
key: _get_message_attribute(val) for key, val in message_attributes.items()
|
@@ -125,10 +125,10 @@ class CloudWatchRemoteLogIO(LoggingMixin): # noqa: D101
|
|
125
125
|
def proc(logger: structlog.typing.WrappedLogger, method_name: str, event: structlog.typing.EventDict):
|
126
126
|
if not logger or not (stream_name := relative_path_from_logger(logger)):
|
127
127
|
return event
|
128
|
-
#
|
129
|
-
#
|
130
|
-
|
131
|
-
|
128
|
+
# We can't set the log stream name in the above init handler because
|
129
|
+
# the log path isn't known at that stage.
|
130
|
+
# Instead, we should always rely on the path (log stream name) provided by the logger.
|
131
|
+
_handler.log_stream_name = stream_name.as_posix().replace(":", "_")
|
132
132
|
name = event.get("logger_name") or event.get("logger", "")
|
133
133
|
level = structlog.stdlib.NAME_TO_LEVEL.get(method_name.lower(), logging.INFO)
|
134
134
|
msg = copy.copy(event)
|
@@ -149,7 +149,14 @@ class CloudWatchRemoteLogIO(LoggingMixin): # noqa: D101
|
|
149
149
|
return (proc,)
|
150
150
|
|
151
151
|
def close(self):
|
152
|
-
|
152
|
+
# Use the flush method to ensure all logs are sent to CloudWatch.
|
153
|
+
# Closing the handler sets `shutting_down` to True, which prevents any further logs from being sent.
|
154
|
+
# When `shutting_down` is True, means the logging system is in the process of shutting down,
|
155
|
+
# during which it attempts to flush the logs which are queued.
|
156
|
+
if self.handler is None or self.handler.shutting_down:
|
157
|
+
return
|
158
|
+
|
159
|
+
self.handler.flush()
|
153
160
|
|
154
161
|
def upload(self, path: os.PathLike | str, ti: RuntimeTI):
|
155
162
|
# No-op, as we upload via the processor as we go
|
@@ -32,7 +32,6 @@ from typing import TYPE_CHECKING, Any
|
|
32
32
|
|
33
33
|
from airflow.configuration import conf
|
34
34
|
from airflow.exceptions import AirflowException
|
35
|
-
from airflow.models.mappedoperator import MappedOperator
|
36
35
|
from airflow.providers.amazon.aws.hooks.batch_client import BatchClientHook
|
37
36
|
from airflow.providers.amazon.aws.links.batch import (
|
38
37
|
BatchJobDefinitionLink,
|
@@ -145,7 +144,7 @@ class BatchOperator(AwsBaseOperator[BatchClientHook]):
|
|
145
144
|
def operator_extra_links(self):
|
146
145
|
op_extra_links = [BatchJobDetailsLink()]
|
147
146
|
|
148
|
-
if
|
147
|
+
if self.is_mapped:
|
149
148
|
wait_for_completion = self.partial_kwargs.get(
|
150
149
|
"wait_for_completion"
|
151
150
|
) or self.expand_input.value.get("wait_for_completion")
|
@@ -98,13 +98,11 @@ class CloudFormationDeleteStackOperator(AwsBaseOperator[CloudFormationHook]):
|
|
98
98
|
*,
|
99
99
|
stack_name: str,
|
100
100
|
cloudformation_parameters: dict | None = None,
|
101
|
-
aws_conn_id: str | None = "aws_default",
|
102
101
|
**kwargs,
|
103
102
|
):
|
104
103
|
super().__init__(**kwargs)
|
105
104
|
self.cloudformation_parameters = cloudformation_parameters or {}
|
106
105
|
self.stack_name = stack_name
|
107
|
-
self.aws_conn_id = aws_conn_id
|
108
106
|
|
109
107
|
def execute(self, context: Context):
|
110
108
|
self.log.info("CloudFormation Parameters: %s", self.cloudformation_parameters)
|
@@ -289,7 +289,6 @@ class ComprehendCreateDocumentClassifierOperator(AwsBaseOperator[ComprehendHook]
|
|
289
289
|
waiter_delay: int = 60,
|
290
290
|
waiter_max_attempts: int = 20,
|
291
291
|
deferrable: bool = conf.getboolean("operators", "default_deferrable", fallback=False),
|
292
|
-
aws_conn_id: str | None = "aws_default",
|
293
292
|
**kwargs,
|
294
293
|
):
|
295
294
|
super().__init__(**kwargs)
|
@@ -305,7 +304,6 @@ class ComprehendCreateDocumentClassifierOperator(AwsBaseOperator[ComprehendHook]
|
|
305
304
|
self.waiter_delay = waiter_delay
|
306
305
|
self.waiter_max_attempts = waiter_max_attempts
|
307
306
|
self.deferrable = deferrable
|
308
|
-
self.aws_conn_id = aws_conn_id
|
309
307
|
|
310
308
|
def execute(self, context: Context) -> str:
|
311
309
|
if self.output_data_config:
|
@@ -91,7 +91,6 @@ class DmsCreateTaskOperator(AwsBaseOperator[DmsHook]):
|
|
91
91
|
table_mappings: dict,
|
92
92
|
migration_type: str = "full-load",
|
93
93
|
create_task_kwargs: dict | None = None,
|
94
|
-
aws_conn_id: str | None = "aws_default",
|
95
94
|
**kwargs,
|
96
95
|
):
|
97
96
|
super().__init__(**kwargs)
|
@@ -102,7 +101,6 @@ class DmsCreateTaskOperator(AwsBaseOperator[DmsHook]):
|
|
102
101
|
self.migration_type = migration_type
|
103
102
|
self.table_mappings = table_mappings
|
104
103
|
self.create_task_kwargs = create_task_kwargs or {}
|
105
|
-
self.aws_conn_id = aws_conn_id
|
106
104
|
|
107
105
|
def execute(self, context: Context):
|
108
106
|
"""
|
@@ -517,7 +517,7 @@ class EcsRunTaskOperator(EcsBaseOperator):
|
|
517
517
|
if self.reattach:
|
518
518
|
# Generate deterministic UUID which refers to unique TaskInstanceKey
|
519
519
|
ti: TaskInstance = context["ti"]
|
520
|
-
self._started_by = generate_uuid(*map(str, ti.
|
520
|
+
self._started_by = generate_uuid(*map(str, [ti.dag_id, ti.task_id, ti.run_id, ti.map_index]))
|
521
521
|
self.log.info("Try to find run with startedBy=%r", self._started_by)
|
522
522
|
self._try_reattach_task(started_by=self._started_by)
|
523
523
|
|
@@ -1056,6 +1056,7 @@ class EksPodOperator(KubernetesPodOperator):
|
|
1056
1056
|
in_cluster=self.in_cluster,
|
1057
1057
|
namespace=self.namespace,
|
1058
1058
|
name=self.pod_name,
|
1059
|
+
trigger_kwargs={"eks_cluster_name": cluster_name},
|
1059
1060
|
**kwargs,
|
1060
1061
|
)
|
1061
1062
|
# There is no need to manage the kube_config file, as it will be generated automatically.
|
@@ -1072,3 +1073,15 @@ class EksPodOperator(KubernetesPodOperator):
|
|
1072
1073
|
eks_cluster_name=self.cluster_name, pod_namespace=self.namespace
|
1073
1074
|
) as self.config_file:
|
1074
1075
|
return super().execute(context)
|
1076
|
+
|
1077
|
+
def trigger_reentry(self, context: Context, event: dict[str, Any]) -> Any:
|
1078
|
+
eks_hook = EksHook(
|
1079
|
+
aws_conn_id=self.aws_conn_id,
|
1080
|
+
region_name=self.region,
|
1081
|
+
)
|
1082
|
+
eks_cluster_name = event["eks_cluster_name"]
|
1083
|
+
pod_namespace = event["namespace"]
|
1084
|
+
with eks_hook.generate_config_file(
|
1085
|
+
eks_cluster_name=eks_cluster_name, pod_namespace=pod_namespace
|
1086
|
+
) as self.config_file:
|
1087
|
+
return super().trigger_reentry(context, event)
|
@@ -984,7 +984,7 @@ class EmrServerlessCreateApplicationOperator(AwsBaseOperator[EmrServerlessHook])
|
|
984
984
|
:param region_name: AWS region_name. If not specified then the default boto3 behaviour is used.
|
985
985
|
:param verify: Whether or not to verify SSL certificates. See:
|
986
986
|
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/core/session.html
|
987
|
-
:waiter_max_attempts: Number of times the waiter should poll the application to check the state.
|
987
|
+
:param waiter_max_attempts: Number of times the waiter should poll the application to check the state.
|
988
988
|
If not set, the waiter will use its default value.
|
989
989
|
:param waiter_delay: Number of seconds between polling the state of the application.
|
990
990
|
:param deferrable: If True, the operator will wait asynchronously for application to be created.
|
@@ -1128,7 +1128,7 @@ class EmrServerlessStartJobOperator(AwsBaseOperator[EmrServerlessHook]):
|
|
1128
1128
|
:param verify: Whether or not to verify SSL certificates. See:
|
1129
1129
|
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/core/session.html
|
1130
1130
|
:param name: Name for the EMR Serverless job. If not provided, a default name will be assigned.
|
1131
|
-
:waiter_max_attempts: Number of times the waiter should poll the application to check the state.
|
1131
|
+
:param waiter_max_attempts: Number of times the waiter should poll the application to check the state.
|
1132
1132
|
If not set, the waiter will use its default value.
|
1133
1133
|
:param waiter_delay: Number of seconds between polling the state of the job run.
|
1134
1134
|
:param deferrable: If True, the operator will wait asynchronously for the crawl to complete.
|
@@ -1438,7 +1438,7 @@ class EmrServerlessStopApplicationOperator(AwsBaseOperator[EmrServerlessHook]):
|
|
1438
1438
|
Otherwise, trying to stop an app with running jobs will return an error.
|
1439
1439
|
If you want to wait for the jobs to finish gracefully, use
|
1440
1440
|
:class:`airflow.providers.amazon.aws.sensors.emr.EmrServerlessJobSensor`
|
1441
|
-
:waiter_max_attempts: Number of times the waiter should poll the application to check the state.
|
1441
|
+
:param waiter_max_attempts: Number of times the waiter should poll the application to check the state.
|
1442
1442
|
Default is 25.
|
1443
1443
|
:param waiter_delay: Number of seconds between polling the state of the application.
|
1444
1444
|
Default is 60 seconds.
|
@@ -1573,7 +1573,7 @@ class EmrServerlessDeleteApplicationOperator(EmrServerlessStopApplicationOperato
|
|
1573
1573
|
:param region_name: AWS region_name. If not specified then the default boto3 behaviour is used.
|
1574
1574
|
:param verify: Whether or not to verify SSL certificates. See:
|
1575
1575
|
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/core/session.html
|
1576
|
-
:waiter_max_attempts: Number of times the waiter should poll the application to check the state.
|
1576
|
+
:param waiter_max_attempts: Number of times the waiter should poll the application to check the state.
|
1577
1577
|
Defaults to 25.
|
1578
1578
|
:param waiter_delay: Number of seconds between polling the state of the application.
|
1579
1579
|
Defaults to 60 seconds.
|
@@ -313,7 +313,6 @@ class GlueDataQualityOperator(AwsBaseOperator[GlueDataQualityHook]):
|
|
313
313
|
description: str = "AWS Glue Data Quality Rule Set With Airflow",
|
314
314
|
update_rule_set: bool = False,
|
315
315
|
data_quality_ruleset_kwargs: dict | None = None,
|
316
|
-
aws_conn_id: str | None = "aws_default",
|
317
316
|
**kwargs,
|
318
317
|
):
|
319
318
|
super().__init__(**kwargs)
|
@@ -322,7 +321,6 @@ class GlueDataQualityOperator(AwsBaseOperator[GlueDataQualityHook]):
|
|
322
321
|
self.description = description
|
323
322
|
self.update_rule_set = update_rule_set
|
324
323
|
self.data_quality_ruleset_kwargs = data_quality_ruleset_kwargs or {}
|
325
|
-
self.aws_conn_id = aws_conn_id
|
326
324
|
|
327
325
|
def validate_inputs(self) -> None:
|
328
326
|
if not self.ruleset.startswith("Rules") or not self.ruleset.endswith("]"):
|
@@ -421,7 +419,6 @@ class GlueDataQualityRuleSetEvaluationRunOperator(AwsBaseOperator[GlueDataQualit
|
|
421
419
|
waiter_delay: int = 60,
|
422
420
|
waiter_max_attempts: int = 20,
|
423
421
|
deferrable: bool = conf.getboolean("operators", "default_deferrable", fallback=False),
|
424
|
-
aws_conn_id: str | None = "aws_default",
|
425
422
|
**kwargs,
|
426
423
|
):
|
427
424
|
super().__init__(**kwargs)
|
@@ -437,7 +434,6 @@ class GlueDataQualityRuleSetEvaluationRunOperator(AwsBaseOperator[GlueDataQualit
|
|
437
434
|
self.waiter_delay = waiter_delay
|
438
435
|
self.waiter_max_attempts = waiter_max_attempts
|
439
436
|
self.deferrable = deferrable
|
440
|
-
self.aws_conn_id = aws_conn_id
|
441
437
|
|
442
438
|
def validate_inputs(self) -> None:
|
443
439
|
glue_table = self.datasource.get("GlueTable", {})
|
@@ -584,7 +580,6 @@ class GlueDataQualityRuleRecommendationRunOperator(AwsBaseOperator[GlueDataQuali
|
|
584
580
|
waiter_delay: int = 60,
|
585
581
|
waiter_max_attempts: int = 20,
|
586
582
|
deferrable: bool = conf.getboolean("operators", "default_deferrable", fallback=False),
|
587
|
-
aws_conn_id: str | None = "aws_default",
|
588
583
|
**kwargs,
|
589
584
|
):
|
590
585
|
super().__init__(**kwargs)
|
@@ -598,7 +593,6 @@ class GlueDataQualityRuleRecommendationRunOperator(AwsBaseOperator[GlueDataQuali
|
|
598
593
|
self.waiter_delay = waiter_delay
|
599
594
|
self.waiter_max_attempts = waiter_max_attempts
|
600
595
|
self.deferrable = deferrable
|
601
|
-
self.aws_conn_id = aws_conn_id
|
602
596
|
|
603
597
|
def execute(self, context: Context) -> str:
|
604
598
|
glue_table = self.datasource.get("GlueTable", {})
|
@@ -54,12 +54,8 @@ class RdsBaseOperator(AwsBaseOperator[RdsHook]):
|
|
54
54
|
def __init__(
|
55
55
|
self,
|
56
56
|
*args,
|
57
|
-
aws_conn_id: str | None = "aws_conn_id",
|
58
|
-
region_name: str | None = None,
|
59
57
|
**kwargs,
|
60
58
|
):
|
61
|
-
self.aws_conn_id = aws_conn_id
|
62
|
-
self.region_name = region_name
|
63
59
|
super().__init__(*args, **kwargs)
|
64
60
|
|
65
61
|
self._await_interval = 60 # seconds
|