In my seemingly endless quest for the CCIE, I have learned about two decently powerful tools that together make an incredibly powerful and custom solution for modern DevOps/DevNet network; Embedded Event Manager (EEM) scripting, and Guestshell in IOS-XE devices. EEM scripting is far from new in the world of Cisco networks, it is a custom event driven scripting tool that executes custom actions/configuration changes based on a verity of events. The most common being configuration changes based on a syslog event. Guestshell is the relative newcomer to this discussion. Guestshell is a container containing a Linux server that lives on an IOS-XE device and is accessible from the CLI.
EEM SCRIPTING
EEM scripting can be both simple and very complex depending on what you want to do with it. For our purposes I will show some simple examples of EEM scripting, as this topic can be a discussion unto itself. Maybe in the future I will write a whole blog on EEM scripting.
When configuring EEM there are two pieces to the configuration puzzle. First you must configure the event, which in our example we will trigger this script using a syslog event. Second you must configure the action, which in our example is a configuration change, or really in the next section a call to Guestshell.
device(config)# event manager applet <EEM-Name>
device(config-applet)# event syslog pattern "<syslog message you want to match>"
device(config-applet)# action <sequence number> cli command "<cli command>"
Below is an example of how a simple EEM script would look when matching on the syslog pattern for a tracked item going down (in the lab I just tracked a loopback interface but this could be any tracked object), and then adding a static default route. Note that when you are using the cli command it starts in privileged mode. Failing to include enable command causes the script to fail.
device(config)# event manager applet EEM-Test
device(config-applet)# event syslog pattern "%TRACK-6-STATE: 1 interface Lo0 line-protocol Up -> Down"
device(config-applet)# action 1.0 cli command "enable"
device(config-applet)# action 1.1 cli command "config t"
device(config-applet)# action 1.2 cli command "ip route 0.0.0.0 0.0.0.0 10.10.10.2"
Note that when you are using the cli command it starts in privileged mode. Failing to include enable command causes the script to fail. Also when you use something like a track state to make a configuration change, a second EEM script is needed when the track state changes back to revert the configuration changes made.
GUESTSHELL
Guestshell is a relatively new as a tool for network engineers. Guestshell is a virtualized Linux CentOS environment, designed to run custom Linux applications, including python, in a container on the IOS-XE device. Based on the version of IOS installed on the device, the Guestshell image is updated with specific version of python already installed on the Linux OS:
- IOS-XE version up to 17.3.1: Python 2.7 pre-installed
- IOS-XE version 17.1.1 and beyond: Python 3.6 pre-installed
Any version before 17.3.1 will have python version 2.7, and any version after 17.1.1 will have python 3.6, which means version between 17.1.1 and 17.3.1 will have both versions of python installed. This is important as the version of your IOS device will determine which version of python you will write your script in.
NOTE: Guestshell is only enabled on devices that use the full IOS-XE image, the IOS-XE-lite image does not come with Guestshell.
SETUP GUESTSHELL
By default, Guestshell allows applications to access the management network through the dedicated management port. Users cannot change the management VRF networking configurations from inside the Guestshell so any non default configurations have to be made within IOS-XE itself. For platforms without a management port, a VirtualPortGroup can be associated with Guest Shell in the Cisco IOS configuration and the same non default configurations can be made using the VirtualPortGroup instead.
The first step in setting up Guestshell is to enable IOX. IOX, as Cisco puts it, is a combination of the words IOS-XE + LinuX. To enable IOX, from configuration mode just type the command iox. From there you should see a syslog message letting you know IOX is booting. It will take a few minutes for the Linux machine to boot.
Device(config)#iox
%UICFGEXP-6-SERVER_NOTIFIED_START: Switch 1 R0/0: psd: Server iox has been notified to start
%IOX-3-PD_PARTITION_CREATE: Switch 1 R0/0: run_ioxn_caf: IOX may take upto 5 mins to be ready. Wait for iox to be ready before installing the apps
%IOX-3-PD_PARTITION_CREATE: Switch 1 R0/0: run_ioxn_caf: Successfully allocated 4.0G in flash for hosting Applications
%IOX-3-IOX_RESTARTABITLITY: Switch 1 R0/0: run_ioxn_caf: Stack is in N+1 mode, disabling sync for IOx restartability
%IM-6-IOX_INST_INFO: Switch 1 R0/0: ioxman: IOX SERVICE guestshell LOG: Guestshell is up at 02/28/2024 18:49:35
%IM-6-IOX_ENABLEMENT: Switch 1 R0/0: ioxman: IOX is ready.
Once you see the “IOX is ready” log message then you know the linux container is ready for Guestshell. If you want to use the default settings on devices that have a dedicated management port, then the next command is to enable guestshell from the exec mode:
Device# guestshell enable
Interface will be selected if configured in app-hosting
Please wait for completion
Guestshell enabled successfully
CUSTOMIZING GUESTSHELL NETWORK INFORMATION
For devices that do not have a dedicated management port, or if you don’t want to use the dedicated management port on your IOS-XE device, then you will need to configure a virtual port group. Think of a virtual port group as another SVI on a switch. its a logical port that you can enable and interact with other physical ports. In our example we have Virtual port group 0 that is being PAT’d to the ip of the physical port GigEth1. The first part of this example is your standard IOS NAT overload configuration between two interfaces using a source list.
Device(config)# interface GigabitEthernet1
Device(config-if)# ip address dhcp
Device(config-if)# ip nat outside
Device(config-if)# exit
Device(config-if)# interface VirtualPortGroup0
Device(config-if)# ip address 192.168.35.1 255.255.255.0
Device(config-if)# ip nat inside
Device(config-if)# exit
Device(config)# ip nat inside source list GS_NAT_ACL interface GigabitEthernet1 overload
Device(config)# ip access-list standard GS_NAT_ACL
Device(config)# permit 192.168.0.0 0.0.255.255
The second half of this example sets the network settings of the Linux OS itself. This configuration is also useful if for whatever reason you need to change network settings of the Linux OS in Guestshell. (To identify a new gateway1 with the default management port, just substitute virtualportgroup 0 with management 0 on the second line.) The most common reason to make changes when you use a dedicated management port is to add a DNS server (line 6).
Device(config)# app-hosting appid guestshell
Device(config-app-hosting)# app-vnic gateway1 virtualportgroup 0 guest-interface 0
Device(config-app-hosting-gateway)# guest-ipaddress 192.168.35.2 netmask 255.255.255.0
Device(config-app-hosting-gateway)# exit
Device(config-app-hosting)# app-default-gateway 192.168.35.1 guest-interface 0
Device(config-app-hosting)# name-server0 172.16.0.1
Device(config-app-hosting)# end
Device# guestshell enable
Interface will be selected if configured in app-hosting
Please wait for completion
Guestshell enabled successfully
Once the Guestshell is enabled then you can simply launch into the Linux Bash prompt by typing “guestshell” in exec mode:
Device# guestshell
[guestshell@guestshell ~]$
USING PYTHON IN GUESTSHELL
To start using python in Guestshell you can either launch bash and then run python the normal way you would in Linux, or you can launch into python from the IOS-XE cli by using the keyword “run python”. You can see in my example that I was able to launch into python 3. We see we are in python by the >>>, and we can see that we can run python commands like print.
Device# guestshell run python3
Python 3.6.8 (default, Dec 22 2020, 19:04:08)
[GCC 8.4.1 20200928 (Red Hat 8.4.1-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> print('hello world')
hello world
>>>
Now running a few python commands is cool and all, however the power really comes when you want to execute a python script. Guestshell is able to read directly from IOS-XE flash, enabling you to quickly upload a python script and execute it from the Guestshell command. We can see I created a python script in flash, and it contains a simple print statement.
Device# more flash:guestshell.py
print("Hello from inside of the GuestShell.py script")
Now when I run it using the Guestshell command we can see the output:
Device# guestshell run python3 /flash/guestshell.py
Hello from inside of the GuestShell.py script
Device#
CLI MODULE
Cisco has built and installed a special python module called CLI. What it does is allow you to access the IOS-XE cli from within the python code. Just remember to add the import cli line at the top of your script to add this module. While I won’t go into detail on the whole method list, there are two that stand out:
- execute(‘<exec level command>‘)
- configurep([‘<python list>‘ , ‘<of configuration commands>‘])
As you can gather from the names of these two methods, the execute command will execute an exec level command such as any show commands. The output can then be stored as a variable in your script for you to parse and use. The configurep command is used to actually send configuration commands to IOS-XE. This command takes in a list of commands to execute. For instance:
cli.configurep([“interface loopback0″,”ip address 10.10.10.1 255.255.255.0″,”no shut”,”end”])
This will turn into the following configuration:
interface loopback0
ip address 10.10.10.1 255.255.255.0
no shut
end
LETS BRING IT ALL TOGETHER
Now that we know how to trigger events using EEM, how to execute custom python scripts using Guestshell, and how to execute CLI commands from python we can now bring it all together. Using EEM we can trigger on an action such as a syslog message, that calls the Guestshell command, which executes a python scripted stored in flash which can do most anything.
device(config)# event manager applet EEM-GUESTSHELL
device(config-applet)# event syslog pattern "%TRACK-6-STATE: 1 interface Lo0 line-protocol Up -> Down"
device(config-applet)# action 1.0 cli command "enable"
device(config-applet)# action 1.1 cli command "guestshell run python3 /flash/guestshell.py"
Using EEM and Guestshell together further provides a dynamic way of making changes to not only local network devices, but really anything with an API or SSH shell (using python ssh module). Here are a list of a couple of use cases for this powerful tool:
- Fixing asymmetric routing between two redundant edge routers on-premise and a cloud service like AWS or Azure: Using EEM you can trigger on a failover event where routing is now preferring the backup link and automatically run a python script that though the AWS or Azure APIs changes the priority of the routing tables to prefer the backup link on AWS or Azures side (assuming static routing on this side).
- Automatically backup the running configuration of a switch to GetHub for version control anytime a change is made on the device: Cisco actually has a demo of this, check it out here: https://www.youtube.com/watch?v=z2WW1RNjOq4
When we started to adopt cloud IaaS services, the world of networking changing to match the cloud DevOps model. Being able to use python to automatically control your environment is becoming a skill more and more companies are demanding. Taking the skills used in the cloud and being able to bring them on-premise only strengthens the tie between the two, and better automates the network as a whole.
As always if you have any questions on your network configuration and would like to schedule a free consultation with us, please reach out to us at sales@lookingpoint.com and we’ll be happy to help!
Trevor Butler, Network Architect