552 lines
14 KiB
Bash
552 lines
14 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
if [[ ! -z "${DEBUG}" ]]; then
|
|
set -x
|
|
fi
|
|
|
|
|
|
SCRIPT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|
SUITE=$(caller)
|
|
SUITE=$(basename "${SUITE}" .sh )
|
|
|
|
tabs 1
|
|
declare -i PADDING_LEVEL=0
|
|
declare -i STEP=1
|
|
declare -a REQUIRED_COMPONENTS
|
|
|
|
find_selenium_dir() {
|
|
TEST_PATH=$1
|
|
FOUND=""
|
|
while [[ $TEST_PATH != "" && $FOUND == "" ]]; do
|
|
FILENAME=$(basename "$TEST_PATH")
|
|
if [[ $FILENAME == "selenium" ]]; then
|
|
FOUND=$TEST_PATH
|
|
fi
|
|
TEST_PATH="$(dirname $TEST_PATH)"
|
|
done
|
|
echo $FOUND
|
|
}
|
|
|
|
SELENIUM_ROOT_FOLDER=$(find_selenium_dir $SCRIPT)
|
|
TEST_DIR=$SELENIUM_ROOT_FOLDER/test
|
|
BIN_DIR=$SELENIUM_ROOT_FOLDER/bin
|
|
LOGS=${SELENIUM_ROOT_FOLDER}/logs/${SUITE}
|
|
SCREENS=${SELENIUM_ROOT_FOLDER}/screens/${SUITE}
|
|
CONF_DIR=/tmp/selenium/${SUITE}
|
|
ENV_FILE=$CONF_DIR/.env
|
|
|
|
rm -rf $CONF_DIR
|
|
|
|
for f in $SCRIPT/components/*; do
|
|
if [[ ! "$f" == *README.md ]]
|
|
then
|
|
source $f;
|
|
fi
|
|
done
|
|
|
|
parse_arguments() {
|
|
if [[ "$#" -gt 0 ]]
|
|
then
|
|
if [[ "$1" == "start-rabbitmq" ]]
|
|
then
|
|
echo "start-rabbitmq"
|
|
elif [[ "$1" == "start-others" ]]
|
|
then
|
|
echo "start-others"
|
|
elif [[ "$1" == "ensure-others" ]]
|
|
then
|
|
echo "ensure-others"
|
|
elif [[ "$1" == "stop-others" ]]
|
|
then
|
|
echo "stop-others"
|
|
elif [[ "$1" == "stop-rabbitmq" ]]
|
|
then
|
|
echo "stop-rabbitmq"
|
|
elif [[ "$1" == "test" ]]
|
|
then
|
|
echo "test $2"
|
|
fi
|
|
else
|
|
echo "run"
|
|
fi
|
|
}
|
|
|
|
COMMAND=$(parse_arguments $@)
|
|
|
|
|
|
|
|
|
|
print() {
|
|
tabbing=""
|
|
if [[ $PADDING_LEVEL -gt 0 ]]; then
|
|
for i in $(seq $PADDING_LEVEL); do
|
|
tabbing="$tabbing\t"
|
|
done
|
|
fi
|
|
echo -e "$tabbing$1"
|
|
}
|
|
|
|
begin() {
|
|
print "\n[$STEP] $@"
|
|
PADDING_LEVEL=$(($PADDING_LEVEL + 1))
|
|
STEP=$(($STEP + 1))
|
|
}
|
|
end() {
|
|
PADDING_LEVEL=$(($PADDING_LEVEL - 1))
|
|
print "$@"
|
|
}
|
|
ensure_docker_network() {
|
|
begin "Ensuring $DOCKER_NETWORK network ..."
|
|
if [ ! "$(docker network ls | grep $DOCKER_NETWORK)" ]; then
|
|
print "> DOCKER_NETWORK: $DOCKER_NETWORK created"
|
|
docker network create $DOCKER_NETWORK
|
|
fi
|
|
end "$DOCKER_NETWORK network exists"
|
|
}
|
|
init_suite() {
|
|
TEST_CASES_DIR=$(realpath ${TEST_DIR}${TEST_CASES_PATH:?"missing TEST_CASES_PATH"})
|
|
if [ -z "${TEST_CONFIG_PATH}" ]; then TEST_CONFIG_DIR=$TEST_CASES_DIR
|
|
else TEST_CONFIG_DIR=$(realpath ${TEST_DIR}${TEST_CONFIG_PATH})
|
|
fi
|
|
DOCKER_NETWORK=${DOCKER_NETWORK:-rabbitmq_net}
|
|
|
|
begin "Initializing suite $SUITE ..."
|
|
print "> REQUIRED_COMPONENTS: ${REQUIRED_COMPONENTS[*]}"
|
|
print "> TEST_CASES_DIR: ${TEST_CASES_DIR} "
|
|
print "> TEST_CONFIG_DIR: ${TEST_CONFIG_DIR} "
|
|
print "> DOCKER_NETWORK: ${DOCKER_NETWORK} "
|
|
print "> initial PROFILES: ${PROFILES} "
|
|
print "> (+) ADDON_PROFILES: ${ADDON_PROFILES} "
|
|
PROFILES="${PROFILES} ${ADDON_PROFILES}"
|
|
print "> (=) final PROFILES: ${PROFILES} "
|
|
print "> ENV_FILE: ${ENV_FILE} "
|
|
print "> COMMAND: ${COMMAND}"
|
|
end "Initialized suite"
|
|
|
|
mkdir -p ${LOGS}/${SUITE}
|
|
mkdir -p ${SCREENS}/${SUITE}
|
|
}
|
|
|
|
build_mocha_image() {
|
|
begin "Ensuring mocha-test image ..."
|
|
tag=($(md5sum $SELENIUM_ROOT_FOLDER/package.json))
|
|
print "> tag : $tag"
|
|
if [[ $(docker images -q mocha-test:$tag 2> /dev/null) == "" ]]; then
|
|
docker build -t mocha-test:$tag --target test $SCRIPT/..
|
|
print "> Built docker image mocha-test:$tag"
|
|
fi
|
|
end "mocha-test image exists"
|
|
}
|
|
|
|
kill_container_if_exist() {
|
|
if docker stop $1 &> /dev/null; then
|
|
docker rm $1 &> /dev/null
|
|
fi
|
|
}
|
|
wait_for_message() {
|
|
attemps_left=10
|
|
while ! docker logs $1 2>&1 | grep -q "$2";
|
|
do
|
|
sleep 5
|
|
print "Waiting 5sec for $1 to start ($attemps_left attempts left )..."
|
|
((attemps_left--))
|
|
if [[ "$attemps_left" -lt 1 ]]; then
|
|
print "Timed out waiting"
|
|
save_container_log $1
|
|
exit 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
wait_for_oidc_endpoint() {
|
|
NAME=$1
|
|
BASE_URL=$2
|
|
if [[ $BASE_URL == *"localhost"** || $BASE_URL == *"0.0.0.0"** ]]; then
|
|
wait_for_oidc_endpoint_local $@
|
|
else
|
|
wait_for_oidc_endpoint_docker $@
|
|
fi
|
|
}
|
|
wait_for_oidc_endpoint_local() {
|
|
NAME=$1
|
|
BASE_URL=$2
|
|
CURL_ARGS="-L --fail "
|
|
DELAY_BETWEEN_ATTEMPTS=5
|
|
if [[ $# -eq 3 ]]; then
|
|
CURL_ARGS="$CURL_ARGS --cacert $3"
|
|
DELAY_BETWEEN_ATTEMPTS=10
|
|
fi
|
|
max_retry=10
|
|
counter=0
|
|
print "Waiting for OIDC discovery endpoint $NAME ... (BASE_URL: $BASE_URL)"
|
|
until (curl $CURL_ARGS ${BASE_URL}/.well-known/openid-configuration >/dev/null 2>&1)
|
|
do
|
|
sleep $DELAY_BETWEEN_ATTEMPTS
|
|
[[ counter -eq $max_retry ]] && print "Failed!" && exit 1
|
|
print "Trying again. Try #$counter"
|
|
((counter++))
|
|
done
|
|
sleep 20
|
|
}
|
|
wait_for_oidc_endpoint_docker() {
|
|
NAME=$1
|
|
BASE_URL=$2
|
|
CURL_ARGS="-L --fail "
|
|
DOCKER_ARGS="--rm --net ${DOCKER_NETWORK} "
|
|
DELAY_BETWEEN_ATTEMPTS=5
|
|
if [[ $# -gt 2 ]]; then
|
|
DOCKER_ARGS="$DOCKER_ARGS -v $3:/tmp/ca_certificate.pem"
|
|
CURL_ARGS="$CURL_ARGS --cacert /tmp/ca_certificate.pem"
|
|
DELAY_BETWEEN_ATTEMPTS=10
|
|
fi
|
|
max_retry=10
|
|
counter=0
|
|
print "Waiting for OIDC discovery endpoint $NAME ... (BASE_URL: $BASE_URL)"
|
|
until (docker run $DOCKER_ARGS curlimages/curl:7.85.0 $CURL_ARGS ${BASE_URL}/.well-known/openid-configuration >/dev/null 2>&1)
|
|
do
|
|
sleep $DELAY_BETWEEN_ATTEMPTS
|
|
[[ counter -eq $max_retry ]] && print "Failed!" && exit 1
|
|
print "Trying again. Try #$counter"
|
|
((counter++))
|
|
done
|
|
sleep 20
|
|
}
|
|
calculate_rabbitmq_url() {
|
|
echo "${RABBITMQ_SCHEME:-http}://$1${PUBLIC_RABBITMQ_PATH:-$RABBITMQ_PATH}"
|
|
}
|
|
|
|
wait_for_url() {
|
|
BASE_URL=$1
|
|
if [[ $BASE_URL == *"localhost"** ]]; then
|
|
wait_for_url_local $BASE_URL
|
|
else
|
|
wait_for_url_docker $BASE_URL
|
|
fi
|
|
}
|
|
wait_for_url_local() {
|
|
url=$1
|
|
max_retry=10
|
|
counter=0
|
|
until (curl -L -f -v $url >/dev/null 2>&1)
|
|
do
|
|
print "Waiting for $url to start (local)"
|
|
sleep 5
|
|
[[ counter -eq $max_retry ]] && print "Failed!" && exit 1
|
|
print "Trying again. Try #$counter"
|
|
((counter++))
|
|
done
|
|
}
|
|
wait_for_url_docker() {
|
|
url=$1
|
|
max_retry=10
|
|
counter=0
|
|
until (docker run --net ${DOCKER_NETWORK} --rm curlimages/curl:7.85.0 -L -f -v $url >/dev/null 2>&1)
|
|
do
|
|
print "Waiting for $url to start (docker)"
|
|
sleep 5
|
|
[[ counter -eq $max_retry ]] && print "Failed!" && exit 1
|
|
print "Trying again. Try #$counter"
|
|
((counter++))
|
|
done
|
|
}
|
|
|
|
test_on_cluster() {
|
|
IFS=', ' read -r -a array <<< "$RABBITMQ_CLUSTER_NODES"
|
|
begin "Running against all nodes in cluster $RABBITMQ_CLUSTER_NODES :"
|
|
for item in "${array[@]}"
|
|
do
|
|
RMQ_HOST_0=${RABBITMQ_HOST:-rabbitmq:15672}
|
|
RMQ_HOST=$(rewrite_rabbitmq_hostname ${item} $RMQ_HOST_0)
|
|
PUBLIC_RMQ_HOST_0=${PUBLIC_RABBITMQ_HOST:-$RMQ_HOST}
|
|
PUBLIC_RMQ_HOST=$(rewrite_rabbitmq_hostname ${item} $PUBLIC_RMQ_HOST_0)
|
|
RMQ_URL=$(calculate_rabbitmq_url $PUBLIC_RMQ_HOST)
|
|
RMQ_HOSTNAME=${item}
|
|
_test $RMQ_HOST \
|
|
$PUBLIC_RMQ_HOST \
|
|
$RMQ_URL \
|
|
$RMQ_HOSTNAME
|
|
TEST_RESULT=$?
|
|
if [ $TEST_RESULT -ne 0 ]; then
|
|
break
|
|
fi
|
|
done
|
|
end "Finishing running test ($TEST_RESULT)"
|
|
}
|
|
rewrite_rabbitmq_hostname() {
|
|
IFS=':' read -r -a array <<< "$2"
|
|
if [ "${array[0]}" == "rabbitmq" ]; then
|
|
echo "${2//rabbitmq/$1}"
|
|
else
|
|
echo "$2"
|
|
fi
|
|
}
|
|
test() {
|
|
if [[ "$PROFILES" == *"cluster"* && ! -z "$RABBITMQ_CLUSTER_NODES" ]]; then
|
|
test_on_cluster
|
|
else
|
|
RMQ_HOST=${RABBITMQ_HOST:-rabbitmq:15672}
|
|
PUBLIC_RMQ_HOST=${PUBLIC_RABBITMQ_HOST:-$RMQ_HOST}
|
|
_test $RABBITMQ_HOST \
|
|
$PUBLIC_RMQ_HOST \
|
|
$(calculate_rabbitmq_url $PUBLIC_RMQ_HOST) \
|
|
${RABBITMQ_HOSTNAME:-rabbitmq}
|
|
fi
|
|
}
|
|
|
|
_test() {
|
|
RMQ_HOST=$1
|
|
PUBLIC_RMQ_HOST=$2
|
|
RMQ_URL=$3
|
|
RMQ_HOSTNAME=$4
|
|
|
|
kill_container_if_exist mocha
|
|
begin "Running tests against $RMQ_HOSTNAME with these env variable:"
|
|
|
|
SELENIUM_TIMEOUT=${SELENIUM_TIMEOUT:-20000}
|
|
SELENIUM_POLLING=${SELENIUM_POLLING:-500}
|
|
|
|
print "> SELENIUM_TIMEOUT: ${SELENIUM_TIMEOUT}"
|
|
print "> SELENIUM_POLLING: ${SELENIUM_POLLING}"
|
|
print "> RABBITMQ_HOST: ${RMQ_HOST}"
|
|
print "> RABBITMQ_HOSTNAME: ${RMQ_HOSTNAME}"
|
|
print "> PUBLIC_RABBITMQ_HOST: ${PUBLIC_RMQ_HOST}"
|
|
print "> RABBITMQ_PATH: ${RABBITMQ_PATH}"
|
|
print "> RABBITMQ_URL: ${RMQ_URL}"
|
|
print "> UAA_URL: ${UAA_URL}"
|
|
print "> FAKEPORTAL_URL: ${FAKEPORTAL_URL}"
|
|
mocha_test_tag=($(md5sum $SELENIUM_ROOT_FOLDER/package.json))
|
|
|
|
print "> OAUTH_NODE_EXTRA_CA_CERTS: ${OAUTH_NODE_EXTRA_CA_CERTS}"
|
|
MOUNT_NODE_EXTRA_CA_CERTS=${TEST_DIR}/${OAUTH_NODE_EXTRA_CA_CERTS}
|
|
print "> MOUNT_NODE_EXTRA_CA_CERTS: ${MOUNT_NODE_EXTRA_CA_CERTS}"
|
|
|
|
docker run \
|
|
--rm \
|
|
--name mocha \
|
|
--net ${DOCKER_NETWORK} \
|
|
--env RABBITMQ_URL=${RMQ_URL} \
|
|
--env RABBITMQ_HOSTNAME=${RMQ_HOSTNAME} \
|
|
--env UAA_URL=${UAA_URL} \
|
|
--env FAKE_PORTAL_URL=${FAKEPORTAL_URL} \
|
|
--env RUN_LOCAL=false \
|
|
--env SELENIUM_TIMEOUT=${SELENIUM_TIMEOUT} \
|
|
--env SELENIUM_POLLING=${SELENIUM_POLLING} \
|
|
--env PROFILES="${PROFILES}" \
|
|
--env ENV_FILE="/code/.env" \
|
|
--env NODE_EXTRA_CA_CERTS=/nodejs/ca.pem \
|
|
-v ${MOUNT_NODE_EXTRA_CA_CERTS}:/nodejs/ca.pem \
|
|
-v ${TEST_DIR}:/code/test \
|
|
-v ${SCREENS}:/screens \
|
|
-v ${ENV_FILE}:/code/.env \
|
|
mocha-test:${mocha_test_tag} test /code/test${TEST_CASES_PATH}
|
|
|
|
TEST_RESULT=$?
|
|
end "Finishing running test ($TEST_RESULT)"
|
|
return $TEST_RESULT
|
|
}
|
|
|
|
save_logs() {
|
|
mkdir -p $LOGS
|
|
save_container_logs selenium
|
|
}
|
|
save_container_logs() {
|
|
echo "Saving logs for $1"
|
|
if docker container ls | grep $1 >/dev/null 2>&1; then
|
|
docker logs $1 &> $LOGS/$1.log
|
|
else
|
|
echo "$1 not running"
|
|
fi
|
|
}
|
|
save_container_log() {
|
|
echo "Saving container $1 logs to $LOGS/$1.log ..."
|
|
docker logs $1 &> $LOGS/$1.log
|
|
}
|
|
profiles_with_local_or_docker() {
|
|
if [[ "$PROFILES" != *"local"* && "$PROFILES" != *"docker"* ]]; then
|
|
echo "$PROFILES docker"
|
|
else
|
|
echo "$PROFILES"
|
|
fi
|
|
}
|
|
generate_env_file() {
|
|
begin "Generating env file ..."
|
|
mkdir -p $CONF_DIR
|
|
${BIN_DIR}/gen-env-file $TEST_CONFIG_DIR $ENV_FILE
|
|
source $ENV_FILE
|
|
end "Finished generating env file."
|
|
}
|
|
run() {
|
|
runWith rabbitmq
|
|
}
|
|
runWith() {
|
|
if [[ "$COMMAND" == "run" ]]
|
|
then
|
|
run_on_docker_with $@
|
|
else
|
|
run_local_with $@
|
|
fi
|
|
}
|
|
|
|
run_local_with() {
|
|
export PROFILES="local ${PROFILES}"
|
|
determine_required_components_excluding_rabbitmq $@
|
|
init_suite
|
|
ensure_docker_network
|
|
generate_env_file
|
|
build_mocha_image
|
|
|
|
|
|
if [[ "$COMMAND" == "start-rabbitmq" ]]
|
|
then
|
|
start_local_rabbitmq
|
|
elif [[ "$COMMAND" == "stop-rabbitmq" ]]
|
|
then
|
|
stop_local_rabbitmq
|
|
elif [[ "$COMMAND" == "start-others" ]]
|
|
then
|
|
start_local_others
|
|
elif [[ "$COMMAND" == "ensure-others" ]]
|
|
then
|
|
ensure_local_others
|
|
elif [[ "$COMMAND" == "stop-others" ]]
|
|
then
|
|
teardown_local_others
|
|
elif [[ "$COMMAND" == "stop-rabbitmq" ]]
|
|
then
|
|
stop_local_rabbitmq
|
|
elif [[ "$COMMAND" =~ test[[:space:]]*([^[:space:]]*) ]]
|
|
then
|
|
test_local ${BASH_REMATCH[1]}
|
|
fi
|
|
}
|
|
determine_required_components_including_rabbitmq() {
|
|
if [[ "$@" != *"rabbitmq"* ]]; then
|
|
REQUIRED_COMPONENTS+=("rabbitmq")
|
|
fi
|
|
for (( i=1; i<=$#; i++)) {
|
|
eval val='$'$i
|
|
REQUIRED_COMPONENTS+=( "$val" )
|
|
}
|
|
}
|
|
determine_required_components_excluding_rabbitmq() {
|
|
for (( i=1; i<=$#; i++)) {
|
|
if [[ $i != "rabbitmq" ]]; then
|
|
eval val='$'$i
|
|
REQUIRED_COMPONENTS+=( "$val" )
|
|
fi
|
|
}
|
|
}
|
|
run_on_docker_with() {
|
|
determine_required_components_including_rabbitmq $@
|
|
export PROFILES=`profiles_with_local_or_docker`
|
|
init_suite
|
|
ensure_docker_network
|
|
generate_env_file
|
|
build_mocha_image
|
|
start_selenium
|
|
|
|
trap teardown_components EXIT
|
|
|
|
start_components
|
|
test
|
|
TEST_RESULT=$?
|
|
save_logs
|
|
save_components_logs
|
|
|
|
kill_container_if_exist selenium
|
|
|
|
exit $TEST_RESULT
|
|
}
|
|
start_local_others() {
|
|
if [[ $REQUIRED_COMPONENTS == "" ]]; then
|
|
print "There are no other components"
|
|
else
|
|
start_components
|
|
fi
|
|
}
|
|
ensure_local_others() {
|
|
if [[ $REQUIRED_COMPONENTS == "" ]]; then
|
|
print "There are no other components"
|
|
else
|
|
ensure_components
|
|
fi
|
|
}
|
|
teardown_local_others() {
|
|
if [[ $REQUIRED_COMPONENTS == "" ]]; then
|
|
print "There are no other components"
|
|
else
|
|
teardown_components
|
|
fi
|
|
}
|
|
test_local() {
|
|
begin "Running local test ${1:-}"
|
|
|
|
RABBITMQ_HOST=${RABBITMQ_HOST:-rabbitmq:15672}
|
|
PUBLIC_RABBITMQ_HOST=${PUBLIC_RABBITMQ_HOST:-$RABBITMQ_HOST}
|
|
export RABBITMQ_URL=$(calculate_rabbitmq_url $PUBLIC_RABBITMQ_HOST)
|
|
export RABBITMQ_HOSTNAME=${RABBITMQ_HOSTNAME:-rabbitmq}
|
|
export RABBITMQ_AMQP_USERNAME=${RABBITMQ_AMQP_USERNAME}
|
|
export RABBITMQ_AMQP_PASSWORD=${RABBITMQ_AMQP_PASSWORD}
|
|
export SELENIUM_TIMEOUT=${SELENIUM_TIMEOUT:-20000}
|
|
export SELENIUM_POLLING=${SELENIUM_POLLING:-500}
|
|
|
|
print "> SELENIUM_TIMEOUT: ${SELENIUM_TIMEOUT}"
|
|
print "> SELENIUM_POLLING: ${SELENIUM_POLLING}"
|
|
print "> RABBITMQ_HOST: ${RABBITMQ_HOST}"
|
|
print "> RABBITMQ_HOSTNAME: ${RABBITMQ_HOSTNAME}"
|
|
print "> PUBLIC_RABBITMQ_HOST: ${PUBLIC_RABBITMQ_HOST}"
|
|
print "> RABBITMQ_PATH: ${RABBITMQ_PATH}"
|
|
print "> RABBITMQ_URL: ${RABBITMQ_URL}"
|
|
print "> UAA_URL: ${UAA_URL}"
|
|
print "> FAKE_PORTAL_URL: ${FAKE_PORTAL_URL}"
|
|
print "> OAUTH_NODE_EXTRA_CA_CERTS: ${OAUTH_NODE_EXTRA_CA_CERTS}"
|
|
MOUNT_NODE_EXTRA_CA_CERTS=${TEST_DIR}/${OAUTH_NODE_EXTRA_CA_CERTS}
|
|
print "> MOUNT_NODE_EXTRA_CA_CERTS: ${MOUNT_NODE_EXTRA_CA_CERTS}"
|
|
|
|
export RUN_LOCAL=true
|
|
export SCREENSHOTS_DIR=${SCREENS}
|
|
|
|
export PROFILES
|
|
export ENV_FILE
|
|
export NODE_EXTRA_CA_CERTS=$MOUNT_NODE_EXTRA_CA_CERTS
|
|
npm test $TEST_CASES_DIR/$1
|
|
|
|
}
|
|
ensure_components() {
|
|
for i in "${REQUIRED_COMPONENTS[@]}"
|
|
do
|
|
start="ensure_$i"
|
|
$start
|
|
done
|
|
}
|
|
start_components() {
|
|
for i in "${REQUIRED_COMPONENTS[@]}"
|
|
do
|
|
start="start_$i"
|
|
$start
|
|
done
|
|
}
|
|
|
|
teardown_components() {
|
|
begin "Tear down ..."
|
|
for i in "${REQUIRED_COMPONENTS[@]}"
|
|
do
|
|
local component="$i"
|
|
stop="stop_$i"
|
|
type "$stop" &>/dev/null && $stop || kill_container_if_exist "$component"
|
|
print "Tear down $component"
|
|
done
|
|
end "Finished teardown"
|
|
}
|
|
save_components_logs() {
|
|
begin "Saving Logs to $LOGS for ${REQUIRED_COMPONENTS[@]} ..."
|
|
for i in "${REQUIRED_COMPONENTS[@]}"
|
|
do
|
|
local component="$i"
|
|
save="save_logs_$i"
|
|
type "$save" &>/dev/null && $save || save_container_logs "$component"
|
|
print "Saving logs for component $component"
|
|
done
|
|
end "Finished saving logs"
|
|
}
|