source: palm/trunk/SCRIPTS/palm_wd @ 1612

Last change on this file since 1612 was 1612, checked in by maronga, 6 years ago

last commit documented

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