diff options
author | Zuul <zuul@review.opendev.org> | 2020-04-14 14:38:26 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2020-04-14 14:38:26 +0000 |
commit | 3a390a2b71c94a23d37ec45e2464a74fb40447e1 (patch) | |
tree | dacecfcf3a2ef7777555d7a31a7886a09c6b7be1 | |
parent | 35a51e27df17e60357329e1018f3e1bbc5534174 (diff) | |
parent | 7c7a25aa1eda9b1815f12cce25dda0a840d562f1 (diff) | |
download | nova-3a390a2b71c94a23d37ec45e2464a74fb40447e1.tar.gz |
Merge "workarounds: Add option to locally attach RBD volumes on compute hosts"
-rw-r--r-- | lower-constraints.txt | 2 | ||||
-rw-r--r-- | nova/conf/workarounds.py | 28 | ||||
-rw-r--r-- | nova/tests/unit/virt/libvirt/volume/test_net.py | 50 | ||||
-rw-r--r-- | nova/virt/libvirt/volume/net.py | 58 | ||||
-rw-r--r-- | releasenotes/notes/workarounds-libvirt-rbd-host-block-devices-ca5e3c187342ab4d.yaml | 23 | ||||
-rw-r--r-- | requirements.txt | 2 |
6 files changed, 151 insertions, 12 deletions
diff --git a/lower-constraints.txt b/lower-constraints.txt index c8beee8dc3..dd0151fadc 100644 --- a/lower-constraints.txt +++ b/lower-constraints.txt @@ -63,7 +63,7 @@ netifaces==0.10.4 networkx==1.11 numpy==1.14.2 openstacksdk==0.35.0 -os-brick==2.6.2 +os-brick==3.0.1 os-client-config==1.29.0 os-resource-classes==0.4.0 os-service-types==1.7.0 diff --git a/nova/conf/workarounds.py b/nova/conf/workarounds.py index 4d315ebc81..366744ad23 100644 --- a/nova/conf/workarounds.py +++ b/nova/conf/workarounds.py @@ -290,12 +290,36 @@ Enabling this workaround option will cause Nova to use the legacy dm-crypt based os-brick encryptor to decrypt the LUKSv1 volume. Note that enabling this option while using volumes that do not provide a host -block device such as Ceph will result in a failure to either boot from or -attach the volume. +block device such as Ceph will result in a failure to boot from or attach the +volume to an instance. See the ``[workarounds]/rbd_block_device`` option for a +way to avoid this for RBD. Related options: * ``compute_driver`` (libvirt) +* ``rbd_block_device`` (workarounds) +"""), + cfg.BoolOpt('rbd_volume_local_attach', + default=False, + help=""" +Attach RBD Cinder volumes to the compute as host block devices. + +When enabled this option instructs os-brick to connect RBD volumes locally on +the compute host as block devices instead of natively through QEMU. + +This workaround does not currently support extending attached volumes. + +This can be used with the disable_native_luksv1 workaround configuration +option to avoid the recently discovered performance issues found within the +libgcrypt library. + +This workaround is temporary and will be removed during the W release once +all impacted distributions have been able to update their versions of the +libgcrypt library. + +Related options: +* ``compute_driver`` (libvirt) +* ``disable_qemu_native_luksv1`` (workarounds) """), ] diff --git a/nova/tests/unit/virt/libvirt/volume/test_net.py b/nova/tests/unit/virt/libvirt/volume/test_net.py index 0332afc3c2..25e0af7f39 100644 --- a/nova/tests/unit/virt/libvirt/volume/test_net.py +++ b/nova/tests/unit/virt/libvirt/volume/test_net.py @@ -221,7 +221,9 @@ class LibvirtNetVolumeDriverTestCase( def test_extend_volume(self): device_path = '/dev/fake-dev' - connection_info = {'data': {'device_path': device_path}} + connection_info = { + 'driver_volume_type': 'net', + 'data': {'device_path': device_path}} requested_size = 20 * pow(1024, 3) # 20GiB @@ -231,3 +233,49 @@ class LibvirtNetVolumeDriverTestCase( requested_size) self.assertEqual(requested_size, new_size) + + def test_libvirt_rbd_driver_block_connect(self): + self.flags(rbd_volume_local_attach=True, group='workarounds') + connection_info = self.rbd_connection(self.vol) + libvirt_driver = net.LibvirtNetVolumeDriver(self.fake_host) + libvirt_driver.connector.connect_volume = mock.MagicMock( + return_value = {'path': mock.sentinel.rbd_dev}) + libvirt_driver.connect_volume(connection_info, mock.sentinel.instance) + + # Assert that the connector is called correctly and device_path updated + libvirt_driver.connector.connect_volume.assert_called_once_with( + connection_info['data']) + + def test_libvirt_rbd_driver_block_disconnect(self): + self.flags(rbd_volume_local_attach=True, group='workarounds') + connection_info = self.rbd_connection(self.vol) + libvirt_driver = net.LibvirtNetVolumeDriver(self.fake_host) + libvirt_driver.connector.disconnect_volume = mock.MagicMock() + libvirt_driver.disconnect_volume(connection_info, + mock.sentinel.instance) + + # Assert that the connector is called correctly + libvirt_driver.connector.disconnect_volume.assert_called_once_with( + connection_info['data'], None) + + def test_libvirt_rbd_driver_block_config(self): + self.flags(rbd_volume_local_attach=True, group='workarounds') + connection_info = self.rbd_connection(self.vol) + connection_info['data']['device_path'] = '/dev/rbd0' + libvirt_driver = net.LibvirtNetVolumeDriver(self.fake_host) + conf = libvirt_driver.get_config(connection_info, self.disk_info) + + # Assert that the returned config is for a RBD block device + self.assertEqual('block', conf.source_type) + self.assertEqual('/dev/rbd0', conf.source_path) + self.assertEqual('native', conf.driver_io) + + def test_libvirt_rbd_driver_block_extend(self): + self.flags(rbd_volume_local_attach=True, group='workarounds') + connection_info = self.rbd_connection(self.vol) + libvirt_driver = net.LibvirtNetVolumeDriver(self.fake_host) + + # Assert NotImplementedError is raised for extend_volume + self.assertRaises(NotImplementedError, libvirt_driver.extend_volume, + connection_info, mock.sentinel.instance, + mock.sentinel.requested_size) diff --git a/nova/virt/libvirt/volume/net.py b/nova/virt/libvirt/volume/net.py index 1164395a4b..ef065c8f5a 100644 --- a/nova/virt/libvirt/volume/net.py +++ b/nova/virt/libvirt/volume/net.py @@ -10,9 +10,13 @@ # License for the specific language governing permissions and limitations # under the License. +from os_brick import exception as os_brick_exception +from os_brick import initiator +from os_brick.initiator import connector from oslo_log import log as logging import nova.conf +from nova import utils from nova.virt.libvirt.volume import volume as libvirt_volume @@ -25,6 +29,10 @@ class LibvirtNetVolumeDriver(libvirt_volume.LibvirtBaseVolumeDriver): def __init__(self, host): super(LibvirtNetVolumeDriver, self).__init__(host, is_block_dev=False) + self.connector = None + if CONF.workarounds.rbd_volume_local_attach: + self.connector = connector.InitiatorConnector.factory( + initiator.RBD, utils.get_root_helper(), do_local_attach=True) def _set_auth_config_rbd(self, conf, netdisk_properties): # The rbd volume driver in cinder sets auth_enabled if the rbd_user is @@ -67,11 +75,37 @@ class LibvirtNetVolumeDriver(libvirt_volume.LibvirtBaseVolumeDriver): # secret_type is always hard-coded to 'ceph' in cinder conf.auth_secret_type = netdisk_properties['secret_type'] - def get_config(self, connection_info, disk_info): - """Returns xml for libvirt.""" - conf = super(LibvirtNetVolumeDriver, - self).get_config(connection_info, disk_info) + def _use_rbd_volume_local_attach(self, connection_info): + return (connection_info['driver_volume_type'] == 'rbd' and + CONF.workarounds.rbd_volume_local_attach) + def connect_volume(self, connection_info, instance): + if self._use_rbd_volume_local_attach(connection_info): + LOG.debug("Calling os-brick to attach RBD Volume as block device", + instance=instance) + device_info = self.connector.connect_volume( + connection_info['data']) + LOG.debug("Attached RBD volume %s", device_info, instance=instance) + connection_info['data']['device_path'] = device_info['path'] + + def disconnect_volume(self, connection_info, instance): + if self._use_rbd_volume_local_attach(connection_info): + LOG.debug("calling os-brick to detach RBD Volume", + instance=instance) + try: + self.connector.disconnect_volume(connection_info['data'], None) + except os_brick_exception.VolumeDeviceNotFound as exc: + LOG.warning('Ignoring VolumeDeviceNotFound: %s', exc) + return + LOG.debug("Disconnected RBD Volume", instance=instance) + + def _get_block_config(self, conf, connection_info): + conf.source_type = "block" + conf.source_path = connection_info['data']['device_path'] + conf.driver_io = "native" + return conf + + def _get_net_config(self, conf, connection_info): netdisk_properties = connection_info['data'] conf.source_type = "network" conf.source_protocol = connection_info['driver_volume_type'] @@ -82,8 +116,18 @@ class LibvirtNetVolumeDriver(libvirt_volume.LibvirtBaseVolumeDriver): self._set_auth_config_rbd(conf, netdisk_properties) return conf + def get_config(self, connection_info, disk_info): + """Returns xml for libvirt.""" + conf = super(LibvirtNetVolumeDriver, + self).get_config(connection_info, disk_info) + if self._use_rbd_volume_local_attach(connection_info): + return self._get_block_config(conf, connection_info) + return self._get_net_config(conf, 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. + if self._use_rbd_volume_local_attach(connection_info): + raise NotImplementedError + # 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/releasenotes/notes/workarounds-libvirt-rbd-host-block-devices-ca5e3c187342ab4d.yaml b/releasenotes/notes/workarounds-libvirt-rbd-host-block-devices-ca5e3c187342ab4d.yaml new file mode 100644 index 0000000000..eb740d0ada --- /dev/null +++ b/releasenotes/notes/workarounds-libvirt-rbd-host-block-devices-ca5e3c187342ab4d.yaml @@ -0,0 +1,23 @@ +--- +other: + - | + The ``[workarounds]/rbd_volume_local_attach`` configuration option has been + introduced. This can be used by operators to ensure RBD volumes are + connected to compute hosts as block devices. This can be used with + the ``[worarounds]/disable_native_luksv1`` configuration option to + workaround recently discovered performance issues found within the + `libgcrypt library`__ used by QEMU when natively decrypting LUKSv1 + encrypted disks. + + This workaround does not currently support extending attached volumes. + + This workaround is temporary and will be removed during the W release once + all impacted distributions have been able to update their versions of the + libgcrypt library. + + .. warning:: Operators must ensure no instances are running on the compute + host before enabling this workaround. Any instances with attached RBD + volumes left running on the hosts will fail to migrate or stop after this + workaround has been enabled. + + .. __: https://bugzilla.redhat.com/show_bug.cgi?id=1762765 diff --git a/requirements.txt b/requirements.txt index 099f7cabd7..ac0404d081 100644 --- a/requirements.txt +++ b/requirements.txt @@ -53,7 +53,7 @@ rfc3986>=1.1.0 # Apache-2.0 oslo.middleware>=3.31.0 # Apache-2.0 psutil>=3.2.2 # BSD oslo.versionedobjects>=1.35.0 # Apache-2.0 -os-brick>=2.6.2 # Apache-2.0 +os-brick>=3.0.1 # Apache-2.0 os-resource-classes>=0.4.0 # Apache-2.0 os-traits>=2.2.0 # Apache-2.0 os-vif>=1.14.0 # Apache-2.0 |