Implement pre functions.
[whenjobs.git] / daemon / daemon.ml
index 25b81b7..ac0f1ff 100644 (file)
@@ -329,57 +329,87 @@ and run_job job =
       serial
     | _ -> assert false in
 
-  Syslog.notice "running %s (JOBSERIAL=%s)"
-    job.job_name (string_of_big_int serial);
-
-  (* Create a temporary directory.  The current directory of the job
-   * will be in this directory.  The directory is removed when the
-   * child process exits.
+  (* Call the pre-condition script.  Note this may decide not to run
+   * the job by returning false.
    *)
-  let dir = tmpdir () in
-
-  let pid = fork () in
-  if pid = 0 then ( (* child process running the job *)
-    chdir dir;
-
-    (* Set environment variables corresponding to each variable. *)
-    List.iter
-      (fun (name, value) -> putenv name (string_of_variable value))
-      (Whenstate.get_variables !state);
-
-    (* Set the $JOBNAME environment variable. *)
-    putenv "JOBNAME" job.job_name;
-
-    (* Create a temporary file containing the shell script fragment. *)
-    let script = dir // "script.sh" in
-    let chan = open_out script in
-    fprintf chan "set -e\n"; (* So that jobs exit on error. *)
-    output_string chan job.job_script.sh_script;
-    close_out chan;
-    chmod script 0o700;
-
-    let shell = try getenv "SHELL" with Not_found -> "/bin/sh" in
-
-    (* Set output to file. *)
-    let output = dir // "output.txt" in
-    let fd = openfile output [O_WRONLY; O_CREAT; O_TRUNC; O_NOCTTY] 0o600 in
-    dup2 fd stdout;
-    dup2 fd stderr;
-    close fd;
-
-    (* Execute the shell script. *)
-    (try execvp shell [| shell; "-c"; script |];
-     with Unix_error (err, fn, _) ->
-       Syslog.error "%s failed: %s: %s" fn script (error_message err)
+  let pre_condition () =
+    match job.job_pre with
+    | None -> true
+    | Some pre ->
+      let rs = ref [] in
+      IntMap.iter (
+        fun pid (job, _, serial, start_time) ->
+          let r = { pirun_job_name = job.job_name;
+                    pirun_serial = serial;
+                    pirun_start_time = start_time;
+                    pirun_pid = pid } in
+          rs := r :: !rs
+      ) !runningmap;
+      let preinfo = {
+        pi_job_name = job.job_name;
+        pi_serial = serial;
+        pi_variables = Whenstate.get_variables !state;
+        pi_running = !rs;
+      } in
+      pre preinfo
+  in
+  if pre_condition () then (
+    Syslog.notice "running %s (JOBSERIAL=%s)"
+      job.job_name (string_of_big_int serial);
+
+    (* Create a temporary directory.  The current directory of the job
+     * will be in this directory.  The directory is removed when the
+     * child process exits.
+     *)
+    let dir = tmpdir () in
+
+    let pid = fork () in
+    if pid = 0 then ( (* child process running the job *)
+      chdir dir;
+
+      (* Set environment variables corresponding to each variable. *)
+      List.iter
+        (fun (name, value) -> putenv name (string_of_variable value))
+        (Whenstate.get_variables !state);
+
+      (* Set the $JOBNAME environment variable. *)
+      putenv "JOBNAME" job.job_name;
+
+      (* Create a temporary file containing the shell script fragment. *)
+      let script = dir // "script.sh" in
+      let chan = open_out script in
+      fprintf chan "set -e\n"; (* So that jobs exit on error. *)
+      output_string chan job.job_script.sh_script;
+      close_out chan;
+      chmod script 0o700;
+
+      let shell = try getenv "SHELL" with Not_found -> "/bin/sh" in
+
+      (* Set output to file. *)
+      let output = dir // "output.txt" in
+      let fd = openfile output [O_WRONLY; O_CREAT; O_TRUNC; O_NOCTTY] 0o600 in
+      dup2 fd stdout;
+      dup2 fd stderr;
+      close fd;
+
+      (* Execute the shell script. *)
+      (try execvp shell [| shell; "-c"; script |];
+       with Unix_error (err, fn, _) ->
+         Syslog.error "%s failed: %s: %s" fn script (error_message err)
+      );
+      _exit 1
     );
-    _exit 1
-  );
 
-  (* Remember this PID, the job and the temporary directory, so we
-   * can clean up when the child exits.
-   *)
-  runningmap := IntMap.add pid (job, dir, serial, time ()) !runningmap;
-  serialmap := BigIntMap.add serial pid !serialmap
+    (* Remember this PID, the job and the temporary directory, so we
+     * can clean up when the child exits.
+     *)
+    runningmap := IntMap.add pid (job, dir, serial, time ()) !runningmap;
+    serialmap := BigIntMap.add serial pid !serialmap
+  )
+  else (
+    Syslog.notice "not running %s (JOBSERIAL=%s) because pre() condition returned false"
+      job.job_name (string_of_big_int serial);
+  )
 
 and tmpdir () =
   let chan = open_in "/dev/urandom" in