clear-skies-aws 1.10.2__py3-none-any.whl → 2.0.1__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.1.dist-info}/METADATA +36 -35
- clear_skies_aws-2.0.1.dist-info/RECORD +4 -0
- {clear_skies_aws-1.10.2.dist-info → clear_skies_aws-2.0.1.dist-info}/WHEEL +1 -1
- clear_skies_aws-2.0.1.dist-info/licenses/LICENSE +21 -0
- clear_skies_aws-1.10.2.dist-info/LICENSE +0 -7
- clear_skies_aws-1.10.2.dist-info/RECORD +0 -71
- clearskies_aws/__init__.py +0 -2
- clearskies_aws/actions/__init__.py +0 -108
- clearskies_aws/actions/action_aws.py +0 -118
- clearskies_aws/actions/assume_role.py +0 -102
- clearskies_aws/actions/assume_role_test.py +0 -72
- clearskies_aws/actions/ses.py +0 -194
- clearskies_aws/actions/ses_test.py +0 -89
- clearskies_aws/actions/sns.py +0 -64
- clearskies_aws/actions/sns_test.py +0 -77
- clearskies_aws/actions/sqs.py +0 -82
- clearskies_aws/actions/sqs_test.py +0 -127
- clearskies_aws/actions/step_function.py +0 -66
- clearskies_aws/actions/step_function_test.py +0 -103
- clearskies_aws/backends/__init__.py +0 -12
- clearskies_aws/backends/dynamo_db_backend.py +0 -614
- clearskies_aws/backends/dynamo_db_backend_test.py +0 -300
- clearskies_aws/backends/dynamo_db_condition_parser.py +0 -365
- clearskies_aws/backends/dynamo_db_condition_parser_test.py +0 -266
- clearskies_aws/backends/dynamo_db_parti_ql_backend.py +0 -1123
- clearskies_aws/backends/dynamo_db_parti_ql_backend_test.py +0 -544
- clearskies_aws/backends/sqs_backend.py +0 -80
- clearskies_aws/backends/sqs_backend_test.py +0 -31
- clearskies_aws/contexts/__init__.py +0 -10
- clearskies_aws/contexts/cli.py +0 -19
- clearskies_aws/contexts/cli_websocket_mock.py +0 -33
- clearskies_aws/contexts/lambda_api_gateway.py +0 -30
- clearskies_aws/contexts/lambda_api_gateway_web_socket.py +0 -30
- clearskies_aws/contexts/lambda_elb.py +0 -30
- clearskies_aws/contexts/lambda_http_gateway.py +0 -30
- clearskies_aws/contexts/lambda_invocation.py +0 -48
- clearskies_aws/contexts/lambda_sns.py +0 -43
- clearskies_aws/contexts/lambda_sqs_standard_partial_batch.py +0 -51
- clearskies_aws/contexts/lambda_sqs_standard_partial_batch_test.py +0 -66
- clearskies_aws/contexts/wsgi.py +0 -19
- clearskies_aws/di/__init__.py +0 -1
- clearskies_aws/di/standard_dependencies.py +0 -60
- clearskies_aws/handlers/__init__.py +0 -2
- clearskies_aws/handlers/secrets_manager_rotation.py +0 -174
- clearskies_aws/handlers/simple_body_routing.py +0 -39
- clearskies_aws/input_outputs/__init__.py +0 -8
- clearskies_aws/input_outputs/cli_websocket_mock.py +0 -12
- clearskies_aws/input_outputs/lambda_api_gateway.py +0 -105
- clearskies_aws/input_outputs/lambda_api_gateway_test.py +0 -87
- clearskies_aws/input_outputs/lambda_api_gateway_web_socket.py +0 -8
- clearskies_aws/input_outputs/lambda_elb.py +0 -21
- clearskies_aws/input_outputs/lambda_http_gateway.py +0 -12
- clearskies_aws/input_outputs/lambda_invocation.py +0 -34
- clearskies_aws/input_outputs/lambda_sns.py +0 -52
- clearskies_aws/input_outputs/lambda_sqs_standard.py +0 -54
- clearskies_aws/mocks/__init__.py +0 -1
- clearskies_aws/mocks/actions/__init__.py +0 -6
- clearskies_aws/mocks/actions/ses.py +0 -28
- clearskies_aws/mocks/actions/sns.py +0 -23
- clearskies_aws/mocks/actions/sqs.py +0 -23
- clearskies_aws/mocks/actions/step_function.py +0 -26
- clearskies_aws/secrets/__init__.py +0 -7
- clearskies_aws/secrets/additional_configs/__init__.py +0 -54
- clearskies_aws/secrets/additional_configs/iam_db_auth.py +0 -29
- clearskies_aws/secrets/additional_configs/iam_db_auth_with_ssm.py +0 -92
- clearskies_aws/secrets/additional_configs/mysql_connection_dynamic_producer_via_ssh_cert_bastion.py +0 -81
- clearskies_aws/secrets/additional_configs/mysql_connection_dynamic_producer_via_ssm_bastion.py +0 -141
- clearskies_aws/secrets/akeyless_with_ssm_cache.py +0 -46
- clearskies_aws/secrets/parameter_store.py +0 -50
- clearskies_aws/secrets/parameter_store_test.py +0 -18
- clearskies_aws/secrets/secrets_manager.py +0 -75
- clearskies_aws/secrets/secrets_manager_test.py +0 -18
- clearskies_aws/web_socket_connection_model.py +0 -43
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import clearskies
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class SimpleBodyRouting(clearskies.handlers.Routing):
|
|
5
|
-
def __init__(self, di):
|
|
6
|
-
super().__init__(di)
|
|
7
|
-
|
|
8
|
-
_configuration_defaults = {
|
|
9
|
-
"routes": {},
|
|
10
|
-
"route_key": "route",
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
def handler_classes(self, configuration):
|
|
14
|
-
# not actually used but required by base
|
|
15
|
-
return []
|
|
16
|
-
|
|
17
|
-
def _check_configuration(self, configuration):
|
|
18
|
-
for config_name in ["route_key", "routes"]:
|
|
19
|
-
if not configuration.get(config_name):
|
|
20
|
-
raise KeyError(f"Missing required configuration for SimpleBodyRouting handler: '{config_name}'")
|
|
21
|
-
if not isinstance(configuration["routes"], dict):
|
|
22
|
-
raise ValueError(f"COnfiguration 'routes' for handler SimpleBodyRouting must be a dictionary, but instead I got something else.")
|
|
23
|
-
|
|
24
|
-
def handle(self, input_output):
|
|
25
|
-
body = input_output.json_body(required=True)
|
|
26
|
-
if not body or not body.get(self.configuration("route_key")):
|
|
27
|
-
return self.error(input_output, "Not Found", 404)
|
|
28
|
-
|
|
29
|
-
route = body[self.configuration("route_key")]
|
|
30
|
-
if route not in self.configuration("routes"):
|
|
31
|
-
return self.error(input_output, "Not Found", 404)
|
|
32
|
-
return input_output.respond(self._di.call_function(
|
|
33
|
-
self.configuration("routes")[route],
|
|
34
|
-
request_data=body,
|
|
35
|
-
**input_output.context_specifics(),
|
|
36
|
-
), 200)
|
|
37
|
-
|
|
38
|
-
def documentation(self):
|
|
39
|
-
return []
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
from .cli_websocket_mock import CLIWebsocketMock
|
|
2
|
-
from .lambda_api_gateway import LambdaAPIGateway
|
|
3
|
-
from .lambda_api_gateway_web_socket import LambdaAPIGatewayWebSocket
|
|
4
|
-
from .lambda_elb import LambdaELB
|
|
5
|
-
from .lambda_http_gateway import LambdaHTTPGateway
|
|
6
|
-
from .lambda_invocation import LambdaInvocation
|
|
7
|
-
from .lambda_sqs_standard import LambdaSqsStandard
|
|
8
|
-
from .lambda_sns import LambdaSns
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import clearskies
|
|
2
|
-
class CLIWebsocketMock(clearskies.input_outputs.CLI):
|
|
3
|
-
def context_specifics(self):
|
|
4
|
-
connection_id = self.json_body().get("connection_id")
|
|
5
|
-
if not connection_id:
|
|
6
|
-
raise KeyError("When using the CLIWebsocketMock you must provide connection_id in the request body")
|
|
7
|
-
|
|
8
|
-
return {
|
|
9
|
-
"event": {},
|
|
10
|
-
"context": {},
|
|
11
|
-
"connection_id": connection_id,
|
|
12
|
-
}
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
from clearskies.input_outputs.input_output import InputOutput
|
|
2
|
-
import json
|
|
3
|
-
import base64
|
|
4
|
-
import urllib
|
|
5
|
-
class LambdaAPIGateway(InputOutput):
|
|
6
|
-
_event = None
|
|
7
|
-
_context = None
|
|
8
|
-
_request_headers = None
|
|
9
|
-
_request_method = None
|
|
10
|
-
_path = None
|
|
11
|
-
_resource = None
|
|
12
|
-
_query_parameters = None
|
|
13
|
-
_path_parameters = None
|
|
14
|
-
_cached_body = None
|
|
15
|
-
_body_was_cached = False
|
|
16
|
-
|
|
17
|
-
def __init__(self, event, context):
|
|
18
|
-
self._event = event
|
|
19
|
-
self._context = context
|
|
20
|
-
self._request_method = event.get('httpMethod', '').upper()
|
|
21
|
-
self._path = event.get('path')
|
|
22
|
-
self._resource = event.get('resource')
|
|
23
|
-
self._query_parameters = event.get('queryStringParameters', {})
|
|
24
|
-
self._path_parameters = event.get('pathParameters', {})
|
|
25
|
-
self._request_headers = {}
|
|
26
|
-
for (key, value) in event.get('headers', {}).items():
|
|
27
|
-
self._request_headers[key.lower()] = value
|
|
28
|
-
|
|
29
|
-
def respond(self, body, status_code=200):
|
|
30
|
-
if not self.has_header('content-type'):
|
|
31
|
-
self.set_header('content-type', 'application/json; charset=UTF-8')
|
|
32
|
-
|
|
33
|
-
is_base64 = False
|
|
34
|
-
if type(body) == bytes:
|
|
35
|
-
is_base64 = True
|
|
36
|
-
final_body = base64.encodebytes(body).decode('utf8')
|
|
37
|
-
elif type(body) == str:
|
|
38
|
-
final_body = body
|
|
39
|
-
else:
|
|
40
|
-
final_body = json.dumps(body)
|
|
41
|
-
|
|
42
|
-
return {
|
|
43
|
-
"isBase64Encoded": is_base64,
|
|
44
|
-
"statusCode": status_code,
|
|
45
|
-
"headers": self._response_headers,
|
|
46
|
-
"body": final_body,
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
def has_body(self):
|
|
50
|
-
return bool(self.get_body())
|
|
51
|
-
|
|
52
|
-
def get_body(self):
|
|
53
|
-
if not self._body_was_cached:
|
|
54
|
-
self._cached_body = self._event.get('body')
|
|
55
|
-
if self._cached_body is not None and self._event.get('isBase64Encoded'):
|
|
56
|
-
self._cached_body = base64.decodebytes(self._cached_body.encode('utf-8')).decode('utf-8')
|
|
57
|
-
return self._cached_body
|
|
58
|
-
|
|
59
|
-
def get_request_method(self):
|
|
60
|
-
return self._request_method
|
|
61
|
-
|
|
62
|
-
def get_script_name(self):
|
|
63
|
-
return ''
|
|
64
|
-
|
|
65
|
-
def get_path_info(self):
|
|
66
|
-
return self._path
|
|
67
|
-
|
|
68
|
-
def get_query_string(self):
|
|
69
|
-
return urllib.parse.urlencode(self._query_parameters)
|
|
70
|
-
|
|
71
|
-
def get_content_type(self):
|
|
72
|
-
return self.get_request_header('content-type', True)
|
|
73
|
-
|
|
74
|
-
def get_protocol(self):
|
|
75
|
-
return 'https'
|
|
76
|
-
|
|
77
|
-
def has_request_header(self, header_name):
|
|
78
|
-
return header_name.lower() in self._request_headers
|
|
79
|
-
|
|
80
|
-
def get_request_header(self, header_name, silent=False):
|
|
81
|
-
if not header_name.lower() in self._request_headers:
|
|
82
|
-
if not silent:
|
|
83
|
-
raise KeyError(f"HTTP header '{header_name}' was not found in request")
|
|
84
|
-
return ''
|
|
85
|
-
return self._request_headers[header_name.lower()]
|
|
86
|
-
|
|
87
|
-
def get_query_parameter(self, key):
|
|
88
|
-
return self._query_parameters[key] if key in self._query_parameters else []
|
|
89
|
-
|
|
90
|
-
def get_query_parameters(self):
|
|
91
|
-
return self._query_parameters
|
|
92
|
-
|
|
93
|
-
def context_specifics(self):
|
|
94
|
-
return {
|
|
95
|
-
"event": self._event,
|
|
96
|
-
"context": self._context,
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
def get_client_ip(self):
|
|
100
|
-
# I haven't actually tested with an API gateway yet to figure out which of these works...
|
|
101
|
-
sourceIp = self._event.get('requestContext', {}).get('identity', {}).get('sourceIp')
|
|
102
|
-
if sourceIp:
|
|
103
|
-
return sourceIp
|
|
104
|
-
|
|
105
|
-
return self.get_request_header('x-forwarded-for', silent=True)
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import unittest
|
|
2
|
-
from collections import OrderedDict
|
|
3
|
-
|
|
4
|
-
from .lambda_api_gateway import LambdaAPIGateway
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class LambdaAPIGatewayTest(unittest.TestCase):
|
|
8
|
-
dummy_event = {
|
|
9
|
-
'httpMethod': 'GET',
|
|
10
|
-
'path': '/test',
|
|
11
|
-
'resource': 'bob',
|
|
12
|
-
'queryStringParameters': {
|
|
13
|
-
'q': 'hey',
|
|
14
|
-
'bob': 'sup'
|
|
15
|
-
},
|
|
16
|
-
'pathParameters': None,
|
|
17
|
-
'headers': {
|
|
18
|
-
'Content-Type': 'application/json'
|
|
19
|
-
},
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
def test_respond(self):
|
|
23
|
-
aws_lambda = LambdaAPIGateway(self.dummy_event, {})
|
|
24
|
-
aws_lambda.set_headers({'bob': 'hey', 'jane': 'kay'})
|
|
25
|
-
aws_lambda.set_header('hey', 'sup')
|
|
26
|
-
aws_lambda.clear_header('bob')
|
|
27
|
-
response = aws_lambda.respond({'some': 'data'}, 200)
|
|
28
|
-
self.assertEqual(
|
|
29
|
-
{
|
|
30
|
-
"isBase64Encoded": False,
|
|
31
|
-
"statusCode": 200,
|
|
32
|
-
"headers": OrderedDict(
|
|
33
|
-
[
|
|
34
|
-
("JANE", "kay"),
|
|
35
|
-
("HEY", "sup"),
|
|
36
|
-
("CONTENT-TYPE", "application/json; charset=UTF-8"),
|
|
37
|
-
]
|
|
38
|
-
),
|
|
39
|
-
"body": '{"some": "data"}',
|
|
40
|
-
},
|
|
41
|
-
response,
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
def test_headers(self):
|
|
45
|
-
aws_lambda = LambdaAPIGateway({
|
|
46
|
-
**self.dummy_event,
|
|
47
|
-
**{
|
|
48
|
-
'headers': {
|
|
49
|
-
'Content-Type': 'application/json',
|
|
50
|
-
'AUTHORIZATION': 'hey',
|
|
51
|
-
'X-Auth': 'asdf',
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}, {})
|
|
55
|
-
self.assertEqual("hey", aws_lambda.get_request_header("authorizatiON"))
|
|
56
|
-
self.assertEqual("asdf", aws_lambda.get_request_header("x-auth"))
|
|
57
|
-
self.assertTrue(aws_lambda.has_request_header('authorization'))
|
|
58
|
-
self.assertTrue(aws_lambda.has_request_header('x-auth'))
|
|
59
|
-
self.assertFalse(aws_lambda.has_request_header('bearer'))
|
|
60
|
-
|
|
61
|
-
def test_body_plain(self):
|
|
62
|
-
aws_lambda = LambdaAPIGateway({**self.dummy_event, **{'body': '{"hey": "sup"}', 'isBase64Encoded': False}}, {})
|
|
63
|
-
|
|
64
|
-
self.assertEqual({"hey": "sup"}, aws_lambda.json_body())
|
|
65
|
-
self.assertEqual('{"hey": "sup"}', aws_lambda.get_body())
|
|
66
|
-
self.assertTrue(aws_lambda.has_body())
|
|
67
|
-
|
|
68
|
-
def test_body_base64(self):
|
|
69
|
-
aws_lambda = LambdaAPIGateway({
|
|
70
|
-
**self.dummy_event,
|
|
71
|
-
**{
|
|
72
|
-
'body': 'eyJoZXkiOiAic3VwIn0=',
|
|
73
|
-
'isBase64Encoded': True
|
|
74
|
-
}
|
|
75
|
-
}, {})
|
|
76
|
-
|
|
77
|
-
self.assertEqual({"hey": "sup"}, aws_lambda.json_body())
|
|
78
|
-
self.assertEqual('{"hey": "sup"}', aws_lambda.get_body())
|
|
79
|
-
self.assertTrue(aws_lambda.has_body())
|
|
80
|
-
|
|
81
|
-
def test_path(self):
|
|
82
|
-
aws_lambda = LambdaAPIGateway(self.dummy_event, {})
|
|
83
|
-
self.assertEqual("/test", aws_lambda.get_path_info())
|
|
84
|
-
|
|
85
|
-
def test_query_string(self):
|
|
86
|
-
aws_lambda = LambdaAPIGateway(self.dummy_event, {})
|
|
87
|
-
self.assertEqual("q=hey&bob=sup", aws_lambda.get_query_string())
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
from .lambda_api_gateway import LambdaAPIGateway
|
|
2
|
-
class LambdaELB(LambdaAPIGateway):
|
|
3
|
-
_event = None
|
|
4
|
-
_context = None
|
|
5
|
-
_request_headers = None
|
|
6
|
-
_request_method = None
|
|
7
|
-
_path = None
|
|
8
|
-
_query_parameters = None
|
|
9
|
-
|
|
10
|
-
def __init__(self, event, context):
|
|
11
|
-
self._event = event
|
|
12
|
-
self._context = context
|
|
13
|
-
self._request_method = event.get('httpMethod', 'GET').upper()
|
|
14
|
-
self._path = event.get('path', '/')
|
|
15
|
-
self._query_parameters = event.get('queryStringParameters', {})
|
|
16
|
-
self._request_headers = {}
|
|
17
|
-
for (key, value) in event.get('headers', {}).items():
|
|
18
|
-
self._request_headers[key.lower()] = value
|
|
19
|
-
|
|
20
|
-
def get_client_ip(self):
|
|
21
|
-
return self.get_request_header('x-forwarded-for')
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
from .lambda_api_gateway import LambdaAPIGateway
|
|
2
|
-
class LambdaHTTPGateway(LambdaAPIGateway):
|
|
3
|
-
def __init__(self, event, context):
|
|
4
|
-
self._event = event
|
|
5
|
-
self._context = context
|
|
6
|
-
self._path = event.get('requestContext', {}).get('http', {}).get('path')
|
|
7
|
-
self._request_method = event.get('requestContext', {}).get('http', {}).get('method').upper()
|
|
8
|
-
self._query_parameters = event['queryStringParameters'] if event['queryStringParameters'] is not None else {}
|
|
9
|
-
self._path_parameters = event['pathParameters']
|
|
10
|
-
self._request_headers = {}
|
|
11
|
-
for (key, value) in event['headers'].items():
|
|
12
|
-
self._request_headers[key.lower()] = value
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
from .lambda_api_gateway import LambdaAPIGateway
|
|
2
|
-
import json
|
|
3
|
-
from clearskies.handlers.exceptions import ClientError
|
|
4
|
-
class LambdaInvocation(LambdaAPIGateway):
|
|
5
|
-
def __init__(
|
|
6
|
-
self,
|
|
7
|
-
event,
|
|
8
|
-
context,
|
|
9
|
-
method=None,
|
|
10
|
-
url=None,
|
|
11
|
-
):
|
|
12
|
-
self._event = event
|
|
13
|
-
self._context = context
|
|
14
|
-
self._path = url if url else ''
|
|
15
|
-
self._request_method = method.upper() if method else 'GET'
|
|
16
|
-
self._query_parameters = {}
|
|
17
|
-
self._path_parameters = []
|
|
18
|
-
self._request_headers = {}
|
|
19
|
-
|
|
20
|
-
def has_body(self):
|
|
21
|
-
return True
|
|
22
|
-
|
|
23
|
-
def get_body(self):
|
|
24
|
-
return self._event
|
|
25
|
-
|
|
26
|
-
def json_body(self, required=True, allow_non_json_bodies=False):
|
|
27
|
-
# we ignore the allow_non_json_bodies flag here because with the way invoking lambdas works,
|
|
28
|
-
# the event already is an object, so it's a moot point.
|
|
29
|
-
if required and not self._event:
|
|
30
|
-
raise ClientError("Request body was not valid JSON")
|
|
31
|
-
return self._event
|
|
32
|
-
|
|
33
|
-
def respond(self, body, status_code=200):
|
|
34
|
-
return body.decode('utf-8') if type(body) == bytes else body
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
from .lambda_api_gateway import LambdaAPIGateway
|
|
2
|
-
from clearskies.handlers.exceptions import ClientError
|
|
3
|
-
import json
|
|
4
|
-
class LambdaSns(LambdaAPIGateway):
|
|
5
|
-
def __init__(self, event, context, url=None, method=None):
|
|
6
|
-
self._event = event
|
|
7
|
-
self._context = context
|
|
8
|
-
self._path = url if url else ''
|
|
9
|
-
self._request_method = method.upper() if method else 'GET'
|
|
10
|
-
record = event['Records'][0]['Sns']['Message']
|
|
11
|
-
try:
|
|
12
|
-
self._record = json.loads(record)
|
|
13
|
-
except json.JSONDecodeError as e:
|
|
14
|
-
raise ClientError("The message from AWS was not a serialized JSON string. The lambda_sns context for clearskies only accepts serialized JSON")
|
|
15
|
-
|
|
16
|
-
def respond(self, body, status_code=200):
|
|
17
|
-
pass
|
|
18
|
-
|
|
19
|
-
def get_body(self):
|
|
20
|
-
return self._record
|
|
21
|
-
|
|
22
|
-
def request_data(self, required=True, allow_non_json_bodies=False):
|
|
23
|
-
return self.json_body(required=required, allow_non_json_bodies=allow_non_json_bodies)
|
|
24
|
-
|
|
25
|
-
def json_body(self, required=True, allow_non_json_bodies=False):
|
|
26
|
-
if not self._record:
|
|
27
|
-
if required:
|
|
28
|
-
raise ClientError("No SNS message found")
|
|
29
|
-
return {}
|
|
30
|
-
|
|
31
|
-
return self._record
|
|
32
|
-
|
|
33
|
-
def get_query_string(self):
|
|
34
|
-
raise NotImplementedError("The query string doesn't exist in an SNS context")
|
|
35
|
-
|
|
36
|
-
def get_content_type(self):
|
|
37
|
-
raise NotImplementedError("Content type doesn't exist in an SNS context")
|
|
38
|
-
|
|
39
|
-
def get_protocol(self):
|
|
40
|
-
raise NotImplementedError("A request protocol is not defined in an SNS context")
|
|
41
|
-
|
|
42
|
-
def has_request_header(self, header_name):
|
|
43
|
-
raise NotImplementedError("SNS contexts don't have request headers")
|
|
44
|
-
|
|
45
|
-
def get_request_header(self, header_name, silent=True):
|
|
46
|
-
raise NotImplementedError("SNS contexts don't have request headers")
|
|
47
|
-
|
|
48
|
-
def get_query_parameter(self, key):
|
|
49
|
-
raise NotImplementedError("SNS contexts don't have query parameters")
|
|
50
|
-
|
|
51
|
-
def get_query_parameters(self):
|
|
52
|
-
raise NotImplementedError("SNS contexts don't have query parameters")
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
from .lambda_api_gateway import LambdaAPIGateway
|
|
2
|
-
from clearskies.handlers.exceptions import ClientError
|
|
3
|
-
import json
|
|
4
|
-
class LambdaSqsStandard(LambdaAPIGateway):
|
|
5
|
-
def __init__(self, record, event, context, url=None, method=None):
|
|
6
|
-
self._record = record
|
|
7
|
-
self._context = context
|
|
8
|
-
self._event = event
|
|
9
|
-
self._path = url if url else ''
|
|
10
|
-
self._request_method = method.upper() if method else 'GET'
|
|
11
|
-
|
|
12
|
-
def respond(self, body, status_code=200):
|
|
13
|
-
pass
|
|
14
|
-
|
|
15
|
-
def get_body(self):
|
|
16
|
-
return self._record
|
|
17
|
-
|
|
18
|
-
def has_body(self):
|
|
19
|
-
return True
|
|
20
|
-
|
|
21
|
-
def request_data(self, required=True, allow_non_json_bodies=False):
|
|
22
|
-
return self.json_body(required=required, allow_non_json_bodies=allow_non_json_bodies)
|
|
23
|
-
|
|
24
|
-
def json_body(self, required=True, allow_non_json_bodies=False):
|
|
25
|
-
if not self._record:
|
|
26
|
-
if required:
|
|
27
|
-
raise ClientError("SQS message was not valid JSON")
|
|
28
|
-
return {}
|
|
29
|
-
|
|
30
|
-
try:
|
|
31
|
-
return json.loads(self._record)
|
|
32
|
-
except json.JSONDecodeError:
|
|
33
|
-
raise ClientError("SQS message was not valid JSON")
|
|
34
|
-
|
|
35
|
-
def get_query_string(self):
|
|
36
|
-
raise NotImplementedError("The query string doesn't exist in an SQS context")
|
|
37
|
-
|
|
38
|
-
def get_content_type(self):
|
|
39
|
-
raise NotImplementedError("Content type doesn't exist in an SQS context")
|
|
40
|
-
|
|
41
|
-
def get_protocol(self):
|
|
42
|
-
raise NotImplementedError("A request protocol is not defined in an SQS context")
|
|
43
|
-
|
|
44
|
-
def has_request_header(self, header_name):
|
|
45
|
-
raise NotImplementedError("SQS contexts don't have request headers")
|
|
46
|
-
|
|
47
|
-
def get_request_header(self, header_name, silent=True):
|
|
48
|
-
raise NotImplementedError("SQS contexts don't have request headers")
|
|
49
|
-
|
|
50
|
-
def get_query_parameter(self, key):
|
|
51
|
-
raise NotImplementedError("SQS contexts don't have query parameters")
|
|
52
|
-
|
|
53
|
-
def get_query_parameters(self):
|
|
54
|
-
raise NotImplementedError("SQS contexts don't have query parameters")
|
clearskies_aws/mocks/__init__.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
from . import actions
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
from ...actions.ses import SES as BaseSES
|
|
2
|
-
class SES(BaseSES):
|
|
3
|
-
calls = None
|
|
4
|
-
|
|
5
|
-
def __init__(self, environment, boto3, di):
|
|
6
|
-
super().__init__(environment, boto3, di)
|
|
7
|
-
|
|
8
|
-
@classmethod
|
|
9
|
-
def mock(cls, di):
|
|
10
|
-
cls.calls = []
|
|
11
|
-
di.mock_class(BaseSES, SES)
|
|
12
|
-
|
|
13
|
-
def __call__(self, model) -> None:
|
|
14
|
-
"""Send a notification as configured."""
|
|
15
|
-
if SES.calls == None:
|
|
16
|
-
SES.calls = []
|
|
17
|
-
utcnow = self.di.build('utcnow')
|
|
18
|
-
if self.when and not self.di.call_function(self.when, model=model):
|
|
19
|
-
return
|
|
20
|
-
|
|
21
|
-
SES.calls.append({
|
|
22
|
-
"from": self.sender,
|
|
23
|
-
"to": self._resolve_destination("to", model),
|
|
24
|
-
"cc": self._resolve_destination("cc", model),
|
|
25
|
-
"bcc": self._resolve_destination("bcc", model),
|
|
26
|
-
"subject": self._resolve_subject(model, utcnow),
|
|
27
|
-
"message": self._resolve_message_as_html(model, utcnow),
|
|
28
|
-
})
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
from types import ModuleType
|
|
2
|
-
from clearskies import Model
|
|
3
|
-
from ...actions.sns import SNS as BaseSNS
|
|
4
|
-
class SNS(BaseSNS):
|
|
5
|
-
calls = None
|
|
6
|
-
|
|
7
|
-
def __init__(self, environment, boto3, di):
|
|
8
|
-
super().__init__(environment, boto3, di)
|
|
9
|
-
|
|
10
|
-
@classmethod
|
|
11
|
-
def mock(cls, di):
|
|
12
|
-
cls.calls = []
|
|
13
|
-
di.mock_class(BaseSNS, SNS)
|
|
14
|
-
|
|
15
|
-
def _execute_action(self, client: ModuleType, model: Model) -> None:
|
|
16
|
-
"""Send a notification as configured."""
|
|
17
|
-
if SNS.calls == None:
|
|
18
|
-
SNS.calls = []
|
|
19
|
-
|
|
20
|
-
SNS.calls.append({
|
|
21
|
-
"TopicArn": self.get_topic_arn(model),
|
|
22
|
-
"Message": self.get_message_body(model),
|
|
23
|
-
})
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
from types import ModuleType
|
|
2
|
-
from clearskies import Model
|
|
3
|
-
from ...actions.sqs import SQS as BaseSQS
|
|
4
|
-
class SQS(BaseSQS):
|
|
5
|
-
calls = None
|
|
6
|
-
|
|
7
|
-
def __init__(self, environment, boto3, di):
|
|
8
|
-
super().__init__(environment, boto3, di)
|
|
9
|
-
|
|
10
|
-
@classmethod
|
|
11
|
-
def mock(cls, di):
|
|
12
|
-
cls.calls = []
|
|
13
|
-
di.mock_class(BaseSQS, SQS)
|
|
14
|
-
|
|
15
|
-
def _execute_action(self, client: ModuleType, model: Model) -> None:
|
|
16
|
-
"""Send a notification as configured."""
|
|
17
|
-
if SQS.calls == None:
|
|
18
|
-
SQS.calls = []
|
|
19
|
-
|
|
20
|
-
SQS.calls.append({
|
|
21
|
-
"QueueUrl": self.get_queue_url(model),
|
|
22
|
-
"MessageBody": self.get_message_body(model),
|
|
23
|
-
})
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
from types import ModuleType
|
|
2
|
-
from clearskies import Model
|
|
3
|
-
from ...actions.step_function import StepFunction as BaseStepFunction
|
|
4
|
-
class StepFunction(BaseStepFunction):
|
|
5
|
-
calls = None
|
|
6
|
-
|
|
7
|
-
def __init__(self, environment, boto3, di):
|
|
8
|
-
super().__init__(environment, boto3, di)
|
|
9
|
-
|
|
10
|
-
@classmethod
|
|
11
|
-
def mock(cls, di):
|
|
12
|
-
StepFunction.calls = []
|
|
13
|
-
di.mock_class(BaseStepFunction, StepFunction)
|
|
14
|
-
|
|
15
|
-
def _execute_action(self, client: ModuleType, model: Model) -> None:
|
|
16
|
-
"""Send a notification as configured."""
|
|
17
|
-
if StepFunction.calls == None:
|
|
18
|
-
StepFunction.calls = []
|
|
19
|
-
|
|
20
|
-
StepFunction.calls.append({
|
|
21
|
-
"stateMachineArn": self.get_arn(model),
|
|
22
|
-
"input": self.get_message_body(model),
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
if self.column_to_store_execution_arn:
|
|
26
|
-
model.save({self.column_to_store_execution_arn: "mock_execution_arn"})
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
from clearskies import BindingConfig
|
|
2
|
-
from .parameter_store import ParameterStore
|
|
3
|
-
from .secrets_manager import SecretsManager
|
|
4
|
-
from .akeyless_with_ssm_cache import AkeylessWithSsmCache
|
|
5
|
-
from . import additional_configs
|
|
6
|
-
def akeyless_with_ssm_cache(*args, **kwargs):
|
|
7
|
-
return BindingConfig(AkeylessWithSsmCache, *args, **kwargs)
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
from .mysql_connection_dynamic_producer_via_ssh_cert_bastion import MySQLConnectionDynamicProducerViaSSHCertBastion
|
|
2
|
-
from .mysql_connection_dynamic_producer_via_ssm_bastion import MySQLConnectionDynamicProducerViaSSMBastion
|
|
3
|
-
from .iam_db_auth import IAMDBAuth
|
|
4
|
-
from .iam_db_auth_with_ssm import IAMDBAuthWithSSM
|
|
5
|
-
def mysql_connection_dynamic_producer_via_ssh_cert_bastion(
|
|
6
|
-
producer_name=None,
|
|
7
|
-
bastion_host=None,
|
|
8
|
-
bastion_name=None,
|
|
9
|
-
bastion_region=None,
|
|
10
|
-
bastion_username=None,
|
|
11
|
-
public_key_file_path=None,
|
|
12
|
-
cert_issuer_name=None,
|
|
13
|
-
database_host=None,
|
|
14
|
-
database_name=None,
|
|
15
|
-
local_proxy_port=None,
|
|
16
|
-
):
|
|
17
|
-
return MySQLConnectionDynamicProducerViaSSHCertBastion(
|
|
18
|
-
producer_name=producer_name,
|
|
19
|
-
bastion_host=bastion_host,
|
|
20
|
-
bastion_name=bastion_name,
|
|
21
|
-
bastion_region=bastion_region,
|
|
22
|
-
bastion_username=bastion_username,
|
|
23
|
-
cert_issuer_name=cert_issuer_name,
|
|
24
|
-
public_key_file_path=public_key_file_path,
|
|
25
|
-
database_host=database_host,
|
|
26
|
-
database_name=database_name,
|
|
27
|
-
local_proxy_port=local_proxy_port,
|
|
28
|
-
)
|
|
29
|
-
def mysql_connection_dynamic_producer_via_ssm_bastion(
|
|
30
|
-
producer_name=None,
|
|
31
|
-
bastion_instance_id=None,
|
|
32
|
-
bastion_name=None,
|
|
33
|
-
bastion_region=None,
|
|
34
|
-
bastion_username=None,
|
|
35
|
-
public_key_file_path=None,
|
|
36
|
-
database_host=None,
|
|
37
|
-
database_name=None,
|
|
38
|
-
local_proxy_port=None,
|
|
39
|
-
):
|
|
40
|
-
return MySQLConnectionDynamicProducerViaSSMBastion(
|
|
41
|
-
producer_name=producer_name,
|
|
42
|
-
bastion_instance_id=bastion_instance_id,
|
|
43
|
-
bastion_name=bastion_name,
|
|
44
|
-
bastion_region=bastion_region,
|
|
45
|
-
bastion_username=bastion_username,
|
|
46
|
-
public_key_file_path=public_key_file_path,
|
|
47
|
-
database_host=database_host,
|
|
48
|
-
database_name=database_name,
|
|
49
|
-
local_proxy_port=local_proxy_port,
|
|
50
|
-
)
|
|
51
|
-
def iam_db_auth():
|
|
52
|
-
return IAMDBAuth()
|
|
53
|
-
def iam_db_auth_with_ssm():
|
|
54
|
-
return IAMDBAuthWithSSM()
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import clearskies
|
|
2
|
-
import os
|
|
3
|
-
class IAMDBAuth(clearskies.di.AdditionalConfig):
|
|
4
|
-
def provide_boto3(self):
|
|
5
|
-
import boto3
|
|
6
|
-
return boto3
|
|
7
|
-
|
|
8
|
-
def provide_connection_details(self, environment, boto3):
|
|
9
|
-
"""
|
|
10
|
-
I really need to make these configurable - both the values themselves and the environment
|
|
11
|
-
variables that things get pulled from.
|
|
12
|
-
"""
|
|
13
|
-
endpoint = environment.get('db_endpoint')
|
|
14
|
-
username = environment.get('db_username')
|
|
15
|
-
database = environment.get('db_database')
|
|
16
|
-
region = environment.get('AWS_REGION')
|
|
17
|
-
ssl_ca_bundle_name = environment.get('ssl_ca_bundle_filename')
|
|
18
|
-
os.environ['LIBMYSQL_ENABLE_CLEARTEXT_PLUGIN'] = '1'
|
|
19
|
-
|
|
20
|
-
rds_api = boto3.Session().client('rds')
|
|
21
|
-
rds_token = rds_api.generate_db_auth_token(DBHostname=endpoint, Port='3306', DBUsername=username, Region=region)
|
|
22
|
-
|
|
23
|
-
return {
|
|
24
|
-
'username': username,
|
|
25
|
-
'password': rds_token,
|
|
26
|
-
'host': endpoint,
|
|
27
|
-
'database': database,
|
|
28
|
-
'ssl_ca': ssl_ca_bundle_name,
|
|
29
|
-
}
|