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)
This commit is contained in:
Erik Hollensbe 2014-09-07 12:33:51 -07:00 коммит произвёл Alexandr Morozov
Родитель 3109fc9537
Коммит 3b6a29b81a
2 изменённых файлов: 65 добавлений и 11 удалений

Просмотреть файл

@ -100,11 +100,28 @@ func Map(container net.Addr, hostIP net.IP, hostPort int) (host net.Addr, err er
m.userlandProxy = proxy m.userlandProxy = proxy
currentMappings[key] = m currentMappings[key] = m
if err := proxy.Start(); err != nil { cleanup := func() error {
// need to undo the iptables rules before we return // need to undo the iptables rules before we return
forward(iptables.Delete, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort) 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 return m.host, nil

Просмотреть файл

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