2020-01-20 22:28:48 +00:00
#!/bin/bash
2020-02-18 23:33:26 +00:00
# Copyright (c) 2020 Status Research & Development GmbH. Licensed under
# either of:
# - Apache License, version 2.0
# - MIT license
# at your option. This file may not be copied, modified, or distributed except
# according to those terms.
2020-01-20 22:28:48 +00:00
# Mostly a duplication of "tests/simulation/{start.sh,run_node.sh}", but with a focus on
2020-02-13 12:19:12 +00:00
# replicating testnets as closely as possible, which means following the Docker execution labyrinth.
2020-01-20 22:28:48 +00:00
set -e
cd " $( dirname " ${ BASH_SOURCE [0] } " ) " /..
2020-02-18 23:33:26 +00:00
####################
# argument parsing #
####################
2020-07-29 12:08:27 +00:00
GETOPT_BINARY = "getopt"
if uname | grep -qi darwin; then
# macOS
GETOPT_BINARY = "/usr/local/opt/gnu-getopt/bin/getopt"
2020-07-30 00:46:10 +00:00
[ [ -f " $GETOPT_BINARY " ] ] || { echo "GNU getopt not installed. Please run 'brew install gnu-getopt'. Aborting." ; exit 1; }
2020-07-29 12:08:27 +00:00
fi
! ${ GETOPT_BINARY } --test > /dev/null
2020-02-18 23:33:26 +00:00
if [ ${ PIPESTATUS [0] } != 4 ] ; then
2020-07-30 00:46:10 +00:00
echo '`getopt --test` failed in this environment.'
exit 1
2020-02-18 23:33:26 +00:00
fi
2020-06-22 18:22:45 +00:00
OPTS = "hgt:n:d:"
2020-09-01 13:38:34 +00:00
LONGOPTS = "help,testnet:,nodes:,data-dir:,stop-at-epoch:,disable-htop,disable-vc,enable-logtrace,log-level:,base-port:,base-rpc-port:,base-metrics-port:,with-ganache,reuse-existing-data-dir"
2020-01-20 22:28:48 +00:00
2020-02-18 23:33:26 +00:00
# default values
TESTNET = "1"
NUM_NODES = "10"
2020-01-20 22:28:48 +00:00
DATA_DIR = "local_testnet_data"
2020-02-18 23:33:26 +00:00
USE_HTOP = "1"
2020-09-01 13:38:34 +00:00
USE_VC = "1"
2020-06-22 18:22:45 +00:00
USE_GANACHE = "0"
2020-03-09 00:32:58 +00:00
LOG_LEVEL = "DEBUG"
2020-05-14 17:34:47 +00:00
BASE_PORT = "9000"
BASE_METRICS_PORT = "8008"
2020-09-01 13:38:34 +00:00
BASE_RPC_PORT = "7000"
2020-07-30 00:46:10 +00:00
REUSE_EXISTING_DATA_DIR = "0"
2020-08-16 09:12:19 +00:00
ENABLE_LOGTRACE = "0"
2020-09-01 13:38:34 +00:00
STOP_AT_EPOCH_FLAG = ""
2020-02-18 23:33:26 +00:00
print_help( ) {
2020-07-30 00:46:10 +00:00
cat <<EOF
2020-08-17 06:36:29 +00:00
Usage: $( basename " $0 " ) --testnet <testnet number> [ OTHER OPTIONS] -- [ BEACON NODE OPTIONS]
2020-09-01 13:38:34 +00:00
E.g.: $( basename " $0 " ) --testnet ${ TESTNET } --nodes ${ NUM_NODES } --stop-at-epoch 5 --data-dir " ${ DATA_DIR } " # defaults
CI run: $( basename " $0 " ) --disable-htop -- --verify-finalization
2020-02-18 23:33:26 +00:00
2020-07-30 00:46:10 +00:00
-h, --help this help message
-t, --testnet testnet number ( default: ${ TESTNET } )
-n, --nodes number of nodes to launch ( default: ${ NUM_NODES } )
-g, --with-ganache simulate a genesis event based on a deposit contract
2020-09-01 13:38:34 +00:00
-s, --stop-at-epoch stop simulation at epoch ( default: infinite)
2020-07-30 00:46:10 +00:00
-d, --data-dir directory where all the node data and logs will end up
( default: " ${ DATA_DIR } " )
--base-port bootstrap node' s Eth2 traffic port ( default: ${ BASE_PORT } )
2020-09-01 13:38:34 +00:00
--base-rpc-port bootstrap node' s RPC port ( default: ${ BASE_RPC_PORT } )
2020-07-30 00:46:10 +00:00
--base-metrics-port bootstrap node' s metrics server port ( default: ${ BASE_METRICS_PORT } )
--disable-htop don' t use "htop" to see the beacon_node processes
2020-09-01 13:38:34 +00:00
--disable-vc don' t use validator client binaries for validators ( by default validators are split 50/50 between beacon nodes and validator clients)
2020-08-16 09:12:19 +00:00
--enable-logtrace display logtrace asr analysis
2020-07-30 00:46:10 +00:00
--log-level set the log level ( default: ${ LOG_LEVEL } )
--reuse-existing-data-dir instead of deleting and recreating the data dir, keep it and reuse everything we can from it
2020-02-18 23:33:26 +00:00
EOF
}
2020-07-29 12:08:27 +00:00
! PARSED = $( ${ GETOPT_BINARY } --options= ${ OPTS } --longoptions= ${ LONGOPTS } --name " $0 " -- " $@ " )
2020-02-18 23:33:26 +00:00
if [ ${ PIPESTATUS [0] } != 0 ] ; then
2020-07-30 00:46:10 +00:00
# getopt has complained about wrong arguments to stdout
exit 1
2020-02-18 23:33:26 +00:00
fi
# read getopt's output this way to handle the quoting right
eval set -- " $PARSED "
while true; do
2020-07-30 00:46:10 +00:00
case " $1 " in
-h| --help)
print_help
exit
; ;
-t| --testnet)
TESTNET = " $2 "
shift 2
; ;
2020-09-01 13:38:34 +00:00
-n| --stop-at-epoch)
STOP_AT_EPOCH_FLAG = " --stop-at-epoch= $2 "
shift 2
; ;
2020-07-30 00:46:10 +00:00
-n| --nodes)
NUM_NODES = " $2 "
shift 2
; ;
-d| --data-dir)
DATA_DIR = " $2 "
shift 2
; ;
--disable-htop)
USE_HTOP = "0"
shift
; ;
2020-09-01 13:38:34 +00:00
--disable-vc)
USE_VC = "0"
shift
; ;
2020-07-30 00:46:10 +00:00
-g| --with-ganache)
USE_GANACHE = "1"
shift
; ;
--log-level)
LOG_LEVEL = " $2 "
shift 2
; ;
--base-port)
BASE_PORT = " $2 "
shift 2
; ;
2020-09-01 13:38:34 +00:00
--base-rpc-port)
BASE_RPC_PORT = " $2 "
shift 2
; ;
2020-07-30 00:46:10 +00:00
--base-metrics-port)
BASE_METRICS_PORT = " $2 "
shift 2
; ;
--reuse-existing-data-dir)
REUSE_EXISTING_DATA_DIR = "1"
shift
; ;
2020-08-16 09:12:19 +00:00
--enable-logtrace)
ENABLE_LOGTRACE = "1"
shift
; ;
2020-07-30 00:46:10 +00:00
--)
shift
break
; ;
*)
echo "argument parsing error"
print_help
exit 1
esac
2020-02-18 23:33:26 +00:00
done
2020-02-26 00:14:20 +00:00
# when sourcing env.sh, it will try to execute $@, so empty it
EXTRA_ARGS = " $@ "
if [ [ $# != 0 ] ] ; then
2020-07-30 00:46:10 +00:00
shift $#
2020-02-26 00:14:20 +00:00
fi
2020-02-18 23:33:26 +00:00
NETWORK = " testnet ${ TESTNET } "
2020-07-30 00:46:10 +00:00
if [ [ " $REUSE_EXISTING_DATA_DIR " = = "0" ] ] ; then
rm -rf " ${ DATA_DIR } "
fi
2020-06-01 19:48:20 +00:00
2020-07-17 20:59:50 +00:00
DEPOSITS_FILE = " ${ DATA_DIR } /deposits.json "
2020-07-27 19:26:30 +00:00
VALIDATORS_DIR = " ${ DATA_DIR } /validators "
mkdir -p " ${ VALIDATORS_DIR } "
2020-06-01 19:48:20 +00:00
SECRETS_DIR = " ${ DATA_DIR } /secrets "
mkdir -p " ${ SECRETS_DIR } "
2020-01-20 22:28:48 +00:00
NETWORK_DIR = " ${ DATA_DIR } /network_dir "
mkdir -p " ${ NETWORK_DIR } "
set -a
source " scripts/ ${ NETWORK } .env "
set +a
2020-02-18 23:33:26 +00:00
# Windows detection
if uname | grep -qiE "mingw|msys" ; then
2020-07-30 00:46:10 +00:00
MAKE = "mingw32-make"
2020-02-18 23:33:26 +00:00
else
2020-07-30 00:46:10 +00:00
MAKE = "make"
2020-02-18 23:33:26 +00:00
fi
2020-08-17 06:36:29 +00:00
NETWORK_NIM_FLAGS = $( scripts/load-testnet-nim-flags.sh " ${ NETWORK } " )
2020-09-01 13:44:40 +00:00
$MAKE -j2 LOG_LEVEL = " ${ LOG_LEVEL } " NIMFLAGS = " ${ NIMFLAGS } -d:insecure -d:testnet_servers_image -d:local_testnet ${ NETWORK_NIM_FLAGS } " beacon_node signing_process validator_client deposit_contract
2020-08-16 09:12:19 +00:00
if [ [ " $ENABLE_LOGTRACE " = = "1" ] ] ; then
$MAKE LOG_LEVEL = " ${ LOG_LEVEL } " NIMFLAGS = " ${ NIMFLAGS } -d:insecure -d:testnet_servers_image -d:local_testnet ${ NETWORK_NIM_FLAGS } " logtrace
fi
2020-01-20 22:28:48 +00:00
2020-06-22 18:22:45 +00:00
PIDS = ""
WEB3_ARG = ""
STATE_SNAPSHOT_ARG = ""
2020-07-23 20:51:56 +00:00
BOOTSTRAP_TIMEOUT = 30 # in seconds
2020-07-09 22:08:54 +00:00
DEPOSIT_CONTRACT_ADDRESS = "0x0000000000000000000000000000000000000000"
DEPOSIT_CONTRACT_BLOCK = "0x0000000000000000000000000000000000000000000000000000000000000000"
NETWORK_METADATA_FILE = " ${ DATA_DIR } /network.json "
2020-09-01 13:38:34 +00:00
NUM_JOBS = ${ NUM_NODES }
2020-06-22 18:22:45 +00:00
2020-07-30 00:46:10 +00:00
if [ [ " $REUSE_EXISTING_DATA_DIR " = = "0" ] ] ; then
./build/deposit_contract generateSimulationDeposits \
--count= ${ TOTAL_VALIDATORS } \
--out-validators-dir= " ${ VALIDATORS_DIR } " \
--out-secrets-dir= " ${ SECRETS_DIR } " \
--out-deposits-file= " ${ DEPOSITS_FILE } "
fi
2020-01-20 22:28:48 +00:00
2020-06-22 18:22:45 +00:00
if [ [ $USE_GANACHE = = "0" ] ] ; then
2020-07-30 00:46:10 +00:00
GENESIS_OFFSET = 30
BOOTSTRAP_IP = "127.0.0.1"
./build/beacon_node createTestnet \
--deposits-file= " ${ DEPOSITS_FILE } " \
--total-validators= ${ TOTAL_VALIDATORS } \
--last-user-validator= ${ USER_VALIDATORS } \
--output-genesis= " ${ NETWORK_DIR } /genesis.ssz " \
--output-bootstrap-file= " ${ NETWORK_DIR } /bootstrap_nodes.txt " \
--bootstrap-address= ${ BOOTSTRAP_IP } \
--bootstrap-port= ${ BASE_PORT } \
--genesis-offset= ${ GENESIS_OFFSET } # Delay in seconds
STATE_SNAPSHOT_ARG = " --state-snapshot= ${ NETWORK_DIR } /genesis.ssz "
2020-06-22 18:22:45 +00:00
else
2020-07-30 00:46:10 +00:00
echo "Launching ganache"
ganache-cli --blockTime 17 --gasLimit 100000000 -e 100000 --verbose > " ${ DATA_DIR } /log_ganache.txt " 2>& 1 &
PIDS = " ${ PIDS } , $! "
2020-06-22 18:22:45 +00:00
2020-07-30 00:46:10 +00:00
WEB3_ARG = "--web3-url=ws://localhost:8545"
2020-07-09 22:08:54 +00:00
2020-07-30 00:46:10 +00:00
echo "Deploying deposit contract"
DEPLOY_CMD_OUTPUT = $( ./build/deposit_contract deploy $WEB3_ARG )
# https://stackoverflow.com/questions/918886/how-do-i-split-a-string-on-a-delimiter-in-bash
OUTPUT_PIECES = ( ${ DEPLOY_CMD_OUTPUT //;/ } )
DEPOSIT_CONTRACT_ADDRESS = ${ OUTPUT_PIECES [0] }
DEPOSIT_CONTRACT_BLOCK = ${ OUTPUT_PIECES [1] }
2020-07-09 22:08:54 +00:00
2020-08-17 06:36:29 +00:00
echo Contract deployed at " $DEPOSIT_CONTRACT_ADDRESS " :" $DEPOSIT_CONTRACT_BLOCK "
2020-06-11 13:31:35 +00:00
2020-07-30 00:46:10 +00:00
MIN_DELAY = 1
MAX_DELAY = 5
2020-06-22 18:22:45 +00:00
2020-07-30 00:46:10 +00:00
BOOTSTRAP_TIMEOUT = $(( MAX_DELAY * TOTAL_VALIDATORS ))
2020-06-22 18:22:45 +00:00
2020-07-30 00:46:10 +00:00
./build/deposit_contract sendDeposits \
--deposits-file= " ${ DEPOSITS_FILE } " \
--min-delay= $MIN_DELAY --max-delay= $MAX_DELAY \
$WEB3_ARG \
--deposit-contract= ${ DEPOSIT_CONTRACT_ADDRESS } > " ${ DATA_DIR } /log_deposit_maker.txt " 2>& 1 &
2020-06-22 18:22:45 +00:00
2020-07-30 00:46:10 +00:00
PIDS = " ${ PIDS } , $! "
2020-06-22 18:22:45 +00:00
fi
2020-01-20 22:28:48 +00:00
2020-06-10 15:21:32 +00:00
./scripts/make_prometheus_config.sh \
2020-07-30 00:46:10 +00:00
--nodes ${ NUM_NODES } \
--base-metrics-port ${ BASE_METRICS_PORT } \
--config-file " ${ DATA_DIR } /prometheus.yml " || true # TODO: this currently fails on macOS,
# but it can be considered non-critical
2020-05-05 22:02:39 +00:00
2020-07-09 22:08:54 +00:00
echo Wrote $NETWORK_METADATA_FILE :
tee " $NETWORK_METADATA_FILE " <<EOF
{
"runtimePreset" : {
"MIN_GENESIS_ACTIVE_VALIDATOR_COUNT" : ${ TOTAL_VALIDATORS } ,
"MIN_GENESIS_TIME" : 0,
"GENESIS_DELAY" : 10,
"GENESIS_FORK_VERSION" : "0x00000000"
} ,
"depositContractAddress" : " ${ DEPOSIT_CONTRACT_ADDRESS } " ,
"depositContractDeployedAt" : " ${ DEPOSIT_CONTRACT_BLOCK } "
}
EOF
2020-04-30 13:59:57 +00:00
# Kill child processes on Ctrl-C/SIGTERM/exit, passing the PID of this shell
# instance as the parent and the target process name as a pattern to the
# "pkill" command.
2020-01-20 22:28:48 +00:00
cleanup( ) {
2020-07-30 00:46:10 +00:00
pkill -P $$ beacon_node & >/dev/null || true
2020-09-01 13:38:34 +00:00
pkill -P $$ validator_client & >/dev/null || true
2020-07-30 00:46:10 +00:00
sleep 2
pkill -9 -P $$ beacon_node & >/dev/null || true
2020-09-01 13:38:34 +00:00
pkill -9 -P $$ validator_client & >/dev/null || true
2020-01-20 22:28:48 +00:00
}
2020-04-30 13:59:57 +00:00
trap 'cleanup' SIGINT SIGTERM EXIT
2020-01-20 22:28:48 +00:00
2020-05-01 22:09:04 +00:00
dump_logs( ) {
2020-07-30 00:46:10 +00:00
LOG_LINES = 20
for LOG in " ${ DATA_DIR } " /log*.txt; do
echo " Last ${ LOG_LINES } lines of ${ LOG } : "
tail -n ${ LOG_LINES } " ${ LOG } "
echo "======"
done
2020-05-01 22:09:04 +00:00
}
2020-08-16 09:12:19 +00:00
dump_logtrace( ) {
if [ [ " $ENABLE_LOGTRACE " = = "1" ] ] ; then
2020-08-17 06:36:29 +00:00
find " ${ DATA_DIR } " -maxdepth 1 -type f -name 'log*.txt' | sed -e" s/ ${ DATA_DIR } \//--nodes=/ " | sort | xargs ./build/logtrace asr --log-dir= " ${ DATA_DIR } " || true
2020-08-16 09:12:19 +00:00
fi
}
2020-02-21 13:19:34 +00:00
NODES_WITH_VALIDATORS = ${ NODES_WITH_VALIDATORS :- 4 }
2020-07-16 17:04:57 +00:00
BOOTSTRAP_NODE = 0
2020-06-03 11:40:14 +00:00
SYSTEM_VALIDATORS = $(( TOTAL_VALIDATORS - USER_VALIDATORS ))
VALIDATORS_PER_NODE = $(( SYSTEM_VALIDATORS / NODES_WITH_VALIDATORS ))
2020-09-01 13:38:34 +00:00
if [ " ${ USE_VC :- } " = = "1" ] ; then
# if using validator client binaries in addition to beacon nodes we will
# split the keys for this instance in half between the BN and the VC
# and the validators for the BNs will be from the first half of all validators
VALIDATORS_PER_NODE = $(( VALIDATORS_PER_NODE / 2 ))
NUM_JOBS = $(( NUM_JOBS * 2 ))
fi
VALIDATORS_PER_VALIDATOR = $(( ( SYSTEM_VALIDATORS / NODES_WITH_VALIDATORS) / 2 ))
VALIDATOR_OFFSET = $(( SYSTEM_VALIDATORS / 2 ))
2020-07-30 00:46:10 +00:00
BOOTSTRAP_ENR = " ${ DATA_DIR } /node ${ BOOTSTRAP_NODE } /beacon_node.enr "
2020-02-21 13:19:34 +00:00
2020-07-16 17:04:57 +00:00
for NUM_NODE in $( seq 0 $(( NUM_NODES - 1 )) ) ; do
2020-07-30 00:46:10 +00:00
if [ [ ${ NUM_NODE } = = ${ BOOTSTRAP_NODE } ] ] ; then
BOOTSTRAP_ARG = ""
else
BOOTSTRAP_ARG = " --bootstrap-file= ${ BOOTSTRAP_ENR } "
# Wait for the master node to write out its address file
START_TIMESTAMP = $( date +%s)
while [ [ ! -f " ${ BOOTSTRAP_ENR } " ] ] ; do
sleep 0.1
NOW_TIMESTAMP = $( date +%s)
if [ [ " $(( NOW_TIMESTAMP - START_TIMESTAMP - GENESIS_OFFSET )) " -ge " $BOOTSTRAP_TIMEOUT " ] ] ; then
echo " Bootstrap node failed to start in ${ BOOTSTRAP_TIMEOUT } seconds. Aborting. "
dump_logs
exit 1
fi
done
fi
# Copy validators to individual nodes.
# The first $NODES_WITH_VALIDATORS nodes split them equally between them, after skipping the first $USER_VALIDATORS.
NODE_DATA_DIR = " ${ DATA_DIR } /node ${ NUM_NODE } "
rm -rf " ${ NODE_DATA_DIR } "
mkdir -p " ${ NODE_DATA_DIR } /validators "
mkdir -p " ${ NODE_DATA_DIR } /secrets "
if [ [ $NUM_NODE -lt $NODES_WITH_VALIDATORS ] ] ; then
2020-09-01 13:38:34 +00:00
if [ " ${ USE_VC :- } " = = "1" ] ; then
VALIDATOR_DATA_DIR = " ${ DATA_DIR } /validator ${ NUM_NODE } "
rm -rf " ${ VALIDATOR_DATA_DIR } "
mkdir -p " ${ VALIDATOR_DATA_DIR } /validators "
mkdir -p " ${ VALIDATOR_DATA_DIR } /secrets "
for VALIDATOR in $( ls " ${ VALIDATORS_DIR } " | tail -n +$(( $USER_VALIDATORS + ( $VALIDATORS_PER_VALIDATOR * $NUM_NODE ) + 1 + $VALIDATOR_OFFSET )) | head -n $VALIDATORS_PER_VALIDATOR ) ; do
cp -a " ${ VALIDATORS_DIR } / $VALIDATOR " " ${ VALIDATOR_DATA_DIR } /validators/ "
cp -a " ${ SECRETS_DIR } / ${ VALIDATOR } " " ${ VALIDATOR_DATA_DIR } /secrets/ "
done
fi
2020-08-17 06:36:29 +00:00
for VALIDATOR in $( ls " ${ VALIDATORS_DIR } " | tail -n +$(( $USER_VALIDATORS + ( $VALIDATORS_PER_NODE * $NUM_NODE ) + 1 )) | head -n $VALIDATORS_PER_NODE ) ; do
2020-07-30 00:46:10 +00:00
cp -a " ${ VALIDATORS_DIR } / $VALIDATOR " " ${ NODE_DATA_DIR } /validators/ "
cp -a " ${ SECRETS_DIR } / ${ VALIDATOR } " " ${ NODE_DATA_DIR } /secrets/ "
done
fi
./build/beacon_node \
--non-interactive \
--nat:extip:127.0.0.1 \
--network= " ${ NETWORK_METADATA_FILE } " \
--log-level= " ${ LOG_LEVEL } " \
--tcp-port= $(( BASE_PORT + NUM_NODE )) \
--udp-port= $(( BASE_PORT + NUM_NODE )) \
--data-dir= " ${ NODE_DATA_DIR } " \
${ BOOTSTRAP_ARG } \
${ STATE_SNAPSHOT_ARG } \
${ WEB3_ARG } \
2020-09-01 13:38:34 +00:00
${ STOP_AT_EPOCH_FLAG } \
--rpc \
--rpc-address= "127.0.0.1" \
--rpc-port= " $(( BASE_RPC_PORT + NUM_NODE )) " \
2020-07-30 00:46:10 +00:00
--metrics \
--metrics-address= "127.0.0.1" \
--metrics-port= " $(( BASE_METRICS_PORT + NUM_NODE )) " \
${ EXTRA_ARGS } \
> " ${ DATA_DIR } /log ${ NUM_NODE } .txt " 2>& 1 &
if [ [ " ${ PIDS } " = = "" ] ] ; then
PIDS = " $! "
else
PIDS = " ${ PIDS } , $! "
fi
2020-09-01 13:38:34 +00:00
if [ " ${ USE_VC :- } " = = "1" ] ; then
./build/validator_client \
--log-level= " ${ LOG_LEVEL } " \
${ STOP_AT_EPOCH_FLAG } \
--data-dir= " ${ VALIDATOR_DATA_DIR } " \
--rpc-port= " $(( BASE_RPC_PORT + NUM_NODE )) " \
> " ${ DATA_DIR } /log_val ${ NUM_NODE } .txt " 2>& 1 & PIDS = " ${ PIDS } , $! "
fi
2020-01-20 22:28:48 +00:00
done
2020-05-01 18:57:12 +00:00
# give the regular nodes time to crash
sleep 5
2020-07-29 12:08:27 +00:00
BG_JOBS = " $( jobs | wc -l | tr -d ' ' ) "
2020-09-01 13:38:34 +00:00
if [ [ " $BG_JOBS " != " $NUM_JOBS " ] ] ; then
echo " $(( NUM_JOBS - BG_JOBS )) beacon_node/validator_client instance(s) exited early. Aborting. "
2020-07-30 00:46:10 +00:00
dump_logs
2020-08-16 09:12:19 +00:00
dump_logtrace
2020-07-30 00:46:10 +00:00
exit 1
2020-05-01 18:57:12 +00:00
fi
2020-02-18 23:33:26 +00:00
if [ [ " $USE_HTOP " = = "1" ] ] ; then
2020-07-30 00:46:10 +00:00
htop -p " $PIDS "
cleanup
2020-02-18 23:33:26 +00:00
else
2020-07-30 00:46:10 +00:00
FAILED = 0
for PID in $( echo " $PIDS " | tr ',' ' ' ) ; do
2020-08-17 06:36:29 +00:00
wait " $PID " || FAILED = " $(( FAILED += 1 )) "
2020-07-30 00:46:10 +00:00
done
if [ [ " $FAILED " != "0" ] ] ; then
echo " ${ FAILED } child processes had non-zero exit codes (or exited early). "
dump_logs
2020-08-16 09:12:19 +00:00
dump_logtrace
2020-07-30 00:46:10 +00:00
exit 1
fi
2020-02-18 23:33:26 +00:00
fi
2020-08-16 09:12:19 +00:00
dump_logtrace