diff --git a/api/server/server.go b/api/server/server.go index 4648de24aa..fd4b88d30c 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -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 diff --git a/api/server/server_unix.go b/api/server/server_unix.go index 31eebb37d4..d8e88221bb 100644 --- a/api/server/server_unix.go +++ b/api/server/server_unix.go @@ -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, }) diff --git a/api/server/server_windows.go b/api/server/server_windows.go index 3e183bc430..826dd2e008 100644 --- a/api/server/server_windows.go +++ b/api/server/server_windows.go @@ -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, }) diff --git a/docker/daemon.go b/docker/daemon.go index 422ba4b3ee..1d8bd0f11c 100644 --- a/docker/daemon.go +++ b/docker/daemon.go @@ -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 diff --git a/integration-cli/docker_cli_daemon_test.go b/integration-cli/docker_cli_daemon_test.go index 1a90d44c5b..5e2dd0aa78 100644 --- a/integration-cli/docker_cli_daemon_test.go +++ b/integration-cli/docker_cli_daemon_test.go @@ -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) }