Merge "Fixes multi-registry config in Quobyte driver" into stable/queens

This commit is contained in:
Zuul 2019-10-29 23:18:40 +00:00 committed by Gerrit Code Review
commit 0f0693f0d8
4 changed files with 59 additions and 38 deletions

View File

@ -342,6 +342,10 @@ class InvalidVolumeAccessMode(Invalid):
msg_fmt = _("Invalid volume access mode: %(access_mode)s") msg_fmt = _("Invalid volume access mode: %(access_mode)s")
class StaleVolumeMount(InvalidVolume):
msg_fmt = _("The volume mount at %(mount_path)s is unusable.")
class InvalidMetadata(Invalid): class InvalidMetadata(Invalid):
msg_fmt = _("Invalid metadata: %(reason)s") msg_fmt = _("Invalid metadata: %(reason)s")

View File

@ -294,13 +294,15 @@ class LibvirtQuobyteVolumeDriverTestCase(
test_volume.LibvirtVolumeBaseTestCase): test_volume.LibvirtVolumeBaseTestCase):
"""Tests the LibvirtQuobyteVolumeDriver class.""" """Tests the LibvirtQuobyteVolumeDriver class."""
@mock.patch.object(quobyte, 'umount_volume')
@mock.patch.object(quobyte, 'validate_volume') @mock.patch.object(quobyte, 'validate_volume')
@mock.patch.object(quobyte, 'mount_volume') @mock.patch.object(quobyte, 'mount_volume')
@mock.patch.object(libvirt_utils, 'is_mounted', return_value=False) @mock.patch.object(libvirt_utils, 'is_mounted', return_value=False)
def test_libvirt_quobyte_driver_mount(self, def test_libvirt_quobyte_driver_mount(self,
mock_is_mounted, mock_is_mounted,
mock_mount_volume, mock_mount_volume,
mock_validate_volume mock_validate_volume,
mock_umount_volume
): ):
mnt_base = '/mnt' mnt_base = '/mnt'
self.flags(quobyte_mount_point_base=mnt_base, group='libvirt') self.flags(quobyte_mount_point_base=mnt_base, group='libvirt')
@ -314,6 +316,9 @@ class LibvirtQuobyteVolumeDriverTestCase(
connection_info = {'data': {'export': export_string, connection_info = {'data': {'export': export_string,
'name': self.name}} 'name': self.name}}
mock_validate_volume.side_effect = [nova_exception.StaleVolumeMount(
"This shall fail."), True, True]
libvirt_driver.connect_volume(connection_info, mock.sentinel.instance) libvirt_driver.connect_volume(connection_info, mock.sentinel.instance)
conf = libvirt_driver.get_config(connection_info, self.disk_info) conf = libvirt_driver.get_config(connection_info, self.disk_info)
@ -325,12 +330,12 @@ class LibvirtQuobyteVolumeDriverTestCase(
export_mnt_base, export_mnt_base,
mock.ANY) mock.ANY)
mock_validate_volume.assert_called_with(export_mnt_base) mock_validate_volume.assert_called_with(export_mnt_base)
mock_umount_volume.assert_called_once_with(
libvirt_driver._get_mount_path(connection_info))
@mock.patch.object(quobyte, 'validate_volume') @mock.patch.object(quobyte, 'validate_volume', return_value=True)
@mock.patch.object(quobyte, 'umount_volume') @mock.patch.object(quobyte, 'umount_volume')
@mock.patch.object(libvirt_utils, 'is_mounted', return_value=True) def test_libvirt_quobyte_driver_umount(self, mock_umount_volume,
def test_libvirt_quobyte_driver_umount(self, mock_is_mounted,
mock_umount_volume,
mock_validate_volume): mock_validate_volume):
mnt_base = '/mnt' mnt_base = '/mnt'
self.flags(quobyte_mount_point_base=mnt_base, group='libvirt') self.flags(quobyte_mount_point_base=mnt_base, group='libvirt')
@ -353,7 +358,9 @@ class LibvirtQuobyteVolumeDriverTestCase(
libvirt_driver.disconnect_volume(connection_info, libvirt_driver.disconnect_volume(connection_info,
mock.sentinel.instance) mock.sentinel.instance)
mock_validate_volume.assert_called_once_with(export_mnt_base) mock_validate_volume.assert_has_calls([mock.call(export_mnt_base),
mock.call(export_mnt_base),
mock.call(export_mnt_base)])
mock_umount_volume.assert_called_once_with(export_mnt_base) mock_umount_volume.assert_called_once_with(export_mnt_base)
@mock.patch.object(quobyte, 'validate_volume') @mock.patch.object(quobyte, 'validate_volume')
@ -386,15 +393,14 @@ class LibvirtQuobyteVolumeDriverTestCase(
mock.sentinel.instance) mock.sentinel.instance)
mock_umount_volume.assert_called_once_with(export_mnt_base) mock_umount_volume.assert_called_once_with(export_mnt_base)
mock_validate_volume.assert_called_once_with(export_mnt_base) mock_validate_volume.assert_has_calls([mock.call(export_mnt_base),
mock.call(export_mnt_base)])
@mock.patch.object(quobyte, 'umount_volume')
@mock.patch.object(quobyte, 'validate_volume') @mock.patch.object(quobyte, 'validate_volume')
@mock.patch.object(quobyte, 'mount_volume') @mock.patch.object(quobyte, 'mount_volume')
@mock.patch.object(libvirt_utils, 'is_mounted', return_value=False) def test_libvirt_quobyte_driver_qcow2(self, mock_mount_volume,
def test_libvirt_quobyte_driver_qcow2(self, mock_is_mounted, mock_validate_volume, mock_umount):
mock_mount_volume,
mock_validate_volume
):
mnt_base = '/mnt' mnt_base = '/mnt'
self.flags(quobyte_mount_point_base=mnt_base, group='libvirt') self.flags(quobyte_mount_point_base=mnt_base, group='libvirt')
libvirt_driver = quobyte.LibvirtQuobyteVolumeDriver(self.fake_host) libvirt_driver = quobyte.LibvirtQuobyteVolumeDriver(self.fake_host)
@ -409,6 +415,8 @@ class LibvirtQuobyteVolumeDriverTestCase(
export_mnt_base = os.path.join(mnt_base, export_mnt_base = os.path.join(mnt_base,
utils.get_hash_str(quobyte_volume)) utils.get_hash_str(quobyte_volume))
mock_validate_volume.side_effect = [nova_exception.StaleVolumeMount(
"This shall fail."), True, True]
libvirt_driver.connect_volume(connection_info, mock.sentinel.instance) libvirt_driver.connect_volume(connection_info, mock.sentinel.instance)
conf = libvirt_driver.get_config(connection_info, self.disk_info) conf = libvirt_driver.get_config(connection_info, self.disk_info)
@ -424,6 +432,8 @@ class LibvirtQuobyteVolumeDriverTestCase(
libvirt_driver.disconnect_volume(connection_info, libvirt_driver.disconnect_volume(connection_info,
mock.sentinel.instance) mock.sentinel.instance)
mock_umount.assert_has_calls([mock.call(export_mnt_base),
mock.call(export_mnt_base)])
@mock.patch.object(libvirt_utils, 'is_mounted', return_value=True) @mock.patch.object(libvirt_utils, 'is_mounted', return_value=True)
def test_libvirt_quobyte_driver_mount_non_quobyte_volume(self, def test_libvirt_quobyte_driver_mount_non_quobyte_volume(self,

View File

@ -13,7 +13,6 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import errno
import os import os
from oslo_concurrency import processutils from oslo_concurrency import processutils
@ -26,7 +25,6 @@ import nova.conf
from nova import exception as nova_exception from nova import exception as nova_exception
from nova.i18n import _ from nova.i18n import _
from nova import utils from nova import utils
from nova.virt.libvirt import utils as libvirt_utils
from nova.virt.libvirt.volume import fs from nova.virt.libvirt.volume import fs
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -75,7 +73,10 @@ def umount_volume(mnt_base):
def validate_volume(mount_path): def validate_volume(mount_path):
"""Runs a number of tests to be sure this is a (working) Quobyte mount""" """Determine if the volume is a valid Quobyte mount.
Runs a number of tests to be sure this is a (working) Quobyte mount
"""
partitions = psutil.disk_partitions(all=True) partitions = psutil.disk_partitions(all=True)
for p in partitions: for p in partitions:
if mount_path != p.mountpoint: if mount_path != p.mountpoint:
@ -90,10 +91,10 @@ def validate_volume(mount_path):
msg = (_("The mount %(mount_path)s is not a " msg = (_("The mount %(mount_path)s is not a "
"valid Quobyte volume. Stale mount?") "valid Quobyte volume. Stale mount?")
% {'mount_path': mount_path}) % {'mount_path': mount_path})
raise nova_exception.InvalidVolume(msg) raise nova_exception.StaleVolumeMount(msg, mount_path=mount_path)
else: else:
msg = (_("The mount %(mount_path)s is not a valid" msg = (_("The mount %(mount_path)s is not a valid "
" Quobyte volume according to partition list.") "Quobyte volume according to partition list.")
% {'mount_path': mount_path}) % {'mount_path': mount_path})
raise nova_exception.InvalidVolume(msg) raise nova_exception.InvalidVolume(msg)
msg = (_("No matching Quobyte mount entry for %(mount_path)s" msg = (_("No matching Quobyte mount entry for %(mount_path)s"
@ -128,39 +129,40 @@ class LibvirtQuobyteVolumeDriver(fs.LibvirtBaseFileSystemVolumeDriver):
data = connection_info['data'] data = connection_info['data']
quobyte_volume = self._normalize_export(data['export']) quobyte_volume = self._normalize_export(data['export'])
mount_path = self._get_mount_path(connection_info) mount_path = self._get_mount_path(connection_info)
mounted = libvirt_utils.is_mounted(mount_path, try:
SOURCE_PROTOCOL validate_volume(mount_path)
+ '@' + quobyte_volume) mounted = True
if mounted: except nova_exception.StaleVolumeMount:
try: mounted = False
os.stat(mount_path) LOG.info('Fixing previous mount %s which was not '
except OSError as exc: 'unmounted correctly.', mount_path)
if exc.errno == errno.ENOTCONN: umount_volume(mount_path)
mounted = False except nova_exception.InvalidVolume:
LOG.info('Fixing previous mount %s which was not' mounted = False
' unmounted correctly.', mount_path)
umount_volume(mount_path)
if not mounted: if not mounted:
mount_volume(quobyte_volume, mount_volume(quobyte_volume,
mount_path, mount_path,
CONF.libvirt.quobyte_client_cfg) CONF.libvirt.quobyte_client_cfg)
validate_volume(mount_path) try:
validate_volume(mount_path)
except (nova_exception.InvalidVolume,
nova_exception.StaleVolumeMount) as nex:
LOG.error("Could not mount Quobyte volume: %s", nex)
@utils.synchronized('connect_qb_volume') @utils.synchronized('connect_qb_volume')
def disconnect_volume(self, connection_info, instance): def disconnect_volume(self, connection_info, instance):
"""Disconnect the volume.""" """Disconnect the volume."""
quobyte_volume = self._normalize_export(
connection_info['data']['export'])
mount_path = self._get_mount_path(connection_info) mount_path = self._get_mount_path(connection_info)
try:
if libvirt_utils.is_mounted(mount_path, 'quobyte@' + quobyte_volume): validate_volume(mount_path)
umount_volume(mount_path) except (nova_exception.InvalidVolume,
nova_exception.StaleVolumeMount) as exc:
LOG.warning("Could not disconnect Quobyte volume mount: %s", exc)
else: else:
LOG.info("Trying to disconnected unmounted volume at %s", umount_volume(mount_path)
mount_path)
def _normalize_export(self, export): def _normalize_export(self, export):
protocol = SOURCE_PROTOCOL + "://" protocol = SOURCE_PROTOCOL + "://"

View File

@ -0,0 +1,5 @@
---
fixes:
- |
Fixes a bug that caused Nova to fail on mounting Quobyte volumes
whose volume URL contained multiple registries.