#!/bin/bash # (1) Init. #--------------------------------------------------------# # (1) Get current absolute dir ROOT=$(dirname `realpath $0`); # (2) Check argc test $# -lt 2 && echo -e "error: too few arguments\n\n\e[1mUSAGE\e[0m\n\tmaster \n\n\e[1mARGUMENTS\e[0m\n\t\tThe key of the pool\n\t\tThe host where the pool is hosted\n\t\tTo port where the pool is bound\n\t\tThe folder containing ONLY the logger daemons\n" && exit 1; # (3) Check @PORT range # MIN_PORT=1024; MAX_PORT=49151; test "$3" -gt "$MAX_PORT" -o "$3" -lt "$MIN_PORT" && echo "error: must be between $MIN_PORT and $MAX_PORT" && exit 1; # (4) Set argument explicit names # POOL_KEY="$1"; POOL_HOST="$2"; POOL_PORT="$3"; LOGGER_DIR="`realpath $4`"; # (5) Check @LOGGER_DIR # test ! -d "$LOGGER_DIR" && echo "error: is not a valid folder." && exit 1; # (6) init logger variables # declare -A OUTPUT_PID; # will contain each bind-output PIDs declare -A LOGGER_PID; # will contain each logger PIDs # (7) get logger list # LOGGERS=(`ls $LOGGER_DIR`); # (8) If no logger -> exit # test "${#LOGGERS[@]}" -eq 0 && echo "error: no logger found in ." && exit 1; # (9) Get local IP address # LOCAL_IP="`ip addr | grep 'state UP' -A2 | tail -n1 | awk '{print $2}' | cut -f1 -d'/'`"; test -z "$LOCAL_IP" && echo "error: cannot get local IP address." && exit 1; # (10) Create a temporary file # TMPFILE="/dev/shm/master_pid"; # (2) Set exit management #--------------------------------------------------------# # (1) On-Exit routine # on_exit(){ echo "- killing ${#OUTPUT_PID[@]} output"; for logger_name in "${!OUTPUT_PID[@]}"; do # kill each logger OUTPUT echo " - killing $logger_name (${OUTPUT_PID[$logger_name]})"; kill -INT ${OUTPUT_PID[$logger_name]} 2>/dev/null; done; echo "- killing ${#LOGGER_PID[@]} loggers"; for logger_name in "${!LOGGER_PID[@]}"; do # kill each logger OUTPUT echo " - killing $logger_name (${LOGGER_PID[$logger_name]})"; kill -INT ${LOGGER_PID[$logger_name]} 2>/dev/null; done; echo "- killing main output"; kill -INT $MASTER_PID 2>/dev/null; echo "- killing loop"; # kill -INT $LOOP_PID 2>/dev/null; # delete tmp file echo "- deleting tmp file"; rm $TMPFILE 2>/dev/null; } trap "on_exit;" HUP INT KILL TERM; # (3) Connect to pool #--------------------------------------------------------# # (1) Bind-output # echo -e "\e[32m+\e[0m connect to $POOL_HOST:$POOL_PORT"; $ROOT/bind-output master $POOL_HOST $POOL_PORT > $TMPFILE; MASTER_PID="`cat $TMPFILE`"; echo " + flush connection before using it"; # $ROOT/write master ""; # (4) Launch master manager #--------------------------------------------------------# # (1) For each logger for logger_name in "${LOGGERS[@]}"; do echo " + logger '$logger_name'"; # Find an available port PORT="$MIN_PORT"; while true; do # if port not in use -> use it ss -tl4 "( sport = :$PORT )" | grep "$PORT" >/dev/null 2>&1 || break; # else try next port (+1) PORT="`expr $PORT + 1`"; done; # listen for pool response (port number) echo -e " \e[32m+\e[0m listen $PORT"; $ROOT/bind-input freeport $PORT > $TMPFILE; FREEPORT_PID="`cat $TMPFILE`"; sleep 1; # send port request echo " + sending port request"; $ROOT/write master "$POOL_KEY:$logger_name:$LOCAL_IP:$PORT"; echo " + waiting for response"; RESP=""; timeout=8; # 4sec = 8 x .5sec while [ "$timeout" -gt "0" ]; do RESP="`$ROOT/read freeport`"; # if empty answer, try again in .5 sec if [ -z "$RESP" ]; then # echo " + empty response (remaining $timeout)"; timeout="`expr $timeout - 1`"; sleep .5; continue; # else -> stop reading else # echo " + got response '$RESP'"; break; fi done; # closing listen socket echo -e " + received '\e[33m$RESP\e[0m'"; echo -e " \e[31m+\e[0m stop listening on $PORT"; kill -INT $FREEPORT_PID 2>/dev/null; # empty response -> ignore test -z "$RESP" && echo " + no answer" && continue; # not a number -> ignore echo -n "$RESP" | grep -P '^\d+$' >/dev/null || ( echo " + invalid format"; exit 1 ) || continue; # Create output bound echo " + connecting to $POOL_HOST:$RESP"; $ROOT/bind-output $logger_name $POOL_HOST $RESP > $TMPFILE; OUTPUT_PID[$logger_name]="`cat $TMPFILE`"; echo " + logger launched in background"; # launch logger bound to output ( $LOGGER_DIR/$logger_name | cat > /tmp/outbuf_$logger_name )& LOGGER_PID[$logger_name]=$!; done; # When all loggers are bound, destroy pool connection # 1. Send END msg to pool (but wait for it to manage last logger) sleep 2; $ROOT/write master "END${POOL_KEY}END"; # 2. Close pool connection echo -e "\e[31m+\e[0m close connection to $POOL_HOST:$POOL_PORT "; kill -INT $MASTER_PID 2>/dev/null; echo " + ${#LOGGER_PID[@]} loggers running in background"; for logger_name in "${!LOGGER_PID[@]}"; do wait ${LOGGER_PID[$logger_name]}; done; on_exit;