aws-advanced-python-wrapper 1.2.0__tar.gz → 1.4.0__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.
- aws_advanced_python_wrapper-1.4.0/NOTICE +2 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/PKG-INFO +18 -17
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/README.md +15 -11
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/aurora_connection_tracker_plugin.py +0 -13
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/aurora_initial_connection_strategy_plugin.py +13 -16
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/aws_secrets_manager_plugin.py +24 -10
- aws_advanced_python_wrapper-1.4.0/aws_advanced_python_wrapper/blue_green_plugin.py +1926 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/connection_provider.py +7 -5
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/database_dialect.py +162 -48
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/default_plugin.py +6 -3
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/driver_info.py +1 -1
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/failover_plugin.py +2 -23
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/fastest_response_strategy_plugin.py +3 -22
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/federated_plugin.py +5 -2
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/host_list_provider.py +10 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/host_monitoring_plugin.py +7 -24
- aws_advanced_python_wrapper-1.4.0/aws_advanced_python_wrapper/host_monitoring_v2_plugin.py +518 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/host_selector.py +88 -4
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/hostinfo.py +23 -9
- aws_advanced_python_wrapper-1.4.0/aws_advanced_python_wrapper/limitless_plugin.py +532 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/okta_plugin.py +5 -2
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/plugin.py +3 -2
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/plugin_service.py +175 -33
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/read_write_splitting_plugin.py +2 -15
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/reader_failover_handler.py +9 -3
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/resources/aws_advanced_python_wrapper_messages.properties +118 -1
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/sql_alchemy_connection_provider.py +7 -4
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/stale_dns_plugin.py +0 -12
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/atomic.py +41 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/cache_map.py +4 -4
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/concurrent.py +72 -3
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/properties.py +115 -10
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/rds_url_type.py +1 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/rdsutils.py +66 -8
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/utils.py +8 -0
- aws_advanced_python_wrapper-1.4.0/aws_advanced_python_wrapper/utils/value_container.py +71 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/wrapper.py +7 -1
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/writer_failover_handler.py +7 -7
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/pyproject.toml +5 -3
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/CONTRIBUTING.md +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/LICENSE +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/__init__.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/allowed_and_blocked_hosts.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/connect_time_plugin.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/credentials_provider_factory.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/custom_endpoint_plugin.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/developer_plugin.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/driver_configuration_profiles.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/driver_dialect.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/driver_dialect_codes.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/driver_dialect_manager.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/errors.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/exception_handling.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/execute_time_plugin.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/failover_result.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/host_availability.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/iam_plugin.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/mysql_driver_dialect.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/pep249.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/pg_driver_dialect.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/sqlalchemy_driver_dialect.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/states/__init__.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/states/session_state.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/states/session_state_service.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/__init__.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/decorators.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/failover_mode.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/iam_utils.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/log.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/messages.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/mysql_exception_handler.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/notifications.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/pg_exception_handler.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/region_utils.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/saml_utils.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/sliding_expiration_cache.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/telemetry/default_telemetry_factory.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/telemetry/null_telemetry.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/telemetry/open_telemetry.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/telemetry/telemetry.py +0 -0
- {aws_advanced_python_wrapper-1.2.0 → aws_advanced_python_wrapper-1.4.0}/aws_advanced_python_wrapper/utils/telemetry/xray_telemetry.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
|
-
Name:
|
|
3
|
-
Version: 1.
|
|
2
|
+
Name: aws_advanced_python_wrapper
|
|
3
|
+
Version: 1.4.0
|
|
4
4
|
Summary: Amazon Web Services (AWS) Advanced Python Wrapper
|
|
5
5
|
Home-page: https://github.com/awslabs/aws-advanced-python-wrapper
|
|
6
6
|
License: Apache-2.0
|
|
@@ -15,12 +15,9 @@ Classifier: Programming Language :: Python :: 3
|
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.9
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.10
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
-
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
19
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
20
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
22
20
|
Classifier: Programming Language :: Python :: 3.8
|
|
23
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
24
21
|
Requires-Dist: aws-xray-sdk (>=2.13.1,<3.0.0)
|
|
25
22
|
Requires-Dist: boto3 (>=1.34.111,<2.0.0)
|
|
26
23
|
Requires-Dist: opentelemetry-api (>=1.22.0,<2.0.0)
|
|
@@ -83,10 +80,9 @@ with AwsWrapperConnection.connect(
|
|
|
83
80
|
autocommit=True
|
|
84
81
|
) as awsconn:
|
|
85
82
|
awscursor = awsconn.cursor()
|
|
86
|
-
awscursor.execute("SELECT aurora_db_instance_identifier()")
|
|
87
|
-
awscursor.fetchone()
|
|
88
|
-
|
|
89
|
-
print(record)
|
|
83
|
+
awscursor.execute("SELECT pg_catalog.aurora_db_instance_identifier()")
|
|
84
|
+
row = awscursor.fetchone()
|
|
85
|
+
print(row)
|
|
90
86
|
```
|
|
91
87
|
The `AwsWrapperConnection#connect` method accepts the connection configuration through both the connection string and the keyword arguments.
|
|
92
88
|
|
|
@@ -107,9 +103,8 @@ with AwsWrapperConnection.connect(
|
|
|
107
103
|
) as awsconn:
|
|
108
104
|
awscursor = awsconn.cursor()
|
|
109
105
|
awscursor.execute("SELECT @@aurora_server_id")
|
|
110
|
-
awscursor.fetchone()
|
|
111
|
-
|
|
112
|
-
print(record)
|
|
106
|
+
row = awscursor.fetchone()
|
|
107
|
+
print(row)
|
|
113
108
|
```
|
|
114
109
|
|
|
115
110
|
For more details on how to download the AWS Advanced Python Driver, minimum requirements to use it,
|
|
@@ -155,6 +150,8 @@ The following table lists the connection properties used with the AWS Advanced P
|
|
|
155
150
|
| `secrets_manager_secret_id` | [Secrets Manager Plugin](./docs/using-the-python-driver/using-plugins/UsingTheAwsSecretsManagerPlugin.md) |
|
|
156
151
|
| `secrets_manager_region` | [Secrets Manager Plugin](./docs/using-the-python-driver/using-plugins/UsingTheAwsSecretsManagerPlugin.md) |
|
|
157
152
|
| `secrets_manager_endpoint` | [Secrets Manager Plugin](./docs/using-the-python-driver/using-plugins/UsingTheAwsSecretsManagerPlugin.md) |
|
|
153
|
+
| `secrets_manager_secret_username` | [Secrets Manager Plugin](./docs/using-the-python-driver/using-plugins/UsingTheAwsSecretsManagerPlugin.md) |
|
|
154
|
+
| `secrets_manager_secret_password` | [Secrets Manager Plugin](./docs/using-the-python-driver/using-plugins/UsingTheAwsSecretsManagerPlugin.md) |
|
|
158
155
|
| `reader_host_selector_strategy` | [Connection Strategy](./docs/using-the-python-driver/using-plugins/UsingTheReadWriteSplittingPlugin.md#connection-strategies) |
|
|
159
156
|
| `db_user` | [Federated Authentication Plugin](./docs/using-the-python-driver/using-plugins/UsingTheFederatedAuthenticationPlugin.md) |
|
|
160
157
|
| `idp_username` | [Federated Authentication Plugin](./docs/using-the-python-driver/using-plugins/UsingTheFederatedAuthenticationPlugin.md) |
|
|
@@ -181,9 +178,13 @@ To find all the documentation and concrete examples on how to use the AWS Advanc
|
|
|
181
178
|
|
|
182
179
|
#### Amazon RDS Blue/Green Deployments
|
|
183
180
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
181
|
+
Support for Blue/Green deployments using the AWS Advanced Python Driver requires specific metadata tables. The following service versions provide support for Blue/Green Deployments:
|
|
182
|
+
|
|
183
|
+
- Supported RDS PostgreSQL Versions: `rds_tools v1.7 (17.1, 16.5, 15.9, 14.14, 13.17, 12.21)` and above.
|
|
184
|
+
- Supported Aurora PostgreSQL Versions: Engine Release `17.5, 16.9, 15.13, 14.18, 13.21` and above.
|
|
185
|
+
- Supported Aurora MySQL Versions: Engine Release `3.07` and above.
|
|
186
|
+
|
|
187
|
+
Please note that Aurora Global Database and RDS Multi-AZ clusters with Blue/Green deployments is currently not supported. For detailed information on supported database versions, refer to the [Blue/Green Deployment Plugin Documentation](./docs/using-the-python-driver/using-plugins/UsingTheBlueGreenPlugin.md).
|
|
187
188
|
|
|
188
189
|
#### MySQL Connector/Python C Extension
|
|
189
190
|
|
|
@@ -236,7 +237,7 @@ For all other questions, please use [GitHub discussions](https://github.com/awsl
|
|
|
236
237
|
|
|
237
238
|
1. Set up your environment by following the directions in the [Development Guide](./docs/development-guide/DevelopmentGuide.md).
|
|
238
239
|
2. To contribute, first make a fork of this project.
|
|
239
|
-
3. Make any changes on your fork. Make sure you are aware of the requirements for the project (e.g. do not require Python 3.7 if we are supporting Python 3.8
|
|
240
|
+
3. Make any changes on your fork. Make sure you are aware of the requirements for the project (e.g. do not require Python 3.7 if we are supporting Python 3.8 - 3.11 (inclusive)).
|
|
240
241
|
4. Create a pull request from your fork.
|
|
241
242
|
5. Pull requests need to be approved and merged by maintainers into the main branch. <br />
|
|
242
243
|
|
|
@@ -48,10 +48,9 @@ with AwsWrapperConnection.connect(
|
|
|
48
48
|
autocommit=True
|
|
49
49
|
) as awsconn:
|
|
50
50
|
awscursor = awsconn.cursor()
|
|
51
|
-
awscursor.execute("SELECT aurora_db_instance_identifier()")
|
|
52
|
-
awscursor.fetchone()
|
|
53
|
-
|
|
54
|
-
print(record)
|
|
51
|
+
awscursor.execute("SELECT pg_catalog.aurora_db_instance_identifier()")
|
|
52
|
+
row = awscursor.fetchone()
|
|
53
|
+
print(row)
|
|
55
54
|
```
|
|
56
55
|
The `AwsWrapperConnection#connect` method accepts the connection configuration through both the connection string and the keyword arguments.
|
|
57
56
|
|
|
@@ -72,9 +71,8 @@ with AwsWrapperConnection.connect(
|
|
|
72
71
|
) as awsconn:
|
|
73
72
|
awscursor = awsconn.cursor()
|
|
74
73
|
awscursor.execute("SELECT @@aurora_server_id")
|
|
75
|
-
awscursor.fetchone()
|
|
76
|
-
|
|
77
|
-
print(record)
|
|
74
|
+
row = awscursor.fetchone()
|
|
75
|
+
print(row)
|
|
78
76
|
```
|
|
79
77
|
|
|
80
78
|
For more details on how to download the AWS Advanced Python Driver, minimum requirements to use it,
|
|
@@ -120,6 +118,8 @@ The following table lists the connection properties used with the AWS Advanced P
|
|
|
120
118
|
| `secrets_manager_secret_id` | [Secrets Manager Plugin](./docs/using-the-python-driver/using-plugins/UsingTheAwsSecretsManagerPlugin.md) |
|
|
121
119
|
| `secrets_manager_region` | [Secrets Manager Plugin](./docs/using-the-python-driver/using-plugins/UsingTheAwsSecretsManagerPlugin.md) |
|
|
122
120
|
| `secrets_manager_endpoint` | [Secrets Manager Plugin](./docs/using-the-python-driver/using-plugins/UsingTheAwsSecretsManagerPlugin.md) |
|
|
121
|
+
| `secrets_manager_secret_username` | [Secrets Manager Plugin](./docs/using-the-python-driver/using-plugins/UsingTheAwsSecretsManagerPlugin.md) |
|
|
122
|
+
| `secrets_manager_secret_password` | [Secrets Manager Plugin](./docs/using-the-python-driver/using-plugins/UsingTheAwsSecretsManagerPlugin.md) |
|
|
123
123
|
| `reader_host_selector_strategy` | [Connection Strategy](./docs/using-the-python-driver/using-plugins/UsingTheReadWriteSplittingPlugin.md#connection-strategies) |
|
|
124
124
|
| `db_user` | [Federated Authentication Plugin](./docs/using-the-python-driver/using-plugins/UsingTheFederatedAuthenticationPlugin.md) |
|
|
125
125
|
| `idp_username` | [Federated Authentication Plugin](./docs/using-the-python-driver/using-plugins/UsingTheFederatedAuthenticationPlugin.md) |
|
|
@@ -146,9 +146,13 @@ To find all the documentation and concrete examples on how to use the AWS Advanc
|
|
|
146
146
|
|
|
147
147
|
#### Amazon RDS Blue/Green Deployments
|
|
148
148
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
149
|
+
Support for Blue/Green deployments using the AWS Advanced Python Driver requires specific metadata tables. The following service versions provide support for Blue/Green Deployments:
|
|
150
|
+
|
|
151
|
+
- Supported RDS PostgreSQL Versions: `rds_tools v1.7 (17.1, 16.5, 15.9, 14.14, 13.17, 12.21)` and above.
|
|
152
|
+
- Supported Aurora PostgreSQL Versions: Engine Release `17.5, 16.9, 15.13, 14.18, 13.21` and above.
|
|
153
|
+
- Supported Aurora MySQL Versions: Engine Release `3.07` and above.
|
|
154
|
+
|
|
155
|
+
Please note that Aurora Global Database and RDS Multi-AZ clusters with Blue/Green deployments is currently not supported. For detailed information on supported database versions, refer to the [Blue/Green Deployment Plugin Documentation](./docs/using-the-python-driver/using-plugins/UsingTheBlueGreenPlugin.md).
|
|
152
156
|
|
|
153
157
|
#### MySQL Connector/Python C Extension
|
|
154
158
|
|
|
@@ -201,7 +205,7 @@ For all other questions, please use [GitHub discussions](https://github.com/awsl
|
|
|
201
205
|
|
|
202
206
|
1. Set up your environment by following the directions in the [Development Guide](./docs/development-guide/DevelopmentGuide.md).
|
|
203
207
|
2. To contribute, first make a fork of this project.
|
|
204
|
-
3. Make any changes on your fork. Make sure you are aware of the requirements for the project (e.g. do not require Python 3.7 if we are supporting Python 3.8
|
|
208
|
+
3. Make any changes on your fork. Make sure you are aware of the requirements for the project (e.g. do not require Python 3.7 if we are supporting Python 3.8 - 3.11 (inclusive)).
|
|
205
209
|
4. Create a pull request from your fork.
|
|
206
210
|
5. Pull requests need to be approved and merged by maintainers into the main branch. <br />
|
|
207
211
|
|
|
@@ -173,19 +173,6 @@ class AuroraConnectionTrackerPlugin(Plugin):
|
|
|
173
173
|
props: Properties,
|
|
174
174
|
is_initial_connection: bool,
|
|
175
175
|
connect_func: Callable) -> Connection:
|
|
176
|
-
return self._connect(host_info, connect_func)
|
|
177
|
-
|
|
178
|
-
def force_connect(
|
|
179
|
-
self,
|
|
180
|
-
target_driver_func: Callable,
|
|
181
|
-
driver_dialect: DriverDialect,
|
|
182
|
-
host_info: HostInfo,
|
|
183
|
-
props: Properties,
|
|
184
|
-
is_initial_connection: bool,
|
|
185
|
-
force_connect_func: Callable) -> Connection:
|
|
186
|
-
return self._connect(host_info, force_connect_func)
|
|
187
|
-
|
|
188
|
-
def _connect(self, host_info: HostInfo, connect_func: Callable):
|
|
189
176
|
conn = connect_func()
|
|
190
177
|
|
|
191
178
|
if conn:
|
|
@@ -35,9 +35,7 @@ from aws_advanced_python_wrapper.utils.rdsutils import RdsUtils
|
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
class AuroraInitialConnectionStrategyPlugin(Plugin):
|
|
38
|
-
_SUBSCRIBED_METHODS: Set[str] = {"init_host_provider",
|
|
39
|
-
"connect",
|
|
40
|
-
"force_connect"}
|
|
38
|
+
_SUBSCRIBED_METHODS: Set[str] = {"init_host_provider", "connect"}
|
|
41
39
|
|
|
42
40
|
_host_list_provider_service: Optional[HostListProviderService] = None
|
|
43
41
|
|
|
@@ -52,29 +50,24 @@ class AuroraInitialConnectionStrategyPlugin(Plugin):
|
|
|
52
50
|
|
|
53
51
|
def connect(self, target_driver_func: Callable, driver_dialect: DriverDialect, host_info: HostInfo, props: Properties,
|
|
54
52
|
is_initial_connection: bool, connect_func: Callable) -> Connection:
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def force_connect(self, target_driver_func: Callable, driver_dialect: DriverDialect, host_info: HostInfo, props: Properties,
|
|
58
|
-
is_initial_connection: bool, force_connect_func: Callable) -> Connection:
|
|
59
|
-
return self._connect(host_info, props, is_initial_connection, force_connect_func)
|
|
60
|
-
|
|
61
|
-
def _connect(self, host_info: HostInfo, props: Properties, is_initial_connection: bool, connect_func: Callable):
|
|
62
|
-
type: RdsUrlType = self._rds_utils.identify_rds_type(host_info.host)
|
|
63
|
-
if not type.is_rds_cluster:
|
|
53
|
+
url_type: RdsUrlType = self._rds_utils.identify_rds_type(host_info.host)
|
|
54
|
+
if not url_type.is_rds_cluster:
|
|
64
55
|
return connect_func()
|
|
65
56
|
|
|
66
|
-
if
|
|
57
|
+
if url_type == RdsUrlType.RDS_WRITER_CLUSTER:
|
|
67
58
|
writer_candidate_conn: Optional[Connection] = self._get_verified_writer_connection(props, is_initial_connection, connect_func)
|
|
68
59
|
if writer_candidate_conn is None:
|
|
69
60
|
return connect_func()
|
|
70
61
|
return writer_candidate_conn
|
|
71
62
|
|
|
72
|
-
if
|
|
63
|
+
if url_type == RdsUrlType.RDS_READER_CLUSTER:
|
|
73
64
|
reader_candidate_conn: Optional[Connection] = self._get_verified_reader_connection(props, is_initial_connection, connect_func)
|
|
74
65
|
if reader_candidate_conn is None:
|
|
75
66
|
return connect_func()
|
|
76
67
|
return reader_candidate_conn
|
|
77
68
|
|
|
69
|
+
return connect_func()
|
|
70
|
+
|
|
78
71
|
def _get_verified_writer_connection(self, props: Properties, is_initial_connection: bool, connect_func: Callable) -> Connection | None:
|
|
79
72
|
retry_delay_ms: int = WrapperProperties.OPEN_CONNECTION_RETRY_INTERVAL_MS.get_int(props)
|
|
80
73
|
end_time_nano = perf_counter_ns() + (WrapperProperties.OPEN_CONNECTION_RETRY_INTERVAL_MS.get_int(props) * 1000000)
|
|
@@ -84,7 +77,6 @@ class AuroraInitialConnectionStrategyPlugin(Plugin):
|
|
|
84
77
|
|
|
85
78
|
while perf_counter_ns() < end_time_nano:
|
|
86
79
|
writer_candidate_conn = None
|
|
87
|
-
writer_candidate = None
|
|
88
80
|
|
|
89
81
|
try:
|
|
90
82
|
writer_candidate = self._get_writer()
|
|
@@ -94,7 +86,7 @@ class AuroraInitialConnectionStrategyPlugin(Plugin):
|
|
|
94
86
|
self._plugin_service.force_refresh_host_list(writer_candidate_conn)
|
|
95
87
|
writer_candidate = self._plugin_service.identify_connection(writer_candidate_conn)
|
|
96
88
|
|
|
97
|
-
if writer_candidate is
|
|
89
|
+
if writer_candidate is None or writer_candidate.role != HostRole.WRITER:
|
|
98
90
|
self._close_connection(writer_candidate_conn)
|
|
99
91
|
self._delay(retry_delay_ms)
|
|
100
92
|
continue
|
|
@@ -141,6 +133,11 @@ class AuroraInitialConnectionStrategyPlugin(Plugin):
|
|
|
141
133
|
self._plugin_service.force_refresh_host_list(reader_candidate_conn)
|
|
142
134
|
reader_candidate = self._plugin_service.identify_connection(reader_candidate_conn)
|
|
143
135
|
|
|
136
|
+
if reader_candidate is None:
|
|
137
|
+
self._close_connection(reader_candidate_conn)
|
|
138
|
+
self._delay(retry_delay_ms)
|
|
139
|
+
continue
|
|
140
|
+
|
|
144
141
|
if reader_candidate is not None and reader_candidate.role != HostRole.READER:
|
|
145
142
|
if self._has_no_readers():
|
|
146
143
|
# Cluster has no readers. Simulate Aurora reader cluster endpoint logic and return the current writer connection.
|
|
@@ -17,11 +17,13 @@ from __future__ import annotations
|
|
|
17
17
|
from json import JSONDecodeError, loads
|
|
18
18
|
from re import search
|
|
19
19
|
from types import SimpleNamespace
|
|
20
|
-
from typing import TYPE_CHECKING, Callable,
|
|
20
|
+
from typing import TYPE_CHECKING, Callable, Optional, Set, Tuple
|
|
21
21
|
|
|
22
22
|
import boto3
|
|
23
23
|
from botocore.exceptions import ClientError, EndpointConnectionError
|
|
24
24
|
|
|
25
|
+
from aws_advanced_python_wrapper.utils.cache_map import CacheMap
|
|
26
|
+
|
|
25
27
|
if TYPE_CHECKING:
|
|
26
28
|
from boto3 import Session
|
|
27
29
|
from aws_advanced_python_wrapper.driver_dialect import DriverDialect
|
|
@@ -46,8 +48,10 @@ class AwsSecretsManagerPlugin(Plugin):
|
|
|
46
48
|
_SUBSCRIBED_METHODS: Set[str] = {"connect", "force_connect"}
|
|
47
49
|
|
|
48
50
|
_SECRETS_ARN_PATTERN = r"^arn:aws:secretsmanager:(?P<region>[^:\n]*):[^:\n]*:([^:/\n]*[:/])?(.*)$"
|
|
51
|
+
_ONE_YEAR_IN_SECONDS = 60 * 60 * 24 * 365
|
|
49
52
|
|
|
50
|
-
|
|
53
|
+
_secret: Optional[SimpleNamespace] = None
|
|
54
|
+
_secrets_cache: CacheMap[Tuple, SimpleNamespace] = CacheMap()
|
|
51
55
|
_secret_key: Tuple = ()
|
|
52
56
|
|
|
53
57
|
@property
|
|
@@ -94,7 +98,13 @@ class AwsSecretsManagerPlugin(Plugin):
|
|
|
94
98
|
return self._connect(props, force_connect_func)
|
|
95
99
|
|
|
96
100
|
def _connect(self, props: Properties, connect_func: Callable) -> Connection:
|
|
97
|
-
|
|
101
|
+
token_expiration_sec: int = WrapperProperties.SECRETS_MANAGER_EXPIRATION.get_int(props)
|
|
102
|
+
# if value is less than 0, default to one year
|
|
103
|
+
if token_expiration_sec < 0:
|
|
104
|
+
token_expiration_sec = AwsSecretsManagerPlugin._ONE_YEAR_IN_SECONDS
|
|
105
|
+
token_expiration_ns = token_expiration_sec * 1_000_000_000
|
|
106
|
+
|
|
107
|
+
secret_fetched: bool = self._update_secret(token_expiration_ns=token_expiration_ns)
|
|
98
108
|
|
|
99
109
|
try:
|
|
100
110
|
self._apply_secret_to_properties(props)
|
|
@@ -105,7 +115,7 @@ class AwsSecretsManagerPlugin(Plugin):
|
|
|
105
115
|
raise AwsWrapperError(
|
|
106
116
|
Messages.get_formatted("AwsSecretsManagerPlugin.ConnectException", e)) from e
|
|
107
117
|
|
|
108
|
-
secret_fetched = self._update_secret(True)
|
|
118
|
+
secret_fetched = self._update_secret(token_expiration_ns=token_expiration_ns, force_refetch=True)
|
|
109
119
|
|
|
110
120
|
if secret_fetched:
|
|
111
121
|
try:
|
|
@@ -117,9 +127,10 @@ class AwsSecretsManagerPlugin(Plugin):
|
|
|
117
127
|
unhandled_error)) from unhandled_error
|
|
118
128
|
raise AwsWrapperError(Messages.get_formatted("AwsSecretsManagerPlugin.FailedLogin", e)) from e
|
|
119
129
|
|
|
120
|
-
def _update_secret(self, force_refetch: bool = False) -> bool:
|
|
130
|
+
def _update_secret(self, token_expiration_ns: int, force_refetch: bool = False) -> bool:
|
|
121
131
|
"""
|
|
122
132
|
Called to update credentials from the cache, or from the AWS Secrets Manager service.
|
|
133
|
+
:param token_expiration_ns: Expiration time in nanoseconds for secret stored in cache.
|
|
123
134
|
:param force_refetch: Allows ignoring cached credentials and force fetches the latest credentials from the service.
|
|
124
135
|
:return: `True`, if credentials were fetched from the service.
|
|
125
136
|
"""
|
|
@@ -135,7 +146,7 @@ class AwsSecretsManagerPlugin(Plugin):
|
|
|
135
146
|
try:
|
|
136
147
|
self._secret = self._fetch_latest_credentials()
|
|
137
148
|
if self._secret:
|
|
138
|
-
AwsSecretsManagerPlugin._secrets_cache
|
|
149
|
+
AwsSecretsManagerPlugin._secrets_cache.put(self._secret_key, self._secret, token_expiration_ns)
|
|
139
150
|
fetched = True
|
|
140
151
|
except (ClientError, AttributeError) as e:
|
|
141
152
|
logger.debug("AwsSecretsManagerPlugin.FailedToFetchDbCredentials", e)
|
|
@@ -188,12 +199,15 @@ class AwsSecretsManagerPlugin(Plugin):
|
|
|
188
199
|
"""
|
|
189
200
|
Updates credentials in provided properties. Other plugins in the plugin chain may change them if needed.
|
|
190
201
|
Eventually, credentials will be used to open a new connection in :py:class:`DefaultConnectionPlugin`.
|
|
191
|
-
|
|
192
|
-
:param properties: Properties to store credentials.
|
|
193
202
|
"""
|
|
194
203
|
if self._secret:
|
|
195
|
-
WrapperProperties.
|
|
196
|
-
|
|
204
|
+
username_key = WrapperProperties.SECRETS_MANAGER_SECRET_USERNAME_KEY.get(properties)
|
|
205
|
+
username_value = getattr(self._secret, str(username_key))
|
|
206
|
+
WrapperProperties.USER.set(properties, username_value)
|
|
207
|
+
|
|
208
|
+
password_key = WrapperProperties.SECRETS_MANAGER_SECRET_PASSWORD_KEY.get(properties)
|
|
209
|
+
password_value = getattr(self._secret, str(password_key))
|
|
210
|
+
WrapperProperties.PASSWORD.set(properties, password_value)
|
|
197
211
|
|
|
198
212
|
def _get_rds_region(self, secret_id: str, props: Properties) -> str:
|
|
199
213
|
session = self._session if self._session else boto3.Session()
|