Migrating From CLI With NX-API Part 2

In Part 1 of this series we covered how to enable NX-API and access the API via a web browser to a single 7K. In this post we will cover accessing multiple NX-API enabled systems to gather data of interest. I will use the nxapi_utils python library from the Nexus 9000 Community GitHub to access the systems via http.

Acessing Data Elements "Off The Box"

Because we already configured the NX-API feature in part 1, we will skip that step and proceed to access the Nexus 7K via the NXAPI class from nxapi_utils. In the following python script we will import the NXAPI class and xmltodict to convert xml data into an ordered dictionary. We will start small and only access one 7K and issue the command "show interface":

#Import NXAPI and xmltodict
from nxapi_utils import NXAPI, xmltodict

#URL used to access the 7K
url = 'http://N7K_1/ins'

#Function for interface inventory
def int_inv(url='', username='', password=''):  
    thisnxapi = NXAPI()
    thisnxapi.set_target_url(url)
    thisnxapi.set_username(username)
    thisnxapi.set_password(password)
    thisnxapi.set_msg_type('cli_show')
    thisnxapi.set_cmd('show interface')
    returndata = thisnxapi.send_req()
    doc = xmltodict.parse(returndata[1])
    return doc

#Inventory variable
inventory = int_inv(url, 'cisco', 'cisco')  

Now let's take a look at what data is returned by the int_inv() function:

>>>inventory
OrderedDict([(u'ins_api', OrderedDict([(u'type', u'cli_show'), (u'version', u'1.2'), (u'sid', u'eoc'), (u'outputs', OrderedDict([(u'output', OrderedDict([(u'body', OrderedDict([(u'TABLE_interface', OrderedDict([(u'ROW_interface', [ LIST OF INTERFACES ]

**NOTE** The function does not literally return "[ LIST OF INTERFACES ]". This was accomplished for brevity.

Let's look at the key/value pairs of the interface at index 1 in the list:

>>> for k, v in inventory['ins_api']['outputs']['output']['body']['TABLE_interface']['ROW_interface'][1].items():
    print k, v

interface Ethernet3/1  
state down  
state_rsn_desc Administratively down  
admin_state down  
share_state Dedicated  
eth_hw_desc 1000/10000 Ethernet  
eth_hw_addr aaaa.aaaa.aaaa  
eth_bia_addr aaaa.aaaa.aaaa  
eth_mtu MTU 1500 bytes  
eth_bw 10000000  
eth_dly 10  
eth_reliability 255  
eth_txload 1  
eth_rxload 1  
medium p2p  
eth_mode access  
eth_duplex auto  
eth_speed auto-speed  
eth_media 1G  
eth_beacon off  
eth_autoneg on  
eth_in_flowctrl off  
eth_out_flowctrl off  
eth_mdix on  
eth_ratemode dedicated  
eth_swt_monitor off  
eth_ethertype 0x8100  
eth_eee_state n/a  
eth_link_flapped never  
eth_clear_counters 1w4d  
eth_reset_cntr 0  
eth_load_interval1_rx 30  
eth_inrate1_bits 0  
eth_inrate1_pkts 0  
eth_load_interval1_tx 30  
eth_outrate1_bits 0  
eth_outrate1_pkts 0  
eth_inrate1_summary_bits 0 bps  
eth_inrate1_summary_pkts 0 pps  
eth_outrate1_summary_bits 0 bps  
eth_outrate1_summary_pkts 0 pps  
eth_load_interval2_rx 300  
eth_inrate2_bits 0  
eth_inrate2_pkts 0  
eth_load_interval2_tx 300  
eth_outrate2_bits 0  
eth_outrate2_pkts 0  
eth_inrate2_summary_bits 0 bps  
eth_inrate2_summary_pkts 0 pps  
eth_outrate2_summary_bits 0 bps  
eth_outrate2_summary_pkts 0 pps  
eth_inucast 362252  
eth_inmcast 0  
eth_inbcast 0  
eth_inpkts 3028  
eth_inbytes 1891968  
eth_jumbo_inpkts 0  
eth_storm_supp 0  
eth_runts 0  
eth_giants 0  
eth_crc 0  
eth_nobuf 0  
eth_inerr 0  
eth_frame 0  
eth_overrun 0  
eth_underrun 0  
eth_ignored 0  
eth_watchdog 0  
eth_bad_eth 0  
eth_bad_proto 0  
eth_in_ifdown_drops 0  
eth_dribble 0  
eth_indiscard 0  
eth_inpause 0  
eth_outucast 362252  
eth_outmcast 0  
eth_outbcast 0  
eth_outpkts 3028  
eth_outbytes 1889472  
eth_jumbo_outpkts 0  
eth_outerr 0  
eth_coll 0  
eth_deferred 0  
eth_latecoll 0  
eth_lostcarrier 0  
eth_nocarrier 0  
eth_babbles 0  
eth_outdiscard 0  
eth_outpause 0  

From this output we can glean information based on the keys presented to us. For instance, let's create a script to query the 7K and return unused interfaces, the speed capabilities of the interfaces, and what speed SFP is inserted or notify us if an SFP is not present:

>>> for i in inventory['ins_api']['outputs']['output']['body']['TABLE_interface']['ROW_interface']:
    if i.has_key('state_rsn_desc'):
        if i.has_key('eth_media'):
             print i['interface'] + '\t' + i['eth_hw_desc'] + '\t SFP inserted %s' % i['eth_media']
        else:
            print i['interface'] + '\t' + i['eth_hw_desc'] + '\t SFP not inserted'

Ethernet3/1     1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/2     1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/4     1000/10000 Ethernet      SFP not inserted  
Ethernet3/5     1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/6     1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/8     1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/9     1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/10    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/11    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/12    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/13    1000/10000 Ethernet      SFP inserted 10G  
Ethernet3/14    1000/10000 Ethernet      SFP inserted 10G  
Ethernet3/15    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/16    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/17    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/18    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/19    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/20    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/21    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/22    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/23    1000/10000 Ethernet      SFP inserted 10G  
Ethernet3/24    1000/10000 Ethernet      SFP inserted 10G  
Querying Multiple NXAPI Enabled Devices

With the script we created in the previous section we can scale it by the number of NXAPI enabled devices in our environment. For this example we will use the following topology:
NX-API_Topology

Let's modify our script to include these 7Ks:

#Import NXAPI and xmltodict
from nxapi_utils import NXAPI, xmltodict

#URL used to access the 7K
url = ['http://N7K_1/ins', 'http://N7K_2/ins', 'http://N7K_3/ins', 'http://N7K_4/ins', 'http://N7K_5/ins',]

#Function for interface inventory
def int_inv(url='', username='', password=''):  
    thisnxapi = NXAPI()
    thisnxapi.set_target_url(url)
    thisnxapi.set_username(username)
    thisnxapi.set_password(password)
    thisnxapi.set_msg_type('cli_show')
    thisnxapi.set_cmd('show interface')
    returndata = thisnxapi.send_req()
    doc = xmltodict.parse(returndata[1])
    return doc

#Function to iterate over int_inv() key/value pairs to find interfaces not currently used
def unused_int():  
    for switch in url:
        print '\n', switch, 'has the following interfaces not in use: \n'
        inventory = int_inv(switch, 'cisco', 'cisco')
        for i in inventory['ins_api']['outputs']['output']['body']['TABLE_interface']['ROW_interface']:
            if i.has_key('state_rsn_desc'):
                if i.has_key('eth_media'):
                    print i['interface'] + '\t' + i['eth_hw_desc'] + '\t SFP inserted %s' % i['eth_media']
                else:
                    print i['interface'] + '\t' + i['eth_hw_desc'] + '\t SFP not inserted'

unused_int()  

Here is the output of the unused_int() function:

>>> unused_int()

http://N7K_1/ins has the following interfaces not in use:

Ethernet3/2     1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/3     1000/10000 Ethernet      SFP inserted 10G  
Ethernet3/4     1000/10000 Ethernet      SFP inserted 10G  
Ethernet3/6     1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/8     1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/37    1000/10000 Ethernet      SFP inserted 10G  
Ethernet3/38    1000/10000 Ethernet      SFP inserted 10G  
Ethernet3/39    1000/10000 Ethernet      SFP not inserted  
Ethernet3/40    1000/10000 Ethernet      SFP inserted 1G

http://N7K_2/ins has the following interfaces not in use:

Ethernet3/26    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/27    1000/10000 Ethernet      SFP inserted 10G  
Ethernet3/28    1000/10000 Ethernet      SFP inserted 10G  
Ethernet3/29    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/30    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/32    1000/10000 Ethernet      SFP inserted 1G

http://N7K_3/ins has the following interfaces not in use:

Ethernet3/1     1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/2     1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/4     1000/10000 Ethernet      SFP not inserted  
Ethernet3/5     1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/6     1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/8     1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/9     1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/10    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/11    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/12    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/13    1000/10000 Ethernet      SFP inserted 10G  
Ethernet3/14    1000/10000 Ethernet      SFP inserted 10G  
Ethernet3/15    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/16    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/17    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/18    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/19    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/20    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/21    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/22    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/23    1000/10000 Ethernet      SFP inserted 10G  
Ethernet3/24    1000/10000 Ethernet      SFP inserted 10G

http://N7K_4/ins has the following interfaces not in use:

Ethernet3/25    1000/10000 Ethernet      SFP not inserted  
Ethernet3/26    1000/10000 Ethernet      SFP not inserted  
Ethernet3/28    1000/10000 Ethernet      SFP not inserted  
Ethernet3/29    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/30    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/32    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/34    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/35    1000/10000 Ethernet      SFP not inserted  
Ethernet3/36    1000/10000 Ethernet      SFP not inserted  
Ethernet3/37    1000/10000 Ethernet      SFP inserted 10G  
Ethernet3/38    1000/10000 Ethernet      SFP inserted 10G  
Ethernet3/39    1000/10000 Ethernet      SFP not inserted  
Ethernet3/40    1000/10000 Ethernet      SFP not inserted  
Ethernet3/41    1000/10000 Ethernet      SFP not inserted  
Ethernet3/42    1000/10000 Ethernet      SFP not inserted  
Ethernet3/43    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/44    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/45    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/46    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/47    1000/10000 Ethernet      SFP inserted 1G  
Ethernet3/48    1000/10000 Ethernet      SFP inserted 1G

http://N7K_5/ins has the following interfaces not in use:

Ethernet4/1     10/100/1000 Ethernet     SFP not inserted  
Ethernet4/2     10/100/1000 Ethernet     SFP not inserted  
Ethernet4/4     10/100/1000 Ethernet     SFP not inserted  
Ethernet4/6     10/100/1000 Ethernet     SFP not inserted  
Ethernet4/7     10/100/1000 Ethernet     SFP not inserted  
Ethernet4/8     10/100/1000 Ethernet     SFP not inserted  
Ethernet4/9     10/100/1000 Ethernet     SFP not inserted  
Ethernet4/10    10/100/1000 Ethernet     SFP not inserted  
Ethernet4/11    10/100/1000 Ethernet     SFP not inserted  
Ethernet4/12    10/100/1000 Ethernet     SFP not inserted  
Ethernet4/13    10/100/1000 Ethernet     SFP not inserted  
Ethernet4/14    10/100/1000 Ethernet     SFP not inserted  
Ethernet4/15    10/100/1000 Ethernet     SFP not inserted  
Ethernet4/16    10/100/1000 Ethernet     SFP not inserted  
Ethernet4/17    10/100/1000 Ethernet     SFP not inserted  
Ethernet4/18    10/100/1000 Ethernet     SFP not inserted  
Ethernet4/19    10/100/1000 Ethernet     SFP not inserted  
Ethernet4/20    10/100/1000 Ethernet     SFP not inserted  
Ethernet4/21    10/100/1000 Ethernet     SFP not inserted  
Ethernet4/22    10/100/1000 Ethernet     SFP not inserted  
Ethernet4/23    10/100/1000 Ethernet     SFP not inserted  
Ethernet4/24    10/100/1000 Ethernet     SFP not inserted  
Final Thoughts

As you can see, leveraging NX-API to query multiple NX-OS systems and gathering whatever data you need is pretty easy. I believe when vendors implement APIs into their systems it will make our lives as network engineers a whole lot easier. The script above presented us our current interface vacancies in literal seconds. We could've also exported the information to a CSV file or multiple other sources. Our scenario was a small use case for leveraging NX-API, but the possibilities are really endless. I'm excited to see what the future holds for network APIs and what other engineers put out on github.