I am creating a bunch of filter plugins for Ansible (2.9/2.13) and I would like to have a tools library that can be used by these filter plugins.
I have the directory filter_plugins
under my playbook directory and in there, I have a bunch of python scripts that provide Ansible with various filters. This works fine.
Now, some of these python scripts have the same functions. Naturally, I would like to move these shared function to a separate library file. So here is what I tried:
filter_plugins
[WARNING]: Skipping plugin (/<REDACTED>/playbook_dir/filter_plugins/tools.py) as it seems to be invalid: module 'ansible.plugins.filter.966997458576792353_tools' has no attribute 'FilterModule'
import library.tools
or from library.tools import shared_function
)
__init__.py
). Ansible gives me this error:[WARNING]: Skipping plugin (/<REDACTED>/playbook_dir/filter_plugins/check.py) as it seems to be invalid: No module named 'tools'
All the filter scripts look basically the same (some have more filters, some have less):
#!/usr/bin/python
class FilterModule(object):
def filters(self):
return {
'filter1': self.filter1,
'filter2': self.filter2
}
def shared_function(data_to_process):
processed_data = <process_data>
return processed_data
def filter1(self, in_data):
"""some code to process in_data to out_data"""
process_data = <do_some_stuff>
out_data = shared_function(process_data)
return out_data
def filter2(self, in_data):
"""some other code to process in_data to out_data"""
process_data = <do_some_different_stuff>
out_data = shared_function(process_data)
return out_data
As shared_function
is used in more than one filter script, I want to move it out of there to the tools.py
library
Can anybody help me find the correct way to include local library files in filter plugins for Ansible?
Thanx for your help.
If you were writing an Ansible module, the answer would be to place your shared code inside the module_utils
directory. Unfortunately, this solution isn't available to plugins such as filters.
Issue #28770 has some conversation around this topic, and the recommended solution is to use a playbook-adjacent collection. A collection is a set of resources including plugins, modules, roles, playbooks, etc.
As described in the documentation, you can include a collection "adjacent to" (in the same directory as) your playbook:
You can also keep a collection adjacent to the current playbook, under a collections/ansible_collections/ directory structure.
playbook.yaml ├── collections/ │ └── ansible_collections/ │ └── my_namespace/ │ └── my_collection/<collection structure lives here>
I'm going to add a collection larsks.myplugins
to my local directory, and then create a filter plugin and some shared code. I'll use the following structure:
.
├── collections
│ └── ansible_collections
│ └── larsks
│ └── myplugins
│ └── plugins
│ ├── filter
│ │ └── myplugin.py
│ └── module_utils
│ └── mycommon.py
└── playbook.yaml
In mycommon.py
I have:
def mysharedfunction(v):
return v.upper()
In myplugin.py
I have:
from ansible_collections.larsks.myplugins.plugins.module_utils.mycommon import mysharedfunction
class FilterModule:
def filters(self):
return {'myfilter': mysharedfunction}
This allows me to write a playbook like this:
- hosts: all
gather_facts: false
tasks:
- debug:
msg: "{{ 'this is a test' | larsks.myplugins.myfilter }}"
So there you have a filter plugin importing shared code from another module.