diff --git a/changelogs/fragments/31735-fix-hostnames-lookup-order.yaml b/changelogs/fragments/31735-fix-hostnames-lookup-order.yaml new file mode 100644 index 00000000000..fe90db33b68 --- /dev/null +++ b/changelogs/fragments/31735-fix-hostnames-lookup-order.yaml @@ -0,0 +1,2 @@ +bugfixes: + - inventory_hostnames lookup - use the same order for the returned hosts as the inventory manager diff --git a/lib/ansible/inventory/manager.py b/lib/ansible/inventory/manager.py index 10785aa7938..cc43e4e4682 100644 --- a/lib/ansible/inventory/manager.py +++ b/lib/ansible/inventory/manager.py @@ -36,6 +36,7 @@ from ansible.module_utils.six import string_types from ansible.module_utils._text import to_bytes, to_text from ansible.parsing.utils.addresses import parse_address from ansible.plugins.loader import inventory_loader +from ansible.utils.helpers import deduplicate_list from ansible.utils.path import unfrackpath from ansible.utils.display import Display @@ -369,8 +370,7 @@ class InventoryManager(object): # exclude hosts mentioned in any restriction (ex: failed hosts) hosts = [h for h in hosts if h.name in self._restriction] - seen = set() - self._hosts_patterns_cache[pattern_hash] = [x for x in hosts if x not in seen and not seen.add(x)] + self._hosts_patterns_cache[pattern_hash] = deduplicate_list(hosts) # sort hosts list if needed (should only happen when called from strategy) if order in ['sorted', 'reverse_sorted']: diff --git a/lib/ansible/plugins/lookup/inventory_hostnames.py b/lib/ansible/plugins/lookup/inventory_hostnames.py index f04cd8ff326..001abdbab39 100644 --- a/lib/ansible/plugins/lookup/inventory_hostnames.py +++ b/lib/ansible/plugins/lookup/inventory_hostnames.py @@ -36,6 +36,7 @@ RETURN = """ from ansible.inventory.manager import split_host_pattern, order_patterns from ansible.plugins.lookup import LookupBase +from ansible.utils.helpers import deduplicate_list class LookupModule(LookupBase): @@ -70,4 +71,4 @@ class LookupModule(LookupBase): host_list.extend(that) # return unique list - return list(set(host_list)) + return deduplicate_list(host_list) diff --git a/lib/ansible/utils/helpers.py b/lib/ansible/utils/helpers.py index 900e0d1ac3a..658ad99c968 100644 --- a/lib/ansible/utils/helpers.py +++ b/lib/ansible/utils/helpers.py @@ -41,3 +41,11 @@ def object_to_dict(obj, exclude=None): if exclude is None or not isinstance(exclude, list): exclude = [] return dict((key, getattr(obj, key)) for key in dir(obj) if not (key.startswith('_') or key in exclude)) + + +def deduplicate_list(original_list): + """ + Creates a deduplicated list with the order in which each item is first found. + """ + seen = set() + return [x for x in original_list if x not in seen and not seen.add(x)] diff --git a/test/integration/targets/lookup_inventory_hostnames/aliases b/test/integration/targets/lookup_inventory_hostnames/aliases new file mode 100644 index 00000000000..765b70da796 --- /dev/null +++ b/test/integration/targets/lookup_inventory_hostnames/aliases @@ -0,0 +1 @@ +shippable/posix/group2 diff --git a/test/integration/targets/lookup_inventory_hostnames/inventory b/test/integration/targets/lookup_inventory_hostnames/inventory new file mode 100644 index 00000000000..1b968af2991 --- /dev/null +++ b/test/integration/targets/lookup_inventory_hostnames/inventory @@ -0,0 +1,6 @@ +[group01] +test01 +test05 +test03 +test02 +test04 diff --git a/test/integration/targets/lookup_inventory_hostnames/main.yml b/test/integration/targets/lookup_inventory_hostnames/main.yml new file mode 100644 index 00000000000..afc09ea86e3 --- /dev/null +++ b/test/integration/targets/lookup_inventory_hostnames/main.yml @@ -0,0 +1,13 @@ +--- +- hosts: localhost + gather_facts: no + tasks: + - set_fact: + hosts_a: "{{ lookup('inventory_hostnames', 'group01', wantlist=true) }}" + + - set_fact: + hosts_b: "{{ groups['group01'] }}" + + - assert: + that: + - hosts_a == hosts_b diff --git a/test/integration/targets/lookup_inventory_hostnames/runme.sh b/test/integration/targets/lookup_inventory_hostnames/runme.sh new file mode 100755 index 00000000000..8f4b7231915 --- /dev/null +++ b/test/integration/targets/lookup_inventory_hostnames/runme.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -eux + +ansible-playbook main.yml -i inventory -e "$@"