Python fabric 2.3 sudo命令的并行执行

Python fabric 2.3 sudo命令的并行执行,python,fabric,Python,Fabric,我正在尝试使用fabric 2.3在一些服务器上运行一些需要sudo的任务。我这里的主要目标是并行化操作,因此我考虑使用fabric api的ThreadingGroup类,但它不支持sudo 为了清楚起见,下面是我的代码 #!/usr/bin/env python from fabric import ThreadingGroup, Config from getpass import getpass sudo_pass = getpass("Enter your sudo passwo

我正在尝试使用fabric 2.3在一些服务器上运行一些需要sudo的任务。我这里的主要目标是并行化操作,因此我考虑使用fabric api的
ThreadingGroup
类,但它不支持
sudo

为了清楚起见,下面是我的代码

#!/usr/bin/env python

from fabric import ThreadingGroup, Config
from getpass import getpass


sudo_pass = getpass("Enter your sudo password: ")
sudo_config = Config(overrides={'sudo': {'password': sudo_pass}})
server_pool = ThreadingGroup("test1", "test2",
                             config=sudo_config)

result = server_pool.sudo('cat /etc/shadow', hide='stderr')
print(result)
现在,这与上面提到的不一样,因为
ThreadingGroup
不支持
Connection
类支持的所有方法

我可以在多台服务器上运行
sudo
,方法是迭代各个主机,然后为每个主机创建连接,但这并不高效

那么有没有一种方法可以让它与fabric 2.3平行呢?我也查阅了官方文件,但没有发现任何东西

此外,在官方文档之后,我对它进行了更多的测试,似乎
ThreadingGroup
只有在如下方式运行时才能实现并行性

fabric.ThreadingGroup('test1','test2')。run('uname-s')

但是,如果您像下面这样运行它,它不会并行运行

def run_task(c):
    c.run('uname -s')


for cxn in fabric.ThreadingGroup('test1', 'test2'):
    run_task(cxn)

因此,到目前为止,fabric 2.3中似乎没有太多灵活的并行支持,我可能只能切换回fabric版本1。

当前版本(到目前为止为2.4)中似乎没有实现某些功能。 一个可选的解决方案是在源文件中添加一些代码。 您可以找到fabric的安装路径,然后编辑group.py

首先,在group.py中添加此函数:

def thread_worker_sudo(cxn, queue, args, kwargs):
    result = cxn.sudo(*args, **kwargs)
    # TODO: namedtuple or attrs object?
    queue.put((cxn, result))
然后在ThreadingGroup类中添加sudo函数:

class ThreadingGroup(Group):
    .... original ThreadingGroup


    def sudo(self, *args, **kwargs):
        results = GroupResult()
        queue = Queue()
        threads = []
        for cxn in self:
            my_kwargs = dict(cxn=cxn, queue=queue, args=args, kwargs=kwargs)
            thread = ExceptionHandlingThread(
                target=thread_worker_sudo, kwargs=my_kwargs
            )
            threads.append(thread)
        for thread in threads:
            thread.start()
        for thread in threads:
            # TODO: configurable join timeout
            # TODO: (in sudo's version) configurability around interactive
            # prompting resulting in an exception instead, as in v1
            thread.join()
        # Get non-exception results from queue
        while not queue.empty():
            # TODO: io-sleep? shouldn't matter if all threads are now joined
            cxn, result = queue.get(block=False)
            # TODO: outstanding musings about how exactly aggregate results
            # ought to ideally operate...heterogenous obj like this, multiple
            # objs, ??
            results[cxn] = result
        # Get exceptions from the threads themselves.
        # TODO: in a non-thread setup, this would differ, e.g.:
        # - a queue if using multiprocessing
        # - some other state-passing mechanism if using e.g. coroutines
        # - ???
        excepted = False
        for thread in threads:
            wrapper = thread.exception()
            if wrapper is not None:
                # Outer kwargs is Thread instantiation kwargs, inner is kwargs
                # passed to thread target/body.
                cxn = wrapper.kwargs["kwargs"]["cxn"]
                results[cxn] = wrapper.value
                excepted = True
        if excepted:
            raise GroupException(results)
        return results
我只是复制函数run的代码并替换这一行

thread = ExceptionHandlingThread(
    target=thread_worker, kwargs=my_kwargs
)

对我来说是这样的:

def test_sudo(group):
    group.sudo('whoami', user='root')

$ python fabfile.py
root
root
root
root
root

但是,我不确定,它是否适用于所有情况。

如果要以root身份运行所有任务,为什么不从一开始就使用sudo执行脚本?1)我不尝试以root身份运行所有任务,因为只有某些任务需要sudo。2) 在本地机器上以
sudo
的身份运行脚本如何在远程机器上授予
sudo
?3) 如果我有另一组根本不需要
sudo
的远程主机怎么办?您可以在
/etc/sudoers
中为您的用户和该命令设置属性。这样,您就明确地将要在
fabric
中运行的命令列为白名单,并且您的密码不会有泄漏的危险。@NilsWerner这与fabric根本没有关系,更与在系统本身上配置sudo有关。我的问题更多的是关于如何将sudo与新版本的fabric并行运行!!我不担心密码泄露,因为我使用getpass输入密码,密码或无密码是完全不同的问题。一旦密码提示消失,用
server\u pool.sudo('cat/etc/shadow',hide='stderr')
替换为
server\u pool.run('sudo cat/etc/shadow',hide='stderr')
def test_sudo(group):
    group.sudo('whoami', user='root')

$ python fabfile.py
root
root
root
root
root