[toc]
NAPALM 概述
官网链接
其余 drive 链接(国人)
NAPALM 全称为 Network Automation and Programmability Abstraction Layer with Multivendor support,翻译起来就是反对 ” 多厂商 ” 网络自动化和可编程的形象层.
NAPALM 是一个 python 开源的第三方模块,截至 2021.11 月,反对的厂商如下所示:
尽管反对厂商不是很多,临时没有反对国内厂商,但性能都是很弱小的。
Cisco IOS
Cisco NX-OS
Cisco IOS-XR
Juniper JUNOS
Arista EOS
NX-API support on the Nexus 5k, 6k and 7k families was introduced in version 7.2
- 依赖 netmiko,本机装置即可.
反对的设施
通用反对模型
_ | EOS | Junos | IOS-XR (NETCONF) | IOS-XR (XML-Agent) | NX-OS | NX-OS SSH | IOS |
---|---|---|---|---|---|---|---|
Driver Name | eos | junos | iosxr_netconf | iosxr | nxos | nxos_ssh | ios |
Structured data | Yes | Yes | Yes | No | Yes | No | No |
Minimum version | 4.15.0F | 12.1 | 7.0 | 5.1.0 | 6.1 [1] | 12.4(20)T | 6.3.2 |
Backend library | pyeapi | junos-eznc | ncclient | pyIOSXR | pynxos | netmiko | netmiko |
Caveats | EOS | IOS-XR (NETCONF) | NXOS | NXOS | IOS |
阐明:
- driver name:前面咱们写代码须要填写的, 如
get_network_driver(ios)
- structured data:反对的结构化数据
- Minimum version:这里还有最低的版本要求;
配置反对模型
反对配置替换、合并、提交、比照、原子配置、回滚等。
_ | EOS | Junos | IOS-XR (NETCONF) | IOS-XR (XML-Agent) | NX-OS | IOS |
---|---|---|---|---|---|---|
Config. replace | Yes | Yes | Yes | Yes | Yes | Yes |
Config. merge | Yes | Yes | Yes | Yes | Yes | Yes |
Commit Confirm | Yes | Yes | No | No | No | No |
Compare config | Yes | Yes | Yes | Yes [2] | Yes [4] | Yes |
Atomic Changes | Yes | Yes | Yes | Yes | Yes/No [5] | Yes/No [5] |
Rollback | Yes [3] | Yes | Yes | Yes | Yes/No [5] | Yes |
[2] Hand-crafted by the API as the device doesn’t support the feature.
[3] Not supported but emulated. Check caveats.
[4] For merges, the diff is very simplistic. See caveats.
[5] (1, 2, 3) No for merges. See caveats.
[6] NAPALM requires Junos OS >= 14.1 for commit-confirm functionality.
Getters 反对的模型
该表官网会不定期自动更新。
EOS | IOS | IOSXR | IOSXR_NETCONF | JUNOS | NXOS | NXOS_SSH | |
---|---|---|---|---|---|---|---|
get_arp_table | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ |
get_bgp_config | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
get_bgp_neighbors | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
get_bgp_neighbors_detail | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
get_config | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ |
get_environment | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
get_facts | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
get_firewall_policies | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
get_interfaces | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
get_interfaces_counters | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ |
get_interfaces_ip | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
get_ipv6_neighbors_table | ❌ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ |
get_lldp_neighbors | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
get_lldp_neighbors_detail | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
get_mac_address_table | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
get_network_instances | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ |
get_ntp_peers | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
get_ntp_servers | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
get_ntp_stats | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
get_optics | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ✅ |
get_probes_config | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
get_probes_results | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
get_route_to | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
get_snmp_information | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
get_users | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
get_vlans | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ |
is_alive | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
ping | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ |
traceroute | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
- ✅ – supported
- ❌ – not supported
- ☠ – broken
通过 Getters
类,比方 get_config
就能够失去设施的配置 (running 和 startup)、get_facts
获取设施的根本信息、get_interfaces
获取接口信息等等,也是十分不便的。
其余办法
_ | EOS | Junos | IOS-XR (NETCONF) | IOS-XR | NX-OS | IOS |
---|---|---|---|---|---|---|
load_template | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
ping | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ |
traceroute | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
可用的配置模板
set_hostname
(JunOS, IOS-XR, IOS) – Configures the hostname of the device.set_ntp_peers
(JunOS, IOS-XR, EOS, NXOS, IOS) – Configures NTP peers of the device.delete_ntp_peers
(JunOS, IOS-XR, EOS, NXOS, IOS): Removes NTP peers from device’s configuration.set_probes
(JunOS, IOS-XR): Configures RPM/SLA probes.schedule_probes
(IOS-XR): On Cisco devices, after defining the SLA probes, it is mandatory to schedule them. Defined also for JunOS as empty template, for consistency reasons.delete_probes
(JunOS, IOS-XR): Removes RPM/SLA probes.
以上办法,大家能够在试验环境测试下。
如何装置
须要确保 netmiko 曾经被装置,依赖与 netmiko 的。
- 通过 pip3 装置
python -m pip install napalm
备注:从版本 3.0.0 之后,NAPALM 仅反对 Python 3.6+.
如何降级
pip install napalm -U
备注:如果 napalm 有降级了,能够通过该办法进行降级.
实操示例
视频中演示的代码,都在这里了.
根本的设施连贯
from napalm import get_network_driver
import pprint
pp = pprint.PrettyPrinter(indent=2)
# drive 是一个类 class,传入 drive_name
drive = get_network_driver('ios')
# 类实例化
conn = drive(hostname='192.168.0.20',
username='cisco',
password='cisco',
optional_args={'port': 22})
# 建设连贯会话
conn.open()
# 应用其中一个办法,获取接口 ip 地址
ouput = conn.get_interfaces_ip()
# 打印后果
pp.pprint(ouput)
# 敞开连贯
conn.close()
执行脚本后,后果如下所示:
备份配置
from napalm import get_network_driver
import pprint
import os
pp = pprint.PrettyPrinter(indent=2)
host = "192.168.0.20"
# drive 是一个类 class
drive = get_network_driver('ios')
# 类实例化
conn = drive(hostname= host,
username= 'cisco',
password= 'cisco',
optional_args= {'port': 22})
# 建设连贯会话
conn.open()
# 获取设施配置信息
output = conn.get_config()
# 打印后果
pp.pprint(output)
running_config = output['running']
# 写入文件
with open(os.path.join('LOG', f'{host}-running.conf'), 'w+') as f:
f.writelines(running_config)
# 敞开连贯
conn.close()
执行完脚本,后果如下所示:
默认蕴含了 3 个备份配置:
- running 配置:就是以后运行配置.
- startup 配置:就是启动配置了.
- candidate 配置,这个个别为空.
这里,我保留了 running.config
配置文件.
获取设施根底信息
# drive 是一个类 class
drive = get_network_driver('ios')
# 类实例化
conn = drive(hostname='192.168.0.20',
username='cisco',
password='cisco',
optional_args={'port': 22})
# 建设连贯会话
conn.open()
# 获取接口 ip 地址
output = conn.get_facts()
# 打印后果
pp.pprint(ouput)
# 敞开连贯
conn.close()
执行脚本后,后果如下所示:
get_facts()
办法采集了如下字段:
- 域名、主机名称、接口列表、型号、版本号、序列号、运行工夫、厂商.
发送命令
# drive 是一个类 class
drive = get_network_driver('ios')
# 类实例化
conn = drive(hostname='192.168.0.20',
username='cisco',
password='cisco',
optional_args={'port': 22, 'secret': 'cisco'})
# 建设连贯会话
conn.open()
# 发送命令
output = conn.cli(['show ip int brief', 'show arp'])
pp.pprint(output)
# 敞开连贯
conn.close()
执行脚本后,后果如下所示:
阐明:这里要注意下如果用户权限不够或者须要进入 enable
的,须要 optional_args
减少 secret
参数,表明须要进入特权模式了.
如果执行的命令权限不容许,就会报如下谬误:
ValueError: Failed to enter enable mode. Please ensure you pass the 'secret' argument to ConnectHandler.
配置类
通过 scp 协定下发配置,它不须要 enable 明码.
前提条件:
- 设施要开启
scp
服务,ip scp server enable
. -
开启
archive
服务,备份配置到本地 flash 上;archive path flash:R1.conf write-memory
合并配置
阐明:
- load_merge_candidate():加载配置文件.
- commit_config():提交配置.
-
revert_in=30:如果平台反对,能够设置工夫挂起配置提交,超时没 commit 就复原配置。
根底玩法
模板文件门路:
templates\ios_logging_config.cfg
logging host 10.1.1.2
from napalm import get_network_driver
import pprint
pp = pprint.PrettyPrinter(indent=2)
# drive 是一个类 class
drive = get_network_driver('ios')
# 类实例化
conn = drive(hostname='192.168.0.20',
username='cisco',
password='cisco',
optional_args={'port': 22})
# 建设连贯会话
conn.open()
try:
conn.load_merge_candidate(filename='templates/ios_logging_config.cfg')
conn.commit_config()
except Exception as e:
print(e)
如果设施上没开启 scp
服务就会报错:
SCP file transfers are not enabled. Configure 'ip scp server enable' on the device.
高级一点玩法:
模板文件门路:templates\ios_logging_config.cfg
def merge_config(vendor, devices, template_file):
try:
# drive 是一个类 class
drive = get_network_driver(vendor)
# 类实例化
conn = drive(**devices)
# 建设连贯会话
conn.open()
except Exception as e:
print("连贯谬误:{}".format(e))
return
try:
conn.load_merge_candidate(filename=template_file)
new_config = conn.compare_config()
if new_config:
print('预推送的配置如下:')
print('='*80)
print(new_config)
print('=' * 80)
choice = input("你要开始推送这些配置嘛, [Y/N]:")
if choice.lower() == 'y':
print('开始提交配置,请稍后...')
conn.commit_config()
rollback = input("是否须要回滚配置,输出 Y:回滚,输出 N,不回滚. [Y/N]")
if rollback.lower() == 'y':
print('开始回滚配置,请稍后...')
conn.rollback()
print('配置已回滚,请查看配置.')
else:
print('配置曾经下发胜利.')
else:
conn.discard_config()
print('本次预配置没有推送.')
else:
print('无需反复配置.')
except Exception as e:
print(e)
finally:
conn.close()
if __name__ == '__main__':
vendor = 'ios'
devices = {'hostname': '192.168.0.20',
'username': 'cisco',
'password': 'cisco',
'optional_args':{'port': 22}
}
tmp = 'templates/ios_logging_config.cfg'
merge_config(vendor, devices, template_file=tmp)
配置替换
办法:load_replace_candidate()
def replace_config(vendor, devices, template_file):
try:
# drive 是一个类 class
drive = get_network_driver(vendor)
# 类实例化
conn = drive(**devices)
# 建设连贯会话
conn.open()
except Exception as e:
print("连贯谬误:{}".format(e))
return
try:
if not (os.path.exists(template_file) and os.path.isfile(template_file)):
msg = '文件不存在或文件类型不可用.'
raise ValueError(msg)
print("开始加载候选替换配置...")
# 这个还未加载到设施上的
conn.load_replace_candidate(template_file)
# 配置比拟
print("\n 预览配置比照:")
print(">"*80)
compare_result = conn.compare_config()
print(compare_result)
print(">" * 80)
# You can commit or discard the candidate changes.
if compare_result:
try:
choice = input("\nWould you like to commit these changes? [yN]:").lower()
except NameError:
choice = input("\nWould you like to commit these changes? [yN]:").lower()
if choice == "y":
print("Committing ...")
conn.commit_config()
else:
print("Discarding ...")
conn.discard_config()
else:
print('没有新的配置.')
conn.discard_config()
conn.close()
print("Done...")
except Exception as e:
print(e)
if __name__ == '__main__':
vendor = 'ios'
devices = {'hostname': '192.168.0.20',
'username': 'cisco',
'password': 'cisco',
'optional_args':{'port': 22}
}
tmp = 'LOG/192.168.0.20-running.conf'
replace_config(vendor, devices, template_file=tmp)
阐明:这里我用思科的设施,留神的是,如果 running
的配置里应用了banner
,我是都提前把它删除了,不然会报错,这块我临时没测试进去,如果哪位小伙伴试出来了,请告知我,谢谢。
Jinja2 模板
-
装置 jinja2
python -m pip install jinja2
-
jiaja2 模板配置
模板文件门路:templates/ssh-acl.tpl
{% for host in hosts -%} access-list 20 permit host {{host}} {% endfor -%} line vty 0 4 access-class 20 in
-
下发配置
from napalm import get_network_driver from jinja2 import FileSystemLoader, Environment import pprint import logging pp = pprint.PrettyPrinter(indent=2) def connect_device(vendor, devices, hosts): try: # drive 是一个类 class drive = get_network_driver(vendor) # 类实例化 conn = drive(**devices) # 建设连贯会话 conn.open() except Exception as e: print("连贯谬误:{}".format(e)) return try: loader = FileSystemLoader('templates') env = Environment(loader=loader) tpl = env.get_template('ssh-acl.tpl') config_tpl = tpl.render({'hosts': hosts}) # print(config_tpl) conn.load_merge_candidate(config=config_tpl) conn.commit_config() except Exception as e: print(e) finally: conn.close() if __name__ == '__main__': vendor = 'ios' devices = {'hostname': '192.168.0.20', 'username': 'cisco', 'password': 'cisco', 'optional_args':{'secret': 'cisco', 'port': 22} # 如果 enable 须要明码,退出 'secret' 参数 } hosts = ['192.168.0.1', '192.168.0.254'] connect_device(vendor, devices, hosts)
这里能够打印下
config_tpl
, 看看下发的配置是啥:# print(config_tpl)的输入后果如下所示:access-list 20 permit host 192.168.0.1 access-list 20 permit host 192.168.0.254 line vty 0 4 access-class 20 in
配置更改回滚
conn.rollback()
备注:见后面章节演示.
验证部署
验证设施的状态是否是你冀望的.
-
定义一个 yaml 文件,定义预期想要的状态
模板文件门路:
templates/napalm_t.yaml
--- - get_facts: 'serial_number': '99CBK1M35C217V5Z7ABWQ' - get_interfaces_ip: GigabitEthernet0/0: ipv4: 192.168.0.20
-
compliance_report 办法
import pprint from napalm import get_network_driver pp = pprint.PrettyPrinter(indent=2) def connect_device(vendor, devices, hosts): try: # drive 是一个类 class drive = get_network_driver(vendor) # 类实例化 conn = drive(**devices) # 建设连贯会话 conn.open() except Exception as e: print("连贯谬误:{}".format(e)) return try: out = conn.compliance_report('templates/napalm_t.yaml') pp.pprint(out) except Exception as e: print(e) finally: conn.close() if __name__ == '__main__': vendor = 'ios' devices = {'hostname': '192.168.0.20', 'username': 'cisco', 'password': 'cisco', 'optional_args':{'port': 22} } hosts = ['192.168.0.1', '192.168.0.254'] connect_device(vendor, devices, hosts)
执行后果如下所示:
{ 'complies': True, 'get_facts': { 'complies': True, 'extra': [], 'missing': [], 'present': { 'serial_number': { 'complies': True, 'nested': False}}}, 'get_interfaces_ip': { 'complies': True, 'extra': [], 'missing': [], 'present': { 'GigabitEthernet0/0': { 'complies': True, 'nested': True}}}, 'skipped': []}
阐明:
complies
的 value 值为True
阐明失常,如果False
示意和预期构想不太统一。
反对上下文治理
通过上下文治理就不须要调用 open()和 close()办法了.
# 类实例化
drive = get_network_driver('ios')
# with 上下文治理
with drive(hostname='192.168.0.20',username='cisco',password='cisco',optional_args={'port': 22}) as conn:
output = conn.get_facts()
# 打印后果
pp.pprint(ouput)
ping 办法
默认格局:ping x.x.x.x timeout 2 size 100 repeat 5
#!/usr/bin/env python3
#-*- coding:UTF-8 -*-
from napalm import get_network_driver
import pprint
import logging
# logging.basicConfig(filename='debug.log', level=logging.DEBUG)
# logger = logging.getLogger('napalm')
pp = pprint.PrettyPrinter(indent=2)
def connect_device(vendor, devices, dst_ip):
try:
# drive 是一个类 class
drive = get_network_driver(vendor)
# 类实例化
conn = drive(**devices)
# 建设连贯会话
conn.open()
except Exception as e:
print("连贯谬误:{}".format(e))
return
try:
for ip in dst_ip:
output = conn.ping(ip)
pp.pprint(output)
except Exception as e:
print(e)
finally:
conn.close()
if __name__ == '__main__':
vendor = 'ios'
devices = {'hostname': '192.168.0.20',
'username': 'cisco',
'password': 'cisco',
'optional_args':{'port': 22}
}
dst_ip = ['192.168.0.19', '192.168.0.20']
connect_device(vendor, devices, dst_ip)
回显的后果:
{ 'success': { 'packet_loss': 0,
'probes_sent': 5,
'results': [{'ip_address': '192.168.0.19', 'rtt': 0.0},
{'ip_address': '192.168.0.19', 'rtt': 0.0},
{'ip_address': '192.168.0.19', 'rtt': 0.0},
{'ip_address': '192.168.0.19', 'rtt': 0.0},
{'ip_address': '192.168.0.19', 'rtt': 0.0}],
'rtt_avg': 2.0,
'rtt_max': 3.0,
'rtt_min': 2.0,
'rtt_stddev': 0.0}}
{ 'success': { 'packet_loss': 0,
'probes_sent': 5,
'results': [{'ip_address': '192.168.0.20', 'rtt': 0.0},
{'ip_address': '192.168.0.20', 'rtt': 0.0},
{'ip_address': '192.168.0.20', 'rtt': 0.0},
{'ip_address': '192.168.0.20', 'rtt': 0.0},
{'ip_address': '192.168.0.20', 'rtt': 0.0}],
'rtt_avg': 1.0,
'rtt_max': 2.0,
'rtt_min': 1.0,
'rtt_stddev': 0.0}}
好了,文章的解说就到此结束了,各个性能曾经给大家演示了,各位小伙伴如实操一遍,置信就能把握了并依据需要进行改写了。
如果须要更具体的信息,请挪动官网进行查阅。
别忘了,动动手分享下,点击、珍藏、三连击! 哈哈 …
如果喜爱的我的文章,欢送关注我的公众号:点滴技术,扫码关注,不定期分享