Python Functions

Started by dlots, March 27, 2017, 11:38:08 AM

Previous topic - Next topic

dlots

I am going to put some of the simple python functions I use a lot in here incase someone else wants them, please feel free to add more.

Send in a string, and it returns a list with all the IP addresses from the string

import re
def get_ip (input):
return(re.findall(r'(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)', input))

Send in a string, and it returns a list with all the MAC addresses from the string

import re
def get_mac (input):
return(re.findall(r'(?:[0-9a-fA-F].?){12}', input))


ssh to device (See a function on down that will use telnet if SSH fails)

import netmiko
def ssh_router(ip):
try:
net_connect = netmiko.ConnectHandler(device_type='cisco_ios', ip=ip, username=username, password=password)
except:
failtext = "Couldn't SSH to " + ip
to_doc(fails.txt, failtext)

Pass in the file name and what I want written to it, this will delete the existing document of that name, to make it so it appends to the text file instead of over writting it change the 'w' to a 'a'

import os
def to_doc(file_name, varable):
f=open(file_name, 'w')
f.write(varable)
f.close()


read in a file line by line removing the line returns and adding it to a list

def remove_return(entry):
return entry.rstrip('\n')

def read_doc (file_name):
for line in open(file_name, 'r').readlines():
line = remove_return(line)
print (line)
ips.append(line)



Get a list of interfaces with configs

net_connect = netmiko.ConnectHandler(device_type='cisco_ios', ip=ip, username=your_user_name,password=your_password)
output = net_connect.send_command_expect('show run | s interface')
interfaces = output.split("interface")


Find files with specified text in the file-name

import os

name the file is added to the file_list
def pull_file_names_with_text(text):
file_list = []
files = os.listdir()
for file in files:
if text in file:
file_list.append(file)
return (file_list)


Run a windows command and assign the output to a variable, unfortunately the windows output can some-times suck, so a simple decoding will put it into a format something looking at a string will understand.

from subprocess import check_output

tracert = 'tracert '+ip
out = check_output(tracert)
out = out.decode('utf-8')

************updated 8/28/2017*********

int fa0/1 becomes ['fa','0/1']

def split_interface(interface):
num_index = interface.index(next(x for x in interface if x.isdigit()))
str_part = interface[:num_index]
num_part = interface[num_index:]
return [str_part,num_part]

Normalize interface names:  If the name you pass in is in the list[0] it returns list[1]
so "FastEthernet"," FastEthernet","Fa", or "interface FastEthernet" return "Fa"
I tried not to go with regular expressions so anyone could easily update the names

def normalize_interface_names(non_norm_int):
interfaces = [
[["Ethernet","Eth"],"Eth"],
[["FastEthernet"," FastEthernet","Fa","interface FastEthernet"],"Fa"],
[["GigabitEthernet","Gi"," GigabitEthernet","interface GigabitEthernet"],"Gi"],
[["TenGigabitEthernet","Te"],"Te"],
[["Port-channel","Po"],"Po"],
[["Serial"],"Ser"],
]
tmp = split_interface(non_norm_int)
interface_type = tmp[0]
port = tmp[1]
for int_types in interfaces:
for names in int_types:
for name in names:
if interface_type in name:
return_this = int_types[1]+port
return return_this
return "normalize_interface_names Failed"


Gives you the interface on a L2 switch that has it's default gateway on it

def get_main_uplink(ip,username,password):
net_connect = make_connection (ip,username,password)
try:
gatway = get_ip (net_connect.send_command_expect("show run | i gateway"))[0]
except:
#"This is a Layer 3 switch, i can't handel that yet"
return None
command = "ping "+ gatway
net_connect.send_command_expect(command)
command = "show ip arp "+ gatway
arp_table = net_connect.send_command_expect(command)
mac = get_mac (arp_table)
command = "show mac address-table address " + mac[0] + " | i 0"
mac_table = net_connect.send_command_expect(command)
mac_table = mac_table.split("\n")
for line in mac_table:
line = line.split(" ")
return line[-1]
      
Pull an interface config

def pull_run_int(ip,username,password,interface):
net_connect = make_connection (ip,username,password)
command = "show run int "+interface
int_config = net_connect.send_command_expect(command)
return int_config
   
   
Ciscoconfparse function, returns each parent and their children as a list of strings.


from ciscoconfparse import CiscoConfParse

def find_child_text (file, text):
#"all" will end up holding all the info we are looking for being returned
all = []
#Give the file to CiscoConfParse to look at
parse = CiscoConfParse(file)
#Here we are finding all the lines with "nterface" in them
for obj in parse.find_objects(text):
#Make a list that will contain the parent and the children
each_obj = []
#Add the parent to the list as a string
each_obj.append(obj.text)
#For all the parent's children
for each in obj.all_children:
#Add the child to the list as a string
each_obj.append(each.text)
#Add the device/config to a list of devices and configs
all.append(each_obj)
#Once all the interfaces have gone through this the
#function hands the list of all interfaces to the main program
#At this point all is a list of lists, each sub list is the interface
#And all the config for each interface
return all

Find hard coded duplex and speeds
   

def find_speed_and_duplex_hard_code(show_run_file):
speed_and_duples_issues = []
interfaces = find_child_text (show_run_file, "nterface")
for interface in interfaces:
for line in interface:
if "speed" in line:
print (line)
print (interface[0])
temp_name = normalize_interface_names(interface[0])
if temp_name not in speed_and_duples_issues:
speed_and_duples_issues.append(temp_name)
if "duplex" in line:
print (line)
print (interface[0])
temp_name = normalize_interface_names(interface[0])
if temp_name not in speed_and_duples_issues:
speed_and_duples_issues.append(temp_name)
return speed_and_duples_issues

   
Find ports with intersting descrtiptions: Feed it a file with "Show int status" and it will spit out the ports and their descriptions


def find_descriptions_and_ports(file_name):
#Define descrtiptions I don't care about
port_descs_I_dont_care_about = [
"Local LAN Access",
"User LAN Port",
"Local Corporate LA",
"Connection to Work",
]
int_status = []
int_status_tmp = read_doc (file_name)
#find connected ports
for line in int_status_tmp:
if " connect" in line:
add = True
for port_desc in port_descs_I_dont_care_about:
if port_desc in line:
add = False
if add == True:
int_status.append(line.strip("\n"))
tmp = return_port_and_desc(int_status)
return tmp


Fix your Show cdp neighbor * output file to make ciscoconfparse work with it

def fix_for_ciscoconfparse(file_name):
cdp = read_doc(file_name)
cdp_str = ""
for line in cdp:

if "---" not in line:
line = "     "+line
cdp_str = cdp_str+line
#print (cdp_str)
to_doc_w(file_name, cdp_str)

Parse the CDP out to something more easily used


def parse_cdp_out(file_name):
cdp_parse = {}
fix_for_ciscoconfparse(file_name)
cdp_doc=CiscoConfParse(file_name)
strip_these = ("[","]","'", "")
cdp_entries = cdp_doc.find_objects("-----")
all_cdp_entries = []
for cdp_entrie in cdp_entries:
next_line = False
cdp_parse = {}
for cdp_line in cdp_entrie.all_children:
if "IP a" in cdp_line.text:
ip = get_ip(cdp_line.text)[0]
cdp_parse['remote_ip'] = ip

if "Device ID: " in cdp_line.text:
id_start = str(cdp_line.text).find(":")+2
remote_id = str(cdp_line.text)[id_start:]
cdp_parse['remote_id'] = remote_id
if "Platform: " in cdp_line.text:
platform_start = str(cdp_line.text).find(":")+2
tmp = str(cdp_line.text)[platform_start:]
platform_end = tmp.find(",")
platform = tmp[:platform_end]
cdp_parse['platform'] = platform
if "Capabilities: " in cdp_line.text:
capabilities_start = str(cdp_line.text).find("Capabilities:")+14
capabilities = str(cdp_line.text)[capabilities_start:]
cdp_parse['capabilities'] = capabilities
if "Interface: " in cdp_line.text:
interface_start = str(cdp_line.text).find(":")+2
interface_end = str(cdp_line.text).find(",")
local_int = str(cdp_line.text)[interface_start:interface_end]
cdp_parse['local_int'] = local_int
if "Port ID (outgoing port): " in cdp_line.text:
interface_start = str(cdp_line.text).find("Port ID (outgoing port):")+25
remote_int = str(cdp_line.text)[interface_start:]
cdp_parse['remote_int'] = remote_int

if next_line == True:
version = str(cdp_line.text).lstrip(' ')
cdp_parse['version'] = version
next_line = False

if "Version :" in cdp_line.text:
next_line = True


all_cdp_entries.append(cdp_parse)
return all_cdp_entries

Excel work

Pull a cell's info


import openpyxl
from openpyxl.utils import get_column_letter, column_index_from_string
from common_functions import *

def pull_cell (sheet,row, cell_letter):
cell = cell_letter+str(row)
new_device = sheet[cell].value
return new_device

   
Pull lots of info from an excel sheet

def pull_devices(filename,sheet,sitename):
wb = openpyxl.load_workbook(filename)
sheet = wb.get_sheet_by_name(sheet)
last_cell = 'C'+str(sheet.max_row)
rows_i_want = []
all_devices = []
for rowOfCellObjects in sheet['C3':last_cell]:
for cellObj in rowOfCellObjects:
if cellObj.value == sitename:
#print ("Row = "+str(cellObj.row)+ " Column = "+(cellObj.column))
rows_i_want.append(cellObj.row)
for row in rows_i_want:
#Pull the IP
ip = pull_cell(sheet,row,"i")
#Current device type
old_device = pull_cell(sheet,row,"F")
#New Device Type
new_device =  pull_cell(sheet,row,"G")
#Sales Number
sale_num =  str(pull_cell(sheet,row,"BF"))
cell = "BF"+str(row)
sale_num = sheet[cell].value
#Site Name
site_name = pull_cell(sheet,row,"B")
#Addr
addr = pull_cell(sheet,row,"AO")
#City
city = pull_cell(sheet,row,"AP")
state = pull_cell(sheet,row,"AQ")
zip = pull_cell(sheet,row,"AR")
full_address = pull_cell(sheet,row,"AT")
device_swap = [ip,old_device, new_device,sale_num,site_name,addr,city,state,zip,full_address]
all_devices.append(device_swap)
return (all_devices)
   
A good make a SSH/Telnet connection function

def make_connection (ip,username,password):
try:
return netmiko.ConnectHandler(device_type='cisco_ios', ip=ip, username=username, password=password)
except:
try:
return netmiko.ConnectHandler(device_type='cisco_ios_telnet', ip=ip, username=username, password=password)
except:
issue = ip+ ", can't be ssh/telneted to"
to_doc_a("Issues.csv", varable)
return None

Feed it the running config and it will look at what the voice vlan is and return said voice vlan         

def find_voice_vlan_hard_way(file):
run = read_doc (file)
voice_vlan = "None"
for line in run:
#print (line)
if "switchport voice vlan" in line:
line = line.split(" ")
voice_vlan = line[-1]
return voice_vlan
            
         
         
Feed function running config and voice vlan and it will show you any access ports on voice vlan

def are_ports_on_voice_vlan(voice_vlan,show_run):
voice_ports = []
looking_for = "switchport access vlan "+voice_vlan
interfaces = find_child_text (show_run, "nterface")
for interface in interfaces:
add = False
for interface_line in interface:
if looking_for in interface_line:
add = True
if "switchport mode trunk" in interface_line:
add = False
if add == True:
voice_ports.append(interface[0])
return voice_ports


These 3 combined will tell you the vlans allowed though a manually pruned trunk

def get_range (input):
sub_numbers = []
ranges = (re.findall(r'[0-9]+-[0-9]+', input))
for num_range in ranges:
temp = num_range.split("-")
for num in range(int(temp[0]),int(temp[1])+1):
sub_numbers.append(num)
print (sub_numbers)
return (sub_numbers)

def get_vlans (input):
sub_numbers = get_range (input)
temp_numbers = (re.findall(r'[0-9]+', input))
for num in temp_numbers:
if num not in sub_numbers:
sub_numbers.append(num)
return (sub_numbers)

def get_vlans_from_config(input):
input = input.split("\n")
vlans_allowed = []
for line in input:
if "switchport trunk allowed" in line:
temp_vlans_allowed = get_vlans(line)
for vlan in temp_vlans_allowed:
vlans_allowed.append(vlan)
return vlans_allowed

deanwebb

Cool, good to have handy around the python house!
Take a baseball bat and trash all the routers, shout out "IT'S A NETWORK PROBLEM NOW, SUCKERS!" and then peel out of the parking lot in your Ferrari.
"The world could perish if people only worked on things that were easy to handle." -- Vladimir Savchenko
Вопросы есть? Вопросов нет! | BCEB: Belkin Certified Expert Baffler | "Plan B is Plan A with an element of panic." -- John Clarke
Accounting is architecture, remember that!
Air gaps are high-latency Internet connections.

dlots

Pass in a list of interfaces and it should pass you back the range commands.
Not greatly tested yet so be sure you test and make sure it works for you.

def get_interface_range(interfaces):
ranges = []
int_range = []
for interface in interfaces:
tmp = interface.split('net')[1]
ranges.append(tmp)
#print ranges
start_range = []
end_range = []
for each in ranges:
port = each.split('/')[1]
blade = each.split('/')[0]
next_port = int(int(port) + 1)
next_port = str(blade) +str('/') + str(next_port)
if next_port not in ranges:
#print next_port
end_range.append(each)
last_port = int(int(port) - 1)

last_port = str(blade) +str('/') + str(last_port)

if last_port not in ranges:
#start_range = each
start_range.append(each)

spot = 0
for each in start_range:
#print each + " - " + end_range[spot].split('/')[1]
#spot = spot+1
for interface in interfaces:
if each in interface:
int_type =  interface.split('net')[0]
command = "interface range " + int_type + " " + each   + " - " + end_range[spot].split('/')[1]
int_range.append(command)
spot = spot+1
return int_range



icecream-guy

#3
Quote from: dlots on March 27, 2017, 02:51:37 PM
Pass in a list of interfaces and it should pass you back the range commands.
Not greatly tested yet so be sure you test and make sure it works for you.

def get_interface_range(interfaces):
ranges = []
int_range = []
for interface in interfaces:
tmp = interface.split('net')[1]
ranges.append(tmp)
#print ranges
start_range = []
end_range = []
for each in ranges:
port = each.split('/')[1]
blade = each.split('/')[0]
next_port = int(int(port) + 1)
next_port = str(blade) +str('/') + str(next_port)
if next_port not in ranges:
#print next_port
end_range.append(each)
last_port = int(int(port) - 1)

last_port = str(blade) +str('/') + str(last_port)

if last_port not in ranges:
#start_range = each
start_range.append(each)

spot = 0
for each in start_range:
#print each + " - " + end_range[spot].split('/')[1]
#spot = spot+1
for interface in interfaces:
if each in interface:
int_type =  interface.split('net')[0]
command = "interface range " + int_type + " " + each   + " - " + end_range[spot].split('/')[1]
int_range.append(command)
spot = spot+1
return int_range



so where are these functions coming from

e.g.

interface.split()
int_range.append()
start_range.append()
each.split()
etc?

I don't see the functions being defined
are you importing a module from another source?
:professorcat:

My Moral Fibers have been cut.

dlots

Split is part of the string type
append is part of the list type
They are just in python

split takes a string and turns it into a list
each = the boy bought a dog
each = each.split(' ')
each = [the,boy,bought,a,dog]


Append adds to a list on the end
thing = [1,2,3,4,5]
thing.append('butt')
thing = [1,2,3,4,5,'butt']

icecream-guy

Quote from: dlots on March 28, 2017, 07:02:25 AM
Split is part of the string type
append is part of the list type
They are just in python

split takes a string and turns it into a list
each = the boy bought a dog
each = each.split(' ')
each = [the,boy,bought,a,dog]

Append adds to a list on the end
thing = [1,2,3,4,5]
thing.append('butt')
thing = [1,2,3,4,5,'butt']

Guess I'm not far enough along in my studies.. still in the functions chapter...
:professorcat:

My Moral Fibers have been cut.

dlots

append was covered in the course I took, but if it makes you feel any better  splits were something I had to look up on my own

packetherder

Quote from: ristau5741 on March 28, 2017, 06:25:39 AM

so where are these functions coming from

e.g.

interface.split()
int_range.append()
start_range.append()
each.split()
etc?

I don't see the functions being defined
are you importing a module from another source?

Adding to what dlots said. It might be helpful to remember when you get to picking up classes that everything in python is an object. Strings, lists, dictionaries...all the built-in types are just objects with their own methods (like .split() and .append()) that help you do cool shit.

Strings: https://docs.python.org/3/library/stdtypes.html#string-methods
Lists: https://docs.python.org/3/tutorial/datastructures.html
Dicts: https://docs.python.org/2/library/stdtypes.html#mapping-types-dict

dlots

#8
Try and make a connection over SSH, if that fails it makes a telnet connection (FEEL SHAME IF YOU END UP USING TELNET!!)

import netmiko

def make_connection (ip,username,password):
try:
return netmiko.ConnectHandler(device_type='cisco_ios', ip=ip, username=username, password=password)
except:
return netmiko.ConnectHandler(device_type='cisco_ios_telnet', ip=ip, username=username, password=password)


Transfer files over SCP from the program to a router/switch

from netmiko import ConnectHandler, SCPConn

def transfer_file(net_connect,file):
                #Enable SCP server on the device
                net_connect.config_mode()
                net_connect.send_command('ip scp server enable')
                #Do Make an SCP connection
                scp_conn = SCPConn(net_connect)
                #Source file
                s_file = file
                #Destination file
                d_file = file
                #Transfer files
                scp_conn.scp_transfer_file(s_file, d_file)
                #Remove SCP server
                net_connect.send_command('no ip scp server enable')
                net_connect.exit_config_mode()

net_connect = netmiko.ConnectHandler(device_type='cisco_ios', ip=ip, username=username, password=password)

transfer_file(net_connect,"My IOS file.txt")






Launcher to run many copies of the same program (so login to each device and pull info, but that info in a text file or something like that each device will run at the same time). 


import re
import random
import os
import socket
import sys
import netmiko
import subprocess
import time
from getpass import getpass


def get_ips (file_name):
for line in open(file_name, 'r').readlines():
line = get_ip(line)
for ip in line:
ips.append(ip)
def get_ip (input):
return(re.findall(r'(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)', input))

def run_prog(program_to_call,args):
      command =  ["python", program_to_call]+args
      proc = subprocess.Popen(command)
       



username = input("Username: ")
password = getpass()
ips = []
get_ips("IPs.txt")
pause = 0
for ip in ips:
args = [ip,username,password]
#Define the name of the program you want to run
run_prog('check login.py',args)
#If your processer gets bogged down you can set it up to delay # seconds for every # device
if pause == 5:
time.sleep(1)
pause = 0
pause = pause + 1




Note that in the actual program you will need to pull the info out like this

ips = [sys.argv[1]]
username = sys.argv[2]
password = sys.argv[3]

dlots

Ciscoconfparse function, returns each parent and their children as a list of strings.


from ciscoconfparse import CiscoConfParse

def find_child_text (file, text):
#"all" will end up holding all the info we are looking for being returned
all = []
#Give the file to CiscoConfParse to look at
parse = CiscoConfParse(file)
#Here we are finding all the lines with "nterface" in them
for obj in parse.find_objects(text):
#Make a list that will contain the parent and the children
each_obj = []
#Add the parent to the list as a string
each_obj.append(obj.text)
#For all the parent's children
for each in obj.all_children:
#Add the child to the list as a string
each_obj.append(each.text)
#Add the device/config to a list of devices and configs
all.append(each_obj)
#Once all the interfaces have gone through this the
#function hands the list of all interfaces to the main program
#At this point all is a list of lists, each sub list is the interface
#And all the config for each interface
return all

dlots

Inital post updated with for functions