diff --git a/.github/workflows/on-pull-request.yml b/.github/workflows/on-pull-request.yml index b78701d..9977f1f 100644 --- a/.github/workflows/on-pull-request.yml +++ b/.github/workflows/on-pull-request.yml @@ -37,6 +37,7 @@ jobs: - gantry_cleanup_images_spec.sh - gantry_common_options_spec.sh - gantry_filters_spec.sh + - gantry_login_negative_spec.sh - gantry_login_spec.sh - gantry_manifest_spec.sh - gantry_notify_spec.sh diff --git a/.github/workflows/on-push.yml b/.github/workflows/on-push.yml index 1bcdf79..ecb931c 100644 --- a/.github/workflows/on-push.yml +++ b/.github/workflows/on-push.yml @@ -40,6 +40,7 @@ jobs: - gantry_cleanup_images_spec.sh - gantry_common_options_spec.sh - gantry_filters_spec.sh + - gantry_login_negative_spec.sh - gantry_login_spec.sh - gantry_manifest_spec.sh - gantry_notify_spec.sh diff --git a/Dockerfile b/Dockerfile index d2c3cc5..23b5fa8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.20 +FROM alpine:3.20.3 LABEL org.opencontainers.image.title=gantry LABEL org.opencontainers.image.description="Updating docker swarm services" diff --git a/src/entrypoint.sh b/src/entrypoint.sh index a915697..8c78a6b 100755 --- a/src/entrypoint.sh +++ b/src/entrypoint.sh @@ -15,8 +15,7 @@ # along with this program. If not, see . # -load_libraries() { - local LOCAL_LOG_LEVEL="${GANTRY_LOG_LEVEL:-""}" +_get_lib_dir() { local LIB_DIR= if [ -n "${GANTRY_LIB_DIR:-""}" ]; then LIB_DIR="${GANTRY_LIB_DIR}" @@ -29,10 +28,28 @@ load_libraries() { elif [ -r "./lib-gantry.sh" ]; then LIB_DIR="." fi + echo "${LIB_DIR}" +} + +_log_load_libraries() { + local LOG_LEVEL="${GANTRY_LOG_LEVEL:-""}" + local IMAGES_TO_REMOVE="${GANTRY_IMAGES_TO_REMOVE:-""}" + local LIB_DIR="${1}" # log function is not available before loading the library. - if ! echo "${LOCAL_LOG_LEVEL}" | grep -q -i "NONE"; then - echo "Loading libraries from ${LIB_DIR}" + if echo "${LOG_LEVEL}" | grep -q -i "NONE"; then + return 0 + fi + local TIMESTAMP= + if [ -z "${IMAGES_TO_REMOVE}" ]; then + TIMESTAMP="[$(date -Iseconds)] " fi + echo "${TIMESTAMP}Loading libraries from ${LIB_DIR}" >&2 +} + +load_libraries() { + local LIB_DIR= + LIB_DIR=$(_get_lib_dir) + _log_load_libraries "${LIB_DIR}" . "${LIB_DIR}/notification.sh" . "${LIB_DIR}/docker_hub_rate.sh" . "${LIB_DIR}/lib-common.sh" @@ -155,7 +172,7 @@ main() { if [ -n "${IMAGES_TO_REMOVE}" ]; then # Image remover runs as a global job. The log will be collected via docker commands then formatted. # Redefine the log function for the formater. - log() { echo "${@}"; } + log() { echo "${@}" >&2; } gantry_remove_images "${IMAGES_TO_REMOVE}" return $? fi diff --git a/src/lib-common.sh b/src/lib-common.sh index bc6b9a8..f6d6ca9 100755 --- a/src/lib-common.sh +++ b/src/lib-common.sh @@ -228,10 +228,15 @@ read_config() { read_env() { local VNAME="${1}"; shift [ -z "${VNAME}" ] && return 1 - if env | grep -q "${VNAME}="; then - eval "echo \"\${${VNAME}}\"" - else + # "grep -q" will exit immediately when the first line of data matches, and leading to broken pipe errors. + # Add "cat > /dev/null" to avoid broken pipe errors. + local GREP_RETURN= + env | (grep -q "^${VNAME}="; local R=$?; cat >/dev/null; test "${R}" == "0";); + GREP_RETURN=$? + if [ "${GREP_RETURN}" != "0" ]; then echo "${@}" + else + eval "echo \"\${${VNAME}}\"" fi return 0 } @@ -418,6 +423,46 @@ docker_version() { echo "Docker version client ${cver} (API ${capi}) server ${sver} (API ${sapi})" } +# echo the name of the current container. +# echo nothing if unable to find the name. +# return 1 when there is an error. +docker_current_container_name() { + local ALL_NETWORKS= + ALL_NETWORKS=$(docker network ls --format '{{.ID}}') || return 1; + [ -z "${ALL_NETWORKS}" ] && return 0; + local IPS=; + IPS=$(ip route | grep src | sed -n "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; + 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. + [ "${NID}" = "${GWBRIDGE_NETWORK}" ] && continue; + # 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; + for NAME_AND_IP in ${ALL_LOCAL_NAME_AND_IP}; do + [ -z "${NAME_AND_IP}" ] && continue; + # NAME_AND_IP will be in one of the following formats: + # '//' + # '/' (when network mode is host) + local CNAME CIP + CNAME=$(echo "${NAME_AND_IP}/" | cut -d/ -f1); + CIP=$(echo "${NAME_AND_IP}/" | cut -d/ -f2); + # Unable to find the container IP when network mode is host. + [ -z "${CIP}" ] && continue; + for IP in ${IPS}; do + [ "${IP}" != "${CIP}" ] && continue; + echo "${CNAME}"; + return 0; + done + done + done +} + docker_service_remove() { local SERVICE_NAME="${1}" if ! docker service inspect --format '{{.JobStatus}}' "${SERVICE_NAME}" >/dev/null 2>&1; then @@ -493,13 +538,15 @@ docker_run() { local RETRIES=0 local MAX_RETRIES=5 local SLEEP_SECONDS=10 - while ! docker run "${@}" >/dev/null; do + local MSG= + while ! MSG=$(docker run "${@}" 2>&1); do if [ ${RETRIES} -ge ${MAX_RETRIES} ]; then - echo "Failed to run docker. Reached the max retries ${MAX_RETRIES}." >&2 + log ERROR "Failed to run docker. Reached the max retries ${MAX_RETRIES}. ${MSG}" return 1 fi RETRIES=$((RETRIES + 1)) sleep ${SLEEP_SECONDS} - echo "Retry docker run (${RETRIES})." + log WARN "Retry docker run (${RETRIES}). ${MSG}" done + echo "${MSG}" } diff --git a/src/lib-gantry.sh b/src/lib-gantry.sh index 51bb02b..3d54965 100755 --- a/src/lib-gantry.sh +++ b/src/lib-gantry.sh @@ -74,7 +74,6 @@ _read_env_or_label() { echo "${VALUE}" } - _login_registry() { local USER="${1}" local PASSWORD="${2}" @@ -85,24 +84,30 @@ _login_registry() { fi [ -z "${USER}" ] && log ERROR "USER is empty." && return 1 [ -z "${PASSWORD}" ] && log ERROR "PASSWORD is empty." && return 1 - local DOCKER_CONFIG= - local CONFIG_MESSAGE=" ${HOST}" + local REGISTRY_MESSAGE="registry ${HOST}" if [ -z "${HOST}" ]; then log WARN "HOST is empty. Will login to the default registry." - CONFIG_MESSAGE="" + REGISTRY_MESSAGE="default registry" fi + local DOCKER_CONFIG= + local CONFIG_TO_REPORT= + CONFIG_TO_REPORT=$(readlink -f ~/.docker) + local CONFIG_MESSAGE="with default configuration" if [ -n "${CONFIG}" ]; then DOCKER_CONFIG="--config ${CONFIG}" - CONFIG_MESSAGE="${CONFIG_MESSAGE} for config ${CONFIG}" + CONFIG_TO_REPORT="${CONFIG}" + CONFIG_MESSAGE="with configuration ${CONFIG}" fi + local REGISTRY_CONFIG_MESSAGE="${REGISTRY_MESSAGE} ${CONFIG_MESSAGE}" local LOGIN_MSG= # SC2086: Double quote to prevent globbing and word splitting. # shellcheck disable=SC2086 if ! LOGIN_MSG=$(echo "${PASSWORD}" | docker ${DOCKER_CONFIG} login --username="${USER}" --password-stdin "${HOST}" 2>&1); then - log ERROR "Failed to login to registry${CONFIG_MESSAGE}. ${LOGIN_MSG}" + log ERROR "Failed to login to ${REGISTRY_CONFIG_MESSAGE}. ${LOGIN_MSG}" return 1 fi - log INFO "Logged into registry${CONFIG_MESSAGE}. ${LOGIN_MSG}" + log INFO "Logged into ${REGISTRY_CONFIG_MESSAGE}. ${LOGIN_MSG}" + _static_variable_add_unique_to_list STATIC_VAR_SERVICES_DOCKER_CONFIGS "${CONFIG_TO_REPORT}" return 0 } @@ -407,7 +412,7 @@ _remove_images() { docker_service_remove "${SERVICE_NAME}" } -_report_services_list() { +_report_list() { local PRE="${1}"; shift local POST="${1}"; shift local LIST="${*}" @@ -415,7 +420,7 @@ _report_services_list() { NUM=$(_get_number_of_elements "${LIST}") local TITLE= [ -n "${PRE}" ] && TITLE="${PRE} " - TITLE="${TITLE}${NUM} service(s)" + TITLE="${TITLE}${NUM}" [ -n "${POST}" ] && TITLE="${TITLE} ${POST}" echo "${TITLE}:" local ITEM= @@ -424,7 +429,7 @@ _report_services_list() { done } -_report_services_from_static_variable() { +_report_from_static_variable() { local VARIABLE_NAME="${1}" local PRE="${2}" local POST="${3}" @@ -435,7 +440,20 @@ _report_services_from_static_variable() { echo "${EMPTY}" return 0 fi - _report_services_list "${PRE}" "${POST}" "${LIST}" + _report_list "${PRE}" "${POST}" "${LIST}" +} + +_report_services_from_static_variable() { + local VARIABLE_NAME="${1}" + local PRE="${2}" + local POST="${3}" + local EMPTY="${4}" + if [ -z "${POST}" ]; then + POST="service(s)" + else + POST="service(s) ${POST}" + fi + _report_from_static_variable "${VARIABLE_NAME}" "${PRE}" "${POST}" "${EMPTY}" } _get_number_of_elements() { @@ -529,43 +547,15 @@ _current_container_name() { local NO_CURRENT_CONTAINER_NAME= NO_CURRENT_CONTAINER_NAME=$(_static_variable_read_list STATIC_VAR_NO_CURRENT_CONTAINER_NAME) [ -n "${NO_CURRENT_CONTAINER_NAME}" ] && return 0 - local ALL_NETWORKS= - ALL_NETWORKS=$(docker network ls --format '{{.ID}}') || return 1; - [ -z "${ALL_NETWORKS}" ] && return 0; - local IPS=; - IPS=$(ip route | grep src | sed -n "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; - 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. - [ "${NID}" = "${GWBRIDGE_NETWORK}" ] && continue; - # 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; - for NAME_AND_IP in ${ALL_LOCAL_NAME_AND_IP}; do - [ -z "${NAME_AND_IP}" ] && continue; - # NAME_AND_IP will be in one of the following formats: - # '//' - # '/' (when network mode is host) - local CNAME CIP - CNAME=$(echo "${NAME_AND_IP}/" | cut -d/ -f1); - CIP=$(echo "${NAME_AND_IP}/" | cut -d/ -f2); - # Unable to find the container IP when network mode is host. - [ -z "${CIP}" ] && continue; - for IP in ${IPS}; do - [ "${IP}" != "${CIP}" ] && continue; - _static_variable_add_unique_to_list STATIC_VAR_CURRENT_CONTAINER_NAME "${CNAME}" - echo "${CNAME}"; - return 0; - done - done - done - # Explicitly set that we cannot find the name of current container. - _static_variable_add_unique_to_list STATIC_VAR_NO_CURRENT_CONTAINER_NAME "NO_CURRENT_CONTAINER_NAME" + local CNAME= + CNAME=$(docker_current_container_name) || return 1; + if [ -n "${CNAME}" ]; then + _static_variable_add_unique_to_list STATIC_VAR_CURRENT_CONTAINER_NAME "${CNAME}" + else + # Explicitly set that we cannot find the name of current container. + _static_variable_add_unique_to_list STATIC_VAR_NO_CURRENT_CONTAINER_NAME "NO_CURRENT_CONTAINER_NAME" + fi + echo "${CNAME}" return 0; } @@ -659,6 +649,11 @@ _get_config_from_service() { local AUTH_CONFIG= AUTH_CONFIG=$(_get_label_from_service "${SERVICE_NAME}" "${AUTH_CONFIG_LABEL}") [ -z "${AUTH_CONFIG}" ] && return 0 + if [ ! -d "${AUTH_CONFIG}" ]; then + log WARN "${AUTH_CONFIG} is not a directory that contains Docker configuration files." + local MSG="configuration(s) set via GANTRY_REGISTRY_CONFIG* or GANTRY_REGISTRY_CONFIGS_FILE" + _report_from_static_variable STATIC_VAR_SERVICES_DOCKER_CONFIGS "There are" "${MSG}" "There are no ${MSG}." | log_lines WARN + fi echo "--config ${AUTH_CONFIG}" } @@ -708,7 +703,7 @@ _get_image_info() { return 1 fi if [ "${RETURN_VALUE}" != "0" ]; then - log ERROR "Image ${IMAGE} does not exist or it is not available. ${MSG}" + log ERROR "Image ${IMAGE} does not exist or it is not available. Docker ${MANIFEST_CMD} returns: ${MSG}" return 1 fi echo "${MSG}" diff --git a/tests/gantry_cleanup_images_spec.sh b/tests/gantry_cleanup_images_spec.sh index 516aba0..b05629d 100644 --- a/tests/gantry_cleanup_images_spec.sh +++ b/tests/gantry_cleanup_images_spec.sh @@ -37,7 +37,9 @@ Describe 'cleanup-images' When run test_CLEANUP_IMAGES_false "${TEST_NAME}" "${SERVICE_NAME}" The status should be success 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 "${NOT_START_WITH_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}" @@ -79,7 +81,9 @@ Describe 'cleanup-images' When run test_CLEANUP_IMAGES_OPTIONS_bad "${TEST_NAME}" "${SERVICE_NAME}" The status should be success 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 "${NOT_START_WITH_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}" @@ -122,7 +126,9 @@ Describe 'cleanup-images' When run test_CLEANUP_IMAGES_OPTIONS_good "${TEST_NAME}" "${SERVICE_NAME}" The status should be success 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 "${NOT_START_WITH_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}" @@ -209,11 +215,14 @@ Describe 'cleanup-images' When run test_IMAGES_TO_REMOVE_none_empty "${TEST_NAME}" "${SERVICE_NAME}" "${IMAGE_WITH_TAG}" The status should be success The stdout should satisfy display_output - The stdout should satisfy spec_expect_message "Removed exited container.*${SERVICE_NAME0}.*${IMAGE_WITH_TAG0}" - The stdout should satisfy spec_expect_message "${REMOVED_IMAGE}.*${IMAGE_WITH_TAG0}" - The stdout should satisfy spec_expect_message "${FAILED_TO_REMOVE_IMAGE}.*${IMAGE_WITH_TAG1}" - The stdout should satisfy spec_expect_message "There is no image.*${IMAGE_WITH_TAG2}" + The stdout should satisfy spec_expect_no_message ".+" The stderr should satisfy display_output + # It should not use the log function from the lib-common, the messages do not start with "[". + The stderr should satisfy spec_expect_no_message "^((?:\x1b\[[0-9;]*[mG])?\[)" + The stderr should satisfy spec_expect_message "Removed exited container.*${SERVICE_NAME0}.*${IMAGE_WITH_TAG0}" + The stderr should satisfy spec_expect_message "${REMOVED_IMAGE}.*${IMAGE_WITH_TAG0}" + The stderr should satisfy spec_expect_message "${FAILED_TO_REMOVE_IMAGE}.*${IMAGE_WITH_TAG1}" + The stderr should satisfy spec_expect_message "There is no image.*${IMAGE_WITH_TAG2}" End End End # Describe 'Single service' diff --git a/tests/gantry_common_options_spec.sh b/tests/gantry_common_options_spec.sh index 292cde4..fad512c 100644 --- a/tests/gantry_common_options_spec.sh +++ b/tests/gantry_common_options_spec.sh @@ -40,7 +40,9 @@ Describe 'common-options' When run test_common_DOCKER_HOST_not_swarm_manager "${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 "${NOT_START_WITH_A_SQUARE_BRACKET}" The stderr should satisfy spec_expect_message "${SKIP_UPDATING_ALL}.*${SKIP_REASON_NOT_SWARM_MANAGER}" The stderr should satisfy spec_expect_no_message "${SKIP_UPDATING}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${PERFORM_UPDATING}.*${SERVICE_NAME}" @@ -107,7 +109,9 @@ Describe 'common-options' When run test_common_PRE_POST_RUN_CMD "${TEST_NAME}" "${SERVICE_NAME}" The status should be success 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 "${NOT_START_WITH_A_SQUARE_BRACKET}" The stderr should satisfy spec_expect_message "Pre update" 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}" @@ -157,7 +161,9 @@ Describe 'common-options' When run test_common_SLEEP_SECONDS "${TEST_NAME}" "${SERVICE_NAME}" The status should be success 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 "${NOT_START_WITH_A_SQUARE_BRACKET}" The stderr should satisfy spec_expect_multiple_messages "${SKIP_UPDATING}.*${SERVICE_NAME}.*${SKIP_REASON_CURRENT_IS_LATEST}" The stderr should satisfy spec_expect_no_message "${PERFORM_UPDATING}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_SKIP_JOBS}" @@ -201,7 +207,9 @@ Describe 'common-options' When run test_common_SLEEP_SECONDS_not_a_number "${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 "${NOT_START_WITH_A_SQUARE_BRACKET}" The stderr should satisfy spec_expect_message "GANTRY_SLEEP_SECONDS ${MUST_BE_A_NUMBER}.*" The stderr should satisfy spec_expect_no_message "${SKIP_UPDATING_ALL}" The stderr should satisfy spec_expect_no_message "${SKIP_UPDATING}.*${SERVICE_NAME}" diff --git a/tests/gantry_filters_spec.sh b/tests/gantry_filters_spec.sh index ce0a370..f4f7a1f 100644 --- a/tests/gantry_filters_spec.sh +++ b/tests/gantry_filters_spec.sh @@ -36,7 +36,9 @@ Describe 'filters' When run test_SERVICES_FILTERS_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 "${NOT_START_WITH_A_SQUARE_BRACKET}" The stderr should satisfy spec_expect_message "Failed to obtain services list.*" The stderr should satisfy spec_expect_message "${SKIP_UPDATING_ALL}.*${SKIP_REASON_PREVIOUS_ERRORS}" The stderr should satisfy spec_expect_no_message "${SKIP_UPDATING}.*${SERVICE_NAME}" @@ -80,7 +82,7 @@ Describe 'filters' local LABEL="gantry.test" for NUM in $(seq "${NUM_SERVICES_EXCLUDED_FILTER_START}" "${MAX_SERVICES_NUM}"); do local SERVICE_NAME_NUM="${SERVICE_NAME}-${NUM}" - docker service update --quiet --label-add "${LABEL}=true" "${SERVICE_NAME_NUM}" + docker_service_update --label-add "${LABEL}=true" "${SERVICE_NAME_NUM}" done export GANTRY_SERVICES_EXCLUDED_FILTERS="label=${LABEL}=true" run_gantry "${TEST_NAME}" @@ -91,7 +93,9 @@ Describe 'filters' When run test_SERVICES_EXCLUDED_multiple_services "${TEST_NAME}" "${SERVICE_NAME}" "${MAX_SERVICES_NUM}" The status should be success 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 "${NOT_START_WITH_A_SQUARE_BRACKET}" The stderr should satisfy spec_expect_no_message "${SKIP_UPDATING_ALL}" The stderr should satisfy spec_expect_multiple_messages "${EXCLUDE_SERVICE}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${SKIP_UPDATING}.*${SERVICE_NAME}" @@ -129,7 +133,7 @@ Describe 'filters' local LABEL="gantry.services.excluded" for NUM in $(seq 0 "${MAX_SERVICES_NUM}"); do local SERVICE_NAME_NUM="${SERVICE_NAME}-${NUM}" - docker service update --quiet --label-add "${LABEL}=true" "${SERVICE_NAME_NUM}" + docker_service_update --label-add "${LABEL}=true" "${SERVICE_NAME_NUM}" done # Do not set GANTRY_SERVICES_EXCLUDED_FILTERS, check the default one is working. run_gantry "${TEST_NAME}" @@ -140,7 +144,9 @@ Describe 'filters' When run test_SERVICES_EXCLUDED_FILTERS_default "${TEST_NAME}" "${SERVICE_NAME}" "${MAX_SERVICES_NUM}" The status should be success 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 "${NOT_START_WITH_A_SQUARE_BRACKET}" The stderr should satisfy spec_expect_no_message "${SKIP_UPDATING_ALL}" The stderr should satisfy spec_expect_no_message "${SKIP_UPDATING}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${PERFORM_UPDATING}.*${SERVICE_NAME}" @@ -181,7 +187,9 @@ Describe 'filters' When run test_SERVICES_EXCLUDED_FILTERS_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 "${NOT_START_WITH_A_SQUARE_BRACKET}" The stderr should satisfy spec_expect_message "Failed to obtain services list.*" The stderr should satisfy spec_expect_message "${SKIP_UPDATING_ALL}.*${SKIP_REASON_PREVIOUS_ERRORS}" The stderr should satisfy spec_expect_no_message "${SKIP_UPDATING}.*${SERVICE_NAME}" diff --git a/tests/gantry_login_negative_spec.sh b/tests/gantry_login_negative_spec.sh new file mode 100644 index 0000000..c62f601 --- /dev/null +++ b/tests/gantry_login_negative_spec.sh @@ -0,0 +1,408 @@ +#!/bin/bash spellspec +# Copyright (C) 2024 Shizun Ge +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +Describe 'login_negative' + SUITE_NAME="login_negative" + BeforeAll "initialize_all_tests ${SUITE_NAME} ENFORCE_LOGIN" + AfterAll "finish_all_tests ${SUITE_NAME} ENFORCE_LOGIN" + Describe "test_login_no_login" "container_test:false" + TEST_NAME="test_login_no_login" + IMAGE_WITH_TAG=$(get_image_with_tag "${SUITE_NAME}") + SERVICE_NAME="gantry-test-$(unique_id)" + CONFIG="C$(unique_id)" + TEST_REGISTRY=$(load_test_registry "${SUITE_NAME}") || return 1 + test_login_no_login() { + local TEST_NAME="${1}" + local SERVICE_NAME="${2}" + reset_gantry_env "${SERVICE_NAME}" + run_gantry "${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_login_no_login "${TEST_NAME}" "${SERVICE_NAME}" "${CONFIG}" "${TEST_REGISTRY}" "${TEST_USERNAME}" "${TEST_PASSWORD}" + 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 "${NOT_START_WITH_A_SQUARE_BRACKET}" + The stderr should satisfy spec_expect_no_message "${LOGGED_INTO_REGISTRY}" + The stderr should satisfy spec_expect_no_message "${FAILED_TO_LOGIN_TO_REGISTRY}" + The stderr should satisfy spec_expect_no_message "${CONFIG_IS_NOT_A_DIRECTORY}" + The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}.*--config ${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}" + The stderr should satisfy spec_expect_message "${NUM_SERVICES_INSPECT_FAILURE}" + 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}.*--with-registry-auth.*${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}" + The stderr should satisfy spec_expect_no_message "${FAILED_TO_ROLLBACK}.*${SERVICE_NAME}" + 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 "${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}" + End + End + Describe "test_login_incorrect_password" "container_test:false" + TEST_NAME="test_login_incorrect_password" + IMAGE_WITH_TAG=$(get_image_with_tag "${SUITE_NAME}") + SERVICE_NAME="gantry-test-$(unique_id)" + CONFIG="C$(unique_id)" + TEST_REGISTRY=$(load_test_registry "${SUITE_NAME}") || return 1 + test_login_incorrect_password() { + local TEST_NAME="${1}" + local SERVICE_NAME="${2}" + local CONFIG="${3}" + local REGISTRY="${4}" + local USERNAME="${5}" + 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}"; + docker_service_update --label-add "${GANTRY_AUTH_CONFIG_LABEL}=${CONFIG}" "${SERVICE_NAME}" + reset_gantry_env "${SERVICE_NAME}" + export GANTRY_REGISTRY_CONFIG="${CONFIG}" + export GANTRY_REGISTRY_HOST="${REGISTRY}" + export GANTRY_REGISTRY_PASSWORD_FILE="${PASS_FILE}" + export GANTRY_REGISTRY_USER_FILE="${USER_FILE}" + local RETURN_VALUE= + run_gantry "${TEST_NAME}" + RETURN_VALUE="${?}" + rm "${USER_FILE}" + rm "${PASS_FILE}" + [ -d "${CONFIG}" ] && rm -r "${CONFIG}" + return "${RETURN_VALUE}" + } + 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_incorrect_password "${TEST_NAME}" "${SERVICE_NAME}" "${CONFIG}" "${TEST_REGISTRY}" "${TEST_USERNAME}" "${TEST_PASSWORD}" + 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 "${NOT_START_WITH_A_SQUARE_BRACKET}" + The stderr should satisfy spec_expect_no_message "${LOGGED_INTO_REGISTRY}" + The stderr should satisfy spec_expect_message "${FAILED_TO_LOGIN_TO_REGISTRY}.*${TEST_REGISTRY}.*${CONFIG}" + The stderr should satisfy spec_expect_no_message "${CONFIG_IS_NOT_A_DIRECTORY}" + The stderr should satisfy spec_expect_message "${SKIP_UPDATING_ALL}.*${SKIP_REASON_PREVIOUS_ERRORS}" + The stderr should satisfy spec_expect_no_message "${SKIP_UPDATING}.*${SERVICE_NAME}" + The stderr should satisfy spec_expect_no_message "${PERFORM_UPDATING}.*${SERVICE_NAME}" + 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_no_message "${NUM_SERVICES_UPDATING}" + The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}" + 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}" + The stderr should satisfy spec_expect_no_message "${FAILED_TO_ROLLBACK}.*${SERVICE_NAME}" + 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 "${SERVICES_UPDATED}" + The stderr should satisfy spec_expect_no_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}" + End + End + Describe "test_login_read_only_file" "container_test:false" + TEST_NAME="test_login_read_only_file" + IMAGE_WITH_TAG=$(get_image_with_tag "${SUITE_NAME}") + SERVICE_NAME="gantry-test-$(unique_id)" + CONFIG="C$(unique_id)" + TEST_REGISTRY=$(load_test_registry "${SUITE_NAME}") || return 1 + test_login_read_only_file() { + local TEST_NAME="${1}" + local SERVICE_NAME="${2}" + local CONFIG="${3}" + local REGISTRY="${4}" + local USERNAME="${5}" + local PASSWORD="${6}" + check_login_input "${REGISTRY}" "${USERNAME}" "${PASSWORD}" || return 1; + # Set the config folder to read only. (It won't work for container_test) + 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}"; + docker_service_update --label-add "${GANTRY_AUTH_CONFIG_LABEL}=${CONFIG}" "${SERVICE_NAME}" + reset_gantry_env "${SERVICE_NAME}" + export GANTRY_REGISTRY_CONFIG="${CONFIG}" + export GANTRY_REGISTRY_HOST="${REGISTRY}" + export GANTRY_REGISTRY_PASSWORD_FILE="${PASS_FILE}" + export GANTRY_REGISTRY_USER_FILE="${USER_FILE}" + local RETURN_VALUE= + run_gantry "${TEST_NAME}" + RETURN_VALUE="${?}" + rm "${USER_FILE}" + rm "${PASS_FILE}" + [ -d "${CONFIG}" ] && chmod 777 "${CONFIG}" && rm -r "${CONFIG}" + return "${RETURN_VALUE}" + } + 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_read_only_file "${TEST_NAME}" "${SERVICE_NAME}" "${CONFIG}" "${TEST_REGISTRY}" "${TEST_USERNAME}" "${TEST_PASSWORD}" + 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 "${NOT_START_WITH_A_SQUARE_BRACKET}" + The stderr should satisfy spec_expect_no_message "${LOGGED_INTO_REGISTRY}" + The stderr should satisfy spec_expect_message "${FAILED_TO_LOGIN_TO_REGISTRY}.*${TEST_REGISTRY}.*${CONFIG}" + The stderr should satisfy spec_expect_no_message "${CONFIG_IS_NOT_A_DIRECTORY}" + The stderr should satisfy spec_expect_message "${SKIP_UPDATING_ALL}.*${SKIP_REASON_PREVIOUS_ERRORS}" + The stderr should satisfy spec_expect_no_message "${SKIP_UPDATING}.*${SERVICE_NAME}" + The stderr should satisfy spec_expect_no_message "${PERFORM_UPDATING}.*${SERVICE_NAME}" + 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_no_message "${NUM_SERVICES_UPDATING}" + The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}" + 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}" + The stderr should satisfy spec_expect_no_message "${FAILED_TO_ROLLBACK}.*${SERVICE_NAME}" + 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 "${SERVICES_UPDATED}" + The stderr should satisfy spec_expect_no_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}" + End + End + Describe "test_login_config_mismatch" "container_test:false" + TEST_NAME="test_login_config_mismatch" + IMAGE_WITH_TAG=$(get_image_with_tag "${SUITE_NAME}") + SERVICE_NAME="gantry-test-$(unique_id)" + CONFIG="C$(unique_id)" + TEST_REGISTRY=$(load_test_registry "${SUITE_NAME}") || return 1 + test_login_config_mismatch() { + local TEST_NAME="${1}" + local SERVICE_NAME="${2}" + local CONFIG="${3}" + local REGISTRY="${4}" + local USERNAME="${5}" + local PASSWORD="${6}" + check_login_input "${REGISTRY}" "${USERNAME}" "${PASSWORD}" || return 1; + local INCORRECT_CONFIG="${CONFIG}-incorrect" + local USER_FILE=; USER_FILE=$(mktemp); echo "${USERNAME}" > "${USER_FILE}"; + local PASS_FILE=; PASS_FILE=$(mktemp); 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 "${SERVICE_NAME}" + export GANTRY_REGISTRY_CONFIG="${CONFIG}" + export GANTRY_REGISTRY_HOST="${REGISTRY}" + export GANTRY_REGISTRY_PASSWORD_FILE="${PASS_FILE}" + export GANTRY_REGISTRY_USER_FILE="${USER_FILE}" + local RETURN_VALUE= + run_gantry "${TEST_NAME}" + RETURN_VALUE="${?}" + rm "${USER_FILE}" + rm "${PASS_FILE}" + [ -d "${CONFIG}" ] && rm -r "${CONFIG}" + [ -d "${INCORRECT_CONFIG}" ] && rm -r "${INCORRECT_CONFIG}" + return "${RETURN_VALUE}" + } + 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 "${TEST_NAME}" "${SERVICE_NAME}" "${CONFIG}" "${TEST_REGISTRY}" "${TEST_USERNAME}" "${TEST_PASSWORD}" + 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 "${NOT_START_WITH_A_SQUARE_BRACKET}" + The stderr should satisfy spec_expect_message "${LOGGED_INTO_REGISTRY}.*${TEST_REGISTRY}.*${CONFIG}" + The stderr should satisfy spec_expect_no_message "${FAILED_TO_LOGIN_TO_REGISTRY}" + The stderr should satisfy spec_expect_message "${CONFIG_IS_NOT_A_DIRECTORY}" + The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}.*\"--config ${CONFIG}\".*${SERVICE_NAME}" + The stderr should satisfy spec_expect_message "${ADDING_OPTIONS}.*\"--config ${CONFIG}-incorrect\".*${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}" + The stderr should satisfy spec_expect_message "${NUM_SERVICES_INSPECT_FAILURE}" + 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}.*--with-registry-auth.*${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}" + The stderr should satisfy spec_expect_no_message "${FAILED_TO_ROLLBACK}.*${SERVICE_NAME}" + 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 "${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}" + End + End + Describe "test_login_REGISTRY_CONFIGS_FILE_bad_format" "container_test:false" + TEST_NAME="test_login_REGISTRY_CONFIGS_FILE_bad_format" + IMAGE_WITH_TAG=$(get_image_with_tag "${SUITE_NAME}") + SERVICE_NAME="gantry-test-$(unique_id)" + CONFIG="C$(unique_id)" + TEST_REGISTRY=$(load_test_registry "${SUITE_NAME}") || return 1 + test_login_REGISTRY_CONFIGS_FILE_bad_format() { + local TEST_NAME="${1}" + local SERVICE_NAME="${2}" + local CONFIG="${3}" + local REGISTRY="${4}" + local USERNAME="${5}" + local PASSWORD="${6}" + check_login_input "${REGISTRY}" "${USERNAME}" "${PASSWORD}" || return 1; + local CONFIGS_FILE= + CONFIGS_FILE=$(mktemp) + # Add an extra item to the line. + echo "${CONFIG} ${REGISTRY} ${USERNAME} ${PASSWORD} Extra" >> "${CONFIGS_FILE}" + # Missing an item from the line. + echo "The-Only-Item-In-The-Line" >> "${CONFIGS_FILE}" + docker_service_update --label-add "${GANTRY_AUTH_CONFIG_LABEL}=${CONFIG}" "${SERVICE_NAME}" + reset_gantry_env "${SERVICE_NAME}" + export GANTRY_REGISTRY_CONFIGS_FILE="${CONFIGS_FILE}" + local RETURN_VALUE= + run_gantry "${TEST_NAME}" + RETURN_VALUE="${?}" + rm "${CONFIGS_FILE}" + [ -d "${CONFIG}" ] && rm -r "${CONFIG}" + return "${RETURN_VALUE}" + } + 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_REGISTRY_CONFIGS_FILE_bad_format "${TEST_NAME}" "${SERVICE_NAME}" "${CONFIG}" "${TEST_REGISTRY}" "${TEST_USERNAME}" "${TEST_PASSWORD}" + 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 "${NOT_START_WITH_A_SQUARE_BRACKET}" + The stderr should satisfy spec_expect_message "format error.*Found extra item\(s\)" + The stderr should satisfy spec_expect_message "format error.*Missing item\(s\)" + The stderr should satisfy spec_expect_no_message "${LOGGED_INTO_REGISTRY}.*${TEST_REGISTRY}.*${CONFIG}" + The stderr should satisfy spec_expect_no_message "${FAILED_TO_LOGIN_TO_REGISTRY}" + The stderr should satisfy spec_expect_no_message "${CONFIG_IS_NOT_A_DIRECTORY}" + The stderr should satisfy spec_expect_message "${SKIP_UPDATING_ALL}.*${SKIP_REASON_PREVIOUS_ERRORS}" + The stderr should satisfy spec_expect_no_message "${SKIP_UPDATING}.*${SERVICE_NAME}" + The stderr should satisfy spec_expect_no_message "${PERFORM_UPDATING}.*${SERVICE_NAME}" + 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_no_message "${NUM_SERVICES_UPDATING}" + The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}.*--config.*" + 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}" + The stderr should satisfy spec_expect_no_message "${FAILED_TO_ROLLBACK}.*${SERVICE_NAME}" + 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_no_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}" + End + End + Describe "test_login_file_not_exist" "container_test:false" + TEST_NAME="test_login_file_not_exist" + IMAGE_WITH_TAG=$(get_image_with_tag "${SUITE_NAME}") + SERVICE_NAME="gantry-test-$(unique_id)" + CONFIG="C$(unique_id)" + TEST_REGISTRY=$(load_test_registry "${SUITE_NAME}") || return 1 + test_login_file_not_exist() { + local TEST_NAME="${1}" + local SERVICE_NAME="${2}" + local CONFIG="${3}" + local REGISTRY="${4}" + local USERNAME="${5}" + local PASSWORD="${6}" + check_login_input "${REGISTRY}" "${USERNAME}" "${PASSWORD}" || return 1; + docker_service_update --label-add "${GANTRY_AUTH_CONFIG_LABEL}=${CONFIG}" "${SERVICE_NAME}" + local FILE_NOT_EXIST="/tmp/${CONFIG}" + reset_gantry_env "${SERVICE_NAME}" + export GANTRY_REGISTRY_CONFIG_FILE="${FILE_NOT_EXIST}" + export GANTRY_REGISTRY_CONFIGS_FILE="${FILE_NOT_EXIST}" + export GANTRY_REGISTRY_HOST_FILE="${FILE_NOT_EXIST}" + export GANTRY_REGISTRY_PASSWORD_FILE="${FILE_NOT_EXIST}" + export GANTRY_REGISTRY_USER_FILE="${FILE_NOT_EXIST}" + local RETURN_VALUE= + run_gantry "${TEST_NAME}" + RETURN_VALUE="${?}" + [ -d "${CONFIG}" ] && rm -r "${CONFIG}" + return "${RETURN_VALUE}" + } + 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_file_not_exist "${TEST_NAME}" "${SERVICE_NAME}" "${CONFIG}" "${TEST_REGISTRY}" "${TEST_USERNAME}" "${TEST_PASSWORD}" + 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 "${NOT_START_WITH_A_SQUARE_BRACKET}" + The stderr should satisfy spec_expect_no_message "${LOGGED_INTO_REGISTRY}.*${TEST_REGISTRY}.*${CONFIG}" + The stderr should satisfy spec_expect_no_message "${FAILED_TO_LOGIN_TO_REGISTRY}" + The stderr should satisfy spec_expect_no_message "${CONFIG_IS_NOT_A_DIRECTORY}" + The stderr should satisfy spec_expect_message "${SKIP_UPDATING_ALL}.*${SKIP_REASON_PREVIOUS_ERRORS}" + The stderr should satisfy spec_expect_no_message "${SKIP_UPDATING}.*${SERVICE_NAME}" + The stderr should satisfy spec_expect_no_message "${PERFORM_UPDATING}.*${SERVICE_NAME}" + 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_no_message "${NUM_SERVICES_UPDATING}" + The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}.*--config.*" + 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}" + The stderr should satisfy spec_expect_no_message "${FAILED_TO_ROLLBACK}.*${SERVICE_NAME}" + 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_no_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}" + End + End +End # Describe 'login_negative' diff --git a/tests/gantry_login_spec.sh b/tests/gantry_login_spec.sh index 5116e40..9f8e8a9 100644 --- a/tests/gantry_login_spec.sh +++ b/tests/gantry_login_spec.sh @@ -17,9 +17,8 @@ Describe 'login' SUITE_NAME="login" - BeforeAll "initialize_all_tests ${SUITE_NAME}" - AfterAll "finish_all_tests ${SUITE_NAME}" - # Here are just simple login tests. + BeforeAll "initialize_all_tests ${SUITE_NAME} ENFORCE_LOGIN" + AfterAll "finish_all_tests ${SUITE_NAME} ENFORCE_LOGIN" Describe "test_login_config" "container_test:true" TEST_NAME="test_login_config" IMAGE_WITH_TAG=$(get_image_with_tag "${SUITE_NAME}") @@ -33,17 +32,10 @@ Describe 'login' local REGISTRY="${4}" local USERNAME="${5}" local PASSWORD="${6}" - if [ -z "${REGISTRY}" ] || [ -z "${USERNAME}" ] || [ -z "${PASSWORD}" ]; then - echo "No REGISTRY, USERNAME or PASSWORD provided." >&2 - return 1 - fi - local LABEL="gantry.auth.config" - local USER_FILE PASS_FILE - USER_FILE=$(mktemp) - PASS_FILE=$(mktemp) - docker service update --quiet --label-add "${LABEL}=${CONFIG}" "${SERVICE_NAME}" - echo "${USERNAME}" > "${USER_FILE}" - echo "${PASSWORD}" > "${PASS_FILE}" + 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}"; + docker_service_update --label-add "${GANTRY_AUTH_CONFIG_LABEL}=${CONFIG}" "${SERVICE_NAME}" reset_gantry_env "${SERVICE_NAME}" export GANTRY_REGISTRY_CONFIG="${CONFIG}" export GANTRY_REGISTRY_HOST="${REGISTRY}" @@ -63,8 +55,12 @@ Describe 'login' When run test_login_config "${TEST_NAME}" "${SERVICE_NAME}" "${CONFIG}" "${TEST_REGISTRY}" "${TEST_USERNAME}" "${TEST_PASSWORD}" The status should be success 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_message "Logged into registry *${TEST_REGISTRY} for config ${CONFIG}" + The stderr should satisfy spec_expect_no_message "${NOT_START_WITH_A_SQUARE_BRACKET}" + The stderr should satisfy spec_expect_message "${LOGGED_INTO_REGISTRY}.*${TEST_REGISTRY}.*${CONFIG}" + The stderr should satisfy spec_expect_no_message "${FAILED_TO_LOGIN_TO_REGISTRY}" + The stderr should satisfy spec_expect_no_message "${CONFIG_IS_NOT_A_DIRECTORY}" 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}" @@ -89,61 +85,57 @@ Describe 'login' The stderr should satisfy spec_expect_no_message "${FAILED_TO_REMOVE_IMAGE}.*${IMAGE_WITH_TAG}" End End - Describe "test_login_REGISTRY_CONFIGS_FILE" "container_test:true" - TEST_NAME="test_login_REGISTRY_CONFIGS_FILE" + Describe "test_login_default_config" "container_test:true" + TEST_NAME="test_login_default_config" IMAGE_WITH_TAG=$(get_image_with_tag "${SUITE_NAME}") SERVICE_NAME="gantry-test-$(unique_id)" - CONFIG="C$(unique_id)" + CONFIG="NotUsed" TEST_REGISTRY=$(load_test_registry "${SUITE_NAME}") || return 1 - test_login_REGISTRY_CONFIGS_FILE() { + test_login_default_config() { local TEST_NAME="${1}" local SERVICE_NAME="${2}" local CONFIG="${3}" local REGISTRY="${4}" local USERNAME="${5}" local PASSWORD="${6}" - if [ -z "${REGISTRY}" ] || [ -z "${USERNAME}" ] || [ -z "${PASSWORD}" ]; then - echo "No REGISTRY, USERNAME or PASSWORD provided." >&2 - return 1 - fi - local LABEL="gantry.auth.config" - local CONFIGS_FILE= - CONFIGS_FILE=$(mktemp) - docker service update --quiet --label-add "${LABEL}=${CONFIG}" "${SERVICE_NAME}" - echo "# Test comments: CONFIG REGISTRY USERNAME PASSWORD" >> "${CONFIGS_FILE}" - echo "${CONFIG} ${REGISTRY} ${USERNAME} ${PASSWORD}" >> "${CONFIGS_FILE}" + 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}"; + # Do not set GANTRY_AUTH_CONFIG_LABEL on the service. reset_gantry_env "${SERVICE_NAME}" - export GANTRY_REGISTRY_CONFIGS_FILE="${CONFIGS_FILE}" - # Since we pass credentials via the configs file, we can use other envs to login to docker hub and check the rate. - # However we do not actually check whether we read rates correctly, in case password or usrename for docker hub is not set. - # It seems there is no rate limit when running from the github actions, which also gives us a NaN error. - # Do not set GANTRY_REGISTRY_HOST to test the default config. - # export GANTRY_REGISTRY_HOST="docker.io" - export GANTRY_REGISTRY_PASSWORD="${DOCKERHUB_PASSWORD:-""}" - export GANTRY_REGISTRY_USER="${DOCKERHUB_USERNAME:-""}" + # Do not set GANTRY_REGISTRY_CONFIG + export GANTRY_REGISTRY_HOST="${REGISTRY}" + export GANTRY_REGISTRY_PASSWORD_FILE="${PASS_FILE}" + export GANTRY_REGISTRY_USER_FILE="${USER_FILE}" local RETURN_VALUE= run_gantry "${TEST_NAME}" RETURN_VALUE="${?}" - rm "${CONFIGS_FILE}" - [ -d "${CONFIG}" ] && rm -r "${CONFIG}" + rm "${USER_FILE}" + rm "${PASS_FILE}" + [ -d "${CONFIG}" ] && rm -r "${CONFIG}" && echo "${CONFIG} should not exist." >&2 && return 1 return "${RETURN_VALUE}" } 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_REGISTRY_CONFIGS_FILE "${TEST_NAME}" "${SERVICE_NAME}" "${CONFIG}" "${TEST_REGISTRY}" "${TEST_USERNAME}" "${TEST_PASSWORD}" + When run test_login_default_config "${TEST_NAME}" "${SERVICE_NAME}" "${CONFIG}" "${TEST_REGISTRY}" "${TEST_USERNAME}" "${TEST_PASSWORD}" The status should be success 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_message "Logged into registry *${TEST_REGISTRY} for config ${CONFIG}" + The stderr should satisfy spec_expect_no_message "${NOT_START_WITH_A_SQUARE_BRACKET}" + The stderr should satisfy spec_expect_message "${LOGGED_INTO_REGISTRY}.*${TEST_REGISTRY}.*default configuration" + The stderr should satisfy spec_expect_no_message "${FAILED_TO_LOGIN_TO_REGISTRY}" + The stderr should satisfy spec_expect_no_message "${CONFIG_IS_NOT_A_DIRECTORY}" 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_message "${ADDING_OPTIONS}.*--config ${CONFIG}.*${SERVICE_NAME}" - The stderr should satisfy spec_expect_message "${ADDING_OPTIONS}.*--with-registry-auth.*${SERVICE_NAME}" + The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}.*--config ${CONFIG}.*${SERVICE_NAME}" + # When using the default configuration, user must manually set --with-registry-auth. + The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}.*--with-registry-auth.*${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}" @@ -160,33 +152,34 @@ Describe 'login' The stderr should satisfy spec_expect_no_message "${FAILED_TO_REMOVE_IMAGE}.*${IMAGE_WITH_TAG}" End End - Describe "test_login_REGISTRY_CONFIGS_FILE_bad_format" "container_test:false" - TEST_NAME="test_login_REGISTRY_CONFIGS_FILE_bad_format" + Describe "test_login_REGISTRY_CONFIGS_FILE" "container_test:true" + TEST_NAME="test_login_REGISTRY_CONFIGS_FILE" IMAGE_WITH_TAG=$(get_image_with_tag "${SUITE_NAME}") SERVICE_NAME="gantry-test-$(unique_id)" CONFIG="C$(unique_id)" TEST_REGISTRY=$(load_test_registry "${SUITE_NAME}") || return 1 - test_login_REGISTRY_CONFIGS_FILE_bad_format() { + test_login_REGISTRY_CONFIGS_FILE() { local TEST_NAME="${1}" local SERVICE_NAME="${2}" local CONFIG="${3}" local REGISTRY="${4}" local USERNAME="${5}" local PASSWORD="${6}" - if [ -z "${REGISTRY}" ] || [ -z "${USERNAME}" ] || [ -z "${PASSWORD}" ]; then - echo "No REGISTRY, USERNAME or PASSWORD provided." >&2 - return 1 - fi - local LABEL="gantry.auth.config" + check_login_input "${REGISTRY}" "${USERNAME}" "${PASSWORD}" || return 1; local CONFIGS_FILE= CONFIGS_FILE=$(mktemp) - docker service update --quiet --label-add "${LABEL}=${CONFIG}" "${SERVICE_NAME}" - # Add an extra item to the line. - echo "${CONFIG} ${REGISTRY} ${USERNAME} ${PASSWORD} Extra" >> "${CONFIGS_FILE}" - # Missing an item from the line. - echo "The-Only-Item-In-The-Line" >> "${CONFIGS_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}" reset_gantry_env "${SERVICE_NAME}" export GANTRY_REGISTRY_CONFIGS_FILE="${CONFIGS_FILE}" + # Since we pass credentials via the configs file, we can use other envs to login to docker hub and check the rate. + # However we do not actually check whether we read rates correctly, in case password or usrename for docker hub is not set. + # It seems there is no rate limit when running from the github actions, which also gives us a NaN error. + # Do not set GANTRY_REGISTRY_HOST to test the default config. + # export GANTRY_REGISTRY_HOST="docker.io" + export GANTRY_REGISTRY_PASSWORD="${DOCKERHUB_PASSWORD:-""}" + export GANTRY_REGISTRY_USER="${DOCKERHUB_USERNAME:-""}" local RETURN_VALUE= run_gantry "${TEST_NAME}" RETURN_VALUE="${?}" @@ -197,98 +190,36 @@ Describe 'login' 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_REGISTRY_CONFIGS_FILE_bad_format "${TEST_NAME}" "${SERVICE_NAME}" "${CONFIG}" "${TEST_REGISTRY}" "${TEST_USERNAME}" "${TEST_PASSWORD}" - The status should be failure - The stdout should satisfy display_output - The stderr should satisfy display_output - The stderr should satisfy spec_expect_message "format error.*Found extra item\(s\)" - The stderr should satisfy spec_expect_message "format error.*Missing item\(s\)" - The stderr should satisfy spec_expect_no_message "Logged into registry *${TEST_REGISTRY} for config ${CONFIG}" - The stderr should satisfy spec_expect_message "${SKIP_UPDATING_ALL}.*${SKIP_REASON_PREVIOUS_ERRORS}" - The stderr should satisfy spec_expect_no_message "${SKIP_UPDATING}.*${SERVICE_NAME}" - The stderr should satisfy spec_expect_no_message "${PERFORM_UPDATING}.*${SERVICE_NAME}" - 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_no_message "${NUM_SERVICES_UPDATING}" - The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}.*--config.*" - 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}" - The stderr should satisfy spec_expect_no_message "${FAILED_TO_ROLLBACK}.*${SERVICE_NAME}" - 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_no_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}" - End - End - Describe "test_login_file_not_exist" "container_test:false" - TEST_NAME="test_login_file_not_exist" - IMAGE_WITH_TAG=$(get_image_with_tag "${SUITE_NAME}") - SERVICE_NAME="gantry-test-$(unique_id)" - CONFIG="C$(unique_id)" - TEST_REGISTRY=$(load_test_registry "${SUITE_NAME}") || return 1 - test_login_file_not_exist() { - local TEST_NAME="${1}" - local SERVICE_NAME="${2}" - local CONFIG="${3}" - local REGISTRY="${4}" - local USERNAME="${5}" - local PASSWORD="${6}" - if [ -z "${REGISTRY}" ] || [ -z "${USERNAME}" ] || [ -z "${PASSWORD}" ]; then - echo "No REGISTRY, USERNAME or PASSWORD provided." >&2 - return 1 - fi - local LABEL="gantry.auth.config" - docker service update --quiet --label-add "${LABEL}=${CONFIG}" "${SERVICE_NAME}" - local FILE_NOT_EXIST="/tmp/${CONFIG}" - reset_gantry_env "${SERVICE_NAME}" - export GANTRY_REGISTRY_CONFIG_FILE="${FILE_NOT_EXIST}" - export GANTRY_REGISTRY_CONFIGS_FILE="${FILE_NOT_EXIST}" - export GANTRY_REGISTRY_HOST_FILE="${FILE_NOT_EXIST}" - export GANTRY_REGISTRY_PASSWORD_FILE="${FILE_NOT_EXIST}" - export GANTRY_REGISTRY_USER_FILE="${FILE_NOT_EXIST}" - local RETURN_VALUE= - run_gantry "${TEST_NAME}" - RETURN_VALUE="${?}" - [ -d "${CONFIG}" ] && rm -r "${CONFIG}" - return "${RETURN_VALUE}" - } - 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_file_not_exist "${TEST_NAME}" "${SERVICE_NAME}" "${CONFIG}" "${TEST_REGISTRY}" "${TEST_USERNAME}" "${TEST_PASSWORD}" - The status should be failure + When run test_login_REGISTRY_CONFIGS_FILE "${TEST_NAME}" "${SERVICE_NAME}" "${CONFIG}" "${TEST_REGISTRY}" "${TEST_USERNAME}" "${TEST_PASSWORD}" + The status should be success 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 "Logged into registry *${TEST_REGISTRY} for config ${CONFIG}" - The stderr should satisfy spec_expect_message "${SKIP_UPDATING_ALL}.*${SKIP_REASON_PREVIOUS_ERRORS}" + The stderr should satisfy spec_expect_no_message "${NOT_START_WITH_A_SQUARE_BRACKET}" + The stderr should satisfy spec_expect_message "${LOGGED_INTO_REGISTRY}.*${TEST_REGISTRY}.*${CONFIG}" + The stderr should satisfy spec_expect_no_message "${FAILED_TO_LOGIN_TO_REGISTRY}" + The stderr should satisfy spec_expect_no_message "${CONFIG_IS_NOT_A_DIRECTORY}" The stderr should satisfy spec_expect_no_message "${SKIP_UPDATING}.*${SERVICE_NAME}" - The stderr should satisfy spec_expect_no_message "${PERFORM_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_no_message "${NUM_SERVICES_UPDATING}" - The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}.*--config.*" - The stderr should satisfy spec_expect_no_message "${UPDATED}.*${SERVICE_NAME}" + The stderr should satisfy spec_expect_message "${NUM_SERVICES_UPDATING}" + The stderr should satisfy spec_expect_message "${ADDING_OPTIONS}.*--config ${CONFIG}.*${SERVICE_NAME}" + The stderr should satisfy spec_expect_message "${ADDING_OPTIONS}.*--with-registry-auth.*${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}" The stderr should satisfy spec_expect_no_message "${FAILED_TO_ROLLBACK}.*${SERVICE_NAME}" 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_no_message "${NO_SERVICES_UPDATED}" + The stderr should satisfy spec_expect_message "1 ${SERVICES_UPDATED}" The stderr should satisfy spec_expect_no_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 "${NO_IMAGES_TO_REMOVE}" + The stderr should satisfy spec_expect_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_message "${REMOVED_IMAGE}.*${IMAGE_WITH_TAG}" The stderr should satisfy spec_expect_no_message "${FAILED_TO_REMOVE_IMAGE}.*${IMAGE_WITH_TAG}" End End diff --git a/tests/gantry_manifest_spec.sh b/tests/gantry_manifest_spec.sh index df3539e..278e560 100644 --- a/tests/gantry_manifest_spec.sh +++ b/tests/gantry_manifest_spec.sh @@ -37,11 +37,13 @@ Describe 'manifest-command' When run test_MANIFEST_CMD_none "${TEST_NAME}" "${SERVICE_NAME}" The status should be success 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 "${NOT_START_WITH_A_SQUARE_BRACKET}" # Do not set GANTRY_SERVICES_SELF, it should be set autoamtically # If we are not testing gantry inside a container, it should failed to find the service name. # To test gantry container, we need to use run_gantry_container. - The stderr should satisfy spec_expect_no_message ".*GRANTRY_SERVICES_SELF.*" + The stderr should satisfy spec_expect_no_message ".*GANTRY_SERVICES_SELF.*" # Gantry is still trying to update the service. # But it will see no new images. The stderr should satisfy spec_expect_no_message "${SKIP_UPDATING}.*${SERVICE_NAME}" @@ -87,7 +89,9 @@ Describe 'manifest-command' When run test_MANIFEST_CMD_none_SERVICES_SELF "${TEST_NAME}" "${SERVICE_NAME}" The status should be success 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 "${NOT_START_WITH_A_SQUARE_BRACKET}" The stderr should satisfy spec_expect_no_message ".*GANTRY_SERVICES_SELF.*" The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}" The stderr should satisfy spec_expect_message "${SKIP_UPDATING}.*${SERVICE_NAME}.*${SKIP_REASON_CURRENT_IS_LATEST}" @@ -130,7 +134,9 @@ Describe 'manifest-command' When run test_MANIFEST_CMD_manifest "${TEST_NAME}" "${SERVICE_NAME}" The status should be success 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 "${NOT_START_WITH_A_SQUARE_BRACKET}" The stderr should satisfy spec_expect_message "${ADDING_OPTIONS}.*--insecure.*" 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}" @@ -166,9 +172,9 @@ Describe 'manifest-command' # export GANTRY_MANIFEST_CMD="manifest" # export GANTRY_MANIFEST_OPTIONS="--insecure" local LABEL_AND_VALUE="gantry.manifest.cmd=manifest" - docker service update --quiet --label-add "${LABEL_AND_VALUE}" "${SERVICE_NAME}" + docker_service_update --label-add "${LABEL_AND_VALUE}" "${SERVICE_NAME}" LABEL_AND_VALUE="gantry.manifest.options=--insecure" - docker service update --quiet --label-add "${LABEL_AND_VALUE}" "${SERVICE_NAME}" + docker_service_update --label-add "${LABEL_AND_VALUE}" "${SERVICE_NAME}" run_gantry "${TEST_NAME}" } BeforeEach "common_setup_new_image ${TEST_NAME} ${IMAGE_WITH_TAG} ${SERVICE_NAME}" @@ -177,7 +183,9 @@ Describe 'manifest-command' When run test_MANIFEST_CMD_label "${TEST_NAME}" "${SERVICE_NAME}" The status should be success 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 "${NOT_START_WITH_A_SQUARE_BRACKET}" The stderr should satisfy spec_expect_message "${ADDING_OPTIONS}.*--insecure.*" 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}" @@ -219,7 +227,9 @@ Describe 'manifest-command' When run test_MANIFEST_CMD_unsupported_cmd "${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 "${NOT_START_WITH_A_SQUARE_BRACKET}" # No options are added to the unknwon command. The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}" The stderr should satisfy spec_expect_message "Unknown MANIFEST_CMD.*unsupported_cmd" @@ -272,7 +282,9 @@ Describe 'manifest-command' When run test_MANIFEST_CMD_failure "${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 "${NOT_START_WITH_A_SQUARE_BRACKET}" The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}" The stderr should satisfy spec_expect_message "Image.*${IMAGE_WITH_TAG}.*${IMAGE_NOT_EXIST}" The stderr should satisfy spec_expect_message "${SKIP_UPDATING}.*${SERVICE_NAME}.*${SKIP_REASON_MANIFEST_FAILURE}" diff --git a/tests/gantry_notify_spec.sh b/tests/gantry_notify_spec.sh index 8d56b5c..f2d58c8 100644 --- a/tests/gantry_notify_spec.sh +++ b/tests/gantry_notify_spec.sh @@ -97,6 +97,7 @@ Describe 'notify' The stdout should satisfy spec_expect_message "Subject.*1 services updated 0 failed TEST_TITLE" The stdout should satisfy spec_expect_message "${TOTAL_EMAIL_COUNT_IS_ONE}" The stderr should satisfy display_output + The stderr should satisfy spec_expect_no_message "${NOT_START_WITH_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}" @@ -149,6 +150,7 @@ Describe 'notify' The stdout should satisfy spec_expect_message "Subject.*0 services updated 0 failed TEST_TITLE" The stdout should satisfy spec_expect_message "${TOTAL_EMAIL_COUNT_IS_ONE}" The stderr should satisfy display_output + The stderr should satisfy spec_expect_no_message "${NOT_START_WITH_A_SQUARE_BRACKET}" The stderr should satisfy spec_expect_message "${SKIP_UPDATING}.*${SERVICE_NAME}.*${SKIP_REASON_CURRENT_IS_LATEST}" The stderr should satisfy spec_expect_no_message "${PERFORM_UPDATING}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_SKIP_JOBS}" @@ -191,7 +193,9 @@ Describe 'notify' When run test_notify_apprise_bad_url "${TEST_NAME}" "${SERVICE_NAME}" The status should be success 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 "${NOT_START_WITH_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}" @@ -245,6 +249,7 @@ Describe 'notify' The stdout should satisfy spec_expect_message "Subject.*1 services updated 0 failed TEST_TITLE" The stdout should satisfy spec_expect_message "${TOTAL_EMAIL_COUNT_IS_ONE}" The stderr should satisfy display_output + The stderr should satisfy spec_expect_no_message "${NOT_START_WITH_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}" @@ -290,8 +295,10 @@ Describe 'notify' When run test_notify_on_change_no_updates "${TEST_NAME}" "${SERVICE_NAME}" The status should be success The stdout should satisfy display_output + The stdout should satisfy spec_expect_no_message ".+" The stdout should satisfy spec_expect_no_message "TEST_TITLE" The stderr should satisfy display_output + The stderr should satisfy spec_expect_no_message "${NOT_START_WITH_A_SQUARE_BRACKET}" The stderr should satisfy spec_expect_message "${SKIP_UPDATING}.*${SERVICE_NAME}.*${SKIP_REASON_CURRENT_IS_LATEST}" The stderr should satisfy spec_expect_no_message "${PERFORM_UPDATING}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_SKIP_JOBS}" @@ -346,6 +353,7 @@ Describe 'notify' The stdout should satisfy spec_expect_message "Subject.*0 services updated 1 failed TEST_TITLE" The stdout should satisfy spec_expect_message "${TOTAL_EMAIL_COUNT_IS_ONE}" The stderr should satisfy display_output + The stderr should satisfy spec_expect_no_message "${NOT_START_WITH_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}" diff --git a/tests/gantry_parallel_spec.sh b/tests/gantry_parallel_spec.sh index 37d5677..6271a7e 100644 --- a/tests/gantry_parallel_spec.sh +++ b/tests/gantry_parallel_spec.sh @@ -61,7 +61,9 @@ Describe 'service-parallel' When run test_parallel_less_workers "${TEST_NAME}" "${SERVICE_NAME}" "${MAX_SERVICES_NUM}" The status should be success 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 "${NOT_START_WITH_A_SQUARE_BRACKET}" for NUM in $(seq 0 "${MAX_SERVICES_NUM}"); do SERVICE_NAME_NUM="${SERVICE_NAME}-${NUM}" The stderr should satisfy spec_expect_no_message "${SKIP_UPDATING}.* ${SERVICE_NAME_NUM} " @@ -112,7 +114,9 @@ Describe 'service-parallel' When run test_parallel_more_workers "${TEST_NAME}" "${SERVICE_NAME}" "${MAX_SERVICES_NUM}" The status should be success 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 "${NOT_START_WITH_A_SQUARE_BRACKET}" for NUM in $(seq 0 "${MAX_SERVICES_NUM}"); do SERVICE_NAME_NUM="${SERVICE_NAME}-${NUM}" The stderr should satisfy spec_expect_no_message "${SKIP_UPDATING}.* ${SERVICE_NAME_NUM} " @@ -152,7 +156,9 @@ Describe 'service-parallel' When run test_parallel_GANTRY_MANIFEST_NUM_WORKERS_not_a_number "${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 "${NOT_START_WITH_A_SQUARE_BRACKET}" The stderr should satisfy spec_expect_message "GANTRY_MANIFEST_NUM_WORKERS ${MUST_BE_A_NUMBER}.*" The stderr should satisfy spec_expect_no_message "${SKIP_UPDATING}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${PERFORM_UPDATING}.*${SERVICE_NAME}.*${PERFORM_REASON_HAS_NEWER_IMAGE}" @@ -193,7 +199,9 @@ Describe 'service-parallel' When run test_parallel_GANTRY_UPDATE_NUM_WORKERS_not_a_number "${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 "${NOT_START_WITH_A_SQUARE_BRACKET}" The stderr should satisfy spec_expect_message "GANTRY_UPDATE_NUM_WORKERS ${MUST_BE_A_NUMBER}.*" The stderr should satisfy spec_expect_no_message "${SKIP_UPDATING}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${PERFORM_UPDATING}.*${SERVICE_NAME}.*${PERFORM_REASON_HAS_NEWER_IMAGE}" diff --git a/tests/gantry_rollback_spec.sh b/tests/gantry_rollback_spec.sh index 3f97ad5..aff493c 100644 --- a/tests/gantry_rollback_spec.sh +++ b/tests/gantry_rollback_spec.sh @@ -39,7 +39,9 @@ Describe 'rollback' When run test_rollback_due_to_timeout "${TEST_NAME}" "${SERVICE_NAME}" "${TIMEOUT}" 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 "${NOT_START_WITH_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}" @@ -86,7 +88,9 @@ Describe 'rollback' When run test_rollback_failed "${TEST_NAME}" "${SERVICE_NAME}" "${TIMEOUT}" 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 "${NOT_START_WITH_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}" @@ -131,7 +135,9 @@ Describe 'rollback' When run test_rollback_ROLLBACK_ON_FAILURE_false "${TEST_NAME}" "${SERVICE_NAME}" "${TIMEOUT}" 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 "${NOT_START_WITH_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}" @@ -169,7 +175,7 @@ Describe 'rollback' export GANTRY_UPDATE_TIMEOUT_SECONDS="NotANumber" # Assume service update won't be done within TIMEOUT second. local LABEL_AND_VALUE="gantry.update.timeout_seconds=${TIMEOUT}" - docker service update --quiet --label-add "${LABEL_AND_VALUE}" "${SERVICE_NAME}" + docker_service_update --label-add "${LABEL_AND_VALUE}" "${SERVICE_NAME}" run_gantry "${TEST_NAME}" } BeforeEach "common_setup_timeout ${TEST_NAME} ${IMAGE_WITH_TAG} ${SERVICE_NAME} ${TIMEOUT}" @@ -178,7 +184,9 @@ Describe 'rollback' When run test_rollback_lable_due_to_timeout "${TEST_NAME}" "${SERVICE_NAME}" "${TIMEOUT}" 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 "${NOT_START_WITH_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}" @@ -217,11 +225,11 @@ Describe 'rollback' export GANTRY_ROLLBACK_OPTIONS="--insecure" # Assume service update won't be done within TIMEOUT second. local LABEL_AND_VALUE="gantry.update.timeout_seconds=${TIMEOUT}" - docker service update --quiet --label-add "${LABEL_AND_VALUE}" "${SERVICE_NAME}" + docker_service_update --label-add "${LABEL_AND_VALUE}" "${SERVICE_NAME}" # Rollback would fail due to the incorrect option. # --with-registry-auth cannot be combined with --rollback. LABEL_AND_VALUE="gantry.rollback.options=--with-registry-auth" - docker service update --quiet --label-add "${LABEL_AND_VALUE}" "${SERVICE_NAME}" + docker_service_update --label-add "${LABEL_AND_VALUE}" "${SERVICE_NAME}" run_gantry "${TEST_NAME}" } BeforeEach "common_setup_timeout ${TEST_NAME} ${IMAGE_WITH_TAG} ${SERVICE_NAME} ${TIMEOUT}" @@ -230,7 +238,9 @@ Describe 'rollback' When run test_rollback_label_failed "${TEST_NAME}" "${SERVICE_NAME}" "${TIMEOUT}" 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 "${NOT_START_WITH_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}" @@ -268,9 +278,9 @@ Describe 'rollback' export GANTRY_UPDATE_TIMEOUT_SECONDS="NotANumber" # Assume service update won't be done within TIMEOUT second. local LABEL_AND_VALUE="gantry.update.timeout_seconds=${TIMEOUT}" - docker service update --quiet --label-add "${LABEL_AND_VALUE}" "${SERVICE_NAME}" + docker_service_update --label-add "${LABEL_AND_VALUE}" "${SERVICE_NAME}" LABEL_AND_VALUE="gantry.rollback.on_failure=false" - docker service update --quiet --label-add "${LABEL_AND_VALUE}" "${SERVICE_NAME}" + docker_service_update --label-add "${LABEL_AND_VALUE}" "${SERVICE_NAME}" run_gantry "${TEST_NAME}" } BeforeEach "common_setup_timeout ${TEST_NAME} ${IMAGE_WITH_TAG} ${SERVICE_NAME} ${TIMEOUT}" @@ -279,7 +289,9 @@ Describe 'rollback' When run test_rollback_label_ROLLBACK_ON_FAILURE_false "${TEST_NAME}" "${SERVICE_NAME}" "${TIMEOUT}" 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 "${NOT_START_WITH_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}" diff --git a/tests/gantry_service_multiple_spec.sh b/tests/gantry_service_multiple_spec.sh index 8a087ae..90ac14e 100644 --- a/tests/gantry_service_multiple_spec.sh +++ b/tests/gantry_service_multiple_spec.sh @@ -86,7 +86,9 @@ Describe 'service-multiple-services' When run test_multiple_services_excluded_filters "${TEST_NAME}" "${SERVICE_NAME}" The status should be success 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 "${NOT_START_WITH_A_SQUARE_BRACKET}" # Service 0 and 3 should get updated. # Service 1 and 2 should be excluded. # Service 4 and 5 created with new image, no update. diff --git a/tests/gantry_service_no_running_tasks_spec.sh b/tests/gantry_service_no_running_tasks_spec.sh index 2f8144e..461c6af 100644 --- a/tests/gantry_service_no_running_tasks_spec.sh +++ b/tests/gantry_service_no_running_tasks_spec.sh @@ -38,15 +38,14 @@ Describe "service-no-running-tasks" start_replicated_service "${SERVICE_NAME}" "${IMAGE_WITH_TAG}" start_replicated_service "${SERVICE_NAME_SUFFIX}" "${IMAGE_WITH_TAG}" build_and_push_test_image "${IMAGE_WITH_TAG}" + # Set running tasks to 0 for SERVICE_NAME. + # But keep tasks running for SERVICE_NAME_SUFFIX. + docker_service_update --replicas=0 "${SERVICE_NAME}" + wait_zero_running_tasks "${SERVICE_NAME}" } test_no_running_tasks_replicated() { local TEST_NAME="${1}" local SERVICE_NAME="${2}" - local SERVICE_NAME_SUFFIX="${SERVICE_NAME}-suffix" - # Set running tasks to 0 for SERVICE_NAME. - # But keep tasks running for SERVICE_NAME_SUFFIX. - docker service update --quiet --replicas=0 "${SERVICE_NAME}" - wait_zero_running_tasks "${SERVICE_NAME}" reset_gantry_env "${SERVICE_NAME}" run_gantry "${TEST_NAME}" } @@ -66,7 +65,9 @@ Describe "service-no-running-tasks" When run test_no_running_tasks_replicated "${TEST_NAME}" "${SERVICE_NAME}" The status should be success 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 "${NOT_START_WITH_A_SQUARE_BRACKET}" # Add "--detach=true" when there is no running tasks. # https://github.com/docker/cli/issues/627 The stderr should satisfy spec_expect_message "${ADDING_OPTIONS}.*--detach=true.*${SERVICE_NAME}\." @@ -126,7 +127,9 @@ Describe "service-no-running-tasks" When run test_no_running_tasks_global "${TEST_NAME}" "${SERVICE_NAME}" The status should be success 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 "${NOT_START_WITH_A_SQUARE_BRACKET}" # Add "--detach=true" when there is no running tasks. # https://github.com/docker/cli/issues/627 The stderr should satisfy spec_expect_message "${ADDING_OPTIONS}.*--detach=true.*${SERVICE_NAME}" diff --git a/tests/gantry_service_single_spec.sh b/tests/gantry_service_single_spec.sh index 061963b..5f9ea18 100644 --- a/tests/gantry_service_single_spec.sh +++ b/tests/gantry_service_single_spec.sh @@ -35,7 +35,9 @@ Describe 'service-single-service' When run test_new_image_no "${TEST_NAME}" "${SERVICE_NAME}" The status should be success 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 "${NOT_START_WITH_A_SQUARE_BRACKET}" The stderr should satisfy spec_expect_message "${SKIP_UPDATING}.*${SERVICE_NAME}.*${SKIP_REASON_CURRENT_IS_LATEST}" The stderr should satisfy spec_expect_no_message "${PERFORM_UPDATING}.*${SERVICE_NAME}" The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_SKIP_JOBS}" @@ -76,7 +78,9 @@ Describe 'service-single-service' When run test_new_image_yes "${TEST_NAME}" "${SERVICE_NAME}" The status should be success 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 "${NOT_START_WITH_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}" @@ -127,7 +131,9 @@ Describe 'service-single-service' When run test_new_image_no_digest "${TEST_NAME}" "${SERVICE_NAME}" The status should be success 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 "${NOT_START_WITH_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_DIGEST_IS_EMPTY}" The stderr should satisfy spec_expect_no_message "${NUM_SERVICES_SKIP_JOBS}" diff --git a/tests/gantry_update_options_spec.sh b/tests/gantry_update_options_spec.sh index deca3d8..8ff1e17 100644 --- a/tests/gantry_update_options_spec.sh +++ b/tests/gantry_update_options_spec.sh @@ -56,7 +56,9 @@ Describe 'update-options' When run test_update_jobs_skipping "${TEST_NAME}" "${SERVICE_NAME}" The status should be success 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 "${NOT_START_WITH_A_SQUARE_BRACKET}" # Check whether it is a job before checking whether there is a new image. The stderr should satisfy spec_expect_message "${SKIP_UPDATING}.*${SERVICE_NAME_SUFFIX}.*${SKIP_REASON_IS_JOB}" The stderr should satisfy spec_expect_no_message "${PERFORM_UPDATING}.*${SERVICE_NAME_SUFFIX}" @@ -101,7 +103,9 @@ Describe 'update-options' When run test_update_jobs_UPDATE_JOBS_true "${TEST_NAME}" "${SERVICE_NAME}" The status should be success 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 "${NOT_START_WITH_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}" @@ -137,12 +141,12 @@ Describe 'update-options' # label should override the global environment variable. export GANTRY_UPDATE_JOBS="false" local LABEL_AND_VALUE="gantry.update.jobs=true" - docker service update --quiet --detach=true --label-add "${LABEL_AND_VALUE}" "${SERVICE_NAME}" + docker_service_update --detach=true --label-add "${LABEL_AND_VALUE}" "${SERVICE_NAME}" # label should override the global environment variable. export GANTRY_UPDATE_OPTIONS="--incorrect-option" # The job may not reach the desired "Complete" state and blocking update CLI. So add "--detach=true" LABEL_AND_VALUE="gantry.update.options=--detach=true" - docker service update --quiet --detach=true --label-add "${LABEL_AND_VALUE}" "${SERVICE_NAME}" + docker_service_update --detach=true --label-add "${LABEL_AND_VALUE}" "${SERVICE_NAME}" run_gantry "${TEST_NAME}" } BeforeEach "common_setup_job ${TEST_NAME} ${IMAGE_WITH_TAG} ${SERVICE_NAME}" @@ -151,7 +155,9 @@ Describe 'update-options' When run test_update_jobs_label_UPDATE_JOBS_true "${TEST_NAME}" "${SERVICE_NAME}" The status should be success 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 "${NOT_START_WITH_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}" @@ -181,23 +187,32 @@ Describe 'update-options' IMAGE_WITH_TAG=$(get_image_with_tag "${SUITE_NAME}") SERVICE_NAME="gantry-test-$(unique_id)" TASK_SECONDS=15 - test_update_jobs_no_running_tasks() { + test_start() { local TEST_NAME="${1}" - local SERVICE_NAME="${2}" + local IMAGE_WITH_TAG="${2}" + local SERVICE_NAME="${3}" + local TASK_SECONDS="${4}" + common_setup_job "${TEST_NAME}" "${IMAGE_WITH_TAG}" "${SERVICE_NAME}" "${TASK_SECONDS}" # The tasks should exit after TASK_SECONDS seconds sleep. Then it will have 0 running tasks. wait_zero_running_tasks "${SERVICE_NAME}" + } + test_update_jobs_no_running_tasks() { + local TEST_NAME="${1}" + local SERVICE_NAME="${2}" reset_gantry_env "${SERVICE_NAME}" export GANTRY_UPDATE_JOBS="true" run_gantry "${TEST_NAME}" } # The task will finish in ${TASK_SECONDS} seconds - BeforeEach "common_setup_job ${TEST_NAME} ${IMAGE_WITH_TAG} ${SERVICE_NAME} ${TASK_SECONDS}" + BeforeEach "test_start ${TEST_NAME} ${IMAGE_WITH_TAG} ${SERVICE_NAME} ${TASK_SECONDS}" AfterEach "common_cleanup ${TEST_NAME} ${IMAGE_WITH_TAG} ${SERVICE_NAME}" It 'run_test' When run test_update_jobs_no_running_tasks "${TEST_NAME}" "${SERVICE_NAME}" The status should be success 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 "${NOT_START_WITH_A_SQUARE_BRACKET}" The stderr should satisfy spec_expect_message "${ADDING_OPTIONS}.*--detach=true.*${SERVICE_NAME}" # Cannot add "--replicas" to replicated job The stderr should satisfy spec_expect_no_message "${ADDING_OPTIONS}.*--replicas=0" @@ -258,6 +273,7 @@ Describe 'update-options' The stdout should satisfy spec_expect_no_message "Before updating: LABEL_VALUE=.*${SERVICE_NAME}" The stdout should satisfy spec_expect_message "After updating: LABEL_VALUE=.*${SERVICE_NAME}" The stderr should satisfy display_output + The stderr should satisfy spec_expect_no_message "${NOT_START_WITH_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}" @@ -301,7 +317,7 @@ Describe 'update-options' # label should override the global environment variable. export GANTRY_UPDATE_OPTIONS="--incorrect-option" local LABEL_AND_VALUE="gantry.update.options=--label-add=${LABEL}=${SERVICE_NAME}" - docker service update --quiet --label-add "${LABEL_AND_VALUE}" "${SERVICE_NAME}" + docker_service_update --label-add "${LABEL_AND_VALUE}" "${SERVICE_NAME}" local RETURN_VALUE= run_gantry "${TEST_NAME}" RETURN_VALUE="${?}" @@ -319,6 +335,7 @@ Describe 'update-options' The stdout should satisfy spec_expect_no_message "Before updating: LABEL_VALUE=.*${SERVICE_NAME}" The stdout should satisfy spec_expect_message "After updating: LABEL_VALUE=.*${SERVICE_NAME}" The stderr should satisfy display_output + The stderr should satisfy spec_expect_no_message "${NOT_START_WITH_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}" @@ -359,7 +376,9 @@ Describe 'update-options' When run test_update_UPDATE_TIMEOUT_SECONDS_not_a_number "${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 "${NOT_START_WITH_A_SQUARE_BRACKET}" The stderr should satisfy spec_expect_message "UPDATE_TIMEOUT_SECONDS ${MUST_BE_A_NUMBER}.*" 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}" diff --git a/tests/spec_gantry_test_helper.sh b/tests/spec_gantry_test_helper.sh index 5c36196..84080ff 100644 --- a/tests/spec_gantry_test_helper.sh +++ b/tests/spec_gantry_test_helper.sh @@ -18,7 +18,12 @@ set -a # Constant strings for checks. +# NOT_START_WITH_A_SQUARE_BRACKET ignores color codes. Use test_log not to trigger this check. +export NOT_START_WITH_A_SQUARE_BRACKET="^(?!(?:\x1b\[[0-9;]*[mG])?\[)" +export GANTRY_AUTH_CONFIG_LABEL="gantry.auth.config" export MUST_BE_A_NUMBER="must be a number" +export LOGGED_INTO_REGISTRY="Logged into registry" +export FAILED_TO_LOGIN_TO_REGISTRY="Failed to login to registry" export SKIP_UPDATING_ALL="Skip updating all services" export SKIP_REASON_NOT_SWARM_MANAGER="is not a swarm manager" export SKIP_REASON_PREVIOUS_ERRORS="due to previous error\(s\)" @@ -34,6 +39,7 @@ export PERFORM_REASON_KNOWN_NEWER_IMAGE="because there is a known newer version export PERFORM_REASON_DIGEST_IS_EMPTY="because DIGEST is empty" export PERFORM_REASON_HAS_NEWER_IMAGE="because there is a newer version" export IMAGE_NOT_EXIST="does not exist or it is not available" +export CONFIG_IS_NOT_A_DIRECTORY="is not a directory that contains Docker configuration files" export ADDING_OPTIONS="Adding options" 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\)" @@ -57,10 +63,27 @@ export FAILED_TO_REMOVE_IMAGE="Failed to remove image" export SCHEDULE_NEXT_UPDATE_AT="Schedule next update at" export SLEEP_SECONDS_BEFORE_NEXT_UPDATE="Sleep [0-9]+ seconds before next update" +test_log() { + echo "${GANTRY_LOG_LEVEL}" | grep -q -i "^NONE$" && return 0; + [ -n "${GANTRY_IMAGES_TO_REMOVE}" ] && echo "${*}" >&2 && return 0; + echo "[$(date -Iseconds)] Test: ${*}" >&2 +} + display_output() { echo "${display_output:-""}" } +check_login_input() { + local REGISTRY="${1}" + local USERNAME="${2}" + local PASSWORD="${3}" + if [ -z "${REGISTRY}" ] || [ -z "${USERNAME}" ] || [ -z "${PASSWORD}" ]; then + echo "No REGISTRY, USERNAME or PASSWORD provided." >&2 + return 1 + fi + return 0 +} + common_setup_new_image() { local TEST_NAME="${1}" local IMAGE_WITH_TAG="${2}" @@ -200,12 +223,73 @@ _next_available_port() { echo "${PORT}" } +_get_docker_config_file() { + local REGISTRY="${1:?}" + REGISTRY=$(echo "${REGISTRY}" | tr ':' '-') + echo "/tmp/TEST_DOCKER_CONFIG-${REGISTRY}" +} + +_get_docker_config_argument() { + local IMAGE_WITH_TAG="${1:?}" + local REGISTRY= + REGISTRY=$(echo "${IMAGE_WITH_TAG}" | cut -d '/' -f 1) + local CONFIG= + CONFIG=$(_get_docker_config_file "${REGISTRY}") || return 1 + [ -d "${CONFIG}" ] && echo "--config ${CONFIG}" +} + +_login_test_registry() { + local ENFORCE_LOGIN="${1}" + local REGISTRY="${2}" + local USERNAME="${3}" + local PASSWORD="${4}" + if ! _enforce_login_enabled "${ENFORCE_LOGIN}"; then + return 0 + fi + echo "Logging in ${REGISTRY}." + local CONFIG= + CONFIG=$(_get_docker_config_file "${REGISTRY}") || return 1 + echo "${PASSWORD}" | docker --config "${CONFIG}" login --username="${USERNAME}" --password-stdin "${REGISTRY}" 2>&1 +} + +_logout_test_registry() { + local ENFORCE_LOGIN="${1}" + local REGISTRY="${2}" + if ! _enforce_login_enabled "${ENFORCE_LOGIN}"; then + return 0 + fi + echo "Logging out ${REGISTRY}." + local CONFIG= + CONFIG=$(_get_docker_config_file "${REGISTRY}") || return 1 + 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}" } +_remove_test_registry_file() { + local SUITE_NAME="${1:?}" + local REGISTRY_FILE= + REGISTRY_FILE=$(_get_test_registry_file "${SUITE_NAME}") || return 1 + rm "${REGISTRY_FILE}" +} + +_store_test_registry() { + local SUITE_NAME="${1:?}" + local TEST_REGISTRY="${2}" + local REGISTRY_FILE= + if ! REGISTRY_FILE=$(_get_test_registry_file "${SUITE_NAME}" 2>&1); then + echo "_store_test_registry error: ${REGISTRY_FILE}" >&2 + return 1 + fi + echo "Suite \"${SUITE_NAME}\" uses registry ${TEST_REGISTRY}." + echo "${TEST_REGISTRY}" > "${REGISTRY_FILE}" +} + load_test_registry() { local SUITE_NAME="${1:?}" local REGISTRY_FILE= @@ -216,6 +300,7 @@ load_test_registry() { _start_registry() { local SUITE_NAME="${1:?}" + local ENFORCE_LOGIN="${2}" SUITE_NAME=$(echo "${SUITE_NAME}" | tr ' ' '-') local SUITE_NAME_LENGTH="${#SUITE_NAME}" local REGISTRY_SERVICE_NAME="gantry-test-registry-${SUITE_NAME}" @@ -239,9 +324,10 @@ _start_registry() { fi stop_service "${REGISTRY_SERVICE_NAME}" 1>/dev/null 2>&1 TEST_REGISTRY="${REGISTRY_BASE}:${REGISTRY_PORT}" - echo "${SUITE_NAME} starting registry ${TEST_REGISTRY} " + echo "Suite \"${SUITE_NAME}\" starts registry ${TEST_REGISTRY} " # SC2046 (warning): Quote this to prevent word splitting. - # shellcheck disable=SC2046 + # SC2086 (info): Double quote to prevent globbing and word splitting. + # shellcheck disable=SC2046,SC2086 if docker service create --quiet \ --name "${REGISTRY_SERVICE_NAME}" \ --restart-condition "on-failure" \ @@ -249,6 +335,7 @@ _start_registry() { $(_location_constraints) \ --mode=replicated \ -p "${REGISTRY_PORT}:5000" \ + $(_add_htpasswd "${ENFORCE_LOGIN}" "${TEST_USERNAME}" "${TEST_PASSWORD}") \ "${REGISTRY_IMAGE}" 2>&1; then break; fi @@ -260,31 +347,27 @@ _start_registry() { REGISTRY_PORT=$((REGISTRY_PORT+1)) sleep 1 done - local REGISTRY_FILE= - if ! REGISTRY_FILE=$(_get_test_registry_file "${SUITE_NAME}" 2>&1); then - echo "_start_registry _get_test_registry_file error: ${REGISTRY_FILE}" >&2 - return 1 - fi - echo "${SUITE_NAME} uses registry ${TEST_REGISTRY}." - echo "${TEST_REGISTRY}" > "${REGISTRY_FILE}" + _store_test_registry "${SUITE_NAME}" "${TEST_REGISTRY}" || return 1; + _login_test_registry "${ENFORCE_LOGIN}" "${TEST_REGISTRY}" "${TEST_USERNAME}" "${TEST_PASSWORD}" || return 1; } _stop_registry() { local SUITE_NAME="${1:?}" + local ENFORCE_LOGIN="${2}" SUITE_NAME=$(echo "${SUITE_NAME}" | tr ' ' '-') local REGISTRY_SERVICE_NAME="gantry-test-registry-${SUITE_NAME}" local REGISTRY= REGISTRY=$(load_test_registry "${SUITE_NAME}") || return 1 echo "Removing registry ${REGISTRY} " stop_service "${REGISTRY_SERVICE_NAME}" - local REGISTRY_FILE= - REGISTRY_FILE=$(_get_test_registry_file "${SUITE_NAME}") || return 1 - rm "${REGISTRY_FILE}" + _logout_test_registry "${ENFORCE_LOGIN}" "${REGISTRY}" || return 1 + _remove_test_registry_file "${SUITE_NAME}" || return 1 return 0 } initialize_all_tests() { local SUITE_NAME="${1:-"gantry"}" + local ENFORCE_LOGIN="${2}" SUITE_NAME=$(echo "${SUITE_NAME}" | tr ' ' '-') local SCRIPT_DIR= SCRIPT_DIR="$(_get_script_dir)" || return 1 @@ -293,14 +376,15 @@ initialize_all_tests() { echo "== Starting suite ${SUITE_NAME}" echo "==============================" _init_swarm - _start_registry "${SUITE_NAME}" + _start_registry "${SUITE_NAME}" "${ENFORCE_LOGIN}" } # finish_all_tests should return non zero when there are errors. finish_all_tests() { local SUITE_NAME="${1:-"gantry"}" + local ENFORCE_LOGIN="${2}" SUITE_NAME=$(echo "${SUITE_NAME}" | tr ' ' '-') - _stop_registry "${SUITE_NAME}" + _stop_registry "${SUITE_NAME}" "${ENFORCE_LOGIN}" echo "==============================" echo "== Finished all tests in ${SUITE_NAME}" echo "==============================" @@ -442,7 +526,8 @@ unique_id() { # To reduce the possibility that tests run in parallel on the same machine affect each other. local PID="$$" local RANDOM_STR= - RANDOM_STR=$(head /dev/urandom | LANG=C tr -dc 'A-Za-z0-9' | head -c 8) + # repository name must be lowercase + RANDOM_STR=$(head /dev/urandom | LANG=C tr -dc 'a-z0-9' | head -c 8) echo "$(date +%s)-${PID}-${RANDOM_STR}" } @@ -474,16 +559,22 @@ build_and_push_test_image() { local TASK_SECONDS="${2}" local EXIT_SECONDS="${3}" build_test_image "${IMAGE_WITH_TAG}" "${TASK_SECONDS}" "${EXIT_SECONDS}" - echo "Pushing image " - docker push --quiet "${IMAGE_WITH_TAG}" + echo -n "Pushing image " + # SC2046 (warning): Quote this to prevent word splitting. + # shellcheck disable=SC2046 + docker $(_get_docker_config_argument "${IMAGE_WITH_TAG}") push --quiet "${IMAGE_WITH_TAG}" } prune_local_test_image() { local IMAGE_WITH_TAG="${1}" - echo "Removing image ${IMAGE_WITH_TAG} " + echo -n "Removing image ${IMAGE_WITH_TAG} " docker image rm "${IMAGE_WITH_TAG}" --force } +docker_service_update() { + docker service update --quiet "${@}" >/dev/null +} + wait_zero_running_tasks() { local SERVICE_NAME="${1}" local TIMEOUT_SECONDS="${2}" @@ -540,6 +631,32 @@ _location_constraints() { echo "${ARGS}" } +_enforce_login_enabled() { + local ENFORCE_LOGIN="${1}" + test "${ENFORCE_LOGIN}" == "ENFORCE_LOGIN" +} + +_add_htpasswd() { + local ENFORCE_LOGIN="${1}" + local USER="${2}" + local PASS="${3}" + 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)" + if ! docker image inspect "${HTTPD_IMAGE}" > /dev/null 2>&1; then + docker pull "${HTTPD_IMAGE}" > /dev/null + fi + docker_run --entrypoint htpasswd "${HTTPD_IMAGE}" -Bbn "${USER}" "${PASS}" > "${PASSWD}" + echo "--mount type=bind,source=${PASSWD},target=${PASSWD} \ + -e REGISTRY_AUTH=htpasswd \ + -e REGISTRY_AUTH_HTPASSWD_REALM=RegistryRealm \ + -e REGISTRY_AUTH_HTPASSWD_PATH=${PASSWD} " +} + _wait_service_state() { local SERVICE_NAME="${1}" local STATE="${2}" @@ -562,10 +679,11 @@ start_replicated_service() { echo "Creating service ${SERVICE_NAME} in replicated mode " # SC2046 (warning): Quote this to prevent word splitting. # shellcheck disable=SC2046 - timeout 120 docker service create --quiet \ + timeout 120 docker $(_get_docker_config_argument "${IMAGE_WITH_TAG}") service create --quiet \ --name "${SERVICE_NAME}" \ --restart-condition "on-failure" \ --restart-max-attempts 5 \ + --with-registry-auth \ $(_location_constraints) \ --mode=replicated \ "${IMAGE_WITH_TAG}" @@ -578,10 +696,11 @@ start_global_service() { echo "Creating service ${SERVICE_NAME} in global mode " # SC2046 (warning): Quote this to prevent word splitting. # shellcheck disable=SC2046 - timeout 120 docker service create --quiet \ + timeout 120 docker $(_get_docker_config_argument "${IMAGE_WITH_TAG}") service create --quiet \ --name "${SERVICE_NAME}" \ --restart-condition "on-failure" \ --restart-max-attempts 5 \ + --with-registry-auth \ $(_location_constraints) \ --mode=global \ "${IMAGE_WITH_TAG}" @@ -594,10 +713,11 @@ _start_replicated_job() { echo "Creating service ${SERVICE_NAME} in replicated job mode " # SC2046 (warning): Quote this to prevent word splitting. # shellcheck disable=SC2046 - timeout 120 docker service create --quiet \ + timeout 120 docker $(_get_docker_config_argument "${IMAGE_WITH_TAG}") service create --quiet \ --name "${SERVICE_NAME}" \ --restart-condition "on-failure" \ --restart-max-attempts 5 \ + --with-registry-auth \ $(_location_constraints) \ --mode=replicated-job --detach=true \ "${IMAGE_WITH_TAG}" @@ -607,7 +727,7 @@ _start_replicated_job() { stop_service() { local SERVICE_NAME="${1}" - echo "Removing service " + echo -n "Removing service " docker service rm "${SERVICE_NAME}" } @@ -668,9 +788,7 @@ _run_gantry_container() { MOUNT_OPTIONS=$(_add_file_to_mount_options "${MOUNT_OPTIONS}" "${GANTRY_REGISTRY_HOST_FILE}") MOUNT_OPTIONS=$(_add_file_to_mount_options "${MOUNT_OPTIONS}" "${GANTRY_REGISTRY_PASSWORD_FILE}") MOUNT_OPTIONS=$(_add_file_to_mount_options "${MOUNT_OPTIONS}" "${GANTRY_REGISTRY_USER_FILE}") - if [ "${GANTRY_LOG_LEVEL}" != "NONE" ]; then - echo "Starting SUT service ${SERVICE_NAME} with image ${SUT_REPO_TAG}." - fi + test_log "Starting SUT service ${SERVICE_NAME} with image ${SUT_REPO_TAG}." local RETURN_VALUE=0 local CMD_OUTPUT= # SC2086 (info): Double quote to prevent globbing and word splitting.