One of my playbooks contains a task that installs basic Python packages:
---
-
name: "Install Python packages: {{ python_packages_to_install }}"
sudo: true
pip: name={{ item }}
with_items: python_packages_to_install
With the following list of packages:
-
include: python_basics.yaml
vars:
python_packages_to_install:
- virtualenv
- pss
- requests
- comment-builder
- boto
- ansible
- uwsgitop
- gitpull
- ipython
The task works correctly and installs the packages:
TASK: [common | Install Python packages: ['virtualenv', 'pss', 'requests', 'comment-builder', 'boto', 'ansible', 'uwsgitop', 'gitpull', 'ipython']] ***
ok: [push-prod-01] => (item=virtualenv)
ok: [push-prod-01] => (item=pss)
ok: [push-prod-01] => (item=requests)
ok: [push-prod-01] => (item=comment-builder)
ok: [push-prod-01] => (item=boto)
ok: [push-prod-01] => (item=ansible)
ok: [push-prod-01] => (item=uwsgitop)
ok: [push-prod-01] => (item=gitpull)
changed: [push-prod-01] => (item=ipython)
The problem is that each line is executed using a consecutive SSH command, instead of installing all the packages in a single call.
Is there a way to install multiple Python packages on an Ansible pip
command?
To pip install more than one Python package, the packages can be listed in line with the same pip install command as long as they are separated with spaces. Here we are installing both scikit-learn and the statsmodel package in one line of code. You can also upgrade multiple packages in one line of code.
The best and recommended way to install Python modules is to use pip, the Python package manager. Otherwise: Download get-pip.py from https://bootstrap.pypa.io/get-pip.py. Run python get-pip.py.
Ansible pip module is used when you need to manage python libraries on the remote servers. There are two prerequisites if you need to use all the features in the pip module. The pip package should already be installed on the remote server.
Expanding on Ben's answer, you can also continue to preserve the package list as a yaml list like you have it, and do the projection to a single value when you pass it to the pip module like:
pip: name="{{ python_packages_to_install | join(' ') }}"
Keeps your playbook a little more maintainable...
Unlike Ansible apt
module, the pip
module does not accept a comma-delimited list of packages. Instead, you can provide all the package names as a space delimited string, using the ==
syntax to specify versions:
python_packages_to_install: "virtualenv==1.11.6 pss requests comment-builder boto ansible uwsgitop gitpull ipython"
If you're like me it may strike you as ugly and impractical to manage. An alternative is to use the requirements
option in the pip module to specify a requirements file. Of course you'll need to create the requirements file first, probably using a template.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With