workarounds: Add option to locally attach RBD volumes on compute hosts
Building on the ``[workarounds]/disable_native_luksv1`` configurable introduced in Ia500eb614cf575ab846f64f4b69c9068274c8c1f this change introduces another workaround configurable that when enabled will connect RBD volumes to the compute host as block devices using os-brick. When used togther both options allow operators to workaround recently discovered performance issues in the libgcrypt library used by QEMU when natively decrypting LUKSv1 encrypted disks. For now the extend_volume method raises a NotImplemented error in-line with the underlying method in os-brick. Future work will be required to both support this in os-brick and wire up the required calls in the volume driver. 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. Finally os-brick 3.0.1 is now required as it provides the Id507109df80391699074773f4787f74507c4b882 fix when attempting to diconnect locally attached RBD volumes. Closes-Bug: #1869184 Change-Id: Ied3732042738a6194b635c55e0304d71a6fb66e3
This commit is contained in:
parent
dbb58e964a
commit
7c7a25aa1e
@ -62,7 +62,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
|
||||
|
@ -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)
|
||||
"""),
|
||||
]
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user