It has been many years since I explored onboard shell and Python options for Cisco platforms, the post on Cisco Nexus 3000 (https://blog.pythonicneteng.com/2013/06/quickly-change-cisco-nexus-config-via.html) was the last I can recall. Back then, onboard shell and Python works on Cisco, but it always felt a bit clunky and seemed like a hack. In comparison, the Arista switches have always been more open to give engineer access to the underlying Linux shell as well as Python interpreter (https://blog.pythonicneteng.com/2012/12/book-review-arista-warriors.html). There were times when a hot fix from Arista was in the form of a Python script.
However, ever since I received the book 'IOS XE Programmability' book (e-book downloadable via https://www.cisco.com/c/dam/en/us/products/collateral/enterprise-networks/nb-06-ios-xe-prog-ebook-cte-en.pdf) from Hank (https://twitter.com/hfpreston, Thank you Hank!) I wanted to give IOx (https://www.cisco.com/c/en/us/products/cloud-systems-management/iox/index.html) a shot. I thought it would be great to document my learning progress on my blog.
First step for me is to give IOS-XE guestshell and onboard Python interpreter a shot. Here is the quick start that I took, hopefully this can be useful for somebody.
For the topology, I used Cisco VIRL (probably going to switch to DevNet labs later, more on that later):
This is pretty straight forward:
csr1000v-1#confi t
Enter configuration commands, one per line. End with CNTL/Z.
csr1000v-1(config)#iox
csr1000v-1(config)#end
We can see the status with 'show iox':
csr1000v-1#show iox
Virtual Service Global State and Virtualization Limits:
Infrastructure version : 1.7
Total virtual services installed : 1
Total virtual services activated : 0
Machine types supported : KVM, LXC
Machine types disabled : none
Maximum VCPUs per virtual service : 0
Resource virtualization limits:
Name Quota Committed Available
--------------------------------------------------------------
system CPU (%) 7 0 7
memory (MB) 1024 0 804
bootflash (MB) 20000 120 13847
IOx Infrastructure Summary:
---------------------------
IOx service (CAF) : Running
IOx service (HA) : Not Running
IOx service (IOxman) : Not Running
Libvirtd : Running
Many of the examples show the guestshell being enabled via 'guestshell enable'. However, I received the following error from VIRL:
csr1000v-1#guestshell enable
Management Interface will be selected if configured
Please wait for completion
Management Port is not supported on this platform.
Use VPG to enable guestshell.
Example: guestshell enable virtualPortGroup <vpg-num> guest-ip <guest-ip> name-server <name-server>
A bit annoying, but no problem, a learning opportunity for me to configure virtual port group and:
vrf definition TEST-GS
!
address-family ipv4
exit-address-family
!
!
interface VirtualPortGroup0
vrf forwarding TEST-GS
ip address 192.168.100.101 255.255.255.0
ip nat inside
no mop enabled
no mop sysid
!
!
!
interface GigabitEthernet1
..description OOB Management
..vrf forwarding Mgmt-intf
..ip address 172.16.1.150 255.255.255.0
..ip nat outside
!
iox
ip nat inside source list TEST-GS_NAT_ACL interface GigabitEthernet1 vrf TEST-GS overload
!
ip route vrf TEST-GS 0.0.0.0 0.0.0.0 GigabitEthernet1 172.16.1.1
!
ip access-list standard TEST-GS_NAT_ACL
permit 192.168.100.0 0.0.0.255
!
Now we can start the guestshell:
csr1000v-1#guestshell enable VirtualPortGroup 0 guest-ip 192.168.100.102 name-server 8.8.8.8
The box hung for a while and eventually crashed. To save me some heartache and time, I will probably switch to DevNet labs in the future. Also, despite configuring NAT, I noticed there was no Internet access from the Guestshell. This is fine for now since I just wanted to poke around a bit, but would be a big roadblock if I can't install additional packages via pip.
When the device came back from the crash, I was able to enable guestshell and log in.
csr1000v-1#guestshell
[guestshell@guestshell ~]$
[guestshell@guestshell ~]$ pwd
/home/guestshell
[guestshell@guestshell ~]$ ls -lia
total 7
32214 drwx------ 3 guestshell users 1024 Jun 6 23:51 .
31686 drwxr-xr-x 3 root root 1024 May 31 2016 ..
32263 -rw------- 1 guestshell guestshell 39 Jun 6 23:51 .bash_history
34326 -rw-r--r-- 1 guestshell users 18 Mar 5 2015 .bash_logout
33268 -rw-r--r-- 1 guestshell users 193 Mar 5 2015 .bash_profile
33797 -rw-r--r-- 1 guestshell users 231 Mar 5 2015 .bashrc
32261 drwx------ 2 guestshell users 1024 Jun 6 23:49 .ssh
Testing the Python interactive shell was straight forward, no Python 3 support yet however:
csr1000v-1#guestshell run python
Python 2.7.5 (default, Jun 17 2014, 18:11:42)
[GCC 4.8.2 20140120 (Red Hat 4.8.2-16)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> exit()
Step 5. Write some Python script (using vi)
There was only vi available, so that was what I used. However, I learned if I launch the vi editor directly from CLI the input and output were not optimal:
csr1000v-1#guestshell run vi hello_world.py
Vim: Warning: Output is not to a terminal
Vim: Warning: Input is not from a terminal
So I log back into the guestshell and use vi to construct the following scripts. The show_version.py script uses the CLI library to execute a CLI command:
[guestshell@guestshell ~]$ cat show_version.py
import datetime
from cli import *
version = cli("show version | include Version")
print(version)
print(datetime.datetime.now())
The logging_buffer.py script uses the configure method to change configuration in the IOS:
[guestshell@guestshell ~]$ cat logging_buffer.py
from cli import *
config_buffer = '''logging buffered 30000'''
result = configure(config_buffer)
print(result)
The scripts can be launched within IOS via the 'guestshell run' command:
csr1000v-1#guestshell run python logging_buffer.py
[ConfigResult(success=True, command='logging buffered 30000', line=1, output='', notes=None)]
Here is the EEM event that watches syslog to trigger an action:
!
event manager applet Interface_Up
event syslog pattern "Interface GigabitEthernet2, changed state to up"
action 1 cli command "guestshell run python show_version.py"
action 2 cli command "guestshell run python logging_buffer.py"
!
I bounced the GigabitEthernet2 interface:
csr1000v-1#confi t
Enter configuration commands, one per line. End with CNTL/Z.
csr1000v-1(config)#int gig
csr1000v-1(config)#int gigabitEthernet 2
csr1000v-1(config-if)#shutdown
csr1000v-1(config-if)#no shut
csr1000v-1(config-if)#end
Wait for the Syslog message and turn on terminal monitoring to observe the syslog messages as well as the script output:
csr1000v-1#
*Jun 7 01:11:41.111: %LINEPROTO-5-UPDOWN: Line protocol on Interface GigabitEthernet2, changed state to up
csr1000v-1#
*Jun 7 01:22:39.881: %SYS-5-LOG_CONFIG_CHANGE: Buffer logging: level debugging, xml disabled, filtering disabled, size (30000)
csr1000v-1#sh run | i logging
logging buffered 30000
action 1 cli command "guestshell run python logging_buffer.py"
csr1000v-1#
This is probably something others have experienced with but somewhat new to me. As mentioned, I just want to start document my progress in case this is useful for someone else. The true goal is to start getting familiar with IOx and explore the possibility of writing our own container-based applications directly at the edge.
Happy coding!
Eric