Connecting Nova to DRBD storage nodes directly

Our DRBD block storage driver for Cinder can be used to make
Nova directly connect to the DRBD 9 storage servers, instead
of needing an iSCSI hop.

Co-Authored-By: Matt Riedemann <mriedem.os@gmail.com>

Change-Id: I60477778a73701794db0c0860183ea9ab144040b
Implements: blueprint drbd-driver
This commit is contained in:
Philipp Marek 2016-05-19 19:44:02 +02:00 committed by Matt Riedemann
parent a1eca94d89
commit 562a04091f
4 changed files with 132 additions and 0 deletions

View File

@ -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)

View File

@ -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',

View File

@ -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)

View File

@ -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