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:
commit
02a37a281c
5 changed files with 97 additions and 112 deletions
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
22
docker/listeners/listeners.go
Normal file
22
docker/listeners/listeners.go
Normal 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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
}
|
}
|
Loading…
Reference in a new issue