Beispiel #1
0
 def closeWindow(self):
     tmpDbPassword = self.databasePasswordField.text()
     tmpFtpPassword = self.ftpPasswordField.text()
     if checkDatabaseConnection(tmpDbPassword):
         if checkFTPConnection(tmpFtpPassword):
             self.passwordManager.setDatabasePassword(
                 self.databasePasswordField.text())
             self.passwordManager.setFtpPassword(
                 self.ftpPasswordField.text())
             self.passwordsEntered = True
             self.dialog.close()
         else:
             messageWindow(
                 "FTP: Connection Error",
                 "Error raised when connecting to FTP, please check your details and try again",
                 True)
             self.databasePasswordField.setText("")
             self.ftpPasswordField.setText("")
     else:
         messageWindow(
             "Database: Connection Error",
             "Error raised when connecting to Database server, please check your details and try again",
             True)
         self.databasePasswordField.setText("")
         self.ftpPasswordField.setText("")
Beispiel #2
0
    def refreshPage(self):
        try:
            if self.blocked:
                secondaryWindows.messageWindow("Process is currently running", "Cannot refresh page when units are being updated",
                                  False)
            else:
                self.fromConfiguration.addItem("Loading")
                self.toConfiguration.addItem("Loading")
                self.osVersions.addItem("Loading")
                self.clearProgressText()
                self.fromConfiguration.clear()
                self.toConfiguration.clear()
                thread = FileGrabber(self.window)
                thread.setup(self, ".conf",self.ftpPassword)
                thread.trigger.connect(self.fillComboBox)
                thread.start()
                self.threads.append(thread)

                thread = FileGrabber(self.window)
                thread.setup(self, ".tgz",self.ftpPassword)
                thread.trigger.connect(self.fillComboBox)
                thread.start()
                self.threads.append(thread)

                self.initialDevicePassword.setText("")
                self.consolePasswordField.setText("")
                self.willCloneToBackup.setChecked(False)
                self.toPortNo.setText("")
                self.fromPortNo.setText("")
        except Exception as e:
            print(str(e))
            secondaryWindows.messageWindow("Error Refreshing",
                              "An error occured clearing page and connecting to FTP server, try again later", True)
Beispiel #3
0
    def updateDots(self, code):
        try:
            #first clear out layout
            #self.commitDotLayout
            self.dots.clear()
            layout = self.commitDotLayout.layout()
            self.clearLayout(layout)
            self.scrollArea.setWidgetResizable(True)
            if code == 0 and not self.currentFilesHistory == None:  # only deal with conf code from deployment class
                historyList = list(self.currentFilesHistory.keys())
                historyList = self.sortTimeStamps(historyList)
                for index in range(0, len(historyList)):
                    dot = QRadioButton()
                    dot.setText(historyList[index])
                    dot.setStyleSheet("border: 1px solid rgb(96,125,139);")
                    dot.clicked.connect(self.displayFile)
                    layout.insertWidget(0, dot)
                    self.dots.append(dot)

            elif code == 1:  # only deal with conf code from deployment class
                secondaryWindows.messageWindow(
                    "Error",
                    "An error occured pulling down info from the database, check your details and try again",
                    True)
            elif self.currentFilesHistory == None:
                secondaryWindows.messageWindow(
                    "Error",
                    "An error occured pulling down info from the database, check your details and try again",
                    True)

        except Exception as e:
            print(str(e))
Beispiel #4
0
    def refreshPage(self):
        self.canUseCombobox = False
        if self.blocked:
            secondaryWindows.messageWindow("Process is currently running",
                                           "Cannot refresh", False)
        else:
            # clear fields
            self.commitDescription.setText("")
            self.commitTitle.setText("")
            self.whatsRemoved.setText("")
            self.whatsAdded.setText("")
            self.selectedConfig.clear()
            self.openFileButton.setText("Select File")
            self.fileToPush = None
            self.dots.clear()

            layout = self.commitDotLayout.layout()
            self.clearLayout(layout)
            dot = QRadioButton()
            dot.setText("Commits Appear Here")
            dot.setStyleSheet("border: 1px solid rgb(96,125,139);")
            layout.insertWidget(0, dot)
            self.dots.append(dot)

            self.startDatabaseGrabber()

            self.getFileHistory()
Beispiel #5
0
 def finishedPushingToRepo(self, code):
     self.blocked = False
     if code == 0:
         self.refreshPage()
         secondaryWindows.messageWindow(
             "Success!", "Updated the repository successfully", False)
     else:
         secondaryWindows.messageWindow(
             "Error", "Error pushing the files to the repository", False)
Beispiel #6
0
    def checkDatabase(self):
        if self.blocked:
            secondaryWindows.messageWindow("Process Running",
                                           "You're currently runnning an update, wait till this is finished",
                                           True)
            return

        if not checkDatabaseConnection(self.databasePassword):
            secondaryWindows.messageWindow("Database: Connection Error",
                                           "Error raised when connecting to Database, please check your details and try again",
                                           True)
            return

        listing = getDatabaseListing(self.databasePassword)
        if not listing is None:
            secondaryWindows.displayDatabaseWindow(listing)
        elif listing is None:
            secondaryWindows.messageWindow("Database is empty",
                                           "There is no data to pull from your database",
                                           False)
            return
        elif listing is "Error":
            secondaryWindows.messageWindow("Database Error",
                                           "There was an error pulling data from your database",
                                           True)
Beispiel #7
0
 def fillComboBox(self, code):
     self.canUseCombobox = False
     if code == 0 and not self.confFiles == None:  # only deal with conf code from deployment class
         nameList = list(self.confFiles.keys())
         nameList.sort()
         for index in range(len(nameList)):
             self.selectedConfig.addItem(nameList[index])
     elif code == 1:  # only deal with conf code from deployment class
         self.selectedConfig.addItem("None Present")
     elif code == -1:
         secondaryWindows.messageWindow(
             "Error",
             "An error occured pulling down info from the database, check your details and try again",
             True)
     elif self.confFiles == None:
         secondaryWindows.messageWindow(
             "Error",
             "An error occured pulling down info from the database, check your details and try again",
             True)
     self.canUseCombobox = True
Beispiel #8
0
    def updateChanges(self, code):
        if code == 0 and not self.changed is None and not self.removed is None:
            self.whatsAdded.setText("")
            self.whatsRemoved.setText("")

            if len(self.changed) == 0:
                self.whatsAdded.append("Nothing Has Been Added!")

            else:
                for i in range(0, len(self.changed)):
                    self.whatsAdded.append("+ " + self.changed[i])

            if len(self.removed) == 0:
                self.whatsRemoved.append("Nothing Has Been Removed!")
            else:
                for i in range(0, len(self.removed)):
                    self.whatsRemoved.append("- " + self.removed[i])
        elif code == 1:
            secondaryWindows.messageWindow("Error", "Error comparing files",
                                           True)
Beispiel #9
0
    def applySettings(self):
        if self.allSettingsFieldsFilled():
            try:
                #settings are saved in xml file
                settings_file = open("Settings.xml", "w")
                #ensure paths are "legal"
                osPath = self.makeLegalPath(self.ftpOsPath.text())
                confPath = self.makeLegalPath(self.ftpConfPath.text())
                iniconfPath = self.makeLegalPath(self.ftpIniConfPath.text())

                #construct dict to be translated into xml
                dict = {
                    'Settings': {
                        'Ftp-Info': {
                            'ftpServerAddress': self.ftpServerAddress.text(),
                            'ftpUsername': self.ftpUsername.text(),
                            'ftpOsPath': osPath,
                            'ftpConfPath': confPath,
                            'ftpIniConfPath': iniconfPath
                        },
                        'Console-Info': {
                            'consoleAddress': self.consoleAddress.text(),
                            'consoleUsername': self.consoleUsername.text()
                        },
                        'Database-Info': {
                            'databseAddress': self.databseAddress.text(),
                            'databseUsername': self.databseUsername.text()
                        }
                    }
                }
                #convert dict
                xml = xmltodict.unparse(dict, pretty=True)
                #write dict to file
                settings_file.write(xml)
                settings_file.close()
                #alert user to success
                if self.window.notSetup:
                    heading = "Settings Saved! Restarting in 3...."
                    message = "Your Settings are saved, The programme will restart and reload the changes"
                    self.restart = True
                else:
                    heading = "Settings Saved!"
                    message = "Your Settings are saved"
                secondaryWindows.messageWindow(heading, message, False)
                if self.window.notSetup:
                    time.sleep(3)
                    self.window.close()
                else:
                    self.window.initialiseLauncher()

            #catch any exceptions when writing to file and cope gracefully
            except Exception as e:
                secondaryWindows.messageWindow(
                    "An Error Occured",
                    "There was an error saving your settings the details are as follows: \n "
                    + str(e), True)
        else:
            secondaryWindows.messageWindow(
                "Empty Fields", "Please fill in all fields provided", True)
Beispiel #10
0
 def openExplorer(self):
     try:
         #path returned as tuple though we just want the actual path
         name, _ = QFileDialog.getOpenFileName(
             self.window,
             'Open File',
             options=QFileDialog.DontUseNativeDialog)
         if len(name) < 1:
             return
         start = self.findLast(name, "/") + 1
         filename = name[start:]
         extension = filename[len(filename) - 5:]
         if not ".conf" == extension:
             secondaryWindows.messageWindow(
                 "Not a configuration file",
                 "Please select a configuration file to push", False)
             return
         self.openFileButton.setText(name[start:])
         self.fileToPush = name
     except Exception:
         secondaryWindows.messageWindow(
             "Error", "Error parsing file, please ensure "
             "it's a .conf file with a suitable filename", True)
Beispiel #11
0
 def displayFile(self):
     try:
         if not self.currentFilesHistory is None:
             timestampText = ""
             for i in range(len(self.dots)):
                 if self.dots[i].isChecked():
                     timestampText = self.dots[i].text()
             if not "Commit" in timestampText:
                 if not self.fileToPush is None:
                     path = self.currentFilesHistory[timestampText]
                     self.fileToPull = path
                     # thread to compare files
                     thread = FileComparer(self.window)
                     thread.setup(self)
                     thread.trigger.connect(self.updateChanges)
                     thread.start()
                 else:
                     secondaryWindows.messageWindow(
                         "Select File",
                         "Please select a file first to compare them",
                         False)
     except Exception as e:
         print(str(e))
Beispiel #12
0
    def startPush(self):
        if not self.blocked:
            if self.fileToPush is None:
                secondaryWindows.messageWindow("No File Selected",
                                               "Please select a file to push",
                                               False)
                return
            elif len(self.commitTitle.text()) < 1:
                secondaryWindows.messageWindow(
                    "No Commit Title", "Please enter a title for your commit",
                    False)
                return
            elif len(self.commitDescription.toPlainText()) < 1:
                secondaryWindows.messageWindow(
                    "No Commit description",
                    "Please enter a description for your commit", False)
                return

            selectedTimeline = self.selectedConfig.currentText()

            #see if they want to commit to that files timeline
            reply = QMessageBox.question(
                self.window, 'Confirmation',
                "Are you sure you want to push to " + selectedTimeline +
                "'s timeline?", QMessageBox.Yes, QMessageBox.No)
            if reply == QMessageBox.Yes:
                self.blocked = True
                thread = RepoInterface(self.window)
                thread.setup(self)
                thread.trigger.connect(self.finishedPushingToRepo)
                thread.start()
            else:
                return
        else:
            secondaryWindows.messageWindow(
                "Process is currently running",
                "There is still a file being pushed", False)
Beispiel #13
0
def addToRepo(callingWindow):

    #Set variable values
    dbAddress = getDatabaseAddress()
    db = getDatabase()
    configTable = getDatabaseTable()
    dbUsername = getDatabaseUsername()
    dbPassword = callingWindow.databasePassword
    ftpUsername = getFtpUsername()
    ftpPassword = callingWindow.ftpPassword
    configName = callingWindow.selectedConfig.currentText()
    deviceSerial = ""
    configFile = callingWindow.fileToPush
    commitTitle = callingWindow.commitTitle.text()
    commitDesc = callingWindow.commitDescription.toPlainText()
    time = datetime.utcnow().strftime('%d-%m-%Y %H:%M:%S.%f')[:-4]
    newFileName = time.replace(":", "-")[:-3]
    newFileName = newFileName.replace(" ", "_") + ".conf"

    # Get current Config details
    getSerial = ("select serial from " + configTable + " where name=\"" +
                 configName + "\" and isPrimary=\"1\"")
    try:
        conn = None

        conn = pymysql.connect(host=dbAddress,
                               port=3306,
                               user=dbUsername,
                               passwd=dbPassword,
                               db=db)
        cursor = conn.cursor()
        cursor.execute(getSerial)
        deviceSerial = cursor.fetchone()[0]
        conn.close()
    except Exception as e:
        print("Serial couldn't be recovered." + str(e))
        if not conn is None:
            conn.close()

    #Upload file to the FTP Server
    ftpAddress = getFtpAddress()
    path = getConfPath()
    fileContents = ""
    try:
        conn = None
        ftp = None

        #chck if conf file
        if not "conf" in configFile:
            messageWindow("Error!",
                          "Make sure that you are uploading a .conf file,",
                          True)
            return False
        else:
            # Log into FTP
            ftp = FTP(ftpAddress)
            ftp.login(ftpUsername, ftpPassword)
            ftp.cwd(path)
            #Upload the file
            file = open(configFile, "rb")
            ftp.storlines('STOR ' + newFileName, file)
            ftp.close()
            file.close()

            # Get current config info
            updateCurentRecord = ("update " + configTable + " set " +
                                  "isPrimary=\"0\"" + " where name=\"" +
                                  configName + "\" and isPrimary=\"1\"")

            # Send new config details
            newFileNamePath = path + newFileName
            addNewRecord = (
                "insert into " + configTable +
                "(name,serial,user,timestamp,path,title,description,isprimary)"
                + " values (\"" + configName + "\", \"" + deviceSerial +
                "\",\"" + dbUsername + "\",\"" + time + "\",\"" +
                newFileNamePath + "\", \"" + commitTitle + "\", \"" +
                commitDesc + "\", 1)")

            # Push the data to the database

            conn = pymysql.connect(host=dbAddress,
                                   port=3306,
                                   user=dbUsername,
                                   passwd=dbPassword,
                                   db=db)
            cursor = conn.cursor()
            cursor.execute(updateCurentRecord)
            cursor.execute(addNewRecord)
            conn.commit()
            conn.close()
            return True

    except Exception as e:
        print(str(e))
        if not conn is None:
            conn.close()
        if not ftp is None:
            ftp.close()
        return False
Beispiel #14
0
    def compareFiles(self):
        if self.canUseCombobox:
            self.getContentsOfFile(
            )  # first get the contents of the selected file
            if self.fileToPush is None:
                secondaryWindows.messageWindow(
                    "No local file selected",
                    "Need a local file to compare against", False)
                return
            else:
                try:
                    '''
                    every line that changes means another has been removed
                    we go through both files and compare them, keeping track
                    of line numbers as we go for readibility
                    '''
                    changed = []
                    removed = []
                    currentFile = self.pulledFilesContents.split("\n")
                    newFile = self.fileToPush
                    lineCount = 1
                    with open(newFile, 'r', encoding='utf-8') as f:
                        for line in f:
                            line = line.strip("\n")
                            line = line.replace("\\\\", "")
                            if len(currentFile) > 1:
                                for i in range(0, len(currentFile)):
                                    if not line == currentFile[i]:
                                        changed.append("@" + str(lineCount) +
                                                       ": " + line)
                                        removed.append("@" + str(lineCount) +
                                                       ": " + currentFile[i])
                                        del currentFile[i]
                                        break
                                    else:
                                        del currentFile[i]
                                        break
                            else:
                                changed.append("@" + str(lineCount) + ": " +
                                               line)
                            lineCount += 1

                    if len(currentFile) > 1:
                        for i in range(0, len(currentFile)):
                            removed.append("@" + str(lineCount) + ": " +
                                           currentFile[i])
                            lineCount += 1

                    # go through and make sure it's not just moved to another line
                    if len(changed) > 1 and len(removed) > 1:
                        i = 0
                        while i < len(changed):
                            line = changed[i]
                            if len(line) > 1:
                                start = line.index(":")
                                line = line[start + 2:]
                            for j in range(0, len(removed)):
                                if line in removed[j]:
                                    del changed[i]
                                    del removed[j]
                                    i -= 1
                                    break
                            i += 1

                    self.changed = changed
                    self.removed = removed
                except Exception as e:
                    print(str(e))
Beispiel #15
0
    def connect_session(self, portNo, ftpPassword,consolePassword, databasePassword,devicePassword ,OsFile, configFile, willClone, updateGui):
        try:
            # Get values from user input
            ftpAddress = getFtpAddress()
            osFile = getOsPath() + OsFile
            confPath = getIniConfPath() + configFile
            username = getConsoleName() + ":" + str(portNo)
            hostname = getConsoleAddress()

            # Connect to the console server
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            ssh.connect(hostname, 22, username, consolePassword)
            term = ssh.invoke_shell()

            # Log into the device
            if updateGui:
                self.trigger.emit(11)
            waitForTerm(term, 60, "login:"******"set cli screen-length 0")

            # Get device serial number
            originalVersion = send_command(term, "show system software")
            xml = send_command(term, "show chassis hardware | display xml")
            serialNo = parse_xml_serial(xml)

            # Push serial number to the database
            updatedTime = pushSerial(getDatabaseAddress(), getDatabaseUsername(), databasePassword,getDatabase(), configFile, serialNo, confPath)
            if updateGui:
                self.trigger.emit(44)

            # Upgrade JUNOS
            ftpDetails = getFtpUsername() + ":" + ftpPassword + "@" + ftpAddress
            upgradeOs = "request system software add ftp://" + ftpDetails + osFile + " no-copy no-validate reboot"
            send_command(term, upgradeOs)

            # Wait for the device to reboot
            if updateGui:
                self.trigger.emit(55)
            print("upgrading")
            waitForTerm(term, 180, "login:"******"finished")
            waitForLogin(term,devicePassword)
            if updateGui:
                self.trigger.emit(66)
            waitForTerm(term, 2, "root")
            send_command(term, "set cli screen-length 0")

            # Snapshot to the backup partition
            if willClone:
                send_command(term, "request system snapshot media internal slice alternate")
            time.sleep(15)
            waitForTerm(term, 60, "root")

            # Check the version of JUNOS
            updatedVersion = send_command(term, "show system software")
            if updateGui:
                self.trigger.emit(77)

            # Start applying a configuration to the device
            if not updatedVersion == originalVersion:
                send_command(term, "configure")
                time.sleep(2)
                send_command(term, "delete")
                time.sleep(2)
                send_command(term, "yes")
                time.sleep(2)
                # Get the configuration file from the FTP Server
                send_command(term, "load set ftp://" + ftpAddress + confPath)
                time.sleep(2)
                xml = send_command(term, "show snmp location | display xml")
                time.sleep(2)

                # Get device deployment location (rollNo)
                rollNo = ""
                try:
                    xml = xml.split("<rpc-reply")[1]
                    xml = "<rpc-reply" + xml
                    xml = xml.split("</rpc-reply>")[0]
                    xml += "</rpc-reply>"
                    xmlDict = xmltodict.parse(xml)
                    rollNo = xmlDict['rpc-reply']['configuration']['snmp']['location']
                except:
                    print ("No location data.")
                time.sleep(5)

                # Push roll number (deployment location) to the database
                pushRollNo(getDatabaseAddress(), getDatabaseUsername(), databasePassword,getDatabase(),rollNo, updatedTime)
                time.sleep(5)

                #Set device root password
                send_command(term,"set system root-authentication plain-text-password")
                send_command(term,devicePassword)
                send_command(term,devicePassword) #confirm password
                time.sleep(2)

                #Commit the current configuration
                send_command(term, "commit and-quit")
                waitForTerm(term, 60, "root@")
                send_command(term, "request system autorecovery state save")
                time.sleep(30)
                send_command(term, "request system configuration rescue save")
                time.sleep(30)

                # Update the progress bar
                if updateGui:
                    self.trigger.emit(88)

                # Reboot the device
                send_command(term, "request system reboot")
                time.sleep(2)
                send_command(term, "yes")

                #Wait for the device to boot
                waitForTerm(term, 180, "login:"******"root")
                xml = send_command(term, "show configuration snmp location | display xml")
                time.sleep(5)

                # Get device deployment location (rollNo) - in order to perform a final check
                checkRollNo=""
                try:
                    xml = xml.split("<rpc-reply")[1]
                    xml = "<rpc-reply" + xml
                    xml = xml.split("</rpc-reply>")[0]
                    xml += "</rpc-reply>"
                    xmlDict = xmltodict.parse(xml)
                    checkRollNo = xmlDict['rpc-reply']['configuration']['snmp']['location']
                except:
                    print("No location data.")

                if rollNo == checkRollNo:
                    print("Deployment successful.")
                    send_command(term, "request system halt in 0")
                    time.sleep(2)
                    send_command(term, "yes")

                if updateGui:
                    self.trigger.emit(100)
            else:
                print("OS wasn't updated correctly, Not applying config, Shutting down")

        except paramiko.ssh_exception.BadHostKeyException:
            secondaryWindows.messageWindow("Host Key Error!", "Server’s host key could not be verified", True)
        except paramiko.ssh_exception.AuthenticationException:
            secondaryWindows.messageWindow("Authentication Error!", "Authentication failed, Check your details and try again", True)
        except paramiko.ssh_exception.SSHException:
            secondaryWindows.messageWindow("Unknown Error!", "Unknown error connecting or establishing an SSH session", True)
        except socket.gaierror as e:
            print(str(e))
Beispiel #16
0
    def beginDeployment(self):
        try:
            # if the window is pressed twice
            if self.blocked:
                secondaryWindows.messageWindow("Process running.", "Please wait for deployment to finish.", True)
                return
            self.threads.clear()
            # Make sure fields aren't empty
            if self.fieldsEmpty():
                secondaryWindows.messageWindow("Empty Fields", "Please ensure all the fields are filled", True)
                return
            # Make sure both port numbers are actually numbers
            if (not isNumber(self.toPortNo.text()) or not isNumber(self.fromPortNo.text())):
                secondaryWindows.messageWindow("Not a Number", "Please ensure ports are numbers", True)
                return

            # make sure configurations are the same amount as devices being updated
            fromConf = self.fromConfiguration.currentIndex()
            toConf = self.toConfiguration.currentIndex()
            fromPort = int(self.fromPortNo.text())
            toPort = int(self.toPortNo.text())
            if not (toConf >= fromConf):
                secondaryWindows.messageWindow("Config List Error",
                                               "Please ensure your starting configuration is before your final configuration",
                                               True)
                return
            if not ((toConf - fromConf) + 1 == (toPort - fromPort) + 1):
                secondaryWindows.messageWindow("Not Enough Configs",
                                               "Please ensure there are enough config files for each specified device",
                                               True)
                return

            devicePassword = self.initialDevicePassword.text()
            if not self.checkValidity(devicePassword):
                secondaryWindows.messageWindow("Password error",
                                               """
                                               Please ensure the password is at least 6 characters and contains
                                               either a number or an uppercase letter
                                               """,
                                               True)
                return

            # apply patch
            patch_crypto_be_discovery()
            configurationsToUse = []
            for index in range(fromConf, toConf + 1):
                configurationsToUse.append(self.confFiles[index])

            willBackup = self.willCloneToBackup.isChecked()
            OsFile = self.osVersions.currentText()
            ftpPassword = self.ftpPassword
            consolePassword = self.consolePasswordField.text()
            databasePassword = self.databasePassword
            self.progressBar.setValue(0)

            # check if connections are accessible
            if not checkFTPConnection(ftpPassword):
                secondaryWindows.messageWindow("FTP: Connection Error",
                                               "Error raised when connecting to FTP server, please check your details and try again",
                                               True)
                return

            if not checkConsoleConnection(getConsoleAddress(), getConsoleName(), consolePassword):
                secondaryWindows.messageWindow("Console Server: Connection Error",
                                               "Error raised when connecting to Console server, please check your details and try again",
                                               True)
                return

            if not checkDatabaseConnection(databasePassword):
                secondaryWindows.messageWindow("Database: Connection Error",
                                               "Error raised when connecting to Database, please check your details and try again",
                                               True)
                return

            self.blocked = True

            confIndex = 0

            # check to see how many devices we're updating
            if toPort - fromPort + 1 == 1:
                thread = Updater(self.window)
                thread.trigger.connect(self.updateProgress)
                thread.setup(toPort, ftpPassword, consolePassword, databasePassword, devicePassword,OsFile, configurationsToUse[confIndex],
                             willBackup,
                             True)
                thread.start()
                self.threads.append(thread)

            else:
                for index in range(fromPort, toPort):
                    thread = Updater(self.window)
                    thread.trigger.connect(self.updateProgress)
                    thread.setup(index, ftpPassword, consolePassword, databasePassword, devicePassword, OsFile, configurationsToUse[confIndex],
                                 willBackup,
                                 False)
                    thread.start()
                    self.threads.append(thread)
                    confIndex += 1
                    time.sleep(5)  # staggered threads to avoid collision

                # make final thread the one to update GUI
                thread = Updater(self.window)
                thread.trigger.connect(self.updateProgress)
                thread.setup(toPort, ftpPassword, consolePassword, databasePassword, devicePassword, OsFile, configurationsToUse[confIndex],
                             willBackup,
                             True)
                thread.start()
                self.threads.append(thread)
        except Exception as e:
            print(str(e))