从本地到远端
文件传输
之前提到,Fabric集成了Paramiko的ssh基本功能,自然少不了SFTP,所以除了执行shell命令,Fabric也常用于文件传输,封装与Connection.put, Connection.get。这比Paramiko好了不少,Paramiko成功建立链接之后,我记得还需要单独实例化一个SFTP对象。Fabric把所有的操作都赋
予Connection实例了。
>>> from fabric import Connection >>> result = Connection('web1').put('myfiles.tgz', remote='/opt/mydata/') >>> print("Uploaded {0.local} to {0.remote}".format(result)) Uploaded /local/myfiles.tgz to /opt/mydata/
封装多步操作
比如,上传文件,然后解压,从整体来看是一套流程中稀碎的事请,我们完成一件事情,可以封装一系列动作,通过传递Connection实例到方法
,让代码复用性更高,通过被其他API调用组合成更加复杂的用例。更干净
例如:
from fabric import Connection c = Connection('web1') c.put('myfiles.tgz', '/opt/mydata') c.run('tar -C /opt/mydata -xzvf /opt/mydata/myfiles.tgz')
可以变成
def upload_and_unpack(c): c.put('myfiles.tgz', '/opt/mydata') c.run('tar -C /opt/mydata -xzvf /opt/mydata/myfiles.tgz')
多服务器
大多数的实际用例都包含了同时在多台服务器上做一些事请,可以通过,将多台服务器存入数据结构中,然后一一便利,但是fabric提供了更加
方便的方式用来包装所有的Connection实例,叫做Group,它提供了和Connection相同的API,更加具体一点,我们需要选择Group的两个子类之>一,SerialGroup或ThreadingGroup。
>>> from fabric import SerialGroup as Group >>> results = Group('web1', 'web2', 'mac1').run('uname -s') >>> print(results) <GroupResult: { <Connection 'web1'>: <CommandResult 'uname -s'>, <Connection 'web2'>: <CommandResult 'uname -s'>, <Connection 'mac1'>: <CommandResult 'uname -s'>, }> >>> for connection, result in results.items(): ... print("{0.host}: {1.stdout}".format(connection, result)) ... ... web1: Linux web2: Linux mac1: Darwin
相较于Connection返回的内容是Result对象(fabric.runners.Result),Group方法返回的是GroupResult,dict-like 的对象支持访问单个Connection的结果。所以能通过items()来遍历字典。
当任何包含在Group的独立链接发生错误时,会抛出GroupException
全都拉起来
直接上例子,多服务器的串行部署。
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是可便利对象,Group对象的api返回的结果是dict-like对象
使用fab部署我们的项目
我之前在介绍Invoke的时候单独写了一篇文章,里面的task装饰器,可以将方法变成可执行的命令行选项。当然fabric也有。
最后一个例子,还是上传加打包。
from fabric import task @task 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')
之后将会在命令行看到:
$ fab --list Available tasks: upload_and_unpack
更加强大的是下面这两条命令
$ fab -H web1 upload_and_unpack
$ fab -H web1,web2,web3 upload_and_unpack
我没有试验过,但它貌似可以自动的创建该服务的链接并且传递给task装饰的方法。
但我估计执行之后,是需要输入密码的,就像普通的ssh建立链接一样,如果配置免密,估计会执行的更加丝滑。
这只是官方例子,但我认为使用的时候可以不用—H选项,直接写好自己的部署任务,在代码中创建Connection。