Python API

About the Python API

Python is an easy to learn, powerful programming language. It has efficient high-level data structures and a simple but effective approach to object-oriented programming. Python's elegant syntax and dynamic typing, together with its interpreted nature, make it an ideal language for scripting and rapid application development in many areas on most platforms.

The Python interpreter and the extensive standard library are freely available in source or binary form for all major platforms from the Python website:

http://www.python.org/

The same site also contains distributions of and pointers to many free third-party Python modules, programs and tools, and additional documentation.

The Cisco Nexus 7000 Series devices support Python v2.7.2 in both interactive and non-interactive (script) modes.

The Python scripting capability gives programmatic access to the device's command-line interface (CLI) to perform various tasks and PowerOn Auto Provisioning (POAP) or Embedded Event Manager (EEM) actions. Python can also be accessed from the Bash shell.

The Python interpreter is available in the Cisco NX-OS software.

Using Python

This section describes how to write and execute Python scripts.

Cisco Python Package

Cisco NX-OS provides a Cisco Python package. You can display the details of the Cisco Python package by entering the help() command. To obtain additional information about the classes and methods in a module, you can run the help command for a specific module. For example, help(cisco.interface) displays the properties of the cisco.interface module.

The following is an example of how to display information about the Cisco python package:

SWITCH# >>> import cisco
SWITCH# >>> help(cisco)
Help on module cisco:

NAME
    cisco - commands that integrate with CLI

FILE
    (built-in)

FUNCTIONS
    cli(...)
        execute a cli command
    
    clid(...)
        execute a cli command, return name/value pairs
    
    clip(...)
        execute a cli command, dont return it, just display it
    
    set_vrf(...)
        specify the vrf name for socket operations



SWITCH# >>>	
SWITCH# >>> help(cisco.set_vrf)
Help on built-in function set_vrf in module cisco:

set_vrf(...)
    specify the vrf name for socket operations


SWITCH# >>>

Using the CLI Command APIs

The Python programming language uses three APIs that can execute CLI commands. The APIs are available from the Python CLI module.

These APIs are listed in the following table. The arguments for these APIs are strings of CLI commands. To execute a CLI command through the Python interpreter, you enter the CLI command as an argument string of one of the following APIs:

Table 1. CLI Command APIs

API

Description

cli()

Example:

string = cli (“cli-command”)

Returns the raw output of CLI commands, including control/special characters.

Note 

The interactive Python interpreter prints control/special characters 'escaped'. A carriage return is printed as '\n' and gives results that might be difficult to read. The clip() API gives results that are more readable.

clid()

Example:

json_string = clid (“cli-command”)

Returns JSON output for cli-command, if XML support exists for the command, otherwise an exception is thrown.

This API can be useful when searching the output of show commands.

clip()

Example:

clip (“cli-command”)

Prints the output of the CLI command directly to stdout and returns nothing to Python.

Note 
clip (“cli-command”)
is equivalent to
r=cli(“cli-command”)
print r

When two or more commands are run individually, the state is not persistent from one command to subsequent commands.

In the following example, the second command fails because the state from the first command does not persist for the second command:

>>> cli("conf t")
>>> cli("interface eth4/1")

When two or more commands are run together, the state is persistent from one command to subsequent commands.

In the following example, the second command is successful because the state persists for the second and third commands:

>>> cli("conf t ; interface eth4/1 ; shut")

Note

Commands are separated with " ; " as shown in the example. (The ; must be surrounded with single blank characters.)


Invoking the Python Interpreter from the CLI

The following example shows how to invoke Python from the CLI:


Note

The Python interpreter is designated with the ">>>" or "…" prompt.


 switch# python   !-- Enter Python interpreter
switch# >>> cli('conf term ; interface loopback 1')
''
switch(config-if)# >>> cli('ip address 1.1.1.1/24')
''
switch(config-if)# >>> cli('exit')
''
switch(config)# >>> cli('exit')
''
switch# >>> 
switch# >>> a=clid('sh mod')
switch# >>> a.keys()
['TABLE_modmacinfo/serialnum/4', 'TABLE_modinfo/modinf/1', 'TABLE_modmacinfo/serialnum/2', 
'TABLE_modmacinfo/modmac/2', 'TABLE_modmacinfo/serialnum/1', 'TABLE_modinfo/ports/4', 'TABLE_modmacinfo/mac/2', 
'TABLE_moddiaginfo/diagstatus/4', 'TABLE_modinfo/ports/1', 'TABLE_modinfo/ports/2', 'TABLE_modinfo/ports/3', 
'TABLE_modwwninfo/modwwn/4', 'TABLE_xbarinfo/xbarports/1', 'TABLE_xbarinfo/xbarmodel/1', 
'TABLE_modmacinfo/serialnum/3', 'TABLE_modwwninfo/hw/1', 'TABLE_modwwninfo/hw/3', 'TABLE_modwwninfo/hw/2', 
'TABLE_moddiaginfo/diagstatus/3', 'TABLE_modwwninfo/hw/4', 'TABLE_modinfo/modinf/2', 'TABLE_modinfo/modinf/3', 
'TABLE_modwwninfo/modwwn/1', 'TABLE_xbarwwninfo/xbarhw/1', 'TABLE_modinfo/modinf/4', 'TABLE_moddiaginfo/mod/3', 
'TABLE_moddiaginfo/mod/2', 'TABLE_moddiaginfo/mod/1', 'TABLE_xbarinfo/xbartype/1', 
'TABLE_xbarmacinfo/xbarmacaddr/1', 'TABLE_moddiaginfo/mod/4', 'TABLE_modinfo/status/4', 
'TABLE_xbarwwninfo/xbarwwn/1', 'TABLE_modinfo/status/1', 'TABLE_modinfo/status/3', 'TABLE_modinfo/status/2', 
'TABLE_modmacinfo/mac/1', 'TABLE_xbarwwninfo/xbarsw/1', 'TABLE_moddiaginfo/diagstatus/2', 'TABLE_modmacinfo/mac/3', 
'TABLE_modinfo/modtype/2', 'TABLE_modinfo/modtype/3', 'TABLE_moddiaginfo/diagstatus/1', 'TABLE_modinfo/modtype/1', 
'TABLE_modmacinfo/modmac/1', 'TABLE_modinfo/modtype/4', 'TABLE_modmacinfo/modmac/3', 
'TABLE_xbarmacinfo/xbarserialnum/1', 'TABLE_xbarmacinfo/xbarmac/1', 'TABLE_xbarinfo/xbarinf/1', 
'TABLE_modmacinfo/mac/4', 'TABLE_modwwninfo/sw/4', 'TABLE_modmacinfo/modmac/4', 'TABLE_modwwninfo/sw/1', 
'TABLE_modwwninfo/sw/2', 'TABLE_modwwninfo/sw/3', 'TABLE_xbarinfo/xbarstatus/1', 'TABLE_modwwninfo/modwwn/2', 
'TABLE_modinfo/model/4', 'TABLE_modinfo/model/3', 'TABLE_modinfo/model/2', 'TABLE_modinfo/model/1', 
'TABLE_modwwninfo/modwwn/3']
switch# >>> a["TABLE_modinfo/model/2"] 
'N7K-SUP1'
switch# >>>

Display Formats

The following examples show various display formats using the Python APIs:

Example 1:

SWITCH# >>> cli("conf ; interface loopback 1")
''
SWITCH(config-if)# >>> clip('where detail')
  mode:                conf
                       interface loopback1
  username:            admin
  vdc:                 SWITCH
  routing-context vrf: default
SWITCH(config-if)# >>>

Example 2:

SWITCH# >>> cli("conf ; interface loopback 1")
''
SWITCH(config-if)# >>>cli('where detail')
'  mode:                 conf\n      
                         interface loopback1\n  
   username:             admin\n  
   vdc:                  SWITCH\n  
   routing-context vrf:  default\n'
SWITCH(config-if)# >>>

Example 3:

SWITCH# >>> cli("conf ; interface loopback 1")
''
SWITCH(config-if)# >>> r = cli('where detail') ; print r
  mode:                conf
                       interface loopback1
  username:            admin
  vdc:                 SWITCH
  routing-context vrf: default

SWITCH(config-if)# >>>

Example 4:

SWITCH# >>> r = clid('show version')
SWITCH# >>> for k in r.keys():
SWITCH# ...   print "%30s" % k, " = %s" % r[k]
SWITCH# ... 
                kern_uptm_secs  = 58
                kick_file_name  = bootflash:///n7000-s1-kickstart.7.2.0.D1.1.gbin
                    rr_service  = 
                     module_id  = Supervisor Module-1X
                    slot0_size  = 2044854
                   kick_tmstmp  = 06/14/2015 13:57:44
                isan_file_name  = bootflash:///n7000-s1-dk9.7.2.0.D1.1.gbin
                   sys_ver_str  = 7.2(0)D1(1) [gdb]
                bootflash_size  = 2000880
             kickstart_ver_str  = 7.2(0)D1(1) [gdb]
                kick_cmpl_time  =  5/19/2015 11:00:00
                    chassis_id  = Nexus7000 C7010 (10 Slot) Chassis
                 proc_board_id  = JAF1417DKEN
                        memory  = 4115196
                  manufacturer  = Cisco Systems, Inc.
                kern_uptm_mins  = 39
                  bios_ver_str  = 3.22.0
                      cpu_name  = Intel(R) Xeon(R) CPU        
                bios_cmpl_time  = 02/20/10
                 kern_uptm_hrs  = 20
                      rr_usecs  = 228613
                   isan_tmstmp  = 06/14/2015 15:44:55
                    rr_sys_ver  = 7.3(0)ZD(0.114)
                     rr_reason  = Reset Requested by CLI command reload
                      rr_ctime  =  Fri Mar 15 20:41:38 2002

                    header_str  = Cisco Nexus Operating System (NX-OS) Software
TAC support: http://www.cisco.com/tac
Documents: http://www.cisco.com/en/US/products/ps9372/tsd_products_support_series_home.html
Copyright (c) 2002-2015, Cisco Systems, Inc. All rights reserved.
The copyrights to certain works contained in this software are
owned by other third parties and used and distributed under
license. Certain components of this software are licensed under
the GNU General Public License (GPL) version 2.0 or the GNU
Lesser General Public License (LGPL) Version 2.1. A copy of each
such license is available at
http://www.opensource.org/licenses/gpl-2.0.php and
http://www.opensource.org/licenses/lgpl-2.1.php

                isan_cmpl_time  =  5/19/2015 11:00:00
                     host_name  = SWITCH
                      mem_type  = kB
                kern_uptm_days  = 0
SWITCH# >>>  

Non-interactive Python

A Python script can run in non-interactive mode by providing the Python script name as an argument to the Python CLI command. Python scripts must be placed under the bootflash/scripts directory for default vdc, and /bootflash/vdc_x/scripts for the non-default vdc (x).

The Cisco Nexus 7000 Series device also supports the source CLI command for running Python scripts. The bootflash:scripts directory is the default script directory for the source CLI command.

The following example shows a script and how to run it:

SWITCH# sh file bootflash:scripts/test1.py
#!/bin/env python
import os
import syslog
switchname = cli("show switchname")
try:
        user = os.environ['USER']
except:
        user = "No user"
        pass
msg = user + " ran " + __file__ + " on : " + switchname
print msg
syslog.syslog(1,msg)

SWITCH#
SWITCH# source test1.py 
No user ran /bootflash/scripts/test1.py on : SWITCH 

SWITCH# 2002 Mar 15 17:43:29 
SWITCH %$ VDC-1 %$ %USER-1-SYSTEM_MSG: No user ran /bootflash/scripts/test1.py on : SWITCH   - test1.py
                                                                                     

The following example shows how a source command specifies command-line arguments. In the example, policy-map is an argument to the cgrep python script. The example also shows that a source command can follow after the pipe operator ("|").

switch# show running-config | source sys/cgrep policy-map

policy-map type network-qos nw-pfc
policy-map type network-qos no-drop-2
policy-map type network-qos wred-policy
policy-map type network-qos pause-policy
policy-map type qos foo
policy-map type qos classify
policy-map type qos cos-based
policy-map type qos no-drop-2
policy-map type qos pfc-tor-port

Running Scripts with Embedded Event Manager

On Cisco Nexus 7000 Series devices, embedded event manager (EEM) policies support Python scripts.

The following example shows how to run a Python script as an EEM action:

  • An EEM applet can include a Python script with an action command.
    switch# show running-config eem
    
    !Command: show running-config eem
    !Time: Sat Mar 16 09:11:32 2002
    
    version 7.2(0)D1(1)
    event manager applet a2
      event cli match "show clock"
      action 1 cli command "source pydate.py" 
      action 2 event-default
      action 3 syslog priority critical msg "$_cli_result"
     
  • You can see the action triggered by the event by printing the $_cli_result command.
    SWITCH# show clock
    Time source is NTP
    08:58:59.595 PST Sat Mar 16 2002
    SWITCH#   
    2002 Mar 16 08:59:02 SWITCH %$ VDC-1 %$ eem_policy_dir:  %eem_policy_dir-2-LOG: a2: Time source is NTP^M 
    2002 Mar 16 08:59:02 SWITCH %$ VDC-1 %$ eem_policy_dir: 08:59:02.269 PST Sat Mar 16 2002^M 
    2002 Mar 16 08:59:02 SWITCH %$ VDC-1 %$ eem_policy_dir: <Sat Mar 16 08:59:02 2002> <1> The System Manager library is unloading for PID 1985.^M 
    2002 Mar 16 08:59:02 SWITCH %$ VDC-1 %$ eem_policy_dir: ^M
    

Python Integration with Cisco NX-OS Network Interfaces

On Cisco Nexus 7000 Series devices, Python is integrated with the underlying Cisco NX-OS network interfaces. You can switch from one virtual routing context to another by setting up a context through the set_vrf() API.

The following example shows how to retrieve an HTML document over the management interface of a device. You can also establish a connection to an external entity over the inband interface by switching to a desired virtual routing context.

SWITCH# >>> import urllib2
SWITCH# >>> set_vrf('management')
SWITCH# >>> page=urllib2.urlopen('http://172.23.40.211:8000/welcome.html')
SWITCH# >>> print page.read()
Hello Cisco Nexus 7000

>>>


SWITCH# >>> import cisco
SWITCH# >>> help(cisco.set_vrf)
Help on built-in function set_vrf in module cisco:

set_vrf(...)
    specify the vrf name for socket operations


SWITCH# >>>                      

Cisco NX-OS Security with Python

Cisco NX-OS resources are protected by the Cisco NX-OS Sandbox layer of software and by the CLI role-based access control (RBAC).

All users associated with a Cisco NX-OS network-admin or dev-ops role are privileged users. Users who are granted access to Python with a custom role are regarded as non-privileged users. Non-privileged users have a limited access to Cisco NX-OS resources, such as file system, guest shell, and Bash commands. Privileged users have greater access to all the resources of Cisco NX-OS.

Examples of Security and User Authority

The following example shows a non-privileged user being denied access:

switch# python
switch# >>> from os import system
switch# >>> system("ls /isan/bin/")
-1
switch# >>> f=open("/bootflash/alias", "r")
switch# >>> f=open("/isan/bin/vsh", "r")
IOError: [Errno 1] Operation not permitted: '/isan/bin/vsh'

RBAC controls CLI access based on the login user privileges. A login user's identity is given to Python that is invoked from the CLI shell or from Bash. Python passes the login user's identity to any subprocess that is invoked from Python.

The following is an example for a privileged user:

SWITCH# python
Copyright (c) 2001-2012 Python Software Foundation; All Rights Reserved

SWITCH# >>> cli('show clock')
'Time source is NTP\n15:49:21.791 PST Fri Mar 15 2002\n'
SWITCH# >>>

The following is an example for a non-privileged user:

User Access Verification
SWITCH login: name1
Password: 
SWITCH# python
Copyright (c) 2001-2012 Python Software Foundation; All Rights Reserved

SWITCH# >>> cli('sh clock')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
cisco.cli_execution_error: % Permission denied for the role

SWITCH# >>> 

The following example shows an RBAC configuration:

SWITCH(config-role)# show role name role-test 

Role: role-test
  Description: new role
  Vlan policy: permit (default) 
  Interface policy: permit (default) 
  Vrf policy: permit (default)
  -------------------------------------------------------------------
  Rule    Perm    Type        Scope               Entity                  
  -------------------------------------------------------------------
  3       permit  command                         python                  
  2       deny    command                         sh running-config l3vm  
  1       deny    command                         show clock              
SWITCH(config-role)# exit
SWITCH(config)#

Example of Running Script with Scheduler

The following example shows a Python script that is running the script with the scheduler feature:

#!/bin/env python
import os
import syslog
switchname = cli("show switchname")
try:
	user = os.environ['USER']
except:
	user = "No user"
	pass
msg = user + " ran " + __file__ + " on : " + switchname
print msg
syslog.syslog(1,msg)

# Save this script in bootflash:///scripts
SWITCH# conf t
Enter configuration commands, one per line.  End with CNTL/Z.
SWITCH(config)# feature scheduler
SWITCH(config)# scheduler job name test-plan
SWITCH(config-job)# source test1.py 
SWITCH(config-job)# exit
SWITCH(config)# scheduler schedule name test-plan
SWITCH(config-schedule)# job name test-plan
SWITCH(config-schedule)# time start now repeat 0:0:1
Schedule starts from Fri Mar 15 13:43:27 2002
SWITCH(config-schedule)# end
SWITCH# 2002 Mar 15 13:41:34 
SWITCH %$ VDC-1 %$ %VSHD-5-VSHD_SYSLOG_CONFIG_I: Configured from vty by admin on console0

SWITCH# term mon
Console already monitors
SWITCH# show scheduler schedule
Schedule Name       : test-plan
-------------------------------
User Name           : admin
Schedule Type       : Run every 0 Days 0 Hrs 1 Mins
Start Time          : Fri Mar 15 13:43:27 2002
Last Execution Time : Yet to be executed
-----------------------------------------------
     Job Name            Last Execution Status
-----------------------------------------------
test-plan                             -NA-
==============================================================================
SWITCH# 2002 Mar 15 13:43:27 
SWITCH %$ VDC-1 %$ %USER-1-SYSTEM_MSG: No user ran /bootflash/scripts/test1.py on : SWITCH   - test1.py

SWITCH# show scheduler schedule
Schedule Name       : test-plan
-------------------------------
User Name           : admin
Schedule Type       : Run every 0 Days 0 Hrs 1 Mins
Start Time          : Fri Mar 15 13:43:27 2002
Last Execution Time : Fri Mar 15 13:43:27 2002
Last Completion Time: Fri Mar 15 13:43:27 2002
Execution count     : 1
-----------------------------------------------
     Job Name            Last Execution Status
-----------------------------------------------
test-plan                         Success (0)
==============================================================================
SWITCH#