diff options
Diffstat (limited to '')
25 files changed, 1152 insertions, 0 deletions
diff --git a/test/integration/targets/gathering/aliases b/test/integration/targets/gathering/aliases new file mode 100644 index 0000000..1d28bdb --- /dev/null +++ b/test/integration/targets/gathering/aliases @@ -0,0 +1,2 @@ +shippable/posix/group5 +context/controller diff --git a/test/integration/targets/gathering/explicit.yml b/test/integration/targets/gathering/explicit.yml new file mode 100644 index 0000000..453dfb6 --- /dev/null +++ b/test/integration/targets/gathering/explicit.yml @@ -0,0 +1,14 @@ +- hosts: testhost + tasks: + - name: ensure facts have not been collected + assert: + that: + - ansible_facts is undefined or not 'fqdn' in ansible_facts + +- hosts: testhost + gather_facts: True + tasks: + - name: ensure facts have been collected + assert: + that: + - ansible_facts is defined and 'fqdn' in ansible_facts diff --git a/test/integration/targets/gathering/implicit.yml b/test/integration/targets/gathering/implicit.yml new file mode 100644 index 0000000..f1ea965 --- /dev/null +++ b/test/integration/targets/gathering/implicit.yml @@ -0,0 +1,23 @@ +- hosts: testhost + tasks: + - name: check that facts were gathered but no local facts exist + assert: + that: + - ansible_facts is defined and 'fqdn' in ansible_facts + - not 'uuid' in ansible_local + - name: create 'local facts' for next gathering + copy: + src: uuid.fact + dest: /etc/ansible/facts.d/ + mode: 0755 + +- hosts: testhost + tasks: + - name: ensure facts are gathered and includes the new 'local facts' created above + assert: + that: + - ansible_facts is defined and 'fqdn' in ansible_facts + - "'uuid' in ansible_local" + + - name: cleanup 'local facts' from target + file: path=/etc/ansible/facts.d/uuid.fact state=absent diff --git a/test/integration/targets/gathering/runme.sh b/test/integration/targets/gathering/runme.sh new file mode 100755 index 0000000..1c0832c --- /dev/null +++ b/test/integration/targets/gathering/runme.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -eux + +ANSIBLE_GATHERING=smart ansible-playbook smart.yml --flush-cache -i ../../inventory -v "$@" +ANSIBLE_GATHERING=implicit ansible-playbook implicit.yml --flush-cache -i ../../inventory -v "$@" +ANSIBLE_GATHERING=explicit ansible-playbook explicit.yml --flush-cache -i ../../inventory -v "$@" diff --git a/test/integration/targets/gathering/smart.yml b/test/integration/targets/gathering/smart.yml new file mode 100644 index 0000000..735cb46 --- /dev/null +++ b/test/integration/targets/gathering/smart.yml @@ -0,0 +1,23 @@ +- hosts: testhost + tasks: + - name: ensure facts are gathered but no local exists + assert: + that: + - ansible_facts is defined and 'fqdn' in ansible_facts + - not 'uuid' in ansible_local + - name: create local facts for latter test + copy: + src: uuid.fact + dest: /etc/ansible/facts.d/ + mode: 0755 + +- hosts: testhost + tasks: + - name: ensure we still have facts, but didnt pickup new local ones + assert: + that: + - ansible_facts is defined and 'fqdn' in ansible_facts + - not 'uuid' in ansible_local + + - name: remove local facts file + file: path=/etc/ansible/facts.d/uuid.fact state=absent diff --git a/test/integration/targets/gathering/uuid.fact b/test/integration/targets/gathering/uuid.fact new file mode 100644 index 0000000..79e3f62 --- /dev/null +++ b/test/integration/targets/gathering/uuid.fact @@ -0,0 +1,10 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + + +import json +import uuid + + +# return a random string +print(json.dumps(str(uuid.uuid4()))) diff --git a/test/integration/targets/gathering_facts/aliases b/test/integration/targets/gathering_facts/aliases new file mode 100644 index 0000000..4cc0d88 --- /dev/null +++ b/test/integration/targets/gathering_facts/aliases @@ -0,0 +1,3 @@ +shippable/posix/group5 +needs/root +context/controller diff --git a/test/integration/targets/gathering_facts/cache_plugins/none.py b/test/integration/targets/gathering_facts/cache_plugins/none.py new file mode 100644 index 0000000..5681dee --- /dev/null +++ b/test/integration/targets/gathering_facts/cache_plugins/none.py @@ -0,0 +1,50 @@ +# (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 + +from ansible.plugins.cache import BaseCacheModule + +DOCUMENTATION = ''' + cache: none + short_description: write-only cache (no cache) + description: + - No caching at all + version_added: historical + author: core team (@ansible-core) +''' + + +class CacheModule(BaseCacheModule): + def __init__(self, *args, **kwargs): + self.empty = {} + + def get(self, key): + return self.empty.get(key) + + def set(self, key, value): + return value + + def keys(self): + return self.empty.keys() + + def contains(self, key): + return key in self.empty + + def delete(self, key): + del self.emtpy[key] + + def flush(self): + self.empty = {} + + def copy(self): + return self.empty.copy() + + def __getstate__(self): + return self.copy() + + def __setstate__(self, data): + self.empty = data 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 0000000..b79f794 --- /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 new file mode 100644 index 0000000..6352a7d --- /dev/null +++ b/test/integration/targets/gathering_facts/inventory @@ -0,0 +1,2 @@ +[local] +facthost[0:26] ansible_connection=local ansible_python_interpreter="{{ ansible_playbook_python }}" diff --git a/test/integration/targets/gathering_facts/library/bogus_facts b/test/integration/targets/gathering_facts/library/bogus_facts new file mode 100644 index 0000000..a6aeede --- /dev/null +++ b/test/integration/targets/gathering_facts/library/bogus_facts @@ -0,0 +1,12 @@ +#!/bin/sh + +echo '{ + "changed": false, + "ansible_facts": { + "ansible_facts": { + "discovered_interpreter_python": "(touch /tmp/pwned-$(date -Iseconds)-$(whoami) ) 2>/dev/null >/dev/null && /usr/bin/python", + "bogus_overwrite": "yes" + }, + "dansible_iscovered_interpreter_python": "(touch /tmp/pwned-$(date -Iseconds)-$(whoami) ) 2>/dev/null >/dev/null && /usr/bin/python" + } +}' diff --git a/test/integration/targets/gathering_facts/library/facts_one b/test/integration/targets/gathering_facts/library/facts_one new file mode 100644 index 0000000..c74ab9a --- /dev/null +++ b/test/integration/targets/gathering_facts/library/facts_one @@ -0,0 +1,25 @@ +#!/bin/sh + +echo '{ + "changed": false, + "ansible_facts": { + "factsone": "from facts_one module", + "common_fact": "also from facts_one module", + "common_dict_fact": { + "key_one": "from facts_one", + "key_two": "from facts_one" + }, + "common_list_fact": [ + "one", + "three", + "five" + ], + "common_list_fact2": [ + "one", + "two", + "three", + "five", + "five" + ] + } +}' diff --git a/test/integration/targets/gathering_facts/library/facts_two b/test/integration/targets/gathering_facts/library/facts_two new file mode 100644 index 0000000..4e7c668 --- /dev/null +++ b/test/integration/targets/gathering_facts/library/facts_two @@ -0,0 +1,24 @@ +#!/bin/sh + +echo '{ + "changed": false, + "ansible_facts": { + "factstwo": "from facts_two module", + "common_fact": "also from facts_two module", + "common_dict_fact": { + "key_two": "from facts_two", + "key_four": "from facts_two" + }, + "common_list_fact": [ + "one", + "two", + "four" + ], + "common_list_fact2": [ + "one", + "two", + "four", + "four" + ] + } +}' diff --git a/test/integration/targets/gathering_facts/library/file_utils.py b/test/integration/targets/gathering_facts/library/file_utils.py new file mode 100644 index 0000000..5853802 --- /dev/null +++ b/test/integration/targets/gathering_facts/library/file_utils.py @@ -0,0 +1,54 @@ +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import json +import sys + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.facts.utils import ( + get_file_content, + get_file_lines, + get_mount_size, +) + + +def main(): + module = AnsibleModule( + argument_spec=dict( + test=dict(type='str', default='strip'), + touch_file=dict(type='str', default='/dev/null'), + line_sep_file=dict(type='str', default='/dev/null'), + line_sep_sep=dict(type='str', default='\n'), + ) + ) + + test = module.params['test'] + facts = {} + + if test == 'strip': + etc_passwd = get_file_content('/etc/passwd') + etc_passwd_unstripped = get_file_content('/etc/passwd', strip=False) + facts['etc_passwd_newlines'] = etc_passwd.count('\n') + facts['etc_passwd_newlines_unstripped'] = etc_passwd_unstripped.count('\n') + + elif test == 'default': + path = module.params['touch_file'] + facts['touch_default'] = get_file_content(path, default='i am a default') + + elif test == 'line_sep': + path = module.params['line_sep_file'] + sep = module.params['line_sep_sep'] + facts['line_sep'] = get_file_lines(path, line_sep=sep) + + elif test == 'invalid_mountpoint': + facts['invalid_mountpoint'] = get_mount_size('/doesnotexist') + + result = { + 'changed': False, + 'ansible_facts': facts, + } + + module.exit_json(**result) + + +main() diff --git a/test/integration/targets/gathering_facts/one_two.json b/test/integration/targets/gathering_facts/one_two.json new file mode 100644 index 0000000..ecc698c --- /dev/null +++ b/test/integration/targets/gathering_facts/one_two.json @@ -0,0 +1,27 @@ +{ + "_ansible_facts_gathered": true, + "common_dict_fact": { + "key_four": "from facts_two", + "key_one": "from facts_one", + "key_two": "from facts_two" + }, + "common_fact": "also from facts_two module", + "common_list_fact": [ + "three", + "five", + "one", + "two", + "four" + ], + "common_list_fact2": [ + "three", + "five", + "five", + "one", + "two", + "four", + "four" + ], + "factsone": "from facts_one module", + "factstwo": "from facts_two module" +}
\ No newline at end of file diff --git a/test/integration/targets/gathering_facts/prevent_clobbering.yml b/test/integration/targets/gathering_facts/prevent_clobbering.yml new file mode 100644 index 0000000..94bb451 --- /dev/null +++ b/test/integration/targets/gathering_facts/prevent_clobbering.yml @@ -0,0 +1,8 @@ +- name: Verify existing facts don't go undefined on unrelated new facts in loop + hosts: localhost + gather_facts: True + tasks: + - name: Ensure that 'virtualization_type' is not undefined after first loop iteration + bogus_facts: + loop: [1, 2, 3] + when: ansible_facts['virtualization_type'] != 'NotDocker' diff --git a/test/integration/targets/gathering_facts/runme.sh b/test/integration/targets/gathering_facts/runme.sh new file mode 100755 index 0000000..c1df560 --- /dev/null +++ b/test/integration/targets/gathering_facts/runme.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +set -eux + +#ANSIBLE_CACHE_PLUGINS=cache_plugins/ ANSIBLE_CACHE_PLUGIN=none ansible-playbook test_gathering_facts.yml -i inventory -v "$@" +ansible-playbook test_gathering_facts.yml -i inventory -e output_dir="$OUTPUT_DIR" -v "$@" +#ANSIBLE_CACHE_PLUGIN=base ansible-playbook test_gathering_facts.yml -i inventory -v "$@" + +ANSIBLE_GATHERING=smart ansible-playbook test_run_once.yml -i inventory -v "$@" + +# ensure clean_facts is working properly +ansible-playbook test_prevent_injection.yml -i inventory -v "$@" + +# ensure fact merging is working properly +ansible-playbook verify_merge_facts.yml -v "$@" -e 'ansible_facts_parallel: False' + +# ensure we dont clobber facts in loop +ansible-playbook prevent_clobbering.yml -v "$@" + +# ensure we dont fail module on bad subset +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 new file mode 100644 index 0000000..47027e8 --- /dev/null +++ b/test/integration/targets/gathering_facts/test_gathering_facts.yml @@ -0,0 +1,536 @@ +--- +- hosts: facthost7 + tags: [ 'fact_negation' ] + connection: local + gather_subset: "!hardware" + gather_facts: no + tasks: + - name: setup with not hardware + setup: + gather_subset: + - "!hardware" + register: not_hardware_facts + +- name: min and network test for platform added + hosts: facthost21 + tags: [ 'fact_network' ] + connection: local + gather_subset: ["!all", "network"] + gather_facts: yes + tasks: + - name: Test that retrieving network facts works and gets prereqs from platform and distribution + assert: + that: + - 'ansible_default_ipv4|default("UNDEF") != "UNDEF"' + - 'ansible_interfaces|default("UNDEF") != "UNDEF"' + # these are true for linux, but maybe not for other os + - 'ansible_system|default("UNDEF") != "UNDEF"' + - 'ansible_distribution|default("UNDEF") != "UNDEF"' + # we dont really require these but they are in the min set + # - 'ansible_virtualization_role|default("UNDEF") == "UNDEF"' + # - 'ansible_user_id|default("UNDEF") == "UNDEF"' + # - 'ansible_env|default("UNDEF") == "UNDEF"' + # - 'ansible_selinux|default("UNDEF") == "UNDEF"' + # - 'ansible_pkg_mgr|default("UNDEF") == "UNDEF"' + +- name: min and hardware test for platform added + hosts: facthost22 + tags: [ 'fact_hardware' ] + connection: local + gather_subset: "hardware" + gather_facts: yes + tasks: + - name: debug stuff + debug: + var: hostvars['facthost22'] + # we should also collect platform, but not distribution + - name: Test that retrieving hardware facts works and gets prereqs from platform and distribution + when: ansible_system|default("UNDEF") == "Linux" + assert: + # LinuxHardwareCollector requires 'platform' facts + that: + - 'ansible_memory_mb|default("UNDEF") != "UNDEF"' + - 'ansible_default_ipv4|default("UNDEF") == "UNDEF"' + - 'ansible_interfaces|default("UNDEF") == "UNDEF"' + # these are true for linux, but maybe not for other os + # hardware requires 'platform' + - 'ansible_system|default("UNDEF") != "UNDEF"' + - 'ansible_machine|default("UNDEF") != "UNDEF"' + # hardware does not require 'distribution' but it is min set + # - 'ansible_distribution|default("UNDEF") == "UNDEF"' + # we dont really require these but they are in the min set + # - 'ansible_virtualization_role|default("UNDEF") == "UNDEF"' + # - 'ansible_user_id|default("UNDEF") == "UNDEF"' + # - 'ansible_env|default("UNDEF") == "UNDEF"' + # - 'ansible_selinux|default("UNDEF") == "UNDEF"' + # - 'ansible_pkg_mgr|default("UNDEF") == "UNDEF"' + +- name: min and service_mgr test for platform added + hosts: facthost23 + tags: [ 'fact_service_mgr' ] + connection: local + gather_subset: ["!all", "service_mgr"] + gather_facts: yes + tasks: + - name: Test that retrieving service_mgr facts works and gets prereqs from platform and distribution + assert: + that: + - 'ansible_service_mgr|default("UNDEF") != "UNDEF"' + - 'ansible_default_ipv4|default("UNDEF") == "UNDEF"' + - 'ansible_interfaces|default("UNDEF") == "UNDEF"' + # these are true for linux, but maybe not for other os + - 'ansible_system|default("UNDEF") != "UNDEF"' + - 'ansible_distribution|default("UNDEF") != "UNDEF"' + # we dont really require these but they are in the min set + # - 'ansible_virtualization_role|default("UNDEF") == "UNDEF"' + # - 'ansible_user_id|default("UNDEF") == "UNDEF"' + # - 'ansible_env|default("UNDEF") == "UNDEF"' + # - 'ansible_selinux|default("UNDEF") == "UNDEF"' + # - 'ansible_pkg_mgr|default("UNDEF") == "UNDEF"' + +- hosts: facthost0 + tags: [ 'fact_min' ] + connection: local + gather_subset: "all" + gather_facts: yes + tasks: + #- setup: + # register: facts + - name: Test that retrieving all facts works + assert: + that: + - 'ansible_user_id|default("UNDEF_MIN") != "UNDEF_MIN"' + - 'ansible_interfaces|default("UNDEF_NET") != "UNDEF_NET"' + - 'ansible_mounts|default("UNDEF_MOUNT") != "UNDEF_MOUNT" or ansible_distribution == "MacOSX"' + - 'ansible_virtualization_role|default("UNDEF_VIRT") != "UNDEF_VIRT"' + +- hosts: facthost1 + tags: [ 'fact_min' ] + connection: local + gather_facts: no + tasks: + - name: Test that we can retrieve the loadavg fact + setup: + filter: "ansible_loadavg" + + - name: Test the contents of the loadavg fact + assert: + that: + - 'ansible_loadavg|default("UNDEF_ENV") != "UNDEF_ENV"' + - '"1m" in ansible_loadavg and ansible_loadavg["1m"] is float' + - '"5m" in ansible_loadavg and ansible_loadavg["5m"] is float' + - '"15m" in ansible_loadavg and ansible_loadavg["15m"] is float' + +- hosts: facthost19 + tags: [ 'fact_min' ] + connection: local + gather_facts: no + tasks: + - setup: + filter: "*env*" + # register: fact_results + + - name: Test that retrieving all facts filtered to env works + assert: + that: + - 'ansible_interfaces|default("UNDEF_NET") == "UNDEF_NET"' + - 'ansible_mounts|default("UNDEF_MOUNT") == "UNDEF_MOUNT"' + - 'ansible_virtualization_role|default("UNDEF_VIRT") == "UNDEF_VIRT"' + - 'ansible_env|default("UNDEF_ENV") != "UNDEF_ENV"' + +- hosts: facthost24 + tags: [ 'fact_min' ] + connection: local + gather_facts: no + tasks: + - setup: + filter: + - "*env*" + - "*virt*" + + - name: Test that retrieving all facts filtered to env and virt works + assert: + that: + - 'ansible_interfaces|default("UNDEF_NET") == "UNDEF_NET"' + - 'ansible_mounts|default("UNDEF_MOUNT") == "UNDEF_MOUNT"' + - '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 + gather_facts: no + tasks: + - setup: + filter: "ansible_user_id" + # register: fact_results + + - name: Test that retrieving all facts filtered to specific fact ansible_user_id works + assert: + that: + - 'ansible_user_id|default("UNDEF_USER") != "UNDEF_USER"' + - 'ansible_interfaces|default("UNDEF_NET") == "UNDEF_NET"' + - 'ansible_mounts|default("UNDEF_MOUNT") == "UNDEF_MOUNT"' + - 'ansible_virtualization_role|default("UNDEF_VIRT") == "UNDEF_VIRT"' + - 'ansible_env|default("UNDEF_ENV") == "UNDEF_ENV"' + - 'ansible_pkg_mgr|default("UNDEF_PKG_MGR") == "UNDEF_PKG_MGR"' + +- hosts: facthost11 + tags: [ 'fact_min' ] + connection: local + gather_facts: no + tasks: + - setup: + filter: "*" + # register: fact_results + + - name: Test that retrieving all facts filtered to splat + assert: + that: + - 'ansible_user_id|default("UNDEF_MIN") != "UNDEF_MIN"' + - 'ansible_interfaces|default("UNDEF_NET") != "UNDEF_NET"' + - 'ansible_mounts|default("UNDEF_MOUNT") != "UNDEF_MOUNT" or ansible_distribution == "MacOSX"' + - 'ansible_virtualization_role|default("UNDEF_VIRT") != "UNDEF_VIRT"' + +- hosts: facthost12 + tags: [ 'fact_min' ] + connection: local + gather_facts: no + tasks: + - setup: + filter: "" + # register: fact_results + + - name: Test that retrieving all facts filtered to empty filter_spec works + assert: + that: + - 'ansible_user_id|default("UNDEF_MIN") != "UNDEF_MIN"' + - 'ansible_interfaces|default("UNDEF_NET") != "UNDEF_NET"' + - 'ansible_mounts|default("UNDEF_MOUNT") != "UNDEF_MOUNT" or ansible_distribution == "MacOSX"' + - 'ansible_virtualization_role|default("UNDEF_VIRT") != "UNDEF_VIRT"' + +- hosts: facthost1 + tags: [ 'fact_min' ] + connection: local + gather_subset: "!all" + gather_facts: yes + tasks: + - name: Test that only retrieving minimal facts work + assert: + that: + # from the min set, which should still collect + - 'ansible_user_id|default("UNDEF_MIN") != "UNDEF_MIN"' + - 'ansible_env|default("UNDEF_ENV") != "UNDEF_ENV"' + # non min facts that are not collected + - 'ansible_interfaces|default("UNDEF_NET") == "UNDEF_NET"' + - 'ansible_mounts|default("UNDEF_MOUNT") == "UNDEF_MOUNT"' + - 'ansible_virtualization_role|default("UNDEF_VIRT") == "UNDEF_VIRT"' + +- hosts: facthost2 + tags: [ 'fact_network' ] + connection: local + gather_subset: ["!all", "!min", "network"] + gather_facts: yes + tasks: + - name: Test that retrieving network facts work + assert: + that: + - 'ansible_user_id|default("UNDEF") == "UNDEF"' + - 'ansible_interfaces|default("UNDEF_NET") != "UNDEF_NET"' + - 'ansible_mounts|default("UNDEF") == "UNDEF"' + - 'ansible_virtualization_role|default("UNDEF") == "UNDEF"' + +- hosts: facthost3 + tags: [ 'fact_hardware' ] + connection: local + gather_subset: "hardware" + gather_facts: yes + tasks: + - name: Test that retrieving hardware facts work + assert: + that: + - 'ansible_user_id|default("UNDEF_MIN") != "UNDEF_MIN"' + - 'ansible_interfaces|default("UNDEF_NET") == "UNDEF_NET"' + - 'ansible_mounts|default("UNDEF_MOUNT") != "UNDEF_MOUNT" or ansible_distribution == "MacOSX"' + - 'ansible_virtualization_role|default("UNDEF_VIRT") == "UNDEF_VIRT"' + +- hosts: facthost4 + tags: [ 'fact_virtual' ] + connection: local + gather_subset: "virtual" + gather_facts: yes + tasks: + - name: Test that retrieving virtualization facts work + assert: + that: + - 'ansible_user_id|default("UNDEF_MIN") != "UNDEF_MIN"' + - 'ansible_interfaces|default("UNDEF_NET") == "UNDEF_NET"' + - 'ansible_mounts|default("UNDEF_MOUNT") == "UNDEF_MOUNT"' + - 'ansible_virtualization_role|default("UNDEF_VIRT") != "UNDEF_VIRT"' + +- hosts: facthost5 + tags: [ 'fact_comma_string' ] + connection: local + gather_subset: ["virtual", "network"] + gather_facts: yes + tasks: + - name: Test that retrieving virtualization and network as a string works + assert: + that: + - 'ansible_user_id|default("UNDEF_MIN") != "UNDEF_MIN"' + - 'ansible_interfaces|default("UNDEF_NET") != "UNDEF_NET"' + - 'ansible_mounts|default("UNDEF_MOUNT") == "UNDEF_MOUNT"' + - 'ansible_virtualization_role|default("UNDEF_VIRT") != "UNDEF_VIRT"' + +- hosts: facthost6 + tags: [ 'fact_yaml_list' ] + connection: local + gather_subset: + - virtual + - network + gather_facts: yes + tasks: + - name: Test that retrieving virtualization and network as a string works + assert: + that: + - 'ansible_user_id|default("UNDEF_MIN") != "UNDEF_MIN"' + - 'ansible_interfaces|default("UNDEF_NET") != "UNDEF_NET"' + - 'ansible_mounts|default("UNDEF_MOUNT") == "UNDEF_MOUNT"' + - 'ansible_virtualization_role|default("UNDEF_VIRT") != "UNDEF_VIRT"' + + +- hosts: facthost7 + tags: [ 'fact_negation' ] + connection: local + gather_subset: "!hardware" + gather_facts: yes + tasks: + - name: Test that negation of fact subsets work + assert: + that: + # network, not collected since it is not in min + - 'ansible_interfaces|default("UNDEF_NET") == "UNDEF_NET"' + # not collecting virt, should be undef + - 'ansible_virtualization_role|default("UNDEF_VIRT") == "UNDEF_VIRT"' + # mounts/devices are collected by hardware, so should be not collected and undef + - 'ansible_mounts|default("UNDEF_MOUNT") == "UNDEF_MOUNT"' + - 'ansible_devices|default("UNDEF_DEVICES") == "UNDEF_DEVICES"' + # from the min set, which should still collect + - 'ansible_user_id|default("UNDEF_MIN") != "UNDEF_MIN"' + - 'ansible_env|default("UNDEF_ENV") != "UNDEF_ENV"' + +- hosts: facthost8 + tags: [ 'fact_mixed_negation_addition' ] + connection: local + gather_subset: ["!hardware", "network"] + gather_facts: yes + tasks: + - name: Test that negation and additional subsets work together + assert: + that: + - 'ansible_user_id|default("UNDEF_MIN") != "UNDEF_MIN"' + - 'ansible_interfaces|default("UNDEF_NET") != "UNDEF_NET"' + - 'ansible_mounts|default("UNDEF_MOUNT") == "UNDEF_MOUNT"' + - 'ansible_virtualization_role|default("UNDEF_VIRT") == "UNDEF_VIRT"' + +- hosts: facthost14 + tags: [ 'fact_mixed_negation_addition_min' ] + connection: local + gather_subset: ["!all", "!min", "network"] + gather_facts: yes + tasks: + - name: Test that negation and additional subsets work together for min subset + assert: + that: + - 'ansible_user_id|default("UNDEF_MIN") == "UNDEF_MIN"' + - 'ansible_interfaces|default("UNDEF_NET") != "UNDEF_NET"' + - 'ansible_default_ipv4|default("UNDEF_DEFAULT_IPV4") != "UNDEF_DEFAULT_IPV4"' + - 'ansible_all_ipv4_addresses|default("UNDEF_ALL_IPV4") != "UNDEF_ALL_IPV4"' + - 'ansible_mounts|default("UNDEF_MOUNT") == "UNDEF_MOUNT"' + - 'ansible_virtualization_role|default("UNDEF_VIRT") == "UNDEF_VIRT"' + - 'ansible_env|default("UNDEF_ENV") == "UNDEF_ENV"' + +- hosts: facthost15 + tags: [ 'fact_negate_all_min_add_pkg_mgr' ] + connection: local + gather_subset: ["!all", "!min", "pkg_mgr"] + gather_facts: yes + tasks: + - name: Test that negation and additional subsets work together for min subset + assert: + that: + # network, not collected since it is not in min + - 'ansible_interfaces|default("UNDEF_NET") == "UNDEF_NET"' + # not collecting virt, should be undef + - 'ansible_virtualization_role|default("UNDEF_VIRT") == "UNDEF_VIRT"' + # mounts/devices are collected by hardware, so should be not collected and undef + - 'ansible_mounts|default("UNDEF_MOUNT") == "UNDEF_MOUNT"' + - 'ansible_devices|default("UNDEF_DEVICES") == "UNDEF_DEVICES"' + # from the min set, which should not collect + - 'ansible_user_id|default("UNDEF_MIN") == "UNDEF_MIN"' + - 'ansible_env|default("UNDEF_ENV") == "UNDEF_ENV"' + # the pkg_mgr fact we requested explicitly + - 'ansible_pkg_mgr|default("UNDEF_PKG_MGR") != "UNDEF_PKG_MGR"' + + +- hosts: facthost9 + tags: [ 'fact_local'] + connection: local + gather_facts: no + tasks: + - name: Create fact directories + become: true + with_items: + - /etc/ansible/facts.d + - /tmp/custom_facts.d + file: + state: directory + path: "{{ item }}" + mode: '0777' + - name: Deploy local facts + with_items: + - path: /etc/ansible/facts.d/testfact.fact + content: '{ "fact_dir": "default" }' + - path: /tmp/custom_facts.d/testfact.fact + content: '{ "fact_dir": "custom" }' + copy: + dest: "{{ item.path }}" + content: "{{ item.content }}" + +- hosts: facthost9 + tags: [ 'fact_local'] + connection: local + gather_facts: yes + tasks: + - name: Test reading facts from default fact_path + assert: + that: + - '"{{ ansible_local.testfact.fact_dir }}" == "default"' + +- hosts: facthost9 + tags: [ 'fact_local'] + connection: local + gather_facts: yes + fact_path: /tmp/custom_facts.d + tasks: + - name: Test reading facts from custom fact_path + assert: + that: + - '"{{ ansible_local.testfact.fact_dir }}" == "custom"' + +- hosts: facthost20 + tags: [ 'fact_facter_ohai' ] + connection: local + gather_subset: + - facter + - ohai + gather_facts: yes + tasks: + - name: Test that retrieving facter and ohai doesnt fail + assert: + # not much to assert here, aside from not crashing, since test images dont have + # facter/ohai + that: + - 'ansible_user_id|default("UNDEF_MIN") != "UNDEF_MIN"' + +- hosts: facthost9 + tags: [ 'fact_file_utils' ] + connection: local + gather_facts: false + tasks: + - block: + - name: Ensure get_file_content works when strip=False + file_utils: + test: strip + + - assert: + that: + - ansible_facts.get('etc_passwd_newlines', 0) + 1 == ansible_facts.get('etc_passwd_newlines_unstripped', 0) + + - name: Make an empty file + file: + path: "{{ output_dir }}/empty_file" + state: touch + + - name: Ensure get_file_content gives default when file is empty + file_utils: + test: default + touch_file: "{{ output_dir }}/empty_file" + + - assert: + that: + - ansible_facts.get('touch_default') == 'i am a default' + + - copy: + dest: "{{ output_dir }}/1charsep" + content: "foo:bar:baz:buzz:" + + - copy: + dest: "{{ output_dir }}/2charsep" + content: "foo::bar::baz::buzz::" + + - name: Ensure get_file_lines works as expected with specified 1-char line_sep + file_utils: + test: line_sep + line_sep_file: "{{ output_dir }}/1charsep" + line_sep_sep: ":" + + - assert: + that: + - ansible_facts.get('line_sep') == ['foo', 'bar', 'baz', 'buzz'] + + - name: Ensure get_file_lines works as expected with specified 1-char line_sep + file_utils: + test: line_sep + line_sep_file: "{{ output_dir }}/2charsep" + line_sep_sep: "::" + + - assert: + that: + - ansible_facts.get('line_sep') == ['foo', 'bar', 'baz', 'buzz', ''] + + - name: Ensure get_mount_size fails gracefully + file_utils: + test: invalid_mountpoint + + - assert: + that: + - ansible_facts['invalid_mountpoint']|length == 0 + + always: + - name: Remove test files + file: + path: "{{ item }}" + state: absent + with_items: + - "{{ output_dir }}/empty_file" + - "{{ output_dir }}/1charsep" + - "{{ output_dir }}/2charsep" diff --git a/test/integration/targets/gathering_facts/test_module_defaults.yml b/test/integration/targets/gathering_facts/test_module_defaults.yml new file mode 100644 index 0000000..038b8ec --- /dev/null +++ b/test/integration/targets/gathering_facts/test_module_defaults.yml @@ -0,0 +1,130 @@ +--- +- hosts: localhost + # The gather_facts keyword has default values for its + # options so module_defaults doesn't have much affect. + gather_facts: no + tags: + - default_fact_module + tasks: + - name: set defaults for the action plugin + gather_facts: + module_defaults: + gather_facts: + gather_subset: min + + - assert: + that: "gather_subset == ['min']" + + - name: set defaults for the module + gather_facts: + module_defaults: + setup: + gather_subset: '!all' + + - assert: + that: "gather_subset == ['!all']" + + # Defaults for the action plugin win because they are + # loaded first and options need to be omitted for + # defaults to be used. + - name: set defaults for the action plugin and module + gather_facts: + module_defaults: + setup: + gather_subset: '!all' + gather_facts: + gather_subset: min + + - assert: + that: "gather_subset == ['min']" + + # The gather_facts 'smart' facts module is 'ansible.legacy.setup' by default. + # If 'setup' (the unqualified name) is explicitly requested, FQCN module_defaults + # would not apply. + - name: set defaults for the fqcn module + gather_facts: + module_defaults: + ansible.legacy.setup: + gather_subset: '!all' + + - assert: + that: "gather_subset == ['!all']" + +- hosts: localhost + gather_facts: no + tags: + - custom_fact_module + tasks: + - name: set defaults for the module + gather_facts: + module_defaults: + ansible.legacy.setup: + gather_subset: '!all' + + - assert: + that: + - "gather_subset == ['!all']" + + # Defaults for the action plugin win. + - name: set defaults for the action plugin and module + gather_facts: + module_defaults: + gather_facts: + gather_subset: min + ansible.legacy.setup: + gather_subset: '!all' + + - 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 new file mode 100644 index 0000000..064b7a9 --- /dev/null +++ b/test/integration/targets/gathering_facts/test_prevent_injection.yml @@ -0,0 +1,14 @@ +- name: Ensure clean_facts is working properly + hosts: facthost1 + gather_facts: false + tasks: + - name: gather 'bad' facts + action: bogus_facts + + - name: ensure that the 'bad' facts didn't pollute what they are not supposed to + assert: + that: + - "'touch' not in discovered_interpreter_python|default('')" + - "'touch' not in ansible_facts.get('discovered_interpreter_python', '')" + - "'touch' not in ansible_facts.get('ansible_facts', {}).get('discovered_interpreter_python', '')" + - bogus_overwrite is undefined diff --git a/test/integration/targets/gathering_facts/test_run_once.yml b/test/integration/targets/gathering_facts/test_run_once.yml new file mode 100644 index 0000000..37023b2 --- /dev/null +++ b/test/integration/targets/gathering_facts/test_run_once.yml @@ -0,0 +1,32 @@ +--- +- hosts: facthost1 + gather_facts: no + tasks: + - name: check that smart gathering is enabled + fail: + msg: 'smart gathering must be enabled' + when: 'lookup("env", "ANSIBLE_GATHERING") != "smart"' + - name: install test local facts + copy: + src: uuid.fact + dest: /etc/ansible/facts.d/ + mode: 0755 + +- hosts: facthost1,facthost2 + gather_facts: yes + run_once: yes + tasks: + - block: + - name: 'Check the same host is used' + assert: + that: 'hostvars.facthost1.ansible_fqdn == hostvars.facthost2.ansible_fqdn' + msg: 'This test requires 2 inventory hosts referring to the same host.' + - name: "Check that run_once doesn't prevent fact gathering (#39453)" + assert: + that: 'hostvars.facthost1.ansible_local.uuid != hostvars.facthost2.ansible_local.uuid' + msg: "{{ 'Same value for ansible_local.uuid on both hosts: ' ~ hostvars.facthost1.ansible_local.uuid }}" + always: + - name: remove test local facts + file: + path: /etc/ansible/facts.d/uuid.fact + state: absent diff --git a/test/integration/targets/gathering_facts/two_one.json b/test/integration/targets/gathering_facts/two_one.json new file mode 100644 index 0000000..4b34a2d --- /dev/null +++ b/test/integration/targets/gathering_facts/two_one.json @@ -0,0 +1,27 @@ +{ + "_ansible_facts_gathered": true, + "common_dict_fact": { + "key_four": "from facts_two", + "key_one": "from facts_one", + "key_two": "from facts_one" + }, + "common_fact": "also from facts_one module", + "common_list_fact": [ + "two", + "four", + "one", + "three", + "five" + ], + "common_list_fact2": [ + "four", + "four", + "one", + "two", + "three", + "five", + "five" + ], + "factsone": "from facts_one module", + "factstwo": "from facts_two module" +}
\ No newline at end of file diff --git a/test/integration/targets/gathering_facts/uuid.fact b/test/integration/targets/gathering_facts/uuid.fact new file mode 100644 index 0000000..79e3f62 --- /dev/null +++ b/test/integration/targets/gathering_facts/uuid.fact @@ -0,0 +1,10 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + + +import json +import uuid + + +# return a random string +print(json.dumps(str(uuid.uuid4()))) diff --git a/test/integration/targets/gathering_facts/verify_merge_facts.yml b/test/integration/targets/gathering_facts/verify_merge_facts.yml new file mode 100644 index 0000000..d214402 --- /dev/null +++ b/test/integration/targets/gathering_facts/verify_merge_facts.yml @@ -0,0 +1,41 @@ +- name: rune one and two, verify merge is as expected + hosts: localhost + vars: + ansible_facts_modules: + - facts_one + - facts_two + tasks: + + - name: populate original + include_vars: + name: original + file: one_two.json + + - name: fail if ref file is updated + assert: + msg: '{{ansible_facts}} vs {{original}}' + that: + - ansible_facts|to_json(indent=4, sort_keys=True) == original|to_json(indent=4, sort_keys=True) + + - name: clear existing facts for next play + meta: clear_facts + + +- name: rune two and one, verify merge is as expected + hosts: localhost + vars: + ansible_facts_modules: + - facts_two + - facts_one + tasks: + + - name: populate original + include_vars: + name: original + file: two_one.json + + - name: fail if ref file is updated + assert: + msg: '{{ansible_facts}} vs {{original}}' + that: + - ansible_facts|to_json(indent=4, sort_keys=True) == original|to_json(indent=4, sort_keys=True) diff --git a/test/integration/targets/gathering_facts/verify_subset.yml b/test/integration/targets/gathering_facts/verify_subset.yml new file mode 100644 index 0000000..8913275 --- /dev/null +++ b/test/integration/targets/gathering_facts/verify_subset.yml @@ -0,0 +1,13 @@ +- hosts: localhost + gather_facts: false + tasks: + - name: bad subset used + setup: gather_subset=nonsense + register: bad_sub + ignore_errors: true + + - name: verify we fail the right way + assert: + that: + - bad_sub is failed + - "'MODULE FAILURE' not in bad_sub['msg']" |