diff options
author | Lee Garrett <lgarrett@rocketjump.eu> | 2021-11-17 20:15:37 +0100 |
---|---|---|
committer | Lee Garrett <lgarrett@rocketjump.eu> | 2021-11-17 20:15:37 +0100 |
commit | b1739f3e93dadd7d8fa794644ceedc24bddc8388 (patch) | |
tree | 193d287510fd44d67857e2d6b6bfcbb2b495c60a /test/integration/targets | |
parent | 13e2c2e94d3559b85a7d813d98e9835b891b0a9f (diff) | |
download | debian-ansible-core-b1739f3e93dadd7d8fa794644ceedc24bddc8388.zip |
New upstream version 2.12.0
Diffstat (limited to 'test/integration/targets')
586 files changed, 5664 insertions, 1213 deletions
diff --git a/test/integration/targets/adhoc/aliases b/test/integration/targets/adhoc/aliases index 765b70da..90ea9e12 100644 --- a/test/integration/targets/adhoc/aliases +++ b/test/integration/targets/adhoc/aliases @@ -1 +1,2 @@ shippable/posix/group2 +context/controller diff --git a/test/integration/targets/ansiballz_python/aliases b/test/integration/targets/ansiballz_python/aliases index f8e28c7e..e2c8fd39 100644 --- a/test/integration/targets/ansiballz_python/aliases +++ b/test/integration/targets/ansiballz_python/aliases @@ -1,2 +1,3 @@ shippable/posix/group1 skip/aix +context/target diff --git a/test/integration/targets/ansible-doc/aliases b/test/integration/targets/ansible-doc/aliases index a6dafcf8..13e01f0c 100644 --- a/test/integration/targets/ansible-doc/aliases +++ b/test/integration/targets/ansible-doc/aliases @@ -1 +1,2 @@ shippable/posix/group1 +context/controller diff --git a/test/integration/targets/ansible-doc/fakemodule.output b/test/integration/targets/ansible-doc/fakemodule.output index 01070fd5..5548ad5e 100644 --- a/test/integration/targets/ansible-doc/fakemodule.output +++ b/test/integration/targets/ansible-doc/fakemodule.output @@ -2,6 +2,8 @@ this is a fake module +ADDED IN: version 1.0.0 of testns.testcol + OPTIONS (= is mandatory): - _notreal @@ -12,5 +14,3 @@ OPTIONS (= is mandatory): AUTHOR: me SHORT_DESCIPTION: fake module - -VERSION_ADDED_COLLECTION: testns.testcol diff --git a/test/integration/targets/ansible-doc/randommodule-text.output b/test/integration/targets/ansible-doc/randommodule-text.output new file mode 100644 index 00000000..24327a59 --- /dev/null +++ b/test/integration/targets/ansible-doc/randommodule-text.output @@ -0,0 +1,105 @@ +> TESTNS.TESTCOL.RANDOMMODULE (./collections/ansible_collections/testns/testcol/plugins/modules/randommodule.py) + + A random module. + +ADDED IN: version 1.0.0 of testns.testcol + +DEPRECATED: + + Reason: Test deprecation + Will be removed in: Ansible 3.0.0 + Alternatives: Use some other module + + +OPTIONS (= is mandatory): + +- sub + Suboptions. + [Default: (null)] + set_via: + env: + - deprecated: + alternative: none + removed_in: 2.0.0 + version: 2.0.0 + why: Test deprecation + name: TEST_ENV + + type: dict + + OPTIONS: + + - subtest2 + Another suboption. + [Default: (null)] + type: float + added in: version 1.1.0 + + + + SUBOPTIONS: + + - subtest + A suboption. + [Default: (null)] + type: int + added in: version 1.1.0 of testns.testcol + + +- test + Some text. + [Default: (null)] + type: str + added in: version 1.2.0 of testns.testcol + + +- testcol2option + An option taken from testcol2 + [Default: (null)] + type: str + added in: version 1.0.0 of testns.testcol2 + + +- testcol2option2 + Another option taken from testcol2 + [Default: (null)] + type: str + + +AUTHOR: Ansible Core Team + +EXAMPLES: + + + + +RETURN VALUES: +- a_first + A first result. + + returned: success + type: str + +- m_middle + This should be in the middle. + Has some more data + + returned: success and 1st of month + type: dict + + CONTAINS: + + - suboption + A suboption. + (Choices: ARF, BARN, c_without_capital_first_letter) + type: str + added in: version 1.4.0 of testns.testcol + + +- z_last + A last result. + + returned: success + type: str + added in: version 1.3.0 of testns.testcol + diff --git a/test/integration/targets/ansible-doc/runme.sh b/test/integration/targets/ansible-doc/runme.sh index 4f40d7c3..549a341b 100755 --- a/test/integration/targets/ansible-doc/runme.sh +++ b/test/integration/targets/ansible-doc/runme.sh @@ -19,6 +19,11 @@ current_out="$(ansible-doc --playbook-dir ./ testns.testcol.fakemodule | sed '1 expected_out="$(sed '1 s/\(^> TESTNS\.TESTCOL\.FAKEMODULE\).*(.*)$/\1/' fakemodule.output)" test "$current_out" == "$expected_out" +# we use sed to strip the module path from the first line +current_out="$(ansible-doc --playbook-dir ./ testns.testcol.randommodule | sed '1 s/\(^> TESTNS\.TESTCOL\.RANDOMMODULE\).*(.*)$/\1/')" +expected_out="$(sed '1 s/\(^> TESTNS\.TESTCOL\.RANDOMMODULE\).*(.*)$/\1/' randommodule-text.output)" +test "$current_out" == "$expected_out" + # ensure we do work with valid collection name for list ansible-doc --list testns.testcol --playbook-dir ./ 2>&1 | grep -v "Invalid collection pattern" @@ -94,3 +99,6 @@ test "$current_out" == "$expected_out" current_out="$(ansible-doc --json --playbook-dir ./ -t vars testns.testcol.noop_vars_plugin | sed 's/ *$//' | sed 's/ *"filename": "[^"]*",$//')" expected_out="$(sed 's/ *"filename": "[^"]*",$//' noop_vars_plugin.output)" test "$current_out" == "$expected_out" + +# just ensure it runs +ANSIBLE_LIBRARY='./nolibrary' ansible-doc --metadata-dump --playbook-dir /dev/null diff --git a/test/integration/targets/ansible-galaxy-collection-scm/aliases b/test/integration/targets/ansible-galaxy-collection-scm/aliases index 9c34b360..498fedd5 100644 --- a/test/integration/targets/ansible-galaxy-collection-scm/aliases +++ b/test/integration/targets/ansible-galaxy-collection-scm/aliases @@ -1,3 +1,2 @@ shippable/posix/group4 -skip/aix -skip/python2.6 # ansible-galaxy uses tarfile with features not available until 2.7 +context/controller diff --git a/test/integration/targets/ansible-galaxy-collection/aliases b/test/integration/targets/ansible-galaxy-collection/aliases index e501bce5..6c57208a 100644 --- a/test/integration/targets/ansible-galaxy-collection/aliases +++ b/test/integration/targets/ansible-galaxy-collection/aliases @@ -1,3 +1,4 @@ shippable/galaxy/group1 shippable/galaxy/smoketest cloud/galaxy +context/controller diff --git a/test/integration/targets/ansible-galaxy-collection/tasks/install.yml b/test/integration/targets/ansible-galaxy-collection/tasks/install.yml index 7d66be2f..ad10bff8 100644 --- a/test/integration/targets/ansible-galaxy-collection/tasks/install.yml +++ b/test/integration/targets/ansible-galaxy-collection/tasks/install.yml @@ -214,7 +214,7 @@ state: absent - assert: - that: expected_error in error + that: error == expected_error vars: reset_color: '\x1b\[0m' color: '\x1b\[[0-9];[0-9]{2}m' @@ -260,7 +260,7 @@ - debug: msg="Expected - {{ expected_error }}" - assert: - that: expected_error in error + that: error == expected_error always: - name: clean up collection skeleton and artifact file: diff --git a/test/integration/targets/ansible-galaxy-collection/tasks/upgrade.yml b/test/integration/targets/ansible-galaxy-collection/tasks/upgrade.yml index b49f1eec..893ea803 100644 --- a/test/integration/targets/ansible-galaxy-collection/tasks/upgrade.yml +++ b/test/integration/targets/ansible-galaxy-collection/tasks/upgrade.yml @@ -124,9 +124,9 @@ that: - '"parent_dep.parent_collection:1.1.0 was installed successfully" in result.stdout_lines' - (metadata.results[0].content | b64decode | from_json).collection_info.version == '1.1.0' - - "\"Skipping 'child_dep.child_collection:0.9.9' as it is already installed\" in result.stdout_lines" + - "\"'child_dep.child_collection:0.9.9' is already installed, skipping.\" in result.stdout_lines" - (metadata.results[1].content | b64decode | from_json).collection_info.version == '0.9.9' - - "\"Skipping 'child_dep.child_dep2:1.2.2' as it is already installed\" in result.stdout_lines" + - "\"'child_dep.child_dep2:1.2.2' is already installed, skipping.\" in result.stdout_lines" - (metadata.results[2].content | b64decode | from_json).collection_info.version == '1.2.2' ##### Updating collections with --upgrade @@ -187,7 +187,7 @@ register: result - assert: - that: "\"Skipping 'namespace1.name1:1.1.0-beta.1' as it is already installed\" in result.stdout" + that: "\"'namespace1.name1:1.1.0-beta.1' is already installed, skipping.\" in result.stdout" # With deps diff --git a/test/integration/targets/ansible-galaxy-role/aliases b/test/integration/targets/ansible-galaxy-role/aliases index 62548acd..498fedd5 100644 --- a/test/integration/targets/ansible-galaxy-role/aliases +++ b/test/integration/targets/ansible-galaxy-role/aliases @@ -1,2 +1,2 @@ shippable/posix/group4 -skip/python2.6 # build uses tarfile with features not available until 2.7 +context/controller diff --git a/test/integration/targets/ansible-galaxy/aliases b/test/integration/targets/ansible-galaxy/aliases index 48ed7d60..275bdbfd 100644 --- a/test/integration/targets/ansible-galaxy/aliases +++ b/test/integration/targets/ansible-galaxy/aliases @@ -1,4 +1,3 @@ destructive shippable/posix/group4 -skip/python2.6 # build uses tarfile with features not available until 2.7 -skip/aix +context/controller diff --git a/test/integration/targets/ansible-inventory/aliases b/test/integration/targets/ansible-inventory/aliases index 70a7b7a9..1d28bdb2 100644 --- a/test/integration/targets/ansible-inventory/aliases +++ b/test/integration/targets/ansible-inventory/aliases @@ -1 +1,2 @@ shippable/posix/group5 +context/controller diff --git a/test/integration/targets/ansible-inventory/files/invalid_sample.yml b/test/integration/targets/ansible-inventory/files/invalid_sample.yml new file mode 100644 index 00000000..f7bbe0cf --- /dev/null +++ b/test/integration/targets/ansible-inventory/files/invalid_sample.yml @@ -0,0 +1,7 @@ +all: + children: + somegroup: + hosts: + something: + 7.2: bar + ungrouped: {} diff --git a/test/integration/targets/ansible-inventory/files/valid_sample.yml b/test/integration/targets/ansible-inventory/files/valid_sample.yml new file mode 100644 index 00000000..477f82f2 --- /dev/null +++ b/test/integration/targets/ansible-inventory/files/valid_sample.yml @@ -0,0 +1,7 @@ +all: + children: + somegroup: + hosts: + something: + foo: bar + ungrouped: {}
\ No newline at end of file diff --git a/test/integration/targets/ansible-inventory/tasks/main.yml b/test/integration/targets/ansible-inventory/tasks/main.yml index 0ab09c07..685cad88 100644 --- a/test/integration/targets/ansible-inventory/tasks/main.yml +++ b/test/integration/targets/ansible-inventory/tasks/main.yml @@ -1,3 +1,111 @@ +- name: "No command supplied" + command: ansible-inventory + ignore_errors: true + register: result + +- assert: + that: + - result is failed + - '"ERROR! No action selected, at least one of --host, --graph or --list needs to be specified." in result.stderr' + +- name: "test option: --list --export" + command: ansible-inventory --list --export + register: result + +- assert: + that: + - result is succeeded + +- name: "test option: --list --yaml --export" + command: ansible-inventory --list --yaml --export + register: result + +- assert: + that: + - result is succeeded + +- name: "test option: --list --output" + command: ansible-inventory --list --output junk.txt + register: result + +- name: stat output file + stat: + path: junk.txt + register: st + +- assert: + that: + - result is succeeded + - st.stat.exists + +- name: "test option: --graph" + command: ansible-inventory --graph + register: result + +- assert: + that: + - result is succeeded + +- name: "test option: --graph --vars" + command: ansible-inventory --graph --vars + register: result + +- assert: + that: + - result is succeeded + +- name: "test option: --graph with bad pattern" + command: ansible-inventory --graph invalid + ignore_errors: true + register: result + +- assert: + that: + - result is failed + - '"ERROR! Pattern must be valid group name when using --graph" in result.stderr' + +- name: "test option: --host localhost" + command: ansible-inventory --host localhost + register: result + +- assert: + that: + - result is succeeded + +- name: "test option: --host with invalid host" + command: ansible-inventory --host invalid + ignore_errors: true + register: result + +- assert: + that: + - result is failed + - '"ERROR! Could not match supplied host pattern, ignoring: invalid" in result.stderr' + +- name: Install toml package + pip: + name: + - toml + state: present + +- name: "test option: --toml with valid group name" + command: ansible-inventory --list --toml -i {{ role_path }}/files/valid_sample.yml + register: result + +- assert: + that: + - result is succeeded + +- name: "test option: --toml with invalid group name" + command: ansible-inventory --list --toml -i {{ role_path }}/files/invalid_sample.yml + ignore_errors: true + register: result + +- assert: + that: + - result is failed + - '"ERROR! The source inventory contains a non-string key" in result.stderr' + - name: "test json output with unicode characters" command: ansible-inventory --list -i {{ role_path }}/files/unicode.yml register: result @@ -47,12 +155,6 @@ state: absent - block: - - name: Install toml package - pip: - name: - - toml - state: present - - name: "test toml output with unicode characters" command: ansible-inventory --list --toml -i {{ role_path }}/files/unicode.yml register: result diff --git a/test/integration/targets/vault/aliases b/test/integration/targets/ansible-pull/aliases index 757c9966..8278ec8b 100644 --- a/test/integration/targets/vault/aliases +++ b/test/integration/targets/ansible-pull/aliases @@ -1,2 +1,2 @@ shippable/posix/group3 -skip/aix +context/controller diff --git a/test/integration/targets/pull/cleanup.yml b/test/integration/targets/ansible-pull/cleanup.yml index 68686964..68686964 100644 --- a/test/integration/targets/pull/cleanup.yml +++ b/test/integration/targets/ansible-pull/cleanup.yml diff --git a/test/integration/targets/pull/pull-integration-test/ansible.cfg b/test/integration/targets/ansible-pull/pull-integration-test/ansible.cfg index f8fc6cdb..f8fc6cdb 100644 --- a/test/integration/targets/pull/pull-integration-test/ansible.cfg +++ b/test/integration/targets/ansible-pull/pull-integration-test/ansible.cfg diff --git a/test/integration/targets/pull/pull-integration-test/inventory b/test/integration/targets/ansible-pull/pull-integration-test/inventory index 72644cef..72644cef 100644 --- a/test/integration/targets/pull/pull-integration-test/inventory +++ b/test/integration/targets/ansible-pull/pull-integration-test/inventory diff --git a/test/integration/targets/pull/pull-integration-test/local.yml b/test/integration/targets/ansible-pull/pull-integration-test/local.yml index d358ee86..d358ee86 100644 --- a/test/integration/targets/pull/pull-integration-test/local.yml +++ b/test/integration/targets/ansible-pull/pull-integration-test/local.yml diff --git a/test/integration/targets/pull/pull-integration-test/multi_play_1.yml b/test/integration/targets/ansible-pull/pull-integration-test/multi_play_1.yml index 0ec0da6b..0ec0da6b 100644 --- a/test/integration/targets/pull/pull-integration-test/multi_play_1.yml +++ b/test/integration/targets/ansible-pull/pull-integration-test/multi_play_1.yml diff --git a/test/integration/targets/pull/pull-integration-test/multi_play_2.yml b/test/integration/targets/ansible-pull/pull-integration-test/multi_play_2.yml index 1fe5a584..1fe5a584 100644 --- a/test/integration/targets/pull/pull-integration-test/multi_play_2.yml +++ b/test/integration/targets/ansible-pull/pull-integration-test/multi_play_2.yml diff --git a/test/integration/targets/pull/runme.sh b/test/integration/targets/ansible-pull/runme.sh index 347971a4..347971a4 100755 --- a/test/integration/targets/pull/runme.sh +++ b/test/integration/targets/ansible-pull/runme.sh diff --git a/test/integration/targets/pull/setup.yml b/test/integration/targets/ansible-pull/setup.yml index ebd5a1c0..ebd5a1c0 100644 --- a/test/integration/targets/pull/setup.yml +++ b/test/integration/targets/ansible-pull/setup.yml diff --git a/test/integration/targets/ansible-runner/aliases b/test/integration/targets/ansible-runner/aliases index 42d2022b..17ae2d5e 100644 --- a/test/integration/targets/ansible-runner/aliases +++ b/test/integration/targets/ansible-runner/aliases @@ -1,6 +1,5 @@ shippable/posix/group3 -skip/python2 # ansible-runner is for controller and deprecated python2 support -skip/aix +context/controller skip/osx skip/macos skip/freebsd diff --git a/test/integration/targets/ansible-test-cloud-acme/aliases b/test/integration/targets/ansible-test-cloud-acme/aliases new file mode 100644 index 00000000..db3ab680 --- /dev/null +++ b/test/integration/targets/ansible-test-cloud-acme/aliases @@ -0,0 +1,3 @@ +cloud/acme +shippable/generic/group1 +context/controller diff --git a/test/integration/targets/ansible-test-cloud-acme/tasks/main.yml b/test/integration/targets/ansible-test-cloud-acme/tasks/main.yml new file mode 100644 index 00000000..42ebc284 --- /dev/null +++ b/test/integration/targets/ansible-test-cloud-acme/tasks/main.yml @@ -0,0 +1,7 @@ +- name: Verify endpoints respond + uri: + url: "{{ item }}" + validate_certs: no + with_items: + - http://{{ acme_host }}:5000/ + - https://{{ acme_host }}:14000/dir diff --git a/test/integration/targets/ansible-test-cloud-cs/aliases b/test/integration/targets/ansible-test-cloud-cs/aliases new file mode 100644 index 00000000..cf43ff1e --- /dev/null +++ b/test/integration/targets/ansible-test-cloud-cs/aliases @@ -0,0 +1,3 @@ +cloud/cs +shippable/generic/group1 +context/controller diff --git a/test/integration/targets/ansible-test-cloud-cs/tasks/main.yml b/test/integration/targets/ansible-test-cloud-cs/tasks/main.yml new file mode 100644 index 00000000..3b219c7e --- /dev/null +++ b/test/integration/targets/ansible-test-cloud-cs/tasks/main.yml @@ -0,0 +1,8 @@ +- name: Verify endpoints respond + uri: + url: "{{ item }}" + validate_certs: no + register: this + failed_when: "this.status != 401" # authentication is required, but not provided (requests must be signed) + with_items: + - "{{ ansible_env.CLOUDSTACK_ENDPOINT }}" diff --git a/test/integration/targets/ansible-test-cloud-foreman/aliases b/test/integration/targets/ansible-test-cloud-foreman/aliases new file mode 100644 index 00000000..a4bdcea6 --- /dev/null +++ b/test/integration/targets/ansible-test-cloud-foreman/aliases @@ -0,0 +1,3 @@ +cloud/foreman +shippable/generic/group1 +context/controller diff --git a/test/integration/targets/ansible-test-cloud-foreman/tasks/main.yml b/test/integration/targets/ansible-test-cloud-foreman/tasks/main.yml new file mode 100644 index 00000000..4170d83e --- /dev/null +++ b/test/integration/targets/ansible-test-cloud-foreman/tasks/main.yml @@ -0,0 +1,6 @@ +- name: Verify endpoints respond + uri: + url: "{{ item }}" + validate_certs: no + with_items: + - http://{{ ansible_env.FOREMAN_HOST }}:{{ ansible_env.FOREMAN_PORT }}/ping diff --git a/test/integration/targets/ansible-test-cloud-galaxy/aliases b/test/integration/targets/ansible-test-cloud-galaxy/aliases new file mode 100644 index 00000000..6c57208a --- /dev/null +++ b/test/integration/targets/ansible-test-cloud-galaxy/aliases @@ -0,0 +1,4 @@ +shippable/galaxy/group1 +shippable/galaxy/smoketest +cloud/galaxy +context/controller diff --git a/test/integration/targets/ansible-test-cloud-galaxy/tasks/main.yml b/test/integration/targets/ansible-test-cloud-galaxy/tasks/main.yml new file mode 100644 index 00000000..8ae15ea5 --- /dev/null +++ b/test/integration/targets/ansible-test-cloud-galaxy/tasks/main.yml @@ -0,0 +1,25 @@ +# The pulp container has a long start up time. +# The first task to interact with pulp needs to wait until it responds appropriately. +- name: Wait for Pulp API + uri: + url: '{{ pulp_api }}/pulp/api/v3/distributions/ansible/ansible/' + user: '{{ pulp_user }}' + password: '{{ pulp_password }}' + force_basic_auth: true + register: this + until: this is successful + delay: 1 + retries: 60 + +- name: Verify Galaxy NG server + uri: + url: "{{ galaxy_ng_server }}" + user: '{{ pulp_user }}' + password: '{{ pulp_password }}' + force_basic_auth: true + +- name: Verify Pulp server + uri: + url: "{{ pulp_server }}" + status_code: + - 404 # endpoint responds without authentication diff --git a/test/integration/targets/ansible-test-cloud-httptester-windows/aliases b/test/integration/targets/ansible-test-cloud-httptester-windows/aliases new file mode 100644 index 00000000..f45a1623 --- /dev/null +++ b/test/integration/targets/ansible-test-cloud-httptester-windows/aliases @@ -0,0 +1,4 @@ +cloud/httptester +windows +shippable/windows/group1 +context/target diff --git a/test/integration/targets/ansible-test-cloud-httptester-windows/tasks/main.yml b/test/integration/targets/ansible-test-cloud-httptester-windows/tasks/main.yml new file mode 100644 index 00000000..a78b28ca --- /dev/null +++ b/test/integration/targets/ansible-test-cloud-httptester-windows/tasks/main.yml @@ -0,0 +1,15 @@ +- name: Verify HTTPTESTER environment variable + assert: + that: + - "lookup('env', 'HTTPTESTER') == '1'" + +- name: Verify endpoints respond + ansible.windows.win_uri: + url: "{{ item }}" + validate_certs: no + with_items: + - http://ansible.http.tests/ + - https://ansible.http.tests/ + - https://sni1.ansible.http.tests/ + - https://fail.ansible.http.tests/ + - https://self-signed.ansible.http.tests/ diff --git a/test/integration/targets/ansible-test-cloud-httptester/aliases b/test/integration/targets/ansible-test-cloud-httptester/aliases new file mode 100644 index 00000000..eb5f7080 --- /dev/null +++ b/test/integration/targets/ansible-test-cloud-httptester/aliases @@ -0,0 +1,3 @@ +needs/httptester # using legacy alias for testing purposes +shippable/posix/group1 +context/controller diff --git a/test/integration/targets/ansible-test-cloud-httptester/tasks/main.yml b/test/integration/targets/ansible-test-cloud-httptester/tasks/main.yml new file mode 100644 index 00000000..16b632f3 --- /dev/null +++ b/test/integration/targets/ansible-test-cloud-httptester/tasks/main.yml @@ -0,0 +1,15 @@ +- name: Verify HTTPTESTER environment variable + assert: + that: + - "lookup('env', 'HTTPTESTER') == '1'" + +- name: Verify endpoints respond + uri: + url: "{{ item }}" + validate_certs: no + with_items: + - http://ansible.http.tests/ + - https://ansible.http.tests/ + - https://sni1.ansible.http.tests/ + - https://fail.ansible.http.tests/ + - https://self-signed.ansible.http.tests/ diff --git a/test/integration/targets/ansible-test-cloud-nios/aliases b/test/integration/targets/ansible-test-cloud-nios/aliases new file mode 100644 index 00000000..136344a9 --- /dev/null +++ b/test/integration/targets/ansible-test-cloud-nios/aliases @@ -0,0 +1,3 @@ +cloud/nios +shippable/generic/group1 +context/controller diff --git a/test/integration/targets/ansible-test-cloud-nios/tasks/main.yml b/test/integration/targets/ansible-test-cloud-nios/tasks/main.yml new file mode 100644 index 00000000..b4d447d7 --- /dev/null +++ b/test/integration/targets/ansible-test-cloud-nios/tasks/main.yml @@ -0,0 +1,10 @@ +- name: Verify endpoints respond + uri: + url: "{{ item }}" + url_username: "{{ nios_provider.username }}" + url_password: "{{ nios_provider.password }}" + validate_certs: no + register: this + failed_when: "this.status != 404" # authentication succeeded, but the requested path was not found + with_items: + - https://{{ nios_provider.host }}/ diff --git a/test/integration/targets/ansible-test-cloud-openshift/aliases b/test/integration/targets/ansible-test-cloud-openshift/aliases new file mode 100644 index 00000000..6e32db7b --- /dev/null +++ b/test/integration/targets/ansible-test-cloud-openshift/aliases @@ -0,0 +1,4 @@ +cloud/openshift +shippable/generic/group1 +disabled # disabled due to requirements conflict: botocore 1.20.6 has requirement urllib3<1.27,>=1.25.4, but you have urllib3 1.24.3. +context/controller diff --git a/test/integration/targets/ansible-test-cloud-openshift/tasks/main.yml b/test/integration/targets/ansible-test-cloud-openshift/tasks/main.yml new file mode 100644 index 00000000..c3b51904 --- /dev/null +++ b/test/integration/targets/ansible-test-cloud-openshift/tasks/main.yml @@ -0,0 +1,6 @@ +- name: Verify endpoints respond + uri: + url: "{{ item }}" + validate_certs: no + with_items: + - https://openshift-origin:8443/ diff --git a/test/integration/targets/ansible-test-cloud-vcenter/aliases b/test/integration/targets/ansible-test-cloud-vcenter/aliases new file mode 100644 index 00000000..0cd8ad20 --- /dev/null +++ b/test/integration/targets/ansible-test-cloud-vcenter/aliases @@ -0,0 +1,3 @@ +cloud/vcenter +shippable/generic/group1 +context/controller diff --git a/test/integration/targets/ansible-test-cloud-vcenter/tasks/main.yml b/test/integration/targets/ansible-test-cloud-vcenter/tasks/main.yml new file mode 100644 index 00000000..49e5c16a --- /dev/null +++ b/test/integration/targets/ansible-test-cloud-vcenter/tasks/main.yml @@ -0,0 +1,6 @@ +- name: Verify endpoints respond + uri: + url: "{{ item }}" + validate_certs: no + with_items: + - http://{{ vcenter_hostname }}:5000/ # control endpoint for the simulator diff --git a/test/integration/targets/ansible-test-docker/aliases b/test/integration/targets/ansible-test-docker/aliases index d1284cf7..a862ab8b 100644 --- a/test/integration/targets/ansible-test-docker/aliases +++ b/test/integration/targets/ansible-test-docker/aliases @@ -1 +1,2 @@ shippable/generic/group1 # Runs in the default test container so access to tools like pwsh +context/controller diff --git a/test/integration/targets/ansible-test-docker/collection-tests/docker.sh b/test/integration/targets/ansible-test-docker/collection-tests/docker.sh index e0e34290..69372245 100755 --- a/test/integration/targets/ansible-test-docker/collection-tests/docker.sh +++ b/test/integration/targets/ansible-test-docker/collection-tests/docker.sh @@ -7,7 +7,7 @@ cd "${WORK_DIR}/ansible_collections/ns/col" # common args for all tests # because we are running in shippable/generic/ we are already in the default docker container -common=(--python "${ANSIBLE_TEST_PYTHON_VERSION}" --color --truncate 0 "${@}") +common=(--python "${ANSIBLE_TEST_PYTHON_VERSION}" --venv --venv-system-site-packages --color --truncate 0 "${@}") # prime the venv to work around issue with PyYAML detection in ansible-test ansible-test sanity "${common[@]}" --test ignores diff --git a/test/integration/targets/ansible-test/aliases b/test/integration/targets/ansible-test/aliases index f8e28c7e..13e01f0c 100644 --- a/test/integration/targets/ansible-test/aliases +++ b/test/integration/targets/ansible-test/aliases @@ -1,2 +1,2 @@ shippable/posix/group1 -skip/aix +context/controller diff --git a/test/integration/targets/ansible-test/ansible_collections/ns/col_constraints/tests/integration/targets/constraints/aliases b/test/integration/targets/ansible-test/ansible_collections/ns/col_constraints/tests/integration/targets/constraints/aliases new file mode 100644 index 00000000..1af1cf90 --- /dev/null +++ b/test/integration/targets/ansible-test/ansible_collections/ns/col_constraints/tests/integration/targets/constraints/aliases @@ -0,0 +1 @@ +context/controller diff --git a/test/integration/targets/ansible-test/collection-tests/coverage.sh b/test/integration/targets/ansible-test/collection-tests/coverage.sh index 033a9836..221ae66a 100755 --- a/test/integration/targets/ansible-test/collection-tests/coverage.sh +++ b/test/integration/targets/ansible-test/collection-tests/coverage.sh @@ -7,8 +7,8 @@ cd "${WORK_DIR}/ansible_collections/ns/col" # rename the sanity ignore file to match the current ansible version and update import ignores with the python version ansible_version="$(python -c 'import ansible.release; print(".".join(ansible.release.__version__.split(".")[:2]))')" -if [ "${ANSIBLE_TEST_PYTHON_VERSION}" == "2.6" ]; then - # Non-module/module_utils plugins are not checked on this remote-only Python versions +if [[ "${ANSIBLE_TEST_PYTHON_VERSION}" =~ ^2\. ]] || [[ "${ANSIBLE_TEST_PYTHON_VERSION}" =~ ^3\.[567] ]]; then + # Non-module/module_utils plugins are not checked on these remote-only Python versions sed "s/ import$/ import-${ANSIBLE_TEST_PYTHON_VERSION}/;" < "tests/sanity/ignore.txt" | grep -v 'plugins/[^m].* import' > "tests/sanity/ignore-${ansible_version}.txt" else sed "s/ import$/ import-${ANSIBLE_TEST_PYTHON_VERSION}/;" < "tests/sanity/ignore.txt" > "tests/sanity/ignore-${ansible_version}.txt" diff --git a/test/integration/targets/ansible-test/collection-tests/venv.sh b/test/integration/targets/ansible-test/collection-tests/venv.sh index ba0d2628..42dbfde4 100755 --- a/test/integration/targets/ansible-test/collection-tests/venv.sh +++ b/test/integration/targets/ansible-test/collection-tests/venv.sh @@ -7,8 +7,8 @@ cd "${WORK_DIR}/ansible_collections/ns/col" # rename the sanity ignore file to match the current ansible version and update import ignores with the python version ansible_version="$(python -c 'import ansible.release; print(".".join(ansible.release.__version__.split(".")[:2]))')" -if [ "${ANSIBLE_TEST_PYTHON_VERSION}" == "2.6" ]; then - # Non-module/module_utils plugins are not checked on this remote-only Python versions +if [[ "${ANSIBLE_TEST_PYTHON_VERSION}" =~ ^2\. ]] || [[ "${ANSIBLE_TEST_PYTHON_VERSION}" =~ ^3\.[567] ]]; then + # Non-module/module_utils plugins are not checked on these remote-only Python versions sed "s/ import$/ import-${ANSIBLE_TEST_PYTHON_VERSION}/;" < "tests/sanity/ignore.txt" | grep -v 'plugins/[^m].* import' > "tests/sanity/ignore-${ansible_version}.txt" else sed "s/ import$/ import-${ANSIBLE_TEST_PYTHON_VERSION}/;" < "tests/sanity/ignore.txt" > "tests/sanity/ignore-${ansible_version}.txt" diff --git a/test/integration/targets/pull/aliases b/test/integration/targets/ansible-vault/aliases index 757c9966..8278ec8b 100644 --- a/test/integration/targets/pull/aliases +++ b/test/integration/targets/ansible-vault/aliases @@ -1,2 +1,2 @@ shippable/posix/group3 -skip/aix +context/controller diff --git a/test/integration/targets/vault/empty-password b/test/integration/targets/ansible-vault/empty-password index e69de29b..e69de29b 100644 --- a/test/integration/targets/vault/empty-password +++ b/test/integration/targets/ansible-vault/empty-password diff --git a/test/integration/targets/vault/encrypted-vault-password b/test/integration/targets/ansible-vault/encrypted-vault-password index 7aa4e4be..7aa4e4be 100644 --- a/test/integration/targets/vault/encrypted-vault-password +++ b/test/integration/targets/ansible-vault/encrypted-vault-password diff --git a/test/integration/targets/vault/encrypted_file_encrypted_var_password b/test/integration/targets/ansible-vault/encrypted_file_encrypted_var_password index 57bc06e3..57bc06e3 100644 --- a/test/integration/targets/vault/encrypted_file_encrypted_var_password +++ b/test/integration/targets/ansible-vault/encrypted_file_encrypted_var_password diff --git a/test/integration/targets/vault/example1_password b/test/integration/targets/ansible-vault/example1_password index e723c8f9..e723c8f9 100644 --- a/test/integration/targets/vault/example1_password +++ b/test/integration/targets/ansible-vault/example1_password diff --git a/test/integration/targets/vault/example2_password b/test/integration/targets/ansible-vault/example2_password index 7b010f87..7b010f87 100644 --- a/test/integration/targets/vault/example2_password +++ b/test/integration/targets/ansible-vault/example2_password diff --git a/test/integration/targets/vault/example3_password b/test/integration/targets/ansible-vault/example3_password index f5bc5a8c..f5bc5a8c 100644 --- a/test/integration/targets/vault/example3_password +++ b/test/integration/targets/ansible-vault/example3_password diff --git a/test/integration/targets/vault/faux-editor.py b/test/integration/targets/ansible-vault/faux-editor.py index 68f62590..b67c7475 100755 --- a/test/integration/targets/vault/faux-editor.py +++ b/test/integration/targets/ansible-vault/faux-editor.py @@ -14,7 +14,7 @@ # along with Ansible. If not, see <http://www.gnu.org/licenses/>. # # ansible-vault is a script that encrypts/decrypts YAML files. See -# https://docs.ansible.com/playbooks_vault.html for more details. +# https://docs.ansible.com/ansible/latest/user_guide/vault.html for more details. from __future__ import (absolute_import, division, print_function) __metaclass__ = type diff --git a/test/integration/targets/vault/files/test_assemble/nonsecret.txt b/test/integration/targets/ansible-vault/files/test_assemble/nonsecret.txt index 320b6b4c..320b6b4c 100644 --- a/test/integration/targets/vault/files/test_assemble/nonsecret.txt +++ b/test/integration/targets/ansible-vault/files/test_assemble/nonsecret.txt diff --git a/test/integration/targets/vault/files/test_assemble/secret.vault b/test/integration/targets/ansible-vault/files/test_assemble/secret.vault index fd278564..fd278564 100644 --- a/test/integration/targets/vault/files/test_assemble/secret.vault +++ b/test/integration/targets/ansible-vault/files/test_assemble/secret.vault diff --git a/test/integration/targets/vault/format_1_1_AES256.yml b/test/integration/targets/ansible-vault/format_1_1_AES256.yml index 5616605e..5616605e 100644 --- a/test/integration/targets/vault/format_1_1_AES256.yml +++ b/test/integration/targets/ansible-vault/format_1_1_AES256.yml diff --git a/test/integration/targets/vault/format_1_2_AES256.yml b/test/integration/targets/ansible-vault/format_1_2_AES256.yml index 1e3795fb..1e3795fb 100644 --- a/test/integration/targets/vault/format_1_2_AES256.yml +++ b/test/integration/targets/ansible-vault/format_1_2_AES256.yml diff --git a/test/integration/targets/vault/host_vars/myhost.yml b/test/integration/targets/ansible-vault/host_vars/myhost.yml index 1434ec15..1434ec15 100644 --- a/test/integration/targets/vault/host_vars/myhost.yml +++ b/test/integration/targets/ansible-vault/host_vars/myhost.yml diff --git a/test/integration/targets/vault/host_vars/testhost.yml b/test/integration/targets/ansible-vault/host_vars/testhost.yml index b3e569ad..b3e569ad 100644 --- a/test/integration/targets/vault/host_vars/testhost.yml +++ b/test/integration/targets/ansible-vault/host_vars/testhost.yml diff --git a/test/integration/targets/vault/invalid_format/README.md b/test/integration/targets/ansible-vault/invalid_format/README.md index cbbc07a9..cbbc07a9 100644 --- a/test/integration/targets/vault/invalid_format/README.md +++ b/test/integration/targets/ansible-vault/invalid_format/README.md diff --git a/test/integration/targets/vault/invalid_format/broken-group-vars-tasks.yml b/test/integration/targets/ansible-vault/invalid_format/broken-group-vars-tasks.yml index 71dbacc0..71dbacc0 100644 --- a/test/integration/targets/vault/invalid_format/broken-group-vars-tasks.yml +++ b/test/integration/targets/ansible-vault/invalid_format/broken-group-vars-tasks.yml diff --git a/test/integration/targets/vault/invalid_format/broken-host-vars-tasks.yml b/test/integration/targets/ansible-vault/invalid_format/broken-host-vars-tasks.yml index 9afbd58e..9afbd58e 100644 --- a/test/integration/targets/vault/invalid_format/broken-host-vars-tasks.yml +++ b/test/integration/targets/ansible-vault/invalid_format/broken-host-vars-tasks.yml diff --git a/test/integration/targets/vault/invalid_format/group_vars/broken-group-vars.yml b/test/integration/targets/ansible-vault/invalid_format/group_vars/broken-group-vars.yml index 5f477431..5f477431 100644 --- a/test/integration/targets/vault/invalid_format/group_vars/broken-group-vars.yml +++ b/test/integration/targets/ansible-vault/invalid_format/group_vars/broken-group-vars.yml diff --git a/test/integration/targets/vault/invalid_format/host_vars/broken-host-vars.example.com/vars b/test/integration/targets/ansible-vault/invalid_format/host_vars/broken-host-vars.example.com/vars index 2d309eb5..2d309eb5 100644 --- a/test/integration/targets/vault/invalid_format/host_vars/broken-host-vars.example.com/vars +++ b/test/integration/targets/ansible-vault/invalid_format/host_vars/broken-host-vars.example.com/vars diff --git a/test/integration/targets/vault/invalid_format/inventory b/test/integration/targets/ansible-vault/invalid_format/inventory index e6e259a4..e6e259a4 100644 --- a/test/integration/targets/vault/invalid_format/inventory +++ b/test/integration/targets/ansible-vault/invalid_format/inventory diff --git a/test/integration/targets/vault/invalid_format/original-broken-host-vars b/test/integration/targets/ansible-vault/invalid_format/original-broken-host-vars index 6be696b5..6be696b5 100644 --- a/test/integration/targets/vault/invalid_format/original-broken-host-vars +++ b/test/integration/targets/ansible-vault/invalid_format/original-broken-host-vars diff --git a/test/integration/targets/vault/invalid_format/original-group-vars.yml b/test/integration/targets/ansible-vault/invalid_format/original-group-vars.yml index 817557be..817557be 100644 --- a/test/integration/targets/vault/invalid_format/original-group-vars.yml +++ b/test/integration/targets/ansible-vault/invalid_format/original-group-vars.yml diff --git a/test/integration/targets/vault/invalid_format/some-vars b/test/integration/targets/ansible-vault/invalid_format/some-vars index e841a262..e841a262 100644 --- a/test/integration/targets/vault/invalid_format/some-vars +++ b/test/integration/targets/ansible-vault/invalid_format/some-vars diff --git a/test/integration/targets/vault/invalid_format/vault-secret b/test/integration/targets/ansible-vault/invalid_format/vault-secret index 4406e35c..4406e35c 100644 --- a/test/integration/targets/vault/invalid_format/vault-secret +++ b/test/integration/targets/ansible-vault/invalid_format/vault-secret diff --git a/test/integration/targets/vault/inventory.toml b/test/integration/targets/ansible-vault/inventory.toml index d97ed398..d97ed398 100644 --- a/test/integration/targets/vault/inventory.toml +++ b/test/integration/targets/ansible-vault/inventory.toml diff --git a/test/integration/targets/vault/password-script.py b/test/integration/targets/ansible-vault/password-script.py index c47fdfb9..1b7f02be 100755 --- a/test/integration/targets/vault/password-script.py +++ b/test/integration/targets/ansible-vault/password-script.py @@ -14,7 +14,7 @@ # along with Ansible. If not, see <http://www.gnu.org/licenses/>. # # ansible-vault is a script that encrypts/decrypts YAML files. See -# https://docs.ansible.com/playbooks_vault.html for more details. +# https://docs.ansible.com/ansible/latest/user_guide/vault.html for more details. from __future__ import (absolute_import, division, print_function) __metaclass__ = type diff --git a/test/integration/targets/vault/roles/test_vault/tasks/main.yml b/test/integration/targets/ansible-vault/roles/test_vault/tasks/main.yml index 4e5551d9..4e5551d9 100644 --- a/test/integration/targets/vault/roles/test_vault/tasks/main.yml +++ b/test/integration/targets/ansible-vault/roles/test_vault/tasks/main.yml diff --git a/test/integration/targets/vault/roles/test_vault/vars/main.yml b/test/integration/targets/ansible-vault/roles/test_vault/vars/main.yml index cfac107a..cfac107a 100644 --- a/test/integration/targets/vault/roles/test_vault/vars/main.yml +++ b/test/integration/targets/ansible-vault/roles/test_vault/vars/main.yml diff --git a/test/integration/targets/vault/roles/test_vault_embedded/tasks/main.yml b/test/integration/targets/ansible-vault/roles/test_vault_embedded/tasks/main.yml index eba93896..eba93896 100644 --- a/test/integration/targets/vault/roles/test_vault_embedded/tasks/main.yml +++ b/test/integration/targets/ansible-vault/roles/test_vault_embedded/tasks/main.yml diff --git a/test/integration/targets/vault/roles/test_vault_embedded/vars/main.yml b/test/integration/targets/ansible-vault/roles/test_vault_embedded/vars/main.yml index 54e6004f..54e6004f 100644 --- a/test/integration/targets/vault/roles/test_vault_embedded/vars/main.yml +++ b/test/integration/targets/ansible-vault/roles/test_vault_embedded/vars/main.yml diff --git a/test/integration/targets/vault/roles/test_vault_embedded_ids/tasks/main.yml b/test/integration/targets/ansible-vault/roles/test_vault_embedded_ids/tasks/main.yml index 9aeaf240..9aeaf240 100644 --- a/test/integration/targets/vault/roles/test_vault_embedded_ids/tasks/main.yml +++ b/test/integration/targets/ansible-vault/roles/test_vault_embedded_ids/tasks/main.yml diff --git a/test/integration/targets/vault/roles/test_vault_embedded_ids/vars/main.yml b/test/integration/targets/ansible-vault/roles/test_vault_embedded_ids/vars/main.yml index 9c8fa4b2..9c8fa4b2 100644 --- a/test/integration/targets/vault/roles/test_vault_embedded_ids/vars/main.yml +++ b/test/integration/targets/ansible-vault/roles/test_vault_embedded_ids/vars/main.yml diff --git a/test/integration/targets/vault/roles/test_vault_file_encrypted_embedded/README.md b/test/integration/targets/ansible-vault/roles/test_vault_file_encrypted_embedded/README.md index 4a75cece..4a75cece 100644 --- a/test/integration/targets/vault/roles/test_vault_file_encrypted_embedded/README.md +++ b/test/integration/targets/ansible-vault/roles/test_vault_file_encrypted_embedded/README.md diff --git a/test/integration/targets/vault/roles/test_vault_file_encrypted_embedded/tasks/main.yml b/test/integration/targets/ansible-vault/roles/test_vault_file_encrypted_embedded/tasks/main.yml index e09004a1..e09004a1 100644 --- a/test/integration/targets/vault/roles/test_vault_file_encrypted_embedded/tasks/main.yml +++ b/test/integration/targets/ansible-vault/roles/test_vault_file_encrypted_embedded/tasks/main.yml diff --git a/test/integration/targets/vault/roles/test_vault_file_encrypted_embedded/vars/main.yml b/test/integration/targets/ansible-vault/roles/test_vault_file_encrypted_embedded/vars/main.yml index 89cc4a0f..89cc4a0f 100644 --- a/test/integration/targets/vault/roles/test_vault_file_encrypted_embedded/vars/main.yml +++ b/test/integration/targets/ansible-vault/roles/test_vault_file_encrypted_embedded/vars/main.yml diff --git a/test/integration/targets/vault/roles/test_vaulted_template/tasks/main.yml b/test/integration/targets/ansible-vault/roles/test_vaulted_template/tasks/main.yml index b4af5efc..b4af5efc 100644 --- a/test/integration/targets/vault/roles/test_vaulted_template/tasks/main.yml +++ b/test/integration/targets/ansible-vault/roles/test_vaulted_template/tasks/main.yml diff --git a/test/integration/targets/vault/roles/test_vaulted_template/templates/vaulted_template.j2 b/test/integration/targets/ansible-vault/roles/test_vaulted_template/templates/vaulted_template.j2 index af9c3eb1..af9c3eb1 100644 --- a/test/integration/targets/vault/roles/test_vaulted_template/templates/vaulted_template.j2 +++ b/test/integration/targets/ansible-vault/roles/test_vaulted_template/templates/vaulted_template.j2 diff --git a/test/integration/targets/vault/runme.sh b/test/integration/targets/ansible-vault/runme.sh index e3b21d7f..e3b21d7f 100755 --- a/test/integration/targets/vault/runme.sh +++ b/test/integration/targets/ansible-vault/runme.sh diff --git a/test/integration/targets/vault/single_vault_as_string.yml b/test/integration/targets/ansible-vault/single_vault_as_string.yml index 1eb17d04..ca147b0b 100644 --- a/test/integration/targets/vault/single_vault_as_string.yml +++ b/test/integration/targets/ansible-vault/single_vault_as_string.yml @@ -27,7 +27,7 @@ - vaulted_value|forceescape == 'foo bar' - vaulted_value|first == 'f' - "'%s'|format(vaulted_value) == 'foo bar'" - - vaulted_value|indent(indentfirst=True) == ' foo bar' + - vaulted_value|indent(first=True) == ' foo bar' - vaulted_value.split() == ['foo', 'bar'] - vaulted_value|join('-') == 'f-o-o- -b-a-r' - vaulted_value|last == 'r' diff --git a/test/integration/targets/vault/test-vault-client.py b/test/integration/targets/ansible-vault/test-vault-client.py index ee461887..ee461887 100755 --- a/test/integration/targets/vault/test-vault-client.py +++ b/test/integration/targets/ansible-vault/test-vault-client.py diff --git a/test/integration/targets/vault/test_dangling_temp.yml b/test/integration/targets/ansible-vault/test_dangling_temp.yml index 71a9d73a..71a9d73a 100644 --- a/test/integration/targets/vault/test_dangling_temp.yml +++ b/test/integration/targets/ansible-vault/test_dangling_temp.yml diff --git a/test/integration/targets/vault/test_utf8_value_in_filename.yml b/test/integration/targets/ansible-vault/test_utf8_value_in_filename.yml index 9bd394dc..9bd394dc 100644 --- a/test/integration/targets/vault/test_utf8_value_in_filename.yml +++ b/test/integration/targets/ansible-vault/test_utf8_value_in_filename.yml diff --git a/test/integration/targets/vault/test_vault.yml b/test/integration/targets/ansible-vault/test_vault.yml index 7f8ed115..7f8ed115 100644 --- a/test/integration/targets/vault/test_vault.yml +++ b/test/integration/targets/ansible-vault/test_vault.yml diff --git a/test/integration/targets/vault/test_vault_embedded.yml b/test/integration/targets/ansible-vault/test_vault_embedded.yml index ee9739f8..ee9739f8 100644 --- a/test/integration/targets/vault/test_vault_embedded.yml +++ b/test/integration/targets/ansible-vault/test_vault_embedded.yml diff --git a/test/integration/targets/vault/test_vault_embedded_ids.yml b/test/integration/targets/ansible-vault/test_vault_embedded_ids.yml index 23ebbb96..23ebbb96 100644 --- a/test/integration/targets/vault/test_vault_embedded_ids.yml +++ b/test/integration/targets/ansible-vault/test_vault_embedded_ids.yml diff --git a/test/integration/targets/vault/test_vault_file_encrypted_embedded.yml b/test/integration/targets/ansible-vault/test_vault_file_encrypted_embedded.yml index 685d20ef..685d20ef 100644 --- a/test/integration/targets/vault/test_vault_file_encrypted_embedded.yml +++ b/test/integration/targets/ansible-vault/test_vault_file_encrypted_embedded.yml diff --git a/test/integration/targets/vault/test_vaulted_inventory.yml b/test/integration/targets/ansible-vault/test_vaulted_inventory.yml index 06b6582b..06b6582b 100644 --- a/test/integration/targets/vault/test_vaulted_inventory.yml +++ b/test/integration/targets/ansible-vault/test_vaulted_inventory.yml diff --git a/test/integration/targets/vault/test_vaulted_inventory_toml.yml b/test/integration/targets/ansible-vault/test_vaulted_inventory_toml.yml index f6e2c5d6..f6e2c5d6 100644 --- a/test/integration/targets/vault/test_vaulted_inventory_toml.yml +++ b/test/integration/targets/ansible-vault/test_vaulted_inventory_toml.yml diff --git a/test/integration/targets/vault/test_vaulted_template.yml b/test/integration/targets/ansible-vault/test_vaulted_template.yml index b495211d..b495211d 100644 --- a/test/integration/targets/vault/test_vaulted_template.yml +++ b/test/integration/targets/ansible-vault/test_vaulted_template.yml diff --git a/test/integration/targets/vault/test_vaulted_utf8_value.yml b/test/integration/targets/ansible-vault/test_vaulted_utf8_value.yml index 63b602b1..63b602b1 100644 --- a/test/integration/targets/vault/test_vaulted_utf8_value.yml +++ b/test/integration/targets/ansible-vault/test_vaulted_utf8_value.yml diff --git a/test/integration/targets/vault/vault-café.yml b/test/integration/targets/ansible-vault/vault-café.yml index 0d179aec..0d179aec 100644 --- a/test/integration/targets/vault/vault-café.yml +++ b/test/integration/targets/ansible-vault/vault-café.yml diff --git a/test/integration/targets/vault/vault-password b/test/integration/targets/ansible-vault/vault-password index 96973929..96973929 100644 --- a/test/integration/targets/vault/vault-password +++ b/test/integration/targets/ansible-vault/vault-password diff --git a/test/integration/targets/vault/vault-password-ansible b/test/integration/targets/ansible-vault/vault-password-ansible index 90d40550..90d40550 100644 --- a/test/integration/targets/vault/vault-password-ansible +++ b/test/integration/targets/ansible-vault/vault-password-ansible diff --git a/test/integration/targets/vault/vault-password-wrong b/test/integration/targets/ansible-vault/vault-password-wrong index 50e2efad..50e2efad 100644 --- a/test/integration/targets/vault/vault-password-wrong +++ b/test/integration/targets/ansible-vault/vault-password-wrong diff --git a/test/integration/targets/vault/vault-secret.txt b/test/integration/targets/ansible-vault/vault-secret.txt index b6bc9bfb..b6bc9bfb 100644 --- a/test/integration/targets/vault/vault-secret.txt +++ b/test/integration/targets/ansible-vault/vault-secret.txt diff --git a/test/integration/targets/vault/vaulted.inventory b/test/integration/targets/ansible-vault/vaulted.inventory index 1ed258b6..1ed258b6 100644 --- a/test/integration/targets/vault/vaulted.inventory +++ b/test/integration/targets/ansible-vault/vaulted.inventory diff --git a/test/integration/targets/ansible/aliases b/test/integration/targets/ansible/aliases index f71c8117..498fedd5 100644 --- a/test/integration/targets/ansible/aliases +++ b/test/integration/targets/ansible/aliases @@ -1,2 +1,2 @@ shippable/posix/group4 -skip/aix +context/controller diff --git a/test/integration/targets/ansible/module_common_regex_regression.sh b/test/integration/targets/ansible/module_common_regex_regression.sh new file mode 100755 index 00000000..4869f4f0 --- /dev/null +++ b/test/integration/targets/ansible/module_common_regex_regression.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +# #74270 -- ensure we escape directory names before passing to re.compile() +# particularly in module_common. + +set -eux + +lib_path=$(python -c 'import os, ansible; print(os.path.dirname(os.path.dirname(ansible.__file__)))') +bad_dir="${OUTPUT_DIR}/ansi[ble" + +mkdir "${bad_dir}" +cp -a "${lib_path}" "${bad_dir}" + +PYTHONPATH="${bad_dir}/lib" ansible -m ping localhost -i ../../inventory "$@" +rm -rf "${bad_dir}" diff --git a/test/integration/targets/ansible/runme.sh b/test/integration/targets/ansible/runme.sh index fc79e33e..e9e72a9f 100755 --- a/test/integration/targets/ansible/runme.sh +++ b/test/integration/targets/ansible/runme.sh @@ -80,3 +80,7 @@ if ansible-playbook -i ../../inventory --extra-vars ./vars.yml playbook.yml; the fi ansible-playbook -i ../../inventory --extra-vars @./vars.yml playbook.yml + +# #74270 -- ensure we escape directory names before passing to re.compile() +# particularly in module_common. +bash module_common_regex_regression.sh diff --git a/test/integration/targets/any_errors_fatal/18602.yml b/test/integration/targets/any_errors_fatal/18602.yml deleted file mode 100644 index 66bcb88b..00000000 --- a/test/integration/targets/any_errors_fatal/18602.yml +++ /dev/null @@ -1,21 +0,0 @@ ---- - - hosts: localhost - any_errors_fatal: true - tasks: - - block: - - debug: msg='i execute normally' - - name: EXPECTED FAILURE primary block command - command: /bin/false - - debug: msg='i never execute, cause ERROR!' - rescue: - - name: rescue block debug - debug: msg='I caught an error' - - name: EXPECTED FAILURE rescue block command - command: /bin/false - - debug: msg='I also never execute :-(' - always: - - name: A debug task in the always block - debug: msg="this always executes" - - - set_fact: - always_ran: true diff --git a/test/integration/targets/any_errors_fatal/aliases b/test/integration/targets/any_errors_fatal/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/any_errors_fatal/aliases +++ b/test/integration/targets/any_errors_fatal/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/any_errors_fatal/on_includes.yml b/test/integration/targets/any_errors_fatal/on_includes.yml index 981d9f46..cbc51cb2 100644 --- a/test/integration/targets/any_errors_fatal/on_includes.yml +++ b/test/integration/targets/any_errors_fatal/on_includes.yml @@ -4,4 +4,4 @@ hosts: testhost,testhost2 any_errors_fatal: True tasks: - - include: test_fatal.yml + - import_tasks: test_fatal.yml diff --git a/test/integration/targets/apt/tasks/downgrade.yml b/test/integration/targets/apt/tasks/downgrade.yml new file mode 100644 index 00000000..896b644d --- /dev/null +++ b/test/integration/targets/apt/tasks/downgrade.yml @@ -0,0 +1,77 @@ +- block: + - name: Disable ubuntu repos so system packages are not upgraded and do not change testing env + command: mv /etc/apt/sources.list /etc/apt/sources.list.backup + + - name: install latest foo + apt: + name: foo + state: latest + allow_unauthenticated: yes + + - name: check foo version + shell: dpkg -s foo | grep Version | awk '{print $2}' + register: apt_downgrade_foo_version + + - name: ensure the correct version of foo has been installed + assert: + that: + - "'1.0.1' in apt_downgrade_foo_version.stdout" + + - name: try to downgrade foo + apt: + name: foo=1.0.0 + state: present + allow_unauthenticated: yes + ignore_errors: yes + register: apt_downgrade_foo_fail + + - name: verify failure of downgrading without allow downgrade flag + assert: + that: + - apt_downgrade_foo_fail is failed + + - name: try to downgrade foo with flag + apt: + name: foo=1.0.0 + state: present + allow_downgrade: yes + allow_unauthenticated: yes + register: apt_downgrade_foo_succeed + + - name: verify success of downgrading with allow downgrade flag + assert: + that: + - apt_downgrade_foo_succeed is success + + - name: check foo version + shell: dpkg -s foo | grep Version | awk '{print $2}' + register: apt_downgrade_foo_version + + - name: check that version downgraded correctly + assert: + that: + - "'1.0.0' in apt_downgrade_foo_version.stdout" + - "{{ apt_downgrade_foo_version.changed }}" + + - name: downgrade foo with flag again + apt: + name: foo=1.0.0 + state: present + allow_downgrade: yes + allow_unauthenticated: yes + register: apt_downgrade_second_downgrade + + - name: check that nothing has changed (idempotent) + assert: + that: + - "apt_downgrade_second_downgrade.changed == false" + + always: + - name: Clean up + apt: + pkg: foo,foobar + state: absent + autoclean: yes + + - name: Restore ubuntu repos + command: mv /etc/apt/sources.list.backup /etc/apt/sources.list diff --git a/test/integration/targets/apt/tasks/repo.yml b/test/integration/targets/apt/tasks/repo.yml index e1863f38..8269452a 100644 --- a/test/integration/targets/apt/tasks/repo.yml +++ b/test/integration/targets/apt/tasks/repo.yml @@ -210,6 +210,8 @@ - name: Restore ubuntu repos command: mv /etc/apt/sources.list.backup /etc/apt/sources.list +- name: Downgrades + import_tasks: "downgrade.yml" - name: Upgrades block: @@ -263,3 +265,26 @@ state: absent when: - aptitude_status.stdout.find('ii') == -1 + +- block: + - name: Install the foo package with diff=yes + apt: + name: foo + allow_unauthenticated: yes + diff: yes + register: apt_result + + - debug: + var: apt_result + + - name: Check the content of diff.prepared + assert: + that: + - apt_result is success + - "'The following NEW packages will be installed:\n foo' in apt_result.diff.prepared" + always: + - name: Clean up + apt: + name: foo + state: absent + allow_unauthenticated: yes diff --git a/test/integration/targets/args/aliases b/test/integration/targets/args/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/args/aliases +++ b/test/integration/targets/args/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/argspec/aliases b/test/integration/targets/argspec/aliases index 70a7b7a9..1d28bdb2 100644 --- a/test/integration/targets/argspec/aliases +++ b/test/integration/targets/argspec/aliases @@ -1 +1,2 @@ shippable/posix/group5 +context/controller diff --git a/test/integration/targets/assert/aliases b/test/integration/targets/assert/aliases index 757c9966..10179323 100644 --- a/test/integration/targets/assert/aliases +++ b/test/integration/targets/assert/aliases @@ -1,2 +1,2 @@ shippable/posix/group3 -skip/aix +context/controller # this is a controller-only action, the module is just for documentation diff --git a/test/integration/targets/async/tasks/main.yml b/test/integration/targets/async/tasks/main.yml index c8c12f6d..05c789e6 100644 --- a/test/integration/targets/async/tasks/main.yml +++ b/test/integration/targets/async/tasks/main.yml @@ -244,26 +244,6 @@ path: '{{ custom_async_tmp }}' state: absent - - name: run async task with custom dir - deprecated format - command: sleep 1 - register: async_custom_dir_dep - async: 5 - poll: 1 - environment: - ANSIBLE_ASYNC_DIR: '{{ custom_async_tmp }}' - - - name: check if the async temp dir is created - deprecated format - stat: - path: '{{ custom_async_tmp }}' - register: async_custom_dir_dep_result - - - name: assert run async task with custom dir - deprecated format - assert: - that: - - async_custom_dir_dep is successful - - async_custom_dir_dep is finished - - async_custom_dir_dep_result.stat.exists - - name: remove custom async dir after deprecation test file: path: '{{ custom_async_tmp }}' @@ -290,13 +270,6 @@ vars: ansible_async_dir: '{{ custom_async_tmp }}' - - name: get async status with custom dir - deprecated format - async_status: - jid: '{{ async_fandf_custom_dir.ansible_job_id }}' - register: async_fandf_custom_dir_dep_result - environment: - ANSIBLE_ASYNC_DIR: '{{ custom_async_tmp }}' - - name: assert run fire and forget async task with custom dir assert: that: @@ -304,7 +277,6 @@ - async_fandf_custom_dir_fail is failed - async_fandf_custom_dir_fail.msg == "could not find job" - async_fandf_custom_dir_result is successful - - async_fandf_custom_dir_dep_result is successful always: - name: remove custom tmp dir after test @@ -320,6 +292,7 @@ - name: run async poll callback test playbook command: ansible-playbook {{ role_path }}/callback_test.yml + delegate_to: localhost register: callback_output - assert: diff --git a/test/integration/targets/async_extra_data/aliases b/test/integration/targets/async_extra_data/aliases index 70a7b7a9..7bd941e6 100644 --- a/test/integration/targets/async_extra_data/aliases +++ b/test/integration/targets/async_extra_data/aliases @@ -1 +1,2 @@ shippable/posix/group5 +context/target diff --git a/test/integration/targets/become/aliases b/test/integration/targets/become/aliases index 3a07aab3..ad691e7d 100644 --- a/test/integration/targets/become/aliases +++ b/test/integration/targets/become/aliases @@ -1,3 +1,4 @@ destructive shippable/posix/group1 skip/aix +context/target diff --git a/test/integration/targets/become/tasks/main.yml b/test/integration/targets/become/tasks/main.yml index 3feb5cc7..b4c7b601 100644 --- a/test/integration/targets/become/tasks/main.yml +++ b/test/integration/targets/become/tasks/main.yml @@ -1,5 +1,5 @@ - include_vars: default.yml -- include: default.yml -- include: sudo.yml -- include: su.yml +- import_tasks: default.yml +- import_tasks: sudo.yml +- import_tasks: su.yml diff --git a/test/integration/targets/become_su/aliases b/test/integration/targets/become_su/aliases index 3a07aab3..f3e45b5e 100644 --- a/test/integration/targets/become_su/aliases +++ b/test/integration/targets/become_su/aliases @@ -1,3 +1,3 @@ destructive shippable/posix/group1 -skip/aix +context/controller diff --git a/test/integration/targets/become_unprivileged/aliases b/test/integration/targets/become_unprivileged/aliases index c96617f6..c97d2f98 100644 --- a/test/integration/targets/become_unprivileged/aliases +++ b/test/integration/targets/become_unprivileged/aliases @@ -1,5 +1,5 @@ destructive shippable/posix/group1 -skip/aix needs/ssh needs/root +context/controller diff --git a/test/integration/targets/binary/aliases b/test/integration/targets/binary/aliases index 765b70da..6452e6d4 100644 --- a/test/integration/targets/binary/aliases +++ b/test/integration/targets/binary/aliases @@ -1 +1,2 @@ shippable/posix/group2 +context/target diff --git a/test/integration/targets/binary_modules_posix/aliases b/test/integration/targets/binary_modules_posix/aliases index 2c6e4a07..2cfe7ea8 100644 --- a/test/integration/targets/binary_modules_posix/aliases +++ b/test/integration/targets/binary_modules_posix/aliases @@ -1,2 +1,3 @@ shippable/posix/group3 needs/target/binary_modules +context/target diff --git a/test/integration/targets/blocks/aliases b/test/integration/targets/blocks/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/blocks/aliases +++ b/test/integration/targets/blocks/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/blocks/main.yml b/test/integration/targets/blocks/main.yml index 012d5ab2..efe358a3 100644 --- a/test/integration/targets/blocks/main.yml +++ b/test/integration/targets/blocks/main.yml @@ -96,8 +96,8 @@ tasks: - block: - name: include fail.yml in tasks - include: fail.yml - args: + import_tasks: fail.yml + vars: msg: "failed from tasks" - name: tasks flag should not be set after failure set_fact: @@ -106,8 +106,8 @@ - set_fact: rescue_run_after_include_fail: true - name: include fail.yml in rescue - include: fail.yml - args: + import_tasks: fail.yml + vars: msg: "failed from rescue" - name: flag should not be set after failure in rescue set_fact: diff --git a/test/integration/targets/blocks/nested_fail.yml b/test/integration/targets/blocks/nested_fail.yml index 31ae870e..12e33cb4 100644 --- a/test/integration/targets/blocks/nested_fail.yml +++ b/test/integration/targets/blocks/nested_fail.yml @@ -1,3 +1,3 @@ -- include: fail.yml - args: +- import_tasks: fail.yml + vars: msg: "nested {{msg}}" diff --git a/test/integration/targets/blocks/nested_nested_fail.yml b/test/integration/targets/blocks/nested_nested_fail.yml index e9a050fb..f63fa5ce 100644 --- a/test/integration/targets/blocks/nested_nested_fail.yml +++ b/test/integration/targets/blocks/nested_nested_fail.yml @@ -1,3 +1,3 @@ -- include: nested_fail.yml - args: +- import_tasks: nested_fail.yml + vars: msg: "nested {{msg}}" diff --git a/test/integration/targets/builtin_vars_prompt/aliases b/test/integration/targets/builtin_vars_prompt/aliases index 4317d112..4b94ea15 100644 --- a/test/integration/targets/builtin_vars_prompt/aliases +++ b/test/integration/targets/builtin_vars_prompt/aliases @@ -1,3 +1,4 @@ setup/always/setup_passlib setup/always/setup_pexpect shippable/posix/group4 +context/controller diff --git a/test/integration/targets/callback_default/aliases b/test/integration/targets/callback_default/aliases index f8e28c7e..a6dafcf8 100644 --- a/test/integration/targets/callback_default/aliases +++ b/test/integration/targets/callback_default/aliases @@ -1,2 +1 @@ shippable/posix/group1 -skip/aix diff --git a/test/integration/targets/callback_default/runme.sh b/test/integration/targets/callback_default/runme.sh index b5c98ef7..f9b60b6b 100755 --- a/test/integration/targets/callback_default/runme.sh +++ b/test/integration/targets/callback_default/runme.sh @@ -125,6 +125,13 @@ export ANSIBLE_CHECK_MODE_MARKERS=0 run_test default +# Check for async output +# NOTE: regex to match 1 or more digits works for both BSD and GNU grep +ansible-playbook -i inventory test_async.yml 2>&1 | tee async_test.out +grep "ASYNC OK .* jid=[0-9]\{1,\}" async_test.out +grep "ASYNC FAILED .* jid=[0-9]\{1,\}" async_test.out +rm -f async_test.out + # Hide skipped export ANSIBLE_DISPLAY_SKIPPED_HOSTS=0 diff --git a/test/integration/targets/callback_default/test_async.yml b/test/integration/targets/callback_default/test_async.yml new file mode 100644 index 00000000..57294a4c --- /dev/null +++ b/test/integration/targets/callback_default/test_async.yml @@ -0,0 +1,14 @@ +--- +- hosts: testhost + gather_facts: no + tasks: + - name: test success async output + command: sleep 1 + async: 10 + poll: 1 + + - name: test failure async output + command: sleep 10 + async: 1 + poll: 1 + ignore_errors: yes diff --git a/test/integration/targets/changed_when/aliases b/test/integration/targets/changed_when/aliases index 765b70da..90ea9e12 100644 --- a/test/integration/targets/changed_when/aliases +++ b/test/integration/targets/changed_when/aliases @@ -1 +1,2 @@ shippable/posix/group2 +context/controller diff --git a/test/integration/targets/changed_when/tasks/main.yml b/test/integration/targets/changed_when/tasks/main.yml index 7b997189..4f0a8747 100644 --- a/test/integration/targets/changed_when/tasks/main.yml +++ b/test/integration/targets/changed_when/tasks/main.yml @@ -59,3 +59,15 @@ assert: that: - groupby is not changed + +- name: invalid conditional + command: echo foo + changed_when: boomboomboom + register: invalid_conditional + ignore_errors: true + +- assert: + that: + - invalid_conditional is failed + - invalid_conditional.stdout is defined + - invalid_conditional.changed_when_result is contains('boomboomboom') diff --git a/test/integration/targets/check_mode/aliases b/test/integration/targets/check_mode/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/check_mode/aliases +++ b/test/integration/targets/check_mode/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/cli/aliases b/test/integration/targets/cli/aliases index a8816e11..c73d4253 100644 --- a/test/integration/targets/cli/aliases +++ b/test/integration/targets/cli/aliases @@ -3,3 +3,4 @@ needs/root needs/ssh needs/target/setup_pexpect shippable/posix/group3 +context/controller diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/MyCSMUOptional.cs b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/MyCSMUOptional.cs new file mode 100644 index 00000000..0a3e758c --- /dev/null +++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/MyCSMUOptional.cs @@ -0,0 +1,19 @@ +using System; + +using ansible_collections.testns.testcoll.plugins.module_utils.AnotherCSMU; +using ansible_collections.testns.testcoll.plugins.module_utils.subpkg.subcs; + +//TypeAccelerator -Name MyCSMU -TypeName CustomThing + +namespace ansible_collections.testns.testcoll.plugins.module_utils.MyCSMU +{ + public class CustomThing + { + public static string HelloWorld() + { + string res1 = AnotherThing.CallMe(); + string res2 = NestedUtil.HelloWorld(); + return String.Format("Hello from user_mu collection-hosted MyCSMUOptional, also {0} and {1}", res1, res2); + } + } +} diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/MyPSMUOptional.psm1 b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/MyPSMUOptional.psm1 new file mode 100644 index 00000000..1e361598 --- /dev/null +++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/MyPSMUOptional.psm1 @@ -0,0 +1,16 @@ +#AnsibleRequires -CSharpUtil Ansible.Invalid -Optional +#AnsibleRequires -Powershell Ansible.ModuleUtils.Invalid -Optional +#AnsibleRequires -CSharpUtil ansible_collections.testns.testcoll.plugins.module_utils.invalid -Optional +#AnsibleRequires -CSharpUtil ansible_collections.testns.testcoll.plugins.module_utils.invalid.invalid -Optional +#AnsibleRequires -Powershell ansible_collections.testns.testcoll.plugins.module_utils.invalid -Optional +#AnsibleRequires -Powershell ansible_collections.testns.testcoll.plugins.module_utils.invalid.invalid -Optional + +Function Invoke-FromUserPSMU { + <# + .SYNOPSIS + Test function + #> + return "from optional user_mu" +} + +Export-ModuleMember -Function Invoke-FromUserPSMU diff --git a/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_uses_optional.ps1 b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_uses_optional.ps1 new file mode 100644 index 00000000..c44dcfea --- /dev/null +++ b/test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_uses_optional.ps1 @@ -0,0 +1,33 @@ +#!powershell + +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# Test builtin C# still works with -Optional +#AnsibleRequires -CSharpUtil Ansible.Basic -Optional + +# Test no failure when importing an invalid builtin C# and pwsh util with -Optional +#AnsibleRequires -CSharpUtil Ansible.Invalid -Optional +#AnsibleRequires -PowerShell Ansible.ModuleUtils.Invalid -Optional + +# Test valid module_util still works with -Optional +#AnsibleRequires -CSharpUtil ansible_collections.testns.testcoll.plugins.module_utils.MyCSMUOptional -Optional +#AnsibleRequires -Powershell ansible_collections.testns.testcoll.plugins.module_utils.MyPSMUOptional -Optional + +# Test no failure when importing an invalid collection C# and pwsh util with -Optional +#AnsibleRequires -CSharpUtil ansible_collections.testns.testcoll.plugins.module_utils.invalid -Optional +#AnsibleRequires -CSharpUtil ansible_collections.testns.testcoll.plugins.module_utils.invalid.invalid -Optional +#AnsibleRequires -Powershell ansible_collections.testns.testcoll.plugins.module_utils.invalid -Optional +#AnsibleRequires -Powershell ansible_collections.testns.testcoll.plugins.module_utils.invalid.invalid -Optional + +$spec = @{ + options = @{ + data = @{ type = "str"; default = "called $(Invoke-FromUserPSMU)" } + } + supports_check_mode = $true +} +$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec) + +$module.Result.data = $module.Params.data +$module.Result.csharp = [MyCSMU]::HelloWorld() + +$module.ExitJson() diff --git a/test/integration/targets/collections/runme.sh b/test/integration/targets/collections/runme.sh index 1e9584ff..5a5261bb 100755 --- a/test/integration/targets/collections/runme.sh +++ b/test/integration/targets/collections/runme.sh @@ -8,10 +8,6 @@ export ANSIBLE_GATHER_SUBSET=minimal export ANSIBLE_HOST_PATTERN_MISMATCH=error unset ANSIBLE_COLLECTIONS_ON_ANSIBLE_VERSION_MISMATCH -# FUTURE: just use INVENTORY_PATH as-is once ansible-test sets the right dir -ipath=../../$(basename "${INVENTORY_PATH:-../../inventory}") -export INVENTORY_PATH="$ipath" - # ensure we can call collection module ansible localhost -m testns.testcoll.testmodule @@ -137,3 +133,5 @@ if [[ "$(grep -wc "dynamic_host_a" "$CACHEFILE")" -ne "0" ]]; then fi ./vars_plugin_tests.sh + +./test_task_resolved_plugin.sh diff --git a/test/integration/targets/collections/test_task_resolved_plugin.sh b/test/integration/targets/collections/test_task_resolved_plugin.sh new file mode 100755 index 00000000..444b4f11 --- /dev/null +++ b/test/integration/targets/collections/test_task_resolved_plugin.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash + +set -eux + +export ANSIBLE_CALLBACKS_ENABLED=display_resolved_action + +ansible-playbook test_task_resolved_plugin/unqualified.yml "$@" | tee out.txt +action_resolution=( + "legacy_action == legacy_action" + "legacy_module == legacy_module" + "debug == ansible.builtin.debug" + "ping == ansible.builtin.ping" +) +for result in "${action_resolution[@]}"; do + grep -q out.txt -e "$result" +done + +ansible-playbook test_task_resolved_plugin/unqualified_and_collections_kw.yml "$@" | tee out.txt +action_resolution=( + "legacy_action == legacy_action" + "legacy_module == legacy_module" + "debug == ansible.builtin.debug" + "ping == ansible.builtin.ping" + "collection_action == test_ns.test_coll.collection_action" + "collection_module == test_ns.test_coll.collection_module" + "formerly_action == test_ns.test_coll.collection_action" + "formerly_module == test_ns.test_coll.collection_module" +) +for result in "${action_resolution[@]}"; do + grep -q out.txt -e "$result" +done + +ansible-playbook test_task_resolved_plugin/fqcn.yml "$@" | tee out.txt +action_resolution=( + "ansible.legacy.legacy_action == legacy_action" + "ansible.legacy.legacy_module == legacy_module" + "ansible.legacy.debug == ansible.builtin.debug" + "ansible.legacy.ping == ansible.builtin.ping" + "ansible.builtin.debug == ansible.builtin.debug" + "ansible.builtin.ping == ansible.builtin.ping" + "test_ns.test_coll.collection_action == test_ns.test_coll.collection_action" + "test_ns.test_coll.collection_module == test_ns.test_coll.collection_module" + "test_ns.test_coll.formerly_action == test_ns.test_coll.collection_action" + "test_ns.test_coll.formerly_module == test_ns.test_coll.collection_module" +) +for result in "${action_resolution[@]}"; do + grep -q out.txt -e "$result" +done diff --git a/test/integration/targets/collections/test_task_resolved_plugin/action_plugins/legacy_action.py b/test/integration/targets/collections/test_task_resolved_plugin/action_plugins/legacy_action.py new file mode 100644 index 00000000..fa4d514b --- /dev/null +++ b/test/integration/targets/collections/test_task_resolved_plugin/action_plugins/legacy_action.py @@ -0,0 +1,14 @@ +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +from ansible.plugins.action import ActionBase + + +class ActionModule(ActionBase): + TRANSFERS_FILES = False + _VALID_ARGS = frozenset() + + def run(self, tmp=None, task_vars=None): + return {'changed': False} diff --git a/test/integration/targets/collections/test_task_resolved_plugin/callback_plugins/display_resolved_action.py b/test/integration/targets/collections/test_task_resolved_plugin/callback_plugins/display_resolved_action.py new file mode 100644 index 00000000..23cce104 --- /dev/null +++ b/test/integration/targets/collections/test_task_resolved_plugin/callback_plugins/display_resolved_action.py @@ -0,0 +1,37 @@ +# (c) 2020 Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +DOCUMENTATION = ''' + name: display_resolved_action + type: aggregate + short_description: Displays the requested and resolved actions at the end of a playbook. + description: + - Displays the requested and resolved actions in the format "requested == resolved". + requirements: + - Enable in configuration. +''' + +from ansible import constants as C +from ansible.plugins.callback import CallbackBase + + +class CallbackModule(CallbackBase): + + CALLBACK_VERSION = 2.0 + CALLBACK_TYPE = 'aggregate' + CALLBACK_NAME = 'display_resolved_action' + CALLBACK_NEEDS_ENABLED = True + + def __init__(self, *args, **kwargs): + super(CallbackModule, self).__init__(*args, **kwargs) + self.requested_to_resolved = {} + + def v2_playbook_on_task_start(self, task, is_conditional): + self.requested_to_resolved[task.action] = task.resolved_action + + def v2_playbook_on_stats(self, stats): + for requested, resolved in self.requested_to_resolved.items(): + self._display.display("%s == %s" % (requested, resolved), screen_only=True) diff --git a/test/integration/targets/collections/test_task_resolved_plugin/collections/ansible_collections/test_ns/test_coll/meta/runtime.yml b/test/integration/targets/collections/test_task_resolved_plugin/collections/ansible_collections/test_ns/test_coll/meta/runtime.yml new file mode 100644 index 00000000..8c27dba0 --- /dev/null +++ b/test/integration/targets/collections/test_task_resolved_plugin/collections/ansible_collections/test_ns/test_coll/meta/runtime.yml @@ -0,0 +1,7 @@ +plugin_routing: + modules: + formerly_module: + redirect: test_ns.test_coll.collection_module + action: + formerly_action: + redirect: test_ns.test_coll.collection_action diff --git a/test/integration/targets/collections/test_task_resolved_plugin/collections/ansible_collections/test_ns/test_coll/plugins/action/collection_action.py b/test/integration/targets/collections/test_task_resolved_plugin/collections/ansible_collections/test_ns/test_coll/plugins/action/collection_action.py new file mode 100644 index 00000000..fa4d514b --- /dev/null +++ b/test/integration/targets/collections/test_task_resolved_plugin/collections/ansible_collections/test_ns/test_coll/plugins/action/collection_action.py @@ -0,0 +1,14 @@ +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +from ansible.plugins.action import ActionBase + + +class ActionModule(ActionBase): + TRANSFERS_FILES = False + _VALID_ARGS = frozenset() + + def run(self, tmp=None, task_vars=None): + return {'changed': False} diff --git a/test/integration/targets/collections/test_task_resolved_plugin/collections/ansible_collections/test_ns/test_coll/plugins/modules/collection_module.py b/test/integration/targets/collections/test_task_resolved_plugin/collections/ansible_collections/test_ns/test_coll/plugins/modules/collection_module.py new file mode 100644 index 00000000..8f312263 --- /dev/null +++ b/test/integration/targets/collections/test_task_resolved_plugin/collections/ansible_collections/test_ns/test_coll/plugins/modules/collection_module.py @@ -0,0 +1,29 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: collection_module +short_description: A module to test a task's resolved action name. +description: A module to test a task's resolved action name. +options: {} +author: Ansible Core Team +notes: + - Supports C(check_mode). +''' + +from ansible.module_utils.basic import AnsibleModule + + +def main(): + module = AnsibleModule(supports_check_mode=True, argument_spec={}) + module.exit_json(changed=False) + + +if __name__ == '__main__': + main() diff --git a/test/integration/targets/collections/test_task_resolved_plugin/fqcn.yml b/test/integration/targets/collections/test_task_resolved_plugin/fqcn.yml new file mode 100644 index 00000000..ab9e9259 --- /dev/null +++ b/test/integration/targets/collections/test_task_resolved_plugin/fqcn.yml @@ -0,0 +1,14 @@ +--- +- hosts: localhost + gather_facts: no + tasks: + - ansible.legacy.legacy_action: + - ansible.legacy.legacy_module: + - ansible.legacy.debug: + - ansible.legacy.ping: + - ansible.builtin.debug: + - ansible.builtin.ping: + - test_ns.test_coll.collection_action: + - test_ns.test_coll.collection_module: + - test_ns.test_coll.formerly_action: + - test_ns.test_coll.formerly_module: diff --git a/test/integration/targets/collections/test_task_resolved_plugin/library/legacy_module.py b/test/integration/targets/collections/test_task_resolved_plugin/library/legacy_module.py new file mode 100644 index 00000000..4fd75871 --- /dev/null +++ b/test/integration/targets/collections/test_task_resolved_plugin/library/legacy_module.py @@ -0,0 +1,29 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: legacy_module +short_description: A module to test a task's resolved action name. +description: A module to test a task's resolved action name. +options: {} +author: Ansible Core Team +notes: + - Supports C(check_mode). +''' + +from ansible.module_utils.basic import AnsibleModule + + +def main(): + module = AnsibleModule(supports_check_mode=True, argument_spec={}) + module.exit_json(changed=False) + + +if __name__ == '__main__': + main() diff --git a/test/integration/targets/collections/test_task_resolved_plugin/unqualified.yml b/test/integration/targets/collections/test_task_resolved_plugin/unqualified.yml new file mode 100644 index 00000000..076b8cc7 --- /dev/null +++ b/test/integration/targets/collections/test_task_resolved_plugin/unqualified.yml @@ -0,0 +1,8 @@ +--- +- hosts: localhost + gather_facts: no + tasks: + - legacy_action: + - legacy_module: + - debug: + - ping: diff --git a/test/integration/targets/collections/test_task_resolved_plugin/unqualified_and_collections_kw.yml b/test/integration/targets/collections/test_task_resolved_plugin/unqualified_and_collections_kw.yml new file mode 100644 index 00000000..5af4eda9 --- /dev/null +++ b/test/integration/targets/collections/test_task_resolved_plugin/unqualified_and_collections_kw.yml @@ -0,0 +1,14 @@ +--- +- hosts: localhost + gather_facts: no + collections: + - test_ns.test_coll + tasks: + - legacy_action: + - legacy_module: + - debug: + - ping: + - collection_action: + - collection_module: + - formerly_action: + - formerly_module: diff --git a/test/integration/targets/collections/windows.yml b/test/integration/targets/collections/windows.yml index 4bdfb0ed..cf98ca1e 100644 --- a/test/integration/targets/collections/windows.yml +++ b/test/integration/targets/collections/windows.yml @@ -12,6 +12,9 @@ - testns.testcoll.win_uses_coll_csmu: register: uses_coll_csmu + - testns.testcoll.win_uses_optional: + register: uses_coll_optional + - assert: that: - selfcontained_out.source == 'user' @@ -26,3 +29,6 @@ - "'Hello from subpkg.subcs' in uses_coll_csmu.ping" - uses_coll_csmu.subpkg == 'Hello from subpkg.subcs' - uses_coll_csmu.type_accelerator == uses_coll_csmu.ping + # win_uses_optional + - uses_coll_optional.data == "called from optional user_mu" + - uses_coll_optional.csharp == "Hello from user_mu collection-hosted MyCSMUOptional, also Hello from nested user-collection-hosted AnotherCSMU and Hello from subpkg.subcs" diff --git a/test/integration/targets/collections_plugin_namespace/aliases b/test/integration/targets/collections_plugin_namespace/aliases index a6dafcf8..13e01f0c 100644 --- a/test/integration/targets/collections_plugin_namespace/aliases +++ b/test/integration/targets/collections_plugin_namespace/aliases @@ -1 +1,2 @@ shippable/posix/group1 +context/controller diff --git a/test/integration/targets/collections_relative_imports/collection_root/ansible_collections/my_ns/my_col/plugins/module_utils/PSRel4.psm1 b/test/integration/targets/collections_relative_imports/collection_root/ansible_collections/my_ns/my_col/plugins/module_utils/PSRel4.psm1 new file mode 100644 index 00000000..bcb5ec19 --- /dev/null +++ b/test/integration/targets/collections_relative_imports/collection_root/ansible_collections/my_ns/my_col/plugins/module_utils/PSRel4.psm1 @@ -0,0 +1,12 @@ +#AnsibleRequires -CSharpUtil .sub_pkg.CSRel5 -Optional +#AnsibleRequires -PowerShell .sub_pkg.PSRelInvalid -Optional + +Function Invoke-FromPSRel4 { + <# + .SYNOPSIS + Test function + #> + return "Invoke-FromPSRel4" +} + +Export-ModuleMember -Function Invoke-FromPSRel4 diff --git a/test/integration/targets/collections_relative_imports/collection_root/ansible_collections/my_ns/my_col/plugins/modules/win_relative_optional.ps1 b/test/integration/targets/collections_relative_imports/collection_root/ansible_collections/my_ns/my_col/plugins/modules/win_relative_optional.ps1 new file mode 100644 index 00000000..9086ca42 --- /dev/null +++ b/test/integration/targets/collections_relative_imports/collection_root/ansible_collections/my_ns/my_col/plugins/modules/win_relative_optional.ps1 @@ -0,0 +1,17 @@ +#!powershell + +#AnsibleRequires -CSharpUtil Ansible.Basic -Optional +#AnsibleRequires -PowerShell ..module_utils.PSRel4 -optional + +# These do not exist +#AnsibleRequires -CSharpUtil ..invalid_package.name -Optional +#AnsibleRequires -CSharpUtil ..module_utils.InvalidName -optional +#AnsibleRequires -PowerShell ..invalid_package.pwsh_name -optional +#AnsibleRequires -PowerShell ..module_utils.InvalidPwshName -Optional + + +$module = [Ansible.Basic.AnsibleModule]::Create($args, @{}) + +$module.Result.data = Invoke-FromPSRel4 + +$module.ExitJson() diff --git a/test/integration/targets/collections_relative_imports/windows.yml b/test/integration/targets/collections_relative_imports/windows.yml index aa6badfa..3a3c5488 100644 --- a/test/integration/targets/collections_relative_imports/windows.yml +++ b/test/integration/targets/collections_relative_imports/windows.yml @@ -9,3 +9,12 @@ assert: that: - win_relative.data == 'CSRel4.Invoke() -> Invoke-FromPSRel3 -> Invoke-FromPSRel2 -> Invoke-FromPSRel1' + + - name: test out relative imports on Windows modules with optional import + my_ns.my_col.win_relative_optional: + register: win_relative_optional + + - name: assert relative imports on Windows modules with optional import + assert: + that: + - win_relative_optional.data == 'Invoke-FromPSRel4' diff --git a/test/integration/targets/collections_runtime_pythonpath/aliases b/test/integration/targets/collections_runtime_pythonpath/aliases index 0a772ad7..498fedd5 100644 --- a/test/integration/targets/collections_runtime_pythonpath/aliases +++ b/test/integration/targets/collections_runtime_pythonpath/aliases @@ -1,3 +1,2 @@ shippable/posix/group4 -skip/python2.6 -skip/aix +context/controller diff --git a/test/integration/targets/collections_runtime_pythonpath/runme.sh b/test/integration/targets/collections_runtime_pythonpath/runme.sh index 654104a1..38c6c64f 100755 --- a/test/integration/targets/collections_runtime_pythonpath/runme.sh +++ b/test/integration/targets/collections_runtime_pythonpath/runme.sh @@ -25,19 +25,19 @@ ansible \ === Test that the module \ gets picked up if installed \ into site-packages === -python -m pip.__main__ install pep517 +python -m pip install pep517 ( # Build a binary Python dist (a wheel) using PEP517: cp -r ansible-collection-python-dist-boo "${OUTPUT_DIR}/" cd "${OUTPUT_DIR}/ansible-collection-python-dist-boo" python -m pep517.build --binary --out-dir dist . ) # Install a pre-built dist with pip: -python -m pip.__main__ install \ +python -m pip install \ --no-index \ -f "${OUTPUT_DIR}/ansible-collection-python-dist-boo/dist/" \ --only-binary=ansible-collections.python.dist \ ansible-collections.python.dist -python -m pip.__main__ show ansible-collections.python.dist +python -m pip show ansible-collections.python.dist ansible \ -m python.dist.boo \ -a 'name=Frodo' \ diff --git a/test/integration/targets/command_nonexisting/aliases b/test/integration/targets/command_nonexisting/aliases index e2dcf795..90ea9e12 100644 --- a/test/integration/targets/command_nonexisting/aliases +++ b/test/integration/targets/command_nonexisting/aliases @@ -1 +1,2 @@ -shippable/posix/group2
\ No newline at end of file +shippable/posix/group2 +context/controller diff --git a/test/integration/targets/command_shell/tasks/main.yml b/test/integration/targets/command_shell/tasks/main.yml index 653b0059..aad63c0d 100644 --- a/test/integration/targets/command_shell/tasks/main.yml +++ b/test/integration/targets/command_shell/tasks/main.yml @@ -504,11 +504,11 @@ when: ansible_facts.python_version is version('3', '>=') - name: run command with strip - command: '{{ ansible_playbook_python}} -c "import sys; msg=''hello \n \r''; print(msg); {{ print_error_command }}"' + command: '{{ ansible_python_interpreter }} -c "import sys; msg=''hello \n \r''; print(msg); {{ print_error_command }}"' register: command_strip - name: run command without strip - command: '{{ ansible_playbook_python}} -c "import sys; msg=''hello \n \r''; print(msg); {{ print_error_command }}"' + command: '{{ ansible_python_interpreter }} -c "import sys; msg=''hello \n \r''; print(msg); {{ print_error_command }}"' args: strip_empty_ends: no register: command_no_strip diff --git a/test/integration/targets/common_network/aliases b/test/integration/targets/common_network/aliases index 70a7b7a9..1d28bdb2 100644 --- a/test/integration/targets/common_network/aliases +++ b/test/integration/targets/common_network/aliases @@ -1 +1,2 @@ shippable/posix/group5 +context/controller diff --git a/test/integration/targets/conditionals/aliases b/test/integration/targets/conditionals/aliases index a6dafcf8..13e01f0c 100644 --- a/test/integration/targets/conditionals/aliases +++ b/test/integration/targets/conditionals/aliases @@ -1 +1,2 @@ shippable/posix/group1 +context/controller diff --git a/test/integration/targets/conditionals/play.yml b/test/integration/targets/conditionals/play.yml index c6bb3815..455818c9 100644 --- a/test/integration/targets/conditionals/play.yml +++ b/test/integration/targets/conditionals/play.yml @@ -6,10 +6,6 @@ vars_files: - vars/main.yml tasks: - - name: set conditional bare vars status - set_fact: - bare: "{{lookup('config', 'CONDITIONAL_BARE_VARS')|bool}}" - - name: test conditional '==' shell: echo 'testing' when: 1 == 1 @@ -164,6 +160,136 @@ - "result.stdout == 'testing'" - "result.rc == 0" + - name: not test bare conditional + shell: echo 'testing' + when: not test_bare + register: result + + - name: assert did not run + assert: + that: + - result is skipped + + - name: empty string is false + shell: echo 'testing' + when: string_lit_empty + register: result + + - name: assert did not run + assert: + that: + - result is skipped + + - name: not empty string is true + shell: echo 'testing' + when: not string_lit_empty + register: result + + - name: assert ran + assert: + that: + - result is not skipped + + - name: literal 0 is false + shell: echo 'testing' + when: int_lit_0 + register: result + + - name: assert did not run + assert: + that: + - result is skipped + + - name: not literal 0 is true + shell: echo 'testing' + when: not int_lit_0 + register: result + + - name: assert ran + assert: + that: + - result is not skipped + + - name: literal 1 is true + shell: echo 'testing' + when: int_lit_1 + register: result + + - name: assert ran + assert: + that: + - result is not skipped + + - name: not literal 1 is false + shell: echo 'testing' + when: not int_lit_1 + register: result + + - name: assert did not run + assert: + that: + - result is skipped + + - name: null is false + shell: echo 'testing' + when: lit_null + register: result + + - name: assert did not run + assert: + that: + - result is skipped + + - name: literal string "true" is true + shell: echo 'testing' + when: string_lit_true + register: result + + - name: assert ran + assert: + that: + - result is not skipped + + - name: not literal string "true" is false + shell: echo 'testing' + when: not string_lit_true + register: result + + - name: assert did not run + assert: + that: + - result is skipped + + - name: literal string "false" is true (nonempty string) + shell: echo 'testing' + when: string_lit_false + register: result + + - name: assert ran + assert: + that: + - result is not skipped + + - name: not literal string "false" is false + shell: echo 'testing' + when: not string_lit_false + register: result + + - name: assert did not run + assert: + that: + - result is skipped + + - name: not literal string "true" is false + shell: echo 'testing' + when: not string_lit_true + register: result + + - name: assert did not run + assert: + that: + - result is skipped + - name: test conditional using a variable shell: echo 'testing' when: test_bare_var == 123 @@ -195,23 +321,13 @@ - debug: var={{item}} loop: - - bare - result - test_bare_nested_bad - - name: assert that the bad nested conditional is skipped since 'bare' since 'string' template is resolved to 'false' + - name: assert that the bad nested conditional ran (it is a non-empty string, so truthy) assert: that: - - result is skipped - - when: bare|bool - - - name: assert that the bad nested conditional did run since non bare 'string' is untemplated but 'trueish' - assert: - that: - - result is skipped - when: not bare|bool - - result is changed + - result is not skipped - name: test bad conditional based on nested variables with bool filter shell: echo 'testing' @@ -223,6 +339,7 @@ that: - result is skipped + #----------------------------------------------------------------------- # proper booleanification tests (issue #8629) @@ -382,7 +499,6 @@ - name: Deal with multivar equality tags: ['leveldiff'] - when: not bare|bool vars: toplevel_hash: hash_var_one: justastring diff --git a/test/integration/targets/conditionals/runme.sh b/test/integration/targets/conditionals/runme.sh index 934443a5..4858fbf2 100755 --- a/test/integration/targets/conditionals/runme.sh +++ b/test/integration/targets/conditionals/runme.sh @@ -2,14 +2,4 @@ set -eux -ANSIBLE_CONDITIONAL_BARE_VARS=1 ansible-playbook -i ../../inventory play.yml "$@" -ANSIBLE_CONDITIONAL_BARE_VARS=0 ansible-playbook -i ../../inventory play.yml "$@" - -export ANSIBLE_CONDITIONAL_BARE_VARS=1 -export ANSIBLE_DEPRECATION_WARNINGS=True - -# No warnings for conditionals that are already type bool -test "$(ansible-playbook -i ../../inventory test_no_warnings.yml "$@" 2>&1 | grep -c '\[DEPRECATION WARNING\]')" = 0 - -# Warn for bare vars of other types since they may be interpreted differently when CONDITIONAL_BARE_VARS defaults to False -test "$(ansible-playbook -i ../../inventory test_warnings.yml "$@" 2>&1 | grep -c '\[DEPRECATION WARNING\]')" = 2 +ansible-playbook -i ../../inventory play.yml "$@" diff --git a/test/integration/targets/conditionals/test_no_warnings.yml b/test/integration/targets/conditionals/test_no_warnings.yml deleted file mode 100644 index 93280447..00000000 --- a/test/integration/targets/conditionals/test_no_warnings.yml +++ /dev/null @@ -1,18 +0,0 @@ -- hosts: testhost - gather_facts: false - vars: - boolean_var: false - nested: - bool_var: false - tasks: - - name: Run tasks with previous warnings requesting the bool filter on type boolean vars - block: - - debug: - when: boolean_var - - debug: - when: nested.bool_var - - debug: - when: double_interpolated - vars: - double_interpolated: "{{ other }}" - other: false diff --git a/test/integration/targets/conditionals/test_warnings.yml b/test/integration/targets/conditionals/test_warnings.yml deleted file mode 100644 index 4186cd01..00000000 --- a/test/integration/targets/conditionals/test_warnings.yml +++ /dev/null @@ -1,14 +0,0 @@ -- hosts: testhost - gather_facts: false - vars: - str_boolean_var: 'false' - tasks: - - name: Run tasks with warnings for conditionals that will change in behavior depending on CONDITIONAL_BARE_VARS - block: - - debug: - when: str_boolean_var - - debug: - when: double_interpolated - vars: - double_interpolated: other - other: false diff --git a/test/integration/targets/conditionals/vars/main.yml b/test/integration/targets/conditionals/vars/main.yml index d6221478..2af6cee2 100644 --- a/test/integration/targets/conditionals/vars/main.yml +++ b/test/integration/targets/conditionals/vars/main.yml @@ -20,3 +20,10 @@ test_bare: true test_bare_var: 123 test_bare_nested_good: "test_bare_var == 123" test_bare_nested_bad: "{{test_bare_var}} == 321" + +string_lit_true: "true" +string_lit_false: "false" +string_lit_empty: "" +lit_null: null +int_lit_0: 0 +int_lit_1: 1 diff --git a/test/integration/targets/config/aliases b/test/integration/targets/config/aliases index a6dafcf8..13e01f0c 100644 --- a/test/integration/targets/config/aliases +++ b/test/integration/targets/config/aliases @@ -1 +1,2 @@ shippable/posix/group1 +context/controller diff --git a/test/integration/targets/config/files/types.env b/test/integration/targets/config/files/types.env new file mode 100644 index 00000000..b5fc43ee --- /dev/null +++ b/test/integration/targets/config/files/types.env @@ -0,0 +1,11 @@ +# valid(list): does nothihng, just for testing values +ANSIBLE_TYPES_VALID= + +# mustunquote(list): does nothihng, just for testing values +ANSIBLE_TYPES_MUSTUNQUOTE= + +# notvalid(list): does nothihng, just for testing values +ANSIBLE_TYPES_NOTVALID= + +# totallynotvalid(list): does nothihng, just for testing values +ANSIBLE_TYPES_TOTALLYNOTVALID= diff --git a/test/integration/targets/config/files/types.ini b/test/integration/targets/config/files/types.ini new file mode 100644 index 00000000..c04b6d5a --- /dev/null +++ b/test/integration/targets/config/files/types.ini @@ -0,0 +1,13 @@ +[list_values] +# (list) does nothihng, just for testing values +mustunquote= + +# (list) does nothihng, just for testing values +notvalid= + +# (list) does nothihng, just for testing values +totallynotvalid= + +# (list) does nothihng, just for testing values +valid= + diff --git a/test/integration/targets/config/files/types.vars b/test/integration/targets/config/files/types.vars new file mode 100644 index 00000000..d1427fc8 --- /dev/null +++ b/test/integration/targets/config/files/types.vars @@ -0,0 +1,15 @@ +# valid(list): does nothihng, just for testing values +ansible_types_valid: '' + + +# mustunquote(list): does nothihng, just for testing values +ansible_types_mustunquote: '' + + +# notvalid(list): does nothihng, just for testing values +ansible_types_notvalid: '' + + +# totallynotvalid(list): does nothihng, just for testing values +ansible_types_totallynotvalid: '' + diff --git a/test/integration/targets/config/files/types_dump.txt b/test/integration/targets/config/files/types_dump.txt new file mode 100644 index 00000000..2139f4d1 --- /dev/null +++ b/test/integration/targets/config/files/types_dump.txt @@ -0,0 +1,8 @@ + +types: +_____ +_terms(default) = None +mustunquote(default) = None +notvalid(default) = None +totallynotvalid(default) = None +valid(default) = None diff --git a/test/integration/targets/config/lookup_plugins/types.py b/test/integration/targets/config/lookup_plugins/types.py new file mode 100644 index 00000000..d3092296 --- /dev/null +++ b/test/integration/targets/config/lookup_plugins/types.py @@ -0,0 +1,82 @@ +# (c) 2021 Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + +DOCUMENTATION = """ + name: types + author: Ansible Core Team + version_added: histerical + short_description: returns what you gave it + description: + - this is mostly a noop + options: + _terms: + description: stuff to pass through + valid: + description: does nothihng, just for testing values + type: list + ini: + - section: list_values + key: valid + env: + - name: ANSIBLE_TYPES_VALID + vars: + - name: ansible_types_valid + mustunquote: + description: does nothihng, just for testing values + type: list + ini: + - section: list_values + key: mustunquote + env: + - name: ANSIBLE_TYPES_MUSTUNQUOTE + vars: + - name: ansible_types_mustunquote + notvalid: + description: does nothihng, just for testing values + type: list + ini: + - section: list_values + key: notvalid + env: + - name: ANSIBLE_TYPES_NOTVALID + vars: + - name: ansible_types_notvalid + totallynotvalid: + description: does nothihng, just for testing values + type: list + ini: + - section: list_values + key: totallynotvalid + env: + - name: ANSIBLE_TYPES_TOTALLYNOTVALID + vars: + - name: ansible_types_totallynotvalid +""" + +EXAMPLES = """ +- name: like some other plugins, this is mostly useless + debug: msg={{ q('types', [1,2,3])}} +""" + +RETURN = """ + _list: + description: basically the same as you fed in + type: list + elements: raw +""" + +from ansible.plugins.lookup import LookupBase + + +class LookupModule(LookupBase): + + def run(self, terms, variables=None, **kwargs): + + self.set_options(var_options=variables, direct=kwargs) + + return terms diff --git a/test/integration/targets/config/runme.sh b/test/integration/targets/config/runme.sh index bbff6acc..76df44c4 100755 --- a/test/integration/targets/config/runme.sh +++ b/test/integration/targets/config/runme.sh @@ -21,3 +21,19 @@ ANSIBLE_CONFIG=inline_comment_ansible.cfg ansible-config dump --only-changed | g # test the config option validation ansible-playbook validation.yml "$@" + +# test types from config (just lists for now) +ANSIBLE_CONFIG=type_munging.cfg ansible-playbook types.yml "$@" + +cleanup() { + rm -f files/*.new.* +} + +trap 'cleanup' EXIT + +# check a-c init per format +for format in "vars" "ini" "env" +do + ANSIBLE_LOOKUP_PLUGINS=./ ansible-config init types -t lookup -f "${format}" > "files/types.new.${format}" + diff -u "files/types.${format}" "files/types.new.${format}" +done diff --git a/test/integration/targets/config/type_munging.cfg b/test/integration/targets/config/type_munging.cfg new file mode 100644 index 00000000..d6aeaab6 --- /dev/null +++ b/test/integration/targets/config/type_munging.cfg @@ -0,0 +1,8 @@ +[defaults] +nothing = here + +[list_values] +valid = 1, 2, 3 +mustunquote = '1', '2', '3' +notvalid = [1, 2, 3] +totallynotvalid = ['1', '2', '3'] diff --git a/test/integration/targets/config/types.yml b/test/integration/targets/config/types.yml new file mode 100644 index 00000000..650a96f6 --- /dev/null +++ b/test/integration/targets/config/types.yml @@ -0,0 +1,25 @@ +- hosts: localhost + gather_facts: false + tasks: + - name: ensures we got the list we expected + block: + - name: initialize plugin + debug: msg={{ lookup('types', 'starting test') }} + + - set_fact: + valid: '{{ lookup("config", "valid", plugin_type="lookup", plugin_name="types") }}' + mustunquote: '{{ lookup("config", "mustunquote", plugin_type="lookup", plugin_name="types") }}' + notvalid: '{{ lookup("config", "notvalid", plugin_type="lookup", plugin_name="types") }}' + totallynotvalid: '{{ lookup("config", "totallynotvalid", plugin_type="lookup", plugin_name="types") }}' + + - assert: + that: + - 'valid|type_debug == "list"' + - 'mustunquote|type_debug == "list"' + - 'notvalid|type_debug == "list"' + - 'totallynotvalid|type_debug == "list"' + - valid[0]|int == 1 + - mustunquote[0]|int == 1 + - "notvalid[0] == '[1'" + # using 'and true' to avoid quote hell + - totallynotvalid[0] == "['1'" and True diff --git a/test/integration/targets/connection_delegation/aliases b/test/integration/targets/connection_delegation/aliases index 87caabdf..44e49e4f 100644 --- a/test/integration/targets/connection_delegation/aliases +++ b/test/integration/targets/connection_delegation/aliases @@ -1,4 +1,5 @@ shippable/posix/group1 +context/controller skip/freebsd # No sshpass skip/osx # No sshpass skip/macos # No sshpass diff --git a/test/integration/targets/connection_delegation/runme.sh b/test/integration/targets/connection_delegation/runme.sh index eb26f7c5..4d507243 100755 --- a/test/integration/targets/connection_delegation/runme.sh +++ b/test/integration/targets/connection_delegation/runme.sh @@ -3,7 +3,7 @@ set -ux echo "Checking if sshpass is present" -which sshpass 2>&1 || exit 0 +command -v sshpass 2>&1 || exit 0 echo "sshpass is present, continuing with test" sshpass -p my_password ansible-playbook -i inventory.ini test.yml -k "$@" diff --git a/test/integration/targets/connection_paramiko_ssh/aliases b/test/integration/targets/connection_paramiko_ssh/aliases index ad44392e..fd5b08a4 100644 --- a/test/integration/targets/connection_paramiko_ssh/aliases +++ b/test/integration/targets/connection_paramiko_ssh/aliases @@ -2,4 +2,3 @@ needs/ssh shippable/posix/group3 needs/target/setup_paramiko destructive # potentially installs/uninstalls OS packages via setup_paramiko -skip/aix diff --git a/test/integration/targets/connection_ssh/aliases b/test/integration/targets/connection_ssh/aliases index 1d822b45..50fb8eb8 100644 --- a/test/integration/targets/connection_ssh/aliases +++ b/test/integration/targets/connection_ssh/aliases @@ -1,3 +1,2 @@ needs/ssh shippable/posix/group1 -skip/aix diff --git a/test/integration/targets/connection_ssh/runme.sh b/test/integration/targets/connection_ssh/runme.sh index 7e5953ed..cbadf1d5 100755 --- a/test/integration/targets/connection_ssh/runme.sh +++ b/test/integration/targets/connection_ssh/runme.sh @@ -68,3 +68,6 @@ ANSIBLE_SSH_TRANSFER_METHOD=piped ./posix.sh "$@" # test config defaults override ansible-playbook check_ssh_defaults.yml "$@" -i test_connection.inventory + +# ensure we can load from ini cfg +ANSIBLE_CONFIG=./test_ssh_defaults.cfg ansible-playbook verify_config.yml "$@" diff --git a/test/integration/targets/connection_ssh/test_ssh_defaults.cfg b/test/integration/targets/connection_ssh/test_ssh_defaults.cfg new file mode 100644 index 00000000..362f9460 --- /dev/null +++ b/test/integration/targets/connection_ssh/test_ssh_defaults.cfg @@ -0,0 +1,5 @@ +[ssh_connection] +ssh_common_args=fromconfig +ssh_extra_args=fromconfig +scp_extra_args=fromconfig +sftp_extra_args=fromconfig diff --git a/test/integration/targets/connection_ssh/verify_config.yml b/test/integration/targets/connection_ssh/verify_config.yml new file mode 100644 index 00000000..0bf79586 --- /dev/null +++ b/test/integration/targets/connection_ssh/verify_config.yml @@ -0,0 +1,21 @@ +- hosts: localhost + gather_facts: false + vars: + ssh_configs: + - ssh_common_args + - ssh_extra_args + - sftp_extra_args + - scp_extra_args + tasks: + - debug: + msg: '{{item ~ ": " ~ lookup("config", item, plugin_type="connection", plugin_name="ssh")}}' + verbosity: 3 + loop: '{{ssh_configs}}' + tags: [ configfile ] + + - name: check config from file + assert: + that: + - 'lookup("config", item, plugin_type="connection", plugin_name="ssh") == "fromconfig"' + loop: '{{ssh_configs}}' + tags: [ configfile ] diff --git a/test/integration/targets/controller/aliases b/test/integration/targets/controller/aliases new file mode 100644 index 00000000..0ac86c92 --- /dev/null +++ b/test/integration/targets/controller/aliases @@ -0,0 +1,2 @@ +context/controller +shippable/posix/group1 diff --git a/test/integration/targets/controller/tasks/main.yml b/test/integration/targets/controller/tasks/main.yml new file mode 100644 index 00000000..354a593e --- /dev/null +++ b/test/integration/targets/controller/tasks/main.yml @@ -0,0 +1,9 @@ +- name: Verify testhost is control host + stat: + path: "{{ output_dir }}" +- name: Get control host details + setup: + register: control_host +- name: Show control host details + debug: + msg: "{{ control_host.ansible_facts.ansible_distribution }} {{ control_host.ansible_facts.ansible_distribution_version }}" diff --git a/test/integration/targets/copy/tasks/main.yml b/test/integration/targets/copy/tasks/main.yml index e02c0232..bef182b8 100644 --- a/test/integration/targets/copy/tasks/main.yml +++ b/test/integration/targets/copy/tasks/main.yml @@ -27,6 +27,7 @@ chdir: '{{role_path}}/files/subdir/subdir1' warn: no with_dict: "{{ symlinks }}" + delegate_to: localhost - name: Create remote unprivileged remote user user: @@ -78,6 +79,7 @@ when: ansible_os_family == 'RedHat' and ansible_selinux.get('mode') == 'enforcing' - import_tasks: no_log.yml + delegate_to: localhost - import_tasks: check_mode.yml @@ -113,6 +115,7 @@ name: '{{ remote_unprivileged_user }}' state: absent remove: yes + force: yes - name: Remove sudoers.d file file: diff --git a/test/integration/targets/copy/tasks/tests.yml b/test/integration/targets/copy/tasks/tests.yml index be955317..fa4254c7 100644 --- a/test/integration/targets/copy/tasks/tests.yml +++ b/test/integration/targets/copy/tasks/tests.yml @@ -1489,13 +1489,13 @@ # src is a file, dest is a non-existent directory (2 levels of directories): # using remote_src # checks that dest is created -- include: dest_in_non_existent_directories_remote_src.yml +- include_tasks: file=dest_in_non_existent_directories_remote_src.yml with_items: - { src: 'foo.txt', dest: 'new_sub_dir1/sub_dir2/', check: 'new_sub_dir1/sub_dir2/foo.txt' } # src is a file, dest is file in a non-existent directory: checks that a failure occurs # using remote_src -- include: src_file_dest_file_in_non_existent_dir_remote_src.yml +- include_tasks: file=src_file_dest_file_in_non_existent_dir_remote_src.yml with_items: - 'new_sub_dir1/sub_dir2/foo.txt' - 'new_sub_dir1/foo.txt' @@ -1504,7 +1504,7 @@ # src is a file, dest is a non-existent directory (2 levels of directories): # checks that dest is created -- include: dest_in_non_existent_directories.yml +- include_tasks: file=dest_in_non_existent_directories.yml with_items: - { src: 'foo.txt', dest: 'new_sub_dir1/sub_dir2/', check: 'new_sub_dir1/sub_dir2/foo.txt' } - { src: 'subdir', dest: 'new_sub_dir1/sub_dir2/', check: 'new_sub_dir1/sub_dir2/subdir/bar.txt' } @@ -1513,7 +1513,7 @@ - { src: 'subdir/', dest: 'new_sub_dir1/sub_dir2', check: 'new_sub_dir1/sub_dir2/bar.txt' } # src is a file, dest is file in a non-existent directory: checks that a failure occurs -- include: src_file_dest_file_in_non_existent_dir.yml +- include_tasks: file=src_file_dest_file_in_non_existent_dir.yml with_items: - 'new_sub_dir1/sub_dir2/foo.txt' - 'new_sub_dir1/foo.txt' diff --git a/test/integration/targets/cron/tasks/main.yml b/test/integration/targets/cron/tasks/main.yml index 899ec549..32e345d3 100644 --- a/test/integration/targets/cron/tasks/main.yml +++ b/test/integration/targets/cron/tasks/main.yml @@ -110,8 +110,9 @@ - assert: that: remove_task_idempotence is not changed -- name: Check that removing a cron task with cron_file and without specifying an user is allowed (#58493) +- name: Check that removing a cron task with cron_file and without specifying a user is allowed (#58493) cron: + name: test cron task cron_file: unexistent_cron_file state: absent register: remove_cron_file @@ -214,7 +215,24 @@ - assert: that: not cron_file_stats.stat.exists +- name: System cron tab can not be managed + when: ansible_distribution != 'Alpine' + block: + - name: Add cron job + cron: + cron_file: "{{ system_crontab }}" + user: root + name: "integration test cron" + job: 'ls' + ignore_errors: yes + register: result + + - assert: + that: "result.msg == 'Will not manage /etc/crontab via cron_file, see documentation.'" + +# TODO: restrict other root crontab locations - name: System cron tab does not get removed + when: ansible_distribution == 'Alpine' block: - name: Add cron job cron: diff --git a/test/integration/targets/dataloader/aliases b/test/integration/targets/dataloader/aliases index a6dafcf8..13e01f0c 100644 --- a/test/integration/targets/dataloader/aliases +++ b/test/integration/targets/dataloader/aliases @@ -1 +1,2 @@ shippable/posix/group1 +context/controller diff --git a/test/integration/targets/debug/aliases b/test/integration/targets/debug/aliases index a6dafcf8..97c468e5 100644 --- a/test/integration/targets/debug/aliases +++ b/test/integration/targets/debug/aliases @@ -1 +1,2 @@ shippable/posix/group1 +context/controller # this is a controller-only action, the module is just for documentation diff --git a/test/integration/targets/delegate_to/aliases b/test/integration/targets/delegate_to/aliases index b8e973da..d6bb651c 100644 --- a/test/integration/targets/delegate_to/aliases +++ b/test/integration/targets/delegate_to/aliases @@ -1,4 +1,4 @@ shippable/posix/group3 needs/ssh needs/root # only on macOS and FreeBSD to configure network interfaces -skip/aix +context/controller diff --git a/test/integration/targets/dict_transformations/aliases b/test/integration/targets/dict_transformations/aliases index a6dafcf8..13e01f0c 100644 --- a/test/integration/targets/dict_transformations/aliases +++ b/test/integration/targets/dict_transformations/aliases @@ -1 +1,2 @@ shippable/posix/group1 +context/controller diff --git a/test/integration/targets/dnf/tasks/cacheonly.yml b/test/integration/targets/dnf/tasks/cacheonly.yml new file mode 100644 index 00000000..a5c84a37 --- /dev/null +++ b/test/integration/targets/dnf/tasks/cacheonly.yml @@ -0,0 +1,15 @@ +--- +- name: Test cacheonly (clean before testing) + command: dnf clean all + +- name: Try installing from cache where it has been cleaned + dnf: + name: sos + state: latest + cacheonly: true + register: dnf_result + +- name: Verify dnf has not changed + assert: + that: + - "not dnf_result is changed" diff --git a/test/integration/targets/dnf/tasks/dnf.yml b/test/integration/targets/dnf/tasks/dnf.yml index 7e6a8d8f..bf1ea848 100644 --- a/test/integration/targets/dnf/tasks/dnf.yml +++ b/test/integration/targets/dnf/tasks/dnf.yml @@ -700,7 +700,7 @@ content: | [main] exclude=lsof* - dest: '{{ output_dir }}/test-dnf.conf' + dest: '{{ remote_tmp_dir }}/test-dnf.conf' register: test_dnf_copy - block: @@ -728,7 +728,7 @@ always: - name: remove exclude lsof conf file file: - path: '{{ output_dir }}/test-dnf.conf' + path: '{{ remote_tmp_dir }}/test-dnf.conf' state: absent # end test case where disable_excludes is supported @@ -816,3 +816,21 @@ that: - nonexisting is success - nonexisting.msg == 'Nothing to do' + +# running on RHEL which is --remote where .mo language files are present +# for dnf as opposed to in --docker +- when: ansible_distribution == 'RedHat' + block: + - dnf: + name: langpacks-ja + state: present + + - dnf: + name: nginx-mod* + state: absent + environment: + LANG: ja_JP.UTF-8 + always: + - dnf: + name: langpacks-ja + state: absent diff --git a/test/integration/targets/dnf/tasks/main.yml b/test/integration/targets/dnf/tasks/main.yml index 51ab7d20..d66a0653 100644 --- a/test/integration/targets/dnf/tasks/main.yml +++ b/test/integration/targets/dnf/tasks/main.yml @@ -63,6 +63,15 @@ # TODO: Construct our own instance where 'nobest' applies, so we can stop using # a third-party repo to test this behavior. +# +# This fails due to conflicts on Fedora 34, but we can nuke this entirely once +# #74224 lands, because it covers nobest cases. - include_tasks: nobest.yml - when: (ansible_distribution == 'Fedora' and ansible_distribution_major_version is version('24', '>=')) or + when: (ansible_distribution == 'Fedora' and ansible_distribution_major_version is version('24', '>=') and + ansible_distribution_major_version is version('34', '!=')) or + (ansible_distribution in ['RedHat', 'CentOS'] and ansible_distribution_major_version is version('8', '>=')) + + +- include_tasks: cacheonly.yml + when: (ansible_distribution == 'Fedora' and ansible_distribution_major_version is version('23', '>=')) or (ansible_distribution in ['RedHat', 'CentOS'] and ansible_distribution_major_version is version('8', '>=')) diff --git a/test/integration/targets/dnf/vars/Fedora-34.yml b/test/integration/targets/dnf/vars/Fedora-34.yml new file mode 100644 index 00000000..859059f1 --- /dev/null +++ b/test/integration/targets/dnf/vars/Fedora-34.yml @@ -0,0 +1,2 @@ +astream_name: '@httpd:2.4/common' +astream_name_no_stream: '@httpd/common' diff --git a/test/integration/targets/dpkg_selections/tasks/main.yaml b/test/integration/targets/dpkg_selections/tasks/main.yaml index 6abd1dec..abf9fa1b 100644 --- a/test/integration/targets/dpkg_selections/tasks/main.yaml +++ b/test/integration/targets/dpkg_selections/tasks/main.yaml @@ -1,3 +1,3 @@ --- - - include: 'dpkg_selections.yaml' + - include_tasks: file='dpkg_selections.yaml' when: ansible_distribution in ('Ubuntu', 'Debian') diff --git a/test/integration/targets/egg-info/aliases b/test/integration/targets/egg-info/aliases index a6dafcf8..13e01f0c 100644 --- a/test/integration/targets/egg-info/aliases +++ b/test/integration/targets/egg-info/aliases @@ -1 +1,2 @@ shippable/posix/group1 +context/controller diff --git a/test/integration/targets/embedded_module/aliases b/test/integration/targets/embedded_module/aliases index 765b70da..6452e6d4 100644 --- a/test/integration/targets/embedded_module/aliases +++ b/test/integration/targets/embedded_module/aliases @@ -1 +1,2 @@ shippable/posix/group2 +context/target diff --git a/test/integration/targets/environment/aliases b/test/integration/targets/environment/aliases index b5983214..a3ada117 100644 --- a/test/integration/targets/environment/aliases +++ b/test/integration/targets/environment/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/target diff --git a/test/integration/targets/error_from_connection/aliases b/test/integration/targets/error_from_connection/aliases index 765b70da..90ea9e12 100644 --- a/test/integration/targets/error_from_connection/aliases +++ b/test/integration/targets/error_from_connection/aliases @@ -1 +1,2 @@ shippable/posix/group2 +context/controller diff --git a/test/integration/targets/facts_d/aliases b/test/integration/targets/facts_d/aliases index 765b70da..90ea9e12 100644 --- a/test/integration/targets/facts_d/aliases +++ b/test/integration/targets/facts_d/aliases @@ -1 +1,2 @@ shippable/posix/group2 +context/controller diff --git a/test/integration/targets/facts_linux_network/aliases b/test/integration/targets/facts_linux_network/aliases index 21a4e907..703c532e 100644 --- a/test/integration/targets/facts_linux_network/aliases +++ b/test/integration/targets/facts_linux_network/aliases @@ -3,3 +3,4 @@ shippable/posix/group2 skip/freebsd skip/osx skip/macos +context/controller diff --git a/test/integration/targets/failed_when/aliases b/test/integration/targets/failed_when/aliases index 765b70da..90ea9e12 100644 --- a/test/integration/targets/failed_when/aliases +++ b/test/integration/targets/failed_when/aliases @@ -1 +1,2 @@ shippable/posix/group2 +context/controller diff --git a/test/integration/targets/failed_when/tasks/main.yml b/test/integration/targets/failed_when/tasks/main.yml index 3f8ae545..1b10bef1 100644 --- a/test/integration/targets/failed_when/tasks/main.yml +++ b/test/integration/targets/failed_when/tasks/main.yml @@ -66,3 +66,15 @@ that: - "'failed' in result and not result.failed" - "'failed_when_result' in result and not result.failed_when_result" + +- name: invalid conditional + command: echo foo + failed_when: boomboomboom + register: invalid_conditional + ignore_errors: true + +- assert: + that: + - invalid_conditional is failed + - invalid_conditional.stdout is defined + - invalid_conditional.failed_when_result is contains('boomboomboom') diff --git a/test/integration/targets/fetch/aliases b/test/integration/targets/fetch/aliases index fb5d6faa..ff56593d 100644 --- a/test/integration/targets/fetch/aliases +++ b/test/integration/targets/fetch/aliases @@ -1,2 +1,3 @@ shippable/posix/group2 needs/target/setup_remote_tmp_dir +needs/ssh diff --git a/test/integration/targets/fetch/cleanup.yml b/test/integration/targets/fetch/cleanup.yml new file mode 100644 index 00000000..792b603c --- /dev/null +++ b/test/integration/targets/fetch/cleanup.yml @@ -0,0 +1,16 @@ +- name: Cleanup user account + hosts: testhost + + tasks: + - name: remove test user + user: + name: fetcher + state: absent + remove: yes + force: yes + + - name: delete temporary directory + file: + path: "{{ remote_tmp_dir }}" + state: absent + no_log: yes diff --git a/test/integration/targets/fetch/roles/fetch_tests/defaults/main.yml b/test/integration/targets/fetch/roles/fetch_tests/defaults/main.yml new file mode 100644 index 00000000..f0b9cfc4 --- /dev/null +++ b/test/integration/targets/fetch/roles/fetch_tests/defaults/main.yml @@ -0,0 +1 @@ +skip_cleanup: no diff --git a/test/integration/targets/fetch/roles/fetch_tests/handlers/main.yml b/test/integration/targets/fetch/roles/fetch_tests/handlers/main.yml new file mode 100644 index 00000000..c6c296af --- /dev/null +++ b/test/integration/targets/fetch/roles/fetch_tests/handlers/main.yml @@ -0,0 +1,8 @@ +- name: remove test user + user: + name: fetcher + state: absent + remove: yes + force: yes + become: yes + when: not skip_cleanup | bool diff --git a/test/integration/targets/fetch/roles/fetch_tests/tasks/fail_on_missing.yml b/test/integration/targets/fetch/roles/fetch_tests/tasks/fail_on_missing.yml new file mode 100644 index 00000000..d918aaeb --- /dev/null +++ b/test/integration/targets/fetch/roles/fetch_tests/tasks/fail_on_missing.yml @@ -0,0 +1,53 @@ +- name: Attempt to fetch a non-existent file - do not fail on missing + fetch: + src: "{{ remote_tmp_dir }}/doesnotexist" + dest: "{{ output_dir }}/fetched" + fail_on_missing: no + register: fetch_missing_nofail + +- name: Attempt to fetch a non-existent file - fail on missing + fetch: + src: "{{ remote_tmp_dir }}/doesnotexist" + dest: "{{ output_dir }}/fetched" + fail_on_missing: yes + register: fetch_missing + ignore_errors: yes + +- name: Attempt to fetch a non-existent file - fail on missing implicit + fetch: + src: "{{ remote_tmp_dir }}/doesnotexist" + dest: "{{ output_dir }}/fetched" + register: fetch_missing_implicit + ignore_errors: yes + +- name: Attempt to fetch a directory - should not fail but return a message + fetch: + src: "{{ remote_tmp_dir }}" + dest: "{{ output_dir }}/somedir" + fail_on_missing: no + register: fetch_dir + +- name: Attempt to fetch a directory - should fail + fetch: + src: "{{ remote_tmp_dir }}" + dest: "{{ output_dir }}/somedir" + fail_on_missing: yes + register: failed_fetch_dir + ignore_errors: yes + +- name: Check fetch missing with failure with implicit fail + assert: + that: + - fetch_missing_nofail.msg is search('ignored') + - fetch_missing_nofail is not changed + - fetch_missing is failed + - fetch_missing is not changed + - fetch_missing.msg is search ('remote file does not exist') + - fetch_missing_implicit is failed + - fetch_missing_implicit is not changed + - fetch_missing_implicit.msg is search ('remote file does not exist') + - fetch_dir is not changed + - fetch_dir.msg is search('is a directory') + - failed_fetch_dir is failed + - failed_fetch_dir is not changed + - failed_fetch_dir.msg is search('is a directory') diff --git a/test/integration/targets/fetch/roles/fetch_tests/tasks/failures.yml b/test/integration/targets/fetch/roles/fetch_tests/tasks/failures.yml new file mode 100644 index 00000000..8a6b5b7b --- /dev/null +++ b/test/integration/targets/fetch/roles/fetch_tests/tasks/failures.yml @@ -0,0 +1,41 @@ +- name: Fetch with no parameters + fetch: + register: fetch_no_params + ignore_errors: yes + +- name: Fetch with incorrect source type + fetch: + src: [1, 2] + dest: "{{ output_dir }}/fetched" + register: fetch_incorrect_src + ignore_errors: yes + +- name: Try to fetch a file inside an inaccessible directory + fetch: + src: "{{ remote_tmp_dir }}/noaccess/file1" + dest: "{{ output_dir }}" + register: failed_fetch_no_access + become: yes + become_user: fetcher + become_method: su + ignore_errors: yes + +- name: Dest is an existing directory name without trailing slash and flat=yes, should fail + fetch: + src: "{{ remote_tmp_dir }}/orig" + dest: "{{ output_dir }}" + flat: yes + register: failed_fetch_dest_dir + ignore_errors: true + +- name: Ensure fetch failed + assert: + that: + - fetch_no_params is failed + - fetch_no_params.msg is search('src and dest are required') + - fetch_incorrect_src is failed + - fetch_incorrect_src.msg is search('Invalid type supplied for source') + - failed_fetch_no_access is failed + - failed_fetch_no_access.msg is search('file is not readable') + - failed_fetch_dest_dir is failed + - failed_fetch_dest_dir.msg is search('dest is an existing directory') diff --git a/test/integration/targets/fetch/roles/fetch_tests/tasks/main.yml b/test/integration/targets/fetch/roles/fetch_tests/tasks/main.yml index 267ae0f0..eefe95c8 100644 --- a/test/integration/targets/fetch/roles/fetch_tests/tasks/main.yml +++ b/test/integration/targets/fetch/roles/fetch_tests/tasks/main.yml @@ -1,141 +1,5 @@ -# test code for the pip module -# (c) 2014, Michael DeHaan <michael.dehaan@gmail.com> - -# This file is part of Ansible -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see <http://www.gnu.org/licenses/>. - -- name: create a file that we can use to fetch - copy: content="test" dest={{ remote_tmp_dir }}/orig - -- name: fetch the test file - fetch: src={{ remote_tmp_dir }}/orig dest={{ output_dir }}/fetched - register: fetched - -- debug: var=fetched - -- name: Assert that we fetched correctly - assert: - that: - - 'fetched["changed"] == True' - - 'fetched["checksum"] == "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3"' - - 'fetched["remote_checksum"] == "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3"' - - 'lookup("file", output_dir + "/fetched/" + inventory_hostname + remote_tmp_dir + "/orig") == "test"' - -# TODO: check the become and non-become forms of fetch because in one form we'll do -# the get method of the connection plugin and in the become case we'll use the -# fetch module. - -- name: fetch a second time to show idempotence - fetch: src={{ remote_tmp_dir }}/orig dest={{ output_dir }}/fetched - register: fetched - -- name: Assert that the file was not fetched the second time - assert: - that: - - 'fetched["changed"] == False' - - 'fetched["checksum"] == "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3"' - -- name: attempt to fetch a non-existent file - do not fail on missing - fetch: src={{ remote_tmp_dir }}/doesnotexist dest={{ output_dir }}/fetched fail_on_missing=False - register: fetch_missing_nofail - -- name: check fetch missing no fail result - assert: - that: - - "fetch_missing_nofail.msg" - - "fetch_missing_nofail is not changed" - -- name: attempt to fetch a non-existent file - fail on missing - fetch: src={{ remote_tmp_dir }}/doesnotexist dest={{ output_dir }}/fetched fail_on_missing=yes - register: fetch_missing - ignore_errors: true - -- name: check fetch missing with failure - assert: - that: - - "fetch_missing is failed" - - "fetch_missing.msg" - - "fetch_missing is not changed" - -- name: attempt to fetch a non-existent file - fail on missing implicit - fetch: src={{ remote_tmp_dir }}/doesnotexist dest={{ output_dir }}/fetched - register: fetch_missing_implicit - ignore_errors: true - -- name: check fetch missing with failure with implicit fail - assert: - that: - - "fetch_missing_implicit is failed" - - "fetch_missing_implicit.msg" - - "fetch_missing_implicit is not changed" - -- name: attempt to fetch a directory - should not fail but return a message - fetch: src={{ remote_tmp_dir }} dest={{ output_dir }}/somedir fail_on_missing=False - register: fetch_dir - -- name: check fetch directory result - assert: - that: - - "fetch_dir is not changed" - - "fetch_dir.msg" - -- name: attempt to fetch a directory - should fail - fetch: src={{ remote_tmp_dir }} dest={{ output_dir }}/somedir fail_on_missing=True - register: failed_fetch_dir - ignore_errors: true - -- name: check fetch directory result - assert: - that: - - "failed_fetch_dir is failed" - - "fetch_dir.msg" - -- name: create symlink to a file that we can fetch - file: - path: "{{ remote_tmp_dir }}/link" - src: "{{ remote_tmp_dir }}/orig" - state: "link" - -- name: fetch the file via a symlink - fetch: src={{ remote_tmp_dir }}/link dest={{ output_dir }}/fetched-link - register: fetched - -- debug: var=fetched - -- name: Assert that we fetched correctly - assert: - that: - - 'fetched["changed"] == True' - - 'fetched["checksum"] == "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3"' - - 'fetched["remote_checksum"] == "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3"' - - 'lookup("file", output_dir + "/fetched-link/" + inventory_hostname + remote_tmp_dir + "/link") == "test"' - -# TODO: check the become and non-become forms of fetch because in one form we'll do -# the get method of the connection plugin and in the become case we'll use the -# fetch module. - -- name: dest is an existing directory name without trailing slash and flat=yes, should fail - fetch: - src: "{{ remote_tmp_dir }}/orig" - dest: "{{ output_dir }}" - flat: yes - register: failed_fetch_dest_dir - ignore_errors: true - -- name: check that it indeed failed - assert: - that: - - "failed_fetch_dest_dir is failed" - - "failed_fetch_dest_dir.msg" +- import_tasks: setup.yml +- import_tasks: normal.yml +- import_tasks: symlink.yml +- import_tasks: fail_on_missing.yml +- import_tasks: failures.yml diff --git a/test/integration/targets/fetch/roles/fetch_tests/tasks/normal.yml b/test/integration/targets/fetch/roles/fetch_tests/tasks/normal.yml new file mode 100644 index 00000000..6f3ab620 --- /dev/null +++ b/test/integration/targets/fetch/roles/fetch_tests/tasks/normal.yml @@ -0,0 +1,38 @@ +- name: Fetch the test file + fetch: src={{ remote_tmp_dir }}/orig dest={{ output_dir }}/fetched + register: fetched + +- name: Fetch a second time to show no changes + fetch: src={{ remote_tmp_dir }}/orig dest={{ output_dir }}/fetched + register: fetched_again + +- name: Fetch the test file in check mode + fetch: + src: "{{ remote_tmp_dir }}/orig" + dest: "{{ output_dir }}/fetched" + check_mode: yes + register: fetch_check_mode + +- name: Fetch with dest ending in path sep + fetch: + src: "{{ remote_tmp_dir }}/orig" + dest: "{{ output_dir }}/" + flat: yes + +- name: Fetch with dest with relative path + fetch: + src: "{{ remote_tmp_dir }}/orig" + dest: "{{ output_dir[1:] }}" + flat: yes + +- name: Assert that we fetched correctly + assert: + that: + - fetched is changed + - fetched.checksum == "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3" + - fetched_again is not changed + - fetched_again.checksum == "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3" + - fetched.remote_checksum == "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3" + - lookup("file", output_dir + "/fetched/" + inventory_hostname + remote_tmp_dir + "/orig") == "test" + - fetch_check_mode is skipped + - fetch_check_mode.msg is search('not \(yet\) supported') diff --git a/test/integration/targets/fetch/roles/fetch_tests/tasks/setup.yml b/test/integration/targets/fetch/roles/fetch_tests/tasks/setup.yml new file mode 100644 index 00000000..89b94c46 --- /dev/null +++ b/test/integration/targets/fetch/roles/fetch_tests/tasks/setup.yml @@ -0,0 +1,45 @@ +- name: Include system specific variables + include_vars: "{{ lookup('first_found', params) }}" + vars: + params: + files: + - "{{ ansible_facts.system }}.yml" + - default.yml + paths: + - "{{ role_path }}/vars" + +- name: Work-around for locked users on Alpine + # see https://github.com/ansible/ansible/issues/68676 + set_fact: + password: '*' + when: ansible_distribution == 'Alpine' + +- name: Create test user + user: + name: fetcher + create_home: yes + groups: "{{ _fetch_additional_groups | default(omit) }}" + append: "{{ True if _fetch_additional_groups else False }}" + password: "{{ password | default(omit) }}" + become: yes + notify: + - remove test user + +- name: Create a file that we can use to fetch + copy: + content: "test" + dest: "{{ remote_tmp_dir }}/orig" + +- name: Create symlink to a file that we can fetch + file: + path: "{{ remote_tmp_dir }}/link" + src: "{{ remote_tmp_dir }}/orig" + state: "link" + +- name: Create an inaccessible directory + file: + path: "{{ remote_tmp_dir }}/noaccess" + state: directory + mode: '0600' + owner: root + become: yes diff --git a/test/integration/targets/fetch/roles/fetch_tests/tasks/symlink.yml b/test/integration/targets/fetch/roles/fetch_tests/tasks/symlink.yml new file mode 100644 index 00000000..41d7b35a --- /dev/null +++ b/test/integration/targets/fetch/roles/fetch_tests/tasks/symlink.yml @@ -0,0 +1,13 @@ +- name: Fetch the file via a symlink + fetch: + src: "{{ remote_tmp_dir }}/link" + dest: "{{ output_dir }}/fetched-link" + register: fetched_symlink + +- name: Assert that we fetched correctly + assert: + that: + - fetched_symlink is changed + - fetched_symlink.checksum == "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3" + - fetched_symlink.remote_checksum == "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3" + - 'lookup("file", output_dir + "/fetched-link/" + inventory_hostname + remote_tmp_dir + "/link") == "test"' diff --git a/test/integration/targets/fetch/roles/fetch_tests/vars/Darwin.yml b/test/integration/targets/fetch/roles/fetch_tests/vars/Darwin.yml new file mode 100644 index 00000000..0654b711 --- /dev/null +++ b/test/integration/targets/fetch/roles/fetch_tests/vars/Darwin.yml @@ -0,0 +1,3 @@ +# macOS requires users to be in an additional group for ssh access + +_fetch_additional_groups: com.apple.access_ssh diff --git a/test/integration/targets/fetch/roles/fetch_tests/vars/default.yml b/test/integration/targets/fetch/roles/fetch_tests/vars/default.yml new file mode 100644 index 00000000..69d7958d --- /dev/null +++ b/test/integration/targets/fetch/roles/fetch_tests/vars/default.yml @@ -0,0 +1 @@ +_fetch_additional_groups: [] diff --git a/test/integration/targets/fetch/runme.sh b/test/integration/targets/fetch/runme.sh index 7e909dde..a508a0a6 100755 --- a/test/integration/targets/fetch/runme.sh +++ b/test/integration/targets/fetch/runme.sh @@ -2,11 +2,33 @@ set -eux +function cleanup { + ansible-playbook -i "${INVENTORY_PATH}" cleanup.yml -e "output_dir=${OUTPUT_DIR}" -b "$@" + unset ANSIBLE_CACHE_PLUGIN + unset ANSIBLE_CACHE_PLUGIN_CONNECTION +} + +trap 'cleanup "$@"' EXIT + # setup required roles ln -s ../../setup_remote_tmp_dir roles/setup_remote_tmp_dir # run old type role tests -ansible-playbook -i ../../inventory run_fetch_tests.yml -e "output_dir=${OUTPUT_DIR}" -v "$@" +ansible-playbook -i ../../inventory run_fetch_tests.yml -e "output_dir=${OUTPUT_DIR}" "$@" + +# run same test with become +ansible-playbook -i ../../inventory run_fetch_tests.yml -e "output_dir=${OUTPUT_DIR}" -b "$@" # run tests to avoid path injection from slurp when fetch uses become -ansible-playbook -i ../../inventory injection/avoid_slurp_return.yml -e "output_dir=${OUTPUT_DIR}" -v "$@" +ansible-playbook -i ../../inventory injection/avoid_slurp_return.yml -e "output_dir=${OUTPUT_DIR}" "$@" + +## Test unreadable file with stat. Requires running without become and as a user other than root. +# +# Change the known_hosts file to avoid changing the test environment +export ANSIBLE_CACHE_PLUGIN=jsonfile +export ANSIBLE_CACHE_PLUGIN_CONNECTION="${OUTPUT_DIR}/cache" +# Create a non-root user account and configure SSH acccess for that account +ansible-playbook -i "${INVENTORY_PATH}" setup_unreadable_test.yml -e "output_dir=${OUTPUT_DIR}" "$@" + +# Run the tests as the unprivileged user without become to test the use of the stat module from the fetch module +ansible-playbook -i "${INVENTORY_PATH}" test_unreadable_with_stat.yml -e ansible_user=fetcher -e ansible_become=no -e "output_dir=${OUTPUT_DIR}" "$@" diff --git a/test/integration/targets/fetch/setup_unreadable_test.yml b/test/integration/targets/fetch/setup_unreadable_test.yml new file mode 100644 index 00000000..f4cc8c1e --- /dev/null +++ b/test/integration/targets/fetch/setup_unreadable_test.yml @@ -0,0 +1,40 @@ +- name: Create a user account and configure ssh access + hosts: testhost + gather_facts: no + + tasks: + - import_role: + name: fetch_tests + tasks_from: setup.yml + vars: + # Keep the remote temp dir and cache the remote_tmp_dir fact. The directory itself + # and the fact that contains the path are needed in a separate ansible-playbook run. + setup_remote_tmp_dir_skip_cleanup: yes + setup_remote_tmp_dir_cache_path: yes + skip_cleanup: yes + + # This prevents ssh access. It is fixed in some container images but not all. + # https://github.com/ansible/distro-test-containers/pull/70 + - name: Remove /run/nologin + file: + path: /run/nologin + state: absent + + # Setup ssh access for the unprivileged user. + - name: Get home directory for temporary user + command: echo ~fetcher + register: fetcher_home + + - name: Create .ssh dir + file: + path: "{{ fetcher_home.stdout }}/.ssh" + state: directory + owner: fetcher + mode: '0700' + + - name: Configure authorized_keys + copy: + src: "~root/.ssh/authorized_keys" + dest: "{{ fetcher_home.stdout }}/.ssh/authorized_keys" + owner: fetcher + mode: '0600' diff --git a/test/integration/targets/fetch/test_unreadable_with_stat.yml b/test/integration/targets/fetch/test_unreadable_with_stat.yml new file mode 100644 index 00000000..c8a0145c --- /dev/null +++ b/test/integration/targets/fetch/test_unreadable_with_stat.yml @@ -0,0 +1,36 @@ +# This playbook needs to be run as a non-root user without become. Under +# those circumstances, the fetch module uses stat and not slurp. + +- name: Test unreadable file using stat + hosts: testhost + gather_facts: no + + tasks: + - name: Check connectivity + command: whoami + register: whoami + + - name: Verify user + assert: + that: + - whoami.stdout == 'fetcher' + + - name: Try to fetch a file inside an inaccessible directory + fetch: + src: "{{ remote_tmp_dir }}/noaccess/file1" + dest: "{{ output_dir }}" + register: failed_fetch_no_access + ignore_errors: yes + + - name: Try to fetch a file inside an inaccessible directory without fail_on_missing + fetch: + src: "{{ remote_tmp_dir }}/noaccess/file1" + dest: "{{ output_dir }}" + fail_on_missing: no + register: failed_fetch_no_access_fail_on_missing + + - assert: + that: + - failed_fetch_no_access is failed + - failed_fetch_no_access.msg is search('Permission denied') + - failed_fetch_no_access_fail_on_missing.msg is search(', ignored') diff --git a/test/integration/targets/file/handlers/main.yml b/test/integration/targets/file/handlers/main.yml index b5040f6e..553f69ce 100644 --- a/test/integration/targets/file/handlers/main.yml +++ b/test/integration/targets/file/handlers/main.yml @@ -3,6 +3,7 @@ name: "{{ item }}" state: absent remove: yes + force: yes loop: - test1 - test_uid diff --git a/test/integration/targets/file/tasks/directory_as_dest.yml b/test/integration/targets/file/tasks/directory_as_dest.yml index 9b6ddb5d..85451e43 100644 --- a/test/integration/targets/file/tasks/directory_as_dest.yml +++ b/test/integration/targets/file/tasks/directory_as_dest.yml @@ -1,6 +1,6 @@ # File module tests for overwriting directories - name: Initialize the test output dir - include: initialize.yml + import_tasks: initialize.yml # We need to make this more consistent: # https://github.com/ansible/proposals/issues/111 diff --git a/test/integration/targets/file/tasks/main.yml b/test/integration/targets/file/tasks/main.yml index 565afa02..c96beba3 100644 --- a/test/integration/targets/file/tasks/main.yml +++ b/test/integration/targets/file/tasks/main.yml @@ -91,7 +91,10 @@ - "file2_result.state == 'absent'" - name: verify we can touch a file - file: path={{output_dir}}/baz.txt state=touch + file: + path: "{{output_dir}}/baz.txt" + state: touch + mode: '0644' register: file3_result - name: verify that the file was marked as changed diff --git a/test/integration/targets/file/tasks/selinux_tests.yml b/test/integration/targets/file/tasks/selinux_tests.yml index 6a95c442..8efe8195 100644 --- a/test/integration/targets/file/tasks/selinux_tests.yml +++ b/test/integration/targets/file/tasks/selinux_tests.yml @@ -17,7 +17,7 @@ # along with Ansible. If not, see <http://www.gnu.org/licenses/>. - name: Initialize the test output dir - include: initialize.yml + import_tasks: initialize.yml - name: touch a file for testing file: path={{output_dir}}/foo-se.txt state=touch diff --git a/test/integration/targets/file/tasks/state_link.yml b/test/integration/targets/file/tasks/state_link.yml index d84bb310..851b213e 100644 --- a/test/integration/targets/file/tasks/state_link.yml +++ b/test/integration/targets/file/tasks/state_link.yml @@ -1,7 +1,7 @@ # file module tests for dealing with symlinks (state=link) - name: Initialize the test output dir - include: initialize.yml + import_tasks: initialize.yml # # Basic absolute symlink to a file @@ -181,6 +181,8 @@ user: name: '{{ remote_unprivileged_user }}' state: absent + force: yes + remove: yes - name: Delete unprivileged user home and tempdir file: diff --git a/test/integration/targets/filter_core/aliases b/test/integration/targets/filter_core/aliases index 1603f435..765b70da 100644 --- a/test/integration/targets/filter_core/aliases +++ b/test/integration/targets/filter_core/aliases @@ -1,3 +1 @@ shippable/posix/group2 -skip/python2.6 # filters are controller only, and we no longer support Python 2.6 on the controller -skip/aix diff --git a/test/integration/targets/filter_core/tasks/main.yml b/test/integration/targets/filter_core/tasks/main.yml index 8ab9d446..5a5d813f 100644 --- a/test/integration/targets/filter_core/tasks/main.yml +++ b/test/integration/targets/filter_core/tasks/main.yml @@ -283,6 +283,7 @@ multi_line: "{{ 'hello\nworld' | regex_search('^world', multiline=true) }}" named_groups: "{{ 'goodbye' | regex_search('(?P<first>good)(?P<second>bye)', '\\g<second>', '\\g<first>') }}" numbered_groups: "{{ 'goodbye' | regex_search('(good)(bye)', '\\2', '\\1') }}" + no_match_is_none_inline: "{{ 'hello' | regex_search('world') == none }}" - name: regex_search unknown argument (failure expected) set_fact: @@ -299,6 +300,7 @@ - multi_line == 'world' - named_groups == ['bye', 'good'] - numbered_groups == ['bye', 'good'] + - no_match_is_none_inline - failure is failed - name: Verify to_bool @@ -378,6 +380,18 @@ - "2|from_yaml == 2" - "'---\nbananas: yellow\n---\napples: red'|from_yaml_all|list == [{'bananas': 'yellow'}, {'apples': 'red'}]" - "2|from_yaml_all == 2" + - "unsafe_fruit|from_yaml == {'bananas': 'yellow', 'apples': 'red'}" + - "unsafe_fruit_all|from_yaml_all|list == [{'bananas': 'yellow'}, {'apples': 'red'}]" + vars: + unsafe_fruit: !unsafe | + --- + bananas: yellow + apples: red + unsafe_fruit_all: !unsafe | + --- + bananas: yellow + --- + apples: red - name: Verify random raises on non-iterable input (failure expected) set_fact: @@ -435,7 +449,7 @@ - name: Verify password_hash assert: that: - - "'what in the WORLD is up?'|password_hash|length == 106" + - "'what in the WORLD is up?'|password_hash|length == 120 or 'what in the WORLD is up?'|password_hash|length == 106" # This throws a vastly different error on py2 vs py3, so we just check # that it's a failure, not a substring of the exception. - password_hash_1 is failed @@ -480,6 +494,39 @@ - mandatory_2 is failed - "mandatory_2.msg == 'You did not give me a variable. I am a sad wolf.'" +- name: Verify undef throws if resolved + set_fact: + foo: '{{ fail_foo }}' + vars: + fail_foo: '{{ undef("Expected failure") }}' + ignore_errors: yes + register: fail_1 + +- name: Setup fail_foo for overriding in test + block: + - name: Verify undef not executed if overridden + set_fact: + foo: '{{ fail_foo }}' + vars: + fail_foo: 'overridden value' + register: fail_2 + vars: + fail_foo: '{{ undef(hint="Expected failure") }}' + +- name: Verify undef is inspectable + debug: + var: fail_foo + vars: + fail_foo: '{{ undef("Expected failure") }}' + register: fail_3 + +- name: Verify undef + assert: + that: + - fail_1 is failed + - not (fail_2 is failed) + - not (fail_3 is failed) + - name: Verify comment assert: that: diff --git a/test/integration/targets/filter_encryption/aliases b/test/integration/targets/filter_encryption/aliases new file mode 100644 index 00000000..765b70da --- /dev/null +++ b/test/integration/targets/filter_encryption/aliases @@ -0,0 +1 @@ +shippable/posix/group2 diff --git a/test/integration/targets/filter_encryption/base.yml b/test/integration/targets/filter_encryption/base.yml new file mode 100644 index 00000000..8bf25f77 --- /dev/null +++ b/test/integration/targets/filter_encryption/base.yml @@ -0,0 +1,37 @@ +- hosts: localhost + gather_facts: true + vars: + data: secret + dvault: '{{ "secret"|vault("test")}}' + password: test + s_32: '{{(2**31-1)}}' + s_64: '{{(2**63-1)}}' + vaultedstring_32: "$ANSIBLE_VAULT;1.2;AES256;filter_default\n33360a30386436633031333665316161303732656333373131373935623033393964633637346464\n6234613765313539306138373564366363306533356464613334320a666339363037303764636538\n3131633564326637303237313463613864626231\n" + vaultedstring_64: "$ANSIBLE_VAULT;1.2;AES256;filter_default\n33370a34333734353636633035656232613935353432656132646533346233326431346232616261\n6133383034376566366261316365633931356133633337396363370a376664386236313834326561\n6338373864623763613165366636633031303739\n" + vault: !vault | + $ANSIBLE_VAULT;1.1;AES256 + 33323332333033383335333533383338333333303339333733323339333833303334333133313339 + 33373339333133323331333833373335333933323338333633343338333133343334333733383334 + 33333335333433383337333133303339333433353332333333363339333733363335333233303330 + 3337333733353331333633313335333733373334333733320a373938666533366165653830313163 + 62386564343438653437333564383664646538653364343138303831613039313232636437336530 + 3438376662373764650a633366646563386335623161646262366137393635633464333265613938 + 6661 + # allow testing against 32b/64b limited archs, normally you can set higher values for random (2**256) + is_64: '{{ "64" in ansible_facts["architecture"] }}' + salt: '{{ is_64|bool|ternary(s_64, s_32)|random(seed=inventory_hostname)}}' + vaultedstring: '{{ is_64|bool|ternary(vaultedstring_64, vaultedstring_32) }}' + + tasks: + - name: check vaulting + assert: + that: + - data|vault(password, salt=salt) == vaultedstring + - "data|vault(password, salt=salt)|type_debug != 'AnsibleVaultEncryptedUnicode'" + - "data|vault(password, salt=salt, wrap_object=True)|type_debug == 'AnsibleVaultEncryptedUnicode'" + + - name: check unvaulting + assert: + that: + - vaultedstring|unvault(password) == data + - vault|unvault(password) == data diff --git a/test/integration/targets/filter_encryption/runme.sh b/test/integration/targets/filter_encryption/runme.sh new file mode 100755 index 00000000..41b30b1d --- /dev/null +++ b/test/integration/targets/filter_encryption/runme.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -eux + +ANSIBLE_GATHER_SUBSET='min' ansible-playbook base.yml "$@" diff --git a/test/integration/targets/filter_mathstuff/aliases b/test/integration/targets/filter_mathstuff/aliases index 1603f435..765b70da 100644 --- a/test/integration/targets/filter_mathstuff/aliases +++ b/test/integration/targets/filter_mathstuff/aliases @@ -1,3 +1 @@ shippable/posix/group2 -skip/python2.6 # filters are controller only, and we no longer support Python 2.6 on the controller -skip/aix diff --git a/test/integration/targets/filter_mathstuff/host_vars/localhost.yml b/test/integration/targets/filter_mathstuff/host_vars/localhost.yml new file mode 100644 index 00000000..1f5a9e03 --- /dev/null +++ b/test/integration/targets/filter_mathstuff/host_vars/localhost.yml @@ -0,0 +1 @@ +foo: test diff --git a/test/integration/targets/filter_mathstuff/runme.sh b/test/integration/targets/filter_mathstuff/runme.sh new file mode 100755 index 00000000..36503003 --- /dev/null +++ b/test/integration/targets/filter_mathstuff/runme.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +set -eux + +export ANSIBLE_ROLES_PATH=../ + +ansible-playbook runme.yml "$@" + +source virtualenv.sh + +# Install Jinja < 2.10 since we want to test the fallback to Ansible's custom +# unique filter. Jinja < 2.10 does not have do_unique so we will trigger the +# fallback. +pip install 'jinja2 < 2.10' + +# Run the playbook again in the venv with Jinja < 2.10 +ansible-playbook runme.yml "$@" diff --git a/test/integration/targets/filter_mathstuff/runme.yml b/test/integration/targets/filter_mathstuff/runme.yml new file mode 100644 index 00000000..a1eaef7a --- /dev/null +++ b/test/integration/targets/filter_mathstuff/runme.yml @@ -0,0 +1,4 @@ +- hosts: localhost + gather_facts: false + roles: + - { role: filter_mathstuff } diff --git a/test/integration/targets/filter_mathstuff/tasks/main.yml b/test/integration/targets/filter_mathstuff/tasks/main.yml index 2a708be1..019f00e4 100644 --- a/test/integration/targets/filter_mathstuff/tasks/main.yml +++ b/test/integration/targets/filter_mathstuff/tasks/main.yml @@ -1,6 +1,6 @@ -- name: Verify unique's fallback's exception throwing for case_sensitive=True +- name: Verify unique's fallback's exception throwing for case_sensitive=False set_fact: - unique_fallback_exc1: '{{ [{"foo": "bar", "moo": "cow"}]|unique(case_sensitive=True) }}' + unique_fallback_exc1: '{{ [{"foo": "bar", "moo": "cow"}]|unique(case_sensitive=False) }}' ignore_errors: true tags: unique register: unique_fallback_exc1_res @@ -67,6 +67,11 @@ - '[1,2,3]|intersect([3,2,1]) == [1,2,3]' - '(1,2,3)|intersect((4,5,6))|list == []' - '(1,2,3)|intersect((3,4,5,6))|list == [3]' + - '["a","A","b"]|intersect(["B","c","C"]) == []' + - '["a","A","b"]|intersect(["b","B","c","C"]) == ["b"]' + - '["a","A","b"]|intersect(["b","A","a"]) == ["a","A","b"]' + - '("a","A","b")|intersect(("B","c","C"))|list == []' + - '("a","A","b")|intersect(("b","B","c","C"))|list == ["b"]' - name: Verify difference tags: difference @@ -77,6 +82,11 @@ - '[1,2,3]|difference([3,2,1]) == []' - '(1,2,3)|difference((4,5,6))|list == [1,2,3]' - '(1,2,3)|difference((3,4,5,6))|list == [1,2]' + - '["a","A","b"]|difference(["B","c","C"]) == ["a","A","b"]' + - '["a","A","b"]|difference(["b","B","c","C"]) == ["a","A"]' + - '["a","A","b"]|difference(["b","A","a"]) == []' + - '("a","A","b")|difference(("B","c","C"))|list|sort(case_sensitive=True) == ["A","a","b"]' + - '("a","A","b")|difference(("b","B","c","C"))|list|sort(case_sensitive=True) == ["A","a"]' - name: Verify symmetric_difference tags: symmetric_difference @@ -87,6 +97,11 @@ - '[1,2,3]|symmetric_difference([3,2,1]) == []' - '(1,2,3)|symmetric_difference((4,5,6))|list == [1,2,3,4,5,6]' - '(1,2,3)|symmetric_difference((3,4,5,6))|list == [1,2,4,5,6]' + - '["a","A","b"]|symmetric_difference(["B","c","C"]) == ["a","A","b","B","c","C"]' + - '["a","A","b"]|symmetric_difference(["b","B","c","C"]) == ["a","A","B","c","C"]' + - '["a","A","b"]|symmetric_difference(["b","A","a"]) == []' + - '("a","A","b")|symmetric_difference(("B","c","C"))|list|sort(case_sensitive=True) == ["A","B","C","a","b","c"]' + - '("a","A","b")|symmetric_difference(("b","B","c","C"))|list|sort(case_sensitive=True) == ["A","B","C","a","c"]' - name: Verify union tags: union @@ -97,6 +112,11 @@ - '[1,2,3]|union([3,2,1]) == [1,2,3]' - '(1,2,3)|union((4,5,6))|list == [1,2,3,4,5,6]' - '(1,2,3)|union((3,4,5,6))|list == [1,2,3,4,5,6]' + - '["a","A","b"]|union(["B","c","C"]) == ["a","A","b","B","c","C"]' + - '["a","A","b"]|union(["b","B","c","C"]) == ["a","A","b","B","c","C"]' + - '["a","A","b"]|union(["b","A","a"]) == ["a","A","b"]' + - '("a","A","b")|union(("B","c","C"))|list|sort(case_sensitive=True) == ["A","B","C","a","b","c"]' + - '("a","A","b")|union(("b","B","c","C"))|list|sort(case_sensitive=True) == ["A","B","C","a","b","c"]' - name: Verify min tags: min @@ -281,6 +301,18 @@ - rekey_on_member_exc5_res is failed - '"is not unique, cannot correctly turn into dict" in rekey_on_member_exc5_res.msg' +- name: test undefined positional args for rekey_on_member are properly handled + vars: + all_vars: "{{ hostvars[inventory_hostname] }}" + test_var: "{{ all_vars.foo }}" + block: + - include_vars: + file: defined_later.yml + - assert: + that: "test_var == 'test'" + - assert: + that: "rekeyed == {'value': {'test': 'value'}}" + # TODO: For some reason, the coverage tool isn't accounting for the last test # so add another "last test" to fake it... - assert: diff --git a/test/integration/targets/filter_mathstuff/vars/defined_later.yml b/test/integration/targets/filter_mathstuff/vars/defined_later.yml new file mode 100644 index 00000000..dfb2421b --- /dev/null +++ b/test/integration/targets/filter_mathstuff/vars/defined_later.yml @@ -0,0 +1,3 @@ +do_rekey: + - test: value +rekeyed: "{{ do_rekey | rekey_on_member(defined_later) }}" diff --git a/test/integration/targets/filter_mathstuff/vars/main.yml b/test/integration/targets/filter_mathstuff/vars/main.yml new file mode 100644 index 00000000..bb61e12e --- /dev/null +++ b/test/integration/targets/filter_mathstuff/vars/main.yml @@ -0,0 +1 @@ +defined_later: "{{ test_var }}" diff --git a/test/integration/targets/filter_urls/aliases b/test/integration/targets/filter_urls/aliases index 1603f435..765b70da 100644 --- a/test/integration/targets/filter_urls/aliases +++ b/test/integration/targets/filter_urls/aliases @@ -1,3 +1 @@ shippable/posix/group2 -skip/python2.6 # filters are controller only, and we no longer support Python 2.6 on the controller -skip/aix diff --git a/test/integration/targets/filter_urlsplit/aliases b/test/integration/targets/filter_urlsplit/aliases index 1603f435..765b70da 100644 --- a/test/integration/targets/filter_urlsplit/aliases +++ b/test/integration/targets/filter_urlsplit/aliases @@ -1,3 +1 @@ shippable/posix/group2 -skip/python2.6 # filters are controller only, and we no longer support Python 2.6 on the controller -skip/aix diff --git a/test/integration/targets/find/tasks/main.yml b/test/integration/targets/find/tasks/main.yml index 91d92471..366ef312 100644 --- a/test/integration/targets/find/tasks/main.yml +++ b/test/integration/targets/find/tasks/main.yml @@ -207,7 +207,8 @@ - assert: that: - failed_path.files == [] - - failed_path.msg.startswith("Skipped '{{mypath}}' path due to this access issue") + - 'failed_path.msg == "Not all paths examined, check warnings for details"' + - mypath in failed_path.skipped_paths - name: test number of examined directories/files block: @@ -272,3 +273,116 @@ assert: that: - '"{{ output_dir_test }}/e/f/g/h/8.ogg" not in find_test3_list' + +- name: create our age/size testing sub-directory + file: + path: "{{ output_dir_test }}/astest" + state: directory + +- name: create test file with old timestamps + file: + path: "{{ output_dir_test }}/astest/old.txt" + state: touch + modification_time: "202001011200.0" + +- name: create test file with current timestamps + file: + path: "{{ output_dir_test }}/astest/new.txt" + state: touch + +- name: create hidden test file with current timestamps + file: + path: "{{ output_dir_test }}/astest/.hidden.txt" + state: touch + +- name: find files older than 1 week + find: + path: "{{ output_dir_test }}/astest" + age: 1w + hidden: true + register: result + +- set_fact: + astest_list: >- + [ {% for f in result.files %} + {{ f.path }} + {% if not loop.last %},{% endif %} + {% endfor %} + ] + +- name: assert we only find the old file + assert: + that: + - result.matched == 1 + - '"{{ output_dir_test }}/astest/old.txt" in astest_list' + +- name: find files newer than 1 week + find: + path: "{{ output_dir_test }}/astest" + age: -1w + register: result + +- set_fact: + astest_list: >- + [ {% for f in result.files %} + {{ f.path }} + {% if not loop.last %},{% endif %} + {% endfor %} + ] + +- name: assert we only find the current file + assert: + that: + - result.matched == 1 + - '"{{ output_dir_test }}/astest/new.txt" in astest_list' + +- name: add some content to the new file + shell: "echo hello world > {{ output_dir_test }}/astest/new.txt" + +- name: find files with MORE than 5 bytes, also get checksums + find: + path: "{{ output_dir_test }}/astest" + size: 5 + hidden: true + get_checksum: true + register: result + +- set_fact: + astest_list: >- + [ {% for f in result.files %} + {{ f.path }} + {% if not loop.last %},{% endif %} + {% endfor %} + ] + +- name: assert we only find the hello world file + assert: + that: + - result.matched == 1 + - '"{{ output_dir_test }}/astest/new.txt" in astest_list' + - '"checksum" in result.files[0]' + +- name: find ANY item with LESS than 5 bytes, also get checksums + find: + path: "{{ output_dir_test }}/astest" + size: -5 + hidden: true + get_checksum: true + file_type: any + register: result + +- set_fact: + astest_list: >- + [ {% for f in result.files %} + {{ f.path }} + {% if not loop.last %},{% endif %} + {% endfor %} + ] + +- name: assert we do not find the hello world file and a checksum is present + assert: + that: + - result.matched == 2 + - '"{{ output_dir_test }}/astest/old.txt" in astest_list' + - '"{{ output_dir_test }}/astest/.hidden.txt" in astest_list' + - '"checksum" in result.files[0]' diff --git a/test/integration/targets/gathering/aliases b/test/integration/targets/gathering/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/gathering/aliases +++ b/test/integration/targets/gathering/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/gathering_facts/aliases b/test/integration/targets/gathering_facts/aliases index 0ee704e1..027aba88 100644 --- a/test/integration/targets/gathering_facts/aliases +++ b/test/integration/targets/gathering_facts/aliases @@ -1,2 +1,3 @@ shippable/posix/group3 needs/root +context/controller diff --git a/test/integration/targets/gathering_facts/collections/ansible_collections/cisco/ios/plugins/modules/ios_facts.py b/test/integration/targets/gathering_facts/collections/ansible_collections/cisco/ios/plugins/modules/ios_facts.py new file mode 100644 index 00000000..b79f7941 --- /dev/null +++ b/test/integration/targets/gathering_facts/collections/ansible_collections/cisco/ios/plugins/modules/ios_facts.py @@ -0,0 +1,38 @@ +#!/usr/bin/python + +DOCUMENTATION = """ +--- +module: ios_facts +short_description: supporting network facts module +description: + - supporting network facts module for gather_facts + module_defaults tests +options: + gather_subset: + description: + - When supplied, this argument restricts the facts collected + to a given subset. + - Possible values for this argument include + C(all), C(hardware), C(config), and C(interfaces). + - Specify a list of values to include a larger subset. + - Use a value with an initial C(!) to collect all facts except that subset. + required: false + default: '!config' +""" + +from ansible.module_utils.basic import AnsibleModule + + +def main(): + """main entry point for module execution + """ + argument_spec = dict( + gather_subset=dict(default='!config') + ) + module = AnsibleModule(argument_spec=argument_spec, + supports_check_mode=True) + + module.exit_json(ansible_facts={'gather_subset': module.params['gather_subset'], '_ansible_facts_gathered': True}) + + +if __name__ == '__main__': + main() diff --git a/test/integration/targets/gathering_facts/inventory b/test/integration/targets/gathering_facts/inventory index e15ae780..6352a7d7 100644 --- a/test/integration/targets/gathering_facts/inventory +++ b/test/integration/targets/gathering_facts/inventory @@ -1,2 +1,2 @@ [local] -facthost[0:25] ansible_connection=local ansible_python_interpreter="{{ ansible_playbook_python }}" +facthost[0:26] ansible_connection=local ansible_python_interpreter="{{ ansible_playbook_python }}" diff --git a/test/integration/targets/gathering_facts/runme.sh b/test/integration/targets/gathering_facts/runme.sh index ebb82ab4..c1df560c 100755 --- a/test/integration/targets/gathering_facts/runme.sh +++ b/test/integration/targets/gathering_facts/runme.sh @@ -23,3 +23,5 @@ ansible-playbook verify_subset.yml "$@" # ensure we can set defaults for the action plugin and facts module ansible-playbook test_module_defaults.yml "$@" --tags default_fact_module ANSIBLE_FACTS_MODULES='ansible.legacy.setup' ansible-playbook test_module_defaults.yml "$@" --tags custom_fact_module + +ansible-playbook test_module_defaults.yml "$@" --tags networking diff --git a/test/integration/targets/gathering_facts/test_gathering_facts.yml b/test/integration/targets/gathering_facts/test_gathering_facts.yml index 0939cba7..9174675d 100644 --- a/test/integration/targets/gathering_facts/test_gathering_facts.yml +++ b/test/integration/targets/gathering_facts/test_gathering_facts.yml @@ -140,6 +140,34 @@ - 'ansible_virtualization_role|default("UNDEF_VIRT") != "UNDEF_VIRT"' - 'ansible_env|default("UNDEF_ENV") != "UNDEF_ENV"' +- hosts: facthost25 + tags: [ 'fact_min' ] + gather_facts: no + tasks: + - setup: + filter: + - "date_time" + + - name: Test that retrieving all facts filtered to date_time even w/o using ansible_ prefix + assert: + that: + - 'ansible_facts["date_time"]|default("UNDEF_MOUNT") != "UNDEF_MOUNT"' + - 'ansible_date_time|default("UNDEF_MOUNT") != "UNDEF_MOUNT"' + +- hosts: facthost26 + tags: [ 'fact_min' ] + gather_facts: no + tasks: + - setup: + filter: + - "ansible_date_time" + + - name: Test that retrieving all facts filtered to date_time even using ansible_ prefix + assert: + that: + - 'ansible_facts["date_time"]|default("UNDEF_MOUNT") != "UNDEF_MOUNT"' + - 'ansible_date_time|default("UNDEF_MOUNT") != "UNDEF_MOUNT"' + - hosts: facthost13 tags: [ 'fact_min' ] connection: local diff --git a/test/integration/targets/gathering_facts/test_module_defaults.yml b/test/integration/targets/gathering_facts/test_module_defaults.yml index 5b0f9dd8..038b8ecf 100644 --- a/test/integration/targets/gathering_facts/test_module_defaults.yml +++ b/test/integration/targets/gathering_facts/test_module_defaults.yml @@ -77,3 +77,54 @@ - assert: that: - "gather_subset == ['min']" + +- hosts: localhost + gather_facts: no + tags: + - networking + tasks: + - name: test that task args aren't used for fqcn network facts + gather_facts: + gather_subset: min + vars: + ansible_network_os: 'cisco.ios.ios' + register: result + + - assert: + that: + - "ansible_facts.gather_subset == '!config'" + + - name: test that module_defaults are used for fqcn network facts + gather_facts: + vars: + ansible_network_os: 'cisco.ios.ios' + module_defaults: + 'cisco.ios.ios_facts': {'gather_subset': 'min'} + register: result + + - assert: + that: + - "ansible_facts.gather_subset == 'min'" + + - name: test that task args aren't used for legacy network facts + gather_facts: + gather_subset: min + vars: + ansible_network_os: 'ios' + register: result + + - assert: + that: + - "ansible_facts.gather_subset == '!config'" + + - name: test that module_defaults are used for legacy network facts + gather_facts: + vars: + ansible_network_os: 'ios' + module_defaults: + 'ios_facts': {'gather_subset': 'min'} + register: result + + - assert: + that: + - "ansible_facts.gather_subset == 'min'" diff --git a/test/integration/targets/gathering_facts/test_prevent_injection.yml b/test/integration/targets/gathering_facts/test_prevent_injection.yml index f304fe88..064b7a90 100644 --- a/test/integration/targets/gathering_facts/test_prevent_injection.yml +++ b/test/integration/targets/gathering_facts/test_prevent_injection.yml @@ -5,7 +5,7 @@ - name: gather 'bad' facts action: bogus_facts - - name: ensure that the 'bad' facts didn't polute what they are not supposed to + - name: ensure that the 'bad' facts didn't pollute what they are not supposed to assert: that: - "'touch' not in discovered_interpreter_python|default('')" diff --git a/test/integration/targets/get_url/tasks/main.yml b/test/integration/targets/get_url/tasks/main.yml index 32da1d51..b5a9c7e5 100644 --- a/test/integration/targets/get_url/tasks/main.yml +++ b/test/integration/targets/get_url/tasks/main.yml @@ -579,6 +579,35 @@ - '(result.content | b64decode) == "ansible.http.tests:SUCCESS"' when: has_httptester +- name: test unredirected_headers + get_url: + url: 'https://{{ httpbin_host }}/redirect-to?status_code=301&url=/basic-auth/user/passwd' + username: user + password: passwd + force_basic_auth: true + unredirected_headers: + - authorization + dest: "{{ remote_tmp_dir }}/doesnt_matter" + ignore_errors: true + register: unredirected_headers + +- name: test unredirected_headers + get_url: + url: 'https://{{ httpbin_host }}/redirect-to?status_code=301&url=/basic-auth/user/passwd' + username: user + password: passwd + force_basic_auth: true + dest: "{{ remote_tmp_dir }}/doesnt_matter" + register: redirected_headers + +- name: ensure unredirected_headers caused auth to fail + assert: + that: + - unredirected_headers is failed + - unredirected_headers.status_code == 401 + - redirected_headers is successful + - redirected_headers.status_code == 200 + - name: Test use_gssapi=True include_tasks: file: use_gssapi.yml diff --git a/test/integration/targets/git/tasks/archive.yml b/test/integration/targets/git/tasks/archive.yml index 574559ef..18b9dff3 100644 --- a/test/integration/targets/git/tasks/archive.yml +++ b/test/integration/targets/git/tasks/archive.yml @@ -119,6 +119,7 @@ unarchive: src: '{{ checkout_dir }}/test_role.{{ item }}' dest: '{{ checkout_dir }}/{{ git_archive_prefix }}.{{ item }}' + remote_src: yes with_items: "{{ git_archive_extensions[ansible_os_family ~ ansible_distribution_major_version | default('default') ] | default(git_archive_extensions.default) }}" - name: ARCHIVE | Check if prefix directory exists in what's extracted diff --git a/test/integration/targets/git/tasks/main.yml b/test/integration/targets/git/tasks/main.yml index c5aeacbe..ed06eab5 100644 --- a/test/integration/targets/git/tasks/main.yml +++ b/test/integration/targets/git/tasks/main.yml @@ -21,6 +21,7 @@ - import_tasks: formats.yml - import_tasks: missing_hostkey.yml +- import_tasks: missing_hostkey_acceptnew.yml - import_tasks: no-destination.yml - import_tasks: specific-revision.yml - import_tasks: submodules.yml diff --git a/test/integration/targets/git/tasks/missing_hostkey.yml b/test/integration/targets/git/tasks/missing_hostkey.yml index 02d5be35..6e4d53c3 100644 --- a/test/integration/targets/git/tasks/missing_hostkey.yml +++ b/test/integration/targets/git/tasks/missing_hostkey.yml @@ -46,3 +46,16 @@ that: - git_result is changed when: github_ssh_private_key is defined + +- name: MISSING-HOSTEKY | Remove github.com hostkey from known_hosts + lineinfile: + dest: '{{ output_dir }}/known_hosts' + regexp: "github.com" + state: absent + when: github_ssh_private_key is defined + +- name: MISSING-HOSTKEY | clear checkout_dir + file: + state: absent + path: '{{ checkout_dir }}' + when: github_ssh_private_key is defined diff --git a/test/integration/targets/git/tasks/missing_hostkey_acceptnew.yml b/test/integration/targets/git/tasks/missing_hostkey_acceptnew.yml new file mode 100644 index 00000000..fb8bb063 --- /dev/null +++ b/test/integration/targets/git/tasks/missing_hostkey_acceptnew.yml @@ -0,0 +1,78 @@ +- name: MISSING-HOSTKEY | check accept_newhostkey support + shell: ssh -o StrictHostKeyChecking=accept-new -V + register: ssh_supports_accept_newhostkey + ignore_errors: true + +- block: + - name: MISSING-HOSTKEY | accept_newhostkey when ssh does not support the option + git: + repo: '{{ repo_format2 }}' + dest: '{{ checkout_dir }}' + accept_newhostkey: true + ssh_opts: '-o UserKnownHostsFile={{ output_dir }}/known_hosts' + register: git_result + ignore_errors: true + + - assert: + that: + - git_result is failed + - git_result.warnings is search("does not support") + + when: ssh_supports_accept_newhostkey.rc != 0 + +- name: MISSING-HOSTKEY | checkout ssh://git@github.com repo without accept_newhostkey (expected fail) + git: + repo: '{{ repo_format2 }}' + dest: '{{ checkout_dir }}' + ssh_opts: '-o UserKnownHostsFile={{ output_dir }}/known_hosts' + register: git_result + ignore_errors: true + +- assert: + that: + - git_result is failed + +- block: + - name: MISSING-HOSTKEY | checkout git@github.com repo with accept_newhostkey (expected pass) + git: + repo: '{{ repo_format2 }}' + dest: '{{ checkout_dir }}' + accept_newhostkey: true + key_file: '{{ github_ssh_private_key }}' + ssh_opts: '-o UserKnownHostsFile={{ output_dir }}/known_hosts' + register: git_result + + - assert: + that: + - git_result is changed + + - name: MISSING-HOSTKEY | clear checkout_dir + file: + state: absent + path: '{{ checkout_dir }}' + + - name: MISSING-HOSTKEY | checkout ssh://git@github.com repo with accept_newhostkey (expected pass) + git: + repo: '{{ repo_format3 }}' + dest: '{{ checkout_dir }}' + version: 'master' + accept_newhostkey: false # should already have been accepted + key_file: '{{ github_ssh_private_key }}' + ssh_opts: '-o UserKnownHostsFile={{ output_dir }}/known_hosts' + register: git_result + + - assert: + that: + - git_result is changed + + - name: MISSING-HOSTEKY | Remove github.com hostkey from known_hosts + lineinfile: + dest: '{{ output_dir }}/known_hosts' + regexp: "github.com" + state: absent + + - name: MISSING-HOSTKEY | clear checkout_dir + file: + state: absent + path: '{{ checkout_dir }}' + when: github_ssh_private_key is defined and ssh_supports_accept_newhostkey.rc == 0 diff --git a/test/integration/targets/git/tasks/submodules.yml b/test/integration/targets/git/tasks/submodules.yml index 647d1e23..0b311e79 100644 --- a/test/integration/targets/git/tasks/submodules.yml +++ b/test/integration/targets/git/tasks/submodules.yml @@ -122,3 +122,29 @@ - name: SUBMODULES | Enusre submodule2 is at the appropriate commit assert: that: '{{ submodule2.stdout_lines | length }} == 4' + +- name: SUBMODULES | clear checkout_dir + file: + state: absent + path: "{{ checkout_dir }}" + + +- name: SUBMODULES | Clone main submodule repository + git: + repo: "{{ repo_submodules }}" + dest: "{{ checkout_dir }}/test.gitdir" + version: 45c6c07ef10fd9e453d90207e63da1ce5bd3ae1e + recursive: yes + +- name: SUBMODULES | Test that cloning submodule with .git in directory name works + git: + repo: "{{ repo_submodule1 }}" + dest: "{{ checkout_dir }}/test.gitdir/submodule1" + +- name: SUBMODULES | List submodule1 + command: 'ls -1a {{ checkout_dir }}/test.gitdir/submodule1' + register: submodule1 + +- name: SUBMODULES | Ensure submodule1 is at the appropriate commit + assert: + that: '{{ submodule1.stdout_lines | length }} == 4' diff --git a/test/integration/targets/groupby_filter/aliases b/test/integration/targets/groupby_filter/aliases index 31094c31..58201272 100644 --- a/test/integration/targets/groupby_filter/aliases +++ b/test/integration/targets/groupby_filter/aliases @@ -1,2 +1,3 @@ shippable/posix/group2 needs/file/test/lib/ansible_test/_data/requirements/constraints.txt +context/controller diff --git a/test/integration/targets/handler_race/aliases b/test/integration/targets/handler_race/aliases index 68d6d978..1d28bdb2 100644 --- a/test/integration/targets/handler_race/aliases +++ b/test/integration/targets/handler_race/aliases @@ -1,3 +1,2 @@ shippable/posix/group5 -handler_race -skip/aix +context/controller diff --git a/test/integration/targets/handlers/58841.yml b/test/integration/targets/handlers/58841.yml new file mode 100644 index 00000000..eea5c2f3 --- /dev/null +++ b/test/integration/targets/handlers/58841.yml @@ -0,0 +1,9 @@ +--- +- hosts: localhost + gather_facts: no + tasks: + - include_role: + name: import_template_handler_names + tags: + - lazy_evaluation + - evaluation_time diff --git a/test/integration/targets/handlers/aliases b/test/integration/targets/handlers/aliases index 30bb677a..1d28bdb2 100644 --- a/test/integration/targets/handlers/aliases +++ b/test/integration/targets/handlers/aliases @@ -1,3 +1,2 @@ shippable/posix/group5 -handlers -skip/aix +context/controller diff --git a/test/integration/targets/handlers/roles/import_template_handler_names/tasks/main.yml b/test/integration/targets/handlers/roles/import_template_handler_names/tasks/main.yml new file mode 100644 index 00000000..3bc285e5 --- /dev/null +++ b/test/integration/targets/handlers/roles/import_template_handler_names/tasks/main.yml @@ -0,0 +1,11 @@ +- import_role: + name: template_handler_names + tasks_from: lazy_evaluation + tags: + - lazy_evaluation + +- import_role: + name: template_handler_names + tasks_from: evaluation_time + tags: + - evaluation_time diff --git a/test/integration/targets/handlers/roles/template_handler_names/handlers/main.yml b/test/integration/targets/handlers/roles/template_handler_names/handlers/main.yml new file mode 100644 index 00000000..bf8ca851 --- /dev/null +++ b/test/integration/targets/handlers/roles/template_handler_names/handlers/main.yml @@ -0,0 +1,5 @@ +- name: handler name with {{ test_var }} + debug: msg='handler with var ran' + +- name: handler name + debug: msg='handler ran' diff --git a/test/integration/targets/handlers/roles/template_handler_names/tasks/evaluation_time.yml b/test/integration/targets/handlers/roles/template_handler_names/tasks/evaluation_time.yml new file mode 100644 index 00000000..c0706fc5 --- /dev/null +++ b/test/integration/targets/handlers/roles/template_handler_names/tasks/evaluation_time.yml @@ -0,0 +1,5 @@ +- debug: msg='notify handler with variable in name' + notify: handler name with myvar + changed_when: True + tags: + - evaluation_time diff --git a/test/integration/targets/handlers/roles/template_handler_names/tasks/lazy_evaluation.yml b/test/integration/targets/handlers/roles/template_handler_names/tasks/lazy_evaluation.yml new file mode 100644 index 00000000..e82dca06 --- /dev/null +++ b/test/integration/targets/handlers/roles/template_handler_names/tasks/lazy_evaluation.yml @@ -0,0 +1,5 @@ +- debug: msg='notify handler' + notify: handler name + changed_when: True + tags: + - lazy_evaluation diff --git a/test/integration/targets/handlers/roles/test_handlers_include/handlers/main.yml b/test/integration/targets/handlers/roles/test_handlers_include/handlers/main.yml index abe01be4..6c3b73c6 100644 --- a/test/integration/targets/handlers/roles/test_handlers_include/handlers/main.yml +++ b/test/integration/targets/handlers/roles/test_handlers_include/handlers/main.yml @@ -1 +1 @@ -- include: handlers.yml +- import_tasks: handlers.yml diff --git a/test/integration/targets/handlers/runme.sh b/test/integration/targets/handlers/runme.sh index cefa926b..7c403b4e 100755 --- a/test/integration/targets/handlers/runme.sh +++ b/test/integration/targets/handlers/runme.sh @@ -15,7 +15,7 @@ ansible-playbook from_handlers.yml -i inventory.handlers -v "$@" --tags scenario ansible-playbook test_listening_handlers.yml -i inventory.handlers -v "$@" [ "$(ansible-playbook test_handlers.yml -i inventory.handlers -v "$@" --tags scenario2 -l A \ -| grep -E -o 'RUNNING HANDLER \[test_handlers : .*?]')" = "RUNNING HANDLER [test_handlers : test handler]" ] +| grep -E -o 'RUNNING HANDLER \[test_handlers : .*]')" = "RUNNING HANDLER [test_handlers : test handler]" ] # Test forcing handlers using the linear and free strategy for strategy in linear free; do @@ -55,13 +55,13 @@ for strategy in linear free; do done [ "$(ansible-playbook test_handlers_include.yml -i ../../inventory -v "$@" --tags playbook_include_handlers \ -| grep -E -o 'RUNNING HANDLER \[.*?]')" = "RUNNING HANDLER [test handler]" ] +| grep -E -o 'RUNNING HANDLER \[.*]')" = "RUNNING HANDLER [test handler]" ] [ "$(ansible-playbook test_handlers_include.yml -i ../../inventory -v "$@" --tags role_include_handlers \ -| grep -E -o 'RUNNING HANDLER \[test_handlers_include : .*?]')" = "RUNNING HANDLER [test_handlers_include : test handler]" ] +| grep -E -o 'RUNNING HANDLER \[test_handlers_include : .*]')" = "RUNNING HANDLER [test_handlers_include : test handler]" ] [ "$(ansible-playbook test_handlers_include_role.yml -i ../../inventory -v "$@" \ -| grep -E -o 'RUNNING HANDLER \[test_handlers_include_role : .*?]')" = "RUNNING HANDLER [test_handlers_include_role : test handler]" ] +| grep -E -o 'RUNNING HANDLER \[test_handlers_include_role : .*]')" = "RUNNING HANDLER [test_handlers_include_role : test handler]" ] # Notify handler listen ansible-playbook test_handlers_listen.yml -i inventory.handlers -v "$@" @@ -96,3 +96,21 @@ result="$(ansible-playbook test_handlers_template_run_once.yml -i inventory.hand set -e grep -q "handler A" <<< "$result" grep -q "handler B" <<< "$result" + +# Test an undefined variable in another handler name isn't a failure +ansible-playbook 58841.yml "$@" --tags lazy_evaluation 2>&1 | tee out.txt ; cat out.txt +grep out.txt -e "\[WARNING\]: Handler 'handler name with {{ test_var }}' is unusable" +[ "$(grep out.txt -ce 'handler ran')" = "1" ] +[ "$(grep out.txt -ce 'handler with var ran')" = "0" ] + +# Test templating a handler name with a defined variable +ansible-playbook 58841.yml "$@" --tags evaluation_time -e test_var=myvar | tee out.txt ; cat out.txt +[ "$(grep out.txt -ce 'handler ran')" = "0" ] +[ "$(grep out.txt -ce 'handler with var ran')" = "1" ] + +# Test the handler is not found when the variable is undefined +ansible-playbook 58841.yml "$@" --tags evaluation_time 2>&1 | tee out.txt ; cat out.txt +grep out.txt -e "ERROR! The requested handler 'handler name with myvar' was not found" +grep out.txt -e "\[WARNING\]: Handler 'handler name with {{ test_var }}' is unusable" +[ "$(grep out.txt -ce 'handler ran')" = "0" ] +[ "$(grep out.txt -ce 'handler with var ran')" = "0" ] diff --git a/test/integration/targets/handlers/test_handlers_include.yml b/test/integration/targets/handlers/test_handlers_include.yml index 5514fc10..158266d2 100644 --- a/test/integration/targets/handlers/test_handlers_include.yml +++ b/test/integration/targets/handlers/test_handlers_include.yml @@ -6,7 +6,7 @@ notify: test handler tags: ['playbook_include_handlers'] handlers: - - include: handlers.yml + - import_tasks: handlers.yml - name: verify that role can include handler hosts: testhost diff --git a/test/integration/targets/hardware_facts/aliases b/test/integration/targets/hardware_facts/aliases index e00c22c3..3933d2e5 100644 --- a/test/integration/targets/hardware_facts/aliases +++ b/test/integration/targets/hardware_facts/aliases @@ -1,3 +1,4 @@ destructive needs/privileged shippable/posix/group2 +context/controller diff --git a/test/integration/targets/hash/aliases b/test/integration/targets/hash/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/hash/aliases +++ b/test/integration/targets/hash/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/hosts_field/aliases b/test/integration/targets/hosts_field/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/hosts_field/aliases +++ b/test/integration/targets/hosts_field/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/ignore_errors/aliases b/test/integration/targets/ignore_errors/aliases index 3005e4b2..498fedd5 100644 --- a/test/integration/targets/ignore_errors/aliases +++ b/test/integration/targets/ignore_errors/aliases @@ -1 +1,2 @@ shippable/posix/group4 +context/controller diff --git a/test/integration/targets/ignore_unreachable/aliases b/test/integration/targets/ignore_unreachable/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/ignore_unreachable/aliases +++ b/test/integration/targets/ignore_unreachable/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/import_tasks/aliases b/test/integration/targets/import_tasks/aliases index fff62d9f..a1b27a83 100644 --- a/test/integration/targets/import_tasks/aliases +++ b/test/integration/targets/import_tasks/aliases @@ -1,2 +1,2 @@ shippable/posix/group5 -skip/aix +context/controller # this is a controller-only action, the module is just for documentation diff --git a/test/integration/targets/incidental_cloud_init_data_facts/aliases b/test/integration/targets/incidental_cloud_init_data_facts/aliases index 85f7fe0f..544fcacd 100644 --- a/test/integration/targets/incidental_cloud_init_data_facts/aliases +++ b/test/integration/targets/incidental_cloud_init_data_facts/aliases @@ -4,3 +4,4 @@ skip/aix skip/osx skip/macos skip/freebsd +context/target diff --git a/test/integration/targets/incidental_deploy_helper/aliases b/test/integration/targets/incidental_deploy_helper/aliases index 31c6a8b4..3b88c806 100644 --- a/test/integration/targets/incidental_deploy_helper/aliases +++ b/test/integration/targets/incidental_deploy_helper/aliases @@ -1 +1,2 @@ shippable/posix/incidental +context/target diff --git a/test/integration/targets/incidental_inventory_aws_ec2/aliases b/test/integration/targets/incidental_inventory_aws_ec2/aliases index 29f60feb..41a05d3c 100644 --- a/test/integration/targets/incidental_inventory_aws_ec2/aliases +++ b/test/integration/targets/incidental_inventory_aws_ec2/aliases @@ -1,2 +1,3 @@ cloud/aws shippable/aws/incidental +context/controller diff --git a/test/integration/targets/incidental_inventory_aws_ec2/runme.sh b/test/integration/targets/incidental_inventory_aws_ec2/runme.sh index 916f7e8f..339be5dd 100755 --- a/test/integration/targets/incidental_inventory_aws_ec2/runme.sh +++ b/test/integration/targets/incidental_inventory_aws_ec2/runme.sh @@ -2,6 +2,10 @@ set -eux +source virtualenv.sh + +python -m pip install boto3 boto + # ensure test config is empty ansible-playbook playbooks/empty_inventory_config.yml "$@" diff --git a/test/integration/targets/incidental_inventory_docker_swarm/aliases b/test/integration/targets/incidental_inventory_docker_swarm/aliases index c3a38c06..74d3befe 100644 --- a/test/integration/targets/incidental_inventory_docker_swarm/aliases +++ b/test/integration/targets/incidental_inventory_docker_swarm/aliases @@ -1,6 +1,5 @@ shippable/posix/incidental -skip/aix -skip/power/centos +context/controller skip/osx skip/macos skip/freebsd diff --git a/test/integration/targets/incidental_inventory_foreman/aliases b/test/integration/targets/incidental_inventory_foreman/aliases index c28a056e..7eaacbbc 100644 --- a/test/integration/targets/incidental_inventory_foreman/aliases +++ b/test/integration/targets/incidental_inventory_foreman/aliases @@ -1,3 +1,4 @@ shippable/cloud/incidental cloud/foreman destructive +context/controller diff --git a/test/integration/targets/incidental_inventory_foreman/inspect_cache.yml b/test/integration/targets/incidental_inventory_foreman/inspect_cache.yml index c91f4c38..b9e32f7d 100644 --- a/test/integration/targets/incidental_inventory_foreman/inspect_cache.yml +++ b/test/integration/targets/incidental_inventory_foreman/inspect_cache.yml @@ -6,6 +6,10 @@ foreman_stub_api_path: /api/v2 cached_hosts_key: "http://{{ foreman_stub_host }}:{{ foreman_stub_port }}{{ foreman_stub_api_path }}/hosts" tasks: + - name: make sure jmespath is installed + pip: + name: jmespath + - name: verify a cache file was created find: path: diff --git a/test/integration/targets/incidental_inventory_foreman/runme.sh b/test/integration/targets/incidental_inventory_foreman/runme.sh index ba94a936..d81fa02f 100755 --- a/test/integration/targets/incidental_inventory_foreman/runme.sh +++ b/test/integration/targets/incidental_inventory_foreman/runme.sh @@ -43,8 +43,8 @@ password: secure validate_certs: False FOREMAN_YAML -ansible-playbook test_foreman_inventory.yml --connection=local "$@" -ansible-playbook inspect_cache.yml --connection=local "$@" +ansible-playbook test_foreman_inventory.yml --connection=local -e 'ansible_python_interpreter={{ ansible_playbook_python }}' "$@" +ansible-playbook inspect_cache.yml --connection=local -e 'ansible_python_interpreter={{ ansible_playbook_python }}' "$@" # remove inventory cache rm -r ./foreman_cache diff --git a/test/integration/targets/incidental_ios_file/tasks/cli.yaml b/test/integration/targets/incidental_ios_file/tasks/cli.yaml index d4f663b3..3eb57691 100644 --- a/test/integration/targets/incidental_ios_file/tasks/cli.yaml +++ b/test/integration/targets/incidental_ios_file/tasks/cli.yaml @@ -10,7 +10,7 @@ set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" - name: run test cases (connection=ansible.netcommon.network_cli) - include: "{{ test_case_to_run }}" + include_tasks: "{{ test_case_to_run }}" with_items: "{{ test_items }}" loop_control: loop_var: test_case_to_run diff --git a/test/integration/targets/incidental_ios_file/tasks/main.yaml b/test/integration/targets/incidental_ios_file/tasks/main.yaml index 415c99d8..24ad94ae 100644 --- a/test/integration/targets/incidental_ios_file/tasks/main.yaml +++ b/test/integration/targets/incidental_ios_file/tasks/main.yaml @@ -1,2 +1,2 @@ --- -- { include: cli.yaml, tags: ['cli'] } +- { import_tasks: cli.yaml, tags: ['cli'] } diff --git a/test/integration/targets/incidental_mongodb_parameter/aliases b/test/integration/targets/incidental_mongodb_parameter/aliases index dc285483..72ed62eb 100644 --- a/test/integration/targets/incidental_mongodb_parameter/aliases +++ b/test/integration/targets/incidental_mongodb_parameter/aliases @@ -6,3 +6,4 @@ skip/macos skip/freebsd skip/rhel needs/root +context/target diff --git a/test/integration/targets/incidental_setup_docker/vars/RedHat-8.yml b/test/integration/targets/incidental_setup_docker/vars/RedHat-8.yml index ff6dcf7b..82343898 100644 --- a/test/integration/targets/incidental_setup_docker/vars/RedHat-8.yml +++ b/test/integration/targets/incidental_setup_docker/vars/RedHat-8.yml @@ -3,6 +3,7 @@ docker_prereq_packages: - device-mapper-persistent-data - lvm2 - libseccomp + - iptables docker_packages: - docker-ce-19.03.13 diff --git a/test/integration/targets/incidental_vyos_config/tasks/cli.yaml b/test/integration/targets/incidental_vyos_config/tasks/cli.yaml index 22a71d96..d601bb70 100644 --- a/test/integration/targets/incidental_vyos_config/tasks/cli.yaml +++ b/test/integration/targets/incidental_vyos_config/tasks/cli.yaml @@ -10,13 +10,17 @@ set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" - name: run test case (connection=ansible.netcommon.network_cli) - include: "{{ test_case_to_run }} ansible_connection=ansible.netcommon.network_cli" + include_tasks: "file={{ test_case_to_run }}" + vars: + ansible_connection: ansible.netcommon.network_cli with_items: "{{ test_items }}" loop_control: loop_var: test_case_to_run - name: run test case (connection=local) - include: "{{ test_case_to_run }} ansible_connection=local" + include_tasks: "file={{ test_case_to_run }}" + vars: + ansible_connection: local with_first_found: "{{ test_items }}" loop_control: loop_var: test_case_to_run diff --git a/test/integration/targets/incidental_vyos_config/tasks/cli_config.yaml b/test/integration/targets/incidental_vyos_config/tasks/cli_config.yaml index 8ed28748..7e673560 100644 --- a/test/integration/targets/incidental_vyos_config/tasks/cli_config.yaml +++ b/test/integration/targets/incidental_vyos_config/tasks/cli_config.yaml @@ -10,7 +10,9 @@ set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" - name: run test case (connection=ansible.netcommon.network_cli) - include: "{{ test_case_to_run }} ansible_connection=ansible.netcommon.network_cli" + include_tasks: "file={{ test_case_to_run }}" + vars: + ansible_connection: ansible.netcommon.network_cli with_items: "{{ test_items }}" loop_control: loop_var: test_case_to_run diff --git a/test/integration/targets/incidental_vyos_config/tasks/main.yaml b/test/integration/targets/incidental_vyos_config/tasks/main.yaml index 13977a44..0d4e8fdd 100644 --- a/test/integration/targets/incidental_vyos_config/tasks/main.yaml +++ b/test/integration/targets/incidental_vyos_config/tasks/main.yaml @@ -1,3 +1,3 @@ --- -- {include: cli.yaml, tags: ['cli']} -- {include: cli_config.yaml, tags: ['cli_config']} +- {import_tasks: cli.yaml, tags: ['cli']} +- {import_tasks: cli_config.yaml, tags: ['cli_config']} diff --git a/test/integration/targets/incidental_vyos_lldp_interfaces/tasks/cli.yaml b/test/integration/targets/incidental_vyos_lldp_interfaces/tasks/cli.yaml index 83496e0e..c6923f3e 100644 --- a/test/integration/targets/incidental_vyos_lldp_interfaces/tasks/cli.yaml +++ b/test/integration/targets/incidental_vyos_lldp_interfaces/tasks/cli.yaml @@ -11,7 +11,7 @@ set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" - name: Run test case (connection=ansible.netcommon.network_cli) - include: "{{ test_case_to_run }}" + include_tasks: "{{ test_case_to_run }}" vars: ansible_connection: ansible.netcommon.network_cli with_items: "{{ test_items }}" diff --git a/test/integration/targets/incidental_vyos_lldp_interfaces/tasks/main.yaml b/test/integration/targets/incidental_vyos_lldp_interfaces/tasks/main.yaml index d4cf26fc..a6d418bb 100644 --- a/test/integration/targets/incidental_vyos_lldp_interfaces/tasks/main.yaml +++ b/test/integration/targets/incidental_vyos_lldp_interfaces/tasks/main.yaml @@ -1,2 +1,2 @@ --- -- {include: cli.yaml, tags: ['cli']} +- {import_tasks: cli.yaml, tags: ['cli']} diff --git a/test/integration/targets/incidental_win_data_deduplication/tasks/main.yml b/test/integration/targets/incidental_win_data_deduplication/tasks/main.yml index ae6be90e..83c7197c 100644 --- a/test/integration/targets/incidental_win_data_deduplication/tasks/main.yml +++ b/test/integration/targets/incidental_win_data_deduplication/tasks/main.yml @@ -1,2 +1,2 @@ --- -- include: pre_test.yml +- import_tasks: pre_test.yml diff --git a/test/integration/targets/incidental_win_data_deduplication/tasks/pre_test.yml b/test/integration/targets/incidental_win_data_deduplication/tasks/pre_test.yml index f72955e4..0d1c3d50 100644 --- a/test/integration/targets/incidental_win_data_deduplication/tasks/pre_test.yml +++ b/test/integration/targets/incidental_win_data_deduplication/tasks/pre_test.yml @@ -34,7 +34,7 @@ - name: Run tests block: - - include: tests.yml + - import_tasks: tests.yml always: - name: Detach disk win_command: diskpart.exe /s {{ remote_tmp_dir }}\partition_deletion_script.txt diff --git a/test/integration/targets/incidental_win_security_policy/aliases b/test/integration/targets/incidental_win_security_policy/aliases deleted file mode 100644 index a5fc90dc..00000000 --- a/test/integration/targets/incidental_win_security_policy/aliases +++ /dev/null @@ -1,2 +0,0 @@ -shippable/windows/incidental -windows diff --git a/test/integration/targets/incidental_win_security_policy/library/test_win_security_policy.ps1 b/test/integration/targets/incidental_win_security_policy/library/test_win_security_policy.ps1 deleted file mode 100644 index 5c83c1b5..00000000 --- a/test/integration/targets/incidental_win_security_policy/library/test_win_security_policy.ps1 +++ /dev/null @@ -1,53 +0,0 @@ -#!powershell - -# WANT_JSON -# POWERSHELL_COMMON - -# basic script to get the lsit of users in a particular right -# this is quite complex to put as a simple script so this is -# just a simple module - -$ErrorActionPreference = 'Stop' - -$params = Parse-Args $args -supports_check_mode $false -$section = Get-AnsibleParam -obj $params -name "section" -type "str" -failifempty $true -$key = Get-AnsibleParam -obj $params -name "key" -type "str" -failifempty $true - -$result = @{ - changed = $false -} - -Function ConvertFrom-Ini($file_path) { - $ini = @{} - switch -Regex -File $file_path { - "^\[(.+)\]" { - $section = $matches[1] - $ini.$section = @{} - } - "(.+?)\s*=(.*)" { - $name = $matches[1].Trim() - $value = $matches[2].Trim() - if ($value -match "^\d+$") { - $value = [int]$value - } elseif ($value.StartsWith('"') -and $value.EndsWith('"')) { - $value = $value.Substring(1, $value.Length - 2) - } - - $ini.$section.$name = $value - } - } - - $ini -} - -$secedit_ini_path = [IO.Path]::GetTempFileName() -&SecEdit.exe /export /cfg $secedit_ini_path /quiet -$secedit_ini = ConvertFrom-Ini -file_path $secedit_ini_path - -if ($secedit_ini.ContainsKey($section)) { - $result.value = $secedit_ini.$section.$key -} else { - $result.value = $null -} - -Exit-Json $result diff --git a/test/integration/targets/incidental_win_security_policy/tasks/main.yml b/test/integration/targets/incidental_win_security_policy/tasks/main.yml deleted file mode 100644 index 28fdb5ea..00000000 --- a/test/integration/targets/incidental_win_security_policy/tasks/main.yml +++ /dev/null @@ -1,41 +0,0 @@ ---- -- name: get current entry for audit - test_win_security_policy: - section: Event Audit - key: AuditSystemEvents - register: before_value_audit - -- name: get current entry for guest - test_win_security_policy: - section: System Access - key: NewGuestName - register: before_value_guest - -- block: - - name: set AuditSystemEvents entry before tests - win_security_policy: - section: Event Audit - key: AuditSystemEvents - value: 0 - - - name: set NewGuestName entry before tests - win_security_policy: - section: System Access - key: NewGuestName - value: Guest - - - name: run tests - include_tasks: tests.yml - - always: - - name: reset entries for AuditSystemEvents - win_security_policy: - section: Event Audit - key: AuditSystemEvents - value: "{{before_value_audit.value}}" - - - name: reset entries for NewGuestName - win_security_policy: - section: System Access - key: NewGuestName - value: "{{before_value_guest.value}}" diff --git a/test/integration/targets/incidental_win_security_policy/tasks/tests.yml b/test/integration/targets/incidental_win_security_policy/tasks/tests.yml deleted file mode 100644 index 724b6010..00000000 --- a/test/integration/targets/incidental_win_security_policy/tasks/tests.yml +++ /dev/null @@ -1,186 +0,0 @@ ---- -- name: fail with invalid section name - win_security_policy: - section: This is not a valid section - key: KeyName - value: 0 - register: fail_invalid_section - failed_when: fail_invalid_section.msg != "The section 'This is not a valid section' does not exist in SecEdit.exe output ini" - -- name: fail with invalid key name - win_security_policy: - section: System Access - key: InvalidKey - value: 0 - register: fail_invalid_key - failed_when: fail_invalid_key.msg != "The key 'InvalidKey' in section 'System Access' is not a valid key, cannot set this value" - -- name: change existing key check - win_security_policy: - section: Event Audit - key: AuditSystemEvents - value: 1 - register: change_existing_check - check_mode: yes - -- name: get actual change existing key check - test_win_security_policy: - section: Event Audit - key: AuditSystemEvents - register: change_existing_actual_check - -- name: assert change existing key check - assert: - that: - - change_existing_check is changed - - change_existing_actual_check.value == 0 - -- name: change existing key - win_security_policy: - section: Event Audit - key: AuditSystemEvents - value: 1 - register: change_existing - -- name: get actual change existing key - test_win_security_policy: - section: Event Audit - key: AuditSystemEvents - register: change_existing_actual - -- name: assert change existing key - assert: - that: - - change_existing is changed - - change_existing_actual.value == 1 - -- name: change existing key again - win_security_policy: - section: Event Audit - key: AuditSystemEvents - value: 1 - register: change_existing_again - -- name: assert change existing key again - assert: - that: - - change_existing_again is not changed - - change_existing_again.value == 1 - -- name: change existing key with string type - win_security_policy: - section: Event Audit - key: AuditSystemEvents - value: "1" - register: change_existing_key_with_type - -- name: assert change existing key with string type - assert: - that: - - change_existing_key_with_type is not changed - - change_existing_key_with_type.value == "1" - -- name: change existing string key check - win_security_policy: - section: System Access - key: NewGuestName - value: New Guest - register: change_existing_string_check - check_mode: yes - -- name: get actual change existing string key check - test_win_security_policy: - section: System Access - key: NewGuestName - register: change_existing_string_actual_check - -- name: assert change existing string key check - assert: - that: - - change_existing_string_check is changed - - change_existing_string_actual_check.value == "Guest" - -- name: change existing string key - win_security_policy: - section: System Access - key: NewGuestName - value: New Guest - register: change_existing_string - -- name: get actual change existing string key - test_win_security_policy: - section: System Access - key: NewGuestName - register: change_existing_string_actual - -- name: assert change existing string key - assert: - that: - - change_existing_string is changed - - change_existing_string_actual.value == "New Guest" - -- name: change existing string key again - win_security_policy: - section: System Access - key: NewGuestName - value: New Guest - register: change_existing_string_again - -- name: assert change existing string key again - assert: - that: - - change_existing_string_again is not changed - - change_existing_string_again.value == "New Guest" - -- name: add policy setting - win_security_policy: - section: Privilege Rights - # following key is empty by default - key: SeCreateTokenPrivilege - # add Guests - value: '*S-1-5-32-546' - -- name: get actual policy setting - test_win_security_policy: - section: Privilege Rights - key: SeCreateTokenPrivilege - register: add_policy_setting_actual - -- name: assert add policy setting - assert: - that: - - add_policy_setting_actual.value == '*S-1-5-32-546' - -- name: remove policy setting - win_security_policy: - section: Privilege Rights - key: SeCreateTokenPrivilege - value: '' - diff: yes - register: remove_policy_setting - -- name: get actual policy setting - test_win_security_policy: - section: Privilege Rights - key: SeCreateTokenPrivilege - register: remove_policy_setting_actual - -- name: assert remove policy setting - assert: - that: - - remove_policy_setting is changed - - remove_policy_setting.diff.prepared == "[Privilege Rights]\n-SeCreateTokenPrivilege = *S-1-5-32-546\n+SeCreateTokenPrivilege = " - - remove_policy_setting_actual.value is none - -- name: remove policy setting again - win_security_policy: - section: Privilege Rights - key: SeCreateTokenPrivilege - value: '' - register: remove_policy_setting_again - -- name: assert remove policy setting again - assert: - that: - - remove_policy_setting_again is not changed - - remove_policy_setting_again.value == '' diff --git a/test/integration/targets/include_import/aliases b/test/integration/targets/include_import/aliases index fff62d9f..1d28bdb2 100644 --- a/test/integration/targets/include_import/aliases +++ b/test/integration/targets/include_import/aliases @@ -1,2 +1,2 @@ shippable/posix/group5 -skip/aix +context/controller diff --git a/test/integration/targets/include_import/include_role_omit/playbook.yml b/test/integration/targets/include_import/include_role_omit/playbook.yml new file mode 100644 index 00000000..a036906a --- /dev/null +++ b/test/integration/targets/include_import/include_role_omit/playbook.yml @@ -0,0 +1,12 @@ +- hosts: localhost + gather_facts: false + vars: + include_role_omit: false + tasks: + - include_role: + name: foo + tasks_from: '{{ omit }}' + + - assert: + that: + - include_role_omit is sameas(true) diff --git a/test/integration/targets/include_import/include_role_omit/roles/foo/tasks/main.yml b/test/integration/targets/include_import/include_role_omit/roles/foo/tasks/main.yml new file mode 100644 index 00000000..e27ca5b0 --- /dev/null +++ b/test/integration/targets/include_import/include_role_omit/roles/foo/tasks/main.yml @@ -0,0 +1,2 @@ +- set_fact: + include_role_omit: true diff --git a/test/integration/targets/include_import/playbook/test_templated_filenames.yml b/test/integration/targets/include_import/playbook/test_templated_filenames.yml new file mode 100644 index 00000000..2f78ab09 --- /dev/null +++ b/test/integration/targets/include_import/playbook/test_templated_filenames.yml @@ -0,0 +1,47 @@ +- name: test templating import_playbook with extra vars + import_playbook: "{{ pb }}" + +- name: test templating import_playbook with vars + import_playbook: "{{ test_var }}" + vars: + test_var: validate_templated_playbook.yml + +- name: test templating import_tasks + hosts: localhost + gather_facts: no + vars: + play_var: validate_templated_tasks.yml + tasks: + - name: test templating import_tasks with play vars + import_tasks: "{{ play_var }}" + + - name: test templating import_tasks with task vars + import_tasks: "{{ task_var }}" + vars: + task_var: validate_templated_tasks.yml + + - name: test templating import_tasks with extra vars + import_tasks: "{{ tasks }}" + +- name: test templating import_role from_files + hosts: localhost + gather_facts: no + vars: + play_var: templated.yml + tasks: + - name: test templating import_role tasks_from with play vars + import_role: + name: role1 + tasks_from: "{{ play_var }}" + + - name: test templating import_role tasks_from with task vars + import_role: + name: role1 + tasks_from: "{{ task_var }}" + vars: + task_var: templated.yml + + - name: test templating import_role tasks_from with extra vars + import_role: + name: role1 + tasks_from: "{{ tasks_from }}" diff --git a/test/integration/targets/include_import/playbook/validate_templated_playbook.yml b/test/integration/targets/include_import/playbook/validate_templated_playbook.yml new file mode 100644 index 00000000..631ee9b4 --- /dev/null +++ b/test/integration/targets/include_import/playbook/validate_templated_playbook.yml @@ -0,0 +1,5 @@ +--- +- hosts: localhost + gather_facts: no + tasks: + - debug: msg="In imported playbook" diff --git a/test/integration/targets/include_import/playbook/validate_templated_tasks.yml b/test/integration/targets/include_import/playbook/validate_templated_tasks.yml new file mode 100644 index 00000000..16d682d1 --- /dev/null +++ b/test/integration/targets/include_import/playbook/validate_templated_tasks.yml @@ -0,0 +1 @@ +- debug: msg="In imported tasks" diff --git a/test/integration/targets/include_import/roles/role1/tasks/templated.yml b/test/integration/targets/include_import/roles/role1/tasks/templated.yml new file mode 100644 index 00000000..eb9a9976 --- /dev/null +++ b/test/integration/targets/include_import/roles/role1/tasks/templated.yml @@ -0,0 +1 @@ +- debug: msg="In imported role" diff --git a/test/integration/targets/include_import/runme.sh b/test/integration/targets/include_import/runme.sh index f2633032..7029ab6d 100755 --- a/test/integration/targets/include_import/runme.sh +++ b/test/integration/targets/include_import/runme.sh @@ -126,3 +126,12 @@ ANSIBLE_HOST_PATTERN_MISMATCH=error ansible-playbook empty_group_warning/playboo ansible-playbook test_include_loop.yml "$@" ansible-playbook test_include_loop_fqcn.yml "$@" + +ansible-playbook include_role_omit/playbook.yml "$@" + +# Test templating import_playbook, import_tasks, and import_role files +ansible-playbook playbook/test_templated_filenames.yml -e "pb=validate_templated_playbook.yml tasks=validate_templated_tasks.yml tasks_from=templated.yml" "$@" | tee out.txt +cat out.txt +test "$(grep out.txt -ce 'In imported playbook')" = 2 +test "$(grep out.txt -ce 'In imported tasks')" = 3 +test "$(grep out.txt -ce 'In imported role')" = 3 diff --git a/test/integration/targets/include_import/undefined_var/playbook.yml b/test/integration/targets/include_import/undefined_var/playbook.yml index 0584fa8a..6576d50a 100644 --- a/test/integration/targets/include_import/undefined_var/playbook.yml +++ b/test/integration/targets/include_import/undefined_var/playbook.yml @@ -26,8 +26,7 @@ - "_include_role_result is failed" msg: "'include_role' did not evaluate it's attached condition and failed" - - include: include_that_defines_var.yml - static: yes + - import_tasks: include_that_defines_var.yml when: - "_undefined == 'yes'" diff --git a/test/integration/targets/include_vars-ad-hoc/aliases b/test/integration/targets/include_vars-ad-hoc/aliases index 765b70da..90ea9e12 100644 --- a/test/integration/targets/include_vars-ad-hoc/aliases +++ b/test/integration/targets/include_vars-ad-hoc/aliases @@ -1 +1,2 @@ shippable/posix/group2 +context/controller diff --git a/test/integration/targets/include_vars/tasks/main.yml b/test/integration/targets/include_vars/tasks/main.yml index 799d7b26..db15ba3c 100644 --- a/test/integration/targets/include_vars/tasks/main.yml +++ b/test/integration/targets/include_vars/tasks/main.yml @@ -57,6 +57,8 @@ include_vars: dir: vars extensions: ['', 'yaml', 'yml', 'json'] + ignore_files: + - no_auto_unsafe.yml register: include_every_dir - name: verify that the correct files have been loaded and overwrite based on alphabetical order @@ -78,6 +80,7 @@ ignore_files: - webapp.yml - file_without_extension + - no_auto_unsafe.yml register: include_without_webapp - name: verify that the webapp.yml file was not included @@ -162,3 +165,53 @@ that: - "'my_custom_service' == service_name_fqcn" - "'my_custom_service' == service_name_tmpl_fqcn" + +- name: Include a vars file with a hash variable + include_vars: + file: vars2/hashes/hash1.yml + +- name: Verify the hash variable + assert: + that: + - "{{ config | length }} == 3" + - "config.key0 == 0" + - "config.key1 == 0" + - "{{ config.key2 | length }} == 1" + - "config.key2.a == 21" + +- name: Include the second file to merge the hash variable + include_vars: + file: vars2/hashes/hash2.yml + hash_behaviour: merge + +- name: Verify that the hash is merged + assert: + that: + - "{{ config | length }} == 4" + - "config.key0 == 0" + - "config.key1 == 1" + - "{{ config.key2 | length }} == 2" + - "config.key2.a == 21" + - "config.key2.b == 22" + - "config.key3 == 3" + +- name: Include the second file again without hash_behaviour option + include_vars: + file: vars2/hashes/hash2.yml + +- name: Verify that the properties from the first file is cleared + assert: + that: + - "{{ config | length }} == 3" + - "config.key1 == 1" + - "{{ config.key2 | length }} == 1" + - "config.key2.b == 22" + - "config.key3 == 3" + +- include_vars: + file: no_auto_unsafe.yml + register: baz + +- assert: + that: + - baz.ansible_facts.foo|type_debug != "AnsibleUnsafeText" diff --git a/test/integration/targets/include_vars/vars/no_auto_unsafe.yml b/test/integration/targets/include_vars/vars/no_auto_unsafe.yml new file mode 100644 index 00000000..20e9ff3f --- /dev/null +++ b/test/integration/targets/include_vars/vars/no_auto_unsafe.yml @@ -0,0 +1 @@ +foo: bar diff --git a/test/integration/targets/include_vars/vars2/hashes/hash1.yml b/test/integration/targets/include_vars/vars2/hashes/hash1.yml new file mode 100644 index 00000000..b0706f8f --- /dev/null +++ b/test/integration/targets/include_vars/vars2/hashes/hash1.yml @@ -0,0 +1,5 @@ +--- +config: + key0: 0 + key1: 0 + key2: { a: 21 } diff --git a/test/integration/targets/include_vars/vars2/hashes/hash2.yml b/test/integration/targets/include_vars/vars2/hashes/hash2.yml new file mode 100644 index 00000000..1f2a9636 --- /dev/null +++ b/test/integration/targets/include_vars/vars2/hashes/hash2.yml @@ -0,0 +1,5 @@ +--- +config: + key1: 1 + key2: { b: 22 } + key3: 3 diff --git a/test/integration/targets/include_when_parent_is_dynamic/aliases b/test/integration/targets/include_when_parent_is_dynamic/aliases index 41c99f51..8278ec8b 100644 --- a/test/integration/targets/include_when_parent_is_dynamic/aliases +++ b/test/integration/targets/include_when_parent_is_dynamic/aliases @@ -1,2 +1,2 @@ shippable/posix/group3 -skip/python2.6 # include is controller only, and we no longer support Python 2.6 on the controller +context/controller diff --git a/test/integration/targets/include_when_parent_is_static/aliases b/test/integration/targets/include_when_parent_is_static/aliases index 41c99f51..8278ec8b 100644 --- a/test/integration/targets/include_when_parent_is_static/aliases +++ b/test/integration/targets/include_when_parent_is_static/aliases @@ -1,2 +1,2 @@ shippable/posix/group3 -skip/python2.6 # include is controller only, and we no longer support Python 2.6 on the controller +context/controller diff --git a/test/integration/targets/includes/aliases b/test/integration/targets/includes/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/includes/aliases +++ b/test/integration/targets/includes/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/includes/include_on_playbook_should_fail.yml b/test/integration/targets/includes/include_on_playbook_should_fail.yml new file mode 100644 index 00000000..953459dc --- /dev/null +++ b/test/integration/targets/includes/include_on_playbook_should_fail.yml @@ -0,0 +1 @@ +- include: test_includes3.yml diff --git a/test/integration/targets/includes/roles/test_includes/tasks/branch_toplevel.yml b/test/integration/targets/includes/roles/test_includes/tasks/branch_toplevel.yml index 62416705..30cd6f28 100644 --- a/test/integration/targets/includes/roles/test_includes/tasks/branch_toplevel.yml +++ b/test/integration/targets/includes/roles/test_includes/tasks/branch_toplevel.yml @@ -1,9 +1,11 @@ # 'canary2' used instead of 'canary', otherwise a "recursive loop detected in # template string" occurs when both includes use static=yes -- include: 'leaf_sublevel.yml canary2={{ canary }}' - static: yes +- import_tasks: leaf_sublevel.yml + vars: + canary2: '{{ canary }}' when: 'nested_include_static|bool' # value for 'static' can not be a variable, hence use 'when' -- include: 'leaf_sublevel.yml canary2={{ canary }}' - static: no +- include_tasks: leaf_sublevel.yml + vars: + canary2: '{{ canary }}' when: 'not nested_include_static|bool' diff --git a/test/integration/targets/includes/roles/test_includes/tasks/main.yml b/test/integration/targets/includes/roles/test_includes/tasks/main.yml index 6fcac9eb..83ca468b 100644 --- a/test/integration/targets/includes/roles/test_includes/tasks/main.yml +++ b/test/integration/targets/includes/roles/test_includes/tasks/main.yml @@ -81,26 +81,34 @@ - included_handler - verify_handler -- include: branch_toplevel.yml canary=value1 nested_include_static=no - static: no +- include_tasks: branch_toplevel.yml + vars: + canary: value1 + nested_include_static: 'no' - assert: that: - 'canary_fact == "value1"' -- include: branch_toplevel.yml canary=value2 nested_include_static=yes - static: no +- include_tasks: branch_toplevel.yml + vars: + canary: value2 + nested_include_static: 'yes' - assert: that: - 'canary_fact == "value2"' -- include: branch_toplevel.yml canary=value3 nested_include_static=no - static: yes +- import_tasks: branch_toplevel.yml + vars: + canary: value3 + nested_include_static: 'no' - assert: that: - 'canary_fact == "value3"' -- include: branch_toplevel.yml canary=value4 nested_include_static=yes - static: yes +- import_tasks: branch_toplevel.yml + vars: + canary: value4 + nested_include_static: 'yes' - assert: that: - 'canary_fact == "value4"' diff --git a/test/integration/targets/includes/runme.sh b/test/integration/targets/includes/runme.sh index 70ff105b..f4f0a016 100755 --- a/test/integration/targets/includes/runme.sh +++ b/test/integration/targets/includes/runme.sh @@ -5,3 +5,9 @@ set -eux ansible-playbook test_includes.yml -i ../../inventory "$@" ansible-playbook inherit_notify.yml "$@" + +echo "EXPECTED ERROR: Ensure we fail if using 'include' to include a playbook." +set +e +result="$(ansible-playbook -i ../../inventory include_on_playbook_should_fail.yml -v "$@" 2>&1)" +set -e +grep -q "ERROR! 'include' is not a valid attribute for a Play" <<< "$result" diff --git a/test/integration/targets/includes/test_includes.yml b/test/integration/targets/includes/test_includes.yml index 0bcebd4f..adeb80d2 100644 --- a/test/integration/targets/includes/test_includes.yml +++ b/test/integration/targets/includes/test_includes.yml @@ -1,7 +1,7 @@ -- include: test_includes2.yml parameter1=asdf parameter2=jkl +- import_playbook: test_includes2.yml parameter1=asdf parameter2=jkl -- include: test_includes3.yml +- import_playbook: test_includes3.yml -- include: test_include_free.yml +- import_playbook: test_include_free.yml -- include: test_include_host_pinned.yml +- import_playbook: test_include_host_pinned.yml diff --git a/test/integration/targets/includes_race/aliases b/test/integration/targets/includes_race/aliases index fff62d9f..1d28bdb2 100644 --- a/test/integration/targets/includes_race/aliases +++ b/test/integration/targets/includes_race/aliases @@ -1,2 +1,2 @@ shippable/posix/group5 -skip/aix +context/controller diff --git a/test/integration/targets/infra/aliases b/test/integration/targets/infra/aliases index 887d7029..71103238 100644 --- a/test/integration/targets/infra/aliases +++ b/test/integration/targets/infra/aliases @@ -1,3 +1,4 @@ shippable/posix/group3 needs/file/hacking/test-module.py needs/file/lib/ansible/modules/ping.py +context/controller diff --git a/test/integration/targets/infra/runme.sh b/test/integration/targets/infra/runme.sh index c4d84572..9e348b8c 100755 --- a/test/integration/targets/infra/runme.sh +++ b/test/integration/targets/infra/runme.sh @@ -30,10 +30,10 @@ PING_MODULE_PATH="../../../../lib/ansible/modules/ping.py" ../../../../hacking/test-module.py -m "$PING_MODULE_PATH" # ensure test-module.py script works well -../../../../hacking/test-module.py -m "$PING_MODULE_PATH" -I ansible_python_interpreter="$(which python)" +../../../../hacking/test-module.py -m "$PING_MODULE_PATH" -I ansible_python_interpreter="${ANSIBLE_TEST_PYTHON_INTERPRETER}" # ensure module.ansible_version is defined when using test-module.py -../../../../hacking/test-module.py -m library/test.py -I ansible_python_interpreter="$(which python)" <<< '{"ANSIBLE_MODULE_ARGS": {}}' +../../../../hacking/test-module.py -m library/test.py -I ansible_python_interpreter="${ANSIBLE_TEST_PYTHON_INTERPRETER}" <<< '{"ANSIBLE_MODULE_ARGS": {}}' # ensure exercising module code locally works python -m ansible.modules.file <<< '{"ANSIBLE_MODULE_ARGS": {"path": "/path/to/file", "state": "absent"}}' diff --git a/test/integration/targets/interpreter_discovery_python/aliases b/test/integration/targets/interpreter_discovery_python/aliases index 740ed1a5..0dfc90e7 100644 --- a/test/integration/targets/interpreter_discovery_python/aliases +++ b/test/integration/targets/interpreter_discovery_python/aliases @@ -1,2 +1,3 @@ shippable/posix/group1 non_local # workaround to allow override of ansible_python_interpreter; disables coverage on this integration target +context/target diff --git a/test/integration/targets/interpreter_discovery_python/tasks/main.yml b/test/integration/targets/interpreter_discovery_python/tasks/main.yml index b8bafd15..770de0c5 100644 --- a/test/integration/targets/interpreter_discovery_python/tasks/main.yml +++ b/test/integration/targets/interpreter_discovery_python/tasks/main.yml @@ -76,10 +76,10 @@ ping: register: legacy - - name: check for dep warning (only on platforms where auto result is not /usr/bin/python and legacy is) + - name: check for warning (only on platforms where auto result is not /usr/bin/python and legacy is) assert: that: - - legacy.deprecations | default([]) | length > 0 + - legacy.warnings | default([]) | length > 0 # only check for a dep warning if legacy returned /usr/bin/python and auto didn't when: legacy.ansible_facts.discovered_interpreter_python == '/usr/bin/python' and auto_out.ansible_facts.discovered_interpreter_python != '/usr/bin/python' diff --git a/test/integration/targets/interpreter_discovery_python_delegate_facts/aliases b/test/integration/targets/interpreter_discovery_python_delegate_facts/aliases index dc9ac468..b4026b5f 100644 --- a/test/integration/targets/interpreter_discovery_python_delegate_facts/aliases +++ b/test/integration/targets/interpreter_discovery_python_delegate_facts/aliases @@ -1,2 +1,3 @@ shippable/posix/group1 non_local # this test requires interpreter discovery, which means code coverage must be disabled +context/controller diff --git a/test/integration/targets/inventory/aliases b/test/integration/targets/inventory/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/inventory/aliases +++ b/test/integration/targets/inventory/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/module_utils_respawn/aliases b/test/integration/targets/inventory_advanced_host_list/aliases index a6dafcf8..a6dafcf8 100644 --- a/test/integration/targets/module_utils_respawn/aliases +++ b/test/integration/targets/inventory_advanced_host_list/aliases diff --git a/test/integration/targets/inventory_advanced_host_list/runme.sh b/test/integration/targets/inventory_advanced_host_list/runme.sh new file mode 100755 index 00000000..41b1f8b9 --- /dev/null +++ b/test/integration/targets/inventory_advanced_host_list/runme.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +set -eux + +export ANSIBLE_INVENTORY_ENABLED=advanced_host_list + +# A few things to make it easier to grep against adhoc +export ANSIBLE_LOAD_CALLBACK_PLUGINS=True +export ANSIBLE_STDOUT_CALLBACK=oneline + +adhoc="$(ansible -i 'local[0:10],' -m ping --connection=local -e ansible_python_interpreter="{{ ansible_playbook_python }}" all -v)" + +for i in $(seq 0 10); do + grep -qE "local${i} \| SUCCESS.*\"ping\": \"pong\"" <<< "$adhoc" +done + +set +e +parse_fail="$(ansible -i 'local[1:j],' -m ping --connection=local all -v 2>&1)" +set -e + +grep -q "Failed to parse local\[1:j\], with advanced_host_list" <<< "$parse_fail" + +# Intentionally missing comma, ensure we don't fatal. +no_comma="$(ansible -i 'local[1:5]' -m ping --connection=local all -v 2>&1)" +grep -q "No inventory was parsed" <<< "$no_comma" + +# Intentionally botched range (missing end number), ensure we don't fatal. +no_end="$(ansible -i 'local[1:],' -m ping --connection=local -e ansible_python_interpreter="{{ ansible_playbook_python }}" all -vvv 2>&1)" +grep -q "Unable to parse address from hostname, leaving unchanged:" <<< "$no_end" +grep -q "host range must specify end value" <<< "$no_end" +grep -q "local\[3:\] \| SUCCESS" <<< "$no_end" + +# Unset adhoc stuff +unset ANSIBLE_LOAD_CALLBACK_PLUGINS ANSIBLE_STDOUT_CALLBACK + +ansible-playbook -i 'local100,local[100:110:2]' test_advanced_host_list.yml -v "$@" diff --git a/test/integration/targets/inventory_advanced_host_list/test_advanced_host_list.yml b/test/integration/targets/inventory_advanced_host_list/test_advanced_host_list.yml new file mode 100644 index 00000000..918078ae --- /dev/null +++ b/test/integration/targets/inventory_advanced_host_list/test_advanced_host_list.yml @@ -0,0 +1,9 @@ +- hosts: all + connection: local + vars: + ansible_python_interpreter: "{{ ansible_playbook_python }}" + tasks: + - assert: + that: + - inventory_hostname in ["local100", "local102", "local104", "local106", "local108", "local110", "local118"] + - inventory_hostname not in ["local101", "local103", "local105", "local107", "local109", "local111"] diff --git a/test/integration/targets/inventory_cache/aliases b/test/integration/targets/inventory_cache/aliases index 70a7b7a9..1d28bdb2 100644 --- a/test/integration/targets/inventory_cache/aliases +++ b/test/integration/targets/inventory_cache/aliases @@ -1 +1,2 @@ shippable/posix/group5 +context/controller diff --git a/test/integration/targets/inventory_constructed/keyed_group_default_value.yml b/test/integration/targets/inventory_constructed/keyed_group_default_value.yml new file mode 100644 index 00000000..e4d0a76b --- /dev/null +++ b/test/integration/targets/inventory_constructed/keyed_group_default_value.yml @@ -0,0 +1,5 @@ +plugin: constructed +keyed_groups: + - key: tags + prefix: tag + default_value: "running" diff --git a/test/integration/targets/inventory_constructed/keyed_group_list_default_value.yml b/test/integration/targets/inventory_constructed/keyed_group_list_default_value.yml new file mode 100644 index 00000000..1c2d00e0 --- /dev/null +++ b/test/integration/targets/inventory_constructed/keyed_group_list_default_value.yml @@ -0,0 +1,5 @@ +plugin: constructed +keyed_groups: + - key: roles + default_value: storage + prefix: host
\ No newline at end of file diff --git a/test/integration/targets/inventory_constructed/keyed_group_str_default_value.yml b/test/integration/targets/inventory_constructed/keyed_group_str_default_value.yml new file mode 100644 index 00000000..ae3fd5ae --- /dev/null +++ b/test/integration/targets/inventory_constructed/keyed_group_str_default_value.yml @@ -0,0 +1,5 @@ +plugin: constructed +keyed_groups: + - key: os + default_value: "fedora" + prefix: host
\ No newline at end of file diff --git a/test/integration/targets/inventory_constructed/keyed_group_trailing_separator.yml b/test/integration/targets/inventory_constructed/keyed_group_trailing_separator.yml new file mode 100644 index 00000000..cbe57c60 --- /dev/null +++ b/test/integration/targets/inventory_constructed/keyed_group_trailing_separator.yml @@ -0,0 +1,5 @@ +plugin: constructed +keyed_groups: + - key: tags + prefix: tag + trailing_separator: False diff --git a/test/integration/targets/inventory_constructed/runme.sh b/test/integration/targets/inventory_constructed/runme.sh index 0cd1a293..91bbd66b 100755 --- a/test/integration/targets/inventory_constructed/runme.sh +++ b/test/integration/targets/inventory_constructed/runme.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -set -ex +set -eux ansible-inventory -i static_inventory.yml -i constructed.yml --graph | tee out.txt @@ -24,6 +24,33 @@ grep '@prefix_hostvalue1' out.txt grep '@prefix_item0' out.txt grep '@prefix_key0_value0' out.txt +# keyed group with default value for key's value empty (dict) +ansible-inventory -i tag_inventory.yml -i keyed_group_default_value.yml --graph | tee out.txt + +grep '@tag_name_host0' out.txt +grep '@tag_environment_test' out.txt +grep '@tag_status_running' out.txt + +# keyed group with default value for key's value empty (list) +ansible-inventory -i tag_inventory.yml -i keyed_group_list_default_value.yml --graph | tee out.txt + +grep '@host_db' out.txt +grep '@host_web' out.txt +grep '@host_storage' out.txt + +# keyed group with default value for key's value empty (str) +ansible-inventory -i tag_inventory.yml -i keyed_group_str_default_value.yml --graph | tee out.txt + +grep '@host_fedora' out.txt + + +# keyed group with 'trailing_separator' set to 'False' for key's value empty +ansible-inventory -i tag_inventory.yml -i keyed_group_trailing_separator.yml --graph | tee out.txt + +grep '@tag_name_host0' out.txt +grep '@tag_environment_test' out.txt +grep '@tag_status' out.txt + # test using use_vars_plugins ansible-inventory -i invs/1/one.yml -i invs/2/constructed.yml --graph | tee out.txt diff --git a/test/integration/targets/inventory_constructed/tag_inventory.yml b/test/integration/targets/inventory_constructed/tag_inventory.yml new file mode 100644 index 00000000..acf810ea --- /dev/null +++ b/test/integration/targets/inventory_constructed/tag_inventory.yml @@ -0,0 +1,12 @@ +all: + hosts: + host0: + tags: + name: "host0" + environment: "test" + status: "" + os: "" + roles: + - db + - web + - "" diff --git a/test/integration/targets/inventory_yaml/aliases b/test/integration/targets/inventory_yaml/aliases index f8e28c7e..a6dafcf8 100644 --- a/test/integration/targets/inventory_yaml/aliases +++ b/test/integration/targets/inventory_yaml/aliases @@ -1,2 +1 @@ shippable/posix/group1 -skip/aix diff --git a/test/integration/targets/jinja2_native_types/aliases b/test/integration/targets/jinja2_native_types/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/jinja2_native_types/aliases +++ b/test/integration/targets/jinja2_native_types/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/jinja_plugins/aliases b/test/integration/targets/jinja_plugins/aliases new file mode 100644 index 00000000..1d28bdb2 --- /dev/null +++ b/test/integration/targets/jinja_plugins/aliases @@ -0,0 +1,2 @@ +shippable/posix/group5 +context/controller diff --git a/test/integration/targets/jinja_plugins/collections/ansible_collections/foo/bar/plugins/filter/bad_collection_filter.py b/test/integration/targets/jinja_plugins/collections/ansible_collections/foo/bar/plugins/filter/bad_collection_filter.py new file mode 100644 index 00000000..36669532 --- /dev/null +++ b/test/integration/targets/jinja_plugins/collections/ansible_collections/foo/bar/plugins/filter/bad_collection_filter.py @@ -0,0 +1,11 @@ +# Copyright (c) 2021 Matt Martz <matt@sivel.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +class FilterModule: + def filters(self): + raise TypeError('bad_collection_filter') diff --git a/test/integration/targets/jinja_plugins/collections/ansible_collections/foo/bar/plugins/filter/good_collection_filter.py b/test/integration/targets/jinja_plugins/collections/ansible_collections/foo/bar/plugins/filter/good_collection_filter.py new file mode 100644 index 00000000..e2e7ffcd --- /dev/null +++ b/test/integration/targets/jinja_plugins/collections/ansible_collections/foo/bar/plugins/filter/good_collection_filter.py @@ -0,0 +1,13 @@ +# Copyright (c) 2021 Matt Martz <matt@sivel.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +class FilterModule: + def filters(self): + return { + 'hello': lambda x: 'Hello, %s!' % x, + } diff --git a/test/integration/targets/jinja_plugins/collections/ansible_collections/foo/bar/plugins/test/bad_collection_test.py b/test/integration/targets/jinja_plugins/collections/ansible_collections/foo/bar/plugins/test/bad_collection_test.py new file mode 100644 index 00000000..9fce5581 --- /dev/null +++ b/test/integration/targets/jinja_plugins/collections/ansible_collections/foo/bar/plugins/test/bad_collection_test.py @@ -0,0 +1,11 @@ +# Copyright (c) 2021 Matt Martz <matt@sivel.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +class TestModule: + def tests(self): + raise TypeError('bad_collection_test') diff --git a/test/integration/targets/jinja_plugins/collections/ansible_collections/foo/bar/plugins/test/good_collection_test.py b/test/integration/targets/jinja_plugins/collections/ansible_collections/foo/bar/plugins/test/good_collection_test.py new file mode 100644 index 00000000..a4ca2ff2 --- /dev/null +++ b/test/integration/targets/jinja_plugins/collections/ansible_collections/foo/bar/plugins/test/good_collection_test.py @@ -0,0 +1,13 @@ +# Copyright (c) 2021 Matt Martz <matt@sivel.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +class TestModule: + def tests(self): + return { + 'world': lambda x: x.lower() == 'world', + } diff --git a/test/integration/targets/jinja_plugins/filter_plugins/bad_filter.py b/test/integration/targets/jinja_plugins/filter_plugins/bad_filter.py new file mode 100644 index 00000000..eebf39c9 --- /dev/null +++ b/test/integration/targets/jinja_plugins/filter_plugins/bad_filter.py @@ -0,0 +1,11 @@ +# Copyright (c) 2021 Matt Martz <matt@sivel.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +class FilterModule: + def filters(self): + raise TypeError('bad_filter') diff --git a/test/integration/targets/jinja_plugins/filter_plugins/good_filter.py b/test/integration/targets/jinja_plugins/filter_plugins/good_filter.py new file mode 100644 index 00000000..e2e7ffcd --- /dev/null +++ b/test/integration/targets/jinja_plugins/filter_plugins/good_filter.py @@ -0,0 +1,13 @@ +# Copyright (c) 2021 Matt Martz <matt@sivel.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +class FilterModule: + def filters(self): + return { + 'hello': lambda x: 'Hello, %s!' % x, + } diff --git a/test/integration/targets/jinja_plugins/playbook.yml b/test/integration/targets/jinja_plugins/playbook.yml new file mode 100644 index 00000000..789be659 --- /dev/null +++ b/test/integration/targets/jinja_plugins/playbook.yml @@ -0,0 +1,10 @@ +- hosts: localhost + gather_facts: false + tasks: + - assert: + that: + - '"World"|hello == "Hello, World!"' + - '"World" is world' + + - '"World"|foo.bar.hello == "Hello, World!"' + - '"World" is foo.bar.world' diff --git a/test/integration/targets/jinja_plugins/tasks/main.yml b/test/integration/targets/jinja_plugins/tasks/main.yml new file mode 100644 index 00000000..012ec954 --- /dev/null +++ b/test/integration/targets/jinja_plugins/tasks/main.yml @@ -0,0 +1,22 @@ +- shell: ansible-playbook {{ verbosity }} playbook.yml + args: + chdir: '{{ role_path }}' + vars: + verbosity: "{{ '' if not ansible_verbosity else '-' ~ ('v' * ansible_verbosity) }}" + register: result + +- debug: + var: result + +- assert: + that: + - '"[WARNING]: Skipping filter plugin" in result.stderr' + - '"[WARNING]: Skipping test plugin" in result.stderr' + - | + result.stderr|regex_findall('bad_filter')|length == 2 + - | + result.stderr|regex_findall('bad_test')|length == 2 + - | + result.stderr|regex_findall('bad_collection_filter')|length == 2 + - | + result.stderr|regex_findall('bad_collection_test')|length == 2 diff --git a/test/integration/targets/jinja_plugins/test_plugins/bad_test.py b/test/integration/targets/jinja_plugins/test_plugins/bad_test.py new file mode 100644 index 00000000..0cc7a5a8 --- /dev/null +++ b/test/integration/targets/jinja_plugins/test_plugins/bad_test.py @@ -0,0 +1,11 @@ +# Copyright (c) 2021 Matt Martz <matt@sivel.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +class TestModule: + def tests(self): + raise TypeError('bad_test') diff --git a/test/integration/targets/jinja_plugins/test_plugins/good_test.py b/test/integration/targets/jinja_plugins/test_plugins/good_test.py new file mode 100644 index 00000000..a4ca2ff2 --- /dev/null +++ b/test/integration/targets/jinja_plugins/test_plugins/good_test.py @@ -0,0 +1,13 @@ +# Copyright (c) 2021 Matt Martz <matt@sivel.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +class TestModule: + def tests(self): + return { + 'world': lambda x: x.lower() == 'world', + } diff --git a/test/integration/targets/json_cleanup/aliases b/test/integration/targets/json_cleanup/aliases index 765b70da..90ea9e12 100644 --- a/test/integration/targets/json_cleanup/aliases +++ b/test/integration/targets/json_cleanup/aliases @@ -1 +1,2 @@ shippable/posix/group2 +context/controller diff --git a/test/integration/targets/limit_inventory/aliases b/test/integration/targets/limit_inventory/aliases index 3005e4b2..498fedd5 100644 --- a/test/integration/targets/limit_inventory/aliases +++ b/test/integration/targets/limit_inventory/aliases @@ -1 +1,2 @@ shippable/posix/group4 +context/controller diff --git a/test/integration/targets/lineinfile/meta/main.yml b/test/integration/targets/lineinfile/meta/main.yml index 98e60f78..a91e6847 100644 --- a/test/integration/targets/lineinfile/meta/main.yml +++ b/test/integration/targets/lineinfile/meta/main.yml @@ -18,3 +18,4 @@ dependencies: - prepare_tests + - setup_remote_tmp_dir diff --git a/test/integration/targets/lineinfile/tasks/main.yml b/test/integration/targets/lineinfile/tasks/main.yml index cad926b3..3d4678c2 100644 --- a/test/integration/targets/lineinfile/tasks/main.yml +++ b/test/integration/targets/lineinfile/tasks/main.yml @@ -19,7 +19,7 @@ - name: deploy the test file for lineinfile copy: src: test.txt - dest: "{{ output_dir }}/test.txt" + dest: "{{ remote_tmp_dir }}/test.txt" register: result - name: assert that the test file was deployed @@ -29,9 +29,62 @@ - "result.checksum == '5feac65e442c91f557fc90069ce6efc4d346ab51'" - "result.state == 'file'" +- name: "create a file that does not yet exist with `create: yes` and produce diff" + lineinfile: + dest: "{{ remote_tmp_dir }}/a/a.txt" + state: present + line: "First line" + create: yes + diff: yes + register: result1 + +- name: assert that a diff was returned + assert: + that: + - result1.diff | length > 0 + +- name: stat the new file + stat: + path: "{{ remote_tmp_dir }}/a/a.txt" + register: result + +- name: assert that the file exists + assert: + that: + - result.stat.exists + +- block: + - name: "EXPECTED FAILURE - test source file does not exist w/o `create: yes`" + lineinfile: + path: "/some/where/that/doesnotexist.txt" + state: present + line: "Doesn't matter" + - fail: + msg: "Should not get here" + rescue: + - name: Validate failure + assert: + that: + - "'Destination /some/where/that/doesnotexist.txt does not exist !' in ansible_failed_result.msg" + +- block: + - name: EXPECTED FAILURE - test invalid `validate` value + lineinfile: + path: "{{ remote_tmp_dir }}/test.txt" + state: present + line: "Doesn't matter" + validate: '/some/path' + - fail: + msg: "Should not get here" + rescue: + - name: Validate failure + assert: + that: + - "'validate must contain %s: /some/path' in ansible_failed_result.msg" + - name: insert a line at the beginning of the file, and back it up lineinfile: - dest: "{{ output_dir }}/test.txt" + dest: "{{ remote_tmp_dir }}/test.txt" state: present line: "New line at the beginning" insertbefore: "BOF" @@ -40,7 +93,7 @@ - name: insert a line at the beginning of the file again lineinfile: - dest: "{{ output_dir }}/test.txt" + dest: "{{ remote_tmp_dir }}/test.txt" state: present line: "New line at the beginning" insertbefore: "BOF" @@ -66,7 +119,7 @@ - name: stat the test after the insert at the head stat: - path: "{{ output_dir }}/test.txt" + path: "{{ remote_tmp_dir }}/test.txt" register: result - name: assert test hash is what we expect for the file with the insert at the head @@ -76,7 +129,7 @@ - name: insert a line at the end of the file lineinfile: - dest: "{{ output_dir }}/test.txt" + dest: "{{ remote_tmp_dir }}/test.txt" state: present line: "New line at the end" insertafter: "EOF" @@ -90,7 +143,7 @@ - name: stat the test after the insert at the end stat: - path: "{{ output_dir }}/test.txt" + path: "{{ remote_tmp_dir }}/test.txt" register: result - name: assert test checksum matches after the insert at the end @@ -100,7 +153,7 @@ - name: insert a line after the first line lineinfile: - dest: "{{ output_dir }}/test.txt" + dest: "{{ remote_tmp_dir }}/test.txt" state: present line: "New line after line 1" insertafter: "^This is line 1$" @@ -114,7 +167,7 @@ - name: stat the test after insert after the first line stat: - path: "{{ output_dir }}/test.txt" + path: "{{ remote_tmp_dir }}/test.txt" register: result - name: assert test checksum matches after the insert after the first line @@ -124,7 +177,7 @@ - name: insert a line before the last line lineinfile: - dest: "{{ output_dir }}/test.txt" + dest: "{{ remote_tmp_dir }}/test.txt" state: present line: "New line before line 5" insertbefore: "^This is line 5$" @@ -138,7 +191,7 @@ - name: stat the test after the insert before the last line stat: - path: "{{ output_dir }}/test.txt" + path: "{{ remote_tmp_dir }}/test.txt" register: result - name: assert test checksum matches after the insert before the last line @@ -148,7 +201,7 @@ - name: Replace a line with backrefs lineinfile: - dest: "{{ output_dir }}/test.txt" + dest: "{{ remote_tmp_dir }}/test.txt" state: present line: "This is line 3" backrefs: yes @@ -157,13 +210,13 @@ - name: Replace a line with backrefs again lineinfile: - dest: "{{ output_dir }}/test.txt" + dest: "{{ remote_tmp_dir }}/test.txt" state: present line: "This is line 3" backrefs: yes regexp: "^(REF) .* \\1$" register: backrefs_result2 -- command: cat {{ output_dir }}/test.txt +- command: cat {{ remote_tmp_dir }}/test.txt - name: assert that the line with backrefs was changed assert: @@ -174,7 +227,7 @@ - name: stat the test after the backref line was replaced stat: - path: "{{ output_dir }}/test.txt" + path: "{{ remote_tmp_dir }}/test.txt" register: result - name: assert test checksum matches after backref line was replaced @@ -184,7 +237,7 @@ - name: remove the middle line lineinfile: - dest: "{{ output_dir }}/test.txt" + dest: "{{ remote_tmp_dir }}/test.txt" state: absent regexp: "^This is line 3$" register: result @@ -197,7 +250,7 @@ - name: stat the test after the middle line was removed stat: - path: "{{ output_dir }}/test.txt" + path: "{{ remote_tmp_dir }}/test.txt" register: result - name: assert test checksum matches after the middle line was removed @@ -207,7 +260,7 @@ - name: run a validation script that succeeds lineinfile: - dest: "{{ output_dir }}/test.txt" + dest: "{{ remote_tmp_dir }}/test.txt" state: absent regexp: "^This is line 5$" validate: "true %s" @@ -221,7 +274,7 @@ - name: stat the test after the validation succeeded stat: - path: "{{ output_dir }}/test.txt" + path: "{{ remote_tmp_dir }}/test.txt" register: result - name: assert test checksum matches after the validation succeeded @@ -231,7 +284,7 @@ - name: run a validation script that fails lineinfile: - dest: "{{ output_dir }}/test.txt" + dest: "{{ remote_tmp_dir }}/test.txt" state: absent regexp: "^This is line 1$" validate: "/bin/false %s" @@ -245,7 +298,7 @@ - name: stat the test after the validation failed stat: - path: "{{ output_dir }}/test.txt" + path: "{{ remote_tmp_dir }}/test.txt" register: result - name: assert test checksum matches the previous after the validation failed @@ -257,7 +310,7 @@ - name: use create=yes lineinfile: - dest: "{{ output_dir }}/new_test.txt" + dest: "{{ remote_tmp_dir }}/new_test.txt" create: yes insertbefore: BOF state: present @@ -272,7 +325,7 @@ - name: validate that the newly created file exists stat: - path: "{{ output_dir }}/new_test.txt" + path: "{{ remote_tmp_dir }}/new_test.txt" register: result ignore_errors: yes @@ -303,12 +356,12 @@ - name: testnoeof deploy the file for lineinfile copy: src: testnoeof.txt - dest: "{{ output_dir }}/testnoeof.txt" + dest: "{{ remote_tmp_dir }}/testnoeof.txt" register: result - name: testnoeof insert a line at the end of the file lineinfile: - dest: "{{ output_dir }}/testnoeof.txt" + dest: "{{ remote_tmp_dir }}/testnoeof.txt" state: present line: "New line at the end" insertafter: "EOF" @@ -322,7 +375,7 @@ - name: insert a multiple lines at the end of the file lineinfile: - dest: "{{ output_dir }}/test.txt" + dest: "{{ remote_tmp_dir }}/test.txt" state: present line: "This is a line\nwith \\n character" insertafter: "EOF" @@ -336,7 +389,7 @@ - name: testnoeof stat the no newline EOF test after the insert at the end stat: - path: "{{ output_dir }}/testnoeof.txt" + path: "{{ remote_tmp_dir }}/testnoeof.txt" register: result - name: testnoeof assert test checksum matches after the insert at the end @@ -348,12 +401,12 @@ - name: testempty deploy the testempty file for lineinfile copy: src: testempty.txt - dest: "{{ output_dir }}/testempty.txt" + dest: "{{ remote_tmp_dir }}/testempty.txt" register: result - name: testempty insert a line at the end of the file lineinfile: - dest: "{{ output_dir }}/testempty.txt" + dest: "{{ remote_tmp_dir }}/testempty.txt" state: present line: "New line at the end" insertafter: "EOF" @@ -367,7 +420,7 @@ - name: testempty stat the test after the insert at the end stat: - path: "{{ output_dir }}/testempty.txt" + path: "{{ remote_tmp_dir }}/testempty.txt" register: result - name: testempty assert test checksum matches after the insert at the end @@ -376,7 +429,7 @@ - "result.stat.checksum == 'f440dc65ea9cec3fd496c1479ddf937e1b949412'" - stat: - path: "{{ output_dir }}/test.txt" + path: "{{ remote_tmp_dir }}/test.txt" register: result - name: assert test checksum matches after inserting multiple lines @@ -386,7 +439,7 @@ - name: replace a line with backrefs included in the line lineinfile: - dest: "{{ output_dir }}/test.txt" + dest: "{{ remote_tmp_dir }}/test.txt" state: present line: "New \\1 created with the backref" backrefs: yes @@ -401,7 +454,7 @@ - name: stat the test after the backref line was replaced stat: - path: "{{ output_dir }}/test.txt" + path: "{{ remote_tmp_dir }}/test.txt" register: result - name: assert test checksum matches after backref line was replaced @@ -414,7 +467,7 @@ - name: create a new file for testing quoting issues file: - dest: "{{ output_dir }}/test_quoting.txt" + dest: "{{ remote_tmp_dir }}/test_quoting.txt" state: touch register: result @@ -425,7 +478,7 @@ - name: use with_items to add code-like strings to the quoting txt file lineinfile: - dest: "{{ output_dir }}/test_quoting.txt" + dest: "{{ remote_tmp_dir }}/test_quoting.txt" line: "{{ item }}" insertbefore: BOF with_items: @@ -447,7 +500,7 @@ - name: stat the quote test file stat: - path: "{{ output_dir }}/test_quoting.txt" + path: "{{ remote_tmp_dir }}/test_quoting.txt" register: result - name: assert test checksum matches after backref line was replaced @@ -457,7 +510,7 @@ - name: insert a line into the quoted file with a single quote lineinfile: - dest: "{{ output_dir }}/test_quoting.txt" + dest: "{{ remote_tmp_dir }}/test_quoting.txt" line: "import g'" register: result @@ -468,7 +521,7 @@ - name: stat the quote test file stat: - path: "{{ output_dir }}/test_quoting.txt" + path: "{{ remote_tmp_dir }}/test_quoting.txt" register: result - name: assert test checksum matches after backref line was replaced @@ -478,7 +531,7 @@ - name: insert a line into the quoted file with many double quotation strings lineinfile: - dest: "{{ output_dir }}/test_quoting.txt" + dest: "{{ remote_tmp_dir }}/test_quoting.txt" line: "\"quote\" and \"unquote\"" register: result @@ -489,7 +542,7 @@ - name: stat the quote test file stat: - path: "{{ output_dir }}/test_quoting.txt" + path: "{{ remote_tmp_dir }}/test_quoting.txt" register: result - name: assert test checksum matches after backref line was replaced @@ -503,7 +556,7 @@ - name: Deploy the testmultiple file copy: src: testmultiple.txt - dest: "{{ output_dir }}/testmultiple.txt" + dest: "{{ remote_tmp_dir }}/testmultiple.txt" register: result - name: Assert that the testmultiple file was deployed @@ -516,7 +569,7 @@ # Test insertafter - name: Write the same line to a file inserted after different lines lineinfile: - path: "{{ output_dir }}/testmultiple.txt" + path: "{{ remote_tmp_dir }}/testmultiple.txt" insertafter: "{{ item.regex }}" line: "{{ item.replace }}" register: _multitest_1 @@ -532,7 +585,7 @@ - name: Do the same thing again to check for changes lineinfile: - path: "{{ output_dir }}/testmultiple.txt" + path: "{{ remote_tmp_dir }}/testmultiple.txt" insertafter: "{{ item.regex }}" line: "{{ item.replace }}" register: _multitest_2 @@ -548,7 +601,7 @@ - name: Stat the insertafter file stat: - path: "{{ output_dir }}/testmultiple.txt" + path: "{{ remote_tmp_dir }}/testmultiple.txt" register: result - name: Assert that the insertafter file matches expected checksum @@ -561,7 +614,7 @@ - name: Deploy the testmultiple file copy: src: testmultiple.txt - dest: "{{ output_dir }}/testmultiple.txt" + dest: "{{ remote_tmp_dir }}/testmultiple.txt" register: result - name: Assert that the testmultiple file was deployed @@ -573,7 +626,7 @@ - name: Write the same line to a file inserted before different lines lineinfile: - path: "{{ output_dir }}/testmultiple.txt" + path: "{{ remote_tmp_dir }}/testmultiple.txt" insertbefore: "{{ item.regex }}" line: "{{ item.replace }}" register: _multitest_3 @@ -589,7 +642,7 @@ - name: Do the same thing again to check for changes lineinfile: - path: "{{ output_dir }}/testmultiple.txt" + path: "{{ remote_tmp_dir }}/testmultiple.txt" insertbefore: "{{ item.regex }}" line: "{{ item.replace }}" register: _multitest_4 @@ -605,7 +658,7 @@ - name: Stat the insertbefore file stat: - path: "{{ output_dir }}/testmultiple.txt" + path: "{{ remote_tmp_dir }}/testmultiple.txt" register: result - name: Assert that the insertbefore file matches expected checksum @@ -620,7 +673,7 @@ - name: Deploy the test.conf file copy: src: test.conf - dest: "{{ output_dir }}/test.conf" + dest: "{{ remote_tmp_dir }}/test.conf" register: result - name: Assert that the test.conf file was deployed @@ -633,7 +686,7 @@ # Test instertafter - name: Insert lines after with regexp lineinfile: - path: "{{ output_dir }}/test.conf" + path: "{{ remote_tmp_dir }}/test.conf" regexp: "{{ item.regexp }}" line: "{{ item.line }}" insertafter: "{{ item.after }}" @@ -642,7 +695,7 @@ - name: Do the same thing again and check for changes lineinfile: - path: "{{ output_dir }}/test.conf" + path: "{{ remote_tmp_dir }}/test.conf" regexp: "{{ item.regexp }}" line: "{{ item.line }}" insertafter: "{{ item.after }}" @@ -660,7 +713,7 @@ - name: Stat the file stat: - path: "{{ output_dir }}/test.conf" + path: "{{ remote_tmp_dir }}/test.conf" register: result - name: Assert that the file contents match what is expected @@ -670,7 +723,7 @@ - name: Do the same thing a third time without regexp and check for changes lineinfile: - path: "{{ output_dir }}/test.conf" + path: "{{ remote_tmp_dir }}/test.conf" line: "{{ item.line }}" insertafter: "{{ item.after }}" with_items: "{{ test_befaf_regexp }}" @@ -678,7 +731,7 @@ - name: Stat the file stat: - path: "{{ output_dir }}/test.conf" + path: "{{ remote_tmp_dir }}/test.conf" register: result - name: Assert that the file was changed when no regexp was provided @@ -689,7 +742,7 @@ - name: Stat the file stat: - path: "{{ output_dir }}/test.conf" + path: "{{ remote_tmp_dir }}/test.conf" register: result - name: Assert that the file contents match what is expected @@ -701,7 +754,7 @@ - name: Deploy the test.conf file copy: src: test.conf - dest: "{{ output_dir }}/test.conf" + dest: "{{ remote_tmp_dir }}/test.conf" register: result - name: Assert that the test.conf file was deployed @@ -713,7 +766,7 @@ - name: Insert lines before with regexp lineinfile: - path: "{{ output_dir }}/test.conf" + path: "{{ remote_tmp_dir }}/test.conf" regexp: "{{ item.regexp }}" line: "{{ item.line }}" insertbefore: "{{ item.before }}" @@ -722,7 +775,7 @@ - name: Do the same thing again and check for changes lineinfile: - path: "{{ output_dir }}/test.conf" + path: "{{ remote_tmp_dir }}/test.conf" regexp: "{{ item.regexp }}" line: "{{ item.line }}" insertbefore: "{{ item.before }}" @@ -740,7 +793,7 @@ - name: Stat the file stat: - path: "{{ output_dir }}/test.conf" + path: "{{ remote_tmp_dir }}/test.conf" register: result - name: Assert that the file contents match what is expected @@ -750,7 +803,7 @@ - name: Do the same thing a third time without regexp and check for changes lineinfile: - path: "{{ output_dir }}/test.conf" + path: "{{ remote_tmp_dir }}/test.conf" line: "{{ item.line }}" insertbefore: "{{ item.before }}" with_items: "{{ test_befaf_regexp }}" @@ -758,7 +811,7 @@ - name: Stat the file stat: - path: "{{ output_dir }}/test.conf" + path: "{{ remote_tmp_dir }}/test.conf" register: result - name: Assert that the file was changed when no regexp was provided @@ -769,7 +822,7 @@ - name: Stat the file stat: - path: "{{ output_dir }}/test.conf" + path: "{{ remote_tmp_dir }}/test.conf" register: result - name: Assert that the file contents match what is expected @@ -780,25 +833,25 @@ - name: Copy empty file to test with insertbefore copy: src: testempty.txt - dest: "{{ output_dir }}/testempty.txt" + dest: "{{ remote_tmp_dir }}/testempty.txt" - name: Add a line to empty file with insertbefore lineinfile: - path: "{{ output_dir }}/testempty.txt" + path: "{{ remote_tmp_dir }}/testempty.txt" line: top insertbefore: '^not in the file$' register: oneline_insbefore_test1 - name: Add a line to file with only one line using insertbefore lineinfile: - path: "{{ output_dir }}/testempty.txt" + path: "{{ remote_tmp_dir }}/testempty.txt" line: top insertbefore: '^not in the file$' register: oneline_insbefore_test2 - name: Stat the file stat: - path: "{{ output_dir }}/testempty.txt" + path: "{{ remote_tmp_dir }}/testempty.txt" register: oneline_insbefore_file - name: Assert that insertebefore worked properly with a one line file @@ -817,7 +870,7 @@ - name: Deploy the test file for lineinfile copy: src: test.txt - dest: "{{ output_dir }}/test.txt" + dest: "{{ remote_tmp_dir }}/test.txt" register: result - name: Assert that the test file was deployed @@ -829,14 +882,14 @@ - name: Insert a line in the file using an empty string as a regular expression lineinfile: - path: "{{ output_dir }}/test.txt" + path: "{{ remote_tmp_dir }}/test.txt" regexp: '' line: This is line 6 register: insert_empty_regexp - name: Stat the file stat: - path: "{{ output_dir }}/test.txt" + path: "{{ remote_tmp_dir }}/test.txt" register: result - name: Assert that the file contents match what is expected and a warning was displayed @@ -858,7 +911,7 @@ - name: Deploy the test file for lineinfile copy: src: teststring.txt - dest: "{{ output_dir }}/teststring.txt" + dest: "{{ remote_tmp_dir }}/teststring.txt" register: result - name: Assert that the test file was deployed @@ -870,14 +923,14 @@ - name: Insert a line in the file using an empty string as a search string lineinfile: - path: "{{ output_dir }}/teststring.txt" + path: "{{ remote_tmp_dir }}/teststring.txt" search_string: '' line: This is line 6 register: insert_empty_literal - name: Stat the file stat: - path: "{{ output_dir }}/teststring.txt" + path: "{{ remote_tmp_dir }}/teststring.txt" register: result - name: Assert that the file contents match what is expected and a warning was displayed @@ -901,7 +954,7 @@ - name: Deploy the firstmatch test file copy: src: firstmatch.txt - dest: "{{ output_dir }}/firstmatch.txt" + dest: "{{ remote_tmp_dir }}/firstmatch.txt" register: result - name: Assert that the test file was deployed @@ -913,7 +966,7 @@ - name: Insert a line before an existing line using firstmatch lineinfile: - path: "{{ output_dir }}/firstmatch.txt" + path: "{{ remote_tmp_dir }}/firstmatch.txt" line: INSERT insertafter: line1 firstmatch: yes @@ -921,7 +974,7 @@ - name: Insert a line before an existing line using firstmatch again lineinfile: - path: "{{ output_dir }}/firstmatch.txt" + path: "{{ remote_tmp_dir }}/firstmatch.txt" line: INSERT insertafter: line1 firstmatch: yes @@ -929,7 +982,7 @@ - name: Stat the file stat: - path: "{{ output_dir }}/firstmatch.txt" + path: "{{ remote_tmp_dir }}/firstmatch.txt" register: result - name: Assert that the file was modified appropriately @@ -947,7 +1000,7 @@ - name: Deploy the test file copy: src: test_58923.txt - dest: "{{ output_dir }}/test_58923.txt" + dest: "{{ remote_tmp_dir }}/test_58923.txt" register: initial_file - name: Assert that the test file was deployed @@ -968,7 +1021,7 @@ # Regexp is not present in the file, so the line must be inserted after ^#!/bin/sh - name: Add the line using firstmatch, regexp, and insertafter lineinfile: - path: "{{ output_dir }}/test_58923.txt" + path: "{{ remote_tmp_dir }}/test_58923.txt" insertafter: '^#!/bin/sh' regexp: ^export FISHEYE_OPTS firstmatch: true @@ -977,12 +1030,12 @@ - name: Stat the file stat: - path: "{{ output_dir }}/test_58923.txt" + path: "{{ remote_tmp_dir }}/test_58923.txt" register: insertafter_test1_file - name: Add the line using firstmatch, regexp, and insertafter again lineinfile: - path: "{{ output_dir }}/test_58923.txt" + path: "{{ remote_tmp_dir }}/test_58923.txt" insertafter: '^#!/bin/sh' regexp: ^export FISHEYE_OPTS firstmatch: true @@ -994,7 +1047,7 @@ # so nothing has been added: - name: Stat the file again stat: - path: "{{ output_dir }}/test_58923.txt" + path: "{{ remote_tmp_dir }}/test_58923.txt" register: insertafter_test2_file - name: Assert insertafter tests gave the expected results @@ -1009,7 +1062,7 @@ - name: Deploy the test file copy: src: test_58923.txt - dest: "{{ output_dir }}/test_58923.txt" + dest: "{{ remote_tmp_dir }}/test_58923.txt" register: initial_file - name: Assert that the test file was deployed @@ -1021,7 +1074,7 @@ - name: Insert the line using firstmatch and insertafter without regexp lineinfile: - path: "{{ output_dir }}/test_58923.txt" + path: "{{ remote_tmp_dir }}/test_58923.txt" insertafter: '^#!/bin/sh' firstmatch: true line: export FISHEYE_OPTS="-Xmx4096m -Xms2048m" @@ -1029,12 +1082,12 @@ - name: Stat the file stat: - path: "{{ output_dir }}/test_58923.txt" + path: "{{ remote_tmp_dir }}/test_58923.txt" register: insertafter_test3_file - name: Insert the line using firstmatch and insertafter without regexp again lineinfile: - path: "{{ output_dir }}/test_58923.txt" + path: "{{ remote_tmp_dir }}/test_58923.txt" insertafter: '^#!/bin/sh' firstmatch: true line: export FISHEYE_OPTS="-Xmx4096m -Xms2048m" @@ -1042,7 +1095,7 @@ - name: Stat the file again stat: - path: "{{ output_dir }}/test_58923.txt" + path: "{{ remote_tmp_dir }}/test_58923.txt" register: insertafter_test4_file - name: Assert insertafter without regexp tests gave the expected results @@ -1058,7 +1111,7 @@ - name: Deploy the test file copy: src: test_58923.txt - dest: "{{ output_dir }}/test_58923.txt" + dest: "{{ remote_tmp_dir }}/test_58923.txt" register: initial_file - name: Assert that the test file was deployed @@ -1070,7 +1123,7 @@ - name: Add the line using regexp, firstmatch, and insertbefore lineinfile: - path: "{{ output_dir }}/test_58923.txt" + path: "{{ remote_tmp_dir }}/test_58923.txt" insertbefore: '^#!/bin/sh' regexp: ^export FISHEYE_OPTS firstmatch: true @@ -1079,12 +1132,12 @@ - name: Stat the file stat: - path: "{{ output_dir }}/test_58923.txt" + path: "{{ remote_tmp_dir }}/test_58923.txt" register: insertbefore_test1_file - name: Add the line using regexp, firstmatch, and insertbefore again lineinfile: - path: "{{ output_dir }}/test_58923.txt" + path: "{{ remote_tmp_dir }}/test_58923.txt" insertbefore: '^#!/bin/sh' regexp: ^export FISHEYE_OPTS firstmatch: true @@ -1093,7 +1146,7 @@ - name: Stat the file again stat: - path: "{{ output_dir }}/test_58923.txt" + path: "{{ remote_tmp_dir }}/test_58923.txt" register: insertbefore_test2_file - name: Assert insertbefore with regexp tests gave the expected results @@ -1109,7 +1162,7 @@ - name: Deploy the test file copy: src: test_58923.txt - dest: "{{ output_dir }}/test_58923.txt" + dest: "{{ remote_tmp_dir }}/test_58923.txt" register: initial_file - name: Assert that the test file was deployed @@ -1121,7 +1174,7 @@ - name: Add the line using insertbefore and firstmatch lineinfile: - path: "{{ output_dir }}/test_58923.txt" + path: "{{ remote_tmp_dir }}/test_58923.txt" insertbefore: '^#!/bin/sh' firstmatch: true line: export FISHEYE_OPTS="-Xmx4096m -Xms2048m" @@ -1129,12 +1182,12 @@ - name: Stat the file stat: - path: "{{ output_dir }}/test_58923.txt" + path: "{{ remote_tmp_dir }}/test_58923.txt" register: insertbefore_test3_file - name: Add the line using insertbefore and firstmatch again lineinfile: - path: "{{ output_dir }}/test_58923.txt" + path: "{{ remote_tmp_dir }}/test_58923.txt" insertbefore: '^#!/bin/sh' firstmatch: true line: export FISHEYE_OPTS="-Xmx4096m -Xms2048m" @@ -1142,7 +1195,7 @@ - name: Stat the file again stat: - path: "{{ output_dir }}/test_58923.txt" + path: "{{ remote_tmp_dir }}/test_58923.txt" register: insertbefore_test4_file # Test when the line is presented in the file but @@ -1151,7 +1204,7 @@ Add the line using insertbefore and firstmatch when the regexp line is presented but not close to insertbefore spot lineinfile: - path: "{{ output_dir }}/test_58923.txt" + path: "{{ remote_tmp_dir }}/test_58923.txt" insertbefore: ' Darwin\*\) if \[ -z \"\$JAVA_HOME\" \] ; then' firstmatch: true line: export FISHEYE_OPTS="-Xmx4096m -Xms2048m" @@ -1159,7 +1212,7 @@ - name: Stat the file again stat: - path: "{{ output_dir }}/test_58923.txt" + path: "{{ remote_tmp_dir }}/test_58923.txt" register: insertbefore_test5_file - name: Assert insertbefore with regexp tests gave the expected results @@ -1179,7 +1232,7 @@ - name: Deploy the test file copy: src: teststring_58923.txt - dest: "{{ output_dir }}/teststring_58923.txt" + dest: "{{ remote_tmp_dir }}/teststring_58923.txt" register: initial_file - name: Assert that the test file was deployed @@ -1200,7 +1253,7 @@ # literal is not present in the file, so the line must be inserted after ^#!/bin/sh - name: Add the line using firstmatch, regexp, and insertafter lineinfile: - path: "{{ output_dir }}/teststring_58923.txt" + path: "{{ remote_tmp_dir }}/teststring_58923.txt" insertafter: '^#!/bin/sh' search_string: export FISHEYE_OPTS firstmatch: true @@ -1209,12 +1262,12 @@ - name: Stat the file stat: - path: "{{ output_dir }}/teststring_58923.txt" + path: "{{ remote_tmp_dir }}/teststring_58923.txt" register: insertafter_test1_file - name: Add the line using firstmatch, literal, and insertafter again lineinfile: - path: "{{ output_dir }}/teststring_58923.txt" + path: "{{ remote_tmp_dir }}/teststring_58923.txt" insertafter: '^#!/bin/sh' search_string: export FISHEYE_OPTS firstmatch: true @@ -1226,7 +1279,7 @@ # so nothing has been added: - name: Stat the file again stat: - path: "{{ output_dir }}/teststring_58923.txt" + path: "{{ remote_tmp_dir }}/teststring_58923.txt" register: insertafter_test2_file - name: Assert insertafter tests gave the expected results @@ -1241,7 +1294,7 @@ - name: Deploy the test file copy: src: teststring_58923.txt - dest: "{{ output_dir }}/teststring_58923.txt" + dest: "{{ remote_tmp_dir }}/teststring_58923.txt" register: initial_file - name: Assert that the test file was deployed @@ -1253,7 +1306,7 @@ - name: Add the line using literal, firstmatch, and insertbefore lineinfile: - path: "{{ output_dir }}/teststring_58923.txt" + path: "{{ remote_tmp_dir }}/teststring_58923.txt" insertbefore: '^#!/bin/sh' search_string: export FISHEYE_OPTS firstmatch: true @@ -1262,12 +1315,12 @@ - name: Stat the file stat: - path: "{{ output_dir }}/teststring_58923.txt" + path: "{{ remote_tmp_dir }}/teststring_58923.txt" register: insertbefore_test1_file - name: Add the line using literal, firstmatch, and insertbefore again lineinfile: - path: "{{ output_dir }}/teststring_58923.txt" + path: "{{ remote_tmp_dir }}/teststring_58923.txt" insertbefore: '^#!/bin/sh' search_string: export FISHEYE_OPTS firstmatch: true @@ -1276,7 +1329,7 @@ - name: Stat the file again stat: - path: "{{ output_dir }}/teststring_58923.txt" + path: "{{ remote_tmp_dir }}/teststring_58923.txt" register: insertbefore_test2_file - name: Assert insertbefore with literal tests gave the expected results @@ -1291,14 +1344,14 @@ # https://github.com/ansible/ansible/issues/63684 - name: Create a file by inserting a line lineinfile: - path: "{{ output_dir }}/testend.txt" + path: "{{ remote_tmp_dir }}/testend.txt" create: yes line: testline register: testend1 - name: Insert a line at the end of the file lineinfile: - path: "{{ output_dir }}/testend.txt" + path: "{{ remote_tmp_dir }}/testend.txt" insertafter: testline regexp: line at the end line: line at the end @@ -1306,7 +1359,7 @@ - name: Stat the file stat: - path: "{{ output_dir }}/testend.txt" + path: "{{ remote_tmp_dir }}/testend.txt" register: testend_file - name: Assert inserting at the end gave the expected results. @@ -1320,14 +1373,14 @@ - name: Create a file by inserting a line lineinfile: - path: "{{ output_dir }}/testendliteral.txt" + path: "{{ remote_tmp_dir }}/testendliteral.txt" create: yes line: testline register: testend1 - name: Insert a line at the end of the file lineinfile: - path: "{{ output_dir }}/testendliteral.txt" + path: "{{ remote_tmp_dir }}/testendliteral.txt" insertafter: testline search_string: line at the end line: line at the end @@ -1335,7 +1388,7 @@ - name: Stat the file stat: - path: "{{ output_dir }}/testendliteral.txt" + path: "{{ remote_tmp_dir }}/testendliteral.txt" register: testend_file - name: Assert inserting at the end gave the expected results. diff --git a/test/integration/targets/lineinfile/tasks/test_string01.yml b/test/integration/targets/lineinfile/tasks/test_string01.yml index 6e0c12c3..b86cd09a 100644 --- a/test/integration/targets/lineinfile/tasks/test_string01.yml +++ b/test/integration/targets/lineinfile/tasks/test_string01.yml @@ -5,7 +5,7 @@ - name: deploy the test file for lineinfile string copy: src: teststring.txt - dest: "{{ output_dir }}/teststring.txt" + dest: "{{ remote_tmp_dir }}/teststring.txt" register: result - name: assert that the test file was deployed @@ -17,7 +17,7 @@ - name: insert a line at the beginning of the file, and back it up lineinfile: - dest: "{{ output_dir }}/teststring.txt" + dest: "{{ remote_tmp_dir }}/teststring.txt" state: present line: "New line at the beginning" insertbefore: "BOF" @@ -26,7 +26,7 @@ - name: insert a line at the beginning of the file again lineinfile: - dest: "{{ output_dir }}/teststring.txt" + dest: "{{ remote_tmp_dir }}/teststring.txt" state: present line: "New line at the beginning" insertbefore: "BOF" @@ -34,7 +34,7 @@ - name: Replace a line using string lineinfile: - dest: "{{ output_dir }}/teststring.txt" + dest: "{{ remote_tmp_dir }}/teststring.txt" state: present line: "Thi$ i^ [ine 3" search_string: (\\w)(\\s+)([\\.,]) @@ -42,13 +42,13 @@ - name: Replace a line again using string lineinfile: - dest: "{{ output_dir }}/teststring.txt" + dest: "{{ remote_tmp_dir }}/teststring.txt" state: present line: "Thi$ i^ [ine 3" search_string: (\\w)(\\s+)([\\.,]) register: backrefs_result2 -- command: cat {{ output_dir }}/teststring.txt +- command: cat {{ remote_tmp_dir }}/teststring.txt - name: assert that the line with backrefs was changed assert: @@ -59,7 +59,7 @@ - name: stat the test after the backref line was replaced stat: - path: "{{ output_dir }}/teststring.txt" + path: "{{ remote_tmp_dir }}/teststring.txt" register: result - name: assert test checksum matches after backref line was replaced @@ -69,7 +69,7 @@ - name: remove the middle line using string lineinfile: - dest: "{{ output_dir }}/teststring.txt" + dest: "{{ remote_tmp_dir }}/teststring.txt" state: absent search_string: "Thi$ i^ [ine 3" register: result @@ -82,7 +82,7 @@ - name: stat the test after the middle line was removed stat: - path: "{{ output_dir }}/teststring.txt" + path: "{{ remote_tmp_dir }}/teststring.txt" register: result - name: assert test checksum matches after the middle line was removed @@ -92,7 +92,7 @@ - name: run a validation script that succeeds using string lineinfile: - dest: "{{ output_dir }}/teststring.txt" + dest: "{{ remote_tmp_dir }}/teststring.txt" state: absent search_string: <FilesMatch ".py[45]?$"> validate: "true %s" @@ -106,7 +106,7 @@ - name: stat the test after the validation succeeded stat: - path: "{{ output_dir }}/teststring.txt" + path: "{{ remote_tmp_dir }}/teststring.txt" register: result - name: assert test checksum matches after the validation succeeded @@ -116,7 +116,7 @@ - name: run a validation script that fails using string lineinfile: - dest: "{{ output_dir }}/teststring.txt" + dest: "{{ remote_tmp_dir }}/teststring.txt" state: absent search_string: "This is line 1" validate: "/bin/false %s" @@ -130,7 +130,7 @@ - name: stat the test after the validation failed stat: - path: "{{ output_dir }}/teststring.txt" + path: "{{ remote_tmp_dir }}/teststring.txt" register: result - name: assert test checksum matches the previous after the validation failed diff --git a/test/integration/targets/lineinfile/tasks/test_string02.yml b/test/integration/targets/lineinfile/tasks/test_string02.yml index 886b290d..1fa48b85 100644 --- a/test/integration/targets/lineinfile/tasks/test_string02.yml +++ b/test/integration/targets/lineinfile/tasks/test_string02.yml @@ -5,7 +5,7 @@ - name: Deploy the teststring.conf file copy: src: teststring.conf - dest: "{{ output_dir }}/teststring.conf" + dest: "{{ remote_tmp_dir }}/teststring.conf" register: result - name: Assert that the teststring.conf file was deployed @@ -18,7 +18,7 @@ # Test instertafter - name: Insert lines after with string lineinfile: - path: "{{ output_dir }}/teststring.conf" + path: "{{ remote_tmp_dir }}/teststring.conf" search_string: "{{ item.regexp }}" line: "{{ item.line }}" insertafter: "{{ item.after }}" @@ -27,7 +27,7 @@ - name: Do the same thing again and check for changes lineinfile: - path: "{{ output_dir }}/teststring.conf" + path: "{{ remote_tmp_dir }}/teststring.conf" search_string: "{{ item.regexp }}" line: "{{ item.line }}" insertafter: "{{ item.after }}" @@ -45,7 +45,7 @@ - name: Stat the file stat: - path: "{{ output_dir }}/teststring.conf" + path: "{{ remote_tmp_dir }}/teststring.conf" register: result - name: Assert that the file contents match what is expected @@ -55,7 +55,7 @@ - name: Do the same thing a third time without string and check for changes lineinfile: - path: "{{ output_dir }}/teststring.conf" + path: "{{ remote_tmp_dir }}/teststring.conf" line: "{{ item.line }}" insertafter: "{{ item.after }}" with_items: "{{ test_befaf_regexp }}" @@ -63,7 +63,7 @@ - name: Stat the file stat: - path: "{{ output_dir }}/teststring.conf" + path: "{{ remote_tmp_dir }}/teststring.conf" register: result - name: Assert that the file was changed when no string was provided @@ -74,7 +74,7 @@ - name: Stat the file stat: - path: "{{ output_dir }}/teststring.conf" + path: "{{ remote_tmp_dir }}/teststring.conf" register: result - name: Assert that the file contents match what is expected @@ -86,7 +86,7 @@ - name: Deploy the test.conf file copy: src: teststring.conf - dest: "{{ output_dir }}/teststring.conf" + dest: "{{ remote_tmp_dir }}/teststring.conf" register: result - name: Assert that the teststring.conf file was deployed @@ -98,7 +98,7 @@ - name: Insert lines before with string lineinfile: - path: "{{ output_dir }}/teststring.conf" + path: "{{ remote_tmp_dir }}/teststring.conf" search_string: "{{ item.regexp }}" line: "{{ item.line }}" insertbefore: "{{ item.before }}" @@ -107,7 +107,7 @@ - name: Do the same thing again and check for changes lineinfile: - path: "{{ output_dir }}/teststring.conf" + path: "{{ remote_tmp_dir }}/teststring.conf" search_string: "{{ item.regexp }}" line: "{{ item.line }}" insertbefore: "{{ item.before }}" @@ -125,7 +125,7 @@ - name: Stat the file stat: - path: "{{ output_dir }}/teststring.conf" + path: "{{ remote_tmp_dir }}/teststring.conf" register: result - name: Assert that the file contents match what is expected @@ -135,7 +135,7 @@ - name: Do the same thing a third time without string and check for changes lineinfile: - path: "{{ output_dir }}/teststring.conf" + path: "{{ remote_tmp_dir }}/teststring.conf" line: "{{ item.line }}" insertbefore: "{{ item.before }}" with_items: "{{ test_befaf_regexp }}" @@ -143,7 +143,7 @@ - name: Stat the file stat: - path: "{{ output_dir }}/teststring.conf" + path: "{{ remote_tmp_dir }}/teststring.conf" register: result - name: Assert that the file was changed when no string was provided @@ -154,7 +154,7 @@ - name: Stat the file stat: - path: "{{ output_dir }}/teststring.conf" + path: "{{ remote_tmp_dir }}/teststring.conf" register: result - name: Assert that the file contents match what is expected diff --git a/test/integration/targets/lookup_config/aliases b/test/integration/targets/lookup_config/aliases index bc987654..765b70da 100644 --- a/test/integration/targets/lookup_config/aliases +++ b/test/integration/targets/lookup_config/aliases @@ -1,3 +1 @@ shippable/posix/group2 -skip/aix -skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller diff --git a/test/integration/targets/lookup_config/tasks/main.yml b/test/integration/targets/lookup_config/tasks/main.yml index cda9aedc..356d2f80 100644 --- a/test/integration/targets/lookup_config/tasks/main.yml +++ b/test/integration/targets/lookup_config/tasks/main.yml @@ -39,6 +39,19 @@ ignore_errors: yes register: lookup_config_7 +- name: remote user and port for ssh connection + set_fact: + ssh_user_and_port: '{{q("config", "remote_user", "port", plugin_type="connection", plugin_name="ssh")}}' + vars: + ansible_ssh_user: lola + ansible_ssh_port: 2022 + +- name: remote_tmp for sh shell plugin + set_fact: + yolo_remote: '{{q("config", "remote_tmp", plugin_type="shell", plugin_name="sh")}}' + vars: + ansible_remote_tmp: yolo + - name: Verify lookup_config assert: that: @@ -52,8 +65,10 @@ - lookup_config_4 is success - 'lookup4|length == 0' - lookup_config_5 is failed - - '"must be a string and one of" in lookup_config_5.msg' + - '"valid values are" in lookup_config_5.msg' - lookup_config_6 is failed - '"Invalid setting identifier" in lookup_config_6.msg' - lookup_config_7 is failed - '"Invalid setting" in lookup_config_7.msg' + - ssh_user_and_port == ['lola', 2022] + - yolo_remote == ["yolo"] diff --git a/test/integration/targets/lookup_csvfile/aliases b/test/integration/targets/lookup_csvfile/aliases index 45489be8..765b70da 100644 --- a/test/integration/targets/lookup_csvfile/aliases +++ b/test/integration/targets/lookup_csvfile/aliases @@ -1,2 +1 @@ shippable/posix/group2 -skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller diff --git a/test/integration/targets/lookup_csvfile/tasks/main.yml b/test/integration/targets/lookup_csvfile/tasks/main.yml index 14b79bd6..758da71e 100644 --- a/test/integration/targets/lookup_csvfile/tasks/main.yml +++ b/test/integration/targets/lookup_csvfile/tasks/main.yml @@ -1,15 +1,23 @@ -- set_fact: - this_will_error: "{{ lookup('csvfile', 'file=people.csv delimiter=, col=1') }}" +- name: using deprecated syntax but missing keyword + set_fact: + this_will_error: "{{ lookup('csvfile', 'file=people.csv, delimiter=, col=1') }}" ignore_errors: yes register: no_keyword -- set_fact: +- name: extra arg in k=v syntax (deprecated) + set_fact: this_will_error: "{{ lookup('csvfile', 'foo file=people.csv delimiter=, col=1 thisarg=doesnotexist') }}" ignore_errors: yes register: invalid_arg +- name: extra arg in config syntax + set_fact: + this_will_error: "{{ lookup('csvfile', 'foo', file='people.csv', delimiter=',' col=1, thisarg='doesnotexist') }}" + ignore_errors: yes + register: invalid_arg2 + - set_fact: - this_will_error: "{{ lookup('csvfile', 'foo file=doesnotexist delimiter=, col=1') }}" + this_will_error: "{{ lookup('csvfile', 'foo', file='doesnotexist', delimiter=',', col=1) }}" ignore_errors: yes register: missing_file @@ -19,24 +27,30 @@ - no_keyword is failed - > "Search key is required but was not found" in no_keyword.msg + - invalid_arg is failed + - invalid_arg2 is failed - > - "not in paramvals" in invalid_arg.msg + "is not a valid option" in invalid_arg.msg - missing_file is failed - > - "need string or buffer" in missing_file.msg or "expected str, bytes or os.PathLike object" in missing_file.msg + "need string or buffer" in missing_file.msg or + "expected str, bytes or os.PathLike object" in missing_file.msg or + "No such file or directory" in missing_file.msg - name: Check basic comma-separated file assert: that: - - lookup('csvfile', 'Smith file=people.csv delimiter=, col=1') == "Jane" + - lookup('csvfile', 'Smith', file='people.csv', delimiter=',', col=1) == "Jane" - lookup('csvfile', 'German von Lastname file=people.csv delimiter=, col=1') == "Demo" - name: Check tab-separated file assert: that: - lookup('csvfile', 'electronics file=tabs.csv delimiter=TAB col=1') == "tvs" - - lookup('csvfile', 'fruit file=tabs.csv delimiter=TAB col=1') == "bananas" + - "lookup('csvfile', 'fruit', file='tabs.csv', delimiter='TAB', col=1) == 'bananas'" - lookup('csvfile', 'fruit file=tabs.csv delimiter="\t" col=1') == "bananas" + - lookup('csvfile', 'electronics', 'fruit', file='tabs.csv', delimiter='\t', col=1) == "tvs,bananas" + - lookup('csvfile', 'electronics', 'fruit', file='tabs.csv', delimiter='\t', col=1, wantlist=True) == ["tvs", "bananas"] - name: Check \x1a-separated file assert: diff --git a/test/integration/targets/lookup_dict/aliases b/test/integration/targets/lookup_dict/aliases index 07b87020..a6dafcf8 100644 --- a/test/integration/targets/lookup_dict/aliases +++ b/test/integration/targets/lookup_dict/aliases @@ -1,3 +1 @@ shippable/posix/group1 -skip/aix -skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller diff --git a/test/integration/targets/lookup_env/aliases b/test/integration/targets/lookup_env/aliases index 07b87020..a6dafcf8 100644 --- a/test/integration/targets/lookup_env/aliases +++ b/test/integration/targets/lookup_env/aliases @@ -1,3 +1 @@ shippable/posix/group1 -skip/aix -skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller diff --git a/test/integration/targets/lookup_file/aliases b/test/integration/targets/lookup_file/aliases index 07b87020..a6dafcf8 100644 --- a/test/integration/targets/lookup_file/aliases +++ b/test/integration/targets/lookup_file/aliases @@ -1,3 +1 @@ shippable/posix/group1 -skip/aix -skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller diff --git a/test/integration/targets/lookup_first_found/aliases b/test/integration/targets/lookup_first_found/aliases index bc987654..765b70da 100644 --- a/test/integration/targets/lookup_first_found/aliases +++ b/test/integration/targets/lookup_first_found/aliases @@ -1,3 +1 @@ shippable/posix/group2 -skip/aix -skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller diff --git a/test/integration/targets/lookup_first_found/tasks/main.yml b/test/integration/targets/lookup_first_found/tasks/main.yml index 87f2a404..e85f4f27 100644 --- a/test/integration/targets/lookup_first_found/tasks/main.yml +++ b/test/integration/targets/lookup_first_found/tasks/main.yml @@ -1,10 +1,9 @@ - name: test with_first_found - #shell: echo {{ item }} set_fact: "first_found={{ item }}" with_first_found: - - "{{ role_path + '/files/does_not_exist' }}" - - "{{ role_path + '/files/foo1' }}" - - "{{ role_path + '/files/bar1' }}" + - "does_not_exist" + - "foo1" + - "{{ role_path + '/files/bar1' }}" # will only hit this if dwim search is broken - name: set expected set_fact: first_expected="{{ role_path + '/files/foo1' }}" @@ -24,6 +23,7 @@ vars: params: files: "not_a_file.yaml" + skip: True - name: verify q(first_found) result assert: @@ -71,3 +71,16 @@ assert: that: - "this_not_set is not defined" + +- name: test legacy formats + set_fact: hatethisformat={{item}} + vars: + params: + files: not/a/file.yaml;hosts + paths: not/a/path:/etc + loop: "{{ q('first_found', params) }}" + +- name: verify /etc/hosts was found + assert: + that: + - "hatethisformat == '/etc/hosts'" diff --git a/test/integration/targets/lookup_indexed_items/aliases b/test/integration/targets/lookup_indexed_items/aliases index bc987654..765b70da 100644 --- a/test/integration/targets/lookup_indexed_items/aliases +++ b/test/integration/targets/lookup_indexed_items/aliases @@ -1,3 +1 @@ shippable/posix/group2 -skip/aix -skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller diff --git a/test/integration/targets/lookup_indexed_items/tasks/main.yml b/test/integration/targets/lookup_indexed_items/tasks/main.yml index 84f5fbce..434fe0ff 100644 --- a/test/integration/targets/lookup_indexed_items/tasks/main.yml +++ b/test/integration/targets/lookup_indexed_items/tasks/main.yml @@ -14,3 +14,19 @@ - "x2 == 'set'" - "x3 == 'set'" - "x4 == 'set'" + +- block: + - name: "EXPECTED FAILURE - test not a list" + debug: + msg: "{{ item.0 }} is {{ item.1 }}" + with_indexed_items: + "a": 1 + + - fail: + msg: "should not get here" + + rescue: + - assert: + that: + - ansible_failed_task.name == "EXPECTED FAILURE - test not a list" + - ansible_failed_result.msg == "with_indexed_items expects a list" diff --git a/test/integration/targets/lookup_ini/aliases b/test/integration/targets/lookup_ini/aliases index f9f29ef3..b5983214 100644 --- a/test/integration/targets/lookup_ini/aliases +++ b/test/integration/targets/lookup_ini/aliases @@ -1,2 +1 @@ shippable/posix/group3 -skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller diff --git a/test/integration/targets/lookup_ini/lookup_case_check.properties b/test/integration/targets/lookup_ini/lookup_case_check.properties new file mode 100644 index 00000000..ed3faaf8 --- /dev/null +++ b/test/integration/targets/lookup_ini/lookup_case_check.properties @@ -0,0 +1,2 @@ +name = captain +NAME = fantastic diff --git a/test/integration/targets/lookup_ini/mysql.ini b/test/integration/targets/lookup_ini/mysql.ini new file mode 100644 index 00000000..fa62d87e --- /dev/null +++ b/test/integration/targets/lookup_ini/mysql.ini @@ -0,0 +1,8 @@ +[mysqld] +user = mysql +pid-file = /var/run/mysqld/mysqld.pid +skip-external-locking +old_passwords = 1 +skip-bdb +# we don't need ACID today +skip-innodb diff --git a/test/integration/targets/lookup_ini/runme.sh b/test/integration/targets/lookup_ini/runme.sh index 76f836a9..6f44332b 100755 --- a/test/integration/targets/lookup_ini/runme.sh +++ b/test/integration/targets/lookup_ini/runme.sh @@ -2,5 +2,4 @@ set -eux -ansible-playbook test_lookup_properties.yml -i inventory -v "$@" -ansible-playbook test_errors.yml -i inventory -v "$@" +ansible-playbook test_ini.yml -i inventory -v "$@" diff --git a/test/integration/targets/lookup_ini/test_allow_no_value.yml b/test/integration/targets/lookup_ini/test_allow_no_value.yml new file mode 100644 index 00000000..bfdc3765 --- /dev/null +++ b/test/integration/targets/lookup_ini/test_allow_no_value.yml @@ -0,0 +1,23 @@ +- name: Lookup test + hosts: testhost + tasks: + - name: "Read mysql.ini allow_none=False (default)" + set_fact: + test1: "{{ lookup('ini', 'user', file='mysql.ini', section='mysqld') }}" + register: result + ignore_errors: true + + - name: "Read mysql.ini allow_no_value=True" + set_fact: + test2: "{{ lookup('ini', 'user', file='mysql.ini', section='mysqld', allow_no_value=True) }}" + + - name: "Read mysql.ini allow_none=True" + set_fact: + test3: "{{ lookup('ini', 'skip-innodb', file='mysql.ini', section='mysqld', allow_none=True) }}" + + - assert: + that: + - result is failed + - test2 == 'mysql' + - test3 == [] + - test3|length == 0 diff --git a/test/integration/targets/lookup_ini/test_case_sensitive.yml b/test/integration/targets/lookup_ini/test_case_sensitive.yml new file mode 100644 index 00000000..f66674ca --- /dev/null +++ b/test/integration/targets/lookup_ini/test_case_sensitive.yml @@ -0,0 +1,31 @@ +- name: Test case sensitive option + hosts: all + + tasks: + - name: Lookup a file with keys that differ only in case with case sensitivity enabled + debug: + msg: "{{ lookup('ini', 'name', file='duplicate_case_check.ini', section='reggae', case_sensitive=True) }}" + register: duplicate_case_sensitive_name + + - name: Lookup a file with keys that differ only in case with case sensitivity enabled + debug: + msg: "{{ lookup('ini', 'NAME', file='duplicate_case_check.ini', section='reggae', case_sensitive=True) }}" + register: duplicate_case_sensitive_NAME + + - name: Lookup a properties file with keys that differ only in case with case sensitivity enabled + debug: + msg: "{{ lookup('ini', 'name', file='lookup_case_check.properties', type='properties', case_sensitive=True) }}" + register: duplicate_case_sensitive_properties_name + + - name: Lookup a properties file with keys that differ only in case with case sensitivity enabled + debug: + msg: "{{ lookup('ini', 'NAME', file='lookup_case_check.properties', type='properties', case_sensitive=True) }}" + register: duplicate_case_sensitive_properties_NAME + + - name: Ensure the correct case-sensitive values were retieved + assert: + that: + - duplicate_case_sensitive_name.msg == 'bob' + - duplicate_case_sensitive_NAME.msg == 'marley' + - duplicate_case_sensitive_properties_name.msg == 'captain' + - duplicate_case_sensitive_properties_NAME.msg == 'fantastic' diff --git a/test/integration/targets/lookup_ini/test_errors.yml b/test/integration/targets/lookup_ini/test_errors.yml index b7b04d90..c1832a35 100644 --- a/test/integration/targets/lookup_ini/test_errors.yml +++ b/test/integration/targets/lookup_ini/test_errors.yml @@ -7,17 +7,17 @@ block: - name: Lookup a file with duplicate keys debug: - msg: "{{ lookup('ini', 'reggae file=duplicate.ini section=reggae') }}" + msg: "{{ lookup('ini', 'name', file='duplicate.ini', section='reggae') }}" ignore_errors: yes register: duplicate - name: Lookup a file with keys that differ only in case debug: - msg: "{{ lookup('ini', 'reggae file=duplicate_case_check.ini section=reggae') }}" + msg: "{{ lookup('ini', 'name', file='duplicate_case_check.ini', section='reggae') }}" ignore_errors: yes register: duplicate_case_sensitive - - name: Ensure duplicate key errers were handled properly + - name: Ensure duplicate key errors were handled properly assert: that: - duplicate is failed @@ -27,7 +27,7 @@ - name: Lookup a file with a missing section debug: - msg: "{{ lookup('ini', 'reggae file=lookup.ini section=missing') }}" + msg: "{{ lookup('ini', 'name', file='lookup.ini', section='missing') }}" ignore_errors: yes register: missing_section @@ -36,3 +36,27 @@ that: - missing_section is failed - "'No section' in missing_section.msg" + + - name: Mix options type and push key out of order + debug: + msg: "{{ lookup('ini', 'file=lookup.ini', 'value1', section='value_section') }}" + register: bad_mojo + ignore_errors: yes + + - name: Verify bad behavior reported an error + assert: + that: + - bad_mojo is failed + - '"No key to lookup was provided as first term with in string inline option" in bad_mojo.msg' + + - name: Test invalid option + debug: + msg: "{{ lookup('ini', 'invalid=option') }}" + ignore_errors: yes + register: invalid_option + + - name: Ensure invalid option failed + assert: + that: + - invalid_option is failed + - "'is not a valid option' in invalid_option.msg" diff --git a/test/integration/targets/lookup_ini/test_ini.yml b/test/integration/targets/lookup_ini/test_ini.yml new file mode 100644 index 00000000..11a5e57a --- /dev/null +++ b/test/integration/targets/lookup_ini/test_ini.yml @@ -0,0 +1,4 @@ +- import_playbook: test_lookup_properties.yml +- import_playbook: test_errors.yml +- import_playbook: test_case_sensitive.yml +- import_playbook: test_allow_no_value.yml diff --git a/test/integration/targets/lookup_ini/test_lookup_properties.yml b/test/integration/targets/lookup_ini/test_lookup_properties.yml index 3a414bbc..a6fc0f7d 100644 --- a/test/integration/targets/lookup_ini/test_lookup_properties.yml +++ b/test/integration/targets/lookup_ini/test_lookup_properties.yml @@ -5,8 +5,8 @@ - name: "read properties value" set_fact: test1: "{{lookup('ini', 'value1 type=properties file=lookup.properties')}}" - test2: "{{lookup('ini', 'value2 type=properties file=lookup.properties')}}" - test_dot: "{{lookup('ini', 'value.dot type=properties file=lookup.properties')}}" + test2: "{{lookup('ini', 'value2', type='properties', file='lookup.properties')}}" + test_dot: "{{lookup('ini', 'value.dot', type='properties', file='lookup.properties')}}" field_with_space: "{{lookup('ini', 'field.with.space type=properties file=lookup.properties')}}" - assert: @@ -15,10 +15,10 @@ - name: "read ini value" set_fact: - value1_global: "{{lookup('ini', 'value1 section=global file=lookup.ini')}}" - value2_global: "{{lookup('ini', 'value2 section=global file=lookup.ini')}}" - value1_section1: "{{lookup('ini', 'value1 section=section1 file=lookup.ini')}}" - field_with_unicode: "{{lookup('ini', 'unicode section=global file=lookup.ini')}}" + value1_global: "{{lookup('ini', 'value1', section='global', file='lookup.ini')}}" + value2_global: "{{lookup('ini', 'value2', section='global', file='lookup.ini')}}" + value1_section1: "{{lookup('ini', 'value1', section='section1', file='lookup.ini')}}" + field_with_unicode: "{{lookup('ini', 'unicode', section='global', file='lookup.ini')}}" - debug: var={{item}} with_items: [ 'value1_global', 'value2_global', 'value1_section1', 'field_with_unicode' ] diff --git a/test/integration/targets/lookup_inventory_hostnames/aliases b/test/integration/targets/lookup_inventory_hostnames/aliases index 45489be8..765b70da 100644 --- a/test/integration/targets/lookup_inventory_hostnames/aliases +++ b/test/integration/targets/lookup_inventory_hostnames/aliases @@ -1,2 +1 @@ shippable/posix/group2 -skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller diff --git a/test/integration/targets/lookup_items/aliases b/test/integration/targets/lookup_items/aliases index bc987654..765b70da 100644 --- a/test/integration/targets/lookup_items/aliases +++ b/test/integration/targets/lookup_items/aliases @@ -1,3 +1 @@ shippable/posix/group2 -skip/aix -skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller diff --git a/test/integration/targets/lookup_lines/aliases b/test/integration/targets/lookup_lines/aliases index bc987654..765b70da 100644 --- a/test/integration/targets/lookup_lines/aliases +++ b/test/integration/targets/lookup_lines/aliases @@ -1,3 +1 @@ shippable/posix/group2 -skip/aix -skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller diff --git a/test/integration/targets/lookup_list/aliases b/test/integration/targets/lookup_list/aliases index bc987654..765b70da 100644 --- a/test/integration/targets/lookup_list/aliases +++ b/test/integration/targets/lookup_list/aliases @@ -1,3 +1 @@ shippable/posix/group2 -skip/aix -skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller diff --git a/test/integration/targets/lookup_nested/aliases b/test/integration/targets/lookup_nested/aliases index bc987654..765b70da 100644 --- a/test/integration/targets/lookup_nested/aliases +++ b/test/integration/targets/lookup_nested/aliases @@ -1,3 +1 @@ shippable/posix/group2 -skip/aix -skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller diff --git a/test/integration/targets/lookup_password/aliases b/test/integration/targets/lookup_password/aliases index 07b87020..a6dafcf8 100644 --- a/test/integration/targets/lookup_password/aliases +++ b/test/integration/targets/lookup_password/aliases @@ -1,3 +1 @@ shippable/posix/group1 -skip/aix -skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller diff --git a/test/integration/targets/lookup_pipe/aliases b/test/integration/targets/lookup_pipe/aliases index 07b87020..a6dafcf8 100644 --- a/test/integration/targets/lookup_pipe/aliases +++ b/test/integration/targets/lookup_pipe/aliases @@ -1,3 +1 @@ shippable/posix/group1 -skip/aix -skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller diff --git a/test/integration/targets/lookup_random_choice/aliases b/test/integration/targets/lookup_random_choice/aliases index bc987654..765b70da 100644 --- a/test/integration/targets/lookup_random_choice/aliases +++ b/test/integration/targets/lookup_random_choice/aliases @@ -1,3 +1 @@ shippable/posix/group2 -skip/aix -skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller diff --git a/test/integration/targets/lookup_sequence/aliases b/test/integration/targets/lookup_sequence/aliases index bc987654..765b70da 100644 --- a/test/integration/targets/lookup_sequence/aliases +++ b/test/integration/targets/lookup_sequence/aliases @@ -1,3 +1 @@ shippable/posix/group2 -skip/aix -skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller diff --git a/test/integration/targets/lookup_sequence/tasks/main.yml b/test/integration/targets/lookup_sequence/tasks/main.yml index 72181a42..bd0a4d80 100644 --- a/test/integration/targets/lookup_sequence/tasks/main.yml +++ b/test/integration/targets/lookup_sequence/tasks/main.yml @@ -61,3 +61,138 @@ - "ws_z_6 == 'stride_6'" - "ws_z_host07 == 'host07'" - "ws_z_host08 == 'host08'" + +- block: + - name: EXPECTED FAILURE - test invalid arg + set_fact: "{{ 'x' + item }}={{ item }}" + with_sequence: start=0 junk=3 + + - fail: + msg: "should not get here" + rescue: + - assert: + that: + - ansible_failed_task.name == "EXPECTED FAILURE - test invalid arg" + - ansible_failed_result.msg in [expected1, expected2] + vars: + expected1: "unrecognized arguments to with_sequence: ['junk']" + expected2: "unrecognized arguments to with_sequence: [u'junk']" + +- block: + - name: EXPECTED FAILURE - test bad kv value + set_fact: "{{ 'x' + item }}={{ item }}" + with_sequence: start=A end=3 + + - fail: + msg: "should not get here" + rescue: + - assert: + that: + - ansible_failed_task.name == "EXPECTED FAILURE - test bad kv value" + - ansible_failed_result.msg == "can't parse start=A as integer" + +- block: + - name: EXPECTED FAILURE - test bad simple form start value + set_fact: "{{ 'x' + item }}={{ item }}" + with_sequence: A-4/2 + + - fail: + msg: "should not get here" + rescue: + - assert: + that: + - ansible_failed_task.name == "EXPECTED FAILURE - test bad simple form start value" + - ansible_failed_result.msg == "can't parse start=A as integer" + +- block: + - name: EXPECTED FAILURE - test bad simple form end value + set_fact: "{{ 'x' + item }}={{ item }}" + with_sequence: 1-B/2 + + - fail: + msg: "should not get here" + rescue: + - assert: + that: + - ansible_failed_task.name == "EXPECTED FAILURE - test bad simple form end value" + - ansible_failed_result.msg == "can't parse end=B as integer" + +- block: + - name: EXPECTED FAILURE - test bad simple form stride value + set_fact: "{{ 'x' + item }}={{ item }}" + with_sequence: 1-4/C + + - fail: + msg: "should not get here" + rescue: + - assert: + that: + - ansible_failed_task.name == "EXPECTED FAILURE - test bad simple form stride value" + - ansible_failed_result.msg == "can't parse stride=C as integer" + +- block: + - name: EXPECTED FAILURE - test no count or end + set_fact: "{{ 'x' + item }}={{ item }}" + with_sequence: start=1 + + - fail: + msg: "should not get here" + rescue: + - assert: + that: + - ansible_failed_task.name == "EXPECTED FAILURE - test no count or end" + - ansible_failed_result.msg == "must specify count or end in with_sequence" + +- block: + - name: EXPECTED FAILURE - test both count and end + set_fact: "{{ 'x' + item }}={{ item }}" + with_sequence: start=1 end=4 count=2 + + - fail: + msg: "should not get here" + rescue: + - assert: + that: + - ansible_failed_task.name == "EXPECTED FAILURE - test both count and end" + - ansible_failed_result.msg == "can't specify both count and end in with_sequence" + +- block: + - name: EXPECTED FAILURE - test count backwards message + set_fact: "{{ 'x' + item }}={{ item }}" + with_sequence: start=4 end=1 stride=2 + + - fail: + msg: "should not get here" + rescue: + - assert: + that: + - ansible_failed_task.name == "EXPECTED FAILURE - test count backwards message" + - ansible_failed_result.msg == "to count backwards make stride negative" + +- block: + - name: EXPECTED FAILURE - test count forward message + set_fact: "{{ 'x' + item }}={{ item }}" + with_sequence: start=1 end=4 stride=-2 + + - fail: + msg: "should not get here" + rescue: + - assert: + that: + - ansible_failed_task.name == "EXPECTED FAILURE - test count forward message" + - ansible_failed_result.msg == "to count forward don't make stride negative" + +- block: + - name: EXPECTED FAILURE - test bad format string message + set_fact: "{{ 'x' + item }}={{ item }}" + with_sequence: start=1 end=4 format=d + + - fail: + msg: "should not get here" + rescue: + - assert: + that: + - ansible_failed_task.name == "EXPECTED FAILURE - test bad format string message" + - ansible_failed_result.msg == expected + vars: + expected: "bad formatting string: d"
\ No newline at end of file diff --git a/test/integration/targets/lookup_subelements/aliases b/test/integration/targets/lookup_subelements/aliases index bc987654..765b70da 100644 --- a/test/integration/targets/lookup_subelements/aliases +++ b/test/integration/targets/lookup_subelements/aliases @@ -1,3 +1 @@ shippable/posix/group2 -skip/aix -skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller diff --git a/test/integration/targets/lookup_template/aliases b/test/integration/targets/lookup_template/aliases index 07b87020..a6dafcf8 100644 --- a/test/integration/targets/lookup_template/aliases +++ b/test/integration/targets/lookup_template/aliases @@ -1,3 +1 @@ shippable/posix/group1 -skip/aix -skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller diff --git a/test/integration/targets/lookup_template/tasks/main.yml b/test/integration/targets/lookup_template/tasks/main.yml index df115766..36a8ee31 100644 --- a/test/integration/targets/lookup_template/tasks/main.yml +++ b/test/integration/targets/lookup_template/tasks/main.yml @@ -17,3 +17,11 @@ - assert: that: - "hello_world_string|trim == 'Hello world!'" + +- name: Test that we have a proper jinja search path in template lookup with different comment start and end string + set_fact: + hello_world_comment: "{{ lookup('template', 'hello_comment.txt', comment_start_string='[#', comment_end_string='#]') }}" + +- assert: + that: + - "hello_world_comment|trim == 'Hello world!'" diff --git a/test/integration/targets/lookup_template/templates/hello_comment.txt b/test/integration/targets/lookup_template/templates/hello_comment.txt new file mode 100644 index 00000000..92af4b37 --- /dev/null +++ b/test/integration/targets/lookup_template/templates/hello_comment.txt @@ -0,0 +1,2 @@ +[# Comment #] +Hello world! diff --git a/test/integration/targets/lookup_together/aliases b/test/integration/targets/lookup_together/aliases index bc987654..765b70da 100644 --- a/test/integration/targets/lookup_together/aliases +++ b/test/integration/targets/lookup_together/aliases @@ -1,3 +1 @@ shippable/posix/group2 -skip/aix -skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller diff --git a/test/integration/targets/lookup_together/tasks/main.yml b/test/integration/targets/lookup_together/tasks/main.yml index ee59a2ae..71365a15 100644 --- a/test/integration/targets/lookup_together/tasks/main.yml +++ b/test/integration/targets/lookup_together/tasks/main.yml @@ -12,3 +12,18 @@ - "b == '2'" - "c == '3'" - "d == '4'" + +- block: + - name: "EXPECTED FAILURE - test empty list" + debug: + msg: "{{ item.0 }} and {{ item.1 }}" + with_together: [] + + - fail: + msg: "should not get here" + + rescue: + - assert: + that: + - ansible_failed_task.name == "EXPECTED FAILURE - test empty list" + - ansible_failed_result.msg == "with_together requires at least one element in each list"
\ No newline at end of file diff --git a/test/integration/targets/lookup_unvault/aliases b/test/integration/targets/lookup_unvault/aliases index 4a2ce27c..6bd893d4 100644 --- a/test/integration/targets/lookup_unvault/aliases +++ b/test/integration/targets/lookup_unvault/aliases @@ -1,3 +1,2 @@ shippable/posix/group2 needs/root -skip/aix diff --git a/test/integration/targets/lookup_url/aliases b/test/integration/targets/lookup_url/aliases index 28990148..90ef161f 100644 --- a/test/integration/targets/lookup_url/aliases +++ b/test/integration/targets/lookup_url/aliases @@ -1,5 +1,3 @@ destructive shippable/posix/group1 needs/httptester -skip/aix -skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller diff --git a/test/integration/targets/lookup_varnames/aliases b/test/integration/targets/lookup_varnames/aliases index 45489be8..765b70da 100644 --- a/test/integration/targets/lookup_varnames/aliases +++ b/test/integration/targets/lookup_varnames/aliases @@ -1,2 +1 @@ shippable/posix/group2 -skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller diff --git a/test/integration/targets/lookup_vars/aliases b/test/integration/targets/lookup_vars/aliases index 07b87020..a6dafcf8 100644 --- a/test/integration/targets/lookup_vars/aliases +++ b/test/integration/targets/lookup_vars/aliases @@ -1,3 +1 @@ shippable/posix/group1 -skip/aix -skip/python2.6 # lookups are controller only, and we no longer support Python 2.6 on the controller diff --git a/test/integration/targets/lookup_vars/tasks/main.yml b/test/integration/targets/lookup_vars/tasks/main.yml index f24d8657..57b05b8f 100644 --- a/test/integration/targets/lookup_vars/tasks/main.yml +++ b/test/integration/targets/lookup_vars/tasks/main.yml @@ -14,3 +14,43 @@ that: - 'var_host_info[0] == ansible_host' - 'var_host_info[1] == ansible_connection' + +- block: + - name: EXPECTED FAILURE - test invalid var + debug: + var: '{{ lookup("vars", "doesnotexist") }}' + + - fail: + msg: "should not get here" + + rescue: + - assert: + that: + - ansible_failed_task.name == "EXPECTED FAILURE - test invalid var" + - expected in ansible_failed_result.msg + vars: + expected: "No variable found with this name: doesnotexist" + +- block: + - name: EXPECTED FAILURE - test invalid var type + debug: + var: '{{ lookup("vars", 42) }}' + + - fail: + msg: "should not get here" + + rescue: + - assert: + that: + - ansible_failed_task.name == "EXPECTED FAILURE - test invalid var type" + - expected in ansible_failed_result.msg + vars: + expected: "Invalid setting identifier, \"42\" is not a string" + +- name: test default + set_fact: + expected_default_var: '{{ lookup("vars", "doesnotexist", default="some text") }}' + +- assert: + that: + - expected_default_var == "some text" diff --git a/test/integration/targets/loop_control/aliases b/test/integration/targets/loop_control/aliases index 765b70da..90ea9e12 100644 --- a/test/integration/targets/loop_control/aliases +++ b/test/integration/targets/loop_control/aliases @@ -1 +1,2 @@ shippable/posix/group2 +context/controller diff --git a/test/integration/targets/loops/aliases b/test/integration/targets/loops/aliases index ed821c27..90ea9e12 100644 --- a/test/integration/targets/loops/aliases +++ b/test/integration/targets/loops/aliases @@ -1,2 +1,2 @@ shippable/posix/group2 -skip/aix +context/controller diff --git a/test/integration/targets/meta_tasks/aliases b/test/integration/targets/meta_tasks/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/meta_tasks/aliases +++ b/test/integration/targets/meta_tasks/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/meta_tasks/runme.sh b/test/integration/targets/meta_tasks/runme.sh index 3ee419cb..f5916ec7 100755 --- a/test/integration/targets/meta_tasks/runme.sh +++ b/test/integration/targets/meta_tasks/runme.sh @@ -49,4 +49,19 @@ for test_strategy in linear free; do grep -q "META: ending play" <<< "$out" grep -qv 'Failed to end using end_play' <<< "$out" + + out="$(ansible-playbook test_end_play_serial_one.yml -i inventory.yml -e test_strategy=$test_strategy -vv "$@")" + + [ "$(grep -c "Testing end_play on host" <<< "$out" )" -eq 1 ] + grep -q "META: ending play" <<< "$out" + grep -qv 'Failed to end using end_play' <<< "$out" +done + +# test end_batch meta task +for test_strategy in linear free; do + out="$(ansible-playbook test_end_batch.yml -i inventory.yml -e test_strategy=$test_strategy -vv "$@")" + + [ "$(grep -c "Using end_batch" <<< "$out" )" -eq 2 ] + [ "$(grep -c "META: ending batch" <<< "$out" )" -eq 2 ] + grep -qv 'Failed to end_batch' <<< "$out" done diff --git a/test/integration/targets/meta_tasks/test_end_batch.yml b/test/integration/targets/meta_tasks/test_end_batch.yml new file mode 100644 index 00000000..4af020af --- /dev/null +++ b/test/integration/targets/meta_tasks/test_end_batch.yml @@ -0,0 +1,13 @@ +- name: Testing end_batch with strategy {{ test_strategy | default('linear') }} + hosts: testhost:testhost2 + gather_facts: no + serial: 1 + strategy: "{{ test_strategy | default('linear') }}" + tasks: + - debug: + msg: "Using end_batch, current host: {{ inventory_hostname }}, current batch: {{ ansible_play_batch }}" + + - meta: end_batch + + - fail: + msg: "Failed to end_batch, current host: {{ inventory_hostname }}, current batch: {{ ansible_play_batch }}" diff --git a/test/integration/targets/meta_tasks/test_end_play_serial_one.yml b/test/integration/targets/meta_tasks/test_end_play_serial_one.yml new file mode 100644 index 00000000..f838d4a6 --- /dev/null +++ b/test/integration/targets/meta_tasks/test_end_play_serial_one.yml @@ -0,0 +1,13 @@ +- name: Testing end_play with serial 1 and strategy {{ test_strategy | default('linear') }} + hosts: testhost:testhost2 + gather_facts: no + serial: 1 + strategy: "{{ test_strategy | default('linear') }}" + tasks: + - debug: + msg: "Testing end_play on host {{ inventory_hostname }}" + + - meta: end_play + + - fail: + msg: 'Failed to end using end_play' diff --git a/test/integration/targets/missing_required_lib/aliases b/test/integration/targets/missing_required_lib/aliases index 70a7b7a9..1d28bdb2 100644 --- a/test/integration/targets/missing_required_lib/aliases +++ b/test/integration/targets/missing_required_lib/aliases @@ -1 +1,2 @@ shippable/posix/group5 +context/controller diff --git a/test/integration/targets/module_defaults/action_plugins/debug.py b/test/integration/targets/module_defaults/action_plugins/debug.py new file mode 100644 index 00000000..2584fd3d --- /dev/null +++ b/test/integration/targets/module_defaults/action_plugins/debug.py @@ -0,0 +1,80 @@ +# Copyright 2012, Dag Wieers <dag@wieers.com> +# Copyright 2016, Toshio Kuratomi <tkuratomi@ansible.com> +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +from ansible.errors import AnsibleUndefinedVariable +from ansible.module_utils.six import string_types +from ansible.module_utils._text import to_text +from ansible.plugins.action import ActionBase + + +class ActionModule(ActionBase): + ''' Print statements during execution ''' + + TRANSFERS_FILES = False + _VALID_ARGS = frozenset(('msg', 'var', 'verbosity')) + + def run(self, tmp=None, task_vars=None): + if task_vars is None: + task_vars = dict() + + if 'msg' in self._task.args and 'var' in self._task.args: + return {"failed": True, "msg": "'msg' and 'var' are incompatible options"} + + result = super(ActionModule, self).run(tmp, task_vars) + del tmp # tmp no longer has any effect + + # get task verbosity + verbosity = int(self._task.args.get('verbosity', 0)) + + if verbosity <= self._display.verbosity: + if 'msg' in self._task.args: + result['msg'] = self._task.args['msg'] + + elif 'var' in self._task.args: + try: + results = self._templar.template(self._task.args['var'], convert_bare=True, fail_on_undefined=True) + if results == self._task.args['var']: + # if results is not str/unicode type, raise an exception + if not isinstance(results, string_types): + raise AnsibleUndefinedVariable + # If var name is same as result, try to template it + results = self._templar.template("{{" + results + "}}", convert_bare=True, fail_on_undefined=True) + except AnsibleUndefinedVariable as e: + results = u"VARIABLE IS NOT DEFINED!" + if self._display.verbosity > 0: + results += u": %s" % to_text(e) + + if isinstance(self._task.args['var'], (list, dict)): + # If var is a list or dict, use the type as key to display + result[to_text(type(self._task.args['var']))] = results + else: + result[self._task.args['var']] = results + else: + result['msg'] = 'Hello world!' + + # force flag to make debug output module always verbose + result['_ansible_verbose_always'] = True + else: + result['skipped_reason'] = "Verbosity threshold not met." + result['skipped'] = True + + result['failed'] = False + + return result diff --git a/test/integration/targets/module_defaults/aliases b/test/integration/targets/module_defaults/aliases index a6dafcf8..13e01f0c 100644 --- a/test/integration/targets/module_defaults/aliases +++ b/test/integration/targets/module_defaults/aliases @@ -1 +1,2 @@ shippable/posix/group1 +context/controller diff --git a/test/integration/targets/module_defaults/collections/ansible_collections/testns/testcoll/meta/runtime.yml b/test/integration/targets/module_defaults/collections/ansible_collections/testns/testcoll/meta/runtime.yml index 62695fbc..081ee8c2 100644 --- a/test/integration/targets/module_defaults/collections/ansible_collections/testns/testcoll/meta/runtime.yml +++ b/test/integration/targets/module_defaults/collections/ansible_collections/testns/testcoll/meta/runtime.yml @@ -1,5 +1,10 @@ action_groups: testgroup: + # Test metadata 'extend_group' feature does not get stuck in a recursive loop + - metadata: + extend_group: othergroup + - metadata + - ping - testns.testcoll.echo1 - testns.testcoll.echo2 # note we can define defaults for an action @@ -7,3 +12,28 @@ action_groups: # note we can define defaults in this group for actions/modules in another collection - testns.othercoll.other_echoaction - testns.othercoll.other_echo1 + othergroup: + - metadata: + extend_group: + - testgroup + empty_metadata: + - metadata: {} + bad_metadata_format: + - unexpected_key: + key: value + metadata: + extend_group: testgroup + multiple_metadata: + - metadata: + extend_group: testgroup + - metadata: + extend_group: othergroup + bad_metadata_options: + - metadata: + unexpected_key: testgroup + bad_metadata_type: + - metadata: [testgroup] + bad_metadata_option_type: + - metadata: + extend_group: + name: testgroup diff --git a/test/integration/targets/module_defaults/collections/ansible_collections/testns/testcoll/plugins/modules/metadata.py b/test/integration/targets/module_defaults/collections/ansible_collections/testns/testcoll/plugins/modules/metadata.py new file mode 100644 index 00000000..6a818fd8 --- /dev/null +++ b/test/integration/targets/module_defaults/collections/ansible_collections/testns/testcoll/plugins/modules/metadata.py @@ -0,0 +1,45 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: metadata +version_added: 2.12 +short_description: Test module with a specific name +description: Test module with a specific name +options: + data: + description: Required option to test module_defaults work + required: True + type: str +author: + - Ansible Core Team +''' + +EXAMPLES = ''' +''' + +RETURN = ''' +''' + +from ansible.module_utils.basic import AnsibleModule + + +def main(): + module = AnsibleModule( + argument_spec=dict( + data=dict(type='str', required=True), + ), + ) + + module.exit_json() + + +if __name__ == '__main__': + main() diff --git a/test/integration/targets/module_defaults/collections/ansible_collections/testns/testcoll/plugins/modules/ping.py b/test/integration/targets/module_defaults/collections/ansible_collections/testns/testcoll/plugins/modules/ping.py new file mode 100644 index 00000000..2cb1fb23 --- /dev/null +++ b/test/integration/targets/module_defaults/collections/ansible_collections/testns/testcoll/plugins/modules/ping.py @@ -0,0 +1,83 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2012, Michael DeHaan <michael.dehaan@gmail.com> +# (c) 2016, Toshio Kuratomi <tkuratomi@ansible.com> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: ping +version_added: historical +short_description: Try to connect to host, verify a usable python and return C(pong) on success +description: + - A trivial test module, this module always returns C(pong) on successful + contact. It does not make sense in playbooks, but it is useful from + C(/usr/bin/ansible) to verify the ability to login and that a usable Python is configured. + - This is NOT ICMP ping, this is just a trivial test module that requires Python on the remote-node. + - For Windows targets, use the M(ansible.windows.win_ping) module instead. + - For Network targets, use the M(ansible.netcommon.net_ping) module instead. +options: + data: + description: + - Data to return for the C(ping) return value. + - If this parameter is set to C(crash), the module will cause an exception. + type: str + default: pong +seealso: + - module: ansible.netcommon.net_ping + - module: ansible.windows.win_ping +author: + - Ansible Core Team + - Michael DeHaan +notes: + - Supports C(check_mode). +''' + +EXAMPLES = ''' +# Test we can logon to 'webservers' and execute python with json lib. +# ansible webservers -m ping + +- name: Example from an Ansible Playbook + ansible.builtin.ping: + +- name: Induce an exception to see what happens + ansible.builtin.ping: + data: crash +''' + +RETURN = ''' +ping: + description: Value provided with the data parameter. + returned: success + type: str + sample: pong +''' + +from ansible.module_utils.basic import AnsibleModule + + +def main(): + module = AnsibleModule( + argument_spec=dict( + data=dict(type='str', default='pong'), + ), + supports_check_mode=True + ) + + if module.params['data'] == 'crash': + raise Exception("boom") + + result = dict( + ping=module.params['data'], + ) + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/test/integration/targets/module_defaults/library/legacy_ping.py b/test/integration/targets/module_defaults/library/legacy_ping.py new file mode 100644 index 00000000..2cb1fb23 --- /dev/null +++ b/test/integration/targets/module_defaults/library/legacy_ping.py @@ -0,0 +1,83 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2012, Michael DeHaan <michael.dehaan@gmail.com> +# (c) 2016, Toshio Kuratomi <tkuratomi@ansible.com> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: ping +version_added: historical +short_description: Try to connect to host, verify a usable python and return C(pong) on success +description: + - A trivial test module, this module always returns C(pong) on successful + contact. It does not make sense in playbooks, but it is useful from + C(/usr/bin/ansible) to verify the ability to login and that a usable Python is configured. + - This is NOT ICMP ping, this is just a trivial test module that requires Python on the remote-node. + - For Windows targets, use the M(ansible.windows.win_ping) module instead. + - For Network targets, use the M(ansible.netcommon.net_ping) module instead. +options: + data: + description: + - Data to return for the C(ping) return value. + - If this parameter is set to C(crash), the module will cause an exception. + type: str + default: pong +seealso: + - module: ansible.netcommon.net_ping + - module: ansible.windows.win_ping +author: + - Ansible Core Team + - Michael DeHaan +notes: + - Supports C(check_mode). +''' + +EXAMPLES = ''' +# Test we can logon to 'webservers' and execute python with json lib. +# ansible webservers -m ping + +- name: Example from an Ansible Playbook + ansible.builtin.ping: + +- name: Induce an exception to see what happens + ansible.builtin.ping: + data: crash +''' + +RETURN = ''' +ping: + description: Value provided with the data parameter. + returned: success + type: str + sample: pong +''' + +from ansible.module_utils.basic import AnsibleModule + + +def main(): + module = AnsibleModule( + argument_spec=dict( + data=dict(type='str', default='pong'), + ), + supports_check_mode=True + ) + + if module.params['data'] == 'crash': + raise Exception("boom") + + result = dict( + ping=module.params['data'], + ) + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/test/integration/targets/module_defaults/runme.sh b/test/integration/targets/module_defaults/runme.sh index c19e607b..082f4e5b 100755 --- a/test/integration/targets/module_defaults/runme.sh +++ b/test/integration/targets/module_defaults/runme.sh @@ -3,3 +3,7 @@ set -eux ansible-playbook test_defaults.yml "$@" + +ansible-playbook test_action_groups.yml "$@" + +ansible-playbook test_action_group_metadata.yml "$@" diff --git a/test/integration/targets/module_defaults/tasks/main.yml b/test/integration/targets/module_defaults/tasks/main.yml index 3ed960d3..747c2f92 100644 --- a/test/integration/targets/module_defaults/tasks/main.yml +++ b/test/integration/targets/module_defaults/tasks/main.yml @@ -39,7 +39,7 @@ module_defaults: # Meaningless values to make sure that 'module_defaults' gets # evaluated for this block - foo: + ping: bar: baz block: - debug: diff --git a/test/integration/targets/module_defaults/templates/test_metadata_warning.yml.j2 b/test/integration/targets/module_defaults/templates/test_metadata_warning.yml.j2 new file mode 100644 index 00000000..b45aaba2 --- /dev/null +++ b/test/integration/targets/module_defaults/templates/test_metadata_warning.yml.j2 @@ -0,0 +1,8 @@ +--- +- hosts: localhost + gather_facts: no + module_defaults: + group/{{ group_name }}: + data: value + tasks: + - ping: diff --git a/test/integration/targets/module_defaults/test_action_group_metadata.yml b/test/integration/targets/module_defaults/test_action_group_metadata.yml new file mode 100644 index 00000000..d2ba8dc2 --- /dev/null +++ b/test/integration/targets/module_defaults/test_action_group_metadata.yml @@ -0,0 +1,123 @@ +--- +- hosts: localhost + gather_facts: no + vars: + reset_color: '\x1b\[0m' + color: '\x1b\[[0-9];[0-9]{2}m' + tasks: + + - template: + src: test_metadata_warning.yml.j2 + dest: test_metadata_warning.yml + vars: + group_name: testns.testcoll.empty_metadata + + - command: ansible-playbook test_metadata_warning.yml + register: result + + - assert: + that: metadata_warning not in warnings + vars: + warnings: "{{ result.stderr | regex_replace(reset_color) | regex_replace(color) | regex_replace('\\n', ' ') }}" + metadata_warning: "Invalid metadata was found" + + - template: + src: test_metadata_warning.yml.j2 + dest: test_metadata_warning.yml + vars: + group_name: testns.testcoll.bad_metadata_format + + - command: ansible-playbook test_metadata_warning.yml + register: result + + - assert: + that: metadata_warning in warnings + vars: + warnings: "{{ result.stderr | regex_replace(reset_color) | regex_replace(color) | regex_replace('\\n', ' ') }}" + metadata_warning: >- + Invalid metadata was found for action_group testns.testcoll.bad_metadata_format while loading module_defaults. + The only expected key is metadata, but got keys: metadata, unexpected_key + + - template: + src: test_metadata_warning.yml.j2 + dest: test_metadata_warning.yml + vars: + group_name: testns.testcoll.multiple_metadata + + - command: ansible-playbook test_metadata_warning.yml + register: result + + - assert: + that: metadata_warning in warnings + vars: + warnings: "{{ result.stderr | regex_replace(reset_color) | regex_replace(color) | regex_replace('\\n', ' ') }}" + metadata_warning: >- + Invalid metadata was found for action_group testns.testcoll.multiple_metadata while loading module_defaults. + The group contains multiple metadata entries. + + - template: + src: test_metadata_warning.yml.j2 + dest: test_metadata_warning.yml + vars: + group_name: testns.testcoll.bad_metadata_options + + - command: 'ansible-playbook test_metadata_warning.yml' + register: result + + - assert: + that: metadata_warning in warnings + vars: + warnings: "{{ result.stderr | regex_replace(reset_color) | regex_replace(color) | regex_replace('\\n', ' ') }}" + metadata_warning: >- + Invalid metadata was found for action_group testns.testcoll.bad_metadata_options while loading module_defaults. + The metadata contains unexpected keys: unexpected_key + + - template: + src: test_metadata_warning.yml.j2 + dest: test_metadata_warning.yml + vars: + group_name: testns.testcoll.bad_metadata_type + + - command: ansible-playbook test_metadata_warning.yml + register: result + + - assert: + that: metadata_warning in warnings + vars: + warnings: "{{ result.stderr | regex_replace(reset_color) | regex_replace(color) | regex_replace('\\n', ' ') }}" + metadata_warning: >- + Invalid metadata was found for action_group testns.testcoll.bad_metadata_type while loading module_defaults. + The metadata is not a dictionary. Got ['testgroup'] + + - template: + src: test_metadata_warning.yml.j2 + dest: test_metadata_warning.yml + vars: + group_name: testns.testcoll.bad_metadata_option_type + + - command: ansible-playbook test_metadata_warning.yml + register: result + + - assert: + that: metadata_warning in warnings + vars: + warnings: "{{ result.stderr | regex_replace(reset_color) | regex_replace(color) | regex_replace('\\n', ' ') }}" + metadata_warning: >- + Invalid metadata was found for action_group testns.testcoll.bad_metadata_option_type while loading module_defaults. + The metadata contains unexpected key types: extend_group is {'name': 'testgroup'} (expected type list) + + - name: test disabling action_group metadata validation + command: ansible-playbook test_metadata_warning.yml + environment: + ANSIBLE_VALIDATE_ACTION_GROUP_METADATA: False + register: result + + - assert: + that: metadata_warning not in warnings + vars: + warnings: "{{ result.stderr | regex_replace(reset_color) | regex_replace(color) | regex_replace('\\n', ' ') }}" + metadata_warning: "Invalid metadata was found for action_group" + + - file: + path: test_metadata_warning.yml + state: absent diff --git a/test/integration/targets/module_defaults/test_action_groups.yml b/test/integration/targets/module_defaults/test_action_groups.yml new file mode 100644 index 00000000..33a3c9c5 --- /dev/null +++ b/test/integration/targets/module_defaults/test_action_groups.yml @@ -0,0 +1,132 @@ +--- +- hosts: localhost + gather_facts: no + tasks: + - name: test ansible.legacy short group name + module_defaults: + group/testgroup: + data: test + block: + - legacy_ping: + register: result + - assert: + that: "result.ping == 'pong'" + + - ansible.legacy.legacy_ping: + register: result + - assert: + that: "result.ping == 'pong'" + + - ping: + register: result + - assert: + that: "result.ping == 'test'" + + - ansible.legacy.ping: # resolves to ansible.builtin.ping + register: result + - assert: + that: "result.ping == 'test'" + + - ansible.builtin.ping: + register: result + - assert: + that: "result.ping == 'test'" + + - formerly_core_ping: + register: result + - assert: + that: "result.ping == 'test'" + + - ansible.builtin.formerly_core_ping: + register: result + - assert: + that: "result.ping == 'test'" + + - name: test group that includes a legacy action + module_defaults: + # As of 2.12, legacy actions must be included in the action group definition + group/testlegacy: + data: test + block: + - legacy_ping: + register: result + - assert: + that: "result.ping == 'test'" + + - ansible.legacy.legacy_ping: + register: result + - assert: + that: "result.ping == 'test'" + + - name: test ansible.builtin fully qualified group name + module_defaults: + group/ansible.builtin.testgroup: + data: test + block: + # ansible.builtin does not contain ansible.legacy + - legacy_ping: + register: result + - assert: + that: "result.ping != 'test'" + + # ansible.builtin does not contain ansible.legacy + - ansible.legacy.legacy_ping: + register: result + - assert: + that: "result.ping != 'test'" + + - ping: + register: result + - assert: + that: "result.ping == 'test'" + + # Resolves to ansible.builtin.ping + - ansible.legacy.ping: + register: result + - assert: + that: "result.ping == 'test'" + + - ansible.builtin.ping: + register: result + - assert: + that: "result.ping == 'test'" + + - formerly_core_ping: + register: result + - assert: + that: "result.ping == 'test'" + + - ansible.builtin.formerly_core_ping: + register: result + - assert: + that: "result.ping == 'test'" + + - name: test collection group name + module_defaults: + group/testns.testcoll.testgroup: + data: test + block: + # Plugin resolving to a different collection does not get the default + - ping: + register: result + - assert: + that: "result.ping != 'test'" + + - formerly_core_ping: + register: result + - assert: + that: "result.ping == 'test'" + + - ansible.builtin.formerly_core_ping: + register: result + - assert: + that: "result.ping == 'test'" + + - testns.testcoll.ping: + register: result + - assert: + that: "result.ping == 'test'" + + - metadata: + collections: + - testns.testcoll diff --git a/test/integration/targets/module_defaults/test_defaults.yml b/test/integration/targets/module_defaults/test_defaults.yml index 15b66362..70377f12 100644 --- a/test/integration/targets/module_defaults/test_defaults.yml +++ b/test/integration/targets/module_defaults/test_defaults.yml @@ -44,6 +44,51 @@ - debug: var=echo1_fq + - legacy_ping: + register: legacy_ping_1 + module_defaults: + legacy_ping: + data: from task + + - legacy_ping: + register: legacy_ping_2 + module_defaults: + ansible.legacy.legacy_ping: + data: from task + + - ansible.legacy.legacy_ping: + register: legacy_ping_3 + module_defaults: + legacy_ping: + data: from task + + - ansible.legacy.legacy_ping: + register: legacy_ping_4 + module_defaults: + ansible.legacy.legacy_ping: + data: from task + + - name: builtin uses legacy defaults + ansible.builtin.debug: + module_defaults: + debug: + msg: legacy default + register: builtin_legacy_defaults_1 + + - name: builtin uses legacy defaults + ansible.builtin.debug: + module_defaults: + ansible.legacy.debug: + msg: legacy default + register: builtin_legacy_defaults_2 + + - name: legacy does not use builtin defaults + ansible.legacy.debug: + register: legacy_builtin_defaults + module_defaults: + ansible.builtin.debug: + msg: legacy default + - assert: that: - "echoaction_fq.args_in == {'task_arg': 'from task', 'explicit_module_default': 'from playbook', 'group_module_default': 'from playbook' }" @@ -56,5 +101,12 @@ - "other_echoaction_unq.args_in == {'task_arg': 'from task', 'group_module_default': 'from playbook' }" - "other_echo1_fq.args_in == {'task_arg': 'from task', 'group_module_default': 'from playbook' }" - "other_echo1_unq.args_in == {'task_arg': 'from task', 'group_module_default': 'from playbook' }" + - "legacy_ping_1.ping == 'from task'" + - "legacy_ping_2.ping == 'from task'" + - "legacy_ping_3.ping == 'from task'" + - "legacy_ping_4.ping == 'from task'" + - "legacy_builtin_defaults.msg == 'Hello world!'" + - "builtin_legacy_defaults_1.msg == 'legacy default'" + - "builtin_legacy_defaults_2.msg == 'legacy default'" - include_tasks: tasks/main.yml diff --git a/test/integration/targets/module_no_log/aliases b/test/integration/targets/module_no_log/aliases index cbbb8804..2e263309 100644 --- a/test/integration/targets/module_no_log/aliases +++ b/test/integration/targets/module_no_log/aliases @@ -1,5 +1,5 @@ shippable/posix/group1 -skip/aix # not configured to log user.info to /var/log/syslog +context/controller skip/freebsd # not configured to log user.info to /var/log/syslog skip/osx # not configured to log user.info to /var/log/syslog skip/macos # not configured to log user.info to /var/log/syslog diff --git a/test/integration/targets/module_precedence/aliases b/test/integration/targets/module_precedence/aliases index a6dafcf8..13e01f0c 100644 --- a/test/integration/targets/module_precedence/aliases +++ b/test/integration/targets/module_precedence/aliases @@ -1 +1,2 @@ shippable/posix/group1 +context/controller diff --git a/test/integration/targets/module_tracebacks/aliases b/test/integration/targets/module_tracebacks/aliases index 804f0460..757f4fb8 100644 --- a/test/integration/targets/module_tracebacks/aliases +++ b/test/integration/targets/module_tracebacks/aliases @@ -1,3 +1,3 @@ shippable/posix/group4 needs/ssh -skip/aix +context/controller diff --git a/test/integration/targets/module_utils/aliases b/test/integration/targets/module_utils/aliases index 2f5770ff..769d265d 100644 --- a/test/integration/targets/module_utils/aliases +++ b/test/integration/targets/module_utils/aliases @@ -1,3 +1,4 @@ shippable/posix/group3 needs/root needs/target/setup_nobody +context/target 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 97dbf873..2b2b6dbd 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 diff --git a/test/integration/targets/module_utils/module_utils_test.yml b/test/integration/targets/module_utils/module_utils_test.yml index 96b2a9e0..a6019cda 100644 --- a/test/integration/targets/module_utils/module_utils_test.yml +++ b/test/integration/targets/module_utils/module_utils_test.yml @@ -57,8 +57,8 @@ - name: Assert that the deprecation message is given correctly assert: that: - - result.deprecations[0].msg == "Alias 'baz' is deprecated. See the module docs for more information" - - result.deprecations[0].version == '9.99' + - result.deprecations[-1].msg == "Alias 'baz' is deprecated. See the module docs for more information" + - result.deprecations[-1].version == '9.99' - block: - name: Get a string with a \0 in it diff --git a/test/integration/targets/module_utils/module_utils_test_no_log.yml b/test/integration/targets/module_utils/module_utils_test_no_log.yml index bad2efd4..2fa3e101 100644 --- a/test/integration/targets/module_utils/module_utils_test_no_log.yml +++ b/test/integration/targets/module_utils/module_utils_test_no_log.yml @@ -7,3 +7,6 @@ explicit_pass: abc suboption: explicit_sub_pass: def + environment: + SECRET_ENV: ghi + SECRET_SUB_ENV: jkl diff --git a/test/integration/targets/module_utils/module_utils_vvvvv.yml b/test/integration/targets/module_utils/module_utils_vvvvv.yml index 6a9f9201..fc2b0c1c 100644 --- a/test/integration/targets/module_utils/module_utils_vvvvv.yml +++ b/test/integration/targets/module_utils/module_utils_vvvvv.yml @@ -7,11 +7,10 @@ # Invocation usually is output with 3vs or more, our callback plugin displays it anyway - name: Check no_log invocation results command: ansible-playbook -i {{ inventory_file }} module_utils_test_no_log.yml + delegate_to: localhost environment: ANSIBLE_CALLBACK_PLUGINS: callback ANSIBLE_STDOUT_CALLBACK: pure_json - SECRET_ENV: ghi - SECRET_SUB_ENV: jkl register: no_log_invocation - set_fact: diff --git a/test/integration/targets/module_utils_common.respawn/aliases b/test/integration/targets/module_utils_common.respawn/aliases new file mode 100644 index 00000000..a6dafcf8 --- /dev/null +++ b/test/integration/targets/module_utils_common.respawn/aliases @@ -0,0 +1 @@ +shippable/posix/group1 diff --git a/test/integration/targets/module_utils_respawn/library/respawnme.py b/test/integration/targets/module_utils_common.respawn/library/respawnme.py index 6471dba4..6471dba4 100644 --- a/test/integration/targets/module_utils_respawn/library/respawnme.py +++ b/test/integration/targets/module_utils_common.respawn/library/respawnme.py diff --git a/test/integration/targets/module_utils_respawn/tasks/main.yml b/test/integration/targets/module_utils_common.respawn/tasks/main.yml index 246c8f74..246c8f74 100644 --- a/test/integration/targets/module_utils_respawn/tasks/main.yml +++ b/test/integration/targets/module_utils_common.respawn/tasks/main.yml diff --git a/test/integration/targets/module_utils_distro/aliases b/test/integration/targets/module_utils_distro/aliases new file mode 100644 index 00000000..8278ec8b --- /dev/null +++ b/test/integration/targets/module_utils_distro/aliases @@ -0,0 +1,2 @@ +shippable/posix/group3 +context/controller diff --git a/test/integration/targets/module_utils_distro/meta/main.yml b/test/integration/targets/module_utils_distro/meta/main.yml new file mode 100644 index 00000000..1810d4be --- /dev/null +++ b/test/integration/targets/module_utils_distro/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - setup_remote_tmp_dir diff --git a/test/integration/targets/module_utils_distro/runme.sh b/test/integration/targets/module_utils_distro/runme.sh new file mode 100755 index 00000000..e5d3d053 --- /dev/null +++ b/test/integration/targets/module_utils_distro/runme.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +set -eux + +# Ensure that when a non-distro 'distro' package is in PYTHONPATH, we fallback +# to our bundled one. +new_pythonpath="$OUTPUT_DIR/pythonpath" +mkdir -p "$new_pythonpath/distro" +touch "$new_pythonpath/distro/__init__.py" + +export PYTHONPATH="$new_pythonpath:$PYTHONPATH" + +# Sanity test to make sure the above worked +set +e +distro_id_fail="$(python -c 'import distro; distro.id' 2>&1)" +set -e +grep -q "AttributeError:.*has no attribute 'id'" <<< "$distro_id_fail" + +# ansible.module_utils.common.sys_info imports distro, and itself gets imported +# in DataLoader, so all we have to do to test the fallback is run `ansible`. +ansirun="$(ansible -i ../../inventory -a "echo \$PYTHONPATH" localhost)" +grep -q "$new_pythonpath" <<< "$ansirun" + +rm -rf "$new_pythonpath" diff --git a/test/integration/targets/module_utils_selinux/aliases b/test/integration/targets/module_utils_facts.system.selinux/aliases index aab3ff52..ee281d27 100644 --- a/test/integration/targets/module_utils_selinux/aliases +++ b/test/integration/targets/module_utils_facts.system.selinux/aliases @@ -1,5 +1,4 @@ shippable/posix/group1 -skip/aix skip/osx skip/macos skip/freebsd diff --git a/test/integration/targets/module_utils_selinux/tasks/main.yml b/test/integration/targets/module_utils_facts.system.selinux/tasks/main.yml index c599377b..c599377b 100644 --- a/test/integration/targets/module_utils_selinux/tasks/main.yml +++ b/test/integration/targets/module_utils_facts.system.selinux/tasks/main.yml diff --git a/test/integration/targets/module_utils_selinux/tasks/selinux.yml b/test/integration/targets/module_utils_facts.system.selinux/tasks/selinux.yml index 6a2b159c..6a2b159c 100644 --- a/test/integration/targets/module_utils_selinux/tasks/selinux.yml +++ b/test/integration/targets/module_utils_facts.system.selinux/tasks/selinux.yml diff --git a/test/integration/targets/no_log/aliases b/test/integration/targets/no_log/aliases index 70a7b7a9..1d28bdb2 100644 --- a/test/integration/targets/no_log/aliases +++ b/test/integration/targets/no_log/aliases @@ -1 +1,2 @@ shippable/posix/group5 +context/controller diff --git a/test/integration/targets/noexec/aliases b/test/integration/targets/noexec/aliases index 66a77c7b..edabc85a 100644 --- a/test/integration/targets/noexec/aliases +++ b/test/integration/targets/noexec/aliases @@ -1,3 +1,4 @@ shippable/posix/group2 +context/controller skip/docker skip/macos diff --git a/test/integration/targets/old_style_cache_plugins/aliases b/test/integration/targets/old_style_cache_plugins/aliases index 05f65b71..c7c77ce6 100644 --- a/test/integration/targets/old_style_cache_plugins/aliases +++ b/test/integration/targets/old_style_cache_plugins/aliases @@ -1,4 +1,6 @@ +destructive +needs/root shippable/posix/group3 +context/controller skip/osx skip/macos -disabled diff --git a/test/integration/targets/old_style_cache_plugins/cleanup.yml b/test/integration/targets/old_style_cache_plugins/cleanup.yml new file mode 100644 index 00000000..93f5cc58 --- /dev/null +++ b/test/integration/targets/old_style_cache_plugins/cleanup.yml @@ -0,0 +1,41 @@ +--- +- hosts: localhost + gather_facts: no + ignore_errors: yes + tasks: + - command: redis-cli keys + + - name: delete cache keys + command: redis-cli del {{ item }} + loop: + - ansible_facts_localhost + - ansible_inventory_localhost + - ansible_cache_keys + + - name: shutdown the server + command: redis-cli shutdown + + - name: cleanup set up files + file: + path: "{{ item }}" + state: absent + loop: + - redis-stable.tar.gz + + - name: remove executables + file: + state: absent + path: "/usr/local/bin/{{ item }}" + follow: no + become: yes + loop: + - redis-server + - redis-cli + + - name: clean the rest of the files + file: + path: "{{ item }}" + state: absent + loop: + - ./redis-stable.tar.gz + - ./redis-stable diff --git a/test/integration/targets/old_style_cache_plugins/inspect_cache.yml b/test/integration/targets/old_style_cache_plugins/inspect_cache.yml new file mode 100644 index 00000000..72810e19 --- /dev/null +++ b/test/integration/targets/old_style_cache_plugins/inspect_cache.yml @@ -0,0 +1,36 @@ +--- +- hosts: localhost + gather_facts: no + vars: + json_cache: "{{ cache.stdout | from_json }}" + tasks: + - command: redis-cli get ansible_facts_localhost + register: cache + tags: + - always + + - name: test that the cache only contains the set_fact var + assert: + that: + - "json_cache | length == 1" + - "json_cache.foo == ansible_facts.foo" + tags: + - set_fact + + - name: test that the cache contains gathered facts and the var + assert: + that: + - "json_cache | length > 1" + - "json_cache.foo == 'bar'" + - "json_cache.ansible_distribution is defined" + tags: + - additive_gather_facts + + - name: test that the cache contains only gathered facts + assert: + that: + - "json_cache | length > 1" + - "json_cache.foo is undefined" + - "json_cache.ansible_distribution is defined" + tags: + - gather_facts diff --git a/test/integration/targets/old_style_cache_plugins/plugins/cache/configurable_redis.py b/test/integration/targets/old_style_cache_plugins/plugins/cache/configurable_redis.py new file mode 100644 index 00000000..44b6cf93 --- /dev/null +++ b/test/integration/targets/old_style_cache_plugins/plugins/cache/configurable_redis.py @@ -0,0 +1,147 @@ +# (c) 2014, Brian Coca, Josh Drake, et al +# (c) 2017 Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +DOCUMENTATION = ''' + cache: configurable_redis + short_description: Use Redis DB for cache + description: + - This cache uses JSON formatted, per host records saved in Redis. + version_added: "1.9" + requirements: + - redis>=2.4.5 (python lib) + options: + _uri: + description: + - A colon separated string of connection information for Redis. + required: True + env: + - name: ANSIBLE_CACHE_PLUGIN_CONNECTION + ini: + - key: fact_caching_connection + section: defaults + _prefix: + description: User defined prefix to use when creating the DB entries + default: ansible_facts + env: + - name: ANSIBLE_CACHE_PLUGIN_PREFIX + ini: + - key: fact_caching_prefix + section: defaults + _timeout: + default: 86400 + description: Expiration timeout for the cache plugin data + env: + - name: ANSIBLE_CACHE_PLUGIN_TIMEOUT + ini: + - key: fact_caching_timeout + section: defaults + type: integer +''' + +import time +import json + +from ansible import constants as C +from ansible.errors import AnsibleError +from ansible.parsing.ajson import AnsibleJSONEncoder, AnsibleJSONDecoder +from ansible.plugins.cache import BaseCacheModule +from ansible.utils.display import Display + +try: + from redis import StrictRedis, VERSION +except ImportError: + raise AnsibleError("The 'redis' python module (version 2.4.5 or newer) is required for the redis fact cache, 'pip install redis'") + +display = Display() + + +class CacheModule(BaseCacheModule): + """ + A caching module backed by redis. + Keys are maintained in a zset with their score being the timestamp + when they are inserted. This allows for the usage of 'zremrangebyscore' + to expire keys. This mechanism is used or a pattern matched 'scan' for + performance. + """ + def __init__(self, *args, **kwargs): + connection = [] + + super(CacheModule, self).__init__(*args, **kwargs) + if self.get_option('_uri'): + connection = self.get_option('_uri').split(':') + self._timeout = float(self.get_option('_timeout')) + self._prefix = self.get_option('_prefix') + + self._cache = {} + self._db = StrictRedis(*connection) + self._keys_set = 'ansible_cache_keys' + + def _make_key(self, key): + return self._prefix + key + + def get(self, key): + + if key not in self._cache: + value = self._db.get(self._make_key(key)) + # guard against the key not being removed from the zset; + # this could happen in cases where the timeout value is changed + # between invocations + if value is None: + self.delete(key) + raise KeyError + self._cache[key] = json.loads(value, cls=AnsibleJSONDecoder) + + return self._cache.get(key) + + def set(self, key, value): + + value2 = json.dumps(value, cls=AnsibleJSONEncoder, sort_keys=True, indent=4) + if self._timeout > 0: # a timeout of 0 is handled as meaning 'never expire' + self._db.setex(self._make_key(key), int(self._timeout), value2) + else: + self._db.set(self._make_key(key), value2) + + if VERSION[0] == 2: + self._db.zadd(self._keys_set, time.time(), key) + else: + self._db.zadd(self._keys_set, {key: time.time()}) + self._cache[key] = value + + def _expire_keys(self): + if self._timeout > 0: + expiry_age = time.time() - self._timeout + self._db.zremrangebyscore(self._keys_set, 0, expiry_age) + + def keys(self): + self._expire_keys() + return self._db.zrange(self._keys_set, 0, -1) + + def contains(self, key): + self._expire_keys() + return (self._db.zrank(self._keys_set, key) is not None) + + def delete(self, key): + if key in self._cache: + del self._cache[key] + self._db.delete(self._make_key(key)) + self._db.zrem(self._keys_set, key) + + def flush(self): + for key in self.keys(): + self.delete(key) + + def copy(self): + # TODO: there is probably a better way to do this in redis + ret = dict() + for key in self.keys(): + ret[key] = self.get(key) + return ret + + def __getstate__(self): + return dict() + + def __setstate__(self, data): + self.__init__() diff --git a/test/integration/targets/old_style_cache_plugins/plugins/cache/redis.py b/test/integration/targets/old_style_cache_plugins/plugins/cache/legacy_redis.py index 9879dec9..9879dec9 100644 --- a/test/integration/targets/old_style_cache_plugins/plugins/cache/redis.py +++ b/test/integration/targets/old_style_cache_plugins/plugins/cache/legacy_redis.py diff --git a/test/integration/targets/old_style_cache_plugins/runme.sh b/test/integration/targets/old_style_cache_plugins/runme.sh index 13911bd5..ffa6723b 100755 --- a/test/integration/targets/old_style_cache_plugins/runme.sh +++ b/test/integration/targets/old_style_cache_plugins/runme.sh @@ -4,77 +4,44 @@ set -eux source virtualenv.sh -# Run test if dependencies are installed -failed_dep_1=$(ansible localhost -m pip -a "name=redis>=2.4.5 state=present" "$@" | tee out.txt | grep -c 'FAILED!' || true) -cat out.txt +trap 'ansible-playbook cleanup.yml' EXIT -installed_redis=$(ansible localhost -m package -a "name=redis-server state=present" --become "$@" | tee out.txt | grep -c '"changed": true' || true) -failed_dep_2=$(grep out.txt -ce 'FAILED!' || true) -cat out.txt +export PATH="$PATH:/usr/local/bin" -started_redis=$(ansible localhost -m service -a "name=redis-server state=started" --become "$@" | tee out.txt | grep -c '"changed": true' || true) -failed_dep_3=$(grep out.txt -ce 'FAILED!' || true) -cat out.txt +ansible-playbook setup_redis_cache.yml "$@" -CLEANUP_REDIS () { if [ "${installed_redis}" -eq 1 ] ; then ansible localhost -m package -a "name=redis-server state=absent" --become ; fi } -STOP_REDIS () { if [ "${installed_redis}" -ne 1 ] && [ "${started_redis}" -eq 1 ] ; then ansible localhost -m service -a "name=redis-server state=stopped" --become ; fi } +# Cache should start empty +redis-cli keys ansible_ +[ "$(redis-cli keys ansible_)" = "" ] -if [ "${failed_dep_1}" -eq 1 ] || [ "${failed_dep_2}" -eq 1 ] || [ "${failed_dep_3}" -eq 1 ] ; then - STOP_REDIS - CLEANUP_REDIS - exit 0 -fi - -export ANSIBLE_CACHE_PLUGIN=redis -export ANSIBLE_CACHE_PLUGIN_CONNECTION=localhost:6379:0 export ANSIBLE_CACHE_PLUGINS=./plugins/cache +export ANSIBLE_CACHE_PLUGIN_CONNECTION=localhost:6379:0 +export ANSIBLE_CACHE_PLUGIN_PREFIX='ansible_facts_' + +# Test legacy cache plugins (that use ansible.constants) and +# new cache plugins that use config manager both work for facts. +for fact_cache in legacy_redis configurable_redis; do -# Use old redis for fact caching -count=$(ansible-playbook test_fact_gathering.yml -vvv 2>&1 "$@" | tee out.txt | grep -c 'Gathering Facts' || true) -failed_dep_version=$(grep out.txt -ce "'redis' python module (version 2.4.5 or newer) is required" || true) -cat out.txt -if [ "${failed_dep_version}" -eq 1 ] ; then - STOP_REDIS - CLEANUP_REDIS - exit 0 -fi -if [ "${count}" -ne 1 ] ; then - STOP_REDIS - CLEANUP_REDIS - exit 1 -fi + export ANSIBLE_CACHE_PLUGIN="$fact_cache" -# Attempt to use old redis for inventory caching; should not work -export ANSIBLE_INVENTORY_CACHE=True -export ANSIBLE_INVENTORY_CACHE_PLUGIN=redis -export ANSIBLE_INVENTORY_ENABLED=test -export ANSIBLE_INVENTORY_PLUGINS=./plugins/inventory + # test set_fact with cacheable: true + ansible-playbook test_fact_gathering.yml --tags set_fact "$@" + [ "$(redis-cli keys ansible_facts_localhost | wc -l)" -eq 1 ] + ansible-playbook inspect_cache.yml --tags set_fact "$@" -ansible-inventory -i inventory_config --graph 2>&1 "$@" | tee out.txt | grep 'Cache options were provided but may not reconcile correctly unless set via set_options' -res=$? -cat out.txt -if [ "${res}" -eq 1 ] ; then - STOP_REDIS - CLEANUP_REDIS - exit 1 -fi + # cache gathered facts in addition + ansible-playbook test_fact_gathering.yml --tags gather_facts "$@" + ansible-playbook inspect_cache.yml --tags additive_gather_facts "$@" -# Use new style redis for fact caching -unset ANSIBLE_CACHE_PLUGINS -count=$(ansible-playbook test_fact_gathering.yml -vvv "$@" | tee out.txt | grep -c 'Gathering Facts' || true) -cat out.txt -if [ "${count}" -ne 1 ] ; then - STOP_REDIS - CLEANUP_REDIS - exit 1 -fi + # flush cache and only cache gathered facts + ansible-playbook test_fact_gathering.yml --flush-cache --tags gather_facts --tags flush "$@" + ansible-playbook inspect_cache.yml --tags gather_facts "$@" -# Use new redis for inventory caching -ansible-inventory -i inventory_config --graph "$@" 2>&1 | tee out.txt | grep 'host2' -res=$? -cat out.txt + redis-cli del ansible_facts_localhost + unset ANSIBLE_CACHE_PLUGIN -STOP_REDIS -CLEANUP_REDIS +done -exit $res +# Legacy cache plugins need to be updated to use set_options/get_option to be compatible with inventory plugins. +# Inventory plugins load cache options with the config manager. +ansible-playbook test_inventory_cache.yml "$@" diff --git a/test/integration/targets/old_style_cache_plugins/setup_redis_cache.yml b/test/integration/targets/old_style_cache_plugins/setup_redis_cache.yml new file mode 100644 index 00000000..8aad37a3 --- /dev/null +++ b/test/integration/targets/old_style_cache_plugins/setup_redis_cache.yml @@ -0,0 +1,51 @@ +--- +- hosts: localhost + vars: + make: "{{ ( ansible_distribution != 'FreeBSD' ) | ternary('make', 'gmake') }}" + tasks: + - name: name ensure make is available + command: "which {{ make }}" + register: has_make + ignore_errors: yes + + - command: apk add --no-cache make + when: "has_make is failed and ansible_distribution == 'Alpine'" + become: yes + + - package: + name: "{{ make }}" + state: present + become: yes + when: "has_make is failed and ansible_distribution != 'Alpine'" + + - name: get the latest stable redis server release + get_url: + url: http://download.redis.io/redis-stable.tar.gz + dest: ./ + + - name: unzip download + unarchive: + src: redis-stable.tar.gz + dest: ./ + + - command: "{{ make }}" + args: + chdir: redis-stable + + - name: copy the executable into the path + copy: + src: "redis-stable/src/{{ item }}" + dest: /usr/local/bin/ + mode: 755 + become: yes + loop: + - redis-server + - redis-cli + + - name: start the redis server in the background + command: redis-server --daemonize yes + + - name: install dependency for the cache plugin + pip: + name: redis>2.4.5 + state: present diff --git a/test/integration/targets/old_style_cache_plugins/test_fact_gathering.yml b/test/integration/targets/old_style_cache_plugins/test_fact_gathering.yml index 5c720b4e..2c77f0dd 100644 --- a/test/integration/targets/old_style_cache_plugins/test_fact_gathering.yml +++ b/test/integration/targets/old_style_cache_plugins/test_fact_gathering.yml @@ -1,6 +1,22 @@ --- - hosts: localhost gather_facts: no + tags: + - flush + tasks: + - meta: clear_facts - hosts: localhost gather_facts: yes + gather_subset: min + tags: + - gather_facts + +- hosts: localhost + gather_facts: no + tags: + - set_fact + tasks: + - set_fact: + foo: bar + cacheable: true diff --git a/test/integration/targets/old_style_cache_plugins/test_inventory_cache.yml b/test/integration/targets/old_style_cache_plugins/test_inventory_cache.yml new file mode 100644 index 00000000..83b79831 --- /dev/null +++ b/test/integration/targets/old_style_cache_plugins/test_inventory_cache.yml @@ -0,0 +1,45 @@ +- hosts: localhost + gather_facts: no + vars: + reset_color: '\x1b\[0m' + color: '\x1b\[[0-9];[0-9]{2}m' + base_environment: + ANSIBLE_INVENTORY_PLUGINS: ./plugins/inventory + ANSIBLE_INVENTORY_ENABLED: test + ANSIBLE_INVENTORY_CACHE: true + ANSIBLE_CACHE_PLUGINS: ./plugins/cache + ANSIBLE_CACHE_PLUGIN_CONNECTION: localhost:6379:0 + ANSIBLE_CACHE_PLUGIN_PREFIX: 'ansible_inventory_' + legacy_cache: + ANSIBLE_INVENTORY_CACHE_PLUGIN: legacy_redis + updated_cache: + ANSIBLE_INVENTORY_CACHE_PLUGIN: configurable_redis + tasks: + - name: legacy-style cache plugin should cause a warning + command: ansible-inventory -i inventory_config --graph + register: result + environment: "{{ base_environment | combine(legacy_cache) }}" + + - name: test warning message + assert: + that: + - expected_warning in warning + - "'No inventory was parsed, only implicit localhost is available' in warning" + vars: + warning: "{{ result.stderr | regex_replace(reset_color) | regex_replace(color) | regex_replace('\\n', ' ') }}" + expected_warning: "Cache options were provided but may not reconcile correctly unless set via set_options" + + - name: cache plugin updated to use config manager should work + command: ansible-inventory -i inventory_config --graph + register: result + environment: "{{ base_environment | combine(updated_cache) }}" + + - name: test warning message + assert: + that: + - unexpected_warning not in warning + - "'No inventory was parsed, only implicit localhost is available' not in warning" + - '"host1" in result.stdout' + vars: + warning: "{{ result.stderr | regex_replace(reset_color) | regex_replace(color) | regex_replace('\\n', ' ') }}" + unexpected_warning: "Cache options were provided but may not reconcile correctly unless set via set_options" diff --git a/test/integration/targets/old_style_modules_posix/aliases b/test/integration/targets/old_style_modules_posix/aliases index b5983214..a3ada117 100644 --- a/test/integration/targets/old_style_modules_posix/aliases +++ b/test/integration/targets/old_style_modules_posix/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/target diff --git a/test/integration/targets/omit/aliases b/test/integration/targets/omit/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/omit/aliases +++ b/test/integration/targets/omit/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/order/aliases b/test/integration/targets/order/aliases index a6dafcf8..13e01f0c 100644 --- a/test/integration/targets/order/aliases +++ b/test/integration/targets/order/aliases @@ -1 +1,2 @@ shippable/posix/group1 +context/controller diff --git a/test/integration/targets/package/tasks/main.yml b/test/integration/targets/package/tasks/main.yml index 853b4711..c8b75da4 100644 --- a/test/integration/targets/package/tasks/main.yml +++ b/test/integration/targets/package/tasks/main.yml @@ -143,4 +143,108 @@ - name: verify at command is installed shell: which at + - name: remove at package + package: + name: at + state: absent + register: at_install0 + + - name: validate package removal + assert: + that: + - "at_install0 is changed" + when: ansible_distribution in package_distros + +## +## yum +## +#Validation for new parameter 'use' in yum action plugin which aliases to 'use_backend' +#Issue: https://github.com/ansible/ansible/issues/70774 +- block: + - name: verify if using both the parameters 'use' and 'use_backend' throw error + yum: + name: at + state: present + use_backend: yum + use: yum + ignore_errors: yes + register: result + + - name: verify error + assert: + that: + - "'parameters are mutually exclusive' in result.msg" + - "not result is changed" + + - name: verify if package installation is successful using 'use' parameter + yum: + name: at + state: present + use: dnf + register: result + + - name: verify the result + assert: + that: + - "result is changed" + + - name: remove at package + yum: + name: at + state: absent + use: dnf + register: result + + - name: verify package removal + assert: + that: + - "result is changed" + + - name: verify if package installation is successful using 'use_backend' parameter + yum: + name: at + state: present + use_backend: dnf + register: result + + - name: verify the result + assert: + that: + - "result is changed" + + - name: remove at package + yum: + name: at + state: absent + use_backend: dnf + register: result + + - name: verify package removal + assert: + that: + - "result is changed" + + - name: verify if package installation is successful without using 'use_backend' and 'use' parameters + yum: + name: at + state: present + register: result + + - name: verify the result + assert: + that: + - "result is changed" + + - name: remove at package + yum: + name: at + state: absent + register: result + + - name: verify package removal + assert: + that: + - "result is changed" + + when: ansible_distribution == "Fedora"
\ No newline at end of file diff --git a/test/integration/targets/parsing/aliases b/test/integration/targets/parsing/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/parsing/aliases +++ b/test/integration/targets/parsing/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/path_lookups/aliases b/test/integration/targets/path_lookups/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/path_lookups/aliases +++ b/test/integration/targets/path_lookups/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/path_lookups/play.yml b/test/integration/targets/path_lookups/play.yml index 7321589b..233f972d 100644 --- a/test/integration/targets/path_lookups/play.yml +++ b/test/integration/targets/path_lookups/play.yml @@ -10,31 +10,31 @@ - copy: dest={{playbook_dir}}/files/testfile content='in files' - copy: dest={{playbook_dir}}/testfile content='in local' -- include: testplay.yml +- import_playbook: testplay.yml vars: remove: nothing role_out: in role files play_out: in files -- include: testplay.yml +- import_playbook: testplay.yml vars: remove: roles/showfile/files/testfile role_out: in role play_out: in files -- include: testplay.yml +- import_playbook: testplay.yml vars: remove: roles/showfile/testfile role_out: in role tasks play_out: in files -- include: testplay.yml +- import_playbook: testplay.yml vars: remove: roles/showfile/tasks/testfile role_out: in files play_out: in files -- include: testplay.yml +- import_playbook: testplay.yml vars: remove: files/testfile role_out: in local diff --git a/test/integration/targets/path_with_comma_in_inventory/aliases b/test/integration/targets/path_with_comma_in_inventory/aliases index 70a7b7a9..1d28bdb2 100644 --- a/test/integration/targets/path_with_comma_in_inventory/aliases +++ b/test/integration/targets/path_with_comma_in_inventory/aliases @@ -1 +1,2 @@ shippable/posix/group5 +context/controller diff --git a/test/integration/targets/pause/aliases b/test/integration/targets/pause/aliases index 810f1ab6..b07d71c7 100644 --- a/test/integration/targets/pause/aliases +++ b/test/integration/targets/pause/aliases @@ -1,3 +1,3 @@ needs/target/setup_pexpect shippable/posix/group1 -skip/aix +context/controller # this is a controller-only action, the module is just for documentation diff --git a/test/integration/targets/pip/tasks/pip.yml b/test/integration/targets/pip/tasks/pip.yml index 572c7b6f..2b9ad561 100644 --- a/test/integration/targets/pip/tasks/pip.yml +++ b/test/integration/targets/pip/tasks/pip.yml @@ -310,18 +310,51 @@ - "not (pip_install_empty is changed)" # https://github.com/ansible/ansible/issues/41043 -- name: do not consider an empty string as a version - pip: - name: q - state: present - version: "" - virtualenv: "{{ output_dir }}/pipenv" - register: pip_install_empty_version_string +- block: + - name: Ensure previous virtualenv no longer exists + file: + state: absent + name: "{{ output_dir }}/pipenv" -- name: ensure that task installation did not fail - assert: - that: - - pip_install_empty_version_string is successful + - name: do not consider an empty string as a version + pip: + name: q + state: present + version: "" + virtualenv: "{{ output_dir }}/pipenv" + register: pip_empty_version_string + + - name: test idempotency with empty string + pip: + name: q + state: present + version: "" + virtualenv: "{{ output_dir }}/pipenv" + register: pip_empty_version_string_idempotency + + - name: test idempotency without empty string + pip: + name: q + state: present + virtualenv: "{{ output_dir }}/pipenv" + register: pip_no_empty_version_string_idempotency + + # 'present' and version=="" is analogous to latest when first installed + - name: ensure we installed the latest version + pip: + name: q + state: latest + virtualenv: "{{ output_dir }}/pipenv" + register: pip_empty_version_idempotency + + - name: ensure that installation worked and is idempotent + assert: + that: + - pip_empty_version_string is changed + - pip_empty_version_string is successful + - pip_empty_version_idempotency is not changed + - pip_no_empty_version_string_idempotency is not changed + - pip_empty_version_string_idempotency is not changed # test version specifiers - name: make sure no test_package installed now diff --git a/test/integration/targets/pkg_resources/aliases b/test/integration/targets/pkg_resources/aliases index a6dafcf8..13e01f0c 100644 --- a/test/integration/targets/pkg_resources/aliases +++ b/test/integration/targets/pkg_resources/aliases @@ -1 +1,2 @@ shippable/posix/group1 +context/controller diff --git a/test/integration/targets/play_iterator/aliases b/test/integration/targets/play_iterator/aliases index 3005e4b2..498fedd5 100644 --- a/test/integration/targets/play_iterator/aliases +++ b/test/integration/targets/play_iterator/aliases @@ -1 +1,2 @@ shippable/posix/group4 +context/controller diff --git a/test/integration/targets/playbook/aliases b/test/integration/targets/playbook/aliases index a6dafcf8..13e01f0c 100644 --- a/test/integration/targets/playbook/aliases +++ b/test/integration/targets/playbook/aliases @@ -1 +1,2 @@ shippable/posix/group1 +context/controller diff --git a/test/integration/targets/playbook/empty.yml b/test/integration/targets/playbook/empty.yml new file mode 100644 index 00000000..fe51488c --- /dev/null +++ b/test/integration/targets/playbook/empty.yml @@ -0,0 +1 @@ +[] diff --git a/test/integration/targets/playbook/empty_hosts.yml b/test/integration/targets/playbook/empty_hosts.yml new file mode 100644 index 00000000..c9493c09 --- /dev/null +++ b/test/integration/targets/playbook/empty_hosts.yml @@ -0,0 +1,4 @@ +- hosts: [] + tasks: + - debug: + msg: does not run diff --git a/test/integration/targets/playbook/malformed_post_tasks.yml b/test/integration/targets/playbook/malformed_post_tasks.yml new file mode 100644 index 00000000..4c134115 --- /dev/null +++ b/test/integration/targets/playbook/malformed_post_tasks.yml @@ -0,0 +1,2 @@ +- hosts: localhost + post_tasks: 123 diff --git a/test/integration/targets/playbook/malformed_pre_tasks.yml b/test/integration/targets/playbook/malformed_pre_tasks.yml new file mode 100644 index 00000000..6c58477f --- /dev/null +++ b/test/integration/targets/playbook/malformed_pre_tasks.yml @@ -0,0 +1,2 @@ +- hosts: localhost + pre_tasks: 123 diff --git a/test/integration/targets/playbook/malformed_roles.yml b/test/integration/targets/playbook/malformed_roles.yml new file mode 100644 index 00000000..35db56e7 --- /dev/null +++ b/test/integration/targets/playbook/malformed_roles.yml @@ -0,0 +1,2 @@ +- hosts: localhost + roles: 123 diff --git a/test/integration/targets/playbook/malformed_tasks.yml b/test/integration/targets/playbook/malformed_tasks.yml new file mode 100644 index 00000000..123c059f --- /dev/null +++ b/test/integration/targets/playbook/malformed_tasks.yml @@ -0,0 +1,2 @@ +- hosts: localhost + tasks: 123 diff --git a/test/integration/targets/playbook/malformed_vars_prompt.yml b/test/integration/targets/playbook/malformed_vars_prompt.yml new file mode 100644 index 00000000..5447197d --- /dev/null +++ b/test/integration/targets/playbook/malformed_vars_prompt.yml @@ -0,0 +1,3 @@ +- hosts: localhost + vars_prompt: + - foo: bar diff --git a/test/integration/targets/playbook/old_style_role.yml b/test/integration/targets/playbook/old_style_role.yml new file mode 100644 index 00000000..015f263a --- /dev/null +++ b/test/integration/targets/playbook/old_style_role.yml @@ -0,0 +1,3 @@ +- hosts: localhost + roles: + - foo,bar diff --git a/test/integration/targets/playbook/remote_user_and_user.yml b/test/integration/targets/playbook/remote_user_and_user.yml new file mode 100644 index 00000000..c9e2389d --- /dev/null +++ b/test/integration/targets/playbook/remote_user_and_user.yml @@ -0,0 +1,6 @@ +- hosts: localhost + remote_user: a + user: b + tasks: + - debug: + msg: did not run diff --git a/test/integration/targets/playbook/roles_null.yml b/test/integration/targets/playbook/roles_null.yml new file mode 100644 index 00000000..d06bcd15 --- /dev/null +++ b/test/integration/targets/playbook/roles_null.yml @@ -0,0 +1,3 @@ +- name: null roles is okay + hosts: localhost + roles: null diff --git a/test/integration/targets/playbook/runme.sh b/test/integration/targets/playbook/runme.sh index 25e2e5a6..cc8d4957 100755 --- a/test/integration/targets/playbook/runme.sh +++ b/test/integration/targets/playbook/runme.sh @@ -7,3 +7,86 @@ ansible-playbook -i ../../inventory types.yml -v "$@" # test timeout ansible-playbook -i ../../inventory timeout.yml -v "$@" + +# our Play class allows for 'user' or 'remote_user', but not both. +# first test that both user and remote_user work individually +set +e +result="$(ansible-playbook -i ../../inventory user.yml -v "$@" 2>&1)" +set -e +grep -q "worked with user" <<< "$result" +grep -q "worked with remote_user" <<< "$result" + +# then test that the play errors if user and remote_user both exist +echo "EXPECTED ERROR: Ensure we fail properly if a play has both user and remote_user." +set +e +result="$(ansible-playbook -i ../../inventory remote_user_and_user.yml -v "$@" 2>&1)" +set -e +grep -q "ERROR! both 'user' and 'remote_user' are set for this play." <<< "$result" + +# test that playbook errors if len(plays) == 0 +echo "EXPECTED ERROR: Ensure we fail properly if a playbook is an empty list." +set +e +result="$(ansible-playbook -i ../../inventory empty.yml -v "$@" 2>&1)" +set -e +grep -q "ERROR! A playbook must contain at least one play" <<< "$result" + +# test that play errors if len(hosts) == 0 +echo "EXPECTED ERROR: Ensure we fail properly if a play has 0 hosts." +set +e +result="$(ansible-playbook -i ../../inventory empty_hosts.yml -v "$@" 2>&1)" +set -e +grep -q "ERROR! Hosts list cannot be empty. Please check your playbook" <<< "$result" + +# test that play errors if tasks is malformed +echo "EXPECTED ERROR: Ensure we fail properly if tasks is malformed." +set +e +result="$(ansible-playbook -i ../../inventory malformed_tasks.yml -v "$@" 2>&1)" +set -e +grep -q "ERROR! A malformed block was encountered while loading tasks: 123 should be a list or None" <<< "$result" + +# test that play errors if pre_tasks is malformed +echo "EXPECTED ERROR: Ensure we fail properly if pre_tasks is malformed." +set +e +result="$(ansible-playbook -i ../../inventory malformed_pre_tasks.yml -v "$@" 2>&1)" +set -e +grep -q "ERROR! A malformed block was encountered while loading pre_tasks" <<< "$result" + +# test that play errors if post_tasks is malformed +echo "EXPECTED ERROR: Ensure we fail properly if post_tasks is malformed." +set +e +result="$(ansible-playbook -i ../../inventory malformed_post_tasks.yml -v "$@" 2>&1)" +set -e +grep -q "ERROR! A malformed block was encountered while loading post_tasks" <<< "$result" + +# test roles: null -- it gets converted to [] internally +ansible-playbook -i ../../inventory roles_null.yml -v "$@" + +# test roles: 123 -- errors +echo "EXPECTED ERROR: Ensure we fail properly if roles is malformed." +set +e +result="$(ansible-playbook -i ../../inventory malformed_roles.yml -v "$@" 2>&1)" +set -e +grep -q "ERROR! A malformed role declaration was encountered." <<< "$result" + +# test roles: ["foo,bar"] -- errors about old style +echo "EXPECTED ERROR: Ensure we fail properly if old style role is given." +set +e +result="$(ansible-playbook -i ../../inventory old_style_role.yml -v "$@" 2>&1)" +set -e +grep -q "ERROR! Invalid old style role requirement: foo,bar" <<< "$result" + +# test vars prompt that has no name +echo "EXPECTED ERROR: Ensure we fail properly if vars_prompt has no name." +set +e +result="$(ansible-playbook -i ../../inventory malformed_vars_prompt.yml -v "$@" 2>&1)" +set -e +grep -q "ERROR! Invalid vars_prompt data structure, missing 'name' key" <<< "$result" + +# test vars_prompt: null +ansible-playbook -i ../../inventory vars_prompt_null.yml -v "$@" + +# test vars_files: null +ansible-playbook -i ../../inventory vars_files_null.yml -v "$@" + +# test vars_files: filename.yml +ansible-playbook -i ../../inventory vars_files_string.yml -v "$@" diff --git a/test/integration/targets/playbook/some_vars.yml b/test/integration/targets/playbook/some_vars.yml new file mode 100644 index 00000000..78353654 --- /dev/null +++ b/test/integration/targets/playbook/some_vars.yml @@ -0,0 +1,2 @@ +a_variable: yep +another: hi diff --git a/test/integration/targets/playbook/user.yml b/test/integration/targets/playbook/user.yml new file mode 100644 index 00000000..8b4029b8 --- /dev/null +++ b/test/integration/targets/playbook/user.yml @@ -0,0 +1,23 @@ +- hosts: localhost + tasks: + - command: whoami + register: whoami + + - assert: + that: + - whoami is successful + + - set_fact: + me: "{{ whoami.stdout }}" + +- hosts: localhost + user: "{{ me }}" + tasks: + - debug: + msg: worked with user ({{ me }}) + +- hosts: localhost + remote_user: "{{ me }}" + tasks: + - debug: + msg: worked with remote_user ({{ me }}) diff --git a/test/integration/targets/playbook/vars_files_null.yml b/test/integration/targets/playbook/vars_files_null.yml new file mode 100644 index 00000000..64c21c66 --- /dev/null +++ b/test/integration/targets/playbook/vars_files_null.yml @@ -0,0 +1,3 @@ +- name: null vars_files is okay + hosts: localhost + vars_files: null diff --git a/test/integration/targets/playbook/vars_files_string.yml b/test/integration/targets/playbook/vars_files_string.yml new file mode 100644 index 00000000..9191d3c1 --- /dev/null +++ b/test/integration/targets/playbook/vars_files_string.yml @@ -0,0 +1,6 @@ +- hosts: localhost + vars_files: some_vars.yml + tasks: + - assert: + that: + - 'a_variable == "yep"' diff --git a/test/integration/targets/playbook/vars_prompt_null.yml b/test/integration/targets/playbook/vars_prompt_null.yml new file mode 100644 index 00000000..4fdfa7c1 --- /dev/null +++ b/test/integration/targets/playbook/vars_prompt_null.yml @@ -0,0 +1,3 @@ +- name: null vars prompt is okay + hosts: localhost + vars_prompt: null diff --git a/test/integration/targets/plugin_config_for_inventory/aliases b/test/integration/targets/plugin_config_for_inventory/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/plugin_config_for_inventory/aliases +++ b/test/integration/targets/plugin_config_for_inventory/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/plugin_filtering/aliases b/test/integration/targets/plugin_filtering/aliases index 3005e4b2..498fedd5 100644 --- a/test/integration/targets/plugin_filtering/aliases +++ b/test/integration/targets/plugin_filtering/aliases @@ -1 +1,2 @@ shippable/posix/group4 +context/controller diff --git a/test/integration/targets/plugin_loader/aliases b/test/integration/targets/plugin_loader/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/plugin_loader/aliases +++ b/test/integration/targets/plugin_loader/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/plugin_namespace/aliases b/test/integration/targets/plugin_namespace/aliases index a6dafcf8..13e01f0c 100644 --- a/test/integration/targets/plugin_namespace/aliases +++ b/test/integration/targets/plugin_namespace/aliases @@ -1 +1,2 @@ shippable/posix/group1 +context/controller diff --git a/test/integration/targets/prepare_http_tests/tasks/kerberos.yml b/test/integration/targets/prepare_http_tests/tasks/kerberos.yml index 06feea1c..2678b468 100644 --- a/test/integration/targets/prepare_http_tests/tasks/kerberos.yml +++ b/test/integration/targets/prepare_http_tests/tasks/kerberos.yml @@ -38,7 +38,9 @@ - name: Install python gssapi pip: name: - - gssapi + - decorator < 5.0.0 ; python_version < '3.5' # decorator 5.0.5 and later require python 3.5 or later + - gssapi < 1.6.0 ; python_version <= '2.7' # gssapi 1.6.0 and later require python 3 or later + - gssapi ; python_version > '2.7' - importlib ; python_version < '2.7' state: present extra_args: '-c {{ remote_constraints }}' diff --git a/test/integration/targets/rel_plugin_loading/aliases b/test/integration/targets/rel_plugin_loading/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/rel_plugin_loading/aliases +++ b/test/integration/targets/rel_plugin_loading/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/remote_tmp/aliases b/test/integration/targets/remote_tmp/aliases index 757c9966..4b8559d9 100644 --- a/test/integration/targets/remote_tmp/aliases +++ b/test/integration/targets/remote_tmp/aliases @@ -1,2 +1,4 @@ shippable/posix/group3 skip/aix +context/target +needs/target/setup_remote_tmp_dir diff --git a/test/integration/targets/remote_tmp/playbook.yml b/test/integration/targets/remote_tmp/playbook.yml index 43f99ca5..5adef626 100644 --- a/test/integration/targets/remote_tmp/playbook.yml +++ b/test/integration/targets/remote_tmp/playbook.yml @@ -31,13 +31,16 @@ hosts: testhost gather_facts: false tasks: + - import_role: + name: ../setup_remote_tmp_dir + - file: state: touch - path: "{{ output_dir }}/65393" + path: "{{ remote_tmp_dir }}/65393" - copy: - src: "{{ output_dir }}/65393" - dest: "{{ output_dir }}/65393.2" + src: "{{ remote_tmp_dir }}/65393" + dest: "{{ remote_tmp_dir }}/65393.2" remote_src: true - find: @@ -52,6 +55,5 @@ - assert: that: - # Should only be AnsiballZ_find.py because find is actively running - - result.files|length == 1 - - result.files[0].path.endswith('/AnsiballZ_find.py') + # Should find nothing since pipelining is used + - result.files|length == 0 diff --git a/test/integration/targets/remote_tmp/runme.sh b/test/integration/targets/remote_tmp/runme.sh index 8d1eebd6..69efd6e0 100755 --- a/test/integration/targets/remote_tmp/runme.sh +++ b/test/integration/targets/remote_tmp/runme.sh @@ -2,4 +2,4 @@ set -ux -ansible-playbook -i ../../inventory playbook.yml -e "output_dir=${OUTPUT_DIR}" -v "$@" +ansible-playbook -i ../../inventory playbook.yml -v "$@" diff --git a/test/integration/targets/retry_task_name_in_callback/aliases b/test/integration/targets/retry_task_name_in_callback/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/retry_task_name_in_callback/aliases +++ b/test/integration/targets/retry_task_name_in_callback/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/roles/aliases b/test/integration/targets/roles/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/roles/aliases +++ b/test/integration/targets/roles/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/roles/no_dupes.yml b/test/integration/targets/roles/no_dupes.yml index 0ac9ff94..7e1ecb15 100644 --- a/test/integration/targets/roles/no_dupes.yml +++ b/test/integration/targets/roles/no_dupes.yml @@ -17,3 +17,13 @@ tasks: - name: execute role c which depends on a import_role: name=c + +- name: play should only show 1 invocation of a, as dependencies in this play are deduped by include_role + hosts: testhost + gather_facts: false + tags: [ 'intasks' ] + tasks: + - name: execute role b which depends on a + include_role: name=b + - name: execute role c which also depends on a + include_role: name=c diff --git a/test/integration/targets/roles/runme.sh b/test/integration/targets/roles/runme.sh index f2058ff1..5f11c1fc 100755 --- a/test/integration/targets/roles/runme.sh +++ b/test/integration/targets/roles/runme.sh @@ -5,9 +5,10 @@ set -eux # test no dupes when dependencies in b and c point to a in roles: [ "$(ansible-playbook no_dupes.yml -i ../../inventory --tags inroles "$@" | grep -c '"msg": "A"')" = "1" ] [ "$(ansible-playbook no_dupes.yml -i ../../inventory --tags acrossroles "$@" | grep -c '"msg": "A"')" = "1" ] +[ "$(ansible-playbook no_dupes.yml -i ../../inventory --tags intasks "$@" | grep -c '"msg": "A"')" = "1" ] # but still dupe across plays -[ "$(ansible-playbook no_dupes.yml -i ../../inventory "$@" | grep -c '"msg": "A"')" = "2" ] +[ "$(ansible-playbook no_dupes.yml -i ../../inventory "$@" | grep -c '"msg": "A"')" = "3" ] # include/import can execute another instance of role [ "$(ansible-playbook allowed_dupes.yml -i ../../inventory --tags importrole "$@" | grep -c '"msg": "A"')" = "2" ] diff --git a/test/integration/targets/roles_arg_spec/aliases b/test/integration/targets/roles_arg_spec/aliases index 70a7b7a9..1d28bdb2 100644 --- a/test/integration/targets/roles_arg_spec/aliases +++ b/test/integration/targets/roles_arg_spec/aliases @@ -1 +1,2 @@ shippable/posix/group5 +context/controller diff --git a/test/integration/targets/roles_var_inheritance/aliases b/test/integration/targets/roles_var_inheritance/aliases new file mode 100644 index 00000000..1d28bdb2 --- /dev/null +++ b/test/integration/targets/roles_var_inheritance/aliases @@ -0,0 +1,2 @@ +shippable/posix/group5 +context/controller diff --git a/test/integration/targets/roles_var_inheritance/play.yml b/test/integration/targets/roles_var_inheritance/play.yml new file mode 100644 index 00000000..170eef57 --- /dev/null +++ b/test/integration/targets/roles_var_inheritance/play.yml @@ -0,0 +1,4 @@ +- hosts: localhost + roles: + - A + - B diff --git a/test/integration/targets/roles_var_inheritance/roles/A/meta/main.yml b/test/integration/targets/roles_var_inheritance/roles/A/meta/main.yml new file mode 100644 index 00000000..0e99e981 --- /dev/null +++ b/test/integration/targets/roles_var_inheritance/roles/A/meta/main.yml @@ -0,0 +1,4 @@ +dependencies: + - role: common_dep + vars: + test_var: A diff --git a/test/integration/targets/roles_var_inheritance/roles/B/meta/main.yml b/test/integration/targets/roles_var_inheritance/roles/B/meta/main.yml new file mode 100644 index 00000000..4da17403 --- /dev/null +++ b/test/integration/targets/roles_var_inheritance/roles/B/meta/main.yml @@ -0,0 +1,4 @@ +dependencies: + - role: common_dep + vars: + test_var: B diff --git a/test/integration/targets/roles_var_inheritance/roles/child_nested_dep/vars/main.yml b/test/integration/targets/roles_var_inheritance/roles/child_nested_dep/vars/main.yml new file mode 100644 index 00000000..6723fa07 --- /dev/null +++ b/test/integration/targets/roles_var_inheritance/roles/child_nested_dep/vars/main.yml @@ -0,0 +1 @@ +var_precedence: dependency diff --git a/test/integration/targets/roles_var_inheritance/roles/common_dep/meta/main.yml b/test/integration/targets/roles_var_inheritance/roles/common_dep/meta/main.yml new file mode 100644 index 00000000..1ede7be8 --- /dev/null +++ b/test/integration/targets/roles_var_inheritance/roles/common_dep/meta/main.yml @@ -0,0 +1,4 @@ +dependencies: + - role: nested_dep + vars: + nested_var: "{{ test_var }}" diff --git a/test/integration/targets/roles_var_inheritance/roles/common_dep/vars/main.yml b/test/integration/targets/roles_var_inheritance/roles/common_dep/vars/main.yml new file mode 100644 index 00000000..87b6b580 --- /dev/null +++ b/test/integration/targets/roles_var_inheritance/roles/common_dep/vars/main.yml @@ -0,0 +1 @@ +var_precedence: parent diff --git a/test/integration/targets/roles_var_inheritance/roles/nested_dep/meta/main.yml b/test/integration/targets/roles_var_inheritance/roles/nested_dep/meta/main.yml new file mode 100644 index 00000000..231c6c14 --- /dev/null +++ b/test/integration/targets/roles_var_inheritance/roles/nested_dep/meta/main.yml @@ -0,0 +1,3 @@ +allow_duplicates: yes +dependencies: + - child_nested_dep diff --git a/test/integration/targets/roles_var_inheritance/roles/nested_dep/tasks/main.yml b/test/integration/targets/roles_var_inheritance/roles/nested_dep/tasks/main.yml new file mode 100644 index 00000000..c69070ca --- /dev/null +++ b/test/integration/targets/roles_var_inheritance/roles/nested_dep/tasks/main.yml @@ -0,0 +1,5 @@ +- debug: + var: nested_var + +- debug: + var: var_precedence diff --git a/test/integration/targets/roles_var_inheritance/runme.sh b/test/integration/targets/roles_var_inheritance/runme.sh new file mode 100755 index 00000000..791155a8 --- /dev/null +++ b/test/integration/targets/roles_var_inheritance/runme.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +set -eux + +ansible-playbook -i ../../inventory play.yml "$@" | tee out.txt + +test "$(grep out.txt -ce '"nested_var": "A"')" == 1 +test "$(grep out.txt -ce '"nested_var": "B"')" == 1 +test "$(grep out.txt -ce '"var_precedence": "dependency"')" == 2 diff --git a/test/integration/targets/rpm_key/tasks/main.yaml b/test/integration/targets/rpm_key/tasks/main.yaml index 9f6fd4ec..6f71ca6e 100644 --- a/test/integration/targets/rpm_key/tasks/main.yaml +++ b/test/integration/targets/rpm_key/tasks/main.yaml @@ -1,2 +1,2 @@ - - include: 'rpm_key.yaml' + - include_tasks: 'rpm_key.yaml' when: ansible_os_family == "RedHat" diff --git a/test/integration/targets/run_modules/aliases b/test/integration/targets/run_modules/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/run_modules/aliases +++ b/test/integration/targets/run_modules/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/set_fact/aliases b/test/integration/targets/set_fact/aliases index 757c9966..10179323 100644 --- a/test/integration/targets/set_fact/aliases +++ b/test/integration/targets/set_fact/aliases @@ -1,2 +1,2 @@ shippable/posix/group3 -skip/aix +context/controller # this is a controller-only action, the module is just for documentation diff --git a/test/integration/targets/set_fact/runme.sh b/test/integration/targets/set_fact/runme.sh index 781894a0..93093599 100755 --- a/test/integration/targets/set_fact/runme.sh +++ b/test/integration/targets/set_fact/runme.sh @@ -31,3 +31,6 @@ ANSIBLE_JINJA2_NATIVE=1 ansible-playbook -v set_fact_bool_conv_jinja2_native.yml # Test parsing of values when using an empty string as a key ansible-playbook -i inventory set_fact_empty_str_key.yml + +# https://github.com/ansible/ansible/issues/21088 +ansible-playbook -i inventory "$@" set_fact_auto_unsafe.yml diff --git a/test/integration/targets/set_fact/set_fact_auto_unsafe.yml b/test/integration/targets/set_fact/set_fact_auto_unsafe.yml new file mode 100644 index 00000000..b0fb4dcf --- /dev/null +++ b/test/integration/targets/set_fact/set_fact_auto_unsafe.yml @@ -0,0 +1,10 @@ +- hosts: localhost + gather_facts: false + tasks: + - set_fact: + foo: bar + register: baz + + - assert: + that: + - baz.ansible_facts.foo|type_debug != "AnsibleUnsafeText" diff --git a/test/integration/targets/set_stats/aliases b/test/integration/targets/set_stats/aliases new file mode 100644 index 00000000..a1b27a83 --- /dev/null +++ b/test/integration/targets/set_stats/aliases @@ -0,0 +1,2 @@ +shippable/posix/group5 +context/controller # this is a controller-only action, the module is just for documentation diff --git a/test/integration/targets/set_stats/runme.sh b/test/integration/targets/set_stats/runme.sh new file mode 100755 index 00000000..27193dc8 --- /dev/null +++ b/test/integration/targets/set_stats/runme.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +set -eux + +export ANSIBLE_SHOW_CUSTOM_STATS=yes + +# Simple tests +ansible-playbook test_simple.yml -i "${INVENTORY_PATH}" + +# This playbook does two set_stats calls setting my_int to 10 and 15. +# The aggregated output should add to 25. +output=$(ansible-playbook test_aggregate.yml -i "${INVENTORY_PATH}" | grep -c '"my_int": 25') +test "$output" -eq 1 diff --git a/test/integration/targets/set_stats/test_aggregate.yml b/test/integration/targets/set_stats/test_aggregate.yml new file mode 100644 index 00000000..7f12895d --- /dev/null +++ b/test/integration/targets/set_stats/test_aggregate.yml @@ -0,0 +1,13 @@ +--- +- hosts: testhost + gather_facts: false + tasks: + - name: First set_stats + set_stats: + data: + my_int: 10 + + - name: Second set_stats + set_stats: + data: + my_int: 15 diff --git a/test/integration/targets/set_stats/test_simple.yml b/test/integration/targets/set_stats/test_simple.yml new file mode 100644 index 00000000..0f62120d --- /dev/null +++ b/test/integration/targets/set_stats/test_simple.yml @@ -0,0 +1,79 @@ +--- +- hosts: testhost + gather_facts: false + tasks: + - name: test simple data with defaults + set_stats: + data: + my_int: 42 + my_string: "foo" + register: result + + - name: assert simple data return + assert: + that: + - result is succeeded + - not result.changed + - '"ansible_stats" in result' + - '"data" in result.ansible_stats' + - result.ansible_stats.data.my_int == 42 + - result.ansible_stats.data.my_string == "foo" + - '"per_host" in result.ansible_stats' + - not result.ansible_stats.per_host + - '"aggregate" in result.ansible_stats' + - result.ansible_stats.aggregate + + - name: test per_host and aggregate settings + set_stats: + data: + my_int: 42 + per_host: yes + aggregate: no + register: result + + - name: assert per_host and aggregate changes + assert: + that: + - result is succeeded + - not result.changed + - '"ansible_stats" in result' + - '"per_host" in result.ansible_stats' + - result.ansible_stats.per_host + - '"aggregate" in result.ansible_stats' + - not result.ansible_stats.aggregate + + - name: Test bad call + block: + - name: "EXPECTED FAILURE - test invalid data type" + set_stats: + data: + - 1 + - 2 + + - fail: + msg: "should not get here" + rescue: + - assert: + that: + - ansible_failed_task.name == "EXPECTED FAILURE - test invalid data type" + - ansible_failed_result.msg == "The 'data' option needs to be a dictionary/hash" + + - name: Test options from template + set_stats: + data: + my_string: "foo" + aggregate: "x" + + - name: Test bad data + block: + - name: "EXPECTED FAILURE - bad data" + set_stats: + data: + .bad: 1 + - fail: + msg: "should not get here" + rescue: + - assert: + that: + - ansible_failed_task.name == "EXPECTED FAILURE - bad data" + - ansible_failed_result.msg == "The variable name '.bad' is not valid. Variables must start with a letter or underscore character, and contain only letters, numbers and underscores." diff --git a/test/integration/targets/setup_cron/defaults/main.yml b/test/integration/targets/setup_cron/defaults/main.yml index e4b0123d..a6d1965f 100644 --- a/test/integration/targets/setup_cron/defaults/main.yml +++ b/test/integration/targets/setup_cron/defaults/main.yml @@ -1 +1 @@ -remote_dir: "{{ lookup('env', 'OUTPUT_DIR') }}" +remote_dir: "{{ remote_tmp_dir }}" diff --git a/test/integration/targets/setup_cron/meta/main.yml b/test/integration/targets/setup_cron/meta/main.yml new file mode 100644 index 00000000..1810d4be --- /dev/null +++ b/test/integration/targets/setup_cron/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - setup_remote_tmp_dir diff --git a/test/integration/targets/setup_cron/tasks/main.yml b/test/integration/targets/setup_cron/tasks/main.yml index c5a988e0..d7ce3303 100644 --- a/test/integration/targets/setup_cron/tasks/main.yml +++ b/test/integration/targets/setup_cron/tasks/main.yml @@ -82,3 +82,15 @@ FAKETIME: "+0y x10" LD_PRELOAD: "/usr/lib/faketime/libfaketime.so.1" when: ansible_distribution == 'Alpine' + +- name: See if /etc/pam.d/crond exists + stat: + path: /etc/pam.d/crond + register: pamd + +# https://github.com/lxc/lxc/issues/661#issuecomment-222444916 +# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=726661 +- name: Work around containers not being able to write to /proc/self/loginuid + command: sed -i '/pam_loginuid\.so$/ s/required/optional/' /etc/pam.d/crond + when: + - pamd.stat.exists diff --git a/test/integration/targets/setup_paramiko/install-FreeBSD-11-python-2.yml b/test/integration/targets/setup_paramiko/install-FreeBSD-11-python-2.yml deleted file mode 100644 index dec5b548..00000000 --- a/test/integration/targets/setup_paramiko/install-FreeBSD-11-python-2.yml +++ /dev/null @@ -1,3 +0,0 @@ -- name: Install Paramiko for Python 2 on FreeBSD 11 - pkgng: - name: py27-paramiko diff --git a/test/integration/targets/setup_paramiko/install-FreeBSD-11-python-3.yml b/test/integration/targets/setup_paramiko/install-FreeBSD-11-python-3.yml deleted file mode 100644 index eb01d00f..00000000 --- a/test/integration/targets/setup_paramiko/install-FreeBSD-11-python-3.yml +++ /dev/null @@ -1,12 +0,0 @@ -- name: Downgrade to pip version 18.1 to work around a PEP 517 virtualenv bug - # pip 19.0.0 added support for PEP 517 - # versions as recent as 19.0.3 fail to install paramiko in a virtualenv due to a BackendUnavailable exception - # installation without a virtualenv succeeds - pip: - name: pip==18.1 -- name: Setup remote constraints - include_tasks: setup-remote-constraints.yml -- name: Install Paramiko for Python 3 on FreeBSD 11 - pip: # no py36-paramiko package exists for FreeBSD 11 - name: paramiko - extra_args: "-c {{ remote_constraints }}" diff --git a/test/integration/targets/setup_paramiko/install-FreeBSD-11.4-python-3.yml b/test/integration/targets/setup_paramiko/install-FreeBSD-11.4-python-3.yml deleted file mode 100644 index 9a7bfb67..00000000 --- a/test/integration/targets/setup_paramiko/install-FreeBSD-11.4-python-3.yml +++ /dev/null @@ -1,3 +0,0 @@ -- name: Install Paramiko for Python 3 on FreeBSD 11.4 - pkgng: - name: py37-paramiko diff --git a/test/integration/targets/setup_paramiko/install-FreeBSD-12-python-2.yml b/test/integration/targets/setup_paramiko/install-FreeBSD-12-python-2.yml deleted file mode 100644 index 29e78969..00000000 --- a/test/integration/targets/setup_paramiko/install-FreeBSD-12-python-2.yml +++ /dev/null @@ -1,3 +0,0 @@ -- name: Install Paramiko for Python 2 on FreeBSD 12 - pkgng: - name: py27-paramiko diff --git a/test/integration/targets/setup_paramiko/install-FreeBSD-12-python-3.yml b/test/integration/targets/setup_paramiko/install-FreeBSD-12-python-3.yml deleted file mode 100644 index 2aa7b500..00000000 --- a/test/integration/targets/setup_paramiko/install-FreeBSD-12-python-3.yml +++ /dev/null @@ -1,3 +0,0 @@ -- name: Install Paramiko for Python 3 on FreeBSD 12 - pkgng: - name: py36-paramiko diff --git a/test/integration/targets/setup_paramiko/install-FreeBSD-12.2-python-3.yml b/test/integration/targets/setup_paramiko/install-FreeBSD-12.2-python-3.yml deleted file mode 100644 index 4fe6011b..00000000 --- a/test/integration/targets/setup_paramiko/install-FreeBSD-12.2-python-3.yml +++ /dev/null @@ -1,3 +0,0 @@ -- name: Install Paramiko for Python 3 on FreeBSD 12.2 - pkgng: - name: py37-paramiko diff --git a/test/integration/targets/setup_paramiko/install-FreeBSD-python-3.yml b/test/integration/targets/setup_paramiko/install-FreeBSD-python-3.yml new file mode 100644 index 00000000..27daf3cf --- /dev/null +++ b/test/integration/targets/setup_paramiko/install-FreeBSD-python-3.yml @@ -0,0 +1,6 @@ +- name: Setup remote constraints + include_tasks: setup-remote-constraints.yml +- name: Install Paramiko for Python 3 on FreeBSD + pip: # no package in pkg, just use pip + name: paramiko + extra_args: "-c {{ remote_constraints }}" diff --git a/test/integration/targets/setup_paramiko/uninstall-FreeBSD-11-python-2.yml b/test/integration/targets/setup_paramiko/uninstall-FreeBSD-11-python-2.yml deleted file mode 100644 index d27f831c..00000000 --- a/test/integration/targets/setup_paramiko/uninstall-FreeBSD-11-python-2.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: Uninstall Paramiko for Python 2 on FreeBSD 11 - pkgng: - name: py27-paramiko - state: absent diff --git a/test/integration/targets/setup_paramiko/uninstall-FreeBSD-11-python-3.yml b/test/integration/targets/setup_paramiko/uninstall-FreeBSD-11-python-3.yml deleted file mode 100644 index 33f292e8..00000000 --- a/test/integration/targets/setup_paramiko/uninstall-FreeBSD-11-python-3.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: Uninstall Paramiko for Python 3 on FreeBSD 11 - pip: # no py36-paramiko package exists for FreeBSD 11 - name: paramiko - state: absent diff --git a/test/integration/targets/setup_paramiko/uninstall-FreeBSD-11.4-python-3.yml b/test/integration/targets/setup_paramiko/uninstall-FreeBSD-11.4-python-3.yml deleted file mode 100644 index 86956fd9..00000000 --- a/test/integration/targets/setup_paramiko/uninstall-FreeBSD-11.4-python-3.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: Uninstall Paramiko for Python 3 on FreeBSD 11.4 - pkgng: - name: py37-paramiko - state: absent diff --git a/test/integration/targets/setup_paramiko/uninstall-FreeBSD-12-python-2.yml b/test/integration/targets/setup_paramiko/uninstall-FreeBSD-12-python-2.yml deleted file mode 100644 index 79352487..00000000 --- a/test/integration/targets/setup_paramiko/uninstall-FreeBSD-12-python-2.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: Uninstall Paramiko for Python 2 on FreeBSD 12 - pkgng: - name: py27-paramiko - state: absent diff --git a/test/integration/targets/setup_paramiko/uninstall-FreeBSD-12-python-3.yml b/test/integration/targets/setup_paramiko/uninstall-FreeBSD-12-python-3.yml deleted file mode 100644 index 46d26ca3..00000000 --- a/test/integration/targets/setup_paramiko/uninstall-FreeBSD-12-python-3.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: Uninstall Paramiko for Python 3 on FreeBSD 12 - pkgng: - name: py36-paramiko - state: absent diff --git a/test/integration/targets/setup_paramiko/uninstall-FreeBSD-12.2-python-3.yml b/test/integration/targets/setup_paramiko/uninstall-FreeBSD-12.2-python-3.yml deleted file mode 100644 index 0359bf4c..00000000 --- a/test/integration/targets/setup_paramiko/uninstall-FreeBSD-12.2-python-3.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: Uninstall Paramiko for Python 3 on FreeBSD 12.2 - pkgng: - name: py37-paramiko - state: absent diff --git a/test/integration/targets/setup_paramiko/uninstall-FreeBSD-python-3.yml b/test/integration/targets/setup_paramiko/uninstall-FreeBSD-python-3.yml new file mode 100644 index 00000000..d3d3739b --- /dev/null +++ b/test/integration/targets/setup_paramiko/uninstall-FreeBSD-python-3.yml @@ -0,0 +1,4 @@ +- name: Uninstall Paramiko for Python 3 on FreeBSD + pip: + name: paramiko + state: absent diff --git a/test/integration/targets/setup_remote_tmp_dir/defaults/main.yml b/test/integration/targets/setup_remote_tmp_dir/defaults/main.yml new file mode 100644 index 00000000..3375fdf9 --- /dev/null +++ b/test/integration/targets/setup_remote_tmp_dir/defaults/main.yml @@ -0,0 +1,2 @@ +setup_remote_tmp_dir_skip_cleanup: no +setup_remote_tmp_dir_cache_path: no diff --git a/test/integration/targets/setup_remote_tmp_dir/handlers/main.yml b/test/integration/targets/setup_remote_tmp_dir/handlers/main.yml index 229037c8..3c5b14f2 100644 --- a/test/integration/targets/setup_remote_tmp_dir/handlers/main.yml +++ b/test/integration/targets/setup_remote_tmp_dir/handlers/main.yml @@ -1,5 +1,7 @@ - name: delete temporary directory include_tasks: default-cleanup.yml + when: not setup_remote_tmp_dir_skip_cleanup | bool - name: delete temporary directory (windows) include_tasks: windows-cleanup.yml + when: not setup_remote_tmp_dir_skip_cleanup | bool diff --git a/test/integration/targets/setup_remote_tmp_dir/tasks/default.yml b/test/integration/targets/setup_remote_tmp_dir/tasks/default.yml index 1e0f51b8..3be42eff 100644 --- a/test/integration/targets/setup_remote_tmp_dir/tasks/default.yml +++ b/test/integration/targets/setup_remote_tmp_dir/tasks/default.yml @@ -9,3 +9,4 @@ - name: record temporary directory set_fact: remote_tmp_dir: "{{ remote_tmp_dir.path }}" + cacheable: "{{ setup_remote_tmp_dir_cache_path | bool }}" diff --git a/test/integration/targets/setup_rpm_repo/files/create-repo.py b/test/integration/targets/setup_rpm_repo/files/create-repo.py deleted file mode 100644 index a4d10140..00000000 --- a/test/integration/targets/setup_rpm_repo/files/create-repo.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python - -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -import sys -from collections import namedtuple - -try: - from rpmfluff import SimpleRpmBuild - from rpmfluff import YumRepoBuild -except ImportError: - from rpmfluff.rpmbuild import SimpleRpmBuild - from rpmfluff.yumrepobuild import YumRepoBuild - -try: - from rpmfluff import can_use_rpm_weak_deps -except ImportError: - try: - from rpmfluff.utils import can_use_rpm_weak_deps - except ImportError: - can_use_rpm_weak_deps = None - -RPM = namedtuple('RPM', ['name', 'version', 'release', 'epoch', 'recommends']) - - -SPECS = [ - RPM('dinginessentail', '1.0', '1', None, None), - RPM('dinginessentail', '1.0', '2', '1', None), - RPM('dinginessentail', '1.1', '1', '1', None), - RPM('dinginessentail-olive', '1.0', '1', None, None), - RPM('dinginessentail-olive', '1.1', '1', None, None), - RPM('landsidescalping', '1.0', '1', None, None), - RPM('landsidescalping', '1.1', '1', None, None), - RPM('dinginessentail-with-weak-dep', '1.0', '1', None, ['dinginessentail-weak-dep']), - RPM('dinginessentail-weak-dep', '1.0', '1', None, None), -] - - -def main(): - try: - arch = sys.argv[1] - except IndexError: - arch = 'x86_64' - - pkgs = [] - for spec in SPECS: - pkg = SimpleRpmBuild(spec.name, spec.version, spec.release, [arch]) - pkg.epoch = spec.epoch - - if spec.recommends: - # Skip packages that require weak deps but an older version of RPM is being used - if not can_use_rpm_weak_deps or not can_use_rpm_weak_deps(): - continue - - for recommend in spec.recommends: - pkg.add_recommends(recommend) - - pkgs.append(pkg) - - repo = YumRepoBuild(pkgs) - repo.make(arch) - - for pkg in pkgs: - pkg.clean() - - print(repo.repoDir) - - -if __name__ == "__main__": - main() diff --git a/test/integration/targets/special_vars/aliases b/test/integration/targets/special_vars/aliases index 2d9e6788..55b8ec06 100644 --- a/test/integration/targets/special_vars/aliases +++ b/test/integration/targets/special_vars/aliases @@ -1,2 +1,3 @@ shippable/posix/group2 needs/target/include_parent_role_vars +context/controller diff --git a/test/integration/targets/special_vars_hosts/aliases b/test/integration/targets/special_vars_hosts/aliases new file mode 100644 index 00000000..1d28bdb2 --- /dev/null +++ b/test/integration/targets/special_vars_hosts/aliases @@ -0,0 +1,2 @@ +shippable/posix/group5 +context/controller diff --git a/test/integration/targets/special_vars_hosts/inventory b/test/integration/targets/special_vars_hosts/inventory new file mode 100644 index 00000000..8d69e574 --- /dev/null +++ b/test/integration/targets/special_vars_hosts/inventory @@ -0,0 +1,3 @@ +successful ansible_connection=local ansible_host=127.0.0.1 ansible_python_interpreter="{{ ansible_playbook_python }}" +failed ansible_connection=local ansible_host=127.0.0.1 ansible_python_interpreter="{{ ansible_playbook_python }}" +unreachable ansible_connection=ssh ansible_host=127.0.0.1 ansible_port=1011 # IANA Reserved port diff --git a/test/integration/targets/special_vars_hosts/playbook.yml b/test/integration/targets/special_vars_hosts/playbook.yml new file mode 100644 index 00000000..e3d9e435 --- /dev/null +++ b/test/integration/targets/special_vars_hosts/playbook.yml @@ -0,0 +1,53 @@ +--- +- hosts: all + gather_facts: no + tasks: + - name: test magic vars for hosts without any failed/unreachable (no serial) + assert: + that: + - ansible_play_batch | length == 3 + - ansible_play_hosts | length == 3 + - ansible_play_hosts_all | length == 3 + run_once: True + + - ping: + failed_when: "inventory_hostname == 'failed'" + + - meta: clear_host_errors + +- hosts: all + gather_facts: no + tasks: + - name: test host errors were cleared + assert: + that: + - ansible_play_batch | length == 3 + - ansible_play_hosts | length == 3 + - ansible_play_hosts_all | length == 3 + run_once: True + + - ping: + failed_when: "inventory_hostname == 'failed'" + + - name: test magic vars exclude failed/unreachable hosts + assert: + that: + - ansible_play_batch | length == 1 + - ansible_play_hosts | length == 1 + - "ansible_play_batch == ['successful']" + - "ansible_play_hosts == ['successful']" + - ansible_play_hosts_all | length == 3 + run_once: True + +- hosts: all + gather_facts: no + tasks: + - name: test failed/unreachable persists between plays + assert: + that: + - ansible_play_batch | length == 1 + - ansible_play_hosts | length == 1 + - "ansible_play_batch == ['successful']" + - "ansible_play_hosts == ['successful']" + - ansible_play_hosts_all | length == 3 + run_once: True diff --git a/test/integration/targets/special_vars_hosts/runme.sh b/test/integration/targets/special_vars_hosts/runme.sh new file mode 100755 index 00000000..81c1d9be --- /dev/null +++ b/test/integration/targets/special_vars_hosts/runme.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -eux + +ansible-playbook -i ./inventory playbook.yml "$@" | tee out.txt +grep 'unreachable=2' out.txt +grep 'failed=2' out.txt diff --git a/test/integration/targets/split/aliases b/test/integration/targets/split/aliases new file mode 100644 index 00000000..87958830 --- /dev/null +++ b/test/integration/targets/split/aliases @@ -0,0 +1,2 @@ +context/target +shippable/posix/group1 diff --git a/test/integration/targets/split/tasks/main.yml b/test/integration/targets/split/tasks/main.yml new file mode 100644 index 00000000..ead1c536 --- /dev/null +++ b/test/integration/targets/split/tasks/main.yml @@ -0,0 +1,30 @@ +- name: Get control host details + setup: + delegate_to: localhost + register: control_host +- name: Get managed host details + setup: + register: managed_host +- name: Check split state + stat: + path: "{{ output_dir }}" + register: split + ignore_errors: yes +- name: Build non-split status message + set_fact: + message: " + {{ control_host.ansible_facts.ansible_distribution }} {{ control_host.ansible_facts.ansible_distribution_version }} + {{ control_host.ansible_facts.ansible_python.executable }} ({{ control_host.ansible_facts.ansible_python_version }}) -> + {{ managed_host.ansible_facts.ansible_python.executable }} ({{ managed_host.ansible_facts.ansible_python_version }})" + when: split is success and split.stat.exists +- name: Build split status message + set_fact: + message: " + {{ control_host.ansible_facts.ansible_distribution }} {{ control_host.ansible_facts.ansible_distribution_version }} + {{ control_host.ansible_facts.ansible_python.executable }} ({{ control_host.ansible_facts.ansible_python_version }}) -> + {{ managed_host.ansible_facts.ansible_distribution }} {{ managed_host.ansible_facts.ansible_distribution_version }} + {{ managed_host.ansible_facts.ansible_python.executable }} ({{ managed_host.ansible_facts.ansible_python_version }})" + when: split is not success or not split.stat.exists +- name: Show host details + debug: + msg: "{{ message }}" diff --git a/test/integration/targets/subversion/roles/subversion/defaults/main.yml b/test/integration/targets/subversion/roles/subversion/defaults/main.yml index f989345a..e647d598 100644 --- a/test/integration/targets/subversion/roles/subversion/defaults/main.yml +++ b/test/integration/targets/subversion/roles/subversion/defaults/main.yml @@ -1,11 +1,10 @@ --- apache_port: 11386 # cannot use 80 as httptester overrides this -output_dir: "{{ lookup('env', 'OUTPUT_DIR') }}" -subversion_test_dir: '{{ output_dir }}/svn-test' +subversion_test_dir: /tmp/ansible-svn-test-dir subversion_server_dir: /tmp/ansible-svn # cannot use a path in the home dir without userdir or granting exec permission to the apache user subversion_repo_name: ansible-test-repo subversion_repo_url: http://127.0.0.1:{{ apache_port }}/svn/{{ subversion_repo_name }} subversion_repo_auth_url: http://127.0.0.1:{{ apache_port }}/svnauth/{{ subversion_repo_name }} subversion_username: subsvn_user''' subversion_password: Password123! -subversion_external_repo_url: https://github.com/ansible/ansible-base-test-container # GitHub serves SVN +subversion_external_repo_url: https://github.com/ansible/ansible.github.com # GitHub serves SVN diff --git a/test/integration/targets/subversion/roles/subversion/tasks/setup.yml b/test/integration/targets/subversion/roles/subversion/tasks/setup.yml index cab9151a..3cf5af56 100644 --- a/test/integration/targets/subversion/roles/subversion/tasks/setup.yml +++ b/test/integration/targets/subversion/roles/subversion/tasks/setup.yml @@ -44,13 +44,6 @@ chdir: '{{ subversion_server_dir }}' creates: '{{ subversion_server_dir }}/{{ subversion_repo_name }}' -- name: apply ownership for all SVN directories - file: - path: '{{ subversion_server_dir }}' - owner: '{{ apache_user }}' - group: '{{ apache_group }}' - recurse: True - - name: add test user to htpasswd for Subversion site htpasswd: path: '{{ subversion_server_dir }}/svn-auth-users' @@ -58,11 +51,22 @@ password: '{{ subversion_password }}' state: present +- name: apply ownership for all SVN directories + file: + path: '{{ subversion_server_dir }}' + owner: '{{ apache_user }}' + group: '{{ apache_group }}' + recurse: True + - name: start test Apache SVN site - non Red Hat command: apachectl -k start -f {{ subversion_server_dir }}/subversion.conf + async: 3600 # We kill apache manually in the clean up phase + poll: 0 when: ansible_os_family not in ['RedHat', 'Alpine'] # On Red Hat based OS', we can't use apachectl to start up own instance, just use the raw httpd - name: start test Apache SVN site - Red Hat command: httpd -k start -f {{ subversion_server_dir }}/subversion.conf + async: 3600 # We kill apache manually in the clean up phase + poll: 0 when: ansible_os_family in ['RedHat', 'Alpine'] diff --git a/test/integration/targets/subversion/runme.sh b/test/integration/targets/subversion/runme.sh index f505e581..c39bdc00 100755 --- a/test/integration/targets/subversion/runme.sh +++ b/test/integration/targets/subversion/runme.sh @@ -4,7 +4,7 @@ set -eu cleanup() { echo "Cleanup" - ansible-playbook runme.yml -e "output_dir=${OUTPUT_DIR}" "$@" --tags cleanup + ansible-playbook runme.yml -i "${INVENTORY_PATH}" "$@" --tags cleanup echo "Done" } @@ -13,16 +13,19 @@ trap cleanup INT TERM EXIT export ANSIBLE_ROLES_PATH=roles/ # Ensure subversion is set up -ansible-playbook runme.yml "$@" -v --tags setup +ansible-playbook runme.yml -i "${INVENTORY_PATH}" "$@" -v --tags setup # Test functionality -ansible-playbook runme.yml "$@" -v --tags tests +ansible-playbook runme.yml -i "${INVENTORY_PATH}" "$@" -v --tags tests # Test a warning is displayed for versions < 1.10.0 when a password is provided -ansible-playbook runme.yml "$@" --tags warnings 2>&1 | tee out.txt +ansible-playbook runme.yml -i "${INVENTORY_PATH}" "$@" --tags warnings 2>&1 | tee out.txt -version="$(svn --version -q)" -secure=$(python -c "from distutils.version import LooseVersion; print(LooseVersion('$version') >= LooseVersion('1.10.0'))") +version=$(ANSIBLE_FORCE_COLOR=0 ansible -i "${INVENTORY_PATH}" -m shell -a 'svn --version -q' testhost 2>/dev/null | tail -n 1) + +echo "svn --version is '${version}'" + +secure=$(python -c "from ansible.module_utils.compat.version import LooseVersion; print(LooseVersion('$version') >= LooseVersion('1.10.0'))") if [[ "${secure}" = "False" ]] && [[ "$(grep -c 'To securely pass credentials, upgrade svn to version 1.10.0' out.txt)" -eq 1 ]]; then echo "Found the expected warning" diff --git a/test/integration/targets/subversion/runme.yml b/test/integration/targets/subversion/runme.yml index c67d7b89..71c5e4b8 100644 --- a/test/integration/targets/subversion/runme.yml +++ b/test/integration/targets/subversion/runme.yml @@ -1,5 +1,5 @@ --- -- hosts: localhost +- hosts: testhost tasks: - name: load OS specific vars include_vars: '{{ item }}' diff --git a/test/integration/targets/tags/aliases b/test/integration/targets/tags/aliases index 757c9966..8278ec8b 100644 --- a/test/integration/targets/tags/aliases +++ b/test/integration/targets/tags/aliases @@ -1,2 +1,2 @@ shippable/posix/group3 -skip/aix +context/controller diff --git a/test/integration/targets/task_ordering/aliases b/test/integration/targets/task_ordering/aliases index 765b70da..90ea9e12 100644 --- a/test/integration/targets/task_ordering/aliases +++ b/test/integration/targets/task_ordering/aliases @@ -1 +1,2 @@ shippable/posix/group2 +context/controller diff --git a/test/integration/targets/task_ordering/tasks/main.yml b/test/integration/targets/task_ordering/tasks/main.yml index 4a7828bf..a666006b 100644 --- a/test/integration/targets/task_ordering/tasks/main.yml +++ b/test/integration/targets/task_ordering/tasks/main.yml @@ -1,7 +1,7 @@ - set_fact: temppath: "{{ remote_tmp_dir }}/output.txt" -- include: taskorder-include.yml +- include_tasks: taskorder-include.yml with_items: - 1 - 2 diff --git a/test/integration/targets/tasks/aliases b/test/integration/targets/tasks/aliases index a6dafcf8..13e01f0c 100644 --- a/test/integration/targets/tasks/aliases +++ b/test/integration/targets/tasks/aliases @@ -1 +1,2 @@ shippable/posix/group1 +context/controller diff --git a/test/integration/targets/tempfile/aliases b/test/integration/targets/tempfile/aliases new file mode 100644 index 00000000..a6dafcf8 --- /dev/null +++ b/test/integration/targets/tempfile/aliases @@ -0,0 +1 @@ +shippable/posix/group1 diff --git a/test/integration/targets/tempfile/meta/main.yml b/test/integration/targets/tempfile/meta/main.yml new file mode 100644 index 00000000..1810d4be --- /dev/null +++ b/test/integration/targets/tempfile/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - setup_remote_tmp_dir diff --git a/test/integration/targets/tempfile/tasks/main.yml b/test/integration/targets/tempfile/tasks/main.yml new file mode 100644 index 00000000..2d783e6f --- /dev/null +++ b/test/integration/targets/tempfile/tasks/main.yml @@ -0,0 +1,63 @@ +- name: Create a temporary file with defaults + tempfile: + register: temp_file_default + +- name: Create a temporary directory with defaults + tempfile: + state: directory + register: temp_dir_default + +- name: Create a temporary file with optional parameters + tempfile: + path: "{{ remote_tmp_dir }}" + prefix: hello. + suffix: .goodbye + register: temp_file_options + +- name: Create a temporary directory with optional parameters + tempfile: + state: directory + path: "{{ remote_tmp_dir }}" + prefix: hello. + suffix: .goodbye + register: temp_dir_options + +- name: Create a temporary file in a non-existent directory + tempfile: + path: "{{ remote_tmp_dir }}/does_not_exist" + register: temp_file_non_existent_path + ignore_errors: yes + +- name: Create a temporary directory in a non-existent directory + tempfile: + state: directory + path: "{{ remote_tmp_dir }}/does_not_exist" + register: temp_dir_non_existent_path + ignore_errors: yes + +- name: Check results + assert: + that: + - temp_file_default is changed + - temp_file_default.state == 'file' + - temp_file_default.path | basename | split('.') | first == 'ansible' + + - temp_dir_default is changed + - temp_dir_default.state == 'directory' + - temp_dir_default.path | basename | split('.') | first == 'ansible' + + - temp_file_options is changed + - temp_file_options.state == 'file' + - temp_file_options.path.startswith(remote_tmp_dir) + - temp_file_options.path | basename | split('.') | first == 'hello' + - temp_file_options.path | basename | split('.') | last == 'goodbye' + + - temp_dir_options is changed + - temp_dir_options.state == 'directory' + - temp_dir_options.path.startswith(remote_tmp_dir) + - temp_dir_options.path | basename | split('.') | first == 'hello' + - temp_dir_options.path | basename | split('.') | last == 'goodbye' + + - temp_file_non_existent_path is failed + + - temp_dir_non_existent_path is failed diff --git a/test/integration/targets/template/aliases b/test/integration/targets/template/aliases index f0c24d20..327f088b 100644 --- a/test/integration/targets/template/aliases +++ b/test/integration/targets/template/aliases @@ -1,3 +1,3 @@ needs/root shippable/posix/group5 -skip/aix +context/controller # this "module" is actually an action that runs on the controller diff --git a/test/integration/targets/template/files/custom_comment_string.expected b/test/integration/targets/template/files/custom_comment_string.expected new file mode 100644 index 00000000..f3a08f7d --- /dev/null +++ b/test/integration/targets/template/files/custom_comment_string.expected @@ -0,0 +1,2 @@ +Before +After diff --git a/test/integration/targets/template/runme.sh b/test/integration/targets/template/runme.sh index a4f0bbe5..78f8d7b5 100755 --- a/test/integration/targets/template/runme.sh +++ b/test/integration/targets/template/runme.sh @@ -4,8 +4,8 @@ set -eux ANSIBLE_ROLES_PATH=../ ansible-playbook template.yml -i ../../inventory -v "$@" -# Test for #35571 -ansible testhost -i testhost, -m debug -a 'msg={{ hostvars["localhost"] }}' -e "vars1={{ undef }}" -e "vars2={{ vars1 }}" +# Test for https://github.com/ansible/ansible/pull/35571 +ansible testhost -i testhost, -m debug -a 'msg={{ hostvars["localhost"] }}' -e "vars1={{ undef() }}" -e "vars2={{ vars1 }}" # Test for https://github.com/ansible/ansible/issues/27262 ansible-playbook ansible_managed.yml -c ansible_managed.cfg -i ../../inventory -v "$@" diff --git a/test/integration/targets/template/tasks/main.yml b/test/integration/targets/template/tasks/main.yml index c5744d0d..f8848ef5 100644 --- a/test/integration/targets/template/tasks/main.yml +++ b/test/integration/targets/template/tasks/main.yml @@ -141,6 +141,26 @@ - 'import_as_with_context_diff_result.stdout == ""' - "import_as_with_context_diff_result.rc == 0" +# VERIFY comment_start_string and comment_end_string + +- name: Render a template with "comment_start_string" set to [# + template: + src: custom_comment_string.j2 + dest: "{{output_dir}}/custom_comment_string.templated" + comment_start_string: "[#" + comment_end_string: "#]" + register: custom_comment_string_result + +- name: Get checksum of known good custom_comment_string.expected + stat: + path: "{{role_path}}/files/custom_comment_string.expected" + register: custom_comment_string_good + +- name: Verify templated custom_comment_string matches known good using checksum + assert: + that: + - "custom_comment_string_result.checksum == custom_comment_string_good.stat.checksum" + # VERIFY trim_blocks - name: Render a template with "trim_blocks" set to False @@ -727,4 +747,4 @@ - out.stdout == "bar=lookedup_bar" # aliases file requires root for template tests so this should be safe -- include: backup_test.yml +- import_tasks: backup_test.yml diff --git a/test/integration/targets/template/templates/custom_comment_string.j2 b/test/integration/targets/template/templates/custom_comment_string.j2 new file mode 100644 index 00000000..db0af48a --- /dev/null +++ b/test/integration/targets/template/templates/custom_comment_string.j2 @@ -0,0 +1,3 @@ +Before +[# Test comment_start_string #] +After diff --git a/test/integration/targets/template_jinja2_latest/aliases b/test/integration/targets/template_jinja2_latest/aliases index 2a89ae7e..b9c19e3d 100644 --- a/test/integration/targets/template_jinja2_latest/aliases +++ b/test/integration/targets/template_jinja2_latest/aliases @@ -1,5 +1,5 @@ needs/root shippable/posix/group2 needs/target/template -skip/aix +context/controller needs/file/test/lib/ansible_test/_data/requirements/constraints.txt diff --git a/test/integration/targets/template_jinja2_non_native/aliases b/test/integration/targets/template_jinja2_non_native/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/template_jinja2_non_native/aliases +++ b/test/integration/targets/template_jinja2_non_native/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/templating_lookups/aliases b/test/integration/targets/templating_lookups/aliases index f8e28c7e..13e01f0c 100644 --- a/test/integration/targets/templating_lookups/aliases +++ b/test/integration/targets/templating_lookups/aliases @@ -1,2 +1,2 @@ shippable/posix/group1 -skip/aix +context/controller diff --git a/test/integration/targets/templating_settings/aliases b/test/integration/targets/templating_settings/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/templating_settings/aliases +++ b/test/integration/targets/templating_settings/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/test_core/aliases b/test/integration/targets/test_core/aliases index 041b0cc7..70a7b7a9 100644 --- a/test/integration/targets/test_core/aliases +++ b/test/integration/targets/test_core/aliases @@ -1,2 +1 @@ shippable/posix/group5 -skip/python2.6 # tests are controller only, and we no longer support Python 2.6 on the controller diff --git a/test/integration/targets/test_files/aliases b/test/integration/targets/test_files/aliases index 041b0cc7..70a7b7a9 100644 --- a/test/integration/targets/test_files/aliases +++ b/test/integration/targets/test_files/aliases @@ -1,2 +1 @@ shippable/posix/group5 -skip/python2.6 # tests are controller only, and we no longer support Python 2.6 on the controller diff --git a/test/integration/targets/test_mathstuff/aliases b/test/integration/targets/test_mathstuff/aliases index 041b0cc7..70a7b7a9 100644 --- a/test/integration/targets/test_mathstuff/aliases +++ b/test/integration/targets/test_mathstuff/aliases @@ -1,2 +1 @@ shippable/posix/group5 -skip/python2.6 # tests are controller only, and we no longer support Python 2.6 on the controller diff --git a/test/integration/targets/throttle/aliases b/test/integration/targets/throttle/aliases index 765b70da..90ea9e12 100644 --- a/test/integration/targets/throttle/aliases +++ b/test/integration/targets/throttle/aliases @@ -1 +1,2 @@ shippable/posix/group2 +context/controller diff --git a/test/integration/targets/unarchive/tasks/test_download.yml b/test/integration/targets/unarchive/tasks/test_download.yml index 6b17449b..241f11b6 100644 --- a/test/integration/targets/unarchive/tasks/test_download.yml +++ b/test/integration/targets/unarchive/tasks/test_download.yml @@ -4,31 +4,41 @@ path: '{{remote_tmp_dir}}/test-unarchive-tar-gz' state: directory -- name: Install packages to make TLS connections work on CentOS 6 - pip: - name: - - urllib3==1.10.2 - - ndg_httpsclient==0.4.4 - - pyOpenSSL==16.2.0 - state: present - when: - - ansible_facts.distribution == 'CentOS' - - not ansible_facts.python.has_sslcontext - -- name: unarchive a tar from an URL - unarchive: - src: "https://releases.ansible.com/ansible/ansible-latest.tar.gz" - dest: "{{ remote_tmp_dir }}/test-unarchive-tar-gz" - mode: "0700" - remote_src: yes - register: unarchive13 - -- name: Test that unarchive succeeded - assert: - that: - - "unarchive13.changed == true" - -- name: remove our tar.gz unarchive destination - file: - path: '{{ remote_tmp_dir }}/test-unarchive-tar-gz' - state: absent +- name: Test TLS download + block: + - name: Install packages to make TLS connections work on CentOS 6 + pip: + name: + - urllib3==1.10.2 + - ndg_httpsclient==0.4.4 + - pyOpenSSL==16.2.0 + state: present + when: + - ansible_facts.distribution == 'CentOS' + - not ansible_facts.python.has_sslcontext + - name: unarchive a tar from an URL + unarchive: + src: "https://releases.ansible.com/ansible/ansible-latest.tar.gz" + dest: "{{ remote_tmp_dir }}/test-unarchive-tar-gz" + mode: "0700" + remote_src: yes + register: unarchive13 + - name: Test that unarchive succeeded + assert: + that: + - "unarchive13.changed == true" + always: + - name: Uninstall CentOS 6 TLS connections packages + pip: + name: + - urllib3 + - ndg_httpsclient + - pyOpenSSL + state: absent + when: + - ansible_facts.distribution == 'CentOS' + - not ansible_facts.python.has_sslcontext + - name: remove our tar.gz unarchive destination + file: + path: '{{ remote_tmp_dir }}/test-unarchive-tar-gz' + state: absent diff --git a/test/integration/targets/unarchive/tasks/test_include.yml b/test/integration/targets/unarchive/tasks/test_include.yml index 3ed30fa3..04842e0e 100644 --- a/test/integration/targets/unarchive/tasks/test_include.yml +++ b/test/integration/targets/unarchive/tasks/test_include.yml @@ -15,6 +15,7 @@ unarchive: src: "{{ remote_tmp_dir }}/test-unarchive.zip" dest: "{{ remote_tmp_dir }}/include-zip" + remote_src: yes include: - FOO-UNAR.TXT @@ -39,6 +40,7 @@ unarchive: src: "{{ remote_tmp_dir }}/test-unarchive-multi.tar" dest: "{{ remote_tmp_dir }}/include-tar" + remote_src: yes include: - foo-unarchive-777.txt @@ -61,6 +63,7 @@ unarchive: src: "{{ remote_tmp_dir }}/test-unarchive-multi.tar" dest: "{{ remote_tmp_dir }}/include-tar" + remote_src: yes include: - foo-unarchive-777.txt exclude: diff --git a/test/integration/targets/unarchive/tasks/test_owner_group.yml b/test/integration/targets/unarchive/tasks/test_owner_group.yml index 95f1457e..227ad9ce 100644 --- a/test/integration/targets/unarchive/tasks/test_owner_group.yml +++ b/test/integration/targets/unarchive/tasks/test_owner_group.yml @@ -155,6 +155,8 @@ user: name: testuser state: absent + remove: yes + force: yes - name: Remove testgroup group: diff --git a/test/integration/targets/unarchive/tasks/test_tar_gz_owner_group.yml b/test/integration/targets/unarchive/tasks/test_tar_gz_owner_group.yml index 257692e1..e99f0380 100644 --- a/test/integration/targets/unarchive/tasks/test_tar_gz_owner_group.yml +++ b/test/integration/targets/unarchive/tasks/test_tar_gz_owner_group.yml @@ -41,6 +41,8 @@ user: name: testuser state: absent + remove: yes + force: yes - name: Remove testgroup group: diff --git a/test/integration/targets/unarchive/tasks/test_unprivileged_user.yml b/test/integration/targets/unarchive/tasks/test_unprivileged_user.yml index e4c2bec5..7022bba1 100644 --- a/test/integration/targets/unarchive/tasks/test_unprivileged_user.yml +++ b/test/integration/targets/unarchive/tasks/test_unprivileged_user.yml @@ -75,7 +75,9 @@ name: unarchivetest1 state: absent remove: yes - become: no + force: yes + become: yes + become_user: root - name: Remove user home directory on macOS file: diff --git a/test/integration/targets/undefined/aliases b/test/integration/targets/undefined/aliases index 70a7b7a9..1d28bdb2 100644 --- a/test/integration/targets/undefined/aliases +++ b/test/integration/targets/undefined/aliases @@ -1 +1,2 @@ shippable/posix/group5 +context/controller diff --git a/test/integration/targets/undefined/tasks/main.yml b/test/integration/targets/undefined/tasks/main.yml index de6681a0..bbd82845 100644 --- a/test/integration/targets/undefined/tasks/main.yml +++ b/test/integration/targets/undefined/tasks/main.yml @@ -11,7 +11,8 @@ - assert: that: - - '"%r"|format(undef) == "AnsibleUndefined"' + - '"%r"|format(an_undefined_var) == "AnsibleUndefined"' + - '"%r"|format(undef()) == "AnsibleUndefined"' # The existence of AnsibleUndefined in a templating result # prevents safe_eval from turning the value into a python object - names is string diff --git a/test/integration/targets/unicode/aliases b/test/integration/targets/unicode/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/unicode/aliases +++ b/test/integration/targets/unicode/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/unsafe_writes/aliases b/test/integration/targets/unsafe_writes/aliases index 4fb7a116..cf954afc 100644 --- a/test/integration/targets/unsafe_writes/aliases +++ b/test/integration/targets/unsafe_writes/aliases @@ -1,6 +1,8 @@ +context/target needs/root skip/freebsd skip/osx skip/macos skip/aix shippable/posix/group3 +needs/target/setup_remote_tmp_dir diff --git a/test/integration/targets/unsafe_writes/basic.yml b/test/integration/targets/unsafe_writes/basic.yml index 410726ad..99a3195f 100644 --- a/test/integration/targets/unsafe_writes/basic.yml +++ b/test/integration/targets/unsafe_writes/basic.yml @@ -1,9 +1,23 @@ - hosts: testhost gather_facts: false - vars: - testudir: '{{output_dir}}/unsafe_writes_test' - testufile: '{{testudir}}/unreplacablefile.txt' tasks: + - import_role: + name: ../setup_remote_tmp_dir + - name: define test directory + set_fact: + testudir: '{{remote_tmp_dir}}/unsafe_writes_test' + - name: define test file + set_fact: + testufile: '{{testudir}}/unreplacablefile.txt' + - name: define test environment with unsafe writes set + set_fact: + test_env: + ANSIBLE_UNSAFE_WRITES: "{{ lookup('env', 'ANSIBLE_UNSAFE_WRITES') }}" + when: lookup('env', 'ANSIBLE_UNSAFE_WRITES') + - name: define test environment without unsafe writes set + set_fact: + test_env: {} + when: not lookup('env', 'ANSIBLE_UNSAFE_WRITES') - name: test unsafe_writes on immutable dir (file cannot be atomically replaced) block: - name: create target dir @@ -61,6 +75,7 @@ msg: "Failed with envvar: {{env_enabled}}, due AUW: to {{q('env', 'ANSIBLE_UNSAFE_WRITES')}}" that: - env_enabled and copy_with_env is changed or not env_enabled and copy_with_env is failed + environment: "{{ test_env }}" always: - name: remove immutable flag from dir to prevent issues with cleanup file: path={{testudir}} state=directory attributes="-i" diff --git a/test/integration/targets/unsafe_writes/runme.sh b/test/integration/targets/unsafe_writes/runme.sh index 791a5676..619ce025 100755 --- a/test/integration/targets/unsafe_writes/runme.sh +++ b/test/integration/targets/unsafe_writes/runme.sh @@ -3,10 +3,10 @@ set -eux # test w/o fallback env var -ansible-playbook basic.yml -i ../../inventory -e "output_dir=${OUTPUT_DIR}" "$@" +ansible-playbook basic.yml -i ../../inventory "$@" # test enabled fallback env var -ANSIBLE_UNSAFE_WRITES=1 ansible-playbook basic.yml -i ../../inventory -e "output_dir=${OUTPUT_DIR}" "$@" +ANSIBLE_UNSAFE_WRITES=1 ansible-playbook basic.yml -i ../../inventory "$@" # test disnabled fallback env var -ANSIBLE_UNSAFE_WRITES=0 ansible-playbook basic.yml -i ../../inventory -e "output_dir=${OUTPUT_DIR}" "$@" +ANSIBLE_UNSAFE_WRITES=0 ansible-playbook basic.yml -i ../../inventory "$@" diff --git a/test/integration/targets/until/aliases b/test/integration/targets/until/aliases index 765b70da..90ea9e12 100644 --- a/test/integration/targets/until/aliases +++ b/test/integration/targets/until/aliases @@ -1 +1,2 @@ shippable/posix/group2 +context/controller diff --git a/test/integration/targets/unvault/aliases b/test/integration/targets/unvault/aliases index 765b70da..90ea9e12 100644 --- a/test/integration/targets/unvault/aliases +++ b/test/integration/targets/unvault/aliases @@ -1 +1,2 @@ shippable/posix/group2 +context/controller diff --git a/test/integration/targets/uri/meta/main.yml b/test/integration/targets/uri/meta/main.yml index 39b94950..2c2155ab 100644 --- a/test/integration/targets/uri/meta/main.yml +++ b/test/integration/targets/uri/meta/main.yml @@ -2,4 +2,3 @@ dependencies: - prepare_tests - prepare_http_tests - setup_remote_tmp_dir - - setup_remote_constraints diff --git a/test/integration/targets/uri/tasks/main.yml b/test/integration/targets/uri/tasks/main.yml index 4cefc6b3..700e7f10 100644 --- a/test/integration/targets/uri/tasks/main.yml +++ b/test/integration/targets/uri/tasks/main.yml @@ -228,6 +228,33 @@ headers: Cookie: "fake=fake_value" +- name: test unredirected_headers + uri: + url: 'https://{{ httpbin_host }}/redirect-to?status_code=301&url=/basic-auth/user/passwd' + user: user + password: passwd + force_basic_auth: true + unredirected_headers: + - authorization + ignore_errors: true + register: unredirected_headers + +- name: test omitting unredirected headers + uri: + url: 'https://{{ httpbin_host }}/redirect-to?status_code=301&url=/basic-auth/user/passwd' + user: user + password: passwd + force_basic_auth: true + register: redirected_headers + +- name: ensure unredirected_headers caused auth to fail + assert: + that: + - unredirected_headers is failed + - unredirected_headers.status == 401 + - redirected_headers is successful + - redirected_headers.status == 200 + - name: test PUT uri: url: 'https://{{ httpbin_host }}/put' @@ -339,10 +366,25 @@ with_items: "{{ uri_os_packages[ansible_os_family].step2 | default([]) }}" when: not ansible_python.has_sslcontext and not is_ubuntu_precise|bool +- name: create constraints path + set_fact: + remote_constraints: "{{ remote_tmp_dir }}/constraints.txt" + when: not ansible_python.has_sslcontext and not is_ubuntu_precise|bool + +- name: create constraints file + copy: + content: | + cryptography == 2.1.4 + idna == 2.5 + pyopenssl == 17.5.0 + six == 1.13.0 + urllib3 == 1.23 + dest: "{{ remote_constraints }}" + when: not ansible_python.has_sslcontext and not is_ubuntu_precise|bool + - name: install urllib3 and pyopenssl via pip pip: name: "{{ item }}" - state: latest extra_args: "-c {{ remote_constraints }}" with_items: - urllib3 @@ -474,6 +516,16 @@ - multipart.json.form.text_form_field1 == 'value1' - multipart.json.form.text_form_field2 == 'value2' +# https://github.com/ansible/ansible/issues/74276 - verifies we don't have a traceback +- name: multipart/form-data with invalid value + uri: + url: https://{{ httpbin_host }}/post + method: POST + body_format: form-multipart + body: + integer_value: 1 + register: multipart_invalid + failed_when: 'multipart_invalid.msg != "failed to parse body as form-multipart: value must be a string, or mapping, cannot be type int"' - name: Validate invalid method uri: diff --git a/test/integration/targets/user/tasks/main.yml b/test/integration/targets/user/tasks/main.yml index d3bae056..5e1d2d22 100644 --- a/test/integration/targets/user/tasks/main.yml +++ b/test/integration/targets/user/tasks/main.yml @@ -37,3 +37,5 @@ - import_tasks: test_password_lock.yml - import_tasks: test_password_lock_new_user.yml - import_tasks: test_local.yml +- import_tasks: test_umask.yml + when: ansible_facts.system == 'Linux' diff --git a/test/integration/targets/user/tasks/test_umask.yml b/test/integration/targets/user/tasks/test_umask.yml new file mode 100644 index 00000000..9e162976 --- /dev/null +++ b/test/integration/targets/user/tasks/test_umask.yml @@ -0,0 +1,57 @@ +--- +- name: remove comments of /etc/login.defs + command: sed -e '/^[ \t]*#/d' /etc/login.defs + register: logindefs + +- block: + - name: Create user with 000 umask + user: + name: umaskuser_test_1 + umask: "000" + register: umaskuser_test_1 + + - name: Create user with 077 umask + user: + name: umaskuser_test_2 + umask: "077" + register: umaskuser_test_2 + + - name: check permissions on created home folder + stat: + path: "{{ user_home_prefix[ansible_facts.system] }}/umaskuser_test_1" + register: umaskuser_test_1_path + + - name: check permissions on created home folder + stat: + path: "{{ user_home_prefix[ansible_facts.system] }}/umaskuser_test_2" + register: umaskuser_test_2_path + + - name: remove created users + user: + name: "{{ item }}" + state: absent + register: umaskuser_test_remove + loop: + - umaskuser_test_1 + - umaskuser_test_2 + + - name: Ensure correct umask has been set on created users + assert: + that: + - umaskuser_test_1_path.stat.mode == "0777" + - umaskuser_test_2_path.stat.mode == "0700" + - umaskuser_test_remove is changed + when: logindefs.stdout_lines is not search ("HOME_MODE") + +- name: Create user with setting both umask and local + user: + name: umaskuser_test_3 + umask: "077" + local: true + register: umaskuser_test_3 + ignore_errors: true + +- name: Ensure task has been failed + assert: + that: + - umaskuser_test_3 is failed diff --git a/test/integration/targets/var_blending/aliases b/test/integration/targets/var_blending/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/var_blending/aliases +++ b/test/integration/targets/var_blending/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/var_precedence/aliases b/test/integration/targets/var_precedence/aliases index 3005e4b2..498fedd5 100644 --- a/test/integration/targets/var_precedence/aliases +++ b/test/integration/targets/var_precedence/aliases @@ -1 +1,2 @@ shippable/posix/group4 +context/controller diff --git a/test/integration/targets/var_reserved/aliases b/test/integration/targets/var_reserved/aliases index 765b70da..90ea9e12 100644 --- a/test/integration/targets/var_reserved/aliases +++ b/test/integration/targets/var_reserved/aliases @@ -1 +1,2 @@ shippable/posix/group2 +context/controller diff --git a/test/integration/targets/var_templating/aliases b/test/integration/targets/var_templating/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/var_templating/aliases +++ b/test/integration/targets/var_templating/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/vault/runme_change_pip_installed.sh b/test/integration/targets/vault/runme_change_pip_installed.sh deleted file mode 100755 index 5ab2a8ec..00000000 --- a/test/integration/targets/vault/runme_change_pip_installed.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash - -# start by removing pycrypto and cryptography - -pip uninstall -y cryptography -pip uninstall -y pycrypto - -./runme.sh - -# now just pycrypto -pip install --user pycrypto - -./runme.sh - - -# now just cryptography - -pip uninstall -y pycrypto -pip install --user cryptography - -./runme.sh - -# now both - -pip install --user pycrypto - -./runme.sh diff --git a/test/integration/targets/want_json_modules_posix/aliases b/test/integration/targets/want_json_modules_posix/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/want_json_modules_posix/aliases +++ b/test/integration/targets/want_json_modules_posix/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/yaml_parsing/aliases b/test/integration/targets/yaml_parsing/aliases index b5983214..8278ec8b 100644 --- a/test/integration/targets/yaml_parsing/aliases +++ b/test/integration/targets/yaml_parsing/aliases @@ -1 +1,2 @@ shippable/posix/group3 +context/controller diff --git a/test/integration/targets/yum/filter_plugins/filter_list_of_tuples_by_first_param.py b/test/integration/targets/yum/filter_plugins/filter_list_of_tuples_by_first_param.py new file mode 100644 index 00000000..27f38ce5 --- /dev/null +++ b/test/integration/targets/yum/filter_plugins/filter_list_of_tuples_by_first_param.py @@ -0,0 +1,25 @@ +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +from ansible.errors import AnsibleError, AnsibleFilterError + + +def filter_list_of_tuples_by_first_param(lst, search, startswith=False): + out = [] + for element in lst: + if startswith: + if element[0].startswith(search): + out.append(element) + else: + if search in element[0]: + out.append(element) + return out + + +class FilterModule(object): + ''' filter ''' + + def filters(self): + return { + 'filter_list_of_tuples_by_first_param': filter_list_of_tuples_by_first_param, + } diff --git a/test/integration/targets/yum/tasks/cacheonly.yml b/test/integration/targets/yum/tasks/cacheonly.yml new file mode 100644 index 00000000..03cbd0e9 --- /dev/null +++ b/test/integration/targets/yum/tasks/cacheonly.yml @@ -0,0 +1,16 @@ +--- +- name: Test cacheonly (clean before testing) + command: yum clean all + +- name: Try installing from cache where it has been cleaned + yum: + name: sos + state: latest + cacheonly: true + register: yum_result + ignore_errors: true + +- name: Verify yum failure + assert: + that: + - "yum_result is failed" diff --git a/test/integration/targets/yum/tasks/main.yml b/test/integration/targets/yum/tasks/main.yml index 3a7f4cf5..157124a9 100644 --- a/test/integration/targets/yum/tasks/main.yml +++ b/test/integration/targets/yum/tasks/main.yml @@ -10,7 +10,7 @@ name: - sos state: absent - + - import_tasks: yum.yml always: - name: remove installed packages @@ -69,3 +69,14 @@ - import_tasks: lock.yml when: - ansible_distribution in ['RedHat', 'CentOS', 'ScientificLinux'] + +- import_tasks: multiarch.yml + when: + - ansible_distribution in ['RedHat', 'CentOS', 'ScientificLinux'] + - ansible_architecture == 'x86_64' + # Our output parsing expects us to be on yum, not dnf + - ansible_distribution_major_version is version('7', '<=') + +- import_tasks: cacheonly.yml + when: + - ansible_distribution in ['RedHat', 'CentOS', 'ScientificLinux', 'Fedora'] diff --git a/test/integration/targets/yum/tasks/multiarch.yml b/test/integration/targets/yum/tasks/multiarch.yml new file mode 100644 index 00000000..bced634c --- /dev/null +++ b/test/integration/targets/yum/tasks/multiarch.yml @@ -0,0 +1,154 @@ +- block: + - name: Set up test yum repo + yum_repository: + name: multiarch-test-repo + description: ansible-test multiarch test repo + baseurl: "{{ multiarch_repo_baseurl }}" + gpgcheck: no + repo_gpgcheck: no + + - name: Install two out of date packages from the repo + yum: + name: + - multiarch-a-1.0 + - multiarch-b-1.0 + register: outdated + + - name: See what we installed + command: rpm -q multiarch-a multiarch-b + register: rpm_q + + # Here we assume we're running on x86_64 (and limit to this in main.yml) + # (avoid comparing ansible_architecture because we only have test RPMs + # for i686 and x86_64 and ansible_architecture could be other things.) + - name: Assert that we got the right architecture + assert: + that: + - outdated is changed + - outdated.changes.installed | length == 2 + - rpm_q.stdout_lines | length == 2 + - rpm_q.stdout_lines[0].endswith('x86_64') + - rpm_q.stdout_lines[1].endswith('x86_64') + + - name: Install the same versions, but i686 instead + yum: + name: + - multiarch-a-1.0*.i686 + - multiarch-b-1.0*.i686 + register: outdated_i686 + + - name: See what we installed + command: rpm -q multiarch-a multiarch-b + register: rpm_q + + - name: Assert that all four are installed + assert: + that: + - outdated_i686 is changed + - outdated.changes.installed | length == 2 + - rpm_q.stdout_lines | length == 4 + + - name: Update them all to 2.0 + yum: + name: multiarch-* + state: latest + update_only: true + register: yum_latest + + - name: Assert that all were updated and shown in results + assert: + that: + - yum_latest is changed + # This is just testing UI stability. The behavior is arguably not + # correct, because multiple packages are being updated. But the + # "because of (at least)..." wording kinda locks us in to only + # showing one update in this case. :( + - yum_latest.changes.updated | length == 1 + + - name: Downgrade them so we can upgrade them a different way + yum: + name: + - multiarch-a-1.0* + - multiarch-b-1.0* + allow_downgrade: true + register: downgrade + + - name: See what we installed + command: rpm -q multiarch-a multiarch-b --queryformat '%{name}-%{version}.%{arch}\n' + register: rpm_q + + - name: Ensure downgrade worked + assert: + that: + - downgrade is changed + - rpm_q.stdout_lines | sort == ['multiarch-a-1.0.i686', 'multiarch-a-1.0.x86_64', 'multiarch-b-1.0.i686', 'multiarch-b-1.0.x86_64'] + + # This triggers a different branch of logic that the partial wildcard + # above, but we're limited to check_mode here since it's '*'. + - name: Upgrade with full wildcard + yum: + name: '*' + state: latest + update_only: true + update_cache: true + check_mode: true + register: full_wildcard + + # https://github.com/ansible/ansible/issues/73284 + - name: Ensure we report things correctly (both arches) + assert: + that: + - full_wildcard is changed + - full_wildcard.changes.updated | filter_list_of_tuples_by_first_param('multiarch', startswith=True) | length == 4 + + - name: Downgrade them so we can upgrade them a different way + yum: + name: + - multiarch-a-1.0* + - multiarch-b-1.0* + allow_downgrade: true + register: downgrade + + - name: Try to install again via virtual provides, should be unchanged + yum: + name: + - virtual-provides-multiarch-a + - virtual-provides-multiarch-b + state: present + register: install_vp + + - name: Ensure the above did not change + assert: + that: + - install_vp is not changed + + - name: Try to upgrade via virtual provides + yum: + name: + - virtual-provides-multiarch-a + - virtual-provides-multiarch-b + state: latest + update_only: true + register: upgrade_vp + + - name: Ensure we report things correctly (both arches) + assert: + that: + - upgrade_vp is changed + # This is just testing UI stability, like above. + # We'll only have one package in "updated" per spec, even though + # (in this case) two are getting updated per spec. + - upgrade_vp.changes.updated | length == 2 + + always: + - name: Remove test yum repo + yum_repository: + name: multiarch-test-repo + state: absent + + - name: Remove all test packages installed + yum: + name: + - multiarch-* + - virtual-provides-multiarch-* + state: absent diff --git a/test/integration/targets/yum/tasks/repo.yml b/test/integration/targets/yum/tasks/repo.yml index c1a7a016..f312b1ca 100644 --- a/test/integration/targets/yum/tasks/repo.yml +++ b/test/integration/targets/yum/tasks/repo.yml @@ -703,3 +703,27 @@ yum: name: dinginessentail,dinginessentail-olive,landsidescalping state: absent + +- block: + - yum: + name: dinginessentail + state: present + + - yum: + list: dinginessentail* + register: list_out + + - set_fact: + passed: true + loop: "{{ list_out.results }}" + when: item.yumstate == 'installed' + + - name: Test that there is yumstate=installed in the result + assert: + that: + - passed is defined + always: + - name: Clean up + yum: + name: dinginessentail + state: absent diff --git a/test/integration/targets/yum/tasks/yum.yml b/test/integration/targets/yum/tasks/yum.yml index 7abfea17..e1caa852 100644 --- a/test/integration/targets/yum/tasks/yum.yml +++ b/test/integration/targets/yum/tasks/yum.yml @@ -867,3 +867,18 @@ - test-package-that-provides-toaster - toaster state: absent + +- yum: + list: "{{ package1 }}" + register: list_out + +- name: check that both yum and dnf return envra + assert: + that: + - '"envra" in list_out["results"][0]' + +- name: check that dnf returns nevra for backwards compat + assert: + that: + - '"nevra" in list_out["results"][0]' + when: ansible_pkg_mgr == 'dnf' diff --git a/test/integration/targets/yum/vars/main.yml b/test/integration/targets/yum/vars/main.yml new file mode 100644 index 00000000..2be15132 --- /dev/null +++ b/test/integration/targets/yum/vars/main.yml @@ -0,0 +1 @@ +multiarch_repo_baseurl: https://ansible-ci-files.s3.amazonaws.com/test/integration/targets/yum/multiarch-test-repo/RPMS/ diff --git a/test/integration/targets/yum_repository/tasks/main.yml b/test/integration/targets/yum_repository/tasks/main.yml index d8195775..90866523 100644 --- a/test/integration/targets/yum_repository/tasks/main.yml +++ b/test/integration/targets/yum_repository/tasks/main.yml @@ -106,6 +106,11 @@ module_hotfixes: no register: test_repo_add1 + - name: Get repo file contents + slurp: + path: "{{ '/etc/yum.repos.d/' ~ yum_repository_test_repo.name ~ '2.repo' }}" + register: slurp + - name: check that options are correctly getting written to the repo file assert: that: @@ -116,8 +121,7 @@ - "'keepalive = 0' in repo_file_contents" - "'module_hotfixes = 0' in repo_file_contents" vars: - repo_file: "{{ '/etc/yum.repos.d/' ~ yum_repository_test_repo.name ~ '2.repo' }}" - repo_file_contents: "{{ lookup('file', repo_file) }}" + repo_file_contents: "{{ slurp.content | b64decode }}" - name: check new config doesn't change (Idempotant) yum_repository: @@ -163,7 +167,7 @@ description: Testing list feature baseurl: - "{{ yum_repository_test_repo.baseurl }}" - - "{{ yum_repository_test_repo.baseurl | replace('download[0-9]?\\.', 'download2\\.', 1) }}" + - "{{ yum_repository_test_repo.baseurl ~ 'another_baseurl' }}" gpgkey: - gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-{{ ansible_facts.distribution_major_version }} - gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG2-KEY-EPEL-{{ ansible_facts.distribution_major_version }} @@ -175,16 +179,20 @@ - ddd notify: remove listtest repo + - name: Get repo file + slurp: + path: /etc/yum.repos.d/listtest.repo + register: slurp + - name: Assert that lists were properly inserted assert: that: - - url_hostname in repofile - - url_hostname2 in repofile + - yum_repository_test_repo.baseurl in repofile + - another_baseurl in repofile - "'RPM-GPG-KEY-EPEL' in repofile" - "'RPM-GPG2-KEY-EPEL' in repofile" - "'aaa bbb' in repofile" - "'ccc ddd' in repofile" vars: - repofile: "{{ lookup('file', '/etc/yum.repos.d/listtest.repo') }}" - url_hostname: "{{ yum_repository_test_repo.baseurl | urlsplit('hostname') }}" - url_hostname2: "{{ url_hostname | replace('download[0-9]?\\.', 'download2\\.', 1) }}" + repofile: "{{ slurp.content | b64decode }}" + another_baseurl: "{{ yum_repository_test_repo.baseurl ~ 'another_baseurl' }}" |