Merge "libvirt: move the LibvirtQuobyteVolumeDriver into the quobyte module"
This commit is contained in:
commit
31396bc1b1
@ -22,11 +22,14 @@ from oslo_utils import fileutils
|
|||||||
|
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova import test
|
from nova import test
|
||||||
|
from nova.tests.unit.virt.libvirt.volume import test_volume
|
||||||
from nova import utils
|
from nova import utils
|
||||||
|
from nova.virt.libvirt import utils as libvirt_utils
|
||||||
from nova.virt.libvirt.volume import quobyte
|
from nova.virt.libvirt.volume import quobyte
|
||||||
|
|
||||||
|
|
||||||
class QuobyteTestCase(test.NoDBTestCase):
|
class QuobyteTestCase(test.NoDBTestCase):
|
||||||
|
"""Tests the nova.virt.libvirt.volume.quobyte module utilities."""
|
||||||
|
|
||||||
@mock.patch.object(fileutils, "ensure_tree")
|
@mock.patch.object(fileutils, "ensure_tree")
|
||||||
@mock.patch.object(utils, "execute")
|
@mock.patch.object(utils, "execute")
|
||||||
@ -181,3 +184,182 @@ class QuobyteTestCase(test.NoDBTestCase):
|
|||||||
self.assertRaises(exception.NovaException,
|
self.assertRaises(exception.NovaException,
|
||||||
quobyte.validate_volume,
|
quobyte.validate_volume,
|
||||||
export_mnt_base)
|
export_mnt_base)
|
||||||
|
|
||||||
|
|
||||||
|
class LibvirtQuobyteVolumeDriverTestCase(
|
||||||
|
test_volume.LibvirtVolumeBaseTestCase):
|
||||||
|
"""Tests the LibvirtQuobyteVolumeDriver class."""
|
||||||
|
|
||||||
|
@mock.patch.object(quobyte, 'validate_volume')
|
||||||
|
@mock.patch.object(quobyte, 'mount_volume')
|
||||||
|
@mock.patch.object(libvirt_utils, 'is_mounted', return_value=False)
|
||||||
|
def test_libvirt_quobyte_driver_mount(self,
|
||||||
|
mock_is_mounted,
|
||||||
|
mock_mount_volume,
|
||||||
|
mock_validate_volume
|
||||||
|
):
|
||||||
|
mnt_base = '/mnt'
|
||||||
|
self.flags(quobyte_mount_point_base=mnt_base, group='libvirt')
|
||||||
|
|
||||||
|
libvirt_driver = quobyte.LibvirtQuobyteVolumeDriver(self.fake_conn)
|
||||||
|
export_string = 'quobyte://192.168.1.1/volume-00001'
|
||||||
|
quobyte_volume = '192.168.1.1/volume-00001'
|
||||||
|
export_mnt_base = os.path.join(mnt_base,
|
||||||
|
utils.get_hash_str(quobyte_volume))
|
||||||
|
file_path = os.path.join(export_mnt_base, self.name)
|
||||||
|
|
||||||
|
connection_info = {'data': {'export': export_string,
|
||||||
|
'name': self.name}}
|
||||||
|
libvirt_driver.connect_volume(connection_info, self.disk_info)
|
||||||
|
|
||||||
|
conf = libvirt_driver.get_config(connection_info, self.disk_info)
|
||||||
|
tree = conf.format_dom()
|
||||||
|
|
||||||
|
self._assertFileTypeEquals(tree, file_path)
|
||||||
|
|
||||||
|
mock_mount_volume.assert_called_once_with(quobyte_volume,
|
||||||
|
export_mnt_base,
|
||||||
|
mock.ANY)
|
||||||
|
mock_validate_volume.assert_called_with(export_mnt_base)
|
||||||
|
|
||||||
|
@mock.patch.object(quobyte, 'validate_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_is_mounted,
|
||||||
|
mock_umount_volume,
|
||||||
|
mock_validate_volume):
|
||||||
|
mnt_base = '/mnt'
|
||||||
|
self.flags(quobyte_mount_point_base=mnt_base, group='libvirt')
|
||||||
|
|
||||||
|
libvirt_driver = quobyte.LibvirtQuobyteVolumeDriver(self.fake_conn)
|
||||||
|
export_string = 'quobyte://192.168.1.1/volume-00001'
|
||||||
|
quobyte_volume = '192.168.1.1/volume-00001'
|
||||||
|
export_mnt_base = os.path.join(mnt_base,
|
||||||
|
utils.get_hash_str(quobyte_volume))
|
||||||
|
file_path = os.path.join(export_mnt_base, self.name)
|
||||||
|
|
||||||
|
connection_info = {'data': {'export': export_string,
|
||||||
|
'name': self.name}}
|
||||||
|
libvirt_driver.connect_volume(connection_info, self.disk_info)
|
||||||
|
|
||||||
|
conf = libvirt_driver.get_config(connection_info, self.disk_info)
|
||||||
|
tree = conf.format_dom()
|
||||||
|
self._assertFileTypeEquals(tree, file_path)
|
||||||
|
|
||||||
|
libvirt_driver.disconnect_volume(connection_info, "vde")
|
||||||
|
|
||||||
|
mock_validate_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, 'umount_volume')
|
||||||
|
def test_libvirt_quobyte_driver_already_mounted(self,
|
||||||
|
mock_umount_volume,
|
||||||
|
mock_validate_volume
|
||||||
|
):
|
||||||
|
mnt_base = '/mnt'
|
||||||
|
self.flags(quobyte_mount_point_base=mnt_base, group='libvirt')
|
||||||
|
|
||||||
|
libvirt_driver = quobyte.LibvirtQuobyteVolumeDriver(self.fake_conn)
|
||||||
|
export_string = 'quobyte://192.168.1.1/volume-00001'
|
||||||
|
quobyte_volume = '192.168.1.1/volume-00001'
|
||||||
|
export_mnt_base = os.path.join(mnt_base,
|
||||||
|
utils.get_hash_str(quobyte_volume))
|
||||||
|
file_path = os.path.join(export_mnt_base, self.name)
|
||||||
|
|
||||||
|
connection_info = {'data': {'export': export_string,
|
||||||
|
'name': self.name}}
|
||||||
|
|
||||||
|
libvirt_driver.connect_volume(connection_info, self.disk_info)
|
||||||
|
|
||||||
|
conf = libvirt_driver.get_config(connection_info, self.disk_info)
|
||||||
|
tree = conf.format_dom()
|
||||||
|
self._assertFileTypeEquals(tree, file_path)
|
||||||
|
libvirt_driver.disconnect_volume(connection_info, "vde")
|
||||||
|
|
||||||
|
expected_commands = [
|
||||||
|
('findmnt', '--target', export_mnt_base,
|
||||||
|
'--source', "quobyte@" + quobyte_volume),
|
||||||
|
('findmnt', '--target', export_mnt_base,
|
||||||
|
'--source', "quobyte@" + quobyte_volume),
|
||||||
|
]
|
||||||
|
self.assertEqual(expected_commands, self.executes)
|
||||||
|
|
||||||
|
mock_umount_volume.assert_called_once_with(export_mnt_base)
|
||||||
|
mock_validate_volume.assert_called_once_with(export_mnt_base)
|
||||||
|
|
||||||
|
@mock.patch.object(quobyte, 'validate_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_is_mounted,
|
||||||
|
mock_mount_volume,
|
||||||
|
mock_validate_volume
|
||||||
|
):
|
||||||
|
mnt_base = '/mnt'
|
||||||
|
self.flags(quobyte_mount_point_base=mnt_base, group='libvirt')
|
||||||
|
libvirt_driver = quobyte.LibvirtQuobyteVolumeDriver(self.fake_conn)
|
||||||
|
export_string = 'quobyte://192.168.1.1/volume-00001'
|
||||||
|
name = 'volume-00001'
|
||||||
|
image_format = 'qcow2'
|
||||||
|
quobyte_volume = '192.168.1.1/volume-00001'
|
||||||
|
|
||||||
|
connection_info = {'data': {'export': export_string,
|
||||||
|
'name': name,
|
||||||
|
'format': image_format}}
|
||||||
|
|
||||||
|
export_mnt_base = os.path.join(mnt_base,
|
||||||
|
utils.get_hash_str(quobyte_volume))
|
||||||
|
|
||||||
|
libvirt_driver.connect_volume(connection_info, self.disk_info)
|
||||||
|
conf = libvirt_driver.get_config(connection_info, self.disk_info)
|
||||||
|
tree = conf.format_dom()
|
||||||
|
self.assertEqual(tree.get('type'), 'file')
|
||||||
|
self.assertEqual(tree.find('./driver').get('type'), 'qcow2')
|
||||||
|
|
||||||
|
(mock_mount_volume.
|
||||||
|
assert_called_once_with('192.168.1.1/volume-00001',
|
||||||
|
export_mnt_base,
|
||||||
|
mock.ANY))
|
||||||
|
mock_validate_volume.assert_called_with(export_mnt_base)
|
||||||
|
|
||||||
|
libvirt_driver.disconnect_volume(connection_info, "vde")
|
||||||
|
|
||||||
|
def test_libvirt_quobyte_driver_mount_non_quobyte_volume(self):
|
||||||
|
mnt_base = '/mnt'
|
||||||
|
self.flags(quobyte_mount_point_base=mnt_base, group='libvirt')
|
||||||
|
|
||||||
|
libvirt_driver = quobyte.LibvirtQuobyteVolumeDriver(self.fake_conn)
|
||||||
|
export_string = 'quobyte://192.168.1.1/volume-00001'
|
||||||
|
|
||||||
|
connection_info = {'data': {'export': export_string,
|
||||||
|
'name': self.name}}
|
||||||
|
|
||||||
|
def exe_side_effect(*cmd, **kwargs):
|
||||||
|
if cmd == mock.ANY:
|
||||||
|
raise exception.NovaException()
|
||||||
|
|
||||||
|
with mock.patch.object(quobyte,
|
||||||
|
'validate_volume') as mock_execute:
|
||||||
|
mock_execute.side_effect = exe_side_effect
|
||||||
|
self.assertRaises(exception.NovaException,
|
||||||
|
libvirt_driver.connect_volume,
|
||||||
|
connection_info,
|
||||||
|
self.disk_info)
|
||||||
|
|
||||||
|
def test_libvirt_quobyte_driver_normalize_url_with_protocol(self):
|
||||||
|
mnt_base = '/mnt'
|
||||||
|
self.flags(quobyte_mount_point_base=mnt_base, group='libvirt')
|
||||||
|
|
||||||
|
libvirt_driver = quobyte.LibvirtQuobyteVolumeDriver(self.fake_conn)
|
||||||
|
export_string = 'quobyte://192.168.1.1/volume-00001'
|
||||||
|
self.assertEqual(libvirt_driver._normalize_url(export_string),
|
||||||
|
"192.168.1.1/volume-00001")
|
||||||
|
|
||||||
|
def test_libvirt_quobyte_driver_normalize_url_without_protocol(self):
|
||||||
|
mnt_base = '/mnt'
|
||||||
|
self.flags(quobyte_mount_point_base=mnt_base, group='libvirt')
|
||||||
|
|
||||||
|
libvirt_driver = quobyte.LibvirtQuobyteVolumeDriver(self.fake_conn)
|
||||||
|
export_string = '192.168.1.1/volume-00001'
|
||||||
|
self.assertEqual(libvirt_driver._normalize_url(export_string),
|
||||||
|
"192.168.1.1/volume-00001")
|
||||||
|
@ -29,7 +29,6 @@ from nova.tests.unit.virt.libvirt import fakelibvirt
|
|||||||
from nova import utils
|
from nova import utils
|
||||||
from nova.virt.libvirt import host
|
from nova.virt.libvirt import host
|
||||||
from nova.virt.libvirt import utils as libvirt_utils
|
from nova.virt.libvirt import utils as libvirt_utils
|
||||||
from nova.virt.libvirt.volume import quobyte
|
|
||||||
from nova.virt.libvirt.volume import volume
|
from nova.virt.libvirt.volume import volume
|
||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
@ -59,10 +58,11 @@ class FakeSecret(object):
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
class LibvirtVolumeTestCase(test.NoDBTestCase):
|
class LibvirtVolumeBaseTestCase(test.NoDBTestCase):
|
||||||
|
"""Contains common setup and helper methods for libvirt volume tests."""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(LibvirtVolumeTestCase, self).setUp()
|
super(LibvirtVolumeBaseTestCase, self).setUp()
|
||||||
self.executes = []
|
self.executes = []
|
||||||
|
|
||||||
def fake_execute(*cmd, **kwargs):
|
def fake_execute(*cmd, **kwargs):
|
||||||
@ -98,6 +98,13 @@ class LibvirtVolumeTestCase(test.NoDBTestCase):
|
|||||||
self.uuid = '875a8070-d0b9-4949-8b31-104d125c9a64'
|
self.uuid = '875a8070-d0b9-4949-8b31-104d125c9a64'
|
||||||
self.user = 'foo'
|
self.user = 'foo'
|
||||||
|
|
||||||
|
def _assertFileTypeEquals(self, tree, file_path):
|
||||||
|
self.assertEqual(tree.get('type'), 'file')
|
||||||
|
self.assertEqual(tree.find('./source').get('file'), file_path)
|
||||||
|
|
||||||
|
|
||||||
|
class LibvirtVolumeTestCase(LibvirtVolumeBaseTestCase):
|
||||||
|
|
||||||
def _assertNetworkAndProtocolEquals(self, tree):
|
def _assertNetworkAndProtocolEquals(self, tree):
|
||||||
self.assertEqual(tree.get('type'), 'network')
|
self.assertEqual(tree.get('type'), 'network')
|
||||||
self.assertEqual(tree.find('./source').get('protocol'), 'rbd')
|
self.assertEqual(tree.find('./source').get('protocol'), 'rbd')
|
||||||
@ -110,10 +117,6 @@ class LibvirtVolumeTestCase(test.NoDBTestCase):
|
|||||||
iscsi_name = '%s/%s' % (self.iqn, self.vol['id'])
|
iscsi_name = '%s/%s' % (self.iqn, self.vol['id'])
|
||||||
self.assertEqual(tree.find('./source').get('name'), iscsi_name)
|
self.assertEqual(tree.find('./source').get('name'), iscsi_name)
|
||||||
|
|
||||||
def _assertFileTypeEquals(self, tree, file_path):
|
|
||||||
self.assertEqual(tree.get('type'), 'file')
|
|
||||||
self.assertEqual(tree.find('./source').get('file'), file_path)
|
|
||||||
|
|
||||||
def _assertDiskInfoEquals(self, tree, disk_info):
|
def _assertDiskInfoEquals(self, tree, disk_info):
|
||||||
self.assertEqual(tree.get('device'), disk_info['type'])
|
self.assertEqual(tree.get('device'), disk_info['type'])
|
||||||
self.assertEqual(tree.find('./target').get('bus'),
|
self.assertEqual(tree.find('./target').get('bus'),
|
||||||
@ -933,177 +936,3 @@ Setting up iSCSI targets: unused
|
|||||||
tree = conf.format_dom()
|
tree = conf.format_dom()
|
||||||
self.assertEqual('file', tree.get('type'))
|
self.assertEqual('file', tree.get('type'))
|
||||||
self.assertEqual('fake_serial', tree.find('./serial').text)
|
self.assertEqual('fake_serial', tree.find('./serial').text)
|
||||||
|
|
||||||
@mock.patch.object(quobyte, 'validate_volume')
|
|
||||||
@mock.patch.object(quobyte, 'mount_volume')
|
|
||||||
@mock.patch.object(libvirt_utils, 'is_mounted', return_value=False)
|
|
||||||
def test_libvirt_quobyte_driver_mount(self,
|
|
||||||
mock_is_mounted,
|
|
||||||
mock_mount_volume,
|
|
||||||
mock_validate_volume
|
|
||||||
):
|
|
||||||
mnt_base = '/mnt'
|
|
||||||
self.flags(quobyte_mount_point_base=mnt_base, group='libvirt')
|
|
||||||
|
|
||||||
libvirt_driver = volume.LibvirtQuobyteVolumeDriver(self.fake_conn)
|
|
||||||
export_string = 'quobyte://192.168.1.1/volume-00001'
|
|
||||||
quobyte_volume = '192.168.1.1/volume-00001'
|
|
||||||
export_mnt_base = os.path.join(mnt_base,
|
|
||||||
utils.get_hash_str(quobyte_volume))
|
|
||||||
file_path = os.path.join(export_mnt_base, self.name)
|
|
||||||
|
|
||||||
connection_info = {'data': {'export': export_string,
|
|
||||||
'name': self.name}}
|
|
||||||
libvirt_driver.connect_volume(connection_info, self.disk_info)
|
|
||||||
|
|
||||||
conf = libvirt_driver.get_config(connection_info, self.disk_info)
|
|
||||||
tree = conf.format_dom()
|
|
||||||
|
|
||||||
self._assertFileTypeEquals(tree, file_path)
|
|
||||||
|
|
||||||
mock_mount_volume.assert_called_once_with(quobyte_volume,
|
|
||||||
export_mnt_base,
|
|
||||||
mock.ANY)
|
|
||||||
mock_validate_volume.assert_called_with(export_mnt_base)
|
|
||||||
|
|
||||||
@mock.patch.object(quobyte, 'validate_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_is_mounted,
|
|
||||||
mock_umount_volume,
|
|
||||||
mock_validate_volume):
|
|
||||||
mnt_base = '/mnt'
|
|
||||||
self.flags(quobyte_mount_point_base=mnt_base, group='libvirt')
|
|
||||||
|
|
||||||
libvirt_driver = volume.LibvirtQuobyteVolumeDriver(self.fake_conn)
|
|
||||||
export_string = 'quobyte://192.168.1.1/volume-00001'
|
|
||||||
quobyte_volume = '192.168.1.1/volume-00001'
|
|
||||||
export_mnt_base = os.path.join(mnt_base,
|
|
||||||
utils.get_hash_str(quobyte_volume))
|
|
||||||
file_path = os.path.join(export_mnt_base, self.name)
|
|
||||||
|
|
||||||
connection_info = {'data': {'export': export_string,
|
|
||||||
'name': self.name}}
|
|
||||||
libvirt_driver.connect_volume(connection_info, self.disk_info)
|
|
||||||
|
|
||||||
conf = libvirt_driver.get_config(connection_info, self.disk_info)
|
|
||||||
tree = conf.format_dom()
|
|
||||||
self._assertFileTypeEquals(tree, file_path)
|
|
||||||
|
|
||||||
libvirt_driver.disconnect_volume(connection_info, "vde")
|
|
||||||
|
|
||||||
mock_validate_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, 'umount_volume')
|
|
||||||
def test_libvirt_quobyte_driver_already_mounted(self,
|
|
||||||
mock_umount_volume,
|
|
||||||
mock_validate_volume
|
|
||||||
):
|
|
||||||
mnt_base = '/mnt'
|
|
||||||
self.flags(quobyte_mount_point_base=mnt_base, group='libvirt')
|
|
||||||
|
|
||||||
libvirt_driver = volume.LibvirtQuobyteVolumeDriver(self.fake_conn)
|
|
||||||
export_string = 'quobyte://192.168.1.1/volume-00001'
|
|
||||||
quobyte_volume = '192.168.1.1/volume-00001'
|
|
||||||
export_mnt_base = os.path.join(mnt_base,
|
|
||||||
utils.get_hash_str(quobyte_volume))
|
|
||||||
file_path = os.path.join(export_mnt_base, self.name)
|
|
||||||
|
|
||||||
connection_info = {'data': {'export': export_string,
|
|
||||||
'name': self.name}}
|
|
||||||
|
|
||||||
libvirt_driver.connect_volume(connection_info, self.disk_info)
|
|
||||||
|
|
||||||
conf = libvirt_driver.get_config(connection_info, self.disk_info)
|
|
||||||
tree = conf.format_dom()
|
|
||||||
self._assertFileTypeEquals(tree, file_path)
|
|
||||||
libvirt_driver.disconnect_volume(connection_info, "vde")
|
|
||||||
|
|
||||||
expected_commands = [
|
|
||||||
('findmnt', '--target', export_mnt_base,
|
|
||||||
'--source', "quobyte@" + quobyte_volume),
|
|
||||||
('findmnt', '--target', export_mnt_base,
|
|
||||||
'--source', "quobyte@" + quobyte_volume),
|
|
||||||
]
|
|
||||||
self.assertEqual(expected_commands, self.executes)
|
|
||||||
|
|
||||||
mock_umount_volume.assert_called_once_with(export_mnt_base)
|
|
||||||
mock_validate_volume.assert_called_once_with(export_mnt_base)
|
|
||||||
|
|
||||||
@mock.patch.object(quobyte, 'validate_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_is_mounted,
|
|
||||||
mock_mount_volume,
|
|
||||||
mock_validate_volume
|
|
||||||
):
|
|
||||||
mnt_base = '/mnt'
|
|
||||||
self.flags(quobyte_mount_point_base=mnt_base, group='libvirt')
|
|
||||||
libvirt_driver = volume.LibvirtQuobyteVolumeDriver(self.fake_conn)
|
|
||||||
export_string = 'quobyte://192.168.1.1/volume-00001'
|
|
||||||
name = 'volume-00001'
|
|
||||||
image_format = 'qcow2'
|
|
||||||
quobyte_volume = '192.168.1.1/volume-00001'
|
|
||||||
|
|
||||||
connection_info = {'data': {'export': export_string,
|
|
||||||
'name': name,
|
|
||||||
'format': image_format}}
|
|
||||||
|
|
||||||
export_mnt_base = os.path.join(mnt_base,
|
|
||||||
utils.get_hash_str(quobyte_volume))
|
|
||||||
|
|
||||||
libvirt_driver.connect_volume(connection_info, self.disk_info)
|
|
||||||
conf = libvirt_driver.get_config(connection_info, self.disk_info)
|
|
||||||
tree = conf.format_dom()
|
|
||||||
self.assertEqual(tree.get('type'), 'file')
|
|
||||||
self.assertEqual(tree.find('./driver').get('type'), 'qcow2')
|
|
||||||
|
|
||||||
(mock_mount_volume.
|
|
||||||
assert_called_once_with('192.168.1.1/volume-00001',
|
|
||||||
export_mnt_base,
|
|
||||||
mock.ANY))
|
|
||||||
mock_validate_volume.assert_called_with(export_mnt_base)
|
|
||||||
|
|
||||||
libvirt_driver.disconnect_volume(connection_info, "vde")
|
|
||||||
|
|
||||||
def test_libvirt_quobyte_driver_mount_non_quobyte_volume(self):
|
|
||||||
mnt_base = '/mnt'
|
|
||||||
self.flags(quobyte_mount_point_base=mnt_base, group='libvirt')
|
|
||||||
|
|
||||||
libvirt_driver = volume.LibvirtQuobyteVolumeDriver(self.fake_conn)
|
|
||||||
export_string = 'quobyte://192.168.1.1/volume-00001'
|
|
||||||
|
|
||||||
connection_info = {'data': {'export': export_string,
|
|
||||||
'name': self.name}}
|
|
||||||
|
|
||||||
def exe_side_effect(*cmd, **kwargs):
|
|
||||||
if cmd == mock.ANY:
|
|
||||||
raise exception.NovaException()
|
|
||||||
|
|
||||||
with mock.patch.object(quobyte,
|
|
||||||
'validate_volume') as mock_execute:
|
|
||||||
mock_execute.side_effect = exe_side_effect
|
|
||||||
self.assertRaises(exception.NovaException,
|
|
||||||
libvirt_driver.connect_volume,
|
|
||||||
connection_info,
|
|
||||||
self.disk_info)
|
|
||||||
|
|
||||||
def test_libvirt_quobyte_driver_normalize_url_with_protocol(self):
|
|
||||||
mnt_base = '/mnt'
|
|
||||||
self.flags(quobyte_mount_point_base=mnt_base, group='libvirt')
|
|
||||||
|
|
||||||
libvirt_driver = volume.LibvirtQuobyteVolumeDriver(self.fake_conn)
|
|
||||||
export_string = 'quobyte://192.168.1.1/volume-00001'
|
|
||||||
self.assertEqual(libvirt_driver._normalize_url(export_string),
|
|
||||||
"192.168.1.1/volume-00001")
|
|
||||||
|
|
||||||
def test_libvirt_quobyte_driver_normalize_url_without_protocol(self):
|
|
||||||
mnt_base = '/mnt'
|
|
||||||
self.flags(quobyte_mount_point_base=mnt_base, group='libvirt')
|
|
||||||
|
|
||||||
libvirt_driver = volume.LibvirtQuobyteVolumeDriver(self.fake_conn)
|
|
||||||
export_string = '192.168.1.1/volume-00001'
|
|
||||||
self.assertEqual(libvirt_driver._normalize_url(export_string),
|
|
||||||
"192.168.1.1/volume-00001")
|
|
||||||
|
@ -286,7 +286,7 @@ libvirt_volume_drivers = [
|
|||||||
'nova.virt.libvirt.volume.volume.LibvirtFibreChannelVolumeDriver',
|
'nova.virt.libvirt.volume.volume.LibvirtFibreChannelVolumeDriver',
|
||||||
'scality=nova.virt.libvirt.volume.volume.LibvirtScalityVolumeDriver',
|
'scality=nova.virt.libvirt.volume.volume.LibvirtScalityVolumeDriver',
|
||||||
'gpfs=nova.virt.libvirt.volume.volume.LibvirtGPFSVolumeDriver',
|
'gpfs=nova.virt.libvirt.volume.volume.LibvirtGPFSVolumeDriver',
|
||||||
'quobyte=nova.virt.libvirt.volume.volume.LibvirtQuobyteVolumeDriver',
|
'quobyte=nova.virt.libvirt.volume.quobyte.LibvirtQuobyteVolumeDriver',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,9 +13,11 @@
|
|||||||
# 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
|
||||||
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_utils import fileutils
|
from oslo_utils import fileutils
|
||||||
|
|
||||||
@ -23,11 +25,25 @@ from nova import exception as nova_exception
|
|||||||
from nova.i18n import _
|
from nova.i18n import _
|
||||||
from nova.i18n import _LE
|
from nova.i18n import _LE
|
||||||
from nova.i18n import _LI
|
from nova.i18n import _LI
|
||||||
|
from nova import paths
|
||||||
from nova import utils
|
from nova import utils
|
||||||
|
from nova.virt.libvirt import utils as libvirt_utils
|
||||||
|
from nova.virt.libvirt.volume import volume as libvirt_volume
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
volume_opts = [
|
||||||
|
cfg.StrOpt('quobyte_mount_point_base',
|
||||||
|
default=paths.state_path_def('mnt'),
|
||||||
|
help='Directory where the Quobyte volume is mounted on the '
|
||||||
|
'compute node'),
|
||||||
|
cfg.StrOpt('quobyte_client_cfg',
|
||||||
|
help='Path to a Quobyte Client configuration file.'),
|
||||||
|
]
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
|
CONF.register_opts(volume_opts, 'libvirt')
|
||||||
|
|
||||||
SOURCE_PROTOCOL = 'quobyte'
|
SOURCE_PROTOCOL = 'quobyte'
|
||||||
SOURCE_TYPE = 'file'
|
SOURCE_TYPE = 'file'
|
||||||
DRIVER_CACHE = 'none'
|
DRIVER_CACHE = 'none'
|
||||||
@ -78,3 +94,82 @@ def validate_volume(mnt_base):
|
|||||||
msg = (_LE("Volume is not writable. Please broaden the file"
|
msg = (_LE("Volume is not writable. Please broaden the file"
|
||||||
" permissions. Mount: %s") % mnt_base)
|
" permissions. Mount: %s") % mnt_base)
|
||||||
raise nova_exception.NovaException(msg)
|
raise nova_exception.NovaException(msg)
|
||||||
|
|
||||||
|
|
||||||
|
class LibvirtQuobyteVolumeDriver(libvirt_volume.LibvirtBaseVolumeDriver):
|
||||||
|
"""Class implements libvirt part of volume driver for Quobyte."""
|
||||||
|
|
||||||
|
def __init__(self, connection):
|
||||||
|
"""Create back-end to Quobyte."""
|
||||||
|
super(LibvirtQuobyteVolumeDriver,
|
||||||
|
self).__init__(connection, is_block_dev=False)
|
||||||
|
|
||||||
|
def get_config(self, connection_info, disk_info):
|
||||||
|
conf = super(LibvirtQuobyteVolumeDriver,
|
||||||
|
self).get_config(connection_info, disk_info)
|
||||||
|
data = connection_info['data']
|
||||||
|
conf.source_protocol = SOURCE_PROTOCOL
|
||||||
|
conf.source_type = SOURCE_TYPE
|
||||||
|
conf.driver_cache = DRIVER_CACHE
|
||||||
|
conf.driver_io = DRIVER_IO
|
||||||
|
conf.driver_format = data.get('format', 'raw')
|
||||||
|
|
||||||
|
quobyte_volume = self._normalize_url(data['export'])
|
||||||
|
path = os.path.join(self._get_mount_point_for_share(quobyte_volume),
|
||||||
|
data['name'])
|
||||||
|
conf.source_path = path
|
||||||
|
|
||||||
|
return conf
|
||||||
|
|
||||||
|
@utils.synchronized('connect_volume')
|
||||||
|
def connect_volume(self, connection_info, disk_info):
|
||||||
|
"""Connect the volume."""
|
||||||
|
data = connection_info['data']
|
||||||
|
quobyte_volume = self._normalize_url(data['export'])
|
||||||
|
mount_path = self._get_mount_point_for_share(quobyte_volume)
|
||||||
|
mounted = libvirt_utils.is_mounted(mount_path,
|
||||||
|
SOURCE_PROTOCOL
|
||||||
|
+ '@' + quobyte_volume)
|
||||||
|
if mounted:
|
||||||
|
try:
|
||||||
|
os.stat(mount_path)
|
||||||
|
except OSError as exc:
|
||||||
|
if exc.errno == errno.ENOTCONN:
|
||||||
|
mounted = False
|
||||||
|
LOG.info(_LI('Fixing previous mount %s which was not'
|
||||||
|
' unmounted correctly.'), mount_path)
|
||||||
|
umount_volume(mount_path)
|
||||||
|
|
||||||
|
if not mounted:
|
||||||
|
mount_volume(quobyte_volume,
|
||||||
|
mount_path,
|
||||||
|
CONF.libvirt.quobyte_client_cfg)
|
||||||
|
|
||||||
|
validate_volume(mount_path)
|
||||||
|
|
||||||
|
@utils.synchronized('connect_volume')
|
||||||
|
def disconnect_volume(self, connection_info, disk_dev):
|
||||||
|
"""Disconnect the volume."""
|
||||||
|
|
||||||
|
quobyte_volume = self._normalize_url(connection_info['data']['export'])
|
||||||
|
mount_path = self._get_mount_point_for_share(quobyte_volume)
|
||||||
|
|
||||||
|
if libvirt_utils.is_mounted(mount_path, 'quobyte@' + quobyte_volume):
|
||||||
|
umount_volume(mount_path)
|
||||||
|
else:
|
||||||
|
LOG.info(_LI("Trying to disconnected unmounted volume at %s"),
|
||||||
|
mount_path)
|
||||||
|
|
||||||
|
def _normalize_url(self, export):
|
||||||
|
protocol = SOURCE_PROTOCOL + "://"
|
||||||
|
if export.startswith(protocol):
|
||||||
|
export = export[len(protocol):]
|
||||||
|
return export
|
||||||
|
|
||||||
|
def _get_mount_point_for_share(self, quobyte_volume):
|
||||||
|
"""Return mount point for Quobyte volume.
|
||||||
|
|
||||||
|
:param quobyte_volume: Example: storage-host/openstack-volumes
|
||||||
|
"""
|
||||||
|
return os.path.join(CONF.libvirt.quobyte_mount_point_base,
|
||||||
|
utils.get_hash_str(quobyte_volume))
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
"""Volume drivers for libvirt."""
|
"""Volume drivers for libvirt."""
|
||||||
|
|
||||||
import errno
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
@ -31,13 +30,11 @@ import six.moves.urllib.parse as urlparse
|
|||||||
from nova import exception
|
from nova import exception
|
||||||
from nova.i18n import _
|
from nova.i18n import _
|
||||||
from nova.i18n import _LE
|
from nova.i18n import _LE
|
||||||
from nova.i18n import _LI
|
|
||||||
from nova.i18n import _LW
|
from nova.i18n import _LW
|
||||||
from nova import paths
|
from nova import paths
|
||||||
from nova import utils
|
from nova import utils
|
||||||
from nova.virt.libvirt import config as vconfig
|
from nova.virt.libvirt import config as vconfig
|
||||||
from nova.virt.libvirt import utils as libvirt_utils
|
from nova.virt.libvirt import utils as libvirt_utils
|
||||||
from nova.virt.libvirt.volume import quobyte
|
|
||||||
from nova.virt.libvirt.volume import remotefs
|
from nova.virt.libvirt.volume import remotefs
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@ -92,12 +89,6 @@ volume_opts = [
|
|||||||
default=[],
|
default=[],
|
||||||
help='Protocols listed here will be accessed directly '
|
help='Protocols listed here will be accessed directly '
|
||||||
'from QEMU. Currently supported protocols: [gluster]'),
|
'from QEMU. Currently supported protocols: [gluster]'),
|
||||||
cfg.StrOpt('quobyte_mount_point_base',
|
|
||||||
default=paths.state_path_def('mnt'),
|
|
||||||
help='Directory where the Quobyte volume is mounted on the '
|
|
||||||
'compute node'),
|
|
||||||
cfg.StrOpt('quobyte_client_cfg',
|
|
||||||
help='Path to a Quobyte Client configuration file.'),
|
|
||||||
cfg.StrOpt('iscsi_iface',
|
cfg.StrOpt('iscsi_iface',
|
||||||
deprecated_name='iscsi_transport',
|
deprecated_name='iscsi_transport',
|
||||||
help='The iSCSI transport iface to use to connect to target in '
|
help='The iSCSI transport iface to use to connect to target in '
|
||||||
@ -787,82 +778,3 @@ class LibvirtGPFSVolumeDriver(LibvirtBaseVolumeDriver):
|
|||||||
conf.source_type = "file"
|
conf.source_type = "file"
|
||||||
conf.source_path = connection_info['data']['device_path']
|
conf.source_path = connection_info['data']['device_path']
|
||||||
return conf
|
return conf
|
||||||
|
|
||||||
|
|
||||||
class LibvirtQuobyteVolumeDriver(LibvirtBaseVolumeDriver):
|
|
||||||
"""Class implements libvirt part of volume driver for Quobyte."""
|
|
||||||
|
|
||||||
def __init__(self, connection):
|
|
||||||
"""Create back-end to Quobyte."""
|
|
||||||
super(LibvirtQuobyteVolumeDriver,
|
|
||||||
self).__init__(connection, is_block_dev=False)
|
|
||||||
|
|
||||||
def get_config(self, connection_info, disk_info):
|
|
||||||
conf = super(LibvirtQuobyteVolumeDriver,
|
|
||||||
self).get_config(connection_info, disk_info)
|
|
||||||
data = connection_info['data']
|
|
||||||
conf.source_protocol = quobyte.SOURCE_PROTOCOL
|
|
||||||
conf.source_type = quobyte.SOURCE_TYPE
|
|
||||||
conf.driver_cache = quobyte.DRIVER_CACHE
|
|
||||||
conf.driver_io = quobyte.DRIVER_IO
|
|
||||||
conf.driver_format = data.get('format', 'raw')
|
|
||||||
|
|
||||||
quobyte_volume = self._normalize_url(data['export'])
|
|
||||||
path = os.path.join(self._get_mount_point_for_share(quobyte_volume),
|
|
||||||
data['name'])
|
|
||||||
conf.source_path = path
|
|
||||||
|
|
||||||
return conf
|
|
||||||
|
|
||||||
@utils.synchronized('connect_volume')
|
|
||||||
def connect_volume(self, connection_info, disk_info):
|
|
||||||
"""Connect the volume."""
|
|
||||||
data = connection_info['data']
|
|
||||||
quobyte_volume = self._normalize_url(data['export'])
|
|
||||||
mount_path = self._get_mount_point_for_share(quobyte_volume)
|
|
||||||
mounted = libvirt_utils.is_mounted(mount_path,
|
|
||||||
quobyte.SOURCE_PROTOCOL
|
|
||||||
+ '@' + quobyte_volume)
|
|
||||||
if mounted:
|
|
||||||
try:
|
|
||||||
os.stat(mount_path)
|
|
||||||
except OSError as exc:
|
|
||||||
if exc.errno == errno.ENOTCONN:
|
|
||||||
mounted = False
|
|
||||||
LOG.info(_LI('Fixing previous mount %s which was not'
|
|
||||||
' unmounted correctly.'), mount_path)
|
|
||||||
quobyte.umount_volume(mount_path)
|
|
||||||
|
|
||||||
if not mounted:
|
|
||||||
quobyte.mount_volume(quobyte_volume,
|
|
||||||
mount_path,
|
|
||||||
CONF.libvirt.quobyte_client_cfg)
|
|
||||||
|
|
||||||
quobyte.validate_volume(mount_path)
|
|
||||||
|
|
||||||
@utils.synchronized('connect_volume')
|
|
||||||
def disconnect_volume(self, connection_info, disk_dev):
|
|
||||||
"""Disconnect the volume."""
|
|
||||||
|
|
||||||
quobyte_volume = self._normalize_url(connection_info['data']['export'])
|
|
||||||
mount_path = self._get_mount_point_for_share(quobyte_volume)
|
|
||||||
|
|
||||||
if libvirt_utils.is_mounted(mount_path, 'quobyte@' + quobyte_volume):
|
|
||||||
quobyte.umount_volume(mount_path)
|
|
||||||
else:
|
|
||||||
LOG.info(_LI("Trying to disconnected unmounted volume at %s"),
|
|
||||||
mount_path)
|
|
||||||
|
|
||||||
def _normalize_url(self, export):
|
|
||||||
protocol = quobyte.SOURCE_PROTOCOL + "://"
|
|
||||||
if export.startswith(protocol):
|
|
||||||
export = export[len(protocol):]
|
|
||||||
return export
|
|
||||||
|
|
||||||
def _get_mount_point_for_share(self, quobyte_volume):
|
|
||||||
"""Return mount point for Quobyte volume.
|
|
||||||
|
|
||||||
:param quobyte_volume: Example: storage-host/openstack-volumes
|
|
||||||
"""
|
|
||||||
return os.path.join(CONF.libvirt.quobyte_mount_point_base,
|
|
||||||
utils.get_hash_str(quobyte_volume))
|
|
||||||
|
Loading…
Reference in New Issue
Block a user