summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSloane Hertel <19572925+s-hertel@users.noreply.github.com>2021-11-24 13:15:23 -0500
committerGitHub <noreply@github.com>2021-11-24 10:15:23 -0800
commit4079bc948bfc32cdbaee2ae2789eb5c81f2f3840 (patch)
treea4e7a8ca7e77a9733ce51c12cb5cf995fd80046a
parenta17581efa67c26771efa75b7197067b358de5625 (diff)
downloadansible-4079bc948bfc32cdbaee2ae2789eb5c81f2f3840.tar.gz
Skip recursive suboption validation if sub_parameters is not a dict (#75635) (#76189)
* Skip recursive suboption validation if sub_parameters is not a dictionary * Ensure sub parameter elements is a sequence to prevent iterating over string characters and causing duplicate error messages for the same param (cherry picked from commit b5ed41edb34a387c560e172ee2928cc8ac9b4959)
-rw-r--r--changelogs/fragments/75635-fix-role-argspec-suboption-validation.yml2
-rw-r--r--lib/ansible/module_utils/common/parameters.py7
-rw-r--r--test/integration/targets/roles_arg_spec/roles/test1/meta/argument_specs.yml5
-rw-r--r--test/integration/targets/roles_arg_spec/test_complex_role_fails.yml6
4 files changed, 16 insertions, 4 deletions
diff --git a/changelogs/fragments/75635-fix-role-argspec-suboption-validation.yml b/changelogs/fragments/75635-fix-role-argspec-suboption-validation.yml
new file mode 100644
index 0000000000..981f2548c3
--- /dev/null
+++ b/changelogs/fragments/75635-fix-role-argspec-suboption-validation.yml
@@ -0,0 +1,2 @@
+bugfixes:
+ - validate_argument_spec - Skip suboption validation if the top level option is an invalid type (https://github.com/ansible/ansible/issues/75612).
diff --git a/lib/ansible/module_utils/common/parameters.py b/lib/ansible/module_utils/common/parameters.py
index 2624bb5092..8bba4d5f32 100644
--- a/lib/ansible/module_utils/common/parameters.py
+++ b/lib/ansible/module_utils/common/parameters.py
@@ -724,14 +724,17 @@ def _validate_sub_spec(argument_spec, parameters, prefix='', options_context=Non
options_context.append(param)
# Make sure we can iterate over the elements
- if isinstance(parameters[param], dict):
+ if not isinstance(parameters[param], Sequence) or isinstance(parameters[param], string_types):
elements = [parameters[param]]
else:
elements = parameters[param]
for idx, sub_parameters in enumerate(elements):
+ no_log_values.update(set_fallbacks(sub_spec, sub_parameters))
+
if not isinstance(sub_parameters, dict):
errors.append(SubParameterTypeError("value of '%s' must be of type dict or list of dicts" % param))
+ continue
# Set prefix for warning messages
new_prefix = prefix + param
@@ -739,8 +742,6 @@ def _validate_sub_spec(argument_spec, parameters, prefix='', options_context=Non
new_prefix += '[%d]' % idx
new_prefix += '.'
- no_log_values.update(set_fallbacks(sub_spec, sub_parameters))
-
alias_warnings = []
alias_deprecations = []
try:
diff --git a/test/integration/targets/roles_arg_spec/roles/test1/meta/argument_specs.yml b/test/integration/targets/roles_arg_spec/roles/test1/meta/argument_specs.yml
index 02edac6606..427946e538 100644
--- a/test/integration/targets/roles_arg_spec/roles/test1/meta/argument_specs.yml
+++ b/test/integration/targets/roles_arg_spec/roles/test1/meta/argument_specs.yml
@@ -73,6 +73,11 @@ argument_specs:
some_second_level:
type: "bool"
default: true
+ some_more_dict_options:
+ type: "dict"
+ options:
+ some_second_level:
+ type: "str"
some_str_removed_in:
type: "str"
removed_in: 2.10
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 a04785fb12..923e92f719 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
@@ -34,7 +34,10 @@
"value of test1_choices must be one of: this paddle game, the astray, this remote control, the chair, got: My dog",
"value of some_choices must be one of: choice1, choice2, got: choice4",
"argument 'some_second_level' is of type <class 'ansible.parsing.yaml.objects.AnsibleUnicode'> found in 'some_dict_options'. and we were unable to convert to bool: The value 'not-a-bool' is not a valid boolean. ",
- "argument 'third_level' is of type <class 'ansible.parsing.yaml.objects.AnsibleUnicode'> found in 'multi_level_option -> second_level'. and we were unable to convert to int: <class 'ansible.parsing.yaml.objects.AnsibleUnicode'> cannot be converted to an int"
+ "argument 'third_level' is of type <class 'ansible.parsing.yaml.objects.AnsibleUnicode'> found in 'multi_level_option -> second_level'. and we were unable to convert to int: <class 'ansible.parsing.yaml.objects.AnsibleUnicode'> cannot be converted to an int",
+ "argument 'some_more_dict_options' is of type <class 'ansible.parsing.yaml.objects.AnsibleUnicode'> and we were unable to convert to dict: dictionary requested, could not parse JSON or key=value",
+ "value of 'some_more_dict_options' must be of type dict or list of dicts",
+ "dictionary requested, could not parse JSON or key=value",
]
tasks:
@@ -86,6 +89,7 @@
some_str_removed_in: "foo"
some_dict_options:
some_second_level: "not-a-bool"
+ some_more_dict_options: "not-a-dict"
multi_level_option:
second_level:
third_level: "should_be_int"