fabric: run() 无错误挂起

3 投票
3 回答
5128 浏览
提问于 2025-04-18 05:45
from fabric.api import env
from fabric.api import run

class FabricSupport:
    def __init__ (self):
        pass

    def run(self, host, command):
        env.key_filename = 'C:/.ssh/dev.pub'
        env.host_string = "%s:%s" % (host, 22)
        run(command, timeout=5)

fab = FabricSupport()

def execute(host, txt):
    stdout = ""
    try:
        stdout = fab.run(host, txt)
    except Exception, e:
        stdout = str(e)
    return stdout

result = execute("23.23.23.23", "uname -a")

它只是输出以下内容,然后一直保持这个状态,没有结束。超时似乎也没有起作用。如果能输出更多信息就好了,这样我可以调查一下发生了什么。

[12.45.241.11:22] 运行命令: uname -a

3 个回答

0

这周我在远程机器上运行一个需要很长时间的任务时,遇到了同样的挂起错误。

我通过在fabric.api.env配置中指定'keepalive'选项解决了这个问题。这个配置会让fabric每隔几分钟发送一个保持连接的消息。

http://docs.fabfile.org/en/1.14/usage/env.html#keepalive

我把这个值设置为30,这样在运行3个小时的任务时就不会挂起了。

2

今天我在使用Ubuntu的时候遇到了同样的问题。我的问题出在活动的shell设置上:

env.shell = /bin/sh -l -c

用这个shell的时候,脚本无法顺利执行远程命令,导致ssh连接挂掉。控制权一直停留在ssh的shell里,结果在fabric中出现了超时。

但是当我把设置改成:

env.shell = "/bin/bash -c"

一切就正常了。

总的建议是:根据你的操作系统检查一下shell和参数设置。

2

我不太清楚你这段代码的最终目的是什么。如果你想通过把它放在一个类里来隔离修改环境的影响,那是不行的。因为在fabric中,它是一个模块级别的全局变量,无论你在哪里修改它(就像你在这里做的那样),都会影响后面的代码。我觉得你可能真正想要的是这个:

from fabric.api import run, execute, task, settings

@task
def custom_runner(command):
    """Runs command with custom key_filename"""
    with settings(warn_only=True, key_filename=r"C:\.ssh\dev.pub"):
        result = run(command, timeout=5)
    return result

result = execute(custom_runner, "uname -a", host="23.23.23.23")

请记住,这个代码不能直接被“fab”命令行工具使用,因为它会在fab加载fabfile时立即执行那段代码(result = execute...)。这只能作为库来使用。

你可以使用roledefs来处理一组主机。结果对象会是一个字典,每个主机都是一个键,对应的值是任务的返回对象。你几乎不想使用裸露的异常处理,Fabric有自己的一套方法来防止异常导致你的程序崩溃。

撰写回答