From 3dde61805ee0fecac2216ee6b0558558be78da2a Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Wed, 30 Aug 2023 13:37:07 -0400 Subject: [PATCH 01/24] constructed inventory add priority to keyed_groups --- lib/ansible/plugins/inventory/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/ansible/plugins/inventory/__init__.py b/lib/ansible/plugins/inventory/__init__.py index 348e8dc8834..a72d29c1d63 100644 --- a/lib/ansible/plugins/inventory/__init__.py +++ b/lib/ansible/plugins/inventory/__init__.py @@ -415,6 +415,7 @@ class Constructable(_BaseInventoryPlugin): if strict: raise AnsibleParserError("Could not generate group for host %s from %s entry: %s" % (host, keyed.get('key'), to_native(e))) continue + group_priority = keyed.get('priority', None) default_value_name = keyed.get('default_value', None) trailing_separator = keyed.get('trailing_separator') if trailing_separator is not None and default_value_name is not None: @@ -466,6 +467,8 @@ class Constructable(_BaseInventoryPlugin): sep = '' gname = self._sanitize_group_name('%s%s%s' % (prefix, sep, bare_name)) result_gname = self.inventory.add_group(gname) + if priority is not None: + result_gname.set_priority(int(priority)) self.inventory.add_host(host, result_gname) if raw_parent_name: From 48026d511dae84df9e38a7cff37ed1e000fad26d Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Wed, 30 Aug 2023 13:40:33 -0400 Subject: [PATCH 02/24] add docs --- lib/ansible/plugins/doc_fragments/constructed.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/ansible/plugins/doc_fragments/constructed.py b/lib/ansible/plugins/doc_fragments/constructed.py index 4e10afce100..d6aaf1b3642 100644 --- a/lib/ansible/plugins/doc_fragments/constructed.py +++ b/lib/ansible/plugins/doc_fragments/constructed.py @@ -58,6 +58,10 @@ options: type: bool default: true version_added: '2.12' + priority: + descrioption: Set group's priority for fine control of variable precedence + type: int + version_Added: '2.16' use_extra_vars: version_added: '2.11' description: Merge extra vars into the available variables for composition (highest precedence). From 63a456187d450ac81342a9c1dbcd59d80e7bed3a Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Thu, 31 Aug 2023 11:11:49 -0400 Subject: [PATCH 03/24] typeo fxi --- lib/ansible/plugins/doc_fragments/constructed.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ansible/plugins/doc_fragments/constructed.py b/lib/ansible/plugins/doc_fragments/constructed.py index d6aaf1b3642..3c14a3c7938 100644 --- a/lib/ansible/plugins/doc_fragments/constructed.py +++ b/lib/ansible/plugins/doc_fragments/constructed.py @@ -61,7 +61,7 @@ options: priority: descrioption: Set group's priority for fine control of variable precedence type: int - version_Added: '2.16' + version_added: '2.16' use_extra_vars: version_added: '2.11' description: Merge extra vars into the available variables for composition (highest precedence). From fee9552bcc4d441d5f71f221c81b50dc74f68730 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Thu, 31 Aug 2023 11:15:34 -0400 Subject: [PATCH 04/24] type check handling --- lib/ansible/plugins/inventory/__init__.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/ansible/plugins/inventory/__init__.py b/lib/ansible/plugins/inventory/__init__.py index a72d29c1d63..46b761edf7a 100644 --- a/lib/ansible/plugins/inventory/__init__.py +++ b/lib/ansible/plugins/inventory/__init__.py @@ -415,7 +415,10 @@ class Constructable(_BaseInventoryPlugin): if strict: raise AnsibleParserError("Could not generate group for host %s from %s entry: %s" % (host, keyed.get('key'), to_native(e))) continue - group_priority = keyed.get('priority', None) + try: + group_priority = int(keyed.get('priority', None)) + except ValueError as e: + raise AnsibleParserError("Invalid group priority given: %s" % to_native(e)) default_value_name = keyed.get('default_value', None) trailing_separator = keyed.get('trailing_separator') if trailing_separator is not None and default_value_name is not None: @@ -467,8 +470,9 @@ class Constructable(_BaseInventoryPlugin): sep = '' gname = self._sanitize_group_name('%s%s%s' % (prefix, sep, bare_name)) result_gname = self.inventory.add_group(gname) - if priority is not None: - result_gname.set_priority(int(priority)) + if group_priority is not None: + result_gname.set_priority(group_priority) + self.inventory.add_host(host, result_gname) if raw_parent_name: From 95858a98230fbe13c02cec4404b3c16e812a02a2 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Thu, 31 Aug 2023 11:17:07 -0400 Subject: [PATCH 05/24] descri be it --- lib/ansible/plugins/doc_fragments/constructed.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ansible/plugins/doc_fragments/constructed.py b/lib/ansible/plugins/doc_fragments/constructed.py index 3c14a3c7938..e59a7b5c99b 100644 --- a/lib/ansible/plugins/doc_fragments/constructed.py +++ b/lib/ansible/plugins/doc_fragments/constructed.py @@ -59,7 +59,7 @@ options: default: true version_added: '2.12' priority: - descrioption: Set group's priority for fine control of variable precedence + description: Set group's priority for fine control of variable precedence type: int version_added: '2.16' use_extra_vars: From 2e07984901c2cb98a9725a7bd66ef3f4e438fa6e Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Thu, 31 Aug 2023 11:24:40 -0400 Subject: [PATCH 06/24] handle none --- lib/ansible/plugins/inventory/__init__.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/ansible/plugins/inventory/__init__.py b/lib/ansible/plugins/inventory/__init__.py index 46b761edf7a..b37ab9b6549 100644 --- a/lib/ansible/plugins/inventory/__init__.py +++ b/lib/ansible/plugins/inventory/__init__.py @@ -415,10 +415,12 @@ class Constructable(_BaseInventoryPlugin): if strict: raise AnsibleParserError("Could not generate group for host %s from %s entry: %s" % (host, keyed.get('key'), to_native(e))) continue - try: - group_priority = int(keyed.get('priority', None)) - except ValueError as e: - raise AnsibleParserError("Invalid group priority given: %s" % to_native(e)) + group_priority = keyed.get('priority', None) + if group_priority is not None: + try: + group_priority = int(group_priority) + except ValueError as e: + raise AnsibleParserError("Invalid group priority given: %s" % to_native(e)) default_value_name = keyed.get('default_value', None) trailing_separator = keyed.get('trailing_separator') if trailing_separator is not None and default_value_name is not None: From ceefcea33625ce5e83ecad491a693d36725c7a23 Mon Sep 17 00:00:00 2001 From: acziryak <106108844+acziryak@users.noreply.github.com> Date: Thu, 19 Oct 2023 16:46:32 -0400 Subject: [PATCH 07/24] Cgroup priority (#13) * Fix setting group priority and add tests Add all the tests to ensure the overrides for priority work as advertised, and fix the set_priority function so that it operates on a group rather than on a string in `__init__.py` * Implement ansible_keyed_group_name Add more comments Add example Change where we're setting the group_priority to allow it to be templated with all available variables and `ansible_keyed_group_name` * Reverse precedence of combining variables * Move group priority to after the `add_host` call in case the group does not exist yet --- .../plugins/doc_fragments/constructed.py | 2 +- lib/ansible/plugins/inventory/__init__.py | 22 +++++++++++-------- lib/ansible/plugins/inventory/constructed.py | 8 +++++++ .../a_keyed_group_priority_3/all.yml | 1 + .../b_keyed_group_priority_2/all.yml | 2 ++ .../c_static_group_priority_1/all.yml | 3 +++ ..._group_str_default_value_with_priority.yml | 11 ++++++++++ .../invs/3/priority_inventory.yml | 7 ++++++ .../targets/inventory_constructed/runme.sh | 21 ++++++++++++++++++ 9 files changed, 67 insertions(+), 10 deletions(-) create mode 100644 test/integration/targets/inventory_constructed/invs/3/group_vars/a_keyed_group_priority_3/all.yml create mode 100644 test/integration/targets/inventory_constructed/invs/3/group_vars/b_keyed_group_priority_2/all.yml create mode 100644 test/integration/targets/inventory_constructed/invs/3/group_vars/c_static_group_priority_1/all.yml create mode 100644 test/integration/targets/inventory_constructed/invs/3/keyed_group_str_default_value_with_priority.yml create mode 100644 test/integration/targets/inventory_constructed/invs/3/priority_inventory.yml diff --git a/lib/ansible/plugins/doc_fragments/constructed.py b/lib/ansible/plugins/doc_fragments/constructed.py index e59a7b5c99b..4d3484b1a25 100644 --- a/lib/ansible/plugins/doc_fragments/constructed.py +++ b/lib/ansible/plugins/doc_fragments/constructed.py @@ -59,7 +59,7 @@ options: default: true version_added: '2.12' priority: - description: Set group's priority for fine control of variable precedence + description: Set group's priority for fine control of variable precedence. type: int version_added: '2.16' use_extra_vars: diff --git a/lib/ansible/plugins/inventory/__init__.py b/lib/ansible/plugins/inventory/__init__.py index b37ab9b6549..a1fbb18f9d0 100644 --- a/lib/ansible/plugins/inventory/__init__.py +++ b/lib/ansible/plugins/inventory/__init__.py @@ -415,12 +415,6 @@ class Constructable(_BaseInventoryPlugin): if strict: raise AnsibleParserError("Could not generate group for host %s from %s entry: %s" % (host, keyed.get('key'), to_native(e))) continue - group_priority = keyed.get('priority', None) - if group_priority is not None: - try: - group_priority = int(group_priority) - except ValueError as e: - raise AnsibleParserError("Invalid group priority given: %s" % to_native(e)) default_value_name = keyed.get('default_value', None) trailing_separator = keyed.get('trailing_separator') if trailing_separator is not None and default_value_name is not None: @@ -472,11 +466,21 @@ class Constructable(_BaseInventoryPlugin): sep = '' gname = self._sanitize_group_name('%s%s%s' % (prefix, sep, bare_name)) result_gname = self.inventory.add_group(gname) - if group_priority is not None: - result_gname.set_priority(group_priority) - self.inventory.add_host(host, result_gname) + # Add `ansible_keyed_group_name` to the variables that we can use to template + templar_variables = combine_vars(variables, {'ansible_keyed_group_name': result_gname}) + self.templar.available_variables = templar_variables + # Template the group_priority. There are not many variables available at this point, + # But what we have should be able to be used here. + group_priority = self.templar.template(keyed.get('priority', None)) + if group_priority is not None: + result_group = self.inventory.groups.get(result_gname) + try: + result_group.set_priority(int(group_priority)) + except ValueError as e: + raise AnsibleParserError("Invalid group priority given: %s" % to_native(e)) + if raw_parent_name: parent_name = self._sanitize_group_name(raw_parent_name) self.inventory.add_group(parent_name) diff --git a/lib/ansible/plugins/inventory/constructed.py b/lib/ansible/plugins/inventory/constructed.py index 6954e3aeab5..02b2fc03184 100644 --- a/lib/ansible/plugins/inventory/constructed.py +++ b/lib/ansible/plugins/inventory/constructed.py @@ -77,6 +77,14 @@ EXAMPLES = r""" # this creates a common parent group for all ec2 availability zones - key: placement.availability_zone parent_group: all_ec2_zones + + # Assuming that there exist `tags` that are assigned to various servers such as 'stuff', 'things', 'status', etc. + # The variable `ansible_keyed_group_name` is exposed to the priority. Its value is the resolved group name once + # it's been completely templated. + - key: tags + prefix: tag + default_value: "running" + priority: "{{ 10 if 'status' in ansible_keyed_group_name else 50 }}" """ import os diff --git a/test/integration/targets/inventory_constructed/invs/3/group_vars/a_keyed_group_priority_3/all.yml b/test/integration/targets/inventory_constructed/invs/3/group_vars/a_keyed_group_priority_3/all.yml new file mode 100644 index 00000000000..cf3a79108fa --- /dev/null +++ b/test/integration/targets/inventory_constructed/invs/3/group_vars/a_keyed_group_priority_3/all.yml @@ -0,0 +1 @@ +override_priority_3: "a_keyed_group_priority_3" diff --git a/test/integration/targets/inventory_constructed/invs/3/group_vars/b_keyed_group_priority_2/all.yml b/test/integration/targets/inventory_constructed/invs/3/group_vars/b_keyed_group_priority_2/all.yml new file mode 100644 index 00000000000..fe004a22ace --- /dev/null +++ b/test/integration/targets/inventory_constructed/invs/3/group_vars/b_keyed_group_priority_2/all.yml @@ -0,0 +1,2 @@ +override_priority_2: "b_keyed_group_priority_2" +override_priority_3: "b_keyed_group_priority_2" diff --git a/test/integration/targets/inventory_constructed/invs/3/group_vars/c_static_group_priority_1/all.yml b/test/integration/targets/inventory_constructed/invs/3/group_vars/c_static_group_priority_1/all.yml new file mode 100644 index 00000000000..c53c1bcaf4d --- /dev/null +++ b/test/integration/targets/inventory_constructed/invs/3/group_vars/c_static_group_priority_1/all.yml @@ -0,0 +1,3 @@ +override_priority_1: "c_static_group_priority_1" +override_priority_2: "c_static_group_priority_1" +override_priority_3: "c_static_group_priority_1" diff --git a/test/integration/targets/inventory_constructed/invs/3/keyed_group_str_default_value_with_priority.yml b/test/integration/targets/inventory_constructed/invs/3/keyed_group_str_default_value_with_priority.yml new file mode 100644 index 00000000000..18783ca91b5 --- /dev/null +++ b/test/integration/targets/inventory_constructed/invs/3/keyed_group_str_default_value_with_priority.yml @@ -0,0 +1,11 @@ +plugin: ansible.builtin.constructed +keyed_groups: + - key: keyed_group_1 + default_value: "priority_2" + prefix: b_keyed_group + priority: 2 + + - key: keyed_group_2 + default_value: "priority_3" + prefix: a_keyed_group + priority: '{{ 3 if "priority_3" in ansible_keyed_group_name else 1 }}' diff --git a/test/integration/targets/inventory_constructed/invs/3/priority_inventory.yml b/test/integration/targets/inventory_constructed/invs/3/priority_inventory.yml new file mode 100644 index 00000000000..695dab16d59 --- /dev/null +++ b/test/integration/targets/inventory_constructed/invs/3/priority_inventory.yml @@ -0,0 +1,7 @@ +all: + children: + c_static_group_priority_1: + hosts: + host0: + keyed_group_1: "" + keyed_group_2: "" diff --git a/test/integration/targets/inventory_constructed/runme.sh b/test/integration/targets/inventory_constructed/runme.sh index 8dc9c4f4d43..6799c909df1 100755 --- a/test/integration/targets/inventory_constructed/runme.sh +++ b/test/integration/targets/inventory_constructed/runme.sh @@ -66,3 +66,24 @@ ansible-inventory -i invs/1/one.yml -i invs/2/constructed.yml --graph | tee out. grep '@c_lola' out.txt grep '@c_group4testing' out.txt + +# Testing the priority +ansible-inventory -i invs/3/priority_inventory.yml -i invs/3/keyed_group_str_default_value_with_priority.yml --list | tee out.txt + +# If we expect the variables to be resolved lexicographically, ('c' would override 'b', which would override 'a') +# then we would expect c_static_group_priority_1 to take precedence. +# However, setting the priorities here is what we're testing, and is indicated in the names of the groups. +# +# If you comment out the priorities of the keyed groups, all of the below will return c_static_group_priority_1 + +# override_priority_1 is ONLY set in c_static_group_priority_1 - so it should not get overridden by any other group +grep '"override_priority_1": "c_static_group_priority_1"' out.txt +# override_priority_2 is set in both c_static_group_priority_1 and b_keyed_group_priority_2 which (as advertised) has a priority +# of 2, which should override c_static_group_priority_1. This means that the value from b_keyed_group_priority_2 should return. +grep '"override_priority_2": "b_keyed_group_priority_2"' out.txt +# override_priority_3 is set in all the groups, which means the group with the highest priority set should win. +# Lexicographically, this would otherwise be c_static_group_priority_1. However, since we set the priority of +# a_keyed_group_priority_3 to 3, we will expect it to override the other two groups, and return its variable. +# Note that a_keyed_group_priority_3 has its priority set with a conditional, so here we are testing our ability +# to set this priority with a variable, including the `ansible_keyed_group_name` variable that we expose. +grep '"override_priority_3": "a_keyed_group_priority_3"' out.txt From 0089cec434b9237ac1ff0ccc9d033336566f89d0 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Thu, 31 Aug 2023 11:56:37 -0400 Subject: [PATCH 08/24] note --- lib/ansible/plugins/inventory/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ansible/plugins/inventory/__init__.py b/lib/ansible/plugins/inventory/__init__.py index a1fbb18f9d0..a54a0d69715 100644 --- a/lib/ansible/plugins/inventory/__init__.py +++ b/lib/ansible/plugins/inventory/__init__.py @@ -415,6 +415,7 @@ class Constructable(_BaseInventoryPlugin): if strict: raise AnsibleParserError("Could not generate group for host %s from %s entry: %s" % (host, keyed.get('key'), to_native(e))) continue + default_value_name = keyed.get('default_value', None) trailing_separator = keyed.get('trailing_separator') if trailing_separator is not None and default_value_name is not None: From 40e2578a773c9c743ddd49ed60bcbbc855523864 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Thu, 19 Oct 2023 17:47:47 -0400 Subject: [PATCH 09/24] up v --- lib/ansible/plugins/doc_fragments/constructed.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ansible/plugins/doc_fragments/constructed.py b/lib/ansible/plugins/doc_fragments/constructed.py index 4d3484b1a25..35dab615f8b 100644 --- a/lib/ansible/plugins/doc_fragments/constructed.py +++ b/lib/ansible/plugins/doc_fragments/constructed.py @@ -61,7 +61,7 @@ options: priority: description: Set group's priority for fine control of variable precedence. type: int - version_added: '2.16' + version_added: '2.17' use_extra_vars: version_added: '2.11' description: Merge extra vars into the available variables for composition (highest precedence). From 8e55ce9d0ebeb89d504cabbb434655934f64dac5 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Thu, 26 Oct 2023 10:57:31 -0400 Subject: [PATCH 10/24] clog --- changelogs/fragments/constructed_priority.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 changelogs/fragments/constructed_priority.yml diff --git a/changelogs/fragments/constructed_priority.yml b/changelogs/fragments/constructed_priority.yml new file mode 100644 index 00000000000..613a10f3a1b --- /dev/null +++ b/changelogs/fragments/constructed_priority.yml @@ -0,0 +1,2 @@ +minor_changes: + - Constructed inventory (and those that inherit from it) can now set group priority on keyed_groups. From 3ca19028a4ed703211d01e3365911972caccf814 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Thu, 26 Oct 2023 10:58:39 -0400 Subject: [PATCH 11/24] updated clog --- changelogs/fragments/constructed_priority.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/changelogs/fragments/constructed_priority.yml b/changelogs/fragments/constructed_priority.yml index 613a10f3a1b..e5b554f2d59 100644 --- a/changelogs/fragments/constructed_priority.yml +++ b/changelogs/fragments/constructed_priority.yml @@ -1,2 +1,3 @@ minor_changes: - - Constructed inventory (and those that inherit from it) can now set group priority on keyed_groups. + - The constructed inventory plugin (and those that inherit from it) can now set group priority on keyed_groups. + - The constructed inventnory plugin group priority is templatable and can use the `ansbile_keyed_group_name` special variable to refer to it's own keyed_group entry resolution. From e53e787d57cda2ba75d364c4af2311c734e66ab6 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Thu, 26 Oct 2023 11:00:01 -0400 Subject: [PATCH 12/24] more comments on special var --- lib/ansible/plugins/doc_fragments/constructed.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/ansible/plugins/doc_fragments/constructed.py b/lib/ansible/plugins/doc_fragments/constructed.py index 35dab615f8b..b2c7b658017 100644 --- a/lib/ansible/plugins/doc_fragments/constructed.py +++ b/lib/ansible/plugins/doc_fragments/constructed.py @@ -59,7 +59,9 @@ options: default: true version_added: '2.12' priority: - description: Set group's priority for fine control of variable precedence. + description: + - Set group's priority for fine control of variable precedence. + - The ``ansible_keyed_group_name`` variable that reflects the current keyed_group name, is available for templating this value. type: int version_added: '2.17' use_extra_vars: From 0260027ddae9a165afe2613f7166d0eac64891f8 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Thu, 26 Oct 2023 14:18:22 -0400 Subject: [PATCH 13/24] topey --- changelogs/fragments/constructed_priority.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelogs/fragments/constructed_priority.yml b/changelogs/fragments/constructed_priority.yml index e5b554f2d59..8261e7fd716 100644 --- a/changelogs/fragments/constructed_priority.yml +++ b/changelogs/fragments/constructed_priority.yml @@ -1,3 +1,3 @@ minor_changes: - The constructed inventory plugin (and those that inherit from it) can now set group priority on keyed_groups. - - The constructed inventnory plugin group priority is templatable and can use the `ansbile_keyed_group_name` special variable to refer to it's own keyed_group entry resolution. + - The constructed inventory plugin group priority is templatable and can use the `ansbile_keyed_group_name` special variable to refer to it's own keyed_group entry resolution. From 905630a3a00fb615107406a1edb4d171dee9878d Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Thu, 26 Oct 2023 14:29:04 -0400 Subject: [PATCH 14/24] Update lib/ansible/plugins/inventory/__init__.py Co-authored-by: Matt Davis <6775756+nitzmahone@users.noreply.github.com> --- lib/ansible/plugins/inventory/__init__.py | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/lib/ansible/plugins/inventory/__init__.py b/lib/ansible/plugins/inventory/__init__.py index a54a0d69715..e9923ed26b2 100644 --- a/lib/ansible/plugins/inventory/__init__.py +++ b/lib/ansible/plugins/inventory/__init__.py @@ -469,19 +469,13 @@ class Constructable(_BaseInventoryPlugin): result_gname = self.inventory.add_group(gname) self.inventory.add_host(host, result_gname) - # Add `ansible_keyed_group_name` to the variables that we can use to template - templar_variables = combine_vars(variables, {'ansible_keyed_group_name': result_gname}) - self.templar.available_variables = templar_variables - # Template the group_priority. There are not many variables available at this point, - # But what we have should be able to be used here. - group_priority = self.templar.template(keyed.get('priority', None)) - if group_priority is not None: - result_group = self.inventory.groups.get(result_gname) - try: - result_group.set_priority(int(group_priority)) - except ValueError as e: - raise AnsibleParserError("Invalid group priority given: %s" % to_native(e)) - + if (priority := keyed.get('priority')) is not None: + with self.templar.set_temporary_context(available_variables=variables | {'ansible_keyed_group_name': result_gname}): + if (priority := self.templar.template(priority)) is not None: + try: + self.inventory.groups.get(result_gname).set_priority(priority) + except ValueError as ve: + raise AnsibleParserError(f"Invalid group priority given: {ve}") if raw_parent_name: parent_name = self._sanitize_group_name(raw_parent_name) self.inventory.add_group(parent_name) From 2cd8fe92e450ea70de453bc28aff1ec0044b6b85 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Mon, 13 Nov 2023 12:41:27 -0500 Subject: [PATCH 15/24] Update changelogs/fragments/constructed_priority.yml Co-authored-by: Matt Davis <6775756+nitzmahone@users.noreply.github.com> --- changelogs/fragments/constructed_priority.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelogs/fragments/constructed_priority.yml b/changelogs/fragments/constructed_priority.yml index 8261e7fd716..05fdb8f8072 100644 --- a/changelogs/fragments/constructed_priority.yml +++ b/changelogs/fragments/constructed_priority.yml @@ -1,3 +1,3 @@ minor_changes: - The constructed inventory plugin (and those that inherit from it) can now set group priority on keyed_groups. - - The constructed inventory plugin group priority is templatable and can use the `ansbile_keyed_group_name` special variable to refer to it's own keyed_group entry resolution. + - The constructed inventory plugin group priority is templatable and can use the `ansible_keyed_group_name` special variable to refer to it's own keyed_group entry resolution. From 7e1156d3ed3bb1b4d449170f0d3b9a23d92e1bde Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Mon, 13 Nov 2023 12:41:34 -0500 Subject: [PATCH 16/24] Update lib/ansible/plugins/doc_fragments/constructed.py Co-authored-by: Matt Davis <6775756+nitzmahone@users.noreply.github.com> --- lib/ansible/plugins/doc_fragments/constructed.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ansible/plugins/doc_fragments/constructed.py b/lib/ansible/plugins/doc_fragments/constructed.py index b2c7b658017..627eabdafff 100644 --- a/lib/ansible/plugins/doc_fragments/constructed.py +++ b/lib/ansible/plugins/doc_fragments/constructed.py @@ -61,7 +61,7 @@ options: priority: description: - Set group's priority for fine control of variable precedence. - - The ``ansible_keyed_group_name`` variable that reflects the current keyed_group name, is available for templating this value. + - The ``ansible_keyed_group_name`` variable that reflects the current keyed_group name is available for templating this value. type: int version_added: '2.17' use_extra_vars: From aecffb0d8050bffe11060ea28e9af7c6e86f3ab6 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Fri, 17 Nov 2023 11:41:13 -0500 Subject: [PATCH 17/24] lets try this --- .../plugins/doc_fragments/constructed.py | 7 ++-- lib/ansible/plugins/inventory/__init__.py | 18 ++++++----- lib/ansible/plugins/inventory/constructed.py | 32 +++++++++++++++++-- ..._group_str_default_value_with_priority.yml | 6 ++-- 4 files changed, 47 insertions(+), 16 deletions(-) diff --git a/lib/ansible/plugins/doc_fragments/constructed.py b/lib/ansible/plugins/doc_fragments/constructed.py index 627eabdafff..958b898a975 100644 --- a/lib/ansible/plugins/doc_fragments/constructed.py +++ b/lib/ansible/plugins/doc_fragments/constructed.py @@ -58,11 +58,10 @@ options: type: bool default: true version_added: '2.12' - priority: + vars: description: - - Set group's priority for fine control of variable precedence. - - The ``ansible_keyed_group_name`` variable that reflects the current keyed_group name is available for templating this value. - type: int + - Set variables for this group + type: dict version_added: '2.17' use_extra_vars: version_added: '2.11' diff --git a/lib/ansible/plugins/inventory/__init__.py b/lib/ansible/plugins/inventory/__init__.py index e9923ed26b2..c39e30c8749 100644 --- a/lib/ansible/plugins/inventory/__init__.py +++ b/lib/ansible/plugins/inventory/__init__.py @@ -407,6 +407,11 @@ class Constructable(_BaseInventoryPlugin): for keyed in keys: if keyed and isinstance(keyed, dict): + group_vars = keyed.get('vars', {}) + if group_vars: + # allow using group vars for templating + variables = combine_vars(variables, group_vars) + if fetch_hostvars: variables = combine_vars(variables, self.inventory.get_host(host).get_vars()) try: @@ -469,18 +474,15 @@ class Constructable(_BaseInventoryPlugin): result_gname = self.inventory.add_group(gname) self.inventory.add_host(host, result_gname) - if (priority := keyed.get('priority')) is not None: - with self.templar.set_temporary_context(available_variables=variables | {'ansible_keyed_group_name': result_gname}): - if (priority := self.templar.template(priority)) is not None: - try: - self.inventory.groups.get(result_gname).set_priority(priority) - except ValueError as ve: - raise AnsibleParserError(f"Invalid group priority given: {ve}") + # set group variables + gobj = self.inventory.groups.get(result_gname) + for gvar in group_vars: + gobj.set_variable(gvar, group_vars[gvar]) + if raw_parent_name: parent_name = self._sanitize_group_name(raw_parent_name) self.inventory.add_group(parent_name) self.inventory.add_child(parent_name, result_gname) - else: # exclude case of empty list and dictionary, because these are valid constructions # simply no groups need to be constructed, but are still falsy diff --git a/lib/ansible/plugins/inventory/constructed.py b/lib/ansible/plugins/inventory/constructed.py index 02b2fc03184..a5e1379afd9 100644 --- a/lib/ansible/plugins/inventory/constructed.py +++ b/lib/ansible/plugins/inventory/constructed.py @@ -31,6 +31,12 @@ DOCUMENTATION = """ default: false type: boolean version_added: '2.11' + group_vars: + description: dictionary of dictionaries, the top keys are group names, the dictionaries withtin are variables for that group. + required: false + type: dict + default: {} + version_added: '2.17' extends_documentation_fragment: - constructed """ @@ -79,12 +85,27 @@ EXAMPLES = r""" parent_group: all_ec2_zones # Assuming that there exist `tags` that are assigned to various servers such as 'stuff', 'things', 'status', etc. - # The variable `ansible_keyed_group_name` is exposed to the priority. Its value is the resolved group name once - # it's been completely templated. + # also add vars directly to these groups - key: tags prefix: tag default_value: "running" priority: "{{ 10 if 'status' in ansible_keyed_group_name else 50 }}" + vars: + ansible_group_priority: '{{ *'status' in tags)|ternary(10, 30)}}' + allowed_ssh_groups: qa,ops + group_origin: tags + + group_vars: + # group names: mapped to variables for those groups + all: + ntpserver: 'ntp.{{ansible_facts['domain']}}' + webservers: + open_ports: 80,8080,443 + allowed_ssh_groups: webdevs,qa,ops + dbservers: + open_ports: 1283 + allowed_ssh_groups: dbas,qa,ops + ansible_group_priority: 111 """ import os @@ -179,5 +200,12 @@ class InventoryModule(BaseInventoryPlugin, Constructable): # constructed groups based variable values self._add_host_to_keyed_groups(self.get_option('keyed_groups'), hostvars, host, strict=strict, fetch_hostvars=False) + # handle group vars + groups = self.get_option('group_vars') + for group in groups.keys(): + gobj = self.inventory.groups.get(group) + for gvar in groups[group].keys(): + gobj.set_variable(gvar, groups[group][gvar] + except Exception as ex: raise AnsibleParserError(f"Failed to parse {path!r}.") from ex diff --git a/test/integration/targets/inventory_constructed/invs/3/keyed_group_str_default_value_with_priority.yml b/test/integration/targets/inventory_constructed/invs/3/keyed_group_str_default_value_with_priority.yml index 18783ca91b5..d7300c3da21 100644 --- a/test/integration/targets/inventory_constructed/invs/3/keyed_group_str_default_value_with_priority.yml +++ b/test/integration/targets/inventory_constructed/invs/3/keyed_group_str_default_value_with_priority.yml @@ -3,9 +3,11 @@ keyed_groups: - key: keyed_group_1 default_value: "priority_2" prefix: b_keyed_group - priority: 2 + vars: + ansible_group_priority: 2 - key: keyed_group_2 default_value: "priority_3" prefix: a_keyed_group - priority: '{{ 3 if "priority_3" in ansible_keyed_group_name else 1 }}' + vars: + ansilbe_group_priority: '{{ 3 if "priority_3" in keyed_group_2 else 1 }}' From 667a57a5621489dd17e0ed08ea3e6e55a5b5eb00 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Fri, 17 Nov 2023 11:47:49 -0500 Subject: [PATCH 18/24] one function to rule em all --- lib/ansible/plugins/inventory/__init__.py | 11 +++++++---- lib/ansible/plugins/inventory/constructed.py | 6 ++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/ansible/plugins/inventory/__init__.py b/lib/ansible/plugins/inventory/__init__.py index c39e30c8749..049bd9be1bd 100644 --- a/lib/ansible/plugins/inventory/__init__.py +++ b/lib/ansible/plugins/inventory/__init__.py @@ -299,6 +299,12 @@ class _BaseInventoryPlugin(AnsiblePlugin): return (hostnames, port) + def _set_group_vars(group_name, gvars): + + gobj = self.inventory.groups.get(group_name) + for gvar in gvars: + gobj.set_variable(gvar, gvars[gvar]) + class BaseInventoryPlugin(_BaseInventoryPlugin): """ Parses an Inventory Source """ @@ -474,10 +480,7 @@ class Constructable(_BaseInventoryPlugin): result_gname = self.inventory.add_group(gname) self.inventory.add_host(host, result_gname) - # set group variables - gobj = self.inventory.groups.get(result_gname) - for gvar in group_vars: - gobj.set_variable(gvar, group_vars[gvar]) + self._set_group_vars(result_gname, group_vars) if raw_parent_name: parent_name = self._sanitize_group_name(raw_parent_name) diff --git a/lib/ansible/plugins/inventory/constructed.py b/lib/ansible/plugins/inventory/constructed.py index a5e1379afd9..d3f690bfdb7 100644 --- a/lib/ansible/plugins/inventory/constructed.py +++ b/lib/ansible/plugins/inventory/constructed.py @@ -202,10 +202,8 @@ class InventoryModule(BaseInventoryPlugin, Constructable): # handle group vars groups = self.get_option('group_vars') - for group in groups.keys(): - gobj = self.inventory.groups.get(group) - for gvar in groups[group].keys(): - gobj.set_variable(gvar, groups[group][gvar] + for group_name in groups.keys(): + self._set_group_vars(group_name, groups[group_name]) except Exception as ex: raise AnsibleParserError(f"Failed to parse {path!r}.") from ex From 11724ff4303f1b6a822c05ea8d3188be560d49d8 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Fri, 17 Nov 2023 11:53:01 -0500 Subject: [PATCH 19/24] updated clog --- changelogs/fragments/constructed_priority.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/changelogs/fragments/constructed_priority.yml b/changelogs/fragments/constructed_priority.yml index 05fdb8f8072..25f9e51937e 100644 --- a/changelogs/fragments/constructed_priority.yml +++ b/changelogs/fragments/constructed_priority.yml @@ -1,3 +1,3 @@ minor_changes: - - The constructed inventory plugin (and those that inherit from it) can now set group priority on keyed_groups. - - The constructed inventory plugin group priority is templatable and can use the `ansible_keyed_group_name` special variable to refer to it's own keyed_group entry resolution. + - The ``Constructed`` base class (and plugin) no has a ``vars`` key in the ``keyed_groups`` option, so users can add vars directly w/o need of a 2nd inventory or vars plugin or guessing group names. + - The ``constructed`` inventory plugin also now can have an option ``group_vars`` to allow for assiging vars to groups w/o the need of a 2nd inventory or vars plugin. From e6c8569fa3976d919dd759dfbd370c71a3d29e34 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Fri, 17 Nov 2023 11:56:51 -0500 Subject: [PATCH 20/24] selfish!! --- lib/ansible/plugins/inventory/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ansible/plugins/inventory/__init__.py b/lib/ansible/plugins/inventory/__init__.py index 049bd9be1bd..0b963fab7e4 100644 --- a/lib/ansible/plugins/inventory/__init__.py +++ b/lib/ansible/plugins/inventory/__init__.py @@ -299,7 +299,7 @@ class _BaseInventoryPlugin(AnsiblePlugin): return (hostnames, port) - def _set_group_vars(group_name, gvars): + def _set_group_vars(self, group_name, gvars): gobj = self.inventory.groups.get(group_name) for gvar in gvars: From 402ef22f31408cf5e1c110d9b95dfec16e5bedcd Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Fri, 17 Nov 2023 12:53:29 -0500 Subject: [PATCH 21/24] Update test/integration/targets/inventory_constructed/invs/3/keyed_group_str_default_value_with_priority.yml Co-authored-by: Matt Davis <6775756+nitzmahone@users.noreply.github.com> --- .../invs/3/keyed_group_str_default_value_with_priority.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/targets/inventory_constructed/invs/3/keyed_group_str_default_value_with_priority.yml b/test/integration/targets/inventory_constructed/invs/3/keyed_group_str_default_value_with_priority.yml index d7300c3da21..446b6fee1eb 100644 --- a/test/integration/targets/inventory_constructed/invs/3/keyed_group_str_default_value_with_priority.yml +++ b/test/integration/targets/inventory_constructed/invs/3/keyed_group_str_default_value_with_priority.yml @@ -10,4 +10,4 @@ keyed_groups: default_value: "priority_3" prefix: a_keyed_group vars: - ansilbe_group_priority: '{{ 3 if "priority_3" in keyed_group_2 else 1 }}' + ansible_group_priority: '{{ 3 if "priority_3" in keyed_group_2 else 1 }}' From 0b9192c2837e2e343582f98c95b09e8329f80bb6 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Fri, 17 Nov 2023 12:59:53 -0500 Subject: [PATCH 22/24] quoteit --- lib/ansible/plugins/inventory/constructed.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ansible/plugins/inventory/constructed.py b/lib/ansible/plugins/inventory/constructed.py index d3f690bfdb7..666823fc7ed 100644 --- a/lib/ansible/plugins/inventory/constructed.py +++ b/lib/ansible/plugins/inventory/constructed.py @@ -91,7 +91,7 @@ EXAMPLES = r""" default_value: "running" priority: "{{ 10 if 'status' in ansible_keyed_group_name else 50 }}" vars: - ansible_group_priority: '{{ *'status' in tags)|ternary(10, 30)}}' + ansible_group_priority: '{{ "status" in tags)|ternary(10, 30)}}' allowed_ssh_groups: qa,ops group_origin: tags From 1a0b3b78a3693cd3bb8f096300821877a30d502a Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Thu, 28 Mar 2024 15:00:30 -0400 Subject: [PATCH 23/24] fixes --- lib/ansible/plugins/inventory/constructed.py | 2 +- .../invs/3/keyed_group_str_default_value_with_priority.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ansible/plugins/inventory/constructed.py b/lib/ansible/plugins/inventory/constructed.py index 666823fc7ed..fd9ead7018d 100644 --- a/lib/ansible/plugins/inventory/constructed.py +++ b/lib/ansible/plugins/inventory/constructed.py @@ -98,7 +98,7 @@ EXAMPLES = r""" group_vars: # group names: mapped to variables for those groups all: - ntpserver: 'ntp.{{ansible_facts['domain']}}' + ntpserver: "ntp.{{ansible_facts['domain']}}" webservers: open_ports: 80,8080,443 allowed_ssh_groups: webdevs,qa,ops diff --git a/test/integration/targets/inventory_constructed/invs/3/keyed_group_str_default_value_with_priority.yml b/test/integration/targets/inventory_constructed/invs/3/keyed_group_str_default_value_with_priority.yml index 446b6fee1eb..edfbac0807f 100644 --- a/test/integration/targets/inventory_constructed/invs/3/keyed_group_str_default_value_with_priority.yml +++ b/test/integration/targets/inventory_constructed/invs/3/keyed_group_str_default_value_with_priority.yml @@ -10,4 +10,4 @@ keyed_groups: default_value: "priority_3" prefix: a_keyed_group vars: - ansible_group_priority: '{{ 3 if "priority_3" in keyed_group_2 else 1 }}' + ansible_group_priority: '{{("priority_3" in keyed_group_2)|ternary(3, 1)}}' From dd10d80914aea774b9dfae6d7eff33a3c5bc185d Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Tue, 9 Apr 2024 09:33:38 -0400 Subject: [PATCH 24/24] bumped version --- lib/ansible/plugins/doc_fragments/constructed.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ansible/plugins/doc_fragments/constructed.py b/lib/ansible/plugins/doc_fragments/constructed.py index 958b898a975..8e091123f9a 100644 --- a/lib/ansible/plugins/doc_fragments/constructed.py +++ b/lib/ansible/plugins/doc_fragments/constructed.py @@ -62,7 +62,7 @@ options: description: - Set variables for this group type: dict - version_added: '2.17' + version_added: '2.18' use_extra_vars: version_added: '2.11' description: Merge extra vars into the available variables for composition (highest precedence).