How to use ansible pip executable `/usr/local/bin/python3 -m pip`? - pip

My playbook
- name: "Install python package 'requests'"
pip:
name: requests
executable: /usr/local/bin/python3 -m pip
become: yes
Which errors with:
TASK [Install python package 'requests'] **************************
fatal: [integration]: FAILED! => changed=false
cmd: '''/usr/local/bin/python3 -m pip'' install requests'
msg: '[Errno 2] No such file or directory'
rc: 2
stderr: ''
stderr_lines: <omitted>
stdout: ''
stdout_lines: <omitted>
I didn't install pip or pip3 in the managed node, that is why executable: pip3 would not work.

As per documentation, the recommended way to achieve this is to use the easy_install module in order to make pip available on the managed node, and then, use the builtin module pip, normally.
Please note that the easy_install module can only install Python libraries. Thus this module is not able to remove libraries. It is generally recommended to use the ansible.builtin.pip module which you can first install using community.general.easy_install.
So, in a two tasks:
- name: Install or update pip
community.general.easy_install:
name: pip
state: latest
become: yes
- name: Install python package 'requests'
ansible.builtin.pip:
name: requests
become: yes

Related

How to activate python virtual environment on remote machine with ansible?

I'm learning Vagrant and Ansible, I'm trying to setup a local development environment for a basic flask app in ubuntu20.04 with Nginx.
my vagrantfile looks like this:
Vagrant.configure("2") do |config|
config.vm.define :ubuntuserver do | ubuntuserver |
ubuntuserver.vm.box = "bento/ubuntu-20.04"
ubuntuserver.vm.hostname = "ubuntuserver"
ubuntuserver.vm.provision :ansible do | ansible |
ansible.playbook = "development.yml"
end
ubuntuserver.vm.network "private_network", ip:"10.11.1.105"
ubuntuserver.vm.network "forwarded_port", guest: 80, host: 8080
ubuntuserver.vm.network "public_network", bridge: "en1: Wi-Fi (AirPort)"
ubuntuserver.vm.provider :virtualbox do |vb|
vb.memory = "1024"
end
ubuntuserver.vm.synced_folder "./shared", "/var/www"
end
end
my ansible-playbook like so:
-
name: local env
hosts: ubuntuserver
tasks:
- name: update and upgrade apt packages
become: yes
apt:
upgrade: yes
update_cache: yes
- name: install software properties common
apt:
name: software-properties-common
state: present
- name: install nginx
become: yes
apt:
name: nginx
state: present
update_cache: yes
- name: ufw allow http
become: yes
community.general.ufw:
rule: allow
name: "Nginx HTTP"
- name: installing packages for python env
become: yes
apt:
name:
- python3-pip
- python3-dev
- build-essential
- libssl-dev
- libffi-dev
- python3-setuptools
- python3-venv
update_cache: yes
- name: Create app directory if it does not exist
ansible.builtin.file:
path: /var/www/app
state: directory
mode: '0774'
- name: Install virtualenv via pip
become: yes
pip:
name: virtualenv
executable: pip3
- name: Set python virual env
command:
cmd: virtualenv /var/www/app/ -p python3
creates: "/var/www/app/"
- name: Install requirements
pip:
requirements: /var/www/requirements.txt
virtualenv: /var/www/app/appenv
virtualenv_python: python3
My playbook fails at the next task with error:
- name: Activate /var/www/app/appenv
become: yes
command: source /var/www/app/appenv/bin/activate
fatal: [ubuntuserver]: FAILED! => {"changed": false, "cmd": "source /var/www/app/appenv/bin/activate", "msg": "[Errno 2] No such file or directory: b'source'", "rc": 2}
Rest of the playbook
- name: ufw allow 5000
become: yes
community.general.ufw:
rule: allow
to_port: 5000
- name: Run app
command: python3 /var/www/app/appenv/app.py
From what I understand from this thread, The "source" command must be used from inside the vagrant machine. (I tried solutions from the thread but couldn't get it to work)
If I ssh into the vagrant machine and execute the three last commands of my playbook manually:
source /var/www/app/appenv/bin/activate
sudo ufw allow 5000
python3 /var/www/app/appenv/app.py
my basic flask app is running on port 5000 at the IP set in the vagrantfile 10.11.1.105
My questions are:
How can I get the playbook to work and not have to ssh into the machine to accomplish the same?
Is my approach even correct, knowing that my end goal is to replicate in the vagrant machine a similar environment to what would be the production environment and develop the flask app from my local machine in the synced folder?
to give a maximum of information, if one wants to reproduce this.
I also have a shared/app/appenv/app.py file containing the basic flask app
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return "<h1 style='color:blue'>Hello There!</h1>"
if __name__ == "__main__":
app.run(host='0.0.0.0')
and shared/requirements.txt file
wheel
uwsgi
flask
This question was coming from a misconception about python venv.
I thought that in order to install packages inside the virtual env it had to be activated.
for example:
source env/bin/activate
pip install package_name
I understood later that I can install packages in the venv without activating it by doing:
env/bin/pip install package_name
So the solution with ansible is not to activate the venv to install packages but instead
- name: "Install python packages with the local instance of pip"
shell: "{{virtualenv_path}}/bin/pip3 install package_name"
become: no
or better even with the pip module and the packages in a requirements.txt file:
- name: Install project requirements in venv
pip:
requirements: '{{project_path}}/requirements.txt'
virtualenv: '{{virtualenv_path}}'
virtualenv_python: python3
I wrote this article for a Linux computer with Python 3.x. In this scenario, this is your Ansible development machine. First, verify the installed Python version and path:
# check Python version
$ python3 -V
Python 3.6.8
$ which python3
/usr/bin/python3
I recommend setting up a directory for the virtual environment:
$ mkdir python-venv
$ cd !$
Create a new virtual environment
$ python3 -m venv ansible2.9
$ ls
ansible2.9
activate python venv
$ source ansible2.9/bin/activate
(ansible2.9)$ python3 -V
Python 3.6.8
upgrade pip
(ansible2.9)$ python3 -m pip install --upgrade pip
Install Ansible in a virtual environment
(ansible2.9)$ python3 -m pip install ansible==2.9
(ansible2.9)$ which ansible
~/python-venv/ansible2.9/bin/ansible
Verify your new installation:
(ansible2.9)$ ansible --version
ansible 2.9.0
config file = /etc/ansible/ansible.cfg
configured module search path = ['/home/devops/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /home/devops/python-venv/ansible2.9/lib64/python3.6/site-packages/ansible
executable location = /home/devops/python-venv/ansible2.9/bin/ansible
python version = 3.6.8 (default, Jan 09 2021, 10:57:11) [GCC 8.3.1 20191121 (Red Hat 8.3.1-5)]
Install Ansible roles or collections
(ansible2.9)$ ansible-galaxy collection install \
kubernetes.core:==1.2.1 -p collections
Deactivate a Python virtual environment
(ansible2.9)$ deactivate
Create another Python virtual environment for Ansible 3.0
$ python3 -m venv ansible3.0
$ ls -1
ansible2.9
ansible3.0
$ source ansible3.0/bin/activate
(ansible3.0)$ which python
~/python-venv/ansible3.0/bin/python
(ansible3.0)$ python3 -m pip install --upgrade pip
(ansible3.0)$ python3 -m pip install ansible==3.0

ansible throwing error when using pip command

When I am trying to run pip command through ansible I land up in error.
{"changed": false, "msg": "Unable to find any of pip to use. pip needs to be installed."}
When I debugged on my machine I found pip was installed in latest version. I realized my file uses sudo to run the pip.
So if I do which pip
I get the path of pip but if I do sudo which pip I get nothing.
I don't know how to change my file so instead of sudo it take
- name: "Allow newuser for new super user without SUDO password for using rsync:"
lineinfile:
path: /etc/sudoers
state: present
insertafter: '^%sudo'
line: "{{ user }} ALL=(ALL:ALL) NOPASSWD: /usr/bin/rsync"
- pip:
name: opencv-python
state: forcereinstall
executable: pip
I have no idea how to fix this issue
At the remote host find out which pip is used by the remote user. Use the executable and become the remote user. For example,
- name: Install opencv-python
become_user: admin
become: true
pip:
name: opencv-python
state: forcereinstall
executable: /home/admin/.local/bin/pip
See Becoming an Unprivileged User. Pipelining should solve the problems of becoming an unprivileged user.
shell> grep pipe ansible.cfg
pipelining = true
Notes
Whatever you install by pip this way will be available to this particular remote user only.
Preferably distro packages should be used. For example
shell> apt-cache search python-opencv
python-opencv - Python bindings for the computer vision library
python-opencv-apps - opencv_apps Robot OS package - Python 2 bindings
See The pip module isn't always idempotent #28952 and the Conclusions in particular.

Unable to run Ansible 'expect' module

I am trying to run an Ansible script that invokes the 'expect' module (see end of the message).
When I run it, I get error:
The pexpect python module is required
Yet, the pip task for installing pexpect runs without error.
What am I doing wrong?
Thx.
Alain Désilets
=== Playbook content ===
---
- name: Run Anaconda shell
hosts: all
vars:
conda_home: "~/anaconda2-NEW"
conda_inst_sh_path: /path/to/Anaconda2-2018.12-MacOSX-x86_64.sh
tasks:
- name: install pexpect
pip:
name: pexpect
become: yes
become_user: root
- name: Run anaconda installation script
expect:
command: "sh {{conda_inst_sh_path}}"
responses:
(?i)password: "MySekretPa$$word"
become: yes
become_user: root
As the Ansible documentation of the expect module states:
The below requirements are needed on the host that executes this module.
python >= 2.6
pexpect >= 3.3
You need to install pexpect in a minimum version of 3.3 besides python >= 2.6 on the target system, that means that you have to install pexpect and python on every system, that is defined under hosts: all.

Ansible - pip not found

I am getting this error:
TASK [pip] *********************************************************************
failed: [default] (item=urllib3) =>
{"changed": false, "item": "urllib3",
"msg": "Unable to find any of pip2, pip to use. pip needs to be installed."}
Upon a suggestion I run following command:
ansible default -a "which pip"
I get an error:
default | FAILED | rc=1 >>
non-zero return code
So I guess that means no pip installed. I tried installing pip using:
ansible default -a "easy_install pip"
I get the following error:
default | FAILED | rc=2 >>
[Errno 2] No such file or directory
Any ideas?
UPDATE
In play_local.yaml, I have the following task:
- name: Prepare system
hosts: default
become: yes
gather_facts: false
pre_tasks:
- raw: sudo apt-get -y install python python-setuptools python-pip build-essential libssl-dev libffi-dev python-dev easyinstall pip
- file: path=/etc/sudoers.d/ssh-auth-sock state=touch mode=0440
#- lineinfile: line='Defaults env_keep += "SSH_AUTH_SOCK"' path=/etc/sudoers.d/ssh-auth-sock
- replace:
path: /etc/apt/sources.list
regexp: 'br.'
replace: ''
Shouldn't this task install pip?
Seems like pip is not installed, you can use the following task to install it:
- name: Install pip
apt:
name: python-pip
update_cache: yes
state: present
May be pip is hashed. Meaning pip is installed at path x (may be /usr/local/bin/pip), however, cached at path y (may be /usr/bin/pip). You can confirm that from - ansible default -m shell -a ‘type pip’. To resolve this you’ll need to run - ansible default -m shell -a ‘hash -r’.
BTW, you can also use command module instead of shell.
I've just met the same problem on a brand new CentOS 7. Solved through installing setuptools with yum first and then pip with easy_install as below :
ansible default -b -m yum -a "name=python-setuptools state=present"
ansible default -b -m easy_install -a "name=pip state=present"
For Debian Based systems (RUN THIS ON CLIENT SYSTEMS):
first install package python-is-python3 then add alias for pip echo alias pip=pip3 >> ~/.bashrc
I know my solution would be dumb but It works.
# pip-fix.yml
- name: pip fix
hosts: all
become: true
tasks:
- name: install python-is-python3
apt: name=python-is-python3 update_cache=yes state=present
- name: creating alias
shell: echo alias pip=pip3 >> ~/.bashrc
- name: test and upgrade pip
pip: name=pip state=latest
tags:
- packages
run using ansible-playbook pip-fix.yml
Ansible Not finding / Installing Pip
While not using the author's original details, i think this might help them or others.
I was getting the following error for installing pip:
via Ansible:
FAILED! => {"changed": false, "cmd": "/bin/easy_install --upgrade pip", "failed": true, "msg": "Couldn't find index page for 'pip' (maybe misspelled?)
directly on the host:
Searching for pip
Reading https://pypi.python.org/simple/pip/
Couldn't find index page for 'pip' (maybe misspelled?)
Scanning index of all packages (this may take a while)
Reading https://pypi.python.org/simple/
No local packages or download links found for pip
error: Could not find suitable distribution for
Requirement.parse('pip')
I attempted to use the above hash -r answer:
(NOTE: help hash... hash -r == forget all remembered locations)
- name: forget easy_install path
shell: hash -r
become: true
however this was not a solve for me.
I found via another post: 'pip install' fails for every package ("Could not find a version that satisfies the requirement") that this was the final fix:
curl https://bootstrap.pypa.io/get-pip.py | python
or
- name: manually install pip
shell: curl https://bootstrap.pypa.io/pip/2.7/get-pip.py | python
become: true
NOTE: i changed the pip version. Also, there is a better way to do a curl in ansible, this is simply an example
I then followed with the easy_install pip latest. to ensure it was up to date.
below fix worked for me
#ln -s /usr/local/bin/pip /usr/bin/pip

pexpect version on vagrant box and on host is both 4.6.0, but when installing over ansible, 3.1 is the newest version

I was using ansible to install pexpect on both my vagrant box and also onto my host. When I installed pexpect onto both computers, the version is 4.6.0, but when using ansible to install using apt-get, the maximum version is only 3.1. The error message thrown is: "Insufficient version of pexpect installed (3.1), this module requires pexpect>=3.3. Error was __init__() got an unexpected keyword argument 'echo'"}How am I able to install pexpect in order to use the expect module for ansible?
The code for downloading pexpect is
- hosts: all
become: yes
become_user: root
gather_facts: no
#can use sudo/sudo_user instead of become, but thats depreceated in ansible 2.6 or later
tasks:
- name: download pip
apt: name=python3-pip state=latest
- name: update pexpect
command: pip3 install pexpect
command: pip3 install --upgrade pip3
command: pip3 install --upgrade pexpect
Run a task per command and try to use Ansible pip module.
- name: Install Pexpect
hosts: all
become: True
become_user: root
gather_facts: False
tasks:
- name: download pip
apt:
name: python3-pip
state: latest
- name: Install Pexpect
pip:
name: pexpect
state: latest
- name: Upgrade pip - Force reinstall to the latest version
pip:
name: pip
state: forcereinstall

Resources