Ansible Custom Modules
Introduction
Ansible is a powerful automation tool that allows users to manage and configure systems. While Ansible comes with a vast array of built-in modules, there may be situations where you need to create custom modules to perform specific tasks that are not covered by the built-in modules. This tutorial will guide you through creating your own custom modules in Ansible.
Prerequisites
Before you begin, ensure that you have the following:
- Ansible installed on your system.
- Basic understanding of Python programming.
- Basic knowledge of YAML and Ansible playbooks.
Creating a Basic Custom Module
To create a custom module, you'll need to write a Python script that follows certain conventions. Let's start by creating a simple custom module that returns a message.
Step 1: Create the Python Script
Create a new file named my_custom_module.py
and add the following code:
#!/usr/bin/python
from ansible.module_utils.basic import AnsibleModule
def main():
module_args = dict(
name=dict(type='str', required=True)
)
module = AnsibleModule(
argument_spec=module_args,
supports_check_mode=True
)
name = module.params['name']
result = dict(
changed=False,
message='Hello, {}'.format(name)
)
module.exit_json(**result)
if __name__ == '__main__':
main()
Step 2: Make the Script Executable
Ensure that the script is executable by running the following command:
Step 3: Create a Playbook to Use the Custom Module
Create a new playbook file named custom_module_playbook.yml
and add the following content:
- name: Test custom module
hosts: localhost
tasks:
- name: Run custom module
my_custom_module:
name: World
register: result
- name: Print result
debug:
var: result.message
Step 4: Run the Playbook
Run the playbook using the following command:
You should see output similar to the following:
PLAY [Test custom module] ***********************************************
TASK [Gathering Facts] *******************************************************
ok: [localhost]
TASK [Run custom module] *****************************************************
ok: [localhost]
TASK [Print result] **********************************************************
ok: [localhost] => {
"result.message": "Hello, World"
}
PLAY RECAP *******************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0
Handling Module Parameters
Custom modules can accept various parameters to perform different tasks. Let's enhance our module to accept two parameters: name
and greeting
.
Step 1: Update the Python Script
Modify the my_custom_module.py
script as follows:
#!/usr/bin/python
from ansible.module_utils.basic import AnsibleModule
def main():
module_args = dict(
name=dict(type='str', required=True),
greeting=dict(type='str', required=False, default='Hello')
)
module = AnsibleModule(
argument_spec=module_args,
supports_check_mode=True
)
name = module.params['name']
greeting = module.params['greeting']
result = dict(
changed=False,
message='{}, {}'.format(greeting, name)
)
module.exit_json(**result)
if __name__ == '__main__':
main()
Step 2: Update the Playbook
Update the custom_module_playbook.yml
to use the new parameter:
- name: Test custom module
hosts: localhost
tasks:
- name: Run custom module
my_custom_module:
name: World
greeting: Hi
register: result
- name: Print result
debug:
var: result.message
Step 3: Run the Playbook
Run the playbook again using the same command:
You should see output similar to the following:
PLAY [Test custom module] ***********************************************
TASK [Gathering Facts] *******************************************************
ok: [localhost]
TASK [Run custom module] *****************************************************
ok: [localhost]
TASK [Print result] **********************************************************
ok: [localhost] => {
"result.message": "Hi, World"
}
PLAY RECAP *******************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0
Advanced Features
Custom modules can perform more complex tasks, handle errors, and support check mode. In this section, we'll cover these advanced features.
Error Handling
To handle errors, use the module.fail_json()
method. Modify the script to fail if the name parameter is "error":
#!/usr/bin/python
from ansible.module_utils.basic import AnsibleModule
def main():
module_args = dict(
name=dict(type='str', required=True),
greeting=dict(type='str', required=False, default='Hello')
)
module = AnsibleModule(
argument_spec=module_args,
supports_check_mode=True
)
name = module.params['name']
greeting = module.params['greeting']
if name == 'error':
module.fail_json(msg='An error occurred!')
result = dict(
changed=False,
message='{}, {}'.format(greeting, name)
)
module.exit_json(**result)
if __name__ == '__main__':
main()
Supporting Check Mode
Check mode allows you to see what changes would be made without actually making them. Ensure your module supports check mode by checking module.check_mode
:
#!/usr/bin/python
from ansible.module_utils.basic import AnsibleModule
def main():
module_args = dict(
name=dict(type='str', required=True),
greeting=dict(type='str', required=False, default='Hello')
)
module = AnsibleModule(
argument_spec=module_args,
supports_check_mode=True
)
name = module.params['name']
greeting = module.params['greeting']
if name == 'error':
module.fail_json(msg='An error occurred!')
result = dict(
changed=False,
message='{}, {}'.format(greeting, name)
)
if module.check_mode:
module.exit_json(**result)
# Perform any actions here
module.exit_json(**result)
if __name__ == '__main__':
main()
Conclusion
In this tutorial, we've covered the basics of creating custom modules in Ansible. We started with a simple module and gradually added more features, including handling parameters, error handling, and supporting check mode. With this knowledge, you can create custom modules tailored to your specific needs and extend Ansible's functionality even further.