当前位置:   article > 正文

fabric批量操作工具的基本使用_fabric.runners.result

fabric.runners.result

1、使用fabric连接主机
Fabric的最基本用途是通过SSH在远程系统上执行shell命令,然后(可选)询问结果。默认情况下,远程程序的输出将直接打印到您的终端上并进行捕获。
fabric通过Connection类连接远程主机,并使用run方法执行shell命令,例如:

import fabric
c = fabric.Connection("192.168.3.86", user="root", connect_kwargs={"password":"asdqwe"})
result = c.run("ls -l")
print(result.stdout.strip())
print(result.exited)
print(result.ok)
print(result.command)
print(result.connection)
print(result.connection.host)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

以上是使用密码认证,也可以通过密钥认证例如:

c = Connection(
    host="hostname",
    user="admin",
    connect_kwargs={
        "key_filename": "/home/myuser/.ssh/private.key",
    },)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Connection,它表示SSH连接,并提供Fabric API的核心,例如run。 连接对象至少需要成功创建一个主机名,并且可以通过用户名和/或端口号进一步进行参数化。 您可以通过args / kwargs明确给出这些:

Connection(host='hostname', user='admin', port=2202)
  • 1

或通过将[user @] host [:port]字符串填充到host参数中(尽管这纯粹是方便;只要出现歧义,请始终使用kwargs!):

Connection('deploy@web1:2202')
  • 1

如果不是使用root用户登录,则可能需要使用到 sudo 命令,可以通过run调用sudo程序,并且(如果您的远程系统未配置无密码sudo)则手动响应密码提示,如下所示。 (请注意,我们需要确定如何请求远程伪终端;否则,大多数sudo实现都会在密码提示时出现错误 。)

>>> from fabric import Connection
>>> c = Connection('db1')
>>> c.run('sudo useradd mydbuser', pty=True)
[sudo] password:<Result cmd='sudo useradd mydbuser' exited=0>
>>> c.run('id -u mydbuser')
1001
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
每次手动提供密码都会变旧; 值得庆幸的是,Invoke强大的命令执行功能包括能够使用预定义的输入自动响应程序输出的功能。 我们可以将它用于sudo:
import fabric
from invoke import Responder
c2 =  fabric.Connection("192.168.3.86", user="ye", connect_kwargs={"password":"lala@123"})
sudopass = Responder(pattern=r'\[sudo\] password:', response='asdqwe\n',)
c2.run('sudo whoami', pty=True, watchers=[sudopass])
  • 1
  • 2
  • 3
  • 4
  • 5

执行上述操作后,用户无需输入任何内容; password已自动发送到远程程序。

在这里使用观察者/响应者的效果很好,但是每次都要设置很多样板,尤其是在现实中的用例需要更多工作来检测失败/错误的密码的情况下。

为了解决这个问题,Invoke提供了一个Context.sudo方法来为您处理大部分样板(因为Connection子类为Context,它是免费获得此方法的。)sudo不会做用户无法做的任何事情-但总是,使用共同共享的解决方案可以最好地解决常见问题。

用户需要做的就是确保sudo.password配置值已填充(通过配置文件,环境变量或–prompt-for-sudo-password),而Connection.sudo处理其余部分。为了清楚起见,下面是一个示例,其中库/ shell用户执行他们自己的基于getpass的密码提示:

import fabric
import getpass

sudo_pass = getpass.getpass("What's your sudo password?:")
config = fabric.Config(overrides={'sudo': {'password': sudo_pass}})
c2 =  fabric.Connection("192.168.3.86", user="ye", connect_kwargs={"password":"lal
a@123"}, config=config)
c2.sudo('whoami', hide='stderr')
c2.sudo("useradd test")
c2.run('id -u test')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

在使用sudo的测试中,我的实验环境总是出错,有可能是Centos7系统提示是中文的,或者是其他原因,还没有找到很好的使用方法。

2、传输文件
除了执行shell命令外,SSH连接的另一种常用用法是文件传输。 存在Connection.put和Connection.get可以满足此需求。 例如,假设您有一个要上传的存档文件:

from fabric import Connection
result = Connection('192.168.3.86').put('huhu.txt', remote='/root/')
print("Uploaded {0.local} to {0.remote}".format(result))
  • 1
  • 2
  • 3

这些方法通常在参数评估方面遵循cp和scp / sftp的行为-例如,在以上代码段中,我们省略了远程路径参数的文件名部分。

3、输入多个命令
通常在运用中需要执行多个步骤的命令。 在最基本的级别上,您可以通过多次调用Connection方法来执行此操作:

from fabric import Connection
c = Connection("192.168.3.85", user="root", connect_kwargs={"password":"asdqwe"})
c.put('/root/uu/test.tgz', '/root/uu')
c.run('tar -C /root/uu -xzvf /root/uu/test.tgz')

  • 1
  • 2
  • 3
  • 4
  • 5

可以将此类代码块转换为函数,并使用调用者的Connection对象对其进行参数化,以鼓励重用:

def upload_and_unpack(c):
    c.put('/root/uu/test.tgz', '/root/uu')
    c.run('tar -C /root/uu -xzvf /root/uu/test.tgz')

  • 1
  • 2
  • 3
  • 4

3、连接多台服务器
大多数实际用例都涉及在一台以上的服务器上执行操作。 直接的方法可能是遍历Connection参数的列表或元组(或Connection对象本身,可能通过map):

from fabric import Connection

for host in ('192.168.3.86', '192.168.3.85'):
        result = Connection(host).run('uname -s')
        print("{}: {}".format(host, result.stdout.strip()))

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这种方法有效,但是随着用例变得越来越复杂,将主机集合视为单个对象可能会很有用。 输入Group,这是一个包装一个或多个Connection对象并提供类似API的类; 具体来说,您将要使用其具体的子类之一,例如SerialGroup或ThreadingGroup。

上面的示例使用Group(特别是SerialGroup),如下所示:

from fabric import SerialGroup as Group

results = Group('192.168.3.85', '192.168.3.86').run('ls -l')
print(results)
for connection, result in results.items():
        print("{0.host}: {1.stdout}".format(connection, result))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在Connection方法返回单个Result对象(例如fabric.runners.Result)的情况下,Group方法则返回GroupResult-类似dict的对象,提供对各个连接结果以及整个运行过程的元数据的访问。
当Group中的任何单个连接遇到错误时,GroupResult将被轻巧地包装在GroupException中,从而引发该异常。 因此,聚合行为类似于单个Connection方法的聚合行为,如果成功则返回值,或者如果失败则引发异常。(说人话就是group中有一个连接出错,整个group就会报错)

最后,整合成一个示例:您拥有一堆命令和/或文件传输,并且想要将其应用于多台服务器。 您可以使用多个Group方法调用来执行此操作

from fabric import SerialGroup as Group
pool = Group('web1', 'web2', 'web3')
pool.put('myfiles.tgz', '/opt/mydata')
pool.run('tar -C /opt/mydata -xzvf /opt/mydata/myfiles.tgz')
  • 1
  • 2
  • 3
  • 4

如果需要添加一些逻辑判断,该方法就会失效-例如,如果您只想在/ opt / mydata为空时执行上面的复制和删除操作。 进行这种检查需要在每个服务器上执行。

您可以通过使用Connection对象的可迭代对象来满足这一需求(尽管这放弃了使用组的一些好处):

from fabric import Connectionfor host in ('web1', 'web2', 'web3'):
    c = Connection(host)
    if c.run('test -f /opt/mydata/myfile', warn=True).failed:
        c.put('myfiles.tgz', '/opt/mydata')
        c.run('tar -C /opt/mydata -xzvf /opt/mydata/myfiles.tgz')
  • 1
  • 2
  • 3
  • 4
  • 5

也可以把操作集合改写成函数:

from fabric import SerialGroup as Group


def upload_and_unpack(c):
    if c.run('test -f /opt/mydata/myfile', warn=True).failed:
        c.put('myfiles.tgz', '/opt/mydata')
        c.run('tar -C /opt/mydata -xzvf /opt/mydata/myfiles.tgz')

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

for connection in Group(‘web1’, ‘web2’, ‘web3’):
upload_and_unpack(connection)
这种方法没有与Group.run这样类似方法-如果要汇总跟踪所有upload_and_unpack调用的结果,则需要自己编写相关代码。

如果需要使用线程,则可以使用ThreadingGroup子类,这个类是线程安全的

from fabric import ThreadingGroup as threading

results = threading('192.168.3.85', '192.168.3.86').run('ls -l')
print(results)
for connection, result in results.items():
        print("{0.host}: {1.stdout}".format(connection, result))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

4、fab命令行工具
从shell运行Fabric代码通常很有用,例如 在任意服务器上部署应用程序或运行sysadmin作业。 您可以在其中使用Fabric库代码的常规Invoke任务,但另一个选择是Fabric自己的“面向网络”工具fab。
fab将Invoke的CLI机制与主机选择等功能结合在一起,使您可以在各种服务器上快速运行任务,而不必在所有任务或类似任务上定义主机kwarg。

该模式是Fabric 1.x的主要API。 从2.0开始,这个保留的一种方便使用的方式。

示例,让我们将前面的示例改编为一个名为fabfile.py的fab任务模块:

from fabric import task


@taskdef upload_and_unpack(c):
    if c.run('test -f /opt/mydata/myfile', warn=True).failed:
        c.put('myfiles.tgz', '/opt/mydata')
        c.run('tar -C /opt/mydata -xzvf /opt/mydata/myfiles.tgz')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

将临时任务功能复制到文件中,并在其上拍一个装饰器。 task告诉CLI在命令行上公开执行该任务:

$ fab --list
Available tasks:

  upload_and_unpack
  • 1
  • 2
  • 3
  • 4

然后,当fab实际调用任务时,它知道如何将控制目标服务器的参数组合在一起,并在每个服务器上运行一次任务。 要在单个服务器上运行一次任务,示例如下:

$ fab -H web1 upload_and_unpack
  • 1

您可以提供一个以上的主机,多次运行该任务,并且每次都要传递一个不同的Connection实例:


$ fab -H web1,web2,web3 upload_and_unpack
  • 1
  • 2

以上是阅读官方文档后的个人理解小结

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/418536
推荐阅读
相关标签
  

闽ICP备14008679号