I am working on this script for a repetitive task we do at work. We often do a scan for inactive ports in building switches and if they are inactive for a long time, we set them to a dummy vlan that offers no ip connectivity to anyone connecting to it and turning on the snmp traps for that port for changes in up/down status. Then if a user wants to connect to the network through a new workstation, that would probably get connected to such an “inactive port” and we would be called to “turn on” that port by switching it back from the dummy vlan to a regular one. In this case we would either run the script (http://www.mythryll.com/?p=861) I put up a few days ago to find his mac address or search for traps and logs in the switches and find the port that was connected.
The script reads a file that contains a list of the switches, one switch per line, with the following info: ip address, platform, list of interfaces, all separated by commas (CSV). You have to build that to process those switches.
Regular expressions are used to identify the vlanid and construct the list of interfaces per switch that need to be modified. We also test for the existence of the “snmp trap link-status command” (if it’s not active, the negation of the command is present: “no snmp trap link-status) and run that as well if necessary.
There are three lists in the code. Each line is first split into a list as a result of applying .split(‘,’) to the string. After that there is the interface list (interlist) that is used to store all interfaces to be examined. Then a configlist gets created to store all interfaces that need to be modified.
The commands that check the config mode and print vlanid and other info are for control and can be ommited if you prefer.
I have to admit that the script takes a lot of time. I am guessing it’s the time needed to run each switch command, either for pattern recognition for the switch prompt or to allow the time to pass if we are sending timed commands with send_command_timing for 2950s. I guess there must be a more efficient way but I don’t know what it is yet. I definitely know it would run faster in pearl or tcl (did similar things before with those, see post
http://www.mythryll.com/?p=861 .
So here it is, the dummy vlan id is supposed to be 599 :
from netmiko import ConnectHandler, ssh_exception
from paramiko.ssh_exception import SSHException
from getpass import getpass
from datetime import datetime
import os
import subprocess
import re
import sys
user = input('username:')
passwd = getpass()#count the time
print('Starting:', datetime.now().time())
totalcounter = 0
#open the switch list file
with open("switchlist.txt") as switchfile:
#each line represents one switch with ipaddress,platform,int1,int2,int3,.. format
for nextline in switchfile:
#turn the line into a list for the current switch, split at commas
linestring = nextline.strip().split(',')
switchlength = len(linestring)
#show how many interfaces were entered for the switch to be changed
interlist = []
index = 1
#we store first item as switchaddress, second as platform to choose commands, and third and so forth as interfaces
for switchitem in linestring:
print (switchitem)
if index == 1 :
switchaddress = switchitem.strip()
index +=1
elif index == 2:
switchplatform = switchitem.strip()
index +=1
print(switchlength-2)
else:
switchinterface = switchitem.strip()
interlist.append(switchitem)
#2950s don't support ssh
if "2950" not in switchplatform:
contype = "cisco_ios_ssh"
else:
contype = "cisco_ios_telnet"
#define connection
swcon = {
'device_type': contype,
'ip': switchaddress,
'username': user,
'password': passwd,
}
#if connections fails we want to exit the script with the correct message
try:
net_connect = ConnectHandler(**swcon)
except SSHException:
print ("can't connect to last device")
sys.exit(1)
except ssh_exception.NetMikoTimeoutException:
print(" SSH Timed out")
sys.exit(1)
except ssh_exception.NetMikoAuthenticationException:
print("Invalid Credentials: ", switchaddress)
sys.exit(1)
#the configlist will contain only those interfaces that need to change access vlan
configlist = []
for interface in interlist:
#define pattern to look for vlanid
vlanpt = re.compile(r"switchport access vlan\s+(?P<vlanid>\d+)")
snmppt = re.compile(r"no snmp trap link-status")
commandstring = "show run int " + interface + " | in vlan"
commandstring2 = "show run int " + interface
#check platform to send command
if switchplatform == "2950":
output = net_connect.send_command_timing(commandstring)
output2 = net_connect.send_command_timing(commandstring2)
else:
output = net_connect.send_command(commandstring)
output2 = net_connect.send_command(commandstring2)
#perform search for vlanid and get back match objects
vlansearch = vlanpt.search(output)
snmpsearch = snmppt.search(output2)
#if there are no matches we have to inform user that vlanid was not captured
#that would imply an incorrect filter for the platform or a connection issue
#if there are matches we go ahead and append those interfaces to the list
if vlansearch != None:
vlanid = vlansearch.group('vlanid')
if (vlanid != "599") or (snmpsearch != None):
configlist.append(interface)
print(vlanid)
else:
print("vlan id not recognized for interface ",interface,"at",switchaddress)
#proceed in config mode only if there are any interfaces to change access vlan
if len(configlist) > 0:
output = net_connect.config_mode()
confcheck = net_connect.check_config_mode()
print("config mode :",confcheck)
for interface in configlist:
commandstring = "interface " + interface
output = net_connect.send_command_timing(commandstring)
output = net_connect.send_command_timing("switchport access vlan 599")
print(output)
output = net_connect.send_command_timing("snmp trap link-status")
print(output)
net_connect.exit_config_mode()
confcheck = net_connect.check_config_mode()
print("config mode :",confcheck)
print("no of interfaces changed:", len(configlist))
#save configuration
output = net_connect.save_config()
print(output)
totalcounter = totalcounter + int(len(configlist))
#get out
net_connect.disconnect()
print("done with", switchaddress)
#show time and number of changes when finished
print('Finished:', datetime.now().time())
print("interfaces changed:", totalcounter)
print("\nEnd")
Take a look, modify it if you need to and try it out. Always test before deploying.
JT