From: Seiji Aguchi Date: Fri, 23 Jan 2015 05:24:41 +0000 (+0900) Subject: Add manage/unmanage methods for Hitachi Block Storage Driver X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=83e15a16537e71b558d068b2996a3bf3edf4d469;p=openstack-build%2Fcinder-build.git Add manage/unmanage methods for Hitachi Block Storage Driver This patch adds manage_existing, manage_existing_get_size, and unmanage methods for Hitachi Block Storage Driver. Implements: blueprint hitachi-driver-manage-api Change-Id: I8dc9086452f4db2e2635bf9c933e1fd9d4328367 Signed-off-by: Seiji Aguchi --- diff --git a/cinder/exception.py b/cinder/exception.py index b5458de25..7c54adb7a 100644 --- a/cinder/exception.py +++ b/cinder/exception.py @@ -903,6 +903,10 @@ class HBSDNotFound(NotFound): message = _("Storage resource could not be found.") +class HBSDVolumeIsBusy(VolumeIsBusy): + message = _("Volume %(volume_name)s is busy.") + + # Datera driver class DateraAPIException(VolumeBackendAPIException): message = _("Bad response from Datera API") diff --git a/cinder/tests/test_hitachi_hbsd_horcm_fc.py b/cinder/tests/test_hitachi_hbsd_horcm_fc.py index 1cb2c218b..f0550fdc6 100644 --- a/cinder/tests/test_hitachi_hbsd_horcm_fc.py +++ b/cinder/tests/test_hitachi_hbsd_horcm_fc.py @@ -33,6 +33,38 @@ def _exec_raidcom(*args, **kargs): return HBSDHORCMFCDriverTest.horcm_vals.get(args) +def _exec_raidcom_get_ldev_no_stdout(*args, **kargs): + return HBSDHORCMFCDriverTest.horcm_get_ldev_no_stdout.get(args) + + +def _exec_raidcom_get_ldev_no_nml(*args, **kargs): + return HBSDHORCMFCDriverTest.horcm_get_ldev_no_nml.get(args) + + +def _exec_raidcom_get_ldev_no_open_v(*args, **kargs): + return HBSDHORCMFCDriverTest.horcm_get_ldev_no_open_v.get(args) + + +def _exec_raidcom_get_ldev_no_hdp(*args, **kargs): + return HBSDHORCMFCDriverTest.horcm_get_ldev_no_hdp.get(args) + + +def _exec_raidcom_get_ldev_pair(*args, **kargs): + return HBSDHORCMFCDriverTest.horcm_get_ldev_pair.get(args) + + +def _exec_raidcom_get_ldev_permit(*args, **kargs): + return HBSDHORCMFCDriverTest.horcm_get_ldev_permit.get(args) + + +def _exec_raidcom_get_ldev_invalid_size(*args, **kargs): + return HBSDHORCMFCDriverTest.horcm_get_ldev_invalid_size.get(args) + + +def _exec_raidcom_get_ldev_num_port(*args, **kargs): + return HBSDHORCMFCDriverTest.horcm_get_ldev_num_port.get(args) + + class HBSDHORCMFCDriverTest(test.TestCase): """Test HBSDHORCMFCDriver.""" @@ -52,7 +84,11 @@ VOL_TYPE : NOT DEFINED" LDEV : 1\n\ DUMMY\n\ DUMMY\n\ -VOL_TYPE : OPEN-V-CVS" +VOL_TYPE : OPEN-V-CVS\n\ +VOL_ATTR : CVS : HDP\n\ +VOL_Capacity(BLK) : 2097152\n\ +NUM_PORT : 0\n\ +STS : NML" raidcom_get_result3 = "Serial# : 210944\n\ LDEV : 0\n\ @@ -298,6 +334,108 @@ HBSD-127.0.0.1None1A30P HBSD-127.0.0.1None1A30S -mirror_id 0'): ('raidcom', u'delete lun -port CL1-A-1 -ldev_id 1'): [1, "", ""]} + horcm_get_ldev_no_stdout = { + ('raidcom', 'get ldev -ldev_id 1'): + [0, "", ""]} + + raidcom_get_ldev_no_nml = "DUMMY\n\ +LDEV : 1\n\ +DUMMY\n\ +DUMMY\n\ +VOL_TYPE : OPEN-V-CVS\n\ +VOL_ATTR : CVS : HDP\n\ +VOL_Capacity(BLK) : 2097152\n\ +NUM_PORT : 0\n\ +STS :" + + horcm_get_ldev_no_nml = { + ('raidcom', 'get ldev -ldev_id 1'): + [0, "%s" % raidcom_get_ldev_no_nml, ""]} + + raidcom_get_ldev_no_open_v = "DUMMY\n\ +LDEV : 1\n\ +DUMMY\n\ +DUMMY\n\ +VOL_TYPE : CVS\n\ +VOL_ATTR : CVS : HDP\n\ +VOL_Capacity(BLK) : 2097152\n\ +NUM_PORT : 0\n\ +STS : NML" + + horcm_get_ldev_no_open_v = { + ('raidcom', 'get ldev -ldev_id 1'): + [0, "%s" % raidcom_get_ldev_no_open_v, ""]} + + raidcom_get_ldev_no_hdp = "DUMMY\n\ +LDEV : 1\n\ +DUMMY\n\ +DUMMY\n\ +VOL_TYPE : OPEN-V-CVS\n\ +VOL_ATTR : CVS :\n\ +VOL_Capacity(BLK) : 2097152\n\ +NUM_PORT : 0\n\ +STS : NML" + + horcm_get_ldev_no_hdp = { + ('raidcom', 'get ldev -ldev_id 1'): + [0, "%s" % raidcom_get_ldev_no_hdp, ""]} + + raidcom_get_ldev_pair = "DUMMY\n\ +LDEV : 1\n\ +DUMMY\n\ +DUMMY\n\ +VOL_TYPE : OPEN-V-CVS\n\ +VOL_ATTR : HORC : HDP\n\ +VOL_Capacity(BLK) : 2097152\n\ +NUM_PORT : 0\n\ +STS : NML" + + horcm_get_ldev_pair = { + ('raidcom', 'get ldev -ldev_id 1'): + [0, "%s" % raidcom_get_ldev_pair, ""]} + + raidcom_get_ldev_permit = "DUMMY\n\ +LDEV : 1\n\ +DUMMY\n\ +DUMMY\n\ +VOL_TYPE : OPEN-V-CVS\n\ +VOL_ATTR : XXX : HDP\n\ +VOL_Capacity(BLK) : 2097152\n\ +NUM_PORT : 0\n\ +STS : NML" + + horcm_get_ldev_permit = { + ('raidcom', 'get ldev -ldev_id 1'): + [0, "%s" % raidcom_get_ldev_permit, ""]} + + raidcom_get_ldev_invalid_size = "DUMMY\n\ +LDEV : 1\n\ +DUMMY\n\ +DUMMY\n\ +VOL_TYPE : OPEN-V-CVS\n\ +VOL_ATTR : CVS : HDP\n\ +VOL_Capacity(BLK) : 2097151\n\ +NUM_PORT : 0\n\ +STS : NML" + + horcm_get_ldev_invalid_size = { + ('raidcom', 'get ldev -ldev_id 1'): + [0, "%s" % raidcom_get_ldev_invalid_size, ""]} + + raidcom_get_ldev_num_port = "DUMMY\n\ +LDEV : 1\n\ +DUMMY\n\ +DUMMY\n\ +VOL_TYPE : OPEN-V-CVS\n\ +VOL_ATTR : CVS : HDP\n\ +VOL_Capacity(BLK) : 2097152\n\ +NUM_PORT : 1\n\ +STS : NML" + + horcm_get_ldev_num_port = { + ('raidcom', 'get ldev -ldev_id 1'): + [0, "%s" % raidcom_get_ldev_num_port, ""]} + # The following information is passed on to tests, when creating a volume _VOLUME = {'size': 128, 'volume_type': None, 'source_volid': '0', @@ -347,6 +485,17 @@ HBSD-127.0.0.1None1A30P HBSD-127.0.0.1None1A30S -mirror_id 0'): 'volume': _VOLUME, 'provider_location': '1', 'status': 'available'} + SERIAL_NUM = '210944' + test_existing_ref = {'ldev': '1', 'serial_number': SERIAL_NUM} + test_existing_none_ldev_ref = {'ldev': None, + 'serial_number': SERIAL_NUM} + test_existing_invalid_ldev_ref = {'ldev': 'AAA', + 'serial_number': SERIAL_NUM} + test_existing_no_ldev_ref = {'serial_number': SERIAL_NUM} + test_existing_none_serial_ref = {'ldev': '1', 'serial_number': None} + test_existing_invalid_serial_ref = {'ldev': '1', 'serial_number': '999999'} + test_existing_no_serial_ref = {'ldev': '1'} + def __init__(self, *args, **kwargs): super(HBSDHORCMFCDriverTest, self).__init__(*args, **kwargs) @@ -364,6 +513,7 @@ HBSD-127.0.0.1None1A30P HBSD-127.0.0.1None1A30S -mirror_id 0'): self._setup_driver() self.driver.check_param() self.driver.common.pair_flock = hbsd_basiclib.NopLock() + self.driver.common.command = hbsd_horcm.HBSDHORCM(self.configuration) self.driver.common.command.horcmgr_flock = hbsd_basiclib.NopLock() self.driver.common.create_lock_file() self.driver.common.command.connect_storage() @@ -668,3 +818,184 @@ HBSD-127.0.0.1None1A30P HBSD-127.0.0.1None1A30S -mirror_id 0'): self.driver.terminate_connection, self._VOLUME, connector) return + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_horcm.HBSDHORCM, 'exec_raidcom', + side_effect=_exec_raidcom) + def test_manage_existing(self, arg1, arg2): + self.configuration.hitachi_serial_number = self.SERIAL_NUM + rc = self.driver.manage_existing(self._VOLUME, self.test_existing_ref) + self.assertEqual(1, rc['provider_location']) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_horcm.HBSDHORCM, 'exec_raidcom', + side_effect=_exec_raidcom) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size(self, arg1, arg2, arg3): + self.configuration.hitachi_serial_number = self.SERIAL_NUM + size = self.driver.manage_existing_get_size(self._VOLUME, + self.test_existing_ref) + self.assertEqual(1, size) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_horcm.HBSDHORCM, 'exec_raidcom', + side_effect=_exec_raidcom) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size_none_ldev_ref(self, arg1, arg2, arg3): + self.configuration.hitachi_serial_number = self.SERIAL_NUM + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_none_ldev_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_horcm.HBSDHORCM, 'exec_raidcom', + side_effect=_exec_raidcom) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size_invalid_ldev_ref(self, arg1, arg2, arg3): + self.configuration.hitachi_serial_number = self.SERIAL_NUM + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_invalid_ldev_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_horcm.HBSDHORCM, 'exec_raidcom', + side_effect=_exec_raidcom) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size_no_ldev_ref(self, arg1, arg2, arg3): + self.configuration.hitachi_serial_number = self.SERIAL_NUM + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_no_ldev_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_horcm.HBSDHORCM, 'exec_raidcom', + side_effect=_exec_raidcom) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size_none_serial_ref(self, arg1, arg2, + arg3): + self.configuration.hitachi_serial_number = self.SERIAL_NUM + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_none_serial_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_horcm.HBSDHORCM, 'exec_raidcom', + side_effect=_exec_raidcom) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size_invalid_serial_ref(self, arg1, arg2, + arg3): + self.configuration.hitachi_serial_number = self.SERIAL_NUM + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_invalid_serial_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_horcm.HBSDHORCM, 'exec_raidcom', + side_effect=_exec_raidcom) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size_no_serial_ref(self, arg1, arg2, arg3): + self.configuration.hitachi_serial_number = self.SERIAL_NUM + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_no_serial_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_horcm.HBSDHORCM, 'start_horcm', + return_value=[0, "", ""]) + @mock.patch.object(hbsd_horcm.HBSDHORCM, 'check_horcm', + return_value=[0, "", ""]) + @mock.patch.object(hbsd_horcm.HBSDHORCM, 'exec_raidcom', + side_effect=_exec_raidcom) + def test_unmanage(self, arg1, arg2, arg3, arg4): + self.driver.unmanage(self._VOLUME) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_horcm.HBSDHORCM, 'exec_raidcom', + side_effect=_exec_raidcom) + def test_unmanage_busy(self, arg1, arg2): + self.assertRaises(exception.HBSDVolumeIsBusy, + self.driver.unmanage, self.test_volume_error3) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_horcm.HBSDHORCM, 'exec_raidcom', + side_effect=_exec_raidcom_get_ldev_no_stdout) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size_get_ldev_no_stdout(self, arg1, arg2, + arg3): + self.configuration.hitachi_serial_number = self.SERIAL_NUM + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_horcm.HBSDHORCM, 'exec_raidcom', + side_effect=_exec_raidcom_get_ldev_no_nml) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size_get_ldev_no_nml(self, arg1, arg2, arg3): + self.configuration.hitachi_serial_number = self.SERIAL_NUM + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_horcm.HBSDHORCM, 'exec_raidcom', + side_effect=_exec_raidcom_get_ldev_no_open_v) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size_get_ldev_no_open_v(self, arg1, arg2, + arg3): + self.configuration.hitachi_serial_number = self.SERIAL_NUM + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_horcm.HBSDHORCM, 'exec_raidcom', + side_effect=_exec_raidcom_get_ldev_no_hdp) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size_get_ldev_no_hdp(self, arg1, arg2, arg3): + self.configuration.hitachi_serial_number = self.SERIAL_NUM + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_horcm.HBSDHORCM, 'exec_raidcom', + side_effect=_exec_raidcom_get_ldev_pair) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size_get_ldev_pair(self, arg1, arg2, arg3): + self.configuration.hitachi_serial_number = self.SERIAL_NUM + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_horcm.HBSDHORCM, 'exec_raidcom', + side_effect=_exec_raidcom_get_ldev_permit) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size_get_ldev_permit(self, arg1, arg2, arg3): + self.configuration.hitachi_serial_number = self.SERIAL_NUM + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_horcm.HBSDHORCM, 'exec_raidcom', + side_effect=_exec_raidcom_get_ldev_invalid_size) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size_get_ldev_invalid_size(self, arg1, arg2, + arg3): + self.configuration.hitachi_serial_number = self.SERIAL_NUM + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_horcm.HBSDHORCM, 'exec_raidcom', + side_effect=_exec_raidcom_get_ldev_num_port) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size_get_ldev_num_port(self, arg1, arg2, + arg3): + self.configuration.hitachi_serial_number = self.SERIAL_NUM + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_ref) diff --git a/cinder/tests/test_hitachi_hbsd_snm2_fc.py b/cinder/tests/test_hitachi_hbsd_snm2_fc.py index 4f5b5e8af..d00e13c8b 100644 --- a/cinder/tests/test_hitachi_hbsd_snm2_fc.py +++ b/cinder/tests/test_hitachi_hbsd_snm2_fc.py @@ -32,6 +32,26 @@ def _exec_hsnm(*args, **kargs): return HBSDSNM2FCDriverTest.hsnm_vals.get(args) +def _exec_hsnm_get_lu_ret_err(*args, **kargs): + return HBSDSNM2FCDriverTest.hsnm_get_lu_ret_err.get(args) + + +def _exec_hsnm_get_lu_vol_type_err(*args, **kargs): + return HBSDSNM2FCDriverTest.hsnm_get_lu_vol_type_err.get(args) + + +def _exec_hsnm_get_lu_dppool_err(*args, **kargs): + return HBSDSNM2FCDriverTest.hsnm_get_lu_dppool_err.get(args) + + +def _exec_hsnm_get_lu_size_err(*args, **kargs): + return HBSDSNM2FCDriverTest.hsnm_get_lu_size_err.get(args) + + +def _exec_hsnm_get_lu_num_port_err(*args, **kargs): + return HBSDSNM2FCDriverTest.hsnm_get_lu_num_port_err.get(args) + + class HBSDSNM2FCDriverTest(test.TestCase): """Test HBSDSNM2FCDriver.""" @@ -63,7 +83,13 @@ LUN Status Copy Type Group \ RAID Rotational Number\n\ LU Capacity Size Group Pool Mode Level Type\ Speed of Paths Status\n\ - 0 2097152 blocks 256KB 0 0 Enable 5( 3D+1P) SAS" + 0 2097152 blocks 256KB 0 0 Enable 0 Normal" + + auluref_result1 = " Stripe RAID DP Tier \ + RAID Rotational Number\n\ + LU Capacity Size Group Pool Mode Level Type\ + Speed of Paths Status\n\ + 0 2097152 blocks 256KB 0 0 Enable 0 DUMMY" auhgwwn_result = "Port 00 Host Group Security ON\n Detected WWN\n \ Name Port Name Host Group\n\ @@ -103,11 +129,63 @@ Host Group\n abcdefg 10000000C97BCE7A \ ('auluadd', '-unit None -lu 1 -dppoolno 30 -size 128g'): [0, 0, ""], ('auluadd', '-unit None -lu 1 -dppoolno 30 -size 256g'): [1, "", ""], ('auluref', '-unit None'): [0, "%s" % auluref_result, ""], + ('auluref', '-unit None -lu 0'): [0, "%s" % auluref_result, ""], ('auhgmap', '-unit None -add 0 0 1 1 1'): [0, 0, ""], ('auhgwwn', '-unit None -refer'): [0, "%s" % auhgwwn_result, ""], ('aufibre1', '-unit None -refer'): [0, "%s" % aufibre1_result, ""], ('auhgmap', '-unit None -refer'): [0, "%s" % auhgmap_result, ""]} + auluref_ret_err = "Stripe RAID DP Tier \ + RAID Rotational Number\n\ + LU Capacity Size Group Pool Mode Level Type\ + Speed of Paths Status\n\ + 0 2097152 blocks 256KB 0 0 Enable 0 Normal" + + hsnm_get_lu_ret_err = { + ('auluref', '-unit None -lu 0'): [1, "%s" % auluref_ret_err, ""], + } + + auluref_vol_type_err = "Stripe RAID DP Tier \ + RAID Rotational Number\n\ + LU Capacity Size Group Pool Mode Level Type\ + Speed of Paths Status\n\ + 0 2097152 blocks 256KB 0 0 Enable 0 DUMMY" + + hsnm_get_lu_vol_type_err = { + ('auluref', '-unit None -lu 0'): + [0, "%s" % auluref_vol_type_err, ""], + } + + auluref_dppool_err = "Stripe RAID DP Tier \ + RAID Rotational Number\n\ + LU Capacity Size Group Pool Mode Level Type\ + Speed of Paths Status\n\ + 0 2097152 blocks 256KB 0 N/A Enable 0 Normal" + + hsnm_get_lu_dppool_err = { + ('auluref', '-unit None -lu 0'): + [0, "%s" % auluref_dppool_err, ""], + } + + auluref_size_err = "Stripe RAID DP Tier \ + RAID Rotational Number\n\ + LU Capacity Size Group Pool Mode Level Type\ + Speed of Paths Status\n\ + 0 2097151 blocks 256KB N/A 0 Enable 0 Normal" + hsnm_get_lu_size_err = { + ('auluref', '-unit None -lu 0'): [0, "%s" % auluref_size_err, ""], + } + + auluref_num_port_err = "Stripe RAID DP Tier \ + RAID Rotational Number\n\ + LU Capacity Size Group Pool Mode Level Type\ + Speed of Paths Status\n\ + 0 2097152 blocks 256KB 0 0 Enable 1 Normal" + + hsnm_get_lu_num_port_err = { + ('auluref', '-unit None -lu 0'): [0, "%s" % auluref_num_port_err, ""], + } + # The following information is passed on to tests, when creating a volume _VOLUME = {'size': 128, 'volume_type': None, 'source_volid': '0', @@ -151,6 +229,15 @@ Host Group\n abcdefg 10000000C97BCE7A \ 'volume': test_volume_error, 'provider_location': None, 'status': 'available'} + UNIT_NAME = 'HUS110_91122819' + test_existing_ref = {'ldev': '0', 'unit_name': UNIT_NAME} + test_existing_none_ldev_ref = {'ldev': None, 'unit_name': UNIT_NAME} + test_existing_invalid_ldev_ref = {'ldev': 'AAA', 'unit_name': UNIT_NAME} + test_existing_no_ldev_ref = {'unit_name': UNIT_NAME} + test_existing_none_unit_ref = {'ldev': '0', 'unit_name': None} + test_existing_invalid_unit_ref = {'ldev': '0', 'unit_name': 'Dummy'} + test_existing_no_unit_ref = {'ldev': '0'} + def __init__(self, *args, **kwargs): super(HBSDSNM2FCDriverTest, self).__init__(*args, **kwargs) @@ -184,6 +271,8 @@ Host Group\n abcdefg 10000000C97BCE7A \ self.driver.common.command = hbsd_snm2.HBSDSNM2(self.configuration) self.driver.common.pair_flock = \ self.driver.common.command.set_pair_flock() + self.driver.common.horcmgr_flock = \ + self.driver.common.command.set_horcmgr_flock() self.driver.do_setup_status.set() # API test cases @@ -377,3 +466,133 @@ Host Group\n abcdefg 10000000C97BCE7A \ self.driver.terminate_connection, self._VOLUME, connector) return + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_snm2.HBSDSNM2, 'exec_hsnm', side_effect=_exec_hsnm) + def test_manage_existing(self, arg1, arg2): + rc = self.driver.manage_existing(self._VOLUME, self.test_existing_ref) + self.assertEqual(0, rc['provider_location']) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_snm2.HBSDSNM2, 'exec_hsnm', side_effect=_exec_hsnm) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size(self, arg1, arg2, arg3): + self.configuration.hitachi_unit_name = self.UNIT_NAME + size = self.driver.manage_existing_get_size(self._VOLUME, + self.test_existing_ref) + self.assertEqual(1, size) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_snm2.HBSDSNM2, 'exec_hsnm', side_effect=_exec_hsnm) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size_none_ldev(self, arg1, arg2, arg3): + self.configuration.hitachi_unit_name = self.UNIT_NAME + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_none_ldev_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_snm2.HBSDSNM2, 'exec_hsnm', side_effect=_exec_hsnm) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size_invalid_ldev_ref(self, arg1, arg2, arg3): + self.configuration.hitachi_unit_name = self.UNIT_NAME + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_invalid_ldev_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_snm2.HBSDSNM2, 'exec_hsnm', side_effect=_exec_hsnm) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size_no_ldev_ref(self, arg1, arg2, arg3): + self.configuration.hitachi_unit_name = self.UNIT_NAME + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_no_ldev_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_snm2.HBSDSNM2, 'exec_hsnm', side_effect=_exec_hsnm) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size_none_unit_ref(self, arg1, arg2, arg3): + self.configuration.hitachi_unit_name = self.UNIT_NAME + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_none_unit_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_snm2.HBSDSNM2, 'exec_hsnm', side_effect=_exec_hsnm) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size_invalid_unit_ref(self, arg1, arg2, arg3): + self.configuration.hitachi_unit_name = self.UNIT_NAME + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_invalid_unit_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_snm2.HBSDSNM2, 'exec_hsnm', side_effect=_exec_hsnm) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size_no_unit_ref(self, arg1, arg2, arg3): + self.configuration.hitachi_unit_name = self.UNIT_NAME + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_no_unit_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_snm2.HBSDSNM2, 'exec_hsnm', + side_effect=_exec_hsnm_get_lu_ret_err) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size_ret_err(self, arg1, arg2, arg3): + self.configuration.hitachi_unit_name = self.UNIT_NAME + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_snm2.HBSDSNM2, 'exec_hsnm', + side_effect=_exec_hsnm_get_lu_vol_type_err) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_lu_vol_type_err(self, arg1, arg2, arg3): + self.configuration.hitachi_unit_name = self.UNIT_NAME + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_snm2.HBSDSNM2, 'exec_hsnm', + side_effect=_exec_hsnm_get_lu_dppool_err) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_lu_dppool_err(self, arg1, arg2, arg3): + self.configuration.hitachi_unit_name = self.UNIT_NAME + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_snm2.HBSDSNM2, 'exec_hsnm', + side_effect=_exec_hsnm_get_lu_size_err) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_lu_size_err(self, arg1, arg2, arg3): + self.configuration.hitachi_unit_name = self.UNIT_NAME + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_snm2.HBSDSNM2, 'exec_hsnm', + side_effect=_exec_hsnm_get_lu_num_port_err) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_lu_num_port_err(self, arg1, arg2, arg3): + self.configuration.hitachi_unit_name = self.UNIT_NAME + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_snm2.HBSDSNM2, 'exec_hsnm', side_effect=_exec_hsnm) + def test_unmanage(self, arg1, arg2): + self.driver.unmanage(self._VOLUME) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_snm2.HBSDSNM2, 'exec_hsnm', side_effect=_exec_hsnm) + def test_unmanage_busy(self, arg1, arg2): + self.assertRaises(exception.HBSDVolumeIsBusy, + self.driver.unmanage, self.test_volume_error3) diff --git a/cinder/tests/test_hitachi_hbsd_snm2_iscsi.py b/cinder/tests/test_hitachi_hbsd_snm2_iscsi.py index 757c28d58..a210e226b 100644 --- a/cinder/tests/test_hitachi_hbsd_snm2_iscsi.py +++ b/cinder/tests/test_hitachi_hbsd_snm2_iscsi.py @@ -68,7 +68,7 @@ LUN Status Copy Type Group \ RAID Rotational Number\n\ LU Capacity Size Group Pool Mode Level Type\ Speed of Paths Status\n\ - 0 2097152 blocks 256KB 0 0 Enable 5( 3D+1P) SAS" + 0 2097152 blocks 256KB 0 0 Enable 0 Normal" auhgwwn_result = "Port 00 Host Group Security ON\n Detected WWN\n \ Name Port Name Host Group\n\ @@ -144,6 +144,7 @@ Authentication\n\ ('auluadd', '-unit None -lu 1 -dppoolno 30 -size 128g'): [0, "", ""], ('auluadd', '-unit None -lu 1 -dppoolno 30 -size 256g'): [1, "", ""], ('auluref', '-unit None'): [0, "%s" % auluref_result, ""], + ('auluref', '-unit None -lu 0'): [0, "%s" % auluref_result, ""], ('autargetmap', '-unit None -add 0 0 1 1 1'): [0, "", ""], ('autargetmap', '-unit None -add 0 0 0 0 1'): [0, "", ""], ('autargetini', '-unit None -refer'): @@ -244,6 +245,15 @@ Authentication\n\ 'volume': test_volume_error, 'provider_location': None, 'status': 'available'} + UNIT_NAME = 'HUS110_91122819' + test_existing_ref = {'ldev': '0', 'unit_name': UNIT_NAME} + test_existing_none_ldev_ref = {'ldev': None, 'unit_name': UNIT_NAME} + test_existing_invalid_ldev_ref = {'ldev': 'AAA', 'unit_name': UNIT_NAME} + test_existing_no_ldev_ref = {'unit_name': UNIT_NAME} + test_existing_none_unit_ref = {'ldev': '0', 'unit_name': None} + test_existing_invalid_unit_ref = {'ldev': '0', 'unit_name': 'Dummy'} + test_existing_no_unit_ref = {'ldev': '0'} + def __init__(self, *args, **kwargs): super(HBSDSNM2ISCSIDriverTest, self).__init__(*args, **kwargs) @@ -296,6 +306,9 @@ Authentication\n\ db = None self.driver.common = hbsd_common.HBSDCommon( self.configuration, self.driver, context, db) + self.driver.common.command = hbsd_snm2.HBSDSNM2(self.configuration) + self.driver.common.horcmgr_flock = \ + self.driver.common.command.set_horcmgr_flock() # API test cases @mock.patch.object(hbsd_basiclib, 'get_process_lock') @@ -492,3 +505,83 @@ Authentication\n\ self.driver.terminate_connection, self._VOLUME, connector) return + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_snm2.HBSDSNM2, 'exec_hsnm', side_effect=_exec_hsnm) + def test_manage_existing(self, arg1, arg2): + rc = self.driver.manage_existing(self._VOLUME, self.test_existing_ref) + self.assertEqual(0, rc['provider_location']) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_snm2.HBSDSNM2, 'exec_hsnm', side_effect=_exec_hsnm) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size(self, arg1, arg2, arg3): + self.configuration.hitachi_unit_name = self.UNIT_NAME + size = self.driver.manage_existing_get_size(self._VOLUME, + self.test_existing_ref) + self.assertEqual(1, size) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_snm2.HBSDSNM2, 'exec_hsnm', side_effect=_exec_hsnm) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size_none_ldev(self, arg1, arg2, arg3): + self.configuration.hitachi_unit_name = self.UNIT_NAME + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_none_ldev_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_snm2.HBSDSNM2, 'exec_hsnm', side_effect=_exec_hsnm) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size_invalid_ldev_ref(self, arg1, arg2, arg3): + self.configuration.hitachi_unit_name = self.UNIT_NAME + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_invalid_ldev_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_snm2.HBSDSNM2, 'exec_hsnm', side_effect=_exec_hsnm) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size_no_ldev_ref(self, arg1, arg2, arg3): + self.configuration.hitachi_unit_name = self.UNIT_NAME + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_no_ldev_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_snm2.HBSDSNM2, 'exec_hsnm', side_effect=_exec_hsnm) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size_none_unit_ref(self, arg1, arg2, arg3): + self.configuration.hitachi_unit_name = self.UNIT_NAME + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_none_unit_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_snm2.HBSDSNM2, 'exec_hsnm', side_effect=_exec_hsnm) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size_invalid_unit_ref(self, arg1, arg2, arg3): + self.configuration.hitachi_unit_name = self.UNIT_NAME + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_invalid_unit_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_snm2.HBSDSNM2, 'exec_hsnm', side_effect=_exec_hsnm) + @mock.patch.object(hbsd_common.HBSDCommon, '_update_volume_metadata') + def test_manage_existing_get_size_no_unit_ref(self, arg1, arg2, arg3): + self.configuration.hitachi_unit_name = self.UNIT_NAME + self.assertRaises(exception.ManageExistingInvalidReference, + self.driver.manage_existing_get_size, self._VOLUME, + self.test_existing_no_unit_ref) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_snm2.HBSDSNM2, 'exec_hsnm', side_effect=_exec_hsnm) + def test_unmanage(self, arg1, arg2): + self.driver.unmanage(self._VOLUME) + + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_snm2.HBSDSNM2, 'exec_hsnm', side_effect=_exec_hsnm) + def test_unmanage_busy(self, arg1, arg2): + self.assertRaises(exception.HBSDVolumeIsBusy, + self.driver.unmanage, self.test_volume_error3) diff --git a/cinder/volume/drivers/hitachi/hbsd_basiclib.py b/cinder/volume/drivers/hitachi/hbsd_basiclib.py index dcd0094c6..ee761a8fb 100644 --- a/cinder/volume/drivers/hitachi/hbsd_basiclib.py +++ b/cinder/volume/drivers/hitachi/hbsd_basiclib.py @@ -48,6 +48,8 @@ DEFAULT_GROUP_RANGE = [0, 65535] NAME_PREFIX = 'HBSD-' +NORMAL_VOLUME_TYPE = 'Normal' + LOCK_DIR = '/var/lock/hbsd/' LOG = logging.getLogger(__name__) @@ -56,6 +58,9 @@ HBSD_INFO_MSG = { 1: _('The parameter of the storage backend. ' '(config_group: %(config_group)s)'), 3: _('The storage backend can be used. (config_group: %(config_group)s)'), + 4: _('The volume %(volume_id)s is managed successfully. (LDEV: %(ldev)s)'), + 5: _('The volume %(volume_id)s is unmanaged successfully. ' + '(LDEV: %(ldev)s)'), } HBSD_WARN_MSG = { @@ -131,6 +136,20 @@ HBSD_ERR_MSG = { 655: _('A snapshot status is invalid. (status: %(status)s)'), 659: _('A host group is invalid. (host group: %(gid)s)'), 660: _('The specified %(desc)s is busy.'), + 700: _('There is no designation of the %(param)s. ' + 'The specified storage is essential to manage the volume.'), + 701: _('There is no designation of the ldev. ' + 'The specified ldev is essential to manage the volume.'), + 702: _('The specified ldev %(ldev)s could not be managed. ' + 'The volume type must be DP-VOL.'), + 703: _('The specified ldev %(ldev)s could not be managed. ' + 'The ldev size must be in multiples of gigabyte.'), + 704: _('The specified ldev %(ldev)s could not be managed. ' + 'The ldev must not be mapping.'), + 705: _('The specified ldev %(ldev)s could not be managed. ' + 'The ldev must not be paired.'), + 706: _('The volume %(volume_id)s could not be unmanaged. ' + 'The volume type must be %(volume_type)s.'), } @@ -249,6 +268,9 @@ class HBSDBasicLib(object): def set_pair_flock(self): return NopLock() + def set_horcmgr_flock(self): + return NopLock() + def discard_zero_page(self, ldev): pass diff --git a/cinder/volume/drivers/hitachi/hbsd_common.py b/cinder/volume/drivers/hitachi/hbsd_common.py index a07a84de4..439eff124 100644 --- a/cinder/volume/drivers/hitachi/hbsd_common.py +++ b/cinder/volume/drivers/hitachi/hbsd_common.py @@ -35,8 +35,12 @@ from cinder.volume.drivers.hitachi import hbsd_horcm as horcm from cinder.volume.drivers.hitachi import hbsd_snm2 as snm2 from cinder.volume import utils as volume_utils - -VERSION = '1.0.0' +""" +Version history: + 1.0.0 - Initial driver + 1.1.0 - Add manage_existing/manage_existing_get_size/unmanage methods +""" +VERSION = '1.1.0' PARAM_RANGE = { 'hitachi_copy_check_interval': {'min': 1, 'max': 600}, @@ -152,6 +156,10 @@ class HBSDCommon(object): def get_snapshot_metadata(self, snapshot_id): return self.db.snapshot_metadata_get(self.context, snapshot_id) + def _update_volume_metadata(self, volume_id, volume_metadata): + self.db.volume_metadata_update(self.context, volume_id, + volume_metadata, False) + def get_ldev(self, obj): if not obj: return None @@ -195,6 +203,21 @@ class HBSDCommon(object): method = self.configuration.hitachi_default_copy_method return method + def _string2int(self, num): + if not num: + return None + if num.isdigit(): + return int(num, 10) + if not re.match(r'\w\w:\w\w:\w\w', num): + return None + + try: + num = int(num.replace(':', ''), 16) + except ValueError: + return None + + return num + def _range2list(self, conf, param): str = getattr(conf, param) lists = str.split('-') @@ -305,6 +328,7 @@ class HBSDCommon(object): self.command = horcm.HBSDHORCM(conf) self.command.check_param() self.pair_flock = self.command.set_pair_flock() + self.horcmgr_flock = self.command.set_horcmgr_flock() def create_lock_file(self): basic_lib.create_empty_file(self.system_lock_file) @@ -734,3 +758,85 @@ class HBSDCommon(object): def init_volinfo(self, vol_info, ldev): vol_info[ldev] = {'in_use': TryLock(), 'lock': threading.Lock()} + + def manage_existing(self, volume, existing_ref): + """Manage an existing Hitachi storage volume. + + existing_ref is a dictionary of the form: + + For HUS 100 Family, + {'ldev': , + 'unit_name': } + + For VSP G1000/VSP/HUS VM, + {'ldev': , + 'serial_number': } + """ + + ldev = self._string2int(existing_ref.get('ldev')) + + msg = basic_lib.set_msg(4, volume_id=volume['id'], ldev=ldev) + LOG.info(msg) + + return {'provider_location': ldev} + + def _manage_existing_get_size(self, volume, existing_ref): + """Return size of volume for manage_existing.""" + + ldev = self._string2int(existing_ref.get('ldev')) + if ldev is None: + msg = basic_lib.output_err(701) + raise exception.HBSDError(data=msg) + + size = self.command.get_ldev_size_in_gigabyte(ldev, existing_ref) + + metadata = {'type': basic_lib.NORMAL_VOLUME_TYPE, 'ldev': ldev} + self._update_volume_metadata(volume['id'], metadata) + + return size + + def manage_existing_get_size(self, volume, existing_ref): + try: + return self._manage_existing_get_size(volume, existing_ref) + except exception.HBSDError as ex: + raise exception.ManageExistingInvalidReference( + existing_ref=existing_ref, + reason=six.text_type(ex)) + + def _unmanage(self, volume, ldev): + with self.horcmgr_flock: + self.delete_pair(ldev) + + with self.volinfo_lock: + if ldev in self.volume_info: + self.volume_info.pop(ldev) + + def unmanage(self, volume): + """Remove the specified volume from Cinder management.""" + + ldev = self.get_ldev(volume) + + if ldev is None: + return + + self.add_volinfo(ldev, volume['id']) + if not self.volume_info[ldev]['in_use'].lock.acquire(False): + desc = self.volume_info[ldev]['in_use'].desc + basic_lib.output_err(660, desc=desc) + raise exception.HBSDVolumeIsBusy(volume_name=volume['name']) + + is_vvol = self.get_volume_is_vvol(volume) + if is_vvol: + basic_lib.output_err(706, volume_id=volume['id'], + volume_type=basic_lib.NORMAL_VOLUME_TYPE) + raise exception.HBSDVolumeIsBusy(volume_name=volume['name']) + try: + self._unmanage(volume, ldev) + except exception.HBSDBusy: + raise exception.HBSDVolumeIsBusy(volume_name=volume['name']) + else: + msg = basic_lib.set_msg(5, volume_id=volume['id'], ldev=ldev) + LOG.info(msg) + finally: + if ldev in self.volume_info: + self.volume_info[ldev]['in_use'].lock.release() diff --git a/cinder/volume/drivers/hitachi/hbsd_fc.py b/cinder/volume/drivers/hitachi/hbsd_fc.py index e7947dfc5..01ac4374e 100644 --- a/cinder/volume/drivers/hitachi/hbsd_fc.py +++ b/cinder/volume/drivers/hitachi/hbsd_fc.py @@ -519,3 +519,14 @@ class HBSDFCDriver(cinder.volume.driver.FibreChannelDriver): super(HBSDFCDriver, self).restore_backup(context, backup, volume, backup_service) self.discard_zero_page(volume) + + def manage_existing(self, volume, existing_ref): + return self.common.manage_existing(volume, existing_ref) + + def manage_existing_get_size(self, volume, existing_ref): + self.do_setup_status.wait() + return self.common.manage_existing_get_size(volume, existing_ref) + + def unmanage(self, volume): + self.do_setup_status.wait() + self.common.unmanage(volume) diff --git a/cinder/volume/drivers/hitachi/hbsd_horcm.py b/cinder/volume/drivers/hitachi/hbsd_horcm.py index 8a0570926..94b5b4bf4 100644 --- a/cinder/volume/drivers/hitachi/hbsd_horcm.py +++ b/cinder/volume/drivers/hitachi/hbsd_horcm.py @@ -23,6 +23,7 @@ import time from oslo_concurrency import processutils as putils from oslo_config import cfg from oslo_utils import excutils +from oslo_utils import units import six from cinder import exception @@ -46,6 +47,8 @@ LUN_DELETE_INTERVAL = 3 EXEC_MAX_WAITTIME = 30 EXEC_RETRY_INTERVAL = 5 HORCM_WAITTIME = 1 +PAIR_TYPE = ('HORC', 'MRCF', 'QS') +PERMITTED_TYPE = ('CVS', 'HDP', 'HDT') RAIDCOM_LOCK_FILE = basic_lib.LOCK_DIR + 'raidcom_' HORCMGR_LOCK_FILE = basic_lib.LOCK_DIR + 'horcmgr_' @@ -1507,3 +1510,78 @@ HORCM_CMD self.add_used_hlun(port, gid, list) return list + + def get_ldev_size_in_gigabyte(self, ldev, existing_ref): + param = 'serial_number' + + if param not in existing_ref: + msg = basic_lib.output_err(700, param=param) + raise exception.HBSDError(data=msg) + + storage = existing_ref.get(param) + if storage != self.conf.hitachi_serial_number: + msg = basic_lib.output_err(648, resource=param) + raise exception.HBSDError(data=msg) + + stdout = self.comm_get_ldev(ldev) + if not stdout: + msg = basic_lib.output_err(648, resource='LDEV') + raise exception.HBSDError(data=msg) + + sts_line = vol_type = "" + vol_attrs = [] + size = num_port = 1 + + lines = stdout.splitlines() + for line in lines: + if line.startswith("STS :"): + sts_line = line + + elif line.startswith("VOL_TYPE :"): + vol_type = shlex.split(line)[2] + + elif line.startswith("VOL_ATTR :"): + vol_attrs = shlex.split(line)[2:] + + elif line.startswith("VOL_Capacity(BLK) :"): + size = int(shlex.split(line)[2]) + + elif line.startswith("NUM_PORT :"): + num_port = int(shlex.split(line)[2]) + + if 'NML' not in sts_line: + msg = basic_lib.output_err(648, resource='LDEV') + + raise exception.HBSDError(data=msg) + + if 'OPEN-V' not in vol_type: + msg = basic_lib.output_err(702, ldev=ldev) + raise exception.HBSDError(data=msg) + + if 'HDP' not in vol_attrs: + msg = basic_lib.output_err(702, ldev=ldev) + raise exception.HBSDError(data=msg) + + for vol_attr in vol_attrs: + if vol_attr == ':': + continue + + if vol_attr in PAIR_TYPE: + msg = basic_lib.output_err(705, ldev=ldev) + raise exception.HBSDError(data=msg) + + if vol_attr not in PERMITTED_TYPE: + msg = basic_lib.output_err(702, ldev=ldev) + raise exception.HBSDError(data=msg) + + # Hitachi storage calculates volume sizes in a block unit, 512 bytes. + # So, units.Gi is divided by 512. + if size % (units.Gi / 512): + msg = basic_lib.output_err(703, ldev=ldev) + raise exception.HBSDError(data=msg) + + if num_port: + msg = basic_lib.output_err(704, ldev=ldev) + raise exception.HBSDError(data=msg) + + return size / (units.Gi / 512) diff --git a/cinder/volume/drivers/hitachi/hbsd_iscsi.py b/cinder/volume/drivers/hitachi/hbsd_iscsi.py index 11515f8d6..06997c315 100644 --- a/cinder/volume/drivers/hitachi/hbsd_iscsi.py +++ b/cinder/volume/drivers/hitachi/hbsd_iscsi.py @@ -418,3 +418,14 @@ class HBSDISCSIDriver(cinder.volume.driver.ISCSIDriver): super(HBSDISCSIDriver, self).copy_volume_to_image(context, volume, image_service, image_meta) + + def manage_existing(self, volume, existing_ref): + return self.common.manage_existing(volume, existing_ref) + + def manage_existing_get_size(self, volume, existing_ref): + self.do_setup_status.wait() + return self.common.manage_existing_get_size(volume, existing_ref) + + def unmanage(self, volume): + self.do_setup_status.wait() + self.common.unmanage(volume) diff --git a/cinder/volume/drivers/hitachi/hbsd_snm2.py b/cinder/volume/drivers/hitachi/hbsd_snm2.py index c72506ed8..6d39d3a61 100644 --- a/cinder/volume/drivers/hitachi/hbsd_snm2.py +++ b/cinder/volume/drivers/hitachi/hbsd_snm2.py @@ -18,6 +18,8 @@ import shlex import threading import time +from oslo_utils import excutils +from oslo_utils import units import six from cinder import exception @@ -99,6 +101,21 @@ class HBSDSNM2(basic_lib.HBSDBasicLib): return loop.start(interval=interval).wait() + def _execute_with_exception(self, cmd, args, **kwargs): + ret, stdout, stderr = self.exec_hsnm(cmd, args, **kwargs) + if ret: + cmds = '%(cmd)s %(args)s' % {'cmd': cmd, 'args': args} + msg = basic_lib.output_err( + 600, cmd=cmds, ret=ret, out=stdout, err=stderr) + raise exception.HBSDError(data=msg) + + return ret, stdout, stderr + + def _execute_and_return_stdout(self, cmd, args, **kwargs): + result = self._execute_with_exception(cmd, args, **kwargs) + + return result[1] + def get_comm_version(self): ret, stdout, stderr = self.exec_hsnm('auman', '-help') m = re.search('Version (\d+).(\d+)', stdout) @@ -132,6 +149,15 @@ class HBSDSNM2(basic_lib.HBSDBasicLib): return hlu return None + def _get_lu(self, lu=None): + # When 'lu' is 0, it should be true. So, it cannot remove 'is None'. + if lu is None: + args = '-unit %s' % self.unit_name + else: + args = '-unit %s -lu %s' % (self.unit_name, lu) + + return self._execute_and_return_stdout('auluref', args) + def get_unused_ldev(self, ldev_range): start = ldev_range[0] end = ldev_range[1] @@ -1084,3 +1110,48 @@ class HBSDSNM2(basic_lib.HBSDBasicLib): self.add_used_hlun('auhgmap', port, gid, list, DUMMY_LU) return list + + def get_ldev_size_in_gigabyte(self, ldev, existing_ref): + param = 'unit_name' + if param not in existing_ref: + msg = basic_lib.output_err(700, param=param) + raise exception.HBSDError(data=msg) + storage = existing_ref.get(param) + if storage != self.conf.hitachi_unit_name: + msg = basic_lib.output_err(648, resource=param) + raise exception.HBSDError(data=msg) + + try: + stdout = self._get_lu(ldev) + except exception.HBSDError: + with excutils.save_and_reraise_exception(): + basic_lib.output_err(648, resource='LDEV') + + lines = stdout.splitlines() + line = lines[2] + + splits = shlex.split(line) + + vol_type = splits[len(splits) - 1] + if basic_lib.NORMAL_VOLUME_TYPE != vol_type: + msg = basic_lib.output_err(702, ldev=ldev) + raise exception.HBSDError(data=msg) + + dppool = splits[5] + if 'N/A' == dppool: + msg = basic_lib.output_err(702, ldev=ldev) + raise exception.HBSDError(data=msg) + + # Hitachi storage calculates volume sizes in a block unit, 512 bytes. + # So, units.Gi is divided by 512. + size = int(splits[1]) + if size % (units.Gi / 512): + msg = basic_lib.output_err(703, ldev=ldev) + raise exception.HBSDError(data=msg) + + num_port = int(splits[len(splits) - 2]) + if num_port: + msg = basic_lib.output_err(704, ldev=ldev) + raise exception.HBSDError(data=msg) + + return size / (units.Gi / 512)