apache-airflow-providers-amazon 8.0.0rc1__tar.gz → 8.0.0rc2__tar.gz

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.
Files changed (153) hide show
  1. {apache-airflow-providers-amazon-8.0.0rc1/apache_airflow_providers_amazon.egg-info → apache-airflow-providers-amazon-8.0.0rc2}/PKG-INFO +10 -4
  2. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/README.rst +9 -3
  3. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/base_aws.py +101 -18
  4. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/batch_waiters.py +3 -1
  5. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/emr.py +35 -5
  6. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/links/emr.py +1 -3
  7. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/operators/emr.py +22 -0
  8. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/operators/rds.py +1 -1
  9. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/operators/redshift_cluster.py +22 -1
  10. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/transfers/dynamodb_to_s3.py +1 -1
  11. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/triggers/redshift_cluster.py +54 -2
  12. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/waiters/base_waiter.py +12 -1
  13. apache-airflow-providers-amazon-8.0.0rc2/airflow/providers/amazon/aws/waiters/emr-serverless.json +18 -0
  14. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/get_provider_info.py +1 -0
  15. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2/apache_airflow_providers_amazon.egg-info}/PKG-INFO +10 -4
  16. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/apache_airflow_providers_amazon.egg-info/SOURCES.txt +1 -0
  17. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/apache_airflow_providers_amazon.egg-info/requires.txt +1 -0
  18. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/setup.cfg +2 -1
  19. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/LICENSE +0 -0
  20. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/MANIFEST.in +0 -0
  21. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/NOTICE +0 -0
  22. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/__init__.py +0 -0
  23. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/__init__.py +0 -0
  24. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/exceptions.py +0 -0
  25. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/__init__.py +0 -0
  26. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/appflow.py +0 -0
  27. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/athena.py +0 -0
  28. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/batch_client.py +0 -0
  29. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/batch_waiters.json +0 -0
  30. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/cloud_formation.py +0 -0
  31. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/datasync.py +0 -0
  32. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/dms.py +0 -0
  33. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/dynamodb.py +0 -0
  34. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/ec2.py +0 -0
  35. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/ecr.py +0 -0
  36. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/ecs.py +0 -0
  37. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/eks.py +0 -0
  38. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/elasticache_replication_group.py +0 -0
  39. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/glacier.py +0 -0
  40. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/glue.py +0 -0
  41. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/glue_catalog.py +0 -0
  42. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/glue_crawler.py +0 -0
  43. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/kinesis.py +0 -0
  44. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/lambda_function.py +0 -0
  45. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/logs.py +0 -0
  46. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/quicksight.py +0 -0
  47. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/rds.py +0 -0
  48. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/redshift_cluster.py +0 -0
  49. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/redshift_data.py +0 -0
  50. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/redshift_sql.py +0 -0
  51. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/s3.py +0 -0
  52. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/sagemaker.py +0 -0
  53. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/secrets_manager.py +0 -0
  54. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/ses.py +0 -0
  55. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/sns.py +0 -0
  56. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/sqs.py +0 -0
  57. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/ssm.py +0 -0
  58. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/step_function.py +0 -0
  59. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/hooks/sts.py +0 -0
  60. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/links/__init__.py +0 -0
  61. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/links/base_aws.py +0 -0
  62. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/links/batch.py +0 -0
  63. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/links/glue.py +0 -0
  64. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/links/logs.py +0 -0
  65. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/log/__init__.py +0 -0
  66. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/log/cloudwatch_task_handler.py +0 -0
  67. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/log/s3_task_handler.py +0 -0
  68. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/operators/__init__.py +0 -0
  69. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/operators/appflow.py +0 -0
  70. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/operators/athena.py +0 -0
  71. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/operators/batch.py +0 -0
  72. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/operators/cloud_formation.py +0 -0
  73. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/operators/datasync.py +0 -0
  74. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/operators/dms.py +0 -0
  75. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/operators/ec2.py +0 -0
  76. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/operators/ecs.py +0 -0
  77. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/operators/eks.py +0 -0
  78. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/operators/glacier.py +0 -0
  79. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/operators/glue.py +0 -0
  80. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/operators/glue_crawler.py +0 -0
  81. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/operators/lambda_function.py +0 -0
  82. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/operators/quicksight.py +0 -0
  83. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/operators/redshift_data.py +0 -0
  84. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/operators/s3.py +0 -0
  85. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/operators/sagemaker.py +0 -0
  86. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/operators/sns.py +0 -0
  87. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/operators/sqs.py +0 -0
  88. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/operators/step_function.py +0 -0
  89. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/secrets/__init__.py +0 -0
  90. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/secrets/secrets_manager.py +0 -0
  91. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/secrets/systems_manager.py +0 -0
  92. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/sensors/__init__.py +0 -0
  93. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/sensors/athena.py +0 -0
  94. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/sensors/batch.py +0 -0
  95. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/sensors/cloud_formation.py +0 -0
  96. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/sensors/dms.py +0 -0
  97. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/sensors/dynamodb.py +0 -0
  98. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/sensors/ec2.py +0 -0
  99. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/sensors/ecs.py +0 -0
  100. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/sensors/eks.py +0 -0
  101. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/sensors/emr.py +0 -0
  102. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/sensors/glacier.py +0 -0
  103. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/sensors/glue.py +0 -0
  104. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/sensors/glue_catalog_partition.py +0 -0
  105. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/sensors/glue_crawler.py +0 -0
  106. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/sensors/lambda_function.py +0 -0
  107. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/sensors/quicksight.py +0 -0
  108. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/sensors/rds.py +0 -0
  109. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/sensors/redshift_cluster.py +0 -0
  110. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/sensors/s3.py +0 -0
  111. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/sensors/sagemaker.py +0 -0
  112. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/sensors/sqs.py +0 -0
  113. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/sensors/step_function.py +0 -0
  114. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/transfers/__init__.py +0 -0
  115. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/transfers/base.py +0 -0
  116. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/transfers/exasol_to_s3.py +0 -0
  117. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/transfers/ftp_to_s3.py +0 -0
  118. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/transfers/gcs_to_s3.py +0 -0
  119. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/transfers/glacier_to_gcs.py +0 -0
  120. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/transfers/google_api_to_s3.py +0 -0
  121. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/transfers/hive_to_dynamodb.py +0 -0
  122. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/transfers/imap_attachment_to_s3.py +0 -0
  123. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/transfers/local_to_s3.py +0 -0
  124. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/transfers/mongo_to_s3.py +0 -0
  125. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/transfers/redshift_to_s3.py +0 -0
  126. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/transfers/s3_to_ftp.py +0 -0
  127. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/transfers/s3_to_redshift.py +0 -0
  128. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/transfers/s3_to_sftp.py +0 -0
  129. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/transfers/s3_to_sql.py +0 -0
  130. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/transfers/salesforce_to_s3.py +0 -0
  131. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/transfers/sftp_to_s3.py +0 -0
  132. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/transfers/sql_to_s3.py +0 -0
  133. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/triggers/__init__.py +0 -0
  134. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/utils/__init__.py +0 -0
  135. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/utils/connection_wrapper.py +0 -0
  136. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/utils/eks_get_token.py +0 -0
  137. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/utils/emailer.py +0 -0
  138. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/utils/rds.py +0 -0
  139. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/utils/redshift.py +0 -0
  140. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/utils/sagemaker.py +0 -0
  141. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/utils/tags.py +0 -0
  142. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/utils/waiter.py +0 -0
  143. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/waiters/__init__.py +0 -0
  144. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/waiters/appflow.json +0 -0
  145. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/waiters/ecs.json +0 -0
  146. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/waiters/eks.json +0 -0
  147. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/airflow/providers/amazon/aws/waiters/emr.json +0 -0
  148. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/apache_airflow_providers_amazon.egg-info/dependency_links.txt +0 -0
  149. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/apache_airflow_providers_amazon.egg-info/entry_points.txt +0 -0
  150. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/apache_airflow_providers_amazon.egg-info/not-zip-safe +0 -0
  151. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/apache_airflow_providers_amazon.egg-info/top_level.txt +0 -0
  152. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/pyproject.toml +0 -0
  153. {apache-airflow-providers-amazon-8.0.0rc1 → apache-airflow-providers-amazon-8.0.0rc2}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: apache-airflow-providers-amazon
3
- Version: 8.0.0rc1
3
+ Version: 8.0.0rc2
4
4
  Summary: Provider for Apache Airflow. Implements apache-airflow-providers-amazon package
5
5
  Home-page: https://airflow.apache.org/
6
6
  Download-URL: https://archive.apache.org/dist/airflow/providers
@@ -64,7 +64,7 @@ License-File: NOTICE
64
64
 
65
65
  Package ``apache-airflow-providers-amazon``
66
66
 
67
- Release: ``8.0.0rc1``
67
+ Release: ``8.0.0rc2``
68
68
 
69
69
 
70
70
  Amazon integration (including `Amazon Web Services (AWS) <https://aws.amazon.com/>`__).
@@ -106,6 +106,7 @@ PIP package Version required
106
106
  ``mypy-boto3-rds`` ``>=1.24.0``
107
107
  ``mypy-boto3-redshift-data`` ``>=1.24.0``
108
108
  ``mypy-boto3-appflow`` ``>=1.24.0``
109
+ ``aiobotocore[boto3]`` ``>=2.2.0``
109
110
  ======================================= ==================
110
111
 
111
112
  Cross provider package dependencies
@@ -176,8 +177,6 @@ Breaking changes
176
177
 
177
178
  Removed deprecated parameter ``max_tries`` from the Athena & EMR hook & operators in favor of ``max_polling_attempts``.
178
179
 
179
- Disabled deprecated behavior of switching to an empty aws connection ID on error. You can set it to None explicitly.
180
-
181
180
  Removed deprecated method ``waiter`` from emr hook in favor of the more generic ``airflow.providers.amazon.aws.utils.waiter.waiter``
182
181
 
183
182
  Removed deprecated unused parameter ``cluster_identifier`` from Redshift Cluster's hook method ``get_cluster_snapshot_status``
@@ -211,6 +210,8 @@ Features
211
210
  * ``add a stop operator to emr serverless (#30720)``
212
211
  * ``SqlToS3Operator - Add feature to partition SQL table (#30460)``
213
212
  * ``New AWS sensor — DynamoDBValueSensor (#28338)``
213
+ * ``Add a "force" option to emr serverless stop/delete operator (#30757)``
214
+ * ``Add support for deferrable operators in AMPP (#30032)``
214
215
 
215
216
  Bug Fixes
216
217
  ~~~~~~~~~
@@ -227,10 +228,15 @@ Misc
227
228
  * ``Remove @poke_mode_only from EmrStepSensor (#30774)``
228
229
  * ``Organize Amazon providers docs index (#30541)``
229
230
  * ``Remove duplicate param docstring in EksPodOperator (#30634)``
231
+ * ``Update AWS EMR Cluster Link to use the new dashboard (#30844)``
230
232
 
231
233
  .. Below changes are excluded from the changelog. Move them to
232
234
  appropriate section above if needed. Do not delete the lines(!):
233
235
  * ``Decouple "job runner" from BaseJob ORM model (#30255)``
236
+ * ``Upgrade ruff to 0.0.262 (#30809)``
237
+ * ``fixes to system tests following obsolete cleanup (#30804)``
238
+ * ``restore fallback to empty connection behavior (#30806)``
239
+ * ``Prepare docs for adhoc release of providers (#30787)``
234
240
 
235
241
  7.4.1
236
242
  .....
@@ -19,7 +19,7 @@
19
19
 
20
20
  Package ``apache-airflow-providers-amazon``
21
21
 
22
- Release: ``8.0.0rc1``
22
+ Release: ``8.0.0rc2``
23
23
 
24
24
 
25
25
  Amazon integration (including `Amazon Web Services (AWS) <https://aws.amazon.com/>`__).
@@ -61,6 +61,7 @@ PIP package Version required
61
61
  ``mypy-boto3-rds`` ``>=1.24.0``
62
62
  ``mypy-boto3-redshift-data`` ``>=1.24.0``
63
63
  ``mypy-boto3-appflow`` ``>=1.24.0``
64
+ ``aiobotocore[boto3]`` ``>=2.2.0``
64
65
  ======================================= ==================
65
66
 
66
67
  Cross provider package dependencies
@@ -131,8 +132,6 @@ Breaking changes
131
132
 
132
133
  Removed deprecated parameter ``max_tries`` from the Athena & EMR hook & operators in favor of ``max_polling_attempts``.
133
134
 
134
- Disabled deprecated behavior of switching to an empty aws connection ID on error. You can set it to None explicitly.
135
-
136
135
  Removed deprecated method ``waiter`` from emr hook in favor of the more generic ``airflow.providers.amazon.aws.utils.waiter.waiter``
137
136
 
138
137
  Removed deprecated unused parameter ``cluster_identifier`` from Redshift Cluster's hook method ``get_cluster_snapshot_status``
@@ -166,6 +165,8 @@ Features
166
165
  * ``add a stop operator to emr serverless (#30720)``
167
166
  * ``SqlToS3Operator - Add feature to partition SQL table (#30460)``
168
167
  * ``New AWS sensor — DynamoDBValueSensor (#28338)``
168
+ * ``Add a "force" option to emr serverless stop/delete operator (#30757)``
169
+ * ``Add support for deferrable operators in AMPP (#30032)``
169
170
 
170
171
  Bug Fixes
171
172
  ~~~~~~~~~
@@ -182,10 +183,15 @@ Misc
182
183
  * ``Remove @poke_mode_only from EmrStepSensor (#30774)``
183
184
  * ``Organize Amazon providers docs index (#30541)``
184
185
  * ``Remove duplicate param docstring in EksPodOperator (#30634)``
186
+ * ``Update AWS EMR Cluster Link to use the new dashboard (#30844)``
185
187
 
186
188
  .. Below changes are excluded from the changelog. Move them to
187
189
  appropriate section above if needed. Do not delete the lines(!):
188
190
  * ``Decouple "job runner" from BaseJob ORM model (#30255)``
191
+ * ``Upgrade ruff to 0.0.262 (#30809)``
192
+ * ``fixes to system tests following obsolete cleanup (#30804)``
193
+ * ``restore fallback to empty connection behavior (#30806)``
194
+ * ``Prepare docs for adhoc release of providers (#30787)``
189
195
 
190
196
  7.4.1
191
197
  .....
@@ -53,10 +53,10 @@ from airflow.compat.functools import cached_property
53
53
  from airflow.configuration import conf
54
54
  from airflow.exceptions import (
55
55
  AirflowException,
56
+ AirflowNotFoundException,
56
57
  )
57
58
  from airflow.hooks.base import BaseHook
58
59
  from airflow.providers.amazon.aws.utils.connection_wrapper import AwsConnectionWrapper
59
- from airflow.providers.amazon.aws.waiters.base_waiter import BaseBotoWaiter
60
60
  from airflow.providers_manager import ProvidersManager
61
61
  from airflow.utils.helpers import exactly_one
62
62
  from airflow.utils.log.logging_mixin import LoggingMixin
@@ -70,12 +70,15 @@ if TYPE_CHECKING:
70
70
 
71
71
  class BaseSessionFactory(LoggingMixin):
72
72
  """
73
- Base AWS Session Factory class to handle boto3 session creation.
73
+ Base AWS Session Factory class to handle synchronous and async boto session creation.
74
74
  It can handle most of the AWS supported authentication methods.
75
75
 
76
76
  User can also derive from this class to have full control of boto3 session
77
77
  creation or to support custom federation.
78
78
 
79
+ Note: Not all features implemented for synchronous sessions are available for async
80
+ sessions.
81
+
79
82
  .. seealso::
80
83
  - :ref:`howto/connection:aws:session-factory`
81
84
  """
@@ -125,17 +128,50 @@ class BaseSessionFactory(LoggingMixin):
125
128
  """Assume Role ARN from AWS Connection"""
126
129
  return self.conn.role_arn
127
130
 
128
- def create_session(self) -> boto3.session.Session:
129
- """Create boto3 Session from connection config."""
131
+ def _apply_session_kwargs(self, session):
132
+ if self.conn.session_kwargs.get("profile_name", None) is not None:
133
+ session.set_config_variable("profile", self.conn.session_kwargs["profile_name"])
134
+
135
+ if (
136
+ self.conn.session_kwargs.get("aws_access_key_id", None)
137
+ or self.conn.session_kwargs.get("aws_secret_access_key", None)
138
+ or self.conn.session_kwargs.get("aws_session_token", None)
139
+ ):
140
+ session.set_credentials(
141
+ self.conn.session_kwargs["aws_access_key_id"],
142
+ self.conn.session_kwargs["aws_secret_access_key"],
143
+ self.conn.session_kwargs["aws_session_token"],
144
+ )
145
+
146
+ if self.conn.session_kwargs.get("region_name", None) is not None:
147
+ session.set_config_variable("region", self.conn.session_kwargs["region_name"])
148
+
149
+ def get_async_session(self):
150
+ from aiobotocore.session import get_session as async_get_session
151
+
152
+ return async_get_session()
153
+
154
+ def create_session(self, deferrable: bool = False) -> boto3.session.Session:
155
+ """Create boto3 or aiobotocore Session from connection config."""
130
156
  if not self.conn:
131
157
  self.log.info(
132
158
  "No connection ID provided. Fallback on boto3 credential strategy (region_name=%r). "
133
159
  "See: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/configuration.html",
134
160
  self.region_name,
135
161
  )
136
- return boto3.session.Session(region_name=self.region_name)
162
+ if deferrable:
163
+ session = self.get_async_session()
164
+ self._apply_session_kwargs(session)
165
+ return session
166
+ else:
167
+ return boto3.session.Session(region_name=self.region_name)
137
168
  elif not self.role_arn:
138
- return self.basic_session
169
+ if deferrable:
170
+ session = self.get_async_session()
171
+ self._apply_session_kwargs(session)
172
+ return session
173
+ else:
174
+ return self.basic_session
139
175
 
140
176
  # Values stored in ``AwsConnectionWrapper.session_kwargs`` are intended to be used only
141
177
  # to create the initial boto3 session.
@@ -148,12 +184,18 @@ class BaseSessionFactory(LoggingMixin):
148
184
  assume_session_kwargs = {}
149
185
  if self.conn.region_name:
150
186
  assume_session_kwargs["region_name"] = self.conn.region_name
151
- return self._create_session_with_assume_role(session_kwargs=assume_session_kwargs)
187
+ return self._create_session_with_assume_role(
188
+ session_kwargs=assume_session_kwargs, deferrable=deferrable
189
+ )
152
190
 
153
191
  def _create_basic_session(self, session_kwargs: dict[str, Any]) -> boto3.session.Session:
154
192
  return boto3.session.Session(**session_kwargs)
155
193
 
156
- def _create_session_with_assume_role(self, session_kwargs: dict[str, Any]) -> boto3.session.Session:
194
+ def _create_session_with_assume_role(
195
+ self, session_kwargs: dict[str, Any], deferrable: bool = False
196
+ ) -> boto3.session.Session:
197
+ from aiobotocore.session import get_session as async_get_session
198
+
157
199
  if self.conn.assume_role_method == "assume_role_with_web_identity":
158
200
  # Deferred credentials have no initial credentials
159
201
  credential_fetcher = self._get_web_identity_credential_fetcher()
@@ -170,10 +212,10 @@ class BaseSessionFactory(LoggingMixin):
170
212
  method="sts-assume-role",
171
213
  )
172
214
 
173
- session = botocore.session.get_session()
215
+ session = async_get_session() if deferrable else botocore.session.get_session()
216
+
174
217
  session._credentials = credentials
175
- region_name = self.basic_session.region_name
176
- session.set_config_variable("region", region_name)
218
+ session.set_config_variable("region", self.basic_session.region_name)
177
219
 
178
220
  return boto3.session.Session(botocore_session=session, **session_kwargs)
179
221
 
@@ -498,7 +540,12 @@ class AwsGenericHook(BaseHook, Generic[BaseAwsConnection]):
498
540
  """Get the Airflow Connection object and wrap it in helper (cached)."""
499
541
  connection = None
500
542
  if self.aws_conn_id:
501
- connection = self.get_connection(self.aws_conn_id)
543
+ try:
544
+ connection = self.get_connection(self.aws_conn_id)
545
+ except AirflowNotFoundException:
546
+ self.log.warning(
547
+ "Unable to find AWS Connection ID '%s', switching to empty.", self.aws_conn_id
548
+ )
502
549
 
503
550
  return AwsConnectionWrapper(
504
551
  conn=connection, region_name=self._region_name, botocore_config=self._config, verify=self._verify
@@ -524,11 +571,11 @@ class AwsGenericHook(BaseHook, Generic[BaseAwsConnection]):
524
571
  """Verify or not SSL certificates boto3 client/resource read-only property."""
525
572
  return self.conn_config.verify
526
573
 
527
- def get_session(self, region_name: str | None = None) -> boto3.session.Session:
574
+ def get_session(self, region_name: str | None = None, deferrable: bool = False) -> boto3.session.Session:
528
575
  """Get the underlying boto3.session.Session(region_name=region_name)."""
529
576
  return SessionFactory(
530
577
  conn=self.conn_config, region_name=region_name, config=self.config
531
- ).create_session()
578
+ ).create_session(deferrable=deferrable)
532
579
 
533
580
  def _get_config(self, config: Config | None = None) -> Config:
534
581
  """
@@ -551,10 +598,19 @@ class AwsGenericHook(BaseHook, Generic[BaseAwsConnection]):
551
598
  self,
552
599
  region_name: str | None = None,
553
600
  config: Config | None = None,
601
+ deferrable: bool = False,
554
602
  ) -> boto3.client:
555
603
  """Get the underlying boto3 client using boto3 session"""
556
604
  client_type = self.client_type
557
- session = self.get_session(region_name=region_name)
605
+ session = self.get_session(region_name=region_name, deferrable=deferrable)
606
+ if not isinstance(session, boto3.session.Session):
607
+ return session.create_client(
608
+ client_type,
609
+ endpoint_url=self.conn_config.endpoint_url,
610
+ config=self._get_config(config),
611
+ verify=self.verify,
612
+ )
613
+
558
614
  return session.client(
559
615
  client_type,
560
616
  endpoint_url=self.conn_config.endpoint_url,
@@ -594,6 +650,14 @@ class AwsGenericHook(BaseHook, Generic[BaseAwsConnection]):
594
650
  else:
595
651
  return self.get_resource_type(region_name=self.region_name)
596
652
 
653
+ @property
654
+ def async_conn(self):
655
+ """Get an aiobotocore client to use for async operations."""
656
+ if not self.client_type:
657
+ raise ValueError("client_type must be specified.")
658
+
659
+ return self.get_client_type(region_name=self.region_name, deferrable=True)
660
+
597
661
  @cached_property
598
662
  def conn_client_meta(self) -> ClientMeta:
599
663
  """Get botocore client metadata from Hook connection (cached)."""
@@ -747,18 +811,35 @@ class AwsGenericHook(BaseHook, Generic[BaseAwsConnection]):
747
811
  path = Path(__file__).parents[1].joinpath(f"waiters/{filename}.json").resolve()
748
812
  return path if path.exists() else None
749
813
 
750
- def get_waiter(self, waiter_name: str, parameters: dict[str, str] | None = None) -> Waiter:
814
+ def get_waiter(
815
+ self,
816
+ waiter_name: str,
817
+ parameters: dict[str, str] | None = None,
818
+ deferrable: bool = False,
819
+ client=None,
820
+ ) -> Waiter:
751
821
  """
752
822
  First checks if there is a custom waiter with the provided waiter_name and
753
823
  uses that if it exists, otherwise it will check the service client for a
754
824
  waiter that matches the name and pass that through.
755
825
 
826
+ If `deferrable` is True, the waiter will be an AIOWaiter, generated from the
827
+ client that is passed as a parameter. If `deferrable` is True, `client` must be
828
+ provided.
829
+
756
830
  :param waiter_name: The name of the waiter. The name should exactly match the
757
831
  name of the key in the waiter model file (typically this is CamelCase).
758
832
  :param parameters: will scan the waiter config for the keys of that dict, and replace them with the
759
833
  corresponding value. If a custom waiter has such keys to be expanded, they need to be provided
760
834
  here.
835
+ :param deferrable: If True, the waiter is going to be an async custom waiter.
836
+
761
837
  """
838
+ from airflow.providers.amazon.aws.waiters.base_waiter import BaseBotoWaiter
839
+
840
+ if deferrable and not client:
841
+ raise ValueError("client must be provided for a deferrable waiter.")
842
+ client = client or self.conn
762
843
  if self.waiter_path and (waiter_name in self._list_custom_waiters()):
763
844
  # Technically if waiter_name is in custom_waiters then self.waiter_path must
764
845
  # exist but MyPy doesn't like the fact that self.waiter_path could be None.
@@ -766,7 +847,9 @@ class AwsGenericHook(BaseHook, Generic[BaseAwsConnection]):
766
847
  config = json.loads(config_file.read())
767
848
 
768
849
  config = self._apply_parameters_value(config, waiter_name, parameters)
769
- return BaseBotoWaiter(client=self.conn, model_config=config).waiter(waiter_name)
850
+ return BaseBotoWaiter(client=client, model_config=config, deferrable=deferrable).waiter(
851
+ waiter_name
852
+ )
770
853
  # If there is no custom waiter found for the provided name,
771
854
  # then try checking the service's official waiters.
772
855
  return self.conn.get_waiter(waiter_name)
@@ -935,7 +1018,7 @@ class BaseAsyncSessionFactory(BaseSessionFactory):
935
1018
  aio_session.set_config_variable("region", region_name)
936
1019
  return aio_session
937
1020
 
938
- def create_session(self) -> AioSession:
1021
+ def create_session(self, deferrable: bool = False) -> AioSession:
939
1022
  """Create aiobotocore Session from connection and config."""
940
1023
  if not self._conn:
941
1024
  self.log.info("No connection ID provided. Fallback on boto3 credential strategy")
@@ -138,7 +138,9 @@ class BatchWaitersHook(BatchClientHook):
138
138
  """
139
139
  return self._waiter_model
140
140
 
141
- def get_waiter(self, waiter_name: str, _: dict[str, str] | None = None) -> botocore.waiter.Waiter:
141
+ def get_waiter(
142
+ self, waiter_name: str, _: dict[str, str] | None = None, deferrable: bool = False, client=None
143
+ ) -> botocore.waiter.Waiter:
142
144
  """
143
145
  Get an AWS Batch service waiter, using the configured ``.waiter_model``.
144
146
 
@@ -24,7 +24,6 @@ from typing import Any
24
24
 
25
25
  from botocore.exceptions import ClientError
26
26
 
27
- from airflow.compat.functools import cached_property
28
27
  from airflow.exceptions import AirflowException, AirflowNotFoundException
29
28
  from airflow.providers.amazon.aws.hooks.base_aws import AwsBaseHook
30
29
  from airflow.utils.helpers import prune_dict
@@ -253,10 +252,41 @@ class EmrServerlessHook(AwsBaseHook):
253
252
  kwargs["client_type"] = "emr-serverless"
254
253
  super().__init__(*args, **kwargs)
255
254
 
256
- @cached_property
257
- def conn(self):
258
- """Get the underlying boto3 EmrServerlessAPIService client (cached)"""
259
- return super().conn
255
+ def cancel_running_jobs(self, application_id: str, waiter_config: dict = {}):
256
+ """
257
+ List all jobs in an intermediate state and cancel them.
258
+ Then wait for those jobs to reach a terminal state.
259
+ Note: if new jobs are triggered while this operation is ongoing,
260
+ it's going to time out and return an error.
261
+ """
262
+ paginator = self.conn.get_paginator("list_job_runs")
263
+ results_per_response = 50
264
+ iterator = paginator.paginate(
265
+ applicationId=application_id,
266
+ states=list(self.JOB_INTERMEDIATE_STATES),
267
+ PaginationConfig={
268
+ "PageSize": results_per_response,
269
+ },
270
+ )
271
+ count = 0
272
+ for r in iterator:
273
+ job_ids = [jr["id"] for jr in r["jobRuns"]]
274
+ count += len(job_ids)
275
+ if len(job_ids) > 0:
276
+ self.log.info(
277
+ "Cancelling %s pending job(s) for the application %s so that it can be stopped",
278
+ len(job_ids),
279
+ application_id,
280
+ )
281
+ for job_id in job_ids:
282
+ self.conn.cancel_job_run(applicationId=application_id, jobRunId=job_id)
283
+ if count > 0:
284
+ self.log.info("now waiting for the %s cancelled job(s) to terminate", count)
285
+ self.get_waiter("no_job_running").wait(
286
+ applicationId=application_id,
287
+ states=list(self.JOB_INTERMEDIATE_STATES.union({"CANCELLING"})),
288
+ WaiterConfig=waiter_config,
289
+ )
260
290
 
261
291
 
262
292
  class EmrContainerHook(AwsBaseHook):
@@ -24,9 +24,7 @@ class EmrClusterLink(BaseAwsLink):
24
24
 
25
25
  name = "EMR Cluster"
26
26
  key = "emr_cluster"
27
- format_str = (
28
- BASE_AWS_CONSOLE_LINK + "/elasticmapreduce/home?region={region_name}#cluster-details:{job_flow_id}"
29
- )
27
+ format_str = BASE_AWS_CONSOLE_LINK + "/emr/home?region={region_name}#/clusterDetails/{job_flow_id}"
30
28
 
31
29
 
32
30
  class EmrLogsLink(BaseAwsLink):
@@ -1025,6 +1025,10 @@ class EmrServerlessStopApplicationOperator(BaseOperator):
1025
1025
  the application be stopped. Defaults to 5 minutes.
1026
1026
  :param waiter_check_interval_seconds: Number of seconds between polling the state of the application.
1027
1027
  Defaults to 30 seconds.
1028
+ :param force_stop: If set to True, any job for that app that is not in a terminal state will be cancelled.
1029
+ Otherwise, trying to stop an app with running jobs will return an error.
1030
+ If you want to wait for the jobs to finish gracefully, use
1031
+ :class:`airflow.providers.amazon.aws.sensors.emr.EmrServerlessJobSensor`
1028
1032
  """
1029
1033
 
1030
1034
  template_fields: Sequence[str] = ("application_id",)
@@ -1036,6 +1040,7 @@ class EmrServerlessStopApplicationOperator(BaseOperator):
1036
1040
  aws_conn_id: str = "aws_default",
1037
1041
  waiter_countdown: int = 5 * 60,
1038
1042
  waiter_check_interval_seconds: int = 30,
1043
+ force_stop: bool = False,
1039
1044
  **kwargs,
1040
1045
  ):
1041
1046
  self.aws_conn_id = aws_conn_id
@@ -1043,6 +1048,7 @@ class EmrServerlessStopApplicationOperator(BaseOperator):
1043
1048
  self.wait_for_completion = wait_for_completion
1044
1049
  self.waiter_countdown = waiter_countdown
1045
1050
  self.waiter_check_interval_seconds = waiter_check_interval_seconds
1051
+ self.force_stop = force_stop
1046
1052
  super().__init__(**kwargs)
1047
1053
 
1048
1054
  @cached_property
@@ -1052,6 +1058,16 @@ class EmrServerlessStopApplicationOperator(BaseOperator):
1052
1058
 
1053
1059
  def execute(self, context: Context) -> None:
1054
1060
  self.log.info("Stopping application: %s", self.application_id)
1061
+
1062
+ if self.force_stop:
1063
+ self.hook.cancel_running_jobs(
1064
+ self.application_id,
1065
+ waiter_config={
1066
+ "Delay": self.waiter_check_interval_seconds,
1067
+ "MaxAttempts": self.waiter_countdown / self.waiter_check_interval_seconds,
1068
+ },
1069
+ )
1070
+
1055
1071
  self.hook.conn.stop_application(applicationId=self.application_id)
1056
1072
 
1057
1073
  if self.wait_for_completion:
@@ -1088,6 +1104,10 @@ class EmrServerlessDeleteApplicationOperator(EmrServerlessStopApplicationOperato
1088
1104
  the application to be stopped, and then deleted. Defaults to 25 minutes.
1089
1105
  :param waiter_check_interval_seconds: Number of seconds between polling the state of the application.
1090
1106
  Defaults to 60 seconds.
1107
+ :param force_stop: If set to True, any job for that app that is not in a terminal state will be cancelled.
1108
+ Otherwise, trying to delete an app with running jobs will return an error.
1109
+ If you want to wait for the jobs to finish gracefully, use
1110
+ :class:`airflow.providers.amazon.aws.sensors.emr.EmrServerlessJobSensor`
1091
1111
  """
1092
1112
 
1093
1113
  template_fields: Sequence[str] = ("application_id",)
@@ -1099,6 +1119,7 @@ class EmrServerlessDeleteApplicationOperator(EmrServerlessStopApplicationOperato
1099
1119
  aws_conn_id: str = "aws_default",
1100
1120
  waiter_countdown: int = 25 * 60,
1101
1121
  waiter_check_interval_seconds: int = 60,
1122
+ force_stop: bool = False,
1102
1123
  **kwargs,
1103
1124
  ):
1104
1125
  self.wait_for_delete_completion = wait_for_completion
@@ -1110,6 +1131,7 @@ class EmrServerlessDeleteApplicationOperator(EmrServerlessStopApplicationOperato
1110
1131
  aws_conn_id=aws_conn_id,
1111
1132
  waiter_countdown=waiter_countdown,
1112
1133
  waiter_check_interval_seconds=waiter_check_interval_seconds,
1134
+ force_stop=force_stop,
1113
1135
  **kwargs,
1114
1136
  )
1115
1137
 
@@ -80,7 +80,7 @@ class RdsCreateDbSnapshotOperator(RdsBaseOperator):
80
80
  db_snapshot_identifier: str,
81
81
  tags: Sequence[TagTypeDef] | dict | None = None,
82
82
  wait_for_completion: bool = True,
83
- aws_conn_id: str = "aws_conn_id",
83
+ aws_conn_id: str = "aws_default",
84
84
  **kwargs,
85
85
  ):
86
86
  super().__init__(aws_conn_id=aws_conn_id, **kwargs)
@@ -22,7 +22,10 @@ from typing import TYPE_CHECKING, Any, Sequence
22
22
  from airflow.exceptions import AirflowException
23
23
  from airflow.models import BaseOperator
24
24
  from airflow.providers.amazon.aws.hooks.redshift_cluster import RedshiftHook
25
- from airflow.providers.amazon.aws.triggers.redshift_cluster import RedshiftClusterTrigger
25
+ from airflow.providers.amazon.aws.triggers.redshift_cluster import (
26
+ RedshiftClusterTrigger,
27
+ RedshiftCreateClusterTrigger,
28
+ )
26
29
 
27
30
  if TYPE_CHECKING:
28
31
  from airflow.utils.context import Context
@@ -88,6 +91,7 @@ class RedshiftCreateClusterOperator(BaseOperator):
88
91
  :param wait_for_completion: Whether wait for the cluster to be in ``available`` state
89
92
  :param max_attempt: The maximum number of attempts to be made. Default: 5
90
93
  :param poll_interval: The amount of time in seconds to wait between attempts. Default: 60
94
+ :param deferrable: If True, the operator will run in deferrable mode
91
95
  """
92
96
 
93
97
  template_fields: Sequence[str] = (
@@ -140,6 +144,7 @@ class RedshiftCreateClusterOperator(BaseOperator):
140
144
  wait_for_completion: bool = False,
141
145
  max_attempt: int = 5,
142
146
  poll_interval: int = 60,
147
+ deferrable: bool = False,
143
148
  **kwargs,
144
149
  ):
145
150
  super().__init__(**kwargs)
@@ -180,6 +185,7 @@ class RedshiftCreateClusterOperator(BaseOperator):
180
185
  self.wait_for_completion = wait_for_completion
181
186
  self.max_attempt = max_attempt
182
187
  self.poll_interval = poll_interval
188
+ self.deferrable = deferrable
183
189
  self.kwargs = kwargs
184
190
 
185
191
  def execute(self, context: Context):
@@ -252,6 +258,16 @@ class RedshiftCreateClusterOperator(BaseOperator):
252
258
  self.master_user_password,
253
259
  params,
254
260
  )
261
+ if self.deferrable:
262
+ self.defer(
263
+ trigger=RedshiftCreateClusterTrigger(
264
+ cluster_identifier=self.cluster_identifier,
265
+ poll_interval=self.poll_interval,
266
+ max_attempt=self.max_attempt,
267
+ aws_conn_id=self.aws_conn_id,
268
+ ),
269
+ method_name="execute_complete",
270
+ )
255
271
  if self.wait_for_completion:
256
272
  redshift_hook.get_conn().get_waiter("cluster_available").wait(
257
273
  ClusterIdentifier=self.cluster_identifier,
@@ -264,6 +280,11 @@ class RedshiftCreateClusterOperator(BaseOperator):
264
280
  self.log.info("Created Redshift cluster %s", self.cluster_identifier)
265
281
  self.log.info(cluster)
266
282
 
283
+ def execute_complete(self, context, event=None):
284
+ if event["status"] != "success":
285
+ raise AirflowException(f"Error creating cluster: {event}")
286
+ return
287
+
267
288
 
268
289
  class RedshiftCreateClusterSnapshotOperator(BaseOperator):
269
290
  """
@@ -87,7 +87,7 @@ class DynamoDBToS3Operator(AwsToAwsBaseOperator):
87
87
  :param dynamodb_scan_kwargs: kwargs pass to <https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#DynamoDB.Table.scan>
88
88
  :param s3_key_prefix: Prefix of s3 object key
89
89
  :param process_func: How we transforms a dynamodb item to bytes. By default we dump the json
90
- """ # noqa: E501
90
+ """
91
91
 
92
92
  template_fields: Sequence[str] = (
93
93
  *AwsToAwsBaseOperator.template_fields,
@@ -18,7 +18,8 @@ from __future__ import annotations
18
18
 
19
19
  from typing import Any, AsyncIterator
20
20
 
21
- from airflow.providers.amazon.aws.hooks.redshift_cluster import RedshiftAsyncHook
21
+ from airflow.compat.functools import cached_property
22
+ from airflow.providers.amazon.aws.hooks.redshift_cluster import RedshiftAsyncHook, RedshiftHook
22
23
  from airflow.triggers.base import BaseTrigger, TriggerEvent
23
24
 
24
25
 
@@ -55,7 +56,7 @@ class RedshiftClusterTrigger(BaseTrigger):
55
56
  },
56
57
  )
57
58
 
58
- async def run(self) -> AsyncIterator["TriggerEvent"]:
59
+ async def run(self) -> AsyncIterator[TriggerEvent]:
59
60
  hook = RedshiftAsyncHook(aws_conn_id=self.aws_conn_id)
60
61
  while self.attempts >= 1:
61
62
  self.attempts = self.attempts - 1
@@ -85,3 +86,54 @@ class RedshiftClusterTrigger(BaseTrigger):
85
86
  except Exception as e:
86
87
  if self.attempts < 1:
87
88
  yield TriggerEvent({"status": "error", "message": str(e)})
89
+
90
+
91
+ class RedshiftCreateClusterTrigger(BaseTrigger):
92
+ """
93
+ Trigger for RedshiftCreateClusterOperator.
94
+ The trigger will asynchronously poll the boto3 API and wait for the
95
+ Redshift cluster to be in the `available` state.
96
+
97
+ :param cluster_identifier: A unique identifier for the cluster.
98
+ :param poll_interval: The amount of time in seconds to wait between attempts.
99
+ :param max_attempt: The maximum number of attempts to be made.
100
+ :param aws_conn_id: The Airflow connection used for AWS credentials.
101
+ """
102
+
103
+ def __init__(
104
+ self,
105
+ cluster_identifier: str,
106
+ poll_interval: int,
107
+ max_attempt: int,
108
+ aws_conn_id: str,
109
+ ):
110
+ self.cluster_identifier = cluster_identifier
111
+ self.poll_interval = poll_interval
112
+ self.max_attempt = max_attempt
113
+ self.aws_conn_id = aws_conn_id
114
+
115
+ def serialize(self) -> tuple[str, dict[str, Any]]:
116
+ return (
117
+ "airflow.providers.amazon.aws.triggers.redshift_cluster.RedshiftCreateClusterTrigger",
118
+ {
119
+ "cluster_identifier": str(self.cluster_identifier),
120
+ "poll_interval": str(self.poll_interval),
121
+ "max_attempt": str(self.max_attempt),
122
+ "aws_conn_id": str(self.aws_conn_id),
123
+ },
124
+ )
125
+
126
+ @cached_property
127
+ def hook(self) -> RedshiftHook:
128
+ return RedshiftHook(aws_conn_id=self.aws_conn_id)
129
+
130
+ async def run(self):
131
+ async with self.hook.async_conn as client:
132
+ await client.get_waiter("cluster_available").wait(
133
+ ClusterIdentifier=self.cluster_identifier,
134
+ WaiterConfig={
135
+ "Delay": int(self.poll_interval),
136
+ "MaxAttempts": int(self.max_attempt),
137
+ },
138
+ )
139
+ yield TriggerEvent({"status": "success", "message": "Cluster Created"})