Bootstrap FreeKB - Ansible - pip module
Ansible - pip module

Updated:   |  Ansible articles

If you are not familiar with modules, check out Ansible - Getting Started with Modules.

Let's say you have two systems, the Ansible controller (that's the system Ansible is installed and running on) and a target server, and let's say each system has a different version of Python. Perhaps the Python CLI on the Ansible controller is Python version 3.12.0.

[admin@controller ~]$ python --version
Python 3.12.0

 

And the target server contains both Python version 2.7.5 and 3.9.18.

[john.doe@server1 ~]$ python --version
Python 2.7.5

[john.doe@server1 ~]$ python3 --version
Python 3.9.18

 

Let's say you have the following playbook, which uses the ansible.builtin.pip module to install the "requests" module in Python on the target server.

You may need to include become: yes and become_user: root since this probably requires sudo or root.

---
- hosts: all
  tasks:
  - name: use pip to install the 'requests' module in Python
    become: yes
    become_user: root
    ansible.builtin.pip:
      name: requests
      state: latest
...

 

Let's run the ansible-playbook command with the -vvv (very verbose) flag.

ansible-playbook example.yml --inventory server1.example.com, --user john.doe --ask-pass -vvv

 

So, underneath the hood, a directory is created on the target server, something like this.

/home/john.doe/.ansible/tmp/ansible-tmp-1713408593.1331322-16539-164674748277391

 

This can been seen in the output with the -vvv flag. The output should have something like this.

<server1.example.com> SSH: EXEC \
sshpass -d12 \
ssh -C \
-o ControlMaster=auto \
-o ControlPersist=60s \
-o 'User="john.doe"' \
-o ConnectTimeout=10 \
-o 'ControlPath="/home/john.doe/.ansible/cp/da9b18fba3"' \
server1.example.com \
'/bin/sh -c '"'"'( umask 77 && mkdir -p "` echo /home/john.doe/.ansible/tmp `"&& mkdir "` echo /home/john.doe/.ansible/tmp/ansible-tmp-1713408596.274309-16590-237914960550324 `" && echo ansible-tmp-1713408596.274309-16590-237914960550324="` echo /home/john.doe/.ansible/tmp/ansible-tmp-1713408596.274309-16590-237914960550324 `" ) && sleep 0'"'"''

 

It is important to recognize that the directory will be removed, so for this excercise, I would set the ANSIBLE_KEEP_REMOTE_FILES environment variable to 1 which instructs the Ansible controller to not delete the tmp files and directories that get created on the target server.

export ANSIBLE_KEEP_REMOTE_FILES=1

 

And then the AnsiballZ_file.py Python script is PUT from the Ansible controller to the target server.

<server1.example.com> PUT /home/admin/.ansible/tmp/ansible-local-1681708tty8e7/tmpclmqm36v TO /home/john.doe/.ansible/tmp/ansible-tmp-1713405726.6487887-17223-276200849623319/AnsiballZ_pip.py

 

Ansible uses the sshpass command to connect to the target server and then ssh command and the /bin/sh (shell) CLI with the -c (command) flag to run a command on the target server. The command that is run on the target server is almost always /home/john.doe/.ansible/tmp/ansible-tmp/AnsiballZ_<module name>.py, a Python script. Since this command is being run on the target server, this uses the Python CLI on the target server, not Python on the Ansible controller.

<server1.example.com> SSH: EXEC \
sshpass -d12 \
ssh -C \
-o ControlMaster=auto \
-o ControlPersist=60s \
-o 'User="john.doe"' \
-o ConnectTimeout=10 \
-o 'ControlPath="/home/john.doe/.ansible/cp/da9b18fba3"' \
server1.example.com \
'/bin/sh -c '"'"'chmod u+x /home/john.doe/.ansible/tmp/ansible-tmp-1713405726.6487887-17223-276200849623319/ /home/john.doe/.ansible/tmp/ansible-tmp-1713405726.6487887-17223-276200849623319/AnsiballZ_pip.py && sleep 0'"'"''

 

And if we look at line 1 in AnsiballZ_pip.py, we can see it is using /usr/bin/python (in this example).

[john.doe@server1 ~]$ head -1 /home/webproc/.ansible/tmp/ansible-tmp-1713408594.9606252-16563-253322922038816/AnsiballZ_file.py 
#!/usr/bin/python

 

Which means that the "requests" module would be installed in /usr/bin/python which is almost always a symbolic link to a certain version of Python. In this example, /usr/bin/python is symbolically linked to /usr/bin/python2.7, meaning that the actual version of Python being used here is Python verison 2.7.

[john.doe@server1 ~]$ ll /usr/bin/ | grep -i python
lrwxrwxrwx. 1 root root 9 Jan  5 07:55 /usr/bin/python -> python2.7
lrwxrwxrwx. 1 root root 9 Jan  5 07:55 /usr/bin/python3 -> python3.9

 

One option is to include the executable parameter in the ansible.builtin.pip module to use pip (for Python 2.7 in this example) or pip3 (for Python 3.9 in this example).

---
- hosts: all
  tasks:
  - name: use pip3 to install the 'requests' module in Python3
    ansible.builtin.pip:
      name: requests
      state: latest
      executable: pip3
...

 

Or, there are a few different ways to tell Ansible to run the AnsiballZ_<module>.py files on the target servers with a certain version of Python.

Let's say the playbook includes ansible_python_interpreter: /usr/bin/python3.9.

---
- hosts: all
  vars:
    ansible_python_interpreter: /usr/bin/python3.9
  tasks:
  - ansible.builtin.file:
      path: /tmp/foo.txt
      state: "{{ item }}"
    with_items:
    - touch
    - absent
...

 

This will cause the AnsiballZ_file.py to have /usr/bin/python3.9.

[john.doe@server1 ~]$ head /home/john.doe/.ansible/tmp/ansible-tmp-1713410268.6565683-30050-40883123872239/AnsiballZ_file.py 
#!/usr/bin/python3.9

 

Here is how you could install a specific version of the "requests" module.

---
- hosts: all
  tasks:
  - name: use pip to install version 2.25.1 of the 'requests' module in Python
    ansible.builtin.pip:
      name: requests=2.25.1
...

 

To install two (or more) packages.

---
- hosts: all
  tasks:
  - name: pip install the latest versions of requests and django
    ansible.builtin.pip:
      name:
        - requests
        - django
      state: latest
...

 

To uninstall pymysql.

---
- hosts: all
  tasks:
  - name: pip uninstall pymysql
    ansible.builtin.pip:
      name: pymysql
      state: absent
...

 




Did you find this article helpful?

If so, consider buying me a coffee over at Buy Me A Coffee



Comments


Add a Comment


Please enter 47d8a5 in the box below so that we can be sure you are a human.