'; */ // Create a banner if we're not on the official docs site if (location.host == "docs.testing.ansible.com") { document.write('
'); } // Create a banner current_url_path = window.location.pathname; var important = false; var msg = '
'; if (startsWith(current_url_path, "/ansible-core/")) { msg += 'You are reading documentation for Ansible Core, which contains no plugins except for those in ansible.builtin. For documentation of the Ansible package, go to the latest documentation.'; } else if (startsWithOneOf(current_url_path, ["/ansible/latest/", "/ansible/9/"])) { /* temp extra banner to advertise something */ banner += extra_banner; msg += 'This is the latest (stable) Ansible community documentation. For Red Hat Ansible Automation Platform subscriptions, see Life Cycle for version details.'; } else if (startsWith(current_url_path, "/ansible/2.9/")) { msg += 'You are reading the latest Red Hat released version of the Ansible documentation. Community users can use this version, or select latest from the version selector to the left for the most recent community version.'; } else if (startsWith(current_url_path, "/ansible/devel/")) { /* temp extra banner to advertise something */ banner += extra_banner; msg += 'You are reading the devel version of the Ansible documentation - this version is not guaranteed stable. Use the version selection to the left if you want the latest (stable) released version.'; } else { msg += 'You are reading an older version of the Ansible documentation. Use the version selection to the left if you want the latest (stable) released version.'; /* temp extra banner to advertise something - this is for testing*/ banner += extra_banner; } msg += '
'; banner += important ? '
' : ''; banner += msg; banner += important ? '
' : ''; banner += '
If you are working on the ansible-core
code, writing an Ansible module, or developing an action plugin, you may need to understand how Ansible’s program flow executes. If you are just using Ansible Modules in playbooks, you can skip this section.
Types of modules
Ansible supports several different types of modules in its code base. Some ofthese are for backwards compatibility and others are to enable flexibility.
Action plugins
Action plugins look like modules to anyone writing a playbook. Usage documentation for most action plugins lives inside a module of the same name. Some action plugins do all the work, with the module providing only documentation. Some action plugins execute modules. The normal
action plugin executes modules that don’t have special action plugins. Action plugins always execute on the control node.
Some action plugins do all their work on the control node. Forexample, the debug action plugin (which prints text forthe user to see) and the assert action plugin (whichtests whether values in a playbook satisfy certain criteria) execute entirely on the control node.
Most action plugins set up some values on the control node, then invoke anactual module on the managed node that does something with these values. For example, the template action plugin takes values fromthe user to construct a file in a temporary location on the control node usingvariables from the playbook environment. It then transfers the temporary fileto a temporary file on the remote system. After that, it invokes thecopy module which operates on the remote system to move the fileinto its final location, sets file permissions, and so on.
New-style modules
All of the modules that ship with Ansible fall into this category. While you can write modules in any language, all official modules (shipped with Ansible) use either Python or PowerShell.
New-style modules have the arguments to the module embedded inside of them insome manner. Old-style modules must copy a separate file over to themanaged node, which is less efficient as it requires two over-the-wireconnections instead of only one.
Python
New-style Python modules use the Ansiballz framework framework for constructingmodules. These modules use imports from ansible.module_utils
to pull inboilerplate module code, such as argument parsing, formatting of returnvalues as JSON, and various file operations.
Note
In Ansible, up to version 2.0.x, the official Python modules used theModule Replacer framework framework. For module authors, Ansiballz framework islargely a superset of Module Replacer framework functionality, so you usuallydo not need to understand the differences between them.
PowerShell
New-style PowerShell modules use the Module Replacer framework framework forconstructing modules. These modules get a library of PowerShell code embeddedin them before being sent to the managed node.
JSONARGS modules
These modules are scripts that include the string<<INCLUDE_ANSIBLE_MODULE_JSON_ARGS>>
in their body.This string is replaced with the JSON-formatted argument string. These modules typically set a variable to that value like this:
json_arguments = """<<INCLUDE_ANSIBLE_MODULE_JSON_ARGS>>"""
Which is expanded as:
json_arguments = """{"param1": "test's quotes", "param2": "\"To be or not to be\" - Hamlet"}"""
Note
Ansible outputs a JSON string with bare quotes. Double quotes areused to quote string values, double quotes inside of string values arebackslash escaped, and single quotes may appear unescaped inside ofa string value. To use JSONARGS, your scripting language must have a wayto handle this type of string. The example uses Python’s triple quotedstrings to do this. Other scripting languages may have a similar quotecharacter that won’t be confused by any quotes in the JSON or it mayallow you to define your own start-of-quote and end-of-quote characters.If the language doesn’t give you any of these then you’ll need to writea non-native JSON module orOld-style module instead.
These modules typically parse the contents of json_arguments
using a JSONlibrary and then use them as native variables throughout the code.
Non-native want JSON modules
If a module has the string WANT_JSON
in it anywhere, Ansible treatsit as a non-native module that accepts a filename as its only command-lineparameter. The filename is for a temporary file containing a JSONstring containing the module’s parameters. The module needs to open the file,read and parse the parameters, operate on the data, and print its return dataas a JSON encoded dictionary to stdout before exiting.
These types of modules are self-contained entities. As of Ansible 2.1, Ansibleonly modifies them to change a shebang line if present.
See also
Examples of Non-native modules written in ruby are in the Ansiblefor Rubyists repository.
Binary modules
From Ansible 2.2 onwards, modules may also be small binary programs. Ansibledoesn’t perform any magic to make these portable to different systems so theymay be specific to the system on which they were compiled or require otherbinary runtime dependencies. Despite these drawbacks, you may haveto compile a custom module against a specific binarylibrary if that’s the only way to get access to certain resources.
Binary modules take their arguments and return data to Ansible in the sameway as want JSON modules.
See also
One example of a binary modulewritten in go.
Old-style modules
Old-style modules are similar towant JSON modules, except that the file thatthey take contains key=value
pairs for their parameters instead ofJSON. Ansible decides that a module is old-style when it doesn’t haveany of the markers that would show that it is one of the other types.
How modules are executed
When a user uses ansible or ansible-playbook, theyspecify a task to execute. The task is usually the name of a module alongwith several parameters to be passed to the module. Ansible takes thesevalues and processes them in various ways before they are finally executed onthe remote machine.
Executor/task_executor
The TaskExecutor receives the module name and parameters that were parsed fromthe playbook (or from the command-line in the case of/usr/bin/ansible). It uses the name to decide whether it is lookingat a module or an Action Plugin. If it isa module, it loads the Normal Action Pluginand passes the name, variables, and other information about the task and playto that Action Plugin for further processing.
The normal action plugin
The normal
action plugin executes the module on the remote host. It isthe primary coordinator of much of the work to actually execute the module onthe managed machine.
It loads the appropriate connection plugin for the task, which then transfersor executes as needed to create a connection to that host.
It adds any internal Ansible properties to the module’s parameters (forinstance, the ones that pass along
no_log
to the module).It works with other plugins (connection, shell, become, other action plugins)to create any temporary files on the remote machine andcleans up afterwards.
It pushes the module and module parameters to theremote host, although the module_commoncode described in the next section decides which formatthose will take.
It handles any special cases regarding modules (for example, asyncexecution, or complications around Windows modules that must have the same names as Python modules, so that internal calling of modules from other Action Plugins work.)
Much of this functionality comes from the BaseAction class,which lives in plugins/action/__init__.py
. It uses theConnection
and Shell
objects to do its work.
Note
When tasks are run with the async:
parameter, Ansibleuses the async
Action Plugin instead of the normal
Action Pluginto invoke it. That program flow is currently not documented. Read thesource for information on how that works.
Executor/module_common.py
Code in executor/module_common.py
assembles the moduleto be shipped to the managed node. The module is first read in, then examinedto determine its type:
PowerShell and JSON-args modules are passed through Module Replacer.
New-style Python modules are assembled by Ansiballz framework.
Non-native-want-JSON, Binary modules, and Old-Style modules aren’t touched by either of these and pass through unchanged.
After the assembling step, one finalmodification is made to all modules that have a shebang line. Ansible checkswhether the interpreter in the shebang line has a specific path configured withan ansible_$X_interpreter
inventory variable. If it does, Ansiblesubstitutes that path for the interpreter path given in the module. Afterthis, Ansible returns the complete module data and the module type to theNormal Action which continues execution ofthe module.
Assembler frameworks
Ansible supports two assembler frameworks: Ansiballz and the older Module Replacer.
Module Replacer framework
The Module Replacer framework is the original framework implementing new-stylemodules, and is still used for PowerShell modules. It is essentially a preprocessor (like the C Preprocessor for thosefamiliar with that programming language). It does straight substitutions ofspecific substring patterns in the module file. There are two types ofsubstitutions:
Replacements that only happen in the module file. These are publicreplacement strings that modules can utilize to get helpful boilerplate oraccess to arguments.
from ansible.module_utils.MOD_LIB_NAME import *
is replaced with thecontents of theansible/module_utils/MOD_LIB_NAME.py
These shouldonly be used with new-style Python modules.#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
is equivalent tofrom ansible.module_utils.basic import *
and should also only applyto new-style Python modules.# POWERSHELL_COMMON
substitutes the contents ofansible/module_utils/powershell.ps1
. It should only be used withnew-style Powershell modules.
Replacements that are used by
ansible.module_utils
code. These are internal replacement patterns. They may be used internally, in the above public replacements, but shouldn’t be used directly by modules."<<ANSIBLE_VERSION>>"
is substituted with the Ansible version. Innew-style Python modules under theAnsiballz framework framework the proper way is to instead instantiate anAnsibleModule and then access the version from:attr:AnsibleModule.ansible_version
."<<INCLUDE_ANSIBLE_MODULE_COMPLEX_ARGS>>"
is substituted witha string which is the Pythonrepr
of the JSON encoded moduleparameters. Usingrepr
on the JSON string makes it safe to embed ina Python file. In new-style Python modules under the Ansiballz frameworkthis is better accessed by instantiating an AnsibleModule andthen usingAnsibleModule.params
.<<SELINUX_SPECIAL_FILESYSTEMS>>
substitutes a string which isa comma-separated list of file systems which have a file system dependentsecurity context in SELinux. In new-style Python modules, if you reallyneed this you should instantiate an AnsibleModule and then useAnsibleModule._selinux_special_fs
. The variable has also changedfrom a comma-separated string of file system names to an actual pythonlist of file system names.<<INCLUDE_ANSIBLE_MODULE_JSON_ARGS>>
substitutes the moduleparameters as a JSON string. Care must be taken to properly quote thestring as JSON data may contain quotes. This pattern is not substitutedin new-style Python modules as they can get the module parameters anotherway.The string
syslog.LOG_USER
is replaced wherever it occurs with thesyslog_facility
which was named inansible.cfg
or anyansible_syslog_facility
inventory variable that applies to this host. Innew-style Python modules this has changed slightly. If you really need toaccess it, you should instantiate an AnsibleModule and then useAnsibleModule._syslog_facility
to access it. It is no longer theactual syslog facility and is now the name of the syslog facility. Seethe documentation on internal argumentsfor details.
Ansiballz framework
The Ansiballz framework was adopted in Ansible 2.1 and is used for all new-style Python modules. Unlike the Module Replacer, Ansiballz uses real Python imports of things inansible/module_utils
instead of merely preprocessing the module. Itdoes this by constructing a zipfile – which includes the module file, filesin ansible/module_utils
that are imported by the module, and someboilerplate to pass in the module’s parameters. The zipfile is then Base64encoded and wrapped in a small Python script which decodes the Base64 encodingand places the zipfile into a temp directory on the managed node. It thenextracts just the Ansible module script from the zip file and places that inthe temporary directory as well. Then it sets the PYTHONPATH to find Pythonmodules inside of the zip file and imports the Ansible module as the special name, __main__
.Importing it as __main__
causes Python to think that it is executing a script rather than simplyimporting a module. This lets Ansible run both the wrapper script and the module code in a single copy of Python on the remote machine.
Note
Ansible wraps the zipfile in the Python script for two reasons:
for compatibility with Python 2.6 which has a lessfunctional version of Python’s
-m
command-line switch.so that pipelining will function properly. Pipelining needs to pipe thePython module into the Python interpreter on the remote node. Pythonunderstands scripts on stdin but does not understand zip files.
Prior to Ansible 2.7, the module was executed by a second Python interpreter instead of beingexecuted inside of the same process. This change was made once Python-2.4 support was droppedto speed up module execution.
In Ansiballz, any imports of Python modules from theansible.module_utils
package trigger inclusion of that Python fileinto the zipfile. Instances of #<<INCLUDE_ANSIBLE_MODULE_COMMON>>
inthe module are turned into from ansible.module_utils.basic import *
and ansible/module-utils/basic.py
is then included in the zipfile.Files that are included from module_utils
are themselves scanned forimports of other Python modules from module_utils
to be included inthe zipfile as well.
Passing args
Arguments are passed differently by the two frameworks:
In Module Replacer framework, module arguments are turned into a JSON-ified string and substituted into the combined module file.
In Ansiballz framework, the JSON-ified string is part of the script which wraps the zipfile. Just before the wrapper script imports the Ansible module as
__main__
, it monkey-patches the private,_ANSIBLE_ARGS
variable inbasic.py
with the variable values. When aansible.module_utils.basic.AnsibleModule
is instantiated, it parses this string and places the args intoAnsibleModule.params
where it can be accessed by the module’s other code.
Warning
If you are writing modules, remember that the way we pass arguments is an internal implementation detail: it has changed in the past and will change again as soon as changes to the common module_utilscode allow Ansible modules to forgo using ansible.module_utils.basic.AnsibleModule
. Do not rely on the internal global _ANSIBLE_ARGS
variable.
Very dynamic custom modules which need to parse arguments before theyinstantiate an AnsibleModule
may use _load_params
to retrieve those parameters.Although _load_params
may change in breaking ways if necessary to supportchanges in the code, it is likely to be more stable than either the way we pass parameters or the internal global variable.
Note
Prior to Ansible 2.7, the Ansible module was invoked in a second Python interpreter and thearguments were then passed to the script over the script’s stdin.
Internal arguments
Both Module Replacer framework and Ansiballz framework send additional arguments tothe Ansible module beyond those which the user specified in the playbook. Theseadditional arguments are internal parameters that help implement globalAnsible features. Modules often do not need to know about these explicitly becausethe features are implemented in ansible.module_utils.basic
. However, certainfeatures need support from modules and some knowledge of the internal arguments is useful.
The internal arguments in this section are global. If you need to add a local internal argument to a custom module, create an action plugin for that specific module. See _original_basename
in the copy action plugin for an example.
_ansible_no_log
Type: bool
Set to True
whenever an argument in a task or play specifies no_log
. Any module that calls the AnsibleModule.log()
function handles this action automatically. If you have a module that implements its own logging then you need to check the value of _ansible_no_log
. To access _ansible_no_log
in a module, instantiate the AnsibleModule
utility and then check the value of AnsibleModule.no_log
.
Note
no_log
specified in a module’s argument_spec
is handled by a different mechanism.
_ansible_debug
Type: bool
Operates verbose logging and logging of external commands that a module executes. If the module uses the AnsibleModule.debug()
function rather than the AnsibleModule.log()
function then the messages are only logged if you set the _ansible_debug
argument to True
. To access _ansible_debug
in a module, instantiate the AnsibleModule
utility and access AnsibleModule._debug
. For more details, see DEFAULT_DEBUG.
_ansible_diff
Type: bool
With this parameter you can configure your module to show a unified diff of changes that will be applied to the templated files. To access _ansible_diff
in a module, instantiate the AnsibleModule
utility and access AnsibleModule._diff
. You can also access this parameter using the diff
keyword in your playbook, or the relevant environment variable. For more details, see Playbook Keywords and the DIFF_ALWAYS configuration option.
_ansible_verbosity
Type: int
You can use this argument to control the level (0 for none) of verbosity in logging.
_ansible_selinux_special_fs
Type: list
Elements: strings
This argument provides modules with the names of file systems which should have a special SELinux context. They are used by the AnsibleModule
methods which operate on files (changing attributes, moving, and copying).
Most modules can use the built-in AnsibleModule
methods to manipulate files. To access in a module that needs to know about these special context file systems, instantiate AnsibleModule
and examine the list in AnsibleModule._selinux_special_fs
.
This argument replaces ansible.module_utils.basic.SELINUX_SPECIAL_FS
from Module Replacer framework. In the module replacer framework the argument was formatted as a comma-separated string of file system names. Under the Ansiballz framework it is a list. You can access _ansible_selinux_special_fs
using the corresponding environment variable. For more details, see the DEFAULT_SELINUX_SPECIAL_FS configuration option.
New in version 2.1.
_ansible_syslog_facility
This argument controls which syslog facility the module logs to. Most modules should just use the AnsibleModule.log()
function which will then make use of this. If a module has to use this on its own, it should instantiate the AnsibleModule
method and then retrieve the name of the syslog facility from AnsibleModule._syslog_facility
. The Ansiballz code is less elegant than the Module Replacer framework code:
# Old module_replacer wayimport syslogsyslog.openlog(NAME, 0, syslog.LOG_USER)# New Ansiballz wayimport syslogfacility_name = module._syslog_facilityfacility = getattr(syslog, facility_name, syslog.LOG_USER)syslog.openlog(NAME, 0, facility)
For more details, see the DEFAULT_SYSLOG_FACILITY configuration option.
New in version 2.1.
_ansible_version
This argument passes the version of Ansible to the module. To access it, a module should instantiate the AnsibleModule
method and then retrieve the version from AnsibleModule.ansible_version
. This replaces ansible.module_utils.basic.ANSIBLE_VERSION
from Module Replacer framework.
New in version 2.1.
_ansible_module_name
Type: str
This argument passes the information to modules about their name. For more details see, the configuration option DEFAULT_MODULE_NAME.
_ansible_string_conversion_action
This argument provides instructions about what modules should do after the values of the user-specified module parameters are converted to strings. For more details, see the STRING_CONVERSION_ACTION configuration option.
_ansible_keep_remote_files
Type: bool
This argument provides instructions that modules must be ready if they need to keep the remote files. For more details, see the DEFAULT_KEEP_REMOTE_FILES configuration option.
_ansible_socket
This argument provides modules with a socket for persistent connections. The argument is created using the PERSISTENT_CONTROL_PATH_DIR configuration option.
_ansible_shell_executable
Type: bool
This argument ensures that modules use the designated shell executable. For more details, see the ansible_shell_executable remote host environment parameter.
_ansible_tmpdir
Type: str
This argument provides instructions to modules that all commands must use the designated temporary directory, if created. The action plugin designs this temporary directory.
Modules can access this parameter by using the public tmpdir
property. The tmpdir
property will create a temporary directory if the action plugin did not set the parameter.
The directory name is generated randomly, and the the root of the directory is determined by one of these:
As a result, using the ansible.cfg
configuration file to activate or customize this setting will not guarantee that you control the full value.
_ansible_remote_tmp
The module’s tmpdir
property creates a randomized directory name in this directory if the action plugin did not set _ansible_tmpdir
. For more details, see the remote_tmp parameter of the shell plugin.
At the end of a module’s execution, it formats the data that it wants to return as a JSON string and prints the string to its stdout. The normal action plugin receives the JSON string, parses it into a Python dictionary, and returns it to the executor.
If Ansible templated every string return value, it would be vulnerable to an attack from users with access to managed nodes. If an unscrupulous user disguised malicious code as Ansible return value strings, and if those strings were then templated on the control node, Ansible could execute arbitrary code. To prevent this scenario, Ansible marks all strings inside returned data as Unsafe
, emitting any Jinja2 templates in the strings verbatim, not expanded by Jinja2.
Strings returned by invoking a module through ActionPlugin._execute_module()
are automatically marked as Unsafe
by the normal action plugin. If another action plugin retrieves information from a module through some other means, it must mark its return data as Unsafe
on its own.
In case a poorly-coded action plugin fails to mark its results as “Unsafe,” Ansible audits the results again when they are returned to the executor,marking all strings as Unsafe
. The normal action plugin protects itself and any other code that it calls with the result data as a parameter. The check inside the executor protects the output of all other action plugins, ensuring that subsequent tasks run by Ansible will not template anything from those results either.
Special considerations
Pipelining
Ansible can transfer a module to a remote machine in one of two ways:
it can write out the module to a temporary file on the remote host and thenuse a second connection to the remote host to execute it with theinterpreter that the module needs
or it can use what’s known as pipelining to execute the module by piping itinto the remote interpreter’s stdin.
Pipelining only works with modules written in Python at this time becauseAnsible only knows that Python supports this mode of operation. Supportingpipelining means that whatever format the module payload takes before beingsent over the wire must be executable by Python through stdin.
Why pass args over stdin?
Passing arguments through stdin was chosen for the following reasons:
When combined with ANSIBLE_PIPELINING, this keeps the module’s arguments fromtemporarily being saved onto disk on the remote machine. This makes itharder (but not impossible) for a malicious user on the remote machine tosteal any sensitive information that may be present in the arguments.
Command line arguments would be insecure as most systems allow unprivilegedusers to read the full commandline of a process.
Environment variables are usually more secure than the commandline but somesystems limit the total size of the environment. This could lead totruncation of the parameters if we hit that limit.
AnsibleModule
Argument spec
The argument_spec
provided to AnsibleModule
defines the supported arguments for a module, as well as their type, defaults and more.
Example argument_spec
:
module = AnsibleModule(argument_spec=dict( top_level=dict( type='dict', options=dict( second_level=dict( default=True, type='bool', ) ) )))
This section will discuss the behavioral attributes for arguments:
- type:
type
allows you to define the type of the value accepted for the argument. The default value fortype
isstr
. Possible values are:str
list
dict
bool
int
float
path
raw
jsonarg
json
bytes
bits
The
raw
type, performs no type validation or type casting, and maintains the type of the passed value.- elements:
elements
works in combination withtype
whentype='list'
.elements
can then be defined aselements='int'
or any other type, indicating that each element of the specified list should be of that type.- default:
The
default
option allows sets a default value for the argument for the scenario when the argument is not provided to the module. When not specified, the default value isNone
.- fallback:
fallback
accepts atuple
where the first argument is a callable (function) that will be used to perform the lookup, based on the second argument. The second argument is a list of values to be accepted by the callable.The most common callable used is
env_fallback
which will allow an argument to optionally use an environment variable when the argument is not supplied.Example:
username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME']))
- choices:
choices
accepts a list of choices that the argument will accept. The types ofchoices
should match thetype
.- required:
required
accepts a boolean, eitherTrue
orFalse
that indicates that the argument is required. When not specified,required
defaults toFalse
. This should not be used in combination withdefault
.- no_log:
no_log
accepts a boolean, eitherTrue
orFalse
, that indicates explicitly whether or not the argument value should be masked in logs and output.Note
In the absence of
no_log
, if the parameter name appears to indicate that the argument value is a password or passphrase (such as “admin_password”), a warning will be shown and the value will be masked in logs but not output. To disable the warning and masking for parameters that do not contain sensitive information, setno_log
toFalse
.- aliases:
aliases
accepts a list of alternative argument names for the argument, such as the case where the argument isname
but the module acceptsaliases=['pkg']
to allowpkg
to be interchangeably withname
- options:
options
implements the ability to create a sub-argument_spec, where the sub options of the top level argument are also validated using the attributes discussed in this section. The example at the top of this section demonstrates use ofoptions
.type
orelements
should bedict
is this case.- apply_defaults:
apply_defaults
works alongsideoptions
and allows thedefault
of the sub-options to be applied even when the top-level argument is not supplied.In the example of the
argument_spec
at the top of this section, it would allowmodule.params['top_level']['second_level']
to be defined, even if the user does not providetop_level
when calling the module.- removed_in_version:
removed_in_version
indicates which version of ansible-core or a collection a deprecated argument will be removed in. Mutually exclusive withremoved_at_date
, and must be used withremoved_from_collection
.Example:
option = { 'type': 'str', 'removed_in_version': '2.0.0', 'removed_from_collection': 'testns.testcol',},
- removed_at_date:
removed_at_date
indicates that a deprecated argument will be removed in a minor ansible-core release or major collection release after this date. Mutually exclusive withremoved_in_version
, and must be used withremoved_from_collection
.Example:
option = { 'type': 'str', 'removed_at_date': '2020-12-31', 'removed_from_collection': 'testns.testcol',},
- removed_from_collection:
Specifies which collection (or ansible-core) deprecates this deprecated argument. Specify
ansible.builtin
for ansible-core, or the collection’s name (formatfoo.bar
). Must be used withremoved_in_version
orremoved_at_date
.- deprecated_aliases:
Deprecates aliases of this argument. Must contain a list or tuple of dictionaries having some the following keys:
- name:
The name of the alias to deprecate. (Required.)
- version:
The version of ansible-core or the collection this alias will be removed in. Either
version
ordate
must be specified.- date:
The a date after which a minor release of ansible-core or a major collection release will no longer contain this alias.. Either
version
ordate
must be specified.- collection_name:
Specifies which collection (or ansible-core) deprecates this deprecated alias. Specify
ansible.builtin
for ansible-core, or the collection’s name (formatfoo.bar
). Must be used withversion
ordate
.
Examples:
option = { 'type': 'str', 'aliases': ['foo', 'bar'], 'deprecated_aliases': [ { 'name': 'foo', 'version': '2.0.0', 'collection_name': 'testns.testcol', }, { 'name': 'foo', 'date': '2020-12-31', 'collection_name': 'testns.testcol', }, ],},
- mutually_exclusive:
If
options
is specified,mutually_exclusive
refers to the sub-options described inoptions
and behaves as in Dependencies between module options.- required_together:
If
options
is specified,required_together
refers to the sub-options described inoptions
and behaves as in Dependencies between module options.- required_one_of:
If
options
is specified,required_one_of
refers to the sub-options described inoptions
and behaves as in Dependencies between module options.- required_if:
If
options
is specified,required_if
refers to the sub-options described inoptions
and behaves as in Dependencies between module options.- required_by:
If
options
is specified,required_by
refers to the sub-options described inoptions
and behaves as in Dependencies between module options.
Dependencies between module options
The following are optional arguments for AnsibleModule()
:
module = AnsibleModule( argument_spec, mutually_exclusive=[ ('path', 'content'), ], required_one_of=[ ('path', 'content'), ],)
- mutually_exclusive:
Must be a sequence (list or tuple) of sequences of strings. Every sequence of strings is a list of option names which are mutually exclusive. If more than one options of a list are specified together, Ansible will fail the module with an error.
Example:
mutually_exclusive=[ ('path', 'content'), ('repository_url', 'repository_filename'),],
In this example, the options
path
andcontent
must not specified at the same time. Also the optionsrepository_url
andrepository_filename
must not be specified at the same time. But specifyingpath
andrepository_url
is accepted.To ensure that precisely one of two (or more) options is specified, combine
mutually_exclusive
withrequired_one_of
.- required_together:
Must be a sequence (list or tuple) of sequences of strings. Every sequence of strings is a list of option names which are must be specified together. If at least one of these options are specified, the other ones from the same sequence must all be present.
Example:
required_together=[ ('file_path', 'file_hash'),],
In this example, if one of the options
file_path
orfile_hash
is specified, Ansible will fail the module with an error if the other one is not specified.- required_one_of:
Must be a sequence (list or tuple) of sequences of strings. Every sequence of strings is a list of option names from which at least one must be specified. If none one of these options are specified, Ansible will fail module execution.
Example:
required_one_of=[ ('path', 'content'),],
In this example, at least one of
path
andcontent
must be specified. If none are specified, execution will fail. Specifying both is explicitly allowed; to prevent this, combinerequired_one_of
withmutually_exclusive
.- required_if:
Must be a sequence of sequences. Every inner sequence describes one conditional dependency. Every sequence must have three or four values. The first two values are the option’s name and the option’s value which describes the condition. The further elements of the sequence are only needed if the option of that name has precisely this value.
If you want that all options in a list of option names are specified if the condition is met, use one of the following forms:
('option_name', option_value, ('option_a', 'option_b', ...)),('option_name', option_value, ('option_a', 'option_b', ...), False),
If you want that at least one option of a list of option names is specified if the condition is met, use the following form:
('option_name', option_value, ('option_a', 'option_b', ...), True),
Example:
required_if=[ ('state', 'present', ('path', 'content'), True), ('force', True, ('force_reason', 'force_code')),],
In this example, if the user specifies
state=present
, at least one of the optionspath
andcontent
must be supplied (or both). To make sure that precisely one can be specified, combinerequired_if
withmutually_exclusive
.On the other hand, if
force
(a boolean parameter) is set totrue
,yes
and so on, bothforce_reason
andforce_code
must be specified.- required_by:
Must be a dictionary mapping option names to sequences of option names. If the option name in a dictionary key is specified, the option names it maps to must all also be specified. Note that instead of a sequence of option names, you can also specify one single option name.
Example:
required_by={ 'force': 'force_reason', 'path': ('mode', 'owner', 'group'),},
In the example, if
force
is specified,force_reason
must also be specified. Also, ifpath
is specified, then three three optionsmode
,owner
andgroup
also must be specified.
Declaring check mode support
To declare that a module supports check mode, supply supports_check_mode=True
to the AnsibleModule()
call:
module = AnsibleModule(argument_spec, supports_check_mode=True)
The module can determine whether it is called in check mode by checking the boolean value module.check_mode
. If it evaluates to True
, the module must take care not to do any modification.
If supports_check_mode=False
is specified, which is the default value, the module will exit in check mode with skipped=True
and message remote module (<insert module name here>) does not support check mode
.
Adding file options
To declare that a module should add support for all common file options, supply add_file_common_args=True
to the AnsibleModule()
call:
module = AnsibleModule(argument_spec, add_file_common_args=True)
You can find a list of all file options here. It is recommended that you make your DOCUMENTATION
extend the doc fragment ansible.builtin.files
(see Documentation fragments) in this case, to make sure that all these fields are correctly documented.
The helper functions module.load_file_common_arguments()
and module.set_fs_attributes_if_different()
can be used to handle these arguments for you:
argument_spec = { 'path': { 'type': 'str', 'required': True, },}module = AnsibleModule(argument_spec, add_file_common_args=True)changed = False# TODO do something with module.params['path'], like update its contents# Ensure that module.params['path'] satisfies the file options supplied by the userfile_args = module.load_file_common_arguments(module.params)changed = module.set_fs_attributes_if_different(file_args, changed)module.exit_json(changed=changed)