简体   繁体   English

如何在 Python Fabric `fabfile.py` 的函数中正确设置 `env.hosts`?

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

When I run this fabfile.py ...当我运行这个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 .使用这个命令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.我已经设置了env.hosts并且它似乎在mycmd函数“内部”有效,但是由于某种原因, run命令不知道我指定的hosts

Color me confused.颜色让我困惑。 Any help would be appreciated!任何帮助,将不胜感激!

@Chris, the reason you're seeing this behavior is because the host list is constructed before the task function is called. @Chris,您看到此行为的原因是因为在调用任务函数之前构建了主机列表。 So, even though you're changing env.hosts inside the function, it is too late for it to have any effect.因此,即使您在函数内部更改env.hosts ,也为时已晚,无法产生任何效果。

Whereas the command fab setenv:foo mycmd:bar , would have resulted in something you would have expected:而命令fab setenv:foo mycmd:bar ,会产生你所期望的结果:

$ 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.这与接受的答案相同,但由于setenv的定义方式,需要一个参数。

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 .如您所见,当fabric 开始执行mycmd时,主机列表已经设置为['other_host', ]

The way you are doing it is not normally how I would use Fabric.您这样做的方式通常不是我使用 Fabric 的方式。

from fabric.api import *

def hostname():

    env.hosts = ['myhosts']

def mycmd():
    print env.hosts
    run('ls -l')

To run this I would then do要运行它,我会这样做

fab hostname mycmd

this allows you to seperate which host/hosts you want to perform the command on.这允许您将要执行命令的主机分开。

hope it helps.希望能帮助到你。

Have you tried to used the hosts decorator?您是否尝试过使用主机装饰器?

from fabric.api import env, run, hosts

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

I know this question is super old, but just in case someone stumbles across this, I have found that you don't need to call this as a fab file per se (your file doesn't need to be called "fabfile.py" and command doesn't need to be fab setenv(foo) mycmd(bar) . Since you are importing the needed fab elements, you can call the file anything you want (let's call it "testfile.py") and simply use the execute function in the file. That would make your command python testfile.py .我知道这个问题非常古老,但以防万一有人偶然发现这个问题,我发现您不需要将其称为 fab 文件本身(您的文件不需要称为“fabfile.py”并且命令不需要是fab setenv(foo) mycmd(bar) 。由于您正在导入所需的 fab 元素,因此您可以随意调用该文件(我们称其为“testfile.py”),然后只需使用 execute文件中的函数。这将使您的命令python testfile.py

Inside the testfile, set everything up like you would normally, but start the function using the execute keyword.在测试文件中,像往常一样设置所有内容,但使用execute关键字启动该函数。 Your file would look something like this:您的文件将如下所示:

from fabric.api import env, run

def setenv(foo):
    env.hosts = ['myhost']
    execute(mycmd, bar)

def mycmd(bar):
    run('ls')

setenv(foo)

** It's important to note that the execute command does look like a regular function call. ** 需要注意的是,execute 命令确实看起来像一个普通的函数调用。 It will call the function and send the arguments in a single comma separated line.它将调用该函数并在单个逗号分隔行中发送参数。 You can find more information here你可以在这里找到更多信息

So you'd start your program which would first call setenv, then setenv would execute the mycmd function.因此,您将启动首先调用 setenv 的程序,然后 setenv 将执行mycmd 函数。 With this, you can also set multiple hosts within the same array.有了这个,您还可以在同一阵列中设置多个主机。 Something like:就像是:

env.hosts=['myhost1','myhost2','myhost3']

I have figured out how to make it work:我已经想出了如何使它工作:

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

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM