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:
Isaac Beckman 2017-03-21 17:28:32 +02:00
parent debc2b8fa8
commit 23cf5b08ce
3 changed files with 345 additions and 293 deletions

View File

@ -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"""

View File

@ -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):

View File

@ -0,0 +1,4 @@
---
features:
- Add consistent group capability to generic volume groups in
XIV, Spectrum Accelerate and A9000/R storage systems.