|
|
|
@ -1,716 +0,0 @@
|
|
|
|
|
# Copyright (c) 2014 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.
|
|
|
|
|
|
|
|
|
|
import collections
|
|
|
|
|
import eventlet
|
|
|
|
|
import six
|
|
|
|
|
import sys
|
|
|
|
|
import time
|
|
|
|
|
|
|
|
|
|
import mock
|
|
|
|
|
from oslo_utils import importutils
|
|
|
|
|
from oslo_utils import timeutils
|
|
|
|
|
|
|
|
|
|
from cinder import context
|
|
|
|
|
from cinder import test
|
|
|
|
|
from cinder.volume import configuration as conf
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class mock_dbus(object):
|
|
|
|
|
def __init__(self):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
def Array(defaults, signature=None):
|
|
|
|
|
return defaults
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class mock_dm_consts(object):
|
|
|
|
|
|
|
|
|
|
TQ_GET_PATH = "get_path"
|
|
|
|
|
|
|
|
|
|
NODE_ADDR = "addr"
|
|
|
|
|
|
|
|
|
|
CSTATE_PREFIX = "cstate:"
|
|
|
|
|
TSTATE_PREFIX = "tstate:"
|
|
|
|
|
|
|
|
|
|
FLAG_UPD_POOL = "upd_pool"
|
|
|
|
|
FLAG_UPDATE = "update"
|
|
|
|
|
FLAG_DRBDCTRL = "drbdctrl"
|
|
|
|
|
FLAG_STORAGE = "storage"
|
|
|
|
|
FLAG_EXTERNAL = "external"
|
|
|
|
|
FLAG_DEPLOY = "deploy"
|
|
|
|
|
|
|
|
|
|
FLAG_DISKLESS = "diskless"
|
|
|
|
|
FLAG_CONNECT = "connect"
|
|
|
|
|
FLAG_UPD_CON = "upd_con"
|
|
|
|
|
FLAG_RECONNECT = "reconnect"
|
|
|
|
|
FLAG_OVERWRITE = "overwrite"
|
|
|
|
|
FLAG_DISCARD = "discard"
|
|
|
|
|
FLAG_UPD_CONFIG = "upd_config"
|
|
|
|
|
FLAG_STANDBY = "standby"
|
|
|
|
|
FLAG_QIGNORE = "qignore"
|
|
|
|
|
FLAG_REMOVE = "remove"
|
|
|
|
|
|
|
|
|
|
AUX_PROP_PREFIX = "aux:"
|
|
|
|
|
|
|
|
|
|
BOOL_TRUE = "true"
|
|
|
|
|
BOOL_FALSE = "false"
|
|
|
|
|
|
|
|
|
|
VOL_ID = "vol_id"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class mock_dm_exc(object):
|
|
|
|
|
|
|
|
|
|
DM_SUCCESS = 0
|
|
|
|
|
DM_INFO = 1
|
|
|
|
|
DM_EEXIST = 101
|
|
|
|
|
DM_ENOENT = 102
|
|
|
|
|
DM_ERROR = 1000
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class mock_dm_utils(object):
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
def _aux_prop_name(key):
|
|
|
|
|
if six.text_type(key).startswith(mock_dm_consts.AUX_PROP_PREFIX):
|
|
|
|
|
return key[len(mock_dm_consts.AUX_PROP_PREFIX):]
|
|
|
|
|
else:
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
def aux_props_to_dict(props):
|
|
|
|
|
aux_props = {}
|
|
|
|
|
for (key, val) in props.items():
|
|
|
|
|
aux_key = mock_dm_utils._aux_prop_name(key)
|
|
|
|
|
if aux_key is not None:
|
|
|
|
|
aux_props[aux_key] = val
|
|
|
|
|
return aux_props
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
def dict_to_aux_props(props):
|
|
|
|
|
aux_props = {}
|
|
|
|
|
for (key, val) in props.items():
|
|
|
|
|
aux_key = mock_dm_consts.AUX_PROP_PREFIX + six.text_type(key)
|
|
|
|
|
aux_props[aux_key] = six.text_type(val)
|
|
|
|
|
return aux_props
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def public_keys(c):
|
|
|
|
|
return [n for n in c.__dict__.keys() if not n.startswith("_")]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sys.modules['dbus'] = mock_dbus
|
|
|
|
|
sys.modules['drbdmanage'] = collections.namedtuple(
|
|
|
|
|
'module', ['consts', 'exceptions', 'utils'])
|
|
|
|
|
sys.modules['drbdmanage.utils'] = collections.namedtuple(
|
|
|
|
|
'module', public_keys(mock_dm_utils))
|
|
|
|
|
sys.modules['drbdmanage.consts'] = collections.namedtuple(
|
|
|
|
|
'module', public_keys(mock_dm_consts))
|
|
|
|
|
sys.modules['drbdmanage.exceptions'] = collections.namedtuple(
|
|
|
|
|
'module', public_keys(mock_dm_exc))
|
|
|
|
|
|
|
|
|
|
import cinder.volume.drivers.drbdmanagedrv as drv
|
|
|
|
|
|
|
|
|
|
drv.dbus = mock_dbus
|
|
|
|
|
drv.dm_const = mock_dm_consts
|
|
|
|
|
drv.dm_utils = mock_dm_utils
|
|
|
|
|
drv.dm_exc = mock_dm_exc
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def create_configuration(object):
|
|
|
|
|
configuration = mock.MockObject(conf.Configuration)
|
|
|
|
|
configuration.san_is_local = False
|
|
|
|
|
configuration.append_config_values(mock.IgnoreArg())
|
|
|
|
|
return configuration
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class DrbdManageFakeDriver(object):
|
|
|
|
|
|
|
|
|
|
resources = {}
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.calls = []
|
|
|
|
|
self.cur = -1
|
|
|
|
|
|
|
|
|
|
def call_count(self):
|
|
|
|
|
return len(self.calls)
|
|
|
|
|
|
|
|
|
|
def next_call(self):
|
|
|
|
|
self.cur += 1
|
|
|
|
|
return self.calls[self.cur][0]
|
|
|
|
|
|
|
|
|
|
def call_parm(self, arg_idx):
|
|
|
|
|
return self.calls[self.cur][arg_idx]
|
|
|
|
|
|
|
|
|
|
def run_external_plugin(self, name, props):
|
|
|
|
|
self.calls.append(["run_external_plugin", name, props])
|
|
|
|
|
|
|
|
|
|
call_okay = [[mock_dm_exc.DM_SUCCESS, "ACK", []]]
|
|
|
|
|
not_done_yet = (call_okay,
|
|
|
|
|
dict(timeout=mock_dm_consts.BOOL_FALSE,
|
|
|
|
|
result=mock_dm_consts.BOOL_FALSE))
|
|
|
|
|
success = (call_okay,
|
|
|
|
|
dict(timeout=mock_dm_consts.BOOL_FALSE,
|
|
|
|
|
result=mock_dm_consts.BOOL_TRUE))
|
|
|
|
|
got_timeout = (call_okay,
|
|
|
|
|
dict(timeout=mock_dm_consts.BOOL_TRUE,
|
|
|
|
|
result=mock_dm_consts.BOOL_FALSE))
|
|
|
|
|
|
|
|
|
|
if "retry" not in props:
|
|
|
|
|
# Fake success, to not slow tests down
|
|
|
|
|
return success
|
|
|
|
|
|
|
|
|
|
if props["retry"] > 1:
|
|
|
|
|
props["retry"] -= 1
|
|
|
|
|
return not_done_yet
|
|
|
|
|
|
|
|
|
|
if props.get("run-into-timeout"):
|
|
|
|
|
return got_timeout
|
|
|
|
|
|
|
|
|
|
return success
|
|
|
|
|
|
|
|
|
|
def list_resources(self, res, serial, prop, req):
|
|
|
|
|
self.calls.append(["list_resources", res, prop, req])
|
|
|
|
|
if ('aux:cinder-id' in prop and
|
|
|
|
|
prop['aux:cinder-id'].startswith("deadbeef")):
|
|
|
|
|
return ([[mock_dm_exc.DM_ENOENT, "none", []]],
|
|
|
|
|
[])
|
|
|
|
|
else:
|
|
|
|
|
return ([[mock_dm_exc.DM_SUCCESS, "ACK", []]],
|
|
|
|
|
[("res", dict(prop))])
|
|
|
|
|
|
|
|
|
|
def create_resource(self, res, props):
|
|
|
|
|
self.calls.append(["create_resource", res, props])
|
|
|
|
|
return [[mock_dm_exc.DM_SUCCESS, "ack", []]]
|
|
|
|
|
|
|
|
|
|
def create_volume(self, res, size, props):
|
|
|
|
|
self.calls.append(["create_volume", res, size, props])
|
|
|
|
|
return [[mock_dm_exc.DM_SUCCESS, "ack", []],
|
|
|
|
|
[mock_dm_exc.DM_INFO,
|
|
|
|
|
"create_volume",
|
|
|
|
|
[(mock_dm_consts.VOL_ID, '2')]]]
|
|
|
|
|
|
|
|
|
|
def auto_deploy(self, res, red, delta, site_clients):
|
|
|
|
|
self.calls.append(["auto_deploy", res, red, delta, site_clients])
|
|
|
|
|
return [[mock_dm_exc.DM_SUCCESS, "ack", []] * red]
|
|
|
|
|
|
|
|
|
|
def list_volumes(self, res, ser, prop, req):
|
|
|
|
|
self.calls.append(["list_volumes", res, ser, prop, req])
|
|
|
|
|
if ('aux:cinder-id' in prop and
|
|
|
|
|
prop['aux:cinder-id'].startswith("deadbeef")):
|
|
|
|
|
return ([[mock_dm_exc.DM_SUCCESS, "none", []]],
|
|
|
|
|
[])
|
|
|
|
|
else:
|
|
|
|
|
return ([[mock_dm_exc.DM_SUCCESS, "ACK", []]],
|
|
|
|
|
[("res", dict(), [(2, dict(prop))])
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
def remove_volume(self, res, nr, force):
|
|
|
|
|
self.calls.append(["remove_volume", res, nr, force])
|
|
|
|
|
return [[mock_dm_exc.DM_SUCCESS, "ack", []]]
|
|
|
|
|
|
|
|
|
|
def text_query(self, cmd):
|
|
|
|
|
self.calls.append(["text_query", cmd])
|
|
|
|
|
if cmd[0] == mock_dm_consts.TQ_GET_PATH:
|
|
|
|
|
return ([(mock_dm_exc.DM_SUCCESS, "ack", [])], ['/dev/drbd0'])
|
|
|
|
|
return ([(mock_dm_exc.DM_ERROR, 'unknown command', [])], [])
|
|
|
|
|
|
|
|
|
|
def list_assignments(self, nodes, res, ser, prop, req):
|
|
|
|
|
self.calls.append(["list_assignments", nodes, res, ser, prop, req])
|
|
|
|
|
if ('aux:cinder-id' in prop and
|
|
|
|
|
prop['aux:cinder-id'].startswith("deadbeef")):
|
|
|
|
|
return ([[mock_dm_exc.DM_SUCCESS, "none", []]],
|
|
|
|
|
[])
|
|
|
|
|
else:
|
|
|
|
|
return ([[mock_dm_exc.DM_SUCCESS, "ACK", []]],
|
|
|
|
|
[("node", "res", dict(), [(2, dict(prop))])
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
def create_snapshot(self, res, snap, nodes, props):
|
|
|
|
|
self.calls.append(["create_snapshot", res, snap, nodes, props])
|
|
|
|
|
return [[mock_dm_exc.DM_SUCCESS, "ack", []]]
|
|
|
|
|
|
|
|
|
|
def list_snapshots(self, res, sn, serial, prop, req):
|
|
|
|
|
self.calls.append(["list_snapshots", res, sn, serial, prop, req])
|
|
|
|
|
if ('aux:cinder-id' in prop and
|
|
|
|
|
prop['aux:cinder-id'].startswith("deadbeef")):
|
|
|
|
|
return ([[mock_dm_exc.DM_SUCCESS, "none", []]],
|
|
|
|
|
[])
|
|
|
|
|
else:
|
|
|
|
|
return ([[mock_dm_exc.DM_SUCCESS, "ACK", []]],
|
|
|
|
|
[("res", [("snap", dict(prop))])
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
def remove_snapshot(self, res, snap, force):
|
|
|
|
|
self.calls.append(["remove_snapshot", res, snap, force])
|
|
|
|
|
return [[mock_dm_exc.DM_SUCCESS, "ack", []]]
|
|
|
|
|
|
|
|
|
|
def resize_volume(self, res, vol, ser, size, delta):
|
|
|
|
|
self.calls.append(["resize_volume", res, vol, ser, size, delta])
|
|
|
|
|
return [[mock_dm_exc.DM_SUCCESS, "ack", []]]
|
|
|
|
|
|
|
|
|
|
def restore_snapshot(self, res, snap, new, rprop, vprops):
|
|
|
|
|
self.calls.append(["restore_snapshot", res, snap, new, rprop, vprops])
|
|
|
|
|
return [[mock_dm_exc.DM_SUCCESS, "ack", []]]
|
|
|
|
|
|
|
|
|
|
def assign(self, host, resource, props):
|
|
|
|
|
self.calls.append(["assign", host, resource, props])
|
|
|
|
|
return [[mock_dm_exc.DM_SUCCESS, "ack", []]]
|
|
|
|
|
|
|
|
|
|
def create_node(self, name, prop):
|
|
|
|
|
self.calls.append(["create_node", name, prop])
|
|
|
|
|
if name.startswith('EXIST'):
|
|
|
|
|
return [(mock_dm_exc.DM_EEXIST, "none", [])]
|
|
|
|
|
else:
|
|
|
|
|
return [(mock_dm_exc.DM_SUCCESS, "ack", [])]
|
|
|
|
|
|
|
|
|
|
def set_drbdsetup_props(self, options):
|
|
|
|
|
self.calls.append(["set_drbdsetup_props", options])
|
|
|
|
|
return [[mock_dm_exc.DM_SUCCESS, "ack", []]]
|
|
|
|
|
|
|
|
|
|
def modify_resource(self, res, ser, props):
|
|
|
|
|
self.calls.append(["modify_resource", res, ser, props])
|
|
|
|
|
return [[mock_dm_exc.DM_SUCCESS, "ack", []]]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class DrbdManageIscsiTestCase(test.TestCase):
|
|
|
|
|
|
|
|
|
|
def _fake_safe_get(self, key):
|
|
|
|
|
if key == 'target_helper':
|
|
|
|
|
return 'fake'
|
|
|
|
|
|
|
|
|
|
if key.endswith('_policy'):
|
|
|
|
|
return '{}'
|
|
|
|
|
|
|
|
|
|
if key.endswith('_options'):
|
|
|
|
|
return '{}'
|
|
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def _fake_safe_get_with_options(self, key):
|
|
|
|
|
if key == 'drbdmanage_net_options':
|
|
|
|
|
return('{"connect-int": "4", "allow-two-primaries": "yes", '
|
|
|
|
|
'"ko-count": "30"}')
|
|
|
|
|
if key == 'drbdmanage_resource_options':
|
|
|
|
|
return '{"auto-promote-timeout": "300"}'
|
|
|
|
|
if key == 'drbdmanage_disk_options':
|
|
|
|
|
return '{"c-min-rate": "4M"}'
|
|
|
|
|
|
|
|
|
|
return self._fake_safe_get(key)
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
def _fake_sleep(amount):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
|
self.ctxt = context.get_admin_context()
|
|
|
|
|
self._mock = mock.Mock()
|
|
|
|
|
self.configuration = mock.Mock(conf.Configuration)
|
|
|
|
|
self.configuration.san_is_local = True
|
|
|
|
|
self.configuration.reserved_percentage = 1
|
|
|
|
|
|
|
|
|
|
super(DrbdManageIscsiTestCase, self).setUp()
|
|
|
|
|
|
|
|
|
|
self.mock_object(importutils, 'import_object',
|
|
|
|
|
self.fake_import_object)
|
|
|
|
|
self.mock_object(drv.DrbdManageBaseDriver,
|
|
|
|
|
'call_or_reconnect',
|
|
|
|
|
self.fake_issue_dbus_call)
|
|
|
|
|
self.mock_object(drv.DrbdManageBaseDriver,
|
|
|
|
|
'dbus_connect',
|
|
|
|
|
self.fake_issue_dbus_connect)
|
|
|
|
|
self.mock_object(drv.DrbdManageBaseDriver,
|
|
|
|
|
'_wait_for_node_assignment',
|
|
|
|
|
self.fake_wait_node_assignment)
|
|
|
|
|
|
|
|
|
|
self.configuration.safe_get = self._fake_safe_get
|
|
|
|
|
|
|
|
|
|
self.mock_object(eventlet, 'sleep', self._fake_sleep)
|
|
|
|
|
|
|
|
|
|
# Infrastructure
|
|
|
|
|
def fake_import_object(self, what, configuration, db, executor):
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def fake_issue_dbus_call(self, fn, *args):
|
|
|
|
|
return fn(*args)
|
|
|
|
|
|
|
|
|
|
def fake_wait_node_assignment(self, *args, **kwargs):
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def fake_issue_dbus_connect(self):
|
|
|
|
|
self.odm = DrbdManageFakeDriver()
|
|
|
|
|
|
|
|
|
|
def call_or_reconnect(self, method, *params):
|
|
|
|
|
return method(*params)
|
|
|
|
|
|
|
|
|
|
def fake_is_external_node(self, name):
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
# Tests per se
|
|
|
|
|
|
|
|
|
|
def test_create_volume(self):
|
|
|
|
|
testvol = {'project_id': 'testprjid',
|
|
|
|
|
'name': 'testvol',
|
|
|
|
|
'size': 1,
|
|
|
|
|
'id': 'deadbeef-8068-11e4-98c0-5254008ea111',
|
|
|
|
|
'volume_type_id': 'drbdmanage',
|
|
|
|
|
'created_at': timeutils.utcnow()}
|
|
|
|
|
|
|
|
|
|
dmd = drv.DrbdManageIscsiDriver(configuration=self.configuration)
|
|
|
|
|
dmd.drbdmanage_devs_on_controller = False
|
|
|
|
|
dmd.odm = DrbdManageFakeDriver()
|
|
|
|
|
dmd.create_volume(testvol)
|
|
|
|
|
self.assertEqual(8, dmd.odm.call_count())
|
|
|
|
|
self.assertEqual("create_resource", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("set_drbdsetup_props", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("set_drbdsetup_props", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("set_drbdsetup_props", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("list_volumes", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("create_volume", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual(1048576, dmd.odm.call_parm(2))
|
|
|
|
|
self.assertEqual("auto_deploy", dmd.odm.next_call())
|
|
|
|
|
|
|
|
|
|
def test_create_volume_with_options(self):
|
|
|
|
|
testvol = {'project_id': 'testprjid',
|
|
|
|
|
'name': 'testvol',
|
|
|
|
|
'size': 1,
|
|
|
|
|
'id': 'deadbeef-8068-11e4-98c0-5254008ea111',
|
|
|
|
|
'volume_type_id': 'drbdmanage',
|
|
|
|
|
'created_at': timeutils.utcnow()}
|
|
|
|
|
|
|
|
|
|
self.configuration.safe_get = self._fake_safe_get_with_options
|
|
|
|
|
dmd = drv.DrbdManageIscsiDriver(configuration=self.configuration)
|
|
|
|
|
dmd.drbdmanage_devs_on_controller = False
|
|
|
|
|
dmd.odm = DrbdManageFakeDriver()
|
|
|
|
|
dmd.create_volume(testvol)
|
|
|
|
|
|
|
|
|
|
self.assertEqual(8, dmd.odm.call_count())
|
|
|
|
|
|
|
|
|
|
self.assertEqual("create_resource", dmd.odm.next_call())
|
|
|
|
|
|
|
|
|
|
self.assertEqual("set_drbdsetup_props", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("reso", dmd.odm.call_parm(1)["type"])
|
|
|
|
|
self.assertEqual("300", dmd.odm.call_parm(1)["auto-promote-timeout"])
|
|
|
|
|
|
|
|
|
|
self.assertEqual("set_drbdsetup_props", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("neto", dmd.odm.call_parm(1)["type"])
|
|
|
|
|
self.assertEqual("30", dmd.odm.call_parm(1)["ko-count"])
|
|
|
|
|
|
|
|
|
|
self.assertEqual("set_drbdsetup_props", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("disko", dmd.odm.call_parm(1)["type"])
|
|
|
|
|
self.assertEqual("4M", dmd.odm.call_parm(1)["c-min-rate"])
|
|
|
|
|
|
|
|
|
|
self.assertEqual("list_volumes", dmd.odm.next_call())
|
|
|
|
|
|
|
|
|
|
self.assertEqual("create_volume", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual(1048576, dmd.odm.call_parm(2))
|
|
|
|
|
|
|
|
|
|
self.assertEqual("auto_deploy", dmd.odm.next_call())
|
|
|
|
|
|
|
|
|
|
def test_create_volume_controller_all_vols(self):
|
|
|
|
|
testvol = {'project_id': 'testprjid',
|
|
|
|
|
'name': 'testvol',
|
|
|
|
|
'size': 1,
|
|
|
|
|
'id': 'deadbeef-8068-11e4-98c0-5254008ea111',
|
|
|
|
|
'volume_type_id': 'drbdmanage',
|
|
|
|
|
'created_at': timeutils.utcnow()}
|
|
|
|
|
|
|
|
|
|
dmd = drv.DrbdManageIscsiDriver(configuration=self.configuration)
|
|
|
|
|
dmd.drbdmanage_devs_on_controller = True
|
|
|
|
|
dmd.odm = DrbdManageFakeDriver()
|
|
|
|
|
dmd.create_volume(testvol)
|
|
|
|
|
self.assertEqual("create_resource", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("set_drbdsetup_props", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("set_drbdsetup_props", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("set_drbdsetup_props", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("list_volumes", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("create_volume", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual(1048576, dmd.odm.call_parm(2))
|
|
|
|
|
self.assertEqual("auto_deploy", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("run_external_plugin", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("assign", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual(9, dmd.odm.call_count())
|
|
|
|
|
|
|
|
|
|
def test_delete_volume(self):
|
|
|
|
|
testvol = {'project_id': 'testprjid',
|
|
|
|
|
'name': 'testvol',
|
|
|
|
|
'size': 1,
|
|
|
|
|
'id': 'ba253fd0-8068-11e4-98c0-5254008ea111',
|
|
|
|
|
'volume_type_id': 'drbdmanage',
|
|
|
|
|
'created_at': timeutils.utcnow()}
|
|
|
|
|
|
|
|
|
|
dmd = drv.DrbdManageIscsiDriver(configuration=self.configuration)
|
|
|
|
|
dmd.odm = DrbdManageFakeDriver()
|
|
|
|
|
dmd.delete_volume(testvol)
|
|
|
|
|
self.assertEqual("list_volumes", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual(testvol['id'], dmd.odm.call_parm(3)["aux:cinder-id"])
|
|
|
|
|
self.assertEqual("remove_volume", dmd.odm.next_call())
|
|
|
|
|
|
|
|
|
|
def test_local_path(self):
|
|
|
|
|
testvol = {'project_id': 'testprjid',
|
|
|
|
|
'name': 'testvol',
|
|
|
|
|
'size': 1,
|
|
|
|
|
'id': 'ba253fd0-8068-11e4-98c0-5254008ea111',
|
|
|
|
|
'volume_type_id': 'drbdmanage',
|
|
|
|
|
'created_at': timeutils.utcnow()}
|
|
|
|
|
|
|
|
|
|
dmd = drv.DrbdManageIscsiDriver(configuration=self.configuration)
|
|
|
|
|
dmd.odm = DrbdManageFakeDriver()
|
|
|
|
|
data = dmd.local_path(testvol)
|
|
|
|
|
self.assertTrue(data.startswith("/dev/drbd"))
|
|
|
|
|
|
|
|
|
|
def test_create_snapshot(self):
|
|
|
|
|
testsnap = {'id': 'ca253fd0-8068-11e4-98c0-5254008ea111',
|
|
|
|
|
'volume_id': 'ba253fd0-8068-11e4-98c0-5254008ea111'}
|
|
|
|
|
|
|
|
|
|
dmd = drv.DrbdManageIscsiDriver(configuration=self.configuration)
|
|
|
|
|
dmd.odm = DrbdManageFakeDriver()
|
|
|
|
|
dmd.create_snapshot(testsnap)
|
|
|
|
|
self.assertEqual("list_volumes", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("list_assignments", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("create_snapshot", dmd.odm.next_call())
|
|
|
|
|
self.assertIn('node', dmd.odm.call_parm(3))
|
|
|
|
|
|
|
|
|
|
def test_delete_snapshot(self):
|
|
|
|
|
testsnap = {'id': 'ca253fd0-8068-11e4-98c0-5254008ea111'}
|
|
|
|
|
|
|
|
|
|
dmd = drv.DrbdManageIscsiDriver(configuration=self.configuration)
|
|
|
|
|
dmd.odm = DrbdManageFakeDriver()
|
|
|
|
|
dmd.delete_snapshot(testsnap)
|
|
|
|
|
self.assertEqual("list_snapshots", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("remove_snapshot", dmd.odm.next_call())
|
|
|
|
|
|
|
|
|
|
def test_extend_volume(self):
|
|
|
|
|
testvol = {'project_id': 'testprjid',
|
|
|
|
|
'name': 'testvol',
|
|
|
|
|
'size': 1,
|
|
|
|
|
'id': 'ba253fd0-8068-11e4-98c0-5254008ea111',
|
|
|
|
|
'volume_type_id': 'drbdmanage',
|
|
|
|
|
'created_at': timeutils.utcnow()}
|
|
|
|
|
|
|
|
|
|
dmd = drv.DrbdManageIscsiDriver(configuration=self.configuration)
|
|
|
|
|
dmd.odm = DrbdManageFakeDriver()
|
|
|
|
|
dmd.extend_volume(testvol, 5)
|
|
|
|
|
self.assertEqual("list_volumes", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual(testvol['id'], dmd.odm.call_parm(3)["aux:cinder-id"])
|
|
|
|
|
self.assertEqual("resize_volume", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("res", dmd.odm.call_parm(1))
|
|
|
|
|
self.assertEqual(2, dmd.odm.call_parm(2))
|
|
|
|
|
self.assertEqual(-1, dmd.odm.call_parm(3))
|
|
|
|
|
self.assertEqual(5242880, dmd.odm.call_parm(4))
|
|
|
|
|
|
|
|
|
|
def test_create_cloned_volume(self):
|
|
|
|
|
srcvol = {'project_id': 'testprjid',
|
|
|
|
|
'name': 'testvol',
|
|
|
|
|
'size': 1,
|
|
|
|
|
'id': 'ba253fd0-8068-11e4-98c0-5254008ea111',
|
|
|
|
|
'volume_type_id': 'drbdmanage',
|
|
|
|
|
'created_at': timeutils.utcnow()}
|
|
|
|
|
|
|
|
|
|
newvol = {'id': 'ca253fd0-8068-11e4-98c0-5254008ea111'}
|
|
|
|
|
|
|
|
|
|
dmd = drv.DrbdManageIscsiDriver(configuration=self.configuration)
|
|
|
|
|
dmd.odm = DrbdManageFakeDriver()
|
|
|
|
|
dmd.create_cloned_volume(newvol, srcvol)
|
|
|
|
|
self.assertEqual("list_volumes", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("list_assignments", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("create_snapshot", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("run_external_plugin", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("list_snapshots", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("restore_snapshot", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("set_drbdsetup_props", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("set_drbdsetup_props", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("set_drbdsetup_props", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("run_external_plugin", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("list_snapshots", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("remove_snapshot", dmd.odm.next_call())
|
|
|
|
|
|
|
|
|
|
def test_create_cloned_volume_larger_size(self):
|
|
|
|
|
srcvol = {'project_id': 'testprjid',
|
|
|
|
|
'name': 'testvol',
|
|
|
|
|
'size': 1,
|
|
|
|
|
'id': 'ba253fd0-8068-11e4-98c0-5254008ea111',
|
|
|
|
|
'volume_type_id': 'drbdmanage',
|
|
|
|
|
'created_at': timeutils.utcnow()}
|
|
|
|
|
|
|
|
|
|
newvol = {'size': 5,
|
|
|
|
|
'id': 'ca253fd0-8068-11e4-98c0-5254008ea111'}
|
|
|
|
|
|
|
|
|
|
dmd = drv.DrbdManageIscsiDriver(configuration=self.configuration)
|
|
|
|
|
dmd.odm = DrbdManageFakeDriver()
|
|
|
|
|
dmd.create_cloned_volume(newvol, srcvol)
|
|
|
|
|
self.assertEqual("list_volumes", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("list_assignments", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("create_snapshot", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("run_external_plugin", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("list_snapshots", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("restore_snapshot", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("set_drbdsetup_props", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("set_drbdsetup_props", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("set_drbdsetup_props", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("run_external_plugin", dmd.odm.next_call())
|
|
|
|
|
|
|
|
|
|
# resize image checks
|
|
|
|
|
self.assertEqual("list_volumes", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual(newvol['id'], dmd.odm.call_parm(3)["aux:cinder-id"])
|
|
|
|
|
self.assertEqual("resize_volume", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("res", dmd.odm.call_parm(1))
|
|
|
|
|
self.assertEqual(2, dmd.odm.call_parm(2))
|
|
|
|
|
self.assertEqual(-1, dmd.odm.call_parm(3))
|
|
|
|
|
self.assertEqual(5242880, dmd.odm.call_parm(4))
|
|
|
|
|
|
|
|
|
|
self.assertEqual("run_external_plugin", dmd.odm.next_call())
|
|
|
|
|
|
|
|
|
|
self.assertEqual("list_snapshots", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("remove_snapshot", dmd.odm.next_call())
|
|
|
|
|
|
|
|
|
|
def test_create_volume_from_snapshot(self):
|
|
|
|
|
snap = {'project_id': 'testprjid',
|
|
|
|
|
'name': 'testvol',
|
|
|
|
|
'volume_size': 1,
|
|
|
|
|
'id': 'ba253fd0-8068-11e4-98c0-5254008ea111',
|
|
|
|
|
'volume_type_id': 'drbdmanage',
|
|
|
|
|
'created_at': timeutils.utcnow()}
|
|
|
|
|
|
|
|
|
|
newvol = {'id': 'ca253fd0-8068-11e4-98c0-5254008ea111'}
|
|
|
|
|
|
|
|
|
|
dmd = drv.DrbdManageIscsiDriver(configuration=self.configuration)
|
|
|
|
|
dmd.odm = DrbdManageFakeDriver()
|
|
|
|
|
dmd.create_volume_from_snapshot(newvol, snap)
|
|
|
|
|
self.assertEqual("list_snapshots", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("restore_snapshot", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("set_drbdsetup_props", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("set_drbdsetup_props", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("set_drbdsetup_props", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("run_external_plugin", dmd.odm.next_call())
|
|
|
|
|
|
|
|
|
|
def test_create_volume_from_snapshot_larger_size(self):
|
|
|
|
|
snap = {'project_id': 'testprjid',
|
|
|
|
|
'name': 'testvol',
|
|
|
|
|
'volume_size': 1,
|
|
|
|
|
'id': 'ba253fd0-8068-11e4-98c0-5254008ea111',
|
|
|
|
|
'volume_type_id': 'drbdmanage',
|
|
|
|
|
'created_at': timeutils.utcnow()}
|
|
|
|
|
|
|
|
|
|
newvol = {'size': 5,
|
|
|
|
|
'id': 'ca253fd0-8068-11e4-98c0-5254008ea111'}
|
|
|
|
|
|
|
|
|
|
dmd = drv.DrbdManageIscsiDriver(configuration=self.configuration)
|
|
|
|
|
dmd.odm = DrbdManageFakeDriver()
|
|
|
|
|
dmd.create_volume_from_snapshot(newvol, snap)
|
|
|
|
|
self.assertEqual("list_snapshots", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("restore_snapshot", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("set_drbdsetup_props", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("set_drbdsetup_props", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("set_drbdsetup_props", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("run_external_plugin", dmd.odm.next_call())
|
|
|
|
|
|
|
|
|
|
def test_unit_conversions(self):
|
|
|
|
|
dmd = drv.DrbdManageIscsiDriver(configuration=self.configuration)
|
|
|
|
|
|
|
|
|
|
self.assertEqual(1048576, dmd._vol_size_to_dm(1))
|
|
|
|
|
self.assertEqual(1, dmd._vol_size_to_cinder(1048576))
|
|
|
|
|
|
|
|
|
|
self.assertEqual(5368709120, dmd._vol_size_to_dm(5120))
|
|
|
|
|
self.assertEqual(5120, dmd._vol_size_to_cinder(5368709120))
|
|
|
|
|
|
|
|
|
|
self.assertEqual(10737418240, dmd._vol_size_to_dm(10240))
|
|
|
|
|
self.assertEqual(10240, dmd._vol_size_to_cinder(10737418240))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class DrbdManageDrbdTestCase(DrbdManageIscsiTestCase):
|
|
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
|
super(DrbdManageDrbdTestCase, self).setUp()
|
|
|
|
|
|
|
|
|
|
self.mock_object(drv.DrbdManageDrbdDriver,
|
|
|
|
|
'_is_external_node',
|
|
|
|
|
self.fake_is_external_node)
|
|
|
|
|
|
|
|
|
|
def test_drbd_create_export(self):
|
|
|
|
|
volume = {'project_id': 'testprjid',
|
|
|
|
|
'name': 'testvol',
|
|
|
|
|
'size': 1,
|
|
|
|
|
'id': 'ba253fd0-8068-11e4-98c0-5254008ea111',
|
|
|
|
|
'volume_type_id': 'drbdmanage',
|
|
|
|
|
'created_at': timeutils.utcnow()}
|
|
|
|
|
|
|
|
|
|
connector = {'host': 'node99',
|
|
|
|
|
'ip': '127.0.0.99'}
|
|
|
|
|
|
|
|
|
|
dmd = drv.DrbdManageDrbdDriver(configuration=self.configuration)
|
|
|
|
|
dmd.odm = DrbdManageFakeDriver()
|
|
|
|
|
|
|
|
|
|
x = dmd.create_export({}, volume, connector)
|
|
|
|
|
self.assertEqual("list_volumes", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("create_node", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("assign", dmd.odm.next_call())
|
|
|
|
|
# local_path
|
|
|
|
|
self.assertEqual("list_volumes", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("text_query", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("local", x["driver_volume_type"])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class DrbdManageCommonTestCase(DrbdManageIscsiTestCase):
|
|
|
|
|
def test_drbd_policy_loop_timeout(self):
|
|
|
|
|
dmd = drv.DrbdManageDrbdDriver(configuration=self.configuration)
|
|
|
|
|
dmd.odm = DrbdManageFakeDriver()
|
|
|
|
|
|
|
|
|
|
res = dmd._call_policy_plugin('void', {},
|
|
|
|
|
{'retry': 4,
|
|
|
|
|
'run-into-timeout': True})
|
|
|
|
|
self.assertFalse(res)
|
|
|
|
|
self.assertEqual(4, dmd.odm.call_count())
|
|
|
|
|
self.assertEqual("run_external_plugin", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("run_external_plugin", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("run_external_plugin", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("run_external_plugin", dmd.odm.next_call())
|
|
|
|
|
|
|
|
|
|
def test_drbd_policy_loop_success(self):
|
|
|
|
|
dmd = drv.DrbdManageDrbdDriver(configuration=self.configuration)
|
|
|
|
|
dmd.odm = DrbdManageFakeDriver()
|
|
|
|
|
|
|
|
|
|
res = dmd._call_policy_plugin('void',
|
|
|
|
|
{'base': 'data',
|
|
|
|
|
'retry': 4},
|
|
|
|
|
{'override': 'xyz'})
|
|
|
|
|
self.assertTrue(res)
|
|
|
|
|
self.assertEqual(4, dmd.odm.call_count())
|
|
|
|
|
self.assertEqual("run_external_plugin", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("run_external_plugin", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("run_external_plugin", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual("run_external_plugin", dmd.odm.next_call())
|
|
|
|
|
|
|
|
|
|
def test_drbd_policy_loop_simple(self):
|
|
|
|
|
dmd = drv.DrbdManageDrbdDriver(configuration=self.configuration)
|
|
|
|
|
dmd.odm = DrbdManageFakeDriver()
|
|
|
|
|
|
|
|
|
|
res = dmd._call_policy_plugin('policy-name',
|
|
|
|
|
{'base': "value",
|
|
|
|
|
'over': "ignore"},
|
|
|
|
|
{'over': "ride",
|
|
|
|
|
'starttime': 0})
|
|
|
|
|
self.assertTrue(res)
|
|
|
|
|
|
|
|
|
|
self.assertEqual(1, dmd.odm.call_count())
|
|
|
|
|
self.assertEqual("run_external_plugin", dmd.odm.next_call())
|
|
|
|
|
self.assertEqual('policy-name', dmd.odm.call_parm(1))
|
|
|
|
|
incoming = dmd.odm.call_parm(2)
|
|
|
|
|
|
|
|
|
|
self.assertGreaterEqual(4, abs(float(incoming['starttime']) -
|
|
|
|
|
time.time()))
|
|
|
|
|
self.assertEqual('value', incoming['base'])
|
|
|
|
|
self.assertEqual('ride', incoming['over'])
|