一、定义任务
以前升级路由器的方式是通过 ssh 进入每个设备,然后 tftp 或 scp 将映像文件复制到闪存并更改引导顺序。
特别是,路由器是Cisco uBR 10k 路由器系列有很多不同的路由引擎。在这种环境中,它们被称为 PRE4 和 PRE5,每种类型都有专属的镜像文件(.bin)。线路卡还需要一个每种路由引擎对应的板块也要求特定的 .pkg 文件。许多路由器具有冗余路由引擎,因此也需要将镜像从主磁盘上复制一份到备用磁盘上。
完成升级所需的步骤如下所示:
- 确定设备是否有冗余路由引擎
- 确定路由引擎是 PRE4 还是 PRE5
- 将boot镜像和线路卡镜像正确地复制到设备
- 更改系统启动顺序
- 保存配置
- 重启
设置Ansible任务
如果你是刚接触Ansible,还不完全了解,建议先去学一下Ansible的基础知识,不过你放心,Ansible简单易学。
想了一下,我决定用最简单的方法来检查目标设备是否有冗余路由引擎,就是通过SNMP查询,使用CISCO-RF-MIB的cRFStatusPeerUnitState (1.3.6.1.4.1.9.9.176.1.1.4) oid ,所以我使用了snmp_query模块设置了第一个任务:
- name: Collect snmp_query: host: "{{ inventory_hostname }}" version: 2c community: "{{ snmp_community }}" oid: - 1.3.6.1.4.1.9.9.176.1.1.4.0 register: output
然后结果就看这个output变量了。如果值等于9,则表明是有冗余引擎的;如果值等于2(disabled),则表明设备为非冗余的。其他值,则说明有问题,可能会升级失败,所以不能继续。
- name: Device is redundant set_fact: redundant: True when: output['1.3.6.1.4.1.9.9.176.1.1.4.0'] == 9 - name: The device is not redundant set_fact: redundant: False when: output['1.3.6.1.4.1.9.9.176.1.1.4.0'] == 2 - name: Exit fail: msg: "Broken" when: output['1.3.6.1.4.1.9.9.176.1.1.4.0'] not in [2, 9]
接下来,就是确定路由引擎是 PRE4 还是 PRE5?一开始我也是打算继续使用snmp来完成,然而我发现它会对每个设备进行全部轮询,这样我会得到一堆我不感兴趣的信息。最后我想到一个简单的办法,不错的办法,从屏幕捕获,例如当我们使用“show version”的时候,就可以看到,如果是PRE4设备,有一行显示UBR10K4,如果是PRE5,是显示UBR10K5,所以我打算使用在Ansible新版本中的ios_command模块,这样就可以从捕获的信息那里获取一些数据,然后判断,把结果赋值给“pre”变量。
- name: Collect version ios_command: host: "{{ inventory_hostname }}" username: "{{ device_ssh_username }}" password: "{{ device_ssh_password }}" commands: "show version" register: version - name: Pre5 set_fact: pre: 5 when: '"UBR10K5" in version["stdout"][0]' - name: Pre4 set_fact: pre: 4 when: '"UBR10K4" in version["stdout"][0]'
现在,我们也已经有所有的信息了,接下来就是需要把镜像copy到设备上。
所以,我使用了ntc-ansible中的ntc_file_copy模块。
- name: Copy Pre4 boot image ntc_file_copy: host: "{{ inventory_hostname }}" username: "{{ device_ssh_username }}" password: "{{ device_ssh_password }}" platform: cisco_ios_ssh local_file: "{{ cmts_boot_image_pre4 }}" remote_file: "{{ cmts_boot_image_pre4 }}" file_system: "disk0:" when: pre == 4 - name: Copy Pre4 boot image redundant ntc_file_copy: host: "{{ inventory_hostname }}" username: "{{ device_ssh_username }}" password: "{{ device_ssh_password }}" platform: cisco_ios_ssh local_file: "{{ cmts_boot_image_pre4 }}" remote_file: "{{ cmts_boot_image_pre4 }}" file_system: "stby-disk0:" when: pre == 4 and redundant
实际上Playbook还有一些任务,比如把linecard镜像和PRE5不同的系统文件,为了简单这些就省略了。(欢迎关注公众号@网络工程师阿龙)
一旦上述文件都传完后,接下来就需要更改一些boot顺序。这里我使用Ansible的ios_config 模块,这模块在Ansible2.1有提供。
如果你配置需要修改一下然后再保存,这个可以通过handler来完成。以PRE5为例(这里就省略了为PRE4设置):
- name: Configure startup ios_config: lines: - boot-start-marker - boot system disk0:{{ cmts_boot_image_pre5 }} - boot-end-marker before: ['default boot system'] replace: block host: '{{ inventory_hostname }}' username: "{{ device_ssh_username }}" password: "{{ device_ssh_password }}" when: pre == 5 notify: save config handlers: - name: save config ios_command: host: "{{ inventory_hostname }}" username: "{{ device_ssh_username }}" password: "{{ device_ssh_password }}" commands: "write mem"
重启
上面列举的仅是完成设备导入新版本的工作,之后它们还需要重启。
可以在上述代码handler中添加“reload”命令来完成,但你应该在一个维护窗口来完成重启。另外,Playbook可以轻松地创建使用snmp_device_version 模块来获取当前版本是否是我们期望的版本,如果不是,则根据上述设置后再次重启。
总结
虽然本期的老外的这个Playbook可能不能完全帮助到你,但老外还是希望通过分享一些想法给龙哥的粉丝,让大家知道我们手中有些的工作是如何通过Ansible来实现自动化运维我们的网络。