Merge "DRBD connector class"
This commit is contained in:
commit
7ca487a668
@ -58,6 +58,9 @@ drv_cfg: CommandFilter, /opt/emc/scaleio/sdc/bin/drv_cfg, root, /opt/emc/scaleio
|
|||||||
# initiator/connector.py
|
# initiator/connector.py
|
||||||
sds_cli: CommandFilter, /usr/local/bin/sds/sds_cli, root
|
sds_cli: CommandFilter, /usr/local/bin/sds/sds_cli, root
|
||||||
|
|
||||||
|
# initiator/connector.py
|
||||||
|
drbdadm: CommandFilter, drbdadm, root
|
||||||
|
|
||||||
# initiator/connector.py: 'vgc-cluster', 'domain-list', '-l'
|
# initiator/connector.py: 'vgc-cluster', 'domain-list', '-l'
|
||||||
# initiator/connector.py: 'vgc-cluster', 'space-set-apphosts', '-n'...
|
# initiator/connector.py: 'vgc-cluster', 'space-set-apphosts', '-n'...
|
||||||
vgc-cluster: CommandFilter, vgc-cluster, root
|
vgc-cluster: CommandFilter, vgc-cluster, root
|
||||||
|
@ -30,6 +30,7 @@ import re
|
|||||||
import requests
|
import requests
|
||||||
import socket
|
import socket
|
||||||
import sys
|
import sys
|
||||||
|
import tempfile
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from oslo_concurrency import lockutils
|
from oslo_concurrency import lockutils
|
||||||
@ -66,6 +67,7 @@ ISCSI = "ISCSI"
|
|||||||
ISER = "ISER"
|
ISER = "ISER"
|
||||||
FIBRE_CHANNEL = "FIBRE_CHANNEL"
|
FIBRE_CHANNEL = "FIBRE_CHANNEL"
|
||||||
AOE = "AOE"
|
AOE = "AOE"
|
||||||
|
DRBD = "DRBD"
|
||||||
NFS = "NFS"
|
NFS = "NFS"
|
||||||
GLUSTERFS = "GLUSTERFS"
|
GLUSTERFS = "GLUSTERFS"
|
||||||
LOCAL = "LOCAL"
|
LOCAL = "LOCAL"
|
||||||
@ -214,6 +216,11 @@ class InitiatorConnector(executor.Executor):
|
|||||||
execute=execute,
|
execute=execute,
|
||||||
device_scan_attempts=device_scan_attempts,
|
device_scan_attempts=device_scan_attempts,
|
||||||
*args, **kwargs)
|
*args, **kwargs)
|
||||||
|
elif protocol == DRBD:
|
||||||
|
return DRBDConnector(root_helper=root_helper,
|
||||||
|
driver=driver,
|
||||||
|
execute=execute,
|
||||||
|
*args, **kwargs)
|
||||||
elif protocol == LOCAL:
|
elif protocol == LOCAL:
|
||||||
return LocalConnector(root_helper=root_helper,
|
return LocalConnector(root_helper=root_helper,
|
||||||
driver=driver,
|
driver=driver,
|
||||||
@ -1885,6 +1892,83 @@ class LocalConnector(InitiatorConnector):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class DRBDConnector(InitiatorConnector):
|
||||||
|
""""Connector class to attach/detach DRBD resources."""
|
||||||
|
|
||||||
|
def __init__(self, root_helper, driver=None,
|
||||||
|
execute=putils.execute, *args, **kwargs):
|
||||||
|
|
||||||
|
super(DRBDConnector, self).__init__(root_helper, driver=driver,
|
||||||
|
execute=execute, *args, **kwargs)
|
||||||
|
|
||||||
|
self._execute = execute
|
||||||
|
self._root_helper = root_helper
|
||||||
|
|
||||||
|
def check_valid_device(self, path, run_as_root=True):
|
||||||
|
"""Verify an existing volume."""
|
||||||
|
# TODO(linbit): check via drbdsetup first, to avoid blocking/hanging
|
||||||
|
# in case of network problems?
|
||||||
|
|
||||||
|
return super(DRBDConnector, self).check_valid_device(path, run_as_root)
|
||||||
|
|
||||||
|
def get_all_available_volumes(self, connection_properties=None):
|
||||||
|
|
||||||
|
base = "/dev/"
|
||||||
|
blkdev_list = []
|
||||||
|
|
||||||
|
for e in os.listdir(base):
|
||||||
|
path = base + e
|
||||||
|
if os.path.isblk(path):
|
||||||
|
blkdev_list.append(path)
|
||||||
|
|
||||||
|
return blkdev_list
|
||||||
|
|
||||||
|
def _drbdadm_command(self, cmd, data_dict, sh_secret):
|
||||||
|
# TODO(linbit): Write that resource file to a permanent location?
|
||||||
|
tmp = tempfile.NamedTemporaryFile(suffix="res", delete=False, mode="w")
|
||||||
|
try:
|
||||||
|
kv = {'shared-secret': sh_secret}
|
||||||
|
tmp.write(data_dict['config'] % kv)
|
||||||
|
tmp.close()
|
||||||
|
|
||||||
|
(out, err) = self._execute('drbdadm', cmd,
|
||||||
|
"-c", tmp.name,
|
||||||
|
data_dict['name'],
|
||||||
|
run_as_root=True,
|
||||||
|
root_helper=self._root_helper)
|
||||||
|
finally:
|
||||||
|
os.unlink(tmp.name)
|
||||||
|
|
||||||
|
return (out, err)
|
||||||
|
|
||||||
|
def connect_volume(self, connection_properties):
|
||||||
|
"""Attach the volume."""
|
||||||
|
|
||||||
|
self._drbdadm_command("adjust", connection_properties,
|
||||||
|
connection_properties['provider_auth'])
|
||||||
|
|
||||||
|
device_info = {
|
||||||
|
'type': 'block',
|
||||||
|
'path': connection_properties['device'],
|
||||||
|
}
|
||||||
|
|
||||||
|
return device_info
|
||||||
|
|
||||||
|
def disconnect_volume(self, connection_properties, device_info):
|
||||||
|
"""Detach the volume."""
|
||||||
|
|
||||||
|
self._drbdadm_command("down", connection_properties,
|
||||||
|
connection_properties['provider_auth'])
|
||||||
|
|
||||||
|
def get_volume_paths(self, connection_properties):
|
||||||
|
path = connection_properties['device']
|
||||||
|
return [path]
|
||||||
|
|
||||||
|
def get_search_path(self):
|
||||||
|
# TODO(linbit): is it allowed to return "/dev", or is that too broad?
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class HuaweiStorHyperConnector(InitiatorConnector):
|
class HuaweiStorHyperConnector(InitiatorConnector):
|
||||||
""""Connector class to attach/detach SDSHypervisor volumes."""
|
""""Connector class to attach/detach SDSHypervisor volumes."""
|
||||||
attached_success_code = 0
|
attached_success_code = 0
|
||||||
|
@ -2045,6 +2045,66 @@ class RBDConnectorTestCase(ConnectorTestCase):
|
|||||||
self.assertEqual(1, volume_close.call_count)
|
self.assertEqual(1, volume_close.call_count)
|
||||||
|
|
||||||
|
|
||||||
|
class DRBDConnectorTestCase(ConnectorTestCase):
|
||||||
|
|
||||||
|
RESOURCE_TEMPLATE = '''
|
||||||
|
resource r0 {
|
||||||
|
on host1 {
|
||||||
|
}
|
||||||
|
net {
|
||||||
|
shared-secret "%(shared-secret)s";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(DRBDConnectorTestCase, self).setUp()
|
||||||
|
|
||||||
|
self.connector = connector.DRBDConnector(
|
||||||
|
None, execute=self._fake_exec)
|
||||||
|
|
||||||
|
self.execs = []
|
||||||
|
|
||||||
|
def _fake_exec(self, *cmd, **kwargs):
|
||||||
|
self.execs.append(cmd)
|
||||||
|
|
||||||
|
# out, err
|
||||||
|
return ('', '')
|
||||||
|
|
||||||
|
def test_connect_volume(self):
|
||||||
|
"""Test connect_volume."""
|
||||||
|
|
||||||
|
cprop = {
|
||||||
|
'provider_auth': 'my-secret',
|
||||||
|
'config': self.RESOURCE_TEMPLATE,
|
||||||
|
'name': 'my-precious',
|
||||||
|
'device': '/dev/drbd951722',
|
||||||
|
'data': {},
|
||||||
|
}
|
||||||
|
|
||||||
|
res = self.connector.connect_volume(cprop)
|
||||||
|
|
||||||
|
self.assertEqual(cprop['device'], res['path'])
|
||||||
|
self.assertEqual('adjust', self.execs[0][1])
|
||||||
|
self.assertEqual(cprop['name'], self.execs[0][4])
|
||||||
|
|
||||||
|
def test_disconnect_volume(self):
|
||||||
|
"""Test the disconnect volume case."""
|
||||||
|
|
||||||
|
cprop = {
|
||||||
|
'provider_auth': 'my-secret',
|
||||||
|
'config': self.RESOURCE_TEMPLATE,
|
||||||
|
'name': 'my-precious',
|
||||||
|
'device': '/dev/drbd951722',
|
||||||
|
'data': {},
|
||||||
|
}
|
||||||
|
dev_info = {}
|
||||||
|
|
||||||
|
self.connector.disconnect_volume(cprop, dev_info)
|
||||||
|
|
||||||
|
self.assertEqual('down', self.execs[0][1])
|
||||||
|
|
||||||
|
|
||||||
class ScaleIOConnectorTestCase(ConnectorTestCase):
|
class ScaleIOConnectorTestCase(ConnectorTestCase):
|
||||||
"""Test cases for ScaleIO connector"""
|
"""Test cases for ScaleIO connector"""
|
||||||
# Fake volume information
|
# Fake volume information
|
||||||
|
Loading…
Reference in New Issue
Block a user