diff options
-rw-r--r-- | etc/nova/rootwrap.d/compute.filters | 5 | ||||
-rw-r--r-- | nova/tests/test_libvirt_volume.py | 28 | ||||
-rw-r--r-- | nova/virt/libvirt/driver.py | 3 | ||||
-rw-r--r-- | nova/virt/libvirt/volume.py | 68 |
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 |