使用Ansible的网络自动化:命令模块

说到网络自动化的典型场景,没有一组命令模块就无法做到。 由于有了这些模块,Ansible允许您在网络设备上运行命令,就像直接从控制台输入命令一样。 同时,命令的输出不仅会滑入终端窗口而被遗忘,而且将来可以保存和使用。 可以将其写入变量,可以对其进行解析以用于后续任务,也可以将其保存以供将来保存在宿主变量中。



这篇文章的目的是表明任何重复性的网络管理任务都可以自动化,并且Ansible不仅可以让您管理配置,而且还可以摆脱日常工作并节省时间。

让我们分析使用网络命令模块的基本方法,包括使用register参数保存命令输出。 我们还将考虑如何使用hostvars扩展到多个网络设备,以及如何使用wait_for参数和其他三个相关参数来组织条件执行:interval,retries和match。

不同的网络平台都有自己的命令模块,在Red Hat Ansible Engine Networking附件扩展级别上都支持所有命令模块:

网络平台模块* os_command
Arista Eoseos_command
思科IOS / IOS-XEios_command
思科IOS-XRiosxr_command
思科NX-OSnxos_command
杜松朱诺斯junos_command
维约斯vyos_command

命令模块基础


考虑一个使用eos_command模块仅运行show version命令的剧本:

--- - name: COMMAND MODULE PLAYBOOK hosts: eos connection: network_cli tasks: - name: EXECUTE ARISTA EOS COMMAND eos_command: commands: show version register: output - name: PRINT OUT THE OUTPUT VARIABLE debug: var: output 

这里我们有两个任务,第一个使用带有单个命令参数的eos_command模块。 由于我们只运行一个命令-show version-它可以在命令参数本身的同一行上指定。 如果有两个或两个以上的团队,则必须将每个团队放在命令:之后。 在此示例中,我们使用register关键字保存show version命令的输出。 register参数(可以在任何Ansible任务中使用)设置用于保存任务输出的变量,以便以后使用。 在我们的示例中,此变量称为输出。

本示例中的第二个任务使用调试模块显示新创建的输出变量的内容。 也就是说,如果您在EOS设备的命令行界面上输入“ show version”,则该数据与您在EOS设备的命令行界面上看到的数据相同。 不同之处在于我们的剧本会在您启动它的终端窗口中显示它们。 如您所见,调试模块使检查Ansible变量变得容易。

这是我们的剧本的输出:

 PLAY [eos] ************************************************************************* TASK [execute Arista eos command] ************************************************** ok: [eos] TASK [print out the output variable] *********************************************** ok: [eos] => { "output": { "changed": false, "failed": false, "stdout": [ "Arista vEOS\nHardware version: \nSerial number: \nSystem MAC address: 0800.27ec.005e\n\nSoftware image version: 4.20.1F\nArchitecture: i386\nInternal build version: 4.20.1F-6820520.4201F\nInternal build ID: 790a11e8-5aaf-4be7-a11a-e61795d05b91\n\nUptime: 1 day, 3 hours and 23 minutes\nTotal memory: 2017324 kB\nFree memory: 1111848 kB" ], "stdout_lines": [ [ "Arista vEOS", "Hardware version: ", "Serial number: ", "System MAC address: 0800.27ec.005e", "", "Software image version: 4.20.1F", "Architecture: i386", "Internal build version: 4.20.1F-6820520.4201F", "Internal build ID: 790a11e8-5aaf-4be7-a11a-e61795d05b91", "", "Uptime: 1 day, 3 hours and 23 minutes", "Total memory: 2017324 kB", "Free memory: 1111848 kB" ] ] } } PLAY RECAP ************************************************************************* eos : ok=2 changed=0 unreachable=0 failed=0 

从屏幕截图可以看出,我们两个任务都成功完成了。 由于第一个任务使用默认的消息详细级别,因此它仅表示eos主机以ok的结果完成了任务,以绿色表示执行成功。 第二个任务,带有调试模块,返回已执行命令的输出,以两种格式显示相同的信息:

  • 标准输出
  • stdout_lines

stdout部分显示的内容与您在设备的命令行界面中看到的内容相同,但以长行的形式显示。 并且stdout_lines部分将此输出分成几行,以便于阅读。 该列表中的每个项目在命令输出中都是单独的一行。

比较设备上和Ansible中命令的输出:

Arista EOS中的团队输出Ansible中的stdout_lines
eos>显示版本
Arista vEOS
硬件版本:
序列号:
系统MAC地址:0800.27ec.005e

软件映像版本:4.20.1F
架构:i386
内部内部版本:4.20.1F-6820520.4201F
内部内部版本ID:790a11e8-5aaf-4be7-a11a-e61795d05b91

正常运行时间:1天3小时56分钟
总内存:2017324 kB
可用内存:1116624 kB
“ Stdout_lines”:[
[
“ Arista vEOS”,
“硬件版本:”,
“序列号:”,
“系统MAC地址:0800.27ec.005e”,
“”,
“软件映像版本:4.20.1F”,
“架构:i386”,
“内部版本:
4.20.1F-6820520.4201F“,
“内部版本号:
790a11e8-5aaf-4be7-a11a-e61795d05b91“,
“”,
“正常运行时间:1天3小时23分钟”,
“总内存:2017324 kB”,
“可用内存:1111848 kB”
]

如果您熟悉JSON和YAML,那么您可能已经注意到了一个奇怪的地方:stdout_lines以两个大括号开头:

 "stdout_lines": [ [ 

两个大括号表示stdout_lines实际上返回线列表的列表。 如果您稍微修改我们的调试任务,则可以使用该芯片有选择地查看命令结果。 由于列表中只有一个行列表,因此该列表称为零(实际上,它是第一个,但计数是从头开始的)。 现在让我们看看如何从中提取单独的一行,例如,系统MAC地址。 在命令的输出中,该行是第四行,但是由于我们是从头开始计算的,因此最终需要列表0中的第3行,换句话说:output.stdout_lines [0] [3]。

  - name: print out a single line of the output variable debug: var: output.stdout_lines[0][3]   debug-   : TASK [print out a single line of the output variable] ****************************** ok: [eos] => { "output.stdout_lines[0][3]": "System MAC address: 0800.27ec.005e" } 

列表编号的重点是什么,为什么还需要? 事实是,在同一任务中,您可以运行多个团队,例如,像这样(这里我们有三个团队):

 --- - hosts: eos connection: network_cli tasks: - name: execute Arista eos command eos_command: commands: - show version - show ip int br - show int status register: output - name: print out command debug: var: output.stdout_lines 

输出如下所示:

  "output.stdout_lines": [ [ "Arista vEOS", "Hardware version: ", "Serial number: ", "System MAC address: 0800.27ec.005e", "", "Software image version: 4.20.1F", "Architecture: i386", "Internal build version: 4.20.1F-6820520.4201F", "Internal build ID: 790a11e8-5aaf-4be7-a11a-e61795d05b91", "", "Uptime: 1 day, 4 hours and 20 minutes", "Total memory: 2017324 kB", "Free memory: 1111104 kB" ], [ "Interface IP Address Status Protocol MTU", "Ethernet1 172.16.1.1/24 up up 1500", "Management1 192.168.2.10/24 up up 1500" ], [ "Port Name Status Vlan Duplex Speed Type Flags", "Et1 connected routed full unconf EbraTestPhyPort ", "Et2 connected 1 full unconf EbraTestPhyPort ", "Et3 connected 1 full unconf EbraTestPhyPort ", "Ma1 connected routed a-full a-1G 10/100/1000" ] ] 

在此,列表编号零是show version命令的输出,列表编号一是show ip int br输出,列表编号二是show int status输出。 即,列表号由命令执行的顺序确定。

Arista EOS团队匹配输出列表
显示版本output.stdout_lines [0]
显示ip int broutput.stdout_lines [1]
显示int状态output.stdout_lines [2]

命令模块缩放:主机变量


如果同时在多个设备上运行该剧本,会发生什么情况?



为了唯一,输出变量将作为清单中每个主机的主机变量存储。 如果我们有三个开关,并且在它们上运行我们的剧本,我们将获得每个唯一主机的输出变量。 假设我们需要show ip int br命令的IP地址作为switch03上的Ethernet1端口。 由于show ip int br是作为任务一部分运行的第二个命令,并且Ethernet1数据包含在其输出的第二行中,因此我们将需要编写stdout_lines [1] [1]。 要访问特定主机的变量,我们使用hostvars关键字并按名称搜索所需的主机。

方法如下:

  - name: debug hostvar debug: var: hostvars["switch03"].output.stdout_lines[1][1] 

结果,输出完全包含了我们所需要的:

 TASK [debug hostvar] *************************************************************** ok: [switch03] => { "hostvars[\"switch03\"].output.stdout_lines[1][1]": "Ethernet1 172.16.1.3/24 up up 1500" } 

默认情况下,该任务使用当前主机的变量,但是hostvars允许您直接访问其他主机的变量。

带有命令模块的任务中的条件:wait_for参数


使用wait_for参数可以在执行命令后立即执行条件检查。 例如,只有在状态检查命令的输出包含某些文本的情况下,才能使任务被视为成功完成。 默认情况下,不使用wait_for参数,因此任务仅运行一次,如上例所示。 但是,如果您进行了明确设置,则任务将重新启动,直到满足条件或超出尝试次数限制为止(默认为10)。 如果启用命令日志记录,则可以在下面的剧本(专门编写以使条件永远不会发生)中看到,一切都会像这样发生。

 --- - hosts: eos connection: network_cli tasks: - name: execute Arista eos command eos_command: commands: - show int status wait_for: - result[0] contains DURHAM 

该剧本将运行show int status命令10次,因为其输出将永远不会包含DURHAM行。

您可以使用show logging命令验证这一点:

 Mar 24 20:33:52 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=17 start_time=1521923632.5 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status Mar 24 20:33:53 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=18 start_time=1521923633.71 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status Mar 24 20:33:54 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=19 start_time=1521923634.81 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status Mar 24 20:33:55 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=20 start_time=1521923635.92 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status Mar 24 20:33:56 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=21 start_time=1521923636.99 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status Mar 24 20:33:58 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=22 start_time=1521923638.07 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status Mar 24 20:33:59 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=23 start_time=1521923639.22 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status Mar 24 20:34:00 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=24 start_time=1521923640.32 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status Mar 24 20:34:01 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=25 start_time=1521923641.4 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status Mar 24 20:34:02 eos Aaa: %ACCOUNTING-6-CMD: admin vty6 192.168.2.1 stop task_id=26 start_time=1521923642.47 timezone=UTC service=shell priv-lvl=15 cmd=show interfaces status 

现在,让我们看一个真实剧本的示例,其中所有内容都配置为使用ip ospf area命令以外的设备建立OSPF邻居(邻接)。 我们应用此命令,然后使用wait_for参数检查输出中是否存在单词FULL:如果存在,则表明邻居已成功建立。 如果在10次尝试中未出现FULL,则该任务将失败。

 --- - hosts: eos connection: network_cli tasks: - name: turn on OSPF for interface Ethernet1 eos_config: lines: - ip ospf area 0.0.0.0 parents: interface Ethernet1 - name: execute Arista eos command eos_command: commands: - show ip ospf neigh wait_for: - result[0] contains FULL 

使用ansible-playbook命令运行此剧本:

 ➜ ansible-playbook ospf.yml PLAY [eos] ********************************************************************************************* TASK [turn on OSPF for interface Ethernet1] ******************************************************* changed: [eos] TASK [execute Arista eos command] **************************************************************** ok: [eos] PLAY RECAP ****************************************************************************************** eos : ok=2 changed=1 unreachable=0 failed=0 

我们在命令行中查看该剧本是否成功:

 eos#show ip ospf neigh Neighbor ID VRF Pri State Dead Time Address Interface 2.2.2.2 default 1 FULL/DR 00:00:33 172.16.1.2 Ethernet1 

除了包含之外,还可以使用以下比较运算符:

  • eq:-等于
  • neq:-不相等
  • gt:-更多
  • ge:-大于或等于
  • lt:-更少
  • le:-小于或等于

另外,您可以与wait_for一起使用三个附加参数(在模块文档中进行了详细说明):

参量内容描述
间隔团队重复之间的时间。
重试最高 任务以错误完成或满足条件之前的重复次数。
比赛所有条件或至少一个条件的巧合。

让我们更详细地讨论match参数:

  - name: execute Arista eos command eos_command: commands: - show ip ospf neigh match: any wait_for: - result[0] contains FULL - result[0] contains 172.16.1.2 

当match:指定了any时,如果结果包含FULL或172.16.1.2。,则认为任务成功。 如果指定match:all,则结果必须同时包含FULL和172.16.1.2。 默认情况下,使用match:all,因为如果您规定了多个条件,则很可能希望所有条件都得到满足,但至少不满足。

什么时候可以匹配:有什么用处吗? 假设您需要验证数据中心是否具有到Internet的双向连接。 数据中心连接到五个不同的Internet提供商,每个提供商都有其自己的BGP连接。 剧本可以检查这五个连接中的所有连接,如果其中至少有一个连接正常(而不是全部五个),则报告一切正常。 只要记住,任何一个都是逻辑“或”,所有都是逻辑“与”。

参量内容描述
匹配:任意逻辑“或”
至少需要一个条件
匹配:全部逻辑“与”
所需的所有条件

负条件:建立逆逻辑


有时,重要的不是结论中的内容,而是结论中的内容。 当然,这里总是使用neq比较运算符,但是对于某些条件为负的情况,有更好的选择。 例如,如果您需要反转contains语句(类型为“命令的输出中不应包含诸如此类”),则可以使用register关键字保存输出,然后使用when表达式在下一个任务中对其进行处理。 或者,例如,如果在不满足条件的情况下需要停止剧本,只需使用failassert模块专门退出并显示错误。 对于比较运算符neq,仅当您可以从输出(例如,从键值对或JSON)中提取确切值,而不仅仅是字符串或字符串列表时,才有用。 否则,将执行字符串的逐字符比较。

接下来是什么


阅读有关使用网络模块中的命令输出的文档 。 它提供了在特定网络平台上处理JSON格式输出时使用ge,le和其他条件的有用示例。

Source: https://habr.com/ru/post/zh-CN438312/


All Articles