How to use NAPALM (Python library) to Manage IOS Devices

  • April 28, 2016

NAPALM (Network Automation and Programmability Abstraction Layer with Multivendor support) is a Python library that eases configuration management and data collection for various types of network devices. It uses vendor specific APIs such as eAPI for Arista and NETCONF for Juniper, as two examples, but has a pluggable architecture, so it's quite extensible should you want to add different drivers for each device type. Further more, it's actually re-using existing Python libraries such as Juniper's PyEZ for Junos, Arista's pyeapifor EOS, and netmiko for IOS support. It has immense value because it unifies networks operations for various tasks across a large number device platforms.

This tutorial is focused on providing a jump start on using the NAPALM Python library specifically for managing configurations on IOS devices. In follow up tutorials, we'll look at gathering data, using other vendors, and then using Ansible + NAPALM together.

Installing NAPALM

The first thing you need to do is ensure you have NAPALM installed.

This is already done on our jump host in the pre-built NAPALM IOS environment.

pip install napalm # sudo if you must

For instructions on how to perform upgrades and selectively install certain drivers and upgrades, see here.

Prepare Devices

Each IOS device needs to have a basic configuration before you can use NAPALM.

Ensure each device has a proper user account with privileges, SCP enabled, a management IP address, and the archive feature enabled.

Here is a base configuration we use in our labs to prepare the CSR 1000V for NAPALM.

username ntc privilege 15 password 0 ntc123
!
ip scp server enable
!
archive path bootflash:archive
!
interface GigabitEthernet1
 description MANAGEMENT
 vrf forwarding Mgmt-Intf
 ip address dhcp
!
line vty 0 4
privilege level 15
login local transport
input ssh
!

Note: this is already done on our jump host in the pre-built NAPALM IOS environment.

Create New Config File

The goal is to push a new configuration file to the device and activate it as the new running configuration in real time. First, we need to create our new configuration.

SSH into csr1, do a show run, and save the output into a file called newconfig.cfg. When you save the new config, ensure these lines are NOT in the new config:

Building configuration...
Current configuration : 1745 bytes

The only change you should make is for Gig4 (in reality, it could be a complete new configuration). This is the interface that connects to csr2.

Ensure the following section is included in newconfig.cfg.

interface GigabitEthernet4
 description CONNECTS_TO_CSR2_GI4
 ip address 10.1.12.1 255.255.255.0
 no shutdown
 negotiation auto
 cdp enable
!

Save it in the home directory (/home/ntc).

Create Device Object

We need to establish a connection to the device, but before that, we need to select the right driver to use in NAPALM. You can just drop right into the Python shell from the home directory (/home/ntc) on the jump host to try it out.

>>> from napalm import get_network_driver
>>> driver = get_network_driver('ios') `

Now we can create the device object and connect to the device.

>>> device = driver('csr1', 'ntc', 'ntc123')
>>> device.open() `

Load New Configuration (REPLACE)

The next step is to load the actual configuration onto the router. Behind the scenes, newconfig.cfg is being SCP'd to csr1 and saves it as the filename candidate_config.txt.

device.load_replace_candidate(filename='newconfig.cfg')

If you do a dir on csr1 now, you'll see this file:

20 -rw- 1836 Apr 28 2016 14:42:06 +00:00 candidate_config.txt

It's officially loaded (copied) onto the device.

Compare New Configuration with Running Configuration

It's time to compare the new candidate configuration, i.e. candidate_config.txt with the existing running configuration. We'll use the compare_config method.

>>> diffs = device.compare_config()
>>> 
>>> print diffs
interface GigabitEthernet4
 +description CONNECTS_TO_CSR2_GI4
 +ip address 10.1.12.1 255.255.0
 +no shutdown
interface GigabitEthernet2
 -no ip address

You can now see exactly what WILL get applied when this configuration is committed to the device.

Commit the New Configuration

If you are okay with the diffs, the next step is to commit the configuration.

>>> device.commit_config()
>>>

Once it completes, you can check the router and view the new configuration:

csr1#show run int gi4
Building configuration...

Current configuration : 134 bytes
!
interface GigabitEthernet4
 description CONNECTS_TO_CSR2_GI4
 ip address 10.1.12.1 255.255.255.0
 negotiation auto
 cdp enable
end

And that's it! That is how you use the configuration replace functionality using NAPALM. This offers a way to declaratively push a configuration to a network device and only apply the diffs, required to get the device into the desired state.

Rollback

After the configuration is committed, you'll see a new file on the router file system called rollback_config.txt. This file is used just in case you must rollback.

To rollback, you use the rollback method.

>>> device.rollback()
>>>

If you choose to rollback, your initial configuration is re-applied to the device. If you SSH back into the device, you'll see this.

We'll now briefly look at how to do a merge of a configuration as compared to a full replacement. This may be needed if you don't or can't push a full configuration to the device.

Create Config File for Merge Operation

We'll configure csr2 using the configuration merge method to establish IP connectivity between csr1 and csr2.

In the home directory, create a new config file called csr2-interface.cfg. It should ONLY have the following in it. It should NOT be a full configuration.

interface GigabitEthernet4
 description CONNECTS_TO_CSR1_GI4 
 ip address 10.1.12.2 255.255.255.0
 no shutdown
 negotiation auto
 cdp enable
!

Establish Connectivity to CSR2

>>> csr2 = driver('csr2', 'ntc', 'ntc123')
>>> csr2.open()

Load New Configuration (MERGE)

When you're doing a merge, just a partial config, and not a full replace, you use the load_merge_candidate method.

>>> csr2.load_merge_candidate(filename='csr2-interface.cfg')
>>>

This method SCPs the file to the router. On the router, it'll have the filename merge_config.txt.

NOTE: CURRENTLY, YOU CANNOT VIEW DIFFS / COMPARE CONFIGS FOR IOS DEVICES.

Commit the Configuration

>>> device.commit_config()
>>>


csr2#show run int gi4
Building configuration...

Current configuration : 135 bytes
!
interface GigabitEthernet4
 description CONNECTS_TO_CSR1_GI4
 ip address 10.1.12.2 255.255.255.0
 negotiation auto
 cdp enable
end

You should now be able to ping 10.1.12.1 from csr2 and 10.1.12.2 from csr1.