summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--etc/nova/rootwrap.d/compute.filters5
-rw-r--r--nova/tests/test_libvirt_volume.py28
-rw-r--r--nova/virt/libvirt/driver.py3
-rw-r--r--nova/virt/libvirt/volume.py68
4 files changed, 103 insertions, 1 deletions
diff --git a/etc/nova/rootwrap.d/compute.filters b/etc/nova/rootwrap.d/compute.filters
index 9562a23aa..6396315b9 100644
--- a/etc/nova/rootwrap.d/compute.filters
+++ b/etc/nova/rootwrap.d/compute.filters
@@ -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
diff --git a/nova/tests/test_libvirt_volume.py b/nova/tests/test_libvirt_volume.py
index 6cc8ee2f6..6b93729e5 100644
--- a/nova/tests/test_libvirt_volume.py
+++ b/nova/tests/test_libvirt_volume.py
@@ -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")
diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py
index fef44d6b6..ae240657d 100644
--- a/nova/virt/libvirt/driver.py
+++ b/nova/virt/libvirt/driver.py
@@ -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',
diff --git a/nova/virt/libvirt/volume.py b/nova/virt/libvirt/volume.py
index f8ed95e0f..886371aad 100644
--- a/nova/virt/libvirt/volume.py
+++ b/nova/virt/libvirt/volume.py
@@ -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