1---2title: "Fabric task 和 Invoke"3date: 2021-02-28T10:22:25+08:004---56## 前言7本文是个人使用 Fabric Task进行自动化的一点经验。89本文使用 Fabric 2,对于不熟悉的读者,请先阅读官方文档中的 [Getting started](https://docs.fabfile.org/en/latest/getting-started.html)1011本篇文章中的实例文件可在 [fabric-example](https://git.sr.ht/~lindsay/fabric-example) 找到1213## 文档结构1415```16fabric17├── fabfile.py18├── fabric.log19├── log.py20├── static21│ └── project.tar.gz22└── submodule.py23```242526## 日志记录27使用 Python 的 logging 模块对 Fabric 的操作进行记录,替代 print 。2829个人的通用 log.py 代码如下:3031```32import logging333435logger = logging.getLogger('Fabric')36logger.setLevel(logging.DEBUG)37fh = logging.FileHandler('fabric.log')38fh.setLevel(logging.INFO)3940ch = logging.StreamHandler()41ch.setLevel(logging.ERROR)424344formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(funcName)s - %(message)s')45fh.setFormatter(formatter)46ch.setFormatter(formatter)474849logger.addHandler(fh)50logger.addHandler(ch)51```5253这段代码会将 INFO 级别的日志存入 fabric.log 文件中,ERROR 级别的日志输出到 Shell。5455使用 logger 的示例如下5657```58from fabric import task59from log import logger6061@task62def test(c):63 """root task for test"""64 if c.run('uname -a', warn=True).ok:65 logger.info('test task done')66 else:67 logger.error('test task failed')68```6970运行后 fab test 后,日志的输出如下:7172```732021-02-28 18:08:55,464 - Fabric - INFO - test - test task done74```757677## 使用 Invoke 对 Fabric task 进行归类78Invoke 是从 Fabric 独立出去的一个自动化任务管理模块,Fabric 的 task 直接继承自 Invoke 的 task。因此,可以通过引入 Invoke 来对 Fabric 脚本进行一系列优化。7980这里主要介绍如何使用 Invoke 的 Collection 类,对 Fabric 的 task 进行分类。8182首先需要创建一个根分类,并添加 task 。在 fabfile.py 中写入以下内容:8384```85from invoke import Collection86from fabric import task8788from log import logger8990ns = Collection()9192@task93def test(c):94 """root task for test"""95 c.run('uname -a')96 logger.info('test task done')9798ns.add_task(test)99100```101102运行 fab -l 命令后可以看到与不使用 Collection 相同的输出103104```105(venv) lindsay@Arch-G5400> fab -l106Available tasks:107108 test root task for test109110```111112在 submodule.py 文件中创建子分类,并添加 task113114```115from invoke import Collection116from fabric import task, Connection117from log import logger118119subc = Collection('subc')120121@task122def sub_task(c):123 """task in submodule"""124 c.run('hostname')125 logger.info('sub-task done')126127subc.add_task(sub_task, name='subt')128129```130131最后在 fabfile.py 中引入这个子分类132133```134from submodule import subc135```136137并将这个子模块添加进根分类138139```140ns.add_collection(subc)141```142143输入 fab -l 可以看到所有的 task144145```146(venv) lindsay@Arch-G5400> fab -l147Available tasks:148149 test root task for test150 subc.subt task in submodule151152```153154输入 fab -l subc 可以看到 subc 子分类中的 task155156```157(venv) lindsay@Arch-G5400> fab -l subc158Available 'subc' tasks:159160 .subt task in submodule161162```163164输入 fab subc.subt 运行子任务165166```167(venv) lindsay@Arch-G5400> fab subc.subt168Arch-G5400169```170171指定远程机器运行 task:172173```174(venv) lindsay@Arch-G5400> fab test -H tab175Linux Tablet-Lindsay 5.11.1-arch1-1 #1 SMP PREEMPT Tue, 23 Feb 2021 14:05:30 +0000 x86_64 GNU/Linux176(venv) lindsay@Arch-G5400> fab subc.subt -H tab177Tablet-Lindsay178```179