- A+
本文是本人在2020年的一篇文章,随着认知的不断深入以及堵着门的相关,本人又编写了上下两篇三万字的最强Netmiko攻略(不接受反驳,手动狗头~)
————————————————————分割线—————————————————————
采集网络设备有多种方法,常见的有SSH、Telnet、SNMP、Netconf、设备或控制器的Restful API。
之前的分享讲解了Netconf的采集,Netconf的前提是设备支持此协议,如果设备不支持或者是工程师一时难以接受,我们就来分享一个基于CLI的网络设备信息采集工具Netmiko(也是Python的第三方包,非常优秀的网络工具包)。
使用ssh登录设备输入命令回显输出。python常用的包有pexpect、paramiko、netmiko。个人推荐使用netmiko,封装的比较好,支持的厂商和型号(系列)比较多,也可以对Linux进行操作。
pexpect像是Linux的expect,实际使用中需要二次开发或者定制回显的expect字符串(比如每敲一段show version,当我们看到“设备名#“就代表回显结束,这个“设备名#”就是expect的字符串)。
paramiko相比pexpect进行过一些封装,可以比较好的自动判断回显,但是遇到分页还是需要自己处理,程序无法处理。而网络设备在执行命令的时候经常有分页,或者一些特殊模式等等。所以paramiko对网络设备支持还是有限。
那Netmiko是基于paramiko的二次封装,从名字上就可以看出来它有两部分,net代表网络,miko代表的是paramiko。它能非常好的适配网络设备,处理好各厂商的分页、特殊模式,同时针对网络的一些特点加入了config、save、enable、文件传输(多用于备份)等网络所特有的一些功能。
安装netmiko包
请安装python(建议Anaconda,简单粗暴)后。记得是python3.7及以上版本
执行"pip install netmiko"命令即可。
使用netmiko
from netmiko import ConnectHandler
'''
关于netmiko的使用,建议查看官网的说明,
简单的show命令的话,用以下代码即可,注意的是device_type
内置常用的有有以下 请留意左侧的key值,是支持的设备系列。
CLASS_MAPPER_BASE = {
'a10': A10SSH,
'accedian': AccedianSSH,
'alcatel_aos': AlcatelAosSSH,
'alcatel_sros': AlcatelSrosSSH,
'apresia_aeos': ApresiaAeosSSH,
'arista_eos': AristaSSH,
'aruba_os': ArubaSSH,
'avaya_ers': AvayaErsSSH,
'avaya_vsp': AvayaVspSSH,
'brocade_fastiron': RuckusFastironSSH,
'brocade_netiron': BrocadeNetironSSH,
'brocade_nos': BrocadeNosSSH,
'brocade_vdx': BrocadeNosSSH,
'brocade_vyos': VyOSSSH,
'checkpoint_gaia': CheckPointGaiaSSH,
'calix_b6': CalixB6SSH,
'ciena_saos': CienaSaosSSH,
'cisco_asa': CiscoAsaSSH,
'cisco_ios': CiscoIosSSH,
'cisco_nxos': CiscoNxosSSH,
'cisco_s300': CiscoS300SSH,
'cisco_tp': CiscoTpTcCeSSH,
'cisco_wlc': CiscoWlcSSH,
'cisco_xe': CiscoIosSSH,
'cisco_xr': CiscoXrSSH,
'coriant': CoriantSSH,
'dell_force10': DellForce10SSH,
'dell_os10': DellOS10SSH,
'dell_powerconnect': DellPowerConnectSSH,
'dell_isilon': DellIsilonSSH,
'eltex': EltexSSH,
'enterasys': EnterasysSSH,
'extreme': ExtremeSSH,
'extreme_wing': ExtremeWingSSH,
'f5_ltm': F5LtmSSH,
'fortinet': FortinetSSH,
'generic_termserver': TerminalServerSSH,
'hp_comware': HPComwareSSH,
'hp_procurve': HPProcurveSSH,
'huawei': HuaweiSSH,
'huawei_vrpv8': HuaweiVrpv8SSH,
'juniper': JuniperSSH,
'juniper_junos': JuniperSSH,
'linux': LinuxSSH,
'mellanox': MellanoxSSH,
'mrv_optiswitch': MrvOptiswitchSSH,
'netapp_cdot': NetAppcDotSSH,
'netscaler': NetscalerSSH,
'ovs_linux': OvsLinuxSSH,
'paloalto_panos': PaloAltoPanosSSH,
'pluribus': PluribusSSH,
'quanta_mesh': QuantaMeshSSH,
'ruckus_fastiron': RuckusFastironSSH,
'ubiquiti_edge': UbiquitiEdgeSSH,
'ubiquiti_edgeswitch': UbiquitiEdgeSSH,
'vyatta_vyos': VyOSSSH,
'vyos': VyOSSSH,
}
'''
def ssh_dev_exc(dev_type, ip, commands, port=22,
username='readonly', password='readonly'):
dev_info = {
'device_type': dev_type,
'ip': ip,
'port': port,
'username': username,
'password': password
}
with ConnectHandler(**dev_info) as dev_connection:
outputs = []
for c in commands:
output = dev_connection.send_command(c)
outputs.append(output)
return outputs
if __name__ == '__main__':
some_dev_ssh_info = {
'dev_type': 'cisco_nxos',
'ip': '192.168.1.23',
'port': 22,
'username': 'user',
'password': 'passowrd',
'commands': ['show int']
}
outputs = ssh_dev_exc(**some_dev_ssh_info)
print(outputs)
看到满满的支持的设备类型,笔者是在一个设备类型众多的数据中心工作,我反正是心动了,尤其是华为华三等国产厂商的支持,happy
悄悄说一句 netmiko的封装太优秀,cisco_nxos可以直接但是不完全驱动非常多的网络设备。其他很多驱动都是基于cisco的一个底层通用驱动类进行小改的。
这段代码我们往前往后都可以去拓展开,我给大家抛砖:
1、读取csv,遍历设备,执行此函数,并将命令结果保存到txt,这不就是备份脚本了吗?
2、按照上面的,解析文本内容,输出到Excel或者word文档,这不就是巡检脚本了吗?
3、读取csv,遍历设备,执行函数,进入config模式(下面会讲config),执行命令,这不就是批量下发了吗?
4、定时登录设备采集解析某指标入库,再可视化出来数据,这不就是一个小小的监控了吗?很多SNMP采集不到的信息,不就是通过命令行来采集解析的吗?
当然这都是一些比较raw的想法,实际中,还是需要处理一些特殊情况,比如认证如果是动态的需要处理,比如库表设计。向上向下都可以加很多封装抽象。
进行设备的配置
设备最开始是普通状态,无法写操作(视具体网络设备而言,大部分遵循此原则),通过命令行后才可以进行写操作。netmiko为了安全起见,也将平时的show 和config区别了开,你通过命令行输入config,大部分情况下是无效的。
from netmiko import SSHDetect, Netmiko
from getpass import getpass
device = {'device_type': 'cisco_nxos',
'host': 'XXX',
'port': 'XXX',
'username': 'admin',
'password': 'XXX!', }
connection = Netmiko(**device)
in_config_mode = connection.check_config_mode()
print('config mode is :{}'.format(in_config_mode))
# 方法1 进入config model 输入命令,确定expect的字符,可以是正则,保存
connection.config_mode()
connection.send_command('interface eth1/50',expect_string='.*#')
connection.send_command('description configed by netmiko',expect_string='.*#')
connection.save_config()
方法一
是进入config模式,调用config_mode'函数即可,函数会根据device_type,自动输入对应的命令比如config或者是system-view等。
用send_command发送命令,我们实际操作中,config后操作提示符会不断变化(比如配置一个端口的时候提示符会变成“dev_name(config-if)#“),所以写一个通配的正则匹配这种,用expect_string保证脚本确认动作执行完成。实际效果如下。(普通模式下发送命令不会修改提示符)
最后用save_config函数来保存配置,这个也是netmiko帮我们自动完成,根据设备自动输入对应的命令行保存配置。
方法二
实际上,有更简单的方法,方法2 用send_config_set函数发送命令集。无需进入config_mode。但是需要save_config.
connection.send_config_set(config_commands=['interface eth1/50','description configed by netmiko in method 2'])
方法三
从文件中读取
无需进入config_mode。但是需要save_config
# 方法3 通过文本文件进行配置
connection.send_config_from_file(config_file='config.txt')
自动判断设备的device_type
有时候我们不太清楚用哪个device_type,没关系,netmiko有一个自动检测的函数。上代码:
from netmiko import SSHDetect, Netmiko
device = {'device_type': 'autodetect',
'host': 'XXX',
'port': 'XXX',
'username': 'root',
'password': 'XXX', }
guesser = SSHDetect(**device)
best_match = guesser.autodetect()
print('best_match is:{}'.format(best_match))
print('all guessers is:{}'.format(guesser.potential_matches))
device['device_type'] = best_match
connection = Netmiko(**device)
# 获取回显的前缀,提示符,prompt。
print('prompt is :{}'.format(connection.find_prompt())
这个在简单show的时候可以使用,常见设备准确率还可以,比如笔者去用nxos和linux检测的时候很准。但是有时候推荐的并不是可用的,我也遇到过。
find_prompt可以获取提示符,从而获取设备名,划重点,脑洞大的同学会不会有一些别的想法呢?我们从prompt中获取提示符,用正则提取出设备名,是不是可以与CMDB里的信息进行比对呢?我觉得这是一个很实在的运维场景,可以在自己内部扩展成一个简单的小工具了。
这个操作本质是用遍历内置的一些适配,执行命令看看是否符合预期,会给一个准确度的值。由于是遍历所以有时候比较耗时。
我们去看卡这个SSH_MAPPER_BASE
就是去执行命令,根据回显的文本去用正则匹配,匹配到了就返回device_type,在这里是这个字典的Key值。通过优先级返回best_match。其实我们可以重写这个netmiko的这个函数,基于这个字典丰富,按我们的所需去发现device_type。
我们初步用一个工具的时候,怎么用都可以,但是当我们用的越深入要求越多,会发现有时候需要做一些必要的二次开发。所以后期我也花了很多时间去看源代码,并结合自己的实际需求继续封装:
- 一方面是满足自己的奇葩需求,比如有新的适配,或者自动检测不准做调整。
- 一方面是加速开发的速度,以前写十行,封装后可能就3行了。
所以我的分享有时候会深入到源代码层面去。大家愿意看就看看,了解即可。如果一些大厂有特殊需求,我们也可以探讨一下,互通有无。比如我们基于netmiko和一些web框架,就可以实现like SDN的网络设备了,通过RESTful API来调用设备信息,作为一个微服务。传统网络设备也可以像Nexus交换机一样有RESTful API了。大家在传统网络向SDN网络过渡的过程中,肯定是敏态稳态并存,新老设备和谐相处的,那我们可以通过这个方法,去改造传统网络,使之具备一些SDN网络才有的功能,拉平两种网络,我个人觉得会比ansible更加实用(后续我们也会从国内的网络视角分享ansible的长与短,先挖坑)。
- 我的微信
- 这是我的微信扫一扫
- 我的微信公众号
- 我的微信公众号扫一扫