任务
之前的内容中已经了解了如何初始化 nornir 对象并查看其主机清单和主机组信息,这节内容说明了如何在主机或主机组中执行任务。
任务是针对单台主机实现某种功能的一段可以重复使用的代码,例如收集信息等。
在 nornir 中, 任务(Tasks) 是一个将 Task
对象作为第一个参数并且返回值是 Result
对象的函数。
在旧版本中,nornir 提供了一些内置的任务可以直接使用。从 3.0 版本开始,为了保持框架的纯粹性,剔除了除核心功能外的插件代码,现在需要自己来编写 Task 或者使用其他人贡献出来的插件。
可以在 nornir.tech 中获取当前已经公开发布的插件。。
现在来看一个 Task
的示例:
[1]:
# 初始化一个 nornir 对象
# 导入 print_result 模块来处理 Result 对象
from nornir import InitNornir
from nornir_utils.plugins.functions import print_result
nr = InitNornir(config_file="files/config.yaml")
# 为了保持内容简洁,只针对一些主机进行操作
nr = nr.filter(site='bj',role='spine')
[2]:
# 首先导入 Task 、Result 模块
from nornir.core.task import Task, Result
# 定义一个 task,作用是让主机输出 hello world。
def hello_world(task: Task) -> Result:
return Result(
host=task.host,
result=f"{task.host.name} says hello world!"
)
要运行这个 task,需要使用 nornir 对象的 run
方法,将 task 函数作为参数传递给 run
,要获取到任务执行的结果,需要使用 print_result
方法打印出来:
[3]:
result = nr.run(task=hello_world)
print_result(result)
hello_world*********************************************************************
* spine00.bj ** changed : False ************************************************
vvvv hello_world ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
spine00.bj says hello world!
^^^^ END hello_world ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* spine01.bj ** changed : False ************************************************
vvvv hello_world ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
spine01.bj says hello world!
^^^^ END hello_world ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
定义 Task 函数时,支持 **kwargs
来传参,这样可以扩展 task 的功能性,例如:
[4]:
def say(task: Task, text: str) -> Result:
return Result(
host=task.host,
result=f"{task.host.name} says {text}"
)
然后可以像之前一样使用 nornir 对象的 run
方法来运行 task,这次需要指定额外的参数 text
:
[5]:
result = nr.run(
name="再见~",
task=say,
text="byebye!"
)
print_result(result)
再见~*****************************************************************************
* spine00.bj ** changed : False ************************************************
vvvv 再见~ ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
spine00.bj says byebye!
^^^^ END 再见~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* spine01.bj ** changed : False ************************************************
vvvv 再见~ ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
spine01.bj says byebye!
^^^^ END 再见~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
需要注意的是,在这个例子中传入了 name
参数来作为这个 task 的描述性名字,这个参数会在结果中显示出来。如果没有指定这个参数的话,则会使用 task 函数的名字。
任务组
一个任务(Tasks)可以调用其他的任务,这样就可以使用多个功能来组成更复杂的功能,这称为任务组(Grouping tasks)。
来定义一个新的 task:
[6]:
def count(task: Task, number: int) -> Result:
return Result(
host=task.host,
result=f"{[n for n in range(0, number)]}"
)
然后将这个新的 task count
和之前的 say
结合起来,形成任务组,实现更复杂的工作流:
[7]:
def greet_and_count(task: Task, number: int) -> Result:
task.run(
name="你好~",
task=say,
text="Hi~",
)
task.run(
name="计数",
task=count,
number=number,
)
task.run(
name="再见",
task=say,
text="byebye."
)
# 计算打招呼打了奇数次还是偶数次
even_or_odds = "even" if number % 2 == 1 else "odd"
return Result(
host=task.host,
result = f"{task.host} counted {even_or_odds} times!",
)
来简单分析一个这个 task: 1. 首先调用了 say
任务并传入了文本 “Hi~”; 2. 之后调用了 count
任务,它接收中在父任务 greet_and_count
也定义的参数 number
,这样可以在执行父任务时动态调整这部分参数; 3. 然后再次调用了 say
任务,这次传入了文本 “byebye”; 4. 之后 if
来判断计数情况; 5. 最后返回了 Result
对象,将需要的信息返回。
现在可以像调用一个普通的 task 一样来调用新定义的任务组:
[8]:
result = nr.run(
name="对打招呼次数进行计数",
task=greet_and_count,
number=5,
)
print_result(result)
对打招呼次数进行计数**********************************************************************
* spine00.bj ** changed : False ************************************************
vvvv 对打招呼次数进行计数 ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
spine00.bj counted even times!
---- 你好~ ** changed : False ---------------------------------------------------- INFO
spine00.bj says Hi~
---- 计数 ** changed : False ----------------------------------------------------- INFO
[0, 1, 2, 3, 4]
---- 再见 ** changed : False ----------------------------------------------------- INFO
spine00.bj says byebye.
^^^^ END 对打招呼次数进行计数 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* spine01.bj ** changed : False ************************************************
vvvv 对打招呼次数进行计数 ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
spine01.bj counted even times!
---- 你好~ ** changed : False ---------------------------------------------------- INFO
spine01.bj says Hi~
---- 计数 ** changed : False ----------------------------------------------------- INFO
[0, 1, 2, 3, 4]
---- 再见 ** changed : False ----------------------------------------------------- INFO
spine01.bj says byebye.
^^^^ END 对打招呼次数进行计数 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^