[toc]
NAPALM概述
官网链接
其余drive链接(国人)
NAPALM全称为Network Automation and Programmability Abstraction Layer with Multivendor support,翻译起来就是反对"多厂商"网络自动化和可编程的形象层.
NAPALM是一个python开源的第三方模块,截至2021.11月,反对的厂商如下所示:
尽管反对厂商不是很多,临时没有反对国内厂商,但性能都是很弱小的。
Cisco IOSCisco NX-OSCisco IOS-XRJuniper JUNOSArista 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_driverimport pprintpp = pprint.PrettyPrinter(indent=2)# drive是一个类class,传入drive_namedrive = 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_driverimport pprintimport ospp = pprint.PrettyPrinter(indent=2)host = "192.168.0.20"# drive是一个类classdrive = 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是一个类classdrive = 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是一个类classdrive = 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_driverimport pprintpp = pprint.PrettyPrinter(indent=2)# drive是一个类classdrive = 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_driverfrom jinja2 import FileSystemLoader, Environmentimport pprintimport loggingpp = 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.1access-list 20 permit host 192.168.0.254line 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 pprintfrom napalm import get_network_driverpp = 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_driverimport pprintimport 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}}
好了,文章的解说就到此结束了,各个性能曾经给大家演示了,各位小伙伴如实操一遍,置信就能把握了并依据需要进行改写了。
如果须要更具体的信息,请挪动官网进行查阅。
别忘了,动动手分享下,点击、珍藏、三连击! 哈哈...
如果喜爱的我的文章,欢送关注我的公众号:点滴技术,扫码关注,不定期分享