Browse Source

Merge pull request #561 from mrjana/integ

Introduce end to end overlay integration test
Madhu Venugopal 9 năm trước cách đây
mục cha
commit
ffb13d6e8d

+ 1 - 1
libnetwork/Makefile

@@ -13,7 +13,7 @@ integration-tests: ./cmd/dnet/dnet
 	@./test/integration/dnet/run-integration-tests.sh
 
 ./cmd/dnet/dnet:
-	make build-local
+	make build
 
 clean:
 	@if [ -e ./cmd/dnet/dnet ]; then \

+ 8 - 5
libnetwork/client/service.go

@@ -236,21 +236,22 @@ func (cli *NetworkCli) CmdServiceLs(chain string, args ...string) error {
 	wr := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
 	// unless quiet (-q) is specified, print field titles
 	if !*quiet {
-		fmt.Fprintln(wr, "SERVICE ID\tNAME\tNETWORK\tCONTAINER")
+		fmt.Fprintln(wr, "SERVICE ID\tNAME\tNETWORK\tCONTAINER\tSANDBOX")
 	}
 
 	for _, sr := range serviceResources {
 		ID := sr.ID
-		bkID, err := getBackendID(cli, ID)
+		bkID, sbID, err := getBackendID(cli, ID)
 		if err != nil {
 			return err
 		}
 		if !*noTrunc {
 			ID = stringid.TruncateID(ID)
 			bkID = stringid.TruncateID(bkID)
+			sbID = stringid.TruncateID(sbID)
 		}
 		if !*quiet {
-			fmt.Fprintf(wr, "%s\t%s\t%s\t%s\n", ID, sr.Name, sr.Network, bkID)
+			fmt.Fprintf(wr, "%s\t%s\t%s\t%s\t%s\n", ID, sr.Name, sr.Network, bkID, sbID)
 		} else {
 			fmt.Fprintln(wr, ID)
 		}
@@ -260,24 +261,26 @@ func (cli *NetworkCli) CmdServiceLs(chain string, args ...string) error {
 	return nil
 }
 
-func getBackendID(cli *NetworkCli, servID string) (string, error) {
+func getBackendID(cli *NetworkCli, servID string) (string, string, error) {
 	var (
 		obj []byte
 		err error
 		bk  string
+		sb  string
 	)
 
 	if obj, _, err = readBody(cli.call("GET", "/services/"+servID+"/backend", nil, nil)); err == nil {
 		var sr SandboxResource
 		if err := json.NewDecoder(bytes.NewReader(obj)).Decode(&sr); err == nil {
 			bk = sr.ContainerID
+			sb = sr.ID
 		} else {
 			// Only print a message, don't make the caller cli fail for this
 			fmt.Fprintf(cli.out, "Failed to retrieve backend list for service %s (%v)\n", servID, err)
 		}
 	}
 
-	return bk, err
+	return bk, sb, err
 }
 
 // CmdServiceInfo handles service info UI

+ 17 - 0
libnetwork/cmd/dnet/dnet.go

@@ -9,7 +9,9 @@ import (
 	"net/http"
 	"net/http/httptest"
 	"os"
+	"os/signal"
 	"strings"
+	"syscall"
 
 	"github.com/codegangsta/cli"
 	"github.com/docker/docker/pkg/parsers"
@@ -165,9 +167,24 @@ func (d *dnetConnection) dnetDaemon(cfgFile string) error {
 	post.Methods("GET", "PUT", "POST", "DELETE").HandlerFunc(httpHandler)
 	post = r.PathPrefix("/sandboxes").Subrouter()
 	post.Methods("GET", "PUT", "POST", "DELETE").HandlerFunc(httpHandler)
+
+	handleSignals(controller)
+
 	return http.ListenAndServe(d.addr, r)
 }
 
+func handleSignals(controller libnetwork.NetworkController) {
+	c := make(chan os.Signal, 1)
+	signals := []os.Signal{os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT}
+	signal.Notify(c, signals...)
+	go func() {
+		for _ = range c {
+			controller.Stop()
+			os.Exit(0)
+		}
+	}()
+}
+
 func startTestDriver() error {
 	mux := http.NewServeMux()
 	server := httptest.NewServer(mux)

+ 39 - 15
libnetwork/sandbox.go

@@ -54,16 +54,15 @@ func (sb *sandbox) processOptions(options ...SandboxOption) {
 type epHeap []*endpoint
 
 type sandbox struct {
-	id          string
-	containerID string
-	config      containerConfig
-	osSbox      osl.Sandbox
-	controller  *controller
-	refCnt      int
-	endpoints   epHeap
-	epPriority  map[string]int
-	//hostsPath      string
-	//resolvConfPath string
+	id            string
+	containerID   string
+	config        containerConfig
+	osSbox        osl.Sandbox
+	controller    *controller
+	refCnt        int
+	hostsOnce     sync.Once
+	endpoints     epHeap
+	epPriority    map[string]int
 	joinLeaveDone chan struct{}
 	sync.Mutex
 }
@@ -460,22 +459,47 @@ func (sb *sandbox) buildHostsFile() error {
 }
 
 func (sb *sandbox) updateHostsFile(ifaceIP string, svcRecords []etchosts.Record) error {
+	var err error
+
 	if sb.config.originHostsPath != "" {
 		return nil
 	}
 
-	// Rebuild the hosts file accounting for the passed interface IP and service records
-	extraContent := make([]etchosts.Record, 0, len(sb.config.extraHosts)+len(svcRecords))
+	max := func(a, b int) int {
+		if a < b {
+			return b
+		}
 
-	for _, extraHost := range sb.config.extraHosts {
-		extraContent = append(extraContent, etchosts.Record{Hosts: extraHost.name, IP: extraHost.IP})
+		return a
 	}
 
+	extraContent := make([]etchosts.Record, 0,
+		max(len(sb.config.extraHosts), len(svcRecords)))
+
+	sb.hostsOnce.Do(func() {
+		// Rebuild the hosts file accounting for the passed
+		// interface IP and service records
+
+		for _, extraHost := range sb.config.extraHosts {
+			extraContent = append(extraContent,
+				etchosts.Record{Hosts: extraHost.name, IP: extraHost.IP})
+		}
+
+		err = etchosts.Build(sb.config.hostsPath, ifaceIP,
+			sb.config.hostName, sb.config.domainName, extraContent)
+	})
+
+	if err != nil {
+		return err
+	}
+
+	extraContent = extraContent[:0]
 	for _, svc := range svcRecords {
 		extraContent = append(extraContent, svc)
 	}
 
-	return etchosts.Build(sb.config.hostsPath, ifaceIP, sb.config.hostName, sb.config.domainName, extraContent)
+	sb.addHostsEntries(extraContent)
+	return nil
 }
 
 func (sb *sandbox) addHostsEntries(recs []etchosts.Record) {

+ 49 - 12
libnetwork/test/integration/dnet/helpers.bash

@@ -28,20 +28,40 @@ function stop_consul() {
 }
 
 function start_dnet() {
-    stop_dnet $1 $2
-    name=$(dnet_container_name $1 $2)
-    if [ -z "$3" ]
-    then
-	hport=$((41000+${1}-1))
-	cport=2385
-	hopt=""
+    inst=$1
+    shift
+    suffix=$1
+    shift
+
+    stop_dnet ${inst} ${suffix}
+    name=$(dnet_container_name ${inst} ${suffix})
+
+    hport=$((41000+${inst}-1))
+    cport=2385
+    hopt=""
+    isnum='^[0-9]+$'
+
+    while [ -n "$1" ]
+    do
+	if [[ "$1" =~ ^[0-9]+$ ]]
+	then
+	    hport=$1
+	    cport=$1
+	    hopt="-H tcp://0.0.0.0:${cport}"
+	else
+	    neighip=$1
+	fi
+	shift
+    done
+
+    bridge_ip=$(docker inspect --format '{{.NetworkSettings.Gateway}}' pr_consul)
+
+    if [ -z "$neighip" ]; then
+	labels="\"com.docker.network.driver.overlay.bind_interface=eth0\""
     else
-	hport=$3
-	cport=$3
-	hopt="-H tcp://0.0.0.0:${cport}"
+	labels="\"com.docker.network.driver.overlay.bind_interface=eth0\", \"com.docker.network.driver.overlay.neighbor_ip=${neighip}\""
     fi
 
-    bridge_ip=$(docker inspect --format '{{.NetworkSettings.Gateway}}' pr_consul)
     mkdir -p /tmp/dnet/${name}
     tomlfile="/tmp/dnet/${name}/libnetwork.toml"
     cat > ${tomlfile} <<EOF
@@ -49,13 +69,14 @@ title = "LibNetwork Configuration file"
 
 [daemon]
   debug = false
-  labels = ["com.docker.network.driver.overlay.bind_interface=eth0"]
+  labels = [${labels}]
 [globalstore]
   embedded = false
 [globalstore.client]
   provider = "consul"
   Address = "${bridge_ip}:8500"
 EOF
+    echo "parsed values: " ${name} ${hport} ${cport} ${hopt}
     docker run \
 	   -d \
 	   --name=${name}  \
@@ -63,6 +84,8 @@ EOF
 	   -p ${hport}:${cport} \
 	   -v $(pwd)/:/go/src/github.com/docker/libnetwork \
 	   -v /tmp:/tmp \
+	   -v $(pwd)/${TMPC_ROOT}:/scratch \
+	   -v /usr/local/bin/runc:/usr/local/bin/runc \
 	   -w /go/src/github.com/docker/libnetwork \
 	   golang:1.4 ./cmd/dnet/dnet -d -D ${hopt} -c ${tomlfile}
     sleep 2
@@ -89,3 +112,17 @@ function dnet_cmd() {
     shift
     ./cmd/dnet/dnet -H tcp://127.0.0.1:${hport} $*
 }
+
+function dnet_exec() {
+    docker exec -it ${1} bash -c "$2"
+}
+
+function runc() {
+    dnet=${1}
+    shift
+    dnet_exec ${dnet} "cp /var/lib/docker/network/files/${1}*/* /scratch/rootfs/etc"
+    dnet_exec ${dnet} "mkdir -p /var/run/netns"
+    dnet_exec ${dnet} "touch /var/run/netns/c && mount -o bind /var/run/docker/netns/${1} /var/run/netns/c"
+    dnet_exec ${dnet} "ip netns exec c unshare -fmuip --mount-proc chroot \"/scratch/rootfs\" /bin/sh -c \"/bin/mount -t proc proc /proc && ${2}\""
+    dnet_exec ${dnet} "umount /var/run/netns/c && rm /var/run/netns/c"
+}

+ 49 - 0
libnetwork/test/integration/dnet/overlay.bats

@@ -0,0 +1,49 @@
+# -*- mode: sh -*-
+#!/usr/bin/env bats
+
+load helpers
+
+@test "Test overlay network" {
+    skip_for_circleci
+
+    echo $(docker ps)
+
+    start=1
+    end=3
+    # Setup overlay network and connect containers ot it
+    dnet_cmd $(inst_id2port 1) network create -d overlay multihost
+    for i in `seq ${start} ${end}`;
+    do
+	osvc="svc$i"
+	dnet_cmd $(inst_id2port $i) service publish ${osvc}.multihost
+	dnet_cmd $(inst_id2port $i) container create container_${i}
+	dnet_cmd $(inst_id2port $i) service attach container_${i} ${osvc}.multihost
+    done
+
+    # Now test connectivity between all the containers using service names
+    for i in `seq ${start} ${end}`;
+    do
+	src="svc$i"
+	line=$(dnet_cmd $(inst_id2port $i) service ls | grep ${src})
+	echo ${line}
+	sbid=$(echo ${line} | cut -d" " -f5)
+	for j in `seq ${start} ${end}`;
+	do
+	    if [ "$i" -eq "$j" ]; then
+		continue
+	    fi
+	    runc $(dnet_container_name $i overlay) ${sbid} "ping -c 1 svc$j"
+	done
+    done
+
+    # Teardown the container connections and the network
+    for i in `seq ${start} ${end}`;
+    do
+	osvc="svc$i"
+	dnet_cmd $(inst_id2port $i) service detach container_${i} ${osvc}.multihost
+	dnet_cmd $(inst_id2port $i) container rm container_${i}
+	dnet_cmd $(inst_id2port $i) service unpublish ${osvc}.multihost
+    done
+
+    run dnet_cmd $(inst_id2port 2) network rm multihost
+}

+ 43 - 13
libnetwork/test/integration/dnet/run-integration-tests.sh

@@ -2,12 +2,23 @@
 
 set -e
 
-if [ ! -d ./integration-tmp ]; then
-    mkdir -p ./integration-tmp
-    git clone https://github.com/sstephenson/bats.git ./integration-tmp/bats
+export INTEGRATION_ROOT=./integration-tmp
+export TMPC_ROOT=./integration-tmp/tmpc
+
+if [ ! -d ${INTEGRATION_ROOT} ]; then
+    mkdir -p ${INTEGRATION_ROOT}
+    git clone https://github.com/sstephenson/bats.git ${INTEGRATION_ROOT}/bats
     ./integration-tmp/bats/install.sh ./integration-tmp
 fi
 
+if [ ! -d ${TMPC_ROOT} ]; then
+    mkdir -p ${TMPC_ROOT}
+    docker pull busybox:ubuntu
+    docker export $(docker create busybox:ubuntu) > ${TMPC_ROOT}/busybox.tar
+    mkdir -p ${TMPC_ROOT}/rootfs
+    tar -C ${TMPC_ROOT}/rootfs -xf ${TMPC_ROOT}/busybox.tar
+fi
+
 declare -A cmap
 
 trap "cleanup_containers" EXIT SIGINT
@@ -27,7 +38,7 @@ function cleanup_containers() {
 source ./test/integration/dnet/helpers.bash
 
 # Suite setup
-start_consul 1>/dev/null 2>&1
+start_consul 1>>${INTEGRATION_ROOT}/test.log 2>&1
 cmap[pr_consul]=pr_consul
 
 # Test dnet configuration options
@@ -36,37 +47,56 @@ cmap[pr_consul]=pr_consul
 # Test a single node configuration with a global scope test driver
 
 ## Setup
-start_dnet 1 simple 1>/dev/null 2>&1
+start_dnet 1 simple 1>>${INTEGRATION_ROOT}/test.log 2>&1
 cmap[dnet-1-simple]=dnet-1-simple
 
 ## Run the test cases
 ./integration-tmp/bin/bats ./test/integration/dnet/simple.bats
 
 ## Teardown
-stop_dnet 1 simple 1>/dev/null 2>&1
+stop_dnet 1 simple 1>>${INTEGRATION_ROOT}/test.log 2>&1
 unset cmap[dnet-1-simple]
 
 # Test multi node configuration with a global scope test driver
 
 ## Setup
-start_dnet 1 multi 1>/dev/null 2>&1
+start_dnet 1 multi 1>>${INTEGRATION_ROOT}/test.log 2>&1
 cmap[dnet-1-multi]=dnet-1-multi
-start_dnet 2 multi 1>/dev/null 2>&1
+start_dnet 2 multi 1>>${INTEGRATION_ROOT}/test.log 2>&1
 cmap[dnet-2-multi]=dnet-2-multi
-start_dnet 3 multi 1>/dev/null 2>&1
+start_dnet 3 multi 1>>${INTEGRATION_ROOT}/test.log 2>&1
 cmap[dnet-3-multi]=dnet-3-multi
 
 ## Run the test cases
 ./integration-tmp/bin/bats ./test/integration/dnet/multi.bats
 
 ## Teardown
-stop_dnet 1 multi 1>/dev/null 2>&1
+stop_dnet 1 multi 1>>${INTEGRATION_ROOT}/test.log 2>&1
 unset cmap[dnet-1-multi]
-stop_dnet 2 multi 1>/dev/null 2>&1
+stop_dnet 2 multi 1>>${INTEGRATION_ROOT}/test.log 2>&1
 unset cmap[dnet-2-multi]
-stop_dnet 3 multi 1>/dev/null 2>&1
+stop_dnet 3 multi 1>>${INTEGRATION_ROOT}/test.log 2>&1
 unset cmap[dnet-3-multi]
 
+## Setup
+start_dnet 1 overlay 1>>${INTEGRATION_ROOT}/test.log 2>&1
+cmap[dnet-1-overlay]=dnet-1-overlay
+start_dnet 2 overlay $(docker inspect --format '{{.NetworkSettings.IPAddress}}' dnet-1-overlay) 1>>${INTEGRATION_ROOT}/test.log 2>&1
+cmap[dnet-2-overlay]=dnet-2-overlay
+start_dnet 3 overlay $(docker inspect --format '{{.NetworkSettings.IPAddress}}' dnet-2-overlay) 1>>${INTEGRATION_ROOT}/test.log 2>&1
+cmap[dnet-3-overlay]=dnet-3-overlay
+
+## Run the test cases
+./integration-tmp/bin/bats ./test/integration/dnet/overlay.bats
+
+## Teardown
+stop_dnet 1 overlay 1>>${INTEGRATION_ROOT}/test.log 2>&1
+unset cmap[dnet-1-overlay]
+stop_dnet 2 overlay 1>>${INTEGRATION_ROOT}/test.log 2>&1
+unset cmap[dnet-2-overlay]
+stop_dnet 3 overlay 1>>${INTEGRATION_ROOT}/test.log 2>&1
+unset cmap[dnet-3-overlay]
+
 # Suite teardowm
-stop_consul 1>/dev/null 2>&1
+stop_consul 1>>${INTEGRATION_ROOT}/test.log 2>&1
 unset cmap[pr_consul]