diff --git a/cluster/swarm/cluster.go b/cluster/swarm/cluster.go index ab6f49a3f3..b2934029d5 100644 --- a/cluster/swarm/cluster.go +++ b/cluster/swarm/cluster.go @@ -141,10 +141,10 @@ func (c *Cluster) newEntries(entries []*discovery.Entry) { if old, exists := c.engines[engine.ID]; exists { c.Unlock() - if old.IP != engine.IP { - log.Errorf("ID duplicated. %s shared by %s and %s", engine.ID, old.IP, engine.IP) + if old.Addr != engine.Addr { + log.Errorf("ID duplicated. %s shared by %s and %s", engine.ID, old.Addr, engine.Addr) } else { - log.Errorf("node %q with IP %q is already registered", engine.Name, engine.IP) + log.Debugf("node %q (name: %q) with address %q is already registered", engine.ID, engine.Name, engine.Addr) } return } diff --git a/test/integration/discovery-file.bats b/test/integration/discovery-file.bats new file mode 100644 index 0000000000..98b91557c9 --- /dev/null +++ b/test/integration/discovery-file.bats @@ -0,0 +1,34 @@ +#!/usr/bin/env bats + +load helpers + +# create a blank temp file for discovery +DISCOVERY_FILE=$(mktemp) + +function teardown() { + swarm_manage_cleanup + stop_docker + rm -f "$DISCOVERY_FILE" +} + +function setup_file_discovery() { + rm -f "$DISCOVERY_FILE" + for host in ${HOSTS[@]}; do + echo "$host" >> $DISCOVERY_FILE + done +} + +@test "file discovery" { + # Start 2 engines, register them in a file, then start swarm and make sure + # it sees them. + start_docker 2 + setup_file_discovery + swarm_manage "file://$DISCOVERY_FILE" + check_swarm_nodes + + # Add another engine to the cluster, update the discovery file and make + # sure it's picked up by swarm. + start_docker 1 + setup_file_discovery + retry 10 1 check_swarm_nodes +} diff --git a/test/integration/discovery-token.bats b/test/integration/discovery-token.bats new file mode 100644 index 0000000000..877954fbf9 --- /dev/null +++ b/test/integration/discovery-token.bats @@ -0,0 +1,39 @@ +#!/usr/bin/env bats + +load helpers + +TOKEN="" + +function token_cleanup() { + [ -z "$TOKEN" ] && return + echo "Removing $TOKEN" + curl -X DELETE "https://discovery-stage.hub.docker.com/v1/clusters/$TOKEN" +} + +function teardown() { + swarm_manage_cleanup + swarm_join_cleanup + stop_docker + token_cleanup +} + +@test "token discovery" { + # Create a cluster and validate the token. + run swarm create + [ "$status" -eq 0 ] + [[ "$output" =~ ^[0-9a-f]{32}$ ]] + TOKEN="$output" + + # Start 2 engines and make them join the cluster. + start_docker 2 + swarm_join "token://$TOKEN" + + # Start a manager and ensure it sees all the engines. + swarm_manage "token://$TOKEN" + check_swarm_nodes + + # Add another engine to the cluster and make sure it's picked up by swarm. + start_docker 1 + swarm_join "token://$TOKEN" + retry 10 1 check_swarm_nodes +} diff --git a/test/integration/discovery-zk.bats b/test/integration/discovery-zk.bats new file mode 100644 index 0000000000..638e929fc8 --- /dev/null +++ b/test/integration/discovery-zk.bats @@ -0,0 +1,45 @@ +#!/usr/bin/env bats + +load helpers + +# Address on which Zookeeper will listen (random port between 7000 and 8000). +ZK_HOST=127.0.0.1:$(( ( RANDOM % 1000 ) + 7000 )) + +# Container name for integration test +ZK_CONTAINER_NAME=swarm_integration_zk + +function start_zk() { + run docker_host run --name $ZK_CONTAINER_NAME -p $ZK_HOST:2181 -d jplock/zookeeper + [ "$status" -eq 0 ] +} + +function stop_zk() { + run docker_host rm -f -v $ZK_CONTAINER_NAME + [ "$status" -eq 0 ] +} + +function setup() { + start_zk +} + +function teardown() { + swarm_manage_cleanup + swarm_join_cleanup + stop_docker + stop_zk +} + +@test "zookeeper discovery" { + # Start 2 engines and make them join the cluster. + start_docker 2 + swarm_join "zk://${ZK_HOST}/test" + + # Start a manager and ensure it sees all the engines. + swarm_manage "zk://${ZK_HOST}/test" + check_swarm_nodes + + # Add another engine to the cluster and make sure it's picked up by swarm. + start_docker 1 + swarm_join "zk://${ZK_HOST}/test" + retry 30 1 check_swarm_nodes +} diff --git a/test/integration/file-discovery.bats b/test/integration/file-discovery.bats deleted file mode 100644 index d2ca80a658..0000000000 --- a/test/integration/file-discovery.bats +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bats - -load helpers - -# create a blank temp file for discovery -DISCOVERY_FILE=$(mktemp) - -function teardown() { - swarm_manage_cleanup - rm -f $DISCOVERY_FILE - stop_docker -} - -function setup_file_discovery() { - for host in ${HOSTS[@]}; do - echo "$host" >> $DISCOVERY_FILE - done -} - -@test "file discovery" { - start_docker 2 - setup_file_discovery - swarm_manage file://$DISCOVERY_FILE - - run docker_swarm info - [ "$status" -eq 0 ] - [[ "$output" == *"Nodes: 2"* ]] -} diff --git a/test/integration/helpers.bash b/test/integration/helpers.bash index 20263dc39a..dca57a68f3 100644 --- a/test/integration/helpers.bash +++ b/test/integration/helpers.bash @@ -75,7 +75,7 @@ function retry() { done echo "Command \"$@\" failed $attempts times. Output: $output" - [[ false ]] + false } # Waits until the given docker engine API becomes reachable. @@ -83,6 +83,11 @@ function wait_until_reachable() { retry 10 1 docker -H $1 info } +# Returns true if all nodes have joined the swarm. +function check_swarm_nodes() { + docker_swarm info | grep -q "Nodes: ${#HOSTS[@]}" +} + # Start the swarm manager in background. function swarm_manage() { local discovery @@ -92,32 +97,55 @@ function swarm_manage() { discovery="$@" fi - $SWARM_BINARY manage -H $SWARM_HOST $discovery & + "$SWARM_BINARY" manage -H "$SWARM_HOST" --heartbeat=1 "$discovery" & SWARM_PID=$! - wait_until_reachable $SWARM_HOST + wait_until_reachable "$SWARM_HOST" + retry 10 1 check_swarm_nodes } -# Start swarm join for every engine with the discovery as parameter +# swarm join every engine created with `start_docker`. +# +# It will wait until all nodes are visible in discovery (`swarm list`) before +# returning and will fail if that's not the case after a certain time. +# +# It can be called multiple times and will only join new engines started with +# `start_docker` since the last `swarm_join` call. function swarm_join() { - local i=0 - for h in ${HOSTS[@]}; do - echo "Swarm join #${i}: $h $@" - $SWARM_BINARY join --addr=$h "$@" & + local current=${#SWARM_JOIN_PID[@]} + local nodes=${#HOSTS[@]} + local addr="$1" + shift + + # Start the engines. + local i + echo "current: $current | nodes: $nodes" > log + for ((i=current; i < nodes; i++)); do + local h="${HOSTS[$i]}" + echo "Swarm join #${i}: $h $addr" + "$SWARM_BINARY" join --addr="$h" "$addr" & SWARM_JOIN_PID[$i]=$! - ((++i)) done - retry 30 1 [ -n "$(docker_swarm info | grep -q 'Nodes: $i')" ] + retry 10 0.5 check_discovery_nodes "$addr" +} + +# Returns true if all nodes have joined the discovery. +function check_discovery_nodes() { + local joined=`swarm list "$1" | wc -l` + local total=${#HOSTS[@]} + + echo "${joined} out of ${total} hosts joined discovery" + [ "$joined" -eq "$total" ] } # Stops the manager. function swarm_manage_cleanup() { - kill $SWARM_PID + kill $SWARM_PID || true } # Clean up Swarm join processes function swarm_join_cleanup() { for pid in ${SWARM_JOIN_PID[@]}; do - kill $pid + kill $pid || true done } @@ -148,7 +176,7 @@ function start_docker() { # Wait for the engines to be reachable. for ((i=current; i < (current + instances); i++)); do - wait_until_reachable ${HOSTS[$i]} + wait_until_reachable "${HOSTS[$i]}" done } diff --git a/test/integration/token-discovery.bats b/test/integration/token-discovery.bats deleted file mode 100644 index 126424ca20..0000000000 --- a/test/integration/token-discovery.bats +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bats - -load helpers - -function token_cleanup() { - curl -X DELETE https://discovery-stage.hub.docker.com/v1/clusters/$1 -} - -function teardown() { - swarm_join_cleanup - swarm_manage_cleanup - stop_docker -} - -@test "token discovery" { - start_docker 2 - - TOKEN=$(swarm create) - [ "$status" -eq 0 ] - [[ ${TOKEN} =~ ^[0-9a-f]{32}$ ]] - - swarm_manage token://$TOKEN - swarm_join token://$TOKEN - - run docker_swarm info - echo $output - [[ "$output" == *"Nodes: 2"* ]] - - token_cleanup $TOKEN -} diff --git a/test/integration/zk-discovery.bats b/test/integration/zk-discovery.bats deleted file mode 100644 index c21f3daed7..0000000000 --- a/test/integration/zk-discovery.bats +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env bats - -load helpers - -# Address on which Zookeeper will listen (random port between 7000 and 8000). -ZK_HOST=127.0.0.1:$(( ( RANDOM % 1000 ) + 7000 )) - -# Container name for integration test -ZK_CONTAINER_NAME=swarm_integration_zk - -function start_zk() { - docker_host run --name $ZK_CONTAINER_NAME -p $ZK_HOST:2181 -d jplock/zookeeper -} - -function stop_zk() { - docker_host rm -f -v $ZK_CONTAINER_NAME > /dev/null -} - -function teardown() { - swarm_join_cleanup - swarm_manage_cleanup - stop_docker - stop_zk -} - -@test "zk discovery" { - start_zk - start_docker 1 - - swarm_manage zk://${ZK_HOST}/test - swarm_join zk://${ZK_HOST}/test - - run docker_swarm info - [[ "$output" == *"Nodes: 1"* ]] -}