Fighting CLI cowboys with Napalm – An Introduction

A lot of people who aren’t familiar with Napalm tend to laugh nervously when you suggest they use it in their network. The name Napalm is partly based on getting that perfect acronym and partly a desire to incinerate the old way of doing things and move to network automation. This article is about explaining what Napalm is and what lies behind the acronym.

Playing with fire

What is Napalm Automation?

Napalm is an open source Python library which makes it easy to configure and gather information from network devices through a unified API. As an example if you were to use Napalm and wanted to list the BGP neighbors of three devices running IOS XR, Junos and Arista EOS you could use the get_bgp_neighbors() function and the returned data would be in the same format regardless of the operating system running on the device.

Likewise when configuring devices, Napalm allows you to use the same function without caring about what type of device you are using. First you create the configuration you want to apply to the device, this can be a configuration snippet loaded using the load_merge_candidate() function, or a full configuration using the load_replace_candidate() function. After the configuration is loaded to the device you can use compare_config() to see if the change is actually needed and either use commit_config() or discard_config() to apply or back out of the configuration change.

Origin story

Napalm started its life at Spotify where David Barroso wanted a better way to handle configuration changes in their network. After doing some mockups he talked with Elisa Jasinska about the project and soon after Napalm became a collaborative effort. As time went on more and more people got involved and started to contribute code. Now it has grown into a community effort. While some vendors have shown an interest in helping out with the network drivers, Napalm remains an independent project.

How Napalm is used

Since Napalm is a Python package, developers can install it using pip with “pip install napalm”. You might have to install some other dependencies, check the install docs to be sure. Using Napalm in this way lets you write your own scripts to automate your network with Napalm.

If you’re using Ansible, you might have heard that there’s a repo for napalm-ansible modules. Napalm is also integrated with SaltStack, so it’s easy to use Napalm and Salt together.

Napalm in action – Getting BGP Neighbors

As stated earlier you can use Napalm as a part of an automation frameworks. But for simplicity we’ll take a look at using it directly from Python. This will require some basic knowledge about Python, but even if you don’t know Python you will probably be able to see what’s going on. Here is an example of how you can use Napalm to gather information about BGP neighbors.

import json
from napalm_base import get_network_driver
driver = get_network_driver('iosxr')
dev = driver(hostname='r1', username='admin',
             password='admin')
dev.open()
bgp_neighbors = dev.get_bgp_neighbors()
dev.close()
print(json.dumps(bgp_neighbors, sort_keys=True, indent=4))
{
    "global": {
        "peers": {
            "10.255.255.2": {
                "address_family": {
                    "ipv4": {
                        "accepted_prefixes": 0,
                        "received_prefixes": 0,
                        "sent_prefixes": 1
                    }
                },
                "description": "",
                "is_enabled": true,
                "is_up": true,
                "local_as": 65900,
                "remote_as": 65900,
                "remote_id": "10.255.255.2",
                "uptime": 372
            },
            "10.255.255.3": {
                "address_family": {
                    "ipv4": {
                        "accepted_prefixes": 0,
                        "received_prefixes": 0,
                        "sent_prefixes": 1
                    }
                },
                "description": "",
                "is_enabled": true,
                "is_up": true,
                "local_as": 65900,
                "remote_as": 65900,
                "remote_id": "10.255.255.3",
                "uptime": 372
            }
        },
        "router_id": "10.255.255.1"
    }
}

The above example is using IOS XR, but Napalm will return data in the same format regardless.

Napalm in action – Configuring devices

Moving on to configuration, Napalm currently works with configuration files in raw text format. Typically you create these files with by passing values through a templating language such as Jinja2. A lot can be said about generating configuration using templates and I won’t go into any of that here. Instead we just have a simple file containing an access-list for an XR device.

ACL_SAMPLE.cfg

no ipv4 access-list ACCESS_OUT
ipv4 access-list ACCESS_OUT
 10 permit tcp any any eq domain
 20 remark udp any any eq dns
 30 permit tcp any any eq www
 40 remark tcp any any eq https

The config snipped will start by deleting the access-list and recreated it, the reason for this is to remove potential extra lines in the acl. To configure a device with this access-list we can use the code below and rely on the underlying napalm-iosxr driver to figure out what needs to be done on the device.

from napalm_base import get_network_driver
driver = get_network_driver('iosxr')
dev = driver(hostname='r1', username='admin',
             password='admin')
dev.open()
dev.load_merge_candidate(filename='ACL_SAMPLE.cfg')
dev.commit_config()
dev.close()

While this allows us to push configuration to the devices Napalm also lets you see if a configuration change is actually needed. A modified script could look like this:

from napalm_base import get_network_driver
driver = get_network_driver('iosxr')
dev = driver(hostname='r1', username='admin',
             password='admin')
dev.open()
dev.load_merge_candidate(filename='ACL_SAMPLE.cfg')
diffs = dev.compare_config()
if len(diffs) > 0:
    print(diffs)
    dev.commit_config()
else:
    print('No changes needed')
    dev.discard_config()

dev.close()

Using this check we can validate if a change is actually needed before applying it, or use it to validate that the configuration on the device is what we expect it to be.

Another option is to use the load_replace_candidate function instead of load_merge_candidate. Using the replace option would let you replace the entire configuration on the target device.

What network devices does Napalm support?

As of this writing the list of supported network devices looks like this:

  • Arista EOS
  • Cisco IOS
  • Cisco IOS-XR
  • Cisco NX-OS
  • Fortinet Fortios
  • IBM
  • Juniper JunOS
  • Mikrotik RouterOS
  • Palo Alto NOS
  • Pluribus
  • Vyos

New devices are also being worked on. A thing to keep in mind though is that Napalm is developed by its community. What this means is that the people writing code will focus on the features that they need. This means that not all features of Napalm will work on all of the devices. For more information on this you can look at the support matrix in the documentation.

Network device configuration

As you saw above the configuration sent to an IOS XR device looks like XR config, if you were to target an Arista box you would use EOS config. The unified part about configuration when it comes to Napalm, is how you apply the configuration to the devices. It is however quite easy to choose different Jinja templates as you target different device types, making device types more transparent.

OpenConfig and Yang

Currently we need to use raw text when configuring the devices. However, OpenConfig and Yang support is a work in progress so things might change in the future. Though this is an interesting development, don’t wait for everything to be in place before you start to move away from the CLI. Start testing Napalm and other tools sooner rather than later.

What’s in a name?

So what does the acronym stand for? NAPALM is Network Automation and Programmability Abstraction Layer with Multivendor support. I think it fits quite nicely.

More information

As with many other Python projects the documentation for Napalm uses Read the Docs and the Napalm source code is hosted at GitHub.