Installing an older Ansible version via pipx
Wed 20 November 2024Latest Ansible requires Python 3.8 on the remote hosts
... and therefore, hosts running Debian Buster are now unsupported.
Monday, I updated the system on my laptop (Debian Sid), and I got the latest
version of ansible-core
, 2.18
:
$ ansible --version | head -1
ansible [core 2.18.0]
To my surprise, Ansible started to fail with some remote hosts:
ansible-core requires a minimum of Python version 3.8. Current version: 3.7.3 (default, Mar 23 2024, 16:12:05) [GCC 8.3.0]
Yep, I do have to work with hosts running Debian Buster (aka. oldoldstable). While Buster is old, it's still out there, and it's still supported via Freexian’s Extended LTS.
How are we going to keep managing those machines? Obviously, we'll need an older version of Ansible.
Pipx to the rescue
TL;DR
pipx install --include-deps ansible==10.6.0
pipx inject ansible dnspython # for community.general.dig
Installing Ansible via pipx
Lately I discovered pipx and it's incredibly simple, so I thought I'd give it a try for this use-case.
Reminder: pipx
allows users to install Python applications in isolated
environments. In other words, it doesn't make a mess with your system like
pip
does, and it doesn't require you to learn how to setup Python virtual
environments by yourself. It doesn't ask for root privileges either, as it
installs everything under ~/.local/
.
First thing to know: pipx install ansible
won't cut it, it doesn't install
the whole Ansible suite. Instead we need to use the --include-deps
flag in
order to install all the Ansible commands.
The output should look something like that:
$ pipx install --include-deps ansible==10.6.0
installed package ansible 10.6.0, installed using Python 3.12.7
These apps are now globally available
- ansible
- ansible-community
- ansible-config
- ansible-connection
- ansible-console
- ansible-doc
- ansible-galaxy
- ansible-inventory
- ansible-playbook
- ansible-pull
- ansible-test
- ansible-vault
done! ✨ 🌟 ✨
Note: at the moment 10.6.0
is the latest release of the 10.x
branch, but
make sure to check https://pypi.org/project/ansible/#history and install
whatever is the latest on this branch. The 11.x
branch doesn't work for us,
as it's the branch that comes with ansible-core 2.18, and we don't want that.
Next: do NOT run pipx ensurepath
, even though pipx might suggest that. This
is not needed. Instead, check your ~/.profile
, it should contain these lines:
# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/.local/bin" ] ; then
PATH="$HOME/.local/bin:$PATH"
fi
Meaning: ~/.local/bin/
should already be in your path, unless it's the
first time you installed a program via pipx
and the directory ~/.local/bin/
was just created. If that's the case, you have to log out and log back in.
Now, let's open a new terminal and check if we're good:
$ which ansible
/home/me/.local/bin/ansible
$ ansible --version | head -1
ansible [core 2.17.6]
Yep! And that's working already, I can use Ansible with Buster hosts again.
What's cool is that we can run ansible
to use this specific Ansible version,
but we can also run /usr/bin/ansible
to run the latest version that is
installed via APT.
Injecting Python dependencies needed by collections
Quickly enough, I realized something odd, apparently the plugin
community.general.dig
didn't work anymore. After some research, I found a
one-liner to test that:
# Works with APT-installed Ansible? Yes!
$ /usr/bin/ansible all -i localhost, -m debug -a msg="{{ lookup('dig', 'debian.org./A') }}"
localhost | SUCCESS => {
"msg": "151.101.66.132,151.101.2.132,151.101.194.132,151.101.130.132"
}
# Works with pipx-installed Ansible? No!
$ ansible all -i localhost, -m debug -a msg="{{ lookup('dig', 'debian.org./A') }}"
localhost | FAILED! => {
"msg": "An unhandled exception occurred while running the lookup plugin 'dig'.
Error was a <class 'ansible.errors.AnsibleError'>, original message: The dig
lookup requires the python 'dnspython' library and it is not installed."
}
The issue here is that we need python3-dnspython
, which is installed on my
system, but is not installed within the pipx virtual environment. It seems that
the way to go is to inject the required dependencies in the venv, which is
(again) super easy:
$ pipx inject ansible dnspython
injected package dnspython into venv ansible
done! ✨ 🌟 ✨
Problem fixed! Of course you'll have to iterate to install other missing dependencies, depending on which Ansible external plugins are used in your playbooks.
Closing thoughts
Hopefully there's nothing left to discover and I can get back to work! If there's more quirks and rough edges, drop me an email so that I can update this blog post.
Let me also credit another useful blog post on the matter: https://unfriendlygrinch.info/posts/effortless-ansible-installation/