diff --git a/.gitignore b/.gitignore index 348c7ec..f08ef08 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .shellspec-quick.log coverage +gantry-test-tmp \ No newline at end of file diff --git a/README.md b/README.md index 1153267..5e918a4 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,8 @@ You can configure the most behaviors of *Gantry* via environment variables. | GANTRY_SERVICES_EXCLUDED_FILTERS | `label=gantry.services.excluded=true` | A space separated list of [filters](https://docs.docker.com/engine/reference/commandline/service_ls/#filter), e.g. `label=project=project-a`. Exclude services which match the given filters from updating. The default value allows you to add label `gantry.services.excluded=true` to services to exclude them from updating. Note that multiple filters will be logical **ANDED**. | | GANTRY_SERVICES_FILTERS | | A space separated list of [filters](https://docs.docker.com/engine/reference/commandline/service_ls/#filter) that are accepted by `docker service ls --filter` to select services to update, e.g. `label=project=project-a`. Note that multiple filters will be logical **ANDED**. Also see [How to filters multiple services by name](docs/faq.md#how-to-filters-multiple-services-by-name). | +> NOTE: *Gantry* reads labels on the services not on the containers. The labels need to go to the [deploy](https://docs.docker.com/reference/compose-file/deploy/#labels) section, if you are using docker compose files to setup your services. + ### To check if new images are available | Environment Variable | Default | Description | @@ -105,6 +107,8 @@ You can configure the most behaviors of *Gantry* via environment variables. Labels can be added to services to modify the behavior of *Gantry* for particular services. When *Gantry* sees the following labels on a service, it will modify the Docker command line only for that service. The value on the label overrides the global environment variables. +> NOTE: *Gantry* reads labels on the services not on the containers. The labels need to go to the [deploy](https://docs.docker.com/reference/compose-file/deploy/#labels) section, if you are using docker compose files to setup your services. + | Label | Description | |--------|-------------| | `gantry.auth.config=` | Override [`DOCKER_CONFIG`](https://docs.docker.com/engine/reference/commandline/cli/#environment-variables). See [Authentication](docs/authentication.md). | @@ -117,8 +121,6 @@ Labels can be added to services to modify the behavior of *Gantry* for particula | `gantry.update.options=` | Override [`GANTRY_UPDATE_OPTIONS`](#to-add-options-to-services-update). | | `gantry.update.timeout_seconds=` | Override [`GANTRY_UPDATE_TIMEOUT_SECONDS`](#to-add-options-to-services-update). | -> NOTE: You must apply the labels to the services not the containers. If you are using docker compose files to setup your services, you need to add the label to the [deploy](https://docs.docker.com/reference/compose-file/deploy/#labels) section. - ## FAQ [Authentication](docs/authentication.md) diff --git a/src/docker_hub_rate.sh b/src/docker_hub_rate.sh index 0d46fe7..be4e750 100755 --- a/src/docker_hub_rate.sh +++ b/src/docker_hub_rate.sh @@ -16,7 +16,7 @@ # _curl_installed() { - curl --version 1>/dev/null 2>&1; + curl --version 1>/dev/null 2>/dev/null; } _docker_hub_rate_token() { @@ -66,10 +66,10 @@ _docker_hub_echo_error() { docker_hub_rate() { local IMAGE="${1:-ratelimitpreview/test}" local USER_AND_PASS="${2}" - if ! type log 1>/dev/null 2>&1; then + if ! type log 1>/dev/null 2>/dev/null; then log() { echo "${*}" >&2; } fi - if ! type log_lines 1>/dev/null 2>&1; then + if ! type log_lines 1>/dev/null 2>/dev/null; then # Usage: echo "${LOGS}" | log_lines LEVLE log_lines() { local LEVEL="${1}"; while read -r LINE; do [ -z "${LINE}" ] && continue; log "${LEVEL}" "${LINE}"; done; } fi diff --git a/src/entrypoint.sh b/src/entrypoint.sh index 1041ba1..57281ae 100755 --- a/src/entrypoint.sh +++ b/src/entrypoint.sh @@ -63,7 +63,7 @@ load_libraries() { _run_on_node() { local HOST_NAME= - if ! HOST_NAME=$(docker node inspect self --format "{{.Description.Hostname}}" 2>&1); then + if ! HOST_NAME=$(run_cmd docker node inspect self --format "{{.Description.Hostname}}"); then log DEBUG "Failed to run \"docker node inspect self\": ${HOST_NAME}" return 1 fi @@ -73,18 +73,9 @@ _run_on_node() { _read_docker_hub_rate() { local HOST PASSWORD USER - if ! PASSWORD=$(gantry_read_registry_password 2>&1); then - log ERROR "Failed to read registry PASSWORD: ${PASSWORD}"; - PASSWORD= - fi - if ! USER=$(gantry_read_registry_username 2>&1); then - log ERROR "Failed to read registry USER: ${USER}"; - USER= - fi - if ! HOST=$(gantry_read_registry_host 2>&1); then - log ERROR "Failed to read registry HOST: ${HOST}"; - HOST= - fi + USER=$(gantry_read_config "GANTRY_REGISTRY_USER") + PASSWORD=$(gantry_read_config "GANTRY_REGISTRY_PASSWORD") + HOST=$(gantry_read_config "GANTRY_REGISTRY_HOST") local USER_AND_PASS= if [ -n "${USER}" ] && [ -n "${PASSWORD}" ]; then if [ -z "${HOST}" ] || [ "${HOST}" = "docker.io" ]; then @@ -107,6 +98,7 @@ gantry() { START_TIME=$(date +%s) [ -n "${DOCKER_HOST}" ] && log DEBUG "DOCKER_HOST=${DOCKER_HOST}" + [ -n "${DOCKER_CONFIG}" ] && log DEBUG "DOCKER_CONFIG=${DOCKER_CONFIG}" local RUN_ON_NODE= if ! RUN_ON_NODE=$(_run_on_node); then local HOST_STRING="${DOCKER_HOST:-"the current node"}" @@ -123,7 +115,7 @@ gantry() { eval_cmd "pre-run" "${PRE_RUN_CMD}" ACCUMULATED_ERRORS=$((ACCUMULATED_ERRORS + $?)) - log INFO "Starting." + log INFO "Starting Gantry." gantry_initialize "${STACK}" ACCUMULATED_ERRORS=$((ACCUMULATED_ERRORS + $?)) diff --git a/src/lib-common.sh b/src/lib-common.sh index 5b5ada2..cfaa9c8 100755 --- a/src/lib-common.sh +++ b/src/lib-common.sh @@ -39,8 +39,8 @@ grep_q() { # "grep -q" will exit immediately when the first line of data matches, and leading to broken pipe errors. grep -q -- "${@}"; local GREP_RETURN=$?; - # Add "cat > /dev/null" to avoid broken pipe errors. - cat >/dev/null; + # Add "cat 1>/dev/null" to avoid broken pipe errors. + cat 1>/dev/null; return "${GREP_RETURN}" } @@ -49,7 +49,7 @@ grep_q() { grep_q_i() { grep -q -i -- "${@}"; local GREP_RETURN=$?; - cat >/dev/null; + cat 1>/dev/null; return "${GREP_RETURN}" } @@ -242,7 +242,7 @@ _log_docker_time() { # date -d "${TIME_INPUT}" +"$(_time_format)" 2>/dev/null && return 0 local EPOCH= if EPOCH=$(busybox date -d "${TIME_INPUT}" -D "%Y-%m-%dT%H:%M:%S" -u +%s 2>/dev/null); then - date -d "@${EPOCH}" +"$(_time_format)" 2>&1 + date -d "@${EPOCH}" +"$(_time_format)" return 0 fi if [ -n "${TIME_INPUT}" ]; then @@ -367,7 +367,7 @@ read_config() { cat "${CONFIG_FILE}" return $? elif [ -n "${CONFIG_FILE}" ]; then - echo "Failed to read ${CONFIG_FILE}" >&2 + echo "Failed to read file ${CONFIG_FILE}" >&2 return 1 fi eval "local CONFIG=\${${CONFIG_NAME}}" @@ -434,13 +434,36 @@ eval_cmd() { return "${RETURN_VALUE}" } +# When the command returns 0: +# Echo stdout and log stderr as a warning. Return 0. +# When the command returns non-zero: +# Echo stdout + stderr. Return the same value from the docker command. +run_cmd() { + local STDERR_STR= + local RETURN_VALUE= + # Use "3>&2 2>&1 1>&3" to swap stdout and stderr + { STDERR_STR=$("${@}" 3>&2 2>&1 1>&3); } 2>&1 + RETURN_VALUE=$? + + if [ -n "${STDERR_STR}" ]; then + if [ "${RETURN_VALUE}" = 0 ]; then + log WARN "${STDERR_STR} (From command: ${*})" + else + echo "${STDERR_STR}" + fi + fi + return "${RETURN_VALUE}" +} + swarm_network_arguments() { if [ -z "${NETWORK_NAME}" ]; then echo "" return 0 fi - NETWORK_NAME=$(docker network ls --filter "name=${NETWORK_NAME}" --format '{{.Name}}') - if [ -z "${NETWORK_NAME}" ]; then + local RETURN_VALUE= + NETWORK_NAME=$(run_cmd docker network ls --filter "name=${NETWORK_NAME}" --format '{{.Name}}') + RETURN_VALUE=$? + if [ "${RETURN_VALUE}" != "0" ] || [ -z "${NETWORK_NAME}" ]; then echo "" return 0 fi @@ -481,7 +504,7 @@ docker_service_logs() { _docker_service_exists() { local SERVICE_NAME="${1}" - docker service inspect --format '{{.ID}}' "${SERVICE_NAME}" >/dev/null 2>&1 + docker service inspect --format '{{.ID}}' "${SERVICE_NAME}" 1>/dev/null 2>/dev/null } _docker_wait_until_service_removed() { @@ -513,8 +536,8 @@ _docker_service_task_states() { local SERVICE_NAME="${1}" # We won't get the return value of the command via $? if we use "local STATES=$(command)". local STATES= - if ! STATES=$(docker service ps --no-trunc --format '[{{.Name}}][{{.Node}}] {{.CurrentState}} {{.Error}}' "${SERVICE_NAME}" 2>&1); then - echo "${STATES}" >&2 + if ! STATES=$(run_cmd docker service ps --no-trunc --format '[{{.Name}}][{{.Node}}] {{.CurrentState}} {{.Error}}' "${SERVICE_NAME}"); then + log ERROR "${STATES}" return 1 fi local NAME_LIST= @@ -591,7 +614,7 @@ wait_service_state() { local RETURN_VALUE=0 local DOCKER_CMD_ERROR=1 local STATES= - while STATES=$(_docker_service_task_states "${SERVICE_NAME}" 2>&1); do + while STATES=$(_docker_service_task_states "${SERVICE_NAME}"); do DOCKER_CMD_ERROR=0 RETURN_VALUE=$(_all_tasks_reach_state "${WANT_STATE}" "${CHECK_FAILURES}" "${STATES}") && break local SECONDS_ELAPSED= @@ -606,7 +629,7 @@ wait_service_state() { DOCKER_CMD_ERROR=1 done if [ "${DOCKER_CMD_ERROR}" != "0" ]; then - log ERROR "Failed to obtain task states of service ${SERVICE_NAME}: ${STATES}" + log ERROR "Failed to obtain task states of service ${SERVICE_NAME}." return 1 fi local LINE= @@ -621,12 +644,10 @@ docker_service_remove() { local POST_COMMAND="${2}" ! _docker_service_exists "${SERVICE_NAME}" && return 0 log DEBUG "Removing service ${SERVICE_NAME}." - local RETURN_VALUE=0 local LOG= - if ! LOG=$(docker service rm "${SERVICE_NAME}" 2>&1); then - RETURN_VALUE=$? + if ! LOG=$(run_cmd docker service rm "${SERVICE_NAME}"); then log ERROR "Failed to remove docker service ${SERVICE_NAME}: ${LOG}" - return "${RETURN_VALUE}" + return 1 fi if [ -n "${POST_COMMAND}" ]; then eval "${POST_COMMAND}" @@ -654,7 +675,7 @@ docker_global_job() { SERVICE_NAME=$(_get_docker_command_name_arg "${@}") log INFO "Starting global-job ${SERVICE_NAME}." local LOG= - if ! LOG=$(docker service create --mode global-job "${@}" 2>&1); then + if ! LOG=$(run_cmd docker service create --mode global-job "${@}"); then log ERROR "Failed to create global-job ${SERVICE_NAME}: ${LOG}" return 1 fi @@ -669,7 +690,7 @@ docker_replicated_job() { # The Docker CLI does not exit on failures. log INFO "Starting replicated-job ${SERVICE_NAME}." local LOG= - if ! LOG=$(docker service create --mode replicated-job --detach "${@}" 2>&1); then + if ! LOG=$(run_cmd docker service create --mode replicated-job --detach "${@}"); then log ERROR "Failed to create replicated-job ${SERVICE_NAME}: ${LOG}" return 1 fi @@ -682,10 +703,10 @@ docker_replicated_job() { docker_version() { local cver capi sver sapi - if ! cver=$(docker version --format '{{.Client.Version}}' 2>&1); then log ERROR "${cver}"; cver="error"; fi - if ! capi=$(docker version --format '{{.Client.APIVersion}}' 2>&1); then log ERROR "${capi}"; capi="error"; fi - if ! sver=$(docker version --format '{{.Server.Version}}' 2>&1); then log ERROR "${sver}"; sver="error"; fi - if ! sapi=$(docker version --format '{{.Server.APIVersion}}' 2>&1); then log ERROR "${sapi}"; sapi="error"; fi + if ! cver=$(run_cmd docker version --format '{{.Client.Version}}'); then log ERROR "${cver}"; cver="error"; fi + if ! capi=$(run_cmd docker version --format '{{.Client.APIVersion}}'); then log ERROR "${capi}"; capi="error"; fi + if ! sver=$(run_cmd docker version --format '{{.Server.Version}}'); then log ERROR "${sver}"; sver="error"; fi + if ! sapi=$(run_cmd docker version --format '{{.Server.APIVersion}}'); then log ERROR "${sapi}"; sapi="error"; fi echo "Docker version client ${cver} (API ${capi}) server ${sver} (API ${sapi})" } @@ -694,7 +715,7 @@ docker_version() { # return 1 when there is an error. docker_current_container_name() { local ALL_NETWORKS= - ALL_NETWORKS=$(docker network ls --format '{{.ID}}') || return 1; + ALL_NETWORKS=$(run_cmd docker network ls --format '{{.ID}}') || return 1; [ -z "${ALL_NETWORKS}" ] && return 0; local IPS=; # Get the string after "src": @@ -702,8 +723,8 @@ docker_current_container_name() { IPS=$(ip route | grep src | sed -n -E "s/.* src (\S+).*$/\1/p"); [ -z "${IPS}" ] && return 0; local GWBRIDGE_NETWORK HOST_NETWORK; - GWBRIDGE_NETWORK=$(docker network ls --format '{{.ID}}' --filter 'name=^docker_gwbridge$') || return 1; - HOST_NETWORK=$(docker network ls --format '{{.ID}}' --filter 'name=^host$') || return 1; + GWBRIDGE_NETWORK=$(run_cmd docker network ls --format '{{.ID}}' --filter 'name=^docker_gwbridge$') || return 1; + HOST_NETWORK=$(run_cmd docker network ls --format '{{.ID}}' --filter 'name=^host$') || return 1; local NID=; for NID in ${ALL_NETWORKS}; do # The output of gwbridge does not contain the container name. It looks like gateway_8f55496ce4f1/172.18.0.5/16. @@ -711,7 +732,7 @@ docker_current_container_name() { # The output of host does not contain an IP. [ "${NID}" = "${HOST_NETWORK}" ] && continue; local ALL_LOCAL_NAME_AND_IP=; - ALL_LOCAL_NAME_AND_IP=$(docker network inspect "${NID}" --format "{{range .Containers}}{{.Name}}/{{println .IPv4Address}}{{end}}") || return 1; + ALL_LOCAL_NAME_AND_IP=$(run_cmd docker network inspect "${NID}" --format "{{range .Containers}}{{.Name}}/{{println .IPv4Address}}{{end}}") || return 1; local NAME_AND_IP=; for NAME_AND_IP in ${ALL_LOCAL_NAME_AND_IP}; do [ -z "${NAME_AND_IP}" ] && continue; @@ -747,10 +768,10 @@ docker_remove() { fi log DEBUG "Removing container ${CNAME}." if [ "${STATUS}" = "running" ]; then - docker stop "${CNAME}" >/dev/null 2>/dev/null + docker container stop "${CNAME}" 1>/dev/null 2>/dev/null fi # If the container is created with "--rm", it will be removed automatically when being stopped. - docker rm -f "${CNAME}" >/dev/null; + docker container rm -f "${CNAME}" 1>/dev/null; log INFO "Removed container ${CNAME}." } @@ -758,15 +779,15 @@ docker_run() { local RETRIES=0 local MAX_RETRIES=5 local SLEEP_SECONDS=10 - local MSG= - while ! MSG=$(docker run "${@}" 2>&1); do + local LOG= + while ! LOG=$(run_cmd docker container run "${@}"); do if [ ${RETRIES} -ge ${MAX_RETRIES} ]; then - log ERROR "Failed to run docker. Reached the max retries ${MAX_RETRIES}. ${MSG}" + log ERROR "Failed to run docker. Reached the max retries ${MAX_RETRIES}. ${LOG}" return 1 fi RETRIES=$((RETRIES + 1)) sleep ${SLEEP_SECONDS} - log WARN "Retry docker run (${RETRIES}). ${MSG}" + log WARN "Retry docker container run (${RETRIES}). ${LOG}" done - echo "${MSG}" + echo "${LOG}" } diff --git a/src/lib-gantry.sh b/src/lib-gantry.sh index 3f0a21a..1f97774 100755 --- a/src/lib-gantry.sh +++ b/src/lib-gantry.sh @@ -33,7 +33,7 @@ _read_env_default() { gantry_read_number() { local ENV_NAME="${1}" local DEFAULT_VALUE="${2}" - ! is_number "${DEFAULT_VALUE}" && log ERROR "DEFAULT_VALUE must be a number. Got \"${DEFAULT_VALUE}\"." && return 1 + ! is_number "${DEFAULT_VALUE}" && log ERROR "DEFAULT_VALUE for ${ENV_NAME} must be a number. Got \"${DEFAULT_VALUE}\"." && return 1 local VALUE= VALUE=$(_read_env_default "${ENV_NAME}" "${DEFAULT_VALUE}") if ! is_number "${VALUE}"; then @@ -49,7 +49,7 @@ _get_label_from_service() { local SERVICE_NAME="${1}" local LABEL="${2}" local VALUE= - if ! VALUE=$(docker service inspect -f "{{index .Spec.Labels \"${LABEL}\"}}" "${SERVICE_NAME}" 2>&1); then + if ! VALUE=$(run_cmd docker service inspect -f "{{index .Spec.Labels \"${LABEL}\"}}" "${SERVICE_NAME}"); then log ERROR "Failed to obtain the value of label ${LABEL} from service ${SERVICE_NAME}. ${VALUE}" return 1 fi @@ -134,7 +134,7 @@ _login_registry() { local LOGIN_MSG= # SC2086: Double quote to prevent globbing and word splitting. # shellcheck disable=SC2086 - if ! LOGIN_MSG=$(echo "${PASSWORD}" | docker ${AUTH_CONFIG} login --username="${USER}" --password-stdin "${HOST}" 2>&1); then + if ! LOGIN_MSG=$(echo "${PASSWORD}" | run_cmd docker ${AUTH_CONFIG} login --username="${USER}" --password-stdin "${HOST}"); then log ERROR "Failed to login to ${REGISTRY_CONFIG_MESSAGE}. ${LOGIN_MSG}" return 1 fi @@ -146,42 +146,24 @@ _login_registry() { return 0 } -gantry_read_registry_username() { - read_config GANTRY_REGISTRY_USER -} - -gantry_read_registry_password() { - read_config GANTRY_REGISTRY_PASSWORD -} - -gantry_read_registry_host() { - read_config GANTRY_REGISTRY_HOST +gantry_read_config() { + local CONFIG_NAME="${1}" + local CONFIG_VALUE= + if ! CONFIG_VALUE=$(read_config "${CONFIG_NAME}" 2>&1); then + log ERROR "Failed to read ${CONFIG_NAME}: ${CONFIG_VALUE}" + return 1 + fi + echo "${CONFIG_VALUE}" } _authenticate_to_registries() { local CONFIGS_FILE="${GANTRY_REGISTRY_CONFIGS_FILE:-""}" local ACCUMULATED_ERRORS=0 local CONFIG HOST PASSWORD USER - if ! CONFIG=$(read_config GANTRY_REGISTRY_CONFIG 2>&1); then - log ERROR "Failed to read registry CONFIG: ${CONFIG}" - ACCUMULATED_ERRORS=$((ACCUMULATED_ERRORS + 1)) - CONFIG= - fi - if ! HOST=$(gantry_read_registry_host 2>&1); then - log ERROR "Failed to read registry HOST: ${HOST}" - ACCUMULATED_ERRORS=$((ACCUMULATED_ERRORS + 1)) - HOST= - fi - if ! PASSWORD=$(gantry_read_registry_password 2>&1); then - log ERROR "Failed to read registry PASSWORD: ${PASSWORD}" - ACCUMULATED_ERRORS=$((ACCUMULATED_ERRORS + 1)) - PASSWORD= - fi - if ! USER=$(gantry_read_registry_username 2>&1); then - log ERROR "Failed to read registry USER: ${USER}" - ACCUMULATED_ERRORS=$((ACCUMULATED_ERRORS + 1)) - USER= - fi + CONFIG=$(gantry_read_config "GANTRY_REGISTRY_CONFIG") || ACCUMULATED_ERRORS=$((ACCUMULATED_ERRORS + 1)) + HOST=$(gantry_read_config "GANTRY_REGISTRY_HOST") || ACCUMULATED_ERRORS=$((ACCUMULATED_ERRORS + 1)) + PASSWORD=$(gantry_read_config "GANTRY_REGISTRY_PASSWORD") || ACCUMULATED_ERRORS=$((ACCUMULATED_ERRORS + 1)) + USER=$(gantry_read_config "GANTRY_REGISTRY_USER") || ACCUMULATED_ERRORS=$((ACCUMULATED_ERRORS + 1)) if [ "${ACCUMULATED_ERRORS}" -gt 0 ]; then log ERROR "Skip logging in due to previous error(s)." else @@ -229,7 +211,7 @@ _send_notification() { local TYPE="${1}" local TITLE="${2}" local BODY="${3}" - if ! type notify_summary >/dev/null 2>&1; then + if ! type notify_summary 1>/dev/null 2>/dev/null; then return 0 fi notify_summary "${TYPE}" "${TITLE}" "${BODY}" @@ -266,9 +248,9 @@ _get_static_variables_folder() { } _remove_static_variables_folder() { - [ -z "${STATIC_VARIABLES_FOLDER}" ] && return 0 local TO_REMOVE_STATIC_VARIABLES_FOLDER= TO_REMOVE_STATIC_VARIABLES_FOLDER="$(_get_static_variables_folder_name)" + [ ! -d "${TO_REMOVE_STATIC_VARIABLES_FOLDER}" ] && return 0 log DEBUG "Removing STATIC_VARIABLES_FOLDER ${TO_REMOVE_STATIC_VARIABLES_FOLDER}" unset STATIC_VARIABLES_FOLDER rm -r "${TO_REMOVE_STATIC_VARIABLES_FOLDER}" @@ -286,14 +268,14 @@ _lock() { local NAME="${1}" local LOCK_NAME= LOCK_NAME="$(_get_static_variables_folder)/${NAME}-LOCK" - while ! mkdir "${LOCK_NAME}" >/dev/null 2>&1; do sleep 0.001; done + while ! mkdir "${LOCK_NAME}" 1>/dev/null 2>/dev/null; do sleep 0.001; done } _unlock() { local NAME="${1}" local LOCK_NAME= LOCK_NAME="$(_get_static_variables_folder)/${NAME}-LOCK" - rm -r "${LOCK_NAME}" >/dev/null 2>&1 + rm -r "${LOCK_NAME}" 1>/dev/null 2>/dev/null } _static_variable_read_list_core() { @@ -364,15 +346,15 @@ _remove_container() { local IMAGE="${1}"; local STATUS="${2}"; local CIDS= - if ! CIDS=$(docker container ls --all --filter "ancestor=${IMAGE}" --filter "status=${STATUS}" --format '{{.ID}}' 2>&1); then + if ! CIDS=$(run_cmd docker container ls --all --filter "ancestor=${IMAGE}" --filter "status=${STATUS}" --format '{{.ID}}'); then log ERROR "Failed to list ${STATUS} containers with image ${IMAGE}."; echo "${CIDS}" | log_lines ERROR return 1; fi local CID CNAME CRM_MSG for CID in ${CIDS}; do - CNAME=$(docker container inspect --format '{{.Name}}' "${CID}"); - if ! CRM_MSG=$(docker container rm "${CID}" 2>&1); then + CNAME=$(run_cmd docker container inspect --format '{{.Name}}' "${CID}"); + if ! CRM_MSG=$(run_cmd docker container rm "${CID}"); then log ERROR "Failed to remove ${STATUS} container ${CNAME}, which is using image ${IMAGE}."; echo "${CRM_MSG}" | log_lines ERROR continue; @@ -387,13 +369,13 @@ gantry_remove_images() { log DEBUG "$(docker_version)" local IMAGE= for IMAGE in ${IMAGES_TO_REMOVE}; do - if ! docker image inspect "${IMAGE}" 1>/dev/null 2>&1 ; then + if ! run_cmd docker image inspect "${IMAGE}" 1>/dev/null; then log DEBUG "There is no image ${IMAGE} on the node."; continue; fi _remove_container "${IMAGE}" exited; _remove_container "${IMAGE}" dead; - if ! RMI_MSG=$(docker rmi "${IMAGE}" 2>&1); then + if ! RMI_MSG=$(run_cmd docker image rm "${IMAGE}"); then log ERROR "Failed to remove image ${IMAGE}."; echo "${RMI_MSG}" | log_lines ERROR continue; @@ -446,6 +428,7 @@ _remove_images() { # shellcheck disable=SC2086 docker_global_job --name "${SERVICE_NAME}" \ --detach=true \ + --with-registry-auth \ --restart-condition on-failure \ --restart-max-attempts 1 \ --mount type=bind,source=/var/run/docker.sock,destination=/var/run/docker.sock \ @@ -616,7 +599,9 @@ gantry_current_service_name() { CNAME=$(_current_container_name) || return 1 [ -z "${CNAME}" ] && return 0 local SNAME= - SNAME=$(docker container inspect "${CNAME}" --format '{{range $key,$value := .Config.Labels}}{{$key}}={{println $value}}{{end}}' \ + # SC2016 (info): Expressions don't expand in single quotes, use double quotes for that. + # shellcheck disable=SC2016 + SNAME=$(run_cmd docker container inspect "${CNAME}" --format '{{range $key,$value := .Config.Labels}}{{$key}}={{println $value}}{{end}}' \ | grep "com.docker.swarm.service.name" \ | sed -n -E "s/com.docker.swarm.service.name=(.*)$/\1/p") || return 1 _static_variable_add_unique_to_list STATIC_VAR_CURRENT_SERVICE_NAME "${SNAME}" @@ -643,19 +628,37 @@ _service_is_self() { _get_service_image() { local SERVICE_NAME="${1}" [ -z "${SERVICE_NAME}" ] && return 1 - docker service inspect -f '{{.Spec.TaskTemplate.ContainerSpec.Image}}' "${SERVICE_NAME}" + local RETURN_VALUE= + local IMAGE_WITH_DIGEST= + IMAGE_WITH_DIGEST=$(run_cmd docker service inspect -f '{{.Spec.TaskTemplate.ContainerSpec.Image}}' "${SERVICE_NAME}") + RETURN_VALUE=$? + if [ "${RETURN_VALUE}" != "0" ]; then + log ERROR "Failed to obtain image from service ${SERVICE_NAME}. ${IMAGE_WITH_DIGEST}" + else + echo "${IMAGE_WITH_DIGEST}" + fi + return "${RETURN_VALUE}" } _get_service_previous_image() { local SERVICE_NAME="${1}" [ -z "${SERVICE_NAME}" ] && return 1 - docker service inspect -f '{{.PreviousSpec.TaskTemplate.ContainerSpec.Image}}' "${SERVICE_NAME}" + local RETURN_VALUE= + local IMAGE_WITH_DIGEST= + IMAGE_WITH_DIGEST=$(run_cmd docker service inspect -f '{{.PreviousSpec.TaskTemplate.ContainerSpec.Image}}' "${SERVICE_NAME}") + RETURN_VALUE=$? + if [ "${RETURN_VALUE}" != "0" ]; then + log ERROR "Failed to obtain previous image from service ${SERVICE_NAME}. ${IMAGE_WITH_DIGEST}" + else + echo "${IMAGE_WITH_DIGEST}" + fi + return "${RETURN_VALUE}" } _get_service_mode() { local SERVICE_NAME="${1}" local MODE= - if ! MODE=$(docker service ls --filter "name=${SERVICE_NAME}" --format '{{.Mode}} {{.Name}}' 2>&1); then + if ! MODE=$(run_cmd docker service ls --filter "name=${SERVICE_NAME}" --format '{{.Mode}} {{.Name}}'); then log ERROR "Failed to obtain the mode of the service ${SERVICE_NAME}: ${MODE}" return 1 fi @@ -751,13 +754,13 @@ _get_image_info() { [ -n "${MANIFEST_OPTIONS}" ] && log INFO "Adding options \"${MANIFEST_OPTIONS}\" to the command \"docker buildx imagetools inspect\"." # SC2086: Double quote to prevent globbing and word splitting. # shellcheck disable=SC2086 - MSG=$(docker ${AUTH_CONFIG} buildx imagetools inspect ${MANIFEST_OPTIONS} "${IMAGE}" 2>&1); + MSG=$(run_cmd docker ${AUTH_CONFIG} buildx imagetools inspect ${MANIFEST_OPTIONS} "${IMAGE}"); RETURN_VALUE=$? elif echo "${MANIFEST_CMD}" | grep_q_i "manifest"; then [ -n "${MANIFEST_OPTIONS}" ] && log INFO "Adding options \"${MANIFEST_OPTIONS}\" to the command \"docker manifest inspect\"." # SC2086: Double quote to prevent globbing and word splitting. # shellcheck disable=SC2086 - MSG=$(docker ${AUTH_CONFIG} manifest inspect ${MANIFEST_OPTIONS} "${IMAGE}" 2>&1); + MSG=$(run_cmd docker ${AUTH_CONFIG} manifest inspect ${MANIFEST_OPTIONS} "${IMAGE}"); RETURN_VALUE=$? elif echo "${MANIFEST_CMD}" | grep_q_i "none"; then # We should never reach here, the "none" command is already checked inside the function _inspect_image. @@ -782,10 +785,7 @@ _inspect_image() { local MANIFEST_CMD= MANIFEST_CMD=$(_read_env_or_label "${SERVICE_NAME}" "GANTRY_MANIFEST_CMD" "gantry.manifest.cmd" "buildx") local IMAGE_WITH_DIGEST= - if ! IMAGE_WITH_DIGEST=$(_get_service_image "${SERVICE_NAME}" 2>&1); then - log ERROR "Failed to obtain image from service ${SERVICE_NAME}. ${IMAGE_WITH_DIGEST}" - return 1 - fi + IMAGE_WITH_DIGEST=$(_get_service_image "${SERVICE_NAME}") || return $? local IMAGE= local DIGEST= IMAGE=$(extract_string "${IMAGE_WITH_DIGEST}" '@' 1) @@ -869,7 +869,7 @@ _inspect_service() { _get_number_of_running_tasks() { local SERVICE_NAME="${1}" local REPLICAS= - if ! REPLICAS=$(docker service ls --filter "name=${SERVICE_NAME}" --format '{{.Replicas}} {{.Name}}' 2>&1); then + if ! REPLICAS=$(run_cmd docker service ls --filter "name=${SERVICE_NAME}" --format '{{.Replicas}} {{.Name}}'); then log ERROR "Failed to obtain task states of service ${SERVICE_NAME}: ${REPLICAS}" return 1 fi @@ -903,8 +903,8 @@ _get_service_update_additional_options() { local NUM_RUNS= NUM_RUNS=$(_get_number_of_running_tasks "${SERVICE_NAME}") ! is_number "${NUM_RUNS}" && log WARN "NUM_RUNS \"${NUM_RUNS}\" is not a number." && return 1 - local OPTIONS="" - local SPACE="" + local OPTIONS= + local SPACE= if [ "${NUM_RUNS}" = "0" ]; then # Add "--detach=true" when there is no running tasks. # https://github.com/docker/cli/issues/627 @@ -950,18 +950,18 @@ _rollback_service() { # "service update --rollback" needs to take different options from "service update" local AUTOMATIC_OPTIONS= AUTOMATIC_OPTIONS=$(_get_service_rollback_additional_options "${SERVICE_NAME}" "${AUTH_CONFIG}") - [ -n "${AUTOMATIC_OPTIONS}" ] && log INFO "Adding options \"${AUTOMATIC_OPTIONS}\" automatically to the command \"docker service update --rollback\" for ${SERVICE_NAME}." - [ -n "${ROLLBACK_OPTIONS}" ] && log INFO "Adding options \"${ROLLBACK_OPTIONS}\" specified by user to the command \"docker service update --rollback\" for ${SERVICE_NAME}." + local CMD_STRING="\"docker service update --rollback\"" + [ -n "${AUTH_CONFIG}" ] && log INFO "Adding options \"${AUTH_CONFIG}\" to the command ${CMD_STRING} for ${SERVICE_NAME}." + [ -n "${AUTOMATIC_OPTIONS}" ] && log INFO "Adding options \"${AUTOMATIC_OPTIONS}\" automatically to the command ${CMD_STRING} for ${SERVICE_NAME}." + [ -n "${ROLLBACK_OPTIONS}" ] && log INFO "Adding options \"${ROLLBACK_OPTIONS}\" specified by user to the command ${CMD_STRING} for ${SERVICE_NAME}." local ROLLBACK_MSG= # Add "-quiet" to suppress progress output. # SC2086: Double quote to prevent globbing and word splitting. # shellcheck disable=SC2086 - if ! ROLLBACK_MSG=$(docker ${AUTH_CONFIG} service update --quiet ${AUTOMATIC_OPTIONS} ${ROLLBACK_OPTIONS} --rollback "${SERVICE_NAME}" 2>&1); then + if ! ROLLBACK_MSG=$(run_cmd docker ${AUTH_CONFIG} service update --quiet ${AUTOMATIC_OPTIONS} ${ROLLBACK_OPTIONS} --rollback "${SERVICE_NAME}"); then log ERROR "Failed to roll back ${SERVICE_NAME}. ${ROLLBACK_MSG}" return 1 fi - # Usually the ROLLBACK_MSG is same as the SERVICE_NAME. - [ "${ROLLBACK_MSG}" != "${SERVICE_NAME}" ] && log WARN "There are additional messages from rolling back ${SERVICE_NAME}: ${ROLLBACK_MSG}" log INFO "Rolled back ${SERVICE_NAME}." } @@ -976,7 +976,7 @@ _get_timeout_command() { _static_variable_add_unique_to_list STATIC_VAR_SERVICES_UPDATE_INPUT_ERROR "${SERVICE_NAME}" return 1 fi - local TIMEOUT_COMMAND="" + local TIMEOUT_COMMAND= if [ "${UPDATE_TIMEOUT_SECONDS}" != "0" ]; then TIMEOUT_COMMAND="timeout ${UPDATE_TIMEOUT_SECONDS}" log INFO "Set timeout to ${UPDATE_TIMEOUT_SECONDS} for updating ${SERVICE_NAME}." @@ -1005,19 +1005,23 @@ _update_single_service() { local AUTOMATIC_OPTIONS= AUTH_CONFIG=$(_get_auth_config_from_service "${SERVICE_NAME}") AUTOMATIC_OPTIONS=$(_get_service_update_additional_options "${SERVICE_NAME}" "${AUTH_CONFIG}") - [ -n "${AUTH_CONFIG}" ] && log INFO "Adding options \"${AUTH_CONFIG}\" to docker commands for ${SERVICE_NAME}." - [ -n "${AUTOMATIC_OPTIONS}" ] && log INFO "Adding options \"${AUTOMATIC_OPTIONS}\" automatically to the command \"docker service update\" for ${SERVICE_NAME}." - [ -n "${UPDATE_OPTIONS}" ] && log INFO "Adding options \"${UPDATE_OPTIONS}\" specified by user to the command \"docker service update\" for ${SERVICE_NAME}." - local TIMEOUT_COMMAND="" + local CMD_STRING="\"docker service update\"" + [ -n "${AUTH_CONFIG}" ] && log INFO "Adding options \"${AUTH_CONFIG}\" to the command ${CMD_STRING} for ${SERVICE_NAME}." + [ -n "${AUTOMATIC_OPTIONS}" ] && log INFO "Adding options \"${AUTOMATIC_OPTIONS}\" automatically to the command ${CMD_STRING} for ${SERVICE_NAME}." + [ -n "${UPDATE_OPTIONS}" ] && log INFO "Adding options \"${UPDATE_OPTIONS}\" specified by user to the command ${CMD_STRING} for ${SERVICE_NAME}." + local TIMEOUT_COMMAND= TIMEOUT_COMMAND=$(_get_timeout_command "${SERVICE_NAME}") || return 1 - local UPDATE_COMMAND="${TIMEOUT_COMMAND} docker ${AUTH_CONFIG} service update" + local SPACE_T= + [ -n "${TIMEOUT_COMMAND}" ] && SPACE_T=" " + local SPACE_C= + [ -n "${AUTH_CONFIG}" ] && SPACE_C=" " + local UPDATE_COMMAND="${TIMEOUT_COMMAND}${SPACE_T}docker ${AUTH_CONFIG}${SPACE_C}service update" local UPDATE_RETURN_VALUE=0 local UPDATE_MSG= - # Add "2>/dev/null" outside the $(cmd) to suppress the "Terminated" message from "busybox timeout". # Add "-quiet" to suppress progress output. # SC2086: Double quote to prevent globbing and word splitting. # shellcheck disable=SC2086 - UPDATE_MSG=$(${UPDATE_COMMAND} --quiet ${AUTOMATIC_OPTIONS} ${UPDATE_OPTIONS} --image="${IMAGE}" "${SERVICE_NAME}" 2>&1) 2>/dev/null; + UPDATE_MSG=$(run_cmd ${UPDATE_COMMAND} --quiet ${AUTOMATIC_OPTIONS} ${UPDATE_OPTIONS} --image="${IMAGE}" "${SERVICE_NAME}"); UPDATE_RETURN_VALUE=$? if [ "${UPDATE_RETURN_VALUE}" != 0 ]; then # When there is a timeout: @@ -1025,7 +1029,7 @@ _update_single_service() { # * busybox timeout returns 143 local TIMEOUT_RETURN_CODE=124 timeout --help 2>&1 | grep_q_i "BusyBox" && TIMEOUT_RETURN_CODE=143 - local TIMEOUT_MSG="" + local TIMEOUT_MSG= if [ -n "${TIMEOUT_COMMAND}" ] && [ "${UPDATE_RETURN_VALUE}" = "${TIMEOUT_RETURN_CODE}" ]; then TIMEOUT_MSG="The return value ${UPDATE_RETURN_VALUE} indicates the job timed out." fi @@ -1035,8 +1039,6 @@ _update_single_service() { _static_variable_add_unique_to_list STATIC_VAR_SERVICES_UPDATE_FAILED "${SERVICE_NAME}" return 1 fi - # Usually the UPDATE_MSG is same as the SERVICE_NAME. - [ "${UPDATE_MSG}" != "${SERVICE_NAME}" ] && log WARN "There are additional messages from updating ${SERVICE_NAME}: ${UPDATE_MSG}" local TIME_ELAPSED= TIME_ELAPSED=$(time_elapsed_since "${START_TIME}") local PREVIOUS_IMAGE= @@ -1092,13 +1094,15 @@ _get_services_filted() { local SERVICES_FILTERS="${1}" local SERVICES= local FILTERS= + local SPACE= local F= for F in ${SERVICES_FILTERS}; do - FILTERS="${FILTERS} --filter ${F}" + FILTERS="${FILTERS}${SPACE}--filter ${F}" + SPACE=" " done # SC2086: Double quote to prevent globbing and word splitting. # shellcheck disable=SC2086 - if ! SERVICES=$(docker service ls --quiet ${FILTERS} --format '{{.Name}}' 2>&1); then + if ! SERVICES=$(run_cmd docker service ls --quiet ${FILTERS} --format '{{.Name}}'); then log ERROR "Failed to obtain services list with \"${FILTERS}\". ${SERVICES}" return 1 fi diff --git a/tests/gantry_common_options_spec.sh b/tests/gantry_common_options_spec.sh index e6f8424..10066bd 100644 --- a/tests/gantry_common_options_spec.sh +++ b/tests/gantry_common_options_spec.sh @@ -102,9 +102,9 @@ Describe 'common-options' local TEST_NAME="${1}" local SERVICE_NAME="${2}" local ENV_BEFORE_RUN= - ENV_BEFORE_RUN=$(mktemp) + ENV_BEFORE_RUN=$(make_test_temp_file) local ENV_AFTER_RUN= - ENV_AFTER_RUN=$(mktemp) + ENV_AFTER_RUN=$(make_test_temp_file) reset_gantry_env "${SUITE_NAME}" "${SERVICE_NAME}" # There should be no warnings or errors. So it should work the same as LOG_LEVLE=NONE. @@ -113,7 +113,8 @@ Describe 'common-options' run_gantry "${SUITE_NAME}" "${TEST_NAME}" declare -p > "${ENV_AFTER_RUN}" # Allow the 3 mismatches LOG_LEVEL NODE_NAME LOG_SCOPE used in log() function. - # Allow the 2 mismatches LINENO _ for kcov coverage. + # Allow the 1 mismatch LINENO for kcov coverage. + # Allow the 1 mismatch _ for the previous command. for ALLOWED in LOG_LEVEL NODE_NAME LOG_SCOPE LINENO _; do sed -i "s/^declare .* ${ALLOWED}=.*//" "${ENV_BEFORE_RUN}" sed -i "s/^declare .* ${ALLOWED}=.*//" "${ENV_AFTER_RUN}" diff --git a/tests/gantry_login_docker_config_spec.sh b/tests/gantry_login_docker_config_spec.sh index 0bd8ece..d39b27a 100644 --- a/tests/gantry_login_docker_config_spec.sh +++ b/tests/gantry_login_docker_config_spec.sh @@ -42,7 +42,7 @@ Describe 'login-docker-config' # When running with an Gantry image, docker buildx writes files to this folder which are owned by root. # Using a relative path, this the container will not write to the folder on the host. # So do not use an absolute path, otherwise we cannot remove this folder on the host. - AUTH_CONFIG="C$(unique_id)" + AUTH_CONFIG=$(get_config_name) TEST_REGISTRY=$(load_test_registry "${SUITE_NAME}") || return 1 test_login_docker_config_no_label() { local TEST_NAME="${1}" @@ -52,8 +52,8 @@ Describe 'login-docker-config' local USERNAME="${5}" local PASSWORD="${6}" check_login_input "${REGISTRY}" "${USERNAME}" "${PASSWORD}" || return 1; - local USER_FILE=; USER_FILE=$(mktemp); echo "${USERNAME}" > "${USER_FILE}"; - local PASS_FILE=; PASS_FILE=$(mktemp); echo "${PASSWORD}" > "${PASS_FILE}"; + local USER_FILE=; USER_FILE=$(make_test_temp_file); echo "${USERNAME}" > "${USER_FILE}"; + local PASS_FILE=; PASS_FILE=$(make_test_temp_file); echo "${PASSWORD}" > "${PASS_FILE}"; reset_gantry_env "${SUITE_NAME}" "${SERVICE_NAME}" export GANTRY_TEST_DOCKER_CONFIG="${CONFIG}" export GANTRY_REGISTRY_CONFIG="${CONFIG}" @@ -91,7 +91,6 @@ Describe 'login-docker-config' The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}.*--config.*" # Gantry adds --with-registry-auth, because DOCKER_CONFIG and the configuration name are same (default location). The stderr should satisfy spec_expect_message "${ADDING_OPTIONS_WITH_REGISTRY_AUTH}" - The stderr should satisfy spec_expect_no_message "${THERE_ARE_ADDITIONAL_MESSAGES}.*${SERVICE_NAME}.*" The stderr should satisfy spec_expect_message "${UPDATED}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${NO_UPDATES}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${ROLLING_BACK}.*${SERVICE_NAME}" @@ -116,7 +115,7 @@ Describe 'login-docker-config' # When running with an Gantry image, docker buildx writes files to this folder which are owned by root. # Using a relative path, this the container will not write to the folder on the host. # So do not use an absolute path, otherwise we cannot remove this folder on the host. - AUTH_CONFIG="C$(unique_id)" + AUTH_CONFIG=$(get_config_name) TEST_REGISTRY=$(load_test_registry "${SUITE_NAME}") || return 1 test_login_docker_config_default_config() { local TEST_NAME="${1}" @@ -126,8 +125,8 @@ Describe 'login-docker-config' local USERNAME="${5}" local PASSWORD="${6}" check_login_input "${REGISTRY}" "${USERNAME}" "${PASSWORD}" || return 1; - local USER_FILE=; USER_FILE=$(mktemp); echo "${USERNAME}" > "${USER_FILE}"; - local PASS_FILE=; PASS_FILE=$(mktemp); echo "${PASSWORD}" > "${PASS_FILE}"; + local USER_FILE=; USER_FILE=$(make_test_temp_file); echo "${USERNAME}" > "${USER_FILE}"; + local PASS_FILE=; PASS_FILE=$(make_test_temp_file); echo "${PASSWORD}" > "${PASS_FILE}"; # Do not set GANTRY_AUTH_CONFIG_LABEL on the service. reset_gantry_env "${SUITE_NAME}" "${SERVICE_NAME}" export GANTRY_TEST_DOCKER_CONFIG="${CONFIG}" @@ -138,7 +137,7 @@ Describe 'login-docker-config' local RETURN_VALUE= run_gantry "${SUITE_NAME}" "${TEST_NAME}" RETURN_VALUE="${?}" - docker logout "${REGISTRY}" > /dev/null + docker logout "${REGISTRY}" 1>/dev/null rm "${USER_FILE}" rm "${PASS_FILE}" [ -d "${CONFIG}" ] && rm -r "${CONFIG}" @@ -165,7 +164,6 @@ Describe 'login-docker-config' The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}.*--config.*" # Gantry adds --with-registry-auth for using the default configuration. The stderr should satisfy spec_expect_message "${ADDING_OPTIONS_WITH_REGISTRY_AUTH}.*${SERVICE_NAME}" - The stderr should satisfy spec_expect_no_message "${THERE_ARE_ADDITIONAL_MESSAGES}.*${SERVICE_NAME}.*" The stderr should satisfy spec_expect_message "${UPDATED}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${NO_UPDATES}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${ROLLING_BACK}.*${SERVICE_NAME}" @@ -193,7 +191,8 @@ Describe 'login-docker-config' # When running with an Gantry image, docker buildx writes files to this folder which are owned by root. # Using a relative path, this the container will not write to the folder on the host. # So do not use an absolute path, otherwise we cannot remove this folder on the host. - AUTH_CONFIG="C$(unique_id)" + AUTH_CONFIG=$(get_config_name) + INCORRECT_CONFIG=$(get_config_name "incorrect-") TEST_REGISTRY=$(load_test_registry "${SUITE_NAME}") || return 1 test_start() { local TEST_NAME="${1}" @@ -211,13 +210,13 @@ Describe 'login-docker-config' local REGISTRY="${4}" local USERNAME="${5}" local PASSWORD="${6}" + local INCORRECT_CONFIG="${7}" local SERVICE_NAME0="${SERVICE_NAME}-0" local SERVICE_NAME1="${SERVICE_NAME}-1" local SERVICE_NAME2="${SERVICE_NAME}-2" - local INCORRECT_CONFIG="incorrect-${CONFIG}" check_login_input "${REGISTRY}" "${USERNAME}" "${PASSWORD}" || return 1; local CONFIGS_FILE= - CONFIGS_FILE=$(mktemp) + CONFIGS_FILE=$(make_test_temp_file) echo "${CONFIG} ${REGISTRY} ${USERNAME} ${PASSWORD}" > "${CONFIGS_FILE}" # Set GANTRY_AUTH_CONFIG_LABEL on SERVICE_NAME1, but not on SERVICE_NAME0. # Inspection of SERVICE_NAME0 should fail (incorrect label overrides DOCKER_CONFIG). @@ -250,7 +249,7 @@ Describe 'login-docker-config' BeforeEach "test_start ${TEST_NAME} ${IMAGE_WITH_TAG} ${SERVICE_NAME}" AfterEach "test_end ${TEST_NAME} ${IMAGE_WITH_TAG} ${SERVICE_NAME}" It 'run_test' - When run test_login_docker_config_label_override "${TEST_NAME}" "${SERVICE_NAME}" "${AUTH_CONFIG}" "${TEST_REGISTRY}" "${TEST_USERNAME}" "${TEST_PASSWORD}" + When run test_login_docker_config_label_override "${TEST_NAME}" "${SERVICE_NAME}" "${AUTH_CONFIG}" "${TEST_REGISTRY}" "${TEST_USERNAME}" "${TEST_PASSWORD}" "${INCORRECT_CONFIG}" The status should be failure The stdout should satisfy display_output The stdout should satisfy spec_expect_no_message ".+" @@ -258,11 +257,11 @@ Describe 'login-docker-config' The stderr should satisfy spec_expect_no_message "${START_WITHOUT_A_SQUARE_BRACKET}" The stderr should satisfy spec_expect_message "${LOGGED_INTO_REGISTRY}.*${TEST_REGISTRY}.*${AUTH_CONFIG}" The stderr should satisfy spec_expect_no_message "${FAILED_TO_LOGIN_TO_REGISTRY}" - The stderr should satisfy spec_expect_message "incorrect-${AUTH_CONFIG}.*${CONFIG_IS_NOT_A_DIRECTORY}" + The stderr should satisfy spec_expect_message "${INCORRECT_CONFIG}.*${CONFIG_IS_NOT_A_DIRECTORY}" # Check warnings The stderr should satisfy spec_expect_message "${THERE_ARE_NUM_CONFIGURATIONS}.*" The stderr should satisfy spec_expect_message "${USER_LOGGED_INTO_DEFAULT}.*" - The stderr should satisfy spec_expect_message "${ADDING_OPTIONS}.*--config incorrect-${AUTH_CONFIG}.*${SERVICE_NAME0}" + The stderr should satisfy spec_expect_message "${ADDING_OPTIONS}.*--config ${INCORRECT_CONFIG}.*${SERVICE_NAME0}" The stderr should satisfy spec_expect_message "${ADDING_OPTIONS}.*--config ${AUTH_CONFIG}.*${SERVICE_NAME1}" The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}.*--config ${AUTH_CONFIG}.*${SERVICE_NAME2}" The stderr should satisfy spec_expect_no_message "${PERFORM_UPDATING}.*${SERVICE_NAME0}.*" @@ -281,9 +280,6 @@ Describe 'login-docker-config' The stderr should satisfy spec_expect_message "${ADDING_OPTIONS_WITH_REGISTRY_AUTH}.*${SERVICE_NAME1}" # Gantry adds --with-registry-auth, because DOCKER_CONFIG and the configuration name are same (default location). The stderr should satisfy spec_expect_message "${ADDING_OPTIONS_WITH_REGISTRY_AUTH}.*${SERVICE_NAME2}" - The stderr should satisfy spec_expect_no_message "${THERE_ARE_ADDITIONAL_MESSAGES}.*${SERVICE_NAME0}.*" - The stderr should satisfy spec_expect_no_message "${THERE_ARE_ADDITIONAL_MESSAGES}.*${SERVICE_NAME1}.*" - The stderr should satisfy spec_expect_no_message "${THERE_ARE_ADDITIONAL_MESSAGES}.*${SERVICE_NAME2}.*" The stderr should satisfy spec_expect_no_message "${UPDATED}.*${SERVICE_NAME0}" The stderr should satisfy spec_expect_message "${UPDATED}.*${SERVICE_NAME1}" The stderr should satisfy spec_expect_message "${UPDATED}.*${SERVICE_NAME2}" diff --git a/tests/gantry_login_negative_spec.sh b/tests/gantry_login_negative_spec.sh index 0af2a88..3e6d59b 100644 --- a/tests/gantry_login_negative_spec.sh +++ b/tests/gantry_login_negative_spec.sh @@ -26,7 +26,7 @@ Describe 'login-negative' # When running with an Gantry image, docker buildx writes files to this folder which are owned by root. # Using a relative path, this the container will not write to the folder on the host. # So do not use an absolute path, otherwise we cannot remove this folder on the host. - AUTH_CONFIG="C$(unique_id)" + AUTH_CONFIG=$(get_config_name) TEST_REGISTRY=$(load_test_registry "${SUITE_NAME}") || return 1 test_login_no_login() { local TEST_NAME="${1}" @@ -55,7 +55,6 @@ Describe 'login-negative' The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_UPDATING}" # No --with-registry-auth, because no login. The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS_WITH_REGISTRY_AUTH}.*${SERVICE_NAME}" - The stderr should satisfy spec_expect_no_message "${THERE_ARE_ADDITIONAL_MESSAGES}.*${SERVICE_NAME}.*" The stderr should satisfy spec_expect_no_message "${UPDATED}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${NO_UPDATES}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${ROLLING_BACK}.*${SERVICE_NAME}" @@ -80,7 +79,7 @@ Describe 'login-negative' # When running with an Gantry image, docker buildx writes files to this folder which are owned by root. # Using a relative path, this the container will not write to the folder on the host. # So do not use an absolute path, otherwise we cannot remove this folder on the host. - AUTH_CONFIG="C$(unique_id)" + AUTH_CONFIG=$(get_config_name) TEST_REGISTRY=$(load_test_registry "${SUITE_NAME}") || return 1 test_login_incorrect_password() { local TEST_NAME="${1}" @@ -91,8 +90,8 @@ Describe 'login-negative' local PASSWORD="${6}" check_login_input "${REGISTRY}" "${USERNAME}" "${PASSWORD}" || return 1; local INCORRECT_PASSWORD="${PASSWORD}-incorrect-password" - local USER_FILE=; USER_FILE=$(mktemp); echo "${USERNAME}" > "${USER_FILE}"; - local PASS_FILE=; PASS_FILE=$(mktemp); echo "${INCORRECT_PASSWORD}" > "${PASS_FILE}"; + local USER_FILE=; USER_FILE=$(make_test_temp_file); echo "${USERNAME}" > "${USER_FILE}"; + local PASS_FILE=; PASS_FILE=$(make_test_temp_file); echo "${INCORRECT_PASSWORD}" > "${PASS_FILE}"; docker_service_update --label-add "${GANTRY_AUTH_CONFIG_LABEL}=${CONFIG}" "${SERVICE_NAME}" reset_gantry_env "${SUITE_NAME}" "${SERVICE_NAME}" export GANTRY_REGISTRY_CONFIG="${CONFIG}" @@ -127,7 +126,6 @@ Describe 'login-negative' The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_NO_NEW_IMAGES}" The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_UPDATING}" The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}" - The stderr should satisfy spec_expect_no_message "${THERE_ARE_ADDITIONAL_MESSAGES}.*${SERVICE_NAME}.*" The stderr should satisfy spec_expect_no_message "${UPDATED}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${NO_UPDATES}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${ROLLING_BACK}.*${SERVICE_NAME}" @@ -149,7 +147,7 @@ Describe 'login-negative' TEST_NAME="test_login_read_only_file" IMAGE_WITH_TAG=$(get_image_with_tag "${SUITE_NAME}") SERVICE_NAME=$(get_test_service_name "${TEST_NAME}") - AUTH_CONFIG=$(mktemp -d) + AUTH_CONFIG=$(get_config_name) TEST_REGISTRY=$(load_test_registry "${SUITE_NAME}") || return 1 test_login_read_only_file() { local TEST_NAME="${1}" @@ -163,8 +161,8 @@ Describe 'login-negative' # So do not run the test with a container/image. mkdir -p "${CONFIG}" chmod 444 "${CONFIG}" - local USER_FILE=; USER_FILE=$(mktemp); echo "${USERNAME}" > "${USER_FILE}"; - local PASS_FILE=; PASS_FILE=$(mktemp); echo "${PASSWORD}" > "${PASS_FILE}"; + local USER_FILE=; USER_FILE=$(make_test_temp_file); echo "${USERNAME}" > "${USER_FILE}"; + local PASS_FILE=; PASS_FILE=$(make_test_temp_file); echo "${PASSWORD}" > "${PASS_FILE}"; docker_service_update --label-add "${GANTRY_AUTH_CONFIG_LABEL}=${CONFIG}" "${SERVICE_NAME}" reset_gantry_env "${SUITE_NAME}" "${SERVICE_NAME}" # Use GANTRY_TEST_HOST_TO_CONTAINER to mount the file from host to the container. @@ -178,7 +176,7 @@ Describe 'login-negative' RETURN_VALUE="${?}" rm "${USER_FILE}" rm "${PASS_FILE}" - # [ -d "${CONFIG}" ] && chmod 777 "${CONFIG}" && rm -r "${CONFIG}" + [ -d "${CONFIG}" ] && chmod 777 "${CONFIG}" && rm -r "${CONFIG}" return "${RETURN_VALUE}" } BeforeEach "common_setup_new_image ${TEST_NAME} ${IMAGE_WITH_TAG} ${SERVICE_NAME}" @@ -201,7 +199,6 @@ Describe 'login-negative' The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_NO_NEW_IMAGES}" The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_UPDATING}" The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}" - The stderr should satisfy spec_expect_no_message "${THERE_ARE_ADDITIONAL_MESSAGES}.*${SERVICE_NAME}.*" The stderr should satisfy spec_expect_no_message "${UPDATED}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${NO_UPDATES}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${ROLLING_BACK}.*${SERVICE_NAME}" @@ -226,7 +223,8 @@ Describe 'login-negative' # When running with an Gantry image, docker buildx writes files to this folder which are owned by root. # Using a relative path, this the container will not write to the folder on the host. # So do not use an absolute path, otherwise we cannot remove this folder on the host. - AUTH_CONFIG="C$(unique_id)" + AUTH_CONFIG=$(get_config_name) + INCORRECT_CONFIG=$(get_config_name "incorrect-") TEST_REGISTRY=$(load_test_registry "${SUITE_NAME}") || return 1 test_login_config_mismatch_default() { local TEST_NAME="${1}" @@ -235,13 +233,13 @@ Describe 'login-negative' local REGISTRY="${4}" local USERNAME="${5}" local PASSWORD="${6}" + local INCORRECT_CONFIG="${7}" check_login_input "${REGISTRY}" "${USERNAME}" "${PASSWORD}" || return 1; - local INCORRECT_CONFIG="incorrect-${CONFIG}" - local USER_FILE=; USER_FILE=$(mktemp); echo "${USERNAME}" > "${USER_FILE}"; - local PASS_FILE=; PASS_FILE=$(mktemp); echo "${PASSWORD}" > "${PASS_FILE}"; + local USER_FILE=; USER_FILE=$(make_test_temp_file); echo "${USERNAME}" > "${USER_FILE}"; + local PASS_FILE=; PASS_FILE=$(make_test_temp_file); echo "${PASSWORD}" > "${PASS_FILE}"; # Also use CONFIGS_FILE to test a explicitly-set config. local CONFIGS_FILE= - CONFIGS_FILE=$(mktemp) + CONFIGS_FILE=$(make_test_temp_file) echo "${CONFIG} ${REGISTRY} ${USERNAME} ${PASSWORD}" >> "${CONFIGS_FILE}" # The config name on the service is different from the config name used in GANTRY_REGISTRY_CONFIG docker_service_update --label-add "${GANTRY_AUTH_CONFIG_LABEL}=${INCORRECT_CONFIG}" "${SERVICE_NAME}" @@ -258,7 +256,7 @@ Describe 'login-negative' rm "${USER_FILE}" rm "${PASS_FILE}" rm "${CONFIGS_FILE}" - docker logout "${REGISTRY}" > /dev/null + docker logout "${REGISTRY}" 1>/dev/null [ -d "${CONFIG}" ] && rm -r "${CONFIG}" [ -d "${INCORRECT_CONFIG}" ] && rm -r "${INCORRECT_CONFIG}" return "${RETURN_VALUE}" @@ -266,7 +264,7 @@ Describe 'login-negative' BeforeEach "common_setup_new_image ${TEST_NAME} ${IMAGE_WITH_TAG} ${SERVICE_NAME}" AfterEach "common_cleanup ${TEST_NAME} ${IMAGE_WITH_TAG} ${SERVICE_NAME}" It 'run_test' - When run test_login_config_mismatch_default "${TEST_NAME}" "${SERVICE_NAME}" "${AUTH_CONFIG}" "${TEST_REGISTRY}" "${TEST_USERNAME}" "${TEST_PASSWORD}" + When run test_login_config_mismatch_default "${TEST_NAME}" "${SERVICE_NAME}" "${AUTH_CONFIG}" "${TEST_REGISTRY}" "${TEST_USERNAME}" "${TEST_PASSWORD}" "${INCORRECT_CONFIG}" The status should be failure The stdout should satisfy display_output The stdout should satisfy spec_expect_no_message ".+" @@ -275,12 +273,12 @@ Describe 'login-negative' The stderr should satisfy spec_expect_message "${LOGGED_INTO_REGISTRY}.*${TEST_REGISTRY}.*${DEFAULT_CONFIGURATION}" The stderr should satisfy spec_expect_message "${LOGGED_INTO_REGISTRY}.*${TEST_REGISTRY}.*${AUTH_CONFIG}" The stderr should satisfy spec_expect_no_message "${FAILED_TO_LOGIN_TO_REGISTRY}" - The stderr should satisfy spec_expect_message "incorrect-${AUTH_CONFIG}.*${CONFIG_IS_NOT_A_DIRECTORY}" + The stderr should satisfy spec_expect_message "${INCORRECT_CONFIG}.*${CONFIG_IS_NOT_A_DIRECTORY}" # Check warnings The stderr should satisfy spec_expect_message "${THERE_ARE_NUM_CONFIGURATIONS}.*" The stderr should satisfy spec_expect_message "${USER_LOGGED_INTO_DEFAULT}.*" The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}.*--config ${AUTH_CONFIG}.*" - The stderr should satisfy spec_expect_message "${ADDING_OPTIONS}.*--config incorrect-${AUTH_CONFIG}.*${SERVICE_NAME}" + The stderr should satisfy spec_expect_message "${ADDING_OPTIONS}.*--config ${INCORRECT_CONFIG}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_message "${SKIP_UPDATING}.*${SERVICE_NAME}.*${SKIP_REASON_MANIFEST_FAILURE}" The stderr should satisfy spec_expect_no_message "${PERFORM_UPDATING}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_SKIP_JOBS}" @@ -289,7 +287,6 @@ Describe 'login-negative' The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_UPDATING}" # No --with-registry-auth, due to the incorrect configuration, image inspection failed, we did not reach the updating step. The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS_WITH_REGISTRY_AUTH}.*${SERVICE_NAME}" - The stderr should satisfy spec_expect_no_message "${THERE_ARE_ADDITIONAL_MESSAGES}.*${SERVICE_NAME}.*" The stderr should satisfy spec_expect_no_message "${UPDATED}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${NO_UPDATES}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${ROLLING_BACK}.*${SERVICE_NAME}" @@ -314,7 +311,8 @@ Describe 'login-negative' # When running with an Gantry image, docker buildx writes files to this folder which are owned by root. # Using a relative path, this the container will not write to the folder on the host. # So do not use an absolute path, otherwise we cannot remove this folder on the host. - AUTH_CONFIG="C$(unique_id)" + AUTH_CONFIG=$(get_config_name) + INCORRECT_CONFIG=$(get_config_name "incorrect-") TEST_REGISTRY=$(load_test_registry "${SUITE_NAME}") || return 1 test_login_config_mismatch_no_default() { local TEST_NAME="${1}" @@ -323,10 +321,10 @@ Describe 'login-negative' local REGISTRY="${4}" local USERNAME="${5}" local PASSWORD="${6}" - local INCORRECT_CONFIG="incorrect-${CONFIG}" + local INCORRECT_CONFIG="${7}" check_login_input "${REGISTRY}" "${USERNAME}" "${PASSWORD}" || return 1; - local USER_FILE=; USER_FILE=$(mktemp); echo "${USERNAME}" > "${USER_FILE}"; - local PASS_FILE=; PASS_FILE=$(mktemp); echo "${PASSWORD}" > "${PASS_FILE}"; + local USER_FILE=; USER_FILE=$(make_test_temp_file); echo "${USERNAME}" > "${USER_FILE}"; + local PASS_FILE=; PASS_FILE=$(make_test_temp_file); echo "${PASSWORD}" > "${PASS_FILE}"; # The config name on the service is different from the config name used in GANTRY_REGISTRY_CONFIG docker_service_update --label-add "${GANTRY_AUTH_CONFIG_LABEL}=${INCORRECT_CONFIG}" "${SERVICE_NAME}" reset_gantry_env "${SUITE_NAME}" "${SERVICE_NAME}" @@ -347,7 +345,7 @@ Describe 'login-negative' BeforeEach "common_setup_new_image ${TEST_NAME} ${IMAGE_WITH_TAG} ${SERVICE_NAME}" AfterEach "common_cleanup ${TEST_NAME} ${IMAGE_WITH_TAG} ${SERVICE_NAME}" It 'run_test' - When run test_login_config_mismatch_no_default "${TEST_NAME}" "${SERVICE_NAME}" "${AUTH_CONFIG}" "${TEST_REGISTRY}" "${TEST_USERNAME}" "${TEST_PASSWORD}" + When run test_login_config_mismatch_no_default "${TEST_NAME}" "${SERVICE_NAME}" "${AUTH_CONFIG}" "${TEST_REGISTRY}" "${TEST_USERNAME}" "${TEST_PASSWORD}" "${INCORRECT_CONFIG}" The status should be failure The stdout should satisfy display_output The stdout should satisfy spec_expect_no_message ".+" @@ -356,13 +354,13 @@ Describe 'login-negative' The stderr should satisfy spec_expect_no_message "${LOGGED_INTO_REGISTRY}.*${TEST_REGISTRY}.*${DEFAULT_CONFIGURATION}" The stderr should satisfy spec_expect_message "${LOGGED_INTO_REGISTRY}.*${TEST_REGISTRY}.*${AUTH_CONFIG}" The stderr should satisfy spec_expect_no_message "${FAILED_TO_LOGIN_TO_REGISTRY}" - The stderr should satisfy spec_expect_message "incorrect-${AUTH_CONFIG}.*${CONFIG_IS_NOT_A_DIRECTORY}" + The stderr should satisfy spec_expect_message "${INCORRECT_CONFIG}.*${CONFIG_IS_NOT_A_DIRECTORY}" # Check warnings The stderr should satisfy spec_expect_message "${THERE_ARE_NUM_CONFIGURATIONS}.*" # This message does not present, because we don't login with the default configuration. The stderr should satisfy spec_expect_no_message "${USER_LOGGED_INTO_DEFAULT}.*" The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}.*--config ${AUTH_CONFIG}.*" - The stderr should satisfy spec_expect_message "${ADDING_OPTIONS}.*--config incorrect-${AUTH_CONFIG}.*${SERVICE_NAME}" + The stderr should satisfy spec_expect_message "${ADDING_OPTIONS}.*--config ${INCORRECT_CONFIG}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_message "${SKIP_UPDATING}.*${SERVICE_NAME}.*${SKIP_REASON_MANIFEST_FAILURE}" The stderr should satisfy spec_expect_no_message "${PERFORM_UPDATING}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_SKIP_JOBS}" @@ -371,7 +369,6 @@ Describe 'login-negative' The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_UPDATING}" # No --with-registry-auth, due to the incorrect configuration, image inspection failed, we did not reach the updating step. The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS_WITH_REGISTRY_AUTH}.*${SERVICE_NAME}" - The stderr should satisfy spec_expect_no_message "${THERE_ARE_ADDITIONAL_MESSAGES}.*${SERVICE_NAME}.*" The stderr should satisfy spec_expect_no_message "${UPDATED}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${NO_UPDATES}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${ROLLING_BACK}.*${SERVICE_NAME}" @@ -401,7 +398,7 @@ Describe 'login-negative' # When running with an Gantry image, docker buildx writes files to this folder which are owned by root. # Using a relative path, this the container will not write to the folder on the host. # So do not use an absolute path, otherwise we cannot remove this folder on the host. - AUTH_CONFIG="C$(unique_id)" + AUTH_CONFIG=$(get_config_name) TEST_REGISTRY=$(load_test_registry "${SUITE_NAME}") || return 1 test_start() { local TEST_NAME="${1}" @@ -429,8 +426,8 @@ Describe 'login-negative' local SERVICE_NAME0="${SERVICE_NAME}-0" local SERVICE_NAME1="${SERVICE_NAME}-1" check_login_input "${REGISTRY}" "${USERNAME}" "${PASSWORD}" || return 1; - local USER_FILE=; USER_FILE=$(mktemp); echo "${USERNAME}" > "${USER_FILE}"; - local PASS_FILE=; PASS_FILE=$(mktemp); echo "${PASSWORD}" > "${PASS_FILE}"; + local USER_FILE=; USER_FILE=$(make_test_temp_file); echo "${USERNAME}" > "${USER_FILE}"; + local PASS_FILE=; PASS_FILE=$(make_test_temp_file); echo "${PASSWORD}" > "${PASS_FILE}"; # Set GANTRY_AUTH_CONFIG_LABEL on SERVICE_NAME1, but not on SERVICE_NAME0. # Inspection of SERVICE_NAME0 should fail, because GANTRY_AUTH_CONFIG_LABEL is not found. # Inspection of SERVICE_NAME1 should pass, because configuration is set via GANTRY_AUTH_CONFIG_LABEL. @@ -486,8 +483,6 @@ Describe 'login-negative' The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS_WITH_REGISTRY_AUTH}.*${SERVICE_NAME0}" # Gantry adds --with-registry-auth for finding GANTRY_AUTH_CONFIG_LABEL on the service. The stderr should satisfy spec_expect_message "${ADDING_OPTIONS_WITH_REGISTRY_AUTH}.*${SERVICE_NAME1}" - The stderr should satisfy spec_expect_no_message "${THERE_ARE_ADDITIONAL_MESSAGES}.*${SERVICE_NAME0}.*" - The stderr should satisfy spec_expect_no_message "${THERE_ARE_ADDITIONAL_MESSAGES}.*${SERVICE_NAME1}.*" The stderr should satisfy spec_expect_no_message "${UPDATED}.*${SERVICE_NAME0}" The stderr should satisfy spec_expect_message "${UPDATED}.*${SERVICE_NAME1}" The stderr should satisfy spec_expect_no_message "${NO_UPDATES}.*${SERVICE_NAME0}" @@ -514,7 +509,7 @@ Describe 'login-negative' # When running with an Gantry image, docker buildx writes files to this folder which are owned by root. # Using a relative path, this the container will not write to the folder on the host. # So do not use an absolute path, otherwise we cannot remove this folder on the host. - AUTH_CONFIG="C$(unique_id)" + AUTH_CONFIG=$(get_config_name) TEST_REGISTRY=$(load_test_registry "${SUITE_NAME}") || return 1 test_login_REGISTRY_CONFIGS_FILE_bad_format() { local TEST_NAME="${1}" @@ -525,7 +520,7 @@ Describe 'login-negative' local PASSWORD="${6}" check_login_input "${REGISTRY}" "${USERNAME}" "${PASSWORD}" || return 1; local CONFIGS_FILE= - CONFIGS_FILE=$(mktemp) + CONFIGS_FILE=$(make_test_temp_file) # Add an extra item to the line. echo "${CONFIG} ${REGISTRY} ${USERNAME} ${PASSWORD} Extra" >> "${CONFIGS_FILE}" # Missing an item from the line. @@ -562,7 +557,6 @@ Describe 'login-negative' The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_NO_NEW_IMAGES}" The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_UPDATING}" The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}.*--config.*" - The stderr should satisfy spec_expect_no_message "${THERE_ARE_ADDITIONAL_MESSAGES}.*${SERVICE_NAME}.*" The stderr should satisfy spec_expect_no_message "${UPDATED}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${NO_UPDATES}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${ROLLING_BACK}.*${SERVICE_NAME}" @@ -587,7 +581,7 @@ Describe 'login-negative' # When running with an Gantry image, docker buildx writes files to this folder which are owned by root. # Using a relative path, this the container will not write to the folder on the host. # So do not use an absolute path, otherwise we cannot remove this folder on the host. - AUTH_CONFIG="C$(unique_id)" + AUTH_CONFIG=$(get_config_name) TEST_REGISTRY=$(load_test_registry "${SUITE_NAME}") || return 1 test_login_file_not_exist() { local TEST_NAME="${1}" @@ -631,7 +625,6 @@ Describe 'login-negative' The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_NO_NEW_IMAGES}" The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_UPDATING}" The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}.*--config.*" - The stderr should satisfy spec_expect_no_message "${THERE_ARE_ADDITIONAL_MESSAGES}.*${SERVICE_NAME}.*" The stderr should satisfy spec_expect_no_message "${UPDATED}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${NO_UPDATES}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${ROLLING_BACK}.*${SERVICE_NAME}" diff --git a/tests/gantry_login_spec.sh b/tests/gantry_login_spec.sh index 7aaf316..f46fc32 100644 --- a/tests/gantry_login_spec.sh +++ b/tests/gantry_login_spec.sh @@ -15,8 +15,8 @@ # along with this program. If not, see . # -# This warning is generated by a docker command. -export IMAGE_DIGEST_WARNING="image .* could not be accessed on a registry to record its digest. Each node will access .* independently, possibly leading to different nodes running different versions of the image" +# FROM_DOCKER_IMAGE_DIGEST_WARNING is generated by a docker command. +export FROM_DOCKER_IMAGE_DIGEST_WARNING="image .* could not be accessed on a registry to record its digest. Each node will access .* independently, possibly leading to different nodes running different versions of the image" Describe 'login' SUITE_NAME="login" @@ -29,7 +29,7 @@ Describe 'login' # When running with an Gantry image, docker buildx writes files to this folder which are owned by root. # Using a relative path, this the container will not write to the folder on the host. # So do not use an absolute path, otherwise we cannot remove this folder on the host. - AUTH_CONFIG="C$(unique_id)" + AUTH_CONFIG=$(get_config_name) TEST_REGISTRY=$(load_test_registry "${SUITE_NAME}") || return 1 test_login_config() { local TEST_NAME="${1}" @@ -39,8 +39,8 @@ Describe 'login' local USERNAME="${5}" local PASSWORD="${6}" check_login_input "${REGISTRY}" "${USERNAME}" "${PASSWORD}" || return 1; - local USER_FILE=; USER_FILE=$(mktemp); echo "${USERNAME}" > "${USER_FILE}"; - local PASS_FILE=; PASS_FILE=$(mktemp); echo "${PASSWORD}" > "${PASS_FILE}"; + local USER_FILE=; USER_FILE=$(make_test_temp_file); echo "${USERNAME}" > "${USER_FILE}"; + local PASS_FILE=; PASS_FILE=$(make_test_temp_file); echo "${PASSWORD}" > "${PASS_FILE}"; docker_service_update --label-add "${GANTRY_AUTH_CONFIG_LABEL}=${CONFIG}" "${SERVICE_NAME}" reset_gantry_env "${SUITE_NAME}" "${SERVICE_NAME}" export GANTRY_REGISTRY_CONFIG="${CONFIG}" @@ -81,7 +81,7 @@ Describe 'login' # 2 "--with-registry-auth" for SERVICE_NAME. One is automatically added. The other is from user. The stderr should satisfy spec_expect_message "${ADDING_OPTIONS_WITH_REGISTRY_AUTH}.*automatically.*${SERVICE_NAME}" The stderr should satisfy spec_expect_message "${ADDING_OPTIONS_WITH_REGISTRY_AUTH}.*specified by user.*${SERVICE_NAME}" - The stderr should satisfy spec_expect_no_message "${THERE_ARE_ADDITIONAL_MESSAGES}.*${SERVICE_NAME}.*" + The stderr should satisfy spec_expect_no_message "${FROM_DOCKER_IMAGE_DIGEST_WARNING}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_message "${UPDATED}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${NO_UPDATES}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${ROLLING_BACK}.*${SERVICE_NAME}" @@ -113,8 +113,8 @@ Describe 'login' local USERNAME="${5}" local PASSWORD="${6}" check_login_input "${REGISTRY}" "${USERNAME}" "${PASSWORD}" || return 1; - local USER_FILE=; USER_FILE=$(mktemp); echo "${USERNAME}" > "${USER_FILE}"; - local PASS_FILE=; PASS_FILE=$(mktemp); echo "${PASSWORD}" > "${PASS_FILE}"; + local USER_FILE=; USER_FILE=$(make_test_temp_file); echo "${USERNAME}" > "${USER_FILE}"; + local PASS_FILE=; PASS_FILE=$(make_test_temp_file); echo "${PASSWORD}" > "${PASS_FILE}"; # Do not set GANTRY_AUTH_CONFIG_LABEL on the service. reset_gantry_env "${SUITE_NAME}" "${SERVICE_NAME}" # Do not set GANTRY_REGISTRY_CONFIG to login to the default configuration. @@ -124,7 +124,7 @@ Describe 'login' local RETURN_VALUE= run_gantry "${SUITE_NAME}" "${TEST_NAME}" RETURN_VALUE="${?}" - docker logout "${REGISTRY}" > /dev/null + docker logout "${REGISTRY}" 1>/dev/null rm "${USER_FILE}" rm "${PASS_FILE}" [ -d "${CONFIG}" ] && rm -r "${CONFIG}" && echo "${CONFIG} should not exist." >&2 && return 1 @@ -151,7 +151,7 @@ Describe 'login' The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}.*--config.*" # Gantry adds --with-registry-auth for using the default configuration. The stderr should satisfy spec_expect_message "${ADDING_OPTIONS_WITH_REGISTRY_AUTH}.*${SERVICE_NAME}" - The stderr should satisfy spec_expect_no_message "${THERE_ARE_ADDITIONAL_MESSAGES}.*${SERVICE_NAME}.*" + The stderr should satisfy spec_expect_no_message "${FROM_DOCKER_IMAGE_DIGEST_WARNING}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_message "${UPDATED}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${NO_UPDATES}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${ROLLING_BACK}.*${SERVICE_NAME}" @@ -176,7 +176,7 @@ Describe 'login' # When running with an Gantry image, docker buildx writes files to this folder which are owned by root. # Using a relative path, this the container will not write to the folder on the host. # So do not use an absolute path, otherwise we cannot remove this folder on the host. - AUTH_CONFIG="C$(unique_id)" + AUTH_CONFIG=$(get_config_name) TEST_REGISTRY=$(load_test_registry "${SUITE_NAME}") || return 1 test_login_REGISTRY_CONFIGS_FILE() { local TEST_NAME="${1}" @@ -187,7 +187,7 @@ Describe 'login' local PASSWORD="${6}" check_login_input "${REGISTRY}" "${USERNAME}" "${PASSWORD}" || return 1; local CONFIGS_FILE= - CONFIGS_FILE=$(mktemp) + CONFIGS_FILE=$(make_test_temp_file) echo "# Test comments: CONFIG REGISTRY USERNAME PASSWORD" >> "${CONFIGS_FILE}" echo "${CONFIG} ${REGISTRY} ${USERNAME} ${PASSWORD}" >> "${CONFIGS_FILE}" docker_service_update --label-add "${GANTRY_AUTH_CONFIG_LABEL}=${CONFIG}" "${SERVICE_NAME}" @@ -229,7 +229,7 @@ Describe 'login' The stderr should satisfy spec_expect_message "${ADDING_OPTIONS}.*--config ${AUTH_CONFIG}.*${SERVICE_NAME}" # Gantry adds --with-registry-auth for finding GANTRY_AUTH_CONFIG_LABEL on the service. The stderr should satisfy spec_expect_message "${ADDING_OPTIONS_WITH_REGISTRY_AUTH}.*${SERVICE_NAME}" - The stderr should satisfy spec_expect_no_message "${THERE_ARE_ADDITIONAL_MESSAGES}.*${SERVICE_NAME}.*" + The stderr should satisfy spec_expect_no_message "${FROM_DOCKER_IMAGE_DIGEST_WARNING}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_message "${UPDATED}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${NO_UPDATES}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${ROLLING_BACK}.*${SERVICE_NAME}" @@ -251,7 +251,7 @@ Describe 'login' TEST_NAME="test_login_external_config" IMAGE_WITH_TAG=$(get_image_with_tag "${SUITE_NAME}") SERVICE_NAME=$(get_test_service_name "${TEST_NAME}") - AUTH_CONFIG="$(mktemp -d)" + AUTH_CONFIG=$(get_config_name) TEST_REGISTRY=$(load_test_registry "${SUITE_NAME}") || return 1 test_login_external_config() { local TEST_NAME="${1}" @@ -262,7 +262,7 @@ Describe 'login' local PASSWORD="${6}" check_login_input "${REGISTRY}" "${USERNAME}" "${PASSWORD}" || return 1; # Login outside Gantry. - echo "${PASSWORD}" | docker --config "${CONFIG}" login --username="${USERNAME}" --password-stdin "${REGISTRY}" > /dev/null 2>&1 + echo "${PASSWORD}" | docker --config "${CONFIG}" login --username="${USERNAME}" --password-stdin "${REGISTRY}" 1>/dev/null 2>/dev/null chmod 555 "${CONFIG}" # Do not set GANTRY_AUTH_CONFIG_LABEL on service. reset_gantry_env "${SUITE_NAME}" "${SERVICE_NAME}" @@ -272,7 +272,7 @@ Describe 'login' # We cannot remove DOCKER_CONFIG when it containes data from root. export GANTRY_MANIFEST_CMD="manifest" export GANTRY_MANIFEST_OPTIONS="--insecure" - # Do not set --with-registry-auth to trigger a warning IMAGE_DIGEST_WARNING. + # Do not set --with-registry-auth to trigger a warning FROM_DOCKER_IMAGE_DIGEST_WARNING. local RETURN_VALUE= run_gantry "${SUITE_NAME}" "${TEST_NAME}" RETURN_VALUE="${?}" @@ -301,7 +301,7 @@ Describe 'login' # No --with-registry-auth. The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS_WITH_REGISTRY_AUTH}.*" # Check the warning due to missing --with-registry-auth. - The stderr should satisfy spec_expect_message "${THERE_ARE_ADDITIONAL_MESSAGES}.*${SERVICE_NAME}.*${IMAGE_DIGEST_WARNING}" + The stderr should satisfy spec_expect_message "${FROM_DOCKER_IMAGE_DIGEST_WARNING}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_message "${UPDATED}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${NO_UPDATES}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${ROLLING_BACK}.*${SERVICE_NAME}" diff --git a/tests/gantry_notify_spec.sh b/tests/gantry_notify_spec.sh index d535cb0..ad24466 100644 --- a/tests/gantry_notify_spec.sh +++ b/tests/gantry_notify_spec.sh @@ -34,8 +34,8 @@ _notify_before_all() { initialize_all_tests "${SUITE_NAME}" pull_image_if_not_exist caronc/apprise pull_image_if_not_exist axllent/mailpit - docker_remove "${SERVICE_NAME_APPRISE}" 1>/dev/null 2>&1 - docker_remove "${SERVICE_NAME_MAILPIT}" 1>/dev/null 2>&1 + docker_remove "${SERVICE_NAME_APPRISE}" 1>/dev/null 2>/dev/null + docker_remove "${SERVICE_NAME_MAILPIT}" 1>/dev/null 2>/dev/null # Use docker_run to improve coverage on lib-common.sh. `docker run` can do the same thing. docker_run -d --restart=on-failure:10 --name="${SERVICE_NAME_APPRISE}" --network=host \ -e "APPRISE_STATELESS_URLS=mailto://localhost:${SMTP_PORT}?user=userid&pass=password" \ @@ -329,7 +329,8 @@ Describe 'notify' local SERVICE_NAME="${2}" local RETURN_VALUE=0 reset_gantry_env "${SUITE_NAME}" "${SERVICE_NAME}" - export GANTRY_UPDATE_OPTIONS="--bad-options-that-causes-error" + # Bad options will cause an update failure. + export GANTRY_UPDATE_OPTIONS="--incorrect-option" export GANTRY_NOTIFICATION_APPRISE_URL="http://localhost:${APPRISE_PORT}/notify" export GANTRY_NOTIFICATION_CONDITION="on-change" export GANTRY_NOTIFICATION_TITLE="TEST_TITLE" @@ -357,7 +358,8 @@ Describe 'notify' The stderr should satisfy spec_expect_no_message "${UPDATED}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${NO_UPDATES}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_message "${ROLLING_BACK}.*${SERVICE_NAME}" - The stderr should satisfy spec_expect_message "${FAILED_TO_ROLLBACK}.*${SERVICE_NAME}" + # Rollback should fail due to FROM_DOCKER_DOES_NOT_HAVE_A_PREVIOUS_SPEC + The stderr should satisfy spec_expect_message "${FAILED_TO_ROLLBACK}.*${SERVICE_NAME}.*${FROM_DOCKER_DOES_NOT_HAVE_A_PREVIOUS_SPEC}" The stderr should satisfy spec_expect_no_message "${ROLLED_BACK}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_message "${NO_SERVICES_UPDATED}" The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_UPDATED}" diff --git a/tests/gantry_rollback_spec.sh b/tests/gantry_rollback_spec.sh index ca2f9ea..e61a934 100644 --- a/tests/gantry_rollback_spec.sh +++ b/tests/gantry_rollback_spec.sh @@ -55,6 +55,7 @@ Describe 'rollback' The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}" The stderr should satisfy spec_expect_message "${ROLLING_BACK}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${FAILED_TO_ROLLBACK}.*${SERVICE_NAME}" + The stderr should satisfy spec_expect_no_message "${FROM_DOCKER_DOES_NOT_HAVE_A_PREVIOUS_SPEC}" The stderr should satisfy spec_expect_message "${ROLLED_BACK}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_message "${NO_SERVICES_UPDATED}" The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_UPDATED}" @@ -107,6 +108,7 @@ Describe 'rollback' The stderr should satisfy spec_expect_message "${ADDING_OPTIONS}.*--with-registry-auth.*${SERVICE_NAME}" The stderr should satisfy spec_expect_message "${ROLLING_BACK}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_message "${FAILED_TO_ROLLBACK}.*${SERVICE_NAME}" + The stderr should satisfy spec_expect_no_message "${FROM_DOCKER_DOES_NOT_HAVE_A_PREVIOUS_SPEC}" The stderr should satisfy spec_expect_no_message "${ROLLED_BACK}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_message "${NO_SERVICES_UPDATED}" The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_UPDATED}" @@ -157,6 +159,7 @@ Describe 'rollback' The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}" The stderr should satisfy spec_expect_no_message "${ROLLING_BACK}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${FAILED_TO_ROLLBACK}.*${SERVICE_NAME}" + The stderr should satisfy spec_expect_no_message "${FROM_DOCKER_DOES_NOT_HAVE_A_PREVIOUS_SPEC}" The stderr should satisfy spec_expect_no_message "${ROLLED_BACK}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_message "${NO_SERVICES_UPDATED}" The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_UPDATED}" @@ -183,7 +186,7 @@ Describe 'rollback' # Assume service update won't be done within TIMEOUT second. export GANTRY_UPDATE_TIMEOUT_SECONDS="${TIMEOUT}" # label should override the global environment variable. - export GANTRY_ROLLBACK_OPTIONS="--insecure" + export GANTRY_ROLLBACK_OPTIONS="--incorrect-option" # Rollback would fail due to the incorrect option. # --with-registry-auth cannot be combined with --rollback. local LABEL_AND_VALUE="gantry.rollback.options=--with-registry-auth" @@ -212,6 +215,7 @@ Describe 'rollback' The stderr should satisfy spec_expect_message "${ADDING_OPTIONS}.*--with-registry-auth.*${SERVICE_NAME}" The stderr should satisfy spec_expect_message "${ROLLING_BACK}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_message "${FAILED_TO_ROLLBACK}.*${SERVICE_NAME}" + The stderr should satisfy spec_expect_no_message "${FROM_DOCKER_DOES_NOT_HAVE_A_PREVIOUS_SPEC}" The stderr should satisfy spec_expect_no_message "${ROLLED_BACK}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_message "${NO_SERVICES_UPDATED}" The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_UPDATED}" @@ -264,6 +268,7 @@ Describe 'rollback' The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}" The stderr should satisfy spec_expect_no_message "${ROLLING_BACK}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${FAILED_TO_ROLLBACK}.*${SERVICE_NAME}" + The stderr should satisfy spec_expect_no_message "${FROM_DOCKER_DOES_NOT_HAVE_A_PREVIOUS_SPEC}" The stderr should satisfy spec_expect_no_message "${ROLLED_BACK}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_message "${NO_SERVICES_UPDATED}" The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_UPDATED}" diff --git a/tests/gantry_service_single_spec.sh b/tests/gantry_service_single_spec.sh index 5e07452..9c0fd11 100644 --- a/tests/gantry_service_single_spec.sh +++ b/tests/gantry_service_single_spec.sh @@ -47,7 +47,6 @@ Describe 'service-single-service' The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}" The stderr should satisfy spec_expect_no_message "${SET_TIMEOUT_TO}" The stderr should satisfy spec_expect_no_message "${RETURN_VALUE_INDICATES_TIMEOUT}" - The stderr should satisfy spec_expect_no_message "${THERE_ARE_ADDITIONAL_MESSAGES}.*${SERVICE_NAME}.*" The stderr should satisfy spec_expect_no_message "${UPDATED}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${NO_UPDATES}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${ROLLING_BACK}.*${SERVICE_NAME}" @@ -94,7 +93,6 @@ Describe 'service-single-service' The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}" The stderr should satisfy spec_expect_no_message "${SET_TIMEOUT_TO}" The stderr should satisfy spec_expect_no_message "${RETURN_VALUE_INDICATES_TIMEOUT}" - The stderr should satisfy spec_expect_no_message "${THERE_ARE_ADDITIONAL_MESSAGES}.*${SERVICE_NAME}.*" The stderr should satisfy spec_expect_message "${UPDATED}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${NO_UPDATES}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${ROLLING_BACK}.*${SERVICE_NAME}" @@ -151,7 +149,6 @@ Describe 'service-single-service' The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}" The stderr should satisfy spec_expect_no_message "${SET_TIMEOUT_TO}" The stderr should satisfy spec_expect_no_message "${RETURN_VALUE_INDICATES_TIMEOUT}" - The stderr should satisfy spec_expect_no_message "${THERE_ARE_ADDITIONAL_MESSAGES}.*${SERVICE_NAME}.*" The stderr should satisfy spec_expect_message "${UPDATED}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${NO_UPDATES}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${ROLLING_BACK}.*${SERVICE_NAME}" @@ -203,7 +200,6 @@ Describe 'service-single-service' The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}" The stderr should satisfy spec_expect_no_message "${SET_TIMEOUT_TO}" The stderr should satisfy spec_expect_no_message "${RETURN_VALUE_INDICATES_TIMEOUT}" - The stderr should satisfy spec_expect_no_message "${THERE_ARE_ADDITIONAL_MESSAGES}.*${SERVICE_NAME}.*" The stderr should satisfy spec_expect_message "${UPDATED}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${NO_UPDATES}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${ROLLING_BACK}.*${SERVICE_NAME}" diff --git a/tests/gantry_update_options_spec.sh b/tests/gantry_update_options_spec.sh index 49b9495..f0c9e22 100644 --- a/tests/gantry_update_options_spec.sh +++ b/tests/gantry_update_options_spec.sh @@ -25,11 +25,11 @@ Describe 'update-options' SUITE_NAME="update-options" BeforeAll "initialize_all_tests ${SUITE_NAME}" AfterAll "finish_all_tests ${SUITE_NAME}" - Describe "test_update_UPDATE_OPTIONS" - TEST_NAME="test_update_UPDATE_OPTIONS" + Describe "test_update_UPDATE_OPTIONS_good" + TEST_NAME="test_update_UPDATE_OPTIONS_good" IMAGE_WITH_TAG=$(get_image_with_tag "${SUITE_NAME}") SERVICE_NAME=$(get_test_service_name "${TEST_NAME}") - test_update_UPDATE_OPTIONS() { + test_update_UPDATE_OPTIONS_good() { local TEST_NAME="${1}" local SERVICE_NAME="${2}" local LABEL="gantry.test" @@ -48,7 +48,7 @@ Describe 'update-options' BeforeEach "common_setup_new_image ${TEST_NAME} ${IMAGE_WITH_TAG} ${SERVICE_NAME}" AfterEach "common_cleanup ${TEST_NAME} ${IMAGE_WITH_TAG} ${SERVICE_NAME}" It 'run_test' - When run test_update_UPDATE_OPTIONS "${TEST_NAME}" "${SERVICE_NAME}" + When run test_update_UPDATE_OPTIONS_good "${TEST_NAME}" "${SERVICE_NAME}" The status should be success The stdout should satisfy display_output # Check an observable difference before and after applying UPDATE_OPTIONS. @@ -140,6 +140,54 @@ Describe 'update-options' The stderr should satisfy spec_expect_message "${DONE_REMOVING_IMAGES}" End End + Describe "test_update_UPDATE_OPTIONS_bad" + TEST_NAME="test_update_UPDATE_OPTIONS_bad" + IMAGE_WITH_TAG=$(get_image_with_tag "${SUITE_NAME}") + SERVICE_NAME=$(get_test_service_name "${TEST_NAME}") + test_update_UPDATE_OPTIONS_bad() { + local TEST_NAME="${1}" + local SERVICE_NAME="${2}" + reset_gantry_env "${SUITE_NAME}" "${SERVICE_NAME}" + # Bad options will cause an update failure. + export GANTRY_UPDATE_OPTIONS="--incorrect-option" + run_gantry "${SUITE_NAME}" "${TEST_NAME}" + } + BeforeEach "common_setup_new_image ${TEST_NAME} ${IMAGE_WITH_TAG} ${SERVICE_NAME}" + AfterEach "common_cleanup ${TEST_NAME} ${IMAGE_WITH_TAG} ${SERVICE_NAME}" + It 'run_test' + When run test_update_UPDATE_OPTIONS_bad "${TEST_NAME}" "${SERVICE_NAME}" + The status should be failure + The stdout should satisfy display_output + The stdout should satisfy spec_expect_no_message ".+" + The stderr should satisfy display_output + The stderr should satisfy spec_expect_no_message "${START_WITHOUT_A_SQUARE_BRACKET}" + The stderr should satisfy spec_expect_no_message "${SKIP_UPDATING}.*${SERVICE_NAME}" + The stderr should satisfy spec_expect_message "${PERFORM_UPDATING}.*${SERVICE_NAME}.*${PERFORM_REASON_HAS_NEWER_IMAGE}" + The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_SKIP_JOBS}" + The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_INSPECT_FAILURE}" + The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_NO_NEW_IMAGES}" + The stderr should satisfy spec_expect_message "${NUM_SERVICES_UPDATING}" + The stderr should satisfy spec_expect_no_message "${SET_TIMEOUT_TO}" + The stderr should satisfy spec_expect_no_message "${RETURN_VALUE_INDICATES_TIMEOUT}" + The stderr should satisfy spec_expect_no_message "${UPDATED}.*${SERVICE_NAME}" + The stderr should satisfy spec_expect_no_message "${NO_UPDATES}.*${SERVICE_NAME}" + The stderr should satisfy spec_expect_message "${ADDING_OPTIONS}.*--incorrect-option.*${SERVICE_NAME}" + The stderr should satisfy spec_expect_message "${ROLLING_BACK}.*${SERVICE_NAME}" + # Rollback should fail due to FROM_DOCKER_DOES_NOT_HAVE_A_PREVIOUS_SPEC + The stderr should satisfy spec_expect_message "${FAILED_TO_ROLLBACK}.*${SERVICE_NAME}.*${FROM_DOCKER_DOES_NOT_HAVE_A_PREVIOUS_SPEC}" + The stderr should satisfy spec_expect_no_message "${ROLLED_BACK}.*${SERVICE_NAME}" + The stderr should satisfy spec_expect_message "${NO_SERVICES_UPDATED}" + The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_UPDATED}" + The stderr should satisfy spec_expect_message "${NUM_SERVICES_UPDATE_FAILED}" + The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_ERRORS}" + The stderr should satisfy spec_expect_message "${NO_IMAGES_TO_REMOVE}" + The stderr should satisfy spec_expect_no_message "${REMOVING_NUM_IMAGES}" + The stderr should satisfy spec_expect_no_message "${SKIP_REMOVING_IMAGES}" + The stderr should satisfy spec_expect_no_message "${REMOVED_IMAGE}.*${IMAGE_WITH_TAG}" + The stderr should satisfy spec_expect_no_message "${FAILED_TO_REMOVE_IMAGE}.*${IMAGE_WITH_TAG}" + The stderr should satisfy spec_expect_no_message "${DONE_REMOVING_IMAGES}" + End + End Describe "test_update_UPDATE_TIMEOUT_SECONDS_not_a_number" TEST_NAME="test_update_UPDATE_TIMEOUT_SECONDS_not_a_number" IMAGE_WITH_TAG=$(get_image_with_tag "${SUITE_NAME}") diff --git a/tests/spec_gantry_test_helper.sh b/tests/spec_gantry_test_helper.sh index c9c927e..131a8a3 100644 --- a/tests/spec_gantry_test_helper.sh +++ b/tests/spec_gantry_test_helper.sh @@ -45,7 +45,6 @@ export ADDING_OPTIONS="Adding options" export ADDING_OPTIONS_WITH_REGISTRY_AUTH="Adding options.*--with-registry-auth" export SET_TIMEOUT_TO="Set timeout to" export RETURN_VALUE_INDICATES_TIMEOUT="The return value [0-9]+ indicates the job timed out." -export THERE_ARE_ADDITIONAL_MESSAGES="There are additional messages from updating" export NUM_SERVICES_SKIP_JOBS="Skip updating [0-9]+ service\(s\) due to they are job\(s\)" export NUM_SERVICES_INSPECT_FAILURE="Failed to inspect [0-9]+ service\(s\)" export NUM_SERVICES_NO_NEW_IMAGES="No new images for [0-9]+ service\(s\)" @@ -54,6 +53,8 @@ export NO_UPDATES="No updates" export UPDATED="Updated" export ROLLING_BACK="Rolling back" export FAILED_TO_ROLLBACK="Failed to roll back" +# FROM_DOCKER_DOES_NOT_HAVE_A_PREVIOUS_SPEC is generated by a docker command. +export FROM_DOCKER_DOES_NOT_HAVE_A_PREVIOUS_SPEC="does not have a previous spec" export ROLLED_BACK="Rolled back" export NO_SERVICES_UPDATED="No services updated" export NUM_SERVICES_UPDATED="[0-9]+ service\(s\) updated" @@ -69,6 +70,8 @@ export DONE_REMOVING_IMAGES="Done removing images" export SCHEDULE_NEXT_UPDATE_AT="Schedule next update at" export SLEEP_SECONDS_BEFORE_NEXT_UPDATE="Sleep [0-9]+ seconds before next update" +export GANTRY_TEST_TEMP_DIR="gantry-test-tmp" + test_log() { echo "${GANTRY_LOG_LEVEL}" | grep -q -i "^NONE$" && return 0; echo "${GANTRY_LOG_LEVEL}" | grep -q -i "^ERROR$" && return 0; @@ -235,7 +238,7 @@ _next_available_port() { _get_docker_config_file() { local REGISTRY="${1:?}" REGISTRY=$(echo "${REGISTRY}" | tr ':' '-') - echo "/tmp/gantry-test-docker-config-${REGISTRY}" + echo "${GANTRY_TEST_TEMP_DIR}/gantry-test-docker-config-${REGISTRY}" } _get_docker_config_argument() { @@ -249,13 +252,9 @@ _get_docker_config_argument() { _login_test_registry() { local ENFORCE_LOGIN="${1}" - local REGISTRY="${2}" - local USERNAME="${3}" - local PASSWORD="${4}" - if ! _enforce_login_enabled "${ENFORCE_LOGIN}"; then - USERNAME="username" - PASSWORD="password" - fi + local REGISTRY="${2:?}" + local USERNAME="${3:?}" + local PASSWORD="${4:?}" echo "Logging in ${REGISTRY}." local CONFIG= CONFIG=$(_get_docker_config_file "${REGISTRY}") || return 1 @@ -267,17 +266,15 @@ _logout_test_registry() { local REGISTRY="${2}" local CONFIG= CONFIG=$(_get_docker_config_file "${REGISTRY}") || return 1 - if _enforce_login_enabled "${ENFORCE_LOGIN}"; then - echo "Logging out ${REGISTRY}." - docker --config "${CONFIG}" logout - fi + echo "Logging out ${REGISTRY}." + docker --config "${CONFIG}" logout [ -d "${CONFIG}" ] && rm -r "${CONFIG}" } _get_test_registry_file() { local SUITE_NAME="${1:?}" SUITE_NAME=$(echo "${SUITE_NAME}" | tr ' ' '-') - echo "/tmp/TEST_REGISTRY-${SUITE_NAME}" + echo "${GANTRY_TEST_TEMP_DIR}/gantry-test-registry-${SUITE_NAME}" } _remove_test_registry_file() { @@ -299,6 +296,7 @@ _store_test_registry() { echo "${TEST_REGISTRY}" > "${REGISTRY_FILE}" } + load_test_registry() { local SUITE_NAME="${1:?}" local REGISTRY_FILE= @@ -307,6 +305,20 @@ load_test_registry() { cat "${REGISTRY_FILE}" } +_get_test_registry_password_file() { + local SUITE_NAME="${1:?}" + local PASSWORD_FILE= + PASSWORD_FILE="$(_get_test_registry_file "${SUITE_NAME}")-password" || return 1 + readlink -f "${PASSWORD_FILE}" +} + +_remove_test_registry_password_file() { + local SUITE_NAME="${1:?}" + local PASSWORD_FILE= + PASSWORD_FILE=$(_get_test_registry_password_file "${SUITE_NAME}") || return 1 + [ -r "${PASSWORD_FILE}" ] && rm "${PASSWORD_FILE}" +} + _start_registry() { local SUITE_NAME="${1:?}" local ENFORCE_LOGIN="${2}" @@ -314,6 +326,7 @@ _start_registry() { SUITE_NAME=$(echo "${SUITE_NAME}" | tr ' ' '-') local SUITE_NAME_LENGTH="${#SUITE_NAME}" local REGISTRY_SERVICE_NAME="gantry-test-registry-${SUITE_NAME}" + REGISTRY_SERVICE_NAME=$(_sanitize_test_service_name "${REGISTRY_SERVICE_NAME}") local REGISTRY_BASE="localhost" local REGISTRY_PORT= REGISTRY_PORT=$(_get_initial_port "${SUITE_NAME_LENGTH}") @@ -334,8 +347,8 @@ _start_registry() { echo "_start_registry _next_available_port error: REGISTRY_PORT is empty." >&2 return 1 fi - docker container stop "${REGISTRY_SERVICE_NAME}" 1>/dev/null 2>&1; - docker container rm -f "${REGISTRY_SERVICE_NAME}" 1>/dev/null 2>&1; + docker container stop "${REGISTRY_SERVICE_NAME}" 1>/dev/null 2>/dev/null; + docker container rm -f "${REGISTRY_SERVICE_NAME}" 1>/dev/null 2>/dev/null; TEST_REGISTRY="${REGISTRY_BASE}:${REGISTRY_PORT}" echo "Suite \"${SUITE_NAME}\" starts registry ${TEST_REGISTRY} " local CID= @@ -348,7 +361,7 @@ _start_registry() { -e "REGISTRY_HTTP_ADDR=${TEST_REGISTRY}" \ -e "REGISTRY_HTTP_HOST=http://${TEST_REGISTRY}" \ --stop-timeout "${TIMEOUT_SECONDS}" \ - $(_add_htpasswd "${ENFORCE_LOGIN}" "${TEST_USERNAME}" "${TEST_PASSWORD}") \ + $(_add_htpasswd "${SUITE_NAME}" "${ENFORCE_LOGIN}" "${TEST_USERNAME}" "${TEST_PASSWORD}") \ "${REGISTRY_IMAGE}" 2>&1); then local STATUS= while [ "${STATUS}" != "running" ]; do @@ -356,6 +369,7 @@ _start_registry() { done break; fi + echo "docker container run: ${CID}"; if [ "${TRIES}" -ge "${MAX_RETRIES}" ]; then echo "_start_registry Reach MAX_RETRIES ${MAX_RETRIES}" >&2 return 1 @@ -384,11 +398,13 @@ _stop_registry() { local REGISTRY= REGISTRY=$(load_test_registry "${SUITE_NAME}") || return 1 echo "Removing registry ${REGISTRY} " - docker container stop "${REGISTRY_SERVICE_NAME}" 1>/dev/null 2>&1; - docker container rm -f "${REGISTRY_SERVICE_NAME}" 1>/dev/null 2>&1; - _logout_test_registry "${ENFORCE_LOGIN}" "${REGISTRY}" || return 1 - _remove_test_registry_file "${SUITE_NAME}" || return 1 - return 0 + docker container stop "${REGISTRY_SERVICE_NAME}" 1>/dev/null 2>/dev/null; + docker container rm -f "${REGISTRY_SERVICE_NAME}" 1>/dev/null 2>/dev/null; + local RETURN_VALUE=0 + _logout_test_registry "${ENFORCE_LOGIN}" "${REGISTRY}" || RETURN_VALUE=1 + _remove_test_registry_file "${SUITE_NAME}" || RETURN_VALUE=1 + _remove_test_registry_password_file "${SUITE_NAME}" || RETURN_VALUE=1 + return "${RETURN_VALUE}" } _get_test_service_image() { @@ -406,7 +422,7 @@ _build_and_push_gantry_image() { IMAGE="$(_get_gantry_image "${SUITE_NAME}")" || return 1 pull_image_if_not_exist "$(_get_test_service_image)" echo "Building gantry image ${IMAGE}" - timeout 120 docker build --quiet -t "${IMAGE}" . + docker build --quiet --tag "${IMAGE}" . echo "Pushing gantry image ${IMAGE}" # SC2046 (warning): Quote this to prevent word splitting. # shellcheck disable=SC2046 @@ -417,7 +433,7 @@ _remove_gantry_image() { local SUITE_NAME="${1:?}" IMAGE="$(_get_gantry_image "${SUITE_NAME}")" || return 1 echo "Removing gantry image ${IMAGE}" - docker image rm "${IMAGE}" + docker image rm -f "${IMAGE}" } initialize_all_tests() { @@ -430,6 +446,9 @@ initialize_all_tests() { echo "==============================" echo "== Starting suite ${SUITE_NAME}" echo "==============================" + mkdir -p "${GANTRY_TEST_TEMP_DIR}" + uname --all + docker_version _init_swarm _start_registry "${SUITE_NAME}" "${ENFORCE_LOGIN}" _build_and_push_gantry_image "${SUITE_NAME}" @@ -594,6 +613,21 @@ unique_id() { echo "${PID}-${TIME_STR}-${RANDOM_STR}" } +make_test_temp_file() { + local TEMP= + TEMP=$(mktemp -p "${GANTRY_TEST_TEMP_DIR}") + TEMP=$(readlink -f "${TEMP}") + echo "${TEMP}" +} + +get_config_name() { + local BASE="${1}" + local TEMP= + TEMP="${GANTRY_TEST_TEMP_DIR}/${BASE}C$(unique_id)" + TEMP=$(readlink -f "${TEMP}") + echo "${TEMP}" +} + build_test_image() { local IMAGE_WITH_TAG="${1}" local TASK_SECONDS="${2}" @@ -609,12 +643,12 @@ build_test_image() { EXIT_CMD="sleep ${EXIT_SECONDS};" fi local FILE= - FILE=$(mktemp) + FILE=$(make_test_temp_file) echo "FROM $(_get_test_service_image)" > "${FILE}" echo "ENTRYPOINT [\"sh\", \"-c\", \"echo $(unique_id); trap \\\"${EXIT_CMD}\\\" HUP INT TERM; ${TASK_CMD}\"]" >> "${FILE}" pull_image_if_not_exist "$(_get_test_service_image)" echo "Building image ${IMAGE_WITH_TAG} from ${FILE}" - timeout 120 docker build --quiet --tag "${IMAGE_WITH_TAG}" --file "${FILE}" . + docker build --quiet --tag "${IMAGE_WITH_TAG}" --file "${FILE}" . rm "${FILE}" } @@ -636,7 +670,7 @@ prune_local_test_image() { } docker_service_update() { - docker service update --quiet "${@}" >/dev/null + docker service update --quiet "${@}" 1>/dev/null } wait_zero_running_tasks() { @@ -646,7 +680,7 @@ wait_zero_running_tasks() { local REPLICAS= local USED_SECONDS=0 local TRIES=0 - local MAX_RETRIES=120 + local MAX_RETRIES=60 echo "Wait until ${SERVICE_NAME} has zero running tasks." while [ "${NUM_RUNS}" -ne 0 ]; do if [ -n "${TIMEOUT_SECONDS}" ] && [ "${USED_SECONDS}" -ge "${TIMEOUT_SECONDS}" ]; then @@ -697,10 +731,10 @@ _location_constraints() { pull_image_if_not_exist() { local IMAGE="${1}" - if docker image inspect "${IMAGE}" > /dev/null 2>&1; then + if docker image inspect "${IMAGE}" 1>/dev/null 2>/dev/null; then return 0 fi - docker pull "${IMAGE}" > /dev/null + docker pull "${IMAGE}" 1>/dev/null } _enforce_login_enabled() { @@ -709,29 +743,30 @@ _enforce_login_enabled() { } _add_htpasswd() { - local ENFORCE_LOGIN="${1}" - local USER="${2}" - local PASS="${3}" + local SUITE_NAME="${1:?}" + local ENFORCE_LOGIN="${2}" + local USER="${3}" + local PASS="${4}" if ! _enforce_login_enabled "${ENFORCE_LOGIN}"; then return 0 fi local HTTPD_IMAGE="httpd:2" # https://distribution.github.io/distribution/about/deploying/#native-basic-auth - local PASSWD= - PASSWD="$(mktemp)" + local PASSWORD_FILE= + PASSWORD_FILE=$(_get_test_registry_password_file "${SUITE_NAME}") || return 1 pull_image_if_not_exist "${HTTPD_IMAGE}" - docker_run --entrypoint htpasswd "${HTTPD_IMAGE}" -Bbn "${USER}" "${PASS}" > "${PASSWD}" - echo "--mount type=bind,source=${PASSWD},target=${PASSWD} \ + docker_run --entrypoint htpasswd "${HTTPD_IMAGE}" -Bbn "${USER}" "${PASS}" > "${PASSWORD_FILE}" + echo "--mount type=bind,source=${PASSWORD_FILE},target=${PASSWORD_FILE} \ -e REGISTRY_AUTH=htpasswd \ -e REGISTRY_AUTH_HTPASSWD_REALM=RegistryRealm \ - -e REGISTRY_AUTH_HTPASSWD_PATH=${PASSWD} " + -e REGISTRY_AUTH_HTPASSWD_PATH=${PASSWORD_FILE} " } _wait_service_state() { local SERVICE_NAME="${1}"; local WANT_STATE="${2}"; local TIMEOUT_SECONDS="${3}"; - wait_service_state "${SERVICE_NAME}" "${WANT_STATE}" "${TIMEOUT_SECONDS}" 1>/dev/null 2>&1 + wait_service_state "${SERVICE_NAME}" "${WANT_STATE}" "${TIMEOUT_SECONDS}" 1>/dev/null 2>/dev/null } _sanitize_test_service_name() { @@ -767,7 +802,7 @@ start_replicated_service() { # * Add --rollback-monitor=1s: needs to exam the effect. # SC2046 (warning): Quote this to prevent word splitting. # shellcheck disable=SC2046 - timeout 120 docker $(_get_docker_config_argument "${IMAGE_WITH_TAG}") service create --quiet \ + timeout 60 docker $(_get_docker_config_argument "${IMAGE_WITH_TAG}") service create --quiet \ --name "${SERVICE_NAME}" \ --restart-condition "on-failure" \ --restart-max-attempts 5 \ @@ -779,7 +814,7 @@ start_replicated_service() { --mode=replicated \ --detach=true \ "${IMAGE_WITH_TAG}"; - _wait_service_state "${SERVICE_NAME}" "Running" 120 + _wait_service_state "${SERVICE_NAME}" "Running" 60 } start_multiple_replicated_services() { @@ -808,7 +843,7 @@ start_global_service() { # Do not add --detach, because we want to wait for the job finishes. # SC2046 (warning): Quote this to prevent word splitting. # shellcheck disable=SC2046 - timeout 120 docker $(_get_docker_config_argument "${IMAGE_WITH_TAG}") service create --quiet \ + timeout 60 docker $(_get_docker_config_argument "${IMAGE_WITH_TAG}") service create --quiet \ --name "${SERVICE_NAME}" \ --restart-condition "on-failure" \ --restart-max-attempts 5 \ @@ -831,7 +866,7 @@ _start_replicated_job() { # Always add --detach=true, do not wait for the job finishes. # SC2046 (warning): Quote this to prevent word splitting. # shellcheck disable=SC2046 - timeout 120 docker $(_get_docker_config_argument "${IMAGE_WITH_TAG}") service create --quiet \ + timeout 60 docker $(_get_docker_config_argument "${IMAGE_WITH_TAG}") service create --quiet \ --name "${SERVICE_NAME}" \ --restart-condition "on-failure" \ --restart-max-attempts 5 \ @@ -842,7 +877,7 @@ _start_replicated_job() { --detach=true \ "${IMAGE_WITH_TAG}"; # wait until the job is running - _wait_service_state "${SERVICE_NAME}" "Running" 120 + _wait_service_state "${SERVICE_NAME}" "Running" 60 } stop_service() { @@ -917,7 +952,7 @@ _add_file_to_mount_options() { TARGET=$(readlink -f "${HOST_PATH}") local READONLY= READONLY=$(_get_file_readonly "${HOST_PATH}") - MOUNT_OPTIONS="${MOUNT_OPTIONS} --mount type=bind,source=${HOST_PATH},target=${TARGET},readonly=${READONLY}" + MOUNT_OPTIONS="${MOUNT_OPTIONS} --mount type=bind,source=${TARGET},target=${TARGET},readonly=${READONLY}" fi echo "${MOUNT_OPTIONS}" } @@ -933,7 +968,7 @@ stop_gantry_container() { local STACK="${1}" local SERVICE_NAME= SERVICE_NAME=$(_get_gantry_sut_name "${STACK}") - if ! docker service inspect --format '{{.ID}}' "${SERVICE_NAME}" >/dev/null 2>&1; then + if ! docker service inspect --format '{{.ID}}' "${SERVICE_NAME}" 1>/dev/null 2>/dev/null; then return 0 fi local RETURN_VALUE=0 @@ -947,12 +982,13 @@ stop_gantry_container() { } _run_gantry_container() { - local STACK="${1}" - local SUT_REPO_TAG="${2}" + local SUITE_NAME="${1}" + local STACK="${2}" + local SUT_REPO_TAG="${3}" pull_image_if_not_exist "${SUT_REPO_TAG}" local SERVICE_NAME= SERVICE_NAME=$(_get_gantry_sut_name "${STACK}") - docker service rm "${SERVICE_NAME}" >/dev/null 2>&1; + docker service rm "${SERVICE_NAME}" 1>/dev/null 2>/dev/null; local MOUNT_OPTIONS= MOUNT_OPTIONS=$(_add_file_to_mount_options "${MOUNT_OPTIONS}" "${GANTRY_TEST_HOST_TO_CONTAINER}") MOUNT_OPTIONS=$(_add_file_to_mount_options "${MOUNT_OPTIONS}" "${GANTRY_TEST_DOCKER_CONFIG}") @@ -1051,7 +1087,7 @@ run_gantry() { local SUT_REPO_TAG= SUT_REPO_TAG="$(_get_sut_image "${SUITE_NAME}")" if [ -n "${SUT_REPO_TAG}" ]; then - _run_gantry_container "${STACK}" "${SUT_REPO_TAG}" + _run_gantry_container "${SUITE_NAME}" "${STACK}" "${SUT_REPO_TAG}" RETURN_VALUE=$? else [ -n "${GANTRY_TEST_DOCKER_CONFIG}" ] && export DOCKER_CONFIG="${GANTRY_TEST_DOCKER_CONFIG}"