From afb5e02c19c5270c9452177ddd29a99fb6253578 Mon Sep 17 00:00:00 2001 From: Sloane Hertel Date: Thu, 18 Apr 2019 15:54:03 -0400 Subject: [PATCH] preserve same order as inventory manager when using host lookup (#55331) * preserve same order as inventory manager when using inventory_hostnames lookup add a test * move generic code --- lib/ansible/inventory/manager.py | 4 ++-- lib/ansible/plugins/lookup/inventory_hostnames.py | 3 ++- lib/ansible/utils/helpers.py | 8 ++++++++ .../targets/lookup_inventory_hostnames/aliases | 1 + .../targets/lookup_inventory_hostnames/inventory | 6 ++++++ .../targets/lookup_inventory_hostnames/main.yml | 13 +++++++++++++ .../targets/lookup_inventory_hostnames/runme.sh | 5 +++++ 7 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 test/integration/targets/lookup_inventory_hostnames/aliases create mode 100644 test/integration/targets/lookup_inventory_hostnames/inventory create mode 100644 test/integration/targets/lookup_inventory_hostnames/main.yml create mode 100755 test/integration/targets/lookup_inventory_hostnames/runme.sh 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 "$@"