diff --git a/changelogs/fragments/ansiballz-chdir.yml b/changelogs/fragments/ansiballz-chdir.yml new file mode 100644 index 00000000000..01a034f9406 --- /dev/null +++ b/changelogs/fragments/ansiballz-chdir.yml @@ -0,0 +1,3 @@ +minor_changes: + - The AnsiballZ Python wrapper now changes the working directory to ``~`` or ``/`` if the current one is not accessible. + This allows become to drop privileges on macOS when using pipelining. diff --git a/lib/ansible/executor/module_common.py b/lib/ansible/executor/module_common.py index b58aeba0cf2..cf69c2daff6 100644 --- a/lib/ansible/executor/module_common.py +++ b/lib/ansible/executor/module_common.py @@ -116,9 +116,21 @@ _ANSIBALLZ_WRAPPER = True # For test-module.py script to tell this is a ANSIBALL # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. def _ansiballz_main(): -%(rlimit)s import os import os.path + + # Access to the working directory is required by Python when using pipelining, as well as for the coverage module. + # Some platforms, such as macOS, may not allow querying the working directory when using become to drop privileges. + try: + os.getcwd() + except OSError: + try: + os.chdir(os.path.expanduser('~')) + except OSError: + os.chdir('/') + +%(rlimit)s + import sys import __main__ @@ -335,13 +347,6 @@ if __name__ == '__main__': ''' ANSIBALLZ_COVERAGE_TEMPLATE = ''' - # Access to the working directory is required by coverage. - # Some platforms, such as macOS, may not allow querying the working directory when using become to drop privileges. - try: - os.getcwd() - except OSError: - os.chdir('/') - os.environ['COVERAGE_FILE'] = '%(coverage_output)s' import atexit diff --git a/test/integration/targets/module_utils/module_utils_basic_setcwd.yml b/test/integration/targets/module_utils/module_utils_basic_setcwd.yml index 97dbf873175..2b2b6dbd04d 100644 --- a/test/integration/targets/module_utils/module_utils_basic_setcwd.yml +++ b/test/integration/targets/module_utils/module_utils_basic_setcwd.yml @@ -15,8 +15,14 @@ become: yes become_user: nobody # root can read cwd regardless of permissions, so a non-root user is required here + - name: get real path of home directory of the unprivileged user + raw: "{{ ansible_python_interpreter }} -c 'import os.path; print(os.path.realpath(os.path.expanduser(\"~\")))'" + register: home + become: yes + become_user: nobody + - name: verify AnsibleModule was able to adjust cwd as expected assert: that: - missing.before != missing.after - - unreadable.before != unreadable.after or unreadable.before == '/' # allow / fallback on macOS when using an unprivileged user + - unreadable.before != unreadable.after or unreadable.before == '/' or unreadable.before == home.stdout.strip() # allow / and $HOME fallback on macOS when using an unprivileged user