blog-site

git clone git://git.lin.moe/blog-site.git

  1---
  2title: "Fabric task 和 Invoke"
  3date: 2021-02-28T10:22:25+08:00
  4---
  5
  6## 前言
  7本文是个人使用 Fabric Task进行自动化的一点经验。    
  8
  9本文使用 Fabric 2,对于不熟悉的读者,请先阅读官方文档中的 [Getting started](https://docs.fabfile.org/en/latest/getting-started.html)  
 10
 11本篇文章中的实例文件可在 [fabric-example](https://git.sr.ht/~lindsay/fabric-example) 找到  
 12
 13## 文档结构  
 14
 15```
 16fabric
 17├── fabfile.py
 18├── fabric.log
 19├── log.py
 20├── static
 21│   └── project.tar.gz
 22└── submodule.py
 23```
 24
 25
 26## 日志记录
 27使用 Python 的 logging 模块对 Fabric 的操作进行记录,替代 print 。  
 28
 29个人的通用 log.py 代码如下:  
 30
 31```
 32import logging
 33
 34
 35logger = logging.getLogger('Fabric')
 36logger.setLevel(logging.DEBUG)
 37fh = logging.FileHandler('fabric.log')
 38fh.setLevel(logging.INFO)
 39
 40ch = logging.StreamHandler()
 41ch.setLevel(logging.ERROR)
 42
 43
 44formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(funcName)s - %(message)s')
 45fh.setFormatter(formatter)
 46ch.setFormatter(formatter)
 47
 48
 49logger.addHandler(fh)
 50logger.addHandler(ch)
 51```  
 52
 53这段代码会将 INFO 级别的日志存入 fabric.log 文件中,ERROR 级别的日志输出到 Shell。  
 54
 55使用 logger 的示例如下
 56
 57```
 58from fabric import task
 59from log import logger
 60
 61@task
 62def 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```
 69
 70运行后 fab test 后,日志的输出如下:  
 71
 72```
 732021-02-28 18:08:55,464 - Fabric - INFO - test - test task done
 74```
 75
 76
 77## 使用 Invoke 对 Fabric task 进行归类  
 78Invoke 是从 Fabric 独立出去的一个自动化任务管理模块,Fabric 的 task 直接继承自 Invoke 的 task。因此,可以通过引入 Invoke 来对 Fabric 脚本进行一系列优化。  
 79
 80这里主要介绍如何使用 Invoke 的 Collection 类,对 Fabric 的 task 进行分类。   
 81  
 82首先需要创建一个根分类,并添加 task 。在 fabfile.py 中写入以下内容:  
 83
 84```
 85from invoke import Collection
 86from fabric import task
 87
 88from log import logger
 89
 90ns = Collection()
 91
 92@task
 93def test(c):
 94    """root task for test"""
 95    c.run('uname -a')
 96    logger.info('test task done')
 97
 98ns.add_task(test)
 99    
100```  
101
102运行 fab -l 命令后可以看到与不使用 Collection 相同的输出  
103
104```
105(venv) lindsay@Arch-G5400> fab -l           
106Available tasks:
107
108  test   root task for test
109
110```  
111
112在 submodule.py 文件中创建子分类,并添加 task  
113
114```
115from invoke import Collection
116from fabric import task, Connection
117from log import logger
118
119subc = Collection('subc')
120
121@task
122def sub_task(c):
123    """task in submodule"""
124    c.run('hostname')
125    logger.info('sub-task done')
126    
127subc.add_task(sub_task, name='subt')
128
129```
130
131最后在 fabfile.py 中引入这个子分类  
132
133```
134from submodule import subc
135```  
136
137并将这个子模块添加进根分类  
138
139```
140ns.add_collection(subc)
141```  
142
143输入 fab -l 可以看到所有的 task  
144
145```
146(venv) lindsay@Arch-G5400> fab  -l  
147Available tasks:
148
149  test        root task for test
150  subc.subt   task in submodule
151
152```  
153
154输入 fab -l subc 可以看到 subc 子分类中的 task  
155
156```
157(venv) lindsay@Arch-G5400> fab -l subc
158Available 'subc' tasks:
159
160  .subt   task in submodule
161
162```  
163
164输入 fab subc.subt 运行子任务  
165
166```
167(venv) lindsay@Arch-G5400> fab subc.subt 
168Arch-G5400
169```  
170
171指定远程机器运行 task:  
172
173```
174(venv) lindsay@Arch-G5400> fab test -H tab 
175Linux Tablet-Lindsay 5.11.1-arch1-1 #1 SMP PREEMPT Tue, 23 Feb 2021 14:05:30 +0000 x86_64 GNU/Linux
176(venv) lindsay@Arch-G5400> fab subc.subt -H tab 
177Tablet-Lindsay
178```
179