source: palm/trunk/SCRIPTS/palm_wd @ 1614

Last change on this file since 1614 was 1614, checked in by maronga, 9 years ago

last commit documented

  • Property svn:executable set to *
  • Property svn:keywords set to Id
File size: 34.0 KB
Line 
1#!/usr/bin/python
2# -*- coding: utf-8 -*-
3#--------------------------------------------------------------------------------#
4# This file is part of PALM.
5#
6# PALM is free software: you can redistribute it and/or modify it under the terms
7# of the GNU General Public License as published by the Free Software Foundation,
8# either version 3 of the License, or (at your option) any later version.
9#
10# PALM is distributed in the hope that it will be useful, but WITHOUT ANY
11# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along with
15# PALM. If not, see <http://www.gnu.org/licenses/>.
16#
17# Copyright 1997-2015  Leibniz Universitaet Hannover
18#--------------------------------------------------------------------------------#
19#
20# Current revisions:
21# -----------------
22#
23#
24# Former revisions:
25# -----------------
26# $Id: palm_wd 1614 2015-07-08 14:54:35Z maronga $
27#
28# 1613 2015-07-08 14:53:29Z maronga
29# Bugfix: tooltip for queuing name did not show up on first update.
30# New: added contect menu for showing the parameter file and the run control
31# output
32#
33# 1611 2015-07-07 12:23:22Z maronga
34# Initial revision
35#
36#
37# Description:
38# ------------
39# PALM watchdog client for monitoring batch jobs on a variety of hosts specified
40# by the user
41#
42# Instructions:
43# -------------
44# 1) Modify the header section of palm_wd
45# 2) Move .wd.olddata and .wd.newdata to your palm directory
46#    (e.g. /home/user/current_version/.wd.newdata etc.)
47# 3) Modify a copy of palm_wdd for each host to be monitored and move it to the
48#    respective hosts
49# 4) Start the client either from mrungui or from shell by "nohup palm_wd&"
50
51# To do:
52# ------
53# 1) Add "Options", "Help" and "Manual"
54# 2) Move user settings to a configuration file
55#------------------------------------------------------------------------------!
56
57import sys
58import subprocess as sub
59from PyQt4 import QtGui, QtCore, uic
60from PyQt4.QtCore import pyqtSlot,SIGNAL,SLOT
61import time
62import datetime
63import shutil
64import os
65
66# START OF HEADER
67# Each list must contain the login host, the username and a description
68hostname     = ["hlogin.hlrn.de", "blogin.hlrn.de"]
69username     = ["nikmaron"      , "nikmaron"      ]
70description  = ["Hannover"      , "Berlin"        ]
71
72update_frequency = 600*1000
73
74# END OF HEADER
75
76# Determine PALM directories
77try: 
78   devnull = open(os.devnull, 'w')
79   out = sub.check_output("echo $PALM_BIN", shell=True, stderr=sub.STDOUT)
80   palm_bin = out.rstrip()
81   palm_dir = out.split("palm")[0] + "palm/" + out.split("palm")[1].split("/")[1]
82   out = None
83except:   
84   print "Error. $PALM_BIN is not set."
85   raise SystemExit
86
87
88# Dummy variables for the jobname and the progressbars
89jobname = ""
90timestamp = ""
91pbars = []
92job_data_list = []
93
94class MessageBoxScroll(QtGui.QMessageBox):
95    def __init__(self):
96        QtGui.QMessageBox.__init__(self)
97        self.setSizeGripEnabled(True)
98
99    def event(self, e):
100        result = QtGui.QMessageBox.event(self, e)
101
102        self.setMinimumHeight(100)
103        self.setMaximumHeight(16777215)
104        self.setMinimumWidth(400)
105        self.setMaximumWidth(16777215)
106        self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
107
108        textEdit = self.findChild(QtGui.QTextEdit)
109        if textEdit != None :
110            textEdit.setMinimumHeight(800)
111            textEdit.setMaximumHeight(16777215)
112            textEdit.setMinimumWidth(1000)
113            textEdit.setMaximumWidth(16777215)
114            textEdit.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
115            f = QtGui.QFont('not_a_font') #
116            f.setStyleHint(f.TypeWriter, f.PreferDefault)
117            textEdit.setFont(f)
118
119        return result
120
121
122# MainWindow class
123class Watchdog(QtGui.QMainWindow):
124   
125    def __init__(self):
126        super(Watchdog, self).__init__()
127       
128        self.InitUi()   
129       
130   
131    # Initialized MainWindow UI
132    def InitUi(self):
133
134        # Load predefined mainwindow
135        uic.loadUi(palm_bin + '/palm_wd_files/wd.ui', self)
136
137        # Resize columns and set number of rows to zero. Column 6 is hidden and
138        # contains the remote jobname (e.g. hannover.174610)
139        self.table.setColumnWidth(0,230)
140        self.table.setColumnWidth(1,80)
141        self.table.setColumnWidth(2,50)
142        self.table.setColumnWidth(3,80)     
143        self.table.setColumnWidth(4,180)
144        self.table.setColumnWidth(5,115)   
145        self.table.setColumnHidden(6, True)
146        self.table.setRowCount(0) 
147   
148        # Display MainWindow
149        self.show()
150        QtGui.QApplication.processEvents()
151
152        # Start refresh timer. On timeout perform update
153        self.timer = QtCore.QTimer(self)
154        self.timer.timeout.connect(self.Refresh)
155        self.timer.setSingleShot(False)
156        self.timer.start(update_frequency)
157
158        # The timetimer counts the time since last update
159        self.timetimer= QtCore.QElapsedTimer()
160        self.timetimer.start()
161
162        # The labeltimer induces the update of the remaining time in the UI
163        self.labeltimer = QtCore.QTimer(self)
164        self.labeltimer.timeout.connect(self.UpdateLabel)
165        self.labeltimer.setSingleShot(False)
166
167        # Update in the UI will be performed at each 1/10 of the update interval
168        self.labeltimer.start(update_frequency/10)   
169        self.label.setText("Next update in " + str(update_frequency/1000/60) + "min")
170
171        # Update the list now
172        self.Refresh()
173       
174
175    # Add a custom context menu
176    def OpenContextMenu(self, position):
177        menu = QtGui.QMenu()
178       
179        # "Show details" -> fetch details for the selected job
180        detailsjobAction = menu.addAction('Show job details')     
181        detailsjobAction.setStatusTip('Display detailed info for job')
182        detailsjobAction.triggered.connect(self.ShowDetails)
183
184        # "Show parameter file" -> show the contents of PARIN
185        parinAction = menu.addAction('Show parameter file')     
186        parinAction.setStatusTip('Display the parameter file of the job (e.g. PARIN / _p3d)')
187        parinAction.triggered.connect(self.ShowPARIN)
188       
189        rcAction = menu.addAction('Show run control file')     
190        rcAction.setStatusTip('Display the current run control file (e.g. RUN_CONTROL / _rc)')
191        rcAction.triggered.connect(self.ShowRC)
192       
193        # "Cancel job" -> remove job from queuing system
194        canceljobAction = menu.addAction('Cancel job')
195        canceljobAction.setStatusTip('Remove job from queueing system')
196        canceljobAction.triggered.connect(self.CancelJob)
197       
198        # "Force stop" -> force termination of job
199        stopjobAction = menu.addAction('Force stop')
200        stopjobAction.setStatusTip('Terminate job properly')
201        stopjobAction.triggered.connect(self.DoStop)
202   
203        # "Force restart" -> force rermination and restart of job
204        restartjobAction = menu.addAction('Force restart')
205        restartjobAction.setStatusTip('Terminate job properly and initiate restart')
206        restartjobAction.triggered.connect(self.DoRestart)
207 
208        # "Remove from list" -> remove a completed job from the list
209        removefromlistAction = menu.addAction('Remove from list')     
210        removefromlistAction.setStatusTip('Remove finished job')
211        removefromlistAction.triggered.connect(lambda: self.RemoveFromList(-1))     
212
213       
214        # Activate/deactive contect menu items based on the status of the runs
215        state = self.table.item(self.table.currentRow(),3).text()
216        if (state == "Canceled" or state == "Completed" or state == "Terminated"):
217            detailsjobAction.setEnabled(False)
218            canceljobAction.setEnabled(False) 
219            removefromlistAction.setEnabled(True) 
220        else:
221            detailsjobAction.setEnabled(True)
222            canceljobAction.setEnabled(True) 
223            removefromlistAction.setEnabled(False)   
224 
225        if ( state == "Running" ):
226            stopjobAction.setEnabled(True) 
227            restartjobAction.setEnabled(True)   
228            parinAction.setEnabled(True)
229            rcAction.setEnabled(True)         
230        else:
231            stopjobAction.setEnabled(False) 
232            restartjobAction.setEnabled(False)   
233            parinAction.setEnabled(False)
234            rcAction.setEnabled(False) 
235           
236        # Show the context menu
237        action = menu.exec_(self.table.mapToGlobal(position))
238
239
240    # Collecting watchdog data and display in the UI
241    def Refresh(self):
242     
243        # Use global variables
244        global jobs_save
245        global pbars
246
247        # Deactivate timer processes until update is finished
248        # QtGui.QApplication.processEvents() updates the UI whenever needed
249        self.labeltimer.stop() 
250        self.label.setText("Updating...") 
251        QtGui.QApplication.processEvents()
252        self.setEnabled(False)
253        QtGui.QApplication.processEvents()
254
255        # Get current timestamp
256        timestamp = datetime.datetime.now().strftime("%d/%m/%Y %H:%M")
257       
258        # Open an empty file for the watchdog data       
259        file = open(palm_dir + '/.wd.newdata', 'w')
260       
261 
262        # Set all required variables to their initial values. Sorting must be
263        # disabled.
264        self.table.setRowCount(0) 
265        self.table.setSortingEnabled(False)
266        i = -1
267        job_data_list = []
268        pbars = []
269       
270        # Scan all hosts in the variable hostname. For each host perform the
271        # update loop
272        for h in range(0,len(hostname)):
273         
274            # Perform ssh command
275            host    = username[h] + "@" + hostname[h]
276            ssh = sub.Popen(["ssh", "%s" % host, "/sw/tools/python/2.7.6/generic/bin/python palm_wdd queue " + username[h]],
277                           shell=False,
278                           stdout=sub.PIPE,
279                           stderr=sub.PIPE)
280            result = ssh.stdout.readlines()
281            result = filter(None, result)
282 
283 
284            # Delete all job data
285            job_data_tmp = []
286            job_data = []
287            job_data_n = []   
288            job_data_old = []
289            job_data_old_n = []
290            job_progress = 0
291
292            # In case of errors display error message
293            if ( len(result) < 1 ):
294                error = ssh.stderr.readlines()
295                if ( error != [] ):
296                    notify = QtGui.QMessageBox.warning(self,'Collect data',"Error. An error occured during read of job data for user " + username[h] +" for host " + description[h] + ".\n\nError message:\n" + ''.join(error))
297
298            # No error -> save job data
299            else:       
300
301                # Successively write to job_data
302                for j in range(0,len(result)):
303   
304                    job_data_tmp.append(j)
305                    job_data_tmp[j] = result[j].split(" ")
306                    job_data_tmp[j] = filter(None, job_data_tmp[j])
307 
308                    job_data.append(j)   
309                    job_data[j] = [job_data_tmp[j][0], description[h], job_data_tmp[j][2],                 
310                                   job_data_tmp[j][3], int(float(job_data_tmp[j][4])*100), job_data_tmp[j][5], 
311                                   job_data_tmp[j][1], job_data_tmp[j][6].rstrip()]
312                    job_data_n.append(j)
313                    job_data_n[j] = job_data_tmp[j][1]
314
315            del(result)
316
317
318
319            # Now read the data from the last update from file. These data are
320            # already in the prefered format
321            file2 = open(palm_dir + '/.wd.olddata', 'r')
322            result = file2.readlines()
323            file2.close()
324           
325            for j in range(0,len(result)):
326                if ( result[j].split()[1] == description[h] ):
327                    job_data_old.append(j)
328                    job_data_old[j] = result[j].split(" ")
329                    job_data_old[j] = filter(None, job_data_old[j])
330                    job_data_old[j] = [line.rstrip('\n') for line in job_data_old[j]]
331               
332                    job_data_old_n.append(j)
333                    job_data_old_n[j] = job_data_old[j][6]
334
335            # Merge the job_data and job_data_old to find completed, new and
336            # still queued jobs     
337            if ( len(job_data_n) > 0 and len(job_data_old_n) > 0 ):
338               jobs_full  = list(set(job_data_old_n) | set(job_data_n))
339               jobs_known    = list(set(job_data_old_n) & set(job_data_n))
340               jobs_complete = set(job_data_old_n) - set(job_data_n)
341               jobs_new      = set(job_data_n) - set(job_data_old_n)
342            elif ( len(job_data_n) > 0 ):
343               jobs_full  = job_data_n
344               jobs_known    = []
345               jobs_new = job_data_n
346               jobs_complete = []
347            elif ( len(job_data_old_n) > 0 ):
348               jobs_full  = job_data_old_n
349               jobs_known    = []
350               jobs_new = []
351               jobs_complete = job_data_old_n   
352            else:
353               jobs_full  = []
354               jobs_known    = []         
355               jobs_new = []
356               jobs_complete = []
357
358            # Display all known jobs
359            to_display = [list(job_data_n).index(item) for item in list(jobs_known) if list(jobs_known) and list(job_data_n)]
360            for j in range(0,len(to_display)):
361                i = i + 1
362                self.table.insertRow(i)
363                item = QtGui.QTableWidgetItem(job_data[to_display[j]][0])
364                item.setToolTip("Queuing name: " + job_data[to_display[j]][6])
365                self.table.setItem(i, 0, item)           
366                self.table.setItem(i, 1, QtGui.QTableWidgetItem(job_data[to_display[j]][1])) 
367                self.table.setItem(i, 2, QtGui.QTableWidgetItem(job_data[to_display[j]][2]))   
368                self.table.setItem(i, 3, QtGui.QTableWidgetItem(job_data[to_display[j]][3]))
369                item = QtGui.QTableWidgetItem(job_data[to_display[j]][5])
370                item.setToolTip("Estimated job start: " + job_data[to_display[j]][7])               
371                self.table.setItem(i, 5, item) 
372                self.table.setItem(i, 6, QtGui.QTableWidgetItem(job_data[to_display[j]][6])) 
373                self.table.item(i,2).setTextAlignment(QtCore.Qt.AlignRight)
374                self.table.item(i,5).setTextAlignment(QtCore.Qt.AlignRight)
375                pbars.append(i)
376                pbars[i] = QtGui.QProgressBar(self)
377                pbars[i].setValue(int(job_data[to_display[j]][4])) 
378 
379                # Apply a color depending on the status of the job
380                if ( job_data[to_display[j]][3] == "Running" ):
381                    self.table.setCellWidget(i,4,pbars[j]) 
382                    self.table.item(i,0).setBackground(QtGui.QColor(255, 251, 168))
383                    self.table.item(i,1).setBackground(QtGui.QColor(255, 251, 168))
384                    self.table.item(i,2).setBackground(QtGui.QColor(255, 251, 168))
385                    self.table.item(i,3).setBackground(QtGui.QColor(255, 251, 168))
386                    self.table.item(i,5).setBackground(QtGui.QColor(255, 251, 168))
387                    self.table.item(i,6).setBackground(QtGui.QColor(255, 251, 168))
388                else:
389                    pbars[j].setEnabled(False)
390                    self.table.setCellWidget(i,4,pbars[j])
391                    self.table.item(i,0).setBackground(QtGui.QColor(255, 112, 118))
392                    self.table.item(i,1).setBackground(QtGui.QColor(255, 112, 118))
393                    self.table.item(i,2).setBackground(QtGui.QColor(255, 112, 118))
394                    self.table.item(i,3).setBackground(QtGui.QColor(255, 112, 118))
395                    self.table.item(i,5).setBackground(QtGui.QColor(255, 112, 118))
396                    self.table.item(i,6).setBackground(QtGui.QColor(255, 112, 118))
397               
398                # Save the job data to file
399                job_data_list.append(i)
400                job_data_list[i] = job_data[to_display[j]][0]
401               
402                printstring = str(job_data[to_display[j]][0]) + " " + \
403                              str(job_data[to_display[j]][1]) + " " + \
404                              str(job_data[to_display[j]][2]) + " " + \
405                              str(job_data[to_display[j]][3]) + " " + \
406                              str(job_data[to_display[j]][4]) + " " + \
407                              str(job_data[to_display[j]][5]) + " " + \
408                              str(job_data[to_display[j]][6]) + " " + \
409                              str(job_data[to_display[j]][7]) + "\n"
410                file.write(printstring)
411
412
413            # Display all new jobs
414            to_display = [list(job_data_n).index(item) for item in list(jobs_new) if list(jobs_new) and list(job_data_n)]
415            for j in range(0,len(to_display)):
416                i = i + 1
417                self.table.insertRow(i)
418                item = QtGui.QTableWidgetItem(job_data[to_display[j]][0])
419                item.setToolTip("Queuing name: " + job_data[to_display[j]][6])
420                self.table.setItem(i, 0, item)   
421                self.table.setItem(i, 1, QtGui.QTableWidgetItem(job_data[to_display[j]][1])) 
422                self.table.setItem(i, 2, QtGui.QTableWidgetItem(job_data[to_display[j]][2]))   
423                self.table.setItem(i, 3, QtGui.QTableWidgetItem(job_data[to_display[j]][3])) 
424                item = QtGui.QTableWidgetItem(job_data[to_display[j]][5])
425                item.setToolTip("Estimated job start: " + job_data[to_display[j]][7])               
426                self.table.setItem(i, 5, item) 
427                self.table.setItem(i, 6, QtGui.QTableWidgetItem(job_data[to_display[j]][6])) 
428                self.table.item(i,2).setTextAlignment(QtCore.Qt.AlignRight)
429                self.table.item(i,5).setTextAlignment(QtCore.Qt.AlignRight)
430               
431                pbars.append(i)
432                pbars[i] = QtGui.QProgressBar(self)
433                pbars[i].setValue(int(job_data[to_display[j]][4]))   
434
435                # Apply a color depending on the status of the job
436                if ( job_data[to_display[j]][3] == "Running" ):
437                    self.table.setCellWidget(i,4,pbars[i])           
438                    self.table.item(i,0).setBackground(QtGui.QColor(255, 251, 168))
439                    self.table.item(i,1).setBackground(QtGui.QColor(255, 251, 168))
440                    self.table.item(i,2).setBackground(QtGui.QColor(255, 251, 168))
441                    self.table.item(i,3).setBackground(QtGui.QColor(255, 251, 168))
442                    self.table.item(i,5).setBackground(QtGui.QColor(255, 251, 168))
443                    self.table.item(i,6).setBackground(QtGui.QColor(255, 251, 168))
444                else:
445                    pbars[j].setEnabled(False)
446                    self.table.setCellWidget(i,4,pbars[i])
447                    self.table.item(i,0).setBackground(QtGui.QColor(255, 112, 118))
448                    self.table.item(i,1).setBackground(QtGui.QColor(255, 112, 118))
449                    self.table.item(i,2).setBackground(QtGui.QColor(255, 112, 118))
450                    self.table.item(i,3).setBackground(QtGui.QColor(255, 112, 118))
451                    self.table.item(i,5).setBackground(QtGui.QColor(255, 112, 118))
452                    self.table.item(i,6).setBackground(QtGui.QColor(255, 112, 118))
453         
454                # Save job data to file
455                job_data_list.append(i)
456                job_data_list[i] = job_data[to_display[j]][0]
457               
458                printstring = str(job_data[to_display[j]][0]) + " " + \
459                              str(job_data[to_display[j]][1]) + " " + \
460                              str(job_data[to_display[j]][2]) + " " + \
461                              str(job_data[to_display[j]][3]) + " " + \
462                              str(job_data[to_display[j]][4]) + " " + \
463                              str(job_data[to_display[j]][5]) + " " + \
464                              str(job_data[to_display[j]][6]) + " " + \
465                              str(job_data[to_display[j]][7]) + "\n"
466                file.write(printstring)
467
468
469            # Display all completed/canceled/aborted jobs. The watchdog cannot
470            # distinguish why the job has been finished
471            to_display = [list(job_data_old_n).index(item) for item in list(jobs_complete) if list(jobs_complete) and list(job_data_old_n)]
472            for j in range(0,len(to_display)):
473                i = i + 1
474                self.table.insertRow(i)
475                item = QtGui.QTableWidgetItem(job_data_old[to_display[j]][0])
476                item.setToolTip("Queuing name: " + job_data_old[to_display[j]][6])
477                self.table.setItem(i, 0, item)         
478                self.table.setItem(i, 1, QtGui.QTableWidgetItem(job_data_old[to_display[j]][1])) 
479                self.table.setItem(i, 2, QtGui.QTableWidgetItem(job_data_old[to_display[j]][2]))   
480                self.table.setItem(i, 3, QtGui.QTableWidgetItem(job_data_old[to_display[j]][3])) 
481                pbars.append(i)
482                pbars[j] = QtGui.QProgressBar(self)
483                pbars[j].setValue(int(job_data_old[to_display[j]][4])) 
484                pbars[j].setEnabled(False)
485                self.table.setCellWidget(i,4,pbars[j]) 
486                item = QtGui.QTableWidgetItem(job_data_old[to_display[j]][5])
487                item.setToolTip("Estimated job start: " + job_data_old[to_display[j]][7])               
488                self.table.setItem(i, 5, item) 
489                self.table.setItem(i, 6, QtGui.QTableWidgetItem(job_data_old[to_display[j]][6])) 
490                self.table.item(i,2).setTextAlignment(QtCore.Qt.AlignRight)
491                self.table.item(i,5).setTextAlignment(QtCore.Qt.AlignRight)
492                self.table.setItem(i, 3, QtGui.QTableWidgetItem("Completed"))
493               
494                # Apply a color depending on the status of the job
495                self.table.item(i,0).setBackground(QtGui.QColor(172, 252, 175))
496                self.table.item(i,1).setBackground(QtGui.QColor(172, 252, 175))
497                self.table.item(i,2).setBackground(QtGui.QColor(172, 252, 175))
498                self.table.item(i,3).setBackground(QtGui.QColor(172, 252, 175))
499                self.table.item(i,5).setBackground(QtGui.QColor(172, 252, 175))
500                self.table.item(i,6).setBackground(QtGui.QColor(172, 252, 175))
501
502         
503                # Save job data to file
504                job_data_list.append(i)
505                job_data_list[i] = job_data_old[to_display[j]][0]
506
507                printstring = str(job_data_old[to_display[j]][0]) + " " + \
508                              str(job_data_old[to_display[j]][1]) + " " + \
509                              str(job_data_old[to_display[j]][2]) + " " + \
510                              str(job_data_old[to_display[j]][3]) + " " + \
511                              str(job_data_old[to_display[j]][4]) + " " + \
512                              str(job_data_old[to_display[j]][5]) + " " + \
513                              str(job_data_old[to_display[j]][6]) + " " + \
514                              str(job_data_old[to_display[j]][7]) + "\n"
515                file.write(printstring)
516
517            del(jobs_complete)
518            del(jobs_new)
519            del(result)
520
521        file.close()
522
523       
524        # Update is complete, sorting can thus be re-enabled               
525        self.table.setSortingEnabled(True) 
526
527        # Update the logfile
528        if ( os.path.isfile(palm_dir + '/.wd.newdata') ):
529            shutil.copy(palm_dir + '/.wd.newdata',palm_dir + '/.wd.olddata')
530
531        # Re-enable timer processes             
532        self.setEnabled(True)
533        self.label2.setText("Last update: " + timestamp)
534        self.label.setText("Update complete.")
535        self.timetimer.restart()
536        self.timer.start()
537        self.labeltimer.start()
538        QtGui.QApplication.processEvents()
539       
540    # Canceling selected job from table
541    def CancelJob(self):
542
543        # Return internal jobname
544        jobname = self.table.item(self.table.currentRow(),6).text()
545 
546        # Check description of job in order to login on the correct host
547        descr = self.table.item(self.table.currentRow(),1).text()
548        for h in range(0,len(description)):
549            if ( descr == description[h] ):
550                host = username[h] + "@" + hostname[h]
551
552        ssh = sub.Popen(["ssh", "%s" % host, "/sw/tools/python/2.7.6/generic/bin/python palm_wdd cancel " + jobname],
553                           shell=False,
554                           stdout=sub.PIPE,
555                           stderr=sub.PIPE)
556        result = ssh.stdout.readlines()
557        result = filter(None, result)
558       
559        # In case of error display a warning message
560        if ( len(result) == 0 ):
561            error = ssh.stderr.readlines()
562            notify = QtGui.QMessageBox.warning(self,'Cancel job',"Error. Could not cancel job " + jobname + ".\n\nError message:\n" + ''.join(error))
563
564        # Otherwise inform the user and mark the job in the table
565        else:
566            self.table.setItem(self.table.currentRow(),3,QtGui.QTableWidgetItem("Canceled"))
567            notify = QtGui.QMessageBox.information(self,'Cancel job',"Job" + jobname + " canceled!\n\nServer message:\n" + ''.join(result))
568
569
570    # Show detailed information on job. For documentation see above
571    def ShowDetails(self):
572
573        jobname = self.table.item(self.table.currentRow(),6).text()
574        descr   = self.table.item(self.table.currentRow(),1).text()
575        for h in range(0,len(description)):
576            if ( descr == description[h] ):
577                host = username[h] + "@" + hostname[h]
578
579        ssh = sub.Popen(["ssh", "%s" % host, "/sw/tools/python/2.7.6/generic/bin/python palm_wdd check " + jobname],
580                           shell=False,
581                           stdout=sub.PIPE,
582                           stderr=sub.PIPE)
583        result = ssh.stdout.readlines()
584        result = filter(None, result)
585
586        if ( len(result) == 0 ):
587            error = ssh.stderr.readlines()
588            notify = QtGui.QMessageBox.warning(self,'Show job details',"Error. Could not fetch job details for " + jobname + ".\n\nError message:\n" + ''.join(error))
589        else:
590            notify = QtGui.QMessageBox.information(self,'Job details',"Details for job " + jobname + ":\n\n" + ''.join(result))
591
592
593    # Perform a forced stop on the job
594    def DoStop(self):
595
596        # Return internal jobname
597        jobname = self.table.item(self.table.currentRow(),6).text()
598 
599        # Check description of job in order to login on the correct host
600        descr = self.table.item(self.table.currentRow(),1).text()
601        for h in range(0,len(description)):
602            if ( descr == description[h] ):
603                host = username[h] + "@" + hostname[h]
604                user = username[h]
605
606        ssh = sub.Popen(["ssh", "%s" % host, "/sw/tools/python/2.7.6/generic/bin/python palm_wdd stop " + user + " " + jobname],
607                           shell=False,
608                           stdout=sub.PIPE,
609                           stderr=sub.PIPE)
610        result = ssh.stdout.readlines()
611        result = filter(None, result) 
612       
613        # In case of error display a warning message
614        if ( len(result) == 0 ):
615            error = ssh.stderr.readlines()
616            notify = QtGui.QMessageBox.warning(self,'Proper termination of job',"Error. Could not stop job " + jobname + ".\n\nError message:\n" + ''.join(error))
617
618        # Otherwise inform the user and mark the job in the table
619        else:
620            self.table.setItem(self.table.currentRow(),3,QtGui.QTableWidgetItem("Terminated"))
621            notify = QtGui.QMessageBox.information(self,'Terminatie job',"Termination of job " + jobname + " was initiated!\n\nServer message:\n" + ''.join(result))
622
623
624    # Perform a forced stop on the job
625    def DoRestart(self):
626
627        # Return internal jobname
628        jobname = self.table.item(self.table.currentRow(),6).text()
629 
630        # Check description of job in order to login on the correct host
631        descr = self.table.item(self.table.currentRow(),1).text()
632        for h in range(0,len(description)):
633            if ( descr == description[h] ):
634                host = username[h] + "@" + hostname[h]
635                user = username[h]
636
637        ssh = sub.Popen(["ssh", "%s" % host, "/sw/tools/python/2.7.6/generic/bin/python palm_wdd restart " + user + " " + jobname],
638                           shell=False,
639                           stdout=sub.PIPE,
640                           stderr=sub.PIPE)
641        result = ssh.stdout.readlines()
642        result = filter(None, result)
643       
644        # In case of error display a warning message
645        if ( len(result) == 0 ):
646            error = ssh.stderr.readlines()
647            notify = QtGui.QMessageBox.warning(self,'Proper termination of job',"Error. Could not stop job " + jobname + ".\n\nError message:\n" + ''.join(error))
648
649        # Otherwise inform the user and mark the job in the table
650        else:
651            self.table.setItem(self.table.currentRow(),3,QtGui.QTableWidgetItem("Terminated"))
652            notify = QtGui.QMessageBox.information(self,'Terminate job for restart',"Restart for job" + jobname + " was initiated!\n\nServer message:\n" + ''.join(result))
653           
654
655    # Read the PARIN file of the job
656    def ShowPARIN(self):
657
658        # Return internal jobname
659        jobname = self.table.item(self.table.currentRow(),6).text()
660        jobrealname = self.table.item(self.table.currentRow(),0).text()     
661 
662        # Check description of job in order to login on the correct host
663        descr = self.table.item(self.table.currentRow(),1).text()
664        for h in range(0,len(description)):
665            if ( descr == description[h] ):
666                host = username[h] + "@" + hostname[h]
667                user = username[h]
668
669        ssh = sub.Popen(["ssh", "%s" % host, "/sw/tools/python/2.7.6/generic/bin/python palm_wdd parin " + user + " " + jobname],
670                           shell=False,
671                           stdout=sub.PIPE,
672                           stderr=sub.PIPE)
673        result = ssh.stdout.readlines()
674        result = filter(None, result)
675       
676        # In case of error display a warning message
677        if ( len(result) == 0 ):
678            error = ssh.stderr.readlines()
679            notify = QtGui.QMessageBox.warning(self,'Showing parameter file',"Error. Could not fetch parameter file for job " + jobrealname + " (" + jobname + ").\n\nError message:\n" + ''.join(error))
680
681        # Otherwise inform the user and mark the job in the table
682        else:
683           mb = MessageBoxScroll()
684           mb.setText("Parameter file for job: " + jobrealname + "")
685           mb.setDetailedText(''.join(result))
686           mb.exec_()
687
688    # Read the PARIN file of the job
689    def ShowRC(self):
690
691        # Return internal jobname and real job name
692        jobname = self.table.item(self.table.currentRow(),6).text()
693        jobrealname = self.table.item(self.table.currentRow(),0).text()     
694 
695        # Check description of job in order to login on the correct host
696        descr = self.table.item(self.table.currentRow(),1).text()
697        for h in range(0,len(description)):
698            if ( descr == description[h] ):
699                host = username[h] + "@" + hostname[h]
700                user = username[h]
701
702        ssh = sub.Popen(["ssh", "%s" % host, "/sw/tools/python/2.7.6/generic/bin/python palm_wdd rc " + user + " " + jobname],
703                           shell=False,
704                           stdout=sub.PIPE,
705                           stderr=sub.PIPE)
706        result = ssh.stdout.readlines()
707        result = filter(None, result)
708       
709        # In case of error display a warning message
710        if ( len(result) == 0 ):
711            error = ssh.stderr.readlines()
712            notify = QtGui.QMessageBox.warning(self,'Showing run control',"Error. Could not fetch run control file for job " + jobrealname + "(" + jobname + ").\n\nError message:\n" + ''.join(error))
713
714        # Otherwise inform the user and mark the job in the table
715        else:
716           mb = MessageBoxScroll()
717           lastline = result[len(result)-2].split()[2]
718           mb.setText("Simulated time for job " + jobrealname + " is currently: " + lastline)
719           mb.setDetailedText(''.join(result))
720           mb.exec_()
721
722    # Remove a job from list - removes the current row from the table and from
723    # save file
724    def RemoveFromList(self, row):
725        if ( row == -1 ):
726            row = self.table.currentRow()
727
728        # Read data from save file
729        job_to_delete = self.table.item(row,6).text()
730        self.table.removeRow(row)
731        file = open(palm_dir + '/.wd.olddata', 'r')
732        result = file.readlines()
733        result = filter(None, result)
734        file.close()
735        file = open(palm_dir + '/.wd.olddata', 'w')
736       
737        job_data_old = []
738       
739        if ( len(result) == 0 ):
740            notify = QtGui.QMessageBox.warning(self,'Read from .wd.olddata',"Error message:\n\nCould not read from file. I/O error.")
741        else: 
742            # Save data in array job_data_old
743            for j in range(0,len(result)):
744                job_data_old.append(j)
745                job_data_old[j] = result[j].split(" ")
746                job_data_old[j] = filter(None, job_data_old[j])
747                job_data_old[j] = [line.rstrip('\n') for line in job_data_old[j]]
748               
749                # Check if line j is the selected job, if not -> save to file
750                if ( job_data_old[j][6] != job_to_delete ):
751                    printstring = str(job_data_old[j][0]) + " " + \
752                                  str(job_data_old[j][1]) + " " + \
753                                  str(job_data_old[j][2]) + " " + \
754                                  str(job_data_old[j][3]) + " " + \
755                                  str(job_data_old[j][4]) + " " + \
756                                  str(job_data_old[j][5]) + " " + \
757                                  str(job_data_old[j][6]) + " " + \
758                                  str(job_data_old[j][7]) + "\n"
759                    file.write(printstring)
760           
761        file.close() 
762
763    # Remove all completed jobs from list
764    def ClearList(self):
765     
766       num_of_lines = self.table.rowCount()
767       
768       # Delete all lines with completed/canceled jobs from list. The counter
769       # must decrease as the line numbers would be messed up otherwise
770       for j in range(num_of_lines-1,-1,-1): 
771           state = self.table.item(j,3).text()
772           if ( state == "Completed" or state == "Canceled" or state == "Terminated"):
773              self.RemoveFromList(j)
774         
775    # Update the label
776    def UpdateLabel(self):
777        remaining_time = (update_frequency - self.timetimer.elapsed()) / 1000 / 60
778        self.label.setText("Next update in " + str(remaining_time) + " min")
779       
780
781# Main loop       
782def main():
783   
784    app = QtGui.QApplication(sys.argv)
785    res = Watchdog() 
786    sys.exit(app.exec_())
787
788
789if __name__ == '__main__':
790    main()   
Note: See TracBrowser for help on using the repository browser.