~ salmonella-environment-setup (master) ac8cf03665f43e21a8b4294e30c79277ed32a920


commit ac8cf03665f43e21a8b4294e30c79277ed32a920
Author:     Mario Domenech Goulart <mario@parenteses.org>
AuthorDate: Sat Apr 17 20:49:26 2021 +0200
Commit:     Mario Domenech Goulart <mario@parenteses.org>
CommitDate: Sat Apr 17 20:49:29 2021 +0200

    run-salmonella.sh: proper locking to prevent multiple instances
    
    This change implements locking to prevent multiple simultaneous
    executions of run-salmonella.sh.
    
    Locks are created in /tmp.  THe lock is a directory (salmonella-lock)
    with a `pid' file which contains the process identifier of the running
    process.
    
    For debugging, `/tmp/salmonella-$$.log` files are created.  They
    contain information about locking events and are cleaned up upon
    termination of run-salmonella.sh.

diff --git a/run-salmonella.sh b/run-salmonella.sh
index 8a7aaeb..a3cf665 100755
--- a/run-salmonella.sh
+++ b/run-salmonella.sh
@@ -5,7 +5,23 @@ SRC_CONF_DIR=$ROOT_DIR/conf
 HOOKS_DIR=$ROOT_DIR/hooks
 LOCAL_CONF_DIR=$HOME/.salmonella-run-publish
 WORK_DIR=$HOME/salmonella/build
-LOG_DIR=$HOME/salmonella
+
+LOCK_DIR=/tmp/salmonella-lock
+LOCK_PID=/tmp/salmonella-lock/pid
+
+# Temporary log file.  It won't be published as part of job artifacts.
+# It is mostly to log events related to locking.
+TMP_LOG_FILE=/tmp/salmonella-$$.log
+
+
+cleanup() {
+    rm -rf "$LOCK_DIR"
+    rm -f "$TMP_LOG_FILE"
+}
+
+
+trap cleanup EXIT INT TERM
+
 
 usage() {
     cat <<EOF
@@ -71,22 +87,19 @@ SETTINGS_FILES="\
 run_hooks() {
     # Call hooks scripts, passing $OS, $ARCH, CHICKEN_4_PREFIX and
     # CHICKEN_5_PREFIX as arguments
-    local hooks_logfile
     local hook
     local hook_dir
 
-    hooks_logfile=${LOG_DIR}/hooks.log
-
-    mkdir -p "$LOG_DIR"
-    rm -f "$hooks_logfile"
+    mkdir -p "$WORK_DIR"
+    hooks_log_file=${WORK_DIR}/hooks.log
 
     for hook_dir in "${HOOKS_DIR}/common" "${HOOKS_DIR}/${OS}" "${HOOKS_DIR}/${OS}/${ARCH}"
     do
         if [ -d "$hook_dir" ]; then
             for hook in "${hook_dir}/"*; do
                 if [ -x "$hook" ]; then
-                    echo "=== Running hook $hook ===" >>"$hooks_logfile"
-                    "$hook" "$OS" "$ARCH" "$CHICKEN_4_PREFIX" "$CHICKEN_5_PREFIX" >>"$hooks_logfile" 2>&1
+                    echo "=== Running hook $hook ===" > "$hooks_log_file"
+                    "$hook" "$OS" "$ARCH" "$CHICKEN_4_PREFIX" "$CHICKEN_5_PREFIX" >>"$hooks_log_file" 2>&1
                 fi
             done
         fi
@@ -94,50 +107,35 @@ run_hooks() {
 }
 
 
-main() {
+run_salmonella() {
+    local confs
     confs=$@
 
-    # Check if all conf files exist
-    for conf in $confs; do
-        if [ ! -e "$SRC_CONF_DIR/${conf}.conf" ]; then
-            echo "No configuration file found for '$conf'.  Aborting." >&2
-            exit 1
-        fi
-    done
-
-    mkdir -p "$LOG_DIR" "$WORK_DIR"
-    local watchdog_logfile
-    watchdog_logfile="$LOG_DIR/watchdog.log"
+    mkdir -p "$WORK_DIR"
 
     # Run salmonella from $WORK_DIR
     cd "$WORK_DIR"
 
-    ### Prevent two salmonellas from running simultaneously
-    while ps ax | grep '[s]almonella-run-publish'; do
-        echo "[`date`] Salmonella still running" >> "$watchdog_logfile"
-        # OpenBSD's sleep doesn't suffixes like `h' (hours) or `m' (minutes)
-        sleep 3600
-    done
-
-    # Remove leftovers from previous executions
-    rm -rf salmonella-run-publish
-
-    # Create the directory for the log file
-    mkdir -p "$RUN_SALMONELLA_TMP_DIR"
-
-    # Load settings files
-    local settings_file
-    for settings_file in $SETTINGS_FILES; do
-        if [ -e "$settings_file" ]; then
-            info "Loading $settings_file"
-            . "$settings_file"
-        fi
-    done
-
     local salmonella_run_publish
     salmonella_run_publish="$CHICKEN_TESTS_PREFIX/bin/salmonella-run-publish"
 
     for conf in $confs; do
+
+        # Remove leftovers from previous executions.  Once
+        # `$RUN_SALMONELLA_TMP_DIR` is created it is safe to use
+        # `info'.
+        rm -rf "$RUN_SALMONELLA_TMP_DIR"
+        mkdir -p "$RUN_SALMONELLA_TMP_DIR"
+
+        # Load settings files
+        local settings_file
+        for settings_file in $SETTINGS_FILES; do
+            if [ -e "$settings_file" ]; then
+                info "Loading $settings_file"
+                . "$settings_file"
+            fi
+        done
+
         # The inline egg writes some stuff to the home dir
         rm -rf ~/.chicken-inline
 
@@ -157,10 +155,46 @@ main() {
             info "Loading $conf_path"
             "$salmonella_run_publish" "$conf_path" >>"$log_file" 2>&1
         fi
-        [ -d salmonella-run-publish ] && mv salmonella-run-publish "salmonella-$conf"
+        [ -d "$RUN_SALMONELLA_TMP_DIR" ] &&
+            mv "$RUN_SALMONELLA_TMP_DIR" "salmonella-$conf"
     done
 }
 
+
+main() {
+    # Check if all conf files exist
+    local conf
+    for conf in $@; do
+        if [ ! -e "$SRC_CONF_DIR/${conf}.conf" ]; then
+            echo "No configuration file found for '$conf'.  Aborting." >&2
+            exit 1
+        fi
+    done
+
+    while true; do
+        if mkdir "$LOCK_DIR" 2>/dev/null; then
+            echo $$ > "$LOCK_PID"
+            echo "[$(date)] $$ acquired lock" >> "$TMP_LOG_FILE"
+            run_salmonella "$@"
+            cleanup
+            exit
+        else
+            # Check if the lock is stale
+            local pid
+            pid=$(cat "$LOCK_PID")
+            if kill -0 "$pid" 2>/dev/null; then
+                echo "[$(date)] Waiting for $pid" >> "$TMP_LOG_FILE"
+                sleep 60
+            else
+                # Lock is stale.  Cleanup and continue.
+                echo "[$(date)] Cleaning up stale lock (pid=$pid)" >> "$TMP_LOG_FILE"
+                cleanup
+            fi
+        fi
+    done
+}
+
+
 if [ "$1" = "-h" ] || [ "$1" = "-help" ] || [ "$1" = "--help" ]; then
     usage
     exit 0
Trap