Fabric 3中执行远程命令时跳过不可用主机并返回正常结果的实现方法
Fabric 3中执行远程命令时跳过不可用主机并返回正常结果的实现方法
针对你的需求,我们可以分两步解决:修正超时设置(让5秒超时生效)和捕获异常并分离成功结果,以下是具体的实现方案:
1. 正确设置超时时间(连接+命令执行)
你在group.run()中设置的timeout=5是命令执行阶段的超时(即命令运行后最多等待5秒返回),而SSH连接阶段的超时默认是60秒,这部分需要在创建ThreadingGroup时通过connect_kwargs传入connection_timeout参数来修改:
group = fabric.ThreadingGroup( 'boss1', 'boss2', connect_kwargs={"connection_timeout": 5} # 控制SSH连接的超时时间 )
结合group.run()中的timeout=5,现在连接主机和命令执行两个阶段的超时都会被限制为5秒,不会再出现默认的60秒等待。
2. 捕获异常,保留成功结果并隔离错误
当存在不可用主机时,Fabric会抛出GroupException,这个异常的参数是一个字典,键是Connection对象,值要么是成功的Result,要么是对应的异常信息。我们可以捕获这个异常,遍历字典分离出成功主机的结果和失败主机的错误:
完整代码示例
#!/usr/bin/python3 import fabric from fabric.exceptions import GroupException from fabric.runners import Result def main(): # 初始化主机组,设置连接超时为5秒 group = fabric.ThreadingGroup( 'boss1', 'boss2', connect_kwargs={"connection_timeout": 5} ) try: # 执行命令,设置命令执行超时为5秒 results = group.run('uname -a', hide=True, timeout=5) # 所有主机都成功的情况 print("所有主机执行成功:") for conn, result in results.items(): print(f'{conn.host}: {result.stdout.strip()}') except GroupException as e: # 部分主机失败的情况,遍历结果字典 results_dict = e.args[0] print("部分主机执行失败,结果汇总:") for conn, outcome in results_dict.items(): if isinstance(outcome, Result): # 成功执行的主机 print(f'{conn.host}: 成功 - {outcome.stdout.strip()}') else: # 执行失败的主机,输出错误信息 print(f'{conn.host}: 失败 - {type(outcome).__name__}: {str(outcome)}') if __name__ == "__main__": main()
代码说明
- 捕获
GroupException后,通过e.args[0]获取包含所有主机状态的字典 - 用
isinstance(outcome, Result)判断该主机是否执行成功,分别处理输出 - 这样即使有部分主机不可用,你依然能拿到所有成功主机的结果,同时记录失败主机的错误原因
关于skip_bad_hosts的说明
你提到的skip_bad_hosts参数是Fabric 2.x的特性,而Fabric3(作为Fabric1的Python3兼容分支)并不支持这个参数,因此手动捕获GroupException是最可靠的处理方式。
备注:内容来源于stack exchange,提问作者shepster




