1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge pull request #20239 from calavera/remove_server_port_allocation

Move listeners and port allocation outside the server.
This commit is contained in:
Alexander Morozov 2016-02-11 13:50:48 -08:00
commit 02a37a281c
5 changed files with 97 additions and 112 deletions

View file

@ -11,7 +11,6 @@ import (
"github.com/docker/docker/api/server/router" "github.com/docker/docker/api/server/router"
"github.com/docker/docker/pkg/authorization" "github.com/docker/docker/pkg/authorization"
"github.com/docker/docker/utils" "github.com/docker/docker/utils"
"github.com/docker/go-connections/sockets"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"golang.org/x/net/context" "golang.org/x/net/context"
) )
@ -29,7 +28,6 @@ type Config struct {
Version string Version string
SocketGroup string SocketGroup string
TLSConfig *tls.Config TLSConfig *tls.Config
Addrs []Addr
} }
// Server contains instance details for the server // Server contains instance details for the server
@ -41,27 +39,25 @@ type Server struct {
routerSwapper *routerSwapper routerSwapper *routerSwapper
} }
// Addr contains string representation of address and its protocol (tcp, unix...).
type Addr struct {
Proto string
Addr string
}
// New returns a new instance of the server based on the specified configuration. // New returns a new instance of the server based on the specified configuration.
// It allocates resources which will be needed for ServeAPI(ports, unix-sockets). // It allocates resources which will be needed for ServeAPI(ports, unix-sockets).
func New(cfg *Config) (*Server, error) { func New(cfg *Config) *Server {
s := &Server{ return &Server{
cfg: cfg, cfg: cfg,
} }
for _, addr := range cfg.Addrs { }
srv, err := s.newServer(addr.Proto, addr.Addr)
if err != nil { // Accept sets a listener the server accepts connections into.
return nil, err func (s *Server) Accept(addr string, listeners ...net.Listener) {
for _, listener := range listeners {
httpServer := &HTTPServer{
srv: &http.Server{
Addr: addr,
},
l: listener,
} }
logrus.Debugf("Server created for HTTP on %s (%s)", addr.Proto, addr.Addr) s.servers = append(s.servers, httpServer)
s.servers = append(s.servers, srv...)
} }
return s, nil
} }
// Close closes servers and thus stop receiving requests // Close closes servers and thus stop receiving requests
@ -126,19 +122,6 @@ func writeCorsHeaders(w http.ResponseWriter, r *http.Request, corsHeaders string
w.Header().Add("Access-Control-Allow-Methods", "HEAD, GET, POST, DELETE, PUT, OPTIONS") w.Header().Add("Access-Control-Allow-Methods", "HEAD, GET, POST, DELETE, PUT, OPTIONS")
} }
func (s *Server) initTCPSocket(addr string) (l net.Listener, err error) {
if s.cfg.TLSConfig == nil || s.cfg.TLSConfig.ClientAuth != tls.RequireAndVerifyClientCert {
logrus.Warn("/!\\ DON'T BIND ON ANY IP ADDRESS WITHOUT setting -tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\")
}
if l, err = sockets.NewTCPSocket(addr, s.cfg.TLSConfig); err != nil {
return nil, err
}
if err := allocateDaemonPort(addr); err != nil {
return nil, err
}
return
}
func (s *Server) makeHTTPHandler(handler httputils.APIFunc) http.HandlerFunc { func (s *Server) makeHTTPHandler(handler httputils.APIFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
// log the handler call // log the handler call

View file

@ -25,6 +25,7 @@ import (
"github.com/docker/docker/cliconfig" "github.com/docker/docker/cliconfig"
"github.com/docker/docker/daemon" "github.com/docker/docker/daemon"
"github.com/docker/docker/daemon/logger" "github.com/docker/docker/daemon/logger"
"github.com/docker/docker/docker/listeners"
"github.com/docker/docker/dockerversion" "github.com/docker/docker/dockerversion"
"github.com/docker/docker/opts" "github.com/docker/docker/opts"
"github.com/docker/docker/pkg/jsonlog" "github.com/docker/docker/pkg/jsonlog"
@ -233,6 +234,9 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
if len(cli.Config.Hosts) == 0 { if len(cli.Config.Hosts) == 0 {
cli.Config.Hosts = make([]string, 1) cli.Config.Hosts = make([]string, 1)
} }
api := apiserver.New(serverConfig)
for i := 0; i < len(cli.Config.Hosts); i++ { for i := 0; i < len(cli.Config.Hosts); i++ {
var err error var err error
if cli.Config.Hosts[i], err = opts.ParseHost(cli.Config.TLS, cli.Config.Hosts[i]); err != nil { if cli.Config.Hosts[i], err = opts.ParseHost(cli.Config.TLS, cli.Config.Hosts[i]); err != nil {
@ -244,12 +248,13 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
if len(protoAddrParts) != 2 { if len(protoAddrParts) != 2 {
logrus.Fatalf("bad format %s, expected PROTO://ADDR", protoAddr) logrus.Fatalf("bad format %s, expected PROTO://ADDR", protoAddr)
} }
serverConfig.Addrs = append(serverConfig.Addrs, apiserver.Addr{Proto: protoAddrParts[0], Addr: protoAddrParts[1]}) l, err := listeners.Init(protoAddrParts[0], protoAddrParts[1], serverConfig.SocketGroup, serverConfig.TLSConfig)
} if err != nil {
logrus.Fatal(err)
}
api, err := apiserver.New(serverConfig) logrus.Debugf("Listener created for HTTP on %s (%s)", protoAddrParts[0], protoAddrParts[1])
if err != nil { api.Accept(protoAddrParts[1], l...)
logrus.Fatal(err)
} }
if err := migrateKey(); err != nil { if err := migrateKey(); err != nil {

View file

@ -0,0 +1,22 @@
package listeners
import (
"crypto/tls"
"net"
"github.com/Sirupsen/logrus"
"github.com/docker/go-connections/sockets"
)
func initTCPSocket(addr string, tlsConfig *tls.Config) (l net.Listener, err error) {
if tlsConfig == nil || tlsConfig.ClientAuth != tls.RequireAndVerifyClientCert {
logrus.Warn("/!\\ DON'T BIND ON ANY IP ADDRESS WITHOUT setting -tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\")
}
if l, err = sockets.NewTCPSocket(addr, tlsConfig); err != nil {
return nil, err
}
if err := allocateDaemonPort(addr); err != nil {
return nil, err
}
return
}

View file

@ -1,42 +1,35 @@
// +build freebsd linux // +build !windows
package server package listeners
import ( import (
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"net" "net"
"net/http"
"strconv" "strconv"
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
"github.com/coreos/go-systemd/activation"
"github.com/docker/go-connections/sockets" "github.com/docker/go-connections/sockets"
"github.com/docker/libnetwork/portallocator" "github.com/docker/libnetwork/portallocator"
systemdActivation "github.com/coreos/go-systemd/activation"
) )
// newServer sets up the required HTTPServers and does protocol specific checking. // Init creates new listeners for the server.
// newServer does not set any muxers, you should set it later to Handler field func Init(proto, addr, socketGroup string, tlsConfig *tls.Config) (ls []net.Listener, err error) {
func (s *Server) newServer(proto, addr string) ([]*HTTPServer, error) {
var (
err error
ls []net.Listener
)
switch proto { switch proto {
case "fd": case "fd":
ls, err = listenFD(addr, s.cfg.TLSConfig) ls, err = listenFD(addr, tlsConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
case "tcp": case "tcp":
l, err := s.initTCPSocket(addr) l, err := initTCPSocket(addr, tlsConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ls = append(ls, l) ls = append(ls, l)
case "unix": case "unix":
l, err := sockets.NewUnixSocket(addr, s.cfg.SocketGroup) l, err := sockets.NewUnixSocket(addr, socketGroup)
if err != nil { if err != nil {
return nil, fmt.Errorf("can't create unix socket %s: %v", addr, err) return nil, fmt.Errorf("can't create unix socket %s: %v", addr, err)
} }
@ -44,43 +37,8 @@ func (s *Server) newServer(proto, addr string) ([]*HTTPServer, error) {
default: default:
return nil, fmt.Errorf("Invalid protocol format: %q", proto) return nil, fmt.Errorf("Invalid protocol format: %q", proto)
} }
var res []*HTTPServer
for _, l := range ls {
res = append(res, &HTTPServer{
&http.Server{
Addr: addr,
},
l,
})
}
return res, nil
}
func allocateDaemonPort(addr string) error { return
host, port, err := net.SplitHostPort(addr)
if err != nil {
return err
}
intPort, err := strconv.Atoi(port)
if err != nil {
return err
}
var hostIPs []net.IP
if parsedIP := net.ParseIP(host); parsedIP != nil {
hostIPs = append(hostIPs, parsedIP)
} else if hostIPs, err = net.LookupIP(host); err != nil {
return fmt.Errorf("failed to lookup %s address in host specification", host)
}
pa := portallocator.Get()
for _, hostIP := range hostIPs {
if _, err := pa.RequestPort(hostIP, "tcp", intPort); err != nil {
return fmt.Errorf("failed to allocate daemon listening port %d (err: %v)", intPort, err)
}
}
return nil
} }
// listenFD returns the specified socket activated files as a slice of // listenFD returns the specified socket activated files as a slice of
@ -92,9 +50,9 @@ func listenFD(addr string, tlsConfig *tls.Config) ([]net.Listener, error) {
) )
// socket activation // socket activation
if tlsConfig != nil { if tlsConfig != nil {
listeners, err = systemdActivation.TLSListeners(false, tlsConfig) listeners, err = activation.TLSListeners(false, tlsConfig)
} else { } else {
listeners, err = systemdActivation.Listeners(false) listeners, err = activation.Listeners(false)
} }
if err != nil { if err != nil {
return nil, err return nil, err
@ -130,3 +88,32 @@ func listenFD(addr string, tlsConfig *tls.Config) ([]net.Listener, error) {
} }
return []net.Listener{listeners[fdOffset]}, nil return []net.Listener{listeners[fdOffset]}, nil
} }
// allocateDaemonPort ensures that there are no containers
// that try to use any port allocated for the docker server.
func allocateDaemonPort(addr string) error {
host, port, err := net.SplitHostPort(addr)
if err != nil {
return err
}
intPort, err := strconv.Atoi(port)
if err != nil {
return err
}
var hostIPs []net.IP
if parsedIP := net.ParseIP(host); parsedIP != nil {
hostIPs = append(hostIPs, parsedIP)
} else if hostIPs, err = net.LookupIP(host); err != nil {
return fmt.Errorf("failed to lookup %s address in host specification", host)
}
pa := portallocator.Get()
for _, hostIP := range hostIPs {
if _, err := pa.RequestPort(hostIP, "tcp", intPort); err != nil {
return fmt.Errorf("failed to allocate daemon listening port %d (err: %v)", intPort, err)
}
}
return nil
}

View file

@ -1,24 +1,20 @@
// +build windows package listeners
package server
import ( import (
"crypto/tls"
"errors" "errors"
"fmt" "fmt"
"github.com/Microsoft/go-winio"
"net" "net"
"net/http"
"strings" "strings"
"github.com/Microsoft/go-winio"
) )
// NewServer sets up the required Server and does protocol specific checking. // Init creates new listeners for the server.
func (s *Server) newServer(proto, addr string) ([]*HTTPServer, error) { func Init(proto, addr, socketGroup string, tlsConfig *tls.Config) (ls []net.Listener, err error) {
var (
ls []net.Listener
)
switch proto { switch proto {
case "tcp": case "tcp":
l, err := s.initTCPSocket(addr) l, err := initTCPSocket(addr, tlsConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -27,8 +23,8 @@ func (s *Server) newServer(proto, addr string) ([]*HTTPServer, error) {
case "npipe": case "npipe":
// allow Administrators and SYSTEM, plus whatever additional users or groups were specified // allow Administrators and SYSTEM, plus whatever additional users or groups were specified
sddl := "D:P(A;;GA;;;BA)(A;;GA;;;SY)" sddl := "D:P(A;;GA;;;BA)(A;;GA;;;SY)"
if s.cfg.SocketGroup != "" { if socketGroup != "" {
for _, g := range strings.Split(s.cfg.SocketGroup, ",") { for _, g := range strings.Split(socketGroup, ",") {
sid, err := winio.LookupSidByName(g) sid, err := winio.LookupSidByName(g)
if err != nil { if err != nil {
return nil, err return nil, err
@ -46,19 +42,11 @@ func (s *Server) newServer(proto, addr string) ([]*HTTPServer, error) {
return nil, errors.New("Invalid protocol format. Windows only supports tcp and npipe.") return nil, errors.New("Invalid protocol format. Windows only supports tcp and npipe.")
} }
var res []*HTTPServer return
for _, l := range ls {
res = append(res, &HTTPServer{
&http.Server{
Addr: addr,
},
l,
})
}
return res, nil
} }
// allocateDaemonPort ensures that there are no containers
// that try to use any port allocated for the docker server.
func allocateDaemonPort(addr string) error { func allocateDaemonPort(addr string) error {
return nil return nil
} }