Local attach feature in RBD connector
We use RBD kernel module to attach and detach volumes locally without Nova. Change-Id: Iab9b62115f61e334c35003d55a47375cb2eee684
This commit is contained in:
parent
cde2644a91
commit
7a3b7961d3
@ -1974,15 +1974,15 @@ class RBDConnector(BaseLinuxConnector):
|
||||
device_scan_attempts=
|
||||
device_scan_attempts,
|
||||
*args, **kwargs)
|
||||
self.do_local_attach = kwargs.get('do_local_attach', False)
|
||||
|
||||
@staticmethod
|
||||
def get_connector_properties(root_helper, *args, **kwargs):
|
||||
"""The RBD connector properties."""
|
||||
return {}
|
||||
return {'do_local_attach': kwargs.get('do_local_attach', False)}
|
||||
|
||||
def get_volume_paths(self, connection_properties):
|
||||
# TODO(walter-boring): don't know where the connector
|
||||
# looks for RBD volumes.
|
||||
# TODO(e0ne): Implement this for local volume.
|
||||
return []
|
||||
|
||||
def get_search_path(self):
|
||||
@ -1991,7 +1991,7 @@ class RBDConnector(BaseLinuxConnector):
|
||||
return None
|
||||
|
||||
def get_all_available_volumes(self, connection_properties=None):
|
||||
# TODO(walter-boring): not sure what to return here for RBD
|
||||
# TODO(e0ne): Implement this for local volumes.
|
||||
return []
|
||||
|
||||
def _get_rbd_handle(self, connection_properties):
|
||||
@ -2009,6 +2009,17 @@ class RBDConnector(BaseLinuxConnector):
|
||||
linuxrbd.RBDImageMetadata(rbd_volume, pool, user, conf))
|
||||
return rbd_handle
|
||||
|
||||
@staticmethod
|
||||
def get_rbd_device_name(pool, volume):
|
||||
"""Return device name which will be generated by RBD kernel module.
|
||||
|
||||
:param pool: RBD pool name.
|
||||
:type pool: string
|
||||
:param volume: RBD image name.
|
||||
:type volume: string
|
||||
"""
|
||||
return '/dev/rbd/{pool}/{volume}'.format(pool=pool, volume=volume)
|
||||
|
||||
@utils.trace
|
||||
def connect_volume(self, connection_properties):
|
||||
"""Connect to a volume.
|
||||
@ -2019,6 +2030,29 @@ class RBDConnector(BaseLinuxConnector):
|
||||
:returns: dict
|
||||
"""
|
||||
|
||||
do_local_attach = connection_properties.get('do_local_attach',
|
||||
self.do_local_attach)
|
||||
|
||||
if do_local_attach:
|
||||
# NOTE(e0ne): sanity check if ceph-common is installed.
|
||||
cmd = ['which', 'rbd']
|
||||
try:
|
||||
self._execute(*cmd)
|
||||
except putils.ProcessExecutionError:
|
||||
msg = _("ceph-common package is not installed.")
|
||||
LOG.error(msg)
|
||||
raise exception.BrickException(message=msg)
|
||||
|
||||
# NOTE(e0ne): map volume to a block device
|
||||
# via the rbd kernel module.
|
||||
pool, volume = connection_properties['name'].split('/')
|
||||
cmd = ['rbd', 'map', volume, '--pool', pool]
|
||||
self._execute(*cmd, root_helper=self._root_helper,
|
||||
run_as_root=True)
|
||||
|
||||
return {'path': RBDConnector.get_rbd_device_name(pool, volume),
|
||||
'type': 'block'}
|
||||
|
||||
rbd_handle = self._get_rbd_handle(connection_properties)
|
||||
return {'path': rbd_handle}
|
||||
|
||||
@ -2032,10 +2066,19 @@ class RBDConnector(BaseLinuxConnector):
|
||||
:param device_info: historical difference, but same as connection_props
|
||||
:type device_info: dict
|
||||
"""
|
||||
if device_info:
|
||||
rbd_handle = device_info.get('path', None)
|
||||
if rbd_handle is not None:
|
||||
rbd_handle.close()
|
||||
do_local_attach = connection_properties.get('do_local_attach',
|
||||
self.do_local_attach)
|
||||
if do_local_attach:
|
||||
pool, volume = connection_properties['name'].split('/')
|
||||
dev_name = RBDConnector.get_rbd_device_name(pool, volume)
|
||||
cmd = ['rbd', 'unmap', dev_name]
|
||||
self._execute(*cmd, root_helper=self._root_helper,
|
||||
run_as_root=True)
|
||||
else:
|
||||
if device_info:
|
||||
rbd_handle = device_info.get('path', None)
|
||||
if rbd_handle is not None:
|
||||
rbd_handle.close()
|
||||
|
||||
def check_valid_device(self, path, run_as_root=True):
|
||||
"""Verify an existing RBD handle is connected and valid."""
|
||||
|
@ -75,7 +75,8 @@ class ConnectorUtilsTestCase(base.TestCase):
|
||||
'ip': MY_IP,
|
||||
'multipath': multipath_result,
|
||||
'os_type': os_type,
|
||||
'platform': platform}
|
||||
'platform': platform,
|
||||
'do_local_attach': False}
|
||||
self.assertEqual(props, props_actual)
|
||||
|
||||
def test_brick_get_connector_properties_connectors_called(self):
|
||||
@ -2395,7 +2396,7 @@ class RBDConnectorTestCase(ConnectorTestCase):
|
||||
props = connector.RBDConnector.get_connector_properties(
|
||||
'sudo', multipath=True, enforce_multipath=True)
|
||||
|
||||
expected_props = {}
|
||||
expected_props = {'do_local_attach': False}
|
||||
self.assertEqual(expected_props, props)
|
||||
|
||||
@mock.patch('os_brick.initiator.linuxrbd.rbd')
|
||||
@ -2426,6 +2427,19 @@ class RBDConnectorTestCase(ConnectorTestCase):
|
||||
self.assertTrue(isinstance(device_info['path'],
|
||||
linuxrbd.RBDVolumeIOWrapper))
|
||||
|
||||
@mock.patch.object(priv_rootwrap, 'execute')
|
||||
def test_connect_local_volume(self, mock_execute):
|
||||
rbd = connector.RBDConnector(None, do_local_attach=True)
|
||||
conn = {'name': 'pool/image'}
|
||||
device_info = rbd.connect_volume(conn)
|
||||
execute_call1 = mock.call('which', 'rbd')
|
||||
cmd = ['rbd', 'map', 'image', '--pool', 'pool']
|
||||
execute_call2 = mock.call(*cmd, root_helper=None, run_as_root=True)
|
||||
mock_execute.assert_has_calls([execute_call1, execute_call2])
|
||||
expected_info = {'path': '/dev/rbd/pool/image',
|
||||
'type': 'block'}
|
||||
self.assertEqual(expected_info, device_info)
|
||||
|
||||
@mock.patch('os_brick.initiator.linuxrbd.rbd')
|
||||
@mock.patch('os_brick.initiator.linuxrbd.rados')
|
||||
@mock.patch.object(linuxrbd.RBDVolumeIOWrapper, 'close')
|
||||
@ -2437,6 +2451,17 @@ class RBDConnectorTestCase(ConnectorTestCase):
|
||||
|
||||
self.assertEqual(1, volume_close.call_count)
|
||||
|
||||
@mock.patch.object(priv_rootwrap, 'execute')
|
||||
def test_disconnect_local_volume(self, mock_execute):
|
||||
rbd = connector.RBDConnector(None, do_local_attach=True)
|
||||
conn = {'name': 'pool/image'}
|
||||
rbd.disconnect_volume(conn, None)
|
||||
|
||||
dev_name = '/dev/rbd/pool/image'
|
||||
cmd = ['rbd', 'unmap', dev_name]
|
||||
mock_execute.assert_called_once_with(*cmd, root_helper=None,
|
||||
run_as_root=True)
|
||||
|
||||
def test_extend_volume(self):
|
||||
rbd = connector.RBDConnector(None)
|
||||
self.assertRaises(NotImplementedError,
|
||||
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
features:
|
||||
- Local attach feature in RBD connector.
|
||||
We use RBD kernel module to attach and detach volumes locally without
|
||||
Nova.
|
Loading…
Reference in New Issue
Block a user