From e8f1522d1a7365d2b8c6a78a7ee23c54386c3ea4 Mon Sep 17 00:00:00 2001 From: Brian Pandola Date: Sun, 14 Feb 2021 03:38:03 -0800 Subject: [PATCH] Improve autoscaling:CreateLaunchConfiguration request validation (#3687) AWS requires certain parameters to be mutually inclusive. Moto wasn't doing anything with the InstanceId parameter, which is now made clear with a TODO. --- moto/autoscaling/models.py | 12 ++++++++ moto/autoscaling/responses.py | 1 + .../test_launch_configurations.py | 30 +++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/moto/autoscaling/models.py b/moto/autoscaling/models.py index f4afd51be..4cfb8d7ac 100644 --- a/moto/autoscaling/models.py +++ b/moto/autoscaling/models.py @@ -616,7 +616,19 @@ class AutoScalingBackend(BaseBackend): ebs_optimized, associate_public_ip_address, block_device_mappings, + instance_id=None, ): + valid_requests = [ + instance_id is not None, + image_id is not None and instance_type is not None, + ] + if not any(valid_requests): + raise ValidationError( + "Valid requests must contain either the InstanceID parameter or both the ImageId and InstanceType parameters." + ) + if instance_id is not None: + # TODO: https://docs.aws.amazon.com/autoscaling/ec2/userguide/create-lc-with-instanceID.html + pass launch_configuration = FakeLaunchConfiguration( name=name, image_id=image_id, diff --git a/moto/autoscaling/responses.py b/moto/autoscaling/responses.py index a9651a774..638721a64 100644 --- a/moto/autoscaling/responses.py +++ b/moto/autoscaling/responses.py @@ -36,6 +36,7 @@ class AutoScalingResponse(BaseResponse): ebs_optimized=self._get_param("EbsOptimized"), associate_public_ip_address=self._get_param("AssociatePublicIpAddress"), block_device_mappings=self._get_list_prefix("BlockDeviceMappings.member"), + instance_id=self._get_param("InstanceId"), ) template = self.response_template(CREATE_LAUNCH_CONFIGURATION_TEMPLATE) return template.render() diff --git a/tests/test_autoscaling/test_launch_configurations.py b/tests/test_autoscaling/test_launch_configurations.py index 21e415bdd..f0d0c2efa 100644 --- a/tests/test_autoscaling/test_launch_configurations.py +++ b/tests/test_autoscaling/test_launch_configurations.py @@ -3,7 +3,9 @@ import boto import boto3 from boto.ec2.autoscale.launchconfig import LaunchConfiguration from boto.ec2.blockdevicemapping import BlockDeviceType, BlockDeviceMapping +from botocore.exceptions import ClientError +import pytest import sure # noqa from moto import mock_autoscaling_deprecated @@ -239,3 +241,31 @@ def test_launch_configuration_delete(): conn.delete_launch_configuration("tester") conn.get_all_launch_configurations().should.have.length_of(0) + + +@pytest.mark.parametrize( + "request_params", + [ + pytest.param( + {"LaunchConfigurationName": "test"}, + id="No InstanceId, ImageId, or InstanceType parameters", + ), + pytest.param( + {"LaunchConfigurationName": "test", "ImageId": "ami-test"}, + id="ImageId without InstanceType parameter", + ), + pytest.param( + {"LaunchConfigurationName": "test", "InstanceType": "t2.medium"}, + id="InstanceType without ImageId parameter", + ), + ], +) +@mock_autoscaling +def test_invalid_launch_configuration_request_raises_error(request_params): + client = boto3.client("autoscaling", region_name="us-east-1") + with pytest.raises(ClientError) as ex: + client.create_launch_configuration(**request_params) + ex.value.response["Error"]["Code"].should.equal("ValidationError") + ex.value.response["Error"]["Message"].should.match( + r"^Valid requests must contain.*" + )