diff --git a/moto/autoscaling/responses.py b/moto/autoscaling/responses.py index 32eb7b301..267db1f91 100644 --- a/moto/autoscaling/responses.py +++ b/moto/autoscaling/responses.py @@ -6,18 +6,11 @@ from .models import autoscaling_backend class AutoScalingResponse(BaseResponse): - - def _get_param(self, param_name): - return self.querystring.get(param_name, [None])[0] - def _get_int_param(self, param_name): value = self._get_param(param_name) if value is not None: return int(value) - def _get_multi_param(self, param_prefix): - return [value[0] for key, value in self.querystring.items() if key.startswith(param_prefix)] - def _get_list_prefix(self, param_prefix): results = [] param_index = 1 @@ -43,7 +36,7 @@ class AutoScalingResponse(BaseResponse): name=self._get_param('LaunchConfigurationName'), image_id=self._get_param('ImageId'), key_name=self._get_param('KeyName'), - security_groups=self._get_multi_param('SecurityGroups.member.'), + security_groups=self._get_multi_param('SecurityGroups.member'), user_data=self._get_param('UserData'), instance_type=self._get_param('InstanceType'), instance_monitoring=instance_monitoring, diff --git a/moto/core/responses.py b/moto/core/responses.py index 8e6c5bfcc..fee641843 100644 --- a/moto/core/responses.py +++ b/moto/core/responses.py @@ -66,6 +66,14 @@ class BaseResponse(object): def _get_param(self, param_name): return self.querystring.get(param_name, [None])[0] + def _get_multi_param(self, param_prefix): + if param_prefix.endswith("."): + prefix = param_prefix + else: + prefix = param_prefix + "." + return [value[0] for key, value in self.querystring.items() + if key.startswith(prefix)] + def metadata_response(request, full_url, headers): """ diff --git a/moto/ec2/models.py b/moto/ec2/models.py index 708756aff..d40c21f57 100644 --- a/moto/ec2/models.py +++ b/moto/ec2/models.py @@ -37,13 +37,16 @@ class InstanceState(object): class Instance(BotoInstance): - def __init__(self, image_id, user_data, security_groups): + def __init__(self, image_id, user_data, security_groups, **kwargs): super(Instance, self).__init__() self.id = random_instance_id() self.image_id = image_id self._state = InstanceState("running", 16) self.user_data = user_data self.security_groups = security_groups + self.instance_type = kwargs.get("instance_type", "m1.small") + self.subnet_id = kwargs.get("subnet_id") + self.key_name = kwargs.get("key_name") @classmethod def create_from_cloudformation_json(cls, resource_name, cloudformation_json): @@ -57,6 +60,9 @@ class Instance(BotoInstance): user_data=properties.get('UserData'), count=1, security_group_names=group_names, + instance_type=properties.get("InstanceType", "m1.small"), + subnet_id=properties.get("SubnetId"), + key_name=properties.get("KeyName"), ) return reservation.instances[0] @@ -96,16 +102,21 @@ class InstanceBackend(object): if instance.id == instance_id: return instance - def add_instances(self, image_id, count, user_data, security_group_names): + def add_instances(self, image_id, count, user_data, security_group_names, + **kwargs): new_reservation = Reservation() new_reservation.id = random_reservation_id() - security_groups = [self.get_security_group_from_name(name) for name in security_group_names] + security_groups = [self.get_security_group_from_name(name) + for name in security_group_names] + security_groups.extend(self.get_security_group_from_id(sg_id) + for sg_id in kwargs.pop("security_group_ids", [])) for index in range(count): new_instance = Instance( image_id, user_data, security_groups, + **kwargs ) new_reservation.instances.append(new_instance) self.reservations[new_reservation.id] = new_reservation diff --git a/moto/ec2/responses/instances.py b/moto/ec2/responses/instances.py index 13b23fd3f..12b52607f 100644 --- a/moto/ec2/responses/instances.py +++ b/moto/ec2/responses/instances.py @@ -8,9 +8,6 @@ from moto.ec2.exceptions import InvalidIdError class InstanceResponse(BaseResponse): - def _get_multi_param(self, param_prefix): - return [value[0] for key, value in self.querystring.items() if key.startswith(param_prefix)] - def describe_instances(self): instance_ids = instance_ids_from_querystring(self.querystring) if instance_ids: @@ -33,7 +30,14 @@ class InstanceResponse(BaseResponse): image_id = self.querystring.get('ImageId')[0] user_data = self.querystring.get('UserData') security_group_names = self._get_multi_param('SecurityGroup') - new_reservation = ec2_backend.add_instances(image_id, min_count, user_data, security_group_names) + security_group_ids = self._get_multi_param('SecurityGroupId') + instance_type = self.querystring.get("InstanceType", ["m1.small"])[0] + subnet_id = self.querystring.get("SubnetId", [None])[0] + key_name = self.querystring.get("KeyName", [None])[0] + new_reservation = ec2_backend.add_instances( + image_id, min_count, user_data, security_group_names, + instance_type=instance_type, subnet_id=subnet_id, + key_name=key_name, security_group_ids=security_group_ids) template = Template(EC2_RUN_INSTANCES) return template.render(reservation=new_reservation) @@ -110,8 +114,9 @@ EC2_RUN_INSTANCES = """ disabled - subnet-1a2b3c4d + {{ instance.subnet_id }} vpc-1a2b3c4d 10.0.0.12 46.51.219.63 diff --git a/moto/ec2/responses/spot_instances.py b/moto/ec2/responses/spot_instances.py index 2c3d61a40..5ce8ee122 100644 --- a/moto/ec2/responses/spot_instances.py +++ b/moto/ec2/responses/spot_instances.py @@ -13,9 +13,6 @@ class SpotInstances(BaseResponse): if value is not None: return int(value) - def _get_multi_param(self, param_prefix): - return [value[0] for key, value in self.querystring.items() if key.startswith(param_prefix)] - def cancel_spot_instance_requests(self): request_ids = self._get_multi_param('SpotInstanceRequestId') requests = ec2_backend.cancel_spot_instance_requests(request_ids) @@ -49,7 +46,7 @@ class SpotInstances(BaseResponse): launch_group = self._get_param('LaunchGroup') availability_zone_group = self._get_param('AvailabilityZoneGroup') key_name = self._get_param('LaunchSpecification.KeyName') - security_groups = self._get_multi_param('LaunchSpecification.SecurityGroup.') + security_groups = self._get_multi_param('LaunchSpecification.SecurityGroup') user_data = self._get_param('LaunchSpecification.UserData') instance_type = self._get_param('LaunchSpecification.InstanceType') placement = self._get_param('LaunchSpecification.Placement.AvailabilityZone') diff --git a/tests/test_ec2/test_instances.py b/tests/test_ec2/test_instances.py index 9b4cb601a..9a0cd19be 100644 --- a/tests/test_ec2/test_instances.py +++ b/tests/test_ec2/test_instances.py @@ -173,12 +173,54 @@ def test_user_data_with_run_instance(): @mock_ec2 -def test_run_instance_with_security_group(): +def test_run_instance_with_security_group_name(): conn = boto.connect_ec2('the_key', 'the_secret') group = conn.create_security_group('group1', "some description") - reservation = conn.run_instances('ami-1234abcd', security_groups=['group1']) + reservation = conn.run_instances('ami-1234abcd', + security_groups=['group1']) instance = reservation.instances[0] instance.groups[0].id.should.equal(group.id) instance.groups[0].name.should.equal("group1") + + +@mock_ec2 +def test_run_instance_with_security_group_id(): + conn = boto.connect_ec2('the_key', 'the_secret') + group = conn.create_security_group('group1', "some description") + + reservation = conn.run_instances('ami-1234abcd', + security_group_ids=[group.id]) + instance = reservation.instances[0] + + instance.groups[0].id.should.equal(group.id) + instance.groups[0].name.should.equal("group1") + + +@mock_ec2 +def test_run_instance_with_instance_type(): + conn = boto.connect_ec2('the_key', 'the_secret') + reservation = conn.run_instances('ami-1234abcd', instance_type="t1.micro") + instance = reservation.instances[0] + + instance.instance_type.should.equal("t1.micro") + + +@mock_ec2 +def test_run_instance_with_subnet(): + conn = boto.connect_ec2('the_key', 'the_secret') + reservation = conn.run_instances('ami-1234abcd', + subnet_id="subnet-abcd1234") + instance = reservation.instances[0] + + instance.subnet_id.should.equal("subnet-abcd1234") + + +@mock_ec2 +def test_run_instance_with_keypair(): + conn = boto.connect_ec2('the_key', 'the_secret') + reservation = conn.run_instances('ami-1234abcd', key_name="keypair_name") + instance = reservation.instances[0] + + instance.key_name.should.equal("keypair_name")