Fix for subspec options validation issue #27715 (#27728)

* Fix for issue ansible/ansible#27715

* Also fixing mutually exclusive check

* Updating subspec checks
These changes take into account a spec with all features enabled and do
the following tests for subspecs:
1. Test proper specs
2. Test Alias
3. Test missing required param
4. Test mutually exclusive params
5. Test required if params
6. Test required one of params
7. Test required together params
8. Test required if params with a default value
9. Test basis subspec params
10. Test invalid subsec params
pull/27783/head
Philippe Dellaert 7 years ago committed by Ganesh Nalawade
parent 3f12fccd02
commit 6d33e59ca1

@ -1951,7 +1951,7 @@ class AnsibleModule(object):
# check exclusive early # check exclusive early
if not self.bypass_checks: if not self.bypass_checks:
self._check_mutually_exclusive(self.mutually_exclusive, param) self._check_mutually_exclusive(v.get('mutually_exclusive', None), param)
self._set_defaults(pre=True, spec=spec, param=param) self._set_defaults(pre=True, spec=spec, param=param)
@ -1960,9 +1960,9 @@ class AnsibleModule(object):
self._check_argument_types(spec, param) self._check_argument_types(spec, param)
self._check_argument_values(spec, param) self._check_argument_values(spec, param)
self._check_required_together(self.required_together, param) self._check_required_together(v.get('required_together', None), param)
self._check_required_one_of(self.required_one_of, param) self._check_required_one_of(v.get('required_one_of', None), param)
self._check_required_if(self.required_if, param) self._check_required_if(v.get('required_if', None), param)
self._set_defaults(pre=False, spec=spec, param=param) self._set_defaults(pre=False, spec=spec, param=param)

@ -350,20 +350,36 @@ class TestModuleUtilsBasic(ModuleTestCase):
bar=dict(), bar=dict(),
bam=dict(), bam=dict(),
baz=dict(), baz=dict(),
bam1=dict(default='test') bam1=dict(),
bam2=dict(default='test')
)
arg_spec = dict(
foobar=dict(
type='list',
elements='dict',
options=options_spec,
mutually_exclusive=[
['bam', 'bam1']
],
required_if=[
['foo', 'hello', ['bam']],
['foo', 'bam2', ['bam2']]
],
required_one_of=[
['bar', 'bam']
],
required_together=[
['bam1', 'baz']
]
)
) )
arg_spec = dict(foobar=dict(type='list', elements='dict', options=options_spec))
mut_ex = (('bar', 'bam'),)
req_to = (('bam', 'baz'),)
# should test ok # should test ok, tests basic foo requirement and required_if
args = json.dumps(dict(ANSIBLE_MODULE_ARGS={'foobar': [{"foo": "hello"}, {"foo": "test"}]})) args = json.dumps(dict(ANSIBLE_MODULE_ARGS={'foobar': [{"foo": "hello", "bam": "good"}, {"foo": "test", "bar": "good"}]}))
with swap_stdin_and_argv(stdin_data=args): with swap_stdin_and_argv(stdin_data=args):
basic._ANSIBLE_ARGS = None basic._ANSIBLE_ARGS = None
am = basic.AnsibleModule( am = basic.AnsibleModule(
argument_spec=arg_spec, argument_spec=arg_spec,
mutually_exclusive=mut_ex,
required_together=req_to,
no_log=True, no_log=True,
check_invalid_arguments=False, check_invalid_arguments=False,
add_file_common_args=True, add_file_common_args=True,
@ -371,13 +387,11 @@ class TestModuleUtilsBasic(ModuleTestCase):
) )
# should test ok, handles aliases # should test ok, handles aliases
args = json.dumps(dict(ANSIBLE_MODULE_ARGS={'foobar': [{"dup": "hello"}]})) args = json.dumps(dict(ANSIBLE_MODULE_ARGS={'foobar': [{"dup": "test", "bar": "good"}]}))
with swap_stdin_and_argv(stdin_data=args): with swap_stdin_and_argv(stdin_data=args):
basic._ANSIBLE_ARGS = None basic._ANSIBLE_ARGS = None
am = basic.AnsibleModule( am = basic.AnsibleModule(
argument_spec=arg_spec, argument_spec=arg_spec,
mutually_exclusive=mut_ex,
required_together=req_to,
no_log=True, no_log=True,
check_invalid_arguments=False, check_invalid_arguments=False,
add_file_common_args=True, add_file_common_args=True,
@ -392,86 +406,74 @@ class TestModuleUtilsBasic(ModuleTestCase):
SystemExit, SystemExit,
basic.AnsibleModule, basic.AnsibleModule,
argument_spec=arg_spec, argument_spec=arg_spec,
mutually_exclusive=mut_ex,
required_together=req_to,
no_log=True, no_log=True,
check_invalid_arguments=False, check_invalid_arguments=False,
add_file_common_args=True, add_file_common_args=True,
supports_check_mode=True supports_check_mode=True
) )
# fail because of mutually exclusive parameters # fail because of mutually exclusive parameters (mutually_exclusive, baz is added as it is required_together with bam1)
args = json.dumps(dict(ANSIBLE_MODULE_ARGS={'foobar': [{"foo": "hello", "bar": "bad", "bam": "bad"}]})) args = json.dumps(dict(ANSIBLE_MODULE_ARGS={'foobar': [{"foo": "test", "bam": "bad", "bam1": "bad", "baz": "req_to"}]}))
with swap_stdin_and_argv(stdin_data=args): with swap_stdin_and_argv(stdin_data=args):
basic._ANSIBLE_ARGS = None basic._ANSIBLE_ARGS = None
self.assertRaises( self.assertRaises(
SystemExit, SystemExit,
basic.AnsibleModule, basic.AnsibleModule,
argument_spec=arg_spec, argument_spec=arg_spec,
mutually_exclusive=mut_ex,
required_together=req_to,
no_log=True, no_log=True,
check_invalid_arguments=False, check_invalid_arguments=False,
add_file_common_args=True, add_file_common_args=True,
supports_check_mode=True supports_check_mode=True
) )
# fail because a param required due to another param was not specified # fail because a param required if for foo=hello is missing (required_if)
args = json.dumps(dict(ANSIBLE_MODULE_ARGS={'foobar': [{"bam": "bad"}]})) args = json.dumps(dict(ANSIBLE_MODULE_ARGS={'foobar': [{"foo": "hello", "bar": "bad"}]}))
with swap_stdin_and_argv(stdin_data=args): with swap_stdin_and_argv(stdin_data=args):
basic._ANSIBLE_ARGS = None basic._ANSIBLE_ARGS = None
self.assertRaises( self.assertRaises(
SystemExit, SystemExit,
basic.AnsibleModule, basic.AnsibleModule,
argument_spec=arg_spec, argument_spec=arg_spec,
mutually_exclusive=mut_ex,
required_together=req_to,
no_log=True, no_log=True,
check_invalid_arguments=False, check_invalid_arguments=False,
add_file_common_args=True, add_file_common_args=True,
supports_check_mode=True supports_check_mode=True
) )
# fail because one of param is required # fail because one of param is required (required_one_of)
req_one_of = (('bar', 'bam'),) args = json.dumps(dict(ANSIBLE_MODULE_ARGS={'foobar': [{"foo": "test"}]}))
args = json.dumps(dict(ANSIBLE_MODULE_ARGS={'foobar': [{"foo": "hello"}]}))
with swap_stdin_and_argv(stdin_data=args): with swap_stdin_and_argv(stdin_data=args):
basic._ANSIBLE_ARGS = None basic._ANSIBLE_ARGS = None
self.assertRaises( self.assertRaises(
SystemExit, SystemExit,
basic.AnsibleModule, basic.AnsibleModule,
argument_spec=arg_spec, argument_spec=arg_spec,
required_one_of=req_one_of,
no_log=True, no_log=True,
check_invalid_arguments=False, check_invalid_arguments=False,
add_file_common_args=True, add_file_common_args=True,
supports_check_mode=True supports_check_mode=True
) )
# fail because value of one param mandates presence of other param required # fail because one parameter requires another (required_together, bar is added for the required_one_of field)
req_if = (('foo', 'hello', ('bam')),) args = json.dumps(dict(ANSIBLE_MODULE_ARGS={'foobar': [{"foo": "test", "bar": "required_one_of", "bam1": "bad"}]}))
args = json.dumps(dict(ANSIBLE_MODULE_ARGS={'foobar': [{"foo": "hello"}]}))
with swap_stdin_and_argv(stdin_data=args): with swap_stdin_and_argv(stdin_data=args):
basic._ANSIBLE_ARGS = None basic._ANSIBLE_ARGS = None
self.assertRaises( self.assertRaises(
SystemExit, SystemExit,
basic.AnsibleModule, basic.AnsibleModule,
argument_spec=arg_spec, argument_spec=arg_spec,
required_if=req_if,
no_log=True, no_log=True,
check_invalid_arguments=False, check_invalid_arguments=False,
add_file_common_args=True, add_file_common_args=True,
supports_check_mode=True supports_check_mode=True
) )
# should test ok, the required param is set by default from spec # should test ok, the required param is set by default from spec (required_if together with default value, bar added for required_one_of
req_if = [('foo', 'hello', ('bam1',))] args = json.dumps(dict(ANSIBLE_MODULE_ARGS={'foobar': [{"foo": "bam2", "bar": "required_one_of"}]}))
args = json.dumps(dict(ANSIBLE_MODULE_ARGS={'foobar': [{"foo": "hello"}]}))
with swap_stdin_and_argv(stdin_data=args): with swap_stdin_and_argv(stdin_data=args):
basic._ANSIBLE_ARGS = None basic._ANSIBLE_ARGS = None
am = basic.AnsibleModule( am = basic.AnsibleModule(
argument_spec=arg_spec, argument_spec=arg_spec,
required_if=req_if,
no_log=True, no_log=True,
check_invalid_arguments=False, check_invalid_arguments=False,
add_file_common_args=True, add_file_common_args=True,

Loading…
Cancel
Save