From d6fb42d1c5f5ffc9d16a9c227705541fab6f59c8 Mon Sep 17 00:00:00 2001 From: Matt Clay Date: Fri, 26 Jun 2020 16:13:28 -0700 Subject: [PATCH] Add integration tests for basic.py _set_cwd. These tests verify that AnsibleModule can be instantiated when cwd does not exist or is unreadable. --- test/integration/targets/module_utils/aliases | 2 ++ .../module_utils/library/test_cwd_missing.py | 33 +++++++++++++++++++ .../library/test_cwd_unreadable.py | 28 ++++++++++++++++ .../module_utils_basic_setcwd.yml | 22 +++++++++++++ .../integration/targets/module_utils/runme.sh | 2 ++ 5 files changed, 87 insertions(+) create mode 100644 test/integration/targets/module_utils/library/test_cwd_missing.py create mode 100644 test/integration/targets/module_utils/library/test_cwd_unreadable.py create mode 100644 test/integration/targets/module_utils/module_utils_basic_setcwd.yml diff --git a/test/integration/targets/module_utils/aliases b/test/integration/targets/module_utils/aliases index b59832142f2..2f5770ffaac 100644 --- a/test/integration/targets/module_utils/aliases +++ b/test/integration/targets/module_utils/aliases @@ -1 +1,3 @@ shippable/posix/group3 +needs/root +needs/target/setup_nobody diff --git a/test/integration/targets/module_utils/library/test_cwd_missing.py b/test/integration/targets/module_utils/library/test_cwd_missing.py new file mode 100644 index 00000000000..cd1f9c77266 --- /dev/null +++ b/test/integration/targets/module_utils/library/test_cwd_missing.py @@ -0,0 +1,33 @@ +#!/usr/bin/python +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +import os + +from ansible.module_utils.basic import AnsibleModule + + +def main(): + # This module verifies that AnsibleModule works when cwd does not exist. + # This situation can occur as a race condition when the following conditions are met: + # + # 1) Execute a module which has high startup overhead prior to instantiating AnsibleModule (0.5s is enough in many cases). + # 2) Run the module async as the last task in a playbook using connection=local (a fire-and-forget task). + # 3) Remove the directory containing the playbook immediately after playbook execution ends (playbook in a temp dir). + # + # To ease testing of this race condition the deletion of cwd is handled in this module. + # This avoids race conditions in the test, including timing cwd deletion between AnsiballZ wrapper execution and AnsibleModule instantiation. + # The timing issue with AnsiballZ is due to cwd checking in the wrapper when code coverage is enabled. + + temp = os.path.abspath('temp') + + os.mkdir(temp) + os.chdir(temp) + os.rmdir(temp) + + module = AnsibleModule(argument_spec=dict()) + module.exit_json(before=temp, after=os.getcwd()) + + +if __name__ == '__main__': + main() diff --git a/test/integration/targets/module_utils/library/test_cwd_unreadable.py b/test/integration/targets/module_utils/library/test_cwd_unreadable.py new file mode 100644 index 00000000000..d65f31ac30d --- /dev/null +++ b/test/integration/targets/module_utils/library/test_cwd_unreadable.py @@ -0,0 +1,28 @@ +#!/usr/bin/python +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +import os + +from ansible.module_utils.basic import AnsibleModule + + +def main(): + # This module verifies that AnsibleModule works when cwd exists but is unreadable. + # This situation can occur when running tasks as an unprivileged user. + + try: + cwd = os.getcwd() + except OSError: + # Compensate for macOS being unable to access cwd as an unprivileged user. + # This test is a no-op in this case. + # Testing for os.getcwd() failures is handled by the test_cwd_missing module. + cwd = '/' + os.chdir(cwd) + + module = AnsibleModule(argument_spec=dict()) + module.exit_json(before=cwd, after=os.getcwd()) + + +if __name__ == '__main__': + main() diff --git a/test/integration/targets/module_utils/module_utils_basic_setcwd.yml b/test/integration/targets/module_utils/module_utils_basic_setcwd.yml new file mode 100644 index 00000000000..97dbf873175 --- /dev/null +++ b/test/integration/targets/module_utils/module_utils_basic_setcwd.yml @@ -0,0 +1,22 @@ +- hosts: testhost + gather_facts: no + tasks: + - name: make sure the nobody user is available + include_role: + name: setup_nobody + + - name: verify AnsibleModule works when cwd is missing + test_cwd_missing: + register: missing + + - name: verify AnsibleModule works when cwd is unreadable + test_cwd_unreadable: + register: unreadable + become: yes + become_user: nobody # root can read cwd regardless of permissions, so a non-root user is required here + + - 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 diff --git a/test/integration/targets/module_utils/runme.sh b/test/integration/targets/module_utils/runme.sh index efbb7f8208c..0578e7a66b9 100755 --- a/test/integration/targets/module_utils/runme.sh +++ b/test/integration/targets/module_utils/runme.sh @@ -2,5 +2,7 @@ set -eux +ANSIBLE_ROLES_PATH=../ ansible-playbook module_utils_basic_setcwd.yml -i ../../inventory "$@" + ansible-playbook module_utils_test.yml -i ../../inventory -v "$@" ANSIBLE_MODULE_UTILS=other_mu_dir ansible-playbook module_utils_envvar.yml -i ../../inventory -v "$@"