|
Packit Service |
0f71a7 |
# Writing a new Ansible FreeIPA module
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
## Minimum requirements
|
|
Packit Service |
0f71a7 |
A ansible-freeipa module should have:
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
* Code:
|
|
Packit Service |
0f71a7 |
* A module file placed in `plugins/modules/<ipa_module_name>.py`
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
* Documentation:
|
|
Packit Service |
0f71a7 |
* `README-<module_name>.md` file in the root directory and linked from the main README.md
|
|
Packit Service |
0f71a7 |
* Example playbooks in `playbooks/<module_name>/` directory
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
* Tests:
|
|
Packit Service |
0f71a7 |
* Test cases (also playbooks) defined in `tests/<module_name>/test_<something>.yml`. It's ok to have multiple files in this directory.
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
## Code
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
The module file have to start with the python shebang line, license header and definition of the constants `ANSIBLE_METADATA`, `DOCUMENTATION`, `EXAMPLES` and `RETURNS`. Those constants need to be defined before the code (even imports). See https://docs.ansible.com/ansible/latest/dev_guide/developing_modules_general.html#starting-a-new-module for more information.
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
Although it's use is not yet required, ansible-freeipa provides `FreeIPABaseModule` as a helper class for the implementation of new modules. See the example bellow:
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
```python
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
from ansible.module_utils.ansible_freeipa_module import FreeIPABaseModule
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
class SomeIPAModule(FreeIPABaseModule):
|
|
Packit Service |
0f71a7 |
ipa_param_mapping = {
|
|
Packit Service |
0f71a7 |
"arg_to_be_passed_to_ipa_command": "module_param",
|
|
Packit Service |
0f71a7 |
"another_arg": "get_another_module_param",
|
|
Packit Service |
0f71a7 |
}
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
def get_another_module_param(self):
|
|
Packit Service |
0f71a7 |
another_module_param = self.ipa_params.another_module_param
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
# Validate or modify another_module_param ...
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
return another_module_param
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
def check_ipa_params(self):
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
# Validate your params here ...
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
# Example:
|
|
Packit Service |
0f71a7 |
if not self.ipa_params.module_param in VALID_OPTIONS:
|
|
Packit Service |
0f71a7 |
self.fail_json(msg="Invalid value for argument module_param")
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
def define_ipa_commands(self):
|
|
Packit Service |
0f71a7 |
args = self.get_ipa_command_args()
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
self.add_ipa_command("some_ipa_command", name="obj-name", args=args)
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
def main():
|
|
Packit Service |
0f71a7 |
ipa_module = SomeIPAModule(argument_spec=dict(
|
|
Packit Service |
0f71a7 |
module_param=dict(type="str", default=None, required=False),
|
|
Packit Service |
0f71a7 |
another_module_param=dict(type="str", default=None, required=False),
|
|
Packit Service |
0f71a7 |
))
|
|
Packit Service |
0f71a7 |
ipa_module.ipa_run()
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
if __name__ == "__main__":
|
|
Packit Service |
0f71a7 |
main()
|
|
Packit Service |
0f71a7 |
```
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
In the example above, the module will call the command `some_ipa_command`, using "obj-name" as name and, `arg_to_be_passed_to_ipa_command` and `another_arg` as arguments.
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
The values of the arguments will be determined by the class attribute `ipa_param_mapping`.
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
In the case of `arg_to_be_passed_to_ipa_command` the key (`module_param`) is defined in the module `argument_specs` so the value of the argument is actually used.
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
On the other hand, `another_arg` as mapped to something else: a callable method. In this case the method will be called and it's result used as value for `another_arg`.
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
**NOTE**: Keep mind that to take advantage of the parameters mapping defined in `ipa_param_mapping` you will have to call `args = self.get_ipa_command_args()` and use `args` in your command. There is no implicit call of this method.
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
## Disclaimer
|
|
Packit Service |
0f71a7 |
|
|
Packit Service |
0f71a7 |
The `FreeIPABaseModule` is new and might not be suitable to all cases and every module yet. In case you need to extend it's functionality for a new module please open an issue or PR and we'll be happy to discuss it.
|