From 44f0377cc478c6f5ed22e586cc0e4af291eb292b Mon Sep 17 00:00:00 2001 From: Steve Pulec Date: Sat, 28 Nov 2015 09:19:45 -0500 Subject: [PATCH] Fix root volume to show up in other EC2 volume API calls. Closes 470 --- CHANGELOG.md | 7 ++++++ moto/ec2/models.py | 23 +++++++++++++------ .../test_cloudformation_stack_integration.py | 8 ++++--- tests/test_ec2/test_amis.py | 3 ++- tests/test_ec2/test_instances.py | 9 ++++++-- 5 files changed, 37 insertions(+), 13 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..deed022fe --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7 @@ +Moto Changelog +=================== + +Latest +------ + + * Fix root instance volume to show up in other EBS volume calls \ No newline at end of file diff --git a/moto/ec2/models.py b/moto/ec2/models.py index cf45546fe..798325881 100644 --- a/moto/ec2/models.py +++ b/moto/ec2/models.py @@ -319,12 +319,6 @@ class Instance(BotoInstance, TaggedEC2Resource): # If we are in EC2-Classic, autoassign a public IP associate_public_ip = True - self.block_device_mapping = BlockDeviceMapping() - # Default have an instance with root volume should you not wish to override with attach volume cmd. - # However this is a ghost volume and wont show up in get_all_volumes or snapshot-able. - self.block_device_mapping['/dev/sda1'] = BlockDeviceType(volume_id=random_volume_id(), status='attached', - attach_time=utc_date_and_time()) - amis = self.ec2_backend.describe_images(filters={'image-id': image_id}) ami = amis[0] if amis else None @@ -345,11 +339,23 @@ class Instance(BotoInstance, TaggedEC2Resource): subnet = ec2_backend.get_subnet(self.subnet_id) self.vpc_id = subnet.vpc_id + self.block_device_mapping = BlockDeviceMapping() + self.prep_nics(kwargs.get("nics", {}), subnet_id=self.subnet_id, private_ip=kwargs.get("private_ip"), associate_public_ip=associate_public_ip) + def setup_defaults(self): + # Default have an instance with root volume should you not wish to override with attach volume cmd. + volume = self.ec2_backend.create_volume(8, 'us-east-1a') + self.ec2_backend.attach_volume(volume.id, self.id, '/dev/sda1') + + def teardown_defaults(self): + volume_id = self.block_device_mapping['/dev/sda1'].volume_id + self.ec2_backend.detach_volume(volume_id, self.id, '/dev/sda1') + self.ec2_backend.delete_volume(volume_id) + @property def get_block_device_mapping(self): return self.block_device_mapping.items() @@ -420,6 +426,8 @@ class Instance(BotoInstance, TaggedEC2Resource): for nic in self.nics.values(): nic.stop() + self.teardown_defaults() + self._state.name = "terminated" self._state.code = 48 @@ -546,6 +554,7 @@ class InstanceBackend(object): 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", [])) + self.reservations[new_reservation.id] = new_reservation for index in range(count): new_instance = Instance( self, @@ -555,7 +564,7 @@ class InstanceBackend(object): **kwargs ) new_reservation.instances.append(new_instance) - self.reservations[new_reservation.id] = new_reservation + new_instance.setup_defaults() return new_reservation def start_instances(self, instance_ids): diff --git a/tests/test_cloudformation/test_cloudformation_stack_integration.py b/tests/test_cloudformation/test_cloudformation_stack_integration.py index a38a1029b..29b5396e1 100644 --- a/tests/test_cloudformation/test_cloudformation_stack_integration.py +++ b/tests/test_cloudformation/test_cloudformation_stack_integration.py @@ -737,14 +737,16 @@ def test_single_instance_with_ebs_volume(): reservation = ec2_conn.get_all_instances()[0] ec2_instance = reservation.instances[0] - volume = ec2_conn.get_all_volumes()[0] + volumes = ec2_conn.get_all_volumes() + # Grab the mounted drive + volume = [volume for volume in volumes if volume.attach_data.device == '/dev/sdh'][0] volume.volume_state().should.equal('in-use') volume.attach_data.instance_id.should.equal(ec2_instance.id) stack = conn.describe_stacks()[0] resources = stack.describe_resources() - ebs_volume = [resource for resource in resources if resource.resource_type == 'AWS::EC2::Volume'][0] - ebs_volume.physical_resource_id.should.equal(volume.id) + ebs_volumes = [resource for resource in resources if resource.resource_type == 'AWS::EC2::Volume'] + ebs_volumes[0].physical_resource_id.should.equal(volume.id) @mock_cloudformation() diff --git a/tests/test_ec2/test_amis.py b/tests/test_ec2/test_amis.py index 71c47cf9a..aa921f149 100644 --- a/tests/test_ec2/test_amis.py +++ b/tests/test_ec2/test_amis.py @@ -28,6 +28,7 @@ def test_ami_create_and_delete(): image.architecture.should.equal(instance.architecture) image.kernel_id.should.equal(instance.kernel) image.platform.should.equal(instance.platform) + instance.terminate() # Validate auto-created volume and snapshot volumes = conn.get_all_volumes() @@ -61,6 +62,7 @@ def test_ami_copy(): instance = reservation.instances[0] source_image_id = conn.create_image(instance.id, "test-ami", "this is a test ami") + instance.terminate() source_image = conn.get_all_images(image_ids=[source_image_id])[0] # Boto returns a 'CopyImage' object with an image_id attribute here. Use the image_id to fetch the full info. @@ -481,4 +483,3 @@ def test_ami_attribute_error_cases(): cm.exception.code.should.equal('InvalidAMIID.NotFound') cm.exception.status.should.equal(400) cm.exception.request_id.should_not.be.none - diff --git a/tests/test_ec2/test_instances.py b/tests/test_ec2/test_instances.py index 2e9b9834a..0dda4eb9c 100644 --- a/tests/test_ec2/test_instances.py +++ b/tests/test_ec2/test_instances.py @@ -57,8 +57,13 @@ def test_instance_launch_and_terminate(): instances[0].vpc_id.should.equal(None) root_device_name = instances[0].root_device_name - instances[0].block_device_mapping[root_device_name].status.should.equal('attached') - instances[0].block_device_mapping[root_device_name].volume_id.should.match(r'vol-\w+') + instances[0].block_device_mapping[root_device_name].status.should.equal('in-use') + volume_id = instances[0].block_device_mapping[root_device_name].volume_id + volume_id.should.match(r'vol-\w+') + + volume = conn.get_all_volumes(volume_ids=[volume_id])[0] + volume.attach_data.instance_id.should.equal(instance.id) + volume.status.should.equal('in-use') conn.terminate_instances([instances[0].id])