clear-skies-aws 1.10.2__py3-none-any.whl → 2.0.2__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.
- {clear_skies_aws-1.10.2.dist-info → clear_skies_aws-2.0.2.dist-info}/METADATA +36 -35
- clear_skies_aws-2.0.2.dist-info/RECORD +63 -0
- {clear_skies_aws-1.10.2.dist-info → clear_skies_aws-2.0.2.dist-info}/WHEEL +1 -1
- clear_skies_aws-2.0.2.dist-info/licenses/LICENSE +21 -0
- clearskies_aws/__init__.py +15 -2
- clearskies_aws/actions/__init__.py +13 -106
- clearskies_aws/actions/action_aws.py +74 -57
- clearskies_aws/actions/assume_role.py +43 -30
- clearskies_aws/actions/ses.py +82 -73
- clearskies_aws/actions/sns.py +27 -30
- clearskies_aws/actions/sqs.py +32 -33
- clearskies_aws/actions/step_function.py +38 -31
- clearskies_aws/backends/__init__.py +11 -4
- clearskies_aws/backends/backend.py +106 -0
- clearskies_aws/backends/dynamo_db_backend.py +150 -155
- clearskies_aws/backends/dynamo_db_condition_parser.py +40 -80
- clearskies_aws/backends/dynamo_db_parti_ql_backend.py +179 -337
- clearskies_aws/backends/sqs_backend.py +32 -51
- clearskies_aws/configs/__init__.py +0 -0
- clearskies_aws/contexts/__init__.py +23 -10
- clearskies_aws/contexts/cli_web_socket_mock.py +19 -0
- clearskies_aws/contexts/lambda_alb.py +76 -0
- clearskies_aws/contexts/lambda_api_gateway.py +75 -28
- clearskies_aws/contexts/lambda_api_gateway_web_socket.py +56 -29
- clearskies_aws/contexts/lambda_invocation.py +15 -44
- clearskies_aws/contexts/lambda_sns.py +8 -33
- clearskies_aws/contexts/lambda_sqs_standard_partial_batch.py +14 -36
- clearskies_aws/di/__init__.py +6 -1
- clearskies_aws/di/aws_additional_config_auto_import.py +37 -0
- clearskies_aws/di/inject/__init__.py +6 -0
- clearskies_aws/di/inject/boto3.py +15 -0
- clearskies_aws/di/inject/boto3_session.py +13 -0
- clearskies_aws/di/inject/parameter_store.py +15 -0
- clearskies_aws/{handlers → endpoints}/secrets_manager_rotation.py +76 -55
- clearskies_aws/endpoints/simple_body_routing.py +41 -0
- clearskies_aws/input_outputs/__init__.py +21 -8
- clearskies_aws/input_outputs/{cli_websocket_mock.py → cli_web_socket_mock.py} +9 -3
- clearskies_aws/input_outputs/lambda_alb.py +53 -0
- clearskies_aws/input_outputs/lambda_api_gateway.py +106 -88
- clearskies_aws/input_outputs/lambda_api_gateway_web_socket.py +69 -6
- clearskies_aws/input_outputs/lambda_input_output.py +87 -0
- clearskies_aws/input_outputs/lambda_invocation.py +77 -26
- clearskies_aws/input_outputs/lambda_sns.py +66 -39
- clearskies_aws/input_outputs/lambda_sqs_standard.py +70 -40
- clearskies_aws/mocks/actions/ses.py +25 -19
- clearskies_aws/mocks/actions/sns.py +18 -12
- clearskies_aws/mocks/actions/sqs.py +18 -12
- clearskies_aws/mocks/actions/step_function.py +19 -13
- clearskies_aws/models/__init__.py +0 -0
- clearskies_aws/models/web_socket_connection_model.py +182 -0
- clearskies_aws/secrets/__init__.py +13 -7
- clearskies_aws/secrets/additional_configs/__init__.py +10 -2
- clearskies_aws/secrets/additional_configs/iam_db_auth.py +26 -16
- clearskies_aws/secrets/additional_configs/iam_db_auth_with_ssm.py +43 -39
- clearskies_aws/secrets/additional_configs/mysql_connection_dynamic_producer_via_ssh_cert_bastion.py +30 -31
- clearskies_aws/secrets/additional_configs/mysql_connection_dynamic_producer_via_ssm_bastion.py +70 -49
- clearskies_aws/secrets/akeyless_with_ssm_cache.py +32 -18
- clearskies_aws/secrets/parameter_store.py +34 -32
- clearskies_aws/secrets/secrets.py +16 -0
- clearskies_aws/secrets/secrets_manager.py +78 -57
- clear_skies_aws-1.10.2.dist-info/LICENSE +0 -7
- clear_skies_aws-1.10.2.dist-info/RECORD +0 -71
- clearskies_aws/actions/assume_role_test.py +0 -72
- clearskies_aws/actions/ses_test.py +0 -89
- clearskies_aws/actions/sns_test.py +0 -77
- clearskies_aws/actions/sqs_test.py +0 -127
- clearskies_aws/actions/step_function_test.py +0 -103
- clearskies_aws/backends/dynamo_db_backend_test.py +0 -300
- clearskies_aws/backends/dynamo_db_condition_parser_test.py +0 -266
- clearskies_aws/backends/dynamo_db_parti_ql_backend_test.py +0 -544
- clearskies_aws/backends/sqs_backend_test.py +0 -31
- clearskies_aws/contexts/cli.py +0 -19
- clearskies_aws/contexts/cli_websocket_mock.py +0 -33
- clearskies_aws/contexts/lambda_elb.py +0 -30
- clearskies_aws/contexts/lambda_http_gateway.py +0 -30
- clearskies_aws/contexts/lambda_sqs_standard_partial_batch_test.py +0 -66
- clearskies_aws/contexts/wsgi.py +0 -19
- clearskies_aws/di/standard_dependencies.py +0 -60
- clearskies_aws/handlers/simple_body_routing.py +0 -39
- clearskies_aws/input_outputs/lambda_api_gateway_test.py +0 -87
- clearskies_aws/input_outputs/lambda_elb.py +0 -21
- clearskies_aws/input_outputs/lambda_http_gateway.py +0 -12
- clearskies_aws/secrets/parameter_store_test.py +0 -18
- clearskies_aws/secrets/secrets_manager_test.py +0 -18
- clearskies_aws/web_socket_connection_model.py +0 -43
- clearskies_aws/{handlers → endpoints}/__init__.py +1 -1
|
@@ -1,46 +1,48 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: clear-skies-aws
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.2
|
|
4
4
|
Summary: clearskies bindings for working in AWS
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
Project-URL: Repository, https://github.com/clearskies-py/clearskies-aws
|
|
6
|
+
Project-URL: Issues, https://github.com/clearskies-py/clearskies-aws/issues
|
|
7
|
+
Project-URL: Changelog, https://github.com/clearskies-py/clearskies-aws/blob/main/CHANGELOG.md
|
|
8
|
+
Project-URL: Documentation, https://clearskies.info/modules/clearskies-aws/
|
|
9
|
+
Author: tnijboer
|
|
10
|
+
Author-email: Conor Mancone <cmancone@gmail.com>
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
9
15
|
Classifier: License :: OSI Approved :: MIT License
|
|
10
16
|
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
17
|
+
Requires-Python: <4.0,>=3.11
|
|
18
|
+
Requires-Dist: boto3<2.0.0,>=1.26.148
|
|
19
|
+
Requires-Dist: clear-skies<3.0.0,>=2.0.2
|
|
20
|
+
Requires-Dist: types-boto3[dynamodb,sns,sqs]<2.0.0,>=1.38.13
|
|
15
21
|
Provides-Extra: akeyless
|
|
22
|
+
Requires-Dist: akeyless-cloud-id<0.5.0,>=0.2.3; extra == 'akeyless'
|
|
23
|
+
Requires-Dist: akeyless<6.0.0,>=5.0.0; extra == 'akeyless'
|
|
16
24
|
Provides-Extra: ses
|
|
17
|
-
Requires-Dist:
|
|
18
|
-
Requires-Dist: akeyless-cloud-id (>=0.2.3,<0.3.0) ; extra == "akeyless"
|
|
19
|
-
Requires-Dist: boto3 (>=1.26.148,<2.0.0)
|
|
20
|
-
Requires-Dist: clear-skies (>=1.14.4,<2.0.0)
|
|
21
|
-
Requires-Dist: jinja2 (>=3.1.2,<4.0.0) ; extra == "ses"
|
|
22
|
-
Requires-Dist: types-boto3[dynamodb,sns,sqs] (>=1.38.13,<2.0.0)
|
|
23
|
-
Project-URL: Repository, https://github.com/cmancone/clearskies-aws
|
|
25
|
+
Requires-Dist: jinja2<4.0.0,>=3.1.2; extra == 'ses'
|
|
24
26
|
Description-Content-Type: text/markdown
|
|
25
27
|
|
|
26
28
|
# clearskies-aws
|
|
27
29
|
|
|
28
30
|
clearskies bindings for working in AWS, which means additional:
|
|
29
31
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
- backends (DynamoDB, SQS)
|
|
33
|
+
- Secret/environment integrations (parameter store/secret manager)
|
|
34
|
+
- DB connectivity via IAM auth
|
|
35
|
+
- Contexts (ALB, HTTP API Gateway, Rest API Gateway, direct Lambda invocation, lambda+SQS)
|
|
34
36
|
|
|
35
|
-
|
|
37
|
+
## Installation, Documentation, and Usage
|
|
36
38
|
|
|
37
39
|
To install:
|
|
38
40
|
|
|
39
|
-
```
|
|
41
|
+
```shell
|
|
40
42
|
pip3 install clear-skies-aws
|
|
41
43
|
```
|
|
42
44
|
|
|
43
|
-
|
|
45
|
+
## Usage
|
|
44
46
|
|
|
45
47
|
Anytime you use a context from `clearskies-aws`, the default dependencies are adjust to:
|
|
46
48
|
|
|
@@ -49,17 +51,17 @@ Anytime you use a context from `clearskies-aws`, the default dependencies are ad
|
|
|
49
51
|
|
|
50
52
|
In both cases you must provide the AWS region for your resources, which you do by setting the `AWS_REGION` environment variable (either in an actual environment variable or in your `.env` file).
|
|
51
53
|
|
|
52
|
-
|
|
54
|
+
### Parameter Store
|
|
53
55
|
|
|
54
56
|
To use the SSM parameter store you just inject the `secrets` variable into your callables:
|
|
55
57
|
|
|
56
|
-
```
|
|
58
|
+
```python
|
|
57
59
|
import clearskies_aws
|
|
58
60
|
|
|
59
61
|
def parameter_store_demo(secrets):
|
|
60
62
|
return secrets.get('/path/to/parameter')
|
|
61
63
|
|
|
62
|
-
execute_demo_in_elb = clearskies_aws.contexts.
|
|
64
|
+
execute_demo_in_elb = clearskies_aws.contexts.lambda_alb(parameter_store_demo)
|
|
63
65
|
|
|
64
66
|
def lambda_handler(event, context):
|
|
65
67
|
return execute_demo_in_elb(event, context)
|
|
@@ -67,14 +69,14 @@ def lambda_handler(event, context):
|
|
|
67
69
|
|
|
68
70
|
Also, per default behavior, clearskies can fetch things from your secret manager if specified in your environment/.env file. For instance, if your database password is stored in parameter store, then you can reference it from your `.env` file with a standard cursor backend:
|
|
69
71
|
|
|
70
|
-
```
|
|
72
|
+
```env
|
|
71
73
|
db_host = "path-to-aws.rds"
|
|
72
74
|
db_username = "sql_username"
|
|
73
75
|
db_password = "secret://path/to/password/in/parameter/store"
|
|
74
76
|
db_database = "sql_database_name"
|
|
75
77
|
```
|
|
76
78
|
|
|
77
|
-
|
|
79
|
+
### Secret Manager
|
|
78
80
|
|
|
79
81
|
If desired, you can swap out the parameter store integration for secret manager. Just remember that you can configure parameter store to fetch secrets from secret manager, so you might be best off doing that and sticking with the default parameter store integration. Still, if you want to use secret manager, you just configure it in your application or context:
|
|
80
82
|
|
|
@@ -93,7 +95,7 @@ def lambda_handler(event, context):
|
|
|
93
95
|
return execute_demo_in_elb(event, context)
|
|
94
96
|
```
|
|
95
97
|
|
|
96
|
-
|
|
98
|
+
### Contexts
|
|
97
99
|
|
|
98
100
|
clearskies_aws adds the following contexts:
|
|
99
101
|
|
|
@@ -105,7 +107,7 @@ clearskies_aws adds the following contexts:
|
|
|
105
107
|
| `clearskies_aws.contexts.lambda_inocation` | Lambdas invoked directly |
|
|
106
108
|
| `clearskies_aws.contexts.lambda_sqs_standard_partial_batch` | Lambdas attached to an SQS queue |
|
|
107
109
|
|
|
108
|
-
|
|
110
|
+
#### Lambdas+SQS
|
|
109
111
|
|
|
110
112
|
Here's a simple example of using the Lambda+SQS context:
|
|
111
113
|
|
|
@@ -125,7 +127,7 @@ See [the AWS docs](https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html).
|
|
|
125
127
|
|
|
126
128
|
Note that, unlike other contexts, the Lambda+SQS context really only works with a simple callable. Routing and other handlers don't make much sense here. Keep in mind that, before invoking the Lambda, AWS may batch up records together in arbitrary ways. The context will take care of this and will invoke your callable once **for each record in the AWS event** - not once for the event. `request_data` will be populated with the actual message for the event. In addition, it assumes that a JSON message was sent to the queue, so `request_data` will be an object/list/etc, rather than a string. This is intended to be used with [partial batching](https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html#services-sqs-batchfailurereporting). Therefore, if your function raises an error, the context will catch it, return a failure response for the cooresponding message, and then continue processing any other messages in the batch.
|
|
127
129
|
|
|
128
|
-
|
|
130
|
+
### SQS Backend
|
|
129
131
|
|
|
130
132
|
To use the SQS backend just declare it for your model, set the table name to return the queue url, and execute a "create" operation to send data to the queue. Note that the SQS backend is write-only: you can "create" records (resulting in a message being sent to the queue), but you can't read data back out. The way the queue system in SQS works is just too different than a standard database for that to make sense in the context of a clearskies model.
|
|
131
133
|
|
|
@@ -164,7 +166,7 @@ if __name__ == '__main__':
|
|
|
164
166
|
cli()
|
|
165
167
|
```
|
|
166
168
|
|
|
167
|
-
|
|
169
|
+
### IAM DB Auth
|
|
168
170
|
|
|
169
171
|
For non-serverless RDS databases, AWS supports login via IAM. You have to provide a few additional details in your environment to make this work:
|
|
170
172
|
|
|
@@ -195,7 +197,6 @@ def lambda_handler(event, context):
|
|
|
195
197
|
|
|
196
198
|
Of course normally you wouldn't want to interact with it directly. Adding `IAMDBAuth` to your `additional_configs` and setting up the necessary environemnt variables will be sufficient that any models that use the `cursor_backend` will connect via IAM DB Auth, rather than using hard-coded passwords.
|
|
197
199
|
|
|
198
|
-
|
|
200
|
+
### IAM DB Auth with SSM Bastion
|
|
199
201
|
|
|
200
202
|
Coming shortly
|
|
201
|
-
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
clearskies_aws/__init__.py,sha256=LAzXoPm5wVRdxUoQIWuBS_c71t9IT_iq-mIh338154o,297
|
|
2
|
+
clearskies_aws/actions/__init__.py,sha256=YsIi3ZTdByu4R7I77uOAXDE5hzB31J_tRrIoTxe_bjo,371
|
|
3
|
+
clearskies_aws/actions/action_aws.py,sha256=JMogBFIrN72h5oBQLbyMy0LmfVLrqvWCYLQDml1qO4M,4674
|
|
4
|
+
clearskies_aws/actions/assume_role.py,sha256=XNxbVju460aBMS8NQhY80eoNVQgZRJ6-OydsNOx3neA,4319
|
|
5
|
+
clearskies_aws/actions/ses.py,sha256=Cu8USID8vy2IZC6sFOIQRzv8a0LCMvYG15yn0l-fl5g,8431
|
|
6
|
+
clearskies_aws/actions/sns.py,sha256=YS1TbEwtU-0lDbjG2HyTBs2J-ML5OL3ModAiGTMeK-c,2205
|
|
7
|
+
clearskies_aws/actions/sqs.py,sha256=r0z8njU87n09UgAq3l34JuNIbaBE85D_z8IE6ciIs9Q,3359
|
|
8
|
+
clearskies_aws/actions/step_function.py,sha256=Y6tGbQJIAD_IwV9ohwYfuv3vqtryTwpFTNGUFgdj_DQ,2689
|
|
9
|
+
clearskies_aws/backends/__init__.py,sha256=LgMNrf2yD9_PZBGbfs3yQGWM0NelSwk9GO73NfGwc44,587
|
|
10
|
+
clearskies_aws/backends/backend.py,sha256=WpsoT0pZOdilvtOkbiNtk6DoOEzmjyWcCDfUCWOlToc,4316
|
|
11
|
+
clearskies_aws/backends/dynamo_db_backend.py,sha256=cTlbSpMiJ-0YILeHRrMZ6u4blRl_76hmemZZO9BwNN4,29396
|
|
12
|
+
clearskies_aws/backends/dynamo_db_condition_parser.py,sha256=OipIlFpcfS2GQiGpge6ZFX4NZNfNtHF87qi9g3yZgIU,12622
|
|
13
|
+
clearskies_aws/backends/dynamo_db_parti_ql_backend.py,sha256=x1pLNTUsTjCxi1SDryr9_uhL-AQJS7ksP5bvQpnhaC8,46081
|
|
14
|
+
clearskies_aws/backends/sqs_backend.py,sha256=kHTzgBwpYzV31UcGaoSUcC_7eZEwm-GsCHvXFM1OLT0,2152
|
|
15
|
+
clearskies_aws/configs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
+
clearskies_aws/contexts/__init__.py,sha256=sdcIT85OXqwwo8CcBYuyNcN6kvkwv1Ph8MTwuSi4Bnk,767
|
|
17
|
+
clearskies_aws/contexts/cli_web_socket_mock.py,sha256=ZjOhOtQHJ4Vf9V1Bkole6JiGyP1CLTzPqwTrLiiOi0A,660
|
|
18
|
+
clearskies_aws/contexts/lambda_alb.py,sha256=9eLemimudZ4WsWGarONIhoiFnlk_fBygQ6XwJb7NrbY,3237
|
|
19
|
+
clearskies_aws/contexts/lambda_api_gateway.py,sha256=K8sKDV2JtXbzcDy9SOd7kMveuD6t5VGxls2iDMiVhXY,2787
|
|
20
|
+
clearskies_aws/contexts/lambda_api_gateway_web_socket.py,sha256=t3dLRT3s37xHazMa-KVOSWF-0OaUpGQ4an-olbeeJUw,3238
|
|
21
|
+
clearskies_aws/contexts/lambda_invocation.py,sha256=j3AhSXMHRwKufOSTUjhMyeFk4sO_Y4BlX4ECCFvMudw,538
|
|
22
|
+
clearskies_aws/contexts/lambda_sns.py,sha256=FFOIyyCQFKvYsolpf8zlVitdceRkgvEjds3GCXSJjdk,719
|
|
23
|
+
clearskies_aws/contexts/lambda_sqs_standard_partial_batch.py,sha256=kWl3rFtsAbSkadRLZunN20oXvCQpZJFcDhv3VMMWrCg,1093
|
|
24
|
+
clearskies_aws/di/__init__.py,sha256=pLHSIKxS1oELOgttRuwM0yXdJRxjZKXQ6tPxme2db0U,222
|
|
25
|
+
clearskies_aws/di/aws_additional_config_auto_import.py,sha256=qc9AUlFdF9jhAzS99esyvgY1MiW7mLz45fATK7Yp0rg,1271
|
|
26
|
+
clearskies_aws/di/inject/__init__.py,sha256=5_x5_BBQwC6J4k5YLdTm1DfIDM-95zXz1L5a1nMrlrY,186
|
|
27
|
+
clearskies_aws/di/inject/boto3.py,sha256=7qcn5N-RnUKiCd1U31JAjQHF6NDudS4KyBLT0krUD-Y,404
|
|
28
|
+
clearskies_aws/di/inject/boto3_session.py,sha256=11UYHz5kgrrx5lawoYaOFBm-QIoa45YUCMAOn4gT8Jo,383
|
|
29
|
+
clearskies_aws/di/inject/parameter_store.py,sha256=g0uAVwQEywLO9bCcYLbDKuyYnYgVyrfcYsOBJWYGads,475
|
|
30
|
+
clearskies_aws/endpoints/__init__.py,sha256=A2e3zCI8Ywg95WcTk1f92fpmlJ6eD4mTfcR43yX9sow,112
|
|
31
|
+
clearskies_aws/endpoints/secrets_manager_rotation.py,sha256=CqtE7pJ1FiPStRjMI1WsflcYXgcr-miRUE-IU1UKmnk,7764
|
|
32
|
+
clearskies_aws/endpoints/simple_body_routing.py,sha256=B3fnfxUEMuNpzc26Pzly6618DFU9fpaCk8KhTGSaptE,1181
|
|
33
|
+
clearskies_aws/input_outputs/__init__.py,sha256=83rhCp7knun2WB4Pd53H8KvVgM_4_Lt0YuD2Gvo2UPk,755
|
|
34
|
+
clearskies_aws/input_outputs/cli_web_socket_mock.py,sha256=a96M1vnUfpe0YL04iSFpV_oXG6IkygRd710CDo72wc4,496
|
|
35
|
+
clearskies_aws/input_outputs/lambda_alb.py,sha256=iYooG5AlkrQQgzSt304A5_u_UhuqYh-9PeLvFdGM_Eg,2013
|
|
36
|
+
clearskies_aws/input_outputs/lambda_api_gateway.py,sha256=n5XiaxmaFKJ9wMQcNQwizpjcA-L_bdLk1aUk-QyO58w,4672
|
|
37
|
+
clearskies_aws/input_outputs/lambda_api_gateway_web_socket.py,sha256=P9cMrOxRlezUh7OIqGrV_34amksI6n_1ZPYujSLY_so,2702
|
|
38
|
+
clearskies_aws/input_outputs/lambda_input_output.py,sha256=71sW2vQi-yCf0wE8DGso0Zy1G7cn5D-gnEELIvEnbiw,2743
|
|
39
|
+
clearskies_aws/input_outputs/lambda_invocation.py,sha256=y8dPkjt9rvSJd2tkctdtM1-q_SnRPR_bXc9aySjRgdE,2800
|
|
40
|
+
clearskies_aws/input_outputs/lambda_sns.py,sha256=n04gS8bgo3sX8EZTkBvdCykm5dlV4lloc7IoPv71_T8,2657
|
|
41
|
+
clearskies_aws/input_outputs/lambda_sqs_standard.py,sha256=ubrSdU0RTHIURLk_kgKs3Gt7LcxaUlRBdA67169qHlA,2880
|
|
42
|
+
clearskies_aws/mocks/__init__.py,sha256=mn764gINN667tYoJfnsM6HjAAhCsO_kZ6E-fUwdLY50,22
|
|
43
|
+
clearskies_aws/mocks/actions/__init__.py,sha256=to1r8B365Et2PRVfUWWnJGt7Hdr8vwwQuNyZvTSTP6g,152
|
|
44
|
+
clearskies_aws/mocks/actions/ses.py,sha256=KsII9ggU364BQoxgHfO2rxi6tjVsdnwJyMhtclOhWLQ,998
|
|
45
|
+
clearskies_aws/mocks/actions/sns.py,sha256=yGY3V0_htOZ3y8VTLdznoMSUQZvnjulQbrR5z_-0fXQ,706
|
|
46
|
+
clearskies_aws/mocks/actions/sqs.py,sha256=y0Vq7IMbjlfT5JMNHfbPsq9XVZhUF-G0kdXzQnPzyUA,710
|
|
47
|
+
clearskies_aws/mocks/actions/step_function.py,sha256=ENEVy8Ai3vPymbQre5aWa5z2McBjlnopfsLxdO7oEbc,937
|
|
48
|
+
clearskies_aws/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
49
|
+
clearskies_aws/models/web_socket_connection_model.py,sha256=5M1qfQHKuWMYPUDkwT48QPo2ROey7koizvWLfapsfow,7492
|
|
50
|
+
clearskies_aws/secrets/__init__.py,sha256=0mqYja2ETBHJh4b3jgRhhJV1uGdZc9S7cUvcV5QByPs,445
|
|
51
|
+
clearskies_aws/secrets/akeyless_with_ssm_cache.py,sha256=32HUS1KQ5F6Fu70HDtojqDL7VZvP_YDgbWLTTmNJvPA,2073
|
|
52
|
+
clearskies_aws/secrets/parameter_store.py,sha256=nMpkbUnxHGcCoMD5T-weCS13f1RZA7ZHl24O7qXaZLE,1882
|
|
53
|
+
clearskies_aws/secrets/secrets.py,sha256=aDMPj-tuXdRhh8YKMnsJe9V_VLrD8Cru-xUKs8cyDIY,485
|
|
54
|
+
clearskies_aws/secrets/secrets_manager.py,sha256=hK10lVmEFJltTv7h2AkYR3ySCVXx1JVy56jWU1hyYso,3708
|
|
55
|
+
clearskies_aws/secrets/additional_configs/__init__.py,sha256=0NFOMVod8tte_K0Jq1Qf7_DDBvp6aEE4wF4hddQaW8w,1927
|
|
56
|
+
clearskies_aws/secrets/additional_configs/iam_db_auth.py,sha256=PwyiLaacpRfhBKzQBdvGWHUYf5Ymth1sG2ly7Z6RoR0,1238
|
|
57
|
+
clearskies_aws/secrets/additional_configs/iam_db_auth_with_ssm.py,sha256=ABY29X-YvrE6vvNo6kVdf4DqyRNq5cFR5SfK7MNkltE,3463
|
|
58
|
+
clearskies_aws/secrets/additional_configs/mysql_connection_dynamic_producer_via_ssh_cert_bastion.py,sha256=mLaplwvJLSbGh6oXgdOKL9Mv-6hLv5OUYCfEwHbHvLE,3700
|
|
59
|
+
clearskies_aws/secrets/additional_configs/mysql_connection_dynamic_producer_via_ssm_bastion.py,sha256=2VHOwto4I9gBwrpd2HGpL-Wr0T2S-jFjUhe2Ib8hNJ8,6596
|
|
60
|
+
clear_skies_aws-2.0.2.dist-info/METADATA,sha256=BcwJmkUhC-KD2QwepuW2kAeU6IRITpMOKrKCgAO2_b4,8972
|
|
61
|
+
clear_skies_aws-2.0.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
62
|
+
clear_skies_aws-2.0.2.dist-info/licenses/LICENSE,sha256=MkEX8JF8kZxdyBpTTcB0YTd-xZpWnHvbRlw-pQh8u58,1069
|
|
63
|
+
clear_skies_aws-2.0.2.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025, Tom Nijboer
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
clearskies_aws/__init__.py
CHANGED
|
@@ -1,2 +1,15 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from clearskies_aws import actions, backends, contexts, di, endpoints, input_outputs, mocks, models, secrets
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"models",
|
|
7
|
+
"actions",
|
|
8
|
+
"backends",
|
|
9
|
+
"contexts",
|
|
10
|
+
"di",
|
|
11
|
+
"endpoints",
|
|
12
|
+
"input_outputs",
|
|
13
|
+
"mocks",
|
|
14
|
+
"secrets",
|
|
15
|
+
]
|
|
@@ -1,108 +1,15 @@
|
|
|
1
|
-
import
|
|
1
|
+
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from clearskies_aws.actions.assume_role import AssumeRole
|
|
4
|
+
from clearskies_aws.actions.ses import SES
|
|
5
|
+
from clearskies_aws.actions.sns import SNS
|
|
6
|
+
from clearskies_aws.actions.sqs import SQS
|
|
7
|
+
from clearskies_aws.actions.step_function import StepFunction
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
to=None,
|
|
13
|
-
cc=None,
|
|
14
|
-
bcc=None,
|
|
15
|
-
subject=None,
|
|
16
|
-
message=None,
|
|
17
|
-
subject_template=None,
|
|
18
|
-
message_template=None,
|
|
19
|
-
subject_template_file=None,
|
|
20
|
-
message_template_file=None,
|
|
21
|
-
assume_role=None,
|
|
22
|
-
dependencies_for_template=None,
|
|
23
|
-
when=None,
|
|
24
|
-
):
|
|
25
|
-
return clearskies.BindingConfig(
|
|
26
|
-
SES,
|
|
27
|
-
sender,
|
|
28
|
-
to=to,
|
|
29
|
-
cc=cc,
|
|
30
|
-
bcc=bcc,
|
|
31
|
-
subject=subject,
|
|
32
|
-
subject_template=subject_template,
|
|
33
|
-
subject_template_file=subject_template_file,
|
|
34
|
-
message=message,
|
|
35
|
-
message_template=message_template,
|
|
36
|
-
message_template_file=message_template_file,
|
|
37
|
-
assume_role=assume_role,
|
|
38
|
-
dependencies_for_template=dependencies_for_template,
|
|
39
|
-
when=when,
|
|
40
|
-
)
|
|
41
|
-
def sns(
|
|
42
|
-
topic=None,
|
|
43
|
-
topic_environment_key=None,
|
|
44
|
-
topic_callable=None,
|
|
45
|
-
message_callable=None,
|
|
46
|
-
when=None,
|
|
47
|
-
):
|
|
48
|
-
return clearskies.BindingConfig(
|
|
49
|
-
SNS,
|
|
50
|
-
topic=topic,
|
|
51
|
-
topic_environment_key=topic_environment_key,
|
|
52
|
-
topic_callable=topic_callable,
|
|
53
|
-
message_callable=message_callable,
|
|
54
|
-
when=when,
|
|
55
|
-
)
|
|
56
|
-
def sqs(
|
|
57
|
-
queue_url: str = '',
|
|
58
|
-
queue_url_environment_key: str = '',
|
|
59
|
-
queue_url_callable: Callable = '',
|
|
60
|
-
message_callable: Callable = None,
|
|
61
|
-
when: Callable = None,
|
|
62
|
-
assume_role=None,
|
|
63
|
-
message_group_id: Optional[Union[Callable, str]]=None,
|
|
64
|
-
):
|
|
65
|
-
return clearskies.BindingConfig(
|
|
66
|
-
SQS,
|
|
67
|
-
queue_url=queue_url,
|
|
68
|
-
queue_url_environment_key=queue_url_environment_key,
|
|
69
|
-
queue_url_callable=queue_url_callable,
|
|
70
|
-
message_callable=message_callable,
|
|
71
|
-
when=when,
|
|
72
|
-
assume_role=assume_role,
|
|
73
|
-
message_group_id=message_group_id,
|
|
74
|
-
)
|
|
75
|
-
def step_function(
|
|
76
|
-
arn: str = "",
|
|
77
|
-
arn_environment_key: str = "",
|
|
78
|
-
arn_callable: Optional[Callable] = None,
|
|
79
|
-
message_callable: Optional[Callable] = None,
|
|
80
|
-
when: Optional[Callable] = None,
|
|
81
|
-
assume_role: Optional[AssumeRole] = None,
|
|
82
|
-
column_to_store_execution_arn: Optional[str] = None,
|
|
83
|
-
):
|
|
84
|
-
return clearskies.BindingConfig(
|
|
85
|
-
StepFunction,
|
|
86
|
-
arn=arn,
|
|
87
|
-
arn_environment_key=arn_environment_key,
|
|
88
|
-
arn_callable=arn_callable,
|
|
89
|
-
message_callable=message_callable,
|
|
90
|
-
when=when,
|
|
91
|
-
assume_role=assume_role,
|
|
92
|
-
column_to_store_execution_arn=column_to_store_execution_arn,
|
|
93
|
-
)
|
|
94
|
-
def assume_role(
|
|
95
|
-
role_arn: str,
|
|
96
|
-
external_id: str = "",
|
|
97
|
-
role_session_name: str = "",
|
|
98
|
-
duration: int = 3600,
|
|
99
|
-
source: Optional[AssumeRole] = None,
|
|
100
|
-
):
|
|
101
|
-
return AssumeRole(
|
|
102
|
-
role_arn,
|
|
103
|
-
external_id=external_id,
|
|
104
|
-
role_session_name=role_session_name,
|
|
105
|
-
duration=duration,
|
|
106
|
-
source=source,
|
|
107
|
-
)
|
|
108
|
-
__all__ = [assume_role, AssumeRole, ses, SES, sns, SNS, step_function, StepFunction, sqs, SQS]
|
|
9
|
+
__all__ = [
|
|
10
|
+
"AssumeRole",
|
|
11
|
+
"SES",
|
|
12
|
+
"SNS",
|
|
13
|
+
"SQS",
|
|
14
|
+
"StepFunction",
|
|
15
|
+
]
|
|
@@ -1,117 +1,134 @@
|
|
|
1
|
-
import
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
2
3
|
import json
|
|
3
4
|
import logging
|
|
4
|
-
|
|
5
5
|
from abc import ABC
|
|
6
|
-
from
|
|
6
|
+
from collections import OrderedDict
|
|
7
|
+
from types import ModuleType
|
|
8
|
+
from typing import Callable, Generic, TypeVar
|
|
9
|
+
|
|
10
|
+
from botocore.client import BaseClient
|
|
7
11
|
from botocore.exceptions import ClientError
|
|
8
|
-
from clearskies.
|
|
9
|
-
from clearskies.
|
|
12
|
+
from clearskies.action import Action
|
|
13
|
+
from clearskies.configs import Boolean, String
|
|
14
|
+
from clearskies.configs import Callable as CallableConfig
|
|
15
|
+
from clearskies.configurable import Configurable
|
|
16
|
+
from clearskies.decorators import parameters_to_properties
|
|
17
|
+
from clearskies.di.inject import Di, Environment
|
|
18
|
+
from clearskies.di.injectable_properties import InjectableProperties
|
|
10
19
|
from clearskies.functional import string
|
|
11
|
-
from
|
|
12
|
-
|
|
20
|
+
from clearskies.model import Model
|
|
21
|
+
|
|
22
|
+
from clearskies_aws.di import inject
|
|
13
23
|
|
|
14
|
-
from ..di import StandardDependencies
|
|
15
24
|
from .assume_role import AssumeRole
|
|
16
|
-
class ActionAws(ABC):
|
|
17
25
|
|
|
18
|
-
|
|
19
|
-
_client: Optional[boto3.client] = None
|
|
20
|
-
_name: Optional[str] = None
|
|
26
|
+
ClientType = TypeVar("ClientType", bound=BaseClient)
|
|
21
27
|
|
|
22
|
-
def __init__(self, environment: Environment, boto3: boto3, di: StandardDependencies) -> None:
|
|
23
|
-
"""Setup action."""
|
|
24
|
-
self.environment = environment
|
|
25
|
-
self.boto3 = boto3
|
|
26
|
-
self.di = di
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
self.when = when
|
|
36
|
-
self.message_callable = message_callable
|
|
37
|
-
self.assume_role = assume_role
|
|
29
|
+
class ActionAws(Generic[ClientType], Action, Configurable, InjectableProperties):
|
|
30
|
+
logging = logging.getLogger(__name__)
|
|
31
|
+
boto3 = inject.Boto3()
|
|
32
|
+
environment = Environment()
|
|
33
|
+
di = Di()
|
|
34
|
+
|
|
35
|
+
client: ClientType
|
|
38
36
|
|
|
39
|
-
|
|
40
|
-
raise ValueError(
|
|
41
|
-
"'message_callable' should be a callable that returns the message for the queue, but a callable was not passed."
|
|
42
|
-
)
|
|
37
|
+
service_name = String(required=True)
|
|
43
38
|
|
|
44
|
-
|
|
45
|
-
raise ValueError("'when' must be a callable but something else was found")
|
|
39
|
+
message_callable = CallableConfig(required=False, default=None)
|
|
46
40
|
|
|
47
|
-
|
|
48
|
-
raise ValueError(f"Name of client not set.")
|
|
41
|
+
when = CallableConfig(required=False, default=None)
|
|
49
42
|
|
|
50
|
-
|
|
51
|
-
raise ValueError("You must set either the AWS_REGION or AWS_DEFAULT_REGION environment variable when using AWS actions")
|
|
43
|
+
assume_role: AssumeRole | None = None
|
|
52
44
|
|
|
53
|
-
|
|
45
|
+
region = String(required=False)
|
|
46
|
+
|
|
47
|
+
can_cache = Boolean(default=True)
|
|
48
|
+
|
|
49
|
+
@parameters_to_properties
|
|
50
|
+
def __init__(
|
|
51
|
+
self,
|
|
52
|
+
service_name: str,
|
|
53
|
+
message_callable: Callable | None = None,
|
|
54
|
+
when: Callable | None = None,
|
|
55
|
+
assume_role: AssumeRole | None = None,
|
|
56
|
+
region: str | None = None,
|
|
57
|
+
) -> None:
|
|
58
|
+
"""Set up the AWS action."""
|
|
59
|
+
|
|
60
|
+
# def configure(self, **kwargs):
|
|
61
|
+
# """Configure the action with additional parameters."""
|
|
62
|
+
# # Finalize configuration properties from Configurable
|
|
63
|
+
# Configurable.finalize_and_validate_configuration(self)
|
|
64
|
+
|
|
65
|
+
# # Handle any additional kwargs by setting them as attributes
|
|
66
|
+
# for key, value in kwargs.items():
|
|
67
|
+
# if hasattr(self, key):
|
|
68
|
+
# setattr(self, key, value)
|
|
69
|
+
|
|
70
|
+
def __call__(self, model: Model) -> None:
|
|
54
71
|
"""Send a notification as configured."""
|
|
55
72
|
if self.when and not self.di.call_function(self.when, model=model):
|
|
56
73
|
return
|
|
57
74
|
|
|
58
75
|
try:
|
|
59
|
-
client = self.
|
|
76
|
+
client = self._get_client()
|
|
60
77
|
self._execute_action(client, model)
|
|
61
78
|
except ClientError as e:
|
|
62
|
-
self.
|
|
79
|
+
self.logging.exception(f"Failed to retrieve client for {self.__class__.__name__} action.")
|
|
63
80
|
raise e
|
|
64
81
|
|
|
65
|
-
def
|
|
82
|
+
def _get_client(self) -> ClientType:
|
|
66
83
|
"""Retrieve the boto3 client."""
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
return self._client
|
|
84
|
+
if hasattr(self, "client") and self.client and self.can_cache:
|
|
85
|
+
return self.client
|
|
70
86
|
|
|
71
87
|
if self.assume_role:
|
|
72
88
|
boto3 = self.assume_role(self.boto3)
|
|
73
89
|
else:
|
|
74
90
|
boto3 = self.boto3
|
|
75
91
|
|
|
76
|
-
if not region:
|
|
77
|
-
region = self.default_region()
|
|
78
|
-
if region:
|
|
79
|
-
client = boto3.client(self.
|
|
92
|
+
if not self.region:
|
|
93
|
+
self.region = self.default_region()
|
|
94
|
+
if self.region:
|
|
95
|
+
client = boto3.client(self.service_name, region_name=self.region)
|
|
80
96
|
else:
|
|
81
|
-
client = boto3.client(self.
|
|
97
|
+
client = boto3.client(self.service_name)
|
|
82
98
|
|
|
83
|
-
if can_cache:
|
|
84
|
-
self.
|
|
99
|
+
if self.can_cache:
|
|
100
|
+
self.client = client
|
|
85
101
|
return client
|
|
86
102
|
|
|
87
103
|
def default_region(self):
|
|
88
|
-
region = self.environment.get(
|
|
104
|
+
region = self.environment.get("AWS_REGION", silent=True)
|
|
89
105
|
if region:
|
|
90
106
|
return region
|
|
91
|
-
region = self.environment.get(
|
|
107
|
+
region = self.environment.get("DEFAULT_AWS_REGION", silent=True)
|
|
92
108
|
if region:
|
|
93
109
|
return region
|
|
94
110
|
return None
|
|
95
111
|
|
|
96
|
-
def _execute_action(self, client:
|
|
112
|
+
def _execute_action(self, client: ClientType, model: Model) -> None:
|
|
97
113
|
"""Run the action."""
|
|
98
114
|
pass
|
|
99
115
|
|
|
100
|
-
def get_message_body(self, model:
|
|
116
|
+
def get_message_body(self, model: Model) -> str:
|
|
101
117
|
"""Retrieve the message for the action."""
|
|
102
118
|
if self.message_callable:
|
|
103
119
|
result = self.di.call_function(self.message_callable, model=model)
|
|
104
120
|
if isinstance(result, dict) or isinstance(result, list):
|
|
105
121
|
return json.dumps(result, default=string.datetime_to_iso)
|
|
106
122
|
if not isinstance(result, str):
|
|
123
|
+
callable_name = getattr(self.message_callable, "__name__", str(self.message_callable))
|
|
107
124
|
raise TypeError(
|
|
108
125
|
f"The return value from the message callable for the {__name__} action must be a string, dictionary, or list. I received a "
|
|
109
|
-
+ f"{type(result)} after calling '{
|
|
126
|
+
+ f"{type(result)} after calling '{callable_name}'"
|
|
110
127
|
)
|
|
111
128
|
return result
|
|
112
129
|
|
|
113
130
|
model_data = OrderedDict()
|
|
114
|
-
for
|
|
131
|
+
for column_name, column in model.get_columns().items():
|
|
115
132
|
if not column.is_readable:
|
|
116
133
|
continue
|
|
117
134
|
model_data.update(column.to_json(model))
|