目录
Step 1:Hosts文件不动,延用章节一中的配置,思科华为各一台
Step 3: 执行结果(思科的一次OK,华为报错调试了很久忘记截图了)
Step 4:Ansible troubleshooting ,脚本执行到华为设备时报错,一起来troubleshooting吧
三、批量修改思科华为管理IP,添加管理VLAN,添加静态路由(实际业务)
Step 2:思科的play-book, 此次变更数量比较多且第一次尝试在实际业务中,思科与华为分开写的play,思科采用的是module方式。
Step 3: 华为play-book,此次华为采用的是command方式。
4.3 Ansible for Network Automation
————————————————————————————————————————
一、抓取思科与华为设备的信息(测试)
Step 1:在Hosts文件中定义思科与华为的IP地址
只是测试,思科华为各拿一台主机
# This is the default ansible 'hosts' file.
#
# It should live in /etc/ansible/hosts
#
# - Comments begin with the '#' character
# - Blank lines are ignored
# - Groups of hosts are delimited by [header] elements
# - You can enter hostnames or ip addresses
# - A hostname/ip can be a member of multiple groups
[cisco] #思科设备3台
10.26.255.1
#10.26.255.2
#10.26.255.3
[hw] #华为设备1台
10.26.255.100
[cisco:vars] #思科设备的变量
ansible_user=admin #用户名
ansible_password=cisco123 #密码
ansible_connection=network_cli #连接方式,目前普遍使用network_cli
ansible_network_os=ios #os类型
ansible_port=22 #连接端口
[hw:vars] #同上
ansible_user=admin
ansible_password=huawei123
ansible_connection=network_cli
ansible_network_os=community.network.ce
ansible_port=22
Step 2:play-book 脚本
--- #YAML语句的起始标志
- name: For Cisco
connection: network_cli
gather_facts: false
hosts: cisco #调用hosts文件中cisco主机
tasks:
- name: Check the network reachability of the CISCO #task 1
cisco.ios.ios_ping: #使用的module
dest: 10.26.255.130 #module 参数
#task 1: 调用ping module,检测与10.26.255.130这个dest目标主机的连通性
- name: Show ip inter brief #task 2
cisco.ios.ios_command:
commands: show ip inter brief
register: show_ip_inter_brief
#task 2: 调用command module,模块参数使用commands,执行命令 show ip inter brief,结果保存到变量
show_ip_inter_brief
- name: print the show ip inter brief #task 3
debug:
msg: "{{show_ip_inter_brief.stdout_lines}}"
#task 3: 调用debug module, 输出变量show_ip_inter_brief
#解释如上,只是HW调用的模块名称不同
- name: For HW
connection: network_cli
gather_facts: false
hosts: hw
tasks:
- name: HW SHOW
community.network.ce_command:
commands: "display ip inter br"
register: dis_ip_inter_brief
- name: print dis_ip_inter_brief
debug:
msg: "{{dis_ip_inter_brief.stdout_lines}}"
Step 3:执行结果
二、使用Ansible备份思科华为配置(测试)
Step 1:Hosts文件不动,延用章节一中的配置,思科华为各一台
Step 2:play-book脚本
---
- name:Backup Cisco File
connection: network_cli
gather_facts: false
hosts: cisco
tasks:
- name: Gather all cisco info #task 1: 收集cisco信息,后续使用hostname命名文件
ios_facts:
gather_subset: all
- name: Get current date #task 2: 获取当前date
local_action: command date +%Y-%m-%d
register: date
- name: Get current time #task 3: 获取当前time
local_action: command date +%H:%M
register: time
- name: Get running-config and save it #task 4: 保存当前配置并备份
ios_config: #使用config模块
backup: yes #参数:启用备份
backup_option:
filename: "{{ansible_net_hostname}}_{{ansible_host}}.cfg" #备份文件名称hostname+ip
dir_path: /usr/{{date.stdout}}_at_{{time.stdout}} #备份文件夹路径
- name: Tasks done #task 5: 提示任务完成
debug: msg= "All cisco tasks has been done on {{date.stdout}} at {{time.stdout}}"
- name:Backup Huawei File
connection: network_cli
gather_facts: false
hosts: hw
tasks:
- name: Gather hw info
community.network.ce_facts:
gather_subset: config
- name: Get current date
local_action: command date +%Y-%m-%d
register: date
- name: Get current time
local_action: command date +%H:%M
register: time
- name: Get running-config and save it
community.network.ce_config:
backup: yes
backup_option:
filename: "{{hostname}}.cfg"
dir_path: /usr/{{date.stdout}}_at_{{time.stdout}}
- name: Tasks done
debug: msg= "All huawei tasks has been done on {{date.stdout}} at {{time.stdout}}"
Step 3: 执行结果(思科的一次OK,华为报错调试了很久忘记截图了)
Step 4:Ansible troubleshooting ,脚本执行到华为设备时报错,一起来troubleshooting吧
1)排错第一步,打开ansible的debug跟log功能
直接在系统层面执行以下两句语句
# Specify the location for the log file
export ANSIBLE_LOG_PATH=~/ansible.log
# Enable Debug
export ANSIBLE_DEBUG=True
2)复现问题:继续执行play-book脚本,加上-vvv参数就能看到ansible每个task的执行过程,哪里报错,报错原因等。
ansible-playbook backup.yml -vvv
3)报错日志分析,定位问题点(前面的截图找不到了,重新拿了个playbook模拟),大概的排错流程就是这样。
root@rachel-virtual-machine:/etc/ansible# ansible-playbook first_playbook.yml -vvv
ansible-playbook [core 2.12.8]
config file = /etc/ansible/ansible.cfg
configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3/dist-packages/ansible
ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/bin/ansible-playbook
python version = 3.8.10 (default, Jun 22 2022, 20:18:18) [GCC 9.4.0]
jinja version = 2.10.1
libyaml = True
Using /etc/ansible/ansible.cfg as config file
host_list declined parsing /etc/ansible/hosts as it did not pass its verify_file() method
script declined parsing /etc/ansible/hosts as it did not pass its verify_file() method
auto declined parsing /etc/ansible/hosts as it did not pass its verify_file() method
Parsed /etc/ansible/hosts inventory source with ini plugin
Skipping callback 'default', as we already have a stdout callback.
Skipping callback 'minimal', as we already have a stdout callback.
Skipping callback 'oneline', as we already have a stdout callback.
PLAYBOOK: first_playbook.yml *************************************************************************************************
2 plays in first_playbook.yml
PLAY [HW] ********************************************************************************************************************
skipping: no hosts matched
PLAY [Cisco] *****************************************************************************************************************
META: ran handlers
TASK [Get cisco info] ********************************************************************************************************
task path: /etc/ansible/first_playbook.yml:23
redirecting (type: connection) ansible.builtin.network_cli to ansible.netcommon.network_cli
redirecting (type: terminal) ansible.builtin.ce to community.network.ce
redirecting (type: cliconf) ansible.builtin.ce to community.network.ce
redirecting (type: become) ansible.builtin.enable to ansible.netcommon.enable
<192.168.237.100> ESTABLISH LOCAL CONNECTION FOR USER: root
<192.168.237.100> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /root/.ansible/tmp/ansible-local-56413fcuyatyk `"&& mkdir "` echo /root/.ansible/tmp/ansible-local-56413fcuyatyk/ansible-tmp-1665453960.7583842-56418-232110089926773 `" && echo ansible-tmp-1665453960.7583842-56418-232110089926773="` echo /root/.ansible/tmp/ansible-local-56413fcuyatyk/ansible-tmp-1665453960.7583842-56418-232110089926773 `" ) && sleep 0'
Using module file /usr/lib/python3/dist-packages/ansible_collections/cisco/ios/plugins/modules/ios_facts.py
<192.168.237.100> PUT /root/.ansible/tmp/ansible-local-56413fcuyatyk/tmp0zniwxqh TO /root/.ansible/tmp/ansible-local-56413fcuyatyk/ansible-tmp-1665453960.7583842-56418-232110089926773/AnsiballZ_ios_facts.py
<192.168.237.100> EXEC /bin/sh -c 'chmod u+x /root/.ansible/tmp/ansible-local-56413fcuyatyk/ansible-tmp-1665453960.7583842-56418-232110089926773/ /root/.ansible/tmp/ansible-local-56413fcuyatyk/ansible-tmp-1665453960.7583842-56418-232110089926773/AnsiballZ_ios_facts.py && sleep 0'
<192.168.237.100> EXEC /bin/sh -c '/usr/bin/python3 /root/.ansible/tmp/ansible-local-56413fcuyatyk/ansible-tmp-1665453960.7583842-56418-232110089926773/AnsiballZ_ios_facts.py && sleep 0'
<192.168.237.100> EXEC /bin/sh -c 'rm -f -r /root/.ansible/tmp/ansible-local-56413fcuyatyk/ansible-tmp-1665453960.7583842-56418-232110089926773/ > /dev/null 2>&1 && sleep 0'
The full traceback is:
File "/tmp/ansible_cisco.ios.ios_facts_payload__u2fn_f8/ansible_cisco.ios.ios_facts_payload.zip/ansible_collections/ansible/netcommon/plugins/module_utils/network/common/network.py", line 251, in get_capabilities
capabilities = Connection(module._socket_path).get_capabilities()
File "/tmp/ansible_cisco.ios.ios_facts_payload__u2fn_f8/ansible_cisco.ios.ios_facts_payload.zip/ansible/module_utils/connection.py", line 200, in __rpc__
raise ConnectionError(to_text(msg, errors='surrogate_then_replace'), code=code)
fatal: [192.168.237.100]: FAILED! => {
"changed": false,
"invocation": {
"module_args": {
"available_network_resources": false,
"gather_network_resources": null,
"gather_subset": [
"all"
],
"provider": null
}
},
"msg": "command timeout triggered, timeout value is 30 secs.\nSee the timeout setting options in the Network Debug and Troubleshooting Guide."
}
PLAY RECAP *******************************************************************************************************************
192.168.237.100 : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
可以看到此play-book脚本中包含两个play,一个HW一个Cisco,HW无匹配的主机直接跳过,执行Cisco剧本。
Cisco剧本中的第一个task,可以看到类型重定向到了community.network.ce,这是hw的ios类型(故意在hosts文件中将os改为了ce)
4)修改问题点,继续测试
修改为ios
Step 5:排错后,继续执行
hosts文件整了5台
执行命令:
ansible-playbook backup.yml -vvv
执行结果:
三、批量修改思科华为管理IP,添加管理VLAN,添加静态路由(实际业务)
Step 1:准备好hosts地址,也就是需要修改的主机清单,清单中包括新的IP地址,接口地址每行代表一台主机,第一个IP是主机目前的管理地址,new_ip为新IP地址,interface指定现有的trunk接口。
# This is the default ansible 'hosts' file.
#
# It should live in /etc/ansible/hosts
#
# - Comments begin with the '#' character
# - Blank lines are ignored
# - Groups of hosts are delimited by [header] elements
# - You can enter hostnames or ip addresses
# - A hostname/ip can be a member of multiple groups
[cisco]
#3F
192.168.3.238 new_ip="192.168.255.238 255.255.255.0" interface="Port-channel10"
192.168.3.191 new_ip="192.168.255.191 255.255.255.0" interface="Port-channel5"
192.168.3.232 new_ip="192.168.255.232 255.255.255.0" interface="Port-channel1"
192.168.3.237 new_ip="192.168.255.237 255.255.255.0" interface="Port-channel10"
192.168.3.190 new_ip="192.168.255.190 255.255.255.0" interface="Port-channel10"
192.168.3.193 new_ip="192.168.255.193 255.255.255.0" interface="Port-channel2"
[hw]
#3F
192.168.3.240 new_ip="192.168.255.240 24" interface="Eth-Trunk10"
192.168.3.239 new_ip="192.168.255.239 24" interface="Eth-Trunk11"
192.168.3.245 new_ip="192.168.255.245 24" interface="Eth-Trunk12"
192.168.3.244 new_ip="192.168.255.244 24" interface="Eth-Trunk13"
192.168.3.243 new_ip="192.168.255.243 24" interface="Eth-Trunk14"
192.168.3.242 new_ip="192.168.255.242 24" interface="Eth-Trunk15"
192.168.3.225 new_ip="192.168.255.225 24" interface="GigabitEthernet0/0/52"
192.168.3.226 new_ip="192.168.255.226 24" interface="GigabitEthernet0/0/52"
192.168.3.227 new_ip="192.168.255.227 24" interface="GigabitEthernet0/0/52"
[cisco:vars]
ansible_user=admin
ansible_password=admin123
ansible_connection=network_cli
ansible_network_os=ios
ansible_port=22
#ansible_become=yes
#ansible_become_method=enable
#ansible_become_password=admin123
[hw:vars]
ansible_user=admin
ansible_password=admin123
ansible_connection=network_cli
ansible_network_os=community.network.ce
ansible_port=22
Step 2:思科的play-book, 此次变更数量比较多且第一次尝试在实际业务中,思科与华为分开写的play,思科采用的是module方式。
大概流程就是:
1) 创建vlan 255
2) 创建interface vlan 255并设置IP地址
3) Enable interface vlan 255
4) Trunk链路中允许vlan 255通过
5) 添加新的静态路由
---
- name: For Cisco
connection: network_cli
gather_facts: false
hosts: cisco
tasks:
- name: Create VLAN
cisco.ios.ios_vlans: #module name
config:
- name: vlan_255_management #vlan名称
shutdown: disabled #vlan no shutdown
state: active #状态激活
vlan_id: 255 #vlan id 255 (必填参数)
- name: Add vlan 255 ip address #设置interface vlan 255 的IP地址
cisco.ios.ios_l3_interfaces:
config:
- name: vlan 255 #设置interface vlan 255
ipv4: #设置ipv4参数
- address: "{{ new_ip }}" #使用hosts文件中的new_ip变量赋给address
- name: enable vlan 255 interface
cisco.ios.ios_interfaces:
config:
- name: vlan 255
enabled: true #no shutdown
- name: add vlan 255 to interface
cisco.ios.ios_l2_interfaces:
config:
- name: "{{ interface }}" #eg: interface port-channel 10
mode: trunk
trunk:
allowed_vlans: 255 #trunk允许通过的vlan列表中添加vlan 255
- name: add static router
cisco.ios.ios_static_routes:
config:
- address_families:
- afi: ipv4
routes:
- dest: 0.0.0.0/0 # ip route 0.0.0.0 0.0.0.0
next_hops:
- forward_router_address: 192.168.255.253 #下一跳网关
- name: write configuration #保存配置
cisco.ios.ios_command:
commands: write #write
Step 3: 华为play-book,此次华为采用的是command方式。
---
- name: For Huawei
connection: network_cli
gather_facts: false
hosts: hw
tasks:
- name: Huawei Create VLAN
community.network.ce_command:
commands:
- system-view
- vlan 255
- interface vlan 255
- ip address {{ new_ip }}
- undo shutdown
- quit
- interface {{ interface }}
- port trunk allow-pass vlan 255
- quit
- ip route-static 0.0.0.0 0.0.0.0 192.168.255.253
- save
- y
#- undo ip route-static 0.0.0.0 0.0.0.0 192.168.3.253
Step 4:分开执行思科华为脚本
Ansible-playbook -i hosts_1 cisco.yml
Ansible-playbook -i hosts_1 huawei.yml
四、ansible文档
4.1 cisco ios module
Cisco.Ios — Ansible Documentation
4.2 huawei ce module
Community.Network — Ansible Documentation
4.3 Ansible for Network Automation
Ansible for Network Automation — Ansible Documentation
ansible官方module文档写的非常好,包含例子等说明