def __init__(self, cmdargs, config): # initialize values self.log_array = [] self.cmdargs = cmdargs self.config = config self.subs = SubRoutines(cmdargs, config) self.checklog = ""
def __init__(self, cmdargs, config): # initialize values self.log_array = [] self.cmdargs = cmdargs self.config = config self.subs = SubRoutines(cmdargs, config) self.config.logpath = os.path.join( os.path.expanduser(self.config.logpath), "logs", "UpgradeCheck", datetime.date.today().strftime('%Y%m%d'))
def __init__(self, cmdargs, config): # initialize values self.log_array = [] self.cmdargs = cmdargs self.config = config self.subs = SubRoutines(cmdargs, config) self.log_path = os.path.abspath( os.path.join(os.sep, 'var', 'log', 'dnmt')) urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning ) #Supress the ssl unverified notification
def __init__(self, cmdargs, config): # initialize values self.log_array = [] self.cmdargs = cmdargs self.config = config self.subs = SubRoutines(cmdargs, config) # self.log_path = os.path.abspath(os.path.join(os.sep, 'var', 'log', 'dnmt')) # self.subs.log_path = os.path.abspath(os.path.join(os.sep, 'var', 'log', 'dnmt')) self.successful_switches = [] #used for activity tracking self.failure_switches = [] #used for activity tracking self.successful_files = [] #used for activity tracking self.failure_files = [] # used for activity tracking
def __init__(self, cmdargs, config): # initialize values self.log_array = [] self.cmdargs = cmdargs self.config = config self.subs = SubRoutines(cmdargs, config) # self.log_path = os.path.abspath(os.path.join(os.sep, 'var', 'log', 'dnmt')) # self.subs.log_path = os.path.abspath(os.path.join(os.sep, 'var', 'log', 'dnmt')) self.successful_switches = [] #used for activity tracking self.failure_switches = [] #used for activity tracking self.mappedEdges = [] self.visitedNeighbours = [] self.pendingNeighbours = [] self.coreFacingNodes = [] self.coreNodes = [] self.graphObject = Graph(format='png')
class StatusChecks: def __init__(self, cmdargs, config): # initialize values self.log_array = [] self.cmdargs = cmdargs self.config = config self.subs = SubRoutines(cmdargs, config) # self.log_path = os.path.abspath(os.path.join(os.sep, 'var', 'log', 'dnmt')) # self.subs.log_path = os.path.abspath(os.path.join(os.sep, 'var', 'log', 'dnmt')) self.successful_switches = [] #used for activity tracking self.failure_switches = [] #used for activity tracking self.successful_files = [] #used for activity tracking self.failure_files = [] # used for activity tracking def Maintenance(self, maxfiles): # self.subs.verbose_printer("##### Cleaning up files #####") #Remove oldest files (listed first on windows filelist = os.listdir( os.path.join(self.subs.log_path, "activitycheck", "processedfiles")) if len(filelist) > 0 and len(filelist) > maxfiles: # self.subs.verbose_printer("##### unsorted list:{} #####".format(filelist)) sortedfilelist = sorted(filelist) # self.subs.verbose_printer("##### sorted list:{} #####".format(testlist)) filestoremove = sortedfilelist[0:(len(filelist) - maxfiles)] self.subs.verbose_printer( "total files:{}\nremoving files:{}".format( len(filelist), len(filestoremove))) for file in filestoremove: if file.endswith("-FullStatus.csv.zip"): # process try: self.subs.verbose_printer( "##### File to remove:{} #####".format(file)) if 'test' in self.cmdargs and self.cmdargs.test is False: self.subs.verbose_printer( "##### Removing file:{} #####".format(file)) os.remove( os.path.join(self.subs.log_path, "activitycheck", "processedfiles", file)) except Exception as err: # currently a catch all to stop linux from having a conniption when reloading print("FILE ERROR {}:{}".format(file, err.args[0])) self.failure_files.append(file) else: self.subs.verbose_printer( "total files:{} are less than max value:{}".format( len(filelist), maxfiles)) def activity_tracking_begin(self): iplist = [] total_start = time.time() if not os.path.exists( os.path.join(self.subs.log_path, "activitycheck", "rawfiles")): self.subs.custom_printer( "debug", "## DBG - Creating activitycheck/rawfiles directory ##") os.makedirs( os.path.join(self.subs.log_path, "activitycheck", "rawfiles")) if not os.path.exists( os.path.join(self.subs.log_path, "activitycheck", "processedfiles")): self.subs.custom_printer( "debug", "## DBG - Creating activitycheck/processedfiles directory ##") os.makedirs( os.path.join(self.subs.log_path, "activitycheck", "processedfiles")) # Specifying a file only changes what IPs are updated, right now the status check grabs all existing files in # the raw data folder try: if 'file' in self.cmdargs and self.cmdargs.file is not None: file = open(os.path.join(self.cmdargs.file), "r") else: file = open( os.path.abspath( os.path.join(os.sep, 'usr', 'lib', 'capt', "activitycheckIPlist")), "r") self.subs.verbose_printer( "##### file opened:{} #####".format(file)) for ip in file: if len(ip.rstrip()) > 0: iplist.append(ip.rstrip()) else: self.subs.custom_printer( "debug", "## DBG - Creating activitycheck/processedfiles directory ##" ) file.close() # pool = Pool(len(iplist)) # 4 concurrent processes # results = pool.map(self.single_search, iplist) #TODO CHANGE to do them with individual processes if 'check' in self.cmdargs and self.cmdargs.check is False: # pool = Pool(len(iplist)) # 4 concurrent processes if 'parallel' in self.cmdargs and self.cmdargs.parallel is True: if 'numprocs' in self.cmdargs and self.cmdargs.numprocs is False: numprocs = 5 else: if self.cmdargs.numprocs == "all": numprocs = len(iplist) else: try: numprocs = int(self.cmdargs.numprocs) except ValueError: self.subs.verbose_printer( "numprocs is not a number, defaulting to 5!" ) numprocs = 5 except Exception: numprocs = 5 #catch all if things go sideways pool = Pool(numprocs) results = pool.map(self.Activity_Tracking, iplist) for result in results: if result[0]: self.successful_switches.append(result[1]) else: self.failure_switches.append(result[1]) else: for ip in iplist: try: result = self.Activity_Tracking(ip) if result[0]: self.successful_switches.append(result[1]) else: self.failure_switches.append(result[1]) except Exception as err: print("ERROR PROCESSING FILE {}:{}".format( ip, err)) self.subs.verbose_printer( "##### Total Processing Complete, Total Time:{} seconds #####". format(int((time.time() - total_start) * 100) / 100)) except FileNotFoundError: print("##### ERROR iplist files not found #####") except Exception as err: print("##### ERROR with processing:{} #####".format(err)) # After all processes return, read in each pickle and create a single output file? status_filename = "{}-FullStatus.csv".format( datetime.datetime.now().strftime('%Y-%m-%d-%H%M')) try: # self.Create_Readable_Activity_File(status_filename,iplist) self.successful_files, self.failure_files = self.subs.create_readable_activity_file( status_filename, **vars(self.cmdargs)) except Exception as err: print("##### ERROR creating Summary File: {} #####".format(err)) #Compress # with open(os.path.join(self.log_path, "activitycheck", "processedfiles", status_filename), 'rb') as f_in: # with gzip.open(os.path.join(self.log_path, "activitycheck", "processedfiles", "{}.gz".format(status_filename)), 'wb') as f_out: # shutil.copyfileobj(f_in, f_out) #EMail finished file: try: ################## if 'email' in self.cmdargs and self.cmdargs.email is not None: msg_subject = "updated activitycheck - {}".format( datetime.date.today().strftime('%Y-%m-%d')) body = "Processing completed in {} seconds\n".format( int((time.time() - total_start) * 100) / 100) body += "{} switch state files SUCCESSFULLY updated\n".format( len(self.successful_switches)) body += "{} switch state files FAILED to update\n".format( len(self.failure_switches)) body += "{} switch states SUCCESSFULLY added to the summary file\n".format( len(self.successful_files)) body += "{} switch states FAILED to add to the summary file\n".format( len(self.failure_files)) body += "\n--------------------------------------------------------------------------------------\n\n" if len(self.successful_switches) > 0: body += "--- List of switch statuses SUCCESSFULLY updated ---\n" for entry in self.successful_switches: body += "{}\n".format(entry) if len(self.failure_switches) > 0: body += "--- List of switch statuses that FAILED to update ---\n" for entry in self.failure_switches: body += "{}\n".format(entry) if len(self.successful_files) > 0: body += "--- List of files SUCCESSFULLY added to summary file ---\n" for entry in self.successful_files: body += "{}\n".format(entry) if len(self.failure_files) > 0: body += "--- List of files FAILED to be added to summary file ---\n" for entry in self.failure_files: body += "{}\n".format(entry) # self.subs.email_zip_file(msg_subject,self.cmdargs.email,body,status_filename) self.subs.email_zip_file(msg_subject, self.cmdargs.email, body, status_filename) ####################### except Exception as err: print(err) # def Create_Readable_Activity_File(self,status_filename,iplist): # # TotalStatus = StackStruct.getHeader(self.cmdargs) # # if 'xecutive' in self.cmdargs and self.cmdargs.xecutive is True: # # TotalStatus = "IP,Vendor,Hostname,SwitchNum,Model,Serial,SoftwareVer,ModuleNum,PortNum,PortName,PortDesc,PoE draw (1=Yes),Status (1=Up),DataVlan,DataVlan name,VoiceVlan,Mode (1=Trunk),PsViolations,InputErrors,OutputErrors,InputCounters,OutputCounters,LastTimeUpdated,DeltaInputCounters,DeltaOutputCounters\n" # # else: # # TotalStatus = "IP,Vendor,Hostname,SwitchNum,Model,Serial,SoftwareVer,ModuleNum,PortNum,PortName,PortDesc,PoE,Neighbour name,Neighbour port,Neighbour type,Status (1=Up),DataVlan,DataVlan name,VoiceVlan,Mode (1=Trunk),IntID,PsViolations,InputErrors,OutputErrors,InputCounters,OutputCounters,LastTimeUpdated,DeltaInputCounters,DeltaOutputCounters,HistoricalInputErrors,HistoricalOutputErrors,HistoricalInputCounters,HistoricalOutputCounters\n" # #By default grabs all existing statcheck files, this could be changed to only act on the iplist provided # # # if 'limit' in self.cmdargs and self.cmdargs.limit is True: # self.subs.verbose_printer("##### Creating Limited Summary List #####") # fileList = [f+"-statcheck.bz2" for f in iplist] # else: # self.subs.verbose_printer("##### Creating Full Summary List #####") # fileList = [f for f in os.listdir(os.path.join(self.subs.log_path,"activitycheck", "rawfiles","active")) if f.endswith('-statcheck.bz2')] # for ip in fileList: # # process # try: # # LOADING Compressed files # self.subs.custom_printer("debug", "## DBG - Opening pickled file from active for {} ##".format(ip)) # with bz2.open(os.path.join(self.subs.log_path, "activitycheck", "rawfiles", "active", ip), "rb") as f: # self.subs.custom_printer("debug", "## DBG - loading pickled file from active for {} ##".format(ip)) # SwitchStatus = pickle.load(f, encoding='utf-8') # TotalStatus += SwitchStatus.appendSingleLineCustom( # executive_mode=('xecutive' in self.cmdargs and self.cmdargs.xecutive is True)) # # if 'xecutive' in self.cmdargs and self.cmdargs.xecutive is True: # # TotalStatus += SwitchStatus.appendSingleLineExec() # # else: # # TotalStatus += SwitchStatus.appendSingleLine() # self.subs.custom_printer("debug", "## DBG - Appending {} to successful files ##".format(ip)) # self.successful_files.append("{}-statcheck.bz2".format(ip)) # except Exception as err: # currently a catch all to stop linux from having a conniption when reloading # print("FILE ERROR {}-statcheck:{}".format(ip, err.args[0])) # self.subs.custom_printer("debug", "## DBG - Error in create readable activity file ##") # self.failure_files.append("{}-statcheck.bz2".format(ip)) # # ## Works, but emailing is a pain # # with bz2.BZ2File(os.path.join(self.log_path, "activitycheck", "processedfiles", "{}.bz2".format(status_filename)), # # 'wb') as sfile: # # sfile.write(TotalStatus.encode("utf-8")) # # zf = zipfile.ZipFile(os.path.join(self.subs.log_path, "activitycheck", "processedfiles", "{}.zip".format(status_filename)), # mode='w', # compression=zipfile.ZIP_DEFLATED, # ) # try: # zf.writestr(status_filename, TotalStatus) # finally: # zf.close() #Activity_Tracking_Comparison(porttwo.inputerrors,portone.historicalinputerrors,portone.maxhistoricalentries) def Activity_Tracking_Comparison(self, newval, historicalvals, maxvals): if newval is not None: # ensure there are new entries if len(historicalvals ) != 0: # make sure there are existing historical entries if newval != historicalvals[len(historicalvals) - 1][1]: # dont add duplicates if len(historicalvals) >= maxvals: historicalvals = historicalvals[ (len(historicalvals) - maxvals) + 1:] #currently cuts one off historicalvals.append( (int(datetime.datetime.now().strftime("%Y%m%d%H%M")), newval)) else: historicalvals.append( (int(datetime.datetime.now().strftime("%Y%m%d%H%M")), newval)) return historicalvals def Port_Update_Historical_Counters(self, portone, porttwo): if 'maxentries' in self.cmdargs and self.cmdargs.maxentries is not None: if self.cmdargs.maxentries.isdigit(): portone.maxhistoricalentries = int(self.cmdargs.maxentries) else: self.subs.verbose_printer("max entries cmdarg is not a number") portone.historicalinputerrors = self.Activity_Tracking_Comparison( portone.inputerrors, porttwo.historicalinputerrors, portone.maxhistoricalentries) portone.historicaloutputerrors = self.Activity_Tracking_Comparison( portone.outputerrors, porttwo.historicaloutputerrors, portone.maxhistoricalentries) portone.historicalinputcounters = self.Activity_Tracking_Comparison( portone.inputcounters, porttwo.historicalinputcounters, portone.maxhistoricalentries) portone.historicaloutputcounters = self.Activity_Tracking_Comparison( portone.outputcounters, porttwo.historicaloutputcounters, portone.maxhistoricalentries) def Port_Updating_Active(self, portone, porttwo): portone.deltalastin = portone.inputcounters - porttwo.inputcounters portone.deltalastout = portone.outputcounters - porttwo.outputcounters portone.lastupdate = datetime.date.today().strftime('%Y-%m-%d') self.Port_Update_Historical_Counters(portone, porttwo) def Port_Updating_Archive(self, portone, porttwo): portone.deltalastin = porttwo.deltalastin portone.deltalastout = porttwo.deltalastout portone.cdpname = porttwo.cdpname portone.cdpport = porttwo.cdpport portone.cdptype = porttwo.cdptype portone.poe = porttwo.poe portone.description = porttwo.description portone.datavlan = porttwo.datavlan portone.datavlanname = porttwo.datavlanname portone.voicevlan = porttwo.voicevlan portone.status = porttwo.status portone.portmode = porttwo.portmode portone.inputerrors = porttwo.inputerrors portone.outputerrors = porttwo.outputerrors portone.inputcounters = porttwo.inputcounters portone.outputcounters = porttwo.outputcounters portone.lastupdate = porttwo.lastupdate portone.historicalinputerrors = porttwo.historicalinputerrors portone.historicaloutputerrors = porttwo.historicaloutputerrors portone.historicalinputcounters = porttwo.historicalinputcounters portone.historicaloutputcounters = porttwo.historicaloutputcounters def Activity_Tracking(self, ipaddr): # this function will: # -grab the current status, # -load a pickled switch status if there is one, create one if there is not # -Pickled switch status will also include: # -For Ports - (Time last changed} last change in state (append date for first entry, append if changed) # -For Ports - (Delta In from last change) if changed from last check # -For Ports - (Delta Out from last change) if changed from last check # # TODO # -Determine where these log files should go #Wrapping everything in a try catch for multiprocessing purposes try: start = time.time() self.subs.verbose_printer( "##### {} - Processing #####".format(ipaddr)) self.subs.custom_printer( "debug", "## DBG - Grabbing switch data through SNMP ##") # self.subs.config.ro = self.config.ro #reset to default to ensure previous ones did not bork things custom_ro_check = ipaddr.split(',') ro_string = self.subs.config.ro if len(custom_ro_check) > 1: ro_string = custom_ro_check[1] ipaddr = custom_ro_check[0] NewSwitchStatus = self.subs.snmp_get_switch_data_full(ipaddr, ro=ro_string) #TODO Check if a previous static check exists, and load it if it does, otherwise create it and write it out try: if len(NewSwitchStatus.switches) == 0: raise ValueError( '##### {} ERROR - No Data in switchstruct #####'. format(ipaddr)) #load archival information (may have removed switches in it) self.subs.custom_printer( "debug", "## DBG - Opening statcheck file from legacy ##") with bz2.open( os.path.join(self.subs.log_path, "activitycheck", "rawfiles", "legacy", "{}-statcheck.bz2".format(ipaddr)), "rb") as myNewFile: self.subs.custom_printer( "debug", "## DBG - Loading legacy into OldSwitchStatus ##") OldSwitchStatus = pickle.load(myNewFile) # if len(OldSwitchStatus.switches) != len(NewSwitchStatus.switches): #TODO Check if the existing file is empty or if there is a different number of switches. If empty,save NewSwitcStatus instead #If different number, check which switch is which based on serial numbers to try to save historical data? #Then write out OldSwitchStatus to a archive file/folder and write the new one out #TODO Why not use the newswitch status instead? Data may be lost if a switch is down when the new one is there? could fix that by adding any missing data to the new one? #update the new switch status with archival info self.subs.custom_printer( "debug", "## DBG - Updating switch status with OldSwitchStatus ##") for tempswitch in NewSwitchStatus.switches: #if the switchnumber doesn't exist in the archive status file, add it if OldSwitchStatus.getSwitch( tempswitch.switchnumber) is None: OldSwitchStatus.addExistingSwitch( tempswitch) #will be a link, but should be fine # OldSwitchStatus.addExistingSwitch(copy.deepcopy(tempswitch)) # OldSwitchStatus.addExistingSwitch(tempswitch.__dict__.copy()) else: for tempmodule in tempswitch.modules: for newport in tempmodule.ports: oldport = OldSwitchStatus.getPortByPortName( newport.portname) if oldport is not None: #check if the port exists in archival data if newport.activityChanged( oldport ): #if the port info has changed... self.Port_Updating_Active( newport, oldport) #update the new port self.Port_Updating_Archive( oldport, newport ) # update any old ports that exist else: #otherwise, grab the historical data to paste in here newport.lastupdate = oldport.lastupdate newport.deltalastin = oldport.deltalastin newport.deltalastout = oldport.deltalastout newport.historicalinputerrors = oldport.historicalinputerrors newport.historicaloutputerrors = oldport.historicaloutputerrors newport.historicalinputcounters = oldport.historicalinputcounters newport.historicaloutputcounters = oldport.historicaloutputcounters else: #if it is a new port entry newport.lastupdate = datetime.date.today( ).strftime('%Y-%m-%d') newport.deltalastin = 0 newport.deltalastout = 0 #update the old status file for archive. This should prevent losing data if there is an outage during collection # for tempswitch in OldSwitchStatus.switches: #remove this stuff, and just update the old with new values after assigning to the new # for tempmodule in tempswitch.modules: # for oldport in tempmodule.ports: # newport = NewSwitchStatus.getPortByPortName(oldport.portname) #Changed 20200601 from id Cisco changing IDs.... # if newport is not None: #if the port exists in the new status check to see if it has changed # if oldport.activityChanged(newport): #if the port has changed, update it, otherwise leave it # self.Port_Updating_Archive(oldport, newport) #update any old ports that exist for the archive #TODO Compare the two files now #write out active status for combining into statcheck csv self.subs.custom_printer( "debug", "## DBG - Opening Active file to save NewSwitchStatus to ##" ) with bz2.BZ2File( os.path.join(self.subs.log_path, "activitycheck", "rawfiles", "active", "{}-statcheck.bz2".format(ipaddr)), 'wb') as sfile: self.subs.custom_printer( "debug", "## DBG - Writing NewSwitchStatus to active statcheck ##" ) pickle.dump(NewSwitchStatus, sfile) sfile.close() #Write out archival switchstatus to load again later self.subs.custom_printer( "debug", "## DBG - Opening legacy file to save OldSwitchStatus to ##" ) with bz2.BZ2File( os.path.join(self.subs.log_path, "activitycheck", "rawfiles", "legacy", "{}-statcheck.bz2".format(ipaddr)), 'wb') as sfile: self.subs.custom_printer( "debug", "## DBG - Writing OldSwitchStatus to legacy statcheck ##" ) pickle.dump(OldSwitchStatus, sfile) sfile.close() # self.successful_switches.append(ipaddr) returnval = (True, ipaddr) except FileNotFoundError: print( "##### {} - No previous status file found, one will be created #####" .format(ipaddr)) OldSwitchStatus = NewSwitchStatus for tempswitch in OldSwitchStatus.switches: for tempmodule in tempswitch.modules: for tempport in tempmodule.ports: tempport.lastupdate = datetime.date.today( ).strftime('%Y-%m-%d') tempport.deltalastin = 0 tempport.deltalastout = 0 # self.successful_switches.append(ipaddr) returnval = (True, ipaddr) with bz2.BZ2File( os.path.join(self.subs.log_path, "activitycheck", "rawfiles", "active", "{}-statcheck.bz2".format(ipaddr)), 'wb') as sfile: pickle.dump(OldSwitchStatus, sfile) sfile.close() with bz2.BZ2File( os.path.join(self.subs.log_path, "activitycheck", "rawfiles", "legacy", "{}-statcheck.bz2".format(ipaddr)), 'wb') as sfile: pickle.dump(OldSwitchStatus, sfile) sfile.close() except ValueError as err: print(err) # self.failure_switches.append(ipaddr) returnval = (False, ipaddr) except Exception as err: #currently a catch all to stop linux from having a conniption when reloading print("##### {} FILE ERROR:{} #####".format( ipaddr, err.args[0])) self.subs.custom_printer( "debug", "## DBG - Error in Activity_Tracking ##") # self.failure_switches.append(ipaddr) returnval = (False, ipaddr) end = time.time() self.subs.verbose_printer( "##### {} - Processing Complete, time:{} seconds #####". format(ipaddr, int((end - start) * 100) / 100)) return returnval except Exception as err: #catch all exception print("##### {} UNKNOWN ERROR:{} #####".format( ipaddr, err.args[0])) # self.failure_switches.append(ipaddr) end = time.time() self.subs.verbose_printer( "##### {} - Processing aborted/failure, time:{} seconds #####" .format(ipaddr, int((end - start) * 100) / 100)) return (False, ipaddr) def switch_check(self): if 'ro' in self.cmdargs and self.cmdargs.ro is not None: #TODO abstract out to dnmt.py to have custom implementation generic? self.subs.config.ro = self.cmdargs.ro #3560X with ten gig uplink doesn't show gi 1/1-2 only ten 1/1-2. if 'load' in self.cmdargs and self.cmdargs.load is not None: try: # LOADING Compressed files with bz2.open(self.cmdargs.load, "rb") as f: test = pickle.load(f, encoding='utf-8') except FileNotFoundError: print("##### {} - No file found #####".format( self.cmdargs.load)) except Exception as err: # currently a catch all to stop linux from having a conniption when reloading print("FILE ERROR {}".format(err.args[0])) elif 'ipaddr' in self.cmdargs and self.cmdargs.ipaddr is not None: start = time.time() test = self.subs.snmp_get_switch_data_full(self.cmdargs.ipaddr) end = time.time() print("time:{} seconds".format(int((end - start) * 100) / 100)) else: print( "Invalid Syntax, need to specify an IP with -i or a file to check with -l" ) sys.exit(1) # test.printStack() # test.printSingleLine() if 'csv' in self.cmdargs and self.cmdargs.csv is not None: test.exportCSV(self.cmdargs.csv) try: ################## if 'email' in self.cmdargs and self.cmdargs.email is not None: msg_subject = "Switch Status - {}".format( datetime.date.today().strftime('%Y-%m-%d')) body = "Processing complete" self.subs.email_with_attachment(msg_subject, self.cmdargs.email, body, self.cmdargs.csv) ####################### except Exception as err: print(err) else: test.printStack()
class Tools: def __init__(self, cmdargs, config): # initialize values self.log_array = [] self.cmdargs = cmdargs self.config = config self.subs = SubRoutines(cmdargs, config) #self.config.logpath = os.path.join(os.path.expanduser(self.config.logpath), "logs", "UpgradeCheck", # datetime.date.today().strftime('%Y%m%d')) def TDR_Test(self,net_connect,interface): net_connect.enable() print("performing diagnostic on {}".format(interface)) result = net_connect.send_command('test cable-diagno tdr interface {}'.format(interface)) print("waiting for 15 seconds") time.sleep(15) test_result = net_connect.send_command('show cable-diagnostics tdr int {}'.format(interface)) print("Results are:\n{}".format(test_result)) #net_connect.disable() #incorrect syntax return def ap_poke(self): #cmdargs.interface #cmdargs.ipaddr #format interface string: self.cmdargs.interface = re.sub('[a-zA-Z]', '', self.cmdargs.interface) if self.subs.ping_check(self.cmdargs.ipaddr): self.subs.verbose_printer(print( "{} Reachable, Now performing AP Poke Operation on {}".format(self.cmdargs.ipaddr, self.cmdargs.interface))) if self.cmdargs.login: self.config.username = input("Input user name to login to switch:") self.config.password = getpass.getpass("Input password to login to switch:") self.config.enable_pw = getpass.getpass("Input enable password for switch:") try: net_connect = self.subs.create_connection(self.cmdargs.ipaddr) if net_connect: swcheck_dict = {"ip": self.cmdargs.ipaddr, "interface": self.cmdargs.interface} net_connect.send_command('term shell 0') swcheck_dict["sh_int_status"] = net_connect.send_command( 'show int status | include {} .'.format(swcheck_dict["interface"])) #create a variable to grab speed (assuming just a number is passed (1/0/11 for example) # if re.search('[a-zA-Z]', self.cmdargs.interface): # swcheck_dict["local_int"] = self.cmdargs.interface # else: swcheck_dict["local_int"] = self.subs.regex_parser_var0(r'^(\S+)',swcheck_dict["sh_int_status"]) swcheck_dict["sh_int"] = net_connect.send_command( 'show int {} | include {} .'.format(swcheck_dict["local_int"], swcheck_dict["interface"])) swcheck_dict["sh_mac"] = net_connect.send_command( 'show mac address int {}'.format(swcheck_dict["local_int"])) swcheck_dict["mac_stat"] = \ re.findall(r'({}+)'.format(swcheck_dict["interface"]), swcheck_dict["sh_mac"], re.MULTILINE) swcheck_dict["sh_cdp"] = net_connect.send_command( 'show cdp neigh {}'.format(swcheck_dict["local_int"])) swcheck_dict["cdp_stat"] = \ re.findall(r'entries displayed : (\S+)', swcheck_dict["sh_cdp"], re.MULTILINE) swcheck_dict["sh_power"] = net_connect.send_command( 'show power inline | include {} .'.format(swcheck_dict["interface"])) swcheck_dict["power_stat"] = self.subs.regex_parser_var0(r'^(?:\S+\s+\S+\s+\S+\s+\S+\s+)(\S+)', swcheck_dict["sh_power"]) swcheck_dict["int_stat"] = self.subs.regex_parser_var0(r'(?:line protocol is \S+ \()(\S+)\)', swcheck_dict["sh_int"]) swcheck_dict["power_stat"] = self.subs.regex_parser_var0(r'^(?:\S+\s+\S+\s+\S+\s+\S+\s+)(\S+)', swcheck_dict["sh_power"]) swcheck_dict["int_stat"] = self.subs.regex_parser_var0(r'(?:line protocol is )(\S+)',swcheck_dict["sh_int"] ) self.subs.verbose_printer( "Switch:{}\nInterface:{}\nInt Status:{}\nPower Status:{}\n# of MACs:{}".format( swcheck_dict["ip"], swcheck_dict["local_int"], swcheck_dict["int_stat"], swcheck_dict["power_stat"], len(swcheck_dict["mac_stat"]))) # Currently will only work if: # -The port is down (AP may be locked up) # -The port is up with an AP (catches some odd APs behaviour, used on 100M connections) # -The port is up with Ieee and 0 Mac Addresses (AP is locked up) if (swcheck_dict["int_stat"] == "notconnect") or (swcheck_dict["int_stat"] == "connected" and ( ("AIR" in swcheck_dict["power_stat"]) or ( "Ieee" in swcheck_dict["power_stat"] and len(swcheck_dict["mac_stat"]) == 0))): # #TODO Add some logic to reload APs if not fincioning correctly # if "AIR" in swcheck_dict['sh_cdp']: # response = input("Port appears to have a live AP, confirm action of toggling port on/off ('yes'):") # if not response == 'yes': # self.subs.verbose_printer('Did not proceed with change.') # sys.exit(1) print("Change appears safe*") # change mac addresses to be 0, if not self.cmdargs.skip: if self.cmdargs.tdr: #Run a TDR test before if flag is set self.TDR_Test(net_connect,swcheck_dict['local_int']) response = input("Confirm action of toggling port on/off ('yes'):") if not response == 'yes': self.subs.verbose_printer('Did not proceed with change.') sys.exit(1) self.subs.snmp_reset_interface(self.cmdargs.ipaddr, self.subs.snmp_get_interface_id(self.cmdargs.ipaddr, swcheck_dict["local_int"])) # net_connect.enable() # config_command = ["interface " + swcheck_dict["local_int"], "shutdown"] # shutdown_output = net_connect.send_config_set(config_command) # self.subs.verbose_printer('Port Shutdown, waiting 5 seconds.') # time.sleep(5) # config_command = ["interface " + swcheck_dict["local_int"], "no shutdown"] # shutdown_output = net_connect.send_config_set(config_command) # self.subs.verbose_printer('Port Enabled.') else: print("Change may be unsafe, exiting.") # net_connect.send_command('int {}'.format(swcheck_dict["local_int"])) # net_connect.send_command('shutdown') net_connect.disconnect() # netmiko connection error handling except netmiko.ssh_exception.NetMikoAuthenticationException as err: self.subs.verbose_printer(err.args[0], "Netmiko Authentication Failure") sys.exit(1) except netmiko.ssh_exception.NetMikoTimeoutException as err: self.subs.verbose_printer(err.args[0], "Netmiko Timeout Failure") sys.exit(1) except ValueError as err: print(err.args[0]) sys.exit(1) except Exception as err: # currently a catch all to stop linux from having a conniption when reloading print("NETMIKO ERROR {}:{}".format(self.cmdargs.ipaddr, err.args[0])) sys.exit(1) # # def change_port_vlan(self): #TODO update to have batch file act on csv with format <IP,interface,vlan,desc> desc optional? # have csv in format of <KEY=VAL,KEY=VAL,KEY=VAL, need IP,interface as first two EX <A.A.A.A,Gi1/0/1,DESC=blah> vendor = self.subs.snmp_get_vendor_string(self.cmdargs.ipaddr) vlanList = self.subs.snmp_get_vlan_database(self.cmdargs.ipaddr,vendor) for vlan in vlanList: print("Vlan ID:{} Vlan Name:{}".format(vlan["ID"],vlan["Name"].decode("utf-8"))) # Find the ID of the requested interface intId = self.subs.snmp_get_interface_id(self.cmdargs.ipaddr, self.cmdargs.interface) fullInterface = self.subs.snmp_get_full_interface(self.cmdargs.ipaddr, intId) intDescription = self.subs.snmp_get_interface_description(self.cmdargs.ipaddr, intId) currentVlan = self.subs.snmp_get_interface_vlan(self.cmdargs.ipaddr, intId,vendor) #TEST self.subs.snmp_set_interface_vlan(self.cmdargs.ipaddr, intId, 2101,int(currentVlan), vendor) #enter vlan id to change to bLoop = True # TODO make this more efficient while (bLoop): print("Interface {} Description:{}".format(fullInterface,intDescription)) vlanResponse = input("Current Vlan is {} Enter VLAN ID to change to:".format(currentVlan )) if any(d['ID'] == int(vlanResponse) for d in vlanList): bLoop = False else: print("Please enter an existing Vlan ID") response = input("Do you want to change vlan on port {} from {} to {}?\n" "enter (yes) to proceed:".format(self.cmdargs.interface,currentVlan,vlanResponse)) if not response == 'yes': self.subs.verbose_printer('Did not proceed with change.') sys.exit(1) #set new vlan self.subs.snmp_set_interface_vlan(self.cmdargs.ipaddr, intId, int(vlanResponse), int(currentVlan), vendor) #check what vlan is now newVlan = self.subs.snmp_get_interface_vlan(self.cmdargs.ipaddr, intId, vendor) if int(newVlan) == int(vlanResponse): # print("Vlan updated to Vlan {}".format(newVlan)) else: print("vlan not updated, Vlan is still {}".format(newVlan)) response = input("Do you want to change description on port {} from {}?\n" "enter (yes) to proceed:".format(self.cmdargs.interface, intDescription)) if not response == 'yes': self.subs.verbose_printer('No new Description.') sys.exit(1) response = input("Enter new description:") self.subs.snmp_set_interface_description(self.cmdargs.ipaddr,intId,response) newDescription = self.subs.snmp_get_interface_description(self.cmdargs.ipaddr, intId) if newDescription == response: # print("Description updated to \"{}\"".format(response)) else: print("Description not updated, still \"{}\"".format(newDescription)) def diggle(self): switchlisting = None try: # Grab the name server first soa_answer = dns.resolver.query(self.cmdargs.domain, 'SOA') master_answer = dns.resolver.query(soa_answer[0].mname, 'A') # could skip previous 2 lines by presetting Name server address z = dns.zone.from_xfr(dns.query.xfr(master_answer[0].address, self.cmdargs.domain)) names = z.nodes.keys() matchcounter = 0 if 'advanced' in self.cmdargs and self.cmdargs.advanced: switchlisting = "Hostname , IP , Vendor\n" else: switchlisting = "Hostname , IP\n" for n in names: if re.match(self.cmdargs.hoststring, str(n),flags=re.IGNORECASE): #Case insensitive for simplicity matchcounter += 1 FQDN = str(n)+"."+self.cmdargs.domain IP = socket.gethostbyname(FQDN) if 'advanced' in self.cmdargs and self.cmdargs.advanced: vendor = self.subs.snmp_get_vendor_string(IP) switchlisting += "{} , {} , {}\n".format(FQDN, IP, vendor) else: switchlisting += "{} , {}\n".format(FQDN,IP) except socket.error as e: print('Failed to perform zone transfer:', e) except dns.exception.FormError as e: print('Failed to perform zone transfer:', e) except Exception as err: print(err) if switchlisting is not None: print("{}\n Job complete, {} matches found".format(switchlisting,matchcounter)) else: print(" Job complete, NO matches found") def port_label_check(self): # self.read_email_from_gmail() try: #login and grab mail from mailconnection = imaplib.IMAP4_SSL('imap.gmail.com') mailconnection.login(self.config.port_label_email, self.config.port_label_pw) mailconnection.select('PortLabels') # result, data = mail.search(None, 'ALL') # mailconnection.store(b'1', '-FLAGS', '(\\Seen)') # mailconnection.uid('STORE', b'1', '+FLAGS', '\SEEN') result, data = mailconnection.search(None, 'UNSEEN') mail_ids = data[0] id_list = mail_ids.split() if len(id_list) > 0: for msg_index in id_list: int_msg_index = int(msg_index) # need str(i) result, data = mailconnection.fetch(str(int_msg_index), '(RFC822)') #sets read mailconnection.store(msg_index, '-FLAGS', '(\\Seen)') for response_part in data: if isinstance(response_part, tuple): # from_bytes, not from_string msg = email.message_from_bytes(response_part[1]) email_subject = msg['subject'] email_from = msg['from'] if (email_subject == '<PORTLABELS> New Port Labels'): self.log_array.append("Email processing beginning\n") email_body = msg.get_payload(decode=True) dict_str = email_body.decode("UTF-8") label_dict = ast.literal_eval(dict_str) #WILL BALK AT MULTI LINK DESCRIPTIONS if (self.Apply_Port_Labels(label_dict)): self.Print_And_Log("Labels applied correctly, message index:{}".format(str(int_msg_index))) mailconnection.store(msg_index, '+FLAGS', '(\\Seen)') else: self.Print_And_Log("ERROR: Labels did not apply correctly, message index:{}".format( str(int_msg_index))) mailconnection.store(msg_index, '-FLAGS', '(\\Seen)') else: self.Print_And_Log("ERROR: incorrect message subject, message index:{}, subject:{}".format( str(int_msg_index),email_subject)) if self.cmdargs.notify: self.Email_Now(email_from,email_body) except Exception as e: print("Email processing failure:{}".format(e)) def Print_And_Log(self,to_print): self.subs.verbose_printer(to_print) self.log_array[0] += (to_print + "\n") def Apply_Port_Labels(self,full_label_dict,): #TODO list previous description and new description, to show the change #TODO add processing for Vlans #TODO make a list of the ports to change and then change them all at the same time (same command_list) # to send to netmiko to improve processing time, rather than jumping in and out of the config for each one bSuccess = True for switch_dict in full_label_dict['switches']: try: net_connect = self.subs.create_connection(switch_dict['IP']) if net_connect: net_connect.enable() # move this out of the if/else statements net_connect.send_command('term shell 0') for label in switch_dict['Labels']: current_config = net_connect.send_command('show run {}'.format(label['port'])) current_descr = self.subs.regex_parser_var0("description (.*)",current_config) if re.search('Invalid input detected', current_config) is not None: self.Print_And_Log( "\nERROR grabbing port info of {} on {}, skipping\n".format(label['port'], switch_dict['IP'])) bSuccess = False else: if not self.cmdargs.batch: response = input( "Current Config of {}:\n{}\n !!!! Apply new port label of \"{}\"? (type 'yes' to continue'):".format( label['port'], current_config, label['desc'])) if not response == 'yes': self.Print_And_Log("\nDid not proceed with changing {} on {}, skipping\n".format(label['port'],switch_dict['IP'])) bSuccess = False else: bSuccess = self.Apply_Description(net_connect,label,switch_dict['IP'],current_descr,bSuccess) else: #if in batch mode bSuccess = self.Apply_Description(net_connect,label,switch_dict['IP'],current_descr,bSuccess) result = net_connect.save_config() if re.search('Invalid input detected', result) is not None: self.Print_And_Log("\nError saving config on {}\n".format(switch_dict['IP'])) bSuccess = False else: self.Print_And_Log("\nSuccess saving config on {}\n".format(switch_dict['IP'])) net_connect.disconnect() except Exception as e: self.Print_And_Log("\nConnection/label application failure:{}\n".format(e)) bSuccess = False return bSuccess def Apply_Description(self,net_connect,label,ipaddr,current_descr,bSuccess): result = net_connect.send_config_set([label['port'], label['desc']]) if re.search('Invalid input detected', result) is not None: self.Print_And_Log("\nERROR updating port info of {} on {}\n".format(label['port'], ipaddr)) bSuccess = False else: self.Print_And_Log( "\nSuccessfully updated port info of {} on {}\n Old:{} New:{}\n".format(label['port'], ipaddr, current_descr, label['desc'])) return bSuccess def Email_Now(self,to_email,original_text): try: self.subs.verbose_printer("##### Emailing now #####") temp_from = "admin@localhost" # Create the message themsg = MIMEMultipart() themsg["From"] = temp_from themsg["Subject"] = "response from Port Labelling - {}".format(datetime.date.today().strftime('%Y-%m-%d')) themsg["To"] = to_email # themsg.preamble = 'I am not using a MIME-aware mail reader.\n' # msg = MIMEBase('application', 'zip') # msg.set_payload(zf.read()) # encoders.encode_base64(msg) # msg.add_header('Content-Disposition', 'attachment', # filename=status_filename + '.zip') # # # themsg.attach(msg) #create the body of the email body = self.log_array[0] + "\n" body += "\n ------------------------------------\n ORIGINAL MSG BELOW\n{}".format(original_text)+"\n" themsg.attach(MIMEText(body, 'plain')) themsg = themsg.as_string() # send the message smtp = smtplib.SMTP() smtp.connect() smtp.sendmail(temp_from, to_email, themsg) smtp.close() except smtplib.SMTPException as err: print("Failed to send Email:{}".format(err)) except Exception as err: print(err) def standardize_begin(self): if 'apply' in self.cmdargs and self.cmdargs.apply: print("Beginning Apply Standards Operation") else: print("Beginning Check Standards Operation") # File will have mandatory first row with at least these fields: ip, type, user, pass, en, port file = open(self.cmdargs.ipfile, "r") summary_list = [] if 'manual' in self.cmdargs and self.cmdargs.manual: row_titles = next(file).split(',') #grab the first row (the titles) use these to make the standardize switch call dynamic row_titles[len(row_titles)-1] = row_titles[len(row_titles)-1].rstrip() #remove the trailing newline for ip in file: if ('manual' in self.cmdargs and self.cmdargs.manual and len(row_titles) == 6): #{IP][Vendor][UN][PW][EN][PORT.split] ip_entry = ip.split(',') if (len(ip_entry) == len(row_titles)): ip_entry[len(ip_entry)-1] = ip_entry[len(ip_entry)-1].rstrip() summary_list.append(self.Standardize_Switch(ip_entry[row_titles.index("ip")], ip_entry[row_titles.index("type")], ip_entry[row_titles.index("user")], ip_entry[row_titles.index("pass")], ip_entry[row_titles.index("en")], ip_entry[row_titles.index("port")])) elif 'manual' in self.cmdargs and not self.cmdargs.manual: try: vendor = self.subs.snmp_get_vendor_string(ip.rstrip()) if vendor =="Cisco": device_type = "cisco_ios" elif vendor =="HP": device_type="hp_procurve" else: device_type="generic_termserver" summary_list.append(self.Standardize_Switch(ip.rstrip(),device_type,self.config.username, self.config.password,self.config.enable_pw,22)) except Exception as err: print(err) file.close() print("\nSUMMARY:") for entry in summary_list: print(entry) def Standardize_Switch(self,ipaddr,vendor,username,password,enable_pw,port): print_summary = "" if self.subs.ping_check(ipaddr): try: if "hp_procurve_telnet" in vendor: net_connect = self.subs.create_connection_manual(ipaddr, vendor, username, password, enable_pw, port, "sername", "assword") else: net_connect = self.subs.create_connection_custom(ipaddr, vendor, username, password, enable_pw, port) if 'manual' in self.cmdargs and self.cmdargs.manual: enable_success =self.subs.vendor_enable_manual(vendor,net_connect,username,password,enable_pw) else: enable_success = self.subs.vendor_enable(vendor,net_connect) if enable_success: if "hp_procurve" in vendor: #temporary fix for net_connect.send_command("term length 1000") sh_run = net_connect.send_command("show run") # add a check for hp and term length 0? # print(sh_run) #TODO seperate the commandlist into headings like auth= # then have seperate check/apply fields for some that can have hashed values # commandlist = self.gather_standard_commands(vendor,"tacacsshow") foundnum,missingnum,appliednum,errornum = self.gather_standard_commands(ipaddr,vendor,sh_run,net_connect) self.subs.verbose_printer("{} - {} CMDs exist {} CMDs missing {} CMDs applied {} CMDs Errors".format(ipaddr,foundnum,missingnum,appliednum,errornum)) return "{} - {} CMDs exist {} CMDs missing {} CMDs applied {} CMDs Errors".format(ipaddr,foundnum,missingnum,appliednum,errornum) else: self.subs.verbose_printer("###{}### ERROR Unable to enable".format(ipaddr)) return "{} - Unable to Enable".format(ipaddr) net_connect.disconnect() except netmiko.ssh_exception.NetMikoAuthenticationException as err: self.subs.verbose_printer(err.args[0], "###{}### ERROR Netmiko Authentication Failure ".format(ipaddr)) return "{} - {}".format(ipaddr,err.args[0]) except netmiko.ssh_exception.NetMikoTimeoutException as err: self.subs.verbose_printer(err.args[0], "###{}### ERROR Netmiko Timeout Failure".format(ipaddr)) return "{} - {}".format(ipaddr,err.args[0]) except netmiko.ssh_exception.SSHException as err: if (err.args[0] == "Incompatible version (1.5 instead of 2.0)"): self.subs.verbose_printer(err.args[0], "###{}### ERROR Netmiko incompatible version".format(ipaddr)) result2 = self.Standardize_Switch(ipaddr, "{}_telnet".format(vendor), username, password, enable_pw, 23) return "{} - {}\n{}".format(ipaddr, err.args[0], result2) else: self.subs.verbose_printer(err.args[0], "###{}### ERROR Netmiko SSH Exception".format(ipaddr)) return "{} - {}".format(ipaddr, err.args[0]) except Exception as err: # currently a catch all to stop linux from having a conniption when reloading self.subs.verbose_printer("###{}### ERROR NETMIKO:{}".format(ipaddr, err.args[0])) return "{} - {}".format(ipaddr, err.args[0]) else: self.subs.verbose_printer("####{}### ERROR Unable to ping ".format(ipaddr)) return "{} - No Ping Response".format(ipaddr) def gather_standard_commands(self,ipaddr,vendor,sh_run, net_connect): config = configparser.ConfigParser() #Check wehere to grab the config for if 'cmdfile' in self.cmdargs and self.cmdargs.cmdfile is not None: config.read(self.cmdargs.cmdfile) else: config.read(os.path.abspath(os.path.join(os.sep, 'usr', 'lib', 'capt', 'standard.conf'))) #set the heading to grab from the custom file if vendor in ["Cisco", "cisco_ios", "cisco_ios_telnet"]: Vendor_Heading = "CISCO" elif vendor in ["HP", "hp_procurve", "hp_procurve_telnet"]: Vendor_Heading = "HP" else: Vendor_Heading = "UNKNOWN" foundnum = 0 missingnum = 0 appliednum=0 errornum=0 for Heading in (MainHeading for MainHeading in config if Vendor_Heading in MainHeading ): if "BASE" in Heading or "SHOW" in Heading: for Category in config[Heading]: command_list = config[Heading][Category].splitlines() if len(command_list) > 1: #for multiline commands try: for command in command_list: if self.check_config_for_command(command, sh_run): self.subs.verbose_printer("###{}### FOUND: {} ".format(ipaddr, command)) foundnum += 1 else: print("###{}### MISSING: {} ".format(ipaddr, command)) missingnum += 1 if "apply" in self.cmdargs and self.cmdargs.apply: if "solo" not in Category: # exit out and apply all if dependent commands raise ValueError result = net_connect.send_config_set(command) if self.subs.print_config_results(ipaddr,result,command): appliednum +=1 else: errornum += 1 except ValueError: # break out of that for loop if one of the commands are missing and you have apply set if "BASE" in Heading: send_command_set = config[Heading][ Category].splitlines() # if missing any of the values for the entry, apply them all elif "SHOW" in Heading: send_command_set = config["{} APPLY".format(Vendor_Heading)][Category].split(',') result = net_connect.send_config_set(send_command_set) if self.subs.print_config_results(ipaddr, result, send_command_set): appliednum += 1 else: errornum += 1 elif len(command_list) == 1: # for commands with a single entry if self.check_config_for_command(command_list[0],sh_run): self.subs.verbose_printer("###{}### FOUND: {} ".format(ipaddr, command_list[0])) foundnum += 1 else: print("###{}### MISSING: {} ".format(ipaddr, command_list[0])) missingnum += 1 if 'apply' in self.cmdargs and self.cmdargs.apply: if "BASE" in Heading: send_command_set = command_list[0] # if missing any of the values for the entry, apply them all elif "SHOW" in Heading: send_command_set =config["{} APPLY".format(Vendor_Heading)][Category].split(',') result = net_connect.send_config_set(send_command_set) if self.subs.print_config_results(ipaddr, result, send_command_set): appliednum += 1 else: errornum += 1 if "apply" in self.cmdargs and self.cmdargs.apply: result = net_connect.save_config() self.subs.verbose_printer("{} - {}".format(ipaddr,result)) return foundnum,missingnum,appliednum,errornum def check_config_for_command(self,command,sh_run): escapedcommand = command.translate(str.maketrans({"-": r"\-", "]": r"\]", "\\": r"\\", "^": r"\^", "$": r"\$", "*": r"\*", "+": r"\+", ".": r"\."})) if re.search('^\s*{}'.format(escapedcommand), sh_run, flags=re.IGNORECASE | re.MULTILINE): return True else: return False def hp_password_change_begin(self): if 'apply' in self.cmdargs and self.cmdargs.apply: print("Beginning Apply Standards Operation") else: print("Beginning Check Standards Operation") # File will have mandatory first row with at least these fields: ip, type, user, pass, en, port file = open(self.cmdargs.ipfile, "r") summary_list = [] if 'manual' in self.cmdargs and self.cmdargs.manual: row_titles = next(file).split( ',') # grab the first row (the titles) use these to make the standardize switch call dynamic row_titles[len(row_titles) - 1] = row_titles[len(row_titles) - 1].rstrip() # remove the trailing newline for ip in file: if ('manual' in self.cmdargs and self.cmdargs.manual and len( row_titles) == 6): # {IP][Vendor][UN][PW][EN][PORT.split] ip_entry = ip.split(',') if (len(ip_entry) == len(row_titles)): ip_entry[len(ip_entry) - 1] = ip_entry[len(ip_entry) - 1].rstrip() summary_list.append( self.HP_Pass_Change(ip_entry[row_titles.index("ip")], ip_entry[row_titles.index("type")], ip_entry[row_titles.index("user")], ip_entry[row_titles.index("pass")], ip_entry[row_titles.index("en")], ip_entry[row_titles.index("port")])) elif 'manual' in self.cmdargs and not self.cmdargs.manual: try: vendor = self.subs.snmp_get_vendor_string(ip.rstrip()) if vendor == "Cisco": device_type = "cisco_ios" elif vendor == "HP": device_type = "hp_procurve" else: device_type = "generic_termserver" summary_list.append( self.HP_Pass_Change(ip.rstrip(), device_type, self.config.username, self.config.password, self.config.enable_pw, 22)) except Exception as err: print(err) file.close() print("\nSUMMARY:") for entry in summary_list: print(entry) def HP_Pass_Change(self,ipaddr,vendor,username,password,enable_pw,port): print_summary = "" if self.subs.ping_check(ipaddr): try: if "hp_procurve_telnet" in vendor: net_connect = self.subs.create_connection_manual(ipaddr, vendor, username, password, enable_pw, port, "sername","assword") else: net_connect = self.subs.create_connection_custom(ipaddr, vendor, username, password, enable_pw, port) if 'manual' in self.cmdargs and self.cmdargs.manual: enable_success = self.subs.vendor_enable_manual(vendor, net_connect, username, password, enable_pw) else: enable_success = self.subs.vendor_enable(vendor, net_connect) if enable_success: if 'apply' in self.cmdargs and self.cmdargs.apply: result = net_connect.send_command("conf t","#") result += net_connect.send_command("pass manager user-name {}".format(self.cmdargs.username), ":") result += net_connect.send_command("{}".format(self.cmdargs.password), ":") result += net_connect.send_command("{}".format(self.cmdargs.password), "#") result += net_connect.save_config() self.subs.verbose_printer("{} - {}".format(ipaddr,result)) self.subs.verbose_printer("{} - Updated password".format(ipaddr)) return "{} - Updated password".format(ipaddr) else: self.subs.verbose_printer("{} - Logged in successfully, but did not change Password".format(ipaddr)) return "{} - Logged in successfully, but did not change Password".format(ipaddr) else: self.subs.verbose_printer("###{}### ERROR Unable to enable".format(ipaddr)) return "{} - Unable to Enable".format(ipaddr) net_connect.disconnect() except netmiko.ssh_exception.NetMikoAuthenticationException as err: self.subs.verbose_printer(err.args[0], "###{}### ERROR Netmiko Authentication Failure ".format(ipaddr)) return "{} - {}".format(ipaddr, err.args[0]) except netmiko.ssh_exception.NetMikoTimeoutException as err: self.subs.verbose_printer(err.args[0], "###{}### ERROR Netmiko Timeout Failure".format(ipaddr)) return "{} - {}".format(ipaddr, err.args[0]) except netmiko.ssh_exception.SSHException as err: if (err.args[0] == "Incompatible version (1.5 instead of 2.0)"): self.subs.verbose_printer(err.args[0], "###{}### ERROR Netmiko incompatible version".format(ipaddr)) result2 = self.HP_Pass_Change(ipaddr, "{}_telnet".format(vendor), username, password, enable_pw, 23) # try telnet if v1 only return "{} - {}\n{} - {}".format(ipaddr, err.args[0], ipaddr,result2) else: self.subs.verbose_printer(err.args[0], "###{}### ERROR Netmiko SSH Exception".format(ipaddr)) return "{} - {}".format(ipaddr, err.args[0]) except Exception as err: # currently a catch all to stop linux from having a conniption when reloading self.subs.verbose_printer("###{}### ERROR NETMIKO:{}".format(ipaddr, err.args[0])) return "{} - {}".format(ipaddr, err.args[0]) else: self.subs.verbose_printer("####{}### ERROR Unable to ping ".format(ipaddr)) return "{} - No Ping Response".format(ipaddr) def arp_table_check(self): cmdlist = [] file = open(os.path.join(self.cmdargs.cmdfile), "r") self.subs.verbose_printer("##### file opened:{} #####".format(file)) for cmd in file: cmdlist.append(cmd.rstrip()) file.close() if self.subs.ping_check(self.cmdargs.ipaddr): try: net_connect = self.subs.create_connection(self.cmdargs.ipaddr) #added this if net_connect: output = net_connect.send_command("term length 0") for cmd in cmdlist: # Show Interface Status self.subs.custom_printer("verbose", "show ip arp {}".format(cmd)) output = net_connect.send_command("show ip arp {}".format(cmd)) # example output: 2044 0000.AAAA.BBBB DYNAMIC Po9 if 'csv' in self.cmdargs and self.cmdargs.csv: outputlist = output.splitlines() for line in outputlist: if 'filter' in self.cmdargs and self.cmdargs.filter is not None: filterlist = self.cmdargs.filter.split(',') if not any([x in line for x in filterlist]): csv = re.sub("\s+", ",", line) print("{},{},{}".format(self.cmdargs.ipaddr, cmd, csv)) else: csv = re.sub("\s+", ",", line) print("{},{},{}".format(self.cmdargs.ipaddr,cmd,csv)) else: print(output) except netmiko.ssh_exception.NetMikoAuthenticationException as err: self.subs.verbose_printer(err.args[0],"Netmiko Authentication Failure") except netmiko.ssh_exception.NetMikoTimeoutException as err: self.subs.verbose_printer(err.args[0], "Netmiko Timeout Failure") except ValueError as err: #if 'verbose' in self.cmdargs and self.cmdargs.verbose: print(err.args[0]) def mac_table_check(self): iplist = [] file = open(os.path.join(self.cmdargs.ipfile), "r") self.subs.verbose_printer("##### file opened:{} #####".format(file)) for ip in file: iplist.append(ip.rstrip()) file.close() for ip in iplist: if self.subs.ping_check(ip): try: net_connect = self.subs.create_connection(ip) # added this if net_connect: output = net_connect.send_command("term length 0") # Show Interface Status self.subs.custom_printer("verbose", "show mac addr") output = net_connect.send_command("show mac addr") if 'csv' in self.cmdargs and self.cmdargs.csv: outputlist = output.splitlines() for line in outputlist: if 'filter' in self.cmdargs and self.cmdargs.filter is not None: filterlist = self.cmdargs.filter.split(',') if not any([x in line for x in filterlist]): csv = re.sub("\s+", ",", line.strip()) print("{},{}".format(ip, csv)) else: csv = re.sub("\s+", ",", line.strip()) print("{},{}".format(ip, csv)) else: print(output) except netmiko.ssh_exception.NetMikoAuthenticationException as err: self.subs.verbose_printer(err.args[0], "Netmiko Authentication Failure") except netmiko.ssh_exception.NetMikoTimeoutException as err: self.subs.verbose_printer(err.args[0], "Netmiko Timeout Failure") except ValueError as err: # if 'verbose' in self.cmdargs and self.cmdargs.verbose: print(err.args[0])
class MacTracking: def __init__(self, cmdargs, config): # initialize values self.log_array = [] self.cmdargs = cmdargs self.config = config self.subs = SubRoutines(cmdargs, config) # self.log_path = os.path.abspath(os.path.join(os.sep, 'var', 'log', 'dnmt')) # self.subs.log_path = os.path.abspath(os.path.join(os.sep, 'var', 'log', 'dnmt')) self.successful_switches = [] #used for activity tracking self.failure_switches = [] #used for activity tracking self.successful_files = [] #used for activity tracking self.failure_files = [] # used for activity tracking def mac_tracking_begin(self): iplist = [] historical_mac_data = [] # will hold the mac data list of dicts {mac, total_start = time.time() if not os.path.exists( os.path.join(self.subs.log_path, "maccheck", "rawfiles")): self.subs.custom_printer( "debug", "## DBG - Creating maccheck/rawfiles directory ##") os.makedirs( os.path.join(self.subs.log_path, "maccheck", "rawfiles")) # if not os.path.exists(os.path.join(self.subs.log_path, "maccheck", "processedfiles")): # self.subs.custom_printer("debug", "## DBG - Creating maccheck/processedfiles directory ##") # os.makedirs(os.path.join(self.subs.log_path, "maccheck", "processedfiles")) # Specifying a file only changes what IPs are updated, right now the status check grabs all existing files in # the raw data folder file_path = os.path.join(self.subs.log_path, "maccheck", "rawfiles", "macs.db") lock = FileLock("{}.lock".format(file_path)) try: self.subs.custom_printer( "debug", "## DBG - Opening statcheck file from legacy ##") lock.acquire(timeout=10) with bz2.open( os.path.join(self.subs.log_path, "maccheck", "rawfiles", "macs.db"), "rb") as historical_mac_file: self.subs.custom_printer( "debug", "## DBG - Loading historical mac data ##") historical_mac_data = pickle.load(historical_mac_file) historical_mac_file.close() self.subs.custom_printer( "debug", "## DBG - Completed loading Mac database {} ##".format( file_path)) except FileNotFoundError as err: print( "##### {} - No previous mac data found, one will be created if searching #####" .format(file_path)) except Timeout as err: print("##### {} - Lock file exists #####".format(file_path)) finally: lock.release() if 'file' in self.cmdargs and self.cmdargs.file is not None: file_path = os.path.join(self.cmdargs.file) else: file_path = os.path.abspath( os.path.join(os.sep, 'usr', 'lib', 'capt', "activitycheckIPlist")) # added file locking lock = FileLock("{}.lock".format(file_path)) try: self.subs.custom_printer( "debug", "## DBG - Opening iplist {} ##".format(file_path)) lock.acquire(timeout=10) file = open(file_path, "r") self.subs.custom_printer( "debug", "## DBG - Completed opening iplist {} ##".format(file_path)) for ip in file: iplist.append(ip.rstrip()) file.close() self.subs.custom_printer( "debug", "## DBG - Completed loading iplist {} ##".format(file_path)) # pool = Pool(len(iplist)) # 4 concurrent processes # results = pool.map(self.single_search, iplist) #TODO CHANGE to do them with individual processes for ip in iplist: # self.subs.config.ro = self.config.ro #reset to default to ensure previous ones did not bork things custom_ro_check = ip.split(',') ro_string = self.subs.config.ro if len(custom_ro_check) > 1: ro_string = custom_ro_check[1] ip = custom_ro_check[0] try: result = self.mac_tracking(ip, ro_string) if result[0]: self.successful_switches.append(result[1]) #update macdb list with found macs for new_mac_entry in result[2]: try: historical_mac_entry = next( entry for entry in historical_mac_data if entry['MAC'] == new_mac_entry['MAC']) # if found_mac_entry[''] #if found_mac_entry_timestamp is bigger or the count is smaller, update list # if not 1, go for the largest mac count? this would catch the highest up the chain if new_mac_entry[ 'MACCount'] <= historical_mac_entry[ 'MACCount']: historical_mac_entry[ 'MACCount'] = new_mac_entry['MACCount'] historical_mac_entry['timestamp'] = int( datetime.datetime.now().strftime( '%Y%m%d%H%M')) historical_mac_entry['switchIP'] = ip historical_mac_entry[ 'InterfaceID'] = new_mac_entry[ "InterfaceID"] except StopIteration: self.subs.verbose_printer( "##### MAC {} not found adding to list #####" .format(new_mac_entry['MAC'])) historical_mac_data.append({ 'MAC': new_mac_entry['MAC'], "switchIP": ip, "InterfaceID": new_mac_entry["InterfaceID"], "MACCount": new_mac_entry["MACCount"], "timestamp": int(datetime.datetime.now().strftime( '%Y%m%d%H%M')) }) except Exception as err: print( "ERROR PROCESSING MAC ADDRESS RETURN {}:{}" .format(ip, err)) else: self.failure_switches.append(result[1]) except Exception as err: print("ERROR PROCESSING FILE {}:{}".format(ip, err)) self.subs.verbose_printer( "##### Total Processing Complete, Total Time:{} seconds #####". format(int((time.time() - total_start) * 100) / 100)) except FileNotFoundError: print("##### ERROR iplist files not found #####") except Timeout as err: print("##### {} - Lock file exists #####".format(file_path)) except Exception as err: print("##### ERROR with processing:{} #####".format(err)) finally: lock.release() # write out active status for combining into statcheck csv file_path = os.path.join(self.subs.log_path, "maccheck", "rawfiles", "macs.db") lock = FileLock("{}.lock".format(file_path)) try: self.subs.custom_printer( "debug", "## DBG - Opening {} to save mac database to ##".format( file_path)) lock.acquire(timeout=10) with bz2.BZ2File(file_path, 'wb') as sfile: self.subs.custom_printer( "debug", "## DBG - Writing Mac database {} ##".format(file_path)) pickle.dump(historical_mac_data, sfile) sfile.close() self.subs.custom_printer( "debug", "## DBG - Completed Writing Mac database {} ##".format( file_path)) except Timeout as err: print("##### {} - Lock file exists #####".format(file_path)) finally: lock.release() def mac_tracking(self, ipaddr, ro_string): try: start = time.time() self.subs.verbose_printer( "##### {} - Processing #####".format(ipaddr)) self.subs.custom_printer( "debug", "## DBG - Grabbing switch data through SNMP ##") try: vendor = self.subs.snmp_get_vendor_string(ipaddr, ro=ro_string) mac_list = self.subs.snmp_get_mac_table_bulk(ipaddr, vendor, ro=ro_string) # interface_list = {} #used for counting number of macs on a port if len(mac_list) > 0: interface_list = defaultdict(list) #process to find out how many on each port for entry in mac_list: interface_list[entry["InterfaceID"]].append( entry["MAC"]) for entry in mac_list: entry["MACCount"] = len( interface_list[entry['InterfaceID']]) return True, ipaddr, mac_list else: return False, ipaddr, mac_list except Exception as err: #currently a catch all to stop linux from having a conniption when reloading print("##### {} UNKNOWN ERROR:{} #####".format( ipaddr, err.args[0])) return False, ipaddr, None except Exception as err: #catch all exception print("##### {} UNKNOWN ERROR:{} #####".format( ipaddr, err.args[0])) # self.failure_switches.append(ipaddr) end = time.time() self.subs.verbose_printer( "##### {} - Processing aborted/failure, time:{} seconds #####" .format(ipaddr, int((end - start) * 100) / 100)) return (False, ipaddr)
class HostNamer: def __init__(self, cmdargs, config): # initialize values self.log_array = [] self.cmdargs = cmdargs self.config = config self.subs = SubRoutines(cmdargs, config) self.checklog = "" def bulk_vlan_change(self,ipaddr,old_vlan,new_vlan): #add checking if the vlan exists first, add write mem after change for (errorIndication, errorStatus, errorIndex, varBinds) in nextCmd(SnmpEngine(), CommunityData(self.config.ro), UdpTransportTarget((ipaddr, 161)), ContextData(), ObjectType(ObjectIdentity('CISCO-VLAN-MEMBERSHIP-MIB', 'vmVlan').addAsn1MibSource('file:///usr/share/snmp', 'http://mibs.snmplabs.com/asn1/@mib@')), lexicographicMode=False): if errorIndication: print(errorIndication) elif errorStatus: print('%s at %s' % (errorStatus.prettyPrint(), errorIndex and varBinds[int(errorIndex) - 1][0] or '?')) else: # if getting the hostname from snmp was successful grabbed_oid, grabbed_value = varBinds[0] # grab dns value & oid oidvar = grabbed_oid._ObjectIdentity__args[0]._value[grabbed_oid._ObjectIdentity__args[0]._value.__len__()-1] if str(grabbed_value) == old_vlan: if (self.subs.snmp_set(ipaddr, ObjectType(ObjectIdentity( 'CISCO-VLAN-MEMBERSHIP-MIB', 'vmVlan', oidvar).addAsn1MibSource( 'file:///usr/share/snmp', 'http://mibs.snmplabs.com/asn1/@mib@'), new_vlan))): print("placeholder vlan ID updated") self.subs.snmp_save_config(ipaddr) # def snmp_test(ipaddr,config,oid): # # # for (errorIndication, # errorStatus, # errorIndex, # varBinds) in nextCmd(SnmpEngine(), # CommunityData(config.ro), # UdpTransportTarget((ipaddr, 161)), # ContextData(), # ObjectType(ObjectIdentity('CISCO-VLAN-MEMBERSHIP-MIB', 'vmVlan').addAsn1MibSource('file:///usr/share/snmp', # 'http://mibs.snmplabs.com/asn1/@mib@')), # lexicographicMode=False): # if errorIndication: # print(errorIndication) # elif errorStatus: # print('%s at %s' % (errorStatus.prettyPrint(), # errorIndex and varBinds[int(errorIndex) - 1][0] or '?')) # else: # if getting the hostname from snmp was successful # dns_oid, dns_value = varBinds[0] # grab dns value & oid # print ("oid:{}\nvalue:{}".format(str(dns_oid),str(dns_value))) # # def snmpproc(self, ipaddr,dns_hostname,dns_domain,**kwargs): try: reg_FQDN = re.compile("([^.]*)\.(.*)") # Group 0: hostname, Group 1: domain name varBinds = self.subs.snmp_get(ipaddr, ObjectType(ObjectIdentity( '1.3.6.1.2.1.1.5.0'))) if (varBinds): # if getting the hostname from snmp was successful dns_oid, dns_value = varBinds[0] #grab dns value & oid dns_value=str(dns_value) # change dns_value to string rather than DisplayString #add error handling here for if there is no domain name {TODO} sw_reg_hostname = reg_FQDN.search(dns_value) if sw_reg_hostname is None: # HP switches do not have the domain name in The Return sw_hostname = dns_value else: sw_hostname = sw_reg_hostname.group(1) #extract the hostname from the FQDN #check to see if the hostname and dns are the same if dns_hostname.casefold() != sw_hostname.casefold(): #Send the new hostname if they are different if self.cmdargs.check: self.checklog += "{} hostname is different\n".format(ipaddr) print("hostnames are different\n" "IP:{}\n" "DNS/Manual:{}\n" "Switch :{}\n".format(ipaddr, dns_hostname, sw_hostname)) if not self.cmdargs.check: print("Attempting to update hostname on switch...") # varBinds = self.subs.snmp_get(ipaddr, ObjectType(ObjectIdentity( # '1.3.6.1.2.1.1.5.0'),dns_hostname.upper())) varBinds = self.subs.snmp_set(ipaddr, ObjectType(ObjectIdentity( '1.3.6.1.2.1.1.5.0'), dns_hostname.upper())) self.subs.snmp_save_config(ipaddr) if (varBinds):#hostname was updated successfully #call itself to confirm it is updated. self.snmpproc(ipaddr, dns_hostname, dns_domain) return True else: # if check flag is indicated return True # return true so that the program doesn't try to login to check again else: #they are the same if self.cmdargs.check and not self.cmdargs.suppress: self.checklog += "{} hostname is the same\n".format(ipaddr) print("hostnames are up to date\n" "IP:{}\n" "DNS/Manual:{}\n" "Switch :{}\n".format(ipaddr, dns_hostname, sw_hostname)) return True #if sending was not successful except Exception as err: # currently a catch all to stop linux from having a conniption when reloading print("SNMP PROC ERROR {}:{}".format(ipaddr, err.args[0])) return False def loginproc(self, ipaddr,dns_hostname,dns_domain,**kwargs): # SSH Connection try: if 'manual' in self.cmdargs and self.cmdargs.manual: manual_credentials = kwargs.get('manualcreds') row_titles = kwargs.get('rowtitles') if "telnet" in manual_credentials[row_titles.index("type")]: net_connect = self.subs.create_connection_manual(ipaddr, manual_credentials[row_titles.index("type")], manual_credentials[row_titles.index("user")], manual_credentials[row_titles.index("pass")], manual_credentials[row_titles.index("en")], manual_credentials[row_titles.index("port")], "sername", "assword") else: net_connect = self.subs.create_connection_custom(ipaddr, manual_credentials[row_titles.index("type")], manual_credentials[row_titles.index("user")], manual_credentials[row_titles.index("pass")], manual_credentials[row_titles.index("en")], manual_credentials[row_titles.index("port")]) else: net_connect = self.subs.create_connection(ipaddr) #net_connect = ConnectHandler(**cisco_sw) if net_connect: ### ADD ERROR HANDLING FOR FAILED CONNECTION print("-------- CONNECTED --------") # grab hostname sw_hostname = net_connect.find_prompt() # sw_mode = sw_hostname[-1] sw_hostname = sw_hostname.replace(">", "") sw_hostname = sw_hostname.replace("#", "") # output = net_connect.send_command('show ver | i uptime is') # sw_hostname = reg_hostname.search(output) if sw_hostname.casefold() != dns_hostname.casefold(): if self.cmdargs.check: self.checklog += "{} hostname is different\n".format(ipaddr) print("hostnames are different\n" "IP:{}\n" "DNS :{}\n" "Switch:{}\n".format(ipaddr, dns_hostname, sw_hostname)) if not self.cmdargs.check: self.subs.custom_printer("verbose", "## {} - applying new hostname ##".format(ipaddr.rstrip())) command_str = "hostname " + dns_hostname.upper() if 'manual' in self.cmdargs and self.cmdargs.manual: enable_success = self.subs.vendor_enable(manual_credentials[row_titles.index("type")], net_connect) else: net_connect.enable() output = net_connect.send_config_set([command_str]) if 'manual' in self.cmdargs and self.cmdargs.manual: if "telnet" in manual_credentials[row_titles.index("type")]: save_output, new_sw_hostname = self.subs.hp_save_config(net_connect) else: net_connect.save_config() #net_connect.commit() #net_connect.send_command('wr mem') #print (output) new_sw_hostname = new_sw_hostname.strip() new_sw_hostname = new_sw_hostname.replace(">", "") new_sw_hostname = new_sw_hostname.replace("#", "") if new_sw_hostname.casefold() == dns_hostname.casefold(): print("SUCCESS, hostnames are up to date\n" "IP:{}\n" "DNS :{}\n" "Switch:{}\n".format(ipaddr, dns_hostname, sw_hostname)) else: print("ERROR, hostnames are not up to date\n" "IP:{}\n" "DNS :{}\n" "Switch:{}\n".format(ipaddr, dns_hostname, sw_hostname)) else: if self.cmdargs.check and not self.cmdargs.suppress: self.checklog += "{} hostname is the same\n".format(ipaddr) print("hostnames are up to date\n" "IP:{}\n" "DNS :{}\n" "Switch:{}\n".format(ipaddr, dns_hostname, sw_hostname)) # Close Connection net_connect.disconnect() except netmiko.ssh_exception.NetMikoAuthenticationException as err: self.subs.verbose_printer(err.args[0], "Netmiko Authentication Failure") except netmiko.ssh_exception.NetMikoTimeoutException as err: self.subs.verbose_printer(err.args[0], "Netmiko Timeout Failure") except ValueError as err: print(err.args[0]) except Exception as err: # currently a catch all to stop linux from having a conniption when reloading print("NETMIKO ERROR {}:{}".format(ipaddr, err.args[0])) #def hostname_update(iplist,username,password,snmp_ro,snmp_rw,check_flag): def hostname_update(self,): # Regexs reg_FQDN = re.compile("([^.]*)\.(.*)") # Group 0: hostname, Group 1: domain name if self.cmdargs.check: self.checklog = "SUMMARY of Hostnames:\n" file = open(self.cmdargs.iplist, "r") #if not self.cmdargs.check: if self.cmdargs.peek: print("IP,Hostname") if 'manual' in self.cmdargs and self.cmdargs.manual: row_titles = next(file).split(',') # grab the first row (the titles) use these to make the standardize switch call dynamic row_titles[len(row_titles) - 1] = row_titles[len(row_titles) - 1].rstrip() # remove the trailing newline for ipaddr in file: #have a check for gethostbyname or addr) self.subs.custom_printer("verbose", "## processing entry - {} ##".format(ipaddr.rstrip())) try: ipaddr = ipaddr.rstrip().replace(" ","").split(",") if len(ipaddr) == 1: dns_fqdn = socket.gethostbyaddr(ipaddr[0]) dns_reg_hostname = reg_FQDN.search(dns_fqdn[0]) dns_hostname = dns_reg_hostname.group(1) dns_domain = dns_reg_hostname.group(2) elif len(ipaddr) == 3: dns_hostname = ipaddr[1] dns_domain = ipaddr[2] elif ('manual' in self.cmdargs and self.cmdargs.manual): try: dns_hostname = ipaddr[row_titles.index("host")] dns_domain = ipaddr[row_titles.index("domain")] except IndexError: #called if there is no host entry dns_fqdn = socket.gethostbyaddr(ipaddr[row_titles.index("ip")]) dns_reg_hostname = reg_FQDN.search(dns_fqdn[0]) dns_hostname = dns_reg_hostname.group(1) dns_domain = dns_reg_hostname.group(2) if self.cmdargs.peek: print("{},{}.{}".format(ipaddr[0], dns_hostname, dns_domain)) #success = snmpproc(ipaddr,dns_hostname,dns_domain,snmp_ro,snmp_rw,check_flag) if not self.cmdargs.peek: success = self.snmpproc(ipaddr[0], dns_hostname, dns_domain) if not success: print("SNMP failed, attempting through SSH") if ('manual' in self.cmdargs and self.cmdargs.manual): self.loginproc(ipaddr[0],dns_hostname,dns_domain,manualcreds=ipaddr,rowtitles=row_titles) else: self.loginproc(ipaddr[0], dns_hostname, dns_domain) except socket.herror: if self.cmdargs.peek: print("{},N/A".format(ipaddr[0])) else: if self.cmdargs.check: self.checklog += "{} hostname not in dns\n".format(ipaddr) print("Hostname not found in DNS for IP:{}".format(ipaddr)) self.subs.custom_printer("verbose", "## Finished processing entry - {} ##".format(ipaddr[0].rstrip())) file.close() if self.cmdargs.check: print("{}".format(self.checklog)) return
class Archivist: def __init__(self, cmdargs, config): # initialize values self.log_array = [] self.cmdargs = cmdargs self.config = config self.subs = SubRoutines(cmdargs, config) self.config.logpath = os.path.join( os.path.expanduser(self.config.logpath), "logs", "UpgradeCheck", datetime.date.today().strftime('%Y%m%d')) def basic_maintenance(self, maxfiles): # self.subs.verbose_printer("##### Cleaning up backup files #####") #Remove oldest files (listed first on windows filelist = os.listdir( os.path.join(self.subs.log_path, "activitycheck", "backups")) if len(filelist) > 0 and len(filelist) > maxfiles: # self.subs.verbose_printer("##### unsorted list:{} #####".format(filelist)) sortedfilelist = sorted(filelist) # self.subs.verbose_printer("##### sorted list:{} #####".format(testlist)) filestoremove = sortedfilelist[0:(len(filelist) - maxfiles)] self.subs.custom_printer( "verbose", "total files:{}\nremoving files:{}".format( len(filelist), len(filestoremove))) for file in filestoremove: if file.endswith("-SwitchStatus.Backup.zip"): # process try: self.subs.verbose_printer( "##### File to remove:{} #####".format(file)) if 'check' in self.cmdargs and self.cmdargs.check is True: self.subs.custom_printer( "debug", "## DBG - testing, would have removed {} ##". format(file)) else: self.subs.custom_printer( "debug", "## Removing file {} ##".format(file)) os.remove( os.path.join(self.subs.log_path, "activitycheck", "backups", file)) except Exception as err: # currently a catch all to stop linux from having a conniption when reloading print("FILE ERROR {}:{}".format(file, err.args[0])) else: self.subs.verbose_printer( "total files:{} are less than max value:{}".format( len(filelist), maxfiles)) def basic_archival(self): try: working_folder = os.path.join(self.subs.log_path, "activitycheck", "rawfiles", "legacy") zipfile_name = os.path.join( self.subs.log_path, "activitycheck", "backups", "{}-SwitchStatus.Backup.zip".format( datetime.datetime.now().strftime("%Y%m%d%H%M"))) files = os.listdir(working_folder) files_py = files # zipfile_name = "SwitchStatus Backup {}.zip".format(datetime.datetime.now().strftime("%Y%m%d%H%M")) #check for existance of the directory (if a first run) if not os.path.exists( os.path.join(self.subs.log_path, "activitycheck", "backups")): self.subs.custom_printer( "debug", "## DBG - Creating activitycheck/backups directory ##") os.makedirs( os.path.join(self.subs.log_path, "activitycheck", "backups")) ZipFile = zipfile.ZipFile(zipfile_name, "a") self.subs.custom_printer( "debug", "## DBG - adding files to backup zipfile:{} ##".format( zipfile_name)) for a in files_py: full_file_path = os.path.join(working_folder, a) # ZipFile.write(full_file_path, compress_type=zipfile.ZIP_DEFLATED) ZipFile.write(full_file_path, a, compress_type=zipfile.ZIP_DEFLATED) ZipFile.close() self.subs.custom_printer("debug", "## DBG - zipfile backup created ##") if 'email' in self.cmdargs and self.cmdargs.email is not None: msg_subject = "SwitchStatus Backup {}".format( datetime.date.today().strftime('%Y-%m-%d')) body = "Attached is the Legacy Backup files" self.subs.custom_printer("debug", "## DBG - sending email ##") self.subs.email_with_attachment(msg_subject, self.cmdargs.email, body, zipfile_name) if 'remove' in self.cmdargs and self.cmdargs.remove: if os.path.exists("{}".format(zipfile_name)): os.remove("{}".format(zipfile_name)) self.subs.custom_printer( "debug", "## DBG - zipfile {} removed ##".format(zipfile_name)) else: print("The file does not exist") if 'maintenance' in self.cmdargs and self.cmdargs.maintenance is not None: try: self.basic_maintenance(int(self.cmdargs.maintenance)) except ValueError: self.subs.custom_printer( "debug", "## DBG - maintenance({}) is not a number. maintenance not performed ##" .format(self.cmdargs.maintenance)) except Exception as err: print(err) def test(self): try: # write a file foo.txt pass # repo = Repo(self.rorepo.working_tree_dir) # assert not repo.bare except Exception as err: print(err)
class Test: def __init__(self, cmdargs, config): # initialize values self.log_array = [] self.cmdargs = cmdargs self.config = config self.subs = SubRoutines(cmdargs, config) self.log_path = os.path.abspath( os.path.join(os.sep, 'var', 'log', 'dnmt')) urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning ) #Supress the ssl unverified notification # self.config.logpath = os.path.join(os.path.expanduser(self.config.logpath), "logs", "UpgradeCheck", # datetime.date.today().strftime('%Y%m%d')) def error_check(self): error_dict = {"ip": self.cmdargs.ipaddr} intId = self.subs.snmp_get_interface_id(self.cmdargs.ipaddr, self.cmdargs.interface) self.subs.verbose_printer("interface ID:{}".format(intId)) error_dict["input errors"] = self.subs.snmp_get_input_errors_by_id( self.cmdargs.ipaddr, intId) error_dict["output errors"] = self.subs.snmp_get_output_errors_by_id( self.cmdargs.ipaddr, intId) error_dict["crc errors"] = self.subs.snmp_get_crc_errors_by_id( self.cmdargs.ipaddr, intId) for entry in error_dict: print("{}:{}".format(entry, error_dict[entry])) def command_blaster_begin(self): #Make Command List commandlist = [] file = open(self.cmdargs.commandfile, "r") for ip in file: commandlist.append(ip.rstrip()) file.close() #Iterate through addresses List if 'single' in self.cmdargs and self.cmdargs.single: vendor = self.subs.snmp_get_vendor_string( self.cmdargs.ipaddrfile.rstrip()) if vendor == "Cisco": device_type = "cisco_ios" elif vendor == "HP": device_type = "hp_procurve" else: device_type = "generic_termserver" self.Command_Blast(self.cmdargs.ipaddrfile.rstrip(), device_type, self.config.username, self.config.password, self.config.enable_pw, 22, commandlist) # self.Command_Blast(self.cmdargs.ipaddrfile, commandlist) else: file = open(self.cmdargs.ipaddrfile, "r") ##########Begin # summary_list = [] if 'manual' in self.cmdargs and self.cmdargs.manual: row_titles = next(file).split( ',' ) # grab the first row (the titles) use these to make the standardize switch call dynamic row_titles[len(row_titles) - 1] = row_titles[ len(row_titles) - 1].rstrip() # remove the trailing newline ############END for ip in file: #TODO replace the manual flag with a split length check to see if there are multiple fields if ('manual' in self.cmdargs and self.cmdargs.manual and len(row_titles) == 6): # {IP][Vendor][UN][PW][EN][PORT.split] ip_entry = ip.split(',') if (len(ip_entry) == len(row_titles)): ip_entry[len(ip_entry) - 1] = ip_entry[len(ip_entry) - 1].rstrip() self.Command_Blast(ip_entry[row_titles.index("ip")], ip_entry[row_titles.index("type")], ip_entry[row_titles.index("user")], ip_entry[row_titles.index("pass")], ip_entry[row_titles.index("en")], ip_entry[row_titles.index("port")], commandlist) elif 'manual' in self.cmdargs and not self.cmdargs.manual: try: vendor = self.subs.snmp_get_vendor_string(ip.rstrip()) if vendor == "Cisco": device_type = "cisco_ios" elif vendor == "HP": device_type = "hp_procurve" else: device_type = "generic_termserver" self.Command_Blast(ip.rstrip(), device_type, self.config.username, self.config.password, self.config.enable_pw, 22, commandlist) except Exception as err: print(err) # ############# # self.Command_Blast(ip.rstrip(), commandlist) file.close() def Command_Blast(self, ipaddr, vendor, username, password, enable_pw, port, commandlist): # SSH Connection try: # net_connect = self.subs.create_connection(ipaddr) # net_connect = ConnectHandler(**cisco_sw) if "hp_procurve_telnet" in vendor: net_connect = self.subs.create_connection_manual( ipaddr, vendor, username, password, enable_pw, port, "sername", "assword") else: net_connect = self.subs.create_connection_custom( ipaddr, vendor, username, password, enable_pw, port) if net_connect: ### ADD ERROR HANDLING FOR FAILED CONNECTION print("-------- CONNECTED TO {} --------".format(ipaddr)) if 'enable' in self.cmdargs and self.cmdargs.enable: if 'manual' in self.cmdargs and self.cmdargs.manual: enable_success = self.subs.vendor_enable_manual( vendor, net_connect, username, password, enable_pw) else: enable_success = self.subs.vendor_enable( vendor, net_connect) # test = net_connect.find_prompt() for command in commandlist: if 'timing' in self.cmdargs and self.cmdargs.timing: result = net_connect.send_command_timing(command) else: result = net_connect.send_command(command) print("COMMAND:{}\nRESPONSE:{}".format(command, result)) if 'write' in self.cmdargs and self.cmdargs.write: net_connect.save_config() self.subs.custom_printer( "debug", "## DBG - {} config saved ##".format(ipaddr)) net_connect.disconnect() self.subs.custom_printer( "debug", "## DBG - {} disconnected ##".format(ipaddr)) print( "-------- CLOSED CONNECTION TO {} --------".format(ipaddr)) else: print("-------- FAILED TO CONNECTED TO {} --------".format( ipaddr)) except netmiko.ssh_exception.NetMikoAuthenticationException as err: self.subs.verbose_printer(err.args[0], "Netmiko Authentication Failure") except netmiko.ssh_exception.NetMikoTimeoutException as err: self.subs.verbose_printer(err.args[0], "Netmiko Timeout Failure") except ValueError as err: print(err.args[0]) except Exception as err: # currently a catch all to stop linux from having a conniption when reloading print("NETMIKO ERROR {}:{}".format(ipaddr, err.args[0])) def bad_phone_search_begin(self): iplist = [] file = open(self.cmdargs.file, "r") for ip in file: if len(ip.rstrip()) > 0: iplist.append(ip.rstrip()) else: self.subs.custom_printer( "debug", "## DBG - Creating activitycheck/processedfiles directory ##" ) file.close() for ip in iplist: self.BadPhoneFinder(ip) def BadPhoneFinder(self, ipaddr): try: # test = self.subs.snmp_get_mac_table_bulk(self.cmdargs.ipaddr) # test1 = self.subs.snmp_get_switch_data_full(self.cmdargs.ipaddr) net_connect = self.subs.create_connection(ipaddr) if net_connect: sw_dict = {"ip": ipaddr} sw_dict["int_return"] = net_connect.send_command( 'show power inline | include Ieee') sw_dict["int_list"] = re.findall('(?:\s*)(\S+)(?:\s+.*)', sw_dict["int_return"], re.VERBOSE | re.MULTILINE) if len(sw_dict["int_list"]) != 0: print("{} --- {} Ieee interfaces found".format( sw_dict["ip"], len(sw_dict["int_list"]))) for interface in sw_dict["int_list"]: int_status = net_connect.send_command( 'show int {}'.format(interface)).split("\n")[0] if "notconnect" in int_status: if 'skip' in self.cmdargs and not self.cmdargs.skip: response = input( "{} --- {} is showing NotConnected, toggle port on/off ('yes'):" .format(sw_dict["ip"], interface)) if not response == 'yes': self.subs.verbose_printer( 'Did not proceed with change.') sys.exit(1) self.subs.snmp_reset_interface( ipaddr, self.subs.snmp_get_interface_id( ipaddr, interface)) print("{} --- {} interface restarted".format( sw_dict["ip"], interface)) else: print("{} --- {} Port is showing connected".format( sw_dict["ip"], interface)) else: print("{} --- No Ieee entries found".format(sw_dict["ip"])) net_connect.disconnect() # netmiko connection error handling except netmiko.ssh_exception.NetMikoAuthenticationException as err: self.subs.verbose_printer(err.args[0], "Netmiko Authentication Failure") except netmiko.ssh_exception.NetMikoTimeoutException as err: self.subs.verbose_printer(err.args[0], "Netmiko Timeout Failure") except ValueError as err: print(err.args[0]) except Exception as err: #currently a catch all to stop linux from having a conniption when reloading print("NETMIKO ERROR {}:{}".format(ipaddr, err.args[0])) def batch_command_wrapper(self): file = open(self.cmdargs.file, "r") for command in file: self.subs.custom_printer( "verbose", "### running command:{} ### ".format(command.rstrip())) Return_val = subprocess.run(command, shell=True) self.subs.custom_printer( "verbose", "### return :{} ### ".format(command.rstrip(), Return_val)) file.close() def connection_count_begin(self): #Iterate through addresses List file = open(self.cmdargs.file, "r") for ip in file: self.connectcount(ip.rstrip()) file.close() def connectcount(self, ipaddr): try: # test = self.subs.snmp_get_mac_table_bulk(self.cmdargs.ipaddr) # test1 = self.subs.snmp_get_switch_data_full(self.cmdargs.ipaddr) net_connect = self.subs.create_connection(ipaddr) if net_connect: # Show Interface Status # output = net_connect.send_command('show mac address-table ') net_connect.send_command('term shell 0') #before_swcheck_dict = {"ip": ipaddr} intlist = [] desclist = [] vlanlist = [] tempvar = net_connect.send_command( 'show int | include thernet|Last input') lastvar = "" for line in tempvar.splitlines(): portnum = self.subs.regex_parser_var0( r"Ethernet([0-9]/\d{1,2})", line) if portnum is not None: lastvar = portnum elif lastvar != "": innertemp = self.subs.regex_parser_varx( r"Last input (\S+),\s+output (\S+),", line) if innertemp is not None: pass intlist.append( (lastvar, innertemp[0], innertemp[1])) lastvar = "" # if (len(lastvar) == 2): #verify that return isn't borked, should get 3 length tuple # before_swcheck_dict[lastvar] = "test"\ tempvar = net_connect.send_command('show int desc') for line in tempvar.splitlines(): interface = self.subs.regex_parser_var0( r"^\S+(\d/\d{1,2})", line) if interface is not None: description = self.subs.regex_parser_var0( r"^\S+\d/\d{1,2}\s+(?:up|down)\s+(?:up|down)\s+(.+)", line) desclist.append((interface, description)) # if description is not "" and description is not None: # description = description.rstrip() tempvar = net_connect.send_command('show int status') for line in tempvar.splitlines(): interface = self.subs.regex_parser_var0( r"^\S+(\d/\d{1,2})", line) if interface is not None: # description = self.subs.regex_parser_var0(r"^\S+\d/\d{1,2}\s+(.+)(?:connected|notconnect)", line) # if description is not "" and description is not None: # description = description.rstrip() vlan = self.subs.regex_parser_var0( r"(?:connected|notconnect)\s+(\S+)\s+", line) vlanlist.append((interface, vlan)) net_connect.disconnect() # print("Interface,Last input,Last output") # for line in intlist: # print("{},{},{}".format(line[0],line[1],line[2])) # for line in desclist: # print("{},{},{}".format(line[0], line[1], line[2])) print("descint,intint,label,vlan,lastinput,lastoutput") for descit, intit, vlanit in zip(desclist, intlist, vlanlist): print("{},{},{},{},{},{},{},{}".format( ipaddr, descit[0], intit[0], vlanit[0], vlanit[1], descit[1], intit[1], intit[2])) if descit[0] != intit[0] or descit[0] != vlanit[0]: print( "^^^^^^^^^^^^^^^^^^^^^^^ERROR MISMATCHED INTS^^^^^^^^^^^^" ) # netmiko connection error handling except netmiko.ssh_exception.NetMikoAuthenticationException as err: self.subs.verbose_printer(err.args[0], "Netmiko Authentication Failure") except netmiko.ssh_exception.NetMikoTimeoutException as err: self.subs.verbose_printer(err.args[0], "Netmiko Timeout Failure") except ValueError as err: print(err.args[0]) except Exception as err: # currently a catch all to stop linux from having a conniption when reloading print("NETMIKO ERROR {}:{}".format(ipaddr, err.args[0])) def dell_snmp_Begin(self): #Iterate through addresses List file = open(self.cmdargs.file, "r") for ip in file: self.DellSnmpAdd(ip.rstrip()) file.close() def DellSnmpAdd(self, ipaddr): try: # test = self.subs.snmp_get_mac_table_bulk(self.cmdargs.ipaddr) # test1 = self.subs.snmp_get_switch_data_full(self.cmdargs.ipaddr) print(self.cmdargs.snmpstring) net_connect = self.subs.create_connection_vendor( ipaddr, "dell_force10_ssh") if net_connect: net_connect.enable() result = net_connect.send_command('show run | include snmp') print("#####{} SNMP before #####\n{}".format(ipaddr, result)) config_command = ["snmp-server community ncgwWR0C ro"] result = net_connect.send_config_set(config_command) print("#####{} Progress #####\n{}".format(ipaddr, result)) result = net_connect.send_command('show run | include snmp') print("#####{} SNMP after #####\n{}".format(ipaddr, result)) output = net_connect.send_command_timing('write') if "y/n" in output: output += net_connect.send_command_timing( "y", strip_prompt=False, strip_command=False) print("#####{} Save Progress #####\n{}".format( ipaddr, output)) net_connect.disconnect() # netmiko connection error handling except netmiko.ssh_exception.NetMikoAuthenticationException as err: self.subs.verbose_printer(err.args[0], "Netmiko Authentication Failure") except netmiko.ssh_exception.NetMikoTimeoutException as err: self.subs.verbose_printer(err.args[0], "Netmiko Timeout Failure") except ValueError as err: print(err.args[0]) except Exception as err: #currently a catch all to stop linux from having a conniption when reloading print("NETMIKO ERROR {}:{}".format(ipaddr, err.args[0])) def vlan_namer_begin(self): # Iterate through addresses List if 'apply' in self.cmdargs and self.cmdargs.apply: print("Beginning Apply Vlan Naming Operation") else: print("Beginning Check Vlan Naming Operation") file = open(self.cmdargs.file, "r") for ip in file: try: if self.subs.ping_check(ip): #check if reachable first self.Vlan_Namer(ip.rstrip()) else: print("####{}### ERROR Unable to ping ".format( ip.rstrip())) except Exception as err: print(err) file.close() def Vlan_Namer(self, ipaddr): vendor = self.subs.snmp_get_vendor_string(ipaddr) hostname = self.subs.snmp_get_hostname(ipaddr) hostname_split = hostname.split('-') if len(hostname_split) > 0: building_code = hostname_split[0] else: raise Exception( "##### ERROR - unable to parse building name for {}: #####". format(ipaddr)) current_vlan_list = self.subs.snmp_get_vlan_database(ipaddr, vendor) if len(current_vlan_list) > 0: try: new_vlan_list = self.Ipam_Rest_Get( "DNS_DOMAIN_DUMMY", { "WHERE": "vlmdomain_description like '{}'".format(building_code) }) if new_vlan_list is None: raise Exception( "###{}#### ERROR No entries found for building code:{}" .format(ipaddr, building_code)) #grab new vlan name if in IPAM for vlanEntry in current_vlan_list: vlanEntry["NewName"] = next( (newvlanEntry['vlmvlan_name'] for newvlanEntry in new_vlan_list if newvlanEntry["vlmvlan_vlan_id"] == str( vlanEntry["ID"])), None) if 'apply' in self.cmdargs and self.cmdargs.apply: if vendor == "Cisco": net_connect = self.subs.create_connection_vendor( ipaddr, "cisco_ios") result = net_connect.enable() elif vendor == "HP": net_connect = self.subs.create_connection_vendor( ipaddr, "hp_procurve") result = self.subs.hp_connection_enable( net_connect) #TODO ADD error handling here else: net_connect = self.subs.create_connection(ipaddr) result = net_connect.enable() if net_connect: ### ADD ERROR HANDLING FOR FAILED CONNECTION print( "-------- PROCESSING {} --------".format(ipaddr)) for vlanEntry in current_vlan_list: #This can miss the case where nvram is not if vlanEntry["NewName"] is not None and vlanEntry[ "NewName"] != "": if (vlanEntry["NewName"] == vlanEntry["Name"]): self.subs.custom_printer( "verbose", "###{}### vlan {} is the SAME: {} ". format(ipaddr, vlanEntry["ID"], vlanEntry["Name"])) else: result = net_connect.send_config_set([ "vlan {}".format(vlanEntry["ID"]), "name {}".format(vlanEntry["NewName"]) ]) self.subs.custom_printer( "debug", "###{}### vlan {} change result:{}". format(ipaddr, vlanEntry["ID"], result)) #self.subs.verbose_printer(result) #If the names are too long they won't apply, HP Procurve in ASH reporting a limit of 12 characters print( "###{}### vlan {} changed from {} to {}" .format(ipaddr, vlanEntry["ID"], vlanEntry["Name"], vlanEntry["NewName"])) else: self.subs.custom_printer( "verbose", "###{}### vlan {} not found in IPAM. Old Name: {}" .format(ipaddr, vlanEntry["ID"], vlanEntry["Name"])) result = net_connect.save_config() # self.subs.verbose_printer("###{}### {}".format(ipaddr, result)) net_connect.disconnect() print("-------- FINISHED PROCESSING {} --------\n". format(ipaddr)) else: print("-------- FAILED TO CONNECTED TO {} --------\n". format(ipaddr)) else: #just checking print("-------- CHECKING VLANS ON {} --------".format( ipaddr)) for vlanEntry in current_vlan_list: if vlanEntry["NewName"] is not None and vlanEntry[ "NewName"] != "": if (vlanEntry["NewName"] == vlanEntry["Name"]): self.subs.verbose_printer( "###{}### vlan {} is the SAME: {} ".format( ipaddr, vlanEntry["ID"], vlanEntry["Name"])) else: print( "###{}### vlan {} is DIFFERENT. \nOLD: {} \nNEW: {}" .format(ipaddr, vlanEntry["ID"], vlanEntry["Name"], vlanEntry["NewName"])) else: print( "###{}### vlan {} not found in IPAM. Old Name: {}" .format(ipaddr, vlanEntry["ID"], vlanEntry["Name"])) print("-------- FINISHED CHECKING {} --------\n".format( ipaddr)) except netmiko.ssh_exception.NetMikoAuthenticationException as err: self.subs.verbose_printer(err.args[0], "Netmiko Authentication Failure") except netmiko.ssh_exception.NetMikoTimeoutException as err: self.subs.verbose_printer(err.args[0], "Netmiko Timeout Failure") except ValueError as err: print(err.args[0]) except Exception as err: # currently a catch all to stop linux from having a conniption when reloading print("NETMIKO ERROR {}:{}".format(ipaddr, err.args[0])) def Core_Mapper(self, ipaddr): try: vendor = self.subs.snmp_get_vendor_string(ipaddr) # Get CDP information for ports cdp_list = self.subs.snmp_get_neighbour_bulk(ipaddr, vendor) connected_uplinks = [ cdpEntry for cdpEntry, cdpEntry in enumerate(cdp_list) if "corenet" in cdpEntry["Value"] ] if len(connected_uplinks) > 0: vlan_list = self.subs.snmp_get_vlan_database(ipaddr, vendor) for uplinkEntry in connected_uplinks: uplinkEntry["LocalPort"] = next( (cdpEntry['Value'] for cdpEntry in cdp_list if cdpEntry["Id"] == uplinkEntry['Id'] and cdpEntry["Category"] == 7), None) try: net_connect = self.subs.create_connection( uplinkEntry['Value']) if net_connect: ### ADD ERROR HANDLING FOR FAILED CONNECTION print("-------- CONNECTED TO {} for {} --------". format(uplinkEntry['Value'], ipaddr)) for vlanEntry in vlan_list: result = net_connect.send_command( "show vlan id {} | include active".format( vlanEntry['ID'])) vlanEntry["CoreName"] = self.regex_parser_var0( r"^\d+\s+(\S+)$", result) print(" ID:{} Current Name:{} Core Name:{}".format( vlanEntry["ID"], vlanEntry["Name"], vlanEntry["CoreName"])) net_connect.disconnect() else: print( "-------- FAILED TO CONNECTED TO {} --------". format(ipaddr)) except netmiko.ssh_exception.NetMikoAuthenticationException as err: self.subs.verbose_printer( err.args[0], "Netmiko Authentication Failure") except netmiko.ssh_exception.NetMikoTimeoutException as err: self.subs.verbose_printer(err.args[0], "Netmiko Timeout Failure") except ValueError as err: print(err.args[0]) except Exception as err: # currently a catch all to stop linux from having a conniption when reloading print("NETMIKO ERROR {}:{}".format( ipaddr, err.args[0])) #login to edge switch to get the remote port of the cdp stuff #verify which vlans are actually passed to the edge switch #Log onto connected core now to get names of connected vlans vlan_list = self.subs.snmp_get_vlan_database(ipaddr, vendor) except Exception as err: print(err) pass def Ipam_Rest_Get(self, url, params): # url = "IPAM_DUMMY_URL" # params = {"WHERE":"vlmdomain_description like 'VPL' and vlmvlan_vlan_id = 4031"} # params = {"WHERE": "vlmdomain_description like '{}'".format(buildingcode)} try: response = requests.get(url, params, verify=False, auth=(self.config.ipam_un, self.config.ipam_pw)) #Add error handling test = response.json() if len(test) > 0: return test # vlanName = next((vlanEntry['vlmvlan_name'] for vlanEntry in test if vlanEntry["vlmvlan_vlan_id"] == vlanid ), None) # print("ID:{} NAME:{}".format(vlanid,vlanName)) else: raise Exception('##### ERROR - no return from IPAM: #####') except Exception as err: print(err)
class Mapper: def __init__(self, cmdargs, config): # initialize values self.log_array = [] self.cmdargs = cmdargs self.config = config self.subs = SubRoutines(cmdargs, config) # self.log_path = os.path.abspath(os.path.join(os.sep, 'var', 'log', 'dnmt')) # self.subs.log_path = os.path.abspath(os.path.join(os.sep, 'var', 'log', 'dnmt')) self.successful_switches = [] #used for activity tracking self.failure_switches = [] #used for activity tracking self.mappedEdges = [] self.visitedNeighbours = [] self.pendingNeighbours = [] self.coreFacingNodes = [] self.coreNodes = [] self.graphObject = Graph(format='png') def iterate(self): #TODO change RO to a list of strings and try them all if one fails? # os.environ["PATH"] += os.pathsep + "C:\\Program Files\\Graphviz\\bin\\" # required for testing on PC iplist = [] total_start = time.time() try: file = open(os.path.join(self.cmdargs.filename), "r") self.subs.verbose_printer( "##### file opened:{} #####".format(file)) for ip in file: iplist.append(ip.rstrip()) file.close() for ipaddr in iplist: ipaddr = ipaddr.split( ",") #handle custom ip variables in ipfile if len(ipaddr) > 1: self.cmdargs.customro = ipaddr[1] else: self.cmdargs.customro = None neigh_ip = socket.gethostbyname(ipaddr[0]) if neigh_ip not in self.pendingNeighbours and neigh_ip not in self.visitedNeighbours: self.pendingNeighbours.append(ipaddr[0]) while len(self.pendingNeighbours) > 0: self.checkNeighbours(self.pendingNeighbours.pop()) graphFileName = "Graph-{}".format( datetime.datetime.now().strftime('%Y-%m-%d-%H%M')) self.graphObject.render(graphFileName, view=False, cleanup=True) try: ################## if 'email' in self.cmdargs and self.cmdargs.email is not None: msg_subject = "updated activitycheck - {}".format( datetime.date.today().strftime('%Y-%m-%d')) # body = "Testing email" body = "Processing completed in {} seconds\n".format( int((time.time() - total_start) * 100) / 100) body += "{} switch state files SUCCESSFULLY updated\n".format( len(self.successful_switches)) body += "{} switch state files FAILED to update\n".format( len(self.failure_switches)) body += "\n--------------------------------------------------------------------------------------\n\n" if len(self.successful_switches) > 0: body += "--- List of switch statuses SUCCESSFULLY updated ---\n" for entry in self.successful_switches: body += "{}\n".format(entry) if len(self.failure_switches) > 0: body += "--- List of switch statuses that FAILED to update or found no neighbours ---\n" for entry in self.failure_switches: body += "{}\n".format(entry) self.subs.email_with_attachment( msg_subject, self.cmdargs.email, body, "{}.png".format(graphFileName)) else: print(self.graphObject.source) ####################### except Exception as err: print(err) if 'remove' in self.cmdargs and self.cmdargs.remove: if os.path.exists("{}.png".format(graphFileName)): os.remove("{}.png".format(graphFileName)) else: print("The file does not exist") except FileNotFoundError: print("##### ERROR iplist files not found #####") except Exception as err: print("##### ERROR with processing:{} #####".format(err)) def checkNeighbours(self, ipaddr): #TODO use hostname for the name rather than resolving it? self.subs.custom_printer("debug", "##DEBUG - Processing {} ##".format(ipaddr)) try: node_name = socket.gethostbyaddr(ipaddr) except Exception as err: # if failure in resolving hostname, make it the passed ip print("### ERROR on {} ### {}".format( ipaddr, err, )) node_name = [ipaddr, "", [ipaddr]] # test = self.subs.snmp_get_uptime(ipaddr) vendor = self.subs.snmp_get_vendor_string( ipaddr, ro=self.cmdargs.customro ) #if the flag is not set it will default to set RO #TODO combine get_neighbour results to have type & ip in the same entry for filtering bulkCDPList = self.subs.snmp_get_neighbour_bulk( ipaddr, vendor, ro=self.cmdargs.customro) if len(bulkCDPList) > 0: formattedCDPList = [] for entry in bulkCDPList: if not any(d['Id'] == entry['Id'] for d in formattedCDPList): formattedCDPList.append({"Id": entry["Id"]}) for d in formattedCDPList: if d['Id'] == entry['Id']: d[entry['Category']] = entry['Value'] for port in formattedCDPList: self.subs.custom_printer( "debug", "##DEBUG - {} - port {} ##".format(ipaddr, port)) if 'IP' in port.keys() and (not any( x in port['Type'] for x in ['Phone', 'AIR', 'VG', 'ATA']) ): # ignore phones,APs,VGs try: neigh_node_name = socket.gethostbyaddr(port['IP']) except Exception as err: print("### ERROR on {} ### {} for {}".format( ipaddr, err, port['IP'])) neigh_node_name = [port['Name'], "", [port['IP']] ] # if the host is not found #TODO MAKE filter variables custom instead of hardcoded values if any(x in port['Name'].lower() for x in self.cmdargs.multifilter.split(' ') ) and self.cmdargs.filterstring in port['Name']: neigh_node_name[2][0] = port[ 'Name'] # assign the IP to be the core hostname for checking with mapped edges # if "net.ualberta.ca" in neigh_node_name[0] and all(x not in self.mappedEdges for x in [(node_name[2][0],neigh_node_name[2][0]), (neigh_node_name[2][0],node_name[2][0])]): if all(x not in self.mappedEdges for x in [( node_name[2][0], neigh_node_name[2][0] ), (neigh_node_name[2][0], node_name[2][0] )]): #map all edges (turn off other types like linux?) if any(x in port['Name'].lower() for x in self.cmdargs.multifilter.split(' ') ) and self.cmdargs.filterstring in port['Name']: self.graphObject.edge( "{}({})".format(node_name[0], node_name[2][0]), "{}".format(neigh_node_name[2] [0])) # will add a core edge else: self.graphObject.edge("{}({})".format( node_name[0], node_name[2][0]), "{}({})".format( neigh_node_name[0], neigh_node_name[2] [0])) # will add an edge by name if (port["IP"] not in self.visitedNeighbours and port["IP"] not in self.pendingNeighbours): self.pendingNeighbours.append(port["IP"]) self.mappedEdges.append( (node_name[2][0], neigh_node_name[2][0])) self.successful_switches.append(ipaddr) else: self.failure_switches.append(ipaddr) self.visitedNeighbours.append(ipaddr)