From 47e99384a78793558acb1a6ba92677bab576665d Mon Sep 17 00:00:00 2001 From: Cedric Zhuang Date: Thu, 21 May 2015 04:26:23 -0700 Subject: [PATCH] Use symbol for error code in VNX cinder driver Some of the error code of VNX CLI is scattered in the code and is not coded as a constant. Gather all VNX error codes in the VNXError class and compose a new method to check the error in the CLI output. If no specific error is supplied, check all available errors in the output. Change-Id: I145803fbe9fc36dcf432c9aa4d90245790a69859 Closes-Bug: #1454905 --- cinder/tests/unit/test_emc_vnxdirect.py | 58 +++++++++++ cinder/volume/drivers/emc/emc_vnx_cli.py | 121 +++++++++++++++-------- 2 files changed, 137 insertions(+), 42 deletions(-) diff --git a/cinder/tests/unit/test_emc_vnxdirect.py b/cinder/tests/unit/test_emc_vnxdirect.py index edcaff66d..62dfb99ea 100644 --- a/cinder/tests/unit/test_emc_vnxdirect.py +++ b/cinder/tests/unit/test_emc_vnxdirect.py @@ -4329,3 +4329,61 @@ class EMCVNXCLIDMultiPoolsTestCase(DriverTestCaseBase): driver = self.generate_driver(self.configuration) self.assertEqual(set(), driver.cli.storage_pools) + +VNXError = emc_vnx_cli.VNXError + + +class VNXErrorTest(test.TestCase): + + def test_has_error(self): + output = "The specified snapshot name is already in use. (0x716d8005)" + self.assertTrue(VNXError.has_error(output)) + + def test_has_error_with_specific_error(self): + output = "The specified snapshot name is already in use. (0x716d8005)" + has_error = VNXError.has_error(output, VNXError.SNAP_NAME_EXISTED) + self.assertTrue(has_error) + + has_error = VNXError.has_error(output, VNXError.LUN_ALREADY_EXPANDED) + self.assertFalse(has_error) + + def test_has_error_not_found(self): + output = "Cannot find the consistency group." + has_error = VNXError.has_error(output) + self.assertTrue(has_error) + + has_error = VNXError.has_error(output, VNXError.GENERAL_NOT_FOUND) + self.assertTrue(has_error) + + def test_has_error_not_exist(self): + output = "The specified snapshot does not exist" + has_error = VNXError.has_error(output, VNXError.GENERAL_NOT_FOUND) + self.assertTrue(has_error) + + output = "The (pool lun) may not exist" + has_error = VNXError.has_error(output, VNXError.GENERAL_NOT_FOUND) + self.assertTrue(has_error) + + def test_has_error_multi_line(self): + output = """Could not retrieve the specified (pool lun). + The (pool lun) may not exist""" + has_error = VNXError.has_error(output, VNXError.GENERAL_NOT_FOUND) + self.assertTrue(has_error) + + def test_has_error_regular_string_false(self): + output = "Cannot unbind LUN because it's contained in a Storage Group" + has_error = VNXError.has_error(output, VNXError.GENERAL_NOT_FOUND) + self.assertFalse(has_error) + + def test_has_error_multi_errors(self): + output = "Cannot unbind LUN because it's contained in a Storage Group" + has_error = VNXError.has_error(output, + VNXError.LUN_IN_SG, + VNXError.GENERAL_NOT_FOUND) + self.assertTrue(has_error) + + output = "Cannot unbind LUN because it's contained in a Storage Group" + has_error = VNXError.has_error(output, + VNXError.LUN_ALREADY_EXPANDED, + VNXError.LUN_NOT_MIGRATING) + self.assertFalse(has_error) diff --git a/cinder/volume/drivers/emc/emc_vnx_cli.py b/cinder/volume/drivers/emc/emc_vnx_cli.py index 557393bee..afcfaf10f 100644 --- a/cinder/volume/drivers/emc/emc_vnx_cli.py +++ b/cinder/volume/drivers/emc/emc_vnx_cli.py @@ -171,6 +171,65 @@ class PropertyDescriptor(object): self.converter = converter +class VNXError(object): + + GENERAL_NOT_FOUND = 'cannot find|may not exist|does not exist' + + SG_NAME_IN_USE = 'Storage Group name already in use' + + LUN_ALREADY_EXPANDED = 0x712d8e04 + LUN_EXISTED = 0x712d8d04 + LUN_IS_PREPARING = 0x712d8e0e + LUN_IN_SG = 'contained in a Storage Group|LUN mapping still exists' + LUN_NOT_MIGRATING = ('The specified source LUN is ' + 'not currently migrating') + + CG_IS_DELETING = 0x712d8801 + CG_EXISTED = 0x716d8021 + CG_SNAP_NAME_EXISTED = 0x716d8005 + + SNAP_NAME_EXISTED = 0x716d8005 + SNAP_NAME_IN_USE = 0x716d8003 + SNAP_ALREADY_MOUNTED = 0x716d8055 + SNAP_NOT_ATTACHED = ('The specified Snapshot mount point ' + 'is not currently attached.') + + @classmethod + def get_all(cls): + return (member for member in dir(cls) + if cls._is_enum(member)) + + @classmethod + def _is_enum(cls, name): + return (isinstance(name, str) + and hasattr(cls, name) + and not callable(name) + and name.isupper()) + + @staticmethod + def _match(output, error_code): + is_match = False + if VNXError._is_enum(error_code): + error_code = getattr(VNXError, error_code) + + if isinstance(error_code, int): + error_code = hex(error_code) + + if isinstance(error_code, str): + error_code = error_code.strip() + found = re.findall(error_code, output, + flags=re.IGNORECASE) + is_match = len(found) > 0 + return is_match + + @classmethod + def has_error(cls, output, *error_codes): + if error_codes is None or len(error_codes) == 0: + error_codes = VNXError.get_all() + return any([cls._match(output, error_code) + for error_code in error_codes]) + + @decorate_all_methods(log_enter_exit) class CommandLineHelper(object): @@ -263,19 +322,6 @@ class CommandLineHelper(object): POOL_FEATURE_DEFAULT = (MAX_POOL_LUNS, TOTAL_POOL_LUNS) - CLI_RESP_PATTERN_CG_NOT_FOUND = 'Cannot find' - CLI_RESP_PATTERN_SNAP_NOT_FOUND = 'The specified snapshot does not exist' - CLI_RESP_PATTERN_LUN_NOT_EXIST = 'The (pool lun) may not exist' - CLI_RESP_PATTERN_SMP_NOT_ATTACHED = ('The specified Snapshot mount point ' - 'is not currently attached.') - CLI_RESP_PATTERN_SG_NAME_IN_USE = 'Storage Group name already in use' - CLI_RESP_PATTERN_LUN_IN_SG_1 = 'contained in a Storage Group' - CLI_RESP_PATTERN_LUN_IN_SG_2 = 'Host LUN/LUN mapping still exists' - CLI_RESP_PATTERN_LUN_NOT_MIGRATING = ('The specified source LUN ' - 'is not currently migrating') - CLI_RESP_PATTERN_LUN_IS_PREPARING = '0x712d8e0e' - CLI_RESP_PATTERM_IS_NOT_SMP = 'it is not a snapshot mount point' - def __init__(self, configuration): configuration.append_config_values(san.san_opts) @@ -423,7 +469,7 @@ class CommandLineHelper(object): out, rc = self.command_execute(*cmd) if rc != 0: # Ignore the error that due to retry - if rc == 4 and out.find('(0x712d8d04)') >= 0: + if VNXError.has_error(out, VNXError.LUN_EXISTED): LOG.warning(_LW('LUN already exists, LUN name %(name)s. ' 'Message: %(msg)s'), {'name': name, 'msg': out}) @@ -452,8 +498,7 @@ class CommandLineHelper(object): data = self.get_lun_by_name(name, self.LUN_ALL, False) except exception.EMCVnxCLICmdError as ex: orig_out = "\n".join(ex.kwargs["out"]) - if orig_out.find( - self.CLI_RESP_PATTERN_LUN_NOT_EXIST) >= 0: + if VNXError.has_error(orig_out, VNXError.GENERAL_NOT_FOUND): return False else: raise @@ -477,7 +522,7 @@ class CommandLineHelper(object): out, rc = self.command_execute(*command_delete_lun) if rc != 0 or out.strip(): # Ignore the error that due to retry - if rc == 9 and self.CLI_RESP_PATTERN_LUN_NOT_EXIST in out: + if VNXError.has_error(out, VNXError.GENERAL_NOT_FOUND): LOG.warning(_LW("LUN is already deleted, LUN name %(name)s. " "Message: %(msg)s"), {'name': name, 'msg': out}) @@ -550,7 +595,7 @@ class CommandLineHelper(object): poll=poll) if rc != 0: # Ignore the error that due to retry - if rc == 4 and out.find("(0x712d8e04)") >= 0: + if VNXError.has_error(out, VNXError.LUN_ALREADY_EXPANDED): LOG.warning(_LW("LUN %(name)s is already expanded. " "Message: %(msg)s"), {'name': name, 'msg': out}) @@ -601,8 +646,7 @@ class CommandLineHelper(object): out, rc = self.command_execute(*command_create_cg) if rc != 0: # Ignore the error if consistency group already exists - if (rc == 33 and - out.find("(0x716d8021)") >= 0): + if VNXError.has_error(out, VNXError.CG_EXISTED): LOG.warning(_LW('Consistency group %(name)s already ' 'exists. Message: %(msg)s'), {'name': cg_name, 'msg': out}) @@ -694,11 +738,11 @@ class CommandLineHelper(object): out, rc = self.command_execute(*delete_cg_cmd) if rc != 0: # Ignore the error if CG doesn't exist - if rc == 13 and out.find(self.CLI_RESP_PATTERN_CG_NOT_FOUND) >= 0: + if VNXError.has_error(out, VNXError.GENERAL_NOT_FOUND): LOG.warning(_LW("CG %(cg_name)s does not exist. " "Message: %(msg)s"), {'cg_name': cg_name, 'msg': out}) - elif rc == 1 and out.find("0x712d8801") >= 0: + elif VNXError.has_error(out, VNXError.CG_IS_DELETING): LOG.warning(_LW("CG %(cg_name)s is deleting. " "Message: %(msg)s"), {'cg_name': cg_name, 'msg': out}) @@ -722,8 +766,7 @@ class CommandLineHelper(object): out, rc = self.command_execute(*create_cg_snap_cmd) if rc != 0: # Ignore the error if cgsnapshot already exists - if (rc == 5 and - out.find("(0x716d8005)") >= 0): + if VNXError.has_error(out, VNXError.CG_SNAP_NAME_EXISTED): LOG.warning(_LW('Cgsnapshot name %(name)s already ' 'exists. Message: %(msg)s'), {'name': snap_name, 'msg': out}) @@ -738,8 +781,7 @@ class CommandLineHelper(object): out, rc = self.command_execute(*delete_cg_snap_cmd) if rc != 0: # Ignore the error if cgsnapshot does not exist. - if (rc == 5 and - out.find(self.CLI_RESP_PATTERN_SNAP_NOT_FOUND) >= 0): + if VNXError.has_error(out, VNXError.GENERAL_NOT_FOUND): LOG.warning(_LW('Snapshot %(name)s for consistency group ' 'does not exist. Message: %(msg)s'), {'name': snap_name, 'msg': out}) @@ -758,8 +800,7 @@ class CommandLineHelper(object): poll=False) if rc != 0: # Ignore the error that due to retry - if (rc == 5 and - out.find("(0x716d8005)") >= 0): + if VNXError.has_error(out, VNXError.SNAP_NAME_EXISTED): LOG.warning(_LW('Snapshot %(name)s already exists. ' 'Message: %(msg)s'), {'name': name, 'msg': out}) @@ -786,7 +827,7 @@ class CommandLineHelper(object): return True # The snapshot cannot be destroyed because it is # attached to a snapshot mount point. Wait - elif rc == 3 and out.find("(0x716d8003)") >= 0: + elif VNXError.has_error(out, VNXError.SNAP_NAME_IN_USE): LOG.warning(_LW("Snapshot %(name)s is in use, retry. " "Message: %(msg)s"), {'name': name, 'msg': out}) @@ -813,7 +854,7 @@ class CommandLineHelper(object): poll=False) if rc != 0: # Ignore the error that due to retry - if rc == 4 and out.find("(0x712d8d04)") >= 0: + if VNXError.has_error(out, VNXError.LUN_EXISTED): LOG.warning(_LW("Mount point %(name)s already exists. " "Message: %(msg)s"), {'name': name, 'msg': out}) @@ -852,7 +893,7 @@ class CommandLineHelper(object): out, rc = self.command_execute(*command_attach_mount_point) if rc != 0: # Ignore the error that due to retry - if rc == 85 and out.find('(0x716d8055)') >= 0: + if VNXError.has_error(out, VNXError.SNAP_ALREADY_MOUNTED): LOG.warning(_LW("Snapshot %(snapname)s is attached to " "snapshot mount point %(mpname)s already. " "Message: %(msg)s"), @@ -872,8 +913,7 @@ class CommandLineHelper(object): out, rc = self.command_execute(*command_detach_mount_point) if rc != 0: # Ignore the error that due to retry - if (rc == 162 and - out.find(self.CLI_RESP_PATTERN_SMP_NOT_ATTACHED) >= 0): + if VNXError.has_error(out, VNXError.SNAP_NOT_ATTACHED): LOG.warning(_LW("The specified Snapshot mount point %s is not " "currently attached."), smp_name) else: @@ -957,7 +997,7 @@ class CommandLineHelper(object): {"src_id": src_id, "percentage": percentage_complete}) else: - if re.search(self.CLI_RESP_PATTERN_LUN_NOT_MIGRATING, out): + if VNXError.has_error(out, VNXError.LUN_NOT_MIGRATING): LOG.debug("Migration of LUN %s is finished.", src_id) mig_ready = True else: @@ -969,7 +1009,7 @@ class CommandLineHelper(object): out, rc = self.command_execute(*cmd_migrate_list, poll=poll) if rc != 0: - if re.search(self.CLI_RESP_PATTERN_LUN_NOT_MIGRATING, out): + if VNXError.has_error(out, VNXError.LUN_NOT_MIGRATING): LOG.debug("Migration of LUN %s is finished.", src_id) return True else: @@ -1062,7 +1102,7 @@ class CommandLineHelper(object): out, rc = self.command_execute(*command_create_storage_group) if rc != 0: # Ignore the error that due to retry - if rc == 66 and self.CLI_RESP_PATTERN_SG_NAME_IN_USE in out >= 0: + if VNXError.has_error(out, VNXError.SG_NAME_IN_USE): LOG.warning(_LW('Storage group %(name)s already exists. ' 'Message: %(msg)s'), {'name': name, 'msg': out}) @@ -1907,8 +1947,7 @@ class EMCVnxCliBase(object): except exception.EMCVnxCLICmdError as ex: orig_out = "\n".join(ex.kwargs["out"]) if (self.force_delete_lun_in_sg and - (self._client.CLI_RESP_PATTERN_LUN_IN_SG_1 in orig_out or - self._client.CLI_RESP_PATTERN_LUN_IN_SG_2 in orig_out)): + VNXError.has_error(orig_out, VNXError.LUN_IN_SG)): LOG.warning(_LW('LUN corresponding to %s is still ' 'in some Storage Groups.' 'Try to bring the LUN out of Storage Groups ' @@ -1931,8 +1970,7 @@ class EMCVnxCliBase(object): except exception.EMCVnxCLICmdError as ex: with excutils.save_and_reraise_exception(ex) as ctxt: out = "\n".join(ex.kwargs["out"]) - if (self._client.CLI_RESP_PATTERN_LUN_IS_PREPARING - in out): + if VNXError.has_error(out, VNXError.LUN_IS_PREPARING): # The error means the operation cannot be performed # because the LUN is 'Preparing'. Wait for a while # so that the LUN may get out of the transitioning @@ -2220,8 +2258,7 @@ class EMCVnxCliBase(object): except exception.EMCVnxCLICmdError as ex: with excutils.save_and_reraise_exception(ex) as ctxt: out = "\n".join(ex.kwargs["out"]) - if (self._client.CLI_RESP_PATTERN_LUN_IS_PREPARING - in out): + if VNXError.has_error(out, VNXError.LUN_IS_PREPARING): # The error means the operation cannot be performed # because the LUN is 'Preparing'. Wait for a while # so that the LUN may get out of the transitioning -- 2.45.2