clear-skies-aws 2.0.1__py3-none-any.whl → 2.0.3__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-2.0.1.dist-info → clear_skies_aws-2.0.3.dist-info}/METADATA +2 -2
- clear_skies_aws-2.0.3.dist-info/RECORD +63 -0
- {clear_skies_aws-2.0.1.dist-info → clear_skies_aws-2.0.3.dist-info}/WHEEL +1 -1
- clearskies_aws/__init__.py +27 -0
- clearskies_aws/actions/__init__.py +15 -0
- clearskies_aws/actions/action_aws.py +135 -0
- clearskies_aws/actions/assume_role.py +115 -0
- clearskies_aws/actions/ses.py +203 -0
- clearskies_aws/actions/sns.py +61 -0
- clearskies_aws/actions/sqs.py +81 -0
- clearskies_aws/actions/step_function.py +73 -0
- clearskies_aws/backends/__init__.py +19 -0
- clearskies_aws/backends/backend.py +106 -0
- clearskies_aws/backends/dynamo_db_backend.py +609 -0
- clearskies_aws/backends/dynamo_db_condition_parser.py +325 -0
- clearskies_aws/backends/dynamo_db_parti_ql_backend.py +965 -0
- clearskies_aws/backends/sqs_backend.py +61 -0
- clearskies_aws/configs/__init__.py +0 -0
- clearskies_aws/contexts/__init__.py +23 -0
- clearskies_aws/contexts/cli_web_socket_mock.py +20 -0
- clearskies_aws/contexts/lambda_alb.py +81 -0
- clearskies_aws/contexts/lambda_api_gateway.py +81 -0
- clearskies_aws/contexts/lambda_api_gateway_web_socket.py +79 -0
- clearskies_aws/contexts/lambda_invoke.py +138 -0
- clearskies_aws/contexts/lambda_sns.py +124 -0
- clearskies_aws/contexts/lambda_sqs_standard.py +139 -0
- clearskies_aws/di/__init__.py +6 -0
- 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/endpoints/__init__.py +1 -0
- clearskies_aws/endpoints/secrets_manager_rotation.py +194 -0
- clearskies_aws/endpoints/simple_body_routing.py +41 -0
- clearskies_aws/input_outputs/__init__.py +21 -0
- clearskies_aws/input_outputs/cli_web_socket_mock.py +20 -0
- clearskies_aws/input_outputs/lambda_alb.py +53 -0
- clearskies_aws/input_outputs/lambda_api_gateway.py +123 -0
- clearskies_aws/input_outputs/lambda_api_gateway_web_socket.py +73 -0
- clearskies_aws/input_outputs/lambda_input_output.py +89 -0
- clearskies_aws/input_outputs/lambda_invoke.py +88 -0
- clearskies_aws/input_outputs/lambda_sns.py +88 -0
- clearskies_aws/input_outputs/lambda_sqs_standard.py +86 -0
- clearskies_aws/mocks/__init__.py +1 -0
- clearskies_aws/mocks/actions/__init__.py +6 -0
- clearskies_aws/mocks/actions/ses.py +34 -0
- clearskies_aws/mocks/actions/sns.py +29 -0
- clearskies_aws/mocks/actions/sqs.py +29 -0
- clearskies_aws/mocks/actions/step_function.py +32 -0
- clearskies_aws/models/__init__.py +1 -0
- clearskies_aws/models/web_socket_connection_model.py +182 -0
- clearskies_aws/secrets/__init__.py +13 -0
- clearskies_aws/secrets/additional_configs/__init__.py +62 -0
- clearskies_aws/secrets/additional_configs/iam_db_auth.py +39 -0
- clearskies_aws/secrets/additional_configs/iam_db_auth_with_ssm.py +96 -0
- clearskies_aws/secrets/additional_configs/mysql_connection_dynamic_producer_via_ssh_cert_bastion.py +80 -0
- clearskies_aws/secrets/additional_configs/mysql_connection_dynamic_producer_via_ssm_bastion.py +162 -0
- clearskies_aws/secrets/akeyless_with_ssm_cache.py +60 -0
- clearskies_aws/secrets/parameter_store.py +52 -0
- clearskies_aws/secrets/secrets.py +16 -0
- clearskies_aws/secrets/secrets_manager.py +96 -0
- clear_skies_aws-2.0.1.dist-info/RECORD +0 -4
- {clear_skies_aws-2.0.1.dist-info → clear_skies_aws-2.0.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Callable
|
|
4
|
+
|
|
5
|
+
from clearskies.configs import Callable as CallableConfig
|
|
6
|
+
from clearskies.configs import String
|
|
7
|
+
from clearskies.decorators import parameters_to_properties
|
|
8
|
+
from clearskies.model import Model
|
|
9
|
+
from types_boto3_sqs import SQSClient
|
|
10
|
+
|
|
11
|
+
from . import assume_role
|
|
12
|
+
from .action_aws import ActionAws
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class SQS(ActionAws[SQSClient]):
|
|
16
|
+
queue_url = String(required=False)
|
|
17
|
+
queue_url_environment_key = String(required=False)
|
|
18
|
+
queue_url_callable = CallableConfig(required=False)
|
|
19
|
+
message_group_id = CallableConfig(required=False)
|
|
20
|
+
|
|
21
|
+
@parameters_to_properties
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
queue_url: str = "",
|
|
25
|
+
queue_url_environment_key: str = "",
|
|
26
|
+
queue_url_callable: Callable | None = None,
|
|
27
|
+
message_callable: Callable | None = None,
|
|
28
|
+
when: Callable | None = None,
|
|
29
|
+
assume_role: assume_role.AssumeRole | None = None,
|
|
30
|
+
message_group_id: str | Callable | None = None,
|
|
31
|
+
) -> None:
|
|
32
|
+
"""Set up the SQS action."""
|
|
33
|
+
super().__init__(service_name="sqs", message_callable=message_callable, when=when, assume_role=assume_role)
|
|
34
|
+
|
|
35
|
+
def configure(self):
|
|
36
|
+
self.finalize_and_validate_configuration()
|
|
37
|
+
queue_urls = 0
|
|
38
|
+
for value in [self.queue_url, self.queue_url_environment_key, self.queue_url_callable]:
|
|
39
|
+
if value:
|
|
40
|
+
queue_urls += 1
|
|
41
|
+
if queue_urls > 1:
|
|
42
|
+
raise ValueError(
|
|
43
|
+
"You can only provide one of 'queue_url', 'queue_url_environment_key', or 'queue_url_callable', but more than one were provided."
|
|
44
|
+
)
|
|
45
|
+
if not queue_urls:
|
|
46
|
+
raise ValueError(
|
|
47
|
+
"You must provide at least one of 'queue_url', 'queue_url_environment_key', or 'queue_url_callable'."
|
|
48
|
+
)
|
|
49
|
+
if self.message_group_id and not callable(self.message_group_id) and not isinstance(self.message_group_id, str):
|
|
50
|
+
raise ValueError(
|
|
51
|
+
"If provided, 'message_group_id' must be a string or callable, but the provided value was neither."
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
def _execute_action(self, client: SQSClient, model: Model) -> None:
|
|
55
|
+
"""Send a notification as configured."""
|
|
56
|
+
params = {
|
|
57
|
+
"QueueUrl": self.get_queue_url(model),
|
|
58
|
+
"MessageBody": self.get_message_body(model),
|
|
59
|
+
}
|
|
60
|
+
if not params["QueueUrl"]:
|
|
61
|
+
return
|
|
62
|
+
|
|
63
|
+
if self.message_group_id:
|
|
64
|
+
if callable(self.message_group_id):
|
|
65
|
+
message_group_id = self.di.call_function(self.message_group_id, model=model)
|
|
66
|
+
if not isinstance(message_group_id, str):
|
|
67
|
+
raise ValueError(
|
|
68
|
+
f"I called the message_group_id function for SQS for model '{model.__class__.__name__}' but the value it returned was not a string. The message group id must be a string."
|
|
69
|
+
)
|
|
70
|
+
else:
|
|
71
|
+
message_group_id = self.message_group_id
|
|
72
|
+
params["MessageGroupId"] = message_group_id
|
|
73
|
+
|
|
74
|
+
client.send_message(**params)
|
|
75
|
+
|
|
76
|
+
def get_queue_url(self, model: Model):
|
|
77
|
+
if self.queue_url:
|
|
78
|
+
return self.queue_url
|
|
79
|
+
if self.queue_url_environment_key:
|
|
80
|
+
return self.environment.get(self.queue_url_environment_key)
|
|
81
|
+
return self.di.call_function(self.queue_url_callable, model=model)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Callable
|
|
4
|
+
|
|
5
|
+
import boto3
|
|
6
|
+
from clearskies import Model
|
|
7
|
+
from clearskies.configs import Callable as CallableConfig
|
|
8
|
+
from clearskies.configs import String
|
|
9
|
+
from clearskies.decorators import parameters_to_properties
|
|
10
|
+
from types_boto3_stepfunctions import SFNClient
|
|
11
|
+
|
|
12
|
+
from .action_aws import ActionAws
|
|
13
|
+
from .assume_role import AssumeRole
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class StepFunction(ActionAws[SFNClient]):
|
|
17
|
+
arn = String(required=False)
|
|
18
|
+
arn_environment_key = String(required=False)
|
|
19
|
+
arn_callable = CallableConfig(required=False)
|
|
20
|
+
column_to_store_execution_arn = String(required=False)
|
|
21
|
+
|
|
22
|
+
@parameters_to_properties
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
arn: str | None = None,
|
|
26
|
+
arn_environment_key: str | None = None,
|
|
27
|
+
arn_callable: Callable | None = None,
|
|
28
|
+
column_to_store_execution_arn: str | None = None,
|
|
29
|
+
message_callable: Callable | None = None,
|
|
30
|
+
when: Callable | None = None,
|
|
31
|
+
assume_role: AssumeRole | None = None,
|
|
32
|
+
) -> None:
|
|
33
|
+
"""Configure the Step Function action."""
|
|
34
|
+
super().__init__(
|
|
35
|
+
service_name="stepfunctions", message_callable=message_callable, when=when, assume_role=assume_role
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
def configure(self):
|
|
39
|
+
self.finalize_and_validate_configuration()
|
|
40
|
+
|
|
41
|
+
arns = 0
|
|
42
|
+
for value in [self.arn, self.arn_environment_key, self.arn_callable]:
|
|
43
|
+
if value:
|
|
44
|
+
arns += 1
|
|
45
|
+
if arns > 1:
|
|
46
|
+
raise ValueError(
|
|
47
|
+
"You can only provide one of 'arn', 'arn_environment_key', or 'arn_callable', but more than one was provided."
|
|
48
|
+
)
|
|
49
|
+
if not arns:
|
|
50
|
+
raise ValueError("You must provide at least one of 'arn', 'arn_environment_key', or 'arn_callable'.")
|
|
51
|
+
|
|
52
|
+
def _execute_action(self, client: SFNClient, model: Model) -> None:
|
|
53
|
+
"""Send a notification as configured."""
|
|
54
|
+
arn = self.get_arn(model)
|
|
55
|
+
default_region = self.default_region()
|
|
56
|
+
arn_region = arn.split(":")[3]
|
|
57
|
+
if default_region and default_region != arn_region:
|
|
58
|
+
self.region = arn_region
|
|
59
|
+
client = self._get_client()
|
|
60
|
+
response = client.start_execution(
|
|
61
|
+
stateMachineArn=self.get_arn(model),
|
|
62
|
+
input=self.get_message_body(model),
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
if self.column_to_store_execution_arn:
|
|
66
|
+
model.save({self.column_to_store_execution_arn: response["executionArn"]})
|
|
67
|
+
|
|
68
|
+
def get_arn(self, model: Model) -> str:
|
|
69
|
+
if self.arn:
|
|
70
|
+
return self.arn
|
|
71
|
+
if self.arn_environment_key:
|
|
72
|
+
return self.environment.get(self.arn_environment_key)
|
|
73
|
+
return self.di.call_function(self.arn_callable, model=model)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from clearskies_aws.backends.backend import Backend
|
|
4
|
+
from clearskies_aws.backends.dynamo_db_backend import DynamoDBBackend
|
|
5
|
+
from clearskies_aws.backends.dynamo_db_condition_parser import DynamoDBConditionParser
|
|
6
|
+
from clearskies_aws.backends.dynamo_db_parti_ql_backend import (
|
|
7
|
+
DynamoDBPartiQLBackend,
|
|
8
|
+
DynamoDBPartiQLCursor,
|
|
9
|
+
)
|
|
10
|
+
from clearskies_aws.backends.sqs_backend import SqsBackend
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"Backend",
|
|
14
|
+
"DynamoDBBackend",
|
|
15
|
+
"SqsBackend",
|
|
16
|
+
"DynamoDBPartiQLBackend",
|
|
17
|
+
"DynamoDBPartiQLCursor",
|
|
18
|
+
"DynamoDBConditionParser",
|
|
19
|
+
]
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Callable
|
|
4
|
+
|
|
5
|
+
import clearskies
|
|
6
|
+
import clearskies.model
|
|
7
|
+
import clearskies.query
|
|
8
|
+
from clearskies.autodoc.schema import Schema as AutoDocSchema
|
|
9
|
+
from clearskies.di import inject
|
|
10
|
+
|
|
11
|
+
from clearskies_aws.di.inject import boto3
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Backend(clearskies.Configurable, clearskies.backends.Backend, clearskies.di.InjectableProperties):
|
|
15
|
+
"""
|
|
16
|
+
Connect models to their data since 2020.
|
|
17
|
+
|
|
18
|
+
The backend system acts as a flexible layer between models and their data sources. By changing the backend attached to a model,
|
|
19
|
+
you change where the model fetches and saves data. This might be a database, an in-memory data store, a dynamodb table,
|
|
20
|
+
an API, and more. This allows you to interact with a variety of data sources with the models acting as a standardized API.
|
|
21
|
+
Since endpoints also rely on the models for their functionality, this means that you can easily build API endpoints and
|
|
22
|
+
more for a variety of data sources with a minimal amount of code.
|
|
23
|
+
|
|
24
|
+
Of course, not all data sources support all functionality present in the model. Therefore, you do still need to have
|
|
25
|
+
a fair understanding of how your data sources work.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
supports_n_plus_one = False
|
|
29
|
+
can_count = True
|
|
30
|
+
|
|
31
|
+
boto3 = boto3.Boto3()
|
|
32
|
+
environment = inject.Environment()
|
|
33
|
+
|
|
34
|
+
def update(self, id: int | str, data: dict[str, Any], model: clearskies.model.Model) -> dict[str, Any]:
|
|
35
|
+
"""Update the record with the given id with the information from the data dictionary."""
|
|
36
|
+
return {}
|
|
37
|
+
|
|
38
|
+
def create(self, data: dict[str, Any], model: clearskies.model.Model) -> dict[str, Any]:
|
|
39
|
+
"""Create a record with the information from the data dictionary."""
|
|
40
|
+
return {}
|
|
41
|
+
|
|
42
|
+
def delete(self, id: int | str, model: clearskies.model.Model) -> bool:
|
|
43
|
+
"""Delete the record with the given id."""
|
|
44
|
+
return True
|
|
45
|
+
|
|
46
|
+
def count(self, query: clearskies.query.Query) -> int:
|
|
47
|
+
"""Return the number of records which match the given query configuration."""
|
|
48
|
+
return 1
|
|
49
|
+
|
|
50
|
+
def records(
|
|
51
|
+
self,
|
|
52
|
+
query: clearskies.query.Query,
|
|
53
|
+
next_page_data: dict[str, str | int] | None = None,
|
|
54
|
+
) -> list[dict[str, Any]]:
|
|
55
|
+
"""
|
|
56
|
+
Return a list of records that match the given query configuration.
|
|
57
|
+
|
|
58
|
+
next_page_data is used to return data to the caller. Pass in an empty dictionary, and it will be populated
|
|
59
|
+
with the data needed to return the next page of results. If it is still an empty dictionary when returned,
|
|
60
|
+
then there is no additional data.
|
|
61
|
+
"""
|
|
62
|
+
return []
|
|
63
|
+
|
|
64
|
+
def validate_pagination_data(self, data: dict[str, Any], case_mapping: Callable[[str], str]) -> str:
|
|
65
|
+
"""
|
|
66
|
+
Check if the given dictionary is valid pagination data for the background.
|
|
67
|
+
|
|
68
|
+
Return a string with an error message, or an empty string if the data is valid
|
|
69
|
+
"""
|
|
70
|
+
return ""
|
|
71
|
+
|
|
72
|
+
def allowed_pagination_keys(self) -> list[str]:
|
|
73
|
+
"""
|
|
74
|
+
Return the list of allowed keys in the pagination kwargs for the backend.
|
|
75
|
+
|
|
76
|
+
It must always return keys in snake_case so that the auto casing system can
|
|
77
|
+
adjust on the front-end for consistency.
|
|
78
|
+
"""
|
|
79
|
+
return []
|
|
80
|
+
|
|
81
|
+
def documentation_pagination_next_page_response(self, case_mapping: Callable) -> list[Any]:
|
|
82
|
+
"""
|
|
83
|
+
Return a list of autodoc schema objects.
|
|
84
|
+
|
|
85
|
+
It will describe the contents of the `next_page` dictionary
|
|
86
|
+
in the pagination section of the response
|
|
87
|
+
"""
|
|
88
|
+
return []
|
|
89
|
+
|
|
90
|
+
def documentation_pagination_parameters(self, case_mapping: Callable) -> list[tuple[AutoDocSchema, str]]:
|
|
91
|
+
"""
|
|
92
|
+
Return a list of autodoc schema objects describing the allowed input keys to set pagination.
|
|
93
|
+
|
|
94
|
+
It should return a list of tuples, with each tuple corresponding to an input key.
|
|
95
|
+
The first element in the tuple should be the schema, and the second should be the description.
|
|
96
|
+
"""
|
|
97
|
+
return []
|
|
98
|
+
|
|
99
|
+
def documentation_pagination_next_page_example(self, case_mapping: Callable) -> dict[str, Any]:
|
|
100
|
+
"""
|
|
101
|
+
Return an example for next page documentation.
|
|
102
|
+
|
|
103
|
+
Returns an example (as a simple dictionary) of what the next_page data in the pagination response
|
|
104
|
+
should look like
|
|
105
|
+
"""
|
|
106
|
+
return {}
|