def projectChangeHandler(self, index):
     """Handler for the event where the project selection changed."""
     
     selectedProject = self.projectComboBox.itemText(index)
     choice = yesNoBox(self, "Change project", "Reassign this node to " + 
                       selectedProject + "? (will avoid jobs from other"
                       " projects)")
     
     if choice != QMessageBox.Yes:
         aboutBox(self, "No changes", "This node will remain assigned to " + 
                  self.thisNode.project + ".")
         self.projectComboBox.setCurrentIndex(self.lastProjectIndex)
         return
     
     # get the most up to date info from the database
     thisNode = None
     try:
         thisNode = getThisNodeData()
     except sqlerror as err:
         logger.debug(str(err))
         self.sqlErrorBox()
         return
     
     thisNode.project = self.projectComboBox.currentText()
     with transaction() as t:
         thisNode.update(t)
     self.lastProjectIndex = self.projectComboBox.currentIndex()
     aboutBox(self, "Success", "Node reassigned to " + selectedProject)
 def searchByTaskID(self):
     """Given a task id, finds the job, selects it in the job table, and
     displays the tasks for that job, including the one searched for. Does
     nothing if task id doesn't exist."""
     
     # retrieve job id by task id in the database
     task_id = str(self.taskIDLineEdit.text())
     if task_id:
         with transaction() as t:
             query = "select job_id from Hydra_rendertask where id = %s"
             t.cur.execute(query % task_id)
             job_id = t.cur.fetchall()
             
             if not job_id:
                 aboutBox(self, "Error", "The given task ID does not "
                          "correspond to an existing job.")
                 return
             
             # find item with matching job id in the table
             ((job_id,),) = job_id # unpack -- TODO: fix this hack?
             [item] = self.jobTable.findItems(str(job_id), Qt.MatchExactly)
             
             # select the row and trigger the update for the task list
             self.jobTable.setCurrentItem(item)
             self.jobCellClickedHandler(item.row(), item.column())
             [item] = self.taskTable.findItems(str(task_id), Qt.MatchExactly)
             self.taskTable.setCurrentItem(item)
     else:
         aboutBox(self, "Error", "No task ID was entered.")
         return
 def jobCellClickedHandler (self, row, column):
     # populate the task table widget
     item = self.jobTable.item (row, 0)
     job_id = int (item.text ())
     self.taskTableLabel.setText("Task List (job: " + item.text() + ")")
     try:
         tasks = Hydra_rendertask.fetch ("where job_id = %d" % job_id)
         self.taskTable.setRowCount (len (tasks))
         for pos, task in enumerate (tasks):
             # calcuate time difference
             tdiff = None
             if task.endTime:
                 tdiff = task.endTime - task.startTime
             elif task.startTime:
                 tdiff = dt.now().replace(microsecond=0) - task.startTime
             
             # populate table
             self.taskTable.setItem(pos, 0, 
                                    TableWidgetItem_int(str(task.id)))
             self.taskTable.setItem(pos, 1, 
                                    TableWidgetItem_int(str(task.priority)))
             self.taskTable.setItem(pos, 2, 
                                    TableWidgetItem(str(task.host)))
             self.taskTable.setItem(pos, 3, 
                                    TableWidgetItem(str(task.status)))
             self.taskTable.setItem(pos, 4, 
                                    TableWidgetItem_dt(task.startTime))
             self.taskTable.setItem(pos, 5, 
                                    TableWidgetItem_dt(task.endTime))
             self.taskTable.setItem(pos, 6, TableWidgetItem_dt(str(tdiff)))
     except sqlerror as err:
         aboutBox(self, "SQL Error", str(err))
 def refreshHandler(self, *args):
     try:
         jobs = Hydra_job.fetch()
         self.jobTable.setRowCount(len(jobs))
         for pos, job in enumerate(jobs):
             ticket = pickle.loads(job.pickledTicket)
             self.jobTable.setItem(pos, 0, QTableWidgetItem_int(str(job.id)))
             self.jobTable.setItem(pos, 1, QTableWidgetItem_int(str(job.priority)))
             self.jobTable.setItem(pos, 2, QTableWidgetItem(ticket.name()))
     except sqlerror as err:
         logger.debug(str(err))
         aboutBox(self, "SQL error", str(err))
 def killJobButtonHandler(self):
     item = self.jobTable.currentItem()
     if item and item.isSelected():
         row = self.jobTable.currentRow()
         id = int(self.jobTable.item(row, 0).text())  # @ReservedAssignment
         choice = yesNoBox(self, "Confirm", "Really kill job {:d}?".format(id))
         if choice == QMessageBox.Yes:
             try:
                 if killJob(id):
                     aboutBox(self, "Error", "Some nodes couldn't kill " + "their tasks.")
             except sqlerror as err:
                 logger.debug(str(err))
                 aboutBox(self, "SQL Error", str(err))
             finally:
                 self.jobCellClickedHandler(item.row(), 0)
 def getOffThisNodeButtonClicked(self):
     """Offlines the node and sends a message to the render node server 
     running on localhost to kill its current task (task will be 
     resubmitted)"""
     
     thisNode = None
     try:
         thisNode = getThisNodeData()
     except sqlerror as err:
         logger.debug(str(err))
         self.sqlErrorBox()
         return
     
     choice = yesNoBox(self, "Confirm", "All progress on the current job"
                       " will be lost. Are you sure you want to stop it?")
     if choice != QMessageBox.Yes:
         aboutBox(self, "Abort", "No action taken.")
         return
     
     if thisNode:
         offlineNode(thisNode)
             
         if thisNode.task_id:
             try:
                 # TODO: use JobKill for getOff instead of doing it manually
                 killed = sendKillQuestion(renderhost = "localhost", 
                                           newStatus = READY)
                 if not killed:
                     logger.debug("There was a problem killing the task.")
                     aboutBox(self, "Error", "There was a problem killing"
                              " the task.")
                 else:
                     aboutBox(self, "Success", "Job was successfully"
                              " stopped. Node offlined.")
             except socketerror:
                 logger.debug(socketerror.message)
                 aboutBox(self, "Error", "There was a problem communicating"
                          " with the render node software. Either it's not"
                          " running, or it has become unresponsive.")
         else:
             aboutBox(self, "Offline", "No job was running. Node offlined.")
             
     self.doFetch()
 def getOffRenderNodesButtonClicked(self):
     """For all nodes with boxes checked in the render nodes table, changes
     status to offline if idle, or pending if started, and attempts to kill
     any task that is running on each node."""
     
     hosts = getCheckedItems(table=self.renderNodeTable, itemColumn=1,
                             checkBoxColumn=0)
     if len(hosts) == 0:
         self.noneCheckedBox()
         return
     
     choice = yesNoBox(self, "Confirm", "<B>WARNING</B>: All progress on"
                       " current tasks will be lost for the selected"
                       " render nodes. Are you sure you want to stop these"
                       " nodes? <br>" + str(hosts))
     
     if choice != QMessageBox.Yes:
         aboutBox(self, "Aborted", "No action taken.")
         return
     
     error = False
     notKilledList = list()
     with transaction() as t:
         rendernode_rows = Hydra_rendernode.fetch(explicitTransaction=t)
         for node_row in rendernode_rows:
             if node_row.host in hosts:
                 offlineNode(node_row)
                 try:
                     killed = sendKillQuestion(node_row.host, READY)
                     error = error or not killed
                 except socketerror as err:
                     logger.debug(str(err) + '\n' 
                                  + "Error while trying to contact " 
                                  + node_row.host)
                     notKilledList.append(node_row.host)
                     error = True
     if error:
         aboutBox(self, "Error", "The following nodes could not be stopped"
                  " for some reason. Look in FarmView.log for more details."
                  "<br>" + str(notKilledList))
     self.doFetch()
 def onlineRenderNodesButtonClicked(self):
     
     hosts = getCheckedItems(table=self.renderNodeTable, itemColumn=1, 
                             checkBoxColumn=0)
     if len(hosts) == 0:
         self.noneCheckedBox()
         return
     
     choice = yesNoBox(self, "Confirm", "Are you sure you want to online"
                       " these nodes? <br>" + str(hosts))
     
     if choice != QMessageBox.Yes:
         aboutBox(self, "Aborted", "No action taken.")
         return
     
     with transaction() as t:
         rendernode_rows = Hydra_rendernode.fetch(explicitTransaction=t)
         for node_row in rendernode_rows:
             if node_row.host in hosts:
                 onlineNode(node_row)
     self.doFetch()
 def killTaskButtonHandler(self):
     item = self.taskTable.currentItem()
     if item and item.isSelected():
         row = self.taskTable.currentRow()
         id = int(self.taskTable.item(row, 0).text())  # @ReservedAssignment
         choice = yesNoBox(self, "Confirm", "Really kill task {:d}?".format(id))
         if choice == QMessageBox.Yes:
             try:
                 killTask(id)
             except socketerror as err:
                 logger.debug(str(err))
                 aboutBox(
                     self,
                     "Error",
                     "Task couldn't be killed because "
                     "there was a problem communicating with the host running "
                     "it.",
                 )
             except sqlerror as err:
                 logger.debug(str(err))
                 aboutBox(self, "SQL Error", str(err))
 def resurrectTaskButtonHandler(self):
     taskItem = self.taskTable.currentItem()
     if taskItem and taskItem.isSelected():
         row = self.taskTable.currentRow()
         id = int(self.taskTable.item(row, 0).text())  # @ReservedAssignment
         choice = yesNoBox(self, "Confirm", "Resurrect task {:d}?".format(id))
         if choice == QMessageBox.Yes:
             error = None
             try:
                 error = resurrectTask(id)
             except sqlerror as err:
                 logger.debug(str(err))
                 aboutBox(self, "SQL Error", str(err))
             finally:
                 if error:
                     msg = "Task couldn't be resurrected because it's " "either not dead or is currently running."
                     logger.debug(msg)
                     aboutBox(self, "Error", msg)
                 else:
                     jobItem = self.jobTable.currentItem()
                     self.jobCellClickedHandler(jobItem.row(), 0)
    def doSubmit( self ):
        """Submits a job ticket for this scene to be split into
        tasks and processed."""

        logger.debug ('doSubmit')

        reqs = sorted ([str (req.text ())
                        for req in self.requirementsListWidget.selectedItems ()])
        reqs_pattern = '%' + '%'.join (reqs) + '%' if reqs else '%'
        print reqs_pattern
        
        sceneFile = str( self.sceneText.text() ).replace ('\\', '/')
        startFrame = self.startSpinBox.value( )
        endFrame = self.endSpinBox.value( )
        numJobs = self.numJobsSpinBox.value( )
        batchSize = int(math.ceil((endFrame - startFrame + 1.0) / numJobs))
        logger.debug ("numJobs %s batchSize %s", numJobs, batchSize)
        priority = self.prioritySpinBox.value( )
        project = str(self.projectComboBox.currentText())
        executable = str(self.executableComboBox.currentText())
        
        mayaProjectPath = str(self.projectDirLineEdit.text())
        if not os.path.exists(os.path.join (mayaProjectPath, "workspace.mel")):
            # try to find workspace.mel
            mayaProjectPath = self.getMayaProjectPath(sceneFile)
            if not mayaProjectPath:
                logger.debug("workspace.mel not found")
                aboutBox(self, "Error", """
The project path cannot be set because workspace.mel could not
be located. Please set the project path manually.""")
                return
            if yesNoBox(self, "Confirm",
                        "Maya project path set to:<br>" +
                        mayaProjectPath +
                        "<br> Is this correct?") == QMessageBox.No:
                aboutBox(self, "Abort",
"Submission aborted. Please set the Maya project path manually.")
                return
        self.projectDirLineEdit.setText(mayaProjectPath)

        # executable names a class in the JobTicket module
        ticketClass = getattr (JobTicket, executable)
        ticketClass(sceneFile, mayaProjectPath, startFrame, endFrame, batchSize,
                    priority, project, reqs_pattern).submit()

        aboutBox(self, "Success",
"Job submitted. Please close the submitter window.")
 def killTaskButtonHandler (self):
     item = self.taskTable.currentItem ()
     if item and item.isSelected ():
         row = self.taskTable.currentRow ()
         task_id = int(self.taskTable.item(row, 0).text())
         choice = yesNoBox(self, "Confirm", "Really kill task {:d}?"
                           .format(task_id))
         if choice == QMessageBox.Yes:
             killed = None
             try:
                 killed = killTask(task_id)
                 if not killed:
                     # TODO: make a better error message
                     aboutBox(self, "Error", "Task couldn't be killed for "
                              "some reason.")
             except socketerror as err:
                 logger.debug(str(err))
                 aboutBox(self, "Error", "Task couldn't be killed because "
                 "there was a problem communicating with the host running "
                 "it.")
             except sqlerror as err:
                 logger.debug(str(err))
                 aboutBox(self, "SQL Error", str(err))