Chapter 2: Script Framework for Use Cases

This chapter is going to help you to build a Python script framework using some of the core concepts learned in the previous chapter. By using this framework you build some of the common network operational use cases such as inventory, capacity planning and troubleshooting network issues later in this book.

First Script - Show version

In this section, we will write a Python script using pyeapi and connect to one of the Arista switches and collect “show version” from the switch.

Make sure you enable management api on the Arista switch. Below is the sample configuration to enable management api when the management interface is configured under default vrf.

configure
!
interface Management1
   ip address 172.28.132.42/20
!
management api http-commands
  no shutdown
!

Below is the sample configuration to enable management api when the management interface is configured under non default vrf.

configure
!
interface Management1
   vrf forwarding mgmt
   ip address 172.28.132.45/20
!
management api http-commands
   no shutdown
   vrf mgmt
      no shutdown

Launch the Python interpreter from your system and connect to Arista switch using pyeapi. If you have not installed pyeapi module, refer Installing Python Modules.

anees:~ anees$ python
Python 2.7.10 (default, Aug 22 2015, 20:33:39)
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.

>>> import pyeapi

>>> node = pyeapi.connect(transport="https", host="172.28.132.41", username="admin", password="admin", port=None)

>>> version = node.execute(["show version"])

>>> version
{u'jsonrpc': u'2.0', u'result': [{u'memTotal': 8069504, u'version': u'4.15.2F', u'internalVersion': u'4.15.2F-2663444.4152F', u'serialNumber': u'JPE14080457', u'systemMacAddress': u'00:1c:73:57:4f:49', u'bootupTimestamp': 1446677012.2, u'memFree': 4381616, u'modelName': u'DCS-7050SX-128-F', u'architecture': u'i386', u'internalBuildId': u'b664b979-69d7-4157-9543-20278086874a', u'hardwareRevision': u'02.00'}], u'id': u'4522839056'}

Response of the output is stored as dictionary in the variable “version”. Dictionary is a Python data structure represented in { } bracket and the data is represented as key:<value> pair.

>>> type(version)
<type 'dict'>

>>> version.keys()
[u'jsonrpc', u'result', u'id']

>>> version["result"]
[{u'memTotal': 8069504, u'version': u'4.15.2F', u'internalVersion': u'4.15.2F-2663444.4152F', u'serialNumber': u'JPE14080457', u'systemMacAddress': u'00:1c:73:57:4f:49', u'bootupTimestamp': 1446677012.2, u'memFree': 4381616, u'modelName': u'DCS-7050SX-128-F', u'architecture': u'i386', u'internalBuildId': u'b664b979-69d7-4157-9543-20278086874a', u'hardwareRevision': u'02.00'}]

Value of the key “result” is a list which is another Python data structure represents in square [ ] brackets.

>>> type(version["result"])
<type 'list'>
>>>
>>> len(version["result"])
1
>>> version["result"][0]
{u'memTotal': 8069504, u'version': u'4.15.2F', u'internalVersion': u'4.15.2F-2663444.4152F', u'serialNumber': u'JPE14080457', u'systemMacAddress': u'00:1c:73:57:4f:49', u'bootupTimestamp': 1446677012.2, u'memFree': 4381616, u'modelName': u'DCS-7050SX-128-F', u'architecture': u'i386', u'internalBuildId': u'b664b979-69d7-4157-9543-20278086874a', u'hardwareRevision': u'02.00'}

Finally the desired data is accessible in the output of version[“result”][0]. As you see the curly bracket, it is a Python dictionary data structure. You can access the desired data using the keys “version”, “modelName” or “serialNumber”.

>>> version["result"][0]["version"]
u'4.15.2F'

>>> # Data is represented in unicode format u’ ’. You can convert to string using str().

>>> str(version["result"][0]["version"])
'4.15.2F'

>>> str(version["result"][0]["serialNumber"])
'JPE14080457'

>>> str(version["result"][0]["modelName"])
'DCS-7050SX-128-F'

As you have seen, the actual output of show version is stored as dictionary under List which is a value within a parent dictionary. If it is confusing, Python’s pprint module provides a good view of the nested data structure.

>>> import pprint

>>> pprint.pprint(version)
{u'id': u'4522839056',
 u'jsonrpc': u'2.0',
 u'result': [{u'architecture': u'i386',
              u'bootupTimestamp': 1446677012.2,
              u'hardwareRevision': u'02.00',
              u'internalBuildId': u'b664b979-69d7-4157-9543-20278086874a',
              u'internalVersion': u'4.15.2F-2663444.4152F',
              u'memFree': 4381616,
              u'memTotal': 8069504,
              u'modelName': u'DCS-7050SX-128-F',
              u'serialNumber': u'JPE14080457',
              u'systemMacAddress': u'00:1c:73:57:4f:49',
              u'version': u'4.15.2F'}]}

>>> version["result"][0]["serialNumber"]
u'JPE14080457'

Second Script - Running Show Version on Multiple Switches

Power of scriptming language is repeatability. Since you have already created a script to collect show version, let us use this code to collect show version from multiple switches in the network.

Since we will be creating several python scripts, let us create a folder in our systems. In this example I have created a folder called my-scripts under /Users/anees/Google Drive/.

Using IDLE

Now it is the time to start using Python’s IDLE environment. This is helpful while developing the script where we have to test the script as we make progress with the script.

For MAC, type “idle” in the terminal window and you will see Python IDLE shell is opened.

_images/ch02-pic1.png

Create a new file from File → New File

_images/ch02-pic2.png

It opens a new untitled IDLE file. Save this file using File → Save As under the folder you created with the name as inventory_version.py.

_images/ch02-pic3.png

Write your script and save from File → Save (or Command + S).

import pyeapi

node = pyeapi.connect(transport="https", host="172.28.132.41", username="admin", password="admin", port=None)

version = node.execute(["show version"])

Test your script from Run → Run Module (or F5).

_images/ch02-pic4.png

The script runs in the IDLE shell, which you can see, in the right side of the following screenshot. You can also access the variables from the IDLE shell.

for loop

Now let us create a script to collect the Model Name, Serial Number and EOS versions on multiple Arista switches in your network.

import pyeapi

# Create a List of Switches
switches = ["172.28.132.41", "172.28.132.40", "172.28.132.45"]

for switch in switches:
    # Define API Connection String
    node = pyeapi.connect(transport="https", host=switch, username="admin", password="admin", port=None)

    # Execute the desired command
    version = node.execute(["show version"])

    # Print the desired Output
    print
    print ("*******************************************************")
    print ("Switch IP: %s") % (switch)
    print ("Model Name: %s") % (version["result"][0]["modelName"])
    print ("Serial Number: %s") % (version["result"][0]["serialNumber"])
    print ("EOS Version: %s") % (version["result"][0]["version"])
    print ("*******************************************************")
    print

Save and run the command. You will see the output in the IDLE shell similar to the following output.

>>> ================================ RESTART ================================
>>>

*******************************************************
Switch IP: 172.28.132.41
Model Name: DCS-7050SX-128-F
Serial Number: JPE14080457
EOS Version: 4.15.2F
*******************************************************


*******************************************************
Switch IP: 172.28.132.40
Model Name: DCS-7050SX-128-F
Serial Number: JPE14080459
EOS Version: 4.15.2F
*******************************************************


*******************************************************
Switch IP: 172.28.132.45
Model Name: DCS-7280SE-64-F
Serial Number: JPE14443170
EOS Version: 4.15.2F
*******************************************************

Third Script - Using External Input

In the second script, we have listed the switch IP addresses, username and password in the script. In this script, we will enter the IPs in a text file and enforce the script to prompt for username and password when the script is executed.

Create a file named “switches” in the same directory as you are saving the Python scripts using any text editor of your choice. And add the list of IP addresses of the switches. Format the file as plain text (Format → Make Plain Text).

Open the IDLE and create a new python script named inventory_version_input.py.

'''

Third script - Inventory - show version - Using External Input

'''

import pyeapi

# Define file path and file names

file_path = "/Users/anees/Google Drive/my-scripts/"
file_name_switches = "switches.txt"
file_switches = file_path + file_name_switches

Run this command and verify the value of the variable file from the python shell.

_images/ch02-pic5.png

Let us update the script to read the content of the file “switches”.

'''

Third script - Inventory - show version - Using External Input

'''

import pyeapi

# Define file path and file names

file_path = "/Users/anees/Google Drive/my-scripts/"
file_name_switches = "switches.txt"
file_switches = file_path + file_name_switches

# Read the content of the file and save it in a List

with open(file_switches) as readfile:
    for line in readfile:
        print line

Run the script and verify the result.

>>> ================================ RESTART ================================
>>>
172.28.132.41

172.28.132.40

172.28.132.45

We will store the IP addresses read from the file into a list.

'''

Third script - Inventory - show version - Using External Input

'''

import pyeapi

# Define file path and file names

file_path = "/Users/anees/Google Drive/my-scripts/"
file_name_switches = "switches.txt"
file_switches = file_path + file_name_switches


# Read the content of the file and save it in a List

switches = []

with open(file_switches) as readfile:
    for line in readfile:
        switches.append(line)

Run this script.

>>> ================================ RESTART ================================
>>>

# You will not see any output since we are not sending any data to output

# Type the variable name switches

>>> switches
['172.28.132.41\n', '172.28.132.40\n', '172.28.132.45']

# It appears that new line character “\n” is added in the list

>>> type(switches)
<type 'list'>

>>> switches[0]
'172.28.132.41\n'

>>> switches[1]
'172.28.132.40\n'

# You can strip the new line character
>>> switches[0].strip()
'172.28.132.41'

Let us fix the script to strip the new line character.

'''

Third script - Inventory - show version - Using External Input

'''

import pyeapi

# Define file path and file names

file_path = "/Users/anees/Google Drive/my-scripts/"
file_name_switches = "switches.txt"
file_switches = file_path + file_name_switches


# Read the content of the file and save it in a List

switches = []

with open(file_switches) as readfile:
    for line in readfile:
        switches.append(line.strip())

Save and run the script.

>>> ================================ RESTART ================================
>>>
>>> switches
['172.28.132.41', '172.28.132.40', '172.28.132.45']

Now let us get the username and password interactively instead of hard coding in the script.

'''

Third script - Inventory - show version - Using External Input

'''

import pyeapi

# Define file path and file names

file_path = "/Users/anees/Google Drive/my-scripts/"
file_name_switches = "switches.txt"
file_switches = file_path + file_name_switches


# Read the content of the file and save it in a List

switches = []

with open(file_switches) as readfile:
    for line in readfile:
        switches.append(line.strip())

# Input Username and Password
my_username = raw_input("Enter your username: ")
my_password = raw_input("Enter your password: ")

Save and run the script.

>>> ================================ RESTART ================================
>>>
Enter your username: admin
Enter your password: admin

Obviously we don’t want to display the password on the screen when we type. We will use the Python module “getpass” to input password without displaying on the screen.

'''

Third script - Inventory - show version - Using External Input

'''

import pyeapi
import getpass

# Define file path and file names

file_path = "/Users/anees/Google Drive/my-scripts/"
file_name_switches = "switches.txt"
file_switches = file_path + file_name_switches


# Read the content of the file and save it in a List

switches = []

with open(file_switches) as readfile:
    for line in readfile:
        switches.append(line.strip())

# Input Username and Password

my_username = raw_input("Enter your username: ")
my_password = getpass.getpass("Enter your password: ")

When you run this script from IDLE (on Apple Mac), the password prompt will not be prompted in the IDLE shell. It will be shown in the Apple Mac terminal where you have started the IDLE.

_images/ch02-pic6.png

You can also run your Python script from terminal.

anees:my-scripts anees$ pwd
/Users/anees/Google Drive/my-scripts

anees:my-scripts anees$ ls
inventory_version.py          switches.txt
inventory_version_input.py

anees:my-scripts anees$ python inventory_version_input.py
Enter your username: admin
Enter your password:
anees:my-scripts anees$

Now we have achieved our requirements of inputting switch IP addresses, username and password from outside the python script. Let us complete the script with the inventory.

'''

Third script - Inventory - show version - Using External Input

'''

import pyeapi
import getpass

# Define file path and file names

file_path = "/Users/anees/Google Drive/my-scripts/"
file_name_switches = "switches.txt"
file_switches = file_path + file_name_switches


# Read the content of the file and save it in a List

switches = []

with open(file_switches) as readfile:
    for line in readfile:
        switches.append(line.strip())

# Input Username and Password

my_username = raw_input("Enter your username: ")
my_password = getpass.getpass("Enter your password: ")

# Collect Inventory using pyeapi

for switch in switches:
    # Define API Connection String
    node = pyeapi.connect(transport="https", host=switch, username=my_username, password=my_password, port=None)

    # Execute the desired command
    version = node.execute(["show version"])

    # Print the desired Output
    print
    print ("*******************************************************")
    print ("Switch IP: %s") % (switch)
    print ("Model Name: %s") % (version["result"][0]["modelName"])
    print ("Serial Number: %s") % (version["result"][0]["serialNumber"])
    print ("EOS Version: %s") % (version["result"][0]["version"])
    print ("*******************************************************")
    print

Run the script.

================================ RESTART ================================
>>>
Enter your username: admin

*******************************************************
Switch IP: 172.28.132.41
Model Name: DCS-7050SX-128-F
Serial Number: JPE14080457
EOS Version: 4.15.3F
*******************************************************


*******************************************************
Switch IP: 172.28.132.40
Model Name: DCS-7050SX-128-F
Serial Number: JPE14080459
EOS Version: 4.15.3F
*******************************************************


*******************************************************
Switch IP: 172.28.132.45
Model Name: DCS-7280SE-64-F
Serial Number: JPE14443170
EOS Version: 4.15.3F
*******************************************************

Fourth Script – Storing Result in a Dictionary

So far we output the data within the “for loop” as and when we parse the required data using the print statement. In this script we are going to save the output in a Python dictionary instead of printing within the “for loop”. At the end of the script we will print the dictionary using pprint.

Before writing the script, we need to come up with the structure of the dictionary. Structure of the dictionary depends on what data we want to collect and report. Our goal is to collect Model Name, Serial Number and EOS version of each of the switches. Hence the proposed dictionary structure is shown below:

{
IP Address:
      {
      Model Name:
      Serial Number:
      EOS Version:
      }
}

Now, the algorithm is going to look like this

  1. Create a blank dictionary before “for loop” inventory = { }
  2. For each IP address, create an entry (Key, Value) with the IP address as the key and a blank dictionary as the value. inventory[“10.10.10.11”] = { }
  3. Add the entries for inventory[“10.10.10.11”][“Model Name:”] inventory[“10.10.10.11”][“Serial Number:”] inventory[“10.10.10.11”][“EOS Version:”]

Launch Python interpreter from your terminal.

anees:~ anees$ python
Python 2.7.10 (default, Aug 22 2015, 20:33:39)
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.

>>> inventory = { }
>>>
>>> type(inventory)
<type 'dict'>
>>>
>>> inventory["10.10.10.11"] = { }
>>>
>>> inventory
{'10.10.10.11': {}}
>>>
>>> inventory["10.10.10.11"]["Model Name:"] = "7050SX"
>>> inventory["10.10.10.11"]["Serial Number:"] = "srx123456"
>>> inventory["10.10.10.11"]["EOS Version:"] = "4.15.3f"
>>>
>>> inventory
{'10.10.10.11': {'Serial Number:': 'srx123456', 'EOS Version:': '4.15.3f', 'Model Name:': '7050SX'}}
>>>
>>> import pprint
>>>
>>> pprint.pprint(inventory)
{'10.10.10.11': {'EOS Version:': '4.15.3f',
                 'Model Name:': '7050SX',
                 'Serial Number:': 'srx123456'}}

Let us go back and update our original inventory_version script. Create a new python script with the name inventory_version_output.py and save it in your folder.

'''

Fourth script - Inventory - show version - Store Result in a Dictionary

'''

import pyeapi
import getpass
import pprint

# Define file path and file names

file_path = "/Users/anees/Google Drive/my-scripts/"
file_name_switches = "switches.txt"
file_switches = file_path + file_name_switches


# Read the content of the file and save it in a List

switches = []

with open(file_switches) as readfile:
    for line in readfile:
        switches.append(line.strip())

# Input Username and Password

my_username = raw_input("Enter your username: ")
my_password = getpass.getpass("Enter your password: ")

# Collect Inventory using pyeapi

inventory = {}

for switch in switches:
    inventory[switch] = {}

    # Define API Connection String
    node = pyeapi.connect(transport="https", host=switch, username=my_username, password=my_password, port=None)

    # Execute the desired command
    version = node.execute(["show version"])

    # Extract Desired data from show version
    model_name = version["result"][0]["modelName"]
    serial_number = version["result"][0]["serialNumber"]
    EOS_version = version["result"][0]["version"]

    # Update the inventory dictionary with the desired data
    inventory[switch]["Model Name:"] = model_name
    inventory[switch]["Serial Number:"] = serial_number
    inventory[switch]["EOS Version:"] = EOS_version

pprint.pprint(inventory)

Run this script and verify the result.

>>> ================================ RESTART ================================
>>>
Enter your username: admin
{'172.28.132.40': {'EOS Version:': u'4.15.3F',
                   'Model Name:': u'DCS-7050SX-128-F',
                   'Serial Number:': u'JPE14080459'},
 '172.28.132.41': {'EOS Version:': u'4.15.3F',
                   'Model Name:': u'DCS-7050SX-128-F',
                   'Serial Number:': u'JPE14080457'},
 '172.28.132.45': {'EOS Version:': u'4.15.3F',
                   'Model Name:': u'DCS-7280SE-64-F',
                   'Serial Number:': u'JPE14443170'}}

Fifth Script – Handling Exceptions

On the switches.txt file, add an IP address of a switch that does not exist in the network or that does not have eAPI enabled. For example, the below list has the IP address 172.28.170.143 which does not exist in the network.

  • 172.28.132.41
  • 172.28.170.143
  • 172.28.132.40
  • 172.28.132.45

Create a new script inventory_version_exception.py in your folder. Copy the script from inventory_version_output.py and run the script.

>>> ================================ RESTART ================================
>>>
Enter your username: admin
No handlers could be found for logger "pyeapi.eapilib"

Traceback (most recent call last):
  File "/Users/anees/Google Drive/my-scripts/inventory_version_exception.py", line 46, in <module>
    version = node.execute(["show version"])
  File "/Library/Python/2.7/site-packages/pyeapi/eapilib.py", line 464, in execute
    response = self.send(request)
  File "/Library/Python/2.7/site-packages/pyeapi/eapilib.py", line 394, in send
    raise ConnectionError(str(self), 'unable to connect to eAPI')
ConnectionError: unable to connect to eAPI

Because of that one incorrect IP address, the entire script fails. This will be annoying in real world where you may be managing hundreds of devices and any one device that is not available at the moment you are running the script make the entire script fail. Software scriptming languages have a process called Exception Handling which should be used to react to any errors or exceptions that impacts the normal flow of your script.

Python has try/except keywords to handle exceptions so that you can run the scripts without exiting the script and reacts to the errors the way you wanted. The below example is used to explain try/except keywords.

try:
    inventory[switch] = {}
    # Define API Connection String
    node = pyeapi.connect(transport="https", host=switch, username=my_username, password=my_password, port=None)

    # Execute the desired command
    version = node.execute(["show version"])

    # Extract Desired data from show version
    model_name = version["result"][0]["modelName"]
    serial_number = version["result"][0]["serialNumber"]
    EOS_version = version["result"][0]["version"]

    # Update the inventory dictionary with the desired data

    inventory[switch]["Model Name:"] = model_name
    inventory[switch]["Serial Number:"] = serial_number
    inventory[switch]["EOS Version:"] = EOS_version

except:
    errors[switch] = "ConnectionError: unable to connect to eAPI"

The commands under the try: section called as try clause and the commands under except: section called as except clause. If there is any exception occurs while executing try clause, except clause will be executed and then the script execution continues. If there are no exceptions in the try clause, except clause is skipped.

We will update our script inventory_version_exception.py with try/except clause. In this script, we will create a separate dictionary called “errors” in which we will store the IP addresses of the switch that fails the pyeapi call and the corresponding error messages.

'''

Fifth script - Inventory - show version - Handling Exceptions

'''

import pyeapi
import getpass
import pprint


# Define file path and file names

file_path = "/Users/anees/Google Drive/my-scripts/"
file_name_switches = "switches.txt"
file_switches = file_path + file_name_switches

# Read the content of the file and save it in a List

switches = []

with open(file_switches) as readfile:
    for line in readfile:
        switches.append(line.strip())

# Input Username and Password

my_username = raw_input("Enter your username: ")
my_password = getpass.getpass("Enter your password: ")

# Collect Inventory using pyeapi

# Collect Inventory using pyeapi

inventory = {}
errors = {}

for switch in switches:
    try:
        # Define API Connection String
        node = pyeapi.connect(transport="https", host=switch, username=my_username, password=my_password, port=None)

        # Execute the desired command
        version = node.execute(["show version"])

        # Extract Desired data from show version
        model_name = version["result"][0]["modelName"]
        serial_number = version["result"][0]["serialNumber"]
        EOS_version = version["result"][0]["version"]

        # Update the inventory dictionary with the desired data
        inventory[switch] = {}
        inventory[switch]["Model Name:"] = model_name
        inventory[switch]["Serial Number:"] = serial_number
        inventory[switch]["EOS Version:"] = EOS_version

    except:
        errors[switch] = "ConnectionError: unable to connect to eAPI"

pprint.pprint(errors)
pprint.pprint(inventory)

Save and run the script.

>>> ================================ RESTART ================================
>>>
Enter your username: admin
No handlers could be found for logger "pyeapi.eapilib"
{'172.28.170.143': 'ConnectionError: unable to connect to eAPI'}
{'172.28.132.40': {'EOS Version:': u'4.15.3F',
                   'Model Name:': u'DCS-7050SX-128-F',
                   'Serial Number:': u'JPE14080459'},
 '172.28.132.41': {'EOS Version:': u'4.15.3F',
                   'Model Name:': u'DCS-7050SX-128-F',
                   'Serial Number:': u'JPE14080457'},
 '172.28.132.45': {'EOS Version:': u'4.15.3F',
                   'Model Name:': u'DCS-7280SE-64-F',
                   'Serial Number:': u'JPE14443170'}}

Exception can happen due to variety of reasons. For example, it could be because of the switch is not reachable or the switch is reachable but the EOS command entered in the script is incorrect. In that case, we are expecting the module (Pyeapi) that is used to facilitate the connection should differentiate the errors and allow the scriptmer to handle it in the script. Pyeapi module has few types of exceptions. For more information about the exceptions supported by pyeapi module, refer the pyeapi module documentation Python Client for eAPI.

You can also explore the modules from Python interpreter.

>>> dir(pyeapi)
['__all__', '__author__', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', '__version__', 'client', 'config_for', 'connect', 'connect_to', 'eapilib', 'load_config', 'utils']

>>> dir(pyeapi.eapilib)
['CommandError', 'ConnectionError', 'DEFAULT_HTTPS_PORT', 'DEFAULT_HTTP_LOCAL_PORT', 'DEFAULT_HTTP_PATH', 'DEFAULT_HTTP_PORT', 'DEFAULT_UNIX_SOCKET', 'EapiConnection', 'EapiError', 'HTTPConnection', 'HTTPSConnection', 'HttpConnection', 'HttpEapiConnection', 'HttpLocalEapiConnection', 'HttpsConnection', 'HttpsEapiConnection', 'SocketConnection', 'SocketEapiConnection', '_LOGGER', '__builtins__', '__doc__', '__file__', '__name__', '__package__', 'base64', 'debug', 'https_connection_factory', 'json', 'logging', 'make_iterable', 'socket', 'ssl', 'sys']

We can update our script inventory_version_exception.py to differentiate the type of pyeapi exceptions.

'''

Fifth script - Inventory - show version - Handling Exceptions

'''

import pyeapi
import getpass
import pprint


# Define file path and file names

file_path = "/Users/anees/Google Drive/my-scripts/"
file_name_switches = "switches.txt"
file_switches = file_path + file_name_switches


# Read the content of the file and save it in a List

switches = []

with open(file_switches) as readfile:
    for line in readfile:
        switches.append(line.strip())

# Input Username and Password

my_username = raw_input("Enter your username: ")
my_password = getpass.getpass("Enter your password: ")

# Collect Inventory using pyeapi

inventory = {}
errors = {}

for switch in switches:
    try:
        # Define API Connection String
        node = pyeapi.connect(transport="https", host=switch, username=my_username, password=my_password, port=None)

        # Execute the desired command
        version = node.execute(["show version"])

        # Extract Desired data from show version
        model_name = version["result"][0]["modelName"]
        serial_number = version["result"][0]["serialNumber"]
        EOS_version = version["result"][0]["version"]

        # Update the inventory dictionary with the desired data
        inventory[switch] = {}
        inventory[switch]["Model Name:"] = model_name
        inventory[switch]["Serial Number:"] = serial_number
        inventory[switch]["EOS Version:"] = EOS_version

    except pyeapi.eapilib.ConnectionError:
        errors[switch] = "ConnectionError: unable to connect to eAPI"

    except pyeapi.eapilib.CommandError:
        errors[switch] = "CommandError: Check your EOS command syntax"

pprint.pprint(errors)
pprint.pprint(inventory)

Verify the error messages.

>>> ================================ RESTART ================================
>>>
Enter your username: admin
No handlers could be found for logger "pyeapi.eapilib"
{'172.28.170.143': 'ConnectionError: unable to connect to eAPI'}
{'172.28.132.40': {'EOS Version:': u'4.15.3F',
                   'Model Name:': u'DCS-7050SX-128-F',
                   'Serial Number:': u'JPE14080459'},
 '172.28.132.41': {'EOS Version:': u'4.15.3F',
                   'Model Name:': u'DCS-7050SX-128-F',
                   'Serial Number:': u'JPE14080457'},
 '172.28.132.45': {'EOS Version:': u'4.15.3F',
                   'Model Name:': u'DCS-7280SE-64-F',
                   'Serial Number:': u'JPE14443170'}}

Change the command syntax “show version” to “show ver” and run the command.

>>> ================================ RESTART ================================
>>>
Enter your username: admin
No handlers could be found for logger "pyeapi.eapilib"
{'172.28.132.40': 'CommandError: Check your EOS command syntax',
 '172.28.132.41': 'CommandError: Check your EOS command syntax',
 '172.28.132.45': 'CommandError: Check your EOS command syntax',
 '172.28.170.143': 'ConnectionError: unable to connect to eAPI'}

Summary – Script Framework

We have learned various Python concepts step by step using the inventory use case and finally we got a structure for our network use case Python script if you have observed closely all the five scripts. The structure of code is shown below:

Section 1: Import Modules

import pyeapi
import getpass
import pprint

Section 2: Read the list of switch IP addresses from a file and store it in a Python list

file_path = "/Users/anees/Google Drive/my-scripts/"
file_name_switches = "switches.txt"
file_switches = file_path + file_name_switches

switches = []

with open(file_switches) as readfile:
    for line in readfile:
        switches.append(line.strip())

Section 3: Input Username and Password that have access to the switches

my_username = raw_input("Enter your username: ")
my_password = getpass.getpass("Enter your password: ")

Section 4: Main Algorithm Specific to your use case

For every switch in the Python list

  1. Connect to the switch using Arista’s pyeapi module
  2. Execute the commands needed for your logic
  3. Core Logic
  4. Store the result into a dictionary
inventory = {}
errors = {}

for switch in switches:
    try:
        # Define API Connection String
        node = pyeapi.connect(transport="https", host=switch, username=my_username, password=my_password, port=None)

        # Execute the desired command
        version = node.execute(["show version"])

        # Extract Desired data from show version
        model_name = version["result"][0]["modelName"]
        serial_number = version["result"][0]["serialNumber"]
        EOS_version = version["result"][0]["version"]

        # Update the inventory dictionary with the desired data
        inventory[switch] = {}
        inventory[switch]["Model Name:"] = model_name
        inventory[switch]["Serial Number:"] = serial_number
        inventory[switch]["EOS Version:"] = EOS_version

    except pyeapi.eapilib.ConnectionError:
        errors[switch] = "ConnectionError: unable to connect to eAPI"

    except pyeapi.eapilib.CommandError:
        errors[switch] = "CommandError: Check your EOS command syntax"

Section 5: Print the dictionaries

pprint.pprint(errors)
pprint.pprint(inventory)

We are going to use this five sections framework for all the use cases in this document. In all the use cases we reuse the commands from sections 1, 2, 3, 4A and 5. Only sections that changes based on the requirements of use cases are 4B, 4C, and 4D.