8000 fix error being returned when subnet does not exist · localstack/localstack@83da8ee · GitHub
[go: up one dir, main page]

Skip to content

Commit 83da8ee

Browse files
committed
fix error being returned when subnet does not exist
1 parent 3b6bee2 commit 83da8ee

File tree

5 files changed

+189
-4
lines changed

5 files changed

+189
-4
lines changed

localstack-core/localstack/services/lambda_/api_utils.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@
9595
ALIAS_REGEX = re.compile(r"(?!^[0-9]+$)(^[a-zA-Z0-9-_]+$)")
9696
# Permission statement id
9797
STATEMENT_ID_REGEX = re.compile(r"^[a-zA-Z0-9-_]+$")
98+
# Pattern for a valid SubnetId
99+
SUBNET_ID_REGEX = re.compile(r"^subnet-[0-9a-z]*$")
98100

99101

100102
URL_CHAR_SET = string.ascii_lowercase + string.digits

localstack-core/localstack/services/lambda_/provider.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@
147147
from localstack.services.lambda_.api_utils import (
148148
ARCHITECTURES,
149149
STATEMENT_ID_REGEX,
150+
SUBNET_ID_REGEX,
150151
function_locators_from_arn,
151152
)
152153
from localstack.services.lambda_.event_source_mapping.esm_config_factory import (
@@ -468,9 +469,16 @@ def _function_revision_id(resolved_fn: Function, resolved_qualifier: str) -> str
468469
return resolved_fn.versions[resolved_qualifier].config.revision_id
469470

470471
def _resolve_vpc_id(self, account_id: str, region_name: str, subnet_id: str) -> str:
471-
return connect_to(
472-
aws_access_key_id=account_id, region_name=region_name
473-
).ec2.describe_subnets(SubnetIds=[subnet_id])["Subnets"][0]["VpcId"]
472+
ec2_client = connect_to(aws_access_key_id=account_id, region_name=region_name).ec2
473+
try:
474+
return ec2_client.describe_subnets(SubnetIds=[subnet_id])["Subnets"][0]["VpcId"]
475+
except ec2_client.exceptions.ClientError as e:
476+
code = e.response["Error"]["Code"]
477+
message = e.response["Error"]["Message"]
478+
raise InvalidParameterValueException(
479+
f"Error occurred while DescribeSubnets. EC2 Error Code: {code}. EC2 Error Message: {message}",
480+
Type="User",
481+
)
474482

475483
def _build_vpc_config(
476484
self,
@@ -485,8 +493,14 @@ def _build_vpc_config(
485493
if subnet_ids is not None and len(subnet_ids) == 0:
486494
return VpcConfig(vpc_id="", security_group_ids=[], subnet_ids=[])
487495

496+
subnet_id = subnet_ids[0]
497+
if not bool(SUBNET_ID_REGEX.match(subnet_id)):
498+
raise ValidationException(
499+
f"1 validation error detected: Value '[{subnet_id}]' at 'vpcConfig.subnetIds' failed to satisfy constraint: Member must satisfy constraint: [Member must have length less than or equal to 1024, Member must have length greater than or equal to 0, Member must satisfy regular expression pattern: ^subnet-[0-9a-z]*$]"
500+
)
501+
488502
return VpcConfig(
489-
vpc_id=self._resolve_vpc_id(account_id, region_name, subnet_ids[0]),
503+
vpc_id=self._resolve_vpc_id(account_id, region_name, subnet_id),
490504
security_group_ids=vpc_config.get("SecurityGroupIds", []),
491505
subnet_ids=subnet_ids,
492506
)

tests/aws/services/lambda_/test_lambda_api.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1264,6 +1264,112 @@ def test_vpc_config(
12641264
"delete_vpcconfig_get_function_response", delete_vpcconfig_get_function_response
12651265
)
12661266

1267+
@markers.aws.validated
1268+
def test_invalid_vpc_config_subnet(
1269+
self, create_lambda_function, lambda_su_role, snapshot, aws_client, cleanups
1270+
):
1271+
"""
1272+
Test invalid "VpcConfig.SubnetIds" Property on the Lambda Function
1273+
"""
1274+
non_existent_subnet_id = f"subnet-{short_uid()}"
1275+
wrong_format_subnet_id = f"bad-format-{short_uid()}"
1276+
1277+
# AWS validates the Security Group first, so we need a valid one to test SubnetsIds
1278+
security_groups = aws_client.ec2.describe_security_groups(MaxResults=5)["SecurityGroups"]
1279+
security_group_id = security_groups[0]["GroupId"]
1280+
1281+
snapshot.add_transformer(snapshot.transform.regex(non_existent_subnet_id, "<subnet_id_1>"))
1282+
snapshot.add_transformer(snapshot.transform.regex(wrong_format_subnet_id, "<subnet_id_2>"))
1283+
1284+
zip_file_bytes = create_lambda_archive(load_file(TEST_LAMBDA_PYTHON_ECHO), get_content=True)
1285+
1286+
with pytest.raises(ClientError) as e:
1287+
aws_client.lambda_.create_function(
1288+
FunctionName=f"fn-{short_uid()}",
1289+
Handler="index.handler",
1290+
Code={"ZipFile": zip_file_bytes},
1291+
PackageType="Zip",
1292+
Role=lambda_su_role,
1293+
Runtime=Runtime.python3_12,
1294+
VpcConfig={
1295+
"SubnetIds": [non_existent_subnet_id],
1296+
"SecurityGroupIds": [security_group_id],
1297+
},
1298+
)
1299+
1300+
snapshot.match("create-response-non-existent-subnet-id", e.value.response)
1301+
1302+
with pytest.raises(ClientError) as e:
1303+
aws_client.lambda_.create_function(
1304+
FunctionName=f"fn-{short_uid()}",
1305+
Handler="index.handler",
1306+
Code={"ZipFile": zip_file_bytes},
1307+
PackageType="Zip",
1308+
Role=lambda_su_role,
1309+
Runtime=Runtime.python3_12,
1310+
VpcConfig={
1311+
"SubnetIds": [wrong_format_subnet_id],
1312+
"SecurityGroupIds": [security_group_id],
1313+
},
1314+
)
1315+
1316+
snapshot.match("create-response-invalid-format-subnet-id", e.value.response)
1317+
1318+
@markers.aws.validated
1319+
@pytest.mark.skipif(reason="Not yet implemented", condition=not is_aws_cloud())
1320+
def test_invalid_vpc_config_security_group(
1321+
self, create_lambda_function, lambda_su_role, snapshot, aws_client, cleanups
1322+
):
1323+
"""
1324+
Test invalid "VpcConfig.SecurityGroupIds" Property on the Lambda Function
1325+
"""
1326+
# TODO: maybe add validation of security group id, not currently validated in LocalStack
1327+
non_existent_sg_id = f"sg-{short_uid()}"
1328+
wrong_format_sg_id = f"bad-format-{short_uid()}"
1329+
# this way, we assert that SecurityGroups existence is validated before SubnetIds
1330+
subnet_id = f"subnet-{short_uid()}"
1331+
1332+
snapshot.add_transformer(
1333+
snapshot.transform.regex(non_existent_sg_id, "<security_group_id_1>")
1334+
)
1335+
snapshot.add_transformer(
1336+
snapshot.transform.regex(wrong_format_sg_id, "<security_group_id_2>")
1337+
)
1338+
1339+
zip_file_bytes = create_lambda_archive(load_file(TEST_LAMBDA_PYTHON_ECHO), get_content=True)
1340+
1341+
with pytest.raises(ClientError) as e:
1342+
aws_client.lambda_.create_function(
1343+
FunctionName=f"fn-{short_uid()}",
1344+
Handler="index.handler",
1345+
Code={"ZipFile": zip_file_bytes},
1346+
PackageType="Zip",
1347+
Role=lambda_su_role,
1348+
Runtime=Runtime.python3_12,
1349+
VpcConfig={
1350+
"SubnetIds": [subnet_id],
1351+
"SecurityGroupIds": [non_existent_sg_id],
1352+
},
1353+
)
1354+
1355+
snapshot.match("create-response-non-existent-security-group", e.value.response)
1356+
1357+
with pytest.raises(ClientError) as e:
1358+
aws_client.lambda_.create_function(
1359+
FunctionName=f"fn-{short_uid()}",
1360+
Handler="index.handler",
1361+
Code={"ZipFile": zip_file_bytes FE6D },
1362+
PackageType="Zip",
1363+
Role=lambda_su_role,
1364+
Runtime=Runtime.python3_12,
1365+
VpcConfig={
1366+
"SubnetIds": [subnet_id],
1367+
"SecurityGroupIds": [wrong_format_sg_id],
1368+
},
1369+
)
1370+
1371+
snapshot.match("create-response-invalid-format-security-group", e.value.response)
1372+
12671373
@markers.aws.validated
12681374
def test_invalid_invoke(self, aws_client, snapshot):
12691375
region_name = aws_client.lambda_.meta.region_name

tests/aws/services/lambda_/test_lambda_api.snapshot.json

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22258,5 +22258,59 @@
2225822258
}
2225922259
}
2226022260
}
22261+
},
22262+
"tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_invalid_vpc_config_subnet": {
22263+
"recorded-date": "20-02-2025, 17:53:33",
22264+
"recorded-content": {
22265+
"create-response-non-existent-subnet-id": {
22266+
"Error": {
22267+
"Code": "InvalidParameterValueException",
22268+
"Message": "Error occurred while DescribeSubnets. EC2 Error Code: InvalidSubnetID.NotFound. EC2 Error Message: The subnet ID '<subnet_id_1>' does not exist"
22269+
},
22270+
"Type": "User",
22271+
"message": "Error occurred while DescribeSubnets. EC2 Error Code: InvalidSubnetID.NotFound. EC2 Error Message: The subnet ID '<subnet_id_1>' does not exist",
22272+
"ResponseMetadata": {
22273+
"HTTPHeaders": {},
22274+
"HTTPStatusCode": 400
22275+
}
22276+
},
22277+
"create-response-invalid-format-subnet-id": {
22278+
"Error": {
22279+
"Code": "ValidationException",
22280+
"Message": "1 validation error detected: Value '[<subnet_id_2>]' at 'vpcConfig.subnetIds' failed to satisfy constraint: Member must satisfy constraint: [Member must have length less than or equal to 1024, Member must have length greater than or equal to 0, Member must satisfy regular expression pattern: ^subnet-[0-9a-z]*$]"
22281+
},
22282+
"ResponseMetadata": {
22283+
"HTTPHeaders": {},
22284+
"HTTPStatusCode": 400
22285+
}
22286+
}
22287+
}
22288+
},
22289+
"tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_invalid_vpc_config_security_group": {
22290+
"recorded-date": "20-02-2025, 17:57:29",
22291+
"recorded-content": {
22292+
"create-response-non-existent-security-group": {
22293+
"Error": {
22294+
"Code": "InvalidParameterValueException",
22295+
"Message": "Error occurred while DescribeSecurityGroups. EC2 Error Code: InvalidGroup.NotFound. EC2 Error Message: The security group '<security_group_id_1>' does not exist"
22296+
},
22297+
"Type": "User",
22298+
"message": "Error occurred while DescribeSecurityGroups. EC2 Error Code: InvalidGroup.NotFound. EC2 Error Message: The security group '<security_group_id_1>' does not exist",
22299+
"ResponseMetadata": {
22300+
"HTTPHeaders": {},
22301+
"HTTPStatusCode": 400
22302+
}
22303+
},
22304+
"create-response-invalid-format-security-group": {
22305+
"Error": {
22306+
"Code": "ValidationException",
22307+
"Message": "1 validation error detected: Value '[<security_group_id_2>]' at 'vpcConfig.securityGroupIds' failed to satisfy constraint: Member must satisfy constraint: [Member must have length less than or equal to 1024, Member must have length greater than or equal to 0, Member must satisfy regular expression pattern: ^sg-[0-9a-zA-Z]*$]"
22308+
},
22309+
"ResponseMetadata": {
22310+
"HTTPHeaders": {},
22311+
"HTTPStatusCode": 400
22312+
}
22313+
}
22314+
}
2226122315
}
2226222316
}

tests/aws/services/lambda_/test_lambda_api.validation.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,15 @@
356356
"tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_invalid_invoke": {
357357
"last_validated_date": "2024-09-12T11:34:43+00:00"
358358
},
359+
"tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_invalid_vpc_config": {
360+
"last_validated_date": "2025-02-20T17:44:18+00:00"
361+
},
362+
"tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_invalid_vpc_config_security_group": {
363+
"last_validated_date": "2025-02-20T17:57:29+00:00"
364+
},
365+
"tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_invalid_vpc_config_subnet": {
366+
"last_validated_date": "2025-02-20T17:53:33+00:00"
367+
},
359368
"tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_lambda_code_location_s3": {
360369
"last_validated_date": "2024-09-12T11:29:56+00:00"
361370
},

0 commit comments

Comments
 (0)
0