How to fix SSH errors when using Ansible with newer OSes like Ubuntu 16.04

Recently, as I've been building more and more servers running Ubuntu 16.04, I've hit the following errors:

PLAY [host] ************************************************************************************************************

TASK [Gathering Facts] *************************************************************************************************
fatal: [1.2.3.4]: UNREACHABLE! => {"changed": false, "msg": "SSH Error: data could not be sent to remote host "1.2.3.4". Make sure this host can be reached over ssh", "unreachable": true}

or:

/bin/sh: 1: /usr/bin/python: not found

The former error seems to happen when you're running a playbook on an Ubuntu 16.04 host (with gather_facts: yes), while the latter happens if you're using a minimal distribution that doesn't include Python at all. The problem, in both cases, is that Python 2.x is not installed on the server, and there are two different fixes:

  1. If you already have Python 3 installed on the server (such is the case with Ubuntu 16.04, by default), you can set in your inventory: ansible_python_interpreter=/usr/bin/python3. This enables Ansible's (currently experimental as of 2.3) Python 3 support, which seems to work well for most Ansible modules.
  2. If you don't have Python installed on the server, you should change the structure of your playbook so it will ensure Python 2 is installed prior to running the rest of the playbook. See the below example, which is lifted from Drupal VM:
---
- hosts: drupalvm
  gather_facts: no

  pre_tasks:
    # See: https://github.com/geerlingguy/drupal-vm/issues/1245
    - name: Install Python if it's not available.
      raw: test -e /usr/bin/python || (apt -y update && apt install -y python-minimal)
      register: output
      changed_when: output.stdout != ""

    - action: setup
      tags: ['always']

Note that I set gather_facts: no (this prevents Ansible from trying to run Python modules before Python is available)—then after ensuring Python is present, I run the task action: setup (with the always tag so it's always run, even if you're just running a subset of tasks later). This is basically a 'poor man's gather_facts' that gathers facts in the middle of a playbook.

Using this, you should be able to overcome the problems caused by not having Python 2 available on the server you're controlling. Hopefully Ansible will be 100% compatible with Python 3 soon, and this problem will not require any additional code to make it work!

Comments

I had the same problem with gathering facts on Ubuntu 16.04. Your post saved me, thanks!

Useful post - thanks for the insight.

Do you know if this problem will persist for future versions of Ubuntu? Or is there a specific Ansible version in which this problem goes away?

Hi Jeff,

I read your ansible and raspberry pi tips with relish. I can't get past on of these issues on CentOS 7. Here's a sample session:

```$ rm ~/.ansible.cfg
$ ansible -e ansible_python_interpreter=/bin/python3 -i 172.24.145.147, -m ping -u ansible all
[WARNING]: sftp transfer mechanism failed on [172.24.145.147]. Use ANSIBLE_DEBUG=1 to see detailed
information
[WARNING]: scp transfer mechanism failed on [172.24.145.147]. Use ANSIBLE_DEBUG=1 to see detailed
information
172.24.145.147 | UNREACHABLE! => {
"changed": false,
"msg": "Data could not be sent to remote host \"172.24.145.147\". Make sure this host can be reached over ssh: ",
"unreachable": true
}
$ ssh [email protected]
Last login: Fri Oct 29 23:32:41 2021 from hadar.vindaloo.com
[ansible@client-13 ~]$ ls -l /bin/python3
lrwxrwxrwx. 1 root root 9 Oct 29 16:18 /bin/python3 -> python3.6
[ansible@client-13 ~]$ /bin/python3
Python 3.6.8 (default, Nov 16 2020, 16:55:22)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> exit()
[ansible@client-13 ~]$ logout
Connection to 172.24.145.147 closed.
$ ansible --version
ansible 2.9.7
config file = None
configured module search path = [u'/home/chris/.ansible/plugins/modules', u'/usr/local/share/py27-ansible/plugins/modules']
ansible python module location = /usr/local/lib/python2.7/site-packages/ansible
executable location = /usr/local/bin/ansible
python version = 2.7.18 (default, Jun 2 2020, 04:52:07) [GCC 4.2.1 Compatible FreeBSD Clang 8.0.0 (tags/RELEASE_800/final 356365)]
$```