These are hardcoded server-side. See for example the source code for the fetch module. It is empty with a comment stating it is a virtual module.
Call stack:
Runner._execute_module()
inansible/runner/__init__.py
Runner._configure_module()
inansible/runner/__init__.py
ModuleReplacer.modify_module()
inansible/module_common.py
ModuleReplacer._find_snippets_imports()
inansible/module_common.py
To sum things up:
- the module is looked up on the ansible library path
- the file is loaded in memory
- some strings are looked for, and if found in the module file, will modify how it will be called
- If
WANT_JSON
can be found on the file, the type is set tonon_native_want_json
- If a python import from the ansible modules is found (
from ansible.module_utils.
) or a python replacer is found then the type is set tonew
- else the type is set to
old
- If
- some strings are replaced. Mostly python imports are replaced by the actual python module content and magic replacer strings are replaced with boilerplate code and arguments in python format
result of repr()
."<<INCLUDE_ANSIBLE_MODULE_ARGS>>"
is replaced by the python expression for the arguments"<<INCLUDE_ANSIBLE_MODULE_COMPLEX_ARGS>>"
is replaced by the python expression for the complex arguments
- the shebang is parsed
ModuleReplacer
then returns toRunner
with the replaced module source code, the detected type of module and the shebang- depending on the module type, the
Runner
will call the module differently.old
modules: These are considered executable scripts and will be called with the interpreter in the shebang and an argument file containing arguments in the formvar=val var2=val2
that is compatible with shell scriptsnon_native_want_json
modules: Same asold
but the argument file will be a JSON file. This can enable more complex argumentsnew
modules: These are generally python scripts and support more features such as the check mode (testing changes but not doing anything to change the target) and no_log (whatever that means). Arguments are passed by string replacement in the source code. These modules are still executed by the interpreter in the shebang, so you could write it in any language and parse arguments replaced in source code.
To test some of this, the following module was used:
#!/bin/bash
: from ansible.module_utils.
: WANT_JSON
#(
cat <<EOF
args:
"<<INCLUDE_ANSIBLE_MODULE_ARGS>>"
complex args:
"<<INCLUDE_ANSIBLE_MODULE_COMPLEX_ARGS>>"
version:
"<<ANSIBLE_VERSION>>"
EOF
env
echo "$@"
echo =====begin=====
cat ${1:-/dev/null}
echo
echo ======end======
#) | logger
exit 1
And the following playbook:
---
- hosts: localhost
sudo: yes
tasks:
- test:
a: b
c: ["d", "e"]
# yml: file
# yes: true
# no:
# - nein
# - non