seventh
seventh

Reputation: 3086

Ansible: Install Python module only if it not exist

I need to install Python pip via Ansible on a remote server. I do it like this and it work:

  - name: Download pip installer
    get_url:
      url: https://bootstrap.pypa.io/pip/2.7/get-pip.py
      dest: /tmp/get-pip.py

  - name: Install pip
    shell: /usr/bin/python /tmp/get-pip.py

One problem - it have status "changed" every time when I run a playbook. I don't need to install it every time I run playbook.

How can I check and install the pip module only if it didn't installed before?

Upvotes: 2

Views: 2567

Answers (3)

Khaled
Khaled

Reputation: 838

This nice guy William Yeh has written a nice playbook exactly for that purpose:

---
# file: tasks/install-pip.yml
# Mini installer for pip; only to enable the Ansible `pip` module.
#
# For full installer, use something like:
# 
#  - Stouts.python
#  - bobbyrenwick.pip
#
# @see https://github.com/gmacon/ansible-pip/blob/variable_executables/tasks/main.yml
#

- name: check to see if pip is already installed
  command: "pip --version"
  ignore_errors: true
  register: pip_is_installed
  changed_when: false

- block:

    - name: download get-pip.py
      get_url: url=https://bootstrap.pypa.io/get-pip.py  dest=/tmp
    
    - name: install pip
      command: "python /tmp/get-pip.py"
    
    - name: delete get-pip.py
      file: state=absent path=/tmp/get-pip.py

  when: pip_is_installed.rc != 0

Upvotes: 2

Zeitounator
Zeitounator

Reputation: 44615

You can easily bypass both tasks by using the creates parameter which exists for shell and uri. It expects a filename which will be checked for existence. If the file exists the task will not be run.

Note: In my below not entirely tested example, I infered that your script installs the binary in /usr/local/bin/pip. Adapt to the exact installation location if different.

---
- name: Install pip
  hosts: all
  gather_facts: false

  vars:
    pip_location: /usr/local/bin/pip

  tasks:
    - name: Download pip installer
      get_url:
        url: https://bootstrap.pypa.io/pip/2.7/get-pip.py
        dest: /tmp/get-pip.py
        creates: "{{ pip_location }}"

    - name: Install pip
      shell:
        cmd: /usr/bin/python /tmp/get-pip.py
        creates: "{{ pip_location }}"

References:

Upvotes: 3

U880D
U880D

Reputation: 12063

Since a system where pip hasn't been installed reports with

pip --version; echo $?
-bash: pip: command not found
127

you could implement installation and version tests before running the download and installation task.

---
- hosts: test
  become: false
  gather_facts: false

  tasks:

  - name: Gather installed pip version, if there is any
    shell:
      cmd: pip --version | cut -d ' ' -f 2
    register: result
    failed_when: result.rc != 0 and result.rc != 127
    # Since this is a reporting task, it should never change
    # as well run and register a result in any case
    changed_when: false
    check_mode: false

  - name: Set default version, if there is no
    set_fact:
      result:
        stdout_lines: "00.0.0"
    when: "'command not found' in result.stdout"

  - name: Report result
    debug:
      msg: "{{ result.stdout }}"
    check_mode: false
    when: result.stdout != "20.3.4"

Resulting into an output of

TASK [Gather installed pip version, if there is any] ***
ok: [test.example.com]

TASK [Report result] ***********************************
ok: [test.example.com] =>
  msg: 20.3.4

Further Q&A

Documentation


... just an example add-on with shell operators

  - name: Install 'pip' only if it not exist
    shell: 
      cmd: pip --version || /usr/bin/python /tmp/get-pip.py

Upvotes: 3

Related Questions