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

Merge pull request #16769 from LK4D4/fix_volume_socket

Allocate resources for server API before daemon creation
This commit is contained in:
Vincent Demeester 2015-10-05 20:48:41 +02:00
commit 80f2e3f0c6
5 changed files with 56 additions and 47 deletions

View file

@ -2,7 +2,6 @@ package server
import ( import (
"crypto/tls" "crypto/tls"
"fmt"
"net" "net"
"net/http" "net/http"
"os" "os"
@ -28,22 +27,39 @@ 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
type Server struct { type Server struct {
cfg *Config cfg *Config
start chan struct{} start chan struct{}
servers []serverCloser servers []*HTTPServer
routers []router.Router routers []router.Router
} }
// 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.
func New(cfg *Config) *Server { // It allocates resources which will be needed for ServeAPI(ports, unix-sockets).
return &Server{ func New(cfg *Config) (*Server, error) {
s := &Server{
cfg: cfg, cfg: cfg,
start: make(chan struct{}), start: make(chan struct{}),
} }
for _, addr := range cfg.Addrs {
srv, err := s.newServer(addr.Proto, addr.Addr)
if err != nil {
return nil, err
}
logrus.Debugf("Server created for HTTP on %s (%s)", addr.Proto, addr.Addr)
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
@ -55,39 +71,23 @@ func (s *Server) Close() {
} }
} }
type serverCloser interface { // ServeAPI loops through all initialized servers and spawns goroutine
Serve() error // with Server method for each. It sets CreateMux() as Handler also.
Close() error func (s *Server) ServeAPI() error {
} var chErrors = make(chan error, len(s.servers))
for _, srv := range s.servers {
// ServeAPI loops through all of the protocols sent in to docker and spawns srv.srv.Handler = s.CreateMux()
// off a go routine to setup a serving http.Server for each. go func(srv *HTTPServer) {
func (s *Server) ServeAPI(protoAddrs []string) error { var err error
var chErrors = make(chan error, len(protoAddrs)) logrus.Errorf("API listen on %s", srv.l.Addr())
if err = srv.Serve(); err != nil && strings.Contains(err.Error(), "use of closed network connection") {
for _, protoAddr := range protoAddrs { err = nil
protoAddrParts := strings.SplitN(protoAddr, "://", 2) }
if len(protoAddrParts) != 2 { chErrors <- err
return fmt.Errorf("bad format, expected PROTO://ADDR") }(srv)
}
srv, err := s.newServer(protoAddrParts[0], protoAddrParts[1])
if err != nil {
return err
}
s.servers = append(s.servers, srv...)
for _, s := range srv {
logrus.Infof("Listening for HTTP on %s (%s)", protoAddrParts[0], protoAddrParts[1])
go func(s serverCloser) {
if err := s.Serve(); err != nil && strings.Contains(err.Error(), "use of closed network connection") {
err = nil
}
chErrors <- err
}(s)
}
} }
for i := 0; i < len(protoAddrs); i++ { for i := 0; i < len(s.servers); i++ {
err := <-chErrors err := <-chErrors
if err != nil { if err != nil {
return err return err

View file

@ -14,8 +14,9 @@ import (
systemdActivation "github.com/coreos/go-systemd/activation" systemdActivation "github.com/coreos/go-systemd/activation"
) )
// newServer sets up the required serverClosers and does protocol specific checking. // newServer sets up the required HTTPServers and does protocol specific checking.
func (s *Server) newServer(proto, addr string) ([]serverCloser, error) { // newServer does not set any muxers, you should set it later to Handler field
func (s *Server) newServer(proto, addr string) ([]*HTTPServer, error) {
var ( var (
err error err error
ls []net.Listener ls []net.Listener
@ -45,12 +46,11 @@ func (s *Server) newServer(proto, addr string) ([]serverCloser, error) {
default: default:
return nil, fmt.Errorf("Invalid protocol format: %q", proto) return nil, fmt.Errorf("Invalid protocol format: %q", proto)
} }
var res []serverCloser var res []*HTTPServer
for _, l := range ls { for _, l := range ls {
res = append(res, &HTTPServer{ res = append(res, &HTTPServer{
&http.Server{ &http.Server{
Addr: addr, Addr: addr,
Handler: s.CreateMux(),
}, },
l, l,
}) })

View file

@ -9,7 +9,7 @@ import (
) )
// NewServer sets up the required Server and does protocol specific checking. // NewServer sets up the required Server and does protocol specific checking.
func (s *Server) newServer(proto, addr string) ([]serverCloser, error) { func (s *Server) newServer(proto, addr string) ([]*HTTPServer, error) {
var ( var (
ls []net.Listener ls []net.Listener
) )
@ -25,12 +25,11 @@ func (s *Server) newServer(proto, addr string) ([]serverCloser, error) {
return nil, errors.New("Invalid protocol format. Windows only supports tcp.") return nil, errors.New("Invalid protocol format. Windows only supports tcp.")
} }
var res []serverCloser var res []*HTTPServer
for _, l := range ls { for _, l := range ls {
res = append(res, &HTTPServer{ res = append(res, &HTTPServer{
&http.Server{ &http.Server{
Addr: addr, Addr: addr,
Handler: s.CreateMux(),
}, },
l, l,
}) })

View file

@ -223,6 +223,17 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
} }
serverConfig.TLSConfig = tlsConfig serverConfig.TLSConfig = tlsConfig
} }
for _, protoAddr := range commonFlags.Hosts {
protoAddrParts := strings.SplitN(protoAddr, "://", 2)
if len(protoAddrParts) != 2 {
logrus.Fatalf("bad format %s, expected PROTO://ADDR", protoAddr)
}
serverConfig.Addrs = append(serverConfig.Addrs, apiserver.Addr{Proto: protoAddrParts[0], Addr: protoAddrParts[1]})
}
api, err := apiserver.New(serverConfig)
if err != nil {
logrus.Fatal(err)
}
if err := migrateKey(); err != nil { if err := migrateKey(); err != nil {
logrus.Fatal(err) logrus.Fatal(err)
@ -249,7 +260,6 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
"graphdriver": d.GraphDriver().String(), "graphdriver": d.GraphDriver().String(),
}).Info("Docker daemon") }).Info("Docker daemon")
api := apiserver.New(serverConfig)
api.InitRouters(d) api.InitRouters(d)
// The serve API routine never exits unless an error occurs // The serve API routine never exits unless an error occurs
@ -257,7 +267,7 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
// daemon doesn't exit // daemon doesn't exit
serveAPIWait := make(chan error) serveAPIWait := make(chan error)
go func() { go func() {
if err := api.ServeAPI(commonFlags.Hosts); err != nil { if err := api.ServeAPI(); err != nil {
logrus.Errorf("ServeAPI error: %v", err) logrus.Errorf("ServeAPI error: %v", err)
serveAPIWait <- err serveAPIWait <- err
return return

View file

@ -1462,7 +1462,7 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithSocketAsVolume(c *check.C) {
socket := filepath.Join(s.d.folder, "docker.sock") socket := filepath.Join(s.d.folder, "docker.sock")
out, err := s.d.Cmd("run", "-d", "-v", socket+":/sock", "busybox") out, err := s.d.Cmd("run", "-d", "--restart=always", "-v", socket+":/sock", "busybox")
c.Assert(err, check.IsNil, check.Commentf("Output: %s", out)) c.Assert(err, check.IsNil, check.Commentf("Output: %s", out))
c.Assert(s.d.Restart(), check.IsNil) c.Assert(s.d.Restart(), check.IsNil)
} }