Browse code

Try other port on any error from Map

Sometimes other programs can bind on ports from our range, so we just
skip this ports on allocation.

Fixes #9293
Probably fixes #8714

Signed-off-by: Alexander Morozov <lk4d4@docker.com>

Alexandr Morozov authored on 2014/12/02 09:24:43
Showing 2 changed files
... ...
@@ -11,7 +11,6 @@ import (
11 11
 	log "github.com/Sirupsen/logrus"
12 12
 	"github.com/docker/docker/daemon/networkdriver"
13 13
 	"github.com/docker/docker/daemon/networkdriver/ipallocator"
14
-	"github.com/docker/docker/daemon/networkdriver/portallocator"
15 14
 	"github.com/docker/docker/daemon/networkdriver/portmapper"
16 15
 	"github.com/docker/docker/engine"
17 16
 	"github.com/docker/docker/nat"
... ...
@@ -468,22 +467,13 @@ func AllocatePort(job *engine.Job) engine.Status {
468 468
 		if host, err = portmapper.Map(container, ip, hostPort); err == nil {
469 469
 			break
470 470
 		}
471
-
472
-		if allocerr, ok := err.(portallocator.ErrPortAlreadyAllocated); ok {
473
-			// There is no point in immediately retrying to map an explicitly
474
-			// chosen port.
475
-			if hostPort != 0 {
476
-				job.Logf("Failed to bind %s for container address %s: %s", allocerr.IPPort(), container.String(), allocerr.Error())
477
-				break
478
-			}
479
-
480
-			// Automatically chosen 'free' port failed to bind: move on the next.
481
-			job.Logf("Failed to bind %s for container address %s. Trying another port.", allocerr.IPPort(), container.String())
482
-		} else {
483
-			// some other error during mapping
484
-			job.Logf("Received an unexpected error during port allocation: %s", err.Error())
471
+		// There is no point in immediately retrying to map an explicitly
472
+		// chosen port.
473
+		if hostPort != 0 {
474
+			job.Logf("Failed to allocate and map port %d: %s", hostPort, err)
485 475
 			break
486 476
 		}
477
+		job.Logf("Failed to allocate and map port: %s, retry: %d", err, i+1)
487 478
 	}
488 479
 
489 480
 	if err != nil {
... ...
@@ -2701,3 +2701,44 @@ func TestRunTLSverify(t *testing.T) {
2701 2701
 
2702 2702
 	logDone("run - verify tls is set for --tlsverify")
2703 2703
 }
2704
+
2705
+func TestRunPortFromDockerRangeInUse(t *testing.T) {
2706
+	defer deleteAllContainers()
2707
+	// first find allocator current position
2708
+	cmd := exec.Command(dockerBinary, "run", "-d", "-p", ":80", "busybox", "top")
2709
+	out, _, err := runCommandWithOutput(cmd)
2710
+	if err != nil {
2711
+		t.Fatal(out, err)
2712
+	}
2713
+	id := strings.TrimSpace(out)
2714
+	cmd = exec.Command(dockerBinary, "port", id)
2715
+	out, _, err = runCommandWithOutput(cmd)
2716
+	if err != nil {
2717
+		t.Fatal(out, err)
2718
+	}
2719
+	out = strings.TrimSpace(out)
2720
+	out = strings.Split(out, ":")[1]
2721
+	lastPort, err := strconv.Atoi(out)
2722
+	if err != nil {
2723
+		t.Fatal(err)
2724
+	}
2725
+	port := lastPort + 1
2726
+	l, err := net.Listen("tcp", ":"+strconv.Itoa(port))
2727
+	if err != nil {
2728
+		t.Fatal(err)
2729
+	}
2730
+	defer l.Close()
2731
+	cmd = exec.Command(dockerBinary, "run", "-d", "-p", ":80", "busybox", "top")
2732
+	out, _, err = runCommandWithOutput(cmd)
2733
+	if err != nil {
2734
+		t.Fatalf(out, err)
2735
+	}
2736
+	id = strings.TrimSpace(out)
2737
+	cmd = exec.Command(dockerBinary, "port", id)
2738
+	out, _, err = runCommandWithOutput(cmd)
2739
+	if err != nil {
2740
+		t.Fatal(out, err)
2741
+	}
2742
+
2743
+	logDone("run - find another port if port from autorange already bound")
2744
+}