diff --git a/cluster/lib/logging.sh b/cluster/lib/logging.sh index 959f8474427..1c74f66528b 100644 --- a/cluster/lib/logging.sh +++ b/cluster/lib/logging.sh @@ -28,7 +28,16 @@ kube::log::errexit() { set +o xtrace local code="${1:-1}" - kube::log::error_exit "'${BASH_COMMAND}' exited with status $err" "${1:-1}" 1 + # Print out the stack trace described by $function_stack + if [ ${#FUNCNAME[@]} -gt 2 ] + then + kube::log::error "Call tree:" + for ((i=1;i<${#FUNCNAME[@]}-1;i++)) + do + kube::log::error " $i: ${BASH_SOURCE[$i+1]}:${BASH_LINENO[$i]} ${FUNCNAME[$i]}(...)" + done + fi + kube::log::error_exit "Error in ${BASH_SOURCE[1]}:${BASH_LINENO[0]}. '${BASH_COMMAND}' exited with status $err" "${1:-1}" 1 } kube::log::install_errexit() { diff --git a/hack/lib/test.sh b/hack/lib/test.sh index 51b63695c74..6c7f41337c2 100644 --- a/hack/lib/test.sh +++ b/hack/lib/test.sh @@ -31,6 +31,15 @@ kube::test::clear_all() { fi } +# Prints the calling file and line number $1 levels deep +# Defaults to 2 levels so you can call this to find your own caller +kube::test::get_caller() { + local levels=${1:-2} + local caller_file="${BASH_SOURCE[$levels]}" + local caller_line="${BASH_LINENO[$levels-1]}" + echo "$(basename "${caller_file}"):${caller_line}" +} + # Force exact match of a returned result for a object query. Wrap this with || to support multiple # valid return types. kube::test::get_object_assert() { @@ -43,12 +52,12 @@ kube::test::get_object_assert() { if [[ "$res" =~ ^$expected$ ]]; then echo -n ${green} - echo "Successful get $object $request: $res" + echo "$(kube::test::get_caller): Successful get $object $request: $res" echo -n ${reset} return 0 else echo ${bold}${red} - echo "FAIL!" + echo "$(kube::test::get_caller): FAIL!" echo "Get $object $request" echo " Expected: $expected" echo " Got: $res" @@ -68,12 +77,12 @@ kube::test::get_object_jsonpath_assert() { if [[ "$res" =~ ^$expected$ ]]; then echo -n ${green} - echo "Successful get $object $request: $res" + echo "$(kube::test::get_caller): Successful get $object $request: $res" echo -n ${reset} return 0 else echo ${bold}${red} - echo "FAIL!" + echo "$(kube::test::get_caller): FAIL!" echo "Get $object $request" echo " Expected: $expected" echo " Got: $res" @@ -94,7 +103,7 @@ kube::test::describe_object_assert() { for match in ${matches}; do if [[ ! $(echo "$result" | grep ${match}) ]]; then echo ${bold}${red} - echo "FAIL!" + echo "$(kube::test::get_caller): FAIL!" echo "Describe $resource $object" echo " Expected Match: $match" echo " Not found in:" @@ -107,7 +116,7 @@ kube::test::describe_object_assert() { done echo -n ${green} - echo "Successful describe $resource $object:" + echo "$(kube::test::get_caller): Successful describe $resource $object:" echo "$result" echo -n ${reset} return 0 @@ -131,13 +140,13 @@ kube::test::describe_object_events_assert() { fi if [[ $showevents == $has_events ]]; then echo -n ${green} - echo "Successful describe" + echo "$(kube::test::get_caller): Successful describe" echo "$result" echo ${reset} return 0 else echo ${bold}${red} - echo "FAIL" + echo "$(kube::test::get_caller): FAIL" if [[ $showevents == "false" ]]; then echo " Events information should not be described in:" else diff --git a/hack/make-rules/test-cmd-util.sh b/hack/make-rules/test-cmd-util.sh index 667d0956706..a4808b5c768 100644 --- a/hack/make-rules/test-cmd-util.sh +++ b/hack/make-rules/test-cmd-util.sh @@ -21,8 +21,9 @@ set -o nounset set -o pipefail KUBE_ROOT=$(dirname "${BASH_SOURCE}")/../.. -source "${KUBE_ROOT}/hack/lib/init.sh" -source "${KUBE_ROOT}/hack/lib/test.sh" +# Expects the following has already been done by whatever sources this script +# source "${KUBE_ROOT}/hack/lib/init.sh" +# source "${KUBE_ROOT}/hack/lib/test.sh" ETCD_HOST=${ETCD_HOST:-127.0.0.1} ETCD_PORT=${ETCD_PORT:-2379} @@ -2093,7 +2094,12 @@ run_deployment_tests() { # Deletion of both deployments should not be blocked kubectl delete deployment nginx2 "${kube_flags[@]}" # Clean up - kubectl delete deployment nginx "${kube_flags[@]}" + # TODO: cascading deletion of deployments is failing. + # TODO: re-enable this once https://github.com/kubernetes/kubernetes/issues/40433 is fixed + # kubectl delete deployment nginx "${kube_flags[@]}" + # TODO: remove these once https://github.com/kubernetes/kubernetes/issues/40433 is fixed + kubectl delete deployment nginx --cascade=false "${kube_flags[@]}" + kubectl delete replicaset --all "${kube_flags[@]}" ### Set image of a deployment # Pre-condition: no deployment exists @@ -2409,9 +2415,9 @@ run_multi_resources_tests() { # Requires an env var SUPPORTED_RESOURCES which is a comma separated list of # resources for which tests should be run. runTests() { - if [ -z "${SUPPORTED_RESOURCES}" ]; then - echo "Need to set SUPPORTED_RESOURCES env var. It is a comma separated list of resources that are supported and hence should be tested. Set it to (*) to test all resources" - return + if [ -z "${SUPPORTED_RESOURCES:-}" ]; then + echo "Need to set SUPPORTED_RESOURCES env var. It is a list of resources that are supported and hence should be tested. Set it to (*) to test all resources" + exit 1 fi kube::log::status "Checking kubectl version" kubectl version @@ -2472,11 +2478,10 @@ runTests() { # Make sure "kubernetes" service exists. if kube::test::if_supports_resource "${services}" ; then - output_message=$(kubectl get "${kube_flags[@]}" svc) - if [[ ! $(echo "${output_message}" | grep "kubernetes") ]]; then - # Create kubernetes service - kubectl create "${kube_flags[@]}" -f hack/testdata/kubernetes-service.yaml - fi + # Attempt to create the kubernetes service, tolerating failure (since it might already exist) + kubectl create "${kube_flags[@]}" -f hack/testdata/kubernetes-service.yaml || true + # Require the service to exist (either we created it or the API server did) + kubectl get "${kube_flags[@]}" -f hack/testdata/kubernetes-service.yaml fi # Passing no arguments to create is an error diff --git a/hack/make-rules/test-cmd.sh b/hack/make-rules/test-cmd.sh index 4afa2ccc9bf..bd07bf515dc 100755 --- a/hack/make-rules/test-cmd.sh +++ b/hack/make-rules/test-cmd.sh @@ -22,6 +22,8 @@ set -o nounset set -o pipefail KUBE_ROOT=$(dirname "${BASH_SOURCE}")/../.. +source "${KUBE_ROOT}/hack/lib/init.sh" +source "${KUBE_ROOT}/hack/lib/test.sh" source "${KUBE_ROOT}/hack/make-rules/test-cmd-util.sh" function run_kube_apiserver() { @@ -135,10 +137,8 @@ run_kube_controller_manager run_kubelet create_node SUPPORTED_RESOURCES=("*") -output_message=$(runTests "SUPPORTED_RESOURCES=${SUPPORTED_RESOURCES[@]}") -# Ensure that tests were run. We cannot check all resources here. We check a few -# to catch bugs due to which no tests run. -kube::test::if_has_string "${output_message}" "Testing kubectl(v1:pods)" -kube::test::if_has_string "${output_message}" "Testing kubectl(v1:services)" +# WARNING: Do not wrap this call in a subshell to capture output, e.g. output=$(runTests) +# Doing so will suppress errexit behavior inside runTests +runTests kube::log::status "TESTS PASSED" diff --git a/hack/make-rules/test-federation-cmd.sh b/hack/make-rules/test-federation-cmd.sh index bceeaac35b9..7d768def0bc 100755 --- a/hack/make-rules/test-federation-cmd.sh +++ b/hack/make-rules/test-federation-cmd.sh @@ -22,6 +22,8 @@ set -o nounset set -o pipefail KUBE_ROOT=$(dirname "${BASH_SOURCE}")/../.. +source "${KUBE_ROOT}/hack/lib/init.sh" +source "${KUBE_ROOT}/hack/lib/test.sh" source "${KUBE_ROOT}/hack/make-rules/test-cmd-util.sh" function run_federation_apiserver() { @@ -75,10 +77,8 @@ run_federation_apiserver run_federation_controller_manager # TODO: Fix for replicasets and deployments. SUPPORTED_RESOURCES=("configmaps" "daemonsets" "events" "ingress" "namespaces" "secrets" "services") -output_message=$(runTests "SUPPORTED_RESOURCES=${SUPPORTED_RESOURCES[@]}") -# Ensure that tests were run. We cannot check all resources here. We check a few -# to catch bugs due to which no tests run. -kube::test::if_has_string "${output_message}" "Testing kubectl(v1:namespaces)" -kube::test::if_has_string "${output_message}" "Testing kubectl(v1:services)" +# WARNING: Do not wrap this call in a subshell to capture output, e.g. output=$(runTests) +# Doing so will suppress errexit behavior inside runTests +runTests kube::log::status "TESTS PASSED"