From 16a13e8cea53b925dc8608caee38b6e36718fddf Mon Sep 17 00:00:00 2001
From: David Robert Verelst <dave@dtu.dk>
Date: Thu, 4 Aug 2016 20:41:08 +0200
Subject: [PATCH] launch.py: add crontab mode

---
 launch.py | 68 ++++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 57 insertions(+), 11 deletions(-)

diff --git a/launch.py b/launch.py
index 836c4e4..5293931 100755
--- a/launch.py
+++ b/launch.py
@@ -77,6 +77,7 @@ def load_pbsflist(fname):
     f = open(fname, 'r')
     # drop the newline character
     pbsflist = [line[:-1] for line in f]
+    f.close()
     return pbsflist
 
 def save_pbsflist(fname, pbsflist):
@@ -95,6 +96,32 @@ def write_qsub_exe(fname, pbs, tsleep=0.25):
 
     return job_id
 
+def write_crontab():
+    """Create a crontab script, and submit to crontab.
+    """
+    python = '/usr/bin/python'
+    launch = '/home/MET/repositories/toolbox/pbsutils/launch.py'
+
+    cwd = os.getcwd()
+    fpath = os.path.join(cwd, 'launch_crontab.sh')
+    # TODO: parse other relevant arguments as well: --re
+    # but not the free cpu's etc, they are read from the config file
+    crontab = '*/5 * * * * cd "%s"; %s %s --crontab' % (cwd, python, launch)
+    f = open(fpath, 'w')
+    f.write(crontab)
+    f.flush()
+    f.close()
+    cmd = 'crontab %s' % fpath
+    p = sproc.Popen(cmd, stdout=sproc.PIPE, stderr=sproc.STDOUT, shell=True)
+    stdout = p.stdout.readlines()
+    p.wait()
+
+def remove_crontab():
+    cmd = 'crontab -r'
+    p = sproc.Popen(cmd, stdout=sproc.PIPE, stderr=sproc.STDOUT, shell=True)
+    stdout = p.stdout.readlines()
+    p.wait()
+
 def qsub(fname, qsub_cmd='qsub %s'):
     """
     Parameters
@@ -432,10 +459,7 @@ class Scheduler:
         self.fname_cluster_state = 'launch_scheduler_state.txt'
         self.reload_pbsflist = 0
 
-        self.write_config()
-        self.init_state_log()
-
-    def __call__(self, depend=False):
+    def __call__(self, depend=False, crontab_mode=False):
         """
         Parameters
         ----------
@@ -446,7 +470,7 @@ class Scheduler:
         """
         if not depend:
             print '            method ; scheduler'
-            self.launch()
+            self.launch(crontab_mode=crontab_mode)
         else:
             print '        method ; dependencies'
             self.launch_deps()
@@ -535,7 +559,7 @@ class Scheduler:
 
         return cpu_free, cpu_user, cpu_user_queue
 
-    def launch(self):
+    def launch(self, crontab_mode=False):
         """
         Iterate over all the pbs files and launch them if there are cpus
         available, and if the maximum number of predifined cpus is not reached.
@@ -628,6 +652,10 @@ class Scheduler:
                 # measure
                 time.sleep(self.tsleep_short)
                 ii += 1
+            elif crontab_mode:
+                fname = os.path.join(os.getcwd(), 'pbs_in_file_cache.txt')
+                save_pbsflist(fname, self.pbsflist[ii:])
+                break
             else:
                 # wait a bit before trying to launch a job again
                 if self.debug:
@@ -643,6 +671,8 @@ class Scheduler:
             # stop when we handled all the files
             if ii >= ii_max:
                 print 'All jobs have been launched, stopping the scheduler.'
+                if crontab_mode:
+                    remove_crontab()
                 break
 
     def launch_deps(self):
@@ -796,10 +826,10 @@ if __name__ == '__main__':
                         'cpus available for you. Default=48')
     parser.add_argument('--cpu_user_queue', action='store', dest='cpu_user_queue',
                         type='int', default=500, help='No more jobs will be '
-                        'launched after having cpu_user_queue number of jobs'
-                        'in the queue. This prevents users from filling the'
-                        'queue, while still allowing to aim for a high cpu_free'
-                        'target.')
+                        'launched after having cpu_user_queue number of jobs '
+                        'in the queue. This prevents users from filling the '
+                        'queue, while still allowing to aim for a high cpu_free '
+                        'target. Default=500')
     parser.add_argument('--qsub_cmd', action='store', dest='qsub_cmd',
                         default='qsub %s',
                         help='Is set automatically by --node flag')
@@ -807,6 +837,9 @@ if __name__ == '__main__':
                         default=False, help='If executed on dedicated node.')
     parser.add_argument('--sort', action='store_true', dest='sort',
                         default=False, help='Sort pbs file list. Default=False')
+    parser.add_argument('--crontab', action='store_true', dest='crontab',
+                        default=False, help='Crontab mode. Implies --cache, '
+                        'and not compatible with --node. Default=False')
     parser.add_argument('--debug', action='store_true', dest='debug',
                         default=False, help='Debug print statements. Default=False')
     (options, args) = parser.parse_args()
@@ -866,10 +899,23 @@ if __name__ == '__main__':
     else:
         path_log = None
 
+    if options.crontab:
+        options.cache = True
+
     ss = Scheduler(options.nr_cpus, path_pbs_files=options.path_pbs_files,
                    search_crit_re=options.search_crit_re, dryrun=options.dry,
                    tsleep=options.tsleep, logfile=path_log,
                    cache=options.cache, cpu_free=options.cpu_free,
                    qsub_cmd=options.qsub_cmd, sort=options.sort,
                    debug=options.debug, cpu_user_queue=options.cpu_user_queue)
-    ss(options.depend)
+    if options.crontab:
+        if os.path.exists(os.path.join(os.getcwd(), 'launch_crontab.sh')):
+            ss.read_config()
+        else:
+            ss.write_config()
+            ss.init_state_log()
+            write_crontab()
+    else:
+        ss.write_config()
+        ss.init_state_log()
+    ss(depend=options.depend, crontab_mode=options.crontab)
-- 
GitLab