Chapter 11. Python

In this chapter, I’ll show you how Python was used to create much of what you see when using the CLI, and then I’ll show you how to mess with it. Think about that for a minute; not only is EOS designed from the ground up to be extensible, but Arista has also given us the ability to alter the way in which the switch behaves. As far as I’m aware, this is unprecedented in the realm of networking devices. Sure, other devices are based on Linux, but you can’t get to it, and you certainly can’t change anything outside of the typical user-configurable options.

When I visited Arista for the first time, I asked Ken Duda (Founder, Chief Technology Officer, and Senior Vice President of Software Engineering) if they worried about end users rendering their switches inoperable by messing with stuff they didn’t understand. His answer, and I’m paraphrasing here, was that Arista believed in the open source concept so strongly that they encouraged users to make new and exciting solutions based on their products. When I asked what would happen if I managed to Python my switch into a useless pile of network-crushing slag, I was told that Arista would try to help, but that since I had fundamentally altered the intended function of the switch, that my support would be on a best effort case. Again, I’m paraphrasing; I don’t think the word slag was ever uttered during that conversation.

I’ve been in the IT industry for roughly 385 years (since 1984). In all that time, I’ve learned appropriate bitterness and derision for new ideas that are just recycled failures from the era of mainframes. Arista not only does things differently, they act differently. The ability to ruin my switch would be a support nightmare for any other company. Arista embraces the possibilities that for every clod like me who can’t code Python to save his life, there might be someone out there with new ideas that could make an Arista switch into something wonderful that was previously unimaginable. To that end, I’m going to show you how to mess with the CLI.

The entire EOS experience can be viewed, managed, and even changed from the bash shell. Let’s look at an extremely simple example of what I mean.

Note

If you’re afraid of vi, or you don’t know Python, or Unix gives you chills, then you shouldn’t do any of this. Yes, you can muck things up beyond recognition, and yes, Arista will attempt to help you if you do, but your support will be best efforts when you alter the fundamental way your switch works. You can cause a lot of damage messing with these files. This example is meant to show the power and extensible nature of EOS. Mess with it at your own risk.

Within bash, we can find the Python scripts used by EOS for every CLI command. They are located in /usr/lib/python2.6/site-packages/CliPlugin/ on version 4.8.1.

Within this directory are hundreds of files, but for this example, I’ll edit the output of the show version command to include the line “GAD Rocks!” Why? Because I’m a bored nerd with a keyboard, that’s why.

From within the bash shell, we’ll need to change to the proper directory:

[GAD@Arista-1 ~]$ cd /usr/lib/python2.6/site-packages/CliPlugin/
[GAD@Arista-1 CliPlugin]$

Note

File locations differ between versions. Later versions use different versions of Python based on where it resides in the Fedora distribution on which EOS is built. EOS versions 4.9 and 4.10 use Python 2.7, for example.

There are too many files to sift through, but I recommend you poke around and see what’s available for your troublemaking, er, development pleasure. To limit what we’re looking for, I’ll use the command ls –al *Cli*py:

[GAD@Arista-1 CliPlugin]$ ls -al *Cli*py
-rw-r--r-- 1 root root  55478 Jun  9 12:44 AaaCli.py
-rw-r--r-- 1 root root  57944 Jun 10 16:36 AclCli.py
-rw-r--r-- 1 root root  12387 Jun 10 16:36 AclCliRules.py
-rw-r--r-- 1 root root  22636 Jun  9 12:52 AgentCli.py
-rw-r--r-- 1 root root   6923 Jun  9 12:41 AliasIntfCli.py
-rw-r--r-- 1 root root   7671 Jun 10 16:38 BackupIntfCli.py
-rw-r--r-- 1 root root   5696 Jun 10 16:56 BeaconLedCli.py
-rw-r--r-- 1 root root   5994 Jun  9 12:52 BootCli.py
-rw-r--r-- 1 root root  30684 Jun 10 16:27 BridgingCli.py
-rw-r--r-- 1 root root   3731 Jun  9 12:37 CliCli.py
-rw-r--r-- 1 root root    834 Jun  9 12:37 CliError.py
-rw-r--r-- 1 root root   7795 Jun  9 12:52 ClockCli.py
-rw-r--r-- 1 root root  11040 Jun 10 17:11 DcbxCli.py
[--- output truncated ---]

Look around and it should become obvious what commands are controlled by which scripts. For my ludicrous project, I’m looking for the script that controls the output of the show version command. With a little bit of searching, I discovered the file VersionCli.py:

-rw-r--r-- 1 root root   6188 Sep 28 19:01 VersionCli.py

Since I have pathetically dated programming skills and I’m not afraid to use them, I dug right in and edited that file:

[GAD@Arista-1 CliPlugin]$ sudo vi VersionCli.py

Note

As with most implementations of Linux, you should not become root. Use of the sudo command will become second nature. If you really, really want to be running around like you own the place, you can feel like root by using the sudo bash command. But don’t. It’s not good for you.

This rewarded me with a vi session with the VersionCli.py file open:

# Copyright (c) 2006-2010 Arista Networks, Inc.  All rights reserved.
# Arista Networks, Inc. Confidential and Proprietary.

import Tac, CliParser, BasicCli, os, Tracing, EosVersion, Ethernet

__defaultTraceHandle__ = Tracing.Handle( 'VersionCli' )
t0 = Tracing.trace0

#--------------------------------------------------------------------
# The "show version [detail]" command.
#--------------------------------------------------------------------
tokenVersion = CliParser.KeywordRule(
   'version',
   helpdesc='Show switch version information' )

tokenDetail = CliParser.KeywordRule(
   'detail',
   helpdesc='Show additional version information',
   name='detail' )

def showVersion( mode, detail=None ):
"VersionCli.py" 156L, 6188C

Knowing enough to be dangerous, I scrolled down a bit, looking for the beginning of the showVersion definition (seen at the bottom of the previous screen):

tokenDetail = CliParser.KeywordRule(
   'detail',
   helpdesc='Show additional version information',
   name='detail' )

def showVersion( mode, detail=None ):
   vi = EosVersion.VersionInfo( mode.sysdbRoot )
   # Print information about the switch hardware

   print "Arista %s" % ( vi.modelNameExtended() )
   print "Hardware version:    %s" %( vi.hardwareRev() )
   if detail:
      deviations = vi.deviations()
      if deviations:
         print "Deviations:          %s" %( ", ".join( deviations ) )
   print "Serial number:       %s" %( vi.serialNum() )
   entityMib = mode.sysdbRoot[ 'hardware' ][ 'entmib' ]
   print "System MAC address:  %s" 
         %Ethernet.convertMacAddrCanonicalToDisplay(
entityMib.systemMacAddr )
   print ""

   # Print information about the running software image.
   print "Software image version: %s" % vi.version()

I inject a nice chunk of Python statement to print GAD Rocks!, which looks like this:

def showVersion( mode, detail=None ):
   vi = EosVersion.VersionInfo( mode.sysdbRoot )
   # Print information about the switch hardware

   # Added by GAD 9-28-11
   print ""
   print "GAD Rocks!"
   ptint ""

   print "Arista %s" % ( vi.modelNameExtended() )
   print "Hardware version:    %s" %( vi.hardwareRev() )
   if detail:
      deviations = vi.deviations()
      if deviations:
         print "Deviations:          %s" %( ", ".join( deviations ) )
   print "Serial number:       %s" %( vi.serialNum() )
   entityMib = mode.sysdbRoot[ 'hardware' ][ 'entmib' ]

I saved my changes, exited vi, and moved to test my brilliant creation. To do so, I launched another session of CLI from the command line with the Cli Unix command.

Note

Remember how I wrote that even the CLI environment is a process that runs in its own user space? The Cli command lets us launch a new CLI process from Unix. Pretty cool, huh?

When I saw this mess, I knew that I’d done something wrong:

[GAD@Arista-1 CliPlugin]$ Cli
Error loading plugin 'VersionCli'
=============== Exception raised in 'Cli [interac        ' (PID 18604;
PPID 18283) ===============
Local variables by frame (innermost frame last):

  File "/usr/lib/python2.6/site-packages/Plugins.py", line 173,
in _loadPluginAttrs
                 dirName = 'CliPlugin'
              moduleName = 'CliPlugin.VersionCli'
                    name = 'VersionCli'
              pluginList = [('AaaCli', <function Plugin at 0x986fca4>,
 (), ()), ('AclCli', <function Plugin at 0x9ad99cc>, (), ()),
('AclCliRules', None, (), ()), ('AgentCli', <function Plugin at
0x9ae3534>, (), ()), ('AliasIntfCli', <function Plugin at 0x9ae364c>,
(), ()), ('BackupIntfCli', <function Plugin at 0x9b01dbc>, (), ()),
('Banner', <function Plugin at 0x9afc064>, (), ()), ('BeaconLedCli',
<function Plugin at 0x9afc33c>, (), ()), ('BootCli', None, (), ()),
('BridgingCli', <function Plugin at 0x9b0e17c>, (), ()), ('CliCli',
None, (),
[--- output truncated ---]

Sure enough, here’s what I entered, with the mistake in bold:

   # Added by GAD 9-28-11
   print ""
   print "GAD Rocks!"
   ptint ""

Apparently ptint isn’t a command in Python. Who knew? After fixing my syntax error and making ptint into print, I tried again:

[GAD@Arista-1 CliPlugin]$ Cli
Arista-1>

Much better. Now let’s see what the output of show version looks like:

Arista-1>sho ver

GAD Rocks!

Arista DCS-7124S-F
Hardware version:    07.00
Serial number:       JSH10426696
System MAC address:  001c.7308.fa49

Software image version: 4.7.7
Architecture:           i386
Internal build version: 4.7.7-470791.EOS477release
Internal build ID:      91635ce6-88e9-4d07-abe0-3412ea936472

Uptime:                 9 minutes
Total memory:           2043420 kB
Free memory:            803864 kB

Success! How cool is that? Sure it’s a useless modification, but what if your company demanded something like “Property of GAD Technology – Unauthorized use is prohibited” at the end of every command’s output? You could do that with EOS. What if you wanted to display bytes per second instead of bits per second on some command output? (EOS is actually so cool that it converts the displayed values between bps, Kbps, Mbps, and Gbps, on the fly in show interface commands.) Or better yet, you wanted to create a new command that did something wonderful. All of those ideas and more are possible with EOS.

Note

If you’re running EOS version 4.9 or later, you may need to issue the bash command sudo killall FastClid-server to make your changes appear in CLI. This is due to the new FastCLId-server process that makes the CLI load faster by preloading all of the CLI plug-ins.

There’s one more step that needs to be done, or our change will not stay after a reboot. The files we messed with are in a temporary filesystem that is created and mounted at boot time. That means that they are created every time, so our changes will not “stick” after booting.

To rectify this, first copy your altered script to the /mnt/flash directory. This directory is persistent between reboots, so it’s a safe place to store altered code:

[GAD@Arista-1 CliPlugin]$ cp VersionCli.py /mnt/flash/VersionCliNEW.py

Now for the tricky part: the EOS developers have gone to great lengths to make EOS customizable. To that end, when EOS starts, it looks for a script in /mnt/flash called rc.eos. This script allows you to make changes to EOS before it loads. We’ll use it to copy our new script and overwrite the existing one that was just created at boot time:

[GAD@Arista-1 CliPlugin]$ cd /mnt/flash
[GAD@Arista-1 flash]$ vi rc.eos

In my case, I had to create rc.eos, after which I added the following:

#!/bin/sh

# Includes the file /etc/swi-version
. /etc/swi-version

if [ $SWI_VERSION == 4.7.7 ]; then
   # Version is same as original - proced with copy
   echo SWI version match copying modified parser files
   cp /mnt/flash/VersionCliNEW.py 
      /usr/lib/python2.6/site-packages/CliPlugin/VersionCli.py
else
   # Version is different - do not overwrite script
   echo WARNING: SWI version has changed to $SWI_VERSION
fi

This script can be tested by running it through sudo:

[GAD@Arista-1 flash]$ sudo ./rc.eos
SWI version match copying modified parser files

On newer EOS revisions (4.9 and later), the smoother way to accomplish this is with event-handler. event-handler is covered in detail in Chapter 26, but for now, here are the commands that will solve this issue.

First, instead of making the script reside in rc.eos, create the bash script elsewhere. I’ve created one named Load-GAD-CLI in /mnt/flash. I then issue the following commands to create an event handler:

Arista(config)#event-handler Boot-CLI
Arista(config-handler-Boot-CLI)#trigger onBoot
Arista(config-handler-Boot-CLI)#action bash sudo /mnt/flash/Load-GAD-CLI
Arista(config-handler-Boot-CLI)#exit

This will run my script much later in the boot process, which can be a bit cleaner than using rc.eos, since that loads very early in the boot process. This technique only works on EOS 4.9 and later, and naturally, since the script shown was written for 4.7.7, I’d need an updated script as well.

At this point, my change persisted after rebooting and I proceeded to add Python Operating System developer to my resume.

Note

One final note is in order. When upgrading EOS, you should check any changes you have made. If the core Fedora distribution changed, then the Python version (and related directory structure) will change. Additionally, libraries used by the original Python script may have changed, and the original script you altered may have changed.

At this point you should be able to see that EOS is very similar to Cisco’s IOS so far as look and feel are concerned. You should also understand that underneath the surface, EOS is considerably more open and powerful than IOS could ever hope to be. Once you grow accustomed to the power and flexibility of EOS, using anything else becomes an exercise in frustration.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.141.195.128