Hitachi VSP: Specify compute nodes and copy ports

Adds a new config option ``vsp_compute_target_ports`` to specify IDs
of the storage ports used to attach volumes to compute nodes.
Also adds a new config option ``vsp_horcm_pair_target_ports`` to
specify IDs of the storage ports used to copy functions by Hitachi
storage.

DocImpact
Change-Id: I5b0a8ff08b1faddf38567d8b038a4847d00f2fa7
This commit is contained in:
Kazumasa Nomura 2017-01-26 06:35:01 -05:00 committed by Adriano Rosso
parent 2ee3aa1d76
commit b9b352fe61
7 changed files with 639 additions and 220 deletions

View File

@ -54,7 +54,7 @@ CONFIG_MAP = {
# CCI instance numbers
INST_NUMS = (200, 201)
# ShadowImage copy group names
# Shadow Image copy group names
CG_MAP = {'cg%s' % x: vsp_horcm._COPY_GROUP % (
CONFIG_MAP['my_ip'], CONFIG_MAP['serial'], INST_NUMS[1], x)
for x in range(3)
@ -694,7 +694,7 @@ def _snapshot_metadata_update(context, snapshot_id, metadata, delete):
def _fake_is_smpl(*args):
"""Assume the ShadowImage pair status is SMPL."""
"""Assume the Shadow Image pair status is SMPL."""
return True
@ -783,6 +783,8 @@ class VSPHORCMFCDriverTest(test.TestCase):
self.configuration.vsp_copy_check_interval = 1
self.configuration.vsp_async_copy_check_interval = 1
self.configuration.vsp_target_ports = "CL1-A"
self.configuration.vsp_compute_target_ports = "CL1-A"
self.configuration.vsp_horcm_pair_target_ports = "CL1-A"
self.configuration.vsp_group_request = True
self.configuration.vsp_zoning_request = False
@ -809,7 +811,7 @@ class VSPHORCMFCDriverTest(test.TestCase):
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def _setup_driver(self, *args):
def _setup_driver(self, execute, brick_get_connector_properties):
"""Set up the driver environment."""
self.driver = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
@ -824,7 +826,7 @@ class VSPHORCMFCDriverTest(test.TestCase):
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(utils, 'execute', side_effect=_cinder_execute)
def test_do_setup(self, *args):
def test_do_setup(self, execute, brick_get_connector_properties):
"""Normal case: The host group exists beforehand."""
drv = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
@ -839,7 +841,8 @@ class VSPHORCMFCDriverTest(test.TestCase):
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_raidqry_h_invalid(self, *args):
def test_do_setup_raidqry_h_invalid(
self, execute, brick_get_connector_properties):
"""Error case: 'raidqry -h' returns nothing. This error is ignored."""
drv = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
@ -857,7 +860,8 @@ class VSPHORCMFCDriverTest(test.TestCase):
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_specify_pool_name(self, *args):
def test_do_setup_specify_pool_name(
self, execute, brick_get_connector_properties):
"""Normal case: Specify pool name rather than pool number."""
drv = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
@ -870,7 +874,8 @@ class VSPHORCMFCDriverTest(test.TestCase):
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_create_hostgrp(self, *args):
def test_do_setup_create_hostgrp(
self, execute, brick_get_connector_properties):
"""Normal case: The host groups does not exist beforehand."""
drv = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
@ -884,7 +889,8 @@ class VSPHORCMFCDriverTest(test.TestCase):
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_create_hostgrp_error(self, *args):
def test_do_setup_create_hostgrp_error(
self, execute, brick_get_connector_properties):
"""Error case: 'add hba_wwn' fails(MSGID0614-E)."""
drv = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
@ -894,7 +900,7 @@ class VSPHORCMFCDriverTest(test.TestCase):
self.assertRaises(exception.VSPError, drv.do_setup, None)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_thin_pool_not_specified(self, *args):
def test_do_setup_thin_pool_not_specified(self, execute):
"""Error case: Parameter error(vsp_thin_pool).(MSGID0601-E)."""
drv = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
@ -907,7 +913,8 @@ class VSPHORCMFCDriverTest(test.TestCase):
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_ldev_range_not_specified(self, *args):
def test_do_setup_ldev_range_not_specified(
self, execute, brick_get_connector_properties):
"""Normal case: Not specify LDEV range."""
drv = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
@ -917,7 +924,7 @@ class VSPHORCMFCDriverTest(test.TestCase):
drv.do_setup(None)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_storage_id_not_specified(self, *args):
def test_do_setup_storage_id_not_specified(self, execute):
"""Error case: Parameter error(vsp_storage_id).(MSGID0601-E)."""
drv = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
@ -927,7 +934,7 @@ class VSPHORCMFCDriverTest(test.TestCase):
self.assertRaises(exception.VSPError, drv.do_setup, None)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_horcm_numbers_invalid(self, *args):
def test_do_setup_horcm_numbers_invalid(self, execute):
"""Error case: Parameter error(vsp_horcm_numbers).(MSGID0601-E)."""
drv = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
@ -937,7 +944,7 @@ class VSPHORCMFCDriverTest(test.TestCase):
self.assertRaises(exception.VSPError, drv.do_setup, None)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_horcm_user_not_specified(self, *args):
def test_do_setup_horcm_user_not_specified(self, execute):
"""Error case: Parameter error(vsp_horcm_user).(MSGID0601-E)."""
drv = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
@ -946,6 +953,70 @@ class VSPHORCMFCDriverTest(test.TestCase):
self.assertRaises(exception.VSPError, drv.do_setup, None)
@mock.patch.object(
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_only_target_ports_not_specified(
self, execute, brick_get_connector_properties):
"""Normal case: Only target_ports is not specified."""
drv = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
self._setup_config()
self.configuration.vsp_target_ports = None
drv.do_setup(None)
@mock.patch.object(
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_only_compute_target_ports_not_specified(
self, execute, brick_get_connector_properties):
"""Normal case: Only compute_target_ports is not specified."""
drv = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
self._setup_config()
self.configuration.vsp_compute_target_ports = None
drv.do_setup(None)
@mock.patch.object(
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_only_pair_target_ports_not_specified(
self, execute, brick_get_connector_properties):
"""Normal case: Only pair_target_ports is not specified."""
drv = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
self._setup_config()
self.configuration.vsp_horcm_pair_target_ports = None
drv.do_setup(None)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_compute_target_ports_not_specified(self, execute):
"""Error case: Parameter error(compute_target_ports).(MSGID0601-E)."""
drv = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
self._setup_config()
self.configuration.vsp_target_ports = None
self.configuration.vsp_compute_target_ports = None
self.assertRaises(exception.VSPError, drv.do_setup, None)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_pair_target_ports_not_specified(self, execute):
"""Error case: Parameter error(pair_target_ports).(MSGID0601-E)."""
drv = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
self._setup_config()
self.configuration.vsp_target_ports = None
self.configuration.vsp_horcm_pair_target_ports = None
self.assertRaises(exception.VSPError, drv.do_setup, None)
@mock.patch.object(vsp_horcm, '_EXEC_MAX_WAITTIME', 5)
@mock.patch.object(
utils, 'brick_get_connector_properties',
@ -954,7 +1025,9 @@ class VSPHORCMFCDriverTest(test.TestCase):
@mock.patch.object(os.path, 'exists', side_effect=_fake_exists)
@mock.patch.object(os, 'access', side_effect=_access)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_failed_to_create_conf(self, *args):
def test_do_setup_failed_to_create_conf(
self, vsp_utils_execute, access, exists, processutils_execute,
brick_get_connector_properties):
"""Error case: Writing into horcmxxx.conf fails.(MSGID0632-E)."""
drv = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
@ -969,7 +1042,8 @@ class VSPHORCMFCDriverTest(test.TestCase):
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_failed_to_login(self, *args):
def test_do_setup_failed_to_login(
self, execute, brick_get_connector_properties):
"""Error case: 'raidcom -login' fails with EX_ENAUTH(MSGID0600-E)."""
drv = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
@ -985,7 +1059,8 @@ class VSPHORCMFCDriverTest(test.TestCase):
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_failed_to_command(self, *args):
def test_do_setup_failed_to_command(
self, execute, brick_get_connector_properties):
"""Error case: 'raidcom -login' fails with EX_COMERR(MSGID0600-E)."""
drv = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
@ -1002,7 +1077,8 @@ class VSPHORCMFCDriverTest(test.TestCase):
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
@mock.patch.object(
vsp_horcm, '_run_horcmgr', side_effect=_fake_run_horcmgr)
def test_do_setup_failed_to_horcmshutdown(self, *args):
def test_do_setup_failed_to_horcmshutdown(
self, _run_horcmgr, execute, brick_get_connector_properties):
"""Error case: CCI's status is always RUNNING(MSGID0608-E)."""
drv = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
@ -1016,7 +1092,8 @@ class VSPHORCMFCDriverTest(test.TestCase):
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
@mock.patch.object(
vsp_horcm, '_run_horcmstart', side_effect=_fake_run_horcmstart)
def test_do_setup_failed_to_horcmstart(self, *args):
def test_do_setup_failed_to_horcmstart(
self, _run_horcmstart, execute, brick_get_connector_properties):
"""Error case: _run_horcmstart() returns an error(MSGID0609-E)."""
drv = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
@ -1031,7 +1108,8 @@ class VSPHORCMFCDriverTest(test.TestCase):
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties_error)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_wwn_not_found(self, *args):
def test_do_setup_wwn_not_found(
self, execute, brick_get_connector_properties):
"""Error case: The connector does not have 'wwpns'(MSGID0650-E)."""
drv = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
@ -1039,11 +1117,8 @@ class VSPHORCMFCDriverTest(test.TestCase):
self.assertRaises(exception.VSPError, drv.do_setup, None)
@mock.patch.object(
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties_error)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_port_not_found(self, *args):
def test_do_setup_port_not_found(self, execute):
"""Error case: The target port does not exist(MSGID0650-E)."""
drv = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
@ -1053,24 +1128,46 @@ class VSPHORCMFCDriverTest(test.TestCase):
self.assertRaises(exception.VSPError, drv.do_setup, None)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_extend_volume(self, *args):
def test_do_setup_compute_target_ports_not_found(self, execute):
"""Error case: Compute target port does not exist(MSGID0650-E)."""
drv = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
self._setup_config()
self.configuration.vsp_target_ports = None
self.configuration.vsp_compute_target_ports = ["CL4-A"]
self.assertRaises(exception.VSPError, drv.do_setup, None)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_pair_target_ports_not_found(self, execute):
"""Error case: Pair target port does not exist(MSGID0650-E)."""
drv = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
self._setup_config()
self.configuration.vsp_target_ports = None
self.configuration.vsp_horcm_pair_target_ports = ["CL5-A"]
self.assertRaises(exception.VSPError, drv.do_setup, None)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_extend_volume(self, execute):
"""Normal case: Extend volume succeeds."""
self.driver.extend_volume(TEST_VOLUME[0], 256)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_extend_volume_volume_provider_location_is_none(self, *args):
def test_extend_volume_volume_provider_location_is_none(self, execute):
"""Error case: The volume's provider_location is None(MSGID0613-E)."""
self.assertRaises(
exception.VSPError, self.driver.extend_volume, TEST_VOLUME[2], 256)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_extend_volume_volume_ldev_is_vvol(self, *args):
def test_extend_volume_volume_ldev_is_vvol(self, execute):
"""Error case: The volume is a V-VOL(MSGID0618-E)."""
self.assertRaises(
exception.VSPError, self.driver.extend_volume, TEST_VOLUME[5], 256)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_extend_volume_volume_is_busy(self, *args):
def test_extend_volume_volume_is_busy(self, execute):
"""Error case: The volume is in a THIN volume pair(MSGID0616-E)."""
self.assertRaises(
exception.VSPError, self.driver.extend_volume, TEST_VOLUME[4], 256)
@ -1078,26 +1175,26 @@ class VSPHORCMFCDriverTest(test.TestCase):
@mock.patch.object(utils, 'execute', side_effect=_cinder_execute)
@mock.patch.object(vsp_horcm, '_EXTEND_WAITTIME', 1)
@mock.patch.object(vsp_horcm, '_EXEC_RETRY_INTERVAL', 1)
def test_extend_volume_raidcom_error(self, *args):
def test_extend_volume_raidcom_error(self, execute,):
"""Error case: 'extend ldev' returns an error(MSGID0600-E)."""
self.assertRaises(
exception.VSPError, self.driver.extend_volume, TEST_VOLUME[3], 256)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_get_volume_stats(self, *args):
def test_get_volume_stats(self, execute):
"""Normal case: Refreshing data required."""
stats = self.driver.get_volume_stats(True)
self.assertEqual('Hitachi', stats['vendor_name'])
self.assertTrue(stats['multiattach'])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_get_volume_stats_no_refresh(self, *args):
def test_get_volume_stats_no_refresh(self, execute):
"""Normal case: Refreshing data not required."""
stats = self.driver.get_volume_stats()
self.assertEqual({}, stats)
@mock.patch.object(vsp_utils, 'execute', side_effect=_error_execute)
def test_get_volume_stats_failed_to_get_dp_pool(self, *args):
def test_get_volume_stats_failed_to_get_dp_pool(self, execute):
"""Error case: The pool does not exist(MSGID0640-E, MSGID0620-E)."""
self.driver.common.storage_info['pool_id'] = 29
@ -1105,13 +1202,13 @@ class VSPHORCMFCDriverTest(test.TestCase):
self.assertEqual({}, stats)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_create_volume(self, *args):
def test_create_volume(self, execute):
"""Normal case: Available LDEV range is 0-1."""
ret = self.driver.create_volume(fake_volume.fake_volume_obj(self.ctxt))
self.assertEqual('1', ret['provider_location'])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_create_volume_free_ldev_not_found_on_storage(self, *args):
def test_create_volume_free_ldev_not_found_on_storage(self, execute):
"""Error case: No unused LDEV exists(MSGID0648-E)."""
self.driver.common.storage_info['ldev_range'] = [0, 0]
@ -1119,7 +1216,7 @@ class VSPHORCMFCDriverTest(test.TestCase):
exception.VSPError, self.driver.create_volume, TEST_VOLUME[0])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_create_volume_no_setting_ldev_range(self, *args):
def test_create_volume_no_setting_ldev_range(self, execute):
"""Normal case: Available LDEV range is unlimited."""
self.driver.common.storage_info['ldev_range'] = None
@ -1130,22 +1227,22 @@ class VSPHORCMFCDriverTest(test.TestCase):
@mock.patch.object(
vsp_horcm.VSPHORCM,
'_check_ldev_status', side_effect=_fake_check_ldev_status)
def test_delete_volume(self, *args):
def test_delete_volume(self, _check_ldev_status, execute):
"""Normal case: Delete a volume."""
self.driver.delete_volume(TEST_VOLUME[0])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_delete_volume_provider_location_is_none(self, *args):
def test_delete_volume_provider_location_is_none(self, execute):
"""Error case: The volume's provider_location is None(MSGID0304-W)."""
self.driver.delete_volume(TEST_VOLUME[2])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_delete_volume_ldev_not_found_on_storage(self, *args):
def test_delete_volume_ldev_not_found_on_storage(self, execute):
"""Unusual case: The volume's LDEV does not exist.(MSGID0319-W)."""
self.driver.delete_volume(TEST_VOLUME[3])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_delete_volume_volume_is_busy(self, *args):
def test_delete_volume_volume_is_busy(self, execute):
"""Error case: The volume is a P-VOL of a THIN pair(MSGID0616-E)."""
self.assertRaises(
exception.VolumeIsBusy, self.driver.delete_volume, TEST_VOLUME[4])
@ -1155,7 +1252,8 @@ class VSPHORCMFCDriverTest(test.TestCase):
@mock.patch.object(
db, 'snapshot_metadata_update', side_effect=_snapshot_metadata_update)
@mock.patch.object(sqlalchemy_api, 'volume_get', side_effect=_volume_get)
def test_create_snapshot_full(self, *args):
def test_create_snapshot_full(
self, volume_get, snapshot_metadata_update, execute):
"""Normal case: copy_method=FULL."""
self.driver.common.storage_info['ldev_range'] = [0, 9]
@ -1167,7 +1265,8 @@ class VSPHORCMFCDriverTest(test.TestCase):
@mock.patch.object(
db, 'snapshot_metadata_update', side_effect=_snapshot_metadata_update)
@mock.patch.object(sqlalchemy_api, 'volume_get', side_effect=_volume_get)
def test_create_snapshot_thin(self, *args):
def test_create_snapshot_thin(
self, volume_get, snapshot_metadata_update, execute):
"""Normal case: copy_method=THIN."""
self.driver.common.storage_info['ldev_range'] = [0, 9]
self.configuration.vsp_thin_pool = 31
@ -1178,49 +1277,51 @@ class VSPHORCMFCDriverTest(test.TestCase):
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
@mock.patch.object(sqlalchemy_api, 'volume_get', side_effect=_volume_get)
def test_create_snapshot_provider_location_is_none(self, *args):
def test_create_snapshot_provider_location_is_none(
self, volume_get, execute):
"""Error case: Source vol's provider_location is None(MSGID0624-E)."""
self.assertRaises(
exception.VSPError, self.driver.create_snapshot, TEST_SNAPSHOT[2])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
@mock.patch.object(sqlalchemy_api, 'volume_get', side_effect=_volume_get)
def test_create_snapshot_ldev_not_found_on_storage(self, *args):
def test_create_snapshot_ldev_not_found_on_storage(
self, volume_get, execute):
"""Error case: The src-vol's LDEV does not exist.(MSGID0612-E)."""
self.assertRaises(
exception.VSPError, self.driver.create_snapshot, TEST_SNAPSHOT[3])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_delete_snapshot_full(self, *args):
def test_delete_snapshot_full(self, execute):
"""Normal case: Delete a snapshot."""
self.driver.delete_snapshot(TEST_SNAPSHOT[5])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
@mock.patch.object(
vsp_horcm.VSPHORCM, '_is_smpl', side_effect=_fake_is_smpl)
def test_delete_snapshot_full_smpl(self, *args):
def test_delete_snapshot_full_smpl(self, _is_smpl, execute):
"""Normal case: The LDEV in an SI volume pair becomes SMPL."""
self.driver.delete_snapshot(TEST_SNAPSHOT[7])
@mock.patch.object(vsp_utils, 'DEFAULT_PROCESS_WAITTIME', 1)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_delete_snapshot_vvol_timeout(self, *args):
def test_delete_snapshot_vvol_timeout(self, execute):
"""Error case: V-VOL is not deleted from a snapshot(MSGID0611-E)."""
self.assertRaises(
exception.VSPError, self.driver.delete_snapshot, TEST_SNAPSHOT[6])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_delete_snapshot_provider_location_is_none(self, *args):
def test_delete_snapshot_provider_location_is_none(self, execute):
"""Error case: Snapshot's provider_location is None(MSGID0304-W)."""
self.driver.delete_snapshot(TEST_SNAPSHOT[2])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_delete_snapshot_ldev_not_found_on_storage(self, *args):
def test_delete_snapshot_ldev_not_found_on_storage(self, execute):
"""Unusual case: The snapshot's LDEV does not exist.(MSGID0319-W)."""
self.driver.delete_snapshot(TEST_SNAPSHOT[3])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_delete_snapshot_snapshot_is_busy(self, *args):
def test_delete_snapshot_snapshot_is_busy(self, execute):
"""Error case: The snapshot is a P-VOL of a THIN pair(MSGID0616-E)."""
self.assertRaises(
exception.SnapshotIsBusy, self.driver.delete_snapshot,
@ -1240,7 +1341,9 @@ class VSPHORCMFCDriverTest(test.TestCase):
@mock.patch.object(
brick_connector.FibreChannelConnector,
'disconnect_volume', _disconnect_volume)
def test_create_cloned_volume_with_dd_same_size(self, *args):
def test_create_cloned_volume_with_dd_same_size(
self, execute, brick_get_connector, brick_get_connector_properties,
copy_volume):
"""Normal case: The source volume is a V-VOL and copied by dd."""
vol = self.driver.create_cloned_volume(TEST_VOLUME[0], TEST_VOLUME[5])
self.assertEqual('1', vol['provider_location'])
@ -1259,27 +1362,29 @@ class VSPHORCMFCDriverTest(test.TestCase):
@mock.patch.object(
brick_connector.FibreChannelConnector,
'disconnect_volume', _disconnect_volume)
def test_create_cloned_volume_with_dd_extend_size(self, *args):
def test_create_cloned_volume_with_dd_extend_size(
self, execute, brick_get_connector, brick_get_connector_properties,
copy_volume):
"""Normal case: Copy with dd and extend the size afterward."""
vol = self.driver.create_cloned_volume(TEST_VOLUME[1], TEST_VOLUME[5])
self.assertEqual('1', vol['provider_location'])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_create_cloned_volume_provider_location_is_none(self, *args):
def test_create_cloned_volume_provider_location_is_none(self, execute):
"""Error case: Source vol's provider_location is None(MSGID0624-E)."""
self.assertRaises(
exception.VSPError, self.driver.create_cloned_volume,
TEST_VOLUME[0], TEST_VOLUME[2])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_create_cloned_volume_invalid_size(self, *args):
def test_create_cloned_volume_invalid_size(self, execute):
"""Error case: src-size > clone-size(MSGID0617-E)."""
self.assertRaises(
exception.VSPError, self.driver.create_cloned_volume,
TEST_VOLUME[0], TEST_VOLUME[1])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_create_cloned_volume_extend_size_thin(self, *args):
def test_create_cloned_volume_extend_size_thin(self, execute):
"""Error case: clone > src and copy_method=THIN(MSGID0621-E)."""
self.configuration.vsp_thin_pool = 31
test_vol_obj = copy.copy(TEST_VOLUME[1])
@ -1289,15 +1394,15 @@ class VSPHORCMFCDriverTest(test.TestCase):
test_vol_obj, TEST_VOLUME[0])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_create_volume_from_snapshot_same_size(self, *args):
"""Normal case: Copy with ShadowImage."""
def test_create_volume_from_snapshot_same_size(self, execute):
"""Normal case: Copy with Shadow Image."""
vol = self.driver.create_volume_from_snapshot(
TEST_VOLUME[0], TEST_SNAPSHOT[0])
self.assertEqual('1', vol['provider_location'])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute2)
def test_create_volume_from_snapshot_full_extend_normal(self, *args):
"""Normal case: Copy with ShadowImage and extend the size afterward."""
def test_create_volume_from_snapshot_full_extend_normal(self, execute):
"""Normal case: Copy with Shadow Image and extend the size."""
test_vol_obj = copy.copy(TEST_VOLUME[1])
test_vol_obj.metadata.update({'copy_method': 'FULL'})
vol = self.driver.create_volume_from_snapshot(
@ -1305,7 +1410,7 @@ class VSPHORCMFCDriverTest(test.TestCase):
self.assertEqual('1', vol['provider_location'])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute3)
def test_create_volume_from_snapshot_full_extend_PSUE(self, *args):
def test_create_volume_from_snapshot_full_extend_PSUE(self, execute):
"""Error case: SI copy -> pair status: PSUS -> PSUE(MSGID0722-E)."""
test_vol_obj = copy.copy(TEST_VOLUME[1])
test_vol_obj.metadata.update({'copy_method': 'FULL'})
@ -1315,7 +1420,7 @@ class VSPHORCMFCDriverTest(test.TestCase):
@mock.patch.object(vsp_utils, 'DEFAULT_PROCESS_WAITTIME', 1)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute4)
def test_create_volume_from_snapshot_full_PSUE(self, *args):
def test_create_volume_from_snapshot_full_PSUE(self, execute):
"""Error case: SI copy -> pair status becomes PSUE(MSGID0610-E)."""
test_vol_obj = copy.copy(TEST_VOLUME[0])
test_vol_obj.metadata.update({'copy_method': 'FULL'})
@ -1328,7 +1433,8 @@ class VSPHORCMFCDriverTest(test.TestCase):
@mock.patch.object(vsp_horcm, '_LDEV_STATUS_WAITTIME', 1)
@mock.patch.object(vsp_utils, 'DEFAULT_PROCESS_WAITTIME', 1)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute5)
def test_create_volume_from_snapshot_full_SMPL(self, *args):
def test_create_volume_from_snapshot_full_SMPL(
self, execute, _run_horcmstart):
"""Error case: SI copy -> pair status becomes SMPL(MSGID0610-E)."""
test_vol_obj = copy.copy(TEST_VOLUME[0])
test_vol_obj.metadata.update({'copy_method': 'FULL'})
@ -1337,14 +1443,14 @@ class VSPHORCMFCDriverTest(test.TestCase):
test_vol_obj, TEST_SNAPSHOT[0])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_create_volume_from_snapshot_invalid_size(self, *args):
def test_create_volume_from_snapshot_invalid_size(self, execute):
"""Error case: volume-size < snapshot-size(MSGID0617-E)."""
self.assertRaises(
exception.VSPError, self.driver.create_volume_from_snapshot,
TEST_VOLUME[0], TEST_SNAPSHOT[1])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_create_volume_from_snapshot_thin_extend(self, *args):
def test_create_volume_from_snapshot_thin_extend(self, execute):
"""Error case: volume > snapshot and copy_method=THIN(MSGID0621-E)."""
self.configuration.vsp_thin_pool = 31
test_vol_obj = copy.copy(TEST_VOLUME[1])
@ -1355,7 +1461,7 @@ class VSPHORCMFCDriverTest(test.TestCase):
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_create_volume_from_snapshot_provider_location_is_none(
self, *args):
self, execute):
"""Error case: Snapshot's provider_location is None(MSGID0624-E)."""
self.assertRaises(
exception.VSPError, self.driver.create_volume_from_snapshot,
@ -1365,7 +1471,7 @@ class VSPHORCMFCDriverTest(test.TestCase):
@mock.patch.object(
db, 'volume_admin_metadata_get',
side_effect=_volume_admin_metadata_get)
def test_initialize_connection(self, *args):
def test_initialize_connection(self, volume_admin_metadata_get, execute):
"""Normal case: Initialize connection."""
self.configuration.vsp_zoning_request = True
self.driver.common._lookup_service = FakeLookupService()
@ -1383,7 +1489,9 @@ class VSPHORCMFCDriverTest(test.TestCase):
@mock.patch.object(
db, 'volume_admin_metadata_get',
side_effect=_volume_admin_metadata_get)
def test_initialize_connection_multipath(self, *args):
def test_initialize_connection_multipath(
self, volume_admin_metadata_get, execute,
brick_get_connector_properties):
"""Normal case: Initialize connection in multipath environment."""
drv = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
@ -1399,7 +1507,7 @@ class VSPHORCMFCDriverTest(test.TestCase):
self.assertEqual(0, ret['data']['target_lun'])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_initialize_connection_provider_location_is_none(self, *args):
def test_initialize_connection_provider_location_is_none(self, execute):
"""Error case: The volume's provider_location is None(MSGID0619-E)."""
self.assertRaises(
exception.VSPError, self.driver.initialize_connection,
@ -1409,7 +1517,8 @@ class VSPHORCMFCDriverTest(test.TestCase):
@mock.patch.object(
db, 'volume_admin_metadata_get',
side_effect=_volume_admin_metadata_get)
def test_initialize_connection_already_attached(self, *args):
def test_initialize_connection_already_attached(
self, volume_admin_metadata_get, execute):
"""Unusual case: 'add lun' returns 'already defined' error."""
ret = self.driver.initialize_connection(
TEST_VOLUME[6], DEFAULT_CONNECTOR)
@ -1417,23 +1526,69 @@ class VSPHORCMFCDriverTest(test.TestCase):
self.assertEqual(['0123456789abcdef'], ret['data']['target_wwn'])
self.assertEqual(255, ret['data']['target_lun'])
@mock.patch.object(
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_terminate_connection(self, *args):
@mock.patch.object(
db, 'volume_admin_metadata_get',
side_effect=_volume_admin_metadata_get)
def test_initialize_connection_target_port_not_specified(
self, volume_admin_metadata_get, execute,
brick_get_connector_properties):
"""Normal case: target_port is not specified."""
compute_connector = DEFAULT_CONNECTOR.copy()
compute_connector['ip'] = '127.0.0.2'
drv = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
self._setup_config()
self.configuration.vsp_target_ports = None
drv.do_setup(None)
ret = drv.initialize_connection(TEST_VOLUME[0], compute_connector)
self.assertEqual('fibre_channel', ret['driver_volume_type'])
self.assertEqual(['0123456789abcdef'], ret['data']['target_wwn'])
self.assertEqual(0, ret['data']['target_lun'])
@mock.patch.object(
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
@mock.patch.object(
db, 'volume_admin_metadata_get',
side_effect=_volume_admin_metadata_get)
def test_initialize_connection_compute_port_not_specified(
self, volume_admin_metadata_get, execute,
brick_get_connector_properties):
"""Normal case: compute_target_port is not specified."""
compute_connector = DEFAULT_CONNECTOR.copy()
compute_connector['ip'] = '127.0.0.2'
drv = vsp_fc.VSPFCDriver(
configuration=self.configuration, db=db)
self._setup_config()
self.configuration.vsp_compute_target_ports = None
drv.do_setup(None)
ret = drv.initialize_connection(TEST_VOLUME[0], compute_connector)
self.assertEqual('fibre_channel', ret['driver_volume_type'])
self.assertEqual(['0123456789abcdef'], ret['data']['target_wwn'])
self.assertEqual(0, ret['data']['target_lun'])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_terminate_connection(self, execute):
"""Normal case: Terminate connection."""
self.driver.terminate_connection(TEST_VOLUME[6], DEFAULT_CONNECTOR)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_terminate_connection_provider_location_is_none(self, *args):
def test_terminate_connection_provider_location_is_none(self, execute):
"""Unusual case: Volume's provider_location is None(MSGID0302-W)."""
self.driver.terminate_connection(TEST_VOLUME[2], DEFAULT_CONNECTOR)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_terminate_connection_no_port_mapped_to_ldev(self, *args):
def test_terminate_connection_no_port_mapped_to_ldev(self, execute):
"""Unusual case: No port is mapped to the LDEV."""
self.driver.terminate_connection(TEST_VOLUME[3], DEFAULT_CONNECTOR)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_terminate_connection_initiator_iqn_not_found(self, *args):
def test_terminate_connection_initiator_iqn_not_found(self, execute):
"""Error case: The connector does not have 'wwpns'(MSGID0650-E)."""
connector = dict(DEFAULT_CONNECTOR)
del connector['wwpns']
@ -1443,7 +1598,7 @@ class VSPHORCMFCDriverTest(test.TestCase):
TEST_VOLUME[0], connector)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_copy_volume_to_image(self, *args):
def test_copy_volume_to_image(self, execute):
"""Normal case: Copy a volume to an image."""
image_service = 'fake_image_service'
image_meta = 'fake_image_meta'
@ -1457,20 +1612,20 @@ class VSPHORCMFCDriverTest(test.TestCase):
self.ctxt, TEST_VOLUME[0], image_service, image_meta)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_manage_existing(self, *args):
def test_manage_existing(self, execute):
"""Normal case: Bring an existing volume under Cinder's control."""
ret = self.driver.manage_existing(
TEST_VOLUME[0], self.test_existing_ref)
self.assertEqual('0', ret['provider_location'])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_manage_existing_get_size_normal(self, *args):
def test_manage_existing_get_size_normal(self, execute):
"""Normal case: Return an existing LDEV's size."""
self.driver.manage_existing_get_size(
TEST_VOLUME[0], self.test_existing_ref)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_manage_existing_get_size_none_ldev_ref(self, *args):
def test_manage_existing_get_size_none_ldev_ref(self, execute):
"""Error case: Source LDEV's properties do not exist(MSGID0707-E)."""
self.assertRaises(
exception.ManageExistingInvalidReference,
@ -1478,7 +1633,7 @@ class VSPHORCMFCDriverTest(test.TestCase):
self.test_existing_none_ldev_ref)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_manage_existing_get_size_invalid_ldev_ref(self, *args):
def test_manage_existing_get_size_invalid_ldev_ref(self, execute):
"""Error case: Source LDEV's ID is an invalid decimal(MSGID0707-E)."""
self.assertRaises(
exception.ManageExistingInvalidReference,
@ -1486,7 +1641,7 @@ class VSPHORCMFCDriverTest(test.TestCase):
self.test_existing_invalid_ldev_ref)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_manage_existing_get_size_value_error_ref(self, *args):
def test_manage_existing_get_size_value_error_ref(self, execute):
"""Error case: Source LDEV's ID is an invalid hex(MSGID0707-E)."""
self.assertRaises(
exception.ManageExistingInvalidReference,
@ -1494,7 +1649,7 @@ class VSPHORCMFCDriverTest(test.TestCase):
self.test_existing_value_error_ref)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_manage_existing_get_size_no_ldev_ref(self, *args):
def test_manage_existing_get_size_no_ldev_ref(self, execute):
"""Error case: Source LDEV's ID is not specified(MSGID0707-E)."""
self.assertRaises(
exception.ManageExistingInvalidReference,
@ -1502,7 +1657,7 @@ class VSPHORCMFCDriverTest(test.TestCase):
self.test_existing_no_ldev_ref)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_manage_existing_get_size_invalid_sts_ldev(self, *args):
def test_manage_existing_get_size_invalid_sts_ldev(self, execute):
"""Error case: Source LDEV's STS is invalid(MSGID0707-E)."""
self.assertRaises(
exception.ManageExistingInvalidReference,
@ -1510,7 +1665,7 @@ class VSPHORCMFCDriverTest(test.TestCase):
self.test_existing_invalid_sts_ldev)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_manage_existing_get_size_invalid_vol_attr(self, *args):
def test_manage_existing_get_size_invalid_vol_attr(self, execute):
"""Error case: Source LDEV's VOL_ATTR is invalid(MSGID0702-E)."""
self.assertRaises(
exception.ManageExistingInvalidReference,
@ -1518,7 +1673,7 @@ class VSPHORCMFCDriverTest(test.TestCase):
self.test_existing_invalid_vol_attr)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_manage_existing_get_size_invalid_size_ref(self, *args):
def test_manage_existing_get_size_invalid_size_ref(self, execute):
"""Error case: Source LDEV's VOL_Capacity is invalid(MSGID0703-E)."""
self.assertRaises(
exception.ManageExistingInvalidReference,
@ -1526,7 +1681,7 @@ class VSPHORCMFCDriverTest(test.TestCase):
self.test_existing_invalid_size)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_manage_existing_get_size_invalid_port_cnt(self, *args):
def test_manage_existing_get_size_invalid_port_cnt(self, execute):
"""Error case: Source LDEV's NUM_PORT is invalid(MSGID0704-E)."""
self.assertRaises(
exception.ManageExistingInvalidReference,
@ -1536,7 +1691,8 @@ class VSPHORCMFCDriverTest(test.TestCase):
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
@mock.patch.object(
vsp_horcm, '_run_horcmstart', side_effect=_fake_run_horcmstart2)
def test_manage_existing_get_size_failed_to_start_horcmgr(self, *args):
def test_manage_existing_get_size_failed_to_start_horcmgr(
self, _run_horcmstart, execute):
"""Error case: _start_horcmgr() returns an error(MSGID0320-W)."""
global run_horcmstart_returns_error2
run_horcmstart_returns_error2 = True
@ -1547,28 +1703,28 @@ class VSPHORCMFCDriverTest(test.TestCase):
run_horcmstart_returns_error2 = False
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_unmanage(self, *args):
def test_unmanage(self, execute):
"""Normal case: Take out a volume from Cinder's control."""
self.driver.unmanage(TEST_VOLUME[0])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_unmanage_provider_location_is_none(self, *args):
def test_unmanage_provider_location_is_none(self, execute):
"""Error case: The volume's provider_location is None(MSGID0304-W)."""
self.driver.unmanage(TEST_VOLUME[2])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_unmanage_volume_invalid_sts_ldev(self, *args):
def test_unmanage_volume_invalid_sts_ldev(self, execute):
"""Unusual case: The volume's STS is BLK."""
self.driver.unmanage(TEST_VOLUME[13])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_unmanage_volume_is_busy(self, *args):
def test_unmanage_volume_is_busy(self, execute):
"""Error case: The volume is in a THIN volume pair(MSGID0616-E)."""
self.assertRaises(
exception.VolumeIsBusy, self.driver.unmanage, TEST_VOLUME[4])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_copy_image_to_volume(self, *args):
def test_copy_image_to_volume(self, execute):
"""Normal case: Copy an image to a volume."""
image_service = 'fake_image_service'
image_id = 'fake_image_id'
@ -1583,7 +1739,7 @@ class VSPHORCMFCDriverTest(test.TestCase):
self.ctxt, TEST_VOLUME[0], image_service, image_id)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_restore_backup(self, *args):
def test_restore_backup(self, execute):
"""Normal case: Restore a backup volume."""
backup = 'fake_backup'
backup_service = 'fake_backup_service'
@ -1597,7 +1753,7 @@ class VSPHORCMFCDriverTest(test.TestCase):
self.ctxt, backup, TEST_VOLUME[0], backup_service)
@mock.patch.object(utils, 'execute', side_effect=_cinder_execute)
def test_update_migrated_volume_success(self, *args):
def test_update_migrated_volume_success(self, execute):
"""Normal case: 'modify ldev -status discard_zero_page' succeeds."""
self.assertRaises(
NotImplementedError,
@ -1610,7 +1766,7 @@ class VSPHORCMFCDriverTest(test.TestCase):
@mock.patch.object(vsp_horcm, '_EXEC_RETRY_INTERVAL', 1)
@mock.patch.object(vsp_horcm, '_EXEC_MAX_WAITTIME', 1)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_update_migrated_volume_error(self, *args):
def test_update_migrated_volume_error(self, execute):
"""Error case: 'modify ldev' fails(MSGID0315-W)."""
self.assertRaises(
NotImplementedError,
@ -1620,11 +1776,11 @@ class VSPHORCMFCDriverTest(test.TestCase):
TEST_VOLUME[3],
"available")
def test_get_ldev_volume_is_none(self, *args):
def test_get_ldev_volume_is_none(self):
"""Error case: The volume is None."""
self.assertIsNone(vsp_utils.get_ldev(None))
def test_check_ignore_error_string(self, *args):
def test_check_ignore_error_string(self):
"""Normal case: ignore_error is a string."""
ignore_error = 'SSB=0xB980,0xB902'
stderr = ('raidcom: [EX_CMDRJE] An order to the control/command device'
@ -1633,20 +1789,20 @@ class VSPHORCMFCDriverTest(test.TestCase):
'The specified port can not be operated.')
self.assertTrue(vsp_utils.check_ignore_error(ignore_error, stderr))
def test_check_opts_parameter_specified(self, *args):
def test_check_opts_parameter_specified(self):
"""Normal case: A valid parameter is specified."""
cfg.CONF.paramAAA = 'aaa'
vsp_utils.check_opts(conf.Configuration(None),
[cfg.StrOpt('paramAAA')])
def test_check_opt_value_parameter_not_set(self, *args):
def test_check_opt_value_parameter_not_set(self):
"""Error case: A parameter is not set(MSGID0601-E)."""
self.assertRaises(cfg.NoSuchOptError,
vsp_utils.check_opt_value,
conf.Configuration(None),
['paramCCC'])
def test_build_initiator_target_map_no_lookup_service(self, *args):
def test_build_initiator_target_map_no_lookup_service(self):
"""Normal case: None is specified for lookup_service."""
connector = {'wwpns': ['0000000000000000', '1111111111111111']}
target_wwns = ['2222222222222222', '3333333333333333']
@ -1658,7 +1814,7 @@ class VSPHORCMFCDriverTest(test.TestCase):
'1111111111111111': ['2222222222222222', '3333333333333333']},
init_target_map)
def test_update_conn_info_not_update_conn_info(self, *args):
def test_update_conn_info_not_update_conn_info(self):
"""Normal case: Not update connection info."""
vsp_utils.update_conn_info(dict({'data': dict({'target_wwn': []})}),
dict({'wwpns': []}),

View File

@ -54,7 +54,7 @@ CONFIG_MAP = {
# CCI instance numbers
INST_NUMS = (200, 201)
# ShadowImage copy group names
# Shadow Image copy group names
CG_MAP = {'cg%s' % x: vsp_horcm._COPY_GROUP % (
CONFIG_MAP['my_ip'], CONFIG_MAP['serial'], INST_NUMS[1], x)
for x in range(3)
@ -500,6 +500,8 @@ EXECUTE_TABLE = {
"raidcom: [EX_CMDIOE] Control command I/O error"),
('get', 'hba_iscsi', '-port', 'CL1-A', 'HBSD-127.0.0.1'): (
SUCCEED, GET_HBA_ISCSI_CL1A_HOSTGRP_RESULT, STDERR),
('get', 'hba_iscsi', '-port', 'CL1-A', 'HBSD-127.0.0.2'): (
SUCCEED, GET_HBA_ISCSI_CL1A_HOSTGRP_RESULT, STDERR),
('get', 'copy_grp'): (SUCCEED, GET_COPY_GRP_RESULT, STDERR),
('get', 'device_grp', '-device_grp_name', CG_MAP['cg1'] + 'P'): (
SUCCEED, GET_DEVICE_GRP_MU1P_RESULT, STDERR),
@ -769,7 +771,7 @@ def _snapshot_metadata_update(context, snapshot_id, metadata, delete):
def _fake_is_smpl(*args):
"""Assume the ShadowImage pair status is SMPL."""
"""Assume the Shadow Image pair status is SMPL."""
return True
@ -850,6 +852,8 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
self.configuration.vsp_copy_check_interval = 1
self.configuration.vsp_async_copy_check_interval = 1
self.configuration.vsp_target_ports = "CL1-A"
self.configuration.vsp_compute_target_ports = "CL1-A"
self.configuration.vsp_horcm_pair_target_ports = "CL1-A"
self.configuration.vsp_group_request = True
self.configuration.vsp_use_chap_auth = True
@ -878,7 +882,7 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def _setup_driver(self, *args):
def _setup_driver(self, execute, brick_get_connector_properties):
"""Set up the driver environment."""
self.driver = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
@ -893,7 +897,7 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(utils, 'execute', side_effect=_cinder_execute)
def test_do_setup(self, *args):
def test_do_setup(self, execute, brick_get_connector_properties):
"""Normal case: The host group exists beforehand."""
drv = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
@ -908,7 +912,8 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_raidqry_h_invalid(self, *args):
def test_do_setup_raidqry_h_invalid(
self, execute, brick_get_connector_properties):
"""Error case: 'raidqry -h' returns nothing. This error is ignored."""
drv = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
@ -926,7 +931,8 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_specify_pool_name(self, *args):
def test_do_setup_specify_pool_name(
self, execute, brick_get_connector_properties):
"""Normal case: Specify pool name rather than pool number."""
drv = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
@ -939,7 +945,8 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_create_hostgrp(self, *args):
def test_do_setup_create_hostgrp(
self, execute, brick_get_connector_properties):
"""Normal case: The host groups does not exist beforehand."""
drv = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
@ -953,7 +960,8 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_create_hostgrp_error(self, *args):
def test_do_setup_create_hostgrp_error(
self, execute, brick_get_connector_properties):
"""Error case: 'add hba_iscsi' fails(MSGID0309-E)."""
drv = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
@ -963,7 +971,7 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
self.assertRaises(exception.VSPError, drv.do_setup, None)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_thin_pool_not_specified(self, *args):
def test_do_setup_thin_pool_not_specified(self, execute):
"""Error case: Parameter error(vsp_thin_pool).(MSGID0601-E)."""
drv = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
@ -976,7 +984,8 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_ldev_range_not_specified(self, *args):
def test_do_setup_ldev_range_not_specified(
self, execute, brick_get_connector_properties):
"""Normal case: Not specify LDEV range."""
drv = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
@ -986,7 +995,7 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
drv.do_setup(None)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_storage_id_not_specified(self, *args):
def test_do_setup_storage_id_not_specified(self, execute):
"""Error case: Parameter error(vsp_storage_id).(MSGID0601-E)."""
drv = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
@ -996,7 +1005,7 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
self.assertRaises(exception.VSPError, drv.do_setup, None)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_horcm_numbers_invalid(self, *args):
def test_do_setup_horcm_numbers_invalid(self, execute):
"""Error case: Parameter error(vsp_horcm_numbers).(MSGID0601-E)."""
drv = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
@ -1006,7 +1015,7 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
self.assertRaises(exception.VSPError, drv.do_setup, None)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_horcm_user_not_specified(self, *args):
def test_do_setup_horcm_user_not_specified(self, execute):
"""Error case: Parameter error(vsp_horcm_user).(MSGID0601-E)."""
drv = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
@ -1015,6 +1024,70 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
self.assertRaises(exception.VSPError, drv.do_setup, None)
@mock.patch.object(
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_only_target_ports_not_specified(
self, execute, brick_get_connector_properties):
"""Normal case: Only target_ports is not specified."""
drv = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
self._setup_config()
self.configuration.vsp_target_ports = None
drv.do_setup(None)
@mock.patch.object(
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_only_compute_target_ports_not_specified(
self, execute, brick_get_connector_properties):
"""Normal case: Only compute_target_ports is not specified."""
drv = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
self._setup_config()
self.configuration.vsp_compute_target_ports = None
drv.do_setup(None)
@mock.patch.object(
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_only_pair_target_ports_not_specified(
self, execute, brick_get_connector_properties):
"""Normal case: Only pair_target_ports is not specified."""
drv = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
self._setup_config()
self.configuration.vsp_horcm_pair_target_ports = None
drv.do_setup(None)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_compute_target_ports_not_specified(self, execute):
"""Error case: Parameter error(compute_target_ports).(MSGID0601-E)."""
drv = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
self._setup_config()
self.configuration.vsp_target_ports = None
self.configuration.vsp_compute_target_ports = None
self.assertRaises(exception.VSPError, drv.do_setup, None)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_pair_target_ports_not_specified(self, execute):
"""Error case: Parameter error(pair_target_ports).(MSGID0601-E)."""
drv = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
self._setup_config()
self.configuration.vsp_target_ports = None
self.configuration.vsp_horcm_pair_target_ports = None
self.assertRaises(exception.VSPError, drv.do_setup, None)
@mock.patch.object(vsp_horcm, '_EXEC_MAX_WAITTIME', 5)
@mock.patch.object(
utils, 'brick_get_connector_properties',
@ -1023,7 +1096,9 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
@mock.patch.object(os.path, 'exists', side_effect=_fake_exists)
@mock.patch.object(os, 'access', side_effect=_access)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_failed_to_create_conf(self, *args):
def test_do_setup_failed_to_create_conf(
self, vsp_utils_execute, access, exists, processutils_execute,
brick_get_connector_properties):
"""Error case: Writing into horcmxxx.conf fails.(MSGID0632-E)."""
drv = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
@ -1038,7 +1113,8 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_failed_to_login(self, *args):
def test_do_setup_failed_to_login(
self, execute, brick_get_connector_properties):
"""Error case: 'raidcom -login' fails with EX_ENAUTH(MSGID0600-E)."""
drv = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
@ -1054,7 +1130,8 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_failed_to_command(self, *args):
def test_do_setup_failed_to_command(
self, execute, brick_get_connector_properties):
"""Error case: 'raidcom -login' fails with EX_COMERR(MSGID0600-E)."""
drv = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
@ -1071,7 +1148,8 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
@mock.patch.object(
vsp_horcm, '_run_horcmgr', side_effect=_fake_run_horcmgr)
def test_do_setup_failed_to_horcmshutdown(self, *args):
def test_do_setup_failed_to_horcmshutdown(
self, _run_horcmgr, execute, brick_get_connector_properties):
"""Error case: CCI's status is always RUNNING(MSGID0608-E)."""
drv = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
@ -1085,7 +1163,8 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
@mock.patch.object(
vsp_horcm, '_run_horcmstart', side_effect=_fake_run_horcmstart)
def test_do_setup_failed_to_horcmstart(self, *args):
def test_do_setup_failed_to_horcmstart(
self, _run_horcmstart, execute, brick_get_connector_properties):
"""Error case: _run_horcmstart() returns an error(MSGID0609-E)."""
drv = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
@ -1100,7 +1179,8 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties_error)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_initiator_not_found(self, *args):
def test_do_setup_initiator_not_found(
self, execute, brick_get_connector_properties):
"""Error case: The connector does not have 'initiator'(MSGID0650-E)."""
drv = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
@ -1108,11 +1188,8 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
self.assertRaises(exception.VSPError, drv.do_setup, None)
@mock.patch.object(
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties_error)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_port_not_found(self, *args):
def test_do_setup_port_not_found(self, execute):
"""Error case: The target port does not exist(MSGID0650-E)."""
drv = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
@ -1122,24 +1199,46 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
self.assertRaises(exception.VSPError, drv.do_setup, None)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_extend_volume(self, *args):
def test_do_setup_compute_target_ports_not_found(self, execute):
"""Error case: Compute target port does not exist(MSGID0650-E)."""
drv = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
self._setup_config()
self.configuration.vsp_target_ports = None
self.configuration.vsp_compute_target_ports = ["CL4-A"]
self.assertRaises(exception.VSPError, drv.do_setup, None)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_do_setup_pair_target_ports_not_found(self, execute):
"""Error case: Pair target port does not exist(MSGID0650-E)."""
drv = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
self._setup_config()
self.configuration.vsp_target_ports = None
self.configuration.vsp_horcm_pair_target_ports = ["CL5-A"]
self.assertRaises(exception.VSPError, drv.do_setup, None)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_extend_volume(self, execute):
"""Normal case: Extend volume succeeds."""
self.driver.extend_volume(TEST_VOLUME[0], 256)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_extend_volume_volume_provider_location_is_none(self, *args):
def test_extend_volume_volume_provider_location_is_none(self, execute):
"""Error case: The volume's provider_location is None(MSGID0613-E)."""
self.assertRaises(
exception.VSPError, self.driver.extend_volume, TEST_VOLUME[2], 256)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_extend_volume_volume_ldev_is_vvol(self, *args):
def test_extend_volume_volume_ldev_is_vvol(self, execute):
"""Error case: The volume is a V-VOL(MSGID0618-E)."""
self.assertRaises(
exception.VSPError, self.driver.extend_volume, TEST_VOLUME[5], 256)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_extend_volume_volume_is_busy(self, *args):
def test_extend_volume_volume_is_busy(self, execute):
"""Error case: The volume is in a THIN volume pair(MSGID0616-E)."""
self.assertRaises(
exception.VSPError, self.driver.extend_volume, TEST_VOLUME[4], 256)
@ -1147,26 +1246,26 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
@mock.patch.object(utils, 'execute', side_effect=_cinder_execute)
@mock.patch.object(vsp_horcm, '_EXTEND_WAITTIME', 1)
@mock.patch.object(vsp_horcm, '_EXEC_RETRY_INTERVAL', 1)
def test_extend_volume_raidcom_error(self, *args):
def test_extend_volume_raidcom_error(self, execute,):
"""Error case: 'extend ldev' returns an error(MSGID0600-E)."""
self.assertRaises(
exception.VSPError, self.driver.extend_volume, TEST_VOLUME[3], 256)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_get_volume_stats(self, *args):
def test_get_volume_stats(self, execute):
"""Normal case: Refreshing data required."""
stats = self.driver.get_volume_stats(True)
self.assertEqual('Hitachi', stats['vendor_name'])
self.assertTrue(stats['multiattach'])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_get_volume_stats_no_refresh(self, *args):
def test_get_volume_stats_no_refresh(self, execute):
"""Normal case: Refreshing data not required."""
stats = self.driver.get_volume_stats()
self.assertEqual({}, stats)
@mock.patch.object(vsp_utils, 'execute', side_effect=_error_execute)
def test_get_volume_stats_failed_to_get_dp_pool(self, *args):
def test_get_volume_stats_failed_to_get_dp_pool(self, execute):
"""Error case: The pool does not exist(MSGID0640-E, MSGID0620-E)."""
self.driver.common.storage_info['pool_id'] = 29
@ -1174,13 +1273,13 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
self.assertEqual({}, stats)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_create_volume(self, *args):
def test_create_volume(self, execute):
"""Normal case: Available LDEV range is 0-1."""
ret = self.driver.create_volume(fake_volume.fake_volume_obj(self.ctxt))
self.assertEqual('1', ret['provider_location'])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_create_volume_free_ldev_not_found_on_storage(self, *args):
def test_create_volume_free_ldev_not_found_on_storage(self, execute):
"""Error case: No unused LDEV exists(MSGID0648-E)."""
self.driver.common.storage_info['ldev_range'] = [0, 0]
@ -1188,7 +1287,7 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
exception.VSPError, self.driver.create_volume, TEST_VOLUME[0])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_create_volume_no_setting_ldev_range(self, *args):
def test_create_volume_no_setting_ldev_range(self, execute):
"""Normal case: Available LDEV range is unlimited."""
self.driver.common.storage_info['ldev_range'] = None
@ -1199,22 +1298,22 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
@mock.patch.object(
vsp_horcm.VSPHORCM,
'_check_ldev_status', side_effect=_fake_check_ldev_status)
def test_delete_volume(self, *args):
def test_delete_volume(self, _check_ldev_status, execute):
"""Normal case: Delete a volume."""
self.driver.delete_volume(TEST_VOLUME[0])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_delete_volume_provider_location_is_none(self, *args):
def test_delete_volume_provider_location_is_none(self, execute):
"""Error case: The volume's provider_location is None(MSGID0304-W)."""
self.driver.delete_volume(TEST_VOLUME[2])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_delete_volume_ldev_not_found_on_storage(self, *args):
def test_delete_volume_ldev_not_found_on_storage(self, execute):
"""Unusual case: The volume's LDEV does not exist.(MSGID0319-W)."""
self.driver.delete_volume(TEST_VOLUME[3])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_delete_volume_volume_is_busy(self, *args):
def test_delete_volume_volume_is_busy(self, execute):
"""Error case: The volume is a P-VOL of a THIN pair(MSGID0616-E)."""
self.assertRaises(
exception.VolumeIsBusy, self.driver.delete_volume, TEST_VOLUME[4])
@ -1224,7 +1323,8 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
@mock.patch.object(
db, 'snapshot_metadata_update', side_effect=_snapshot_metadata_update)
@mock.patch.object(sqlalchemy_api, 'volume_get', side_effect=_volume_get)
def test_create_snapshot_full(self, *args):
def test_create_snapshot_full(
self, volume_get, snapshot_metadata_update, execute):
"""Normal case: copy_method=FULL."""
self.driver.common.storage_info['ldev_range'] = [0, 9]
@ -1236,7 +1336,8 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
@mock.patch.object(
db, 'snapshot_metadata_update', side_effect=_snapshot_metadata_update)
@mock.patch.object(sqlalchemy_api, 'volume_get', side_effect=_volume_get)
def test_create_snapshot_thin(self, *args):
def test_create_snapshot_thin(
self, volume_get, snapshot_metadata_update, execute):
"""Normal case: copy_method=THIN."""
self.driver.common.storage_info['ldev_range'] = [0, 9]
self.configuration.vsp_thin_pool = 31
@ -1247,49 +1348,51 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
@mock.patch.object(sqlalchemy_api, 'volume_get', side_effect=_volume_get)
def test_create_snapshot_provider_location_is_none(self, *args):
def test_create_snapshot_provider_location_is_none(
self, volume_get, execute):
"""Error case: Source vol's provider_location is None(MSGID0624-E)."""
self.assertRaises(
exception.VSPError, self.driver.create_snapshot, TEST_SNAPSHOT[2])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
@mock.patch.object(sqlalchemy_api, 'volume_get', side_effect=_volume_get)
def test_create_snapshot_ldev_not_found_on_storage(self, *args):
def test_create_snapshot_ldev_not_found_on_storage(
self, volume_get, execute):
"""Error case: The src-vol's LDEV does not exist.(MSGID0612-E)."""
self.assertRaises(
exception.VSPError, self.driver.create_snapshot, TEST_SNAPSHOT[3])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_delete_snapshot_full(self, *args):
def test_delete_snapshot_full(self, execute):
"""Normal case: Delete a snapshot."""
self.driver.delete_snapshot(TEST_SNAPSHOT[5])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
@mock.patch.object(
vsp_horcm.VSPHORCM, '_is_smpl', side_effect=_fake_is_smpl)
def test_delete_snapshot_full_smpl(self, *args):
def test_delete_snapshot_full_smpl(self, _is_smpl, execute):
"""Normal case: The LDEV in an SI volume pair becomes SMPL."""
self.driver.delete_snapshot(TEST_SNAPSHOT[7])
@mock.patch.object(vsp_utils, 'DEFAULT_PROCESS_WAITTIME', 1)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_delete_snapshot_vvol_timeout(self, *args):
def test_delete_snapshot_vvol_timeout(self, execute):
"""Error case: V-VOL is not deleted from a snapshot(MSGID0611-E)."""
self.assertRaises(
exception.VSPError, self.driver.delete_snapshot, TEST_SNAPSHOT[6])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_delete_snapshot_provider_location_is_none(self, *args):
def test_delete_snapshot_provider_location_is_none(self, execute):
"""Error case: Snapshot's provider_location is None(MSGID0304-W)."""
self.driver.delete_snapshot(TEST_SNAPSHOT[2])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_delete_snapshot_ldev_not_found_on_storage(self, *args):
def test_delete_snapshot_ldev_not_found_on_storage(self, execute):
"""Unusual case: The snapshot's LDEV does not exist.(MSGID0319-W)."""
self.driver.delete_snapshot(TEST_SNAPSHOT[3])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_delete_snapshot_snapshot_is_busy(self, *args):
def test_delete_snapshot_snapshot_is_busy(self, execute):
"""Error case: The snapshot is a P-VOL of a THIN pair(MSGID0616-E)."""
self.assertRaises(
exception.SnapshotIsBusy, self.driver.delete_snapshot,
@ -1309,7 +1412,9 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
@mock.patch.object(
brick_connector.ISCSIConnector,
'disconnect_volume', _disconnect_volume)
def test_create_cloned_volume_with_dd_same_size(self, *args):
def test_create_cloned_volume_with_dd_same_size(
self, execute, brick_get_connector, brick_get_connector_properties,
copy_volume):
"""Normal case: The source volume is a V-VOL and copied by dd."""
vol = self.driver.create_cloned_volume(TEST_VOLUME[0], TEST_VOLUME[5])
self.assertEqual('1', vol['provider_location'])
@ -1328,27 +1433,29 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
@mock.patch.object(
brick_connector.ISCSIConnector,
'disconnect_volume', _disconnect_volume)
def test_create_cloned_volume_with_dd_extend_size(self, *args):
def test_create_cloned_volume_with_dd_extend_size(
self, execute, brick_get_connector, brick_get_connector_properties,
copy_volume):
"""Normal case: Copy with dd and extend the size afterward."""
vol = self.driver.create_cloned_volume(TEST_VOLUME[1], TEST_VOLUME[5])
self.assertEqual('1', vol['provider_location'])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_create_cloned_volume_provider_location_is_none(self, *args):
def test_create_cloned_volume_provider_location_is_none(self, execute):
"""Error case: Source vol's provider_location is None(MSGID0624-E)."""
self.assertRaises(
exception.VSPError, self.driver.create_cloned_volume,
TEST_VOLUME[0], TEST_VOLUME[2])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_create_cloned_volume_invalid_size(self, *args):
def test_create_cloned_volume_invalid_size(self, execute):
"""Error case: src-size > clone-size(MSGID0617-E)."""
self.assertRaises(
exception.VSPError, self.driver.create_cloned_volume,
TEST_VOLUME[0], TEST_VOLUME[1])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_create_cloned_volume_extend_size_thin(self, *args):
def test_create_cloned_volume_extend_size_thin(self, execute):
"""Error case: clone > src and copy_method=THIN(MSGID0621-E)."""
self.configuration.vsp_thin_pool = 31
test_vol_obj = copy.copy(TEST_VOLUME[1])
@ -1358,15 +1465,15 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
test_vol_obj, TEST_VOLUME[0])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_create_volume_from_snapshot_same_size(self, *args):
"""Normal case: Copy with ShadowImage."""
def test_create_volume_from_snapshot_same_size(self, execute):
"""Normal case: Copy with Shadow Image."""
vol = self.driver.create_volume_from_snapshot(
TEST_VOLUME[0], TEST_SNAPSHOT[0])
self.assertEqual('1', vol['provider_location'])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute2)
def test_create_volume_from_snapshot_full_extend_normal(self, *args):
"""Normal case: Copy with ShadowImage and extend the size afterward."""
def test_create_volume_from_snapshot_full_extend_normal(self, execute):
"""Normal case: Copy with Shadow Image and extend the size."""
test_vol_obj = copy.copy(TEST_VOLUME[1])
test_vol_obj.metadata.update({'copy_method': 'FULL'})
vol = self.driver.create_volume_from_snapshot(
@ -1374,7 +1481,7 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
self.assertEqual('1', vol['provider_location'])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute3)
def test_create_volume_from_snapshot_full_extend_PSUE(self, *args):
def test_create_volume_from_snapshot_full_extend_PSUE(self, execute):
"""Error case: SI copy -> pair status: PSUS -> PSUE(MSGID0722-E)."""
test_vol_obj = copy.copy(TEST_VOLUME[1])
test_vol_obj.metadata.update({'copy_method': 'FULL'})
@ -1384,7 +1491,7 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
@mock.patch.object(vsp_utils, 'DEFAULT_PROCESS_WAITTIME', 1)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute4)
def test_create_volume_from_snapshot_full_PSUE(self, *args):
def test_create_volume_from_snapshot_full_PSUE(self, execute):
"""Error case: SI copy -> pair status becomes PSUE(MSGID0610-E)."""
test_vol_obj = copy.copy(TEST_VOLUME[0])
test_vol_obj.metadata.update({'copy_method': 'FULL'})
@ -1397,7 +1504,8 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
@mock.patch.object(vsp_horcm, '_LDEV_STATUS_WAITTIME', 1)
@mock.patch.object(vsp_utils, 'DEFAULT_PROCESS_WAITTIME', 1)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute5)
def test_create_volume_from_snapshot_full_SMPL(self, *args):
def test_create_volume_from_snapshot_full_SMPL(
self, execute, _run_horcmstart):
"""Error case: SI copy -> pair status becomes SMPL(MSGID0610-E)."""
test_vol_obj = copy.copy(TEST_VOLUME[0])
test_vol_obj.metadata.update({'copy_method': 'FULL'})
@ -1406,14 +1514,14 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
test_vol_obj, TEST_SNAPSHOT[0])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_create_volume_from_snapshot_invalid_size(self, *args):
def test_create_volume_from_snapshot_invalid_size(self, execute):
"""Error case: volume-size < snapshot-size(MSGID0617-E)."""
self.assertRaises(
exception.VSPError, self.driver.create_volume_from_snapshot,
TEST_VOLUME[0], TEST_SNAPSHOT[1])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_create_volume_from_snapshot_thin_extend(self, *args):
def test_create_volume_from_snapshot_thin_extend(self, execute):
"""Error case: volume > snapshot and copy_method=THIN(MSGID0621-E)."""
self.configuration.vsp_thin_pool = 31
test_vol_obj = copy.copy(TEST_VOLUME[1])
@ -1424,7 +1532,7 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_create_volume_from_snapshot_provider_location_is_none(
self, *args):
self, execute):
"""Error case: Snapshot's provider_location is None(MSGID0624-E)."""
self.assertRaises(
exception.VSPError, self.driver.create_volume_from_snapshot,
@ -1434,7 +1542,7 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
@mock.patch.object(
db, 'volume_admin_metadata_get',
side_effect=_volume_admin_metadata_get)
def test_initialize_connection(self, *args):
def test_initialize_connection(self, volume_admin_metadata_get, execute):
"""Normal case: Initialize connection."""
ret = self.driver.initialize_connection(
TEST_VOLUME[0], DEFAULT_CONNECTOR)
@ -1454,7 +1562,9 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
@mock.patch.object(
db, 'volume_admin_metadata_get',
side_effect=_volume_admin_metadata_get)
def test_initialize_connection_multipath(self, *args):
def test_initialize_connection_multipath(
self, volume_admin_metadata_get, execute,
brick_get_connector_properties):
"""Normal case: Initialize connection in multipath environment."""
drv = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
@ -1476,7 +1586,7 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
self.assertEqual([0, 0], ret['data']['target_luns'])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_initialize_connection_provider_location_is_none(self, *args):
def test_initialize_connection_provider_location_is_none(self, execute):
"""Error case: The volume's provider_location is None(MSGID0619-E)."""
self.assertRaises(
exception.VSPError, self.driver.initialize_connection,
@ -1486,7 +1596,8 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
@mock.patch.object(
db, 'volume_admin_metadata_get',
side_effect=_volume_admin_metadata_get)
def test_initialize_connection_already_attached(self, *args):
def test_initialize_connection_already_attached(
self, volume_admin_metadata_get, execute):
"""Unusual case: 'add lun' returns 'already defined' error."""
ret = self.driver.initialize_connection(
TEST_VOLUME[6], DEFAULT_CONNECTOR)
@ -1499,23 +1610,79 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
self.assertEqual('auth_password', ret['data']['auth_password'])
self.assertEqual(255, ret['data']['target_lun'])
@mock.patch.object(
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_terminate_connection(self, *args):
@mock.patch.object(
db, 'volume_admin_metadata_get',
side_effect=_volume_admin_metadata_get)
def test_initialize_connection_target_port_not_specified(
self, volume_admin_metadata_get, execute,
brick_get_connector_properties):
"""Normal case: target_port is not specified."""
compute_connector = DEFAULT_CONNECTOR.copy()
compute_connector['ip'] = '127.0.0.2'
drv = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
self._setup_config()
self.configuration.vsp_target_ports = None
drv.do_setup(None)
ret = drv.initialize_connection(TEST_VOLUME[0], compute_connector)
self.assertEqual('iscsi', ret['driver_volume_type'])
self.assertEqual('11.22.33.44:3260', ret['data']['target_portal'])
self.assertEqual('iqn-initiator.hbsd-target',
ret['data']['target_iqn'])
self.assertEqual('CHAP', ret['data']['auth_method'])
self.assertEqual('auth_user', ret['data']['auth_username'])
self.assertEqual('auth_password', ret['data']['auth_password'])
self.assertEqual(0, ret['data']['target_lun'])
@mock.patch.object(
utils, 'brick_get_connector_properties',
side_effect=_brick_get_connector_properties)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
@mock.patch.object(
db, 'volume_admin_metadata_get',
side_effect=_volume_admin_metadata_get)
def test_initialize_connection_compute_port_not_specified(
self, volume_admin_metadata_get, execute,
brick_get_connector_properties):
"""Normal case: compute_target_port is not specified."""
compute_connector = DEFAULT_CONNECTOR.copy()
compute_connector['ip'] = '127.0.0.2'
drv = vsp_iscsi.VSPISCSIDriver(
configuration=self.configuration, db=db)
self._setup_config()
self.configuration.vsp_compute_target_ports = None
drv.do_setup(None)
ret = drv.initialize_connection(TEST_VOLUME[0], compute_connector)
self.assertEqual('iscsi', ret['driver_volume_type'])
self.assertEqual('11.22.33.44:3260', ret['data']['target_portal'])
self.assertEqual('iqn-initiator.hbsd-target',
ret['data']['target_iqn'])
self.assertEqual('CHAP', ret['data']['auth_method'])
self.assertEqual('auth_user', ret['data']['auth_username'])
self.assertEqual('auth_password', ret['data']['auth_password'])
self.assertEqual(0, ret['data']['target_lun'])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_terminate_connection(self, execute):
"""Normal case: Terminate connection."""
self.driver.terminate_connection(TEST_VOLUME[6], DEFAULT_CONNECTOR)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_terminate_connection_provider_location_is_none(self, *args):
def test_terminate_connection_provider_location_is_none(self, execute):
"""Unusual case: Volume's provider_location is None(MSGID0302-W)."""
self.driver.terminate_connection(TEST_VOLUME[2], DEFAULT_CONNECTOR)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_terminate_connection_no_port_mapped_to_ldev(self, *args):
def test_terminate_connection_no_port_mapped_to_ldev(self, execute):
"""Unusual case: No port is mapped to the LDEV."""
self.driver.terminate_connection(TEST_VOLUME[3], DEFAULT_CONNECTOR)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_terminate_connection_initiator_iqn_not_found(self, *args):
def test_terminate_connection_initiator_iqn_not_found(self, execute):
"""Error case: The connector does not have 'initiator'(MSGID0650-E)."""
connector = dict(DEFAULT_CONNECTOR)
del connector['initiator']
@ -1525,7 +1692,7 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
TEST_VOLUME[0], connector)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_copy_volume_to_image(self, *args):
def test_copy_volume_to_image(self, execute):
"""Normal case: Copy a volume to an image."""
image_service = 'fake_image_service'
image_meta = 'fake_image_meta'
@ -1539,20 +1706,20 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
self.ctxt, TEST_VOLUME[0], image_service, image_meta)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_manage_existing(self, *args):
def test_manage_existing(self, execute):
"""Normal case: Bring an existing volume under Cinder's control."""
ret = self.driver.manage_existing(
TEST_VOLUME[0], self.test_existing_ref)
self.assertEqual('0', ret['provider_location'])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_manage_existing_get_size_normal(self, *args):
def test_manage_existing_get_size_normal(self, execute):
"""Normal case: Return an existing LDEV's size."""
self.driver.manage_existing_get_size(
TEST_VOLUME[0], self.test_existing_ref)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_manage_existing_get_size_none_ldev_ref(self, *args):
def test_manage_existing_get_size_none_ldev_ref(self, execute):
"""Error case: Source LDEV's properties do not exist(MSGID0707-E)."""
self.assertRaises(
exception.ManageExistingInvalidReference,
@ -1560,7 +1727,7 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
self.test_existing_none_ldev_ref)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_manage_existing_get_size_invalid_ldev_ref(self, *args):
def test_manage_existing_get_size_invalid_ldev_ref(self, execute):
"""Error case: Source LDEV's ID is an invalid decimal(MSGID0707-E)."""
self.assertRaises(
exception.ManageExistingInvalidReference,
@ -1568,7 +1735,7 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
self.test_existing_invalid_ldev_ref)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_manage_existing_get_size_value_error_ref(self, *args):
def test_manage_existing_get_size_value_error_ref(self, execute):
"""Error case: Source LDEV's ID is an invalid hex(MSGID0707-E)."""
self.assertRaises(
exception.ManageExistingInvalidReference,
@ -1576,7 +1743,7 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
self.test_existing_value_error_ref)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_manage_existing_get_size_no_ldev_ref(self, *args):
def test_manage_existing_get_size_no_ldev_ref(self, execute):
"""Error case: Source LDEV's ID is not specified(MSGID0707-E)."""
self.assertRaises(
exception.ManageExistingInvalidReference,
@ -1584,7 +1751,7 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
self.test_existing_no_ldev_ref)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_manage_existing_get_size_invalid_sts_ldev(self, *args):
def test_manage_existing_get_size_invalid_sts_ldev(self, execute):
"""Error case: Source LDEV's STS is invalid(MSGID0707-E)."""
self.assertRaises(
exception.ManageExistingInvalidReference,
@ -1592,7 +1759,7 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
self.test_existing_invalid_sts_ldev)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_manage_existing_get_size_invalid_vol_attr(self, *args):
def test_manage_existing_get_size_invalid_vol_attr(self, execute):
"""Error case: Source LDEV's VOL_ATTR is invalid(MSGID0702-E)."""
self.assertRaises(
exception.ManageExistingInvalidReference,
@ -1600,7 +1767,7 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
self.test_existing_invalid_vol_attr)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_manage_existing_get_size_invalid_size_ref(self, *args):
def test_manage_existing_get_size_invalid_size_ref(self, execute):
"""Error case: Source LDEV's VOL_Capacity is invalid(MSGID0703-E)."""
self.assertRaises(
exception.ManageExistingInvalidReference,
@ -1608,7 +1775,7 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
self.test_existing_invalid_size)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_manage_existing_get_size_invalid_port_cnt(self, *args):
def test_manage_existing_get_size_invalid_port_cnt(self, execute):
"""Error case: Source LDEV's NUM_PORT is invalid(MSGID0704-E)."""
self.assertRaises(
exception.ManageExistingInvalidReference,
@ -1618,7 +1785,8 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
@mock.patch.object(
vsp_horcm, '_run_horcmstart', side_effect=_fake_run_horcmstart2)
def test_manage_existing_get_size_failed_to_start_horcmgr(self, *args):
def test_manage_existing_get_size_failed_to_start_horcmgr(
self, _run_horcmstart, execute):
"""Error case: _start_horcmgr() returns an error(MSGID0320-W)."""
global run_horcmstart_returns_error2
run_horcmstart_returns_error2 = True
@ -1629,28 +1797,28 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
run_horcmstart_returns_error2 = False
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_unmanage(self, *args):
def test_unmanage(self, execute):
"""Normal case: Take out a volume from Cinder's control."""
self.driver.unmanage(TEST_VOLUME[0])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_unmanage_provider_location_is_none(self, *args):
def test_unmanage_provider_location_is_none(self, execute):
"""Error case: The volume's provider_location is None(MSGID0304-W)."""
self.driver.unmanage(TEST_VOLUME[2])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_unmanage_volume_invalid_sts_ldev(self, *args):
def test_unmanage_volume_invalid_sts_ldev(self, execute):
"""Unusual case: The volume's STS is BLK."""
self.driver.unmanage(TEST_VOLUME[13])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_unmanage_volume_is_busy(self, *args):
def test_unmanage_volume_is_busy(self, execute):
"""Error case: The volume is in a THIN volume pair(MSGID0616-E)."""
self.assertRaises(
exception.VolumeIsBusy, self.driver.unmanage, TEST_VOLUME[4])
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_copy_image_to_volume(self, *args):
def test_copy_image_to_volume(self, execute):
"""Normal case: Copy an image to a volume."""
image_service = 'fake_image_service'
image_id = 'fake_image_id'
@ -1665,7 +1833,7 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
self.ctxt, TEST_VOLUME[0], image_service, image_id)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_restore_backup(self, *args):
def test_restore_backup(self, execute):
"""Normal case: Restore a backup volume."""
backup = 'fake_backup'
backup_service = 'fake_backup_service'
@ -1679,7 +1847,7 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
self.ctxt, backup, TEST_VOLUME[0], backup_service)
@mock.patch.object(utils, 'execute', side_effect=_cinder_execute)
def test_update_migrated_volume_success(self, *args):
def test_update_migrated_volume_success(self, execute):
"""Normal case: 'modify ldev -status discard_zero_page' succeeds."""
self.assertRaises(
NotImplementedError,
@ -1692,7 +1860,7 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
@mock.patch.object(vsp_horcm, '_EXEC_RETRY_INTERVAL', 1)
@mock.patch.object(vsp_horcm, '_EXEC_MAX_WAITTIME', 1)
@mock.patch.object(vsp_utils, 'execute', side_effect=_execute)
def test_update_migrated_volume_error(self, *args):
def test_update_migrated_volume_error(self, execute):
"""Error case: 'modify ldev' fails(MSGID0315-W)."""
self.assertRaises(
NotImplementedError,
@ -1702,11 +1870,11 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
TEST_VOLUME[3],
"available")
def test_get_ldev_volume_is_none(self, *args):
def test_get_ldev_volume_is_none(self):
"""Error case: The volume is None."""
self.assertIsNone(vsp_utils.get_ldev(None))
def test_check_ignore_error_string(self, *args):
def test_check_ignore_error_string(self):
"""Normal case: ignore_error is a string."""
ignore_error = 'SSB=0xB980,0xB902'
stderr = ('raidcom: [EX_CMDRJE] An order to the control/command device'
@ -1715,20 +1883,20 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
'The specified port can not be operated.')
self.assertTrue(vsp_utils.check_ignore_error(ignore_error, stderr))
def test_check_opts_parameter_specified(self, *args):
def test_check_opts_parameter_specified(self):
"""Normal case: A valid parameter is specified."""
cfg.CONF.paramAAA = 'aaa'
vsp_utils.check_opts(conf.Configuration(None),
[cfg.StrOpt('paramAAA')])
def test_check_opt_value_parameter_not_set(self, *args):
def test_check_opt_value_parameter_not_set(self):
"""Error case: A parameter is not set(MSGID0601-E)."""
self.assertRaises(cfg.NoSuchOptError,
vsp_utils.check_opt_value,
conf.Configuration(None),
['paramCCC'])
def test_build_initiator_target_map_no_lookup_service(self, *args):
def test_build_initiator_target_map_no_lookup_service(self):
"""Normal case: None is specified for lookup_service."""
connector = {'wwpns': ['0000000000000000', '1111111111111111']}
target_wwns = ['2222222222222222', '3333333333333333']
@ -1740,7 +1908,7 @@ class VSPHORCMISCSIDriverTest(test.TestCase):
'1111111111111111': ['2222222222222222', '3333333333333333']},
init_target_map)
def test_update_conn_info_not_update_conn_info(self, *args):
def test_update_conn_info_not_update_conn_info(self):
"""Normal case: Not update connection info."""
vsp_utils.update_conn_info(dict({'data': dict({'target_wwn': []})}),
dict({'wwpns': []}),

View File

@ -64,14 +64,14 @@ common_opts = [
default='FULL',
choices=['FULL', 'THIN'],
help='Method of volume copy. FULL indicates full data copy by '
'ShadowImage and THIN indicates differential data copy by Thin '
'Shadow Image and THIN indicates differential data copy by Thin '
'Image.'),
cfg.IntOpt(
'vsp_copy_speed',
min=1,
max=15,
default=3,
help='Speed at which data is copied by ShadowImage. 1 or 2 indicates '
help='Speed at which data is copied by Shadow Image. 1 or 2 indicates '
'low speed, 3 indicates middle speed, and a value between 4 and '
'15 indicates high speed.'),
cfg.IntOpt(
@ -90,8 +90,14 @@ common_opts = [
'is checked when volume pairs are deleted.'),
cfg.ListOpt(
'vsp_target_ports',
help='IDs of the storage ports. To specify multiple ports, connect '
'them by commas (e.g. CL1-A,CL2-A).'),
help='IDs of the storage ports used to attach volumes to the '
'controller node. To specify multiple ports, connect them by '
'commas (e.g. CL1-A,CL2-A).'),
cfg.ListOpt(
'vsp_compute_target_ports',
help='IDs of the storage ports used to attach volumes to compute '
'nodes. To specify multiple ports, connect them by commas '
'(e.g. CL1-A,CL2-A).'),
cfg.BoolOpt(
'vsp_group_request',
default=False,
@ -102,7 +108,6 @@ common_opts = [
_REQUIRED_COMMON_OPTS = [
'vsp_storage_id',
'vsp_pool',
'vsp_target_ports',
]
CONF = cfg.CONF
@ -141,7 +146,9 @@ class VSPCommon(object):
'protocol': driverinfo['proto'],
'pool_id': None,
'ldev_range': [],
'ports': [],
'controller_ports': [],
'compute_ports': [],
'pair_ports': [],
'wwns': {},
'portals': {},
'output_first': True,
@ -617,6 +624,12 @@ class VSPCommon(object):
if self.conf.vsp_ldev_range:
self.storage_info['ldev_range'] = self._range2list(
'vsp_ldev_range')
if (not self.conf.vsp_target_ports and
not self.conf.vsp_compute_target_ports):
msg = utils.output_log(MSG.INVALID_PARAMETER,
param='vsp_target_ports or '
'vsp_compute_target_ports')
raise exception.VSPError(msg)
for opt in _REQUIRED_COMMON_OPTS:
if not self.conf.safe_get(opt):
msg = utils.output_log(MSG.INVALID_PARAMETER, param=opt)
@ -666,12 +679,20 @@ class VSPCommon(object):
def check_ports_info(self):
"""Check if available storage ports exist."""
if (self.conf.vsp_target_ports and
not self.storage_info['ports']):
not self.storage_info['controller_ports']):
msg = utils.output_log(MSG.RESOURCE_NOT_FOUND,
resource="Target ports")
raise exception.VSPError(msg)
if (self.conf.vsp_compute_target_ports and
not self.storage_info['compute_ports']):
msg = utils.output_log(MSG.RESOURCE_NOT_FOUND,
resource="Compute target ports")
raise exception.VSPError(msg)
utils.output_log(MSG.SET_CONFIG_VALUE, object='target port list',
value=self.storage_info['ports'])
value=self.storage_info['controller_ports'])
utils.output_log(MSG.SET_CONFIG_VALUE,
object='compute target port list',
value=self.storage_info['compute_ports'])
def get_pool_id(self):
"""Return the storage pool ID as integer."""
@ -686,7 +707,7 @@ class VSPCommon(object):
connector = cinder_utils.brick_get_connector_properties(
multipath=self.conf.use_multipath_for_image_xfer,
enforce_multipath=self.conf.enforce_multipath_for_image_xfer)
target_ports = self.storage_info['ports']
target_ports = self.storage_info['controller_ports']
if target_ports:
if (self.find_targets_from_storage(
@ -796,15 +817,16 @@ class VSPCommon(object):
volume_id=volume['id'])
raise exception.VSPError(msg)
target_ports = self.get_target_ports(connector)
if (self.find_targets_from_storage(
targets, connector, self.storage_info['ports']) and
targets, connector, target_ports) and
self.conf.vsp_group_request):
self.create_mapping_targets(targets, connector)
utils.require_target_existed(targets)
targets['list'].sort()
for port in self.storage_info['ports']:
for port in target_ports:
targets['lun'][port] = False
target_lun = int(self.map_ldev(targets, ldev))
@ -813,6 +835,13 @@ class VSPCommon(object):
'data': self.get_properties(targets, connector, target_lun),
}
def get_target_ports(self, connector):
"""Return a list of ports corresponding to the specified connector."""
if 'ip' in connector and connector['ip'] == CONF.my_ip:
return self.storage_info['controller_ports']
return (self.storage_info['compute_ports'] or
self.storage_info['controller_ports'])
@abc.abstractmethod
def map_ldev(self, targets, ldev):
"""Create the path between the server and the LDEV and return LUN."""
@ -885,12 +914,12 @@ class VSPCommon(object):
utils.output_log(MSG.INVALID_LDEV_FOR_UNMAPPING,
volume_id=volume['id'])
return
self.find_targets_from_storage(targets, connector,
self.storage_info['ports'])
target_ports = self.get_target_ports(connector)
self.find_targets_from_storage(targets, connector, target_ports)
if not targets['list']:
utils.output_log(MSG.NO_CONNECTED_TARGET)
self.find_mapped_targets_from_storage(
mapped_targets, ldev, self.storage_info['ports'])
mapped_targets, ldev, target_ports)
unmap_targets['list'] = self.get_unmap_targets_list(
targets['list'], mapped_targets['list'])

View File

@ -196,7 +196,7 @@ horcm_opts = [
item_type=types.Integer(min=0, max=2047),
default=[200, 201],
help='Command Control Interface instance numbers in the format of '
'\'xxx,yyy\'. The second one is for ShadowImage operation and '
'\'xxx,yyy\'. The second one is for Shadow Image operation and '
'the first one is for other purposes.'),
cfg.StrOpt(
'vsp_horcm_user',
@ -210,6 +210,11 @@ horcm_opts = [
default=True,
help='If True, the driver will create or update the Command Control '
'Interface configuration file as needed.'),
cfg.ListOpt(
'vsp_horcm_pair_target_ports',
help='IDs of the storage ports used to copy volumes by Shadow Image '
'or Thin Image. To specify multiple ports, connect them by '
'commas (e.g. CL1-A,CL2-A).'),
]
_REQUIRED_HORCM_OPTS = [
@ -659,7 +664,7 @@ class VSPHORCM(common.VSPCommon):
raise exception.VSPBusy()
def _get_vol_type_and_pair_info(self, ldev):
"""Return a tuple of the LDEV's ShadowImage pair status and info."""
"""Return a tuple of the LDEV's Shadow Image pair status and info."""
ldev_info = self.get_ldev_info(['sts', 'vol_attr'], '-ldev_id', ldev)
if ldev_info['sts'] != NORMAL_STS:
return (SMPL, None)
@ -680,7 +685,7 @@ class VSPHORCM(common.VSPCommon):
return (SMPL, None)
def _get_full_copy_info(self, ldev):
"""Return a tuple of P-VOL and S-VOL's info of a ShadowImage pair."""
"""Return a tuple of P-VOL and S-VOL's info of a Shadow Image pair."""
vol_type, pair_info = self._get_vol_type_and_pair_info(ldev)
svol_info = []
@ -854,7 +859,7 @@ class VSPHORCM(common.VSPCommon):
{'ldev': ldev, 'info': ldev_info['vol_attr']})
return
self._find_mapped_targets_from_storage(
targets, ldev, self.storage_info['ports'], is_pair=True)
targets, ldev, self.storage_info['controller_ports'], is_pair=True)
self.unmap_ldev(targets, ldev)
def check_param(self):
@ -866,6 +871,12 @@ class VSPHORCM(common.VSPCommon):
msg = utils.output_log(MSG.INVALID_PARAMETER,
param='vsp_horcm_numbers')
raise exception.VSPError(msg)
if (not self.conf.vsp_target_ports and
not self.conf.vsp_horcm_pair_target_ports):
msg = utils.output_log(MSG.INVALID_PARAMETER,
param='vsp_target_ports or '
'vsp_horcm_pair_target_ports')
raise exception.VSPError(msg)
utils.output_log(MSG.SET_CONFIG_VALUE, object='LDEV range',
value=self.storage_info['ldev_range'])
for opt in _REQUIRED_HORCM_OPTS:
@ -874,7 +885,7 @@ class VSPHORCM(common.VSPCommon):
raise exception.VSPError(msg)
def _set_copy_groups(self, host_ip):
"""Initialize an instance variable for ShadowImage copy groups."""
"""Initialize an instance variable for Shadow Image copy groups."""
serial = self.conf.vsp_storage_id
inst = self.conf.vsp_horcm_numbers[_PAIR_HORCMGR]
@ -1118,6 +1129,11 @@ HORCM_CMD
'iqns': {},
}
super(VSPHORCM, self).init_cinder_hosts(targets=targets)
if self.storage_info['pair_ports']:
targets['info'] = {}
ports = self._get_pair_ports()
for port in ports:
targets['info'][port] = True
self._init_pair_targets(targets['info'])
def _init_pair_targets(self, targets_info):
@ -1170,7 +1186,7 @@ HORCM_CMD
self.run_raidcom('delete', 'ldev', '-ldev_id', ldev)
def _run_pairdisplay(self, *args):
"""Execute ShadowImage pairdisplay command."""
"""Execute Shadow Image pairdisplay command."""
result = self._run_pair_cmd(
'pairdisplay', '-CLI', *args, do_raise=False,
success_code=HORCM_EXIT_CODE.union(_NO_SUCH_DEVICE))
@ -1210,7 +1226,7 @@ HORCM_CMD
return stdout.splitlines()[2].split()[9] in _SMPL_STAUS
def _get_full_copy_pair_info(self, ldev, mun):
"""Return info of the ShadowImage volume pair."""
"""Return info of the Shadow Image volume pair."""
stdout = self._run_pairdisplay(
'-d', self.conf.vsp_storage_id, ldev, mun)
if not stdout:
@ -1279,6 +1295,11 @@ HORCM_CMD
return pair_info
def _get_pair_ports(self):
"""Return a list of ports used for volume pair management."""
return (self.storage_info['pair_ports'] or
self.storage_info['controller_ports'])
def _add_pair_config(self, pvol, svol, copy_group, ldev_name, mun):
"""Create device groups and a copy group for the SI volume pair."""
pvol_group = copy_group + 'P'
@ -1302,7 +1323,7 @@ HORCM_CMD
success_code=HORCM_EXIT_CODE)
def _delete_pair_config(self, pvol, svol, copy_group, ldev_name):
"""Delete specified LDEVs from ShadowImage device groups."""
"""Delete specified LDEVs from Shadow Image device groups."""
pvol_group = copy_group + 'P'
svol_group = copy_group + 'S'
if self._check_device_grp(pvol_group, pvol, ldev_name=ldev_name):
@ -1336,7 +1357,7 @@ HORCM_CMD
raise exception.VSPError(msg)
def wait_full_copy_completion(self, pvol, svol):
"""Wait until the ShadowImage volume copy has finished."""
"""Wait until the Shadow Image volume copy has finished."""
self._wait_full_copy(svol, set([PSUS, PSUE]),
timeout=utils.MAX_PROCESS_WAITTIME)
if self._run_pairevtwait(svol) == PSUE:
@ -1346,7 +1367,7 @@ HORCM_CMD
raise exception.VSPError(msg)
def _run_pairevtwait(self, ldev):
"""Execute ShadowImage pairevtwait command."""
"""Execute Shadow Image pairevtwait command."""
result = self._run_pair_cmd(
'pairevtwait', '-d', self.conf.vsp_storage_id,
ldev, '-nowaits')

View File

@ -46,15 +46,29 @@ class VSPHORCMFC(horcm.VSPHORCM):
def connect_storage(self):
"""Prepare for using the storage."""
target_ports = self.conf.vsp_target_ports
compute_target_ports = self.conf.vsp_compute_target_ports
pair_target_ports = self.conf.vsp_horcm_pair_target_ports
super(VSPHORCMFC, self).connect_storage()
result = self.run_raidcom('get', 'port')
for port, wwn in _FC_PORT_PATTERN.findall(result[1]):
if target_ports and port in target_ports:
self.storage_info['ports'].append(port)
self.storage_info['controller_ports'].append(port)
self.storage_info['wwns'][port] = wwn
if compute_target_ports and port in compute_target_ports:
self.storage_info['compute_ports'].append(port)
self.storage_info['wwns'][port] = wwn
if pair_target_ports and port in pair_target_ports:
self.storage_info['pair_ports'].append(port)
self.check_ports_info()
if pair_target_ports and not self.storage_info['pair_ports']:
msg = utils.output_log(MSG.RESOURCE_NOT_FOUND,
resource="Pair target ports")
raise exception.VSPError(msg)
utils.output_log(MSG.SET_CONFIG_VALUE,
object='pair target port list',
value=self.storage_info['pair_ports'])
utils.output_log(MSG.SET_CONFIG_VALUE, object='port-wwn list',
value=self.storage_info['wwns'])

View File

@ -45,15 +45,30 @@ class VSPHORCMISCSI(horcm.VSPHORCM):
def connect_storage(self):
"""Prepare for using the storage."""
target_ports = self.conf.vsp_target_ports
compute_target_ports = self.conf.vsp_compute_target_ports
pair_target_ports = self.conf.vsp_horcm_pair_target_ports
super(VSPHORCMISCSI, self).connect_storage()
result = self.run_raidcom('get', 'port')
for port in _ISCSI_PORT_PATTERN.findall(result[1]):
if (target_ports and port in target_ports and
self._set_target_portal(port)):
self.storage_info['ports'].append(port)
self.storage_info['controller_ports'].append(port)
if (compute_target_ports and port in compute_target_ports and
(port in self.storage_info['portals'] or
self._set_target_portal(port))):
self.storage_info['compute_ports'].append(port)
if pair_target_ports and port in pair_target_ports:
self.storage_info['pair_ports'].append(port)
self.check_ports_info()
if pair_target_ports and not self.storage_info['pair_ports']:
msg = utils.output_log(MSG.RESOURCE_NOT_FOUND,
resource="Pair target ports")
raise exception.VSPError(msg)
utils.output_log(MSG.SET_CONFIG_VALUE,
object='pair target port list',
value=self.storage_info['pair_ports'])
utils.output_log(MSG.SET_CONFIG_VALUE,
object='port-<IP address:port> list',
value=self.storage_info['portals'])

View File

@ -0,0 +1,16 @@
---
features:
- Hitachi VSP drivers have a new config option
``vsp_compute_target_ports`` to specify IDs
of the storage ports used to attach volumes
to compute nodes. The default is the value
specified for the existing ``vsp_target_ports``
option. Either or both of ``vsp_compute_target_ports``
and ``vsp_target_ports`` must be specified.
- Hitachi VSP drivers have a new config option
``vsp_horcm_pair_target_ports`` to specify IDs of the
storage ports used to copy volumes by Shadow Image or
Thin Image. The default is the value specified for
the existing ``vsp_target_ports`` option. Either
or both of ``vsp_horcm_pair_target_ports`` and
``vsp_target_ports`` must be specified.