可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm running into an error I've never seen before. Here is the command and the error:
$ ansible-playbook create_api.yml
PLAY [straw] ******************************************************************
GATHERING FACTS ***************************************************************
failed: [104.55.47.224] => {"failed": true, "parsed": false}
/bin/sh: 1: /usr/bin/python: not found
TASK: [typical | install required system packages] *****************************
FATAL: no hosts matched or all hosts have already failed -- aborting
PLAY RECAP ********************************************************************
to retry, use: --limit @/Users/john/create_api.retry
104.55.47.224 : ok=0 changed=0 unreachable=0 failed=1
Here is the create_api.yml file:
---
- hosts: api
remote_user: root
roles:
- api
And here is the hosts file:
[api]
104.55.47.224
I can remove the roles section and it won't make it to the first TASK, it will instead make it will only make it to the line /bin/sh: 1: /usr/bin/python: not found
. What could be going on here?
NOTE: In case anyone is pinging the IP address and failing to get a response, you should know I've changed the IP address since pasting code.
EDIT
python was installed locally, the problem was that it was not installed on the remote machine, which was running Ubuntu 15.04
回答1:
I stumbled upon this error running ansible on Ubuntu 15.10 server, because it ships with Python 3.4.3 and ansible requires Python 2.
This is how my provision.yml
looks now:
- hosts: my_app
sudo: yes
remote_user: root
gather_facts: no
pre_tasks:
- name: 'install python2'
raw: sudo apt-get -y install python
tasks:
- name: 'ensure user {{ project_name }} exists'
user: name={{ project_name }} state=present
回答2:
Ansible 2.2 features a tech preview of Python 3 support. To take advantage of this (so you don't have to install Python 2 on Ubuntu 16.04), just set the ansible_python_interpreter
config option to /usr/bin/python3
. This can be done on a per-host basis in your inventory file:
[db]
123.123.123.123 ansible_python_interpreter=/usr/bin/python3
回答3:
Solution 1:
If you're using Ansible >2.2.0
, you can set the ansible_python_interpreter
configuration option to /usr/bin/python3
:
ansible my_ubuntu_host -m ping -e 'ansible_python_interpreter=/usr/bin/python3'
or in your inventory file:
[ubuntu_hosts]
<xxx.xxx.xxx.xxx>
[ubuntu_hosts:vars]
ansible_python_interpreter=/usr/bin/python3
Solution 2:
If you're using Ansible <2.2.0
then you can add these pre_tasks
to your playbook:
gather_facts: False
pre_tasks:
- name: Install python for Ansible
raw: test -e /usr/bin/python || (apt -y update && apt install -y python-minimal)
register: output
changed_when: output.stdout != ""
tags: always
- setup: # aka gather_facts
UPDATE
With ansible 2.8.x
, you don't need to worry about it, it's working out of the box for python > 3.5 for both controller and target machine(s)
回答4:
You can use the raw module to install Python on the remote hosts:
- raw: sudo apt-get install python-simplejson
回答5:
To summarize everyone else's answers, here are the combined settings that worked for me:
- hosts: all
become: true
gather_facts: false
# Ansible requires python2, which is not installed by default on Ubuntu Xenial
pre_tasks:
- raw: sudo apt-get -y install python-simplejson
# action: setup will gather facts after python2 has been installed
- action: setup
回答6:
You need python 2.7 to run Ansible.
On Ubuntu 16.04, you can install it via this command:
sudo apt-get install python-minimal
After that, I could run
ansible-playbook -i inventories/staging playbook.yml
Please check more at Using ansible on Ubuntu 16.04
回答7:
I personally found 3 possible solutions to this problem that work well in different situations:
Option 1 - Set ansible_python_interpreter: /usr/bin/python3
for hosts that have python3
installed by default
I think this is the superior method for solving the problem if you have a way to group your hosts by whether or not they have python3
installed by default. As far as I'm aware, python3
is available on all Ubuntu releases 16.04 and higher.
- If all your hosts definitely have
python3
, you could add the variable to your group_vars/all.yml
(or equivalent):
# group_vars/all.yml
ansible_python_interpreter: /usr/bin/python3
- If some of your hosts don't have
python3
and you have a way to tag them when using dynamic inventory (e.g. AWS tagging for ec2.py
), you could apply the variable to certain hosts like this:
# group_vars/tag_OS_ubuntu1804.yml
ansible_python_interpreter: /usr/bin/python3
- If you use static inventory and are able to group hosts based on whether they have
python3
, you could do something like this:
# inventory/hosts
[python2_hosts]
centos7_server
[python3_hosts]
u1804_server
[python3_hosts:vars]
ansible_python_interpreter=/usr/bin/python3
I like this option the most because it requires no changes on the remote host and only minor changes to variables, as opposed to options 2 and 3, which require additions to every playbook.
Option 2 - Install Python 2 using raw
This option requires putting a play at the top of every playbook with gather_facts: false
that uses raw
to install python
:
- name: install python2 on all instances
hosts: "*"
gather_facts: false
tasks:
- name: run apt-get update and install python
raw: "{{ item }}"
loop:
- sudo apt-get update
- sudo apt-get -y install python
become: true
ignore_errors: true
ignore_errors: true
is required if you plan to run the play on hosts that don't have apt-get
installed (e.g. anything RHEL-based), otherwise they will error out in the first play.
This solution works, but is the lowest on my list for a few reasons:
- Needs to go at the top of every playbook (as opposed to option 1)
- Assumes
apt
is on the system and ignores errors (as opposed to option 3)
apt-get
commands are slow (as opposed to option 3)
Option 3 - Symlink /usr/bin/python -> /usr/bin/python3
using raw
I haven't seen this solution proposed by anyone else. It's not ideal, but I think it's superior to option 2 in a lot of ways. My suggestion is to use raw
to run a shell command to symlink /usr/bin/python -> /usr/bin/python3
if python3
is on the system and python
is not:
- name: symlink /usr/bin/python -> /usr/bin/python3
hosts: "*"
gather_facts: false
tasks:
- name: symlink /usr/bin/python -> /usr/bin/python3
raw: |
if [ -f /usr/bin/python3 ] && [ ! -f /usr/bin/python ]; then
ln --symbolic /usr/bin/python3 /usr/bin/python;
fi
become: true
This solution is similar to option 2 in that we need to put it at the top of every playbook, but I think it's superior in a few ways:
- Only creates the symlink in the specific case that
python3
is present and python
is not -- it won't override Python 2 if it's already installed
- Does not assume
apt
is installed
- Can run against all hosts without any special error handling
- Is super fast compared to anything with
apt-get
Obviously if you need Python 2 installed at /usr/bin/python
, this solution is a no go and option 2 is better.
Conclusion
- I suggest using option 1 in all cases if you can.
- I suggest using option 3 if your inventory is really large/complex and you have no way to easily group hosts with
python3
, making option 1 much more difficult and error-prone.
- I only suggest option 2 over option 3 if you need Python 2 installed at
/usr/bin/python
.
Sources
- Fix the
/usr/bin/python: not found
error in Ansible
- Python 3 Support on Ansible Docs
- Ansible
raw
Module on Ansible Docs
- Error handling in playbooks on Ansible Docs
回答8:
What I used to get this working on ubuntu 15.10 on a fresh Digital Ocean droplet:
# my-playbook.yml
- name: python2
hosts: test
gather_facts: no
pre_tasks:
- raw: sudo apt-get -y install python-simplejson
$ ansible-playbook path/to/my-playbook.yml
For ubuntu 16.04 on a fresh OVH SSD, I had to apt-get upgrade before the python2 packages were available.
回答9:
I found out that it's actually possible to have multiple plays in a single playbook, so my setup now contains a "dependency provisioning" play which runs on all hosts, and other plays for specific hosts. So no more pre_tasks
.
For example:
- name: dependency provisioning
hosts: all
become: yes
become_method: sudo
gather_facts: false
tasks:
- name: install python2
raw: sudo apt-get -y install python-simplejson
- name: production
hosts: production_host
roles:
- nginx
tasks:
- name: update apt cache
apt: update_cache=yes cache_valid_time=3600
# ....
- name: staging
hosts: staging_host
roles:
- nginx
tasks:
- name: update apt cache
apt: update_cache=yes cache_valid_time=3600
# ....
回答10:
As others said, this is due to missing python2. Other answers here provide a workaround with pre_tasks
and gather_facts: no
, however if you're on EC2 and you spin up the instance with ansible you can use user_data
option:
- ec2:
key_name: mykey
instance_type: t2.micro
image: ami-123456
wait: yes
group: webserver
count: 3
vpc_subnet_id: subnet-29e63245
assign_public_ip: yes
user_data: |
#!/bin/bash
apt-get update
apt-get install -y python-simplejson
register: ec2
Then people usually wait for ssh to be available like this:
- name: "Wait for the instances to boot and start ssh"
wait_for:
host: "{{item.public_ip}}"
port: 22
delay: 5
timeout: 300
with_items: "{{ ec2.tagged_instances }}"
when: ec2|changed
However I've found, that this isn't always long enough as CloudInit is executed quite late in the boot process so the python2 still might not be installed right after ssh is available. So I've added a pause in case the instance was just created:
- name: "Wait for cloud init on first boot"
pause: minutes=2
when: ec2|changed
This will do the job perfectly and as an advantage you're not checking for python2 on every run and you don't have to do any workarounds to gather facts later.
I'm sure other cloud providers provide similar CloudInit functionality, so adapt for your use case.
回答11:
By default, Ansible requires Python 2, however, Ansible 2.2+ can work with Python 3 as well.
So either install Python 2 using the raw
module, e.g.
ansible localhost --sudo -m raw -a "yum install -y python2 python-simplejson"
or set ansible_python_interpreter
variable in the inventory file, like:
[local]
localhost ansible_python_interpreter="env python3"
For Docker, you can add the following line:
RUN printf '[local]\r\nlocalhost ansible_python_interpreter="env python3"\r\n' > /etc/ansible/hosts
or run it as:
ansible-playbook /ansible/provision.yml -e 'ansible_python_interpreter=/usr/bin/python3' -c local
回答12:
THose using Packer may find below solution helpful
let's assume that you use ansible provisioner of packer, your config may look like below
you could install python using shell provisioner first then configure ansible_python_intepreter option as shown below
"provisioners": [
{
"type": "shell",
"inline": [
"apk update && apk add --no-cache python python-dev ansible bash"
]
},
{
"type": "ansible-local",
"playbook_file": "playbooks/your-play-book.yml",
"playbook_dir": "playbooks",
"extra_arguments": [
"-e",
"'ansible_python_interpreter=/usr/bin/python3'",
"-vvv"
]
},
回答13:
According to this Gist you can install Python2 on Ubuntu 16.04 as follows:
enter code here
gather_facts: False
pre_tasks:
- raw: test -e /usr/bin/python || (apt -y update && apt install -y python-minimal)
- setup: # aka gather_facts
tasks:
# etc. etc.
回答14:
Lots of answers.. Thanks for posting as I got started from this page too!
I did a bit of digging and it was solid with Ubuntu 14.04LTS, Ubuntu 15.04LTS appeared to have dropped the latest python
, and Ubuntu 16.04LTS appears to have dropped aptitude
.
I put the following action in my bootstrap before doing any apt
calls:
- name: "FIX: Ubuntu 16.04 LTS doesn't come with certain modules, required by ansible"
raw: apt-get install python-minimal aptitude -y
become: true
become_user: root
become_method: sudo
If you manage become
elsewhere, feel free to strip it.
Sources:
- https://github.com/ansible/ansible-modules-core/issues/3523#issuecomment-222368182
- https://github.com/ansible/ansible/issues/16884#issuecomment-278138707
回答15:
I was able to fix the same problem by installing Python on target machine i.e. the machine which we want to SSH to. I had used following command:
sudo apt-get install python-minimal
回答16:
@Miroslav, thanks for pointing me in the right direction. I used user_data
in the ec2_instance
module too and it works like a treat.
I.e.
- name: Creating single EC2 instance
ec2_instance:
region: "{{ aws_region }}"
key_name: "{{ aws_ec2_key_pair }}"
name: "some-cool-name"
instance_type: t1.micro
image_id: ami-d38a4ab1
security_group: sg-123456
vpc_subnet_id: sn-678901234
network:
assign_public_ip: no
volumes:
- device_name: /dev/sda1
ebs:
volume_type: gp2
volume_size: 15
user_data: |
#!/bin/bash
#
apt update
apt install -y python-simplejson
termination_protection: yes
wait: yes
回答17:
You can indicate to Ubuntu 18.04 that you want to use python3 as the the first priority for /usr/bin/python
.
- hosts: all
become: true
pre_tasks:
- raw: update-alternatives --install /usr/bin/python python /usr/bin/python3 1
回答18:
I had the same issue, until I realised you also need to install python on the remote host as well as your own local machine. now it works!
回答19:
We just run into this.
We deploy ubuntu 16.04 on a vagrant so if you are not using vagrant my comment is pointless.
We installed the following vagrant plugins (trigger, shell-commander) and we get python 2.7.6 installed on the machine (which were not without thioose plugins) and after ansible can deploy
It was our last test, otherwise we were about to include this installation in a shell command in the Vagrant file
Hope it can help someone