From 5626703634d34d1b7c0060e82aea4b7e711fcfd6 Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Fri, 13 Jun 2014 16:26:38 -0700 Subject: [PATCH 1/5] Add a new e2e test; fix some bugs/usability problems --- cluster/cloudcfg.sh | 2 +- hack/e2e-suite/guestbook.sh | 52 ++++++++++++++++++++++++++++++ hack/e2e-test.sh | 55 +++++++++++++++++++++----------- pkg/client/client.go | 6 ++-- pkg/cloudcfg/resource_printer.go | 15 ++++++--- 5 files changed, 103 insertions(+), 27 deletions(-) create mode 100755 hack/e2e-suite/guestbook.sh diff --git a/cluster/cloudcfg.sh b/cluster/cloudcfg.sh index 4f231ac8b42..4a7e4b6b229 100755 --- a/cluster/cloudcfg.sh +++ b/cluster/cloudcfg.sh @@ -24,6 +24,6 @@ if [ ! -x $CLOUDCFG ]; then exit 1 fi -detect-master +detect-master > /dev/null $CLOUDCFG -h https://${KUBE_MASTER_IP} $@ diff --git a/hack/e2e-suite/guestbook.sh b/hack/e2e-suite/guestbook.sh new file mode 100755 index 00000000000..20d44ee92ee --- /dev/null +++ b/hack/e2e-suite/guestbook.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +# Copyright 2014 Google Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Assumes a running Kubernetes test cluster; verifies that the guestbook example +# works. Assumes that we're being called by hack/e2e-test.sh (we use some env +# vars it sets up). + +set -e + +HAVE_JQ=$(which jq) +if [[ -z ${HAVE_JQ} ]]; then + echo "Please install jq, e.g.: sudo apt-get install jq" + exit 1 +fi + +source "${KUBE_REPO_ROOT}/cluster/util.sh" +GUESTBOOK="${KUBE_REPO_ROOT}/examples/guestbook" + +# Launch the guestbook example +$CLOUDCFG -c "${GUESTBOOK}/redis-master.json" create /pods +$CLOUDCFG -c "${GUESTBOOK}/redis-master-service.json" create /services +$CLOUDCFG -c "${GUESTBOOK}/redis-slave-controller.json" create /replicationControllers + +sleep 5 + +POD_LIST_1=$($CLOUDCFG -json list pods | jq ".items[].id") +echo "Pods running: ${POD_LIST_1}" + +$CLOUDCFG stop redisSlaveController +# Needed until issue #103 gets fixed +sleep 25 +$CLOUDCFG rm redisSlaveController +$CLOUDCFG delete services/redismaster +$CLOUDCFG delete pods/redis-master-2 + +POD_LIST_2=$($CLOUDCFG -json list pods | jq ".items[].id") +echo "Pods running after shutdown: ${POD_LIST_2}" + +exit 0 diff --git a/hack/e2e-test.sh b/hack/e2e-test.sh index a46a20a1567..b5d6f3684d5 100755 --- a/hack/e2e-test.sh +++ b/hack/e2e-test.sh @@ -17,6 +17,11 @@ # Starts a Kubernetes cluster, runs the e2e test suite, and shuts it # down. +# For debugging of this test's components, it's helpful to leave the test +# cluster running. +ALREADY_UP=${1:-0} +LEAVE_UP=${2:-0} + # Exit on error set -e @@ -27,26 +32,30 @@ export CLOUDCFG="${KUBE_REPO_ROOT}/cluster/cloudcfg.sh" source "${KUBE_REPO_ROOT}/cluster/util.sh" -# Build a release -$(dirname $0)/../release/release.sh +if [[ ${ALREADY_UP} -ne 1 ]]; then + # Build a release + $(dirname $0)/../release/release.sh -# Now bring a test cluster up with that release. -$(dirname $0)/../cluster/kube-up.sh + # Now bring a test cluster up with that release. + $(dirname $0)/../cluster/kube-up.sh +fi # Detect the project into $PROJECT if it isn't set detect-project set +e -# Open up port 80 & 8080 so common containers on minions can be reached -gcutil addfirewall \ - --norespect_terminal_width \ - --project ${PROJECT} \ - --target_tags ${MINION_TAG} \ - --allowed tcp:80 \ - --allowed tcp:8080 \ - --network ${NETWORK} \ - ${MINION_TAG}-http-alt +if [[ ${ALREADY_UP} -ne 1 ]]; then + # Open up port 80 & 8080 so common containers on minions can be reached + gcutil addfirewall \ + --norespect_terminal_width \ + --project ${PROJECT} \ + --target_tags ${MINION_TAG} \ + --allowed tcp:80 \ + --allowed tcp:8080 \ + --network ${NETWORK} \ + ${MINION_TAG}-http-alt +fi # Auto shutdown cluster when we exit function shutdown-test-cluster () { @@ -58,17 +67,25 @@ function shutdown-test-cluster () { ${MINION_TAG}-http-alt & $(dirname $0)/../cluster/kube-down.sh > /dev/null & } -trap shutdown-test-cluster EXIT + +if [[ ${LEAVE_UP} -ne 1 ]]; then + trap shutdown-test-cluster EXIT +fi any_failed=0 -for test_file in "$(dirname $0)/e2e-suite/*.sh"; do - $test_file - if [[ -z $? ]]; then - echo "${test_file}: passed!" +for test_file in $(ls $(dirname $0)/e2e-suite/); do + "$(dirname $0)/e2e-suite/${test_file}" + result="$?" + if [[ "${result}" -eq "0" ]]; then + echo "${test_file} returned ${result}; passed!" else - echo "${test_file}: FAILED!" + echo "${test_file} returned ${result}; FAIL!" any_failed=1 fi done +if [[ ${any_failed} -ne 0 ]]; then + echo "At least one test failed." +fi + exit ${any_failed} diff --git a/pkg/client/client.go b/pkg/client/client.go index b30d4094902..e345dd75a5d 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -90,14 +90,14 @@ func (client Client) rawRequest(method, path string, requestBody io.Reader, targ if err != nil { return nil, err } - if response.StatusCode != 200 { - return nil, fmt.Errorf("request [%s %s] failed (%d) %s", method, client.makeURL(path), response.StatusCode, response.Status) - } defer response.Body.Close() body, err := ioutil.ReadAll(response.Body) if err != nil { return body, err } + if response.StatusCode != 200 { + return nil, fmt.Errorf("request [%s %s] failed (%d) %s: %s", method, client.makeURL(path), response.StatusCode, response.Status, string(body)) + } if target != nil { err = json.Unmarshal(body, target) } diff --git a/pkg/cloudcfg/resource_printer.go b/pkg/cloudcfg/resource_printer.go index 30753d385ca..dc31d279fcc 100644 --- a/pkg/cloudcfg/resource_printer.go +++ b/pkg/cloudcfg/resource_printer.go @@ -190,15 +190,22 @@ func (h *HumanReadablePrinter) extractObject(data, kind string) (interface{}, er func (h *HumanReadablePrinter) Print(data string, output io.Writer) error { w := tabwriter.NewWriter(output, 20, 5, 3, ' ', 0) defer w.Flush() - var obj interface{} - if err := json.Unmarshal([]byte(data), &obj); err != nil { + var mapObj map[string]interface{} + if err := json.Unmarshal([]byte(data), &mapObj); err != nil { return err } - if _, contains := obj.(map[string]interface{})["kind"]; !contains { + // Don't complain about empty objects returned by DELETE commands. + if len(mapObj) == 0 { + fmt.Fprint(w, "") + return nil + } + + if _, contains := mapObj["kind"]; !contains { return fmt.Errorf("unexpected object with no 'kind' field: %s", data) } - kind := (obj.(map[string]interface{})["kind"]).(string) + + kind := (mapObj["kind"]).(string) obj, err := h.extractObject(data, kind) if err != nil { return err From 2d0b111ba874892c96543e71ce2bb65ed2962c27 Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Fri, 13 Jun 2014 17:24:12 -0700 Subject: [PATCH 2/5] Fix basic e2e test --- hack/e2e-suite/basic.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hack/e2e-suite/basic.sh b/hack/e2e-suite/basic.sh index bbfe8cef9bb..08bc144f391 100755 --- a/hack/e2e-suite/basic.sh +++ b/hack/e2e-suite/basic.sh @@ -24,7 +24,7 @@ source "${KUBE_REPO_ROOT}/cluster/util.sh" detect-project # Launch a container -$CLOUDCFG -p 8080:80 run dockerfile/nginx 2 myNginx +$CLOUDCFG -p 8080:80 run dockerfile/nginx 3 myNginx # Container turn up on a clean cluster can take a while for the docker image pull. # Sleep for 2 minutes just to be sure. From 74ea18209a16f4902daced49e905026810d922af Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Fri, 13 Jun 2014 17:27:01 -0700 Subject: [PATCH 3/5] Add mac instructions --- hack/e2e-suite/guestbook.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hack/e2e-suite/guestbook.sh b/hack/e2e-suite/guestbook.sh index 20d44ee92ee..f51251a146c 100755 --- a/hack/e2e-suite/guestbook.sh +++ b/hack/e2e-suite/guestbook.sh @@ -22,7 +22,8 @@ set -e HAVE_JQ=$(which jq) if [[ -z ${HAVE_JQ} ]]; then - echo "Please install jq, e.g.: sudo apt-get install jq" + echo "Please install jq, e.g.: 'sudo apt-get install jq' or, " + echo "if you're on a mac with homebrew, 'brew install jq'." exit 1 fi From cba453d72bf3178362d8f3a5bfd7b69ea2b4c98d Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Fri, 13 Jun 2014 17:31:57 -0700 Subject: [PATCH 4/5] Fix basic test the other way. --- cluster/config-test.sh | 2 +- hack/e2e-suite/basic.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cluster/config-test.sh b/cluster/config-test.sh index aa0df6e22d7..aceef0482fd 100755 --- a/cluster/config-test.sh +++ b/cluster/config-test.sh @@ -16,7 +16,7 @@ ZONE=us-central1-b MASTER_SIZE=g1-small MINION_SIZE=g1-small -NUM_MINIONS=3 +NUM_MINIONS=2 # gcloud/gcutil will expand this to the latest supported image. IMAGE=backports-debian-7-wheezy NETWORK=default diff --git a/hack/e2e-suite/basic.sh b/hack/e2e-suite/basic.sh index 08bc144f391..bbfe8cef9bb 100755 --- a/hack/e2e-suite/basic.sh +++ b/hack/e2e-suite/basic.sh @@ -24,7 +24,7 @@ source "${KUBE_REPO_ROOT}/cluster/util.sh" detect-project # Launch a container -$CLOUDCFG -p 8080:80 run dockerfile/nginx 3 myNginx +$CLOUDCFG -p 8080:80 run dockerfile/nginx 2 myNginx # Container turn up on a clean cluster can take a while for the docker image pull. # Sleep for 2 minutes just to be sure. From f02c27312b8cfd400a297cc8686be58fc7cfc138 Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Sat, 14 Jun 2014 09:52:29 -0700 Subject: [PATCH 5/5] Fix --allowed syntax --- hack/e2e-test.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hack/e2e-test.sh b/hack/e2e-test.sh index b5d6f3684d5..81ecb35e644 100755 --- a/hack/e2e-test.sh +++ b/hack/e2e-test.sh @@ -51,8 +51,7 @@ if [[ ${ALREADY_UP} -ne 1 ]]; then --norespect_terminal_width \ --project ${PROJECT} \ --target_tags ${MINION_TAG} \ - --allowed tcp:80 \ - --allowed tcp:8080 \ + --allowed tcp:80,tcp:8080 \ --network ${NETWORK} \ ${MINION_TAG}-http-alt fi