Fabric task 和 Invoke

前言

本文是个人使用 Fabric Task进行自动化的一点经验。
本文使用 Fabric 2,对于不熟悉的读者,请先阅读官方文档中的 Getting started
本篇文章中的实例文件可在 fabric-example 找到

文档结构

fabric
├── fabfile.py
├── fabric.log
├── log.py
├── static
│   └── project.tar.gz
└── submodule.py

日志记录

使用 Python 的 logging 模块对 Fabric 的操作进行记录,替代 print 。
个人的通用 log.py 代码如下:

import logging


logger = logging.getLogger('Fabric')
logger.setLevel(logging.DEBUG)
fh = logging.FileHandler('fabric.log')
fh.setLevel(logging.INFO)

ch = logging.StreamHandler()
ch.setLevel(logging.ERROR)


formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(funcName)s - %(message)s')
fh.setFormatter(formatter)
ch.setFormatter(formatter)


logger.addHandler(fh)
logger.addHandler(ch)

这段代码会将 INFO 级别的日志存入 fabric.log 文件中,ERROR 级别的日志输出到 Shell。
使用 logger 的示例如下

from fabric import task
from log import logger

@task
def test(c):
    """root task for test"""
    if c.run('uname -a', warn=True).ok:
        logger.info('test task done')
    else:
        logger.error('test task failed')

运行后 fab test 后,日志的输出如下:

2021-02-28 18:08:55,464 - Fabric - INFO - test - test task done

使用 Invoke 对 Fabric task 进行归类

Invoke 是从 Fabric 独立出去的一个自动化任务管理模块,Fabric 的 task 直接继承自 Invoke 的 task。
因此,可以通过引入 Invoke 来对 Fabric 脚本进行一系列优化。
这里主要介绍如何使用 Invoke 的 Collection 类,对 Fabric 的 task 进行分类。

首先需要创建一个根分类,并添加 task 。
在 fabfile.py 中写入以下内容:

from invoke import Collection
from fabric import task

from log import logger

ns = Collection()

@task
def test(c):
    """root task for test"""
    c.run('uname -a')
    logger.info('test task done')

ns.add_task(test)
    

运行 fab -l 命令后可以看到与不使用 Collection 相同的输出

(venv) lindsay@Arch-G5400> fab -l           
Available tasks:

  test   root task for test

在 submodule.py 文件中创建子分类,并添加 task

from invoke import Collection
from fabric import task, Connection
from log import logger

subc = Collection('subc')

@task
def sub_task(c):
    """task in submodule"""
    c.run('hostname')
    logger.info('sub-task done')
    
subc.add_task(sub_task, name='subt')

最后在 fabfile.py 中引入这个子分类

from submodule import subc

并将这个子模块添加进根分类

ns.add_collection(subc)

输入 fab -l 可以看到所有的 task

(venv) lindsay@Arch-G5400> fab  -l  
Available tasks:

  test        root task for test
  subc.subt   task in submodule

输入 fab -l subc 可以看到 subc 子分类中的 task

(venv) lindsay@Arch-G5400> fab -l subc
Available 'subc' tasks:

  .subt   task in submodule

输入 fab subc.subt 运行子任务

(venv) lindsay@Arch-G5400> fab subc.subt 
Arch-G5400

指定远程机器运行 task:

(venv) lindsay@Arch-G5400> fab test -H tab 
Linux Tablet-Lindsay 5.11.1-arch1-1 #1 SMP PREEMPT Tue, 23 Feb 2021 14:05:30 +0000 x86_64 GNU/Linux
(venv) lindsay@Arch-G5400> fab subc.subt -H tab 
Tablet-Lindsay