"The What?" - In this post I am going to provide a general understanding on how to use a custom Ansible module. A module is essentially a reusable standalone script that Ansible will run on your behalf. The module can be run remotely and/or locally. Modules have the ability to provide a defined interface, will accept arguments, and return information to Ansible by printing a JSON string to stdout before exiting.
"The Why?" - Sometimes you may want to rely on a custom module if you desire functionality that is not available in any of the already existing modules found in any of the Ansible collections. Custom modules let you choose any programming language and follow your own rules.
"The How?" - In the brief example I am going to provide I will show you how to break out into a module that will interact with a Cisco ISE API, handle XML data manipulation, and finally return a JSON string back to Ansible. There are a couple of pre-reqs. The important one for now, is that you must add the module locally to the appropriate directory so that Ansible has the ability to find and execute it. The other pre-reqs that are equally as important that I am not going to dive into on here include module format & documentation. For tips & guidelines beyond my post see here: https://docs.ansible.com/ansible/latest/dev_guide/developing_modules_documenting.html#developing-modules-documenting
Ok, so I intend on sharing the Ansible playbook along with the module and explaining how things work. Let's move forward with the understanding that this example is simple, yet effective. Also, my main purpose for this custom module was so that I could handle XML data more efficiently with python. The following python code is a boiler template that can be referenced so you have something to use/test with (follow my comments for understanding):
*Be sure to update the uri with the appropriate ISE ip address that fits your environment. Also, update so that you use the respective ERS user/pass too.
One more important note, I actually used curl via cli to see what data would be returned to cli. I then determined what important/valuable information I wanted. Next I extracted the xml tags so I knew what to reference when using tree.findtext.
Next, a rather important piece, after adding the module locally to the Ansible server here is the simple playbook used to invoke the module. Upon invocation with Ansible the python code inside our module is executed against the ISE API to retrieve client data. Here is an overview of the Ansible playbook used to invoke the module:
With tower I have a survey that prompts the user who executed the job template for the mac address (hw_addr variable) that is passed into the module. Running the playbook from CLI would look something like this:
ansible-playbook ise_module.yml --extra-vars "hw_addr=XX:XX:XX:XX:XX:XX"
Once you have added the module to the proper local location on the Ansible server you should be able to execute the playbook via Tower or CLI. In this example I was using Tower, but here is the result from running the playbook that invokes the custom module.
As you can see we have successfully interacted with the ISE API via the python code, and passed the results back to Ansible. The desired extracted information is returned & printed to screen.
See more under the Automation tab, and/or via the <ansible><rest> tags. Cheers!