def setupGlobals(self): #Scene file should be first sys.argv try: self.scene = sys.argv[1] self.scene = self.scene.replace('\\', '/') except IndexError: self.scene = "" #Get the -flag args try: opts = getopt.getopt(sys.argv[2:], "s:e:n:p:l:x:m:d:c:q:t:")[0] except getopt.GetoptError: logger.error("Bad Opt!") aboutBox(self, "Bad Opt!", "One of the command line options you entered was invalid.\n"+ "\nPlease remove any unkown opts and try again.") sys.exit(2) #Defaults defName = self.scene.split("/")[-1] self.settingsDict = {"-s":101, #Start Frame (Int) "-e":101, #End Frame (Int) "-n":defName, #Nice Name (Str) "-p":"", #Proj (Str) "-l":"", #Render Layers (Str,Sep,By,Comma) "-x":"", #Executabe (Str) "-m":"", #CMD (Str) "-d":"", #RenderDirectory (Str) "-c":"", #Compatabilities (Str,Sep,By,Comma) "-q":"", #Project Name (Str) "-t":"", #Job Type (Str) } #Apply the -flag args optsDict = dict(opts) keys = list(optsDict.keys()) for key in keys: self.settingsDict[key] = optsDict[key] logger.debug("Setting Key '%s' with opt: '%s'", key, str(optsDict[key])) #Fix paths self.settingsDict["-p"] = self.settingsDict["-p"].replace('\\', '/') #Fix Compatabilities self.settingsDict["-c"] = self.settingsDict["-c"].split(",") #Add underscores to niceName self.settingsDict["-n"] = self.settingsDict["-n"].replace(" ", "_") #Move RenderDir to Base CMD if self.settingsDict["-d"] != "": self.settingsDict["-d"] = self.settingsDict["-d"].replace('\\', '/') self.settingsDict["-m"] += " -rd \"{0}\"".format(self.settingsDict["-d"])
def __init__(self): QMainWindow.__init__(self) self.setupUi(self) with open(Utils.findResource("styleSheet.css"), "r") as myStyles: self.setStyleSheet(myStyles.read()) self.thisNode = NodeUtils.getThisNodeOBJ() self.isVisable = True self.pulseThreadStatus = False self.renderServerStatus = False self.schedThreadStatus = False self.autoUpdateStatus = False if not self.thisNode: self.offlineButton.setEnabled(False) self.getoffButton.setEnabled(False) logger.error("Node does not exist in database!") aboutBox(self, "Error", "This node was not found in the database! If you wish to render " "on this node it must be registered with the databse. Run " "Register.exe or Register.py to regiester this node and " " try again.") sys.exit(1) self.currentSchedule = self.thisNode.weekSchedule self.currentScheduleEnabled = self.thisNode.scheduleEnabled self.buildUI() self.connectButtons() self.updateThisNodeInfo() self.startupServers() logger.info("Render Node Main is live! Waiting for tasks...") try: autoHide = True if str(sys.argv[1]).lower() == "true" else False logger.info(autoHide) except IndexError: autoHide = False if autoHide and self.trayIconBool: logger.info("Autohide is enabled!") self.sendToTrayHandler() else: self.show()
def loginButtonHandler(self): self.db_username = str(self.user.text()) self._db_password = str(self.password.text()) if self.remoteAccess.isChecked(): #self.host = "REMOTE" pass try: MySQLdb.connect(host=self.host, user=self.db_username, passwd=self._db_password, db=self.databaseName, port=self.port) self.loginSuccess = True self.close() except MySQLdb.Error: logger.error("Could not login!") aboutBox(self, "Could Not Login", "Invalid username/password or server is down...")
def buildUI(self): def addItem(name, handler, statusTip, menu): action = QAction(name, self) action.setStatusTip(statusTip) action.triggered.connect(handler) menu.addAction(action) #Add Logging handlers for output field emStream = EmittingStream(textWritten=self.normalOutputWritten) handler = logging.StreamHandler(emStream) handler.setLevel(logging.INFO) handler.setFormatter(outputWindowFormatter) logger.addHandler(handler) sys.stdout = EmittingStream(textWritten=self.normalOutputWritten) sys.stderr = EmittingStream(textWritten=self.normalOutputWritten) #Get Pixmaps and Icon self.donePixmap = QPixmap(Utils.findResource("Images/status/done.png")) self.inProgPixmap = QPixmap(Utils.findResource("Images/status/inProgress.png")) self.needsAttentionPixmap = QPixmap(Utils.findResource("Images/status/needsAttention.png")) self.nonePixmap = QPixmap(Utils.findResource("Images/status/none.png")) self.notStartedPixmap = QPixmap(Utils.findResource("Images/status/notStarted.png")) self.refreshPixmap = QPixmap(Utils.findResource("Images/refresh.png")) self.refreshIcon = QIcon() self.refreshIcon.addPixmap(self.refreshPixmap) self.RIcon = QIcon(Utils.findResource("Images/RenderNodeMain.png")) self.isVisable = True self.refreshButton.setIcon(self.refreshIcon) self.renderServerPixmap.setPixmap(self.notStartedPixmap) self.scheduleThreadPixmap.setPixmap(self.notStartedPixmap) self.pulseThreadPixmap.setPixmap(self.notStartedPixmap) self.setWindowIcon(self.RIcon) #Setup tray icon self.trayIcon = QSystemTrayIcon() self.trayIconBool = self.trayIcon.isSystemTrayAvailable() if self.trayIconBool: self.trayIcon.setIcon(self.RIcon) self.trayIcon.show() self.trayIcon.setVisible(True) self.trayIcon.activated.connect(self.activate) self.trayIcon.messageClicked.connect(self.activate) #Tray Icon Context Menu self.taskIconMenu = QMenu(self) addItem("Open", self.showWindowHandler, "Show the RenderNodeMain Window", self.taskIconMenu) self.taskIconMenu.addSeparator() addItem("Update", self.updateThisNodeInfo, "Fetch the latest information from the Database", self.taskIconMenu) self.taskIconMenu.addSeparator() addItem("Online", self.onlineThisNodeHandler, "Online this node", self.taskIconMenu) addItem("Offline", self.offlineThisNodeHandler, "Offline this node", self.taskIconMenu) addItem("GetOff!", self.getOffThisNodeHandler, "Kill the current task and offline this node", self.taskIconMenu) self.trayIcon.setContextMenu(self.taskIconMenu) else: logger.error("Tray Icon Error! Could not create tray icon.") aboutBox(self, "Tray Icon Error", "Could not create tray icon. Minimizing to tray has been disabled.") self.trayButton.setEnabled(False)
def aboutBoxHidden(self, title="", msg=""): """Creates a window that has been minimzied to the tray""" if self.isVisable: aboutBox(self, title, msg) else: self.trayIcon.showMessage(title, msg)
hours = int(self.interval / 60 / 60) minutes = int(self.interval / 60 % 60) logger.info("Scheduler Sleeping for %d hours and %d minutes", hours, minutes) self.stopEvent.wait(self.interval) def pulse(): host = Utils.myHostName() with transaction() as t: t.cur.execute("UPDATE hydra_rendernode SET pulse = NOW() " "WHERE host = '{0}'".format(host)) if __name__ == "__main__": logger.info("Starting in %s", os.getcwd()) logger.info("arglist is %s", sys.argv) app = QApplication(sys.argv) app.quitOnLastWindowClosed = False lockFile = InstanceLock("HydraRenderNode") lockStatus = lockFile.isLocked() logger.debug("Lock File Status: %s", lockStatus) if not lockStatus: logger.critical("Only one RenderNode is allowed to run at a time! Exiting...") aboutBox(None, "ERROR", "Only one RenderNode is allowed to run at a time! Exiting...") sys.exit(-1) window = RenderNodeMainUI() retcode = app.exec_() lockFile.remove() sys.exit(retcode)
def submitButtonHandler(self): ####################################################################### #TODO: Rework this to work with multiple job types ####################################################################### #Getting data in same order as JobTicket execName = str(self.executableComboBox.currentText()) baseCMD = str(self.cmdLineEdit.text()) startFrame = int(self.startSpinBox.value()) endFrame = int(self.endSpinBox.value()) byFrame = int(self.testFramesSpinBox.value()) taskFile = str(self.sceneLineEdit.text()) priority = int(self.prioritySpinBox.value()) phase = 0 #Placeholder, set this later when building the commands jobStatus = self.getJobStatus() niceName = str(self.niceNameLineEdit.text()) owner = transaction().db_username compatabilityList = self.getReqs() maxNodesP1 = int(self.maxNodesP1SpinBox.value()) maxNodesP2 = int(self.maxNodesP2SpinBox.value()) timeout = int(self.timeoutSpinbox.value()) projectName = str(self.projectNameLineEdit.text()) renderLayers = str(self.renderLayersLineEdit.text()).replace(" ", "") jobType = str(self.jobTypeComboBox.currentText()) proj = str(self.projLineEdit.text()) #Error Checking if len(baseCMD) > 1000: aboutBox(self, "baseCMD too long!", "baseCMD must be less than 1000 characters!") logger.error("baseCMD too long! baseCMD must be less than 1000 characters!") return if startFrame > endFrame: aboutBox(self, "startFrame is greater than endFrame!", "startFrame must be less than the endFrame!") logger.error("startFrame is greater than endFrame!") return if startFrame > 65535 or endFrame > 65535 or startFrame < 0 or endFrame < 0: aboutBox(self, "Frame range out of range!", "Start/End frames must be between 0 and 65535!") logger.error("Frame range out of range! Start/End frames must be between 0 and 65535!") return if byFrame > 255 or byFrame < 0: aboutBox(self, "byFrame out of range!", "byFrame must be between 0 and 255!") logger.error("byFrame out of range! byFrame must be between 0 and 255!") return if len(taskFile) > 255 or len(taskFile) < 5: aboutBox(self, "taskFile out of range!", "taskFile must be greater than 5 and less than 255 characters") logger.error("taskFile out of range! taskFile path must be greater than 5 and less than 255 characters!") return if priority > 255 or priority < 0: aboutBox(self, "Priority out of range!", "Priority must be between 0 and 255!") logger.error("Priority out of range! Priority must be between 0 and 255!") return if len(niceName) > 60 or len(niceName) < 2: aboutBox(self, "NiceName out of range!", "NiceName must be more than 1 and less than 60 characters!") logger.error("NiceName out of range! NiceName must be more than 1 and less than 60 characters!") return if len(owner) > 45: aboutBox(self, "Owner out of range!", "Owner must be less than 45 characters!") logger.error("Owner out of range! Owner must be less than 45 characters!") return if len(projectName) > 60: aboutBox(self, "Project Name out of range!", "Project name must be less than 60 characters!") return if projectName == "": projectName = "UnkownProject" if jobType not in ["BatchFile", "FusionComp"]: baseCMD += " -proj {0}".format(proj) phase01Status = False if self.testCheckBox.isChecked(): logger.info("Building Phase 01") #Phase specific overrides phase = 1 #This is cool because at least for now anything with a phase one SHOULD be a Maya Job baseCMDOverride = baseCMD + " -x 640 -y 360" if ((endFrame - startFrame) % byFrame) != 0: phase01FinalFrame = True #This looks kinda dumb but works because Python 2.7 divide returns an int endFrameOverride = ((((endFrame - startFrame) / byFrame) * byFrame) + startFrame) else: phase01FinalFrame = False endFrameOverride = endFrame phase01 = submitJob(niceName, projectName, owner, jobStatus, compatabilityList, execName, baseCMDOverride, startFrame, endFrameOverride, byFrame, renderLayers, taskFile, int(priority * 1.25), phase, maxNodesP1, timeout, 10, jobType) logger.info("Phase 01 submitted with id: %s", phase01.id) if phase01FinalFrame: niceNameOverride = "{0}_FinalFrame".format(niceName) byFrameOverride = 1 phase01FinalFrameJob = submitJob(niceNameOverride, projectName, owner, jobStatus, compatabilityList, execName, baseCMDOverride, endFrame, endFrame, byFrameOverride, renderLayers, taskFile, int(priority * 1.25), phase, maxNodesP1, timeout, 10, jobType) logger.info("Phase 01 final frame workaround submitted with id: %s", phase01FinalFrameJob.id) phase01Status = True if self.finalCheckBox.isChecked(): logger.info("Building Phase 02") #Phase specific overrides phase = 2 byFrame = 1 if phase01Status: jobStatusOverride = "U" else: jobStatusOverride = jobStatus phase02 = submitJob(niceName, projectName, owner, jobStatusOverride, compatabilityList, execName, baseCMD, startFrame, endFrame, byFrame, renderLayers, taskFile, priority, phase, maxNodesP2, timeout, 10, jobType) logger.info("Phase 02 submitted with id: %s", phase02.id) self.submitButton.setEnabled(False) self.submitButton.setText("Job Submitted! Please close window.")