Ansible Custom Modules
Quick guide on writing Custom Modules in Ansible

Hello reader, this is Vish currently working as a DevOps Engineer for the past 3+ years and a total of 9+ years of experience in the IT industry. Am passionate about learning DevOps and in the mission of enhancing my learning into container orchestration tools, monitoring and security.
In this article, I have covered how to write/understand custom modules that can be used in our Ansible Playbooks for performing certain tasks. This blog can be a kick-start for you to understand and help write your custom modules.
What is Custom Module in Ansible
Ansible is a powerful Configuration Management tool that has many built-in modules to configure target systems but there would be cases where we would need to perform tasks that are not provided by Ansible. So we have the flexibility of writing our custom modules and using them. These modules can be written in any language of our choice and I have preferred writing here with the help of Python.
Folder Structure
Here is the link to the project which I have pushed to GitHub - https://github.com/devopsvish/ansible-custom-module
Let me go step by step so you can understand the concept with ease. I have also dockerized this project so you can quickly try it out on your machine.
I have followed the below project structure and let's go thru it real quick

inventory.ini - contains the lists of our target hosts. In my case am targeting my local host.
vish_module.py - this is a custom module that I have written to walkthru the blog which outputs us a small employee information
employee_info.yml - the playbook which uses the custom module to give us the result
vishtest_playbook.yml - a test playbook to check if ansible is working on our local machine
ansible.cfg - this is the ansible configuration file where am mentioning where the custom module resides
Custom Module Explanation
Usually, Custom modules are placed inside the library folder and the same path is configured in the ansible.cfg file to pick the modules from the right location during our playbook execution.
Here is the full code of the custom module and I will have it explained line by line.
from ansible.module_utils.basic import AnsibleModule
def main():
parameters = {
'name': {"required": True, "type": 'str'},
'designation': {"required": True, "type": 'str'},
'skills': {"required": True, "type": 'str'},
'location': {"required": False, "type": 'str'}
}
module = AnsibleModule(argument_spec=parameters)
name = module.params['name']
designation = module.params['designation']
skills = module.params['skills']
location = module.params['location']
output = {
'name': name,
'designation': designation,
'skills': skills,
'location': location,
'message': f"{name} is a {designation} with {skills} from {location}",
'location_type': f"{type(location)}"
}
module.exit_json(changed=False, **output)
if __name__ == '__main__':
main()
1. Import the module
from ansible.module_utils.basic import AnsibleModule
This line imports the AnsibleModule class from the ansible.module_utils.basic module which can be used to interact with Ansible.
2. Main function
def main():
# logic of the code goes here
The logic of the custom module goes here which can be used on performing tasks on target systems
3. Argument Specification
parameters = {
'name': {"required": True, "type": 'str'},
'designation': {"required": True, "type": 'str'},
'skills': {"required": True, "type": 'str'},
'location': {"required": False, "type": 'str'}
}
The parameters dictionary defines the expected arguments for the module. Each argument is specified with its name, required status and datatype.
Let me take
designationargument for exampleName of the argument:
designationRequired status of the argument:
True(accepts a boolean)The datatype of the argument:
str(accepts str, bool, int, list, dict, float)
4. Instantiate AnsibleModule
module = AnsibleModule(argument_spec=parameters)
The AnsibleModule class is instantiated with the argument specification defined earlier and this allows the module to receive and validate the arguments passed by Ansible
5. Retrieve the values of the arguments
name = module.params['name']
designation = module.params['designation']
skills = module.params['skills']
location = module.params['location']
The values of the arguments are retrieved with the help of params attribute of the module object
6. Output dictionary
output = {
'name': name,
'designation': designation,
'skills': skills,
'location': location,
'message': f"{name} is a {designation} with {skills} from {location}",
}
Here an output dictionary is created with the desired key-value pair and the values are obtained from the arguments passed to the module. This is the dictionary am going to output during our playbook execution
7. Exit the Module
module.exit_json(changed=False, **output)
The module execution is completed by calling the
exit_jsonmethodThe
changedparameter is set to false as the module does not make any change to the target system. If it changes anything on the target system we can set this to True and the same will be reflected in the Ansible playbook result executionThe result of the module is provided as a keyword argument using the
**outputsyntax
Playbook Execution
- name: Execute vish module for testing
hosts: vish-localhost
become: true
gather_facts: true
tasks:
- name: Get the Employee info
vish_module:
name: "Vish"
designation: "DevOps Engineer"
skills: "Linux, Docker, etc"
location: "Bangalore"
register: output
- name: Show the employee info output
debug:
var: output
Inside the playbook of the first task, the module written can be called just by its name. Here the name of the module is
vish_modulewhich I have mentioned inGet the Employee infotask.Inside the module, I have passed the arguments as required by the module where the required status is mentioned in the module
Am using the
registerkeyword to store the outputIn the second task, am using the debug module to output values for us to verify.
Results

so by writing custom modules the similar way we can make changes to the target system as per our requirements.
Thats it!! It's very easy, right? Try writing your own modules and start testing it. Happy Learning.
Please let me know in the comment section about any corrections/mistakes, am open to improvements and suggestions.
Please do follow me for more such content related to DevOps world
Cheers, Vish. Happy Learning!!!



