|
|
@@ -1,49 +1,79 @@
|
|
|
#!/bin/sh
|
|
|
|
|
|
+readonly DEFAULT_OUT_FMT="%s.out"
|
|
|
+readonly CMD_FEED="$(mktemp -u distributer-XXX.fifo)"
|
|
|
readonly CONF_LIST="$1"
|
|
|
readonly SERVER_LIST="$2"
|
|
|
+readonly OUT_FMT="${3:-$DEFAULT_OUT_FMT}"
|
|
|
+
|
|
|
+readonly MK_DIR_CMD="if [ ! -d \"$(dirname "$OUT_FMT")\" ]; then
|
|
|
+ mkdir -p \"$(dirname "$OUT_FMT")\" > /dev/null
|
|
|
+ fi"
|
|
|
+
|
|
|
+readonly S_SPACE="s/[[:space:].\/]/_/g"
|
|
|
+readonly R_DASH="s/-//g"
|
|
|
+readonly S_QUOTE="s/'/\\\\'/g"
|
|
|
|
|
|
help() {
|
|
|
- printf "Usage: $(basename $0) cmd_list server_list\n" >&2
|
|
|
+ printf "Usage: $(basename $0) cmd_list server_list [out_file_fmt]\n" >&2
|
|
|
printf " cmd_list: A text file containing a list of commands to run.\n" >&2
|
|
|
printf " server_list: A text file containing a list of servers to\n" >&2
|
|
|
- printf " connect to and run commands on.\n\n" >&2
|
|
|
+ printf " connect to and run commands on.\n" >&2
|
|
|
+ printf " out_file_fmt: File name format to write the output of each\n" >&2
|
|
|
+ printf " command to (default: $DEFAULT_OUT_FMT).\n\n" >&2
|
|
|
printf "All commands will be allocated to the first available server.\n" >&2
|
|
|
printf "Each command must be valid on every server.\n" >&2
|
|
|
printf "The output will be saved to a text file on the remote systems.\n" >&2
|
|
|
exit 1
|
|
|
}
|
|
|
|
|
|
+clean_server() {
|
|
|
+ cmd_feed="$1"
|
|
|
+ rm "$cmd_feed"
|
|
|
+ exit 2
|
|
|
+}
|
|
|
+
|
|
|
run_server() {
|
|
|
server="$1"
|
|
|
- loop="/tmp/$(basename $PIPE_NAME .fifo)-$server.fifo"
|
|
|
+ loop="/tmp/$(basename $CMD_FEED .fifo)-$server.fifo"
|
|
|
mkfifo "$loop"
|
|
|
+ trap "clean_server $loop" 2 15
|
|
|
while read cmd; do
|
|
|
- out_file="$(echo "$cmd" | sed 's/[[:space:].\/]/_/g;s/-//g').out"
|
|
|
- printf "$cmd > $out_file\necho\n"
|
|
|
+ cmd_sanitized="$(echo "$cmd" | sed "$S_SPACE;$R_DASH;$S_QUOTE")"
|
|
|
+ out_file="$(printf "$OUT_FMT" "$cmd_sanitized")"
|
|
|
printf "$server: $cmd\n" >&2
|
|
|
+ printf "$cmd > $out_file\necho\n"
|
|
|
read line < "$loop" > /dev/null # Block until command completes
|
|
|
done | ssh -oBatchMode=yes -oStrictHostKeyChecking=no "$server" "sh" > "$loop"
|
|
|
- rm "$loop"
|
|
|
+ clean_server "$loop"
|
|
|
echo "Server '$server' finished!" >&2
|
|
|
}
|
|
|
|
|
|
+clean_up() {
|
|
|
+ for pid in $(pgrep -P $$); do
|
|
|
+ pkill -P $pid
|
|
|
+ done
|
|
|
+ rm "$CMD_FEED"
|
|
|
+ exit 2
|
|
|
+}
|
|
|
+
|
|
|
main() {
|
|
|
- PIPE_NAME="$(mktemp /tmp/distributer-XXX.fifo)"
|
|
|
- rm "$PIPE_NAME"
|
|
|
- mkfifo "$PIPE_NAME"
|
|
|
- sed '/^[[:space:]]*$/d' "$CONF_LIST" > "$PIPE_NAME" &
|
|
|
- cat "$SERVER_LIST" | while read server; do
|
|
|
- run_server "$server" < "$PIPE_NAME" > /dev/null &
|
|
|
- echo $!
|
|
|
- done | while read pid; do
|
|
|
- wait $pid
|
|
|
+ mkfifo "$CMD_FEED"
|
|
|
+ trap clean_up 2 15
|
|
|
+ sed '/^[[:space:]]*$/d' "$CONF_LIST" > "$CMD_FEED" &
|
|
|
+ pids=""
|
|
|
+ for server in $(cat $SERVER_LIST); do
|
|
|
+ run_server "$server" < "$CMD_FEED" > /dev/null &
|
|
|
+ pids="$pids $!"
|
|
|
+ done
|
|
|
+ for pid in $pids; do
|
|
|
+ wait $pids
|
|
|
done
|
|
|
- rm "$PIPE_NAME"
|
|
|
+ clean_up
|
|
|
echo "All jobs finished!"
|
|
|
}
|
|
|
|
|
|
-if [ "$#" -eq 2 ]; then
|
|
|
+if [ "$#" -eq 2 -o "$#" -eq 3 ]; then
|
|
|
main
|
|
|
else
|
|
|
help
|