cinder/cinder/tests/unit/test_emc_xtremio.py

735 lines
31 KiB
Python

# Copyright (c) 2012 - 2014 EMC Corporation, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import time
import mock
from cinder import exception
from cinder import test
from cinder.tests.unit import fake_consistencygroup as fake_cg
from cinder.tests.unit import fake_snapshot
from cinder.tests.unit import fake_volume
from cinder.volume.drivers.emc import xtremio
typ2id = {'volumes': 'vol-id',
'snapshots': 'vol-id',
'initiators': 'initiator-id',
'initiator-groups': 'ig-id',
'lun-maps': 'mapping-id',
'consistency-groups': 'cg-id',
'consistency-group-volumes': 'cg-vol-id',
}
xms_data = {'xms': {1: {'version': '4.0.0'}},
'clusters': {1: {'name': 'brick1',
'sys-sw-version': "4.0.0-devel_ba23ee5381eeab73",
'ud-ssd-space': '8146708710',
'ud-ssd-space-in-use': '708710',
'vol-size': '29884416',
'chap-authentication-mode': 'disabled',
'chap-discovery-mode': 'disabled',
"index": 1,
},
},
'target-groups': {'Default': {"index": 1, },
},
'iscsi-portals': {'10.205.68.5/16':
{"port-address":
"iqn.2008-05.com.xtremio:001e67939c34",
"ip-port": 3260,
"ip-addr": "10.205.68.5/16",
"name": "10.205.68.5/16",
"index": 1,
},
},
'targets': {'X1-SC2-fc1': {'index': 1, "name": "X1-SC2-fc1",
"port-address":
"21:00:00:24:ff:57:b2:36",
'port-state': 'up',
},
'X1-SC2-fc2': {'index': 2, "name": "X1-SC2-fc2",
"port-address":
"21:00:00:24:ff:57:b2:55",
'port-state': 'up',
}
},
'volumes': {},
'initiator-groups': {},
'initiators': {},
'lun-maps': {},
'consistency-groups': {},
'consistency-group-volumes': {},
}
def get_xms_obj_by_name(typ, name):
for item in xms_data[typ].values():
if 'name' in item and item['name'] == name:
return item
raise exception.NotFound()
def clean_xms_data():
xms_data['volumes'] = {}
xms_data['initiator-groups'] = {}
xms_data['initiators'] = {}
xms_data['lun-maps'] = {}
xms_data['consistency-group-volumes'] = {}
xms_data['consistency-groups'] = {}
def fix_data(data, object_type):
d = {}
for key, value in data.items():
if 'name' in key:
key = 'name'
d[key] = value
if object_type == 'lun-maps':
d['lun'] = 1
d[typ2id[object_type]] = ["a91e8c81c2d14ae4865187ce4f866f8a",
d.get('name'),
len(xms_data.get(object_type, [])) + 1]
d['index'] = len(xms_data[object_type]) + 1
return d
def get_xms_obj_key(data):
for key in data.keys():
if 'name' in key:
return key
def get_obj(typ, name, idx):
if name:
return {"content": get_xms_obj_by_name(typ, name)}
elif idx:
if idx not in xms_data.get(typ, {}):
raise exception.NotFound()
return {"content": xms_data[typ][idx]}
def xms_request(object_type='volumes', method='GET', data=None,
name=None, idx=None, ver='v1'):
if object_type == 'snapshots':
object_type = 'volumes'
try:
res = xms_data[object_type]
except KeyError:
raise exception.VolumeDriverException
if method == 'GET':
if name or idx:
return get_obj(object_type, name, idx)
else:
if data and data.get('full') == 1:
return {object_type: list(res.values())}
else:
return {object_type: [{"href": "/%s/%d" % (object_type,
obj['index']),
"name": obj.get('name')}
for obj in res.values()]}
elif method == 'POST':
data = fix_data(data, object_type)
name_key = get_xms_obj_key(data)
try:
if name_key and get_xms_obj_by_name(object_type, data[name_key]):
raise (exception
.VolumeBackendAPIException
('Volume by this name already exists'))
except exception.NotFound:
pass
data['index'] = len(xms_data[object_type]) + 1
xms_data[object_type][data['index']] = data
# find the name key
if name_key:
data['name'] = data[name_key]
if object_type == 'lun-maps':
data['ig-name'] = data['ig-id']
return {"links": [{"href": "/%s/%d" %
(object_type, data[typ2id[object_type]][2])}]}
elif method == 'DELETE':
if object_type == 'consistency-group-volumes':
data = [cgv for cgv in
xms_data['consistency-group-volumes'].values()
if cgv['vol-id'] == data['vol-id']
and cgv['cg-id'] == data['cg-id']][0]
else:
data = get_obj(object_type, name, idx)['content']
if data:
del xms_data[object_type][data['index']]
else:
raise exception.NotFound()
elif method == 'PUT':
obj = get_obj(object_type, name, idx)['content']
data = fix_data(data, object_type)
del data['index']
obj.update(data)
def xms_bad_request(object_type='volumes', method='GET', data=None,
name=None, idx=None, ver='v1'):
if method == 'GET':
raise exception.NotFound()
elif method == 'POST':
raise exception.VolumeBackendAPIException('Failed to create ig')
def xms_failed_rename_snapshot_request(object_type='volumes',
method='GET', data=None,
name=None, idx=None, ver='v1'):
if method == 'POST':
xms_data['volumes'][27] = {}
return {
"links": [
{
"href": "https://host/api/json/v2/types/snapshots/27",
"rel": "self"}]}
elif method == 'PUT':
raise exception.VolumeBackendAPIException(data='Failed to delete')
elif method == 'DELETE':
del xms_data['volumes'][27]
class D(dict):
def update(self, *args, **kwargs):
self.__dict__.update(*args, **kwargs)
return dict.update(self, *args, **kwargs)
class CommonData(object):
connector = {'ip': '10.0.0.2',
'initiator': 'iqn.1993-08.org.debian:01:222',
'wwpns': ["123456789012345", "123456789054321"],
'wwnns': ["223456789012345", "223456789054321"],
'host': 'fakehost',
}
test_volume = {'name': 'vol1',
'size': 1,
'volume_name': 'vol1',
'id': '192eb39b-6c2f-420c-bae3-3cfd117f0001',
'provider_auth': None,
'project_id': 'project',
'display_name': 'vol1',
'display_description': 'test volume',
'volume_type_id': None,
'consistencygroup_id':
'192eb39b-6c2f-420c-bae3-3cfd117f0345',
}
test_snapshot = D()
test_snapshot.update({'name': 'snapshot1',
'size': 1,
'id': '192eb39b-6c2f-420c-bae3-3cfd117f0002',
'volume_name': 'vol-vol1',
'volume_id': '192eb39b-6c2f-420c-bae3-3cfd117f0001',
'project_id': 'project',
'consistencygroup_id':
'192eb39b-6c2f-420c-bae3-3cfd117f0345',
})
test_snapshot.__dict__.update(test_snapshot)
test_volume2 = {'name': 'vol2',
'size': 1,
'volume_name': 'vol2',
'id': '192eb39b-6c2f-420c-bae3-3cfd117f0004',
'provider_auth': None,
'project_id': 'project',
'display_name': 'vol2',
'display_description': 'test volume 2',
'volume_type_id': None,
'consistencygroup_id':
'192eb39b-6c2f-420c-bae3-3cfd117f0345',
}
test_clone = {'name': 'clone1',
'size': 1,
'volume_name': 'vol3',
'id': '192eb39b-6c2f-420c-bae3-3cfd117f0003',
'provider_auth': None,
'project_id': 'project',
'display_name': 'clone1',
'display_description': 'volume created from snapshot',
'volume_type_id': None,
'consistencygroup_id':
'192eb39b-6c2f-420c-bae3-3cfd117f0345',
}
unmanaged1 = {'id': 'unmanaged1',
'name': 'unmanaged1',
'size': 3,
}
context = {'user': 'admin', }
group = {'id': '192eb39b-6c2f-420c-bae3-3cfd117f0345',
'name': 'cg1',
'status': 'OK',
}
cgsnapshot = mock.Mock(id='192eb39b-6c2f-420c-bae3-3cfd117f9876',
consistencygroup_id=group['id'])
def cgsnap_getitem(self, val):
return self.__dict__[val]
cgsnapshot.__getitem__ = cgsnap_getitem
@mock.patch('cinder.volume.drivers.emc.xtremio.XtremIOClient.req')
class EMCXIODriverISCSITestCase(test.TestCase):
def setUp(self):
super(EMCXIODriverISCSITestCase, self).setUp()
clean_xms_data()
config = mock.Mock()
config.san_login = ''
config.san_password = ''
config.san_ip = ''
config.xtremio_cluster_name = 'brick1'
config.xtremio_provisioning_factor = 20.0
config.max_over_subscription_ratio = 20.0
config.xtremio_volumes_per_glance_cache = 100
def safe_get(key):
return getattr(config, key)
config.safe_get = safe_get
self.driver = xtremio.XtremIOISCSIDriver(configuration=config)
self.driver.client = xtremio.XtremIOClient4(config,
config
.xtremio_cluster_name)
self.data = CommonData()
def test_check_for_setup_error(self, req):
req.side_effect = xms_request
clusters = xms_data['clusters']
del xms_data['clusters']
self.assertRaises(exception.VolumeDriverException,
self.driver.check_for_setup_error)
xms_data['clusters'] = clusters
self.driver.check_for_setup_error()
def test_client4_uses_v2(self, req):
def base_req(*args, **kwargs):
self.assertIn('v2', args)
req.side_effect = base_req
self.driver.client.req('volumes')
def test_create_extend_delete_volume(self, req):
req.side_effect = xms_request
self.driver.create_volume(self.data.test_volume)
self.driver.extend_volume(self.data.test_volume, 5)
self.driver.delete_volume(self.data.test_volume)
def test_create_delete_snapshot(self, req):
req.side_effect = xms_request
self.driver.create_volume(self.data.test_volume)
self.driver.create_snapshot(self.data.test_snapshot)
self.assertEqual(self.data.test_snapshot['id'],
xms_data['volumes'][2]['name'])
self.driver.delete_snapshot(self.data.test_snapshot)
self.driver.delete_volume(self.data.test_volume)
def test_failed_rename_snapshot(self, req):
req.side_effect = xms_failed_rename_snapshot_request
self.assertRaises(exception.VolumeBackendAPIException,
self.driver.create_snapshot,
self.data.test_snapshot)
self.assertEqual(0, len(xms_data['volumes']))
def test_volume_from_snapshot(self, req):
req.side_effect = xms_request
xms_data['volumes'] = {}
self.driver.create_volume(self.data.test_volume)
self.driver.create_snapshot(self.data.test_snapshot)
self.driver.create_volume_from_snapshot(self.data.test_volume2,
self.data.test_snapshot)
self.driver.delete_volume(self.data.test_volume2)
self.driver.delete_volume(self.data.test_snapshot)
self.driver.delete_volume(self.data.test_volume)
def test_clone_volume(self, req):
req.side_effect = xms_request
self.driver.db = mock.Mock()
(self.driver.db.
image_volume_cache_get_by_volume_id.return_value) = mock.MagicMock()
self.driver.create_volume(self.data.test_volume)
vol = xms_data['volumes'][1]
vol['num-of-dest-snaps'] = 200
self.assertRaises(exception.CinderException,
self.driver.create_cloned_volume,
self.data.test_clone,
self.data.test_volume)
vol['num-of-dest-snaps'] = 50
self.driver.create_cloned_volume(self.data.test_clone,
self.data.test_volume)
self.driver.delete_volume(self.data.test_clone)
self.driver.delete_volume(self.data.test_volume)
mock.patch.object(self.driver.client,
'create_snapshot',
mock.Mock(side_effect=
exception.XtremIOSnapshotsLimitExceeded()))
self.assertRaises(exception.CinderException,
self.driver.create_cloned_volume,
self.data.test_clone,
self.data.test_volume)
response = mock.MagicMock()
response.status_code = 400
response.json.return_value = {
"message": "too_many_snapshots_per_vol",
"error_code": 400
}
self.assertRaises(exception.XtremIOSnapshotsLimitExceeded,
self.driver.client.handle_errors,
response, '', '')
response.json.return_value = {
"message": "too_many_objs",
"error_code": 400
}
self.assertRaises(exception.XtremIOSnapshotsLimitExceeded,
self.driver.client.handle_errors,
response, '', '')
def test_duplicate_volume(self, req):
req.side_effect = xms_request
self.driver.create_volume(self.data.test_volume)
self.assertRaises(exception.VolumeBackendAPIException,
self.driver.create_volume, self.data.test_volume)
self.driver.delete_volume(self.data.test_volume)
def test_no_portals_configured(self, req):
req.side_effect = xms_request
portals = xms_data['iscsi-portals'].copy()
xms_data['iscsi-portals'].clear()
lunmap = {'lun': 4}
self.assertRaises(exception.VolumeDriverException,
self.driver._get_iscsi_properties, lunmap)
xms_data['iscsi-portals'] = portals
def test_initialize_terminate_connection(self, req):
req.side_effect = xms_request
self.driver.create_volume(self.data.test_volume)
map_data = self.driver.initialize_connection(self.data.test_volume,
self.data.connector)
self.assertEqual(1, map_data['data']['target_lun'])
i1 = xms_data['initiators'][1]
i1['ig-id'] = ['', i1['ig-id'], 1]
i1['chap-authentication-initiator-password'] = 'chap_password1'
i1['chap-discovery-initiator-password'] = 'chap_password2'
map_data = self.driver.initialize_connection(self.data.test_volume2,
self.data.connector)
self.driver.terminate_connection(self.data.test_volume,
self.data.connector)
def test_initialize_chap_connection(self, req):
req.side_effect = xms_request
clean_xms_data()
self.driver.create_volume(self.data.test_volume)
map_data = self.driver.initialize_connection(self.data.test_volume,
self.data.connector)
self.assertIsNone(map_data['data'].get('access_mode'))
c1 = xms_data['clusters'][1]
c1['chap-authentication-mode'] = 'initiator'
c1['chap-discovery-mode'] = 'initiator'
i1 = xms_data['initiators'][1]
i1['ig-id'] = ['', i1['ig-id'], 1]
i1['chap-authentication-initiator-password'] = 'chap_password1'
i1['chap-discovery-initiator-password'] = 'chap_password2'
map_data = self.driver.initialize_connection(self.data.test_volume2,
self.data.connector)
self.assertEqual('chap_password1', map_data['data']['auth_password'])
self.assertEqual('chap_password2',
map_data['data']['discovery_auth_password'])
i1['chap-authentication-initiator-password'] = None
i1['chap-discovery-initiator-password'] = None
map_data = self.driver.initialize_connection(self.data.test_volume2,
self.data.connector)
data = {}
self.driver._add_auth(data, True, True)
self.assertIn('initiator-discovery-user-name', data,
'Missing discovery user in data')
self.assertIn('initiator-discovery-password', data,
'Missing discovery password in data')
def test_initialize_connection_bad_ig(self, req):
req.side_effect = xms_bad_request
self.assertRaises(exception.VolumeBackendAPIException,
self.driver.initialize_connection,
self.data.test_volume,
self.data.connector)
self.driver.delete_volume(self.data.test_volume)
def test_get_stats(self, req):
req.side_effect = xms_request
stats = self.driver.get_volume_stats(True)
self.assertEqual(self.driver.backend_name,
stats['volume_backend_name'])
def test_manage_unmanage(self, req):
req.side_effect = xms_request
xms_data['volumes'] = {1: {'name': 'unmanaged1',
'index': 1,
'vol-size': '3',
},
}
ref_vol = {"source-name": "unmanaged1"}
invalid_ref = {"source-name": "invalid"}
self.assertRaises(exception.ManageExistingInvalidReference,
self.driver.manage_existing_get_size,
self.data.test_volume, invalid_ref)
self.driver.manage_existing_get_size(self.data.test_volume, ref_vol)
self.assertRaises(exception.ManageExistingInvalidReference,
self.driver.manage_existing,
self.data.test_volume, invalid_ref)
self.driver.manage_existing(self.data.test_volume, ref_vol)
self.assertRaises(exception.VolumeNotFound, self.driver.unmanage,
self.data.test_volume2)
self.driver.unmanage(self.data.test_volume)
@mock.patch('cinder.objects.snapshot.SnapshotList.get_all_for_cgsnapshot')
def test_cg_operations(self, get_all_for_cgsnapshot, req):
req.side_effect = xms_request
d = self.data
snapshot_obj = fake_snapshot.fake_snapshot_obj(d.context)
snapshot_obj.consistencygroup_id = d.group['id']
get_all_for_cgsnapshot.return_value = [snapshot_obj]
self.driver.create_consistencygroup(d.context, d.group)
self.assertEqual(1, len(xms_data['consistency-groups']))
self.driver.update_consistencygroup(d.context, d.group,
add_volumes=[d.test_volume,
d.test_volume2])
self.assertEqual(2, len(xms_data['consistency-group-volumes']))
self.driver.update_consistencygroup(d.context, d.group,
remove_volumes=[d.test_volume2])
self.assertEqual(1, len(xms_data['consistency-group-volumes']))
self.driver.db = mock.Mock()
(self.driver.db.
volume_get_all_by_group.return_value) = [mock.MagicMock()]
self.driver.create_cgsnapshot(d.context, d.cgsnapshot, [])
snapset_name = self.driver._get_cgsnap_name(d.cgsnapshot)
self.assertEqual(snapset_name,
'192eb39b6c2f420cbae33cfd117f0345192eb39b6c2f420cbae'
'33cfd117f9876')
snapset1 = {'ancestor-vol-id': ['', d.test_volume['id'], 2],
'consistencygroup_id': d.group['id'],
'name': snapset_name,
'index': 1}
xms_data['snapshot-sets'] = {snapset_name: snapset1, 1: snapset1}
self.driver.delete_cgsnapshot(d.context, d.cgsnapshot, [])
self.driver.delete_consistencygroup(d.context, d.group, [])
xms_data['snapshot-sets'] = {}
@mock.patch('cinder.objects.snapshot.SnapshotList.get_all_for_cgsnapshot')
def test_cg_from_src(self, get_all_for_cgsnapshot, req):
req.side_effect = xms_request
d = self.data
self.assertRaises(exception.InvalidInput,
self.driver.create_consistencygroup_from_src,
d.context, d.group, [], None, None, None, None)
snapshot_obj = fake_snapshot.fake_snapshot_obj(d.context)
snapshot_obj.consistencygroup_id = d.group['id']
snapshot_obj.volume_id = d.test_volume['id']
get_all_for_cgsnapshot.return_value = [snapshot_obj]
self.driver.create_consistencygroup(d.context, d.group)
self.driver.create_volume(d.test_volume)
self.driver.create_cgsnapshot(d.context, d.cgsnapshot, [])
xms_data['volumes'][2]['ancestor-vol-id'] = (xms_data['volumes'][1]
['vol-id'])
snapset_name = self.driver._get_cgsnap_name(d.cgsnapshot)
snapset1 = {'vol-list': [xms_data['volumes'][2]['vol-id']],
'name': snapset_name,
'index': 1}
xms_data['snapshot-sets'] = {snapset_name: snapset1, 1: snapset1}
cg_obj = fake_cg.fake_consistencyobject_obj(d.context)
new_vol1 = fake_volume.fake_volume_obj(d.context)
snapshot1 = (fake_snapshot
.fake_snapshot_obj
(d.context, volume_id=d.test_volume['id']))
self.driver.create_consistencygroup_from_src(d.context, cg_obj,
[new_vol1],
d.cgsnapshot, [snapshot1])
new_cg_obj = fake_cg.fake_consistencyobject_obj(d.context, id=5)
snapset2_name = new_cg_obj.id
new_vol1.id = '192eb39b-6c2f-420c-bae3-3cfd117f0001'
new_vol2 = fake_volume.fake_volume_obj(d.context)
snapset2 = {'vol-list': [xms_data['volumes'][2]['vol-id']],
'name': snapset2_name,
'index': 1}
xms_data['snapshot-sets'].update({5: snapset2,
snapset2_name: snapset2})
self.driver.create_consistencygroup_from_src(d.context, new_cg_obj,
[new_vol2],
None, None,
cg_obj, [new_vol1])
@mock.patch('requests.request')
class EMCXIODriverTestCase(test.TestCase):
def setUp(self):
super(EMCXIODriverTestCase, self).setUp()
configuration = mock.Mock()
configuration.san_login = ''
configuration.san_password = ''
configuration.san_ip = ''
configuration.xtremio_cluster_name = ''
configuration.driver_ssl_cert_verify = True
configuration.driver_ssl_cert_path = '/test/path/root_ca.crt'
def safe_get(key):
return getattr(configuration, key)
configuration.safe_get = safe_get
self.driver = xtremio.XtremIOISCSIDriver(configuration=configuration)
self.data = CommonData()
@mock.patch.object(time, 'sleep', mock.Mock(return_value=0))
def test_retry_request(self, req):
busy_response = mock.MagicMock()
busy_response.status_code = 400
busy_response.json.return_value = {
"message": "system_is_busy",
"error_code": 400
}
good_response = mock.MagicMock()
good_response.status_code = 200
EMCXIODriverTestCase.req_count = 0
def busy_request(*args, **kwargs):
if EMCXIODriverTestCase.req_count < 1:
EMCXIODriverTestCase.req_count += 1
return busy_response
return good_response
req.side_effect = busy_request
self.driver.create_volume(self.data.test_volume)
def test_verify_cert(self, req):
good_response = mock.MagicMock()
good_response.status_code = 200
def request_verify_cert(*args, **kwargs):
self.assertEqual(kwargs['verify'], '/test/path/root_ca.crt')
return good_response
req.side_effect = request_verify_cert
self.driver.client.req('volumes')
@mock.patch('cinder.volume.drivers.emc.xtremio.XtremIOClient.req')
class EMCXIODriverFibreChannelTestCase(test.TestCase):
def setUp(self):
super(EMCXIODriverFibreChannelTestCase, self).setUp()
clean_xms_data()
self.config = mock.Mock(san_login='',
san_password='',
san_ip='',
xtremio_cluster_name='',
xtremio_provisioning_factor=20.0)
self.driver = xtremio.XtremIOFibreChannelDriver(
configuration=self.config)
self.data = CommonData()
def test_initialize_terminate_connection(self, req):
req.side_effect = xms_request
self.driver.client = xtremio.XtremIOClient4(
self.config, self.config.xtremio_cluster_name)
self.driver.create_volume(self.data.test_volume)
map_data = self.driver.initialize_connection(self.data.test_volume,
self.data.connector)
self.assertEqual(1, map_data['data']['target_lun'])
self.driver.terminate_connection(self.data.test_volume,
self.data.connector)
self.driver.delete_volume(self.data.test_volume)
def test_initialize_existing_ig_terminate_connection(self, req):
req.side_effect = xms_request
self.driver.client = xtremio.XtremIOClient4(
self.config, self.config.xtremio_cluster_name)
self.driver.create_volume(self.data.test_volume)
pre_existing = 'pre_existing_host'
self.driver._create_ig(pre_existing)
wwpns = self.driver._get_initiator_name(self.data.connector)
for wwpn in wwpns:
data = {'initiator-name': wwpn, 'ig-id': pre_existing,
'port-address': wwpn}
self.driver.client.req('initiators', 'POST', data)
def get_fake_initiator(wwpn):
return {'port-address': wwpn, 'ig-id': ['', pre_existing, 1]}
with mock.patch.object(self.driver.client, 'get_initiator',
side_effect=get_fake_initiator):
map_data = self.driver.initialize_connection(self.data.test_volume,
self.data.connector)
self.assertEqual(1, map_data['data']['target_lun'])
self.assertEqual(1, len(xms_data['initiator-groups']))
self.driver.terminate_connection(self.data.test_volume,
self.data.connector)
self.driver.delete_volume(self.data.test_volume)
def test_race_on_terminate_connection(self, req):
"""Test for race conditions on num_of_mapped_volumes.
This test confirms that num_of_mapped_volumes won't break even if we
receive a NotFound exception when retrieving info on a specific
mapping, as that specific mapping could have been deleted between
the request to get the list of exiting mappings and the request to get
the info on one of them.
"""
req.side_effect = xms_request
self.driver.client = xtremio.XtremIOClient3(
self.config, self.config.xtremio_cluster_name)
# We'll wrap num_of_mapped_volumes, we'll store here original method
original_method = self.driver.client.num_of_mapped_volumes
def fake_num_of_mapped_volumes(*args, **kwargs):
# Add a nonexistent mapping
mappings = [{'href': 'volumes/1'}, {'href': 'volumes/12'}]
# Side effects will be: 1st call returns the list, then we return
# data for existing mappings, and on the nonexistent one we added
# we return NotFound
side_effect = [{'lun-maps': mappings},
{'content': xms_data['lun-maps'][1]},
exception.NotFound]
with mock.patch.object(self.driver.client, 'req',
side_effect=side_effect):
return original_method(*args, **kwargs)
self.driver.create_volume(self.data.test_volume)
map_data = self.driver.initialize_connection(self.data.test_volume,
self.data.connector)
self.assertEqual(1, map_data['data']['target_lun'])
with mock.patch.object(self.driver.client, 'num_of_mapped_volumes',
side_effect=fake_num_of_mapped_volumes):
self.driver.terminate_connection(self.data.test_volume,
self.data.connector)
self.driver.delete_volume(self.data.test_volume)