Nornir 处理器

处理器是可以在某些事件上执行代码的插件。有关这些事件的更多信息,请参阅类文档。

您可以将处理器视为处理task结果的另一种方法,但是它具有一些优点:

  1. 由于其基于事件的性质,您可以异步处理事件。这意味着您将在host完成后立即处理host的结果,而无需等待其余host完成。
  2. 因为您正在使用事件代码,所以代码更简洁,更容易理解。

让我们看几个例子如何处理处理器。让我们从加载nornir对象和一些我们需要的库开始:

from typing import Dict

from nornir import InitNornir

nr = InitNornir(config_file="config.yaml")

现在让我们编写一个处理器,该处理器将在屏幕上打印一些有关task执行的信息:

# note that these imports are only needed if you are annotating your code with types
from typing import Dict

from nornir.core import Nornir
from nornir.core.inventory import Host
from nornir.core.task import AggregatedResult, MultiResult, Result, Task

class PrintResult:
    def task_started(self, task: Task) -> None:
        print(f">>> starting: {task.name}")

    def task_completed(self, task: Task, result: AggregatedResult) -> None:
        print(f">>> completed: {task.name}")

    def task_instance_started(self, task: Task, host: Host) -> None:
        pass

    def task_instance_completed(
        self, task: Task, host: Host, result: MultiResult
    ) -> None:
        print(f"  - {host.name}: - {result.result}")

    def subtask_instance_started(self, task: Task, host: Host) -> None:
        pass  # to keep example short and sweet we ignore subtasks

    def subtask_instance_completed(
        self, task: Task, host: Host, result: MultiResult
    ) -> None:
        pass  # to keep example short and sweet we ignore subtasks

现在,我们将编写另一个处理器,该处理器会将有关task的一些信息保存在字典中:

class SaveResultToDict:
    def __init__(self, data: Dict[str, None]) -> None:
        self.data = data

    def task_started(self, task: Task) -> None:
        self.data[task.name] = {}
        self.data[task.name]["started"] = True

    def task_completed(self, task: Task, result: AggregatedResult) -> None:
        self.data[task.name]["completed"] = True

    def task_instance_started(self, task: Task, host: Host) -> None:
        self.data[task.name][host.name] = {"started": True}

    def task_instance_completed(
        self, task: Task, host: Host, result: MultiResult
    ) -> None:
        self.data[task.name][host.name] = {
            "completed": True,
            "result": result.result,
        }

    def subtask_instance_started(self, task: Task, host: Host) -> None:
        pass  # to keep example short and sweet we ignore subtasks

    def subtask_instance_completed(
        self, task: Task, host: Host, result: MultiResult
    ) -> None:
        pass  # to keep example short and sweet we ignore subtasks

最后,为了测试处理器,我们将使用一个非常简单的task,它将代表每个设备向我们致意:

def greeter(task: Task, greet: str) -> Result:
    return Result(host=task.host, result=f"{greet}! my name is {task.host.name}")

希望到目前为止,一切都已经清楚了,现在让我们使用它:

# NBVAL_IGNORE_OUTPUT

data = {}  # this is the dictionary where SaveResultToDict will store the information

# similary to .filter, with_processors returns a copy of the nornir object but with
# the processors assigned to it. Let's now use the method to assign both processors
nr_with_processors = nr.with_processors([SaveResultToDict(data), PrintResult()])

# now we can use nr_with_processors to execute our greeter task
nr_with_processors.run(
    name="hi!",
    task=greeter,
    greet="hi",
)
nr_with_processors.run(
    name="bye!",
    task=greeter,
    greet="bye",
)
>>> starting: hi!
  - host1.cmh: - hi! my name is host1.cmh
  - host2.cmh: - hi! my name is host2.cmh
  - spine00.cmh: - hi! my name is spine00.cmh
  - spine01.cmh: - hi! my name is spine01.cmh  - leaf00.cmh: - hi! my name is leaf00.cmh
  - leaf01.cmh: - hi! my name is leaf01.cmh

  - host1.bma: - hi! my name is host1.bma
  - host2.bma: - hi! my name is host2.bma
  - spine00.bma: - hi! my name is spine00.bma
  - spine01.bma: - hi! my name is spine01.bma
  - leaf00.bma: - hi! my name is leaf00.bma
  - leaf01.bma: - hi! my name is leaf01.bma
>>> completed: hi!
>>> starting: bye!
  - host1.cmh: - bye! my name is host1.cmh
  - host2.cmh: - bye! my name is host2.cmh
  - spine00.cmh: - bye! my name is spine00.cmh
  - spine01.cmh: - bye! my name is spine01.cmh
  - leaf00.cmh: - bye! my name is leaf00.cmh
  - leaf01.cmh: - bye! my name is leaf01.cmh
  - host1.bma: - bye! my name is host1.bma
  - host2.bma: - bye! my name is host2.bma
  - spine00.bma: - bye! my name is spine00.bma
  - spine01.bma: - bye! my name is spine01.bma
  - leaf00.bma: - bye! my name is leaf00.bma
  - leaf01.bma: - bye! my name is leaf01.bma
>>> completed: bye!
AggregatedResult (bye!): {'host1.cmh': MultiResult: [Result: "bye!"], 'host2.cmh': MultiResult: [Result: "bye!"], 'spine00.cmh': MultiResult: [Result: "bye!"], 'spine01.cmh': MultiResult: [Result: "bye!"], 'leaf00.cmh': MultiResult: [Result: "bye!"], 'leaf01.cmh': MultiResult: [Result: "bye!"], 'host1.bma': MultiResult: [Result: "bye!"], 'host2.bma': MultiResult: [Result: "bye!"], 'spine00.bma': MultiResult: [Result: "bye!"], 'spine01.bma': MultiResult: [Result: "bye!"], 'leaf00.bma': MultiResult: [Result: "bye!"], 'leaf01.bma': MultiResult: [Result: "bye!"]}

您可能注意到的第一件事是,我们在屏幕上为我们打印了所有这些消息。那是由我们的处理器完成的PrintResult。您可能还注意到我们AggregatedResult回来了,但是我们甚至没有费心将其保存到变量中,因为我们在这里不需要它。

现在,让我们看看是否SaveResultToDict对字典做了一些操作data

import json
print(json.dumps(data, indent=4))
{
    "hi!": {
        "started": true,
        "host1.cmh": {
            "completed": true,
            "result": "hi! my name is host1.cmh"
        },
        "host2.cmh": {
            "completed": true,
            "result": "hi! my name is host2.cmh"
        },
        "spine00.cmh": {
            "completed": true,
            "result": "hi! my name is spine00.cmh"
        },
        "spine01.cmh": {
            "completed": true,
            "result": "hi! my name is spine01.cmh"
        },
        "leaf00.cmh": {
            "completed": true,
            "result": "hi! my name is leaf00.cmh"
        },
        "leaf01.cmh": {
            "completed": true,
            "result": "hi! my name is leaf01.cmh"
        },
        "host1.bma": {
            "completed": true,
            "result": "hi! my name is host1.bma"
        },
        "host2.bma": {
            "completed": true,
            "result": "hi! my name is host2.bma"
        },
        "spine00.bma": {
            "completed": true,
            "result": "hi! my name is spine00.bma"
        },
        "spine01.bma": {
            "completed": true,
            "result": "hi! my name is spine01.bma"
        },
        "leaf00.bma": {
            "completed": true,
            "result": "hi! my name is leaf00.bma"
        },
        "leaf01.bma": {
            "completed": true,
            "result": "hi! my name is leaf01.bma"
        },
        "completed": true
    },
    "bye!": {
        "started": true,
        "host1.cmh": {
            "completed": true,
            "result": "bye! my name is host1.cmh"
        },
        "host2.cmh": {
            "completed": true,
            "result": "bye! my name is host2.cmh"
        },
        "spine00.cmh": {
            "completed": true,
            "result": "bye! my name is spine00.cmh"
        },
        "spine01.cmh": {
            "completed": true,
            "result": "bye! my name is spine01.cmh"
        },
        "leaf00.cmh": {
            "completed": true,
            "result": "bye! my name is leaf00.cmh"
        },
        "leaf01.cmh": {
            "completed": true,
            "result": "bye! my name is leaf01.cmh"
        },
        "host1.bma": {
            "completed": true,
            "result": "bye! my name is host1.bma"
        },
        "host2.bma": {
            "completed": true,
            "result": "bye! my name is host2.bma"
        },
        "spine00.bma": {
            "completed": true,
            "result": "bye! my name is spine00.bma"
        },
        "spine01.bma": {
            "completed": true,
            "result": "bye! my name is spine01.bma"
        },
        "leaf00.bma": {
            "completed": true,
            "result": "bye! my name is leaf00.bma"
        },
        "leaf01.bma": {
            "completed": true,
            "result": "bye! my name is leaf01.bma"
        },
        "completed": true
    }
}

如您所见,多亏了处理器,对结果执行各种操作变得非常容易。您仍然可以得到结果,但是由于有了此插件,您可能不再需要它们。

想法

处理器还可以完成其他哪些操作?

  1. 将事件发送到Slack / IRC / logging_system
  2. 让用户知道发生了什么事,而不必等待所有host的完成(如果您有很多设备,尤其有趣)
  3. 如果给定task失败,则寻呼某人/引发警报
  4. 等等…

觉得文章有用?

点个广告表达一下你的爱意吧 !😁