awslabs.elasticache-mcp-server 0.1.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.
- awslabs/__init__.py +16 -0
- awslabs/elasticache_mcp_server/__init__.py +17 -0
- awslabs/elasticache_mcp_server/common/__init__.py +15 -0
- awslabs/elasticache_mcp_server/common/connection.py +117 -0
- awslabs/elasticache_mcp_server/common/decorators.py +41 -0
- awslabs/elasticache_mcp_server/common/server.py +30 -0
- awslabs/elasticache_mcp_server/context.py +39 -0
- awslabs/elasticache_mcp_server/main.py +52 -0
- awslabs/elasticache_mcp_server/tools/__init__.py +15 -0
- awslabs/elasticache_mcp_server/tools/cc/__init__.py +31 -0
- awslabs/elasticache_mcp_server/tools/cc/connect.py +444 -0
- awslabs/elasticache_mcp_server/tools/cc/create.py +212 -0
- awslabs/elasticache_mcp_server/tools/cc/delete.py +65 -0
- awslabs/elasticache_mcp_server/tools/cc/describe.py +80 -0
- awslabs/elasticache_mcp_server/tools/cc/modify.py +159 -0
- awslabs/elasticache_mcp_server/tools/cc/parsers.py +78 -0
- awslabs/elasticache_mcp_server/tools/cc/processors.py +74 -0
- awslabs/elasticache_mcp_server/tools/ce/__init__.py +19 -0
- awslabs/elasticache_mcp_server/tools/ce/get_cost_and_usage.py +76 -0
- awslabs/elasticache_mcp_server/tools/cw/__init__.py +19 -0
- awslabs/elasticache_mcp_server/tools/cw/get_metric_statistics.py +85 -0
- awslabs/elasticache_mcp_server/tools/cwlogs/__init__.py +29 -0
- awslabs/elasticache_mcp_server/tools/cwlogs/create_log_group.py +68 -0
- awslabs/elasticache_mcp_server/tools/cwlogs/describe_log_groups.py +123 -0
- awslabs/elasticache_mcp_server/tools/cwlogs/describe_log_streams.py +120 -0
- awslabs/elasticache_mcp_server/tools/cwlogs/filter_log_events.py +122 -0
- awslabs/elasticache_mcp_server/tools/cwlogs/get_log_events.py +99 -0
- awslabs/elasticache_mcp_server/tools/firehose/__init__.py +19 -0
- awslabs/elasticache_mcp_server/tools/firehose/list_delivery_streams.py +63 -0
- awslabs/elasticache_mcp_server/tools/misc/__init__.py +31 -0
- awslabs/elasticache_mcp_server/tools/misc/batch_apply_update_action.py +62 -0
- awslabs/elasticache_mcp_server/tools/misc/batch_stop_update_action.py +62 -0
- awslabs/elasticache_mcp_server/tools/misc/describe_cache_engine_versions.py +79 -0
- awslabs/elasticache_mcp_server/tools/misc/describe_engine_default_parameters.py +64 -0
- awslabs/elasticache_mcp_server/tools/misc/describe_events.py +86 -0
- awslabs/elasticache_mcp_server/tools/misc/describe_service_updates.py +71 -0
- awslabs/elasticache_mcp_server/tools/rg/__init__.py +54 -0
- awslabs/elasticache_mcp_server/tools/rg/complete_migration.py +94 -0
- awslabs/elasticache_mcp_server/tools/rg/connect.py +537 -0
- awslabs/elasticache_mcp_server/tools/rg/create.py +318 -0
- awslabs/elasticache_mcp_server/tools/rg/delete.py +68 -0
- awslabs/elasticache_mcp_server/tools/rg/describe.py +68 -0
- awslabs/elasticache_mcp_server/tools/rg/modify.py +236 -0
- awslabs/elasticache_mcp_server/tools/rg/parsers.py +268 -0
- awslabs/elasticache_mcp_server/tools/rg/processors.py +227 -0
- awslabs/elasticache_mcp_server/tools/rg/start_migration.py +151 -0
- awslabs/elasticache_mcp_server/tools/rg/test_migration.py +139 -0
- awslabs/elasticache_mcp_server/tools/serverless/__init__.py +37 -0
- awslabs/elasticache_mcp_server/tools/serverless/connect.py +451 -0
- awslabs/elasticache_mcp_server/tools/serverless/create.py +174 -0
- awslabs/elasticache_mcp_server/tools/serverless/delete.py +49 -0
- awslabs/elasticache_mcp_server/tools/serverless/describe.py +69 -0
- awslabs/elasticache_mcp_server/tools/serverless/models.py +160 -0
- awslabs/elasticache_mcp_server/tools/serverless/modify.py +95 -0
- awslabs_elasticache_mcp_server-0.1.1.dist-info/METADATA +257 -0
- awslabs_elasticache_mcp_server-0.1.1.dist-info/RECORD +60 -0
- awslabs_elasticache_mcp_server-0.1.1.dist-info/WHEEL +4 -0
- awslabs_elasticache_mcp_server-0.1.1.dist-info/entry_points.txt +2 -0
- awslabs_elasticache_mcp_server-0.1.1.dist-info/licenses/LICENSE +175 -0
- awslabs_elasticache_mcp_server-0.1.1.dist-info/licenses/NOTICE +2 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Create serverless cache operations."""
|
|
16
|
+
|
|
17
|
+
from ...common.connection import ElastiCacheConnectionManager
|
|
18
|
+
from ...common.decorators import handle_exceptions
|
|
19
|
+
from ...common.server import mcp
|
|
20
|
+
from ...context import Context
|
|
21
|
+
from .models import CreateServerlessCacheRequest
|
|
22
|
+
from typing import Dict
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@mcp.tool(name='create_serverless_cache')
|
|
26
|
+
@handle_exceptions
|
|
27
|
+
async def create_serverless_cache(request: CreateServerlessCacheRequest) -> Dict:
|
|
28
|
+
"""Create a new Amazon ElastiCache serverless cache.
|
|
29
|
+
|
|
30
|
+
This tool creates a new serverless cache with specified configuration including:
|
|
31
|
+
- Serverless cache name and capacity
|
|
32
|
+
- Optional VPC and security settings
|
|
33
|
+
- Optional encryption settings
|
|
34
|
+
- Optional snapshot restoration and backup settings
|
|
35
|
+
- Optional usage limits and user groups
|
|
36
|
+
- Optional tags
|
|
37
|
+
|
|
38
|
+
Parameters:
|
|
39
|
+
serverless_cache_name (str): Name of the serverless cache.
|
|
40
|
+
engine (str): Cache engine type.
|
|
41
|
+
description (Optional[str]): Description for the cache.
|
|
42
|
+
kms_key_id (Optional[str]): KMS key ID for encryption.
|
|
43
|
+
major_engine_version (Optional[str]): Major engine version.
|
|
44
|
+
snapshot_arns_to_restore (Optional[List[str]]): List of snapshot ARNs to restore from.
|
|
45
|
+
subnet_ids (Optional[List[str]]): List of subnet IDs for VPC configuration.
|
|
46
|
+
tags (Optional[Union[str, List[Dict[str, Optional[str]]], Dict[str, Optional[str]]]]): Tags to apply to the cache.
|
|
47
|
+
Tag requirements:
|
|
48
|
+
- Key: (string) Required. The key for the tag. Must not be empty.
|
|
49
|
+
- Value: (string) Optional. The tag's value. May be null.
|
|
50
|
+
|
|
51
|
+
Supports three formats:
|
|
52
|
+
1. Shorthand syntax: "Key=value,Key2=value2" or "Key=,Key2=" for null values
|
|
53
|
+
2. Dictionary: {"key": "value", "key2": null}
|
|
54
|
+
3. JSON array: [{"Key": "string", "Value": "string"}, {"Key": "string2", "Value": null}]
|
|
55
|
+
|
|
56
|
+
Can be None if no tags are needed.
|
|
57
|
+
vpc_security_group_ids (Optional[List[str]]): List of VPC security group IDs.
|
|
58
|
+
cache_usage_limits (Optional[CacheUsageLimits]): Usage limits for the cache. Structure:
|
|
59
|
+
{
|
|
60
|
+
"DataStorage": {
|
|
61
|
+
"Maximum": int, # Maximum storage in GB
|
|
62
|
+
"Minimum": int, # Minimum storage in GB
|
|
63
|
+
"Unit": "GB" # Storage unit (currently only GB is supported)
|
|
64
|
+
},
|
|
65
|
+
"ECPUPerSecond": {
|
|
66
|
+
"Maximum": int, # Maximum ECPU per second
|
|
67
|
+
"Minimum": int # Minimum ECPU per second
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
user_group_id (Optional[str]): ID of the user group to associate with the cache.
|
|
71
|
+
snapshot_retention_limit (Optional[int]): Number of days for which ElastiCache retains automatic snapshots.
|
|
72
|
+
daily_snapshot_time (Optional[str]): Time range (in UTC) when daily snapshots are taken (e.g., '04:00-05:00').
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
Dict containing information about the created serverless cache.
|
|
76
|
+
"""
|
|
77
|
+
"""Create a new Amazon ElastiCache serverless cache.
|
|
78
|
+
|
|
79
|
+
This tool creates a new serverless cache with specified configuration including:
|
|
80
|
+
- Serverless cache name and capacity
|
|
81
|
+
- Optional VPC and security settings
|
|
82
|
+
- Optional encryption settings
|
|
83
|
+
- Optional snapshot restoration and backup settings
|
|
84
|
+
- Optional usage limits and user groups
|
|
85
|
+
- Optional tags
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
request: The CreateServerlessCacheRequest object containing all parameters
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
Dict containing information about the created serverless cache.
|
|
92
|
+
"""
|
|
93
|
+
# Check if readonly mode is enabled
|
|
94
|
+
if Context.readonly_mode():
|
|
95
|
+
raise ValueError(
|
|
96
|
+
'You have configured this tool in readonly mode. To make this change you will have to update your configuration.'
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
# Get ElastiCache client
|
|
100
|
+
elasticache_client = ElastiCacheConnectionManager.get_connection()
|
|
101
|
+
|
|
102
|
+
# Build AWS API request
|
|
103
|
+
create_request = {}
|
|
104
|
+
|
|
105
|
+
# Required parameters
|
|
106
|
+
create_request['ServerlessCacheName'] = request.serverless_cache_name
|
|
107
|
+
create_request['Engine'] = request.engine
|
|
108
|
+
|
|
109
|
+
# Optional string parameters
|
|
110
|
+
for param_name, value in [
|
|
111
|
+
('Description', request.description),
|
|
112
|
+
('KmsKeyId', request.kms_key_id),
|
|
113
|
+
('MajorEngineVersion', request.major_engine_version),
|
|
114
|
+
('UserGroupId', request.user_group_id),
|
|
115
|
+
('DailySnapshotTime', request.daily_snapshot_time),
|
|
116
|
+
]:
|
|
117
|
+
if value:
|
|
118
|
+
create_request[param_name] = str(value)
|
|
119
|
+
|
|
120
|
+
# Optional list parameters
|
|
121
|
+
for param_name, value in [
|
|
122
|
+
('SnapshotArnsToRestore', request.snapshot_arns_to_restore),
|
|
123
|
+
('SubnetIds', request.subnet_ids),
|
|
124
|
+
('VpcSecurityGroupIds', request.vpc_security_group_ids),
|
|
125
|
+
]:
|
|
126
|
+
if value:
|
|
127
|
+
create_request[param_name] = list(map(str, value))
|
|
128
|
+
|
|
129
|
+
# Optional numeric parameters
|
|
130
|
+
if request.snapshot_retention_limit is not None:
|
|
131
|
+
create_request['SnapshotRetentionLimit'] = str(request.snapshot_retention_limit)
|
|
132
|
+
|
|
133
|
+
# Cache usage limits
|
|
134
|
+
if request.cache_usage_limits:
|
|
135
|
+
limits_dict = request.cache_usage_limits.model_dump()
|
|
136
|
+
# Ensure numeric values are properly formatted
|
|
137
|
+
if 'DataStorage' in limits_dict:
|
|
138
|
+
limits_dict['DataStorage']['Maximum'] = int(limits_dict['DataStorage']['Maximum'])
|
|
139
|
+
limits_dict['DataStorage']['Minimum'] = int(limits_dict['DataStorage']['Minimum'])
|
|
140
|
+
if 'ECPUPerSecond' in limits_dict:
|
|
141
|
+
limits_dict['ECPUPerSecond']['Maximum'] = int(limits_dict['ECPUPerSecond']['Maximum'])
|
|
142
|
+
limits_dict['ECPUPerSecond']['Minimum'] = int(limits_dict['ECPUPerSecond']['Minimum'])
|
|
143
|
+
create_request['CacheUsageLimits'] = limits_dict
|
|
144
|
+
|
|
145
|
+
# Tags
|
|
146
|
+
if request.tags:
|
|
147
|
+
if isinstance(request.tags, str):
|
|
148
|
+
# Parse string format "key=value,key2=value2"
|
|
149
|
+
tags = []
|
|
150
|
+
for pair in request.tags.split(','):
|
|
151
|
+
key, value = pair.split('=')
|
|
152
|
+
tags.append(
|
|
153
|
+
{
|
|
154
|
+
'Key': str(key.strip()),
|
|
155
|
+
'Value': str(value.strip()) if value.strip() else None,
|
|
156
|
+
}
|
|
157
|
+
)
|
|
158
|
+
create_request['Tags'] = tags
|
|
159
|
+
elif isinstance(request.tags, dict):
|
|
160
|
+
# Convert dict format to list of Tag objects
|
|
161
|
+
create_request['Tags'] = [
|
|
162
|
+
{'Key': str(k), 'Value': str(v) if v is not None else None}
|
|
163
|
+
for k, v in request.tags.items()
|
|
164
|
+
]
|
|
165
|
+
else:
|
|
166
|
+
# Convert Tag objects to dict format
|
|
167
|
+
create_request['Tags'] = [
|
|
168
|
+
{'Key': str(tag.Key), 'Value': str(tag.Value) if tag.Value is not None else None}
|
|
169
|
+
for tag in request.tags
|
|
170
|
+
]
|
|
171
|
+
|
|
172
|
+
# Create the cache
|
|
173
|
+
response = elasticache_client.create_serverless_cache(**create_request)
|
|
174
|
+
return response
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Delete serverless cache operations."""
|
|
16
|
+
|
|
17
|
+
from ...common.connection import ElastiCacheConnectionManager
|
|
18
|
+
from ...common.decorators import handle_exceptions
|
|
19
|
+
from ...common.server import mcp
|
|
20
|
+
from typing import Dict, Optional
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@mcp.tool(name='delete_serverless_cache')
|
|
24
|
+
@handle_exceptions
|
|
25
|
+
async def delete_serverless_cache(
|
|
26
|
+
serverless_cache_name: str,
|
|
27
|
+
final_snapshot_name: Optional[str] = None,
|
|
28
|
+
) -> Dict:
|
|
29
|
+
"""Delete an Amazon ElastiCache serverless cache.
|
|
30
|
+
|
|
31
|
+
This tool deletes a specified serverless cache from your AWS account.
|
|
32
|
+
The cache must exist and be in a deletable state.
|
|
33
|
+
|
|
34
|
+
Parameters:
|
|
35
|
+
serverless_cache_name (str): Name of the serverless cache to delete.
|
|
36
|
+
final_snapshot_name (Optional[str]): Name of the final snapshot to create before deletion.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
Dict containing the deletion response or error information.
|
|
40
|
+
"""
|
|
41
|
+
# Get ElastiCache client
|
|
42
|
+
elasticache_client = ElastiCacheConnectionManager.get_connection()
|
|
43
|
+
|
|
44
|
+
delete_request = {'ServerlessCacheName': serverless_cache_name}
|
|
45
|
+
if final_snapshot_name:
|
|
46
|
+
delete_request['FinalSnapshotName'] = str(final_snapshot_name)
|
|
47
|
+
|
|
48
|
+
response = elasticache_client.delete_serverless_cache(**delete_request)
|
|
49
|
+
return response
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Describe serverless cache operations."""
|
|
16
|
+
|
|
17
|
+
from ...common.connection import ElastiCacheConnectionManager
|
|
18
|
+
from ...common.decorators import handle_exceptions
|
|
19
|
+
from ...common.server import mcp
|
|
20
|
+
from typing import Dict, Optional
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@mcp.tool(name='describe-serverless-caches')
|
|
24
|
+
@handle_exceptions
|
|
25
|
+
async def describe_serverless_caches(
|
|
26
|
+
serverless_cache_name: Optional[str] = None,
|
|
27
|
+
max_items: Optional[int] = None,
|
|
28
|
+
starting_token: Optional[str] = None,
|
|
29
|
+
page_size: Optional[int] = None,
|
|
30
|
+
) -> Dict:
|
|
31
|
+
"""Describe Amazon ElastiCache serverless caches in your AWS account.
|
|
32
|
+
|
|
33
|
+
This tool retrieves detailed information about serverless caches including:
|
|
34
|
+
- Cache configuration
|
|
35
|
+
- Cache endpoints
|
|
36
|
+
- Cache status
|
|
37
|
+
- Cache size
|
|
38
|
+
- Cache connections
|
|
39
|
+
|
|
40
|
+
Parameters:
|
|
41
|
+
serverless_cache_name (Optional[str]): Name of the serverless cache to describe. If not provided, describes all caches.
|
|
42
|
+
max_items (Optional[int]): Maximum number of results to return.
|
|
43
|
+
starting_token (Optional[str]): Token to start the list from a specific page.
|
|
44
|
+
page_size (Optional[int]): Number of records to include in each page.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
Dict containing information about the serverless cache(s).
|
|
48
|
+
"""
|
|
49
|
+
# Get ElastiCache client
|
|
50
|
+
elasticache_client = ElastiCacheConnectionManager.get_connection()
|
|
51
|
+
|
|
52
|
+
if serverless_cache_name:
|
|
53
|
+
# Get specific cache details
|
|
54
|
+
response = elasticache_client.describe_serverless_caches(
|
|
55
|
+
ServerlessCacheName=serverless_cache_name
|
|
56
|
+
)
|
|
57
|
+
return response
|
|
58
|
+
else:
|
|
59
|
+
# List all caches with optional pagination
|
|
60
|
+
kwargs = {}
|
|
61
|
+
if max_items:
|
|
62
|
+
kwargs['MaxItems'] = max_items
|
|
63
|
+
if starting_token:
|
|
64
|
+
kwargs['StartingToken'] = starting_token
|
|
65
|
+
if page_size:
|
|
66
|
+
kwargs['PageSize'] = page_size
|
|
67
|
+
|
|
68
|
+
response = elasticache_client.describe_serverless_caches(**kwargs)
|
|
69
|
+
return response
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Models for serverless cache operations."""
|
|
16
|
+
|
|
17
|
+
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
18
|
+
from typing import Dict, List, Optional, Union
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class DataStorageLimits(BaseModel):
|
|
22
|
+
"""Limits for data storage capacity in serverless configuration."""
|
|
23
|
+
|
|
24
|
+
Maximum: int = Field(..., description='Maximum storage in GB', gt=0)
|
|
25
|
+
Minimum: int = Field(..., description='Minimum storage in GB', gt=0)
|
|
26
|
+
Unit: str = Field(..., description='Storage unit (currently only GB is supported)')
|
|
27
|
+
|
|
28
|
+
@field_validator('Unit')
|
|
29
|
+
def validate_unit(cls, v):
|
|
30
|
+
"""Validate that Unit is 'GB'."""
|
|
31
|
+
if v != 'GB':
|
|
32
|
+
raise ValueError("Unit must be 'GB'")
|
|
33
|
+
return v
|
|
34
|
+
|
|
35
|
+
@field_validator('Minimum')
|
|
36
|
+
def minimum_less_than_maximum(cls, v, values):
|
|
37
|
+
"""Validate that Minimum is less than or equal to Maximum."""
|
|
38
|
+
if hasattr(values, 'data') and 'Maximum' in values.data and v > values.data['Maximum']:
|
|
39
|
+
raise ValueError('Minimum must be less than or equal to Maximum')
|
|
40
|
+
return v
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class ECPULimits(BaseModel):
|
|
44
|
+
"""Limits for ECPU (ElastiCache Processing Units) in serverless configuration."""
|
|
45
|
+
|
|
46
|
+
Maximum: int = Field(..., description='Maximum ECPU per second', gt=0)
|
|
47
|
+
Minimum: int = Field(..., description='Minimum ECPU per second', gt=0)
|
|
48
|
+
|
|
49
|
+
@field_validator('Minimum')
|
|
50
|
+
def minimum_less_than_maximum(cls, v, values):
|
|
51
|
+
"""Validate that Minimum is less than or equal to Maximum."""
|
|
52
|
+
if hasattr(values, 'data') and 'Maximum' in values.data and v > values.data['Maximum']:
|
|
53
|
+
raise ValueError('Minimum must be less than or equal to Maximum')
|
|
54
|
+
return v
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class CacheUsageLimits(BaseModel):
|
|
58
|
+
"""Combined limits for data storage and ECPU in serverless configuration."""
|
|
59
|
+
|
|
60
|
+
DataStorage: DataStorageLimits = Field(..., description='Data storage limits configuration')
|
|
61
|
+
ECPUPerSecond: ECPULimits = Field(..., description='ECPU limits configuration')
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class Tag(BaseModel):
|
|
65
|
+
"""Tag model for ElastiCache resources."""
|
|
66
|
+
|
|
67
|
+
Key: str = Field(..., description='The key for the tag')
|
|
68
|
+
Value: Optional[str] = Field(None, description="The tag's value")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class CreateServerlessCacheRequest(BaseModel):
|
|
72
|
+
"""Request model for creating an ElastiCache serverless cache."""
|
|
73
|
+
|
|
74
|
+
serverless_cache_name: str = Field(..., description='The identifier of the serverless cache')
|
|
75
|
+
engine: str = Field(..., description='The name of the cache engine')
|
|
76
|
+
description: Optional[str] = Field(None, description='Description for the cache')
|
|
77
|
+
kms_key_id: Optional[str] = Field(None, description='KMS key ID for encryption')
|
|
78
|
+
major_engine_version: Optional[str] = Field(None, description='Major engine version')
|
|
79
|
+
snapshot_arns_to_restore: Optional[List[str]] = Field(
|
|
80
|
+
None, description='List of snapshot ARNs to restore from'
|
|
81
|
+
)
|
|
82
|
+
subnet_ids: Optional[List[str]] = Field(
|
|
83
|
+
None, description='List of subnet IDs for VPC configuration'
|
|
84
|
+
)
|
|
85
|
+
tags: Optional[Union[str, List[Tag], Dict[str, Optional[str]]]] = Field(
|
|
86
|
+
None,
|
|
87
|
+
description=(
|
|
88
|
+
'Tags to apply. Can be a string in Key=value format, '
|
|
89
|
+
'a list of Tag objects, or a dict of key-value pairs'
|
|
90
|
+
),
|
|
91
|
+
)
|
|
92
|
+
vpc_security_group_ids: Optional[List[str]] = Field(
|
|
93
|
+
None, description='List of VPC security group IDs'
|
|
94
|
+
)
|
|
95
|
+
cache_usage_limits: Optional[CacheUsageLimits] = Field(
|
|
96
|
+
None, description='Usage limits for the cache'
|
|
97
|
+
)
|
|
98
|
+
user_group_id: Optional[str] = Field(
|
|
99
|
+
None, description='ID of the user group to associate with the cache'
|
|
100
|
+
)
|
|
101
|
+
snapshot_retention_limit: Optional[int] = Field(
|
|
102
|
+
None, description='Number of days to retain automatic snapshots', ge=0
|
|
103
|
+
)
|
|
104
|
+
daily_snapshot_time: Optional[str] = Field(
|
|
105
|
+
None,
|
|
106
|
+
description="Time range (in UTC) when daily snapshots are taken (e.g., '04:00-05:00')",
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
@field_validator('daily_snapshot_time')
|
|
110
|
+
def validate_snapshot_time(cls, v):
|
|
111
|
+
"""Validate snapshot time format."""
|
|
112
|
+
if v is not None:
|
|
113
|
+
import re
|
|
114
|
+
|
|
115
|
+
if not re.match(r'^([0-1][0-9]|2[0-3]):[0-5][0-9]-([0-1][0-9]|2[0-3]):[0-5][0-9]$', v):
|
|
116
|
+
raise ValueError('Invalid time range format. Must be in format HH:MM-HH:MM')
|
|
117
|
+
return v
|
|
118
|
+
|
|
119
|
+
model_config = ConfigDict(validate_by_name=True, arbitrary_types_allowed=True)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class ModifyServerlessCacheRequest(BaseModel):
|
|
123
|
+
"""Request model for modifying an ElastiCache serverless cache."""
|
|
124
|
+
|
|
125
|
+
serverless_cache_name: str = Field(
|
|
126
|
+
..., description='The name of the serverless cache to modify'
|
|
127
|
+
)
|
|
128
|
+
description: Optional[str] = Field(None, description='New description for the cache')
|
|
129
|
+
major_engine_version: Optional[str] = Field(None, description='New major engine version')
|
|
130
|
+
snapshot_retention_limit: Optional[int] = Field(
|
|
131
|
+
None, description='Number of days to retain automatic snapshots', ge=0
|
|
132
|
+
)
|
|
133
|
+
daily_snapshot_time: Optional[str] = Field(
|
|
134
|
+
None,
|
|
135
|
+
description="Time range (in UTC) when daily snapshots are taken (e.g., '04:00-05:00')",
|
|
136
|
+
)
|
|
137
|
+
cache_usage_limits: Optional[CacheUsageLimits] = Field(
|
|
138
|
+
None, description='New usage limits for the cache'
|
|
139
|
+
)
|
|
140
|
+
remove_user_group: Optional[bool] = Field(
|
|
141
|
+
None, description='Whether to remove the user group association'
|
|
142
|
+
)
|
|
143
|
+
user_group_id: Optional[str] = Field(
|
|
144
|
+
None, description='ID of the user group to associate with the cache'
|
|
145
|
+
)
|
|
146
|
+
vpc_security_group_ids: Optional[List[str]] = Field(
|
|
147
|
+
None, description='List of VPC security group IDs'
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
@field_validator('daily_snapshot_time')
|
|
151
|
+
def validate_snapshot_time(cls, v):
|
|
152
|
+
"""Validate snapshot time format."""
|
|
153
|
+
if v is not None:
|
|
154
|
+
import re
|
|
155
|
+
|
|
156
|
+
if not re.match(r'^([0-1][0-9]|2[0-3]):[0-5][0-9]-([0-1][0-9]|2[0-3]):[0-5][0-9]$', v):
|
|
157
|
+
raise ValueError('Invalid time range format. Must be in format HH:MM-HH:MM')
|
|
158
|
+
return v
|
|
159
|
+
|
|
160
|
+
model_config = ConfigDict(validate_by_name=True, arbitrary_types_allowed=True)
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Modify serverless cache operations."""
|
|
16
|
+
|
|
17
|
+
from ...common.connection import ElastiCacheConnectionManager
|
|
18
|
+
from ...common.decorators import handle_exceptions
|
|
19
|
+
from ...common.server import mcp
|
|
20
|
+
from .models import ModifyServerlessCacheRequest
|
|
21
|
+
from typing import Dict
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@mcp.tool(name='modify_serverless_cache')
|
|
25
|
+
@handle_exceptions
|
|
26
|
+
async def modify_serverless_cache(request: ModifyServerlessCacheRequest) -> Dict:
|
|
27
|
+
"""Modify an Amazon ElastiCache serverless cache.
|
|
28
|
+
|
|
29
|
+
This tool modifies the configuration of an existing serverless cache including:
|
|
30
|
+
- Cache description
|
|
31
|
+
- Engine version
|
|
32
|
+
- Snapshot settings
|
|
33
|
+
- Usage limits
|
|
34
|
+
- Security groups
|
|
35
|
+
- User groups
|
|
36
|
+
|
|
37
|
+
Parameters:
|
|
38
|
+
serverless_cache_name (str): Name of the serverless cache to modify.
|
|
39
|
+
apply_immediately (Optional[bool]): Whether to apply changes immediately or during maintenance window.
|
|
40
|
+
description (Optional[str]): New description for the cache.
|
|
41
|
+
major_engine_version (Optional[str]): New major engine version.
|
|
42
|
+
snapshot_retention_limit (Optional[int]): Number of days for which ElastiCache retains automatic snapshots.
|
|
43
|
+
daily_snapshot_time (Optional[str]): Time range (in UTC) when daily snapshots are taken (e.g., '04:00-05:00').
|
|
44
|
+
cache_usage_limits (Optional[CacheUsageLimits]): New usage limits for the cache. Structure:
|
|
45
|
+
{
|
|
46
|
+
"DataStorage": {
|
|
47
|
+
"Maximum": int, # Maximum storage in GB
|
|
48
|
+
"Minimum": int, # Minimum storage in GB
|
|
49
|
+
"Unit": "GB" # Storage unit (currently only GB is supported)
|
|
50
|
+
},
|
|
51
|
+
"ECPUPerSecond": {
|
|
52
|
+
"Maximum": int, # Maximum ECPU per second
|
|
53
|
+
"Minimum": int # Minimum ECPU per second
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
security_group_ids (Optional[List[str]]): List of VPC security group IDs.
|
|
57
|
+
user_group_id (Optional[str]): ID of the user group to associate with the cache.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Dict containing information about the modified serverless cache.
|
|
61
|
+
"""
|
|
62
|
+
"""Modify an Amazon ElastiCache serverless cache.
|
|
63
|
+
|
|
64
|
+
This tool modifies the configuration of an existing serverless cache including:
|
|
65
|
+
- Cache description
|
|
66
|
+
- Engine version
|
|
67
|
+
- Snapshot settings
|
|
68
|
+
- Usage limits
|
|
69
|
+
- Security groups
|
|
70
|
+
- User groups
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
request: ModifyServerlessCacheRequest object containing modification parameters
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
Dict containing information about the modified serverless cache.
|
|
77
|
+
"""
|
|
78
|
+
# Get ElastiCache client
|
|
79
|
+
elasticache_client = ElastiCacheConnectionManager.get_connection()
|
|
80
|
+
|
|
81
|
+
# Convert request to dict and remove None values
|
|
82
|
+
modify_request = {k: v for k, v in request.model_dump().items() if v is not None}
|
|
83
|
+
|
|
84
|
+
# Convert snake_case to PascalCase for AWS API
|
|
85
|
+
aws_request = {}
|
|
86
|
+
for key, value in modify_request.items():
|
|
87
|
+
# Special handling for boolean values
|
|
88
|
+
if isinstance(value, bool):
|
|
89
|
+
aws_request[key.title().replace('_', '')] = str(value).lower()
|
|
90
|
+
else:
|
|
91
|
+
aws_request[key.title().replace('_', '')] = value
|
|
92
|
+
|
|
93
|
+
# Modify the cache
|
|
94
|
+
response = elasticache_client.modify_serverless_cache(**aws_request)
|
|
95
|
+
return response
|