There are many reasons to want to use newer modules than a chosen stable Ansible core release:
- Feature enhancements don’t get backported to stable branches
- Non-security bug fixes only tend to get backported one version — which means if say 2.N.0 hasn’t had all the core bugs ironed out yet, you might not get the benefit of module bug fixes while you remain on 2.N-1.0
- Some improvements only exist in PR form. Some improvements only exist in branches made by combining multiple PRs.† Some improvements are very handy but so experimental they’re not even ready for a PR!†
When that happens, thankfully you don’t have to run off your own megamerge branch of ansible†.
Which ever of the two approaches below you take, I recommend keeping a README.md file in the library directory. For modules, it looks a bit like:
|Module | PR | Notes | |---------------------------|-----------------------------------------------|-----------------| |cloudfront_distribution.py | https://github.com/ansible/ansible/pull/31284 | Unmerged | |ec2_placement_group.py | https://github.com/ansible/ansible/pull/33139 | Available in 2.5|
but the same log is useful for plugins and collections.
Keeping track of why I’m using non-core code allows me to remove it when the desired functionality becomes available in newer Ansible or collections releases.
The collections approach
Using ansible collections to incorporate updates from baseline can be a sensible approach when you need several changes at once or just want to track latest or a branch.
You can use ansible-galaxy to install collections. I always recommend pinning to
a specific version to avoid surprises. If you don’t want to use ansible-galaxy,
you can always just commit the results of installing
the collection (or just update a submodule) in the
below your playbooks (other locations are available through configuring
take note of both the plurals, I wasted hours investigating why
ANSIBLE_COLLECTION_PATHS wasn’t working).
mkdir collections git clone firstname.lastname@example.org:ansible-collections/community.kubernetes collections/community.kubernetes
This will get you the latest merged commits from the official community.kubernetes
(as opposed to
ansible-galaxy collection install -p collections community.kubernetes which
gets you the latest released version) - but you can also clone a fork and choose a
branch to get as yet unmerged commits (e.g. if you’re keen to include an unmerged pull
The selective approach
Use this when you don’t necessarily want to update every module or plugin in a collection which might introduce unexpected behaviours in modules you’re not looking to update
My approach for this is to use the default
library directory in the top level of your playbooks repository,
and put any modules that you need but aren’t yet in the version of ansible
you’re using there.
If you’re using modules that rely on updates to
module_utils shared libraries, you can set
module_utils config directive
in ansible.cfg (
./module_utils is an undocumented default) and copy the relevant
module_utils files into your codebase as well.
The layout of your
directory should reflect that of ansible. For example, if you need updates to the
k8s module, you’ll probably
need to copy one or both of
lib/ansible/module_utils to your
module_utils/k8s directory. You will also need an empty
__init__.py at the bottom level directory.
module_utils/ └── k8s ├── __init__.py ├── common.py └── raw.py
Similarly, you can optionally set
./filter_pluginsas an undocumented default),
./lookup_plugins as an undocumented default),
etc. to point to updated plugins — I tend to use
plugins/filter etc. to reflect Ansible’s codebase structure (but
I didn’t know about the defaults until doing some tests for the update to this page).
One other point worth noting is that if you’re already using roles for your logic, you can put updates of modules, libraries
and plugins in your
plugins directories at the top level of the role.
You’ll need a versioning strategy for your role that reflects Ansible versions so that you can remove published changes
later on (for example my Kubernetes role
has a v2.8 branch without the
module_utils/k8s tree) with published
v2.8-1 tags. The need for an
seem to be as apparent when using a role (i.e. my tests pass on my Kubernetes-role without needing an
† — I’ve been there.