From eab58069ea6afba875fb0a7d7ac68c7e83ebf14a Mon Sep 17 00:00:00 2001 From: Gaudenz Steinlin Date: Tue, 11 Sep 2018 16:09:27 +0200 Subject: [PATCH] Extend volume for libvirt network volumes (RBD) Implement support for extending RBD attached volumes using the libvirt network volume driver. This adds a new parameter "requested_size" to the extend_volume method. This is necessary because the new volume size can not be detected by libvirt for network volumes. All other volume types currently implementing the extend_volume call have a block device on the hypervisor which needs to be updated and can be polled for it's new size. For network volumes no such block device exists. Alternatively this could be implemented without a new parameter by calling into Ceph using os_brick to get the new size of the volume. This would make the LibvirtNetVolumeDriver Ceph specific. This also extends the logic to get the device_path for extending volumes in the libvirt driver. This is necessary as network volumes don't have the device path in the connection_info. The device_path is retrieved by matching the connection_info serial (= volume UUID) against all guest disks. Co-Authored-By: Jose Castro Leon Blueprint: extend-in-use-rbd-volumes Change-Id: I5698e451861828a8b1240d046d1610d8d37ca5a2 --- nova/compute/manager.py | 4 +- nova/tests/unit/compute/test_compute_mgr.py | 5 +- nova/tests/unit/virt/libvirt/test_driver.py | 87 +++++++++++++++++-- .../virt/libvirt/volume/test_fibrechannel.py | 9 +- .../unit/virt/libvirt/volume/test_iscsi.py | 9 +- .../unit/virt/libvirt/volume/test_net.py | 13 +++ .../unit/virt/libvirt/volume/test_scaleio.py | 3 +- .../unit/virt/libvirt/volume/test_storpool.py | 16 ++-- nova/tests/unit/virt/powervm/test_driver.py | 2 +- nova/virt/driver.py | 4 +- nova/virt/fake.py | 2 +- nova/virt/libvirt/driver.py | 27 ++++-- nova/virt/libvirt/volume/fibrechannel.py | 2 +- nova/virt/libvirt/volume/iscsi.py | 2 +- nova/virt/libvirt/volume/net.py | 6 ++ nova/virt/libvirt/volume/nvme.py | 2 +- nova/virt/libvirt/volume/scaleio.py | 2 +- nova/virt/libvirt/volume/storpool.py | 2 +- nova/virt/libvirt/volume/volume.py | 15 +++- nova/virt/powervm/driver.py | 3 +- ...d-in-use-rbd-volumes-8f334ce2a06ee247.yaml | 5 ++ 21 files changed, 181 insertions(+), 39 deletions(-) create mode 100644 releasenotes/notes/bp-extend-in-use-rbd-volumes-8f334ce2a06ee247.yaml diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 10a38511dad2..8bb5e2285566 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -52,6 +52,7 @@ from oslo_service import periodic_task from oslo_utils import excutils from oslo_utils import strutils from oslo_utils import timeutils +from oslo_utils import units import six from six.moves import range @@ -8048,7 +8049,8 @@ class ComputeManager(manager.Manager): try: self.driver.extend_volume(connection_info, - instance) + instance, + bdm.volume_size * units.Gi) except Exception as ex: LOG.warning('Extend volume failed, ' 'volume_id=%(volume_id)s, reason: %(msg)s', diff --git a/nova/tests/unit/compute/test_compute_mgr.py b/nova/tests/unit/compute/test_compute_mgr.py index ca0b9ca4c7e1..8544b9d666af 100644 --- a/nova/tests/unit/compute/test_compute_mgr.py +++ b/nova/tests/unit/compute/test_compute_mgr.py @@ -2965,6 +2965,7 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase): def test_extend_volume(self): inst_obj = objects.Instance(id=3, uuid=uuids.instance) connection_info = {'foo': 'bar'} + new_size = 20 bdm = objects.BlockDeviceMapping( source_type='volume', destination_type='volume', @@ -2982,13 +2983,13 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase): def do_test(bdm_save, bdm_get_by_vol_and_inst, extend_volume, volume_api): bdm_get_by_vol_and_inst.return_value = bdm - volume_api.get.return_value = {'size': 20} + volume_api.get.return_value = {'size': new_size} self.compute.extend_volume( self.context, inst_obj, uuids.volume_id) bdm_save.assert_called_once_with() extend_volume.assert_called_once_with( - connection_info, inst_obj) + connection_info, inst_obj, new_size * pow(1024, 3)) do_test() diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index f9a1ac31731a..85292a1b50b0 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -7997,9 +7997,11 @@ class LibvirtConnTestCase(test.NoDBTestCase, for state in (power_state.RUNNING, power_state.PAUSED): guest.get_power_state = mock.Mock(return_value=state) - drvr.extend_volume(connection_info, instance) + drvr.extend_volume(connection_info, + instance, new_size_in_kb * 1024) drvr._extend_volume.assert_called_with(connection_info, - instance) + instance, + new_size_in_kb * 1024) guest.get_block_device.assert_called_with('/fake') block_device.resize.assert_called_with(20480) @@ -8012,7 +8014,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, connection_info = {'driver_volume_type': 'fake'} self.assertRaises(exception.ExtendVolumeNotSupported, drvr.extend_volume, - connection_info, instance) + connection_info, instance, 0) def test_extend_volume_disk_not_found(self): drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) @@ -8031,7 +8033,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, drvr._host.get_guest = mock.Mock(return_value=guest) drvr._extend_volume = mock.Mock(return_value=new_size_in_kb) - drvr.extend_volume(connection_info, instance) + drvr.extend_volume(connection_info, instance, new_size_in_kb * 1024) def test_extend_volume_with_instance_not_found(self): drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) @@ -8046,7 +8048,7 @@ class LibvirtConnTestCase(test.NoDBTestCase, connection_info = {'driver_volume_type': 'fake'} self.assertRaises(exception.InstanceNotFound, drvr.extend_volume, - connection_info, instance) + connection_info, instance, 0) def test_extend_volume_with_libvirt_error(self): drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) @@ -8071,7 +8073,80 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.assertRaises(fakelibvirt.libvirtError, drvr.extend_volume, - connection_info, instance) + connection_info, instance, new_size_in_kb * 1024) + + def test_extend_volume_with_no_device_path_attribute(self): + drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) + instance = objects.Instance(**self.test_instance) + connection_info = { + 'serial': '58a84f6d-3f0c-4e19-a0af-eb657b790657', + 'driver_volume_type': 'fake', + 'data': {'cluster_name': 'fake', + 'auth_enabled': False, + 'volume_id': '58a84f6d-3f0c-4e19-a0af-eb657b790657', + 'access_mode': 'rw'} + } + new_size_in_kb = 20 * 1024 * 1024 + + guest = mock.Mock(spec='nova.virt.libvirt.guest.Guest') + # block_device + block_device = mock.Mock( + spec='nova.virt.libvirt.guest.BlockDevice') + block_device.resize = mock.Mock() + disk = mock.Mock( + spec='nova.virt.libvirt.config.LibvirtConfigGuestDisk', + serial='58a84f6d-3f0c-4e19-a0af-eb657b790657', + target_dev='vdb') + guest.get_block_device = mock.Mock(return_value=block_device) + guest.get_all_disks = mock.Mock(return_value=[disk]) + drvr._host.get_guest = mock.Mock(return_value=guest) + drvr._extend_volume = mock.Mock(return_value=new_size_in_kb) + + for state in (power_state.RUNNING, power_state.PAUSED): + guest.get_power_state = mock.Mock(return_value=state) + drvr.extend_volume(connection_info, instance, + new_size_in_kb * 1024) + drvr._extend_volume.assert_called_with(connection_info, + instance, + new_size_in_kb * 1024) + guest.get_block_device.assert_called_with('vdb') + block_device.resize.assert_called_with(20480) + + def test_extend_volume_no_disk_found_by_serial(self): + drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) + instance = objects.Instance(**self.test_instance) + connection_info = { + 'serial': '58a84f6d-3f0c-4e19-a0af-eb657b790657', + 'driver_volume_type': 'fake', + 'data': {'cluster_name': 'fake', + 'auth_enabled': False, + 'volume_id': '58a84f6d-3f0c-4e19-a0af-eb657b790657', + 'access_mode': 'rw'} + } + new_size_in_kb = 20 * 1024 * 1024 + + guest = mock.Mock(spec='nova.virt.libvirt.guest.Guest') + # block_device + block_device = mock.Mock( + spec='nova.virt.libvirt.guest.BlockDevice') + block_device.resize = mock.Mock() + disk = mock.Mock( + spec='nova.virt.libvirt.config.LibvirtConfigGuestDisk', + serial='12345678-abcd-abcd-abcd-0123456789012', + target_dev='vdb') + guest.get_block_device = mock.Mock(return_value=block_device) + guest.get_all_disks = mock.Mock(return_value=[disk]) + drvr._host.get_guest = mock.Mock(return_value=guest) + drvr._extend_volume = mock.Mock(return_value=new_size_in_kb) + guest.get_power_state = mock.Mock(return_value=power_state.RUNNING) + + self.assertRaises( + exception.VolumeNotFound, + drvr.extend_volume, + connection_info, + instance, + new_size_in_kb * 1024 + ) @mock.patch('os_brick.encryptors.get_encryption_metadata') @mock.patch('nova.virt.libvirt.driver.LibvirtDriver._get_volume_encryptor') diff --git a/nova/tests/unit/virt/libvirt/volume/test_fibrechannel.py b/nova/tests/unit/virt/libvirt/volume/test_fibrechannel.py index 4289ac5aefb6..89a59f2f1abc 100644 --- a/nova/tests/unit/virt/libvirt/volume/test_fibrechannel.py +++ b/nova/tests/unit/virt/libvirt/volume/test_fibrechannel.py @@ -68,13 +68,16 @@ class LibvirtFibreChannelVolumeDriverTestCase( def test_extend_volume(self): device_path = '/dev/fake-dev' connection_info = {'data': {'device_path': device_path}} + requested_size = 1 libvirt_driver = fibrechannel.LibvirtFibreChannelVolumeDriver( self.fake_host) - libvirt_driver.connector.extend_volume = mock.MagicMock(return_value=1) + libvirt_driver.connector.extend_volume = mock.MagicMock( + return_value=requested_size) new_size = libvirt_driver.extend_volume(connection_info, - mock.sentinel.instance) + mock.sentinel.instance, + requested_size) - self.assertEqual(1, new_size) + self.assertEqual(requested_size, new_size) libvirt_driver.connector.extend_volume.assert_called_once_with( connection_info['data']) diff --git a/nova/tests/unit/virt/libvirt/volume/test_iscsi.py b/nova/tests/unit/virt/libvirt/volume/test_iscsi.py index 2991ef1ac9b1..f8a64abea5f6 100644 --- a/nova/tests/unit/virt/libvirt/volume/test_iscsi.py +++ b/nova/tests/unit/virt/libvirt/volume/test_iscsi.py @@ -64,12 +64,15 @@ class LibvirtISCSIVolumeDriverTestCase( def test_extend_volume(self): device_path = '/dev/fake-dev' connection_info = {'data': {'device_path': device_path}} + requested_size = 1 libvirt_driver = iscsi.LibvirtISCSIVolumeDriver(self.fake_host) - libvirt_driver.connector.extend_volume = mock.MagicMock(return_value=1) + libvirt_driver.connector.extend_volume = mock.MagicMock( + return_value=requested_size) new_size = libvirt_driver.extend_volume(connection_info, - mock.sentinel.instance) + mock.sentinel.instance, + requested_size) - self.assertEqual(1, new_size) + self.assertEqual(requested_size, new_size) libvirt_driver.connector.extend_volume.assert_called_once_with( connection_info['data']) diff --git a/nova/tests/unit/virt/libvirt/volume/test_net.py b/nova/tests/unit/virt/libvirt/volume/test_net.py index 640c1709ded8..bea90a24dcfd 100644 --- a/nova/tests/unit/virt/libvirt/volume/test_net.py +++ b/nova/tests/unit/virt/libvirt/volume/test_net.py @@ -240,3 +240,16 @@ class LibvirtNetVolumeDriverTestCase( tree.find('./auth/secret').get('uuid')) libvirt_driver.disconnect_volume(connection_info, mock.sentinel.instance) + + def test_extend_volume(self): + device_path = '/dev/fake-dev' + connection_info = {'data': {'device_path': device_path}} + + requested_size = 20 * pow(1024, 3) # 20GiB + + libvirt_driver = net.LibvirtNetVolumeDriver(self.fake_host) + new_size = libvirt_driver.extend_volume(connection_info, + mock.sentinel.instance, + requested_size) + + self.assertEqual(requested_size, new_size) diff --git a/nova/tests/unit/virt/libvirt/volume/test_scaleio.py b/nova/tests/unit/virt/libvirt/volume/test_scaleio.py index 1c3aa23cdce5..bf42779b186d 100644 --- a/nova/tests/unit/virt/libvirt/volume/test_scaleio.py +++ b/nova/tests/unit/virt/libvirt/volume/test_scaleio.py @@ -71,4 +71,5 @@ class LibvirtScaleIOVolumeDriverTestCase( 'extend_volume', side_effect=brick_extend_vol): self.assertEqual(extended_vol_size, - sio.extend_volume(conn, mock.sentinel.instance)) + sio.extend_volume(conn, mock.sentinel.instance, + extended_vol_size)) diff --git a/nova/tests/unit/virt/libvirt/volume/test_storpool.py b/nova/tests/unit/virt/libvirt/volume/test_storpool.py index 96dd4894e3b2..d9df648f52aa 100644 --- a/nova/tests/unit/virt/libvirt/volume/test_storpool.py +++ b/nova/tests/unit/virt/libvirt/volume/test_storpool.py @@ -127,32 +127,34 @@ class LibvirtStorPoolVolumeDriverTestCase( ci_1 = self.conn_info('1') ci_2 = self.conn_info('2') + rs_1 = ci_1['data']['real_size'] + rs_2 = ci_2['data']['real_size'] self.assertRaises(MockStorPoolExc, libvirt_driver.extend_volume, - ci_1, mock.sentinel.instance) + ci_1, mock.sentinel.instance, rs_1) self.assertRaises(MockStorPoolExc, libvirt_driver.extend_volume, - ci_2, mock.sentinel.instance) + ci_2, mock.sentinel.instance, rs_2) libvirt_driver.connect_volume(ci_1, mock.sentinel.instance) self.assertStorpoolAttached(('1',)) - ns_1 = libvirt_driver.extend_volume(ci_1, mock.sentinel.instance) + ns_1 = libvirt_driver.extend_volume(ci_1, mock.sentinel.instance, rs_1) self.assertEqual(ci_1['data']['real_size'], ns_1) self.assertRaises(MockStorPoolExc, libvirt_driver.extend_volume, - ci_2, mock.sentinel.instance) + ci_2, mock.sentinel.instance, rs_2) libvirt_driver.connect_volume(ci_2, mock.sentinel.instance) self.assertStorpoolAttached(('1', '2')) - ns_1 = libvirt_driver.extend_volume(ci_1, mock.sentinel.instance) + ns_1 = libvirt_driver.extend_volume(ci_1, mock.sentinel.instance, rs_1) self.assertEqual(ci_1['data']['real_size'], ns_1) - ns_2 = libvirt_driver.extend_volume(ci_2, mock.sentinel.instance) + ns_2 = libvirt_driver.extend_volume(ci_2, mock.sentinel.instance, rs_2) self.assertEqual(ci_2['data']['real_size'], ns_2) self.assertRaises(MockStorPoolExc, @@ -168,7 +170,7 @@ class LibvirtStorPoolVolumeDriverTestCase( self.assertRaises(MockStorPoolExc, libvirt_driver.extend_volume, - ci_1, mock.sentinel.instance) + ci_1, mock.sentinel.instance, rs_1) libvirt_driver.disconnect_volume(ci_2, mock.sentinel.instance) self.assertDictEqual({}, test_attached) diff --git a/nova/tests/unit/virt/powervm/test_driver.py b/nova/tests/unit/virt/powervm/test_driver.py index 9f3cd9d8c736..b307c3b76714 100644 --- a/nova/tests/unit/virt/powervm/test_driver.py +++ b/nova/tests/unit/virt/powervm/test_driver.py @@ -587,7 +587,7 @@ class TestPowerVMDriver(test.NoDBTestCase): @mock.patch('nova.virt.powervm.volume.fcvscsi.FCVscsiVolumeAdapter') def test_extend_volume(self, mock_vscsi_adpt): mock_bdm = self._fake_bdms()['block_device_mapping'][0] - self.drv.extend_volume(mock_bdm.get('connection_info'), self.inst) + self.drv.extend_volume(mock_bdm.get('connection_info'), self.inst, 0) mock_vscsi_adpt.return_value.extend_volume.assert_called_once_with() def test_vol_drv_iter(self): diff --git a/nova/virt/driver.py b/nova/virt/driver.py index ff4748cc72c0..819d7dfde8d5 100644 --- a/nova/virt/driver.py +++ b/nova/virt/driver.py @@ -522,13 +522,15 @@ class ComputeDriver(object): """ raise NotImplementedError() - def extend_volume(self, connection_info, instance): + def extend_volume(self, connection_info, instance, requested_size): """Extend the disk attached to the instance. :param dict connection_info: The connection for the extended volume. :param nova.objects.instance.Instance instance: The instance whose volume gets extended. + :param int requested_size + The requested new size of the volume in bytes :return: None """ diff --git a/nova/virt/fake.py b/nova/virt/fake.py index 26a06eabdb30..488817edcc7e 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -326,7 +326,7 @@ class FakeDriver(driver.ComputeDriver): self._mounts[instance_name] = {} self._mounts[instance_name][mountpoint] = new_connection_info - def extend_volume(self, connection_info, instance): + def extend_volume(self, connection_info, instance, requested_size): """Extend the disk attached to the instance.""" pass diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 8668087b65bc..158b64751091 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -1266,9 +1266,10 @@ class LibvirtDriver(driver.ComputeDriver): driver_block_device.get_volume_id(connection_info), instance=instance) - def _extend_volume(self, connection_info, instance): + def _extend_volume(self, connection_info, instance, requested_size): vol_driver = self._get_volume_driver(connection_info) - return vol_driver.extend_volume(connection_info, instance) + return vol_driver.extend_volume(connection_info, instance, + requested_size) def _use_native_luks(self, encryption=None): """Is LUKS the required provider and native QEMU LUKS available @@ -1618,9 +1619,10 @@ class LibvirtDriver(driver.ComputeDriver): self._disconnect_volume(context, connection_info, instance, encryption=encryption) - def extend_volume(self, connection_info, instance): + def extend_volume(self, connection_info, instance, requested_size): try: - new_size = self._extend_volume(connection_info, instance) + new_size = self._extend_volume(connection_info, instance, + requested_size) except NotImplementedError: raise exception.ExtendVolumeNotSupported() @@ -1631,7 +1633,22 @@ class LibvirtDriver(driver.ComputeDriver): state = guest.get_power_state(self._host) active_state = state in (power_state.RUNNING, power_state.PAUSED) if active_state: - disk_path = connection_info['data']['device_path'] + if 'device_path' in connection_info['data']: + disk_path = connection_info['data']['device_path'] + else: + # Some drivers (eg. net) don't put the device_path + # into the connection_info. Match disks by their serial + # number instead + volume_id = driver_block_device.get_volume_id( + connection_info) + disk = next(iter([ + d for d in guest.get_all_disks() + if d.serial == volume_id + ]), None) + if not disk: + raise exception.VolumeNotFound(volume_id=volume_id) + disk_path = disk.target_dev + LOG.debug('resizing block device %(dev)s to %(size)u kb', {'dev': disk_path, 'size': new_size}) dev = guest.get_block_device(disk_path) diff --git a/nova/virt/libvirt/volume/fibrechannel.py b/nova/virt/libvirt/volume/fibrechannel.py index 8a304cd79d06..7a0cf5e843d4 100644 --- a/nova/virt/libvirt/volume/fibrechannel.py +++ b/nova/virt/libvirt/volume/fibrechannel.py @@ -75,7 +75,7 @@ class LibvirtFibreChannelVolumeDriver(libvirt_volume.LibvirtBaseVolumeDriver): super(LibvirtFibreChannelVolumeDriver, self).disconnect_volume(connection_info, instance) - def extend_volume(self, connection_info, instance): + def extend_volume(self, connection_info, instance, requested_size): """Extend the volume.""" LOG.debug("calling os-brick to extend FC Volume", instance=instance) new_size = self.connector.extend_volume(connection_info['data']) diff --git a/nova/virt/libvirt/volume/iscsi.py b/nova/virt/libvirt/volume/iscsi.py index 6a6d6f100615..9eb08b0a9063 100644 --- a/nova/virt/libvirt/volume/iscsi.py +++ b/nova/virt/libvirt/volume/iscsi.py @@ -80,7 +80,7 @@ class LibvirtISCSIVolumeDriver(libvirt_volume.LibvirtBaseVolumeDriver): super(LibvirtISCSIVolumeDriver, self).disconnect_volume(connection_info, instance) - def extend_volume(self, connection_info, instance): + def extend_volume(self, connection_info, instance, requested_size): """Extend the volume.""" LOG.debug("calling os-brick to extend iSCSI Volume", instance=instance) new_size = self.connector.extend_volume(connection_info['data']) diff --git a/nova/virt/libvirt/volume/net.py b/nova/virt/libvirt/volume/net.py index 3b432dea54c1..8faa61a67857 100644 --- a/nova/virt/libvirt/volume/net.py +++ b/nova/virt/libvirt/volume/net.py @@ -132,3 +132,9 @@ class LibvirtNetVolumeDriver(libvirt_volume.LibvirtBaseVolumeDriver): super(LibvirtNetVolumeDriver, self).disconnect_volume(connection_info, instance) self._delete_secret_by_name(connection_info) + + def extend_volume(self, connection_info, instance, requested_size): + # There is nothing to do for network volumes. Cinder already extended + # the volume and there is no local block device which needs to be + # refreshed. + return requested_size diff --git a/nova/virt/libvirt/volume/nvme.py b/nova/virt/libvirt/volume/nvme.py index 8d20ab10d5ec..4b4e701ed9aa 100644 --- a/nova/virt/libvirt/volume/nvme.py +++ b/nova/virt/libvirt/volume/nvme.py @@ -53,7 +53,7 @@ class LibvirtNVMEVolumeDriver(libvirt_volume.LibvirtVolumeDriver): super(LibvirtNVMEVolumeDriver, self).disconnect_volume(connection_info, instance) - def extend_volume(self, connection_info, instance): + def extend_volume(self, connection_info, instance, requested_size): """Extend the volume.""" LOG.debug("calling os-brick to extend NVMe Volume", instance=instance) new_size = self.connector.extend_volume(connection_info['data']) diff --git a/nova/virt/libvirt/volume/scaleio.py b/nova/virt/libvirt/volume/scaleio.py index 4195bc1096e2..2fa2ea3fcc54 100644 --- a/nova/virt/libvirt/volume/scaleio.py +++ b/nova/virt/libvirt/volume/scaleio.py @@ -62,7 +62,7 @@ class LibvirtScaleIOVolumeDriver(libvirt_volume.LibvirtBaseVolumeDriver): super(LibvirtScaleIOVolumeDriver, self).disconnect_volume( connection_info, instance) - def extend_volume(self, connection_info, instance): + def extend_volume(self, connection_info, instance, requested_size): LOG.debug("calling os-brick to extend ScaleIO Volume", instance=instance) new_size = self.connector.extend_volume(connection_info['data']) diff --git a/nova/virt/libvirt/volume/storpool.py b/nova/virt/libvirt/volume/storpool.py index a99589a6ca58..cc950186cab3 100644 --- a/nova/virt/libvirt/volume/storpool.py +++ b/nova/virt/libvirt/volume/storpool.py @@ -46,7 +46,7 @@ class LibvirtStorPoolVolumeDriver(libvirt_volume.LibvirtVolumeDriver): self.connector.disconnect_volume(connection_info['data'], None) LOG.debug("Detached StorPool volume", instance=instance) - def extend_volume(self, connection_info, instance): + def extend_volume(self, connection_info, instance, requested_size): """Extend the volume.""" LOG.debug("Extending StorPool volume %s", connection_info['data']['volume'], instance=instance) diff --git a/nova/virt/libvirt/volume/volume.py b/nova/virt/libvirt/volume/volume.py index aaffaa074c75..114887445efd 100644 --- a/nova/virt/libvirt/volume/volume.py +++ b/nova/virt/libvirt/volume/volume.py @@ -132,8 +132,19 @@ class LibvirtBaseVolumeDriver(object): """Disconnect the volume.""" pass - def extend_volume(self, connection_info, instance): - """Extend the volume.""" + def extend_volume(self, connection_info, instance, requested_size): + """Extend the volume. + + :param: connection_info: connection information about the volume + that has been extended. + :param: instance: instance connected to the newly extended volume. + :param: requested_size: new extended size (in bytes) for the volume to + be extended. + + :returns: the new size to use when resizing the disk in QEMU. + + Note: the requested_size parameter is not used by all volume drivers + """ raise NotImplementedError() diff --git a/nova/virt/powervm/driver.py b/nova/virt/powervm/driver.py index a153257ee721..d8f62954eaf6 100644 --- a/nova/virt/powervm/driver.py +++ b/nova/virt/powervm/driver.py @@ -634,12 +634,13 @@ class PowerVMDriver(driver.ComputeDriver): # Run the flow tf_base.run(flow, instance=instance) - def extend_volume(self, connection_info, instance): + def extend_volume(self, connection_info, instance, requested_size): """Extend the disk attached to the instance. :param dict connection_info: The connection for the extended volume. :param nova.objects.instance.Instance instance: The instance whose volume gets extended. + :param int requested_size: The requested new volume size in bytes. :return: None """ diff --git a/releasenotes/notes/bp-extend-in-use-rbd-volumes-8f334ce2a06ee247.yaml b/releasenotes/notes/bp-extend-in-use-rbd-volumes-8f334ce2a06ee247.yaml new file mode 100644 index 000000000000..4e81eb66656b --- /dev/null +++ b/releasenotes/notes/bp-extend-in-use-rbd-volumes-8f334ce2a06ee247.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + Adds support for extending RBD attached volumes using the libvirt network + volume driver.