Guest Shell and Python On-box on IOS-XE

What is Guest Shell?

Cisco IOS-XE devices (as of release 16.6.1) come with a guest shell, which is essentlially a virtualized Linux (CentOS) environment. It allows to run Linux applications on the network device. It comes prepopulated with common tools like net-tools, iproute, tcpdump and OpenSSH but it allows you also to install and update Linux applications (think of Puppet agents, Chef agents, Splunk agents…). Also Python (at the moment version 2.7) is integrated in the Linux environment so the guest shell allows you to run Python scripts as well. The guest shell is intended for tools, Linux utilities and manageability rather than networking functions.

The guest shell container is managed through IOx, which is Cisco’s Application Hosting Infrastructure for Cisco IOS XE devices. It provides application hosting capabilities for different application types. The guest shell (container deployment) is actually just one such application. The IOx facilitates the lifecycle management of applications, think of distribution, deployment, hosting, starting and stopping, monitoring applications and data.

Note about equipment

For all the examples in this post, we will use a Cisco sandbox environment delivered by Cisco Devnet. Go check out Devnet, really brilliant. To get a list of all sandboxes, check out this link. For this tutorial, I’m using the IOS XE sandbox (see here. In case you prefer to reserve an instance, check out this one.

Enable IOx

In order to work with the guest shell, we need to enable first the IOx. I won’t cover it here as part of this blog post. Though it’s documented really well in the ‘How to Enable Guest Shell’ of this guide.

Enable guest shell

We need to enable connectivity between the guest shell, which is a container and the IOS XE (or outside network). Therefore we need to configure some network settings:

  • Network settings of the host: create a Virtual Port Group
  • Network settings of the container: define the guest shall as an application through app-hosting appid guestshell
  • NAT configuration: create NAT entry on the IOS XE device to allow the container to access the outside world
  • Enable guest shell: use the guestshell enable command to launch the guest shell container (takes several minutes)

Note: for the previous items, check out this Cisco Live.presentation. Slides 15-19 give a step-by-step approach of the above steps.

Applied to the reserved sandbox

Step 1: Enable iox

csr1000v-1#conf t
Enter configuration commands, one per line.  End with CNTL/Z.
csr1000v-1(config)#iox
csr1000v-1(config)#end

Step 2: Network settings of the host

csr1000v-1#conf t
Enter configuration commands, one per line.  End with CNTL/Z.
csr1000v-1(config)#interface VirtualPortGroup0
csr1000v-1(config-if)#ip address 192.168.1.1 255.255.255.0
csr1000v-1(config-if)#end
csr1000v-1#conf t
Enter configuration commands, one per line.  End with CNTL/Z.
csr1000v-1(config)#app-hosting appid guestshell
csr1000v-1(config-app-hosting)#vnic gateway1 virtualportgroup 0 guest-interface 0 guest-ipaddress 192.168.1.2 netmask 255.255.255.0 gateway 192.168.1.1 name-server 8.8.8.8
csr1000v-1(config-app-hosting)#end

Step 3: NAT configuration

csr1000v-1#conf t
Enter configuration commands, one per line.  End with CNTL/Z.
csr1000v-1(config)#interface VirtualPortGroup0
csr1000v-1(config-if)#ip nat inside
csr1000v-1(config-if)#exit
csr1000v-1(config)#interface Gi
csr1000v-1(config)#interface GigabitEthernet1
csr1000v-1(config-if)#ip nat outside
csr1000v-1(config-if)#exit
csr1000v-1(config)#ip access-list extended NAT-ACL
csr1000v-1(config-ext-nacl)#permit ip 192.168.1.0 0.0.0.255 any
csr1000v-1(config-ext-nacl)#exit
csr1000v-1(config)#ip nat inside source list NAT-ACL interface GigabitEthernet1 overload
csr1000v-1(config)#end

Step 4: Enable guestshell

csr1000v-1#guestshell enable
Interface will be selected if configured in app-hosting
Please wait for completion
guestshell installed successfully
Current state is: DEPLOYED
guestshell activated successfully
Current state is: ACTIVATED
guestshell started successfully
Current state is: RUNNING
Guestshell enabled successfully
csr1000v-1#guestshell
[guestshell@guestshell ~]$
Execute commands within Guest Shell

After enabling the guestshell, you can access it as follows:

csr1000v# guestshell
[guestshell@guestshell ~]$

Next, you can execute Linux commands inside the guestshell (which is in fact a Centos linux environment). See below some examples:

csr1000v#guestshell
[guestshell@guestshell ~]$ whoami
guestshell
[guestshell@guestshell ~]$ pwd
/home/guestshell
[guestshell@guestshell ~]$ cat /etc/centos-release
CentOS Linux release 7.8.2003 (Core)

The Guest Shell container is isolated from the rest of operating system - it can’t consume more resources than were dedicated to it and it does not impact the host operating system.

Execute Guest Shell commands from IOS prompt

In the above example, we ran all commands from within the guestshell. What if we want to run these commands from the IOS XE prompt. That’s perfectly possible through the guestshell run command. See below:

csr1000v#guestshell run whoami
guestshell

csr1000v#guestshell run pwd
/home/guestshell

csr1000v#guestshell run cat /etc/centos-release
CentOS Linux release 7.8.2003 (Core)
Execute IOS-XE commands from Guest Shell prompt

From within the guestshell it is also possible to execute IOS XE CLI commands using dohost binary

csr1000v#guestshell
[guestshell@guestshell ~]$ dohost "show memory statistics"

Tracekey : 1#9ae4e6ddd6c2aa2a21997806924e75ee
                Head    Total(b)     Used(b)     Free(b)   Lowest(b)  Largest(b)
Processor  7F9125F80010   2449862632   355170016   2094692616   2092880960   1479733148
 lsmpi_io  7F91257351A8     3149400     3148576         824         824         412

[guestshell@guestshell ~]$
[guestshell@guestshell ~]$
[guestshell@guestshell ~]$ dohost "show ip interface brief"

Interface              IP-Address      OK? Method Status                Protocol
GigabitEthernet1       10.10.20.48     YES other  up                    up
GigabitEthernet2       10.255.255.1    YES other  up                    up
GigabitEthernet3       192.168.122.205 YES other  up                    up
Loopback100            172.16.100.1    YES other  up                    up
Loopback103            172.16.102.1    YES other  up                    up
Loopback321            10.3.2.1        YES other  up                    up
Loopback420            4.20.20.20      YES other  up                    up
Loopback666            12.13.14.1      YES other  up                    up
Loopback901            unassigned      YES unset  up                    up
Loopback1000           unassigned      YES unset  up                    up
Loopback1230           1.2.3.0         YES other  up                    up
Loopback1233           1.2.3.3         YES other  up                    up
Loopback1234           1.2.3.4         YES other  up                    up
Loopback1235           1.2.3.5         YES TFTP   up                    up
Loopback1919           unassigned      YES unset  up                    up
Loopback3040           10.30.40.1      YES other  up                    up
Loopback4040           10.40.40.1      YES other  up                    up
Loopback5040           10.50.40.1      YES other  up                    up
Loopback5555           5.5.5.5         YES other  up                    up
Loopback6040           10.60.40.1      YES other  up                    up
Loopback6692           12.12.12.2      YES other  up                    up
Loopback6694           12.12.12.4      YES other  up                    up
Loopback6789           6.7.8.9         YES other  up                    up
VirtualPortGroup0      192.168.1.1     YES other  up                    up
Installing packages in Guest Shell
[guestshell@guestshell ~]$ sudo yum update -y
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: mirror.sitbv.nl
 * extras: mirrors.powernet.com.ru
 * updates: mirror.cherryservers.com
<truncated output>
...
Complete!

What is Python On-box

On-Box Python is Python interpreter installed inside the Guest Shell that allows to run Python scripts on IOS XE router or switch. It is tied with Embedded Event Manager (EEM) and has direct access to IOS XE CLI commands using custom module called cli. It allows to react to different events directly on the device (Edge Computing), this includes additional reporting, post-configuration checks, complex troubleshooting capabilities, automation of repetitive tasks.

Run Python in Guest Shell
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.
>>>
Commands overview

A) cli.cli(commands)

>>> import cli
>>> output = cli.cli("show ip interface brief")
>>> print (output)

Interface              IP-Address      OK? Method Status                Protocol
GigabitEthernet1       10.10.20.48     YES NVRAM  up                    up
GigabitEthernet2       unassigned      YES NVRAM  administratively down down
GigabitEthernet3       unassigned      YES NVRAM  administratively down down
VirtualPortGroup0      192.168.1.1     YES manual up                    up

>>> cli.cli("show ip interface brief")
'\nInterface              IP-Address      OK? Method Status                Protocol\nGigabitEthernet1       10.10.20.48     YES NVRAM  up                    up      \nGigabitEthernet2       unassigned      YES NVRAM  administratively down down    \nGigabitEthernet3       unassigned      YES NVRAM  administratively down down    \nVirtualPortGroup0      192.168.1.1     YES manual up                    up      \n'

You will have noticed that cli.cli returns the result to a variable that you can then print. You could also directly print it to screen, but then it would essentially return everything as a single string. In that case, it’s better to use the cli.clip command.

B) cli.clip(commands)

>>> cli.clip("show ip interface brief")

Interface              IP-Address      OK? Method Status                Protocol
GigabitEthernet1       10.10.20.48     YES NVRAM  up                    up
GigabitEthernet2       unassigned      YES NVRAM  administratively down down
GigabitEthernet3       unassigned      YES NVRAM  administratively down down
VirtualPortGroup0      192.168.1.1     YES manual up                    up

In case you want to run two or more commands, seperate these with the ;. Pay also attention to the quotes. It should be: "show ip interface brief; show interface description" and not "show ip interface brief"; "show interface description". See below for an example:

>>> cli.clip("show ip interface brief; show interface description")

Interface              IP-Address      OK? Method Status                Protocol
GigabitEthernet1       10.10.20.48     YES NVRAM  up                    up
GigabitEthernet2       unassigned      YES NVRAM  administratively down down
GigabitEthernet3       unassigned      YES NVRAM  administratively down down
VirtualPortGroup0      192.168.1.1     YES manual up                    up
Interface                      Status         Protocol Description
Gi1                            up             up       MANAGEMENT INTERFACE - DON'T TOUCH ME
Gi2                            admin down     down     Network Interface
Gi3                            admin down     down     Network Interface

C) cli.execute(command)

This one is similar to cli.cli but only runs 1 single command

>>> output = cli.execute("show ip interface brief")
>>> print(output)
Interface              IP-Address      OK? Method Status                Protocol
GigabitEthernet1       10.10.20.48     YES NVRAM  up                    up
GigabitEthernet2       unassigned      YES NVRAM  administratively down down
GigabitEthernet3       unassigned      YES NVRAM  administratively down down
VirtualPortGroup0      192.168.1.1     YES manual up                    up
>>> cli.execute("show ip interface brief")
'Interface              IP-Address      OK? Method Status                Protocol\nGigabitEthernet1       10.10.20.48     YES NVRAM  up                    up      \nGigabitEthernet2       unassigned      YES NVRAM  administratively down down    \nGigabitEthernet3       unassigned      YES NVRAM  administratively down down    \nVirtualPortGroup0      192.168.1.1     YES manual up                    up

Also here, you will notice that cli.execute returns the result to a variable that you can then print. You could also directly print it to screen, but then it would essentially return everything as a single string. In that case, it’s better to use the cli.executep command.

D) cli.executep(command) Similarly, the cli.executep executes a single command but does print out the output directly to screen.

>>> cli.executep("show ip interface brief")
Interface              IP-Address      OK? Method Status                Protocol
GigabitEthernet1       10.10.20.48     YES NVRAM  up                    up
GigabitEthernet2       unassigned      YES NVRAM  administratively down down
GigabitEthernet3       unassigned      YES NVRAM  administratively down down
VirtualPortGroup0      192.168.1.1     YES manual up                    up

E) cli.configure(commands)

>>> output = cli.configure(["interface Loopback5000", "description Set through cli.configure"])
>>> print(output)
[ConfigResult(success=True, command='interface Loopback5000', line=1, output='', notes=None), ConfigResult(success=True, command='description Set through cli.configure', line=2, output='', notes=None)]

Let’s see if it worked…We can use one of the previous commands for this:

>>> cli.clip("show ip interface brief; show interface description")

Interface              IP-Address      OK? Method Status                Protocol
GigabitEthernet1       10.10.20.48     YES NVRAM  up                    up
GigabitEthernet2       unassigned      YES NVRAM  administratively down down
GigabitEthernet3       unassigned      YES NVRAM  administratively down down
Loopback5000           unassigned      YES unset  up                    up
VirtualPortGroup0      192.168.1.1     YES manual up                    up
Interface                      Status         Protocol Description
Gi1                            up             up       MANAGEMENT INTERFACE - DON'T TOUCH ME
Gi2                            admin down     down     Network Interface
Gi3                            admin down     down     Network Interface
Lo5000                         up             up       Set through cli.configure
Vi0                            up             up

You can see the loopback interface was added successfully and the description was set properly.

Note: unfortunately in this case, with cli.configure we need to use a , to seperate multiple commands.

F) cli.configurep(commands) Let’s now use the cli.configurep command to remove the Loopback interface that we added previously.

>>> cli.configurep("no interface Loopback5000")
Line 1 SUCCESS: no interface Loopback5000
>>> cli.executep("show ip interface brief")
Interface              IP-Address      OK? Method Status                Protocol
GigabitEthernet1       10.10.20.48     YES NVRAM  up                    up
GigabitEthernet2       unassigned      YES NVRAM  administratively down down
GigabitEthernet3       unassigned      YES NVRAM  administratively down down
VirtualPortGroup0      192.168.1.1     YES manual up                    up
>>>