From a833bcd05f811325f40cb3c8cce7f94c93cd6b6e Mon Sep 17 00:00:00 2001 From: Rawan Herzallah Date: Tue, 11 Jul 2017 20:18:07 +0300 Subject: [PATCH] Adding NVMEoF for libvirt driver Adding NVMEoF libvirt driver for supporting NVMEoF initiator CLI. Libvirt NVMe volume driver is added to handle required calls for attaching and detaching volume from instaces through calling os-brick's NVMe Connector. Implements: blueprint nvme-over-fabirc-nova Co-Authored-By: Ivan Kolodyazhny Change-Id: I67a72c4226e54c18b3a6e4a13b5055fa6e85af09 --- lower-constraints.txt | 2 +- nova/conf/libvirt.py | 13 ++++ .../unit/virt/libvirt/volume/test_nvme.py | 66 +++++++++++++++++++ nova/virt/libvirt/driver.py | 1 + nova/virt/libvirt/volume/nvme.py | 63 ++++++++++++++++++ ...vme-over-fabric-nova-ae1ef46fb5a7fc02.yaml | 4 ++ requirements.txt | 2 +- 7 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 nova/tests/unit/virt/libvirt/volume/test_nvme.py create mode 100644 nova/virt/libvirt/volume/nvme.py create mode 100644 releasenotes/notes/bp-nvme-over-fabric-nova-ae1ef46fb5a7fc02.yaml diff --git a/lower-constraints.txt b/lower-constraints.txt index 2d464e0afe96..99b46bfaae04 100644 --- a/lower-constraints.txt +++ b/lower-constraints.txt @@ -66,7 +66,7 @@ netifaces==0.10.4 networkx==1.11 numpy==1.14.2 openstacksdk==0.12.0 -os-brick==2.4.0 +os-brick==2.5.0 os-client-config==1.29.0 os-service-types==1.2.0 os-traits==0.4.0 diff --git a/nova/conf/libvirt.py b/nova/conf/libvirt.py index 8349455d062e..af96840db9c1 100644 --- a/nova/conf/libvirt.py +++ b/nova/conf/libvirt.py @@ -1190,6 +1190,18 @@ v2.10."""), ] +libvirt_volume_nvmeof_opts = [ + cfg.IntOpt('num_nvme_discover_tries', + default=3, + help=""" +Number of times to rediscover NVMe target to find volume + +Nova provides support for block storage attaching to hosts via NVMe +(Non-Volatile Memory Express). This option allows the user to specify the +maximum number of retry attempts that can be made to discover the NVMe device. +"""), +] + ALL_OPTS = list(itertools.chain( libvirt_general_opts, libvirt_imagebackend_opts, @@ -1208,6 +1220,7 @@ ALL_OPTS = list(itertools.chain( libvirt_remotefs_opts, libvirt_volume_vzstorage_opts, libvirt_virtio_queue_sizes, + libvirt_volume_nvmeof_opts, )) diff --git a/nova/tests/unit/virt/libvirt/volume/test_nvme.py b/nova/tests/unit/virt/libvirt/volume/test_nvme.py new file mode 100644 index 000000000000..997c914927ae --- /dev/null +++ b/nova/tests/unit/virt/libvirt/volume/test_nvme.py @@ -0,0 +1,66 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import mock + +from nova.tests.unit.virt.libvirt.volume import test_volume +from nova.virt.libvirt.volume import nvme + +from os_brick.initiator import connector + + +class LibvirtNVMEVolumeDriverTestCase(test_volume.LibvirtVolumeBaseTestCase): + + @mock.patch('os.path.exists', return_value=True) + def test_libvirt_nvme_driver(self, exists): + libvirt_driver = nvme.LibvirtNVMEVolumeDriver(self.fake_host) + self.assertIsInstance(libvirt_driver.connector, + connector.NVMeConnector) + + def test_libvirt_nvme_driver_connect(self): + nvme_driver = nvme.LibvirtNVMEVolumeDriver(self.fake_host) + config = {'server_ip': '127.0.0.1', 'server_port': 9898} + disk_info = { + 'id': '1234567', + 'name': 'aNVMEVolume', + 'conf': config} + connection_info = {'data': disk_info} + with mock.patch.object(nvme_driver.connector, + 'connect_volume', + return_value={'path': '/dev/dms1234567'}): + nvme_driver.connect_volume(connection_info, None) + self.assertEqual('/dev/dms1234567', + connection_info['data']['device_path']) + + def test_libvirt_nvme_driver_disconnect(self): + nvme_con = nvme.LibvirtNVMEVolumeDriver(self.connr) + nvme_con.connector.disconnect_volume = mock.MagicMock() + disk_info = { + 'path': '/dev/dms1234567', 'name': 'aNVMEVolume', + 'type': 'raw', 'dev': 'vda1', 'bus': 'pci0', + 'device_path': '/dev/dms123456'} + connection_info = {'data': disk_info} + nvme_con.disconnect_volume(connection_info, None) + nvme_con.connector.disconnect_volume.assert_called_once_with( + disk_info, None) + + def test_libvirt_nvme_driver_get_config(self): + nvme_driver = nvme.LibvirtNVMEVolumeDriver(self.fake_host) + device_path = '/dev/fake-dev' + connection_info = {'data': {'device_path': device_path}} + + conf = nvme_driver.get_config(connection_info, self.disk_info) + tree = conf.format_dom() + + self.assertEqual('block', tree.get('type')) + self.assertEqual(device_path, tree.find('./source').get('dev')) + self.assertEqual('raw', tree.find('./driver').get('type')) diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 4e3de8443502..9d283db1b674 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -187,6 +187,7 @@ libvirt_volume_drivers = [ 'nova.virt.libvirt.volume.vrtshyperscale.' 'LibvirtHyperScaleVolumeDriver', 'storpool=nova.virt.libvirt.volume.storpool.LibvirtStorPoolVolumeDriver', + 'nvmeof=nova.virt.libvirt.volume.nvme.LibvirtNVMEVolumeDriver', ] diff --git a/nova/virt/libvirt/volume/nvme.py b/nova/virt/libvirt/volume/nvme.py new file mode 100644 index 000000000000..8d20ab10d5ec --- /dev/null +++ b/nova/virt/libvirt/volume/nvme.py @@ -0,0 +1,63 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import nova.conf +from nova import utils +from nova.virt.libvirt.volume import volume as libvirt_volume + +from os_brick import initiator +from os_brick.initiator import connector + +from oslo_log import log as logging + +LOG = logging.getLogger(__name__) + +CONF = nova.conf.CONF + + +class LibvirtNVMEVolumeDriver(libvirt_volume.LibvirtVolumeDriver): + """Driver to attach NVMe volumes to libvirt.""" + + def __init__(self, connection): + super(LibvirtNVMEVolumeDriver, + self).__init__(connection) + + self.connector = connector.InitiatorConnector.factory( + initiator.NVME, utils.get_root_helper(), + device_scan_attempts=CONF.libvirt.num_nvme_discover_tries) + + def connect_volume(self, connection_info, instance): + + device_info = self.connector.connect_volume( + connection_info['data']) + LOG.debug( + "Connecting NVMe volume with device_info %s", + device_info) + + connection_info['data']['device_path'] = device_info['path'] + + def disconnect_volume(self, connection_info, instance): + """Detach the volume from the instance.""" + LOG.debug("Disconnecting NVMe disk") + self.connector.disconnect_volume( + connection_info['data'], None) + super(LibvirtNVMEVolumeDriver, + self).disconnect_volume(connection_info, instance) + + def extend_volume(self, connection_info, instance): + """Extend the volume.""" + LOG.debug("calling os-brick to extend NVMe Volume", instance=instance) + new_size = self.connector.extend_volume(connection_info['data']) + LOG.debug("Extend NVMe Volume %s; new_size=%s", + connection_info['data']['device_path'], + new_size, instance=instance) + return new_size diff --git a/releasenotes/notes/bp-nvme-over-fabric-nova-ae1ef46fb5a7fc02.yaml b/releasenotes/notes/bp-nvme-over-fabric-nova-ae1ef46fb5a7fc02.yaml new file mode 100644 index 000000000000..1ec6f33d0c01 --- /dev/null +++ b/releasenotes/notes/bp-nvme-over-fabric-nova-ae1ef46fb5a7fc02.yaml @@ -0,0 +1,4 @@ +--- +features: + - | + Added support for ``nvmeof`` type volumes to the libvirt driver. diff --git a/requirements.txt b/requirements.txt index 1b7631771ee2..43b82f6cfbbe 100644 --- a/requirements.txt +++ b/requirements.txt @@ -52,7 +52,7 @@ rfc3986>=0.3.1 # Apache-2.0 oslo.middleware>=3.31.0 # Apache-2.0 psutil>=3.2.2 # BSD oslo.versionedobjects>=1.31.2 # Apache-2.0 -os-brick>=2.4.0 # Apache-2.0 +os-brick>=2.5.0 # Apache-2.0 os-traits>=0.4.0 # Apache-2.0 os-vif!=1.8.0,>=1.7.0 # Apache-2.0 os-win>=3.0.0 # Apache-2.0