From c6c022fa8e87c1b52990fdfaf2fc6c7dcc33388f Mon Sep 17 00:00:00 2001 From: Rodrigo Barbieri Date: Wed, 1 Feb 2017 10:07:18 -0200 Subject: [PATCH] Fix HNAS driver inconsistent exceptions Fix following scenarios: - Driver raises ProcessExecutionError - Driver serializes the exception and passes to LOG.exception - Driver does not handle several commands possible failure - Driver does not log some error situations Also, slightly improvements with regards to affected tests: - Improved coverage - Improved resource names passed to exception messages Change-Id: I7fd9945d4cd6953e6fb33020d44f2d4472da27c7 Closes-bug: #1660952 --- manila/share/drivers/hitachi/hnas/driver.py | 10 +- manila/share/drivers/hitachi/hnas/ssh.py | 214 ++++++++++++------ .../share/drivers/hitachi/hnas/test_driver.py | 1 - .../share/drivers/hitachi/hnas/test_ssh.py | 116 +++++++++- 4 files changed, 256 insertions(+), 85 deletions(-) diff --git a/manila/share/drivers/hitachi/hnas/driver.py b/manila/share/drivers/hitachi/hnas/driver.py index 47da5bbc89..651fffd215 100644 --- a/manila/share/drivers/hitachi/hnas/driver.py +++ b/manila/share/drivers/hitachi/hnas/driver.py @@ -23,7 +23,7 @@ import six from manila.common import constants from manila import exception -from manila.i18n import _, _LE, _LI, _LW +from manila.i18n import _, _LI, _LW from manila.share import driver from manila.share import utils @@ -833,12 +833,10 @@ class HitachiHNASDriver(driver.ShareDriver): self.hnas.cifs_share_add(share_id, snapshot_id=snapshot_id) LOG.debug("CIFS share created to %(shr)s.", {'shr': share_id}) - except exception.HNASBackendException as e: + except exception.HNASBackendException: with excutils.save_and_reraise_exception(): if snapshot_id is None: self.hnas.vvol_delete(share_id) - msg = six.text_type(e) - LOG.exception(msg) def _check_fs_mounted(self): mounted = self.hnas.check_fs_mounted() @@ -1061,10 +1059,6 @@ class HitachiHNASDriver(driver.ShareDriver): self.hnas.cifs_share_add(share['id']) except exception.HNASBackendException: with excutils.save_and_reraise_exception(): - msg = _LE('Failed to create share %(share_id)s from snapshot ' - '%(snap)s.') - LOG.exception(msg, {'share_id': share['id'], - 'snap': hnas_snapshot_id}) self.hnas.vvol_delete(share['id']) return self._get_export_locations( diff --git a/manila/share/drivers/hitachi/hnas/ssh.py b/manila/share/drivers/hitachi/hnas/ssh.py index c488fd6cd1..b6d931880a 100644 --- a/manila/share/drivers/hitachi/hnas/ssh.py +++ b/manila/share/drivers/hitachi/hnas/ssh.py @@ -55,7 +55,13 @@ class HNASSSHBackend(object): dedupe = True if dedupe is enabled on filesystem. """ command = ['df', '-a', '-f', self.fs_name] - output, err = self._execute(command) + try: + output, err = self._execute(command) + + except processutils.ProcessExecutionError: + msg = _("Could not get HNAS backend stats.") + LOG.exception(msg) + raise exception.HNASBackendException(msg=msg) line = output.split('\n') fs = Filesystem(line[3]) @@ -74,7 +80,7 @@ class HNASSSHBackend(object): try: self._execute(command) except processutils.ProcessExecutionError: - msg = _("Could not create NFS export %s.") % share_id + msg = _("Could not create NFS export %s.") % name LOG.exception(msg) raise exception.HNASBackendException(msg=msg) @@ -95,7 +101,7 @@ class HNASSSHBackend(object): LOG.warning(_LW("Export %s does not exist on " "backend anymore."), name) else: - msg = six.text_type(e) + msg = _("Could not delete NFS export %s.") % name LOG.exception(msg) raise exception.HNASBackendException(msg=msg) @@ -111,7 +117,7 @@ class HNASSSHBackend(object): try: self._execute(command) except processutils.ProcessExecutionError: - msg = _("Could not create CIFS share %s.") % share_id + msg = _("Could not create CIFS share %s.") % name LOG.exception(msg) raise exception.HNASBackendException(msg=msg) @@ -125,7 +131,7 @@ class HNASSSHBackend(object): LOG.warning(_LW("CIFS share %s does not exist on " "backend anymore."), name) else: - msg = six.text_type(e) + msg = _("Could not delete CIFS share %s.") % name LOG.exception(msg) raise exception.HNASBackendException(msg=msg) @@ -156,7 +162,12 @@ class HNASSSHBackend(object): command.append(string_command) command.append(name) - self._execute(command) + try: + self._execute(command) + except processutils.ProcessExecutionError: + msg = _("Could not update access rules for NFS export %s.") % name + LOG.exception(msg) + raise exception.HNASBackendException(msg=msg) def cifs_allow_access(self, name, user, permission, is_snapshot=False): command = ['cifs-saa', 'add', '--target-label', self.fs_name, @@ -168,26 +179,43 @@ class HNASSSHBackend(object): if 'already listed as a user' in e.stderr: if is_snapshot: LOG.debug('User %(user)s already allowed to access ' - 'snapshot %(snapshot)s.', - {'user': user, 'snapshot': name}) + 'snapshot %(snapshot)s.', { + 'user': user, + 'snapshot': name, + }) else: self._update_cifs_rule(name, user, permission) else: - msg = six.text_type(e) + entity_type = "share" + if is_snapshot: + entity_type = "snapshot" + + msg = _("Could not add access of user %(user)s to " + "%(entity_type)s %(name)s.") % { + 'user': user, + 'name': name, + 'entity_type': entity_type, + } LOG.exception(msg) - raise exception.InvalidShareAccess(reason=msg) + raise exception.HNASBackendException(msg=msg) def _update_cifs_rule(self, name, user, permission): LOG.debug('User %(user)s already allowed to access ' - 'share %(share)s. Updating access level...', - {'user': user, 'share': name}) + 'share %(share)s. Updating access level...', { + 'user': user, + 'share': name, + }) command = ['cifs-saa', 'change', '--target-label', self.fs_name, name, user, permission] try: self._execute(command) except processutils.ProcessExecutionError: - msg = _("Could not update CIFS rule access for user %s.") % user + msg = _("Could not update access of user %(user)s to " + "share %(share)s.") % { + 'user': user, + 'share': name, + } LOG.exception(msg) raise exception.HNASBackendException(msg=msg) @@ -205,11 +233,18 @@ class HNASSSHBackend(object): if ('not listed as a user' in e.stderr or 'Could not delete user/group' in e.stderr): LOG.warning(_LW('User %(user)s already not allowed to access ' - '%(entity_type)s %(share)s.'), - {'entity_type': entity_type, 'user': user, - 'share': name}) + '%(entity_type)s %(name)s.'), { + 'entity_type': entity_type, + 'user': user, + 'name': name + }) else: - msg = six.text_type(e) + msg = _("Could not delete access of user %(user)s to " + "%(entity_type)s %(name)s.") % { + 'user': user, + 'name': name, + 'entity_type': entity_type, + } LOG.exception(msg) raise exception.HNASBackendException(msg=msg) @@ -224,7 +259,7 @@ class HNASSSHBackend(object): 'added.', {'share': hnas_share_id}) return [] else: - msg = six.text_type(e) + msg = _("Could not list access of share %s.") % hnas_share_id LOG.exception(msg) raise exception.HNASBackendException(msg=msg) @@ -240,10 +275,12 @@ class HNASSSHBackend(object): except processutils.ProcessExecutionError as e: if ('Cannot find any clonable files in the source directory' in e.stderr): - msg = _("Source path %s is empty") % src_path + msg = _("Source path %s is empty.") % src_path + LOG.debug(msg) raise exception.HNASNothingToCloneException(msg=msg) else: - msg = six.text_type(e) + msg = _("Could not submit tree clone job to clone from %(src)s" + " to %(dest)s.") % {'src': src_path, 'dest': dest_path} LOG.exception(msg) raise exception.HNASBackendException(msg=msg) @@ -277,8 +314,8 @@ class HNASSSHBackend(object): self._execute(command) LOG.error(_LE("Timeout in snapshot creation from " "source path %s.") % src_path) - msg = (_("Share snapshot of source path %s " - "was not created.") % src_path) + msg = _("Share snapshot of source path %s " + "was not created.") % src_path raise exception.HNASBackendException(msg=msg) else: time.sleep(job_rechecks ** 2) @@ -297,8 +334,8 @@ class HNASSSHBackend(object): else: LOG.error(_LE('Error creating snapshot of source path %s.'), src_path) - msg = (_('Snapshot of source path %s was not created.') % - src_path) + msg = _('Snapshot of source path %s was not ' + 'created.') % src_path raise exception.HNASBackendException(msg=msg) def tree_delete(self, path): @@ -311,9 +348,10 @@ class HNASSSHBackend(object): LOG.warning(_LW("Attempted to delete path %s " "but it does not exist."), path) else: - msg = six.text_type(e) + msg = _("Could not submit tree delete job to delete path " + "%s.") % path LOG.exception(msg) - raise + raise exception.HNASBackendException(msg=msg) def create_directory(self, dest_path): self._locked_selectfs('create', dest_path) @@ -338,15 +376,18 @@ class HNASSSHBackend(object): {'path': path, 'out': e.stdout}) return False else: - raise + msg = _("Could not check if path %s exists.") % path + LOG.exception(msg) + raise exception.HNASBackendException(msg=msg) return True def check_fs_mounted(self): command = ['df', '-a', '-f', self.fs_name] output, err = self._execute(command) if "not found" in output: - msg = (_("Filesystem %s does not exist or it is not available " - "in the current EVS context.") % self.fs_name) + msg = _("Filesystem %s does not exist or it is not available " + "in the current EVS context.") % self.fs_name + LOG.error(msg) raise exception.HNASItemNotFoundException(msg=msg) else: line = output.split('\n') @@ -359,16 +400,21 @@ class HNASSSHBackend(object): self._execute(command) except processutils.ProcessExecutionError as e: if 'file system is already mounted' not in e.stderr: - msg = six.text_type(e) + msg = _("Failed to mount filesystem %s.") % self.fs_name LOG.exception(msg) - raise + raise exception.HNASBackendException(msg=msg) def vvol_create(self, vvol_name): # create a virtual-volume inside directory path = '/shares/' + vvol_name command = ['virtual-volume', 'add', '--ensure', self.fs_name, vvol_name, path] - self._execute(command) + try: + self._execute(command) + except processutils.ProcessExecutionError: + msg = _("Failed to create vvol %s.") % vvol_name + LOG.exception(msg) + raise exception.HNASBackendException(msg=msg) def vvol_delete(self, vvol_name): path = '/shares/' + vvol_name @@ -379,43 +425,61 @@ class HNASSSHBackend(object): self._execute(command) except processutils.ProcessExecutionError as e: if 'Source path: Cannot access' in e.stderr: - LOG.debug("Share %(shr)s does not exist.", - {'shr': vvol_name}) + LOG.warning(_LW("Share %s does not exist."), vvol_name) else: - msg = six.text_type(e) + msg = _("Failed to delete vvol %s.") % vvol_name LOG.exception(msg) - raise e + raise exception.HNASBackendException(msg=msg) def quota_add(self, vvol_name, vvol_quota): str_quota = six.text_type(vvol_quota) + 'G' command = ['quota', 'add', '--usage-limit', str_quota, '--usage-hard-limit', 'yes', self.fs_name, vvol_name] - self._execute(command) + try: + self._execute(command) + except processutils.ProcessExecutionError: + msg = _("Failed to add %(quota)s quota to vvol " + "%(vvol)s.") % {'quota': str_quota, 'vvol': vvol_name} + LOG.exception(msg) + raise exception.HNASBackendException(msg=msg) def modify_quota(self, vvol_name, new_size): str_quota = six.text_type(new_size) + 'G' command = ['quota', 'mod', '--usage-limit', str_quota, self.fs_name, vvol_name] - self._execute(command) + try: + self._execute(command) + except processutils.ProcessExecutionError: + msg = _("Failed to update quota of vvol %(vvol)s to " + "%(quota)s.") % {'quota': str_quota, 'vvol': vvol_name} + LOG.exception(msg) + raise exception.HNASBackendException(msg=msg) def check_vvol(self, vvol_name): command = ['virtual-volume', 'list', '--verbose', self.fs_name, vvol_name] try: self._execute(command) - except processutils.ProcessExecutionError as e: - msg = six.text_type(e) + except processutils.ProcessExecutionError: + msg = _("Virtual volume %s does not exist.") % vvol_name LOG.exception(msg) - msg = (_("Virtual volume %s does not exist.") % vvol_name) raise exception.HNASItemNotFoundException(msg=msg) def check_quota(self, vvol_name): command = ['quota', 'list', '--verbose', self.fs_name, vvol_name] - output, err = self._execute(command) + try: + output, err = self._execute(command) + + except processutils.ProcessExecutionError: + msg = _("Could not check quota of vvol %s.") % vvol_name + LOG.exception(msg) + raise exception.HNASBackendException(msg=msg) if 'No quotas matching specified filter criteria' in output: - msg = (_("Virtual volume %s does not have any quota.") % vvol_name) + msg = _("Virtual volume %s does not have any" + " quota.") % vvol_name + LOG.error(msg) raise exception.HNASItemNotFoundException(msg=msg) def check_export(self, vvol_name, is_snapshot=False): @@ -425,6 +489,7 @@ class HNASSSHBackend(object): return else: msg = _("Export %s does not exist.") % export[0].export_name + LOG.error(msg) raise exception.HNASItemNotFoundException(msg=msg) def check_cifs(self, vvol_name): @@ -437,6 +502,7 @@ class HNASSSHBackend(object): "configured filesystem " "%(fs)s.") % {'share': vvol_name, 'fs': self.fs_name} + LOG.error(msg) raise exception.HNASItemNotFoundException(msg=msg) def is_cifs_in_use(self, vvol_name): @@ -455,9 +521,13 @@ class HNASSSHBackend(object): msg = _("CIFS share %(share)s was not found in EVS " "%(evs_id)s") % {'share': vvol_name, 'evs_id': self.evs_id} + LOG.exception(msg) raise exception.HNASItemNotFoundException(msg=msg) else: - raise + msg = _("Could not list CIFS shares by vvol name " + "%s.") % vvol_name + LOG.exception(msg) + raise exception.HNASBackendException(msg=msg) return output @@ -475,8 +545,9 @@ class HNASSSHBackend(object): elif quota.limit_unit == 'GB': return quota.limit else: - msg = (_("Share %s does not support quota values " - "below 1G.") % share_id) + msg = _("Share %s does not support quota values " + "below 1G.") % share_id + LOG.error(msg) raise exception.HNASBackendException(msg=msg) def get_share_usage(self, share_id): @@ -486,7 +557,8 @@ class HNASSSHBackend(object): quota = Quota(output) if quota.usage is None: - msg = (_("Virtual volume %s does not have any quota.") % share_id) + msg = _("Virtual volume %s does not have any quota.") % share_id + LOG.error(msg) raise exception.HNASItemNotFoundException(msg=msg) else: bytes_usage = strutils.string_to_bytes(six.text_type(quota.usage) + @@ -506,11 +578,16 @@ class HNASSSHBackend(object): except processutils.ProcessExecutionError as e: if 'does not exist' in e.stderr: msg = _("Export %(name)s was not found in EVS " - "%(evs_id)s.") % {'name': name, - 'evs_id': self.evs_id} + "%(evs_id)s.") % { + 'name': name, + 'evs_id': self.evs_id, + } + LOG.exception(msg) raise exception.HNASItemNotFoundException(msg=msg) else: - raise + msg = _("Could not list NFS exports by name %s.") % name + LOG.exception(msg) + raise exception.HNASBackendException(msg=msg) items = output.split('Export name') if items[0][0] == '\n': @@ -526,7 +603,7 @@ class HNASSSHBackend(object): if self.admin_ip0 is not None: command = ['ssc', '--smuauth', self.admin_ip0] - command = command + ['console-context', '--evs', self.evs_id] + command += ['console-context', '--evs', self.evs_id] commands = command + commands mutils.check_ssh_injection(commands) @@ -545,22 +622,26 @@ class HNASSSHBackend(object): out, err = processutils.ssh_execute(ssh, commands, check_exit_code=True) LOG.debug("Command %(cmd)s result: out = %(out)s - err = " - "%(err)s.", {'cmd': commands, - 'out': out, 'err': err}) + "%(err)s.", { + 'cmd': commands, + 'out': out, + 'err': err, + }) return out, err except processutils.ProcessExecutionError as e: if 'Failed to establish SSC connection' in e.stderr: - LOG.debug("SSC connection error!") msg = _("Failed to establish SSC connection.") + LOG.debug(msg) raise exception.HNASConnException(msg=msg) else: - LOG.debug("Command %(cmd)s result: out = %(out)s - err = " - "%(err)s - exit = %(exit)s.", {'cmd': e.cmd, - 'out': e.stdout, - 'err': e.stderr, - 'exit': - e.exit_code}) - LOG.error(_LE("Error running SSH command.")) + LOG.debug("Error running SSH command. " + "Command %(cmd)s result: out = %(out)s - err = " + "%(err)s - exit = %(exit)s.", { + 'cmd': e.cmd, + 'out': e.stdout, + 'err': e.stderr, + 'exit': e.exit_code, + }) raise @mutils.synchronized("hitachi_hnas_select_fs", external=True) @@ -569,7 +650,12 @@ class HNASSSHBackend(object): command = ['selectfs', self.fs_name, '\n', 'ssc', '127.0.0.1', 'console-context', '--evs', self.evs_id, 'mkdir', '-p', path] - self._execute(command) + try: + self._execute(command) + except processutils.ProcessExecutionError: + msg = _("Failed to create directory %s.") % path + LOG.exception(msg) + raise exception.HNASBackendException(msg=msg) if op == 'delete': command = ['selectfs', self.fs_name, '\n', @@ -585,9 +671,9 @@ class HNASSSHBackend(object): LOG.warning(_LW("Attempted to delete path %s but it does " "not exist."), path) else: - msg = six.text_type(e) + msg = _("Failed to delete directory %s.") % path LOG.exception(msg) - raise + raise exception.HNASBackendException(msg=msg) class Export(object): diff --git a/manila/tests/share/drivers/hitachi/hnas/test_driver.py b/manila/tests/share/drivers/hitachi/hnas/test_driver.py index 9ac864a425..6576242277 100644 --- a/manila/tests/share/drivers/hitachi/hnas/test_driver.py +++ b/manila/tests/share/drivers/hitachi/hnas/test_driver.py @@ -455,7 +455,6 @@ class HitachiHNASTestCase(test.TestCase): self.assertRaises(exception.HNASBackendException, self._driver.create_share, 'context', share_nfs) self.assertTrue(self.mock_log.debug.called) - self.assertTrue(self.mock_log.exception.called) ssh.HNASSSHBackend.vvol_create.assert_called_once_with(share_nfs['id']) ssh.HNASSSHBackend.quota_add.assert_called_once_with(share_nfs['id'], share_nfs['size']) diff --git a/manila/tests/share/drivers/hitachi/hnas/test_ssh.py b/manila/tests/share/drivers/hitachi/hnas/test_ssh.py index d7f906b5b5..4526267d29 100644 --- a/manila/tests/share/drivers/hitachi/hnas/test_ssh.py +++ b/manila/tests/share/drivers/hitachi/hnas/test_ssh.py @@ -539,6 +539,18 @@ class HNASSSHTestCase(test.TestCase): self.assertEqual(5120.0, free) self.assertTrue(dedupe) + def test_get_stats_error(self): + + fake_list_command = ['df', '-a', '-f', self.fs_name] + + self.mock_object(ssh.HNASSSHBackend, '_execute', + mock.Mock(side_effect=putils.ProcessExecutionError)) + + self.assertRaises(exception.HNASBackendException, + self._driver_ssh.get_stats) + + ssh.HNASSSHBackend._execute.assert_called_with(fake_list_command) + @ddt.data(True, False) def test_nfs_export_add(self, is_snapshot): if is_snapshot: @@ -694,11 +706,24 @@ class HNASSSHTestCase(test.TestCase): self._driver_ssh._execute.assert_called_with(fake_export_command) - def test_update_nfs_access_rule_exception(self): + def test_update_nfs_access_rule_exception_no_share_provided(self): self.assertRaises(exception.HNASBackendException, self._driver_ssh.update_nfs_access_rule, ['127.0.0.1']) + def test_update_nfs_access_rule_exception_error(self): + + fake_export_command = ['nfs-export', 'mod', '-c', + u'"127.0.0.1,127.0.0.2"', '/shares/fake_id'] + self.mock_object(ssh.HNASSSHBackend, "_execute", mock.Mock( + side_effect=putils.ProcessExecutionError)) + + self.assertRaises(exception.HNASBackendException, + self._driver_ssh.update_nfs_access_rule, + ['127.0.0.1', '127.0.0.2'], share_id="fake_id") + + self._driver_ssh._execute.assert_called_with(fake_export_command) + def test_cifs_allow_access(self): fake_cifs_allow_command = ['cifs-saa', 'add', '--target-label', self.fs_name, 'vvol_test', @@ -738,7 +763,7 @@ class HNASSSHTestCase(test.TestCase): stderr='Could not add user/group fake_user to ' 'share \'vvol_test\'')])) - self.assertRaises(exception.InvalidShareAccess, + self.assertRaises(exception.HNASBackendException, self._driver_ssh.cifs_allow_access, 'vvol_test', 'fake_user', 'acr') @@ -931,7 +956,7 @@ class HNASSSHTestCase(test.TestCase): stderr='')] )) - self.assertRaises(putils.ProcessExecutionError, + self.assertRaises(exception.HNASBackendException, self._driver_ssh.tree_delete, "/path") self.assertTrue(self.mock_log.exception.called) self._driver_ssh._execute.assert_called_with(fake_tree_delete_command) @@ -1009,7 +1034,7 @@ class HNASSSHTestCase(test.TestCase): mock.Mock(side_effect=putils.ProcessExecutionError( stdout="Internal Server Error."))) - self.assertRaises(putils.ProcessExecutionError, + self.assertRaises(exception.HNASBackendException, self._driver_ssh.check_snapshot, path) self._driver_ssh._execute.assert_called_with(check_snap_args) @@ -1040,7 +1065,9 @@ class HNASSSHTestCase(test.TestCase): self.mock_object(ssh.HNASSSHBackend, "_execute", mock.Mock( side_effect=putils.ProcessExecutionError(stderr=''))) - self.assertRaises(putils.ProcessExecutionError, self._driver_ssh.mount) + self.assertRaises( + exception.HNASBackendException, self._driver_ssh.mount) + self._driver_ssh._execute.assert_called_with(fake_mount_command) def test_vvol_create(self): @@ -1052,6 +1079,17 @@ class HNASSSHTestCase(test.TestCase): self._driver_ssh._execute.assert_called_with(fake_vvol_create_command) + def test_vvol_create_error(self): + fake_vvol_create_command = ['virtual-volume', 'add', '--ensure', + self.fs_name, 'vvol', '/shares/vvol'] + self.mock_object(ssh.HNASSSHBackend, "_execute", + mock.Mock(side_effect=putils.ProcessExecutionError)) + + self.assertRaises(exception.HNASBackendException, + self._driver_ssh.vvol_create, "vvol") + + self._driver_ssh._execute.assert_called_with(fake_vvol_create_command) + def test_vvol_delete_vvol_does_not_exist(self): fake_vvol_delete_command = ['tree-delete-job-submit', '--confirm', '-f', self.fs_name, '/shares/vvol'] @@ -1073,7 +1111,7 @@ class HNASSSHTestCase(test.TestCase): stderr='')] )) - self.assertRaises(putils.ProcessExecutionError, + self.assertRaises(exception.HNASBackendException, self._driver_ssh.vvol_delete, "vvol") self.assertTrue(self.mock_log.exception.called) self._driver_ssh._execute.assert_called_with(fake_vvol_delete_command) @@ -1097,6 +1135,29 @@ class HNASSSHTestCase(test.TestCase): self._driver_ssh._execute.assert_called_with(fake_modify_quota_command) + def test_quota_add_error(self): + fake_add_quota_command = ['quota', 'add', '--usage-limit', '1G', + '--usage-hard-limit', 'yes', + self.fs_name, 'vvol'] + self.mock_object(ssh.HNASSSHBackend, "_execute", + mock.Mock(side_effect=putils.ProcessExecutionError)) + + self.assertRaises(exception.HNASBackendException, + self._driver_ssh.quota_add, 'vvol', 1) + + self._driver_ssh._execute.assert_called_with(fake_add_quota_command) + + def test_modify_quota_error(self): + fake_modify_quota_command = ['quota', 'mod', '--usage-limit', '1G', + self.fs_name, 'vvol'] + self.mock_object(ssh.HNASSSHBackend, "_execute", + mock.Mock(side_effect=putils.ProcessExecutionError)) + + self.assertRaises(exception.HNASBackendException, + self._driver_ssh.modify_quota, 'vvol', 1) + + self._driver_ssh._execute.assert_called_with(fake_modify_quota_command) + def test_check_vvol(self): fake_check_vvol_command = ['virtual-volume', 'list', '--verbose', self.fs_name, 'vvol'] @@ -1117,6 +1178,16 @@ class HNASSSHTestCase(test.TestCase): self._driver_ssh.check_quota, 'vvol') self._driver_ssh._execute.assert_called_with(fake_check_quota_command) + def test_check_quota_error(self): + fake_check_quota_command = ['quota', 'list', '--verbose', + self.fs_name, 'vvol'] + self.mock_object(ssh.HNASSSHBackend, "_execute", mock.Mock( + side_effect=putils.ProcessExecutionError)) + + self.assertRaises(exception.HNASBackendException, + self._driver_ssh.check_quota, 'vvol') + self._driver_ssh._execute.assert_called_with(fake_check_quota_command) + @ddt.data(True, False) def test_check_export(self, is_snapshot): self.mock_object(ssh.HNASSSHBackend, "_get_export", mock.Mock( @@ -1159,7 +1230,7 @@ class HNASSSHTestCase(test.TestCase): self.mock_object(ssh.HNASSSHBackend, '_execute', mock.Mock( side_effect=[putils.ProcessExecutionError(stderr='Error.')])) - self.assertRaises(putils.ProcessExecutionError, + self.assertRaises(exception.HNASBackendException, self._driver_ssh.check_cifs, 'wrong_vvol') self._driver_ssh._execute.assert_called_with(check_cifs_share_command) @@ -1288,7 +1359,7 @@ class HNASSSHTestCase(test.TestCase): side_effect=putils.ProcessExecutionError(stderr="Some error.") )) - self.assertRaises(putils.ProcessExecutionError, + self.assertRaises(exception.HNASBackendException, self._driver_ssh._get_export, 'fake_id') def test__execute(self): @@ -1336,7 +1407,6 @@ class HNASSSHTestCase(test.TestCase): check_exit_code=True) self.assertTrue(self.mock_log.debug.called) - self.assertTrue(self.mock_log.error.called) def test__locked_selectfs_create_operation(self): exec_command = ['selectfs', self.fs_name, '\n', 'ssc', '127.0.0.1', @@ -1348,7 +1418,19 @@ class HNASSSHTestCase(test.TestCase): self._driver_ssh._execute.assert_called_with(exec_command) - def test__locked_selectfs_delete_operation_successfull(self): + def test__locked_selectfs_create_operation_error(self): + exec_command = ['selectfs', self.fs_name, '\n', 'ssc', '127.0.0.1', + 'console-context', '--evs', six.text_type(self.evs_id), + 'mkdir', '-p', '/path'] + self.mock_object(ssh.HNASSSHBackend, '_execute', + mock.Mock(side_effect=putils.ProcessExecutionError)) + + self.assertRaises(exception.HNASBackendException, + self._driver_ssh._locked_selectfs, 'create', '/path') + + self._driver_ssh._execute.assert_called_with(exec_command) + + def test__locked_selectfs_delete_operation_successful(self): exec_command = ['selectfs', self.fs_name, '\n', 'ssc', '127.0.0.1', 'console-context', '--evs', six.text_type(self.evs_id), 'rmdir', '/path'] @@ -1369,11 +1451,21 @@ class HNASSSHTestCase(test.TestCase): self.assertTrue(self.mock_log.debug.called) def test__locked_selectfs_delete_exception(self): - msg = 'rmdir: cannot remove \'/path\'' + msg = "rmdir: cannot remove '/path'" self.mock_object(ssh.HNASSSHBackend, '_execute', mock.Mock( side_effect=[putils.ProcessExecutionError(stderr=msg)])) - self.assertRaises(putils.ProcessExecutionError, + self.assertRaises(exception.HNASBackendException, self._driver_ssh._locked_selectfs, 'delete', 'path') self.assertTrue(self.mock_log.exception.called) + + def test__locked_selectfs_delete_not_found(self): + msg = "rmdir: NotFound '/path'" + + self.mock_object(ssh.HNASSSHBackend, '_execute', mock.Mock( + side_effect=[putils.ProcessExecutionError(stderr=msg)])) + + self._driver_ssh._locked_selectfs('delete', 'path') + + self.assertTrue(self.mock_log.warning.called)