use super::*;
impl ElastiCacheService {
pub(super) fn create_cache_subnet_group(
&self,
request: &AwsRequest,
) -> Result<AwsResponse, AwsServiceError> {
let name = required_query_param(request, "CacheSubnetGroupName")?;
let description = required_query_param(request, "CacheSubnetGroupDescription")?;
let subnet_ids = parse_query_list_param(request, "SubnetIds", "SubnetIdentifier");
if subnet_ids.is_empty() || subnet_ids.iter().any(|s| s.trim().is_empty()) {
return Err(AwsServiceError::aws_error(
StatusCode::BAD_REQUEST,
"InvalidSubnet",
"At least one subnet ID must be specified.".to_string(),
));
}
let mut accounts = self.state.write();
let state = accounts.get_or_create(&request.account_id);
if state.subnet_groups.contains_key(&name) {
return Err(AwsServiceError::aws_error(
StatusCode::BAD_REQUEST,
"CacheSubnetGroupAlreadyExists",
format!("Cache subnet group {name} already exists."),
));
}
let arn = format!(
"arn:aws:elasticache:{}:{}:subnetgroup:{}",
state.region, state.account_id, name
);
let vpc_id = format!(
"vpc-{:08x}",
name.as_bytes()
.iter()
.fold(0u32, |acc, &b| acc.wrapping_add(b as u32))
);
let group = CacheSubnetGroup {
cache_subnet_group_name: name.clone(),
cache_subnet_group_description: description,
vpc_id,
subnet_ids,
arn,
};
let xml = cache_subnet_group_xml(&group, &state.region);
state.register_arn(&group.arn);
state.subnet_groups.insert(name, group);
Ok(AwsResponse::xml(
StatusCode::OK,
query_response_xml(
"CreateCacheSubnetGroup",
ELASTICACHE_NS,
&format!("<CacheSubnetGroup>{xml}</CacheSubnetGroup>"),
&request.request_id,
),
))
}
pub(super) fn describe_cache_subnet_groups(
&self,
request: &AwsRequest,
) -> Result<AwsResponse, AwsServiceError> {
let group_name = optional_query_param(request, "CacheSubnetGroupName");
let max_records = optional_usize_param(request, "MaxRecords")?;
let marker = optional_query_param(request, "Marker");
let accounts = self.state.read();
let empty = ElastiCacheState::new(&request.account_id, &request.region);
let state = accounts.get(&request.account_id).unwrap_or(&empty);
let groups: Vec<&CacheSubnetGroup> = if let Some(ref name) = group_name {
match state.subnet_groups.get(name) {
Some(g) => vec![g],
None => {
return Err(AwsServiceError::aws_error(
StatusCode::NOT_FOUND,
"CacheSubnetGroupNotFoundFault",
format!("Cache subnet group {name} not found."),
));
}
}
} else {
let mut groups: Vec<&CacheSubnetGroup> = state.subnet_groups.values().collect();
groups.sort_by(|a, b| a.cache_subnet_group_name.cmp(&b.cache_subnet_group_name));
groups
};
let (page, next_marker) = paginate(&groups, marker.as_deref(), max_records);
let members_xml: String = page
.iter()
.map(|g| {
format!(
"<CacheSubnetGroup>{}</CacheSubnetGroup>",
cache_subnet_group_xml(g, &state.region)
)
})
.collect();
let marker_xml = next_marker
.map(|m| format!("<Marker>{}</Marker>", xml_escape(&m)))
.unwrap_or_default();
Ok(AwsResponse::xml(
StatusCode::OK,
query_response_xml(
"DescribeCacheSubnetGroups",
ELASTICACHE_NS,
&format!("<CacheSubnetGroups>{members_xml}</CacheSubnetGroups>{marker_xml}"),
&request.request_id,
),
))
}
pub(super) fn delete_cache_subnet_group(
&self,
request: &AwsRequest,
) -> Result<AwsResponse, AwsServiceError> {
let name = required_query_param(request, "CacheSubnetGroupName")?;
let mut accounts = self.state.write();
let state = accounts.get_or_create(&request.account_id);
if name == "default" {
return Err(AwsServiceError::aws_error(
StatusCode::BAD_REQUEST,
"CacheSubnetGroupInUse",
"Cannot delete default cache subnet group.".to_string(),
));
}
if let Some(group) = state.subnet_groups.remove(&name) {
state.tags.remove(&group.arn);
} else {
return Err(AwsServiceError::aws_error(
StatusCode::NOT_FOUND,
"CacheSubnetGroupNotFoundFault",
format!("Cache subnet group {name} not found."),
));
}
Ok(AwsResponse::xml(
StatusCode::OK,
query_response_xml(
"DeleteCacheSubnetGroup",
ELASTICACHE_NS,
"",
&request.request_id,
),
))
}
pub(super) fn modify_cache_subnet_group(
&self,
request: &AwsRequest,
) -> Result<AwsResponse, AwsServiceError> {
let name = required_query_param(request, "CacheSubnetGroupName")?;
let description = optional_query_param(request, "CacheSubnetGroupDescription");
let subnet_ids = parse_query_list_param(request, "SubnetIds", "SubnetIdentifier");
if subnet_ids.iter().any(|s| s.trim().is_empty()) {
return Err(AwsServiceError::aws_error(
StatusCode::BAD_REQUEST,
"InvalidSubnet",
"At least one subnet ID must be specified.".to_string(),
));
}
let mut accounts = self.state.write();
let state = accounts.get_or_create(&request.account_id);
let region = state.region.clone();
let group = state.subnet_groups.get_mut(&name).ok_or_else(|| {
AwsServiceError::aws_error(
StatusCode::NOT_FOUND,
"CacheSubnetGroupNotFoundFault",
format!("Cache subnet group {name} not found."),
)
})?;
if let Some(desc) = description {
group.cache_subnet_group_description = desc;
}
if !subnet_ids.is_empty() {
group.subnet_ids = subnet_ids;
}
let xml = cache_subnet_group_xml(group, ®ion);
Ok(AwsResponse::xml(
StatusCode::OK,
query_response_xml(
"ModifyCacheSubnetGroup",
ELASTICACHE_NS,
&format!("<CacheSubnetGroup>{xml}</CacheSubnetGroup>"),
&request.request_id,
),
))
}
}