Ver código fonte

Fix an issue where already allocated ports would not trigger an error.

Docker-DCO-1.1-Signed-off-by: Erik Hollensbe <github@hollensbe.org> (github: erikh)
Erik Hollensbe 10 anos atrás
pai
commit
3b6a29b81a

+ 19 - 2
daemon/networkdriver/portmapper/mapper.go

@@ -100,11 +100,28 @@ func Map(container net.Addr, hostIP net.IP, hostPort int) (host net.Addr, err er
 	m.userlandProxy = proxy
 	currentMappings[key] = m
 
-	if err := proxy.Start(); err != nil {
+	cleanup := func() error {
 		// need to undo the iptables rules before we return
 		forward(iptables.Delete, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort)
+		proxy.Stop()
+		forward(iptables.Delete, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort)
+		m.userlandProxy = nil
+		delete(currentMappings, key)
+		if err := portallocator.ReleasePort(hostIP, m.proto, allocatedHostPort); err != nil {
+			return err
+		}
 
-		return nil, err
+		return nil
+	}
+
+	if err := proxy.Start(); err != nil {
+		if err := cleanup(); err != nil {
+			return nil, fmt.Errorf("Error during port allocation cleanup: %v", err)
+		}
+
+		if err == ErrPortMappingFailure {
+			return nil, portallocator.NewErrPortAlreadyAllocated(hostIP.String(), allocatedHostPort)
+		}
 	}
 
 	return m.host, nil

+ 46 - 9
daemon/networkdriver/portmapper/proxy.go

@@ -1,6 +1,7 @@
 package portmapper
 
 import (
+	"errors"
 	"flag"
 	"log"
 	"net"
@@ -9,11 +10,14 @@ import (
 	"os/signal"
 	"strconv"
 	"syscall"
+	"time"
 
 	"github.com/docker/docker/pkg/proxy"
 	"github.com/docker/docker/reexec"
 )
 
+var ErrPortMappingFailure = errors.New("Failure Mapping Port")
+
 const userlandProxyCommandName = "docker-proxy"
 
 func init() {
@@ -37,9 +41,12 @@ func execProxy() {
 
 	p, err := proxy.NewProxy(host, container)
 	if err != nil {
-		log.Fatal(err)
+		os.Stdout.WriteString("1\n")
+		os.Exit(1)
 	}
 
+	os.Stdout.WriteString("0\n")
+
 	go handleStopSignals(p)
 
 	// Run will block until the proxy stops
@@ -96,10 +103,8 @@ func NewProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.
 
 	return &proxyCommand{
 		cmd: &exec.Cmd{
-			Path:   reexec.Self(),
-			Args:   args,
-			Stdout: os.Stdout,
-			Stderr: os.Stderr,
+			Path: reexec.Self(),
+			Args: args,
 			SysProcAttr: &syscall.SysProcAttr{
 				Pdeathsig: syscall.SIGTERM, // send a sigterm to the proxy if the daemon process dies
 			},
@@ -108,12 +113,44 @@ func NewProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.
 }
 
 func (p *proxyCommand) Start() error {
-	return p.cmd.Start()
+	stdout, err := p.cmd.StdoutPipe()
+	if err != nil {
+		return err
+	}
+	if err := p.cmd.Start(); err != nil {
+		return err
+	}
+
+	errchan := make(chan error)
+	after := time.After(1 * time.Second)
+	go func() {
+		buf := make([]byte, 2)
+		stdout.Read(buf)
+
+		if string(buf) != "0\n" {
+			errchan <- ErrPortMappingFailure
+		} else {
+			errchan <- nil
+		}
+	}()
+
+	var readErr error
+
+	select {
+	case readErr = <-errchan:
+	case <-after:
+		readErr = ErrPortMappingFailure
+	}
+
+	return readErr
 }
 
 func (p *proxyCommand) Stop() error {
-	err := p.cmd.Process.Signal(os.Interrupt)
-	p.cmd.Wait()
+	if p.cmd.Process != nil {
+		err := p.cmd.Process.Signal(os.Interrupt)
+		p.cmd.Wait()
+		return err
+	}
 
-	return err
+	return nil
 }