script inventory plugin correct error message (#85765) (#85868)

type was reflecting 'converted' type, not 'pre conversion' of the data
now message points at specific data keys
add deprecation tests

(cherry picked from commit c87dc6ed7d)
This commit is contained in:
Brian Coca
2025-09-29 13:19:39 -07:00
committed by GitHub
parent 3f7210d00a
commit 06900bbbac
6 changed files with 122 additions and 98 deletions
@@ -0,0 +1,2 @@
bugfixes:
- script inventory plugin will now show correct 'incorrect' type when doing implicit conversions on groups.
+2 -1
View File
@@ -256,9 +256,10 @@ class InventoryModule(BaseInventoryPlugin):
group = self.inventory.add_group(group)
if not isinstance(data, dict):
original_type = native_type_name(data)
data = {'hosts': data}
display.deprecated(
msg=f"Group {group!r} was converted to {native_type_name(dict)!r} from {native_type_name(data)!r}.",
msg=f"Group {group!r} was converted to {native_type_name(dict)!r} from {original_type!r}.",
version='2.23',
obj=origin,
)
+13
View File
@@ -0,0 +1,13 @@
#!/bin/sh
echo '{
"good_group": {
"vars": {
"test1": "value1",
"test2": "value2"
},
"hosts": ["example1", "example2"]
},
"bad_group": "should be list",
"_meta": {}
}'
@@ -1,95 +1,103 @@
- name: run valid script output test cases
include_tasks: test_valid_inventory.yml
loop:
- mode: no_profile
show_stderr: '1'
emit_stderr: '1'
assertions: &standard_assertions
- inventory_data | length == 5
- inventory_data._meta | length == 2
- inventory_data._meta.hostvars.host1.a_host1_hostvar == "avalue"
- inventory_data._meta.hostvars.host1.a_host1_hostvar is ansible._protomatter.tagged_with "TrustedAsTemplate"
- inventory_data._meta.hostvars.localhost.a_localhost_hostvar == "avalue"
- inventory_data._meta.hostvars.localhost.a_localhost_hostvar is ansible._protomatter.tagged_with "TrustedAsTemplate"
- inventory_data.all | length == 1
- inventory_data.all.children | symmetric_difference(["ungrouped", "group1", "empty_group", "list_as_group", "rewrite_as_host"]) | length == 0
- inventory_data.group1 | length == 2
- inventory_data.group1.hosts == ["host1"]
- inventory_data.group1.vars | length == 2
- inventory_data.group1.vars.a_group1_groupvar == "avalue"
- inventory_data.group1.vars.a_group1_groupvar is ansible._protomatter.tagged_with "TrustedAsTemplate"
- inventory_data.group1.vars.group1_untrusted_var == "untrusted value"
- inventory_data.group1.vars.group1_untrusted_var is not ansible._protomatter.tagged_with "TrustedAsTemplate"
- inventory_data.rewrite_as_host | length == 2
- inventory_data.rewrite_as_host.hosts == ["rewrite_as_host"]
- inventory_data.rewrite_as_host.vars.avar == "value"
- inventory_data.rewrite_as_host.vars.avar is not ansible._protomatter.tagged_with "TrustedAsTemplate" # rewritten groups are too hard to trust and are deprecated
- inv_out.stderr is contains "Treating malformed group 'rewrite_as_host'"
- inventory_data.rewrite_as_host.vars.untrusted_var == "untrusted value"
- inventory_data.rewrite_as_host.vars.untrusted_var is not ansible._protomatter.tagged_with "TrustedAsTemplate"
- inventory_data.ungrouped | length == 1
- inventory_data.ungrouped.hosts == ["localhost"]
- mode: with_profile
show_stderr: '1'
assertions: *standard_assertions
- mode: no_hosts
assertions:
- inventory_data | length == 2
- inventory_data._meta.hostvars == {}
- inventory_data.all | length == 1
- inventory_data.all.children == ["ungrouped"]
- mode: no_meta_hostvars
assertions:
- inventory_data | length == 3
- inventory_data._meta.hostvars | length == 1
- inventory_data._meta.hostvars.myhost.avar == "avalue"
- inventory_data._meta.hostvars.myhost.avar is ansible._protomatter.tagged_with "TrustedAsTemplate"
- inventory_data._meta.hostvars.myhost.untrusted == "untrusted value"
- inventory_data._meta.hostvars.myhost.untrusted is not ansible._protomatter.tagged_with "TrustedAsTemplate"
- inventory_data.all | length == 1
- inventory_data.all.children | symmetric_difference(["ungrouped", "mygroup"]) | length == 0
- inventory_data.mygroup | length == 1
- inventory_data.mygroup.hosts == ["myhost"]
- mode: no_meta_hostvars_empty_host_result
assertions:
- inventory_data | length == 3
- inventory_data._meta.hostvars == {}
- inventory_data.all | length == 1
- inventory_data.all.children | symmetric_difference(["ungrouped", "mygroup"]) | length == 0
- inventory_data.mygroup | length == 1
- inventory_data.mygroup.hosts == ["myhost"]
- name: run invalid script output test cases
include_tasks: test_broken_inventory.yml
loop:
- {mode: bad_shebang, script_name: bad_shebang, expected_error: Failed to execute inventory script command}
- {mode: non_zero_exit, expected_error: Inventory script returned non-zero exit code 1}
- {mode: invalid_utf8, expected_error: Inventory script result contained characters that cannot be interpreted as UTF-8}
- {mode: invalid_json, expected_error: Unable to get JSON decoder for inventory script result. Value could not be parsed as JSON}
- {mode: invalid_type, expected_error: Unable to get JSON decoder for inventory script result. Value is 'str' instead of 'dict'}
- {mode: invalid_meta_type, expected_error: Unable to get JSON decoder for inventory script result. Value contains '_meta' which is 'str' instead of 'dict'}
- {mode: invalid_profile_type, expected_error: Unable to get JSON decoder for inventory script result. Value contains '_meta.profile' which is 'int' instead of 'str'}
- {mode: invalid_profile_name, expected_error: Non-inventory profile 'invalid_profile' is not allowed.}
- {mode: invalid_inventory_profile_name, expected_error: Unable to get JSON decoder for inventory script result. Unknown profile name 'inventory_invalid_profile'}
- {mode: invalid_json_for_profile, expected_error: Inventory script result could not be parsed as JSON}
- {mode: invalid_meta_hostvars_type, expected_error: Value contains '_meta.hostvars' which is 'list' instead of 'dict'}
- {mode: invalid_meta_hostvars_type_for_host, expected_error: Invalid data from file, expected dictionary and got}
- {mode: invalid_group_type, expected_error: Value contains 'mygroup.hosts' which is 'NoneType' instead of 'list'}
- {mode: invalid_group_vars_type, expected_error: Value contains 'mygroup.vars' which is 'list' instead of 'dict'}
- {mode: no_meta_hostvars_host_nonzero_rc, expected_error: Inventory script returned non-zero exit code 1}
- {mode: no_meta_hostvars_host_invalid_json, expected_error: Inventory script result for host 'myhost' could not be parsed as JSON}
- name: Restrict tests to 'script'
environment:
INVENTORY_TEST_MODE: '{{ item.mode | default(omit) }}'
block:
- name: run valid script output test cases
include_tasks: test_valid_inventory.yml
loop:
- mode: no_profile
show_stderr: '1'
emit_stderr: '1'
assertions: &standard_assertions
- inventory_data | length == 5
- inventory_data._meta | length == 2
- inventory_data._meta.hostvars.host1.a_host1_hostvar == "avalue"
- inventory_data._meta.hostvars.host1.a_host1_hostvar is ansible._protomatter.tagged_with "TrustedAsTemplate"
- inventory_data._meta.hostvars.localhost.a_localhost_hostvar == "avalue"
- inventory_data._meta.hostvars.localhost.a_localhost_hostvar is ansible._protomatter.tagged_with "TrustedAsTemplate"
- inventory_data.all | length == 1
- inventory_data.all.children | symmetric_difference(["ungrouped", "group1", "empty_group", "list_as_group", "rewrite_as_host"]) | length == 0
- inventory_data.group1 | length == 2
- inventory_data.group1.hosts == ["host1"]
- inventory_data.group1.vars | length == 2
- inventory_data.group1.vars.a_group1_groupvar == "avalue"
- inventory_data.group1.vars.a_group1_groupvar is ansible._protomatter.tagged_with "TrustedAsTemplate"
- inventory_data.group1.vars.group1_untrusted_var == "untrusted value"
- inventory_data.group1.vars.group1_untrusted_var is not ansible._protomatter.tagged_with "TrustedAsTemplate"
- inventory_data.rewrite_as_host | length == 2
- inventory_data.rewrite_as_host.hosts == ["rewrite_as_host"]
- inventory_data.rewrite_as_host.vars.avar == "value"
- inventory_data.rewrite_as_host.vars.avar is not ansible._protomatter.tagged_with "TrustedAsTemplate" # rewritten groups are too hard to trust and are deprecated
- inv_out.stderr is contains "Treating malformed group 'rewrite_as_host'"
- inventory_data.rewrite_as_host.vars.untrusted_var == "untrusted value"
- inventory_data.rewrite_as_host.vars.untrusted_var is not ansible._protomatter.tagged_with "TrustedAsTemplate"
- inventory_data.ungrouped | length == 1
- inventory_data.ungrouped.hosts == ["localhost"]
- mode: with_profile
show_stderr: '1'
assertions: *standard_assertions
- mode: no_hosts
assertions:
- inventory_data | length == 2
- inventory_data._meta.hostvars == {}
- inventory_data.all | length == 1
- inventory_data.all.children == ["ungrouped"]
- mode: no_meta_hostvars
assertions:
- inventory_data | length == 3
- inventory_data._meta.hostvars | length == 1
- inventory_data._meta.hostvars.myhost.avar == "avalue"
- inventory_data._meta.hostvars.myhost.avar is ansible._protomatter.tagged_with "TrustedAsTemplate"
- inventory_data._meta.hostvars.myhost.untrusted == "untrusted value"
- inventory_data._meta.hostvars.myhost.untrusted is not ansible._protomatter.tagged_with "TrustedAsTemplate"
- inventory_data.all | length == 1
- inventory_data.all.children | symmetric_difference(["ungrouped", "mygroup"]) | length == 0
- inventory_data.mygroup | length == 1
- inventory_data.mygroup.hosts == ["myhost"]
- mode: no_meta_hostvars_empty_host_result
assertions:
- inventory_data | length == 3
- inventory_data._meta.hostvars == {}
- inventory_data.all | length == 1
- inventory_data.all.children | symmetric_difference(["ungrouped", "mygroup"]) | length == 0
- inventory_data.mygroup | length == 1
- inventory_data.mygroup.hosts == ["myhost"]
- name: run invalid script output test cases
include_tasks: test_broken_inventory.yml
loop:
- {mode: bad_shebang, script_name: bad_shebang, expected_error: Failed to execute inventory script command}
- {mode: non_zero_exit, expected_error: Inventory script returned non-zero exit code 1}
- {mode: invalid_utf8, expected_error: Inventory script result contained characters that cannot be interpreted as UTF-8}
- {mode: invalid_json, expected_error: Unable to get JSON decoder for inventory script result. Value could not be parsed as JSON}
- {mode: invalid_type, expected_error: Unable to get JSON decoder for inventory script result. Value is 'str' instead of 'dict'}
- {mode: invalid_meta_type, expected_error: Unable to get JSON decoder for inventory script result. Value contains '_meta' which is 'str' instead of 'dict'}
- {mode: invalid_profile_type, expected_error: Unable to get JSON decoder for inventory script result. Value contains '_meta.profile' which is 'int' instead of 'str'}
- {mode: invalid_profile_name, expected_error: Non-inventory profile 'invalid_profile' is not allowed.}
- {mode: invalid_inventory_profile_name, expected_error: Unable to get JSON decoder for inventory script result. Unknown profile name 'inventory_invalid_profile'}
- {mode: invalid_json_for_profile, expected_error: Inventory script result could not be parsed as JSON}
- {mode: invalid_meta_hostvars_type, expected_error: Value contains '_meta.hostvars' which is 'list' instead of 'dict'}
- {mode: invalid_meta_hostvars_type_for_host, expected_error: Invalid data from file, expected dictionary and got}
- {mode: invalid_group_type, expected_error: Value contains 'mygroup.hosts' which is 'NoneType' instead of 'list'}
- {mode: invalid_group_vars_type, expected_error: Value contains 'mygroup.vars' which is 'list' instead of 'dict'}
- {mode: no_meta_hostvars_host_nonzero_rc, expected_error: Inventory script returned non-zero exit code 1}
- {mode: no_meta_hostvars_host_invalid_json, expected_error: Inventory script result for host 'myhost' could not be parsed as JSON}
- mode: bad_types
script_name: bad_types
deprecation: "Group 'bad_group' was converted to 'dict' from 'str'" # this deprecation is removed in 2.23
expected_error: "Value contains 'bad_group.hosts' which is 'str' instead of 'list'"
@@ -2,8 +2,8 @@
shell: ansible-inventory -i {{ role_path | quote }}/{{ item.script_name | default('script_inventory_fixture.py') }} --list --export
changed_when: false
environment:
INVENTORY_TEST_MODE: '{{ item.mode | default(omit) }}'
INVENTORY_EMIT_STDERR: '1'
ANSIBLE_DEPRECATION_WARNINGS: '{{ "deprecation" in item }}'
ignore_errors: true
register: inv_out
@@ -12,3 +12,4 @@
that:
- inv_out.stderr is contains("this is stderr") if item.script_name is undefined else true
- inv_out.stderr is regex(item.expected_error)
- item.deprecation is undefined or inv_out.stderr is regex(item.deprecation)
@@ -4,7 +4,6 @@
environment:
ANSIBLE_INVENTORY_PLUGIN_SCRIPT_STDERR: '{{ item.show_stderr | default(omit) }}'
ANSIBLE_DEPRECATION_WARNINGS: 1 # some tests assert deprecation warnings
INVENTORY_TEST_MODE: '{{ item.mode | default(omit) }}'
INVENTORY_EMIT_STDERR: '{{ item.emit_stderr | default(omit) }}'
register: inv_out