XIV: switch to generic volume group
Implements consistency groups for XIV and A9000 through generic groups mechanism (required in Pike) Depends-On: Id9964f868c2dc14aaee37e4bcbba330fb4575492 Closes-Bug: #1674261 Change-Id: I3e0809789ba420cc6b5250f7e383ce952d960b93
This commit is contained in:
parent
debc2b8fa8
commit
23cf5b08ce
@ -14,18 +14,19 @@
|
||||
# under the License.
|
||||
#
|
||||
import mock
|
||||
import unittest
|
||||
from xml.etree import ElementTree
|
||||
|
||||
from cinder import context
|
||||
from cinder import exception
|
||||
from cinder.objects import consistencygroup
|
||||
from cinder.objects import fields
|
||||
from cinder import objects
|
||||
from cinder import test
|
||||
from cinder.tests.unit import fake_constants as fake
|
||||
from cinder.tests.unit import utils as testutils
|
||||
from cinder.tests.unit.volume.drivers.ibm import fake_pyxcli
|
||||
import cinder.volume.drivers.ibm.ibm_storage as storage
|
||||
from cinder.volume.drivers.ibm.ibm_storage import cryptish
|
||||
from cinder.volume.drivers.ibm.ibm_storage.xiv_proxy import XIVProxy
|
||||
from cinder.volume import group_types
|
||||
|
||||
errors = fake_pyxcli.pyxcli_client.errors
|
||||
|
||||
@ -35,10 +36,6 @@ module_patcher = mock.MagicMock()
|
||||
test_mock.cinder.exception = exception
|
||||
|
||||
|
||||
class dummyException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
TEST_LOG_PREFIX = storage.XIV_LOG_PREFIX
|
||||
TEST_VOLUME = {
|
||||
'name': 'BLA',
|
||||
@ -46,35 +43,7 @@ TEST_VOLUME = {
|
||||
'size': 17,
|
||||
'consistencygroup_id': fake.CONSISTENCY_GROUP_ID,
|
||||
}
|
||||
TEST_CLONED_VOLUME = {
|
||||
'name': 'CLONE',
|
||||
'id': 46,
|
||||
'size': 17,
|
||||
}
|
||||
TEST_CONS_GROUP = {
|
||||
'name': 'WTF32',
|
||||
'id': 'WTF32',
|
||||
'volume_type_ids': ['WTF32'],
|
||||
}
|
||||
TEST_CG_SNAPSHOT = {
|
||||
'id': 'WTF',
|
||||
'consistencygroup_id': "WTF32"
|
||||
}
|
||||
|
||||
|
||||
class TestSnapshot(dict):
|
||||
|
||||
def volume_name(self):
|
||||
return self.volume_name
|
||||
|
||||
TEST_SNAPSHOT = TestSnapshot({
|
||||
'name': 'SNAP',
|
||||
'id': 32,
|
||||
'volume_id': 23,
|
||||
'size': 17,
|
||||
'volume_size': 17,
|
||||
'volume_name': 'volume-32',
|
||||
})
|
||||
TEST_EXTRA_SPECS = {
|
||||
'replication_enabled': '<is> False',
|
||||
}
|
||||
@ -132,17 +101,13 @@ REPLICA_PARAMS = {
|
||||
}
|
||||
|
||||
|
||||
class XIVProxyTest(unittest.TestCase):
|
||||
class XIVProxyTest(test.TestCase):
|
||||
|
||||
"""Tests the main Proxy driver"""
|
||||
|
||||
test_cg = consistencygroup.ConsistencyGroup(
|
||||
context=None, name='WTF32', id=fake.CONSISTENCY_GROUP_ID,
|
||||
volume_type_id=fake.VOLUME_TYPE_ID,
|
||||
status=fields.ConsistencyGroupStatus.AVAILABLE)
|
||||
|
||||
def setUp(self):
|
||||
"""import at setup to ensure module patchers are in place"""
|
||||
super(XIVProxyTest, self).setUp()
|
||||
|
||||
self.proxy = XIVProxy
|
||||
self.version = "cinder"
|
||||
@ -176,9 +141,9 @@ class XIVProxyTest(unittest.TestCase):
|
||||
|
||||
p = self.proxy(storage_info, mock.MagicMock(),
|
||||
test_mock.cinder.exception)
|
||||
with self.assertRaises(
|
||||
test_mock.cinder.exception.InvalidParameterValue):
|
||||
p.setup({})
|
||||
|
||||
self.assertRaises(test_mock.cinder.exception.InvalidParameterValue,
|
||||
p.setup, {})
|
||||
|
||||
@mock.patch("cinder.volume.drivers.ibm.ibm_storage.xiv_proxy.client."
|
||||
"XCLIClient")
|
||||
@ -200,8 +165,8 @@ class XIVProxyTest(unittest.TestCase):
|
||||
side_effect=errors.CredentialsError(
|
||||
'bla', 'bla', ElementTree.Element("bla")))
|
||||
|
||||
with self.assertRaises(test_mock.cinder.exception.NotAuthorized):
|
||||
p.setup({})
|
||||
self.assertRaises(test_mock.cinder.exception.NotAuthorized,
|
||||
p.setup, {})
|
||||
|
||||
@mock.patch("cinder.volume.drivers.ibm.ibm_storage."
|
||||
"xiv_proxy.client.XCLIClient")
|
||||
@ -223,8 +188,8 @@ class XIVProxyTest(unittest.TestCase):
|
||||
side_effect=errors.ConnectionError(
|
||||
'bla', 'bla', ElementTree.Element("bla")))
|
||||
|
||||
with self.assertRaises(test_mock.cinder.exception.HostNotFound):
|
||||
p.setup({})
|
||||
self.assertRaises(test_mock.cinder.exception.HostNotFound,
|
||||
p.setup, {})
|
||||
|
||||
@mock.patch("cinder.volume.drivers.ibm.ibm_storage.xiv_proxy."
|
||||
"client.XCLIClient")
|
||||
@ -297,8 +262,7 @@ class XIVProxyTest(unittest.TestCase):
|
||||
'bla', 'bla', ElementTree.Element('bla')))
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
p.create_volume({'size': 16, 'name': 'WTF32'})
|
||||
self.assertRaises(ex, p.create_volume, {'size': 16, 'name': 'WTF32'})
|
||||
|
||||
def test_create_volume_with_consistency_group(self):
|
||||
"""Test Create volume with consistency_group"""
|
||||
@ -373,8 +337,7 @@ class XIVProxyTest(unittest.TestCase):
|
||||
volume = {'size': 16, 'name': 'WTF32',
|
||||
'consistencygroup_id': 'WTF', 'volume_type_id': 'WTF'}
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
p.create_volume(volume)
|
||||
self.assertRaises(ex, p.create_volume, volume)
|
||||
|
||||
@mock.patch("cinder.volume.drivers.ibm.ibm_storage."
|
||||
"xiv_proxy.XIVProxy._get_targets",
|
||||
@ -401,8 +364,7 @@ class XIVProxyTest(unittest.TestCase):
|
||||
|
||||
volume = {'size': 16, 'name': 'WTF32', 'volume_type_id': 'WTF'}
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
p.create_volume(volume)
|
||||
self.assertRaises(ex, p.create_volume, volume)
|
||||
|
||||
def test_delete_volume_should_pass_the_correct_parameters(self):
|
||||
"""Delete volume should call xcli with the correct parameters"""
|
||||
@ -488,8 +450,7 @@ class XIVProxyTest(unittest.TestCase):
|
||||
'name': 'WTF32', 'volume_type_id': 'WTF'}
|
||||
target = 'Invalid'
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
p.failover_host({}, [volume], target)
|
||||
self.assertRaises(ex, p.failover_host, {}, [volume], target)
|
||||
|
||||
@mock.patch("cinder.volume.drivers.ibm.ibm_storage."
|
||||
"xiv_proxy.client.XCLIClient")
|
||||
@ -515,8 +476,7 @@ class XIVProxyTest(unittest.TestCase):
|
||||
'name': 'WTF32', 'volume_type_id': 'WTF'}
|
||||
target = REPLICA_ID
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
p.failover_host({}, [volume], target)
|
||||
self.assertRaises(ex, p.failover_host, {}, [volume], target)
|
||||
|
||||
@mock.patch("cinder.volume.drivers.ibm.ibm_storage."
|
||||
"xiv_proxy.client.XCLIClient")
|
||||
@ -585,10 +545,11 @@ class XIVProxyTest(unittest.TestCase):
|
||||
driver)
|
||||
|
||||
p.ibm_storage_cli = mock.MagicMock()
|
||||
p.ibm_storage_cli.cmd.perf_class_list.side_effect = errors.XCLIError(
|
||||
'')
|
||||
p.ibm_storage_cli.cmd.perf_class_list.side_effect = (
|
||||
errors.XCLIError(''))
|
||||
|
||||
self.assertRaises(errors.XCLIError)
|
||||
ex = getattr(p, "_get_exception")()
|
||||
self.assertRaises(ex, p._check_perf_class_on_backend, {'bw': '100'})
|
||||
|
||||
@mock.patch("cinder.volume.drivers.ibm.ibm_storage."
|
||||
"xiv_proxy.XIVProxy._check_storage_version_for_qos_support",
|
||||
@ -718,9 +679,8 @@ class XIVProxyTest(unittest.TestCase):
|
||||
p.ibm_storage_cli.cmd.vol_list.return_value.as_list = []
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
p.manage_volume(volume={'name': 'WTF32'},
|
||||
reference={'source-name': 'WTF64'})
|
||||
self.assertRaises(ex, p.manage_volume, volume={'name': 'WTF32'},
|
||||
reference={'source-name': 'WTF64'})
|
||||
|
||||
def test_manage_volume_get_size_if_volume_exists(self):
|
||||
"""Manage volume get size should return size"""
|
||||
@ -822,9 +782,9 @@ class XIVProxyTest(unittest.TestCase):
|
||||
p.ibm_storage_cli.cmd.vol_list.return_value.as_list = []
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
p.manage_volume_get_size(volume={'name': 'WTF32'},
|
||||
reference={'source-name': 'WTF64'})
|
||||
self.assertRaises(ex, p.manage_volume_get_size,
|
||||
volume={'name': 'WTF32'},
|
||||
reference={'source-name': 'WTF64'})
|
||||
|
||||
def test_initialize_connection(self):
|
||||
"""Test initialize_connection
|
||||
@ -876,8 +836,8 @@ class XIVProxyTest(unittest.TestCase):
|
||||
connector['initiator'] = None
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
p.initialize_connection(TEST_VOLUME, connector)
|
||||
self.assertRaises(ex, p.initialize_connection, TEST_VOLUME,
|
||||
connector)
|
||||
|
||||
def test_initialize_connection_bad_iqn(self):
|
||||
"""Initialize connection raises exception on bad formatted IQN"""
|
||||
@ -895,8 +855,8 @@ class XIVProxyTest(unittest.TestCase):
|
||||
connector['initiator'] = 5555
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
p.initialize_connection(TEST_VOLUME, connector)
|
||||
self.assertRaises(ex, p.initialize_connection, TEST_VOLUME,
|
||||
connector)
|
||||
|
||||
def test_get_fc_targets_returns_optimized_wwpns_list(self):
|
||||
driver = mock.MagicMock()
|
||||
@ -1093,8 +1053,8 @@ class XIVProxyTest(unittest.TestCase):
|
||||
p._define_host_according_to_chap = mock.MagicMock()
|
||||
p._define_host_according_to_chap.return_value = dict(id=100)
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
p.initialize_connection(TEST_VOLUME, TEST_CONNECTOR)
|
||||
self.assertRaises(ex, p.initialize_connection, TEST_VOLUME,
|
||||
TEST_CONNECTOR)
|
||||
|
||||
def _get_test_host(self):
|
||||
host = {
|
||||
@ -1106,9 +1066,41 @@ class XIVProxyTest(unittest.TestCase):
|
||||
}
|
||||
return host
|
||||
|
||||
@mock.patch("cinder.volume.drivers.ibm.ibm_storage."
|
||||
"xiv_proxy.XIVProxy._get_extra_specs",
|
||||
mock.MagicMock(return_value=TEST_EXTRA_SPECS))
|
||||
def _create_test_group(self, g_name='group', is_cg=True):
|
||||
extra_specs = {}
|
||||
if is_cg:
|
||||
extra_specs['consistent_group_snapshot_enabled'] = '<is> True'
|
||||
|
||||
group_type = group_types.create(self.ctxt, g_name, extra_specs)
|
||||
return testutils.create_group(self.ctxt,
|
||||
host=self._get_test_host()['name'],
|
||||
group_type_id=group_type.id,
|
||||
volume_type_ids=[])
|
||||
|
||||
def _create_test_cgsnapshot(self, group_id):
|
||||
group_type = group_types.create(
|
||||
self.ctxt, 'group_snapshot',
|
||||
{'consistent_group_snapshot_enabled': '<is> True'})
|
||||
return testutils.create_group_snapshot(self.ctxt, group_id=group_id,
|
||||
group_type_id=group_type.id)
|
||||
|
||||
def test_create_generic_group(self):
|
||||
"""test create generic group"""
|
||||
driver = mock.MagicMock()
|
||||
driver.VERSION = "VERSION"
|
||||
|
||||
p = self.proxy(
|
||||
self.default_storage_info,
|
||||
mock.MagicMock(),
|
||||
test_mock.cinder.exception,
|
||||
driver)
|
||||
|
||||
p.ibm_storage_cli = mock.MagicMock()
|
||||
group_obj = self._create_test_group(is_cg=False)
|
||||
|
||||
self.assertRaises(NotImplementedError,
|
||||
p.create_group, {}, group_obj)
|
||||
|
||||
def test_create_consistencygroup(self):
|
||||
"""test a successful cg create"""
|
||||
driver = mock.MagicMock()
|
||||
@ -1121,18 +1113,16 @@ class XIVProxyTest(unittest.TestCase):
|
||||
driver)
|
||||
|
||||
p.ibm_storage_cli = mock.MagicMock()
|
||||
group_obj = self._create_test_group()
|
||||
|
||||
model_update = p.create_consistencygroup({}, self.test_cg)
|
||||
model_update = p.create_group({}, group_obj)
|
||||
|
||||
p.ibm_storage_cli.cmd.cg_create.assert_called_once_with(
|
||||
cg=p._cg_name_from_id(fake.CONSISTENCY_GROUP_ID),
|
||||
cg=p._cg_name_from_id(group_obj.id),
|
||||
pool='WTF32')
|
||||
|
||||
self.assertEqual('available', model_update['status'])
|
||||
|
||||
@mock.patch("cinder.volume.drivers.ibm.ibm_storage."
|
||||
"xiv_proxy.XIVProxy._get_extra_specs",
|
||||
mock.MagicMock(return_value=TEST_EXTRA_SPECS))
|
||||
def test_create_consistencygroup_already_exists(self):
|
||||
"""test create_consistenygroup when cg already exists"""
|
||||
driver = mock.MagicMock()
|
||||
@ -1150,12 +1140,8 @@ class XIVProxyTest(unittest.TestCase):
|
||||
'bla', 'bla', ElementTree.Element('bla'))
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
p.create_consistencygroup({}, TEST_CONS_GROUP)
|
||||
self.assertRaises(ex, p.create_group, {}, self._create_test_group())
|
||||
|
||||
@mock.patch("cinder.volume.drivers.ibm.ibm_storage."
|
||||
"xiv_proxy.XIVProxy._get_extra_specs",
|
||||
mock.MagicMock(return_value=TEST_EXTRA_SPECS))
|
||||
def test_create_consistencygroup_reached_limit(self):
|
||||
"""test create_consistenygroup when reached maximum CGs"""
|
||||
driver = mock.MagicMock()
|
||||
@ -1174,12 +1160,8 @@ class XIVProxyTest(unittest.TestCase):
|
||||
'bla', 'bla', ElementTree.Element('bla')))
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
p.create_consistencygroup({}, TEST_CONS_GROUP)
|
||||
self.assertRaises(ex, p.create_group, {}, self._create_test_group())
|
||||
|
||||
@mock.patch("cinder.volume.drivers.ibm.ibm_storage."
|
||||
"xiv_proxy.XIVProxy._get_extra_specs",
|
||||
mock.MagicMock(return_value=TEST_EXTRA_SPECS_REPL))
|
||||
def test_create_consistencygroup_with_replication(self):
|
||||
"""test create_consistenygroup when replication is set"""
|
||||
|
||||
@ -1190,13 +1172,19 @@ class XIVProxyTest(unittest.TestCase):
|
||||
|
||||
p.ibm_storage_cli = mock.MagicMock()
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
p.create_consistencygroup({}, TEST_CONS_GROUP)
|
||||
group_obj = self._create_test_group()
|
||||
|
||||
vol_type = objects.VolumeType(context=self.ctxt,
|
||||
name='volume_type_rep',
|
||||
extra_specs=(
|
||||
{'replication_enabled': '<is> True',
|
||||
'replication_type': 'sync'}))
|
||||
group_obj.volume_types = objects.VolumeTypeList(context=self.ctxt,
|
||||
objects=[vol_type])
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
self.assertRaises(ex, p.create_group, {}, group_obj)
|
||||
|
||||
@mock.patch("cinder.volume.drivers.ibm.ibm_storage."
|
||||
"xiv_proxy.XIVProxy._get_extra_specs",
|
||||
mock.MagicMock(return_value=TEST_EXTRA_SPECS))
|
||||
def test_create_consistencygroup_from_src_cgsnapshot(self):
|
||||
"""test a successful cg create from cgsnapshot"""
|
||||
driver = mock.MagicMock()
|
||||
@ -1211,19 +1199,21 @@ class XIVProxyTest(unittest.TestCase):
|
||||
p.ibm_storage_cli = mock.MagicMock()
|
||||
p.ibm_storage_cli.cmd.create_volume_from_snapshot.return_value = []
|
||||
|
||||
model_update, vols_model_update = p.create_consistencygroup_from_src(
|
||||
{}, self.test_cg, [TEST_VOLUME],
|
||||
TEST_CG_SNAPSHOT, [TEST_SNAPSHOT], None, None)
|
||||
group_obj = self._create_test_group()
|
||||
cgsnap_group_obj = self._create_test_cgsnapshot(group_obj.id)
|
||||
|
||||
p.ibm_storage_cli.cmd.cg_create.assert_called_once_with(
|
||||
cg=p._cg_name_from_volume(TEST_VOLUME),
|
||||
pool='WTF32')
|
||||
volume = testutils.create_volume(self.ctxt)
|
||||
snapshot = testutils.create_snapshot(self.ctxt, volume.id)
|
||||
|
||||
model_update, vols_model_update = p.create_group_from_src(
|
||||
{}, group_obj, [volume],
|
||||
cgsnap_group_obj, [snapshot], None, None)
|
||||
|
||||
p.ibm_storage_cli.cmd.cg_create.assert_called_once_with(cg=group_obj,
|
||||
pool='WTF32')
|
||||
|
||||
self.assertEqual('available', model_update['status'])
|
||||
|
||||
@mock.patch("cinder.volume.drivers.ibm.ibm_storage."
|
||||
"xiv_proxy.XIVProxy._get_extra_specs",
|
||||
mock.MagicMock(return_value=TEST_EXTRA_SPECS))
|
||||
def test_create_consistencygroup_from_src_cg(self):
|
||||
"""test a successful cg create from consistencygroup"""
|
||||
driver = mock.MagicMock()
|
||||
@ -1238,19 +1228,21 @@ class XIVProxyTest(unittest.TestCase):
|
||||
p.ibm_storage_cli = mock.MagicMock()
|
||||
p.ibm_storage_cli.cmd.create_volume_from_snapshot.return_value = []
|
||||
|
||||
model_update, vols_model_update = p.create_consistencygroup_from_src(
|
||||
{}, self.test_cg, [TEST_VOLUME],
|
||||
None, None, TEST_CONS_GROUP, [TEST_CLONED_VOLUME])
|
||||
group_obj = self._create_test_group()
|
||||
src_group_obj = self._create_test_group(g_name='src_group')
|
||||
|
||||
p.ibm_storage_cli.cmd.cg_create.assert_called_once_with(
|
||||
cg=p._cg_name_from_volume(TEST_VOLUME),
|
||||
pool='WTF32')
|
||||
volume = testutils.create_volume(self.ctxt)
|
||||
src_volume = testutils.create_volume(self.ctxt)
|
||||
|
||||
model_update, vols_model_update = p.create_group_from_src(
|
||||
{}, group_obj, [volume],
|
||||
None, None, src_group_obj, [src_volume])
|
||||
|
||||
p.ibm_storage_cli.cmd.cg_create.assert_called_once_with(cg=group_obj,
|
||||
pool='WTF32')
|
||||
|
||||
self.assertEqual('available', model_update['status'])
|
||||
|
||||
@mock.patch("cinder.volume.drivers.ibm.ibm_storage."
|
||||
"xiv_proxy.XIVProxy._get_extra_specs",
|
||||
mock.MagicMock(return_value=TEST_EXTRA_SPECS))
|
||||
def test_create_consistencygroup_from_src_fails_cg_create_from_cgsnapshot(
|
||||
self):
|
||||
"""test cg create from cgsnapshot fails on cg_create"""
|
||||
@ -1267,15 +1259,17 @@ class XIVProxyTest(unittest.TestCase):
|
||||
p.ibm_storage_cli.cmd.cg_create.side_effect = errors.XCLIError(
|
||||
'bla', 'bla', ElementTree.Element('bla'))
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
model_update, vols_update = p.create_consistencygroup_from_src(
|
||||
{}, TEST_CONS_GROUP, [TEST_VOLUME],
|
||||
TEST_CG_SNAPSHOT, [TEST_SNAPSHOT], None, None)
|
||||
group_obj = self._create_test_group()
|
||||
cgsnap_group_obj = self._create_test_cgsnapshot(group_obj.id)
|
||||
|
||||
volume = testutils.create_volume(self.ctxt)
|
||||
snapshot = testutils.create_snapshot(self.ctxt, volume.id)
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
self.assertRaises(ex, p.create_group_from_src, {},
|
||||
group_obj, [volume], cgsnap_group_obj,
|
||||
[snapshot], None, None)
|
||||
|
||||
@mock.patch("cinder.volume.drivers.ibm.ibm_storage."
|
||||
"xiv_proxy.XIVProxy._get_extra_specs",
|
||||
mock.MagicMock(return_value=TEST_EXTRA_SPECS))
|
||||
def test_create_consistencygroup_from_src_fails_cg_create_from_cg(self):
|
||||
"""test cg create from cg fails on cg_create"""
|
||||
driver = mock.MagicMock()
|
||||
@ -1291,15 +1285,17 @@ class XIVProxyTest(unittest.TestCase):
|
||||
p.ibm_storage_cli.cmd.cg_create.side_effect = errors.XCLIError(
|
||||
'bla', 'bla', ElementTree.Element('bla'))
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
model_update, vols_update = p.create_consistencygroup_from_src(
|
||||
{}, TEST_CONS_GROUP, [TEST_VOLUME],
|
||||
None, None, TEST_CONS_GROUP, [TEST_CLONED_VOLUME])
|
||||
group_obj = self._create_test_group()
|
||||
src_group_obj = self._create_test_group(g_name='src_group')
|
||||
|
||||
volume = testutils.create_volume(self.ctxt)
|
||||
src_volume = testutils.create_volume(self.ctxt)
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
self.assertRaises(ex, p.create_group_from_src, {},
|
||||
group_obj, [volume], None, None,
|
||||
src_group_obj, [src_volume])
|
||||
|
||||
@mock.patch("cinder.volume.drivers.ibm.ibm_storage."
|
||||
"xiv_proxy.XIVProxy._get_extra_specs",
|
||||
mock.MagicMock(return_value=TEST_EXTRA_SPECS))
|
||||
def test_create_consistencygroup_from_src_fails_vol_create_from_cgsnapshot(
|
||||
self):
|
||||
"""test cg create from cgsnapshot fails on vol_create"""
|
||||
@ -1316,15 +1312,17 @@ class XIVProxyTest(unittest.TestCase):
|
||||
p.ibm_storage_cli.cmd.vol_create.side_effect = errors.XCLIError(
|
||||
'bla', 'bla', ElementTree.Element('bla'))
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
model_update, vols_update = p.create_consistencygroup_from_src(
|
||||
{}, TEST_CONS_GROUP, [TEST_VOLUME],
|
||||
TEST_CG_SNAPSHOT, [TEST_SNAPSHOT], None, None)
|
||||
group_obj = self._create_test_group()
|
||||
cgsnap_group_obj = self._create_test_cgsnapshot(group_obj.id)
|
||||
|
||||
volume = testutils.create_volume(self.ctxt)
|
||||
snapshot = testutils.create_snapshot(self.ctxt, volume.id)
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
self.assertRaises(ex, p.create_group_from_src, {},
|
||||
group_obj, [volume], cgsnap_group_obj,
|
||||
[snapshot], None, None)
|
||||
|
||||
@mock.patch("cinder.volume.drivers.ibm.ibm_storage."
|
||||
"xiv_proxy.XIVProxy._get_extra_specs",
|
||||
mock.MagicMock(return_value=TEST_EXTRA_SPECS))
|
||||
def test_create_consistencygroup_from_src_fails_vol_create_from_cg(self):
|
||||
"""test cg create from cg fails on vol_create"""
|
||||
driver = mock.MagicMock()
|
||||
@ -1340,15 +1338,17 @@ class XIVProxyTest(unittest.TestCase):
|
||||
p.ibm_storage_cli.cmd.vol_create.side_effect = errors.XCLIError(
|
||||
'bla', 'bla', ElementTree.Element('bla'))
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
model_update, vols_update = p.create_consistencygroup_from_src(
|
||||
{}, TEST_CONS_GROUP, [TEST_VOLUME],
|
||||
None, None, TEST_CONS_GROUP, [TEST_CLONED_VOLUME])
|
||||
group_obj = self._create_test_group()
|
||||
src_group_obj = self._create_test_group(g_name='src_group')
|
||||
|
||||
volume = testutils.create_volume(self.ctxt)
|
||||
src_volume = testutils.create_volume(self.ctxt)
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
self.assertRaises(ex, p.create_group_from_src, {},
|
||||
group_obj, [volume], None, None,
|
||||
src_group_obj, [src_volume])
|
||||
|
||||
@mock.patch("cinder.volume.drivers.ibm.ibm_storage."
|
||||
"xiv_proxy.XIVProxy._get_extra_specs",
|
||||
mock.MagicMock(return_value=TEST_EXTRA_SPECS))
|
||||
def test_create_consistencygroup_from_src_fails_vol_copy_from_cgsnapshot(
|
||||
self):
|
||||
"""test cg create from cgsnapshot fails on vol_copy"""
|
||||
@ -1365,15 +1365,17 @@ class XIVProxyTest(unittest.TestCase):
|
||||
p.ibm_storage_cli.cmd.vol_copy.side_effect = errors.XCLIError(
|
||||
'bla', 'bla', ElementTree.Element('bla'))
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
model_update, vols_update = p.create_consistencygroup_from_src(
|
||||
{}, TEST_CONS_GROUP, [TEST_VOLUME],
|
||||
TEST_CG_SNAPSHOT, [TEST_SNAPSHOT], None, None)
|
||||
group_obj = self._create_test_group()
|
||||
cgsnap_group_obj = self._create_test_cgsnapshot(group_obj.id)
|
||||
|
||||
volume = testutils.create_volume(self.ctxt)
|
||||
snapshot = testutils.create_snapshot(self.ctxt, volume.id)
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
self.assertRaises(ex, p.create_group_from_src, {}, group_obj,
|
||||
[volume], cgsnap_group_obj, [snapshot],
|
||||
None, None)
|
||||
|
||||
@mock.patch("cinder.volume.drivers.ibm.ibm_storage."
|
||||
"xiv_proxy.XIVProxy._get_extra_specs",
|
||||
mock.MagicMock(return_value=TEST_EXTRA_SPECS))
|
||||
def test_create_consistencygroup_from_src_fails_vol_copy_from_cg(self):
|
||||
"""test cg create from cg fails on vol_copy"""
|
||||
driver = mock.MagicMock()
|
||||
@ -1389,15 +1391,18 @@ class XIVProxyTest(unittest.TestCase):
|
||||
p.ibm_storage_cli.cmd.vol_copy.side_effect = errors.XCLIError(
|
||||
'bla', 'bla', ElementTree.Element('bla'))
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
model_update, vols_update = p.create_consistencygroup_from_src(
|
||||
{}, TEST_CONS_GROUP, [TEST_VOLUME],
|
||||
None, None, TEST_CONS_GROUP, [TEST_CLONED_VOLUME])
|
||||
group_obj = self._create_test_group()
|
||||
src_group_obj = self._create_test_group(g_name='src_group')
|
||||
|
||||
@mock.patch("cinder.db.volume_get_all_by_group", new=mock.MagicMock(
|
||||
return_value=[]))
|
||||
def test_delete_consistencygroup(self):
|
||||
volume = testutils.create_volume(self.ctxt)
|
||||
src_volume = testutils.create_volume(self.ctxt)
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
self.assertRaises(ex, p.create_group_from_src, {},
|
||||
group_obj, [volume], None, None,
|
||||
src_group_obj, [src_volume])
|
||||
|
||||
def test_delete_consistencygroup_with_no_volumes(self):
|
||||
"""test a successful cg delete"""
|
||||
driver = mock.MagicMock()
|
||||
driver.VERSION = "VERSION"
|
||||
@ -1410,17 +1415,16 @@ class XIVProxyTest(unittest.TestCase):
|
||||
|
||||
p.ibm_storage_cli = mock.MagicMock()
|
||||
|
||||
model_update, volumes = p.delete_consistencygroup(
|
||||
{}, TEST_CONS_GROUP, [])
|
||||
group_obj = self._create_test_group()
|
||||
|
||||
model_update, volumes = p.delete_group({}, group_obj, [])
|
||||
|
||||
p.ibm_storage_cli.cmd.cg_delete.assert_called_once_with(
|
||||
cg='cg_WTF32')
|
||||
cg=p._cg_name_from_id(group_obj.id))
|
||||
|
||||
self.assertEqual('deleted', model_update['status'])
|
||||
|
||||
@mock.patch("cinder.db.volume_get_all_by_group", new=mock.MagicMock(
|
||||
return_value=[]))
|
||||
def test_delete_consistencygroup_already_exists(self):
|
||||
def test_delete_consistencygroup_not_exists(self):
|
||||
"""test delete_consistenygroup when CG does not exist"""
|
||||
driver = mock.MagicMock()
|
||||
driver.VERSION = "VERSION"
|
||||
@ -1437,17 +1441,16 @@ class XIVProxyTest(unittest.TestCase):
|
||||
errors.CgDoesNotExistError(
|
||||
'bla', 'bla', ElementTree.Element('bla')))
|
||||
|
||||
model_update, volumes = p.delete_consistencygroup(
|
||||
{}, TEST_CONS_GROUP, [])
|
||||
group_obj = self._create_test_group()
|
||||
|
||||
model_update, volumes = p.delete_group({}, group_obj, [])
|
||||
|
||||
p.ibm_storage_cli.cmd.cg_delete.assert_called_once_with(
|
||||
cg='cg_WTF32')
|
||||
cg=p._cg_name_from_id(group_obj.id))
|
||||
|
||||
self.assertEqual('deleted', model_update['status'])
|
||||
|
||||
@mock.patch("cinder.db.volume_get_all_by_group", new=mock.MagicMock(
|
||||
return_value=[]))
|
||||
def test_delete_consistencygroup_already_exists_2(self):
|
||||
def test_delete_consistencygroup_not_exists_2(self):
|
||||
"""test delete_consistenygroup when CG does not exist bad name"""
|
||||
driver = mock.MagicMock()
|
||||
driver.VERSION = "VERSION"
|
||||
@ -1464,16 +1467,14 @@ class XIVProxyTest(unittest.TestCase):
|
||||
errors.CgBadNameError(
|
||||
'bla', 'bla', ElementTree.Element('bla')))
|
||||
|
||||
model_update, volumes = p.delete_consistencygroup(
|
||||
{}, TEST_CONS_GROUP, [])
|
||||
group_obj = self._create_test_group()
|
||||
model_update, volumes = p.delete_group({}, group_obj, [])
|
||||
|
||||
p.ibm_storage_cli.cmd.cg_delete.assert_called_once_with(
|
||||
cg='cg_WTF32')
|
||||
cg=p._cg_name_from_id(group_obj.id))
|
||||
|
||||
self.assertEqual('deleted', model_update['status'])
|
||||
|
||||
@mock.patch("cinder.db.volume_get_all_by_group", new=mock.MagicMock(
|
||||
return_value=[]))
|
||||
def test_delete_consistencygroup_not_empty(self):
|
||||
"""test delete_consistenygroup when CG is not empty"""
|
||||
driver = mock.MagicMock()
|
||||
@ -1490,13 +1491,11 @@ class XIVProxyTest(unittest.TestCase):
|
||||
p.ibm_storage_cli.cmd.cg_delete.side_effect = errors.CgNotEmptyError(
|
||||
'bla', 'bla', ElementTree.Element('bla'))
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
model_update, volumes = p.delete_consistencygroup(
|
||||
{}, TEST_CONS_GROUP, [])
|
||||
group_obj = self._create_test_group()
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
self.assertRaises(ex, p.delete_group, {}, group_obj, [])
|
||||
|
||||
@mock.patch("cinder.db.volume_get_all_by_group", new=mock.MagicMock(
|
||||
return_value=[]))
|
||||
def test_delete_consistencygroup_is_mirrored(self):
|
||||
"""test delete_consistenygroup when CG is mirroring"""
|
||||
driver = mock.MagicMock()
|
||||
@ -1513,10 +1512,10 @@ class XIVProxyTest(unittest.TestCase):
|
||||
p.ibm_storage_cli.cmd.cg_delete.side_effect = errors.CgHasMirrorError(
|
||||
'bla', 'bla', ElementTree.Element('bla'))
|
||||
|
||||
group_obj = self._create_test_group()
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
model_update, volumes = p.delete_consistencygroup(
|
||||
{}, TEST_CONS_GROUP, [])
|
||||
self.assertRaises(ex, p.delete_group, {}, group_obj, [])
|
||||
|
||||
def test_update_consistencygroup(self):
|
||||
"""test update_consistencygroup"""
|
||||
@ -1531,14 +1530,17 @@ class XIVProxyTest(unittest.TestCase):
|
||||
|
||||
p.ibm_storage_cli = mock.MagicMock()
|
||||
|
||||
group_obj = self._create_test_group()
|
||||
vol_add = testutils.create_volume(self.ctxt, display_name='WTF32')
|
||||
vol_remove = testutils.create_volume(self.ctxt, display_name='WTF64')
|
||||
|
||||
model_update, add_model_update, remove_model_update = (
|
||||
p.update_consistencygroup({}, TEST_CONS_GROUP,
|
||||
[{'name': 'WTF32'}],
|
||||
[{'name': 'WTF64'}]))
|
||||
p.update_group({}, group_obj, [vol_add], [vol_remove]))
|
||||
|
||||
p.ibm_storage_cli.cmd.cg_add_vol.assert_called_once_with(
|
||||
vol='WTF32', cg='cg_WTF32')
|
||||
vol=vol_add['name'], cg=p._cg_name_from_id(group_obj.id))
|
||||
p.ibm_storage_cli.cmd.cg_remove_vol.assert_called_once_with(
|
||||
vol='WTF64')
|
||||
vol=vol_remove['name'])
|
||||
self.assertEqual('available', model_update['status'])
|
||||
|
||||
def test_update_consistencygroup_exception_in_add_vol(self):
|
||||
@ -1556,12 +1558,11 @@ class XIVProxyTest(unittest.TestCase):
|
||||
p.ibm_storage_cli.cmd.cg_add_vol.side_effect = errors.XCLIError(
|
||||
'bla', 'bla', ElementTree.Element('bla'))
|
||||
|
||||
group_obj = self._create_test_group()
|
||||
vol_add = testutils.create_volume(self.ctxt, display_name='WTF32')
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
model_update, add_model_update, remove_model_update = (
|
||||
p.update_consistencygroup({}, TEST_CONS_GROUP,
|
||||
[{'name': 'WTF32'}],
|
||||
[{'name': 'WTF64'}]))
|
||||
self.assertRaises(ex, p.update_group, {}, group_obj, [vol_add], [])
|
||||
|
||||
def test_update_consistencygroup_exception_in_remove_vol(self):
|
||||
"""test update_consistencygroup with exception in cg_remove_vol"""
|
||||
@ -1578,15 +1579,13 @@ class XIVProxyTest(unittest.TestCase):
|
||||
p.ibm_storage_cli.cmd.cg_remove_vol.side_effect = errors.XCLIError(
|
||||
'bla', 'bla', ElementTree.Element('bla'))
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
model_update, add_model_update, remove_model_update = (
|
||||
p.update_consistencygroup({}, TEST_CONS_GROUP,
|
||||
[{'name': 'WTF32'}],
|
||||
[{'name': 'WTF64'}]))
|
||||
group_obj = self._create_test_group()
|
||||
vol_remove = testutils.create_volume(self.ctxt)
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
self.assertRaises(ex, p.update_group, {},
|
||||
group_obj, [], [vol_remove])
|
||||
|
||||
@mock.patch("cinder.db.snapshot_get_all_for_cgsnapshot",
|
||||
new=mock.MagicMock(return_value=[]))
|
||||
def test_create_cgsnapshot(self):
|
||||
"""test a successful cgsnapshot create"""
|
||||
driver = mock.MagicMock()
|
||||
@ -1599,17 +1598,18 @@ class XIVProxyTest(unittest.TestCase):
|
||||
driver)
|
||||
|
||||
p.ibm_storage_cli = mock.MagicMock()
|
||||
group_obj = self._create_test_group()
|
||||
cgsnap_group_obj = self._create_test_cgsnapshot(group_obj.id)
|
||||
|
||||
model_update, snapshots_model_update = p.create_cgsnapshot(
|
||||
{}, TEST_CG_SNAPSHOT, [])
|
||||
model_update, snapshots_model_update = (
|
||||
p.create_group_snapshot({}, cgsnap_group_obj, []))
|
||||
|
||||
p.ibm_storage_cli.cmd.cg_snapshots_create.assert_called_once_with(
|
||||
cg='cg_WTF32', snap_group='cgs_WTF')
|
||||
cg=p._cg_name_from_cgsnapshot(cgsnap_group_obj),
|
||||
snap_group=p._group_name_from_cgsnapshot(cgsnap_group_obj))
|
||||
|
||||
self.assertEqual('available', model_update['status'])
|
||||
|
||||
@mock.patch("cinder.db.snapshot_get_all_for_cgsnapshot",
|
||||
new=mock.MagicMock(return_value=[]))
|
||||
def test_create_cgsnapshot_is_empty(self):
|
||||
"""test create_cgsnapshot when CG is empty"""
|
||||
driver = mock.MagicMock()
|
||||
@ -1622,17 +1622,16 @@ class XIVProxyTest(unittest.TestCase):
|
||||
driver)
|
||||
|
||||
p.ibm_storage_cli = mock.MagicMock()
|
||||
group_obj = self._create_test_group()
|
||||
cgsnap_group_obj = self._create_test_cgsnapshot(group_obj.id)
|
||||
|
||||
p.ibm_storage_cli.cmd.cg_snapshots_create.side_effect = (
|
||||
errors.CgEmptyError('bla', 'bla', ElementTree.Element('bla')))
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
model_update, snapshots_model_update = p.create_cgsnapshot(
|
||||
{}, TEST_CG_SNAPSHOT, [])
|
||||
self.assertRaises(ex, p.create_group_snapshot, {},
|
||||
cgsnap_group_obj, [])
|
||||
|
||||
@mock.patch("cinder.db.snapshot_get_all_for_cgsnapshot",
|
||||
new=mock.MagicMock(return_value=[]))
|
||||
def test_create_cgsnapshot_cg_not_exist(self):
|
||||
"""test create_cgsnapshot when CG does not exist"""
|
||||
driver = mock.MagicMock()
|
||||
@ -1645,18 +1644,17 @@ class XIVProxyTest(unittest.TestCase):
|
||||
driver)
|
||||
|
||||
p.ibm_storage_cli = mock.MagicMock()
|
||||
group_obj = self._create_test_group()
|
||||
cgsnap_group_obj = self._create_test_cgsnapshot(group_obj.id)
|
||||
|
||||
p.ibm_storage_cli.cmd.cg_snapshots_create.side_effect = (
|
||||
errors.CgDoesNotExistError(
|
||||
'bla', 'bla', ElementTree.Element('bla')))
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
model_update, snapshots_model_update = p.create_cgsnapshot(
|
||||
{}, TEST_CG_SNAPSHOT, [])
|
||||
self.assertRaises(ex, p.create_group_snapshot, {},
|
||||
cgsnap_group_obj, [])
|
||||
|
||||
@mock.patch("cinder.db.snapshot_get_all_for_cgsnapshot",
|
||||
new=mock.MagicMock(return_value=[]))
|
||||
def test_create_cgsnapshot_snapshot_limit(self):
|
||||
"""test create_cgsnapshot when reached snapshot limit"""
|
||||
driver = mock.MagicMock()
|
||||
@ -1669,18 +1667,17 @@ class XIVProxyTest(unittest.TestCase):
|
||||
driver)
|
||||
|
||||
p.ibm_storage_cli = mock.MagicMock()
|
||||
group_obj = self._create_test_group()
|
||||
cgsnap_group_obj = self._create_test_cgsnapshot(group_obj.id)
|
||||
|
||||
p.ibm_storage_cli.cmd.cg_snapshots_create.side_effect = (
|
||||
errors.PoolSnapshotLimitReachedError(
|
||||
'bla', 'bla', ElementTree.Element('bla')))
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
model_update, snapshots_model_update = p.create_cgsnapshot(
|
||||
{}, TEST_CG_SNAPSHOT, [])
|
||||
self.assertRaises(ex, p.create_group_snapshot, {},
|
||||
cgsnap_group_obj, [])
|
||||
|
||||
@mock.patch("cinder.db.snapshot_get_all_for_cgsnapshot",
|
||||
new=mock.MagicMock(return_value=[]))
|
||||
def test_delete_cgsnapshot(self):
|
||||
"""test a successful cgsnapshot delete"""
|
||||
driver = mock.MagicMock()
|
||||
@ -1693,17 +1690,17 @@ class XIVProxyTest(unittest.TestCase):
|
||||
driver)
|
||||
|
||||
p.ibm_storage_cli = mock.MagicMock()
|
||||
group_obj = self._create_test_group()
|
||||
cgsnap_group_obj = self._create_test_cgsnapshot(group_obj.id)
|
||||
|
||||
model_update, snapshots_model_update = p.delete_cgsnapshot(
|
||||
{}, TEST_CG_SNAPSHOT, [])
|
||||
model_update, snapshots_model_update = p.delete_group_snapshot(
|
||||
{}, cgsnap_group_obj, [])
|
||||
|
||||
p.ibm_storage_cli.cmd.snap_group_delete.assert_called_once_with(
|
||||
snap_group='cgs_WTF')
|
||||
snap_group=p._group_name_from_cgsnapshot(cgsnap_group_obj))
|
||||
|
||||
self.assertEqual('deleted', model_update['status'])
|
||||
|
||||
@mock.patch("cinder.db.snapshot_get_all_for_cgsnapshot",
|
||||
new=mock.MagicMock(return_value=[]))
|
||||
def test_delete_cgsnapshot_cg_does_not_exist(self):
|
||||
"""test delete_cgsnapshot with bad CG name"""
|
||||
driver = mock.MagicMock()
|
||||
@ -1716,18 +1713,17 @@ class XIVProxyTest(unittest.TestCase):
|
||||
driver)
|
||||
|
||||
p.ibm_storage_cli = mock.MagicMock()
|
||||
group_obj = self._create_test_group()
|
||||
cgsnap_group_obj = self._create_test_cgsnapshot(group_obj.id)
|
||||
|
||||
p.ibm_storage_cli.cmd.snap_group_delete.side_effect = (
|
||||
errors.CgDoesNotExistError(
|
||||
'bla', 'bla', ElementTree.Element('bla')))
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
model_update, snapshots_model_update = p.delete_cgsnapshot(
|
||||
{}, TEST_CG_SNAPSHOT, [])
|
||||
self.assertRaises(ex, p.delete_group_snapshot, {},
|
||||
cgsnap_group_obj, [])
|
||||
|
||||
@mock.patch("cinder.db.snapshot_get_all_for_cgsnapshot",
|
||||
new=mock.MagicMock(return_value=[]))
|
||||
def test_delete_cgsnapshot_no_space_left_for_snapshots(self):
|
||||
"""test delete_cgsnapshot when no space left for snapshots"""
|
||||
driver = mock.MagicMock()
|
||||
@ -1740,18 +1736,17 @@ class XIVProxyTest(unittest.TestCase):
|
||||
driver)
|
||||
|
||||
p.ibm_storage_cli = mock.MagicMock()
|
||||
group_obj = self._create_test_group()
|
||||
cgsnap_group_obj = self._create_test_cgsnapshot(group_obj.id)
|
||||
|
||||
p.ibm_storage_cli.cmd.snap_group_delete.side_effect = (
|
||||
errors.PoolSnapshotLimitReachedError(
|
||||
'bla', 'bla', ElementTree.Element('bla')))
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
model_update, snapshots_model_update = p.delete_cgsnapshot(
|
||||
{}, TEST_CG_SNAPSHOT, [])
|
||||
self.assertRaises(ex, p.delete_group_snapshot, {},
|
||||
cgsnap_group_obj, [])
|
||||
|
||||
@mock.patch("cinder.db.snapshot_get_all_for_cgsnapshot",
|
||||
new=mock.MagicMock(return_value=[]))
|
||||
def test_delete_cgsnapshot_with_empty_consistency_group(self):
|
||||
"""test delete_cgsnapshot with empty consistency group"""
|
||||
driver = mock.MagicMock()
|
||||
@ -1764,14 +1759,15 @@ class XIVProxyTest(unittest.TestCase):
|
||||
driver)
|
||||
|
||||
p.ibm_storage_cli = mock.MagicMock()
|
||||
group_obj = self._create_test_group()
|
||||
cgsnap_group_obj = self._create_test_cgsnapshot(group_obj.id)
|
||||
|
||||
p.ibm_storage_cli.cmd.snap_group_delete.side_effect = (
|
||||
errors.CgEmptyError('bla', 'bla', ElementTree.Element('bla')))
|
||||
|
||||
ex = getattr(p, "_get_exception")()
|
||||
with self.assertRaises(ex):
|
||||
model_update, snapshots_model_update = p.delete_cgsnapshot(
|
||||
{}, TEST_CG_SNAPSHOT, [])
|
||||
self.assertRaises(ex, p.delete_group_snapshot, {},
|
||||
cgsnap_group_obj, [])
|
||||
|
||||
def test_silent_delete_volume(self):
|
||||
"""test _silent_delete_volume fails silently without exception"""
|
||||
|
@ -31,7 +31,7 @@ if pyxcli:
|
||||
|
||||
from cinder import context
|
||||
from cinder.i18n import _
|
||||
from cinder import objects
|
||||
from cinder.objects import fields
|
||||
from cinder import volume as c_volume
|
||||
import cinder.volume.drivers.ibm.ibm_storage as storage
|
||||
from cinder.volume.drivers.ibm.ibm_storage import certificate
|
||||
@ -39,8 +39,10 @@ from cinder.volume.drivers.ibm.ibm_storage import cryptish
|
||||
from cinder.volume.drivers.ibm.ibm_storage import proxy
|
||||
from cinder.volume.drivers.ibm.ibm_storage import strings
|
||||
from cinder.volume import qos_specs
|
||||
from cinder.volume import utils
|
||||
from cinder.volume import volume_types
|
||||
|
||||
|
||||
OPENSTACK_PRODUCT_NAME = "OpenStack"
|
||||
PERF_CLASS_NAME_PREFIX = "cinder-qos"
|
||||
HOST_BAD_NAME = "HOST_BAD_NAME"
|
||||
@ -1291,7 +1293,7 @@ class XIVProxy(proxy.IBMStorageProxy):
|
||||
raise self.meta['exception'].VolumeBackendAPIException(
|
||||
data=msg)
|
||||
pool_master = self.storage_info[storage.FLAG_KEYS['storage_pool']]
|
||||
goal_status = objects.fields.ReplicationStatus.FAILED_OVER
|
||||
goal_status = fields.ReplicationStatus.FAILED_OVER
|
||||
|
||||
# connnect xcli to secondary storage according to backend_id by
|
||||
# calling _init_xcli with secondary_id
|
||||
@ -1489,7 +1491,7 @@ class XIVProxy(proxy.IBMStorageProxy):
|
||||
pool.get('empty_space_soft', pool.get('empty_space')))
|
||||
self.meta['stat']['reserved_percentage'] = (
|
||||
self.driver.configuration.safe_get('reserved_percentage'))
|
||||
self.meta['stat']['consistencygroup_support'] = True
|
||||
self.meta['stat']['consistent_group_snapshot_enabled'] = True
|
||||
|
||||
# thin/thick provision
|
||||
self.meta['stat']['thin_provision'] = ('True' if soft_size > hard_size
|
||||
@ -1617,7 +1619,7 @@ class XIVProxy(proxy.IBMStorageProxy):
|
||||
A utility method to translate from openstack cgsnapshot
|
||||
to CG name on the storage
|
||||
'''
|
||||
return self._cg_name_from_id(cgsnapshot['consistencygroup_id'])
|
||||
return self._cg_name_from_id(cgsnapshot['group_id'])
|
||||
|
||||
def _group_name_from_cgsnapshot(self, cgsnapshot):
|
||||
'''Get storage Snaphost Group name from snapshot.
|
||||
@ -1632,34 +1634,33 @@ class XIVProxy(proxy.IBMStorageProxy):
|
||||
return ('%(cgs)s.%(vol)s' % {'cgs': cgs, 'vol': vol})[0:62]
|
||||
|
||||
@proxy._trace_time
|
||||
def create_consistencygroup(self, context, group):
|
||||
"""Creates a consistency group."""
|
||||
def create_group(self, context, group):
|
||||
"""Creates a group."""
|
||||
|
||||
cgname = self._cg_name_from_group(group)
|
||||
LOG.info("Creating consistency group %(name)s.",
|
||||
{'name': cgname})
|
||||
if isinstance(group, objects.Group):
|
||||
volume_type_ids = group.volume_type_ids
|
||||
elif isinstance(group, objects.ConsistencyGroup):
|
||||
volume_type_ids = filter(None, group.volume_type_id.split(","))
|
||||
else:
|
||||
msg = (_("Consistency group %(group)s has no volume_type_ids") %
|
||||
{'group': cgname})
|
||||
LOG.error(msg)
|
||||
raise self.meta['exception'].VolumeBackendAPIException(data=msg)
|
||||
LOG.debug("volume_type_ids: %s", volume_type_ids)
|
||||
for volume_type_id in volume_type_ids:
|
||||
specs = self._get_extra_specs(volume_type_id)
|
||||
replication_info = self._get_replication_info(specs)
|
||||
for volume_type in group.volume_types:
|
||||
replication_info = self._get_replication_info(
|
||||
volume_type.extra_specs)
|
||||
|
||||
if replication_info.get('enabled'):
|
||||
# An unsupported illegal configuration
|
||||
msg = _("Unable to create consistency group: "
|
||||
"Replication of consistency group is not supported")
|
||||
msg = _("Unable to create group: create group with "
|
||||
"replication volume type is not supported")
|
||||
LOG.error(msg)
|
||||
raise self.meta['exception'].VolumeBackendAPIException(
|
||||
data=msg)
|
||||
|
||||
if utils.is_group_a_cg_snapshot_type(group):
|
||||
cgname = self._cg_name_from_group(group)
|
||||
return self._create_consistencygroup(context, cgname)
|
||||
# For generic group, create is executed by manager
|
||||
raise NotImplementedError()
|
||||
|
||||
def _create_consistencygroup(self, context, cgname):
|
||||
"""Creates a consistency group."""
|
||||
|
||||
LOG.info("Creating consistency group %(name)s.",
|
||||
{'name': cgname})
|
||||
|
||||
# call XCLI
|
||||
try:
|
||||
self._call_xiv_xcli(
|
||||
@ -1680,7 +1681,7 @@ class XIVProxy(proxy.IBMStorageProxy):
|
||||
{'details': self._get_code_and_status_or_message(e)})
|
||||
LOG.error(error)
|
||||
raise self._get_exception()(error)
|
||||
model_update = {'status': 'available'}
|
||||
model_update = {'status': fields.GroupStatus.AVAILABLE}
|
||||
return model_update
|
||||
|
||||
def _silent_cleanup_consistencygroup_from_src(self, context, group,
|
||||
@ -1694,16 +1695,30 @@ class XIVProxy(proxy.IBMStorageProxy):
|
||||
for volume in volumes:
|
||||
self._silent_delete_volume_from_cg(volume=volume, cgname=cgname)
|
||||
try:
|
||||
self.delete_consistencygroup(context, group, [])
|
||||
self._delete_consistencygroup(context, group, [])
|
||||
except Exception as e:
|
||||
details = self._get_code_and_status_or_message(e)
|
||||
LOG.error('Failed to cleanup CG %(details)s',
|
||||
{'details': details})
|
||||
|
||||
@proxy._trace_time
|
||||
def create_consistencygroup_from_src(self, context, group, volumes,
|
||||
cgsnapshot, snapshots,
|
||||
source_cg, sorted_source_vols):
|
||||
def create_group_from_src(self, context, group, volumes, group_snapshot,
|
||||
sorted_snapshots, source_group,
|
||||
sorted_source_vols):
|
||||
"""Create volume group from volume group or volume group snapshot."""
|
||||
if utils.is_group_a_cg_snapshot_type(group):
|
||||
return self._create_consistencygroup_from_src(context, group,
|
||||
volumes,
|
||||
group_snapshot,
|
||||
sorted_snapshots,
|
||||
source_group,
|
||||
sorted_source_vols)
|
||||
else:
|
||||
raise NotImplementedError()
|
||||
|
||||
def _create_consistencygroup_from_src(self, context, group, volumes,
|
||||
cgsnapshot, snapshots, source_cg,
|
||||
sorted_source_vols):
|
||||
"""Creates a consistencygroup from source.
|
||||
|
||||
Source can be a cgsnapshot with the relevant list of snapshots,
|
||||
@ -1718,7 +1733,7 @@ class XIVProxy(proxy.IBMStorageProxy):
|
||||
LOG.debug("Creating from cgsnapshot %(cg)s",
|
||||
{'cg': self._cg_name_from_group(cgsnapshot)})
|
||||
try:
|
||||
self.create_consistencygroup(context, group)
|
||||
self._create_consistencygroup(context, group)
|
||||
except Exception as e:
|
||||
LOG.error(
|
||||
"Creating CG from cgsnapshot failed: %(details)s",
|
||||
@ -1762,7 +1777,7 @@ class XIVProxy(proxy.IBMStorageProxy):
|
||||
{'cg': self._cg_name_from_group(source_cg)})
|
||||
LOG.debug("Creating from CG %(cg)s .", {'cg': source_cg['id']})
|
||||
try:
|
||||
self.create_consistencygroup(context, group)
|
||||
self._create_consistencygroup(context, group)
|
||||
except Exception as e:
|
||||
LOG.error("Creating CG from CG failed: %(details)s",
|
||||
{'details': self._get_code_and_status_or_message(e)})
|
||||
@ -1792,18 +1807,27 @@ class XIVProxy(proxy.IBMStorageProxy):
|
||||
error = 'create_consistencygroup_from_src called without a source'
|
||||
raise self._get_exception()(error)
|
||||
|
||||
model_update = {'status': 'available'}
|
||||
model_update = {'status': fields.GroupStatus.AVAILABLE}
|
||||
return model_update, volumes_model_update
|
||||
|
||||
@proxy._trace_time
|
||||
def delete_consistencygroup(self, context, group, volumes):
|
||||
def delete_group(self, context, group, volumes):
|
||||
"""Deletes a group."""
|
||||
if utils.is_group_a_cg_snapshot_type(group):
|
||||
return self._delete_consistencygroup(context, group, volumes)
|
||||
else:
|
||||
# For generic group delete the volumes only - executed by manager
|
||||
raise NotImplementedError()
|
||||
|
||||
def _delete_consistencygroup(self, context, group, volumes):
|
||||
"""Deletes a consistency group."""
|
||||
|
||||
cgname = self._cg_name_from_group(group)
|
||||
LOG.info("Deleting consistency group %(name)s.",
|
||||
{'name': cgname})
|
||||
model_update = {}
|
||||
model_update['status'] = group.get('status', 'deleting')
|
||||
model_update['status'] = group.get('status',
|
||||
fields.GroupStatus.DELETING)
|
||||
|
||||
# clean up volumes
|
||||
volumes_model_update = []
|
||||
@ -1832,9 +1856,9 @@ class XIVProxy(proxy.IBMStorageProxy):
|
||||
LOG.error(DELETE_VOLUME_BASE_ERROR,
|
||||
{'volume': volume['name'],
|
||||
'error': self._get_code_and_status_or_message(e)})
|
||||
model_update['status'] = 'error_deleting'
|
||||
model_update['status'] = fields.GroupStatus.ERROR_DELETING
|
||||
# size and volume_type_id are required in liberty code
|
||||
# they are maintained here for backwards compatability
|
||||
# they are maintained here for backwards compatibility
|
||||
volumes_model_update.append(
|
||||
{
|
||||
'id': volume['id'],
|
||||
@ -1842,18 +1866,18 @@ class XIVProxy(proxy.IBMStorageProxy):
|
||||
})
|
||||
|
||||
# delete CG from cinder.volume.drivers.ibm.ibm_storage
|
||||
if model_update['status'] != 'error_deleting':
|
||||
if model_update['status'] != fields.GroupStatus.ERROR_DELETING:
|
||||
try:
|
||||
self._call_xiv_xcli(
|
||||
"cg_delete", cg=cgname).as_list
|
||||
model_update['status'] = 'deleted'
|
||||
model_update['status'] = fields.GroupStatus.DELETED
|
||||
except (errors.CgDoesNotExistError, errors.CgBadNameError):
|
||||
LOG.warning("consistency group %(cgname)s does not "
|
||||
"exist on backend",
|
||||
{'cgname': cgname})
|
||||
# if the object was already deleted on the backend, we can
|
||||
# continue and delete the openstack object
|
||||
model_update['status'] = 'deleted'
|
||||
model_update['status'] = fields.GroupStatus.DELETED
|
||||
except errors.CgHasMirrorError:
|
||||
error = (_("consistency group %s is being mirrored") % cgname)
|
||||
LOG.error(error)
|
||||
@ -1871,13 +1895,23 @@ class XIVProxy(proxy.IBMStorageProxy):
|
||||
return model_update, volumes_model_update
|
||||
|
||||
@proxy._trace_time
|
||||
def update_consistencygroup(self, context, group,
|
||||
add_volumes=None, remove_volumes=None):
|
||||
def update_group(self, context, group,
|
||||
add_volumes=None, remove_volumes=None):
|
||||
"""Updates a group."""
|
||||
if utils.is_group_a_cg_snapshot_type(group):
|
||||
return self._update_consistencygroup(context, group, add_volumes,
|
||||
remove_volumes)
|
||||
else:
|
||||
# For generic group update executed by manager
|
||||
raise NotImplementedError()
|
||||
|
||||
def _update_consistencygroup(self, context, group,
|
||||
add_volumes=None, remove_volumes=None):
|
||||
"""Updates a consistency group."""
|
||||
|
||||
cgname = self._cg_name_from_group(group)
|
||||
LOG.info("Updating consistency group %(name)s.", {'name': cgname})
|
||||
model_update = {'status': 'available'}
|
||||
model_update = {'status': fields.GroupStatus.AVAILABLE}
|
||||
|
||||
add_volumes_update = []
|
||||
if add_volumes:
|
||||
@ -1939,9 +1973,18 @@ class XIVProxy(proxy.IBMStorageProxy):
|
||||
{'name': volume['name'], 'cgname': cgname})
|
||||
|
||||
@proxy._trace_time
|
||||
def create_cgsnapshot(self, context, cgsnapshot, snapshots):
|
||||
def create_group_snapshot(self, context, group_snapshot, snapshots):
|
||||
"""Create volume group snapshot."""
|
||||
|
||||
if utils.is_group_a_cg_snapshot_type(group_snapshot):
|
||||
return self._create_cgsnapshot(context, group_snapshot, snapshots)
|
||||
else:
|
||||
# For generic group snapshot create executed by manager
|
||||
raise NotImplementedError()
|
||||
|
||||
def _create_cgsnapshot(self, context, cgsnapshot, snapshots):
|
||||
"""Creates a CG snapshot."""
|
||||
model_update = {'status': 'available'}
|
||||
model_update = {'status': fields.GroupSnapshotStatus.AVAILABLE}
|
||||
|
||||
cgname = self._cg_name_from_cgsnapshot(cgsnapshot)
|
||||
groupname = self._group_name_from_cgsnapshot(cgsnapshot)
|
||||
@ -2000,12 +2043,20 @@ class XIVProxy(proxy.IBMStorageProxy):
|
||||
snapshots_model_update.append(
|
||||
{
|
||||
'id': snapshot['id'],
|
||||
'status': 'available',
|
||||
'status': fields.SnapshotStatus.AVAILABLE,
|
||||
})
|
||||
return model_update, snapshots_model_update
|
||||
|
||||
@proxy._trace_time
|
||||
def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
|
||||
def delete_group_snapshot(self, context, group_snapshot, snapshots):
|
||||
"""Delete volume group snapshot."""
|
||||
if utils.is_group_a_cg_snapshot_type(group_snapshot):
|
||||
return self._delete_cgsnapshot(context, group_snapshot, snapshots)
|
||||
else:
|
||||
# For generic group snapshot delete is executed by manager
|
||||
raise NotImplementedError()
|
||||
|
||||
def _delete_cgsnapshot(self, context, cgsnapshot, snapshots):
|
||||
"""Deletes a CG snapshot."""
|
||||
|
||||
cgname = self._cg_name_from_cgsnapshot(cgsnapshot)
|
||||
@ -2038,14 +2089,15 @@ class XIVProxy(proxy.IBMStorageProxy):
|
||||
LOG.error(error)
|
||||
raise self._get_exception()(error)
|
||||
|
||||
model_update = {'status': fields.GroupSnapshotStatus.DELETED}
|
||||
snapshots_model_update = []
|
||||
for snapshot in snapshots:
|
||||
snapshots_model_update.append(
|
||||
{
|
||||
'id': snapshot['id'],
|
||||
'status': 'deleted',
|
||||
'status': fields.SnapshotStatus.DELETED,
|
||||
})
|
||||
model_update = {'status': 'deleted'}
|
||||
|
||||
return model_update, snapshots_model_update
|
||||
|
||||
def _generate_chap_secret(self, chap_name):
|
||||
|
4
releasenotes/notes/xiv-generic-volume-group-4609cdc86d6aaf81.yaml
Executable file
4
releasenotes/notes/xiv-generic-volume-group-4609cdc86d6aaf81.yaml
Executable file
@ -0,0 +1,4 @@
|
||||
---
|
||||
features:
|
||||
- Add consistent group capability to generic volume groups in
|
||||
XIV, Spectrum Accelerate and A9000/R storage systems.
|
Loading…
Reference in New Issue
Block a user