赞
踩
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)
以上是使用密码认证,也可以通过密钥认证例如:
c = Connection(
host="hostname",
user="admin",
connect_kwargs={
"key_filename": "/home/myuser/.ssh/private.key",
},)
Connection,它表示SSH连接,并提供Fabric API的核心,例如run。 连接对象至少需要成功创建一个主机名,并且可以通过用户名和/或端口号进一步进行参数化。 您可以通过args / kwargs明确给出这些:
Connection(host='hostname', user='admin', port=2202)
或通过将[user @] host [:port]字符串填充到host参数中(尽管这纯粹是方便;只要出现歧义,请始终使用kwargs!):
Connection('deploy@web1:2202')
如果不是使用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
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])
执行上述操作后,用户无需输入任何内容; 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')
在使用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))
这些方法通常在参数评估方面遵循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')
可以将此类代码块转换为函数,并使用调用者的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')
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()))
这种方法有效,但是随着用例变得越来越复杂,将主机集合视为单个对象可能会很有用。 输入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))
在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')
如果需要添加一些逻辑判断,该方法就会失效-例如,如果您只想在/ 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')
也可以把操作集合改写成函数:
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')
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))
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')
将临时任务功能复制到文件中,并在其上拍一个装饰器。 task告诉CLI在命令行上公开执行该任务:
$ fab --list
Available tasks:
upload_and_unpack
然后,当fab实际调用任务时,它知道如何将控制目标服务器的参数组合在一起,并在每个服务器上运行一次任务。 要在单个服务器上运行一次任务,示例如下:
$ fab -H web1 upload_and_unpack
您可以提供一个以上的主机,多次运行该任务,并且每次都要传递一个不同的Connection实例:
$ fab -H web1,web2,web3 upload_and_unpack
以上是阅读官方文档后的个人理解小结
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。