Cisco IOS-XE now comes with a neat feature called Guest Shell, it give us the power of spinning up a Linux Container on the router, giving us many new Network Programmability options, the main one being the option of running custom Python Scripts. With that we can write things like custom Metrics, Integrations, Features and tools not natively available.
Enabling the Guest Shell
I will be using a Cisco CSR1000v on AWS as an example (its easier to spin up and lab), but the feature is also available on ASR and ISR, and the way to enable is is fairly similar.
When you bring the CSR up, you should notice that it has a VirtualPortGroup Interface enabled, this Interface will be responsible for the Interface between the GuestShell Container and the router IOS-XE/External World. On platforms with managements ports, the mgmt interface/vrf would be used for the Interface with the GuestShell.
app-hosting appid guestshell vnic gateway1 virtualportgroup 0 guest-interface 0 guest-ipaddress 192.168.35.2 netmask 255.255.255.0 gateway 192.168.35.1 resource profile custom cpu 1500 memory 512 guestshell enable VirtualPortGroup 0 guest-ip 192.168.35.2
That’s it, we can run show app-hosting list to confirm that GuestShell is enabled:
#show app-hosting list App id State ------------------------------------------------------ guestshell RUNNING
To gain shell access, run guestshell run bash:
#guestshell run bash [guestshell@guestshell ~]$ uname -a Linux guestshell 4.4.51 #1 SMP Sun Apr 23 01:42:33 PDT 2017 x86_64 x86_64 x86_64 GNU/Linux [guestshell@guestshell ~]$
We are now able to start playing with Python. Your main Python package will be the cli package, this let you run IOS commands from the shell:
[guestshell@guestshell ~]$ 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. >>> from cli import cli >>> from cli import configure >>> >>> configure('hostname IT-WORKS') [ConfigResult(success=True, command='hostname IT-WORKS', line=1, output='', notes=None)] >>> cli('show running-config | in hostname') '\nhostname IT-WORKS\n' >>>
It also comes with pip installed, so you are able to install pretty much any package that you need to write your code.
I’ve been implementing a bunch of Cisco routers with ZBF lately, its a simple and nice Firewall solution for those that don’t need all that fancy features that vendors as CheckPoint or Palo Alto offer you, and one thing that happened a couple of times is ACL out o Sync between the devices, before we wrote a NAPALM script to update both devices at same time (more of this on a future post), I would sometimes update the ACL in one Router and forget to update the pair device, I would then test a failover and notice that traffic was dropped on the secondary router. (Oops!)
Verify ACL Sync with IOS-XE GuestShell and Python
This gave the Idea to write this example using GuestShell and Python for this blog post, the following Script runs after X specified seconds, compare the Local ACLs with the Remote ACLs, and generate a Syslog Message in case they are out of sync. Simple and helpful. Here’s the code, which is also available on my github:
#!/usr/bin/env python | |
from cli import cli | |
from cli import configure | |
from netmiko import ConnectHandler | |
''' | |
This script should run on the GustShell, it requires netmiko to be installed. This will check the local acls, the peer | |
router ACls, compare the difference and generate a SysLog message in case they are out-of-sync. | |
''' | |
#Users hardcoded in code as this is just an example script. In production you may want to use | |
#Some sort of Vault. | |
username = "superuser" | |
password = "superpass" | |
def get_remote_acls(): | |
remote_acls = "" | |
#Specify the ip for the pair Router | |
device = { 'device_type': 'cisco_ios', 'ip':'10.250.0.20', 'username': username, | |
'password': password} | |
net_connect = ConnectHandler(**device) | |
remote_acls = net_connect.send_command("show run | sec access-list") | |
return remote_acls | |
def acl_diff(local_acls,remote_acls): | |
lines = local_acls.splitlines() | |
lines = [line for line in lines if line.strip()] | |
local_acls = lines | |
lines = remote_acls.splitlines() | |
lines = [line for line in lines if line.strip()] | |
remote_acls = lines | |
if len(local_acls) > len(remote_acls): | |
diff = "ATTENTION. ACLs are not in Sync, local ACL has more entries than Peer." | |
elif len(remote_acls) > len(local_acls): | |
diff = "ATTENTION. ACLs are not in Sync, remote ACL has more entries than Peer." | |
else: | |
diff = False | |
return diff | |
def log(message, severity): | |
cli('send log {} {}'.format(severity, message)) | |
def reschedule(seconds, diff): | |
UPDATE_SCRIPT_FIRING_COMMANDS = """ | |
event manager applet ACL-SYNC-CHECK | |
event timer watchdog time %s | |
action 1.0 cli command "enable" | |
action 1.1 cli command "guestshell run /home/guestshell/check_acl_sync.py | |
""" | |
configure(UPDATE_SCRIPT_FIRING_COMMANDS % (seconds)) | |
if diff: | |
log(diff,4) | |
def main(): | |
local_acls = cli("show run | sec access-list") | |
remote_acls = get_remote_acls() | |
diff = acl_diff(local_acls, remote_acls) | |
#specify in seconds how long to wait between checks. | |
reschedule(1800, diff) | |
if __name__ == "__main__": | |
main() |
Copy this to a .py on the GuestShell, make it an executable with chmod +x file_name.py, and execute it! If the ACLs on both devices are not the same, you will see this log msg on the Router:
*Feb 8 11:57:16.924: %SYS-4-USERLOG_WARNING: Message from tty3(user id: ): ATTENTION. ACLs are not in Sync, local ACL has more entries than Peer.
If you have a syslog Collector that Integrates with Slack or some other Chat Platform that your team uses, it should be easy to see when the ACLs are not in-sync, and now anyone can go to their favourite Version Control system where they manage their ACLs and re-apply the ACL to the device with missing entries. I am sure you store you ACLs in a repo, right? 🙂
With imagination and some available time this Script could be much improved, and many other cool tools/features could be written to level-up your Cisco IO-XE Routers!
I hope this helps someone, thanks for reading.