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

View file

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

View file

@ -9,7 +9,7 @@ import (
)
// 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 (
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.")
}
var res []serverCloser
var res []*HTTPServer
for _, l := range ls {
res = append(res, &HTTPServer{
&http.Server{
Addr: addr,
Handler: s.CreateMux(),
Addr: addr,
},
l,
})

View file

@ -223,6 +223,17 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
}
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 {
logrus.Fatal(err)
@ -249,7 +260,6 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
"graphdriver": d.GraphDriver().String(),
}).Info("Docker daemon")
api := apiserver.New(serverConfig)
api.InitRouters(d)
// 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
serveAPIWait := make(chan error)
go func() {
if err := api.ServeAPI(commonFlags.Hosts); err != nil {
if err := api.ServeAPI(); err != nil {
logrus.Errorf("ServeAPI error: %v", err)
serveAPIWait <- err
return

View file

@ -1462,7 +1462,7 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithSocketAsVolume(c *check.C) {
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(s.d.Restart(), check.IsNil)
}