Lightbits LightOS driver

This commit introduces the LightOS driver for nova. LightOS is a
software-defined disaggregated clustered storage solution running on
commodity servers with commodity SSDs. It it developed by Lightbits
Labs (https://www.lightbitslabs.com) and is actively developed and
maintained. LightOS is proprietary but the openstack drivers are
licensed under Apache v2.0.

The Cinder driver for LightOS currently supports the following
functionality:

Create volume
Delete volume
Attach volume
Detach volume
Create image from volume
create volume from image
Live migration
Volume replication
Thin provisioning
Multi-attach
Extend volume
Create snapshot
Delete snapshot
Create volume from snapshot
Create volume from volume (clone)

This driver has been developed and has been in use for a couple of
years by Lightbits and our clients. We have tested it extensively
internally with multiple openstack versions, including Queens, Rocky,
Stein, and Train. We have also tested it with master (19.1 xena) and we
are working to extend testing to cover additional openstack releases.

We are glad to join the openstack community and hope to get your
feedback and comments on this driver, and if it is acceptable, to see
it merged into the tree.

Note: the patch depends on os-brick 5.2.0. That version also increased
the lower constraints of several dependencies, thus needs nova to
increase those as well in requirements.txt, lower-constraints.txt and
setup.cfg.

Depends-On: I2e86fa84049053b7c75421d33ad1a1af459ef4e0
Signed-off-by: Yuval Brave  yuval@lightbitslabs.com
Change-Id: Ic314b26695d9681d31a18adcec0794c2ff41fe71
This commit is contained in:
yuval brave 2021-12-13 18:13:19 +02:00 committed by Elod Illes
parent 0c31561792
commit b5e2128f38
6 changed files with 167 additions and 22 deletions

View File

@ -58,31 +58,31 @@ netifaces==0.10.4
networkx==2.1.0
numpy==1.19.0
openstacksdk==0.35.0
os-brick==4.3.1
os-brick==5.2
os-client-config==1.29.0
os-resource-classes==1.1.0
os-service-types==1.7.0
os-traits==2.7.0
os-vif==1.15.2
os-win==5.4.0
os-win==5.5.0
osc-lib==1.10.0
oslo.cache==1.26.0
oslo.concurrency==4.4.0
oslo.concurrency==4.5.0
oslo.config==8.6.0
oslo.context==3.1.1
oslo.context==3.4.0
oslo.db==10.0.0
oslo.i18n==5.0.1
oslo.log==4.4.0
oslo.i18n==5.1.0
oslo.log==4.6.1
oslo.messaging==10.3.0
oslo.middleware==3.31.0
oslo.policy==3.7.0
oslo.privsep==2.4.0
oslo.privsep==2.6.2
oslo.reports==1.18.0
oslo.rootwrap==5.8.0
oslo.serialization==4.1.0
oslo.service==2.5.0
oslo.serialization==4.2.0
oslo.service==2.8.0
oslo.upgradecheck==1.3.0
oslo.utils==4.8.0
oslo.utils==4.12.1
oslo.versionedobjects==1.35.0
oslo.vmware==3.6.0
oslotest==3.8.0
@ -93,7 +93,7 @@ packaging==20.4
paramiko==2.7.1
Paste==2.0.2
PasteDeploy==1.5.0
pbr==5.5.1
pbr==5.8.0
pluggy==0.6.0
ply==3.11
prettytable==0.7.1

View File

@ -0,0 +1,81 @@
# 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 lightos
from os_brick import initiator
class LibvirtLightVolumeDriverTestCase(test_volume.LibvirtVolumeBaseTestCase):
@mock.patch('queue.Queue', return_value='queue')
@mock.patch('nova.utils.get_root_helper')
@mock.patch('os_brick.initiator.connector.InitiatorConnector.factory')
def test_libvirt_lightos_driver(self, mock_factory, mock_helper,
queue):
self.flags(group='libvirt')
mock_helper.return_value = 'sudo'
lightos.LibvirtLightOSVolumeDriver(self.fake_host)
mock_factory.assert_called_once_with(
initiator.LIGHTOS, root_helper='sudo',
device_scan_attempts=5)
@mock.patch('os_brick.initiator.connector.InitiatorConnector.factory',
new=mock.Mock(return_value=mock.Mock()))
def test_libvirt_lightos_driver_connect(self):
lightos_driver = lightos.LibvirtLightOSVolumeDriver(
self.fake_host)
config = {'server_ip': '127.0.0.1', 'server_port': 9898}
disk_info = {
'id': '1234567',
'name': 'aLightVolume',
'conf': config}
connection_info = {'data': disk_info}
with mock.patch.object(lightos_driver.connector,
'connect_volume',
return_value={'path': '/dev/dms1234567'}):
lightos_driver.connect_volume(connection_info, None)
(lightos_driver.connector.connect_volume.
assert_called_once_with(
connection_info['data']))
self.assertEqual('/dev/dms1234567',
connection_info['data']['device_path'])
@mock.patch('os_brick.initiator.connector.InitiatorConnector.factory',
new=mock.Mock(return_value=mock.Mock()))
def test_libvirt_lightos_driver_disconnect(self):
lightos_driver = lightos.LibvirtLightOSVolumeDriver(self.connr)
disk_info = {
'path': '/dev/dms1234567', 'name': 'aLightosVolume',
'type': 'raw', 'dev': 'vda1', 'bus': 'pci0',
'device_path': '/dev/dms123456'}
connection_info = {'data': disk_info}
lightos_driver.disconnect_volume(connection_info, None)
lightos_driver.connector.disconnect_volume.assert_called_once_with(
disk_info, None)
@mock.patch('os_brick.initiator.connector.InitiatorConnector.factory',
new=mock.Mock(return_value=mock.Mock()))
def test_libvirt_lightos_driver_get_config(self):
lightos_driver = lightos.LibvirtLightOSVolumeDriver(self.fake_host)
device_path = '/dev/fake-dev'
connection_info = {'data': {'device_path': device_path}}
conf = lightos_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'))

View File

@ -188,6 +188,7 @@ VOLUME_DRIVERS = {
'vzstorage': 'nova.virt.libvirt.volume.vzstorage.LibvirtVZStorageVolumeDriver', # noqa:E501
'storpool': 'nova.virt.libvirt.volume.storpool.LibvirtStorPoolVolumeDriver', # noqa:E501
'nvmeof': 'nova.virt.libvirt.volume.nvme.LibvirtNVMEVolumeDriver',
'lightos': 'nova.virt.libvirt.volume.lightos.LibvirtLightOSVolumeDriver',
}

View File

@ -0,0 +1,63 @@
# Copyright (C) 2016-2020 Lightbits Labs Ltd.
# Copyright (C) 2020 Intel Corporation
# All Rights Reserved.
#
# 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 LibvirtLightOSVolumeDriver(libvirt_volume.LibvirtVolumeDriver):
"""Driver to attach NVMe volumes to libvirt."""
VERSION = '2.3.12'
def __init__(self, connection):
super(LibvirtLightOSVolumeDriver, self).__init__(connection)
self.connector = connector.InitiatorConnector.factory(
initiator.LIGHTOS,
root_helper=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. instance:%s, volume_id:%s",
connection_info.get("instance", ""),
connection_info.get("volume_id", ""))
self.connector.disconnect_volume(connection_info['data'], None)
super(LibvirtLightOSVolumeDriver, self).disconnect_volume(
connection_info, instance)
def extend_volume(self, connection_info, instance, requested_size=None):
"""Extend the volume."""
LOG.debug("calling os-brick to extend LightOS Volume."
"instance:%s, volume_id:%s",
connection_info.get("instance", ""),
connection_info.get("volume_id", ""))
new_size = self.connector.extend_volume(connection_info['data'])
LOG.debug("Extend LightOS Volume %s; new_size=%s",
connection_info['data']['device_path'], new_size)
return new_size

View File

@ -1,4 +1,4 @@
pbr>=5.5.1 # Apache-2.0
pbr>=5.8.0 # Apache-2.0
SQLAlchemy>=1.4.13 # MIT
decorator>=4.1.0 # BSD
eventlet>=0.30.1 # MIT
@ -27,26 +27,26 @@ requests>=2.25.1 # Apache-2.0
stevedore>=1.20.0 # Apache-2.0
websockify>=0.9.0 # LGPLv3
oslo.cache>=1.26.0 # Apache-2.0
oslo.concurrency>=4.4.0 # Apache-2.0
oslo.concurrency>=4.5.0 # Apache-2.0
oslo.config>=8.6.0 # Apache-2.0
oslo.context>=3.1.1 # Apache-2.0
oslo.log>=4.4.0 # Apache-2.0
oslo.context>=3.4.0 # Apache-2.0
oslo.log>=4.6.1 # Apache-2.0
oslo.reports>=1.18.0 # Apache-2.0
oslo.serialization>=4.1.0 # Apache-2.0
oslo.serialization>=4.2.0 # Apache-2.0
oslo.upgradecheck>=1.3.0
oslo.utils>=4.8.0 # Apache-2.0
oslo.utils>=4.12.1 # Apache-2.0
oslo.db>=10.0.0 # Apache-2.0
oslo.rootwrap>=5.8.0 # Apache-2.0
oslo.messaging>=10.3.0 # Apache-2.0
oslo.policy>=3.7.0 # Apache-2.0
oslo.privsep>=2.4.0 # Apache-2.0
oslo.i18n>=5.0.1 # Apache-2.0
oslo.service>=2.5.0 # Apache-2.0
oslo.privsep>=2.6.2 # Apache-2.0
oslo.i18n>=5.1.0 # Apache-2.0
oslo.service>=2.8.0 # Apache-2.0
rfc3986>=1.2.0 # Apache-2.0
oslo.middleware>=3.31.0 # Apache-2.0
psutil>=3.2.2 # BSD
oslo.versionedobjects>=1.35.0 # Apache-2.0
os-brick>=4.3.1 # Apache-2.0
os-brick>=5.2 # Apache-2.0
os-resource-classes>=1.1.0 # Apache-2.0
os-traits>=2.7.0 # Apache-2.0
os-vif>=1.15.2 # Apache-2.0

View File

@ -35,7 +35,7 @@ powervm =
zvm =
zVMCloudConnector>=1.3.0;sys_platform!='win32' # Apache 2.0 License
hyperv =
os-win>=5.4.0 # Apache-2.0
os-win>=5.5.0 # Apache-2.0
vmware =
oslo.vmware>=3.6.0 # Apache-2.0