diff --git a/manila/share/drivers/helpers.py b/manila/share/drivers/helpers.py index bdf6a9b342..d7a257dbc7 100644 --- a/manila/share/drivers/helpers.py +++ b/manila/share/drivers/helpers.py @@ -529,6 +529,30 @@ class CIFSHelperIPAccess(CIFSHelperBase): ] self._ssh_exec(server, backup_exports) self._set_allow_hosts(server, [], share_name) + self._kick_out_users(server, share_name) + + def _kick_out_users(self, server, share_name): + """Kick out all users of share""" + (out, _) = self._ssh_exec(server, ['sudo', 'smbstatus', '-S']) + + shares = [] + header = True + regexp = r"^(?P[^ ]+)\s+(?P[0-9]+)\s+(?P[^ ]+).*" + for line in out.splitlines(): + line = line.strip() + if not header and line: + match = re.match(regexp, line) + if match: + shares.append(match.groupdict()) + else: + raise exception.ShareBackendException( + msg="Failed to obtain smbstatus for %s!" % share_name) + elif line.startswith('----'): + header = False + to_kill = [s['pid'] for s in shares if + share_name == s['share'] or share_name is None] + if to_kill: + self._ssh_exec(server, ['sudo', 'kill', '-15'] + to_kill) def restore_access_after_maintenance(self, server, share_name): maintenance_file = self._get_maintenance_file_path(share_name) diff --git a/manila/tests/share/drivers/test_helpers.py b/manila/tests/share/drivers/test_helpers.py index c7f6ad6c12..873c3c7a5c 100644 --- a/manila/tests/share/drivers/test_helpers.py +++ b/manila/tests/share/drivers/test_helpers.py @@ -678,11 +678,39 @@ class CIFSHelperIPAccessTestCase(test.TestCase): self.server_details, self.share_name) self._helper._set_allow_hosts.assert_called_once_with( self.server_details, [], self.share_name) + kickoff_user_cmd = ['sudo', 'smbstatus', '-S'] + self._helper._ssh_exec.assert_any_call( + self.server_details, kickoff_user_cmd) valid_cmd = ['echo', "'test test2'", '|', 'sudo', 'tee', maintenance_path] - self._helper._ssh_exec.assert_called_once_with( + self._helper._ssh_exec.assert_any_call( self.server_details, valid_cmd) + def test__kick_out_users_success(self): + smbstatus_return = """Service pid machine Connected at +------------------------------------------------------- +fake_share_name 1001 fake_machine1 Thu Sep 14 14:59:07 2017 +fake_share_name 1002 fake_machine2 Thu Sep 14 14:59:07 2017 +""" + self.mock_object(self._helper, '_ssh_exec', mock.Mock( + side_effect=[(smbstatus_return, "fake_stderr"), ("fake", "fake")])) + self._helper._kick_out_users(self.server_details, self.share_name) + self._helper._ssh_exec.assert_any_call( + self.server_details, ['sudo', 'smbstatus', '-S']) + self._helper._ssh_exec.assert_any_call( + self.server_details, ["sudo", "kill", "-15", "1001", "1002"]) + + def test__kick_out_users_failed(self): + smbstatus_return = """Service pid machine Connected at +------------------------------------------------------- +fake line +""" + self.mock_object(self._helper, '_ssh_exec', mock.Mock( + return_value=(smbstatus_return, "fake_stderr"))) + self.assertRaises(exception.ShareBackendException, + self._helper._kick_out_users, self.server_details, + self.share_name) + def test_restore_access_after_maintenance(self): fake_maintenance_path = "test.path" self.mock_object(self._helper, '_set_allow_hosts') diff --git a/releasenotes/notes/bug-1703581-cifs-extension-failing-because-of-volume-in-use-3fea31c4a58e2f1b.yaml b/releasenotes/notes/bug-1703581-cifs-extension-failing-because-of-volume-in-use-3fea31c4a58e2f1b.yaml new file mode 100644 index 0000000000..910bf7a2ec --- /dev/null +++ b/releasenotes/notes/bug-1703581-cifs-extension-failing-because-of-volume-in-use-3fea31c4a58e2f1b.yaml @@ -0,0 +1,4 @@ +--- +fixes: + - Fixed the Generic driver to evict and kill any user processes accessing + a share before attempting to extend or shrink a CIFS share.