From f087a6f77ef1338bb8d10943d2a18712220c3c44 Mon Sep 17 00:00:00 2001 From: Thang Pham Date: Sun, 27 Apr 2014 00:28:35 -0400 Subject: [PATCH] Update block_device_info to contain swap and ephemeral disks An ephemeral or swap disk is attached to an instance on boot as follows: nova boot --flavor FLAVOR --image IMAGE_ID --swap 512 --ephemeral size=2 INSTANCE. When a hard reboot is performed on the instance, nova fails to recreate the appropriate libvirt XML definition, containing the ephemeral disk. This is because the correct block_device_info dict that is passed to the compute manager's reboot_instance method does not contain swap or ephemeral disk key values that are necessary to recreate those disks. In addition to nova boot, the correct block_device_info dict is also needed by nova rebuild, reboot, resize, and migrate to recreate those disks. This patch updates _get_instance_volume_block_device_info (renamed _get_instance_block_device_info) to return the swap and ephemeral disk key values, in addition to the block_device_mapping it already returns today. Change-Id: Iec329d1c12a48ea90ba9d57decd0996fde6544f0 Closes-Bug: #1305423 --- nova/compute/manager.py | 67 ++++++++++------- nova/tests/compute/test_compute.py | 100 +++++++++++++++++++------ nova/tests/compute/test_compute_mgr.py | 10 +-- 3 files changed, 122 insertions(+), 55 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 35b11e754d..a48ad1c1ce 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -697,8 +697,8 @@ class ComputeManager(manager.Manager): try: network_info = self._get_instance_nw_info(context, instance) - bdi = self._get_instance_volume_block_device_info(context, - instance) + bdi = self._get_instance_block_device_info(context, + instance) destroy_disks = not (self._is_instance_storage_shared( context, instance)) except exception.InstanceNotFound: @@ -928,8 +928,8 @@ class ComputeManager(manager.Manager): power_on = (instance.system_metadata.get('old_vm_state') != vm_states.STOPPED) - block_dev_info = self._get_instance_volume_block_device_info( - context, instance) + block_dev_info = self._get_instance_block_device_info(context, + instance) self.driver.finish_revert_migration(context, instance, net_info, block_dev_info, power_on) @@ -959,8 +959,7 @@ class ComputeManager(manager.Manager): instance=instance) block_device_info = \ - self._get_instance_volume_block_device_info( - context, instance) + self._get_instance_block_device_info(context, instance) try: self.driver.resume_state_on_host_boot( @@ -1808,14 +1807,16 @@ class ComputeManager(manager.Manager): self.network_api.deallocate_for_instance( context, instance, requested_networks=requested_networks) - def _get_instance_volume_block_device_info(self, context, instance, - refresh_conn_info=False, - bdms=None): + def _get_instance_block_device_info(self, context, instance, + refresh_conn_info=False, + bdms=None): """Transform volumes to the driver block_device format.""" if not bdms: bdms = (block_device_obj.BlockDeviceMappingList. get_by_instance_uuid(context, instance['uuid'])) + swap = driver_block_device.convert_swap(bdms) + ephemerals = driver_block_device.convert_ephemerals(bdms) block_device_mapping = ( driver_block_device.convert_volumes(bdms) + driver_block_device.convert_snapshots(bdms) + @@ -1833,9 +1834,17 @@ class ComputeManager(manager.Manager): self.driver) if self.use_legacy_block_device_info: + swap = driver_block_device.legacy_block_devices(swap) + ephemerals = driver_block_device.legacy_block_devices(ephemerals) block_device_mapping = driver_block_device.legacy_block_devices( block_device_mapping) - return {'block_device_mapping': block_device_mapping} + + # Get swap out of the list + swap = driver_block_device.get_swap(swap) + + return {'swap': swap, + 'ephemerals': ephemerals, + 'block_device_mapping': block_device_mapping} # NOTE(mikal): No object_compat wrapper on this method because its # callers all pass objects already @@ -2134,7 +2143,7 @@ class ComputeManager(manager.Manager): # NOTE(vish) get bdms before destroying the instance vol_bdms = [bdm for bdm in bdms if bdm.is_volume] - block_device_info = self._get_instance_volume_block_device_info( + block_device_info = self._get_instance_block_device_info( context, instance, bdms=bdms) # NOTE(melwitt): attempt driver destroy before releasing ip, may @@ -2298,8 +2307,8 @@ class ComputeManager(manager.Manager): def _power_on(self, context, instance): network_info = self._get_instance_nw_info(context, instance) - block_device_info = self._get_instance_volume_block_device_info( - context, instance) + block_device_info = self._get_instance_block_device_info(context, + instance) self.driver.power_on(context, instance, network_info, block_device_info) @@ -2518,7 +2527,7 @@ class ComputeManager(manager.Manager): get_by_instance_uuid(context, instance.uuid)) block_device_info = \ - self._get_instance_volume_block_device_info( + self._get_instance_block_device_info( context, instance, bdms=bdms) def detach_block_devices(context, bdms): @@ -2612,8 +2621,8 @@ class ComputeManager(manager.Manager): context = context.elevated() LOG.audit(_("Rebooting instance"), context=context, instance=instance) - block_device_info = self._get_instance_volume_block_device_info( - context, instance) + block_device_info = self._get_instance_block_device_info(context, + instance) network_info = self._get_instance_nw_info(context, instance) @@ -3198,7 +3207,7 @@ class ComputeManager(manager.Manager): network_info = self._get_instance_nw_info(context, instance) bdms = (block_device_obj.BlockDeviceMappingList. get_by_instance_uuid(context, instance.uuid)) - block_device_info = self._get_instance_volume_block_device_info( + block_device_info = self._get_instance_block_device_info( context, instance, bdms=bdms) self.driver.destroy(context, instance, network_info, @@ -3260,7 +3269,7 @@ class ComputeManager(manager.Manager): self.network_api.setup_networks_on_host(context, instance, migration['source_compute']) - block_device_info = self._get_instance_volume_block_device_info( + block_device_info = self._get_instance_block_device_info( context, instance, refresh_conn_info=True) power_on = old_vm_state != vm_states.STOPPED @@ -3453,7 +3462,7 @@ class ComputeManager(manager.Manager): bdms = (block_device_obj.BlockDeviceMappingList. get_by_instance_uuid(context, instance.uuid)) - block_device_info = self._get_instance_volume_block_device_info( + block_device_info = self._get_instance_block_device_info( context, instance, bdms=bdms) disk_info = self.driver.migrate_disk_and_power_off( @@ -3539,7 +3548,7 @@ class ComputeManager(manager.Manager): context, instance, "finish_resize.start", network_info=network_info) - block_device_info = self._get_instance_volume_block_device_info( + block_device_info = self._get_instance_block_device_info( context, instance, refresh_conn_info=True) # NOTE(mriedem): If the original vm_state was STOPPED, we don't @@ -3748,7 +3757,7 @@ class ComputeManager(manager.Manager): LOG.audit(_('Resuming'), context=context, instance=instance) network_info = self._get_instance_nw_info(context, instance) - block_device_info = self._get_instance_volume_block_device_info( + block_device_info = self._get_instance_block_device_info( context, instance) self.driver.resume(context, instance, network_info, @@ -3834,8 +3843,8 @@ class ComputeManager(manager.Manager): current_power_state = self._get_power_state(context, instance) network_info = self._get_instance_nw_info(context, instance) - block_device_info = self._get_instance_volume_block_device_info( - context, instance) + block_device_info = self._get_instance_block_device_info(context, + instance) self.driver.destroy(context, instance, network_info, block_device_info) @@ -4495,7 +4504,7 @@ class ComputeManager(manager.Manager): required for live migration without shared storage. """ - block_device_info = self._get_instance_volume_block_device_info( + block_device_info = self._get_instance_block_device_info( context, instance, refresh_conn_info=True) network_info = self._get_instance_nw_info(context, instance) @@ -4594,7 +4603,7 @@ class ComputeManager(manager.Manager): ctxt, instance['uuid']) # Cleanup source host post live-migration - block_device_info = self._get_instance_volume_block_device_info( + block_device_info = self._get_instance_block_device_info( ctxt, instance, bdms) self.driver.post_live_migration(ctxt, instance, block_device_info, migrate_data) @@ -4706,8 +4715,8 @@ class ComputeManager(manager.Manager): self._notify_about_instance_usage( context, instance, "live_migration.post.dest.start", network_info=network_info) - block_device_info = self._get_instance_volume_block_device_info( - context, instance) + block_device_info = self._get_instance_block_device_info(context, + instance) self.driver.post_live_migration_at_destination(context, instance, network_info, @@ -4804,8 +4813,8 @@ class ComputeManager(manager.Manager): # NOTE(vish): The mapping is passed in so the driver can disconnect # from remote volumes if necessary - block_device_info = self._get_instance_volume_block_device_info( - context, instance) + block_device_info = self._get_instance_block_device_info(context, + instance) self.driver.rollback_live_migration_at_destination(context, instance, network_info, block_device_info) self._notify_about_instance_usage( diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py index a61a45fcc7..3ceec84893 100644 --- a/nova/tests/compute/test_compute.py +++ b/nova/tests/compute/test_compute.py @@ -2341,7 +2341,7 @@ class ComputeTestCase(BaseTestCase): fake_network.unset_stub_network_methods(self.stubs) self.mox.StubOutWithMock(self.compute, - '_get_instance_volume_block_device_info') + '_get_instance_block_device_info') self.mox.StubOutWithMock(self.compute, '_get_instance_nw_info') self.mox.StubOutWithMock(self.compute, '_notify_about_instance_usage') self.mox.StubOutWithMock(self.compute, '_instance_update') @@ -2393,7 +2393,7 @@ class ComputeTestCase(BaseTestCase): self.mox.StubOutWithMock(self.context, 'elevated') self.context.elevated().AndReturn(econtext) - self.compute._get_instance_volume_block_device_info( + self.compute._get_instance_block_device_info( econtext, instance).AndReturn(fake_block_dev_info) self.compute._get_instance_nw_info(econtext, instance).AndReturn( @@ -2540,7 +2540,7 @@ class ComputeTestCase(BaseTestCase): self._test_reboot(False, fail_reboot=True, fail_running=True) - def test_get_instance_volume_block_device_info_source_image(self): + def test_get_instance_block_device_info_source_image(self): bdms = block_device_obj.block_device_make_list(self.context, [fake_block_device.FakeDbBlockDeviceDict({ 'id': 3, @@ -2560,10 +2560,12 @@ class ComputeTestCase(BaseTestCase): return_value=bdms) ) as mock_get_by_instance: block_device_info = ( - self.compute._get_instance_volume_block_device_info( + self.compute._get_instance_block_device_info( self.context, self._create_fake_instance()) ) expected = { + 'swap': None, + 'ephemerals': [], 'block_device_mapping': [{ 'connection_info': { 'driver_volume_type': 'rbd' @@ -2575,7 +2577,7 @@ class ComputeTestCase(BaseTestCase): self.assertTrue(mock_get_by_instance.called) self.assertEqual(block_device_info, expected) - def test_get_instance_volume_block_device_info_passed_bdms(self): + def test_get_instance_block_device_info_passed_bdms(self): bdms = block_device_obj.block_device_make_list(self.context, [fake_block_device.FakeDbBlockDeviceDict({ 'id': 3, @@ -2589,10 +2591,12 @@ class ComputeTestCase(BaseTestCase): block_device_obj.BlockDeviceMappingList, 'get_by_instance_uuid')) as mock_get_by_instance: block_device_info = ( - self.compute._get_instance_volume_block_device_info( + self.compute._get_instance_block_device_info( self.context, self._create_fake_instance(), bdms=bdms) ) expected = { + 'swap': None, + 'ephemerals': [], 'block_device_mapping': [{ 'connection_info': { 'driver_volume_type': 'rbd' @@ -2604,6 +2608,57 @@ class ComputeTestCase(BaseTestCase): self.assertFalse(mock_get_by_instance.called) self.assertEqual(block_device_info, expected) + def test_get_instance_block_device_info_swap_and_ephemeral(self): + instance = self._create_fake_instance() + + ephemerals = fake_block_device.FakeDbBlockDeviceDict({ + 'id': 1, 'instance_uuid': 'fake-instance', + 'device_name': '/dev/vdb', + 'source_type': 'blank', + 'destination_type': 'local', + 'device_type': 'disk', + 'disk_bus': 'virtio', + 'delete_on_termination': True, + 'guest_format': None, + 'volume_size': 1, + 'boot_index': -1 + }) + swap = fake_block_device.FakeDbBlockDeviceDict({ + 'id': 2, 'instance_uuid': 'fake-instance', + 'device_name': '/dev/vdc', + 'source_type': 'blank', + 'destination_type': 'local', + 'device_type': 'disk', + 'disk_bus': 'virtio', + 'delete_on_termination': True, + 'guest_format': 'swap', + 'volume_size': 1, + 'boot_index': -1 + }) + + bdms = block_device_obj.block_device_make_list(self.context, + [swap, ephemerals]) + + with ( + mock.patch.object(block_device_obj.BlockDeviceMappingList, + 'get_by_instance_uuid', return_value=bdms) + ) as mock_get_by_instance_uuid: + expected_block_device_info = { + 'swap': {'device_name': '/dev/vdc', 'swap_size': 1}, + 'ephemerals': [{'device_name': '/dev/vdb', 'num': 0, 'size': 1, + 'virtual_name': 'ephemeral0'}], + 'block_device_mapping': [] + } + + block_device_info = ( + self.compute._get_instance_block_device_info( + self.context, instance) + ) + + mock_get_by_instance_uuid.assert_called_once_with(self.context, + instance.uuid) + self.assertEqual(expected_block_device_info, block_device_info) + def test_set_admin_password(self): # Ensure instance can have its admin password set. instance = jsonutils.to_primitive(self._create_fake_instance()) @@ -4059,7 +4114,7 @@ class ComputeTestCase(BaseTestCase): '_notify_about_instance_usage') self.mox.StubOutWithMock(self.compute.driver, 'finish_migration') self.mox.StubOutWithMock(self.compute, - '_get_instance_volume_block_device_info') + '_get_instance_block_device_info') self.mox.StubOutWithMock(migration, 'save') self.mox.StubOutWithMock(instance, 'save') self.mox.StubOutWithMock(self.context, 'elevated') @@ -4109,7 +4164,7 @@ class ComputeTestCase(BaseTestCase): self.context, instance, 'finish_resize.start', network_info='fake-nwinfo1') - self.compute._get_instance_volume_block_device_info( + self.compute._get_instance_block_device_info( self.context, instance, refresh_conn_info=True).AndReturn('fake-bdminfo') # nova.conf sets the default flavor to m1.small and the test @@ -4689,7 +4744,7 @@ class ComputeTestCase(BaseTestCase): mock.patch.object(block_device_obj.BlockDeviceMappingList, 'get_by_instance_uuid', return_value='fake_bdms'), mock.patch.object( - self.compute, '_get_instance_volume_block_device_info', + self.compute, '_get_instance_block_device_info', return_value='fake_bdinfo'), mock.patch.object(self.compute, '_terminate_volume_connections') ) as (mock_get_by_inst_uuid, mock_get_instance_vol_bdinfo, @@ -5066,7 +5121,8 @@ class ComputeTestCase(BaseTestCase): # creating mocks self.mox.StubOutWithMock(self.compute.driver, 'pre_live_migration') self.compute.driver.pre_live_migration(mox.IsA(c), mox.IsA(instance), - {'block_device_mapping': []}, + {'swap': None, 'ephemerals': [], + 'block_device_mapping': []}, mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg()) @@ -5308,7 +5364,8 @@ class ComputeTestCase(BaseTestCase): self.compute._post_live_migration(c, instance, dest) post_live_migration.assert_has_calls([ - mock.call(c, instance, {'block_device_mapping': []}, None)]) + mock.call(c, instance, {'swap': None, 'ephemerals': [], + 'block_device_mapping': []}, None)]) unfilter_instance.assert_has_calls([mock.call(instance, [])]) migration = {'source_compute': srchost, 'dest_compute': dest, } @@ -5350,7 +5407,7 @@ class ComputeTestCase(BaseTestCase): mock.patch.object(self.compute.instance_events, 'clear_events_for_instance'), mock.patch.object(self.compute, - '_get_instance_volume_block_device_info'), + '_get_instance_block_device_info'), mock.patch.object(block_device_obj.BlockDeviceMappingList, 'get_by_instance_uuid'), mock.patch.object(self.compute.driver, 'get_volume_connector'), @@ -5466,7 +5523,8 @@ class ComputeTestCase(BaseTestCase): self.mox.StubOutWithMock(self.compute.driver, 'rollback_live_migration_at_destination') self.compute.driver.rollback_live_migration_at_destination(c, - instance, [], {'block_device_mapping': []}) + instance, [], {'swap': None, 'ephemerals': [], + 'block_device_mapping': []}) # start test self.mox.ReplayAll() @@ -6145,7 +6203,7 @@ class ComputeTestCase(BaseTestCase): self.mox.StubOutWithMock(self.compute, '_get_instance_nw_info') self.mox.StubOutWithMock(self.compute, - '_get_instance_volume_block_device_info') + '_get_instance_block_device_info') self.mox.StubOutWithMock(self.compute, '_is_instance_storage_shared') self.mox.StubOutWithMock(self.compute.driver, 'destroy') @@ -6155,7 +6213,7 @@ class ComputeTestCase(BaseTestCase): self.compute._get_instance_nw_info(fake_context, evacuated_instance).AndReturn( 'fake_network_info') - self.compute._get_instance_volume_block_device_info( + self.compute._get_instance_block_device_info( fake_context, evacuated_instance).AndReturn('fake_bdi') self.compute._is_instance_storage_shared(fake_context, evacuated_instance).AndReturn(True) @@ -6192,7 +6250,7 @@ class ComputeTestCase(BaseTestCase): self.mox.StubOutWithMock(self.compute, '_get_instance_nw_info') self.mox.StubOutWithMock(self.compute, - '_get_instance_volume_block_device_info') + '_get_instance_block_device_info') self.mox.StubOutWithMock(self.compute.driver, 'check_instance_shared_storage_local') self.mox.StubOutWithMock(self.compute.compute_rpcapi, @@ -6206,7 +6264,7 @@ class ComputeTestCase(BaseTestCase): self.compute._get_instance_nw_info(fake_context, evacuated_instance).AndReturn( 'fake_network_info') - self.compute._get_instance_volume_block_device_info( + self.compute._get_instance_block_device_info( fake_context, evacuated_instance).AndReturn('fake_bdi') self.compute.driver.check_instance_shared_storage_local(fake_context, evacuated_instance).AndReturn({'filename': 'tmpfilename'}) @@ -6248,7 +6306,7 @@ class ComputeTestCase(BaseTestCase): self.mox.StubOutWithMock(self.compute, '_get_instance_nw_info') self.mox.StubOutWithMock(self.compute, - '_get_instance_volume_block_device_info') + '_get_instance_block_device_info') self.mox.StubOutWithMock(self.compute.driver, 'check_instance_shared_storage_local') self.mox.StubOutWithMock(self.compute.compute_rpcapi, @@ -6262,7 +6320,7 @@ class ComputeTestCase(BaseTestCase): self.compute._get_instance_nw_info(fake_context, evacuated_instance).AndReturn( 'fake_network_info') - self.compute._get_instance_volume_block_device_info( + self.compute._get_instance_block_device_info( fake_context, evacuated_instance).AndReturn('fake_bdi') self.compute.driver.check_instance_shared_storage_local(fake_context, evacuated_instance).AndRaise(NotImplementedError()) @@ -10140,13 +10198,13 @@ class ComputeRescheduleOrErrorTestCase(BaseTestCase): mock.patch.object(self.compute, '_get_instance_nw_info', side_effect=error), mock.patch.object(self.compute, - '_get_instance_volume_block_device_info'), + '_get_instance_block_device_info'), mock.patch.object(self.compute.driver, 'destroy'), mock.patch.object(self.compute, '_try_deallocate_network') ) as ( elevated_mock, _get_instance_nw_info_mock, - _get_instance_volume_block_device_info_mock, + _get_instance_block_device_info_mock, destroy_mock, _try_deallocate_network_mock ): diff --git a/nova/tests/compute/test_compute_mgr.py b/nova/tests/compute/test_compute_mgr.py index 4ade10e591..10d58d278b 100644 --- a/nova/tests/compute/test_compute_mgr.py +++ b/nova/tests/compute/test_compute_mgr.py @@ -286,7 +286,7 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase): self.mox.StubOutWithMock(self.compute.driver, 'resume_state_on_host_boot') self.mox.StubOutWithMock(self.compute, - '_get_instance_volume_block_device_info') + '_get_instance_block_device_info') self.mox.StubOutWithMock(self.compute, '_set_instance_error_state') self.compute._get_power_state(mox.IgnoreArg(), @@ -296,7 +296,7 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase): self.compute._get_power_state(mox.IgnoreArg(), instance).AndReturn(power_state.SHUTDOWN) self.compute.driver.plug_vifs(instance, mox.IgnoreArg()) - self.compute._get_instance_volume_block_device_info(mox.IgnoreArg(), + self.compute._get_instance_block_device_info(mox.IgnoreArg(), instance).AndReturn('fake-bdm') self.compute.driver.resume_state_on_host_boot(mox.IgnoreArg(), instance, mox.IgnoreArg(), @@ -350,7 +350,7 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase): self.mox.StubOutWithMock(self.compute.driver, 'finish_revert_migration') self.mox.StubOutWithMock(self.compute, - '_get_instance_volume_block_device_info') + '_get_instance_block_device_info') self.mox.StubOutWithMock(self.compute.driver, 'get_info') self.mox.StubOutWithMock(instance, 'save') self.mox.StubOutWithMock(self.compute, '_retry_reboot') @@ -360,7 +360,7 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase): compute_utils.get_nw_info_for_instance(instance).AndReturn( network_model.NetworkInfo()) self.compute.driver.plug_vifs(instance, []) - self.compute._get_instance_volume_block_device_info( + self.compute._get_instance_block_device_info( self.context, instance).AndReturn([]) self.compute.driver.finish_revert_migration(self.context, instance, [], [], power_on) @@ -1891,7 +1891,7 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase): mock.patch.object(self.instance, 'save'), mock.patch.object(self.compute, '_notify_about_instance_usage'), mock.patch.object(self.compute, - '_get_instance_volume_block_device_info', + '_get_instance_block_device_info', return_value=None), mock.patch.object(block_device_obj.BlockDeviceMappingList, 'get_by_instance_uuid',