在 Ansible 操作指南中使用 Python 中的 Junos 快照管理员 (JSNAPy)
将 JSNAPy 测试作为 Ansible 操作指南的一部分执行,以捕获和审核 Junos 设备的运行时环境快照。
Python 中的 Junos® 快照管理员 (JSNAPy) 允许您捕获和审核 Junos 设备的运行时环境快照。您可以捕获并验证设备的配置和运行状态,并验证对设备的更改。瞻博网络提供了一个 Ansible 模块,您可以使用该模块对 Junos 设备执行 JSNAPy 测试,作为 Ansible 操作指南的一部分。 表 1 概述了可用的模块。
|
收藏 |
模块集 |
模块名称 |
|---|---|---|
|
|
您必须在 Ansible 控制节点上安装 Python 中的 Junos 快照管理员,才能使用该 juniper.device.jsnapy 模块。有关创建 JSNAPy 配置和测试文件的安装说明和信息,请参阅 Python 文档中的 Junos 快照管理员。
以下部分讨论如何在 Ansible 剧本中使用该 juniper.device.jsnapy 模块。
模块概述
该 juniper.device.jsnapy 模块允许您从 Ansible 操作指南中执行 JSNAPy 函数,包括:
-
捕获和保存运行时环境快照
-
比较两个快照
-
捕获快照并立即进行评估
该模块需要指定 action 参数和 the config_file 或 test_files 参数。 action 该参数指定要执行的 JSNAPy 操作。 表 2 概述了有效 action 值和等效的 JSNAPy 命令。
|
|
描述 |
等效 JSNAPy 命令 |
|---|---|---|
|
|
根据给定的测试用例比较两个现有快照,或者如果未提供测试用例,则逐个节点比较快照。 |
|
|
|
在给定设备上进行更改后,为测试文件中指定的命令或 RPC 拍摄快照。 |
|
|
|
在给定设备上进行更改之前,请为测试文件中指定的命令或 RPC 拍摄快照。 |
|
|
|
拍摄测试文件中指定的命令或 RPC 的快照,并立即根据测试用例中的预定义标准评估快照。 |
|
在命令行上执行 JSNAPy 时,JSNAPy 会在配置文件部分 hosts 中指定的主机上执行请求的操作。另一方面,Ansible 模块会在 Ansible 操作指南中指定的主机上执行请求的操作。因此,模块可以引用配置文件,忽略该 hosts 部分,也可以直接引用一个或多个测试文件。
因此,除了参数之外 action ,模块 juniper.device.jsnapy 还需要 config_file 参数或 test_files 参数来指定要用于给定操作的 JSNAPy 配置文件或 JSNAPy 测试文件。 表 3 概述了 config_file and test_files 参数。
|
模块参数 |
value |
其他信息 |
|---|---|---|
|
|
JSNAPy 配置文件的绝对或相对文件路径。 |
如果路径是相对路径,则模块将按指示的顺序检查以下位置的配置文件:
如果配置文件使用相对文件路径引用测试文件,则模块首先检查 playbook 目录中的测试文件。然后,它会检查默认 |
|
|
JSNAPy 测试文件的绝对或相对文件路径。此值可以是单个文件路径或文件路径列表。 |
对于指定相对路径的每个测试文件,模块将按指示的顺序检查以下位置中的文件:
|
config_file和test_files参数可以采用绝对或相对文件路径。使用相对文件路径时,可以选择包含 dir module 参数来指定文件所在的目录。如果 or test_files 参数使用相对文件路径,则config_file该模块将首先检查 Ansible playbook 目录中的文件,即使dir该参数存在也是如此。如果该文件在 playbook 目录中不存在,则模块将在参数目录(如果指定了)或 /etc/jsnapy/testfiles 目录(如果省略了dir参数)中dir进行检查。如果找不到文件,操作指南将生成错误消息。
请务必注意,当您包含参数 dir 时,模块仅检查该位置的指定 config_file or test_files 参数。因此,当您指定配置文件时,模块不会检查 dir 您在配置文件中指定的测试文件的目录。如果配置文件引用测试文件的相对路径,则模块仅检查 playbook 目录和默认 testfiles 目录中的测试文件。
假设您有以下 JSNAPy 配置文件 jsnapy_config_base_tests.yaml,它驻留在 ~/jsnapy/testfiles 目录中并引用多个 JSNAPy 测试文件:
user@ansible-cn:~/ansible$ cat ~/jsnapy/testfiles/jsnapy_config_base_tests.yaml tests: - system_util_baseline.yaml - verify_ldp_neighbors.yaml - verify_ospf_neighbors.yaml - verify_bgp_neighbors.yaml - test_interface_operstate.yaml
以下示例 playbook 对 snap_pre jsnapy_config_base_tests.yaml 配置文件中的每个测试文件执行操作。如果配置文件在 playbook 目录中不存在,则模块会检查目录中的 dir 文件,在本例中为 ~/jsnapy/testfiles。配置文件使用测试文件的相对路径。因此,该模块首先检查 playbook 目录中的测试文件,然后检查默认 testfiles 目录中的测试文件。
---
- name: Junos Snapshot Administrator tests
hosts: dc1a
connection: local
gather_facts: no
tasks:
- name: Take a pre-maintenance snapshot
juniper.device.jsnapy:
action: "snap_pre"
dir: "~/jsnapy/testfiles"
config_file: "jsnapy_config_base_tests.yaml"
或者,模块 jsnapy 可以使用该 test_files 参数来指定要使用的单个测试文件。以下 playbook 执行的测试与上一个 playbook 示例中相同的测试。在这种情况下,模块首先检查 playbook 目录中的测试文件,然后检查目录中的 dir 测试文件。
---
- name: Junos Snapshot Administrator tests
hosts: dc1a
connection: local
gather_facts: no
tasks:
- name: Take a pre-maintenance snapshot
juniper.device.jsnapy:
action: "snap_pre"
dir: "~/jsnapy/testfiles"
test_files:
- system_util_baseline.yaml
- verify_ldp_neighbors.yaml
- verify_ospf_neighbors.yaml
- verify_bgp_neighbors.yaml
- test_interface_operstate.yaml
从 Python 1.3.0 版中的 Junos 快照管理员开始,配置和测试文件的默认位置为 ~/jsnapy/testfiles。但是,虚拟环境中或早期版本的默认位置是 /etc/jsnapy/testfiles。
该模块将在 Ansible 操作指南中指定的主机上执行请求的操作,即使该模块引用的配置文件包含某个 hosts 部分也是如此。如果模块遇到错误并且无法执行 JSNAPy 测试,则该模块报告失败。如果一个或多个 JSNAPy 测试失败,则 不会 报告失败。要检查 JSNAPy 测试结果,请注册模块的响应,并使用该 ansible.builtin.assert 模块验证响应中的预期结果。
默认情况下,JSNAPy 将有关其操作的信息记录到 /var/log/jsnapy/jsnapy.log 文件中。该juniper.device.jsnapy模块可以选择包含logfile参数。其值指定 Ansible 控制节点上可写文件的路径。Ansible 的详细程度和调试选项决定了文件中记录的信息级别。默认情况下,仅记录严重性级别为 WARNING 或更高的消息。要记录等于或高于严重性级别 INFO 或严重性级别 DEBUG 的消息,请分别使用 or -vv 命令行选项执行 -v playbook。
在 Ansible 操作指南中执行 JSNAPy 测试时,可以保存或汇总失败的 JSNAPy 测试的信息。有关更多信息,请参阅 查看失败的 JSNAPy 测试。
拍摄和比较快照
JSNAPy 允许您在更改前后捕获 Junos 设备的运行时环境快照,然后比较快照以验证预期的更改或识别意外问题。该 juniper.device.jsnapy 模块允许您拍摄和比较 JSNAPy 快照,作为 Ansible 操作指南的一部分。该模块使用预定的文件名将每个主机的每个快照保存在默认 JSNAPy 快照目录中的单独文件中。有关输出文件的更多信息,请参阅 了解 jsnapy 模块输出。
要在进行更改之前对一个或多个设备进行基线快照:
-
将模块的
action参数snap_pre设置为 。 -
指定一个配置文件或一个或多个测试文件。
以下操作指南为 Ansible 清单组中的每台设备保存 PRE 快照。该任务引用 ~/jsnapy/testfiles 目录中的 jsnapy_config_base_tests.yaml 配置文件,并将消息记录到 playbook 目录中的 jsnapy_tests.log 文件。
---
- name: Junos Snapshot Administrator tests
hosts: dc1
connection: local
gather_facts: no
tasks:
- name: Take a pre-maintenance snapshot
juniper.device.jsnapy:
action: "snap_pre"
dir: "~/jsnapy/testfiles"
config_file: "jsnapy_config_base_tests.yaml"
logfile: "jsnapy_tests.log"
要在执行更改后拍摄一个或多个设备的快照:
-
将模块的
action参数snap_post设置为 。 -
指定一个配置文件或一个或多个测试文件。
以下操作指南为 Ansible 清单组中每台设备保存 POST 快照。该任务引用 ~/jsnapy/testfiles 目录中的相同 jsnapy_config_base_tests.yaml 配置文件,并将消息记录到 playbook 目录中的 jsnapy_tests.log 文件。
---
- name: Junos Snapshot Administrator tests
hosts: dc1
connection: local
gather_facts: no
tasks:
- name: Take a post-maintenance snapshot
juniper.device.jsnapy:
action: "snap_post"
dir: "~/jsnapy/testfiles"
config_file: "jsnapy_config_base_tests.yaml"
logfile: "jsnapy_tests.log"
当模块juniper.device.jsnapy执行操作snap_pre或操作snap_post时,它会使用分别包含“PRE”或“POST”标签的自动生成的文件名将每个主机的每个快照保存在单独的文件中。您可以执行操作check来比较 和PREPOST快照,以快速验证更新或确定更改可能导致的任何问题。
当模块执行操作 check 时,JSNAPy 会比较每个设备上每个测试的 PRE 和 POST 快照,并根据测试文件部分中 tests: 定义的标准对其进行评估。如果测试文件未定义任何测试用例,则 JSNAPy 会逐个节点比较快照。
要比较 PRE 和 POST 快照,请执行以下操作:
-
将模块的
action参数check设置为 。 -
指定用于拍摄快照的相同配置文件或测试文件。
-
通过注册模块的响应并使用模块验证
ansible.builtin.assert响应中的预期结果来检查测试结果。
以下操作指南比较了 Ansible 清单组中为之前执行的设备 snap_pre 拍摄的快照和 snap_post 操作。使用配置文件中引用的测试文件中的标准评估结果。playbook 将模块的响应注册为 'test_result',并使用该 ansible.builtin.assert 模块验证给定设备上的所有测试是否都通过了。
---
- name: Junos Snapshot Administrator tests
hosts: dc1
connection: local
gather_facts: no
tasks:
- name: Compare PRE and POST snapshots
juniper.device.jsnapy:
action: "check"
dir: "~/jsnapy/testfiles"
config_file: "jsnapy_config_base_tests.yaml"
logfile: "jsnapy_tests.log"
register: test_result
- name: Verify JSNAPy tests passed
ansible.builtin.assert:
that:
- "test_result.passPercentage == 100"
运行操作指南时,断言会快速识别出哪些设备未通过测试。
user@host:~$ ansible-playbook jsnapy-baseline-check.yaml
PLAY [Junos Snapshot Administrator tests] *************************************
TASK [Compare PRE and POST snapshots] *****************************************
ok: [dc1a.example.net]
ok: [dc1b.example.net]
TASK [Verify JSNAPy tests passed] *********************************************
ok: [dc1b.example.net] => {
"changed": false,
"msg": "All assertions passed"
}
fatal: [dc1a.example.net]: FAILED! => {
"assertion": "test_result.passPercentage == 100",
"changed": false,
"evaluated_to": false,
"msg": "Assertion failed"
}
to retry, use: --limit @/home/user/jsnapy-baseline-check.retry
PLAY RECAP ********************************************************************
dc1b.example.net : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
dc1a.example.net : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
执行 Snapcheck 操作
JSNAPy 使您能够为 JSNAPy 测试文件中指定的命令或 RPC 拍摄快照,并立即根据测试用例中预定义的标准评估快照。该 juniper.device.jsnapy 模块允许您在 Ansible 操作指南中执行 JSNAPy snapcheck 操作。
要拍摄快照并立即根据测试文件部分中的 tests: 预定义标准集进行评估:
-
将模块的
action参数snapcheck设置为 。 -
指定一个配置文件或一个或多个测试文件。
-
通过注册模块的响应并使用模块验证
ansible.builtin.assert响应中的预期结果来检查测试结果。
例如,对于 Ansible 清单组中的每台设备,以下操作指南会在测试文件中为每个命令或 RPC 保存单独的快照。然后,它注册模块的响应,并使用该模块验证 ansible.builtin.assert 测试文件中定义的所有测试是否在该设备上通过。
---
- name: Junos Snapshot Administrator tests
hosts: dc1
connection: local
gather_facts: no
tasks:
- name: Take a snapshot and immediately evaluate it
juniper.device.jsnapy:
action: "snapcheck"
dir: "~/jsnapy/testfiles/"
test_files:
- "test_interface_status.yaml"
- "test_bgp_neighbor.yaml"
logfile: "jsnapy_tests.log"
register: test_result
- name: Verify JSNAPy tests passed
ansible.builtin.assert:
that:
- "test_result.passPercentage == 100"
了解 jsnapy 模块输出
当模块执行 snap_pre、 snap_post或 snapcheck 操作时juniper.device.jsnapy,它会自动将快照保存在 JSNAPy 快照目录中。该模块使用默认的 JSNAPy 目录,除非您修改 JSNAPy 配置文件 (jsnapy.cfg) 以指定其他位置。该模块会为 Ansible 清单组中每台设备上执行的每个命令或 RPC 创建一个单独的文件。表 4 概述了参数每个action值的快照文件的文件名。
从 Python 1.3.0 版中的 Junos 快照管理员开始,JSNAPy 测试文件和快照的默认目录分别为 ~/jsnapy/testfiles 和 ~/jsnapy/snapshots。但是,虚拟环境中或早期版本的默认目录是 /etc/jsnapy/testfiles 和 /etc/jsnapy/snapshots。
|
|
输出文件 |
|---|---|
|
|
hostname_PRE_hash_command。format |
|
|
hostname_帖子_hash_command。format |
|
|
hostname_snap_temp_hash_command。format |
其中:
-
hostname— 执行命令或 RPC 的设备的主机名。
-
(预览 |发帖 |snap_temp) - 标识操作的标记。在当前版本中,该
snapcheck操作使用PRE该标记;在早期版本中,该操作使用该snap_temp标记。 -
hash- 为包含 和
rpckwargs键的测试文件生成kwargs的散列。如果测试文件使用相同的 RPC 但包含不同的参数,并且 RPC 在同一主机上执行,则哈希确保在这些情况下唯一的输出文件名。如果测试文件定义了密钥,
command或者如果测试文件定义了rpc密钥但不包含kwargs密钥,则省略哈希。 -
command— 在托管设备上执行的命令或 RPC。该模块将命令或RPC名称中的空格和特殊字符替换为下划线( _ )。
-
format- 输出的格式,例如 xml。
该 juniper.device.jsnapy 模块仅根据主机名和命令或 RPC 区分给定操作的快照文件名。因此,如果模块使用定义相同命令或 RPC 的测试文件在同一设备上为同一操作拍摄快照,则模块将生成具有相同文件名的快照,并且新文件将覆盖旧文件。
例如,如果模块包含 action: "snap_pre" 并引用在 dc1a.example.net 和 dc1b.example.net 设备上执行 and show chassis fpc show interfaces terse 命令的测试文件,则生成的文件为:
user@ansible-cn:~$ ls jsnapy/snapshots dc1a.example.net_PRE_show_chassis_fpc.xml dc1a.example.net_PRE_show_interfaces_terse.xml dc1b.example.net_PRE_show_chassis_fpc.xml dc1b.example.net_PRE_show_interfaces_terse.xml
如果模块包含action: "snap_post"并引用了在设备 dc1a.example.net 上执行带有项interface_name: lo0的 kwargs RPC 的测试文件get-interface-information,则生成的文件为:
dc1a.example.net_POST_r1w59I99HXxC3u0VXXshbw==_get_interface_information.xml
除了生成快照文件外,模块还可以 juniper.device.jsnapy 在模块响应中返回以下键:
-
action—模块执行的 JSNAPy 操作。 -
changed— 指示设备的状态是否已更改。由于 JSNAPy 仅报告状态,因此值始终false为 。 -
failed- 指示操作指南任务是否失败。 -
msg—JSNAPy 测试结果。
查看失败的 JSNAPy 测试
对 Junos 设备执行 JSNAPy 测试时,可以快速验证是否所有 JSNAPy 测试都通过。您注册 juniper.device.jsnapy 模块的响应并使用该 ansible.builtin.assert 模块检查 是否 passPercentage 为 100。但是,如果一个或多个测试失败,如果输出很广泛,则可能很难识别和提取失败的测试。
该 juniper.device.jsnapy 模块提供了以下选项来查看失败的 JSNAPy 测试:
-
juniper.device.jsnapy回调插件 — 在剧本输出后打印失败的 JSNAPy 测试摘要。 -
dest_dirmodule argument — 将失败的 JSNAPy 测试写入指定目录中的文件。
jsnapy回调插件使您能够轻松提取和汇总失败的 JSNAPy 测试的信息。当您启用jsnapy回调插件并执行包含 JSNAPy 测试的 playbook 时,该插件会在 playbook PLAY RECAP之后汇总失败的 JSNAPy 测试的信息。
默认情况下, jsnapy 回调插件处于禁用状态。要启用回调插件, jsnapy 请将语 callbacks_enabled = juniper.device.jsnapy 句添加到 Ansible 配置文件中。
[defaults] callbacks_enabled = juniper.device.jsnapy
当您启用 jsnapy 回调插件并运行 playbook 时,该插件会以人类可读的格式汇总失败的 JSNAPy 测试。例如:
...
PLAY RECAP ****************************************************************
qfx10002-01 : ok=3 changed=0 unreachable=0 failed=1
qfx10002-02 : ok=3 changed=0 unreachable=0 failed=1
qfx5100-01 : ok=1 changed=0 unreachable=0 failed=1
JSNAPy Results for: qfx10002-01 *******************************************
Value of 'peer-state' not 'is-equal' at '//bgp-information/bgp-peer' with {"peer-as": "64502", "peer-state": "Active", "peer-address": "198.51.100.21"}
Value of 'peer-state' not 'is-equal' at '//bgp-information/bgp-peer' with {"peer-as": "64510", "peer-state": "Idle", "peer-address": "192.168.0.1"}
Value of 'oper-status' not 'is-equal' at '//interface-information/physical-interface[normalize-space(admin-status)='up' and logical-interface/address-family/address-family-name ]' with {"oper-status": "down", "name": "et-0/0/18"}
JSNAPy Results for: qfx10002-02 *******************************************
Value of 'peer-state' not 'is-equal' at '//bgp-information/bgp-peer' with {"peer-as": "64502", "peer-state": "Active", "peer-address": "198.51.100.21"}
从 1.0.6 版开始juniper.device,该juniper.device.jsnapy模块还支持参数dest_dir。您可以包含dest_dir参数 for 和checksnapcheck操作,这些操作根据测试标准评估快照。当您执行 check or snapcheck 操作并包含dest_dir参数时,模块会将给定主机的每个失败的 JSNAPy 测试写入指定输出目录中的文件。
例如,请考虑以下剧本:
---
- name: Verify BGP
hosts: bgp_routers
connection: local
gather_facts: no
tasks:
- name: Execute snapcheck
juniper.device.jsnapy:
action: "snapcheck"
dir: "~/jsnapy/testfiles"
test_files:
- "jsnapy_test_file_bgp_states.yaml"
- "jsnapy_test_file_bgp_summary.yaml"
logfile: "{{ logfile }}"
dest_dir: "{{ playbook_dir }}/jsnapy_failed_tests"
register: snapcheck_result
执行 playbook 时,模块会在目录中 dest_dir 为给定主机上的每个失败测试生成一个文件。例如,模块为主机 r1 和 r3 上的失败 bgp_neighbor 和 bgp_summary 测试生成了以下文件。
user@ansible-cn:~/ansible$ ls jsnapy_failed_tests r1_bgp_neighbor_False.text r3_bgp_neighbor_False.text r1_bgp_summary_False.text r3_bgp_summary_False.text
示例:使用 Ansible 执行 JSNAPy Snapcheck 操作
该 juniper.device.jsnapy 模块允许您对 Junos 设备执行 JSNAPy 测试,作为 Ansible 操作指南的一部分。此示例使用模块 jsnapy 执行操作 snapcheck ,以在应用特定配置更改后验证 Junos 设备的运行状态。
要求
此示例使用以下硬件和软件组件:
-
Ansible 控制节点正在运行:
-
Python 3.10 或更高版本
-
Ansible 2.17 或更高版本,
juniper.device已安装集合 -
Junos PyEZ 2.7.3 或更高版本
-
Python 1.3.7 或更高版本中的 Junos 快照管理员
-
在执行 Ansible 操作指南之前,请确保您具备以下条件:
-
启用了 NETCONF over SSH 且用户帐户配置了相应权限的 Junos 设备
-
在 Ansible 控制节点和 Junos 设备上为相应用户配置的 SSH 公钥/私钥对
-
定义了所需主机的现有 Ansible 清单文件
概述
在此示例中,Ansible 操作指南在三台 Junos 设备上配置 BGP 对等会话,并使用该jsnapy模块验证是否为每个邻接方地址建立了 BGP 会话。如果操作指南验证会话是否已在设备上建立,则会确认新配置的提交。如果操作指南未确认提交,Junos 设备会自动回滚到之前提交的配置。Ansible 项目分别在 和 host_vars 目录下group_vars定义操作指南的组变量和主变量。
剧本有两部剧本。第一次执行 Load and commit BGP configuration将生成并组装配置,在设备上加载配置,然后使用提交确认操作进行提交。如果配置已更新,则会通知一个处理程序。该剧执行以下任务:
Remove build directory |
删除给定设备的现有构建目录(如果存在)。 |
Create build directory |
为给定设备创建一个新的空构建目录。 |
Build BGP configuration |
将模块与 Jinja2 模板和主机变量一起使用 |
Assemble configuration parts |
使用该 在此示例中,仅存在 BGP 配置文件,因此生成的配置文件与上一个任务中呈现的 BGP 配置文件相同。如果稍后添加新任务以从其他模板生成其他配置文件, |
Load and commit config, require confirmation |
将配置加载到 Junos 设备上,并使用操作 如果设备上已存在请求的配置, |
第二个播放 Verify BGP,使用 JSNAPy 测试文件中的测试在每个设备上执行 JSNAPy snapcheck 操作。如果所有测试都通过,则该剧还会确认提交。该剧执行以下任务:
Execute snapcheck |
执行 JSNAPy 在此示例中,playbook 通过将参数设置为 |
Confirm commit |
执行提交检查操作,该操作将确认上一个提交操作,前提是第一个 playbook 播放更新了配置并且所有 JSNAPy 测试都通过了。如果操作指南更新了配置,但未确认提交,Junos 设备会自动将配置回滚到之前提交的配置。
注意:
您可以使用设备上的 a |
Verify BGP configuration |
(选答)显式指示给定设备上的 JSNAPy 测试是通过还是失败。此任务不是特别必需的,但它更容易识别 JSNAPy 测试何时失败以及在哪些设备上失败。 |
配置
定义组变量
分步程序
要定义组变量,请执行以下操作:
-
在 group_vars/all 文件中,为构建目录以及配置和日志文件的文件名定义变量。
build_dir: "{{ playbook_dir }}/build_conf/{{ inventory_hostname }}" junos_conf: "{{ build_dir }}/junos.conf" logfile: "junos.log"
定义 Jinja2 模板和主机变量
定义 Jinja2 模板
要创建用于生成 BGP 配置的 Jinja2 模板,请执行以下操作:
-
在项目的 playbook 目录中创建一个名为 bgp-template.j2 的文件。
-
将 BGP 配置模板添加到文件中。
interfaces { {% for neighbor in neighbors %} {{ neighbor.interface }} { unit 0 { description "{{ neighbor.name }}"; family inet { address {{ neighbor.local_ip }}/30; } } } {% endfor %} lo0 { unit 0 { family inet { address {{ loopback }}/32; } } } } protocols { bgp { group underlay { import bgp-in; export bgp-out; type external; local-as {{ local_asn }}; multipath multiple-as; {% for neighbor in neighbors %} neighbor {{ neighbor.peer_ip }} { peer-as {{ neighbor.asn }}; } {% endfor %} } } lldp { {% for neighbor in neighbors %} interface "{{ neighbor.interface }}"; {% endfor %} } } routing-options { router-id {{ loopback }}; forwarding-table { export bgp-ecmp; } } policy-options { policy-statement bgp-ecmp { then { load-balance per-packet; } } policy-statement bgp-in { then accept; } policy-statement bgp-out { then { next-hop self; accept; } } }
定义主机变量
要定义与 Jinja2 模板一起使用以生成 BGP 配置的主机变量,请执行以下操作:
-
在项目的 host_vars 目录中,为每个主机创建一个名为 hostname.yaml 的单独文件。
-
在 r1.yaml 文件中定义主机 r1 的变量。
--- loopback: 192.168.0.1 local_asn: 64521 neighbors: - interface: ge-0/0/0 name: to-r2 asn: 64522 peer_ip: 198.51.100.2 local_ip: 198.51.100.1 peer_loopback: 192.168.0.2 - interface: ge-0/0/1 name: to-r3 asn: 64523 peer_ip: 198.51.100.6 local_ip: 198.51.100.5 peer_loopback: 192.168.0.3 -
在 r2.yaml 文件中定义主机 r2 的变量。
--- loopback: 192.168.0.2 local_asn: 64522 neighbors: - interface: ge-0/0/0 name: to-r1 asn: 64521 peer_ip: 198.51.100.1 local_ip: 198.51.100.2 peer_loopback: 192.168.0.1 - interface: ge-0/0/1 name: to-r3 asn: 64523 peer_ip: 198.51.100.10 local_ip: 198.51.100.9 peer_loopback: 192.168.0.3 -
在 r3.yaml 文件中定义主机 r3 的变量。
--- loopback: 192.168.0.3 local_asn: 64523 neighbors: - interface: ge-0/0/0 name: to-r1 asn: 64521 peer_ip: 198.51.100.5 local_ip: 198.51.100.6 peer_loopback: 192.168.0.1 - interface: ge-0/0/1 name: to-r2 asn: 64522 peer_ip: 198.51.100.9 local_ip: 198.51.100.10 peer_loopback: 192.168.0.2
创建 JSNAPy 测试文件
分步程序
该 jsnapy 模块引用 ~/jsnapy/testfiles 目录中的 JSNAPy 测试文件。要创建 JSNAPy 测试文件:
-
创建 jsnapy_test_file_bgp_states.yaml 文件,该文件执行
show bgp neighbor命令并测试BGP 对等体状态是否已建立。bgp_neighbor: - command: show bgp neighbor - ignore-null: true - iterate: xpath: '//bgp-peer' id: './peer-address' tests: # Check if peers are in the established state - is-equal: peer-state, Established err: "Test Failed!! peer <{{post['peer-address']}}> state is not Established, it is <{{post['peer-states']}}>" info: "Test succeeded!! peer <{{post['peer-address']}}> state is <{{post['peer-state']}}>" -
创建 jsnapy_test_file_bgp_summary.yaml 文件,该文件执行
show bgp summary命令并断言BGP关闭对等方计数必须为 0。bgp_summary: - command: show bgp summary - item: xpath: '/bgp-information' tests: - is-equal: down-peer-count, 0 err: "Test Failed!! down-peer-count is not equal to 0. It is equal to <{{post['down-peer-count']}}>" info: "Test succeeded!! down-peer-count is equal to <{{post['down-peer-count']}}>"
创建 Ansible 剧本
定义配置设备的第一步
要创建第一个 play,该 play 将呈现配置,将其加载到设备上,并将配置作为提交确认操作提交:
-
包括 playbook 的样板和在本地执行模块的第一个 play。
--- - name: Load and commit BGP configuration hosts: bgp_routers connection: local gather_facts: no
-
创建将现有构建目录替换为空目录的任务,该目录将存储新的配置文件。
tasks: - name: Remove build directory file: path: "{{ build_dir }}" state: absent - name: Create build directory file: path: "{{ build_dir }}" state: directory -
创建从 Jinja2 模板文件和主机变量呈现 BGP 配置的任务,并将其存储在该主机的构建目录中的 bgp.conf 文件中。
- name: Build BGP configuration template: src: "{{ playbook_dir }}/bgp-template.j2" dest: "{{ build_dir }}/bgp.conf" -
创建一个任务,将构建目录中的配置文件组装成最终的 junos.conf 配置文件。
- name: Assemble configuration parts assemble: src: "{{ build_dir }}" dest: "{{ junos_conf }}" -
创建在设备上加载配置的任务,执行需要确认的提交操作,并通知给定的处理程序(如果配置已更改)。
- name: Load and commit config, require confirmation juniper.device.config: load: "merge" format: "text" src: "{{ junos_conf }}" confirm: 5 comment: "config by Ansible" logfile: "{{ logfile }}" register: config_result # Notify handler, only if configuration changes. notify: - Waiting for BGP peers to establish connections -
创建一个处理程序,用于在设备配置更新时暂停 playbook 执行。将暂停时间设置为适合您的环境的值。
handlers: - name: Waiting for BGP peers to establish connections pause: seconds=60
定义执行 JSNAPy 操作的第二个 play
要创建第二个 play,执行 JSNAPy snapcheck 操作并确认提交的配置,前提是配置已更改且 JSNAPy 测试已通过:
-
包括第二次播放的样板,它在本地执行模块。
- name: Verify BGP hosts: bgp_routers connection: local gather_facts: no
-
创建一个任务,根据给定的 JSNAPy 测试文件中的测试执行 JSNAPy snapcheck 操作,并注册模块的响应。
tasks: - name: Execute snapcheck juniper.device.jsnapy: action: "snapcheck" dir: "~/jsnapy/testfiles" test_files: - "jsnapy_test_file_bgp_states.yaml" - "jsnapy_test_file_bgp_summary.yaml" logfile: "{{ logfile }}" register: snapcheck_result -
创建任务以确认提交,前提是满足给定条件。
# Confirm commit only if configuration changed and JSNAPy tests pass - name: Confirm commit juniper.device.config: check: true commit: false diff: false logfile: "{{ logfile }}" when: - config_result.changed - "snapcheck_result.passPercentage == 100" -
(选答)创建一个任务,该任务使用该
ansible.builtin.assert模块来断言 JSNAPy 测试已通过。- name: Verify BGP configuration ansible.builtin.assert: that: - "snapcheck_result.passPercentage == 100" msg: "JSNAPy test on {{ inventory_hostname }} failed"
结果
在 Ansible 控制节点上,查看完成的操作指南。如果 playbook 未显示预期代码,请重复本部分中的说明以更正 playbook。
---
- name: Load and commit BGP configuration
hosts: bgp_routers
connection: local
gather_facts: no
tasks:
- name: Remove build directory
file:
path: "{{ build_dir }}"
state: absent
- name: Create build directory
file:
path: "{{ build_dir }}"
state: directory
- name: Build BGP configuration
template:
src: "{{ playbook_dir }}/bgp-template.j2"
dest: "{{ build_dir }}/bgp.conf"
- name: Assemble configuration parts
assemble:
src: "{{ build_dir }}"
dest: "{{ junos_conf }}"
- name: Load and commit config, require confirmation
juniper.device.config:
load: "merge"
format: "text"
src: "{{ junos_conf }}"
confirm: 5
comment: "config by Ansible"
logfile: "{{ logfile }}"
register: config_result
# Notify handler, only if configuration changes.
notify:
- Waiting for BGP peers to establish connections
handlers:
- name: Waiting for BGP peers to establish connections
pause: seconds=60
- name: Verify BGP
hosts: bgp_routers
connection: local
gather_facts: no
tasks:
- name: Execute snapcheck
juniper.device.jsnapy:
action: "snapcheck"
dir: "~/jsnapy/testfiles"
test_files:
- "jsnapy_test_file_bgp_states.yaml"
- "jsnapy_test_file_bgp_summary.yaml"
logfile: "{{ logfile }}"
register: snapcheck_result
# Confirm commit only if configuration changed and JSNAPy tests pass
- name: Confirm commit
juniper.device.config:
check: true
commit: false
diff: false
logfile: "{{ logfile }}"
when:
- config_result.changed
- "snapcheck_result.passPercentage == 100"
- name: Verify BGP configuration
ansible.builtin.assert:
that:
- "snapcheck_result.passPercentage == 100"
msg: "JSNAPy test on {{ inventory_hostname }} failed"
执行剧本
要执行该剧本,请执行以下步骤:
-
在控制节点上发出
ansible-playbook命令,并提供 playbook 路径和任何所需的选项。user@ansible-cn:~/ansible$ ansible-playbook ansible-pb-bgp-configuration.yaml PLAY [Load and commit BGP configuration] ************************************* TASK [Remove build directory] ************************************************ changed: [r1] changed: [r2] changed: [r3] TASK [Create build directory] ************************************************ changed: [r1] changed: [r2] changed: [r3] TASK [Build BGP configuration] *********************************************** changed: [r2] changed: [r1] changed: [r3] TASK [Assemble configuration parts] ****************************************** changed: [r3] changed: [r2] changed: [r1] TASK [Load and commit config, require confirmation] ************************** changed: [r2] changed: [r1] changed: [r3] RUNNING HANDLER [Waiting for BGP peers to establish connections] ************* Pausing for 60 seconds (ctrl+C then 'C' = continue early, ctrl+C then 'A' = abort) ok: [r3]
PLAY [Verify BGP] ************************************************************ TASK [Execute snapcheck] ***************************************************** ok: [r2] ok: [r1] ok: [r3] TASK [Confirm commit] ******************************************************** ok: [r2] ok: [r1] ok: [r3] TASK [Verify BGP configuration] ********************************************** ok: [r1] => { "changed": false, "msg": "All assertions passed" } ok: [r2] => { "changed": false, "msg": "All assertions passed" } ok: [r3] => { "changed": false, "msg": "All assertions passed" } PLAY RECAP ******************************************************************* r1 : ok=8 changed=5 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 r2 : ok=8 changed=5 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 r3 : ok=9 changed=5 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
验证
验证 BGP 邻接方
目的
验证是否为每个邻接方地址建立了 BGP 会话。
JSNAPy 测试文件测试是否为每个邻居地址建立了 BGP 会话,并且没有关闭对等方。 Verify BGP configuration 任务输出使您能够快速验证给定设备是否通过了所有 JSNAPy 测试。如果 JSNAPy passPercentage 等于 100%,则任务包含在 "msg": "All assertions passed" 任务输出中。
行动
查看 Verify BGP configuration 任务输出,并验证每个设备是否返回消息 All assertions passed 。
TASK [Verify BGP configuration] **********************************************
ok: [r1] => {
"changed": false,
"msg": "All assertions passed"
}
ok: [r2] => {
"changed": false,
"msg": "All assertions passed"
}
ok: [r3] => {
"changed": false,
"msg": "All assertions passed"
}
意义
该 All assertions passed 消息指示设备已成功建立 BGP 会话。
Ansible Playbook 故障排除错误
配置加载错误故障排除
问题
Ansible 操作指南会生成一个 ConfigLoadError 错误,指示由于语法错误,它无法在设备上加载配置。
fatal: [r1]: FAILED! => {"changed": false, "msg": "Failure loading the configuraton: ConfigLoadError(severity: error, bad_element: protocol, message: error: syntax error\nerror: error recovery ignores input until this point)"}
解决方案
该操作指南使用 Jinja2 模板和 host_vars 目录中为该设备定义的主机变量来呈现 Junos OS 配置。当 Jinja2 模板生成无效的配置时,playbook 会生成语法错误。要更正此错误,请更新 Jinja2 模板以更正错误消息中由 bad_element 键标识的元素。
排除失败的 JSNAPy 测试
问题
Verify BGP configuration任务输出指示断言失败,因为 JSNAPy passPercentage 不等于 100%。
TASK [Verify BGP configuration] *************************************************************
fatal: [r1]: FAILED! => {
"assertion": "snapcheck_result.passPercentage == 100",
"changed": false,
"evaluated_to": false,
"msg": "JSNAPy test on r1 failed"
}
当设备尚未与其邻接方建立 BGP 会话或会话关闭时,断言将失败。如果断言失败,并且该设备的配置在第一次播放中已更新,则操作指南不会确认设备上新配置的提交,并且设备会将配置回滚到之前提交的配置。
解决方案
如果在对等方建立会话之前执行了操作 snapcheck ,或者由于 BGP 邻接方配置不正确,JSNAPy 测试可能会失败。如果 playbook 输出指示配置已成功加载并提交到设备上,请尝试将处理程序的暂停间隔增加到适合您的环境的值,然后重新运行 playbook。
handlers:
- name: Waiting for BGP peers to establish connections
pause: seconds=75
如果测试仍然失败,请验证每个设备的 Jinja2 模板和主机变量是否包含正确的数据,以及每个设备的结果配置是否正确。
确认提交失败故障排除
问题
未在一台或多台设备上确认配置。
TASK [Confirm commit] *********************************************************************** skipping: [r2] skipping: [r2] skipping: [r3]
解决方案
只有当配置已更改且 JSNAPy 测试通过时,操作指南才会确认配置。如果任务输出指示Load and commit config, require confirmation配置未更改,则操作指南不会执行任务以确认提交。如果配置已更改但未确认,则 JSNAPy 测试失败。如果 BGP 邻接方配置不正确,或者操作指南未在播放之间提供足够的时间来让设备建立 BGP 会话,则 JSNAPy 测试可能会失败。有关更多信息,请参阅排除失败的 JSNAPy 测试。