mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
dafddf461e
Port allocation status is stored in a global map: a port detected in use will remain as such for the lifetime of the daemon. Change the behavior to only mark as allocated ports which are claimed by Docker itself (which we can trust to properly remove from the allocation map once released). Ports allocated by other applications will always be retried to account for the eventually of the port having been released. Docker-DCO-1.1-Signed-off-by: Arnaud Porterie <icecrime@gmail.com> (github: icecrime)
106 lines
2.6 KiB
Go
106 lines
2.6 KiB
Go
package bridge
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"strconv"
|
|
"testing"
|
|
|
|
"github.com/dotcloud/docker/engine"
|
|
)
|
|
|
|
func findFreePort(t *testing.T) int {
|
|
l, err := net.Listen("tcp", ":0")
|
|
if err != nil {
|
|
t.Fatal("Failed to find a free port")
|
|
}
|
|
defer l.Close()
|
|
|
|
result, err := net.ResolveTCPAddr("tcp", l.Addr().String())
|
|
if err != nil {
|
|
t.Fatal("Failed to resolve address to identify free port")
|
|
}
|
|
return result.Port
|
|
}
|
|
|
|
func newPortAllocationJob(eng *engine.Engine, port int) (job *engine.Job) {
|
|
strPort := strconv.Itoa(port)
|
|
|
|
job = eng.Job("allocate_port", "container_id")
|
|
job.Setenv("HostIP", "127.0.0.1")
|
|
job.Setenv("HostPort", strPort)
|
|
job.Setenv("Proto", "tcp")
|
|
job.Setenv("ContainerPort", strPort)
|
|
return
|
|
}
|
|
|
|
func TestAllocatePortDetection(t *testing.T) {
|
|
eng := engine.New()
|
|
eng.Logging = false
|
|
|
|
freePort := findFreePort(t)
|
|
|
|
// Init driver
|
|
job := eng.Job("initdriver")
|
|
if res := InitDriver(job); res != engine.StatusOK {
|
|
t.Fatal("Failed to initialize network driver")
|
|
}
|
|
|
|
// Allocate interface
|
|
job = eng.Job("allocate_interface", "container_id")
|
|
if res := Allocate(job); res != engine.StatusOK {
|
|
t.Fatal("Failed to allocate network interface")
|
|
}
|
|
|
|
// Allocate same port twice, expect failure on second call
|
|
job = newPortAllocationJob(eng, freePort)
|
|
if res := AllocatePort(job); res != engine.StatusOK {
|
|
t.Fatal("Failed to find a free port to allocate")
|
|
}
|
|
if res := AllocatePort(job); res == engine.StatusOK {
|
|
t.Fatal("Duplicate port allocation granted by AllocatePort")
|
|
}
|
|
}
|
|
|
|
func TestAllocatePortReclaim(t *testing.T) {
|
|
eng := engine.New()
|
|
eng.Logging = false
|
|
|
|
freePort := findFreePort(t)
|
|
|
|
// Init driver
|
|
job := eng.Job("initdriver")
|
|
if res := InitDriver(job); res != engine.StatusOK {
|
|
t.Fatal("Failed to initialize network driver")
|
|
}
|
|
|
|
// Allocate interface
|
|
job = eng.Job("allocate_interface", "container_id")
|
|
if res := Allocate(job); res != engine.StatusOK {
|
|
t.Fatal("Failed to allocate network interface")
|
|
}
|
|
|
|
// Occupy port
|
|
listenAddr := fmt.Sprintf(":%d", freePort)
|
|
tcpListenAddr, err := net.ResolveTCPAddr("tcp", listenAddr)
|
|
if err != nil {
|
|
t.Fatalf("Failed to resolve TCP address '%s'", listenAddr)
|
|
}
|
|
|
|
l, err := net.ListenTCP("tcp", tcpListenAddr)
|
|
if err != nil {
|
|
t.Fatalf("Fail to listen on port %d", freePort)
|
|
}
|
|
|
|
// Allocate port, expect failure
|
|
job = newPortAllocationJob(eng, freePort)
|
|
if res := AllocatePort(job); res == engine.StatusOK {
|
|
t.Fatal("Successfully allocated currently used port")
|
|
}
|
|
|
|
// Reclaim port, retry allocation
|
|
l.Close()
|
|
if res := AllocatePort(job); res != engine.StatusOK {
|
|
t.Fatal("Failed to allocate previously reclaimed port")
|
|
}
|
|
}
|