diff --git a/lib/ansible/module_utils/basic.py b/lib/ansible/module_utils/basic.py index ee1686509eb..2d91e810c2b 100644 --- a/lib/ansible/module_utils/basic.py +++ b/lib/ansible/module_utils/basic.py @@ -2311,14 +2311,13 @@ class AnsibleModule(object): stderr=subprocess.PIPE, ) - if cwd and os.path.isdir(cwd): - kwargs['cwd'] = cwd - # store the pwd prev_dir = os.getcwd() # make sure we're in the right working directory if cwd and os.path.isdir(cwd): + cwd = os.path.abspath(os.path.expanduser(cwd)) + kwargs['cwd'] = cwd try: os.chdir(cwd) except (OSError, IOError): @@ -2330,7 +2329,6 @@ class AnsibleModule(object): old_umask = os.umask(umask) try: - if self._debug: self.log('Executing: ' + clean_args) cmd = subprocess.Popen(args, **kwargs) diff --git a/test/units/module_utils/basic/test_run_command.py b/test/units/module_utils/basic/test_run_command.py index 904f65b6aab..da56e56a601 100644 --- a/test/units/module_utils/basic/test_run_command.py +++ b/test/units/module_utils/basic/test_run_command.py @@ -61,6 +61,12 @@ class TestAnsibleModuleRunCommand(unittest.TestCase): if path == '/inaccessible': raise OSError(errno.EPERM, "Permission denied: '/inaccessible'") + def mock_os_abspath(path): + if path.startswith('/'): + return path + else: + return self.os.getcwd.return_value + '/' + path + args = json.dumps(dict(ANSIBLE_MODULE_ARGS={})) # unittest doesn't have a clean place to use a context manager, so we have to enter/exit manually self.stdin_swap = swap_stdin_and_argv(stdin_data=args) @@ -78,6 +84,7 @@ class TestAnsibleModuleRunCommand(unittest.TestCase): self.os.path.isdir.return_value = True self.os.chdir.side_effect = mock_os_chdir self.os.read.side_effect = mock_os_read + self.os.path.abspath.side_effect = mock_os_abspath self.subprocess = patch('ansible.module_utils.basic.subprocess').start() self.cmd = Mock() @@ -128,6 +135,12 @@ class TestAnsibleModuleRunCommand(unittest.TestCase): self.assertEqual(self.os.chdir.mock_calls, [call('/new'), call('/old'), ]) + def test_cwd_relative_path(self): + self.os.getcwd.return_value = '/old' + self.module.run_command('/bin/ls', cwd='sub-dir') + self.assertEqual(self.os.chdir.mock_calls, + [call('/old/sub-dir'), call('/old'), ]) + def test_cwd_not_a_dir(self): self.os.getcwd.return_value = '/old' self.os.path.isdir.side_effect = lambda d: d != '/not-a-dir'