[PYTHON] Continuation ・ I tried touching the multi-vendor router control API library NAPALM

This is the article on the 24th day of NetOpsCoding Advent Calendar 2016.

NAPALM is an open source Python library for setting up network devices and acquiring information, and controls multiple vendor products with a unified interface. It is developed for that purpose. For those who are planning to automate in a multi-vendor network operating environment, a multi-vendor library like NAPALM is a long-awaited existence.

NAPALM was introduced in the article "I tried touching the router control API library NAPALM" in June 2015, but it is still NANOG. Development is being actively continued under the initiative of the community centered on, and the number of functions and compatible models is increasing one after another. I felt that it might be time to put it into an actual operation site in a multi-vendor environment, so I summarized the information again this time.

Compatible models

NAPALM supports the following network operating systems.

--Arista EOS: 4.15.0F or later --Juniper JunOS: 12.1 or later --Cisco IOS-XR: 5.1.0 or later --Fortinet FortiOS: 5.2.0 or later --IBM: Supported version unknown --Cisco NXOS: 6.1 or later (Nexus 5k, 6k, 7k version 7.2 or later) --Cisco IOS: 12.4 (20) T or later

In the background of NAPALM, the manufacturer's official API (Juniper PyEZ and Arista eAPI pyeapi) etc.), and unofficial APIs developed by individuals or communities (pyIOSXR and netmiko) Etc.) are combined to make up.

Since it is a community-led development, it seems that the functions are being expanded steadily with the idea that "you can create the missing functions yourself". As of June 2015, there were only four compatible models, IOS XR, JUNOS, EOS, and FortiOS, so it can be seen that development has progressed dramatically in the past year and a half.

Corresponding function

At the time of this article, NAPALM has the following features implemented. However, the functions implemented by the OS vary, so please refer to the official page Supported Devices for details.

--Load config (replace / merge) / Compare / Commit / Dicard / Rollback --Acquisition of device information --Get SNMP information --Acquisition of NTP information --Get ARP table --Getting interface information --Acquisition of LLDP information --Get BGP information --Getting routing information --Getting SLA prove information --Acquisition of user information --Acquisition of optical output information --Getting VRF network instances information --Get firewall policy information --Get ping information --Get Traceroute information

It is very helpful in developing automation software that the function of the status confirmation system is substantial. As I wrote in my previous blog "I tried using PyEZ and JSNAPy", it is very important to make the process of checking the normality of network devices into software. It is a work that breaks. Implement "Implementation of information acquisition command-> Acquire target character string with regular expression-> Acquire extracted character string as information or judge normal / abnormal" which is normally inevitable for software developers By using the process as a library without being aware of the vendor / model, it is possible to significantly reduce the development effort.

Working with automation frameworks

NAPALM is not only embedded in software, but is also expected to be called from an automation framework that is being introduced in server infrastructure operations. At the moment, NAPALM modules are being developed to work with Ansible and Salt.

This article does not provide details, but if you are interested, please refer to the following materials.

I tried using NAPALM

Let's try using a router to see what you can actually do with NAPALM.

As a result of randomly touching the function I want to use, the amount has become quite large, so please check from the item you are interested in.

-Environment -Reference -[Install](http://qiita.com/taijijiji/items/9dfcaa6d868958985095#%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC% E3% 83% AB) -[Preparation of router](http://qiita.com/taijijiji/items/9dfcaa6d868958985095#%E3%83%AB%E3%83%BC%E3%82%BF%E3%81%AE%E4%B8 % 8B% E6% BA% 96% E5% 82% 99) -[NAPALM usage example: Acquisition of device information](http://qiita.com/taijijiji/items/9dfcaa6d868958985095#napalm%E5%88%A9%E7%94%A8%E4%BE%8B-%E6%A9 % 9F% E5% 99% A8% E6% 83% 85% E5% A0% B1% E3% 81% AE% E5% 8F% 96% E5% BE% 97) -[NAPALM usage example: Obtaining interface address information](http://qiita.com/taijijiji/items/9dfcaa6d868958985095#napalm%E5%88%A9%E7%94%A8%E4%BE%8B-%E3% 82% A4% E3% 83% B3% E3% 82% BF% E3% 83% 95% E3% 82% A7% E3% 83% BC% E3% 82% B9% E3% 82% A2% E3% 83% 89% E3% 83% AC% E3% 82% B9% E6% 83% 85% E5% A0% B1% E3% 81% AE% E5% 8F% 96% E5% BE% 97) -[NAPALM usage example: Get ARP table information](http://qiita.com/taijijiji/items/9dfcaa6d868958985095#napalm%E5%88%A9%E7%94%A8%E4%BE%8B-arp%E3 % 83% 86% E3% 83% BC% E3% 83% 96% E3% 83% AB% E6% 83% 85% E5% A0% B1% E3% 81% AE% E5% 8F% 96% E5% BE % 97) -[NAPALM usage example: Acquisition of routing information for a specific route](http://qiita.com/taijijiji/items/9dfcaa6d868958985095#napalm%E5%88%A9%E7%94%A8%E4%BE%8B-% E7% 89% B9% E5% AE% 9A% E7% B5% 8C% E8% B7% AF% E3% 81% AE% E3% 83% AB% E3% 83% BC% E3% 83% 86% E3% 82% A3% E3% 83% B3% E3% 82% B0% E6% 83% 85% E5% A0% B1% E3% 81% AE% E5% 8F% 96% E5% BE% 97) -[NAPALM usage example: Get BGP neighbor information](http://qiita.com/taijijiji/items/9dfcaa6d868958985095#napalm%E5%88%A9%E7%94%A8%E4%BE%8B-bgp%E3 % 83% 8D% E3% 82% A4% E3% 83% 90% E3% 83% BC% E6% 83% 85% E5% A0% B1% E3% 81% AE% E5% 8F% 96% E5% BE % 97) -[NAPALM usage example: Router configuration settings](http://qiita.com/taijijiji/items/9dfcaa6d868958985095#napalm%E5%88%A9%E7%94%A8%E4%BE%8B-%E3%83 % AB% E3% 83% BC% E3% 82% BF% E3% 81% AE% E3% 82% B3% E3% 83% B3% E3% 83% 95% E3% 82% A3% E3% 82% B0 % E8% A8% AD% E5% AE% 9A) -Summary -Finally

environment

In this article, I experimented in the following environment. Everything except the Macbook can be prepared for free.

--PC (host machine) - MacBookAir OSX El Capitan 10.11.6 --Virtual router

If you want to know about Vagrant integration of firefly and IOS XRv, please refer to the following blog. -The story of progress in automated development when running firefly with Vagrant -I tried IOS-XRv Vagrant

reference

This time, I proceeded with the implementation while looking at the following articles. -NAPALM Github Page -NAPALM Official Document

Installation

Install the latest version of NAPALM (version 1.1.0 at the time of this blog). Here, pip, which is a Python package management system, is used.

% pip install napalm
(snip)


% pip list
(snip)
napalm (1.1.0)
napalm-base (0.21.0)
napalm-eos (0.5.0)
napalm-fortios (0.3.0)
napalm-ibm (0.1.6)
napalm-ios (0.5.0)
napalm-iosxr (0.4.2)
napalm-junos (0.5.1)
napalm-nxos (0.5.0)
napalm-panos (0.2.2)
napalm-pluribus (0.4.2)
(snip)


% pip show napalm                                                                                           (git)-[master]
Name: napalm
Version: 1.1.0
Summary: Network Automation and Programmability Abstraction Layer with Multivendor support
Home-page: https://github.com/napalm-automation/napalm
Author: David Barroso
Author-email: [email protected]
License: UNKNOWN
Location: /usr/local/lib/python2.7/site-packages
Requires: napalm-pluribus, napalm-base, napalm-ios, napalm-iosxr, napalm-ibm, napalm-junos, napalm-eos, napalm-nxos, napalm-fortios, napalm-panos

Router preparation

firefly settings

In order to use firefly, it is set as follows. --Host name: firefly1 --IP address: 192.168.34.16/24 --Username: user1 --Password: password1

For the procedure for building firefly Vagrant, please refer to The story of how automated development progressed when running firefly with Vagrant.

Vagrantfile


# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure(2) do |config|
    config.vm.box = "juniper/ffp-12.1X47-D20.7"
    config.vm.define :firefly1 do | firefly1 |
        firefly1.vm.hostname = 'firefly1'
        firefly1.vm.network "private_network",ip: "192.168.34.16",netmask: "255.255.255.0"
    end
end

firefly additional settings


set system root-authentication plain-text-password
set system login user user1 class super-user
set system login user user1 authentication plain-text-password

#The default setting is ge-0/0/Communication with the host machine is not possible because 1 is set in the untrust zone.
#Here the host machine(MacbookAir)I want to operate the automation tool and communicate with ge-0/0/I am changing 1 to trust zone.
set security zones security-zone trust interfaces ge-0/0/1
set security zones security-zone trust interfaces ge-0/0/1.0 host-inbound-traffic system-services all
set system time-zone Asia/Tokyo


#The default setting is flow-based transfer mode(Mode to operate firewall function)Is enabled and
#Routing protocols such as BGP and OSPF will not work as they are.
#Here, in order to operate the routing protocol, packet-The setting to change to based transfer mode is implemented.
#To switch the mode, you need to restart after setting.
delete security policies
set security forwarding-options family mpls mode packet-based
set security forwarding-options family inet6 mode packet-based

#BGP related settings for dummies
set routing-options autonomous-system 65001
set protocols bgp family inet unicast
set protocols bgp group ge-0/0/2 type external
set protocols bgp group ge-0/0/2 neighbor 192.168.35.2 peer-as 65002
set protocols bgp group ge-0/0/2 export advertised_for_firefly2
set routing-options rib inet.0 static route 10.10.10.0/24 discard
set routing-options rib inet.0 static route 10.10.20.0/24 discard
set policy-options policy-statement advertised_for_firefly2 term 10 from route-filter 10.10.10.0/24 exact
set policy-options policy-statement advertised_for_firefly2 term 10 then accept
set policy-options policy-statement advertised_for_firefly2 term 999 then reject


#In addition, I was able to use NAPALM without setting the following NETCONF.
# (Not set) set system services netconf ssh

Check settings with firefly



root@firefly1> show configuration
## Last commit: 2016-12-24 18:32:08 JST by root
version 12.1X47-D20.7;
system {
    host-name firefly1;
    time-zone Asia/Tokyo;
    root-authentication {
        encrypted-password "$1$EUe8ffbf$HT20ATkJCGIyslemV9hTf1"; ## SECRET-DATA
        ssh-rsa "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqs9vHYiqhpS5/5QWI2EskcTz1nMdv+1NlxrCaDyO8+03rzyHiOjXILcYx5MHExvw4JRlMMxiO0D3dHW+i4EtIVTSstyzEyd2coxLtgBp4VfaINBLInQKQNxOPioPUtu7rJynR9cHPk7DQw7QjCCUawYgQHWzCiiYSnmKWZrJAgVQZzfP2LEj1+Cqrg1ro8VQ4CpLeplOT4qXmlTE/dvQFPHabhAmGdP7JZv4IDPwZtkJ7gRv/PfYdTpn96IiG4Y09yIMPXaq40A82bczptazcOdScVyjUrFe8NbzQfnkVpe2C6ieDc7lU7PQhqqBGPpb1eEbQo1vq2Lo9b88dT7EH vagrant"; ## SECRET-DATA
    }
    login {
        user user1 {
            uid 2001;
            class super-user;
            authentication {
                encrypted-password "$1$P9L/Y/Ca$dzv5waDzJeYa5VdKGDm340"; ## SECRET-DATA
            }
        }
        user vagrant {
            uid 2000;
            class super-user;
            authentication {
                ssh-rsa "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key"; ## SECRET-DATA
            }
        }
    }
    services {
        ssh {
            root-login allow;
        }
        web-management {
            http {
                interface ge-0/0/0.0;
            }
        }
    }
    syslog {
        user * {
            any emergency;
        }
        file messages {
            any any;
            authorization info;
        }
        file interactive-commands {
            interactive-commands any;
        }
    }
    license {
        autoupdate {
            url https://ae1.juniper.net/junos/key_retrieval;
        }
    }
}
interfaces {
    ge-0/0/0 {
        unit 0 {
            family inet {
                dhcp;
            }
        }
    }
    ge-0/0/1 {
        unit 0 {
            family inet {
                address 192.168.34.16/24;
            }
        }
    }
    ge-0/0/2 {
        unit 0 {
            family inet {
                address 192.168.35.1/30;
            }
        }
    }
}
routing-options {
    rib inet.0 {
        static {
            route 10.10.10.0/24 discard;
            route 10.10.20.0/24 discard;
        }
    }
    autonomous-system 65001;
}
protocols {
    bgp {
        family inet {
            unicast;
        }
        group ge-0/0/2 {
            type external;
            export advertised_for_firefly2;
            neighbor 192.168.35.2 {
                peer-as 65002;
            }
        }
    }
}
policy-options {
    policy-statement advertised_for_firefly2 {
        term 10 {
            from {
                route-filter 10.10.10.0/24 exact;
            }
            then accept;
        }
        term 999 {
            then reject;
        }
    }
}
security {
    forwarding-options {
        family {
            inet6 {
                mode packet-based;
            }
            mpls {
                mode packet-based;
            }
        }
    }
    screen {
        ids-option untrust-screen {
            icmp {
                ping-death;
            }
            ip {
                source-route-option;
                tear-drop;
            }
            tcp {
                syn-flood {
                    alarm-threshold 1024;
                    attack-threshold 200;
                    source-threshold 1024;
                    destination-threshold 2048;
                    queue-size 2000; ## Warning: 'queue-size' is deprecated
                    timeout 20;
                }
                land;
            }
        }
    }
    zones {
        functional-zone management {
            interfaces {
                ge-0/0/0.0 {
                    host-inbound-traffic {
                        system-services {
                            all;
                        }
                        protocols {
                            all;
                        }
                    }
                }
            }
        }
        security-zone trust {
            tcp-rst;
            interfaces {
                ge-0/0/1.0 {
                    host-inbound-traffic {
                        system-services {
                            all;
                        }
                    }
                }
                ge-0/0/2.0 {
                    host-inbound-traffic {
                        system-services {
                            all;
                        }
                    }
                }
            }
        }
        security-zone untrust {
            screen untrust-screen;
        }
    }
}

Make sure you can ssh login to firefly from the host machine


% ssh [email protected]
Password:
--- JUNOS 12.1X47-D20.7 built 2015-03-03 21:53:50 UTC
user1@firefly1>
user1@firefly1> show version
Hostname: firefly1
Model: firefly-perimeter
JUNOS Software Release [12.1X47-D20.7]

IOSXRv configuration

In order to use IOSXRv, it is set as follows. --Hostname: ios (default) --IP address: 127.0.0.1 --IOSXRv-Vagrant default settings use TCP2223 for SSH port from host machine --Username: vagrant --Password: vagrant

Please refer to I tried IOS-XRv Vagrant for the procedure to build IOSXRv.

Vagrantfile


# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
  config.vm.box = "IOS-XRv"
end

IOSXRv additional settings


#Required when using NAPALM
xml agent tty iteration off

#Dummy BGP settings
router bgp 65001
 timers bgp 30 90
 address-family ipv4 unicast
  network 0.0.0.0/0
 !
 neighbor 192.168.0.1
  remote-as 65002
  description test_AS65002
  address-family ipv4 unicast
   send-community-ebgp
   next-hop-self
   soft-reconfiguration inbound always
  !
 !
!
end

Check settings with IOS XRv


RP/0/RP0/CPU0:ios#show running-config
Fri Dec 23 13:16:25.273 UTC
Building configuration...
!! IOS XR Configuration version = 6.2.1.23I
!! Last configuration change at Fri Dec 23 13:08:29 2016 by vagrant
!
telnet vrf default ipv4 server max-servers 10
username vagrant
 group root-lr
 group cisco-support
 secret 5 $1$RQve$C1P.pH/koIKYsybRgxtSZ0
!
tpa
 address-family ipv4
  update-source MgmtEth0/RP0/CPU0/0
 !
!
interface MgmtEth0/RP0/CPU0/0
 ipv4 address dhcp
!
router static
 address-family ipv4 unicast
  0.0.0.0/0 MgmtEth0/RP0/CPU0/0 10.0.2.2
 !
!
router bgp 65001
 timers bgp 30 90
 address-family ipv4 unicast
  network 0.0.0.0/0
 !
 neighbor 192.168.0.1
  remote-as 65002
  description test_AS65002
  address-family ipv4 unicast
   send-community-ebgp
   next-hop-self
   soft-reconfiguration inbound always
  !
 !
!
grpc
 port 57777
!
xml agent tty
 iteration off
!
ssh server v2
ssh server vrf default
end

NAPALM usage example: Acquisition of device information

First, let's get the device information. Information can be obtained as a dictionary type variable by using get_facts (). ..

For JUNOS

get_info.py


#! /usr/bin/env python
# -*- coding: utf-8 -*-

import napalm
from pprint import pprint

driver = napalm.get_network_driver('junos')
device = driver(
    hostname='192.168.34.16',
    username='user1',
    password='password1' )

print 'Open session: ',
device.open()
print 'OK'

pprint(device.get_facts())

print 'Close session: ',
device.close()
print 'OK'

Execution result


% python get_info.py 

Open session:  OK
get facts:
{u'fqdn': u'firefly1',
 u'hostname': u'firefly1',
 u'interface_list': ['ge-0/0/0',
                     'gr-0/0/0',
                     'ip-0/0/0',
                     'lsq-0/0/0',
                     'lt-0/0/0',
                     'mt-0/0/0',
                     'sp-0/0/0',
                     'ge-0/0/1',
                     'ge-0/0/2',
                     '.local.',
                     'dsc',
                     'gre',
                     'ipip',
                     'irb',
                     'lo0',
                     'lsi',
                     'mtun',
                     'pimd',
                     'pime',
                     'pp0',
                     'ppd0',
                     'ppe0',
                     'st0',
                     'tap',
                     'vlan'],
 u'model': u'FIREFLY-PERIMETER',
 u'os_version': u'12.1X47-D20.7',
 u'serial_number': u'f0016079634f',
 u'uptime': 1740,
 u'vendor': u'Juniper'}
Close session:  OK

Checking the status of the actual router


root@firefly1> show version
Hostname: firefly1
Model: firefly-perimeter
JUNOS Software Release [12.1X47-D20.7]

root@firefly1> show chassis hardware
Hardware inventory:
Item             Version  Part number  Serial number     Description
Chassis                                f0016079634f      FIREFLY-PERIMETER
Midplane
System IO
Routing Engine                                           FIREFLY-PERIMETER RE
FPC 0                                                    Virtual FPC
  PIC 0                                                  Virtual VTNET GE
Power Supply 0

For IOS XR

get_info.py


#! /usr/bin/env python
# -*- coding: utf-8 -*-

import napalm
from pprint import pprint

driver = napalm.get_network_driver('iosxr')
device = driver(
    hostname='127.0.0.1',
    username='vagrant',
    password='vagrant',
    # IOSXRv default ssh port
    optional_args={'port': 2223}) 

print 'Open session: ',
device.open()
print 'OK'

print 'get facts: '
pprint(device.get_facts())

print 'Close session: ',
device.close()
print 'OK'

Execution result


% python get_info.py                                                                                                                                                                         (git)-[master]
Open session:  OK
get facts:
{u'fqdn': u'ios',
 u'hostname': u'ios',
 u'interface_list': [u'Null0', u'MgmtEth0/RP0/CPU0/0'],
 u'model': u'XRV-P-L--CH',
 u'os_version': u'6.2.1.23I',
 u'serial_number': u'XRV-SN---CH',
 u'uptime': 1585,
 u'vendor': u'Cisco'}

Checking the status of the actual router


RP/0/RP0/CPU0:ios#show version
Fri Dec 23 12:38:05.156 UTC

Cisco IOS XR Software, Version 6.2.1.23I
Copyright (c) 2013-2016 by Cisco Systems, Inc.

Build Information:
 Built By     : jwu
 Built On     : Mon Nov 21 00:33:58 PST 2016
 Build Host   : iox-ucs-005
 Workspace    : /auto/iox-ucs-005-san1/nightly/xr-dev_16.11.20C/iosxrv-x64
 Version      : 6.2.1.23I
 Location     : /opt/cisco/XR/packages/

cisco IOS XRv x64 () processor
System uptime is 34 minutes


RP/0/RP0/CPU0:ios#show inventory
Fri Dec 23 12:39:25.870 UTC
NAME: "0/RP0", DESCR: "FLEX_PH"
PID: XRV-P-L--RP       , VID: FLEX_PH, SN: XRV-SN---RP

NAME: "Rack 0", DESCR: "FLEX_PH"
PID: XRV-P-L--CH       , VID: FLEX_PH, SN: XRV-SN---CH

NAPALM usage example: Obtaining interface address information

To get the interface address information, use the get_interfaces_ip () function.

Not implemented this time, but if you want to get interface up / down and MAC information, [get_interfaces () function](https://napalm.readthedocs.io/en/latest/base.html#napalm_base.base.NetworkDriver .get_interfaces), get_interfaces_counters () function if you want to get the interface error counter, If you want to get it, you can get the information by using get_optics () function. ..

For JUNOS

get_info.py


#! /usr/bin/env python
# -*- coding: utf-8 -*-

import napalm
from pprint import pprint

driver = napalm.get_network_driver('junos')
device = driver(
    hostname='192.168.34.16',
    username='user1',
    password='password1')

print 'Open session: ',
device.open()
print 'OK'

print 'get interface IP: '
pprint(device.get_interfaces_ip())

print 'Close session: ',
device.close()
print 'OK'

Execution result


% python get_info.py 

Open session:  OK
get interface IP:
{u'ge-0/0/0.0': {u'ipv4': {u'10.0.2.15': {u'prefix_length': 24}}},
 u'ge-0/0/1.0': {u'ipv4': {u'192.168.34.16': {u'prefix_length': 24}}},
 u'ge-0/0/2.0': {u'ipv4': {u'192.168.35.1': {u'prefix_length': 30}}},
 u'lo0.16384': {u'ipv4': {u'127.0.0.1': {u'prefix_length': 0}}},
 u'lo0.16385': {u'ipv4': {u'10.0.0.1': {u'prefix_length': 0},
                          u'10.0.0.16': {u'prefix_length': 0},
                          u'128.0.0.1': {u'prefix_length': 0},
                          u'128.0.0.4': {u'prefix_length': 0},
                          u'128.0.1.16': {u'prefix_length': 0}}},
 u'sp-0/0/0.16383': {u'ipv4': {u'10.0.0.1': {u'prefix_length': 0},
                               u'10.0.0.6': {u'prefix_length': 0},
                               u'128.0.0.1': {u'prefix_length': 0},
                               u'128.0.0.6': {u'prefix_length': 0}}}}
Close session:  OK

Checking the status of the actual router


root@firefly1> show interfaces terse
Interface               Admin Link Proto    Local                 Remote
ge-0/0/0                up    up
ge-0/0/0.0              up    up   inet     10.0.2.15/24
gr-0/0/0                up    up
ip-0/0/0                up    up
lsq-0/0/0               up    up
lt-0/0/0                up    up
mt-0/0/0                up    up
sp-0/0/0                up    up
sp-0/0/0.0              up    up   inet
                                   inet6
sp-0/0/0.16383          up    up   inet     10.0.0.1            --> 10.0.0.16
                                            10.0.0.6            --> 0/0
                                            128.0.0.1           --> 128.0.1.16
                                            128.0.0.6           --> 0/0
ge-0/0/1                up    up
ge-0/0/1.0              up    up   inet     192.168.34.16/24
ge-0/0/2                up    up
ge-0/0/2.0              up    up   inet     192.168.35.1/30
dsc                     up    up
gre                     up    up
ipip                    up    up
irb                     up    up
lo0                     up    up
lo0.16384               up    up   inet     127.0.0.1           --> 0/0
lo0.16385               up    up   inet     10.0.0.1            --> 0/0
                                            10.0.0.16           --> 0/0
                                            128.0.0.1           --> 0/0
                                            128.0.0.4           --> 0/0
                                            128.0.1.16          --> 0/0
lo0.32768               up    up
lsi                     up    up
mtun                    up    up
pimd                    up    up
pime                    up    up
pp0                     up    up
ppd0                    up    up
ppe0                    up    up
st0                     up    up
tap                     up    up
vlan                    up    down

For IOS XR

get_info.py


#! /usr/bin/env python
# -*- coding: utf-8 -*-

import napalm
from pprint import pprint

driver = napalm.get_network_driver('iosxr')
device = driver(
    hostname='127.0.0.1',
    username='vagrant',
    password='vagrant',
    # IOSXRv default ssh port
    optional_args={'port': 2223}) 

print 'Open session: ',
device.open()
print 'OK'

print 'get interface IP: '
pprint(device.get_interfaces_ip())

print 'Close session: ',
device.close()
print 'OK'

Execution result


% python get_info.py                                                                                                                                                                         (git)-[master]
Open session:  OK

get interface IP:
{u'MgmtEth0/RP0/CPU0/0': {u'ipv4': {u'10.0.2.15': {u'prefix_length': 24}}}}

Close session:  OK

Checking the status of the actual router


RP/0/RP0/CPU0:ios#show ipv4 interface brief
Fri Dec 23 12:44:59.827 UTC

Interface                      IP-Address      Status          Protocol Vrf-Name
MgmtEth0/RP0/CPU0/0            10.0.2.15       Up              Up       default

NAPALM usage example: Get ARP table information

Use the get_arp_table () function to get the ARP table information.

For JUNOS

get_info.py


#! /usr/bin/env python
# -*- coding: utf-8 -*-

import napalm
from pprint import pprint

driver = napalm.get_network_driver('junos')
device = driver(
    hostname='192.168.34.16',
    username='user1',
    password='password1')

print 'Open session: ',
device.open()
print 'OK'

print 'get ARP table'
pprint(device.get_arp_table())

print 'Close session: ',
device.close()
print 'OK'

Execution result


% python get_info.py

Open session:  OK
get ARP table
[{'age': 530.0,
  'interface': u'ge-0/0/0.0',
  'ip': u'10.0.2.2',
  'mac': u'52:54:00:12:35:02'},
 {'age': 505.0,
  'interface': u'ge-0/0/0.0',
  'ip': u'10.0.2.3',
  'mac': u'52:54:00:12:35:03'},
 {'age': 1415.0,
  'interface': u'ge-0/0/1.0',
  'ip': u'192.168.34.1',
  'mac': u'0A:00:27:00:00:04'}]
Close session:  OK

Checking the status of the actual router


root@firefly1> show arp
MAC Address       Address         Name                      Interface           Flags
52:54:00:12:35:02 10.0.2.2        10.0.2.2                  ge-0/0/0.0          none
52:54:00:12:35:03 10.0.2.3        10.0.2.3                  ge-0/0/0.0          none
0a:00:27:00:00:04 192.168.34.1    192.168.34.1              ge-0/0/1.0          none
Total entries: 3

For IOS XR

get_info.py


#! /usr/bin/env python
# -*- coding: utf-8 -*-

import napalm
from pprint import pprint

driver = napalm.get_network_driver('iosxr')
device = driver(
    hostname='127.0.0.1',
    username='vagrant',
    password='vagrant',
    # IOSXRv default ssh port
    optional_args={'port': 2223}) 

print 'Open session: ',
device.open()
print 'OK'

print 'get ARP table'
pprint(device.get_arp_table())

print 'Close session: ',
device.close()
print 'OK'

Execution result


% python get_info.py

Open session:  OK
get ARP table
[{u'age': 1228.0,
  u'interface': u'MgmtEth0/RP0/CPU0/0',
  u'ip': u'10.0.2.2',
  u'mac': u'52:54:00:12:35:02'},
 {u'age': 0.0,
  u'interface': u'MgmtEth0/RP0/CPU0/0',
  u'ip': u'10.0.2.15',
  u'mac': u'08:00:27:0D:1E:94'}]

Close session:  OK

Checking the status of the actual router


RP/0/RP0/CPU0:ios#show arp
Fri Dec 23 12:46:58.918 UTC

-------------------------------------------------------------------------------
0/RP0/CPU0
-------------------------------------------------------------------------------
Address         Age        Hardware Addr   State      Type  Interface
10.0.2.2        00:37:45   5254.0012.3502  Dynamic    ARPA  MgmtEth0/RP0/CPU0/0
10.0.2.15       -          0800.270d.1e94  Interface  ARPA  MgmtEth0/RP0/CPU0/0

NAPALM usage example: Acquisition of routing information for a specific route

You can get the routing information of the specified route by using get_route_to () function.

For JUNOS

get_info.py


#! /usr/bin/env python
# -*- coding: utf-8 -*-

import napalm
from pprint import pprint

driver = napalm.get_network_driver('junos')
device = driver(
    hostname='192.168.34.16',
    username='user1',
    password='password1')

print 'Open session: ',
device.open()
print 'OK'

print 'get route to 192.168.35.0'
pprint(device.get_route_to(destination=u'192.168.35.0'))

print 'Close session: ',
device.close()
print 'OK'

Execution result


% python get_info.py 

Open session:  OK
get route to 192.168.35.0
{u'192.168.35.0/30': [{'age': 3444,
                       'current_active': True,
                       'inactive_reason': u'',
                       'last_active': True,
                       'next_hop': None,
                       'outgoing_interface': u'ge-0/0/2.0',
                       'preference': 0,
                       'protocol': u'Direct',
                       u'protocol_attributes': {},
                       'routing_table': u'inet.0',
                       'selected_next_hop': True}]}
Close session:  OK

Checking the status of the actual router


root@firefly1> show route 192.168.35.2 detail

inet.0: 7 destinations, 7 routes (7 active, 0 holddown, 0 hidden)
192.168.35.0/30 (1 entry, 1 announced)
        *Direct Preference: 0
                Next hop type: Interface
                Address: 0x9350448
                Next-hop reference count: 2
                Next hop: via ge-0/0/2.0, selected
                State: <Active Int>
                Age: 58:00
                Task: IF
                Announcement bits (1): 1-Resolve tree 1
                AS path: I

For IOSXR (failure)

get_info.py


#! /usr/bin/env python
# -*- coding: utf-8 -*-

import napalm
from pprint import pprint

driver = napalm.get_network_driver('iosxr')
device = driver(
    hostname='127.0.0.1',
    username='vagrant',
    password='vagrant',
    # IOSXRv default ssh port
    optional_args={'port': 2223}) 

print 'Open session: ',
device.open()
print 'OK'

pprint 'get route to 10.0.2.2'
pprint(device.get_route_to(destination=u'10.0.2.2'))

print 'Close session: ',
device.close()
print 'OK'

Execution result


% python get_info.py                                                                                                                                                                         

Open session:  OK
get route to 10.0.2.2
Traceback (most recent call last):
  File "get_info.py", line 38, in <module>
    pprint(device.get_route_to(destination=u'10.0.2.2'))
  File "/usr/local/lib/python2.7/site-packages/napalm_iosxr/iosxr.py", line 1218, in get_route_to
    protocol=protocol
TypeError: Protocol not supported: .

I can see the following on the router, but it failed on NAPALM.

Checking the status of the actual router


RP/0/RP0/CPU0:ios#show route 10.0.2.15
Fri Dec 23 12:49:19.184 UTC

Routing entry for 10.0.2.15/32
  Known via "local", distance 0, metric 0 (connected)
  Installed Dec 23 12:09:11.148 for 00:40:08
  Routing Descriptor Blocks
    directly connected, via MgmtEth0/RP0/CPU0/0
      Route metric is 0
  No advertising protos.

get_route_to () function I wondered if it was wrong not to specify the protocol which is an optional argument. I thought, I tried the following patterns, but it didn't work.

pprint(device.get_route_to(destination=u'10.0.2.2', protocol=u'bgp'))

Execution result


% python get_info.py                                                                                                                                                                         

Open session:  OK
get route to 10.0.2.2
Traceback (most recent call last):
  File "get_info.py", line 38, in <module>
    pprint(device.get_route_to(destination=u'10.0.2.2', protocol=u'bgp'))
  File "/usr/local/lib/python2.7/site-packages/napalm_iosxr/iosxr.py", line 1239, in get_route_to
    routes_tree = ETREE.fromstring(self.device.make_rpc_call(route_info_rpc_command))
  File "/usr/local/lib/python2.7/site-packages/pyIOSXR/iosxr.py", line 148, in make_rpc_call
    result = self._execute_rpc(rpc_command)
  File "/usr/local/lib/python2.7/site-packages/pyIOSXR/iosxr.py", line 412, in _execute_rpc
    raise XMLCLIError(error_msg, self)
pyIOSXR.exceptions.XMLCLIError:
Original call was: <?xml version="1.0" encoding="UTF-8"?><Request MajorVersion="1" MinorVersion="0"><Get><Operational><RIB><VRFTable><VRF><Naming><VRFName>default        </VRFName></Naming><AFTable><AF><Naming><AFName>IPv4</AFName></Naming><SAFTable><SAF>        <Naming><SAFName>Unicast</SAFName></Naming><IP_RIBRouteTable><IP_RIBRoute><Naming>        <RouteTableName>default</RouteTableName></Naming><RouteTable><Route><Naming><Address>        10.0.2.2</Address></Naming></Route></RouteTable></IP_RIBRoute></IP_RIBRouteTable>        </SAF></SAFTable></AF></AFTable></VRF></VRFTable></RIB></Operational></Get></Request>

It may be a bug in pyIOSXR, so I'll try to find out more when I have time.

NAPALM usage example: Getting BGP neighbor information

You can get BGP neighbor information by using the get_bgp_neighbors () function.

For JUNOS

get_info.py


#! /usr/bin/env python
# -*- coding: utf-8 -*-

import napalm
from pprint import pprint

driver = napalm.get_network_driver('junos')
device = driver(
    hostname='192.168.34.16',
    username='user1',
    password='password1')

print 'Open session: ',
device.open()
print 'OK'

print 'get BGP neighbors'
pprint(device.get_bgp_neighbors())

print 'Close session: ',
device.close()
print 'OK'

Execution result


% python get_info.py

Open session:  OK
get BGP neighbors
{u'global': {u'peers': {u'192.168.35.2': {u'address_family': {},
                                          'description': u'',
                                          'is_enabled': True,
                                          'is_up': False,
                                          'local_as': 65001,
                                          'remote_as': 65002,
                                          'remote_id': u'',
                                          u'uptime': 291}},
             u'router_id': u'None'}}
Close session:  OK

Checking the status of the actual router


root@firefly1> show bgp neighbor
Peer: 192.168.35.2+179 AS 65002 Local: 192.168.35.1 AS 65001
  Type: External    State: Connect        Flags: <ImportEval>
  Last State: Connect       Last Event: ConnectRetry
  Last Error: None
  Export: [ advertised_for_firefly2 ]
  Options: <Preference AddressFamily PeerAS Refresh>
  Address families configured: inet-unicast
  Holdtime: 90 Preference: 170
  Number of flaps: 0

For IOS XR

get_info.py


#! /usr/bin/env python
# -*- coding: utf-8 -*-

import napalm
from pprint import pprint

driver = napalm.get_network_driver('iosxr')
device = driver(
    hostname='127.0.0.1',
    username='vagrant',
    password='vagrant',
    # IOSXRv default ssh port
    optional_args={'port': 2223}) 

print 'Open session: ',
device.open()
print 'OK'

print 'get BGP neighbors'
pprint(device.get_bgp_neighbors())

print 'Close session: ',
device.close()
print 'OK'

Execution result


% python get_info.py

Open session:  OK
get BGP neighbors
{u'global': {u'peers': {u'192.168.0.1': {u'address_family': {u'ipv4': {u'accepted_prefixes': 0,
                                                                       u'received_prefixes': 0,
                                                                       u'sent_prefixes': 0}},
                                         u'description': u'test_AS65002',
                                         u'is_enabled': False,
                                         u'is_up': False,
                                         u'local_as': 65001,
                                         u'remote_as': 65002,
                                         u'remote_id': u'0.0.0.0',
                                         u'uptime': -1}},
             u'router_id': u'0.0.0.0'}}
Close session:  OK

Checking the status of the actual router


RP/0/RP0/CPU0:ios#show bgp neighbor
Fri Dec 23 13:14:16.879 UTC

BGP neighbor is 192.168.0.1
 Remote AS 65002, local AS 65001, external link
 Description: test_AS65002
 Remote router ID 0.0.0.0
  BGP state = Idle (eBGP neighbor not directly connected)
  NSR State: None
  Last read 00:00:00, Last read before reset 00:00:00
  Hold time is 180, keepalive interval is 60 seconds
  Configured hold time: 90, keepalive: 30, min acceptable hold time: 3
(snip)

NAPALM usage example: Router configuration settings

You can change the config settings using the same procedure as introduced in the previous blog I tried to touch the router control API library NAPALM.

For JUNOS (failure)

change_hostname_JUNOS.conf


system {
    host-name firefly1_changed_by_NAPALM;
}

set_hostname.py


#! /usr/bin/env python
# -*- coding: utf-8 -*-

import napalm

# For JUNOS firefly1
driver = napalm.get_network_driver('junos')
device = driver(
    hostname='192.168.34.16',
    username='user1',
    password='password1')

print 'Open session: ',
device.open()
print 'OK'

print 'get hostname : ', 
print device.get_facts()[u'hostname']

print 'Config load (merge mode): ',
device.load_merge_candidate(filename='./change_hostname_JUNOS.conf')
print 'OK'

print 'Compare config: '
print device.compare_config()

print 'Do you commit? y/n'
choice = raw_input().lower()
if choice == 'y':
    print 'Commit config:',
    device.commit_config()
    print 'OK'
else:
    print 'Discard config:',
    device.discard_config()
    print 'OK'

print 'Close session: ',
device.close()
print 'OK'

Execution result


% python set_hostname.py                                                                                                                                                                     (git)-[master]
Open session:  OK
get hostname :  firefly1
Config load (merge mode):  OK
Compare config:
[edit system]
-  host-name firefly1;
+  host-name firefly1_changed_by_NAPALM;
Do you commit? y/n
y
Commit config: OK
get hostname :
Traceback (most recent call last):
  File "set_hostname.py", line 41, in <module>
    print device.get_facts()[u'hostname']
  File "/usr/local/lib/python2.7/site-packages/napalm_junos/junos.py", line 182, in get_facts
    interfaces.get()
  File "/Library/Python/2.7/site-packages/jnpr/junos/factory/optable.py", line 64, in get
    self.xml = getattr(self.RPC, self.GET_RPC)(**rpc_args)
  File "/Library/Python/2.7/site-packages/jnpr/junos/rpcmeta.py", line 156, in _exec_rpc
    return self._junos.execute(rpc, **dec_args)
  File "/Library/Python/2.7/site-packages/jnpr/junos/decorators.py", line 58, in wrapper
    result = function(*args, **kwargs)
  File "/Library/Python/2.7/site-packages/jnpr/junos/decorators.py", line 26, in wrapper
    return function(*args, **kwargs)
  File "/Library/Python/2.7/site-packages/jnpr/junos/device.py", line 520, in execute
    raise EzErrors.RpcTimeoutError(self, rpc_cmd_e.tag, self.timeout)
jnpr.junos.exception.RpcTimeoutError: RpcTimeoutError(host: 192.168.34.16, cmd: get-interface-information, timeout: 60)

I got an error. .. However, on the actual router, it seems that the changes have been made without any problems.

Checking the status of the actual router


root@firefly1
(Program execution)

root@firefly1_changed_by_NAPALM>

root@firefly1_changed_by_NAPALM> show version
Hostname: firefly1_changed_by_NAPALM
Model: firefly-perimeter
JUNOS Software Release [12.1X47-D20.7]

[edit]
root@firefly1_changed_by_NAPALM# rollback ?
Possible completions:
  <[Enter]>            Execute this command
  0                    2016-12-24 18:55:57 JST by user1 via netconf
  1                    2016-12-24 18:32:08 JST by root via cli
  2                    2016-12-24 15:20:22 JST by root via cli

When I changed the conditions and tried without "device.get_facts () [u'hostname']" immediately after commit, I got another error.

Execution result


% python set_hostname.py                                                                                                                                                                     (git)-[master]
Open session:  OK
get hostname :  firefly1
Config load (merge mode):  OK
Compare config:
[edit system]
-  host-name firefly1;
+  host-name firefly1_changed_by_NAPALM;
Do you commit? y/n
y
Commit config: OK
Close session:
Traceback (most recent call last):
  File "set_hostname.py", line 44, in <module>
    device.close()
  File "/usr/local/lib/python2.7/site-packages/napalm_junos/junos.py", line 94, in close
    self._unlock()
  File "/usr/local/lib/python2.7/site-packages/napalm_junos/junos.py", line 106, in _unlock
    self.device.cu.unlock()
  File "/Library/Python/2.7/site-packages/jnpr/junos/utils/config.py", line 489, in unlock
    raise UnlockError(rsp=err.rsp)
jnpr.junos.exception.UnlockError: <exception str() failed>

I haven't had enough time to troubleshoot, but it may be that something is wrong with JUNOS's Unlock. I will add it as soon as the cause is known.

For IOS XR

change_hostname_IOSXR.conf


hostname iosxrv1_changed_by_NAPALM

set_hostname.py


#! /usr/bin/env python
# -*- coding: utf-8 -*-

import napalm

# For Cisco IOSXRv
driver = napalm.get_network_driver('iosxr')
device = driver(
    hostname='127.0.0.1',
    username='vagrant',
    password='vagrant',
    # IOSXRv default ssh port
    optional_args={'port': 2223}) 

print 'Open session: ',
device.open()
print 'OK'

print 'get hostname : ', 
print device.get_facts()[u'hostname']

print 'Config load (merge mode): ',
device.load_merge_candidate(filename='./change_hostname_IOSXR.conf')
print 'OK'

print 'Compare config: '
print device.compare_config()

print 'Do you commit? y/n'
choice = raw_input().lower()
if choice == 'y':
    print 'Commit config:',
    device.commit_config()
    print 'OK'
else:
    print 'Discard config:',
    device.discard_config()
    print 'OK'

print 'get hostname : ', 
print device.get_facts()[u'hostname']

print 'Close session: ',
device.close()
print 'OK'

Execution result


% python set_hostname.py                                                                                                                                                                     (git)-[master]
Open session:  OK
get hostname :  ios
Config load (merge mode):  OK
Compare config:
---
+++
@@ -1,5 +1,6 @@
 !! Last configuration change at Fri Dec 23 13:20:24 2016 by vagrant
 !
+hostname iosxrv1_changed_by_NAPALM
 telnet vrf default ipv4 server max-servers 10
 username vagrant
  group root-lr
Do you commit? y/n
y
Commit config: OK
get hostname :  iosxrv1_changed_by_NAPALM
Close session:  OK

Checking the status of the actual router


RP/0/RP0/CPU0:ios#
(Program execution)

RP/0/RP0/CPU0:iosxrv1_changed_by_NAPALM#

RP/0/RP0/CPU0:iosxrv1_changed_by_NAPALM#sh running-config hostname
Fri Dec 23 13:21:32.129 UTC
hostname iosxrv1_changed_by_NAPALM

IOSXR was able to change the settings successfully!

Summary

This time, it was confirmed that by using NAPALM, information can be acquired and router settings can be performed in the environment of JUNOS router and IOS XR router. There were some things that didn't go well, but it may be improved in the future. I will add it when I understand the cause of the problem.

NAPALM has already implemented a large number of functions, and it seems that NAPALM can significantly reduce the man-hours for developing automation software in a multi-vendor environment.

In addition, since the development by the NAPALM community is very active, we can expect further expansion of functions and an increase in compatible models in the future.

At the moment, the only functions that seem to be missing are Brocade products, OSPF-related, and MPLS-related functions. If you touch it a little more, you may notice various aspects that are missing.

The program I tried this time is published on Github, so please refer to it if you like. (Sorry for the dirty code ...) https://github.com/taijiji/sample_nalapm

Finally

This time I ended up just introducing the functions of NAPALM, but if I have time in the future, I tried using the past blog "[PyEZ and JSNAPy. Part 4: Automating ISP setting work with PyEZ and JSNAPy]( I will also try to develop a multi-vendor compatible version (JUNOS and IOSXR for the time being) of the automation tool made with "http://qiita.com/taijijiji/items/983189f9bdebaa53e499)".

If anyone has tried to develop an automation tool using NAPALM, please introduce it in the future NetOps Coding. I'm glad.

Have a nice Christmas.

Recommended Posts

Continuation ・ I tried touching the multi-vendor router control API library NAPALM
I tried touching the multi-vendor router control API library NAPALM
I tried the changefinder library!
I tried the Naro novel API 2
I tried the Naruro novel API
I tried using the checkio API
I tried to touch the COTOHA API
I tried using the BigQuery Storage API
I checked the library for using the Gracenote API
I tried hitting the Qiita API from go
I tried using the Google Cloud Vision API
I tried to touch the API of ebay
I tried using the functional programming library toolz
I tried using the API of the salmon data project
I tried hitting the API with echonest's python client
[First COTOHA API] I tried to summarize the old story
I tried using the Python library from Ruby with PyCall
I tried saving the DRF API request history with django-request
[Python] I tried collecting data using the API of wikipedia
I tried the Google Cloud Vision API for the first time
I tried to get various information from the codeforces API
[For beginners] I tried using the Tensorflow Object Detection API
I touched the Qiita API
I created a Python library to call the LINE WORKS API
I tried using the COTOHA API (there is code on GitHub)
Continuation: I tried to introduce the block diagram generation tool blockdiag
I tried the TensorFlow tutorial 1st
I tried to create Quip API
I tried the TensorFlow tutorial 2nd
I tried to touch Tesla's API
I tried to move the ball
I tried to estimate the interval.
I tried calling the prediction API of the machine learning model from WordPress
I tried to control multiple servo motors MG996R using the servo driver PCA9685.
I tried to summarize various sentences using the automatic summarization API "summpy"
I tried using the trained model VGG16 of the deep learning library Keras
I tried to visualize the model with the low-code machine learning library "PyCaret"
I tried to get the movie information of TMDb API with Python
I tried touching touch related methods in the scene module of pythonista
I tried to control the network bandwidth and delay with the tc command