boto3-assist 0.32.0__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.
- boto3_assist/__init__.py +0 -0
- boto3_assist/aws_config.py +199 -0
- boto3_assist/aws_lambda/event_info.py +414 -0
- boto3_assist/aws_lambda/mock_context.py +5 -0
- boto3_assist/boto3session.py +87 -0
- boto3_assist/cloudwatch/cloudwatch_connection.py +84 -0
- boto3_assist/cloudwatch/cloudwatch_connection_tracker.py +17 -0
- boto3_assist/cloudwatch/cloudwatch_log_connection.py +62 -0
- boto3_assist/cloudwatch/cloudwatch_logs.py +39 -0
- boto3_assist/cloudwatch/cloudwatch_query.py +191 -0
- boto3_assist/cognito/cognito_authorizer.py +169 -0
- boto3_assist/cognito/cognito_connection.py +59 -0
- boto3_assist/cognito/cognito_utility.py +514 -0
- boto3_assist/cognito/jwks_cache.py +21 -0
- boto3_assist/cognito/user.py +27 -0
- boto3_assist/connection.py +146 -0
- boto3_assist/connection_tracker.py +120 -0
- boto3_assist/dynamodb/dynamodb.py +1206 -0
- boto3_assist/dynamodb/dynamodb_connection.py +113 -0
- boto3_assist/dynamodb/dynamodb_helpers.py +333 -0
- boto3_assist/dynamodb/dynamodb_importer.py +102 -0
- boto3_assist/dynamodb/dynamodb_index.py +507 -0
- boto3_assist/dynamodb/dynamodb_iservice.py +29 -0
- boto3_assist/dynamodb/dynamodb_key.py +130 -0
- boto3_assist/dynamodb/dynamodb_model_base.py +382 -0
- boto3_assist/dynamodb/dynamodb_model_base_interfaces.py +34 -0
- boto3_assist/dynamodb/dynamodb_re_indexer.py +165 -0
- boto3_assist/dynamodb/dynamodb_reindexer.py +165 -0
- boto3_assist/dynamodb/dynamodb_reserved_words.py +52 -0
- boto3_assist/dynamodb/dynamodb_reserved_words.txt +573 -0
- boto3_assist/dynamodb/readme.md +68 -0
- boto3_assist/dynamodb/troubleshooting.md +7 -0
- boto3_assist/ec2/ec2_connection.py +57 -0
- boto3_assist/environment_services/__init__.py +0 -0
- boto3_assist/environment_services/environment_loader.py +128 -0
- boto3_assist/environment_services/environment_variables.py +219 -0
- boto3_assist/erc/__init__.py +64 -0
- boto3_assist/erc/ecr_connection.py +57 -0
- boto3_assist/errors/custom_exceptions.py +46 -0
- boto3_assist/http_status_codes.py +80 -0
- boto3_assist/models/serializable_model.py +9 -0
- boto3_assist/role_assumption_mixin.py +38 -0
- boto3_assist/s3/s3.py +64 -0
- boto3_assist/s3/s3_bucket.py +67 -0
- boto3_assist/s3/s3_connection.py +76 -0
- boto3_assist/s3/s3_event_data.py +168 -0
- boto3_assist/s3/s3_object.py +695 -0
- boto3_assist/securityhub/securityhub.py +150 -0
- boto3_assist/securityhub/securityhub_connection.py +57 -0
- boto3_assist/session_setup_mixin.py +70 -0
- boto3_assist/ssm/connection.py +57 -0
- boto3_assist/ssm/parameter_store/parameter_store.py +116 -0
- boto3_assist/utilities/datetime_utility.py +349 -0
- boto3_assist/utilities/decimal_conversion_utility.py +140 -0
- boto3_assist/utilities/dictionary_utility.py +32 -0
- boto3_assist/utilities/file_operations.py +135 -0
- boto3_assist/utilities/http_utility.py +48 -0
- boto3_assist/utilities/logging_utility.py +0 -0
- boto3_assist/utilities/numbers_utility.py +329 -0
- boto3_assist/utilities/serialization_utility.py +664 -0
- boto3_assist/utilities/string_utility.py +337 -0
- boto3_assist/version.py +1 -0
- boto3_assist-0.32.0.dist-info/METADATA +76 -0
- boto3_assist-0.32.0.dist-info/RECORD +67 -0
- boto3_assist-0.32.0.dist-info/WHEEL +4 -0
- boto3_assist-0.32.0.dist-info/licenses/LICENSE-EXPLAINED.txt +11 -0
- boto3_assist-0.32.0.dist-info/licenses/LICENSE.txt +21 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Geek Cafe, LLC
|
|
3
|
+
Maintainers: Eric Wilson
|
|
4
|
+
MIT License. See Project Root for the license information.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Optional, List
|
|
8
|
+
|
|
9
|
+
from aws_lambda_powertools import Logger
|
|
10
|
+
from boto3_assist.boto3session import Boto3SessionManager
|
|
11
|
+
from boto3_assist.environment_services.environment_variables import (
|
|
12
|
+
EnvironmentVariables,
|
|
13
|
+
)
|
|
14
|
+
from boto3_assist.connection_tracker import ConnectionTracker
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
logger = Logger()
|
|
18
|
+
tracker: ConnectionTracker = ConnectionTracker()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Connection:
|
|
22
|
+
"""Base Boto 3 Connection"""
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
*,
|
|
27
|
+
service_name: Optional[str] = None,
|
|
28
|
+
aws_profile: Optional[str] = None,
|
|
29
|
+
aws_region: Optional[str] = None,
|
|
30
|
+
aws_access_key_id: Optional[str] = None,
|
|
31
|
+
aws_secret_access_key: Optional[str] = None,
|
|
32
|
+
aws_end_point_url: Optional[str] = None,
|
|
33
|
+
assume_role_arn: Optional[str] = None,
|
|
34
|
+
assume_role_chain: Optional[List[str]] = None,
|
|
35
|
+
assume_role_duration_seconds: Optional[int] = 3600,
|
|
36
|
+
) -> None:
|
|
37
|
+
self.__aws_profile = aws_profile
|
|
38
|
+
self.__aws_region = aws_region
|
|
39
|
+
self.__aws_access_key_id = aws_access_key_id
|
|
40
|
+
self.__aws_secret_access_key = aws_secret_access_key
|
|
41
|
+
self.end_point_url = aws_end_point_url
|
|
42
|
+
self.__session: Boto3SessionManager | None = None
|
|
43
|
+
self.__assume_role_arn: Optional[str] = assume_role_arn
|
|
44
|
+
self.__service_name: str | None = service_name
|
|
45
|
+
self.__assume_role_chain = assume_role_chain
|
|
46
|
+
self.__assume_role_duration_seconds = assume_role_duration_seconds
|
|
47
|
+
if self.__service_name is None:
|
|
48
|
+
raise RuntimeError(
|
|
49
|
+
"Service Name is not available. The service name is required."
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
self.raise_on_error: bool = True
|
|
53
|
+
|
|
54
|
+
def setup(self, setup_source: Optional[str] = None) -> None:
|
|
55
|
+
"""
|
|
56
|
+
Setup the environment. Automatically called via init.
|
|
57
|
+
You can run setup at anytime with new parameters.
|
|
58
|
+
Args: setup_source: Optional[str] = None
|
|
59
|
+
Defines the source of the setup. Useful for logging.
|
|
60
|
+
Returns: None
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
logger.debug(
|
|
64
|
+
{
|
|
65
|
+
"metric_filter": f"{self.service_name}_connection_setup",
|
|
66
|
+
"source": f"{self.service_name} Connection",
|
|
67
|
+
"aws_profile": self.aws_profile,
|
|
68
|
+
"aws_region": self.aws_region,
|
|
69
|
+
"setup_source": setup_source,
|
|
70
|
+
}
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
self.__session = Boto3SessionManager(
|
|
74
|
+
service_name=self.service_name,
|
|
75
|
+
aws_profile=self.aws_profile,
|
|
76
|
+
aws_region=self.aws_region,
|
|
77
|
+
aws_access_key_id=self.aws_access_key_id,
|
|
78
|
+
aws_secret_access_key=self.aws_secret_access_key,
|
|
79
|
+
aws_endpoint_url=self.end_point_url,
|
|
80
|
+
assume_role_arn=self.__assume_role_arn,
|
|
81
|
+
assume_role_chain=self.__assume_role_chain,
|
|
82
|
+
assume_role_duration_seconds=self.__assume_role_duration_seconds,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
tracker.add(service_name=self.service_name)
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def asw_profile(self) -> str | None:
|
|
89
|
+
"""The AWS Profile"""
|
|
90
|
+
return self.__aws_profile or EnvironmentVariables.AWS.profile()
|
|
91
|
+
|
|
92
|
+
@asw_profile.setter
|
|
93
|
+
def aws_profile(self, value: str | None):
|
|
94
|
+
self.__aws_profile = value
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def aws_region(self) -> str | None:
|
|
98
|
+
"""The AWS Region"""
|
|
99
|
+
return self.__aws_region or EnvironmentVariables.AWS.region()
|
|
100
|
+
|
|
101
|
+
@aws_region.setter
|
|
102
|
+
def aws_region(self, value: str | None):
|
|
103
|
+
self.__aws_region = value
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def aws_access_key_id(self) -> str | None:
|
|
107
|
+
"""The AWS Access Key"""
|
|
108
|
+
return self.__aws_access_key_id or EnvironmentVariables.AWS.aws_access_key_id()
|
|
109
|
+
|
|
110
|
+
@aws_access_key_id.setter
|
|
111
|
+
def aws_access_key_id(self, value: str | None):
|
|
112
|
+
self.__aws_access_key_id = value
|
|
113
|
+
|
|
114
|
+
@property
|
|
115
|
+
def aws_secret_access_key(self) -> str | None:
|
|
116
|
+
"""The AWS Access Key"""
|
|
117
|
+
return (
|
|
118
|
+
self.__aws_secret_access_key
|
|
119
|
+
or EnvironmentVariables.AWS.aws_secret_access_key()
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
@aws_secret_access_key.setter
|
|
123
|
+
def aws_secret_access_key(self, value: str | None):
|
|
124
|
+
self.__aws_secret_access_key = value
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def service_name(self) -> str:
|
|
128
|
+
"""Service Name"""
|
|
129
|
+
if self.__service_name is None:
|
|
130
|
+
raise RuntimeError("Service Name is not available")
|
|
131
|
+
return self.__service_name
|
|
132
|
+
|
|
133
|
+
@service_name.setter
|
|
134
|
+
def service_name(self, value: str):
|
|
135
|
+
logger.debug("Setting Service Name")
|
|
136
|
+
self.__service_name = value
|
|
137
|
+
|
|
138
|
+
@property
|
|
139
|
+
def session(self) -> Boto3SessionManager:
|
|
140
|
+
"""Session"""
|
|
141
|
+
if self.__session is None:
|
|
142
|
+
self.setup(setup_source="session init")
|
|
143
|
+
|
|
144
|
+
if self.__session is None:
|
|
145
|
+
raise RuntimeError("Session is not available")
|
|
146
|
+
return self.__session
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Geek Cafe, LLC
|
|
3
|
+
Maintainers: Eric Wilson
|
|
4
|
+
MIT License. See Project Root for the license information.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import traceback
|
|
8
|
+
import os
|
|
9
|
+
from typing import Dict
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ConnectionTracker:
|
|
13
|
+
"""
|
|
14
|
+
Tracks Boto3 connection requests for performance tuning and debugging.
|
|
15
|
+
|
|
16
|
+
Attributes:
|
|
17
|
+
__stack_trace_env_var (str): Environment variable name to enable stack trace logging.
|
|
18
|
+
__issue_stack_trace (bool | None): Caches the result of whether stack trace logging is enabled.
|
|
19
|
+
__connection_counter (Dict[str, int]): Tracks the number of connections per service.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(self) -> None:
|
|
23
|
+
self.__stack_trace_env_var: str = "BOTO3_ASSIST_CONNECTION_STACK_TRACE"
|
|
24
|
+
self.__issue_stack_trace: bool | None = None
|
|
25
|
+
self.__connection_counter: Dict[str, int] = {}
|
|
26
|
+
|
|
27
|
+
def add(self, service_name: str) -> None:
|
|
28
|
+
"""
|
|
29
|
+
Increments the connection count for a given service and
|
|
30
|
+
performs a check on the number of connections.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
service_name (str): Name of the AWS service.
|
|
34
|
+
"""
|
|
35
|
+
self.__connection_counter[service_name] = (
|
|
36
|
+
self.__connection_counter.get(service_name, 0) + 1
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
self.check(service_name=service_name)
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def issue_stack_trace(self) -> bool:
|
|
43
|
+
"""
|
|
44
|
+
Checks if stack trace logging is enabled by the environment variable.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
bool: True if stack trace logging is enabled, False otherwise.
|
|
48
|
+
"""
|
|
49
|
+
if self.__issue_stack_trace is None:
|
|
50
|
+
self.__issue_stack_trace = (
|
|
51
|
+
os.getenv(self.__stack_trace_env_var, "").lower() == "true"
|
|
52
|
+
)
|
|
53
|
+
return self.__issue_stack_trace
|
|
54
|
+
|
|
55
|
+
def check(self, service_name: str) -> None:
|
|
56
|
+
"""
|
|
57
|
+
Checks the connection count for a service and logs warnings if needed.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
service_name (str): Name of the AWS service.
|
|
61
|
+
"""
|
|
62
|
+
connection_count = self.__connection_counter.get(service_name, 0)
|
|
63
|
+
if connection_count > 1:
|
|
64
|
+
service_message = (
|
|
65
|
+
f"Your {service_name} service has more than one connection.\n"
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
if not self.issue_stack_trace:
|
|
69
|
+
stack_trace_message = (
|
|
70
|
+
f"๐ NOTE: To add additional information ๐ to the log and determine where additional connections are being created: "
|
|
71
|
+
f"set the environment variable ๐{self.__stack_trace_env_var}๐ to true โ
. \n"
|
|
72
|
+
)
|
|
73
|
+
else:
|
|
74
|
+
stack = "\n".join(traceback.format_stack())
|
|
75
|
+
stack_trace_message = (
|
|
76
|
+
f"\nStack Trace Enabled with {self.__stack_trace_env_var}\n{stack}"
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
self.__log_warning(
|
|
80
|
+
f"{service_message}"
|
|
81
|
+
f"Your boto3 connection count is {connection_count}. "
|
|
82
|
+
"Under most circumstances, you should be able to use the same connection "
|
|
83
|
+
"instead of creating a new one. Connections are expensive in terms of time and latency. "
|
|
84
|
+
"If you are seeing performance issues, check how and where you are creating your "
|
|
85
|
+
"connections. You should be able to pass the connection to your other objects "
|
|
86
|
+
"and reuse your boto3 connections. "
|
|
87
|
+
"\n๐งช MOCK Testing may show this message as well, in which case you can dismiss this warning.๐งช\n"
|
|
88
|
+
f"{stack_trace_message}"
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
def decrement_connection(self, service_name: str) -> None:
|
|
92
|
+
"""
|
|
93
|
+
Decrements the connection count for a service.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
service_name (str): Name of the AWS service.
|
|
97
|
+
"""
|
|
98
|
+
if (
|
|
99
|
+
service_name in self.__connection_counter
|
|
100
|
+
and self.__connection_counter[service_name] > 0
|
|
101
|
+
):
|
|
102
|
+
self.__connection_counter[service_name] -= 1
|
|
103
|
+
|
|
104
|
+
def reset(self, service_name: str) -> None:
|
|
105
|
+
"""
|
|
106
|
+
Resets the connection count for a service to zero.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
service_name (str): Name of the AWS service.
|
|
110
|
+
"""
|
|
111
|
+
self.__connection_counter[service_name] = 0
|
|
112
|
+
|
|
113
|
+
def __log_warning(self, message: str) -> None:
|
|
114
|
+
"""
|
|
115
|
+
Logs a warning message.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
message (str): The warning message to log.
|
|
119
|
+
"""
|
|
120
|
+
print(f"Warning: {message}")
|