Are module, role and play argument validation the same? (argument_spec)

Hey, I recently discovered role argument validation and started to include meta/argument_specs.yml in my roles. Some of the input arguments of my role are sensitive values, so I was looking through the documentation to see whether something like no_log exists in this specification, since I’m not aware of any method to mark certain variables as sensitive. This is something I’m used to from terraform. I was afraid that the argument validation might print the sensitive values in case any of the role input arguments don’t comply with this spec and the validation fails.

During my search, I discovered that there are three places where argument validation in form of argument_spec exists and I’m a little confused now.

  1. AnsibleModule
  2. Play Argument Validation
  3. Role argument Validation

The first one seems to be for module developers while the other two are for more for endusers like me. The latter two seem to just prepend a special task before the play/role runs (ansible.builtin.validate_argument_spec).

The thing I’m asking myself now is whether all these variants are different or if they are actually the same thing. Are the latter two just subsets of the first one or do they have the same available keywords but it’s just not documented?

Coming back to my the reason why I was searching for this initially, the argument spec in the AnsibleModule documentation has a no_log keyword. The others do not. It in fact has many more keywords that could be useful in a play and role argument_spec, like mutually_exclusive.

So, which keywords can actually be used in the argument_spec for my role? Only those here or also those here?

1 Like

This is not possible to have mutual exclusivity for role variables due to ansible variable visibility model. You cannot unset variables in ansible - so if you want var1 be set for host1 and var2 be set for host2 - and at the same time want them to be mutually exclusive this is not possible (in general)

First link Roles — Ansible Community Documentation is for roles, you should use example there for argument_specs.yml file

That is correct, but it should not stop anyone from adding your own argument validations with ansible.builtin.validate_argument_spec or ansible.builtin.assert, if you feel that you need additional validation. And you might need if it you validation depends on facts.

They are similar as per my understanding, maybe they use same checks somewhere deep. You got documentation links right, this is all documentation. You should be able to find plenty examples on github, search for ‘argument_specs.yml’

1 Like

I don’t see how this can be correct since validation is done per host. var1 and var2 are completely independent in your example. Visibility is thus limited to what a single host sees.

Variables have 2 scopes, per host and for playbook objects, the first is isolated per host (but still accessible via hostvars), the second is not and cannot be isolated, once defined all other contained playbook objects inherit them.

1 Like

Role/play argument spec validation is a subset of module argument spec validation, and some keywords are unsupported/do nothing, so you should only use documented fields for role argument specifications. This is the surface area that is supported and tested.

Supporting no_log for role/play variables would require a different mechanism than the one used by module arguments. There’s an open feature request for that.

Supporting mutually_exclusive would be trivial (and works for suboptions already, although this was not intentional from my understanding, and is not tested/guaranteed to keep working). From the responses on Role argument specification should support "mutually_exclusive", "required_if" and the other Module argument specification features · Issue #74995 · ansible/ansible · GitHub, it sounds like mutually_exclusive support was not added in hopes of improving the interface.

1 Like

Thank you, that clears up some things for me.

From my experiences so far, the ansible.builtin.validate_argument_spec task will not show any of the actual argument values that were supplied to the role if it fails. This was my primary reason for asking for no_log. I don’t want my sensitive values to be leaked in pipeline logs.

I did not yet dive into the code myself yet but can any of you also confirm this?

However, I’m not so sure if there might be other mechanism that might cause ansible to print these sensitive values (aside any verbosity flags). I usually supply them via --extra-vars.

Two other important differences to note are:

  • Default values. These are only used for modules. For role and play argspecs, they are only used for showing them to the user when using ansible-doc etc.
  • Types. While for modules, values are coerced to the type (like a string "12" is converted to an integer 12 if type="int", or a string 1,2,3 is converted to a list [1.0, 2.0, 3.0] if type="list" and elements="float"), this doesn’t happen for role and play argspecs. There, Ansible only makes sure that the values can be coerced this way, but doesn’t do it. So if a parameter is expected to be a list, it could also happen to contain a single value (list of one element) or a string (should be split by comma).

Both can cause quite some confusion, and especially the missing type conversion can easily trigger errors when the role/play author assumes that they can append two lists the user passed in - but then Ansible barfs (or computes an unexpected value) since the inputs aren’t actually lists.

1 Like