summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSloane Hertel <19572925+s-hertel@users.noreply.github.com>2021-07-12 01:34:47 -0400
committerGitHub <noreply@github.com>2021-07-12 00:34:47 -0500
commit35383360d22d8cef3259500208d2525bec4be215 (patch)
tree93b4c542d047ab60e862b4a7e4a8c44e49113613
parent1b6698aba8cd4c7ddfef8c54f50302fb400d085a (diff)
downloadansible-35383360d22d8cef3259500208d2525bec4be215.tar.gz
Template suboptions in a role's arg spec (#75073) (#75094)
(cherry picked from commit ca6123e0ee0707b4cdf74137b5778fd913da8357)
-rw-r--r--changelogs/fragments/75073-role-argspec-suboption-variables.yaml2
-rw-r--r--lib/ansible/plugins/action/validate_argument_spec.py8
-rw-r--r--test/integration/targets/roles_arg_spec/test.yml35
-rw-r--r--test/integration/targets/roles_arg_spec/test_complex_role_fails.yml30
4 files changed, 69 insertions, 6 deletions
diff --git a/changelogs/fragments/75073-role-argspec-suboption-variables.yaml b/changelogs/fragments/75073-role-argspec-suboption-variables.yaml
new file mode 100644
index 0000000000..eca9aad78d
--- /dev/null
+++ b/changelogs/fragments/75073-role-argspec-suboption-variables.yaml
@@ -0,0 +1,2 @@
+bugfixes:
+ - roles - make sure argspec validation task templates suboptions (https://github.com/ansible/ansible/issues/75070).
diff --git a/lib/ansible/plugins/action/validate_argument_spec.py b/lib/ansible/plugins/action/validate_argument_spec.py
index 4162005202..9ad0a46df6 100644
--- a/lib/ansible/plugins/action/validate_argument_spec.py
+++ b/lib/ansible/plugins/action/validate_argument_spec.py
@@ -31,12 +31,8 @@ class ActionModule(ActionBase):
for argument_name, argument_attrs in iteritems(argument_spec):
if argument_name in task_vars:
- if isinstance(task_vars[argument_name], string_types):
- value = self._templar.do_template(task_vars[argument_name])
- if value:
- args[argument_name] = value
- else:
- args[argument_name] = task_vars[argument_name]
+ args[argument_name] = task_vars[argument_name]
+ args = self._templar.template(args)
return args
def run(self, tmp=None, task_vars=None):
diff --git a/test/integration/targets/roles_arg_spec/test.yml b/test/integration/targets/roles_arg_spec/test.yml
index e7c1fae054..06268c6a52 100644
--- a/test/integration/targets/roles_arg_spec/test.yml
+++ b/test/integration/targets/roles_arg_spec/test.yml
@@ -303,3 +303,38 @@
- ansible_failed_result.validate_args_context.name == "blah"
- ansible_failed_result.validate_args_context.type == "role"
- "ansible_failed_result.validate_args_context.path is search('roles_arg_spec/collections/ansible_collections/foo/bar/roles/blah')"
+
+- name: "New play to reset vars: Test templating succeeds"
+ hosts: localhost
+ gather_facts: false
+ vars:
+ value_some_choices: "choice2"
+ value_some_list: [1.5]
+ value_some_dict: {"some_key": "some_value"}
+ value_some_int: 1
+ value_some_float: 1.5
+ value_some_json: '{[1, 3, 3] 345345|45v<#!}'
+ value_some_jsonarg: {"foo": [1, 3, 3]}
+ value_some_second_level: True
+ value_third_level: 5
+ tasks:
+ - block:
+ - include_role:
+ name: test1
+ vars:
+ some_choices: "{{ value_some_choices }}"
+ some_list: "{{ value_some_list }}"
+ some_dict: "{{ value_some_dict }}"
+ some_int: "{{ value_some_int }}"
+ some_float: "{{ value_some_float }}"
+ some_json: "{{ value_some_json }}"
+ some_jsonarg: "{{ value_some_jsonarg }}"
+ some_dict_options:
+ some_second_level: "{{ value_some_second_level }}"
+ multi_level_option:
+ second_level:
+ third_level: "{{ value_third_level }}"
+ rescue:
+ - debug: var=ansible_failed_result
+ - fail:
+ msg: "Should not get here"
diff --git a/test/integration/targets/roles_arg_spec/test_complex_role_fails.yml b/test/integration/targets/roles_arg_spec/test_complex_role_fails.yml
index 35ae3877b7..a04785fb12 100644
--- a/test/integration/targets/roles_arg_spec/test_complex_role_fails.yml
+++ b/test/integration/targets/roles_arg_spec/test_complex_role_fails.yml
@@ -3,13 +3,23 @@
hosts: localhost
gather_facts: false
vars:
+ ansible_unicode_type_match: "<type 'ansible.parsing.yaml.objects.AnsibleUnicode'>"
unicode_type_match: "<type 'unicode'>"
string_type_match: "<type 'str'>"
float_type_match: "<type 'float'>"
+ list_type_match: "<type 'list'>"
+ ansible_list_type_match: "<type 'ansible.parsing.yaml.objects.AnsibleSequence'>"
+ dict_type_match: "<type 'dict'>"
+ ansible_dict_type_match: "<type 'ansible.parsing.yaml.objects.AnsibleMapping'>"
+ ansible_unicode_class_match: "<class 'ansible.parsing.yaml.objects.AnsibleUnicode'>"
unicode_class_match: "<class 'unicode'>"
string_class_match: "<class 'str'>"
bytes_class_match: "<class 'bytes'>"
float_class_match: "<class 'float'>"
+ list_class_match: "<class 'list'>"
+ ansible_list_class_match: "<class 'ansible.parsing.yaml.objects.AnsibleSequence'>"
+ dict_class_match: "<class 'dict'>"
+ ansible_dict_class_match: "<class 'ansible.parsing.yaml.objects.AnsibleMapping'>"
expected:
test1_1:
argument_errors: [
@@ -98,24 +108,44 @@
# because py3 quotes the value in the error while py2 does not, so we just ignore
# the rest of the line.
actual_generic: "{{ ansible_failed_result.argument_errors|
+ map('replace', ansible_unicode_type_match, 'STR')|
map('replace', unicode_type_match, 'STR')|
map('replace', string_type_match, 'STR')|
map('replace', float_type_match, 'FLOAT')|
+ map('replace', list_type_match, 'LIST')|
+ map('replace', ansible_list_type_match, 'LIST')|
+ map('replace', dict_type_match, 'DICT')|
+ map('replace', ansible_dict_type_match, 'DICT')|
+ map('replace', ansible_unicode_class_match, 'STR')|
map('replace', unicode_class_match, 'STR')|
map('replace', string_class_match, 'STR')|
map('replace', bytes_class_match, 'STR')|
map('replace', float_class_match, 'FLOAT')|
+ map('replace', list_class_match, 'LIST')|
+ map('replace', ansible_list_class_match, 'LIST')|
+ map('replace', dict_class_match, 'DICT')|
+ map('replace', ansible_dict_class_match, 'DICT')|
map('regex_replace', '''float:.*$''', 'THE_FLOAT_REPR')|
map('regex_replace', 'Valid booleans include.*$', '')|
list }}"
expected_generic: "{{ expected.test1_1.argument_errors|
+ map('replace', ansible_unicode_type_match, 'STR')|
map('replace', unicode_type_match, 'STR')|
map('replace', string_type_match, 'STR')|
map('replace', float_type_match, 'FLOAT')|
+ map('replace', list_type_match, 'LIST')|
+ map('replace', ansible_list_type_match, 'LIST')|
+ map('replace', dict_type_match, 'DICT')|
+ map('replace', ansible_dict_type_match, 'DICT')|
+ map('replace', ansible_unicode_class_match, 'STR')|
map('replace', unicode_class_match, 'STR')|
map('replace', string_class_match, 'STR')|
map('replace', bytes_class_match, 'STR')|
map('replace', float_class_match, 'FLOAT')|
+ map('replace', list_class_match, 'LIST')|
+ map('replace', ansible_list_class_match, 'LIST')|
+ map('replace', dict_class_match, 'DICT')|
+ map('replace', ansible_dict_class_match, 'DICT')|
map('regex_replace', '''float:.*$''', 'THE_FLOAT_REPR')|
map('regex_replace', 'Valid booleans include.*$', '')|
list }}"