diff --git a/libnetwork/Makefile b/libnetwork/Makefile index 05b1249361..40079bd28f 100644 --- a/libnetwork/Makefile +++ b/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 \ diff --git a/libnetwork/client/service.go b/libnetwork/client/service.go index 6b37db4337..f2ecedddeb 100644 --- a/libnetwork/client/service.go +++ b/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 diff --git a/libnetwork/cmd/dnet/dnet.go b/libnetwork/cmd/dnet/dnet.go index ee114d80f6..989d3b12ca 100644 --- a/libnetwork/cmd/dnet/dnet.go +++ b/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) diff --git a/libnetwork/sandbox.go b/libnetwork/sandbox.go index b40d8a603e..40fc7f6de6 100644 --- a/libnetwork/sandbox.go +++ b/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) { diff --git a/libnetwork/test/integration/dnet/helpers.bash b/libnetwork/test/integration/dnet/helpers.bash index 7b89ddc78a..f0adf6eb40 100644 --- a/libnetwork/test/integration/dnet/helpers.bash +++ b/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="" - else - hport=$3 - cport=$3 - hopt="-H tcp://0.0.0.0:${cport}" - fi + 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 + labels="\"com.docker.network.driver.overlay.bind_interface=eth0\", \"com.docker.network.driver.overlay.neighbor_ip=${neighip}\"" + fi + mkdir -p /tmp/dnet/${name} tomlfile="/tmp/dnet/${name}/libnetwork.toml" cat > ${tomlfile} < ${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]