Chris W. Chris W. - 3 months ago 9
Python Question

How can I properly set the `env.hosts` in a function in my Python Fabric `fabfile.py`?

When I run this

fabfile.py
...

from fabric.api import env, run, local, cd

def setenv(foo):
env.hosts = ['myhost']

def mycmd(foo):
setenv(foo)
print(env.hosts)
run('ls')


with this command
fab mycmd:bar
. I get this output...

['myhost']
No hosts found. Please specify (single) host string for connection:


What, what?! I don't get it? I've set the
env.hosts
and it seems to be valid "inside" the
mycmd
function, but for some reason that
run
command doesn't know about the
hosts
I've specified.

Color me confused. Any help would be appreciated!

Answer

@Chris, the reason you're seeing this behavior is because the host list is constructed before the task function is called. So, even though you're changing env.hosts inside the function, it is too late for it to have any effect.

Whereas the command fab setenv:foo mycmd:bar, would have resulted in something you would have expected:

$ fab setenv:foo mycmd:bar
[myhost] Executing task 'mycmd'
['myhost']
[myhost] run: ls

This is the same as the accepted answer, but because of the way setenv is defined, an argument is needed.

Another example:

from fabric.api import env, run, local, cd

env.hosts = ['other_host']

def setenv(foo):
    env.hosts = ['myhost']

def mycmd(foo):
    setenv(foo)
    print('env.hosts inside mycmd: %s' % env.hosts)
    run('ls')

The output of this is:

$ fab mycmd:bar
[other_host] Executing task 'mycmd'
env.hosts inside mycmd: ['myhost']
[other_host] run: ls

Fatal error: Name lookup failed for other_host

Underlying exception:
    (8, 'nodename nor servname provided, or not known')
Aborting.

As you can see, the host-list is already set to ['other_host', ] when fabric starts to execute mycmd.

Comments