Two problems with ansible-pull on Rocky Linux 8

Hi,

I’d like to use ansible-pull to manage two servers and three desktops in my local network. I’ve read an excellent (though a bit outdated) tutorial about ansible-pull, and it seems like the right fit for my use case.

I have a minimal installation of Rocky Linux 8 on a test box. I just installed Ansible from EPEL, and I have a first draft of a local.yml playbook in a GitHub repository here:

I execute ansible-pull (as root) with the appropriate URL, and here’s an error I get:

fatal: [localhost]: FAILED! => {"changed": false, "msg": "Failed to import 
the required Python library (libselinux-python) on squidbox's Python 
/usr/bin/python3.12.

Now this is a known problem with RHEL8 and compatible clones like Rocky Linux 8. In a “classic” Ansible setup, this can be solved simply by defining this in the appropriate place:

ansible_python_interpreter=/usr/bin/python3

The first problem here is that there seems to be no appropriate place with ansible-pull. Apparently the only solution here is to use an extra variable on the command line like this:

# ansible-pull -U https://github.com/kikinovak/microlinux-squidbox-el8 \
  -e ansible_python_interpreter=/usr/bin/python3

This time things work as expected:

TASK [enable_selinux : Enable SELinux in enforcing mode] **************
ok: [localhost]

So my first question would be: how can I define ansible_python_interpreter=/usr/bin/python3 in a permanent way for ansible-pull ?

In a similar way, I have another problem. Every time I call ansible-pull, I get a series of warnings:

[WARNING]: Could not match supplied host pattern, ignoring: squidbox
[WARNING]: Could not match supplied host pattern, ignoring:
...
[WARNING]: provided hosts list is empty, only localhost is available. 
Note that the implicit localhost does not match 'all'
[WARNING]: Could not match supplied host pattern, ignoring: squidbox
[WARNING]: Could not match supplied host pattern, ignoring:
squidbox.microlinux.lan

Apparently there seems to be no way to explain to ansible-pull that I only want to execute the local.yml play on localhost.

Which brings me to my second question: how do I get rid of these useless warnings ?

Any suggestions ?

Niki

You could use update-alternatives --config python:

[root@rocky8 ~]# update-alternatives --config python

There are 2 programs which provide 'python'.

  Selection    Command
-----------------------------------------------
*  1           /usr/libexec/no-python
 + 2           /usr/bin/python3

as you can see my python is linked to python3. This ansible_python_interpreter shouldn’t be required at this point. As far as I am aware ansible_python_interpreter is required to be configured in the playbook, but you can configure it globally in ansible.cfg as follows in this way instead:

[defaults]
interpreter_python = "/usr/bin/python3"

As for the second problem man ansible-pull:

       -i, --inventory, --inventory-file
          specify inventory host path or comma separated host list. --inventory-file is deprecated. This argument
          may be specified multiple times.

So:

ansible-pull -i host -U url .....

if you want more hosts, comma separate them.

Thank you for your suggestions, but none of them work.

How do you configure your local.yml for ansible-pull ?

Assuming you are not running as root user, you would need to do:

- hosts: localhost
  become: true

currently your playbook doesn’t have that, so if it requires to configure something system-wide then it would fail.

No need for that since ansible-pull runs as root here.

One more thing you can added for those warnings:

[defaults]
localhost_warning=False

[inventory]
inventory_unparsed_warning=False

but then if -i host was used with the ansible-pull command, then it should resolve that anyway since a host has been provided.

No, that doesn’t work either. But then, I’ll just ignore the warnings.

According to ansible documentation that must work, so something not quite right at your end I’m guessing. But yeah, easy enough just to ignore them since they are just warnings.

ansible and ansible-pull are two very different beasts. While ansible-pull is an interesting alternative for machines/networks that are only intermittently online or otherwise sporadically unavailable, it’s also sadly underdocumented.

wild guess, but does it work when you set the following environment variables before running ansible-pull ?

export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8

Red Hat did pull a stunt with el8. They did separate the “platform Python” from “user Python” (and there is no Python for user by default). The platform Python in el8 is /usr/libexec/platform-python3.6 and there is symlink /usr/libexec/platform-python for convenience.

Several Python versions (3.6, 3.8, 3.9, 3.11, 3.12) can be installed for the user and the alternatives can set up the /usr/bin/python3 (and the “unversioned” /usr/bin/python) to point to one of them. If the 3.6 is installed, its /usr/bin/python3.6 is symlink to /usr/libexec/platform-python3.6.

Hence the need to give a hint about ansible_python_interpreter on el8.


EPEL does not actually have Ansible any more. What EPEL has, are “curated sets of Ansible collections”. The ansible-core is in Rocky’s AppStream repo. Whether one needs any of the additional collections does depend on the playbooks.

The ansible-core pulls in Python 3.9 as dependency. Running for example ansible-playbook (on the “control host”) does not work with the 3.6. However, tasks on the managed host can use the 3.6. Not a long ago a managed host could have had mere Python 2.7 …

Perhaps it is safest to use explicitly the same Python (3.9) for both the “control” and “managed” parts (if the ansible-pull even has them separate).

Indeed. The ansible-pull does pull playbooks from git repo and runs them explicitly on localhost. (I wonder how/if delegated tasks would behave?) One could set cron.daily and/or anacron to run it. I did once look at it, but never got into using it. Hence, don’t know where it has the inventory (that is vars for the host, rather than list of hosts). Probably within the repo.

1 Like

Thanks for the detailed explanation. Except now I’m currently jumping through a series of burning loops trying to explain to ansible-pull the simple fact that ansible_python_interpreter has to be /usr/bin/python3. A one-line no-brainer with ansible (using ansible.cfg in one of four possible locations and a corresponding inventory file). But a nightmare with ansible-pull, because nothing seems to work the same. Which is sad, because in principle ansible-pull seems like the perfect tool here.

Any suggestions about how to solve this ? So far no solution seems to work. I think I’ll just drop RHEL 8.x and upgrade everything to RHEL 9.x.

On a side note, buying Ansible and not even providing a fully functional version in the official repositories seems like one of those decisions only Red Hat can make.

I just ran ansible-pull on a rocky 8.10 host - no problem at all:

% uname -a
Linux s03 4.18.0-553.36.1.el8_10.x86_64 #1 SMP Wed Jan 22 16:34:48 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
% which python3
/usr/bin/python3
% ls -al /usr/bin/python3
lrwxrwxrwx. 1 root root 25 Nov 10  2021 /usr/bin/python3 -> /etc/alternatives/python3
% ls -al /etc/alternatives/python3
lrwxrwxrwx. 1 root root 18 Nov 10  2021 /etc/alternatives/python3 -> /usr/bin/python3.6
% ls -al /usr/bin/python3.6
lrwxrwxrwx 1 root root 31 Dec 11 21:41 /usr/bin/python3.6 -> /usr/libexec/platform-python3.6
% ansible-pull -d /home/admin/ansible-pull-test -U https://X.X.X.X/ansible-pull-test.git
Starting Ansible Pull at 2025-02-04 08:48:55
/usr/bin/ansible-pull -d /home/admin/ansible-pull-test -U https://X.X.X.X/ansible-pull-test.git
[WARNING]: Could not match supplied host pattern, ignoring: s03
[WARNING]: Could not match supplied host pattern, ignoring:
localhost.localdomain
localhost | SUCCESS => {
    "after": "80ecd8362236a9b9de573fca2b7366fed903b545",
    "before": "80ecd8362236a9b9de573fca2b7366fed903b545",
    "changed": false,
    "remote_url_changed": false
}
[WARNING]: Could not match supplied host pattern, ignoring: s03
[WARNING]: Could not match supplied host pattern, ignoring:
localhost.localdomain

PLAY [Always run] **************************************************************

TASK [get hostname] ************************************************************
changed: [localhost]

TASK [hostname] ****************************************************************
ok: [localhost] => {
    "msg": "hostname: s03"
}

PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  

1 Like

I misspoke earlier. Should have checked. The /usr/bin/ansible-pull is a Python script.
The el8 version seems to start:

#!/usr/bin/python3.12
# EASY-INSTALL-ENTRY-SCRIPT: 'ansible-core==2.16.3','console_scripts','ansible-pull'

and correspondingly the dnf rq --requires --resolve ansible-core lists python3.12 as dependency. Therefore, the script itself does use Python 3.12, bypassing all alternatives and other configs.

Then it naturally “connects” to localhost, sniffs what Python is there(?), and uses the latter to execute the tasks. That part is where the config could make a difference?


The Ansible developers had some rationale why (after 2.9) the monolith was refactored into core modules and collections of modules. There is ansible-galaxy to “source install” collections from online repo even on distros that do not have any Ansible packages. Yes, Red Hat follows the “less is more” path …

1 Like

Right, here goes. I’ve spent some time with a few sandbox VMs and lots of coffee, and it looks like (almost) all my problems are solved. Only thing left is those pesky warnings about missing hosts, but it looks like this problem is endemic to ansible-pull. I’ll just ignore them.

  1. Configuration files are handled differently with ansible-pull. I had to figure that out. You have to put your stuff in ~/.ansible.cfg. If you just use ./ansible.cfg, things won’t work.
  2. Since stuff is supposed to run locally, an inventory file makes no sense. Well, you can always try to create one, but then watch out for some confusion. This is completely undocumented, except a few educated guesses by a handful of bloggers.
  3. Variables like ansible_python_interpreter have to go in your playbook for lack of an inventory file.

So, after a sunny day of experimenting and working out stuff and then a run in the woods to clear my head, here’s my working configuration (work in progress):

Cheers from the sunny South of France,

Niki