diff --git a/Makefile b/Makefile index 4d43d0675..2f270aaa0 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ docker/weave: curl -L git.io/weave -o docker/weave chmod u+x docker/weave -$(SCOPE_EXPORT): $(APP_EXE) $(PROBE_EXE) $(DOCKER_DISTRIB) docker/weave $(RUNSVINIT) docker/Dockerfile docker/run-app docker/run-probe +$(SCOPE_EXPORT): $(APP_EXE) $(PROBE_EXE) $(DOCKER_DISTRIB) docker/weave $(RUNSVINIT) docker/Dockerfile docker/run-app docker/run-probe docker/entrypoint.sh @if [ -z '$(DOCKER_SQUASH)' ] ; then echo "Please install docker-squash by running 'make deps' (and make sure GOPATH/bin is in your PATH)." && exit 1 ; fi cp $(APP_EXE) $(PROBE_EXE) docker/ cp $(DOCKER_DISTRIB) docker/docker.tgz diff --git a/docker/Dockerfile b/docker/Dockerfile index 783c35ccd..c794b56ce 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -3,7 +3,7 @@ MAINTAINER Weaveworks Inc LABEL works.weave.role=system WORKDIR /home/weave RUN echo "http://dl-4.alpinelinux.org/alpine/edge/testing" >>/etc/apk/repositories && \ - apk add --update runit conntrack-tools iproute2 util-linux && \ + apk add --update runit conntrack-tools iproute2 util-linux curl && \ rm -rf /var/cache/apk/* ADD ./docker.tgz / ADD ./weave /usr/bin/ diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index d6b919bc6..0181edb57 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -1,29 +1,63 @@ #!/bin/sh usage() { - echo "$0 --dns --hostname --searchpath --app.foo bar --probe.foo bar" + echo "$0 --app.foo bar --probe.foo bar" exit 1 } # This script exists to modify the network settings in the scope containers # as docker doesn't allow it when started with --net=host +WEAVE_CONTAINER_NAME=weave +DOCKER_BRIDGE=docker0 +HOSTNAME=scope +DOMAIN=weave.local +IP_REGEXP="[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" + +container_ip() { + if ! status=$(docker inspect --format='{{.State.Running}} {{.NetworkSettings.IPAddress}}' $1 2>/dev/null); then + echo "$2" >&2 + return 1 + fi + case "$status" in + "true ") + echo "$1 container has no IP address; is Docker networking enabled?" >&2 + return 1 + ;; + true*) + CONTAINER_IP="${status#true }" + ;; + *) + echo "$3" >&2 + return 1 + ;; + esac +} + +is_running() { + status=$(docker inspect --format='{{.State.Running}}' $1 2>/dev/null) && [ "$status" = "true" ] + return $? +} + +docker_bridge_ip() { + local DOCKER_BRIDGE_IP=$(ip -f inet address show dev $DOCKER_BRIDGE | grep -m1 -o 'inet \([.0-9]\)*') + echo ${DOCKER_BRIDGE_IP#inet } +} + +# Run `weave expose` if it's not already exposed. +weave_expose() { + status=$(weave --local ps weave:expose | awk '{print $3}' 2>/dev/null) + if [ "$status" = "" ]; then + weave --local expose + fi +} + mkdir -p /etc/weave APP_ARGS="" PROBE_ARGS="" while true; do case "$1" in - --dns) - [ $# -gt 1 ] || usage - DNS_SERVER="$2" - shift - ;; - --searchpath) - [ $# -gt 1 ] || usage - SEARCHPATH="$2" - shift - ;; --app.*) if echo "$1" | grep "=" 1>/dev/null; then ARG_NAME=$(echo "$1" | sed 's/\-\-app\.\([^=]*\)=\(.*\)/\1/') @@ -73,15 +107,34 @@ while true; do shift done +if is_running $WEAVE_CONTAINER_NAME; then + container_ip $WEAVE_CONTAINER_NAME + PROBE_ARGS="$PROBE_ARGS -weave.router.addr=$CONTAINER_IP" + weave_expose + + DOCKER_BRIDGE_IP=$(docker_bridge_ip) + echo "Weave container detected at $CONTAINER_IP, Docker bridge at $DOCKER_BRIDGE_IP" + + echo "domain $DOMAIN" >/etc/resolv.conf + echo "search $DOMAIN" >>/etc/resolv.conf + echo "nameserver $DOCKER_BRIDGE_IP" >>/etc/resolv.conf + + IP_ADDRS=$(find /sys/class/net -type l | xargs -n1 basename | grep -vE 'docker|veth|lo' | \ + xargs -n1 ip addr show | grep inet | awk '{ print $2 }' | grep -oE "$IP_REGEXP") + CONTAINER=$(docker inspect --format='{{.Id}}' weavescope) + if [ -z "$IP_ADDRS" ]; then + echo "Could not determine local IP address; Weave DNS integration will not work correctly." + exit 1 + else + for ip in $IP_ADDRS; do + weave --local dns-add $ip $CONTAINER -h $HOSTNAME.$DOMAIN + done + fi +fi + echo "$APP_ARGS" >/etc/weave/scope-app.args echo "$PROBE_ARGS" >/etc/weave/scope-probe.args -if [ -n "$DNS_SERVER" -a -n "$SEARCHPATH" ]; then - echo "domain $SEARCHPATH" >/etc/resolv.conf - echo "search $SEARCHPATH" >>/etc/resolv.conf - echo "nameserver $DNS_SERVER" >>/etc/resolv.conf -fi - # End of the command line can optionally be some # addresses of apps to connect to, for people not # using Weave DNS. We stick these in /etc/weave/apps diff --git a/integration/.gitignore b/integration/.gitignore index 56dedd820..a3fe6d263 100644 --- a/integration/.gitignore +++ b/integration/.gitignore @@ -1,3 +1,4 @@ insecure_private_key .vagrant .ssh_known_hosts +weave diff --git a/integration/100_launch_test.sh b/integration/100_launch_test.sh index aa308c3ec..a51935a9f 100755 --- a/integration/100_launch_test.sh +++ b/integration/100_launch_test.sh @@ -4,7 +4,13 @@ start_suite "Launch scope and check it boots" +weave_on $HOST1 launch scope_on $HOST1 launch -assert_raises "curl $HOST1:4040" -end_suite +sleep 5 # give the probe a few seconds to build a report and send it to the app + +has_container $HOST1 weave 1 +has_container $HOST1 weaveproxy 1 +has_container $HOST1 weavescope 1 + +scope_end_suite diff --git a/integration/105_launch_sans_weave_test.sh b/integration/105_launch_sans_weave_test.sh index 6f4987f5e..8c0c702ea 100755 --- a/integration/105_launch_sans_weave_test.sh +++ b/integration/105_launch_sans_weave_test.sh @@ -4,11 +4,12 @@ start_suite "Launch scope (without weave installed) and check it boots" -assert_raises "run_on $HOST1 \ - PATH=/usr/local/scope/bin:/usr/sbin:/usr/bin:/sbin:/bin \ - DOCKER_HOST=tcp://$HOST1:$DOCKER_PORT \ - scope launch" +scope_on $HOST1 launch -assert_raises "curl $HOST1:4040" +sleep 5 # give the probe a few seconds to build a report and send it to the app -end_suite +has_container $HOST1 weave 0 +has_container $HOST1 weaveproxy 0 +has_container $HOST1 weavescope 1 + +scope_end_suite diff --git a/integration/110_shutdown_test.sh b/integration/110_shutdown_test.sh index e39a61498..631df89cf 100755 --- a/integration/110_shutdown_test.sh +++ b/integration/110_shutdown_test.sh @@ -13,4 +13,4 @@ assert_raises "docker_on $HOST1 logs weavescope 2>&1 | grep 'app exiting'" assert_raises "docker_on $HOST1 logs weavescope 2>&1 | grep 'probe exiting'" assert_raises "docker_on $HOST1 inspect --format='{{.State.Running}}' weavescope" "false" -end_suite +scope_end_suite diff --git a/integration/200_clustering_2_test.sh b/integration/200_clustering_2_test.sh index e2bd9b75e..64b3310fe 100755 --- a/integration/200_clustering_2_test.sh +++ b/integration/200_clustering_2_test.sh @@ -2,24 +2,28 @@ . ./config.sh -start_suite "Launch 2 scopes and check they cluster" +start_suite "Launch 2 scopes and check they cluster automatically" -weave_on $HOST2 launch -weave_on $HOST2 launch-dns -docker_on $HOST2 run -dit --name db1 peterbourgon/tns-db -container_id=$(docker_on $HOST2 run -dit --name app1 --link db1:db1 peterbourgon/tns-app) +weave_on $HOST1 launch $HOST1 $HOST2 +weave_on $HOST2 launch $HOST1 $HOST2 -scope_on $HOST1 launch $HOST2 -scope_on $HOST2 launch $HOST1 +scope_on $HOST1 launch +scope_on $HOST2 launch -SUCCESS= -for i in {1..10}; do - if (curl -s $HOST1:4040/api/topology/containers | grep "$container_id" >/dev/null); then - SUCCESS=1 - break - fi - sleep 1 -done -assert "echo $SUCCESS" "1" +docker_on $HOST1 run -dit --name db1 peterbourgon/tns-db +docker_on $HOST2 run -dit --name db2 peterbourgon/tns-db -end_suite +sleep 30 # need to allow the scopes to poll dns, resolve the other app ids, and send them reports + +check() { + has_container $1 weave 2 + has_container $1 weaveproxy 2 + has_container $1 weavescope 2 + has_container $1 db1 1 + has_container $1 db2 1 +} + +check $HOST1 +check $HOST2 + +scope_end_suite diff --git a/integration/205_clustering_sans_weave_2_test.sh b/integration/205_clustering_sans_weave_2_test.sh new file mode 100755 index 000000000..0a929fece --- /dev/null +++ b/integration/205_clustering_sans_weave_2_test.sh @@ -0,0 +1,26 @@ +#! /bin/bash + +. ./config.sh + +start_suite "Launch 2 scopes and check they cluster (without weave)" + +scope_on $HOST1 launch $HOST1 $HOST2 +scope_on $HOST2 launch $HOST1 $HOST2 + +docker_on $HOST1 run -dit --name db1 peterbourgon/tns-db +docker_on $HOST2 run -dit --name db2 peterbourgon/tns-db + +sleep 30 # need to allow the scopes to poll dns, resolve the other app ids, and send them reports. + +check() { + has_container $1 weave 0 + has_container $1 weaveproxy 0 + has_container $1 weavescope 2 + has_container $1 db1 1 + has_container $1 db2 1 +} + +check $HOST1 +check $HOST2 + +scope_end_suite diff --git a/integration/config.sh b/integration/config.sh index c3f463624..84769111f 100644 --- a/integration/config.sh +++ b/integration/config.sh @@ -10,21 +10,38 @@ export HOSTS : ${WEAVE_REPO:=github.com/weaveworks/weave} : ${WEAVE_ROOT:="$(go list -e -f {{.Dir}} $WEAVE_REPO)"} +WEAVE="./weave" +SCOPE="../scope" RUNNER="$WEAVE_ROOT/testing/runner/runner" [ -x "$RUNNER" ] || (echo "Could not find weave test runner at $RUNNER." >&2 ; exit 1) . "$WEAVE_ROOT/test/config.sh" scope_on() { - host=$1 - shift 1 - [ -z "$DEBUG" ] || greyly echo "Scope on $host: $@" >&2 - run_on $host DOCKER_HOST=tcp://$host:$DOCKER_PORT scope "$@" + local host=$1 + shift 1 + [ -z "$DEBUG" ] || greyly echo "Scope on $host: $@" >&2 + DOCKER_HOST=tcp://$host:$DOCKER_PORT $SCOPE "$@" } weave_on() { - host=$1 - shift 1 - [ -z "$DEBUG" ] || greyly echo "Weave on $host: $@" >&2 - run_on $host DOCKER_HOST=tcp://$host:$DOCKER_PORT weave "$@" + local host=$1 + shift 1 + [ -z "$DEBUG" ] || greyly echo "Weave on $host: $@" >&2 + DOCKER_HOST=tcp://$host:$DOCKER_PORT $WEAVE "$@" +} + +# this checks we have a weavescope container +has_container() { + local host=$1 + local name=$2 + local count=$3 + assert "curl -s http://$host:4040/api/topology/containers?system=show | jq -r '[.nodes | .[] | select(.label_major == \"$name\")] | length'" $count +} + +scope_end_suite() { + end_suite + for host in $HOSTS; do + docker_on $host rm -f $(docker_on $host ps -a -q) 2>/dev/null 1>&2 || true + done } diff --git a/integration/gce.sh b/integration/gce.sh index a7cabe459..2c78a42de 100755 --- a/integration/gce.sh +++ b/integration/gce.sh @@ -5,6 +5,6 @@ set -e . ./config.sh export PROJECT=scope-integration-tests -export TEMPLATE_NAME="test-template-2" +export TEMPLATE_NAME="test-template-3" export NUM_HOSTS=2 . "$WEAVE_ROOT/test/gce.sh" "$@" diff --git a/integration/setup.sh b/integration/setup.sh index b4222bb32..53325d4c7 100755 --- a/integration/setup.sh +++ b/integration/setup.sh @@ -16,3 +16,11 @@ for HOST in $HOSTS; do run_on $HOST "sudo curl -sL git.io/weave -o /usr/local/bin/weave" run_on $HOST "sudo chmod a+x /usr/local/bin/weave" done + +echo Prefetching Images +for HOST in $HOSTS; do + weave_on $HOST setup + docker_on $HOST pull peterbourgon/tns-db +done + +curl -sL git.io/weave -o ./weave diff --git a/probe/resolver.go b/probe/resolver.go index 58119497a..8e8b90b79 100644 --- a/probe/resolver.go +++ b/probe/resolver.go @@ -10,6 +10,10 @@ import ( "github.com/weaveworks/scope/xfer" ) +const ( + dnsPollInterval = 10 * time.Second +) + var ( tick = time.Tick lookupIP = net.LookupIP @@ -40,7 +44,7 @@ func newStaticResolver(targets []string, set func(target string, endpoints []str func (r staticResolver) loop() { r.resolve() - t := tick(time.Minute) + t := tick(dnsPollInterval) for { select { case <-t: diff --git a/scope b/scope index 2fe04a231..7b72953c1 100755 --- a/scope +++ b/scope @@ -20,33 +20,15 @@ fi IMAGE_VERSION=${VERSION:-$IMAGE_VERSION} SCOPE_IMAGE=weaveworks/scope:$IMAGE_VERSION SCOPE_CONTAINER_NAME=weavescope -WEAVE_CONTAINER_NAME=weave -WEAVEDNS_CONTAINER_NAME=weavedns -HOSTNAME=scope -DOMAINNAME=weave.local -FQDN=$HOSTNAME.$DOMAINNAME -DOCKER_BRIDGE=${DOCKER_BRIDGE:-docker0} IP_REGEXP="[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" IP_ADDR_CMD="find /sys/class/net -type l | xargs -n1 basename | grep -vE 'docker|veth|lo' | \ xargs -n1 ip addr show | grep inet | awk '{ print \$2 }' | grep -oE '$IP_REGEXP'" - WEAVESCOPE_DOCKER_ARGS=${WEAVESCOPE_DOCKER_ARGS:-} -WEAVESCOPE_DNS_ARGS=${WEAVESCOPE_DNS_ARGS:-} [ $# -gt 0 ] || usage COMMAND=$1 shift 1 -# http://stackoverflow.com/questions/592620/how-to-check-if-a-program-exists-from-a-bash-script -command_exists() { - command -v $1 >/dev/null 2>&1 -} - -is_running() { - status=$(docker inspect --format='{{.State.Running}}' $1 2>/dev/null) && [ "$status" = "true" ] - return $? -} - # Check that a container named $1 with image $2 is not running check_not_running() { case $(docker inspect --format='{{.State.Running}} {{.Config.Image}}' $1 2>/dev/null) in @@ -75,113 +57,19 @@ check_not_running() { esac } -# Run `weave expose` if it's not already exposed. -weave_expose() { - status=$(weave ps weave:expose | awk '{print $3}' 2>/dev/null) - if [ "$status" = "" ]; then - weave expose - fi -} - -# Add all Scope IPs to its DNS record. -weave_dns_add() { - CONTAINER_ID="$1" - CONTAINER_FQDN="$2" - shift 2 - - for ip in $*; do - weave dns-add $ip $CONTAINER_ID -h $CONTAINER_FQDN - done -} - -weave_dns_present() { - docker run --rm --entrypoint /bin/sh $SCOPE_IMAGE -c "nc -z $DOCKER_BRIDGE_IP 53" || is_running $WEAVEDNS_CONTAINER_NAME -} - -set_docker_bridge_ip() { - DOCKER_BRIDGE_IP=$(docker run --rm --net=host --entrypoint /bin/sh $SCOPE_IMAGE -c "ip -f inet address show dev $DOCKER_BRIDGE" | grep -m1 -o 'inet \([.0-9]\)*') - DOCKER_BRIDGE_IP=${DOCKER_BRIDGE_IP#inet } -} - -# Call url $4 with http verb $3 on container $1 at port $2 -http_call() { - container_ip $1 \ - "$1 container is not present. Have you launched it?" \ - "$1 container is not running." \ - || return 1 - shift 1 - http_call_ip $CONTAINER_IP "$@" -} - -http_call_ip() { - ip="$1" - port="$2" - http_verb="$3" - url="$4" - shift 4 - curl --connect-timeout 3 -s -X $http_verb "$@" http://$ip:$port$url -} - -container_ip() { - if ! status=$(docker inspect --format='{{.State.Running}} {{.NetworkSettings.IPAddress}}' $1 2>/dev/null); then - echo "$2" >&2 - return 1 - fi - case "$status" in - "true ") - echo "$1 container has no IP address; is Docker networking enabled?" >&2 - return 1 - ;; - true*) - CONTAINER_IP="${status#true }" - ;; - *) - echo "$3" >&2 - return 1 - ;; - esac -} - case "$COMMAND" in launch) check_not_running $SCOPE_CONTAINER_NAME $SCOPE_IMAGE - set_docker_bridge_ip - - # If Weave is running, we want to expose a Weave IP to the host - # network namespace, so Scope can use it. - SCOPE_ARGS= - if command_exists weave && is_running $WEAVE_CONTAINER_NAME; then - container_ip $WEAVE_CONTAINER_NAME - SCOPE_ARGS="--probe.weave.router.addr=$CONTAINER_IP" - weave_expose - fi - - # If WeaveDNS is running, we want to automatically tell the scope - # image to use weave dns. We can't use --dns with --net=host, so we - # have to hack it. - if command_exists weave && weave_dns_present; then - WEAVESCOPE_DNS_ARGS="$WEAVESCOPE_DNS_ARGS --dns $DOCKER_BRIDGE_IP --searchpath $DOMAINNAME" - fi - docker rm -f $SCOPE_CONTAINER_NAME >/dev/null 2>&1 || true CONTAINER=$(docker run --privileged -d --name=$SCOPE_CONTAINER_NAME --net=host --pid=host \ -v /var/run/docker.sock:/var/run/docker.sock \ - $WEAVESCOPE_DOCKER_ARGS $SCOPE_IMAGE $WEAVESCOPE_DNS_ARGS $SCOPE_ARGS --probe.docker true "$@") - - IP_ADDRS=$(docker run --rm --net=host --entrypoint /bin/sh $SCOPE_IMAGE -c "$IP_ADDR_CMD") - if command_exists weave && is_running $WEAVE_CONTAINER_NAME && weave_dns_present; then - if [ -z "$IP_ADDRS" ]; then - echo "Could not determine local IP address; Weave DNS integration will not work correctly." - exit 1 - fi - weave_dns_add $CONTAINER $FQDN $IP_ADDRS - fi - + $WEAVESCOPE_DOCKER_ARGS $SCOPE_IMAGE --probe.docker true "$@") echo $CONTAINER if ! echo "$@" | grep -E "\-\-no\-app|\-\-service\-token" 1>/dev/null; then + IP_ADDRS=$(docker run --rm --net=host --entrypoint /bin/sh $SCOPE_IMAGE -c "$IP_ADDR_CMD") echo "Weave Scope is reachable at the following URL(s):" >&2 for ip in $IP_ADDRS; do echo " * http://$ip:4040/" >&2 diff --git a/xfer/multi_publisher.go b/xfer/multi_publisher.go index 532525600..899551861 100644 --- a/xfer/multi_publisher.go +++ b/xfer/multi_publisher.go @@ -123,6 +123,7 @@ func (p *MultiPublisher) Stop() { func (p *MultiPublisher) appendFilter(list []tuple, f func(tuple) bool) []tuple { for _, t := range p.list { if !f(t) { + t.publisher.Stop() continue } list = append(list, t)