Please note that the CVS and issue trackers have moved to GitHub. These Trac pages are no longer kept up-to-date.

root/seattle/trunk/deploymentscripts/runlocaltests.py@5637

Revision 2810, 26.3 KB (checked in by konp, 10 years ago)

Fixed high cpu usage, added summary tool, a number of other fixes and improvements as well. Note: blackbox node keys have not been added yet.

Line 
1"""
2<Program Name>
3  runlocaltests.py
4
5<Started>
6  May 2009
7
8<Author>
9  n2k8000@u.washington.edu
10  Konstantin Pik
11
12<Purpose>
13  Executes test files from deploy.tar. This file is not to be used by itself,
14  but instead should be packaged in deploy.tar (which is all performed by the
15  deploy.py script). This runs on the remote machine, and assumes that the
16  deploy.tar is in the same directory.
17
18<Usage>
19  Note: Not indended to run as a standalone (but can be).
20
21  python runlocaltests.py myhostname [-v 0|1|2] [scriptname]
22
23  myhostname:   Required. The hostname of this computer. Used for some path
24                  information (logs, etc).
25  -v:           Optional. Sets verbosity level.
26                  0: Default. log only other scripts
27                  1: log other scripts + this script
28                  2: very verbose: log all other + this + console output
29                  all other values default to 0
30  scriptname:   Optional. Default None.  Additional script file to execute.
31                  This must be a python script (TODO: add .sh script capability)
32"""
33
34import os
35import sys
36import time
37import subprocess
38import thread
39
40# used to keep track of how long it took the script to run
41start_time = 0
42
43# the name of custom script to run, if needed
44custom_script_name = ''
45
46# only run the custom script?
47only_custom_script = False
48
49# the hostname of this computer as seen by intiating script
50my_host_name = ''
51
52# Verbosity flag (0, 1, 2)
53verbosity = 0
54
55# Lock on the log file. There isn't any multi threading in this file
56# but just in case I put this here.
57filelock = thread.allocate_lock()
58
59# This file will traverse multiple directories and search for seattle
60# installs.  This variable changes the path to each install directory.
61logdir = ''
62
63
64# The of the seattle_install file: typically either .tar or .tgz TODO: remove
65seattle_linux_ext = ''
66
67def find_seattle_installs():
68  """
69  <Purpose>
70    Finds all seattle install directories. (cares only about the first
71      one found)
72
73    Priority:
74      1. ./seattle_repy folder (exit after find)
75      2. ./[remotehost]/seattle_repy folder (exit after find)
76      3. search ALL folder with search depth 1 for a seattle_repy folder
77
78    Also assumes that seattle_repy is the name of the install directory.
79     
80  <Arguments>
81    None.
82   
83  <Exceptions>
84    None.
85
86  <Side Effects>
87    None.
88
89  <Returns>
90    A list containing the path to the folder containing seattle_repy install
91  """
92  global my_host_name
93
94  # This will keep track of which folders have a seattle installation
95  valid_folder = []
96
97  log("Checking for seattle_repy directory..")
98
99  # Check for seattle_repy dir from where we are now..
100  if os.path.isdir("./"+my_host_name+"/seattle_repy"):
101    log("Good news! seattle_repy found in "+my_host_name+". Not searching anywhere else.")
102    valid_folder.append("./"+my_host_name+"/seattle_repy")
103  elif os.path.isdir("./seattle_repy"):
104    log("Good news! Found seattle_repy in $HOME Not looking anywhere else.")
105    valid_folder.append("./seattle_repy")
106  else:
107    # search each folder in current directory
108    log("NOTICE: seattle_repy not found in default directories.. Searching local folders.")
109    # otherwise check all folders with depth one.
110    for folder in os.listdir('.'):
111      # if inside that folder we have a seattle install, add it to our list
112      if os.path.isdir("./"+folder+"/seattle_repy"):
113        log("Found seattle install in "+folder)
114        valid_folder.append("./"+folder+"/seattle_repy")
115        return valid_folder
116 
117  # return list (with one element, the path) folder with a seattle_install
118  return valid_folder
119
120
121 
122def get_current_time():
123  """
124  <Purpose>
125    Uses python's time lib to return the current time. This is formatted
126    in what I find a convenient way to show time in the logs.
127     
128  <Arguments>
129    None.
130   
131  <Exceptions>
132    None.
133
134  <Side Effects>
135    None.
136
137  <Returns>
138    The date as a string.
139   
140    Sample date returned: May 16 2009 00:21:51
141  """
142  return time.strftime("%b %d %Y %T")
143
144 
145
146def logerror(data):
147  """
148  <Purpose>
149    Wrapper to log to an error log file, and prints to console in case we're
150      not in -v 2 mode.
151     
152  <Arguments>
153    data:
154      The error description/etc.
155   
156  <Exceptions>
157    None.
158
159  <Side Effects>
160    None.
161
162  <Returns>
163    No returns.
164  """
165  global verbosity, logdir, my_host_name
166
167  # print only if not -v 2.. dont want to spam stdout more than we already are
168  if verbosity < 2:
169    print 'ERROR:'+str(data)
170
171  # change logdir to '' so we log to our main error log file, then we'll
172  # change it back to the directory we were working with
173  logdir_temp = logdir
174  logdir = ''
175  log(my_host_name+': Error: '+data+'(logdir: '+logdir_temp+')', False, True, '', 'deployrun.err')
176  logdir = logdir_temp
177  return
178
179 
180 
181def log(data, sep=False, timestamp=False, scriptdesc='[runlocaltests.py] ', fn='deployrun'):
182  """
183  <Purpose>
184    Logs data to a file.
185     
186  <Arguments>
187    data: The data to log.
188    sep:  Optional. Default is False. Is this a separator string?
189    timestamp:  Optional. Default is False. Timestamp this msg?
190    scriptdesc: Optional. Description of the msg (appended to front of msg)
191    fn: Optional. Default is deploy.run. The log file name. Unless you're
192          adding functions to this .py file, it's not recommended you change
193          the log file name.
194
195    IMPORTANT: this will always log to [myhostname].[fn].log
196        fn -> parameter/filename
197        myhostname -> hostname of this computer as seen by others
198   
199  <Exceptions>
200    None.
201
202  <Side Effects>
203    None.
204
205  <Returns>
206    None.
207  """
208  global verbosity
209  global filelock
210  global logdir
211  global my_host_name
212
213  # lock the log file
214  filelock.acquire()
215
216  # logdir path variable isn't empty then use it
217  if logdir:
218    logfile = open(logdir+'/deploy.logs/'+fn+'.log', 'a')
219  else: # otherwise log to default dir with default file name
220    logfile = open(my_host_name+'.'+fn+'.log', 'a')
221
222  # We're going to build up the string we're going to log
223  logstring = ''
224 
225  # Write separator if flag is set
226  if sep :
227    # there is no custom separator to use, use the default
228    if data == '':
229      logstring = '\n------------------------------------------------------------------------'
230    else: # custom separator specified
231      logstring = '\n'+data
232 
233  # if it's not a separator then process rest of args
234  if not sep:
235    # if our verbosity is 0 then script must not be runlocaltests.py
236    # or our verbosity has to be greater than 1
237    # if verbosity == 1, then scriptdesc MUST be blank (means it's a
238    # foreign script)
239    if (verbosity == 1 and scriptdesc == '') or (verbosity == 0 and 
240      scriptdesc != '[runlocaltests.py] ') or (verbosity == 2): 
241        logstring += '\n'
242
243        # do we need a timestamp?
244        if timestamp:
245          logstring += get_current_time()+" | "
246       
247        logstring += scriptdesc+str(data)
248
249  # if our string isn't empty by this time then...
250  if logstring.strip('\n '):
251    # on verbosity == 2, we print to stdout as well.
252    # NOTE: THIS HAS THE POTENTIAL TO MAKE YOUR LOGS LARGE AS
253    # ALL OUTPUT WILL BE DOUBLE.. STDOUT WILL BE LOGGED AS WELL
254    # AS THE LOG FILE (on the calling machine)
255    if verbosity == 2:
256      print my_host_name+': '+logstring.strip('\n ')
257 
258    logfile.write(logstring)
259
260
261
262  logfile.close()
263
264  filelock.release()
265  return
266
267 
268 
269def is_locked(pathtodir):
270  # OBSOLETE
271  """
272  <Purpose>
273    Checks whether a directory was locked with lock_dir().
274   
275  <Arguments>
276    pathtodir
277      Path to the directory to check.
278   
279  <Exceptions>
280    None.
281
282  <Side Effects>
283    None.
284
285  <Returns>
286    A tuple:   (Locked, ValidDirectory, DescriptionString)
287   
288    Detailed
289    Locked: Boolean. Is the directory locked?
290    Valid: Boolean. Is this a valid directory?
291    DescriptionString: String. A human readable response to whether we
292                        obtained a lock or not, and why.
293  """
294  return (False, True, 'Obsolete')
295  #checks whether a dir has a lock
296  if os.path.isdir(pathtodir):
297    # yes it is a dir.. now check if there's a lock file
298    if not os.path.isfile(pathtodir+'/DIR.lock'):
299      return (False, True, 'No lock file in directory')
300    # is a directory, but file exists
301    return (True, True, 'Lock file exists in directory')
302  else:
303    # invalid dirs result in lock = true as far as we're concerned.
304    return (True, False, 'Not a valid directory')
305
306   
307   
308def lock_dir(pathtodir):
309  # OBSOLETE
310  """
311  <Purpose>
312    "Locks" a directory by creating a .LOCK file in it.
313
314    This prevents multiple instances of a script from messing with the same
315    directory at the same time.
316   
317  <Arguments>
318    pathtodir
319      Path to the directory to lock.
320   
321  <Exceptions>
322    None.
323
324  <Side Effects>
325    None.
326
327  <Returns>
328    Boolean. Did we successfully lock the directory?
329  """
330  return True
331  # We'll use this as our flag on whether we succeeded or not.
332  return_status = False
333
334  # is it a directory?
335  if os.path.isdir(pathtodir):
336    # yes! make a file
337    try:
338      lock_handle = open(pathtodir+'/DIR.lock', 'w')
339      lock_handle.write('\n')
340    except Exception, e:
341      logerror('Something went wrong while locking '+pathtodir)
342    else: # no exception
343      return_status = True
344    finally:
345      lock_handle.close()
346
347  return return_status
348
349
350 
351def shellexec(cmd_str):
352  """
353  <Purpose>
354    Uses subprocess to execute the command string in the shell.
355     
356  <Arguments>
357    cmd_str:  The string to be treated as a command (or set of commands,
358                separated by ;).
359   
360  <Exceptions>
361    None.
362
363  <Side Effects>
364    Sometimes on NFS, a file may be 'shared' amongst different computers
365    (since all file uploads are to ~/), so if we get a NFS error, we'll sleep
366    and then try executing our command again.
367
368  <Returns>
369    A tuple containing (stdout, strerr)
370
371    Detailed:
372    stdout: stdout printed to console during command execution.
373    strerr: error (note: some programs print to strerr instead of stdout)
374  """
375  global verbosity
376  # get a handle to the subprocess we're creating..
377  handle = subprocess.Popen(cmd_str, shell=True, 
378      stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
379
380  # execute and grab the stdout and err
381  stdoutdata, strerrdata = handle.communicate("")
382 
383  # this is a hack, but if we run into a stale NFS file handle, then sleep 2-3
384  # seconds, and try to execute command again. we'll put this in a loop, so we can
385  # do this up to three times
386  retries_left = 3
387
388  # set flag so we enter our loop
389  staleNFS = True
390
391  while(retries_left > 3 and staleNFS):
392    if retries_:
393      # check both out and err for the string indicating stale NFS file handle
394      stdout_has_err = stdoutdata.find('Stale NFS file handle') > -1
395      strerr_has_err = strerrdata.find('Stale NFS file handle') > -1
396      if stdout_has_err or strerr_has_err:
397        # stale :(
398        time.sleep(2)
399        # retry the command.
400        handle = subprocess.Popen(cmd_str, shell=True, 
401          stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
402        # execute and grab the stdout and err
403        stdoutdata, strerrdata = handle.communicate("")
404        # decrease times we can retry the command
405        retries_left -= 1
406      else:
407        # no more staleNFS!
408        staleNFS = False
409
410  # If we're really verbose, then log the exact command string we executed.
411  if verbosity == 2:
412    log(cmd_str)
413
414  return stdoutdata, strerrdata
415
416 
417 
418def loghelper(stdout, stderr):
419  """
420  <Purpose>
421    Helper for the log method. This just formats stdout and stderr before
422    passing it off to log().  Esentially strips off excess trailing \n's and spaces.
423     
424  <Arguments>
425    stdout: out to format.
426    stderr: err to format.
427
428  <Exceptions>
429    None.
430
431  <Side Effects>
432    None.
433
434  <Returns>
435    None.
436  """
437
438  # log stdout
439  stdout = stdout.strip('\n ')
440  stderr = stderr.strip('\n ')
441
442  # The 4th parameter='' so it always logs all output regardless of verbosity
443  # Log only if not empty...
444  if stdout:
445    log(stdout.strip(), False, False, '')
446  if stderr:
447    log(stderr.strip(), False, False, '')
448
449   
450
451def start_timer(): 
452  """
453  <Purpose>
454    This sets the current time to be used in keeping track of how long the
455    script's been running.
456     
457  <Arguments>
458    None.
459   
460  <Exceptions>
461    None.
462
463  <Side Effects>
464    None.
465
466  <Returns>
467    None.
468  """
469
470  global start_time
471  start_time = time.time()
472  return
473
474 
475 
476def stop_timer():
477  """
478  <Purpose>
479    This stops the time keeping track of how long the script's been running.
480     
481  <Arguments>
482    None.
483   
484  <Exceptions>
485    None.
486
487  <Side Effects>
488    None.
489
490  <Returns>
491    The elapsed time in seconds.
492  """
493
494  global start_time
495  return (time.time() - start_time)
496
497 
498 
499def kill_hung_testprocess_module():
500  """
501  <Purpose>
502    This is a workaround for killing hung testprocess.py modules that did not
503    have a clean exit.
504     
505  <Arguments>
506    None.
507   
508  <Exceptions>
509    None.
510
511  <Side Effects>
512    Kills all running modules that have the string testprocess.py in their name.
513
514  <Returns>
515    None.
516  """
517  # lists all processes, finds ones that have the testprocess.py string,
518  # eliminates anything with the grep string, the awk command line prints out th PID
519  # and xargs pipes the PID to kill via command line.
520  shellexec("ps -ef | grep testprocess.py | grep -v grep | awk '{ print $2 } ' | xargs kill -9")
521 
522 
523 
524def start_scripts(folder_list):
525  """
526  <Purpose>
527    This initiates the checking of the list of discovered seattle install
528    folders by extracting and executing each script.
529     
530  <Arguments>
531    folder_list:  the list of folders that contain installs of seattle
532   
533  <Exceptions>
534    None.
535
536  <Side Effects>
537    None.
538
539  <Returns>
540    None.
541  """
542  global logdir, seattle_linux_ext, custom_script_name, only_custom_script
543 
544  # the following kills the testprocess module that may be hung from previous timeouts.
545  kill_hung_testprocess_module()
546 
547 
548  # cmd list is our general command list that we will use for each directory
549  # by replacing $INSTALL with the path to the installation directory.
550  # then in the for loop we execute each command by index number
551  cmd_list = []
552
553  # 0. Untar the three files (two scripts, and one dictionary that'll
554  #     be used to verify file hashes.
555  cmd_list.append('tar -xf deploy.tar testprocess.py verifyfiles.mix hashes.dict deploy_helper.py')
556
557  # 1+2. move the two files to install directory
558  cmd_list.append('cp testprocess.py $INSTALL/testprocess.py')
559  cmd_list.append('cp verifyfiles.mix $INSTALL/verifyfiles.mix;'+\
560    'cp hashes.dict $INSTALL/hashes.dict; cp deploy_helper.py $INSTALL/deploy_helper.py')
561
562
563  # 3. Change dir because python will look in cwd when executing repypp.py
564  #     and as a result the files required for the 'include' statements
565  #     run repypp.py on verifyfiles.mix
566  cmd_list.append('cd $INSTALL; python repypp.py verifyfiles.mix '+\
567    'verifyfiles.py')
568
569  # 4. run the first test script
570  cmd_list.append('python $INSTALL/testprocess.py')
571 
572  # 5. run the second test script
573  #  Note that we need to cd to $INSTALL and one above it directory because
574  # of the way that verifyfiles.py is written - starts checking in local
575  # directory for scripts. then we need to assume that the .tar containing the
576  # install is in our home path (which it should be).
577  cmd_list.append('cd $INSTALL; python verifyfiles.py '+\
578    '-readfile hashes.dict ../')
579 
580  # 6+7+8. do we have a custom script? << This is still in progress.
581  if custom_script_name:
582    cmd_list.append('tar -xf deploy.tar '+custom_script_name)
583    cmd_list.append('cp '+custom_script_name+' $INSTALL/'+custom_script_name)
584    cmd_list.append('python $INSTALL/'+custom_script_name+' $INSTALL')
585
586  # enumerate through each folder path now
587  for folder in folder_list:
588    # check if folder is locked
589    # if a folder is locked then another deploy-checking script is using this folder
590    # and we just skip through it.
591    islocked, validdir, dscrptn_str = is_locked(folder)   
592
593    # The directory needs to be 'unlocked' (no other script is checking that
594    # folder now and if it is then we'll go through with our check of that
595    # folder
596    if islocked: # locked.
597      if validdir: # and a valid directory path
598        logerror('Directory '+folder+' is locked. Moving on.')
599      else:
600        # this means that it's an invalid directory. Should technically
601        # never hapnd if the script is running by itself as it auto-discovers
602        # directories and stores them properly. This *might* occur if a
603        # directory is being modified/renamed/deleted WHILE the script is
604        # running (which this script does not do).
605        logerror('Directory '+folder+' is an invalid path. Moving on.')
606    else: # no lock found!
607
608      # try to lock the folder
609      locked_successfully = lock_dir(folder)
610
611      if not locked_successfully: # coudln't lock folder..
612        logerror('Locking '+folder+'. Moving on.')
613      else: # folder locked successfully, start the beefy chunks..
614        # Check if we only need to run the custom test file, or all the scripts
615        if not only_custom_script:
616         
617          # setup a log dir for that install
618          log('Creating log directory in '+folder)
619          shellexec('mkdir '+folder+'/deploy.logs')
620
621          # set the logdir global so we can start logging in that folder.
622          logdir = folder
623
624          log('=============Running from folder:'+folder, True, False, '')
625
626          # NOTE: Please see above what each index means in more detail
627          stdoutdata, stderrdata = shellexec(cmd_list[0])
628          loghelper(stdoutdata, stderrdata)
629          log("Untarred testprocess.py verifyfiles.mix successfully")
630
631          # the .replace's below just replace $INSTALL with the folder we're
632          # dealing with
633
634          stdoutdata, stderrdata = shellexec(cmd_list[1].replace('$INSTALL', folder))
635          loghelper(stdoutdata, stderrdata)
636          stdoutdata, stderrdata = shellexec(cmd_list[2].replace('$INSTALL', folder))
637          loghelper(stdoutdata, stderrdata)
638          log("Moved files into $INSTALL sucessfully".replace('$INSTALL', folder))
639         
640          log("Attempting to run repypp.py on verifyfiles.mix...")
641          stdoutdata, stderrdata = shellexec(cmd_list[3].replace('$INSTALL', folder))
642          loghelper(stdoutdata, stderrdata)
643          log("repypp executed sucessfully.") 
644
645
646          log("Running testprocess.py", False, False)
647          stdoutdata, stderrdata = shellexec(cmd_list[4].replace('$INSTALL', folder))
648          loghelper(stdoutdata, stderrdata)
649         
650          log("Running verifyfiles.py", False, False)
651          stdoutdata, stderrdata = shellexec(cmd_list[5].replace('$INSTALL', folder))
652          # there'll be 4 lines that we need to strip from output because they'll always
653          # marked as 'unknown files' but we know they're safe. Log them only in v = 2
654          if verbosity < 2:
655            stdoutdata = stdoutdata.replace('testprocess.py:Warning:Unknown file\n', '')
656            stdoutdata = stdoutdata.replace('verifyfiles.py:Warning:Unknown file\n', '')
657            stdoutdata = stdoutdata.replace('verifyfiles.mix:Warning:Unknown file\n', '')
658            stdoutdata = stdoutdata.replace('DIR.lock:Warning:Unknown file\n', '')
659            stdoutdata = stdoutdata.replace('hashes.dict:Warning:Unknown file\n', '')
660          loghelper(stdoutdata, stderrdata)
661       
662        # one more script to run.
663        if custom_script_name:
664          log("Running custom script ("+custom_script_name+"):", False, False, '')
665          stdoutdata, stderrdata = shellexec(cmd_list[6].replace('$INSTALL', folder))
666          loghelper(stdoutdata, stderrdata)
667          stdoutdata, stderrdata = shellexec(cmd_list[7].replace('$INSTALL', folder))
668          loghelper(stdoutdata, stderrdata)
669          stdoutdata, stderrdata = shellexec(cmd_list[8].replace('$INSTALL', folder))
670          loghelper(stdoutdata, stderrdata)
671
672
673        log('Cleaning up and moving on...')
674        # Try to delete the files we were using so that we don't leave
675        # any junk behind
676        try:
677          if os.path.isfile(folder+'/verifyfiles.mix'):
678            os.remove(folder+'/verifyfiles.mix')
679          if os.path.isfile(folder+'/verifyfiles.py'):
680            os.remove(folder+'/verifyfiles.py')
681          if os.path.isfile(folder+'/testprocess.py'):
682            os.remove(folder+'/testprocess.py')
683          if os.path.isfile(folder+'/deploy_helper.py'):
684            os.remove(folder+'/deploy_helper.py')
685          if custom_script_name and os.path.isfile(folder+'/'+custom_script_name):
686            os.remove(folder+'/'+custom_script_name)
687        except Exception, e:
688          logerror("Error cleaning temp files from "+folder+"("+str(e)+")")
689          continue # Don't stop! keep going
690        # reset logdir to mainlog file
691        # logdir = ''
692
693
694
695def init_setup():
696  """
697  <Purpose>
698    Calls list of methods that cannot fail. If we can't set up our environment
699    then return false.
700
701  <Arguments>
702    None.
703   
704  <Exceptions>
705    None.
706
707  <Side Effects>
708    None.
709
710  <Returns>
711    Boolean. Did all the setup scripts succeed?
712  """
713  # Currently empty.
714
715  return True
716 
717 
718
719def main(args):
720  """
721  <Purpose>
722    Entry point into the script. This checks that all the parameters are
723    correctly specified and the script is called validly. Next, it finds the
724    seattle_repy directory and moves scripts there, then calls the custom
725    script (if one exists) and passes in one argument: the path to the
726    seattle_install.
727
728    Note: it is important that your custom script must use absolute paths
729    to the install directory.
730
731  <Arguments>
732    None.
733   
734  <Exceptions>
735    None.
736
737  <Side Effects>
738    None.
739
740  <Returns>
741    None.
742  """
743  start_timer()
744  #  runlocaltests.py myhostname [-v 0|1|2] [customscriptname]
745  global verbosity
746  global logdir
747  global my_host_name
748  global custom_script_name
749  global only_custom_script
750 
751  # Method that sets up the environment (verbosity, custom scripts, etc)
752  if args and len(args) >= 2:
753    my_host_name = args[1]
754    if len(args) >=3: # check for -v flags
755      if args[2] == '-v':
756        if len(args) >= 4:
757          # different verbosity levels
758          # 0: default, log only other scripts
759          # 1: log other scripts + this script
760          # 2: very verbosity: log all other + this + console output
761          # all other values default to 0
762          verbosity = int(args[3])
763          # validate verbosity.
764          if verbosity > 2 or verbosity < 0:
765            verbosity = 0
766          if len(args) >= 5:
767            custom_script_name = args[4]
768            log('Obtained a custom script to run ('+custom_script_name+')')
769          if len(args) >= 6:
770            # this last parameter mean we should JUST execute the custom script file
771            only_custom_script = True
772            log('Only running custom script file')
773           
774  else: # no args..
775    print 'CRITICAL ERROR: HOSTNAME FOR THIS COMPUTER NOT SPECIFIED. EXITING'
776    logerror('CRITICAL ERROR: HOSTNAME FOR THIS COMPUTER NOT SPECIFIED. EXITING')
777    logerror('Elapsed time'+str(stop_timer()))
778    pack_logs(None)
779    return
780
781  print "Verbosity is set to "+str(verbosity) 
782
783  # checking env
784  # TODO: provide .dict file
785  init_setup() 
786
787  log("Starting up local scripts on "+my_host_name)
788 
789  # get list of install folders
790  seattle_folders = find_seattle_installs()
791
792  if not seattle_folders:
793    print "Did not find any seattle installs on "+my_host_name+". Aborting."
794    logerror("Did not find any seattle installs on "+my_host_name+". Aborting.")
795    logerror('Elapsed time'+str(stop_timer()))
796    pack_logs(None)
797    return
798 
799  print "Running local scripts..."
800  # Start checking for a seattle install folder
801  start_scripts(seattle_folders)
802
803  logdir_old = logdir
804  logdir = '' # reset logdir so that we log to default log file
805  log("Scripts are done. Begining cleanup...")
806
807  log("Collecting logs...")
808
809  log("Cleanup complete. Exiting")
810
811  # log back to logdir for the install
812  logdir = logdir_old
813  log('Elapsed execution time for all scripts was '+str(stop_timer())+'s', 
814    False, False, '')
815
816  logdir = ''
817  pack_logs(seattle_folders)
818  return
819
820 
821 
822def pack_logs(seattle_install_paths):
823  """
824  <Purpose>
825    This method packs all the log files from this machine into a gzipped tar
826    and names it [remotehostname].tgz. The calling script (or anyone else) can
827    then pick up the file.
828   
829  <Arguments>
830    seattle_install_paths:
831      List containing one (1) element which is the path to the seattle install.
832   
833  <Exceptions>
834    None.
835
836  <Side Effects>
837    None.
838
839  <Returns>
840    None.
841  """
842  # this will pack all the logs in a .tar file and have it ready for pickup
843  global my_host_name, verbosity
844
845  # we'll be passed in a list, but there should only be one element
846  if seattle_install_paths:
847    seattle_install_path = seattle_install_paths[0]
848
849  # this wil keep track of how many file's we're adding to the tar. if zero by
850  # the time it's time to execute, then don't make one. This'll make an error
851  # in deploy.py and we'll have to check out what went wrong.
852  files_added = 0
853
854  # we'll build up a command string to execute to build our tar
855  command_string = ''
856
857  # the tar will be named my_host_name.tgz
858  if verbosity == 2:
859    command_string += 'tar -czvvf '+my_host_name+'.tgz '
860  else:
861    command_string += 'tar -czf '+my_host_name+'.tgz '
862
863  # add the general logfile only if we're in -v 2, otherwise the file'll have nothing
864  if verbosity == 2:
865    if os.path.isfile('./'+my_host_name+'.deployrun.log'):
866      command_string += ' ./'+my_host_name+'.deployrun.log'
867      files_added += 1
868
869  # grab the error file (will exist only if there were errors)
870  if os.path.isfile('./'+my_host_name+'.deployrun.err.log'):
871    command_string += ' ./'+my_host_name+'.deployrun.err.log'
872    files_added += 1
873
874  # grab the info for that seattle install directory (if not None)
875  if seattle_install_paths:
876    # don't make tar freakout about file not existing (if we errored for some
877    # reason)
878    if os.path.isfile(seattle_install_path+'/deploy.logs/deployrun.log'):
879      command_string += ' -C '+seattle_install_path+'/deploy.logs/ deployrun.log'
880      files_added += 1
881
882  if verbosity == 2:
883    print my_host_name+': Building tar with logs : '+command_string
884  # execute the string! (only if we have more than one file we're adding
885  if files_added > 0:
886    out, err = shellexec(command_string)
887
888    if out.strip('\n '):
889      print out.strip('\n ')
890    if err.strip('\n '):
891      print err.strip('\n ')
892  return
893
894if __name__ == "__main__":
895  main(sys.argv)
Note: See TracBrowser for help on using the browser.