Adding support for AoE block storage SANs.
Adding support for AoE (ATA over Ethernet) block storage SANs. AoE initiator driver is supported on all Linux initiators (released under GPL), ATA over Ethernet (AoE) Linux driver for all 3.x and 2.6 kernels. Implements blueprint libvirt-aoe - Fix (minor) Redundant exception caching Change-Id: I00de13eb2d4bd1105b9eb68f1465825414e2d5d7
This commit is contained in:
committed by
Jean-Baptiste RANSY
parent
fc7cece839
commit
43d1410ebf
@@ -88,6 +88,11 @@ dd: CommandFilter, /bin/dd, root
|
||||
# nova/virt/xenapi/volume_utils.py: 'iscsiadm', '-m', ...
|
||||
iscsiadm: CommandFilter, iscsiadm, root
|
||||
|
||||
# nova/virt/libvirt/volume.py: 'aoe-revalidate', aoedev
|
||||
# nova/virt/libvirt/volume.py: 'aoe-discover'
|
||||
aoe-revalidate: CommandFilter, /usr/sbin/aoe-revalidate, root
|
||||
aoe-discover: CommandFilter, /usr/sbin/aoe-discover, root
|
||||
|
||||
# nova/virt/xenapi/vm_utils.py: parted, --script, ...
|
||||
# nova/virt/xenapi/vm_utils.py: 'parted', '--script', dev_path, ..*.
|
||||
parted: CommandFilter, parted, root
|
||||
|
||||
@@ -324,3 +324,31 @@ class LibvirtVolumeTestCase(test.TestCase):
|
||||
('stat', export_mnt_base),
|
||||
('mount', '-t', 'nfs', export_string, export_mnt_base)]
|
||||
self.assertEqual(self.executes, expected_commands)
|
||||
|
||||
def aoe_connection(self, shelf, lun):
|
||||
return {
|
||||
'driver_volume_type': 'aoe',
|
||||
'data': {
|
||||
'target_shelf': shelf,
|
||||
'target_lun': lun,
|
||||
}
|
||||
}
|
||||
|
||||
def test_libvirt_aoe_driver(self):
|
||||
# NOTE(jbr_) exists is to make driver assume connecting worked
|
||||
self.stubs.Set(os.path, 'exists', lambda x: True)
|
||||
libvirt_driver = volume.LibvirtAOEVolumeDriver(self.fake_conn)
|
||||
shelf = '100'
|
||||
lun = '1'
|
||||
connection_info = self.aoe_connection(shelf, lun)
|
||||
disk_info = {
|
||||
"bus": "virtio",
|
||||
"dev": "vde",
|
||||
"type": "disk",
|
||||
}
|
||||
conf = libvirt_driver.connect_volume(connection_info, disk_info)
|
||||
tree = conf.format_dom()
|
||||
aoedevpath = '/dev/etherd/e%s.%s' % (shelf, lun)
|
||||
self.assertEqual(tree.get('type'), 'block')
|
||||
self.assertEqual(tree.find('./source').get('dev'), aoedevpath)
|
||||
libvirt_driver.disconnect_volume(connection_info, "vde")
|
||||
|
||||
@@ -150,7 +150,8 @@ libvirt_opts = [
|
||||
'fake=nova.virt.libvirt.volume.LibvirtFakeVolumeDriver',
|
||||
'rbd=nova.virt.libvirt.volume.LibvirtNetVolumeDriver',
|
||||
'sheepdog=nova.virt.libvirt.volume.LibvirtNetVolumeDriver',
|
||||
'nfs=nova.virt.libvirt.volume.LibvirtNFSVolumeDriver'
|
||||
'nfs=nova.virt.libvirt.volume.LibvirtNFSVolumeDriver',
|
||||
'aoe=nova.virt.libvirt.volume.LibvirtAOEVolumeDriver'
|
||||
],
|
||||
help='Libvirt handlers for remote volumes.'),
|
||||
cfg.StrOpt('libvirt_disk_prefix',
|
||||
|
||||
@@ -50,6 +50,9 @@ volume_opts = [
|
||||
default=None,
|
||||
help='Mount options passed to the nfs client. See section '
|
||||
'of the nfs man page for details'),
|
||||
cfg.StrOpt('num_aoe_discover_tries',
|
||||
default=3,
|
||||
help='number of times to rediscover AoE target to find volume')
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
@@ -315,3 +318,68 @@ class LibvirtNFSVolumeDriver(LibvirtBaseVolumeDriver):
|
||||
return utils.execute('stat', path, run_as_root=True)
|
||||
except exception.ProcessExecutionError:
|
||||
return False
|
||||
|
||||
|
||||
class LibvirtAOEVolumeDriver(LibvirtBaseVolumeDriver):
|
||||
"""Driver to attach AoE volumes to libvirt."""
|
||||
def __init__(self, connection):
|
||||
super(LibvirtAOEVolumeDriver,
|
||||
self).__init__(connection, is_block_dev=True)
|
||||
|
||||
def _aoe_discover(self):
|
||||
"""Call aoe-discover (aoe-tools) AoE Discover."""
|
||||
(out, err) = utils.execute('aoe-discover',
|
||||
run_as_root=True, check_exit_code=0)
|
||||
return (out, err)
|
||||
|
||||
def _aoe_revalidate(self, aoedev):
|
||||
"""Revalidate the LUN Geometry (When an AoE ID is reused)."""
|
||||
(out, err) = utils.execute('aoe-revalidate', aoedev,
|
||||
run_as_root=True, check_exit_code=0)
|
||||
return (out, err)
|
||||
|
||||
def connect_volume(self, connection_info, mount_device):
|
||||
shelf = connection_info['data']['target_shelf']
|
||||
lun = connection_info['data']['target_lun']
|
||||
aoedev = 'e%s.%s' % (shelf, lun)
|
||||
aoedevpath = '/dev/etherd/%s' % (aoedev)
|
||||
|
||||
if os.path.exists(aoedevpath):
|
||||
# NOTE(jbr_): If aoedevpath already exists, revalidate the LUN.
|
||||
self._aoe_revalidate(aoedev)
|
||||
else:
|
||||
# NOTE(jbr_): If aoedevpath does not exist, do a discover.
|
||||
self._aoe_discover()
|
||||
|
||||
#NOTE(jbr_): Device path is not always present immediately
|
||||
def _wait_for_device_discovery(aoedevpath, mount_device):
|
||||
tries = self.tries
|
||||
if os.path.exists(aoedevpath):
|
||||
raise utils.LoopingCallDone()
|
||||
|
||||
if self.tries >= CONF.num_aoe_discover_tries:
|
||||
raise exception.NovaException(_("AoE device not found at %s") %
|
||||
(aoedevpath))
|
||||
LOG.warn(_("AoE volume not yet found at: %(aoedevpath)s. "
|
||||
"Try number: %(tries)s") %
|
||||
locals())
|
||||
|
||||
self._aoe_discover()
|
||||
self.tries = self.tries + 1
|
||||
|
||||
self.tries = 0
|
||||
timer = utils.FixedIntervalLoopingCall(_wait_for_device_discovery,
|
||||
aoedevpath, mount_device)
|
||||
timer.start(interval=2).wait()
|
||||
|
||||
tries = self.tries
|
||||
if tries != 0:
|
||||
LOG.debug(_("Found AoE device %(aoedevpath)s "
|
||||
"(after %(tries)s rediscover)") %
|
||||
locals())
|
||||
|
||||
conf = super(LibvirtAOEVolumeDriver,
|
||||
self).connect_volume(connection_info, mount_device)
|
||||
conf.source_type = "block"
|
||||
conf.source_path = aoedevpath
|
||||
return conf
|
||||
|
||||
Reference in New Issue
Block a user