Categories
Cisco DevOps

Network Automation | Managing Multiple Network Devices using Python, Pexpect & CSV

This script was written to manage multiple switches which require you to enter the user credentials twice during an SSH session. I tried using Paramiko which authenticated fine for the first part, but would then always send the enable password instead of the second username.

Solarwinds NCM was also an option but again I could not find a way for NCM to pass the credentials twice.

In order for this specific script to function, you must first create a CSV file with the fields ‘hostname, ip, password’:

hostname,ip,password
SWITCH-1,10.1.1.1,password01
SWITCH-2,10.1.1.2,password02
SWITCH-3,10.1.1.3,password03

And create a text file which stores the commands to be sent. You do not need to write ‘conf t’ or ‘wr’ in the config file as these are part of the script.

#!/usr/bin/env

'''

Python Script which connects to devices defined in a CSV file and runs
configuration commands from a .TXT file

Usage: python script.py <csvfile.csv> <commands.txt>
e.g:   python script.py test-switches.csv ntp-enable.txt

Log file (./log.txt) shows all data received during SSH session

Written by Tom Whitfield - 2019

'''

import pexpect
import sys
import datetime
import pandas as pd


today = datetime.datetime.now()
log = open('multiconf.txt', 'a+')
csvfile = sys.argv[1]
configfile = sys.argv[2]

hn = pd.read_csv((csvfile), sep=',', usecols=['hostname'], squeeze=True)
ip = pd.read_csv((csvfile), sep=',', usecols=['ip'], squeeze=True)
pw = pd.read_csv((csvfile), sep=',', usecols=['password'], squeeze=True)

index = 0

def yes_or_no(question):
    answer = raw_input(question + "(y/n): ").lower().strip()
    print("")
    while not(answer == "y" or answer == "yes" or \
    answer == "n" or answer == "no"):
        print("Input yes or no")
        answer = raw_input(question + "(y/n):").lower().strip()
        print("")
    if answer[0] == "y":
        return True
    else:
        return False


print('\nWARNING: You are about to send the following configuration:\n')

cfg = open(configfile)
for line in cfg:
    print(line.rstrip())

print('\n\nTo the following devices:\n')
for line in hn:
    print(line.rstrip())

if yes_or_no('\nDo you want to continue?'):
    ()
else:
    quit()

for i in ip:
    print('------------- connecting --------------\n')
    print('connecting to ' + (hn[index]) + '...')

    try:
        log.write('\n\n!----------------------------------------------------------------\n')
        log.write('!    Connection to ' + (hn[index]) + '\n')
        log.write('!    Executed on ' + today.strftime('%d %B %Y at %H:%M') + '\n')
        log.write('!----------------------------------------------------------------\n\n')
        child = pexpect.spawn('ssh -o StrictHostKeyChecking=no [email protected]' + (ip[index]))
        child.logfile_read = log

        child.expect('password:', timeout=10)
        child.sendline(pw[index])
        print('  - auth success (stage 1)')

        e = child.expect (['Username: ', '>'])
        if e == 0:
            child.sendline ('root')
            child.expect ('Password:', timeout=10)
            child.sendline (pw[index])
            print('  - auth success (stage 2)')
        else:
            print('  - stage 2 auth not required')

        child.sendline ('enable')
        child.expect ('Password:', timeout=10)
        child.sendline (pw[index])
        child.expect ('#', timeout=10)
        print('  - entered priviledged mode')

    except pexpect.TIMEOUT:
        print('\nERROR: The connection to ' + (hn[index])  +  ' timed out\n')
        log.write('\nERROR: The connection to ' + (hn[index])  +  ' timed out\n')
        index = index + 1
        continue

    except pexpect.EOF:
        print('\nERROR: EOF\n')
        log.write('\nERROR: EOF\n')
        index = index + 1
        continue

    except Exception as exception:
        print('\nERROR: Script failed (Other)\n')
        print(exception)
        log.write('\nERROR: Script failed (Other)\n')
        index = index + 1
        continue

    try:
        child.sendline ('conf t')
        child.expect ('config', timeout=10)

        cfg = open((configfile), 'r')
        for c in cfg:
            child.sendline(c)

        child.sendline ('exit')
        child.sendline ('wr')
        child.expect ('[OK]', timeout=10)
        child.sendline ('logout')
        child.close()

    except:
        print('\nERROR: Failed to amend configuration on ' + (hn[index])+ '\n' )
        print(child.before)
        index = index + 1
        continue


    print('\nSUCCESS: ' + (hn[index]) + ' configured\n')
    index = index + 1

print('\n------------ end of script ------------\n')
print('updated logfile at ./log.txt\n')

exit()

Leave a Reply

Your email address will not be published. Required fields are marked *