Esempio n. 1
0
 def __init__(self, cmdargs, config):
     # initialize values
     self.log_array = []
     self.cmdargs = cmdargs
     self.config = config
     self.subs = SubRoutines(cmdargs, config)
     self.checklog = ""
Esempio n. 2
0
 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'))
Esempio n. 3
0
 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
Esempio n. 4
0
 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
Esempio n. 5
0
 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')
Esempio n. 6
0
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()
Esempio n. 7
0
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])
Esempio n. 8
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)
Esempio n. 9
0
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
Esempio n. 10
0
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)
Esempio n. 11
0
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)
Esempio n. 12
0
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)