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,150 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Geek Cafe, LLC
|
|
3
|
+
Maintainers: Eric Wilson
|
|
4
|
+
MIT License. See Project Root for the license information.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
from typing import Optional, Literal
|
|
9
|
+
|
|
10
|
+
from aws_lambda_powertools import Logger
|
|
11
|
+
|
|
12
|
+
from boto3_assist.securityhub.securityhub_connection import SecurityHubConnection
|
|
13
|
+
|
|
14
|
+
logger = Logger("security-hub-service")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class SecurityHub(SecurityHubConnection):
|
|
18
|
+
"""Security Hub Service"""
|
|
19
|
+
|
|
20
|
+
def update_findings_status(
|
|
21
|
+
self,
|
|
22
|
+
region_name: str,
|
|
23
|
+
workflow_status: Literal["NEW", "NOTIFIED", "RESOLVED", "SUPPRESSED"],
|
|
24
|
+
note_text: Optional[str] = None,
|
|
25
|
+
updated_by: Optional[str] = None,
|
|
26
|
+
):
|
|
27
|
+
"""
|
|
28
|
+
Updates the workflow status for all findings in the specified region.
|
|
29
|
+
|
|
30
|
+
:param region_name: AWS region where Security Hub findings are located.
|
|
31
|
+
:param workflow_status: The new workflow status to apply (e.g., NEW, NOTIFIED, SUPPRESSED, RESOLVED).
|
|
32
|
+
"""
|
|
33
|
+
# Initialize Security Hub client
|
|
34
|
+
client = self.client
|
|
35
|
+
|
|
36
|
+
findings_to_update = []
|
|
37
|
+
next_token = None
|
|
38
|
+
|
|
39
|
+
logger.info(f"Fetching findings in region: {region_name}...")
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
# Paginate through findings
|
|
43
|
+
while True:
|
|
44
|
+
response = client.get_findings(
|
|
45
|
+
MaxResults=100,
|
|
46
|
+
Filters={
|
|
47
|
+
"Region": [
|
|
48
|
+
{"Value": region_name, "Comparison": "EQUALS"},
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
NextToken=next_token if next_token else "",
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
for finding in response.get("Findings", []):
|
|
55
|
+
current_status = finding.get("Workflow", {}).get("Status")
|
|
56
|
+
if (
|
|
57
|
+
current_status
|
|
58
|
+
and str(current_status).lower() != str(workflow_status).lower()
|
|
59
|
+
):
|
|
60
|
+
findings_to_update.append(
|
|
61
|
+
{
|
|
62
|
+
"Id": finding["Id"],
|
|
63
|
+
"ProductArn": finding["ProductArn"],
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
else:
|
|
67
|
+
logger.debug(
|
|
68
|
+
f"Skipping: {finding['Id']} with a status of {current_status}"
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
next_token = response.get("NextToken")
|
|
72
|
+
if not next_token:
|
|
73
|
+
break
|
|
74
|
+
|
|
75
|
+
print(f"Found {len(findings_to_update)} findings to update.")
|
|
76
|
+
|
|
77
|
+
note_text = note_text or "Automated Update"
|
|
78
|
+
updated_by = updated_by or "System"
|
|
79
|
+
# Update workflow status in batches of 100
|
|
80
|
+
for i in range(0, len(findings_to_update), 100):
|
|
81
|
+
batch = findings_to_update[i : i + 100]
|
|
82
|
+
response = client.batch_update_findings(
|
|
83
|
+
FindingIdentifiers=batch,
|
|
84
|
+
Workflow={"Status": str(workflow_status).upper()},
|
|
85
|
+
Note={"Text": note_text, "UpdatedBy": updated_by},
|
|
86
|
+
)
|
|
87
|
+
logger.debug(
|
|
88
|
+
f"Updated findings {i + 1} to {i + len(batch)} to status: {workflow_status}"
|
|
89
|
+
)
|
|
90
|
+
print(response)
|
|
91
|
+
|
|
92
|
+
logger.info("All findings updated successfully!")
|
|
93
|
+
|
|
94
|
+
except Exception as e:
|
|
95
|
+
logger.exception(f"An error occurred: {str(e)}")
|
|
96
|
+
raise
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def main():
|
|
100
|
+
status = "RESOLVED" # Change to NEW, NOTIFIED, SUPPRESSED, or RESOLVED
|
|
101
|
+
note_text = "This region is now disabled."
|
|
102
|
+
# these are my linked regions and the only ones I care about
|
|
103
|
+
# if have SCP's in place for the other regions
|
|
104
|
+
regions_to_skip = ["us-east-1", "us-west-2", "eu-west-2"]
|
|
105
|
+
|
|
106
|
+
aws_profile = os.getenv("SECURITY_HUB_PROFILE")
|
|
107
|
+
|
|
108
|
+
aws_regions = {
|
|
109
|
+
"af-south-1": "Africa (Cape Town)",
|
|
110
|
+
"ap-east-1": "Asia Pacific (Hong Kong)",
|
|
111
|
+
"ap-northeast-1": "Asia Pacific (Tokyo)",
|
|
112
|
+
"ap-northeast-2": "Asia Pacific (Seoul)",
|
|
113
|
+
"ap-northeast-3": "Asia Pacific (Osaka)",
|
|
114
|
+
"ap-south-1": "Asia Pacific (Mumbai)",
|
|
115
|
+
"ap-south-2": "Asia Pacific (Hyderabad)",
|
|
116
|
+
"ap-southeast-1": "Asia Pacific (Singapore)",
|
|
117
|
+
"ap-southeast-2": "Asia Pacific (Sydney)",
|
|
118
|
+
"ap-southeast-3": "Asia Pacific (Jakarta)",
|
|
119
|
+
"ap-southeast-4": "Asia Pacific (Melbourne)",
|
|
120
|
+
"ap-southeast-5": "Asia Pacific (Auckland)",
|
|
121
|
+
"ca-central-1": "Canada (Central)",
|
|
122
|
+
"ca-west-1": "Canada (West)",
|
|
123
|
+
"eu-central-1": "Europe (Frankfurt)",
|
|
124
|
+
"eu-central-2": "Europe (Zurich)",
|
|
125
|
+
"eu-north-1": "Europe (Stockholm)",
|
|
126
|
+
"eu-south-1": "Europe (Milan)",
|
|
127
|
+
"eu-south-2": "Europe (Spain)",
|
|
128
|
+
"eu-west-1": "Europe (Ireland)",
|
|
129
|
+
"eu-west-2": "Europe (London)",
|
|
130
|
+
"eu-west-3": "Europe (Paris)",
|
|
131
|
+
"il-central-1": "Israel (Tel Aviv)",
|
|
132
|
+
"me-central-1": "Middle East (UAE)",
|
|
133
|
+
"sa-east-1": "South America (São Paulo)",
|
|
134
|
+
"us-east-1": "US East (N. Virginia)",
|
|
135
|
+
"us-east-2": "US East (Ohio)",
|
|
136
|
+
"us-west-1": "US West (N. California)",
|
|
137
|
+
"us-west-2": "US West (Oregon)",
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
sh: SecurityHub = SecurityHub(aws_profile=aws_profile)
|
|
141
|
+
for region in aws_regions:
|
|
142
|
+
print(region)
|
|
143
|
+
if region not in regions_to_skip:
|
|
144
|
+
sh.update_findings_status(region, status, note_text=note_text)
|
|
145
|
+
else:
|
|
146
|
+
print(f"Skipping region: {region}")
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
if __name__ == "__main__":
|
|
150
|
+
main()
|
|
@@ -0,0 +1,57 @@
|
|
|
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
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
from aws_lambda_powertools import Logger
|
|
11
|
+
|
|
12
|
+
from boto3_assist.connection import Connection
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from mypy_boto3_securityhub import SecurityHubClient
|
|
16
|
+
else:
|
|
17
|
+
SecurityHubClient = object
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
logger = Logger()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class SecurityHubConnection(Connection):
|
|
24
|
+
"""Connection"""
|
|
25
|
+
|
|
26
|
+
def __init__(
|
|
27
|
+
self,
|
|
28
|
+
*,
|
|
29
|
+
aws_profile: Optional[str] = None,
|
|
30
|
+
aws_region: Optional[str] = None,
|
|
31
|
+
aws_end_point_url: Optional[str] = None,
|
|
32
|
+
aws_access_key_id: Optional[str] = None,
|
|
33
|
+
aws_secret_access_key: Optional[str] = None,
|
|
34
|
+
) -> None:
|
|
35
|
+
super().__init__(
|
|
36
|
+
service_name="securityhub",
|
|
37
|
+
aws_profile=aws_profile,
|
|
38
|
+
aws_region=aws_region,
|
|
39
|
+
aws_access_key_id=aws_access_key_id,
|
|
40
|
+
aws_secret_access_key=aws_secret_access_key,
|
|
41
|
+
aws_end_point_url=aws_end_point_url,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
self.__client: SecurityHubClient | None = None
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def client(self) -> SecurityHubClient:
|
|
48
|
+
"""Client Connection"""
|
|
49
|
+
if self.__client is None:
|
|
50
|
+
self.__client = self.session.client
|
|
51
|
+
|
|
52
|
+
return self.__client
|
|
53
|
+
|
|
54
|
+
@client.setter
|
|
55
|
+
def client(self, value: SecurityHubClient):
|
|
56
|
+
logger.info("Setting Client")
|
|
57
|
+
self.__client = value
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Geek Cafe, LLC
|
|
3
|
+
Maintainers: Eric Wilson
|
|
4
|
+
MIT License. See Project Root for the license information.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import boto3
|
|
9
|
+
from typing import Optional
|
|
10
|
+
from boto3_assist.aws_config import AWSConfig
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class SessionSetupMixin:
|
|
14
|
+
def _create_base_session(
|
|
15
|
+
self,
|
|
16
|
+
aws_profile: Optional[str],
|
|
17
|
+
aws_region: Optional[str],
|
|
18
|
+
aws_access_key_id: Optional[str],
|
|
19
|
+
aws_secret_access_key: Optional[str],
|
|
20
|
+
aws_session_token: Optional[str],
|
|
21
|
+
) -> boto3.Session:
|
|
22
|
+
try:
|
|
23
|
+
return boto3.Session(
|
|
24
|
+
profile_name=aws_profile,
|
|
25
|
+
region_name=aws_region,
|
|
26
|
+
aws_access_key_id=aws_access_key_id,
|
|
27
|
+
aws_secret_access_key=aws_secret_access_key,
|
|
28
|
+
aws_session_token=aws_session_token,
|
|
29
|
+
)
|
|
30
|
+
except Exception as e:
|
|
31
|
+
|
|
32
|
+
error_message = f"Failed to create boto3 session "
|
|
33
|
+
if "profile" in str(e).lower():
|
|
34
|
+
error_message += " due to a profile error "
|
|
35
|
+
|
|
36
|
+
error_message += f" with profile '{aws_profile}'."
|
|
37
|
+
config: AWSConfig = AWSConfig()
|
|
38
|
+
if not config.path_exists():
|
|
39
|
+
error_message += (
|
|
40
|
+
f" The AWS config file '{config.get_path()}' was not found. "
|
|
41
|
+
"Please ensure that the AWS CLI is installed and configured correctly. "
|
|
42
|
+
"You can install the AWS CLI by running 'pip install awscli' or 'pip install awscli --upgrade'. "
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
if (
|
|
46
|
+
os.getenv("HOME") == "/tmp"
|
|
47
|
+
or os.getenv("AWS_CONFIG_FILE") == "/tmp"
|
|
48
|
+
):
|
|
49
|
+
error_message += (
|
|
50
|
+
f'The environment HOME path is set to {os.getenv("HOME")}. '
|
|
51
|
+
)
|
|
52
|
+
if os.getenv("AWS_CONFIG_FILE"):
|
|
53
|
+
error_message += (
|
|
54
|
+
f"The environment AWS_CONFIG_FILE is set to {os.getenv('AWS_CONFIG_FILE')}. "
|
|
55
|
+
"The AWS_CONFIG_FILE overrides the HOME directory and path. "
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
error_message += (
|
|
59
|
+
"If you are running this locally and expecting it to be in your users home "
|
|
60
|
+
"directory, you may need to set the HOME or AWS_CONFIG_FILE environment variable manually. "
|
|
61
|
+
"There could be other actions such as a Lambda environment resetting the path to /tmp. "
|
|
62
|
+
"If you are running in a GitHub Actions environment, "
|
|
63
|
+
"you may need to set the HOME or AWS_CONFIG_FILE environment variable to '/home/runner'. "
|
|
64
|
+
)
|
|
65
|
+
elif not config.has_profile(aws_profile):
|
|
66
|
+
error_message += f" The profile '{aws_profile}' was not found in the AWS config file in {config.get_path()}."
|
|
67
|
+
|
|
68
|
+
# check for the existence of the profile and the path to the profile
|
|
69
|
+
|
|
70
|
+
raise RuntimeError(error_message) from e
|
|
@@ -0,0 +1,57 @@
|
|
|
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
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
from aws_lambda_powertools import Logger
|
|
11
|
+
|
|
12
|
+
from boto3_assist.connection import Connection
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from mypy_boto3_ssm import Client
|
|
16
|
+
else:
|
|
17
|
+
Client = object
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
logger = Logger()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class SSMConnection(Connection):
|
|
24
|
+
"""Connection"""
|
|
25
|
+
|
|
26
|
+
def __init__(
|
|
27
|
+
self,
|
|
28
|
+
*,
|
|
29
|
+
aws_profile: Optional[str] = None,
|
|
30
|
+
aws_region: Optional[str] = None,
|
|
31
|
+
aws_end_point_url: Optional[str] = None,
|
|
32
|
+
aws_access_key_id: Optional[str] = None,
|
|
33
|
+
aws_secret_access_key: Optional[str] = None,
|
|
34
|
+
) -> None:
|
|
35
|
+
super().__init__(
|
|
36
|
+
service_name="ssm",
|
|
37
|
+
aws_profile=aws_profile,
|
|
38
|
+
aws_region=aws_region,
|
|
39
|
+
aws_access_key_id=aws_access_key_id,
|
|
40
|
+
aws_secret_access_key=aws_secret_access_key,
|
|
41
|
+
aws_end_point_url=aws_end_point_url,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
self.__client: Client | None = None
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def client(self) -> Client:
|
|
48
|
+
"""Client Connection"""
|
|
49
|
+
if self.__client is None:
|
|
50
|
+
self.__client = self.session.client
|
|
51
|
+
|
|
52
|
+
return self.__client
|
|
53
|
+
|
|
54
|
+
@client.setter
|
|
55
|
+
def client(self, value: Client):
|
|
56
|
+
logger.info("Setting Client")
|
|
57
|
+
self.__client = value
|
|
@@ -0,0 +1,116 @@
|
|
|
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, Literal
|
|
8
|
+
|
|
9
|
+
from botocore.exceptions import ClientError
|
|
10
|
+
from boto3_assist.ssm.connection import SSMConnection
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ParameterStore(SSMConnection):
|
|
14
|
+
"""Parameter Store"""
|
|
15
|
+
|
|
16
|
+
def get_parameter(self, name: str, with_decryption=True):
|
|
17
|
+
"""
|
|
18
|
+
Retrieve a parameter from Parameter Store.
|
|
19
|
+
|
|
20
|
+
:param name: The full name of the parameter.
|
|
21
|
+
:param with_decryption: If True, decrypt secure strings.
|
|
22
|
+
:return: The parameter value or None if an error occurs.
|
|
23
|
+
"""
|
|
24
|
+
try:
|
|
25
|
+
response = self.client.get_parameter(
|
|
26
|
+
Name=name, WithDecryption=with_decryption
|
|
27
|
+
)
|
|
28
|
+
return response["Parameter"]["Value"]
|
|
29
|
+
except ClientError as e:
|
|
30
|
+
print(f"Error getting parameter {name}: {e}")
|
|
31
|
+
raise
|
|
32
|
+
|
|
33
|
+
def put_parameter(
|
|
34
|
+
self,
|
|
35
|
+
name: str,
|
|
36
|
+
value: str,
|
|
37
|
+
type: Literal["String", "StringList", "SecureString"] = "String", # pylint: disable=redefined-builtin
|
|
38
|
+
overwrite=True,
|
|
39
|
+
):
|
|
40
|
+
"""
|
|
41
|
+
Create or update a parameter in Parameter Store.
|
|
42
|
+
|
|
43
|
+
:param name: The full name of the parameter.
|
|
44
|
+
:param value: The value to store.
|
|
45
|
+
:param type: Parameter type ('String', 'StringList', or 'SecureString').
|
|
46
|
+
:param overwrite: If True, overwrite an existing parameter.
|
|
47
|
+
:return: The response from the put_parameter call or None on error.
|
|
48
|
+
"""
|
|
49
|
+
try:
|
|
50
|
+
response = self.client.put_parameter(
|
|
51
|
+
Name=name, Value=value, Type=type, Overwrite=overwrite
|
|
52
|
+
)
|
|
53
|
+
return response
|
|
54
|
+
except ClientError as e:
|
|
55
|
+
print(f"Error putting parameter {name}: {e}")
|
|
56
|
+
raise
|
|
57
|
+
|
|
58
|
+
def delete_parameter(self, name: str):
|
|
59
|
+
"""
|
|
60
|
+
Delete a parameter from Parameter Store.
|
|
61
|
+
|
|
62
|
+
:param name: The full name of the parameter.
|
|
63
|
+
:return: The response from the delete_parameter call or None on error.
|
|
64
|
+
"""
|
|
65
|
+
try:
|
|
66
|
+
response = self.client.delete_parameter(Name=name)
|
|
67
|
+
return response
|
|
68
|
+
except ClientError as e:
|
|
69
|
+
print(f"Error deleting parameter {name}: {e}")
|
|
70
|
+
raise
|
|
71
|
+
|
|
72
|
+
def list_parameters(self, path: str = "/", recursive=True):
|
|
73
|
+
"""
|
|
74
|
+
List parameters in a given path.
|
|
75
|
+
|
|
76
|
+
:param path: The hierarchical path for the parameters.
|
|
77
|
+
:param recursive: If True, retrieve parameters recursively.
|
|
78
|
+
:return: A list of parameter metadata dictionaries.
|
|
79
|
+
"""
|
|
80
|
+
try:
|
|
81
|
+
paginator = self.client.get_paginator("describe_parameters")
|
|
82
|
+
parameters = []
|
|
83
|
+
filters = [
|
|
84
|
+
{
|
|
85
|
+
"Key": "Path",
|
|
86
|
+
"Option": "Recursive" if recursive else "OneLevel",
|
|
87
|
+
"Values": [path],
|
|
88
|
+
}
|
|
89
|
+
]
|
|
90
|
+
for page in paginator.paginate(ParameterFilters=filters):
|
|
91
|
+
parameters.extend(page.get("Parameters", []))
|
|
92
|
+
return parameters
|
|
93
|
+
except ClientError as e:
|
|
94
|
+
print(f"Error listing parameters for path {path}: {e}")
|
|
95
|
+
raise
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
# Example usage:
|
|
99
|
+
if __name__ == "__main__":
|
|
100
|
+
# Initialize the ParameterStore class.
|
|
101
|
+
ssm = ParameterStore()
|
|
102
|
+
# Example: Put a parameter.
|
|
103
|
+
put_response = ssm.put_parameter("/myapp/AccountNumber", "123456789012")
|
|
104
|
+
print("Put parameter response:", put_response)
|
|
105
|
+
|
|
106
|
+
# Example: Get a parameter.
|
|
107
|
+
account_number = ssm.get_parameter("/myapp/AccountNumber")
|
|
108
|
+
print("Account Number:", account_number)
|
|
109
|
+
|
|
110
|
+
# Example: List parameters under /myapp.
|
|
111
|
+
params = ssm.list_parameters(path="/myapp")
|
|
112
|
+
print("Parameters under /myapp:", params)
|
|
113
|
+
|
|
114
|
+
# Example: Delete a parameter.
|
|
115
|
+
delete_response = ssm.delete_parameter("/myapp/AccountNumber")
|
|
116
|
+
print("Delete parameter response:", delete_response)
|