Skip to content

Instantly share code, notes, and snippets.

@gwillem
Created June 16, 2016 21:59
Show Gist options
  • Save gwillem/4ba393dceb55e5ae276a87300f6b8e6f to your computer and use it in GitHub Desktop.
Save gwillem/4ba393dceb55e5ae276a87300f6b8e6f to your computer and use it in GitHub Desktop.
Get Ansible to work on bare Ubuntu 16.04 without python 2.7
# Add this snippet to the top of your playbook.
# It will install python2 if missing (but checks first so no expensive repeated apt updates)
# gwillem@gmail.com
- hosts: all
gather_facts: False
tasks:
- name: install python 2
raw: test -e /usr/bin/python || (apt -y update && apt install -y python-minimal)
@mabushey
Copy link

mabushey commented Jun 8, 2017

On Ubuntu 16.04, apt install python-minimal installs: python python-minimal python2.7 python2.7-minimal

Only installing python2.7 does not get you /usr/bin/python, so this does not work for Ansible.

@manelclos
Copy link

based on geromegamez answers, you can make python3 the default adding this to your hosts file (inventory):

[all:vars]
ansible_python_interpreter=/usr/bin/python3

@Lewiscowles1986
Copy link

@mabushey here's what I'm doing (we need python3 for other things)

---
- hosts: all
  gather_facts: true
  vars:
  pre_tasks:
  - name: install python
    raw: bash -c "test -e /usr/bin/python || (apt -qqy update && apt install -qqy python python-pip python3 python3-pip)"
    register: output
    changed_when: output.stdout != ""
  tasks:

This seems to work for us on ubuntu stock and cloud images from various providers

@sebitoelcheater
Copy link

I created many Digitalocean Droplets and all of them failed when tried to run ansible playbook (even after installing python with apt-get!). Adding this script made it works. Why?

@IuryAlves
Copy link

Awesome!! Thanks

@inkatze
Copy link

inkatze commented Sep 18, 2017

Thanks!

@iDemonix
Copy link

I spun up 4x new Ubuntu 17.04 VMs and tried to do the following:

  pre_tasks:
  - name: Install python2 for Ansible
    raw: bash -c "test -e /usr/bin/python || (apt -qqy update && apt install -qqy python-minimal)"
    register: output
    changed_when: output.stdout != ""
  - name: Install pip
    apt:
      name: python-pip
      state: present
fatal: [209.222.2.256]: FAILED! => {"changed": false, "failed": true, "module_stderr": "Shared connection to 209.222.2.256 closed.\r\n", "module_stdout": "Traceback (most recent call last):\r\n  File \"/root/.ansible/tmp/ansible-tmp-1505758704.28-42062379270360/apt.py\", line 17, in <module>\r\n    import zipfile\r\nImportError: No module named zipfile\r\n", "msg": "MODULE FAILURE", "rc": 0}

The python installation worked, but the pip installation failed, as the apt module required zipfile. I couldn't install pip using apt-get, and it was proving a pain to get it another way, so I swapped python-minimal in the above for python, which has the module, and it ran fine.

@philipobrien
Copy link

Using the suggestions above doesn't seem to be affecting the changed status for me

---
- hosts: all
  gather_facts: False
  become: yes
  pre_tasks:
    - name: Install python for Ansible
      raw: bash -c "test -e /usr/bin/python || (apt -qqy update && apt install -qqy python-minimal)"
      register: output
      changed_when: output.stdout != ""
    - name: Gathering Facts
      setup:

running it repeatedly keeps producing

PLAY [all] ***************************************************************************************************************************************************

TASK [Install python for Ansible]
changed: [xx.xx.xx.xxx]

@DanLipsitt
Copy link

Where are people putting this? I wanted to use it in an include in roles/common/main.yml, so that it can be shared between playbooks, but it seems to need to be in the playbook itself.

@dpetukhov
Copy link

dpetukhov commented Oct 13, 2017

By the way, if you're using Vagrant, you can run shell provision before ansible. Here is my Vagrant file example:

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure(2) do |config|
  config.vm.box = "ubuntu/xenial64"

  config.vm.provider "virtualbox" do |vb|  
    vb.customize ["modifyvm", :id, "--cpus", "1"]
    vb.customize ["modifyvm", :id, "--memory", "768"]
    vb.name = "novoansible"
  end

  # Install python for ansible
  config.vm.provision "shell", inline: <<-SHELL
    test -e /usr/bin/python || (apt -qqy update && apt install -qqy python-minimal)
  SHELL
end

@okamos
Copy link

okamos commented Oct 14, 2017

Thanks a lot 😄

@VaesNick
Copy link

VaesNick commented Dec 6, 2017

@DanLipsitt you can make a role for it however you will need to diasable fact gathering for every playbook you use it in, and use the setup module afther to gather facts.

@tmugford
Copy link

Great work all. Just on the question of notifying Ansible when a change has occurred, I found the following worked correctly for me without having to resort to string comparison.

- name: Install Python
  hosts: all
  gather_facts: false
  tasks:
    - name: Install Python 2.x
      raw: test -e /usr/bin/python || (apt update && apt install -y python-simplejson)
      register: test
      changed_when: test.stdout

Using Ansible 2.4.2.0 (macOS) against Ubuntu 16.04.3 (running on Digital Ocean).

@tlc
Copy link

tlc commented Apr 19, 2018

Anyone have a good solution for proxies? (Raw doesn't use the environment.) I can use this.

  - name: Install python2 for ansible
    raw: export http_proxy=http://proxy.example.com:8000/; export https_proxy=http://proxy.example.com:8000/; test -e /usr/bin/python || (apt-get -y update && apt-get install -y python-minimal)
    args:
      executable: /bin/bash
    register: test
    changed_when: test.stdout

But I'd like to make the proxies optional.

@zoredache
Copy link

zoredache commented Apr 20, 2018

@tlc, you could almost certainly use jinja expressions in what you pass to raw:

raw: |
  {% if foo %}
  http_proxy={{foo}}
  {% endif %}
  etc....

@muawiakh
Copy link

muawiakh commented May 7, 2018

I use the following snippet, which can work across different distributions and only expects python to be installed, which is mostly the case with default ubuntu boxes:

  pre_tasks:
    - raw: which /usr/bin/python || which /usr/bin/python3
      register: py_interpreter
      changed_when: py_interpreter.stdout != ""
    - set_fact:
        ansible_python_interpreter: "{{ py_interpreter.stdout }}"
    - name: Gathering Facts
      setup: #aka gather_facts

@dmonagha
Copy link

Thanks @dpetukhov

@DeanKamali
Copy link

DeanKamali commented Oct 10, 2018

ansible -i /path/to/inventory all -m raw -a "apt -y update && apt install -y python"

@ygotame
Copy link

ygotame commented Oct 17, 2018

I needed to install also pyton-setuptools to avoid the error

raw: test -e /usr/bin/python || (apt -y update && apt install -y python-minimal python-setuptools)

@C-Bam
Copy link

C-Bam commented Oct 26, 2018

I don't know if that is possible but if CentOS or RHEL comes without python, I did this:

raw: test -e /usr/bin/python || (yum -y update && yum install -y python) || (apt -y update && apt install -y python-minimal)

@hitme
Copy link

hitme commented Nov 3, 2018

gather_facts: False pre_tasks: - name: Install python for Ansible raw: test -e /usr/bin/python || (apt -y update && apt install -y python-minimal) changed_when: False - setup: # aka gather_facts

works for me, thanks.

@SerenaFeng
Copy link

Thanks, a great help

@staekblw
Copy link

does anyone know how to install python if the target machine has no internet access? Let's say I have python package located on my control machine, is there any way to copy the python package to target machine?

@eengstrom
Copy link

FWIW, I've got an ansible role based upon this thread that works for EL/RedHat/Debian/Ubuntu/FreeBSD. I just published it to ansible- galaxy. Would love for some feedback.

@rmbleeker
Copy link

rmbleeker commented Nov 13, 2019

@staekblw

does anyone know how to install python if the target machine has no internet access? Let's say I have python package located on my control machine, is there any way to copy the python package to target machine?

I hope you've found a solution by now, but if not my suggestion would be to use 'local_action' and perform an scp or sftp command.

@mahlingam
Copy link

mahlingam commented Jan 7, 2020

Lil' update, on ubuntu 18.04 installing python-minimal will prompt interactively for some libssl installation, which then sits there forever. Using test -e /usr/bin/python || (apt -y update && UCF_FORCE_CONFOLD=1 DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" -qq -y install python-minimal) fixes this behavior.
Inspired by https://bugs.launchpad.net/ubuntu/+source/ansible/+bug/1833013/comments/6

@maherio
Copy link

maherio commented Feb 8, 2020

Why is the raw command necessary for this? I've been having trouble running this lately (likely due to @mahlingam's comment above), and I found that this seems to work for me:

- hosts: all
  become: true
  become_user: root
  become_method: sudo
  gather_facts: no
  pre_tasks:
    - name: Install python for Ansible
      apt:
        update_cache: yes
        name:
          - python-minimal
    - setup: # aka gather_facts
  tasks:
    ...

Just wondering if there's a reason not to do this

@ahmgithubahm
Copy link

Just wondering if there's a reason not to do this

Yep, I think it's simply that a target server without python installed, is unable to run normal ansible task steps. Using 'raw' side-steps the need for python.

@ahmgithubahm
Copy link

PS I think bootstrapping a Python 2 installation is now likely to be unnecessary, since Ansible 2.8+ will auto-detect a suitable Python interpreter to use anyway.

https://docs.ansible.com/ansible/latest/reference_appendices/interpreter_discovery.html

@ProExpertProg
Copy link

If anyone is looking for a solution for Ubuntu 20.04 - change python-minimal to python2-minimal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment