diff --git a/nova/tests/unit/virt/libvirt/volume/test_drbd.py b/nova/tests/unit/virt/libvirt/volume/test_drbd.py new file mode 100644 index 0000000000..759e992442 --- /dev/null +++ b/nova/tests/unit/virt/libvirt/volume/test_drbd.py @@ -0,0 +1,63 @@ +# Copyright (c) 2015 LINBIT HA-Solutions GmbH. +# 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. +"""Unit tests for the DRDB volume driver module.""" + +import mock +from os_brick.initiator import connector + +from nova import context as nova_context +from nova.tests.unit import fake_instance +from nova.tests.unit.virt.libvirt.volume import test_volume +from nova.virt.libvirt.volume import drbd + + +class LibvirtDRBDVolumeDriverTestCase( + test_volume.LibvirtVolumeBaseTestCase): + """Tests the LibvirtDRBDVolumeDriver class.""" + + def test_libvirt_drbd_driver(self): + drbd_driver = drbd.LibvirtDRBDVolumeDriver(self.fake_host) + self.assertIsInstance(drbd_driver.connector, connector.DRBDConnector) + # connect a fake volume + connection_info = { + 'data': { + 'device': '/path/to/fake-device' + } + } + ctxt = nova_context.RequestContext('fake-user', 'fake-project') + instance = fake_instance.fake_instance_obj(ctxt) + device_info = { + 'type': 'block', + 'path': connection_info['data']['device'], + } + with mock.patch.object(connector.DRBDConnector, 'connect_volume', + return_value=device_info): + drbd_driver.connect_volume( + connection_info, self.disk_info, instance) + # assert that the device_path was set + self.assertIn('device_path', connection_info['data']) + self.assertEqual('/path/to/fake-device', + connection_info['data']['device_path']) + # now get the config using the updated connection_info + conf = drbd_driver.get_config(connection_info, self.disk_info) + # assert things were passed through to the parent class + self.assertEqual('block', conf.source_type) + self.assertEqual('/path/to/fake-device', conf.source_path) + # now disconnect the volume + with mock.patch.object(connector.DRBDConnector, + 'disconnect_volume') as mock_disconnect: + drbd_driver.disconnect_volume(connection_info, 'vda', instance) + # disconnect is all passthrough so just assert the call + mock_disconnect.assert_called_once_with(connection_info['data'], None) diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 55e8bc27a2..e499a7b02b 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -150,6 +150,7 @@ libvirt_volume_drivers = [ 'iscsi=nova.virt.libvirt.volume.iscsi.LibvirtISCSIVolumeDriver', 'iser=nova.virt.libvirt.volume.iser.LibvirtISERVolumeDriver', 'local=nova.virt.libvirt.volume.volume.LibvirtVolumeDriver', + 'drbd=nova.virt.libvirt.volume.drbd.LibvirtDRBDVolumeDriver', 'fake=nova.virt.libvirt.volume.volume.LibvirtFakeVolumeDriver', 'rbd=nova.virt.libvirt.volume.net.LibvirtNetVolumeDriver', 'sheepdog=nova.virt.libvirt.volume.net.LibvirtNetVolumeDriver', diff --git a/nova/virt/libvirt/volume/drbd.py b/nova/virt/libvirt/volume/drbd.py new file mode 100644 index 0000000000..8d4a64bce1 --- /dev/null +++ b/nova/virt/libvirt/volume/drbd.py @@ -0,0 +1,61 @@ +# 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. + +from os_brick.initiator import connector +from oslo_log import log as logging + +from nova import utils +from nova.virt.libvirt.volume import volume as libvirt_volume + + +LOG = logging.getLogger(__name__) + + +class LibvirtDRBDVolumeDriver(libvirt_volume.LibvirtVolumeDriver): + """Driver to attach DRBD volumes to libvirt.""" + + def __init__(self, host): + super(LibvirtDRBDVolumeDriver, self).__init__(host) + self.connector = connector.InitiatorConnector.factory( + connector.DRBD, utils.get_root_helper()) + + def connect_volume(self, connection_info, disk_info, instance): + """Connect the volume. + + Sets the connection_info['data']['device_path'] value upon successful + connection. + + :param connection_info: dict of connection information for the backend + storage when a connection was initiated with Cinder. Expects + connection_info['data']['device'] to be set. + :param disk_info: dict of block device information (not used). + :param instance: The nova.objects.Instance that is having a volume + connected to it. + """ + LOG.debug("Calling os-brick to attach DRBD Volume.", instance=instance) + device_info = self.connector.connect_volume(connection_info['data']) + LOG.debug("Attached DRBD volume %s", device_info, instance=instance) + connection_info['data']['device_path'] = device_info['path'] + + def disconnect_volume(self, connection_info, disk_dev, instance): + """Disconnect the volume. + + :param connection_info: dict of connection information for the backend + storage when a connection was initiated with Cinder. + :param disk_dev: The block device mountpoint device name (not path). + This is currently not used by this method. + :param instance: The nova.objects.Instance that is having a volume + disconnected from it. + """ + LOG.debug("Calling os-brick to detach DRBD Volume.", instance=instance) + self.connector.disconnect_volume(connection_info['data'], None) + LOG.debug("Disconnected DRBD Volume %s", disk_dev, instance=instance) diff --git a/releasenotes/notes/drbd-libvirt-volume-driver-d27c79e62c0beb64.yaml b/releasenotes/notes/drbd-libvirt-volume-driver-d27c79e62c0beb64.yaml new file mode 100644 index 0000000000..9e5db154cc --- /dev/null +++ b/releasenotes/notes/drbd-libvirt-volume-driver-d27c79e62c0beb64.yaml @@ -0,0 +1,7 @@ +--- +features: + - | + The libvirt compute driver now supports attaching volumes of type "drbd". + See the `DRBD documentation`_ for more information. + + .. _DRBD documentation: http://docs.linbit.com/docs/users-guide-9.0/p-apps/#s-openstack-transport-protocol