Quick Start for Cisco IOS-XE Guestshell and Python

July 14, 2020

Introduction: A quick start for using Guestshell and Python on the Cisco IOS-XE platform

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):


Step 1. Enable IOx

This is pretty straight forward:

csr1000v-1#confi t

Enter configuration commands, one per line.  End with CNTL/Z.



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

Step 2. Enable Guestshell

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




interface VirtualPortGroup0

vrf forwarding TEST-GS

ip address

ip nat inside

no mop enabled

no mop sysid




interface GigabitEthernet1

..description OOB Management

..vrf forwarding Mgmt-intf

..ip address

..ip nat outside



ip nat inside source list TEST-GS_NAT_ACL interface GigabitEthernet1 vrf TEST-GS overload


ip route vrf TEST-GS GigabitEthernet1


ip access-list standard TEST-GS_NAT_ACL



Now we can start the guestshell:

csr1000v-1#guestshell enable VirtualPortGroup 0 guest-ip name-server

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.

Step 3. Log into Guestshell

When the device came back from the crash, I was able to enable guestshell and log in.


[guestshell@guestshell ~]$

[guestshell@guestshell ~]$ pwd


[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

Step 4. Test Python interactive shell

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")



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)


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)]

Step 5. Tie in Scripts with EEM event:

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"


Step 6. Testing

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)#no shut


Wait for the Syslog message and turn on terminal monitoring to observe the syslog messages as well as the script output:


*Jun  7 01:11:41.111: %LINEPROTO-5-UPDOWN: Line protocol on Interface GigabitEthernet2, changed state to up


*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"



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!


Return to blog