]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Add manage/unmanage methods for Hitachi Block Storage Driver
authorSeiji Aguchi <seiji.aguchi.tr@hitachi.com>
Fri, 23 Jan 2015 05:24:41 +0000 (14:24 +0900)
committerSeiji Aguchi <seiji.aguchi.tr@hitachi.com>
Tue, 3 Feb 2015 17:41:09 +0000 (02:41 +0900)
 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 <seiji.aguchi.tr@hitachi.com>
cinder/exception.py
cinder/tests/test_hitachi_hbsd_horcm_fc.py
cinder/tests/test_hitachi_hbsd_snm2_fc.py
cinder/tests/test_hitachi_hbsd_snm2_iscsi.py
cinder/volume/drivers/hitachi/hbsd_basiclib.py
cinder/volume/drivers/hitachi/hbsd_common.py
cinder/volume/drivers/hitachi/hbsd_fc.py
cinder/volume/drivers/hitachi/hbsd_horcm.py
cinder/volume/drivers/hitachi/hbsd_iscsi.py
cinder/volume/drivers/hitachi/hbsd_snm2.py

index b5458de25c67c16705c43458dde7ec4771194429..7c54adb7ae5f470ed628d9258bd21c4f379cc1c5 100644 (file)
@@ -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")
index 1cb2c218b1f383aadca8f23391a93736c4f27fa5..f0550fdc6498ac386b4a9671c4105d3a352665ad 100644 (file)
@@ -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)
index 4f5b5e8af02ad305b3e96416ad48b9c6d6203077..d00e13c8bfdde8f1743bae71fcff856be5e33eba 100644 (file)
@@ -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)
index 757c28d58af6a1d45f68c94ba2f5f96f38adb65d..a210e226b57a67ce33884f73fa5f9ec5e6113ee5 100644 (file)
@@ -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)
index dcd0094c62125c7bd2feb4d4f2ffc949433fd95f..ee761a8fb9303c081ccc60eb0b06b9e1be63c22a 100644 (file)
@@ -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
 
index a07a84de411c302769922d076f62ebc06eb988c2..439eff124c810372ebe67f7d3ddc3b2a426c4e46 100644 (file)
@@ -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': <logical device number on storage>,
+         'unit_name': <storage device name>}
+
+        For VSP G1000/VSP/HUS VM,
+        {'ldev': <logical device number on storage>,
+          'serial_number': <product number of storage system>}
+        """
+
+        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()
index e7947dfc5a7e9eaf6cf0968e80fac804d13f7b75..01ac4374e79c5be4018910d85b1eb45001726685 100644 (file)
@@ -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)
index 8a0570926a10674003348500891bb0d24cca61d6..94b5b4bf4591e36552dea3e3c0a6ac789d89a1e9 100644 (file)
@@ -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)
index 11515f8d6810e739820e15e8cd9e121050f77920..06997c31572a1236350576704fd5a1b17a5cf40a 100644 (file)
@@ -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)
index c72506ed87ed47bfe278e5f2ed0a5d56fa00dd5f..6d39d3a614b239f754c66a5f7d29b0810f3fd6d6 100644 (file)
@@ -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)