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:
parent
a1eca94d89
commit
562a04091f
63
nova/tests/unit/virt/libvirt/volume/test_drbd.py
Normal file
63
nova/tests/unit/virt/libvirt/volume/test_drbd.py
Normal 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)
|
@ -150,6 +150,7 @@ libvirt_volume_drivers = [
|
|||||||
'iscsi=nova.virt.libvirt.volume.iscsi.LibvirtISCSIVolumeDriver',
|
'iscsi=nova.virt.libvirt.volume.iscsi.LibvirtISCSIVolumeDriver',
|
||||||
'iser=nova.virt.libvirt.volume.iser.LibvirtISERVolumeDriver',
|
'iser=nova.virt.libvirt.volume.iser.LibvirtISERVolumeDriver',
|
||||||
'local=nova.virt.libvirt.volume.volume.LibvirtVolumeDriver',
|
'local=nova.virt.libvirt.volume.volume.LibvirtVolumeDriver',
|
||||||
|
'drbd=nova.virt.libvirt.volume.drbd.LibvirtDRBDVolumeDriver',
|
||||||
'fake=nova.virt.libvirt.volume.volume.LibvirtFakeVolumeDriver',
|
'fake=nova.virt.libvirt.volume.volume.LibvirtFakeVolumeDriver',
|
||||||
'rbd=nova.virt.libvirt.volume.net.LibvirtNetVolumeDriver',
|
'rbd=nova.virt.libvirt.volume.net.LibvirtNetVolumeDriver',
|
||||||
'sheepdog=nova.virt.libvirt.volume.net.LibvirtNetVolumeDriver',
|
'sheepdog=nova.virt.libvirt.volume.net.LibvirtNetVolumeDriver',
|
||||||
|
61
nova/virt/libvirt/volume/drbd.py
Normal file
61
nova/virt/libvirt/volume/drbd.py
Normal 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)
|
@ -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
|
Loading…
Reference in New Issue
Block a user