Running ansible in an unrelated virtualenv

Hi,

A Python project of mine uses virtualenv to isolate packages. I want to use Ansible to provision a Vagrant box for testing. However, when I run Vagrant it fails with this error:

[default] Running provisioner: ansible…

File “/usr/bin/ansible-playbook”, line 24, in

import ansible.playbook

ImportError: No module named ansible.playbook

If I deactivate the virtualenv it runs fine. I am now running “(deactivate; vagrant up)” but that is not ideal. Anyone know of a better solution?

Regards,
Joost

Excerpts from Joost Cassee's message of 2013-07-16 07:20:12 -0400:

Hi,

A Python project of mine uses virtualenv to isolate packages. I want to use
Ansible to provision a Vagrant box for testing. However, when I run Vagrant
it fails with this error:

[default] Running provisioner: ansible...
  File "/usr/bin/ansible-playbook", line 24, in <module>
    import ansible.playbook
ImportError: No module named ansible.playbook

If I deactivate the virtualenv it runs fine. I am now running "(deactivate;
vagrant up)" but that is not ideal. Anyone know of a better solution?

Sounds to me like you don't have ansible installed in the virtualenv.
You could either `pip install ansible` form within the virtualenv, or
create the virtualenv with access to site packages.

Indeed, I installed Ansible system-wide. If I also install it in the
virtualenv, I get this error:

[default] Running provisioner: ansible...

PLAY [vagrant] ****************************************************************

GATHERING FACTS ***************************************************************
fatal: [127.0.0.1] => {'msg': "FAILED: (25, 'Inappropriate ioctl for
device')", 'failed': True}

Which is a much weirder error that I do not know how to debug any
further. It is an annoying property of virtualenv that it messes with
Python even for site-wide installed applications...

Regards,
Joost

Did you manage to fix this error? I don’t have virtualenv, but I get the same failure during “GATHERING FACTS” before the start of any play task.

Regards,
S

It’s a private key issue on first connection. You have to call ansible with --private-key=~/.vagrant.d/insecure_private_key

Adding the private key is something I forget once in a while too. But
I have seen the ioctl error a few times even when I specify the key.

I have had more luck with just adding ansible to my requirements.txt file.

Regards,
Joost

Hi,

Sorry to drag this thread up again, but I now have difficulty running Ansible in a virtualenv… See issue 4083 [1].

My Python projects use virtualenv with to isolate the environment. I cannot run the system Ansible installation because tries to pick up packages from the virtualenv environment and I cannot use a local Ansible installation because it tries to pick up modules from the system locations.

I would really love Ansible to make a choice between being a regular Python package or being a system application. The latter for example by changing the hashbang in the main ansible script to the system Python executable (i.e. not /usr/bin/env python).

Regards,
Joost

[1] https://github.com/ansible/ansible/issues/4083

Regards,
Joost

Excerpts from Joost Cassee’s message of 2013-07-16 07:20:12 -0400:

Hi,

A Python project of mine uses virtualenv to isolate packages. I want to use
Ansible to provision a Vagrant box for testing. However, when I run Vagrant
it fails with this error:

[default] Running provisioner: ansible…
File “/usr/bin/ansible-playbook”, line 24, in
import ansible.playbook
ImportError: No module named ansible.playbook

If I deactivate the virtualenv it runs fine. I am now running “(deactivate;
vagrant up)” but that is not ideal. Anyone know of a better solution?

Sounds to me like you don’t have ansible installed in the virtualenv.
You could either pip install ansible form within the virtualenv, or
create the virtualenv with access to site packages.

Please read the web documentation on ansible_python_interpreter.

If you’re having problems setting it, please share where you’ve actually set that information in your inventory, as well as your playbook, so we can tell what you are doing.

ansible_python_interpreter is a required mechanism because on some operating systems python may be in /usr/bin/python26 and relying on /usr/bin/env clearly doesn’t work, and this allows you to manage such a system (say a modified Arch) and CentOS at the same time.

Hi Michael,

The content of the testcase I attached to the ticket contains the following files:

hosts:

[group]
host ansible_python_interpreter=bin/python

playbook.iml:

Hi Joost,

I just checked what you said, and it seem to work properly:

(testansible)devel@devel:~/projects/virtualenvs/testansible$ ansible-playbook -i hostfile --connection=local playbook.yml

PLAY [192.168.1.45] ***********************************************************

TASK: [debug msg=“{{ansible_python_interpreter}}”] ****************************
ok: [192.168.1.45] => {“msg”: “/home/devel/projects/virtualenvs/testansible/bin/python”}

TASK: [command echo “hi”] *****************************************************
changed: [192.168.1.45]

PLAY RECAP ********************************************************************
192.168.1.45 : ok=2 changed=1 unreachable=0 failed=0

my hostfile:

(testansible)devel@devel:~/projects/virtualenvs/testansible$ cat hostfile
xxx.xxx.xxx.xxx ansible_python_interpreter=/home/devel/projects/virtualenvs/testansible/bin/python

and the playbook:

(testansible)devel@devel:~/projects/virtualenvs/testansible$ cat playbook.yml

Hi Christobal,

Did you try to use a module that has an external dependency instead of the command module, like the ec2 one?

Regards,
Joost

Hi Joost,

sorry I couldn’t check this case, I only tested it using the command module.

BR,
Cristóbal

It will work the same for both.

What is happening is that I am confusing the code that is running the
playbook and the code that is running on the remote host. I see now
that it makes perfect sense to separate them.

The problem in my head is that some actions operate on remote systems,
but only make sense in a local_action, for example the ec2 modules. A
local_actions is still a connection to the local system, so it does
not run in the same environment as the playbook-running code.

So in my case I want to set ansible_python_interpreter for 127.0.0.1
to the Python executable from my virtual environment. I tried this
inventory file:

127.0.0.1 ansible_python_interpreter=VIRTUALENV/bin/python

[groups]
host

And that works! Thanks for your help, Cristobal and Michael!

Regards,
Joost

Huh, wierd. If I’m understanding correctly, you have an issue on the master machine. You’ve installed Ansible globally, but when you have a virtualenv activated it doesn’t work?

There are better ways than installing Ansible inside the virtualenv or creating a virtualenv with --system-site-packages (bad idea anyway). How exactly did you install Ansible globally?

If I misunderstood something, ignore. :slight_smile: Also, as I understand it ansible_python_interpreter sets the remote Python interpreter, not the master one.

Hi Tin,

If I install Ansible only in a virtualenv (and not globally), the
modules are simply not found.

My problem was that local_action tasks are still "remote", delegated
to localhost. So the remote Python interpreter is used.

Regards,
Joost

I would suggest just installing Ansible normally.

Most people use packages.

I think it’s kind of a (no offense implied) symptom of Python developers to be like “This is Python, I know this!” and then make it more complicated :slight_smile:

It's no problem, Morgan Hamill suggested in a reply to my original
post that installing Ansible in virtualenv was supported so that
prompted me to go down this path.

The real problem, as I see it, is that Ansible cannot run if you
happen to be inside of a virtualenv. That is unexpected for a
system-installed package. (A user should not have to understand what
language Ansible was written in.)

Regards,
Joost

“The real problem, as I see it, is that Ansible cannot run if you
happen to be inside of a virtualenv.”

I’m not positive that’s true (ansible_python_interpreter), I just believe trying is a very unnecessary complication.

“That is unexpected for a
system-installed package. (A user should not have to understand what
language Ansible was written in.)”

I think for a system installed package you’d be less likely to even look to see what language it was written in, ergo you would be unlikely to think to use virtualenv.
In other words, I think you mean “expected” vs “unexpected”, or at least, that’s the meaning I would take.

"The real problem, as I see it, is that Ansible cannot run if you
happen to be inside of a virtualenv."

I'm not positive that's true (ansible_python_interpreter), I just believe
trying is a very unnecessary complication.

Well, Ansible does not run at all, because the hashbang on the main
ansible script says "#!/usr/bin/env python" and so it picks up the
interpreter of the virtualenv and cannot even find the ansible.runner
package.

"That is unexpected for a
system-installed package. (A user should not have to understand what
language Ansible was written in.)"

I think for a system installed package you'd be less likely to even look to
see what language it was written in, ergo you would be unlikely to think to
use virtualenv.

I agree that using virtualenv for Ansible "on purpose" is strange. But
it is perfectly reasonable to use Ansible as a tool for a project that
is developed in a virtualenv. Why would running ansible be any
different than running, say, grep?