时域分析python需要什么包(网工Python之路Nornir3)
时域分析python需要什么包(网工Python之路Nornir3)router bgp 65100 neighbor 192.168.2.12 remote-as 65200 network 1.1.1.1 255.255.255.255 network 11.11.11.11 255.255.255.255SW2的BGP配置命令:SW1的BGP配置命令:作为华语圈第一位系统编写Nornir3.0.0手把手教程的我决定将这个系列写下去,在计算机网络运维自动化这个小众的领域里继续尽自己的一份绵薄之力。今天就来聊下我昨晚刚刚实验成功的Nornir3.0.0 Jinja2的使用方法。本文承接《弈心:网络工程师的Python之路 -- Nornir3.0.0》的内容,还是老规矩:一台CentOS 8主机(192.168.2.1)上跑Nornir,下面连上5台试验用的虚拟三层思科交换机IP从192.168.2.11到192.168.2.15。使用Nornir3
版权声明:我已加入“维权骑士”的版权保护计划,知乎专栏“网路行者”下的所有文章均为我本人(知乎ID:弈心)原创,未经允许不得转载。
如果你喜欢我的文章,请关注我的知乎专栏“网路行者”里面有更多像本文一样深度讲解计算机网络技术的优质文章。
开篇前的话
上一篇我发布的Nornir3.0.0的保姆式手把手入门教程《弈心:网络工程师的Python之路 -- Nornir3.0.0》的反响很不错,很多读者做完教程里的7个实验后反馈希望学习更多的Nornir的进阶知识。
Nornir3.0.0自从2020年9月16号发布以来,由于其大刀阔斧的改动,加上官方文档质量实在不敢恭维,目前包括国外的NetDevOps英文圈子里都还没有任何人发布Nornir3.0.0的系列教程(至于其他诸如俄语、日语等小语种圈子里的情况就不得而知了,我猜大概率是没有的),在Google上能找到的英文教程99%是基于Nornir1和Nornir2的(剩下的1%都只讲了3.0.0的皮毛,没有系列教程),这两代和Nornir3完全是天壤之别,用1和2的教程来学3是一件极其痛苦的事(大致相当于给你一本Windows95或Windows98的教材让你去自学Windows 10的体验)。
作为华语圈第一位系统编写Nornir3.0.0手把手教程的我决定将这个系列写下去,在计算机网络运维自动化这个小众的领域里继续尽自己的一份绵薄之力。今天就来聊下我昨晚刚刚实验成功的Nornir3.0.0 Jinja2的使用方法。
实验平台:
本文承接《弈心:网络工程师的Python之路 -- Nornir3.0.0》的内容,还是老规矩:一台CentOS 8主机(192.168.2.1)上跑Nornir,下面连上5台试验用的虚拟三层思科交换机IP从192.168.2.11到192.168.2.15。
实验目的:使用Nornir3.0.0配合Jinja2的配置模板给SW1(192.168.2.11)和 SW2 (192.168.2.12)配置BGP,让它们建立eBGP邻居关系,并各自宣告自己Loopback0 (SW1: 1.1.1.1 SW2: 2.2.2.2)以及Loopback1 (SW1: 11.11.11.11 SW2: 22.22.22.22)的IP地址。SW1和SW2上的BGP配置命令分别如下:
SW1的BGP配置命令:
router bgp 65100
neighbor 192.168.2.12 remote-as 65200
network 1.1.1.1 255.255.255.255
network 11.11.11.11 255.255.255.255
SW2的BGP配置命令:
router bgp 65200
neighbor 192.168.2.11 remote-as 65100
network 2.2.2.2 255.255.255.255
network 22.22.22.22 255.255.255.255
实验开始前验证SW1现有配置:
实验开始前验证SW2现有配置:
实验准备:
考虑到还有一些读者还没有来得及做入门篇《弈心:网络工程师的Python之路 -- Nornir3.0.0》里的7个实验,本文我将再次手把手带着大家做一次实验准备,从下一篇Nornir3.0.0的文章开始将不再赘述Nornir的基础配置。
首先请务必确保你的Python版本为3.6以上,然后开一个Venv虚拟环境来安装下面的Python模块以及Nornir3.0.0的插件,缺一不可! 其中pip3 install nornir_jinja2安装的即是本文将要用到的Jinja2插件。
pip3 install netmiko
pip3 install napalm
pip3 install nornir
pip3 install nornir_utils
pip3 install nornir_napalm
pip3 install nornir_netmiko
pip3 install nornir_jinja2
安装好上面的模块和插件后,请务必用pip freeze | grep nornir来确认你安装的是3.0.0版的Nornir,否则本文后面所有的内容都是鸡同鸭讲。
安装好必备的模块和插件后,接下来创建按照前文里讲到的创建下面四个YAML文件,分别为config.yaml defaults.yaml groups.yaml hosts.yaml 关于它们的作用请参考前文。
请务必记住这四个YAML文件是Nornir开局最核心的Inventory的组成部分(虽然groups.yaml是可选项,并且也可以将这些YAML文件以Python代码的形式直接写进runbook脚本里,但是为了减少大家的学习成本,这部分我将略过不做讲解,学有余力的可以自行去延伸阅读Nornir的官方文档),后续的Nornir文章中我将不再赘述这一部分。
config.yaml
---
inventory:
plugin: SimpleInventory
options:
host_file: "hosts.yaml"
group_file: "groups.yaml"
defaults_file: "defaults.yaml"
runner:
plugin: threaded
options:
num_workers: 100
defaults.yaml
---
username: python
password: '123'
groups.yaml
---
cisco:
platform: ios
hosts.yaml
---
sw1:
hostname: 192.168.2.11
username: python
password: '123'
platform: ios
groups:
- cisco_group1
data:
building: '1'
level: '1'
sw2:
hostname: 192.168.2.12
platform: ios
groups:
- cisco_group1
data:
building: '1'
level: '2'
sw3:
hostname: 192.168.2.13
platform: ios
groups:
- cisco_group2
data:
builiding: '2'
level: '1'
sw4:
hostname: 192.168.2.14
platform: ios
groups:
- cisco_group2
data:
building: '2'
level: '2'
最后再检查一遍,看是否config.yaml defaults.yaml groups.yaml hosts.yaml四个YAML文件都已准备就绪。
实验8:使用Nornir3.0.0 Jinja2通过配置模板给设备做配置本文承接入门篇里的7个实验,因此本文的实验序号为实验8(强烈建议读者先做完入门篇的7个试验后再来做本文的实验8)。首先创建一个名为nornir8.py的runbook脚本文件,将下列代码写入进去:
from nornir import InitNornir
from nornir_utils.plugins.tasks.data import load_yaml
from nornir_jinja2.plugins.tasks import template_file
from nornir_utils.plugins.functions import print_result
from nornir.core.filter import F
from nornir_netmiko import netmiko_send_command netmiko_send_config
def load_data(task):
data = task.run(task=load_yaml file=f'{task.host}.yaml')
task.host["asn"] = data.result["asn"]
task.host["neighbor"] = data.result["neighbor"]
task.host["remoteas"] = data.result["remote-as"]
task.host["networks"] = data.result["networks"]
rendering = task.run(task=template_file template="BGP.j2" path="")
task.run(task=netmiko_send_config config_commands=rendering.result.split('\n'))
nr = InitNornir(config_file="config.yaml")
group1 = nr.filter(F(groups__contains="cisco_group1"))
r = group1.run(task=load_data)
print_result(r)
在讲解代码之前,我们还需要创建Jinja2的渲染文件和配置模板文件:
首先创建两个yaml文件,分别取名为sw1.yaml和sw2.yaml,它们的作用是用来渲染(rendering)Jinja2的模板配置文件,如果你对Jinja2不熟的话,可以去读我之前的一篇文章《网络工程师的Python之路——浅谈CSV和Jinja2》,sw1和sw2的内容如下:
sw1.yaml
asn: 65100
neighbor: 192.168.2.12
remote-as: 65200
networks:
- net: 1.1.1.1
mask: 255.255.255.255
- net: 11.11.11.11
mask: 255.255.255.255
sw2.yaml
asn: 65200
neighbor: 192.168.2.11
remote-as: 65100
networks:
- net: 2.2.2.2
mask: 255.255.255.255
- net: 22.22.22.22
mask: 255.255.255.255
然后创建Jinja2的配置模板文件,因为这个实验我们将要为SW1和SW2配置BGP,因此我们将该配置模板文件取名为BGP.j2,其内容如下:
router bgp {{ host.asn }}
neighbor {{ host.neighbor }} remote-as {{ host.remoteas }}
{% for n in host.networks %}
network {{ n.net }} mask {{ n.mask }}
{% endfor %}
是不是感觉有点乱?别急,我们来捋一下。目前为止我们总共创建了8个文件,其中有6个YAML文件,一个py文件,一个j2文件,如下:
在确认你没有任何遗漏之后,接下来我们来讲解Nornir的runbook脚本(也就是nornir8.py)的内容(前文7个实验里已经涉及并讲解过的知识点将略过不讲):
实验8代码讲解:- 为了读取Jinja2渲染文件(sw1.yaml sw2.yaml)里的内容,我们需要调用nornir_utils里的load_yaml这个插件:
from nornir_utils.plugins.tasks.data import load_yaml
- 为了调用Jinja2模板文件(BGP.j2)来做配置渲染,我们需要调用nornir_jinja2里的template_file这个插件:
from nornir_jinja2.plugins.tasks import template_file
- 接下来定义一个load_data(task)函数来执行任务,首先我们调用插件load_yaml来读取sw1.yaml和sw2.yaml里的内容,并将它赋值给data这个变量。注意这里的file=f'{task.host}.yaml',{task.host}的作用是读取hosts.yaml里的4台交换机的设备名(sw1 sw2 sw3 sw4),配合后面的.yaml即为读取sw1.yaml sw2.yaml sw3.yaml sw4.yaml四个文件,其中sw1.yaml和sw2.yaml两个Jinja2的渲染文件我们已经有了,不存在的sw3.yaml和sw4.yaml等下我们会通过高级过滤将其过滤掉。
def load_data(task):
data = task.run(task=load_yaml file=f'{task.host}.yaml')
这里再来回顾一下sw1.yaml和sw2.yaml里面的内容:
sw1.yaml
sw2.yaml
- 接下来我们通过data.result["asn"] data.result["neighbor"] data.result["remote-as"] data.result["networks"]来分别读取sw1.yaml和sw2.yaml里的asn neighbor remote-as networks的内容,然后将得到的赋值依次赋值给task.host["asn"], task.host["neighbor"] task.host["remoteas"] task.host["networks"],以便等下留给BGP.j2这个模板配置文件来做渲染。注意:BGP.j2不是直接去读取sw1.yaml,sw2.yaml里的内容来做渲染,而是需要我们首先通过load_yaml插件将sw1.yaml和sw2.yaml里的内容先读取出来并赋值给task.host后,再来调用template_file这个插件做配置渲染。另外这里你肯定也会问为什么task.host["remoteas"]不写成task.host["remote-as"],这是因为"-"这个符号在j2文件里有另外的含义,如果写成task.host["remote-as"]的话,等下我们用template_file做配置渲染的时候,Jinja只会去读"remote"这个部分,不会去读后面的"-as",导致Python因找不到相应的键名而报错。
task.host["asn"] = data.result["asn"]
task.host["neighbor"] = data.result["neighbor"]
task.host["remoteas"] = data.result["remote-as"]
task.host["networks"] = data.result["networks"]
- 接下来我们启动另外一个任务来调用template_file插件做渲染(task=template_file)并将结果赋值给rendering这个变量。这里的template参数即为我们的BGP.j2配置模板文件(template="BGP.j2")。因为BGP.j2和我们的nornir8.py处于同一个文件夹下,因此这里的path参数设为空(path=""),
rendering = task.run(task=template_file template="BGP.j2" path="")
- 注意使用template_file插件配合BGP.j2做配置渲染后,其返回的值为字符串(也就是说下一行代码中的rendering.result的数据类型为字符串),该字符串里的内容就是我们最终要配置给SW1和SW2的BGP命令,也就是"router bgp 65100\nneighbor 192.168.2.12 remote-as 65200\nnetwork 1.1.1.1 mask 255.255.255.255\nnetwork 11.11.11.11 mask 255.255.255.255"和"router bgp 65200\nneighbor 192.168.2.11 remote-as 65100\nnetwork 2.2.2.2 mask 255.255.255.255\nnetwork 22.22.22.22 mask 255.255.255.255"
- 最后我们调用前面实验6讲到的netmiko_send_config插件,配合config_commands这个参数(该参数要求数据类型必须为列表,因此这里我们要对rendering.result调用split()参数,将其转化为列表)来将渲染好的BGP配置命令配置给SW1和SW2。
task.run(task=netmiko_send_config config_commands=rendering.result.split('\n'))
- 剩下的代码中都是入门篇7个实验里反复提到的内容,这里只讲一下我们前面提到了data = task.run(task=load_yaml file=f'{task.host}.yaml')中的file=f'{task.host}.yaml'会去读取hosts.yaml里的4台交换机的设备名(sw1 sw2 sw3 sw4),配合后面的.yaml读取sw1.yaml sw2.yaml sw3.yaml sw4.yaml四个文件,因为这里我们不存在sw3.yaml和sw4.yaml两个渲染文件,因此我们使用实验3里讲过的F()做高级过滤(group1 = nr.filter(F(groups__contains="cisco_group1")),过滤出cisco_group1分组里的成员,也就是sw1.yaml和sw2.yaml(sw3和sw4属于cisco_group2)。
nr = InitNornir(config_file="config.yaml")
group1 = nr.filter(F(groups__contains="cisco_group1"))
r = group1.run(task=load_data)
print_result(r)
运行脚本看效果并登录SW1和SW2做验证:
下一篇内容也就是实验9我将讲解Nornir3.0.0 Scrapli的用法,敬请期待。
一切准备妥当后,下面正式进入实验环节。