From 181fea24aac7499a3d6dc0c8c9de67e6c0036140 Mon Sep 17 00:00:00 2001 From: Alexander Morozov Date: Fri, 17 Apr 2015 12:03:11 -0700 Subject: [PATCH 1/3] Make daemon initialization in main goroutine It is simplifies code and lead to next refactoring step, where daemon will be incorporated to some structure which represents API. Signed-off-by: Alexander Morozov --- docker/daemon.go | 78 ++++++++--------------- integration-cli/docker_cli_daemon_test.go | 4 +- 2 files changed, 27 insertions(+), 55 deletions(-) diff --git a/docker/daemon.go b/docker/daemon.go index 769b4f5bf..0fe10de65 100644 --- a/docker/daemon.go +++ b/docker/daemon.go @@ -7,7 +7,6 @@ import ( "io" "os" "path/filepath" - "strings" "github.com/Sirupsen/logrus" apiserver "github.com/docker/docker/api/server" @@ -93,40 +92,6 @@ func mainDaemon() { } daemonCfg.TrustKeyPath = *flTrustKey - registryService := registry.NewService(registryCfg) - // load the daemon in the background so we can immediately start - // the http api so that connections don't fail while the daemon - // is booting - daemonInitWait := make(chan error) - go func() { - d, err := daemon.NewDaemon(daemonCfg, eng, registryService) - if err != nil { - daemonInitWait <- err - return - } - - logrus.WithFields(logrus.Fields{ - "version": dockerversion.VERSION, - "commit": dockerversion.GITCOMMIT, - "execdriver": d.ExecutionDriver().Name(), - "graphdriver": d.GraphDriver().String(), - }).Info("Docker daemon") - - if err := d.Install(eng); err != nil { - daemonInitWait <- err - return - } - - b := &builder.BuilderJob{eng, d} - b.Install() - - // after the daemon is done setting up we can tell the api to start - // accepting connections - apiserver.AcceptConnections() - - daemonInitWait <- nil - }() - serverConfig := &apiserver.ServerConfig{ Logging: true, EnableCors: daemonCfg.EnableCors, @@ -153,30 +118,37 @@ func mainDaemon() { serveAPIWait <- nil }() - // Wait for the daemon startup goroutine to finish - // This makes sure we can actually cleanly shutdown the daemon - logrus.Debug("waiting for daemon to initialize") - errDaemon := <-daemonInitWait - if errDaemon != nil { + registryService := registry.NewService(registryCfg) + d, err := daemon.NewDaemon(daemonCfg, eng, registryService) + if err != nil { eng.Shutdown() - outStr := fmt.Sprintf("Shutting down daemon due to errors: %v", errDaemon) - if strings.Contains(errDaemon.Error(), "engine is shutdown") { - // if the error is "engine is shutdown", we've already reported (or - // will report below in API server errors) the error - outStr = "Shutting down daemon due to reported errors" - } - // we must "fatal" exit here as the API server may be happy to - // continue listening forever if the error had no impact to API - logrus.Fatal(outStr) - } else { - logrus.Info("Daemon has completed initialization") + logrus.Fatalf("Error starting daemon: %v", err) } + if err := d.Install(eng); err != nil { + eng.Shutdown() + logrus.Fatalf("Error starting daemon: %v", err) + } + + logrus.Info("Daemon has completed initialization") + + logrus.WithFields(logrus.Fields{ + "version": dockerversion.VERSION, + "commit": dockerversion.GITCOMMIT, + "execdriver": d.ExecutionDriver().Name(), + "graphdriver": d.GraphDriver().String(), + }).Info("Docker daemon") + + b := &builder.BuilderJob{eng, d} + b.Install() + + // after the daemon is done setting up we can tell the api to start + // accepting connections + apiserver.AcceptConnections() + // Daemon is fully initialized and handling API traffic // Wait for serve API job to complete errAPI := <-serveAPIWait - // If we have an error here it is unique to API (as daemonErr would have - // exited the daemon process above) eng.Shutdown() if errAPI != nil { logrus.Fatalf("Shutting down due to ServeAPI error: %v", errAPI) diff --git a/integration-cli/docker_cli_daemon_test.go b/integration-cli/docker_cli_daemon_test.go index 384c96803..d81ad3c80 100644 --- a/integration-cli/docker_cli_daemon_test.go +++ b/integration-cli/docker_cli_daemon_test.go @@ -498,9 +498,9 @@ func TestDaemonExitOnFailure(t *testing.T) { t.Fatalf("Expected daemon not to start, got %v", err) } // look in the log and make sure we got the message that daemon is shutting down - runCmd := exec.Command("grep", "Shutting down daemon due to", d.LogfileName()) + runCmd := exec.Command("grep", "Error starting daemon", d.LogfileName()) if out, _, err := runCommandWithOutput(runCmd); err != nil { - t.Fatalf("Expected 'shutting down daemon due to error' message; but doesn't exist in log: %q, err: %v", out, err) + t.Fatalf("Expected 'Error starting daemon' message; but doesn't exist in log: %q, err: %v", out, err) } } else { //if we didn't get an error and the daemon is running, this is a failure From d9ed3165228b60cb89c31d0d66b99e01ab83eb3e Mon Sep 17 00:00:00 2001 From: Alexander Morozov Date: Fri, 17 Apr 2015 14:32:18 -0700 Subject: [PATCH 2/3] Make API server datastructure Added daemon field to it, will use it later for acces to daemon from handlers Signed-off-by: Alexander Morozov --- api/server/server.go | 122 +++++++++++++++++++++-------------- api/server/server_linux.go | 32 ++++----- api/server/server_windows.go | 30 +++++---- api/server/tcp_socket.go | 4 +- api/server/unix_socket.go | 4 +- docker/daemon.go | 8 ++- integration/runtime_test.go | 28 ++++---- pkg/listenbuffer/buffer.go | 8 +-- 8 files changed, 131 insertions(+), 105 deletions(-) diff --git a/api/server/server.go b/api/server/server.go index d12bec957..3146e09ed 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -40,10 +40,6 @@ import ( "github.com/docker/docker/utils" ) -var ( - activationLock = make(chan struct{}) -) - type ServerConfig struct { Logging bool EnableCors bool @@ -57,6 +53,80 @@ type ServerConfig struct { TlsKey string } +type Server struct { + daemon *daemon.Daemon + cfg *ServerConfig + router *mux.Router + start chan struct{} + + // TODO: delete engine + eng *engine.Engine +} + +func New(cfg *ServerConfig, eng *engine.Engine) *Server { + r := createRouter( + eng, + cfg.Logging, + cfg.EnableCors, + cfg.CorsHeaders, + cfg.Version, + ) + return &Server{ + cfg: cfg, + router: r, + start: make(chan struct{}), + eng: eng, + } +} + +func (s *Server) SetDaemon(d *daemon.Daemon) { + s.daemon = d +} + +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") + } + go func(proto, addr string) { + logrus.Infof("Listening for HTTP on %s (%s)", proto, addr) + srv, err := s.newServer(proto, addr) + if err != nil { + chErrors <- err + return + } + s.eng.OnShutdown(func() { + if err := srv.Close(); err != nil { + logrus.Error(err) + } + }) + if err = srv.Serve(); err != nil && strings.Contains(err.Error(), "use of closed network connection") { + err = nil + } + chErrors <- err + }(protoAddrParts[0], protoAddrParts[1]) + } + + for i := 0; i < len(protoAddrs); i++ { + err := <-chErrors + if err != nil { + return err + } + } + + return nil +} + type HttpServer struct { srv *http.Server l net.Listener @@ -1632,50 +1702,6 @@ func allocateDaemonPort(addr string) error { return nil } -type Server 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 ServeApi(protoAddrs []string, conf *ServerConfig, eng *engine.Engine) 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") - } - go func() { - logrus.Infof("Listening for HTTP on %s (%s)", protoAddrParts[0], protoAddrParts[1]) - srv, err := NewServer(protoAddrParts[0], protoAddrParts[1], conf, eng) - if err != nil { - chErrors <- err - return - } - eng.OnShutdown(func() { - if err := srv.Close(); err != nil { - logrus.Error(err) - } - }) - if err = srv.Serve(); err != nil && strings.Contains(err.Error(), "use of closed network connection") { - err = nil - } - chErrors <- err - }() - } - - for i := 0; i < len(protoAddrs); i++ { - err := <-chErrors - if err != nil { - return err - } - } - - return nil -} - func toBool(s string) bool { s = strings.ToLower(strings.TrimSpace(s)) return !(s == "" || s == "0" || s == "no" || s == "false" || s == "none") diff --git a/api/server/server_linux.go b/api/server/server_linux.go index 4d53a888e..43f0eefe0 100644 --- a/api/server/server_linux.go +++ b/api/server/server_linux.go @@ -8,22 +8,15 @@ import ( "net/http" "github.com/Sirupsen/logrus" - "github.com/docker/docker/engine" + "github.com/docker/docker/daemon" "github.com/docker/docker/pkg/systemd" ) -// NewServer sets up the required Server and does protocol specific checking. -func NewServer(proto, addr string, conf *ServerConfig, eng *engine.Engine) (Server, error) { +// newServer sets up the required serverCloser and does protocol specific checking. +func (s *Server) newServer(proto, addr string) (serverCloser, error) { var ( err error l net.Listener - r = createRouter( - eng, - conf.Logging, - conf.EnableCors, - conf.CorsHeaders, - conf.Version, - ) ) switch proto { case "fd": @@ -35,13 +28,13 @@ func NewServer(proto, addr string, conf *ServerConfig, eng *engine.Engine) (Serv // We don't want to start serving on these sockets until the // daemon is initialized and installed. Otherwise required handlers // won't be ready. - <-activationLock + <-s.start // Since ListenFD will return one or more sockets we have // to create a go func to spawn off multiple serves for i := range ls { listener := ls[i] go func() { - httpSrv := http.Server{Handler: r} + httpSrv := http.Server{Handler: s.router} chErrors <- httpSrv.Serve(listener) }() } @@ -52,17 +45,17 @@ func NewServer(proto, addr string, conf *ServerConfig, eng *engine.Engine) (Serv } return nil, nil case "tcp": - if !conf.TlsVerify { + if !s.cfg.TlsVerify { logrus.Warn("/!\\ DON'T BIND ON ANY IP ADDRESS WITHOUT setting -tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\") } - if l, err = NewTcpSocket(addr, tlsConfigFromServerConfig(conf)); err != nil { + if l, err = NewTcpSocket(addr, tlsConfigFromServerConfig(s.cfg), s.start); err != nil { return nil, err } if err := allocateDaemonPort(addr); err != nil { return nil, err } case "unix": - if l, err = NewUnixSocket(addr, conf.SocketGroup); err != nil { + if l, err = NewUnixSocket(addr, s.cfg.SocketGroup, s.start); err != nil { return nil, err } default: @@ -71,19 +64,20 @@ func NewServer(proto, addr string, conf *ServerConfig, eng *engine.Engine) (Serv return &HttpServer{ &http.Server{ Addr: addr, - Handler: r, + Handler: s.router, }, l, }, nil } -func AcceptConnections() { +func (s *Server) AcceptConnections(d *daemon.Daemon) { // Tell the init daemon we are accepting requests + s.daemon = d go systemd.SdNotify("READY=1") // close the lock so the listeners start accepting connections select { - case <-activationLock: + case <-s.start: default: - close(activationLock) + close(s.start) } } diff --git a/api/server/server_windows.go b/api/server/server_windows.go index e6b23b97e..c121bbd3e 100644 --- a/api/server/server_windows.go +++ b/api/server/server_windows.go @@ -5,30 +5,24 @@ package server import ( "errors" "net" + "net/http" "github.com/Sirupsen/logrus" - "github.com/docker/docker/engine" + "github.com/docker/docker/daemon" ) // NewServer sets up the required Server and does protocol specific checking. -func NewServer(proto, addr string, job *engine.Job) (Server, error) { +func (s *Server) newServer(proto, addr string) (Server, error) { var ( err error l net.Listener - r = createRouter( - job.Eng, - job.GetenvBool("Logging"), - job.GetenvBool("EnableCors"), - job.Getenv("CorsHeaders"), - job.Getenv("Version"), - ) ) switch proto { case "tcp": - if !job.GetenvBool("TlsVerify") { + if !s.cfg.TlsVerify { logrus.Warn("/!\\ DON'T BIND ON ANY IP ADDRESS WITHOUT setting -tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\") } - if l, err = NewTcpSocket(addr, tlsConfigFromJob(job)); err != nil { + if l, err = NewTcpSocket(addr, tlsConfigFromServerConfig(s.cfg)); err != nil { return nil, err } if err := allocateDaemonPort(addr); err != nil { @@ -37,13 +31,21 @@ func NewServer(proto, addr string, job *engine.Job) (Server, error) { default: return nil, errors.New("Invalid protocol format. Windows only supports tcp.") } + return &HttpServer{ + &http.Server{ + Addr: addr, + Handler: s.router, + }, + l, + }, nil } -func AcceptConnections() { +func (s *Server) AcceptConnections(d *daemon.Daemon) { + s.daemon = d // close the lock so the listeners start accepting connections select { - case <-activationLock: + case <-s.start: default: - close(activationLock) + close(s.start) } } diff --git a/api/server/tcp_socket.go b/api/server/tcp_socket.go index 8454e0c58..a1f57231a 100644 --- a/api/server/tcp_socket.go +++ b/api/server/tcp_socket.go @@ -31,8 +31,8 @@ func tlsConfigFromServerConfig(conf *ServerConfig) *tlsConfig { } } -func NewTcpSocket(addr string, config *tlsConfig) (net.Listener, error) { - l, err := listenbuffer.NewListenBuffer("tcp", addr, activationLock) +func NewTcpSocket(addr string, config *tlsConfig, activate <-chan struct{}) (net.Listener, error) { + l, err := listenbuffer.NewListenBuffer("tcp", addr, activate) if err != nil { return nil, err } diff --git a/api/server/unix_socket.go b/api/server/unix_socket.go index e472efd0a..157005da6 100644 --- a/api/server/unix_socket.go +++ b/api/server/unix_socket.go @@ -12,13 +12,13 @@ import ( "github.com/docker/libcontainer/user" ) -func NewUnixSocket(path, group string) (net.Listener, error) { +func NewUnixSocket(path, group string, activate <-chan struct{}) (net.Listener, error) { if err := syscall.Unlink(path); err != nil && !os.IsNotExist(err) { return nil, err } mask := syscall.Umask(0777) defer syscall.Umask(mask) - l, err := listenbuffer.NewListenBuffer("unix", path, activationLock) + l, err := listenbuffer.NewListenBuffer("unix", path, activate) if err != nil { return nil, err } diff --git a/docker/daemon.go b/docker/daemon.go index 0fe10de65..0602ddf65 100644 --- a/docker/daemon.go +++ b/docker/daemon.go @@ -105,12 +105,14 @@ func mainDaemon() { TlsKey: *flKey, } + api := apiserver.New(serverConfig, eng) + // The serve API routine never exits unless an error occurs // We need to start it as a goroutine and wait on it so // daemon doesn't exit serveAPIWait := make(chan error) go func() { - if err := apiserver.ServeApi(flHosts, serverConfig, eng); err != nil { + if err := api.ServeApi(flHosts); err != nil { logrus.Errorf("ServeAPI error: %v", err) serveAPIWait <- err return @@ -143,8 +145,8 @@ func mainDaemon() { b.Install() // after the daemon is done setting up we can tell the api to start - // accepting connections - apiserver.AcceptConnections() + // accepting connections with specified daemon + api.AcceptConnections(d) // Daemon is fully initialized and handling API traffic // Wait for serve API job to complete diff --git a/integration/runtime_test.go b/integration/runtime_test.go index cd9be89a0..beb15b874 100644 --- a/integration/runtime_test.go +++ b/integration/runtime_test.go @@ -156,6 +156,8 @@ func spawnGlobalDaemon() { globalEngine = eng globalDaemon = mkDaemonFromEngine(eng, t) + serverConfig := &apiserver.ServerConfig{Logging: true} + api := apiserver.New(serverConfig, eng) // Spawn a Daemon go func() { logrus.Debugf("Spawning global daemon for integration tests") @@ -164,8 +166,7 @@ func spawnGlobalDaemon() { Host: testDaemonAddr, } - serverConfig := &apiserver.ServerConfig{Logging: true} - if err := apiserver.ServeApi([]string{listenURL.String()}, serverConfig, eng); err != nil { + if err := api.ServeApi([]string{listenURL.String()}); err != nil { logrus.Fatalf("Unable to spawn the test daemon: %s", err) } }() @@ -174,7 +175,7 @@ func spawnGlobalDaemon() { // FIXME: use inmem transports instead of tcp time.Sleep(time.Second) - apiserver.AcceptConnections() + api.AcceptConnections(getDaemon(eng)) } func spawnLegitHttpsDaemon() { @@ -204,6 +205,15 @@ func spawnHttpsDaemon(addr, cacert, cert, key string) *engine.Engine { eng := newTestEngine(t, true, root) + serverConfig := &apiserver.ServerConfig{ + Logging: true, + Tls: true, + TlsVerify: true, + TlsCa: cacert, + TlsCert: cert, + TlsKey: key, + } + api := apiserver.New(serverConfig, eng) // Spawn a Daemon go func() { logrus.Debugf("Spawning https daemon for integration tests") @@ -211,15 +221,7 @@ func spawnHttpsDaemon(addr, cacert, cert, key string) *engine.Engine { Scheme: testDaemonHttpsProto, Host: addr, } - serverConfig := &apiserver.ServerConfig{ - Logging: true, - Tls: true, - TlsVerify: true, - TlsCa: cacert, - TlsCert: cert, - TlsKey: key, - } - if err := apiserver.ServeApi([]string{listenURL.String()}, serverConfig, eng); err != nil { + if err := api.ServeApi([]string{listenURL.String()}); err != nil { logrus.Fatalf("Unable to spawn the test daemon: %s", err) } }() @@ -227,7 +229,7 @@ func spawnHttpsDaemon(addr, cacert, cert, key string) *engine.Engine { // Give some time to ListenAndServer to actually start time.Sleep(time.Second) - apiserver.AcceptConnections() + api.AcceptConnections(getDaemon(eng)) return eng } diff --git a/pkg/listenbuffer/buffer.go b/pkg/listenbuffer/buffer.go index 6e3656d2c..97d622c15 100644 --- a/pkg/listenbuffer/buffer.go +++ b/pkg/listenbuffer/buffer.go @@ -32,7 +32,7 @@ import "net" // NewListenBuffer returns a net.Listener listening on addr with the protocol // passed. The channel passed is used to activate the listenbuffer when the // caller is ready to accept connections. -func NewListenBuffer(proto, addr string, activate chan struct{}) (net.Listener, error) { +func NewListenBuffer(proto, addr string, activate <-chan struct{}) (net.Listener, error) { wrapped, err := net.Listen(proto, addr) if err != nil { return nil, err @@ -46,9 +46,9 @@ func NewListenBuffer(proto, addr string, activate chan struct{}) (net.Listener, // defaultListener is the buffered wrapper around the net.Listener type defaultListener struct { - wrapped net.Listener // The net.Listener wrapped by listenbuffer - ready bool // Whether the listenbuffer has been activated - activate chan struct{} // Channel to control activation of the listenbuffer + wrapped net.Listener // The net.Listener wrapped by listenbuffer + ready bool // Whether the listenbuffer has been activated + activate <-chan struct{} // Channel to control activation of the listenbuffer } // Close closes the wrapped socket. From da7bca449652396dd8a4a0ff2e303d3d3c7a58a2 Mon Sep 17 00:00:00 2001 From: Alexander Morozov Date: Fri, 17 Apr 2015 15:18:28 -0700 Subject: [PATCH 3/3] Make all http handlers api.server.Server methods Signed-off-by: Alexander Morozov --- api/server/server.go | 316 ++++++++++++++++-------------------- integration/runtime_test.go | 3 - 2 files changed, 143 insertions(+), 176 deletions(-) diff --git a/api/server/server.go b/api/server/server.go index 3146e09ed..50dc84ff7 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -64,19 +64,14 @@ type Server struct { } func New(cfg *ServerConfig, eng *engine.Engine) *Server { - r := createRouter( - eng, - cfg.Logging, - cfg.EnableCors, - cfg.CorsHeaders, - cfg.Version, - ) - return &Server{ - cfg: cfg, - router: r, - start: make(chan struct{}), - eng: eng, + srv := &Server{ + cfg: cfg, + start: make(chan struct{}), + eng: eng, } + r := createRouter(srv, eng) + srv.router = r + return srv } func (s *Server) SetDaemon(d *daemon.Daemon) { @@ -250,19 +245,14 @@ func streamJSON(job *engine.Job, w http.ResponseWriter, flush bool) { } } -func getDaemon(eng *engine.Engine) *daemon.Daemon { - return eng.HackGetGlobalVar("httpapi.daemon").(*daemon.Daemon) -} - -func postAuth(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postAuth(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { var config *registry.AuthConfig err := json.NewDecoder(r.Body).Decode(&config) r.Body.Close() if err != nil { return err } - d := getDaemon(eng) - status, err := d.RegistryService.Auth(config) + status, err := s.daemon.RegistryService.Auth(config) if err != nil { return err } @@ -271,7 +261,7 @@ func postAuth(eng *engine.Engine, version version.Version, w http.ResponseWriter }) } -func getVersion(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getVersion(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { w.Header().Set("Content-Type", "application/json") v := &types.Version{ @@ -289,7 +279,7 @@ func getVersion(eng *engine.Engine, version version.Version, w http.ResponseWrit return writeJSON(w, http.StatusOK, v) } -func postContainersKill(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainersKill(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -317,7 +307,7 @@ func postContainersKill(eng *engine.Engine, version version.Version, w http.Resp } } - if err = getDaemon(eng).ContainerKill(name, sig); err != nil { + if err = s.daemon.ContainerKill(name, sig); err != nil { return err } @@ -325,7 +315,7 @@ func postContainersKill(eng *engine.Engine, version version.Version, w http.Resp return nil } -func postContainersPause(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainersPause(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -334,8 +324,7 @@ func postContainersPause(eng *engine.Engine, version version.Version, w http.Res } name := vars["name"] - d := getDaemon(eng) - cont, err := d.Get(name) + cont, err := s.daemon.Get(name) if err != nil { return err } @@ -350,7 +339,7 @@ func postContainersPause(eng *engine.Engine, version version.Version, w http.Res return nil } -func postContainersUnpause(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainersUnpause(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -359,8 +348,7 @@ func postContainersUnpause(eng *engine.Engine, version version.Version, w http.R } name := vars["name"] - d := getDaemon(eng) - cont, err := d.Get(name) + cont, err := s.daemon.Get(name) if err != nil { return err } @@ -375,17 +363,15 @@ func postContainersUnpause(eng *engine.Engine, version version.Version, w http.R return nil } -func getContainersExport(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getContainersExport(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } - d := getDaemon(eng) - - return d.ContainerExport(vars["name"], w) + return s.daemon.ContainerExport(vars["name"], w) } -func getImagesJSON(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getImagesJSON(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -397,7 +383,7 @@ func getImagesJSON(eng *engine.Engine, version version.Version, w http.ResponseW All: toBool(r.Form.Get("all")), } - images, err := getDaemon(eng).Repositories().Images(&imagesConfig) + images, err := s.daemon.Repositories().Images(&imagesConfig) if err != nil { return err } @@ -426,7 +412,7 @@ func getImagesJSON(eng *engine.Engine, version version.Version, w http.ResponseW return writeJSON(w, http.StatusOK, legacyImages) } -func getImagesViz(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getImagesViz(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if version.GreaterThan("1.6") { w.WriteHeader(http.StatusNotFound) return fmt.Errorf("This is now implemented in the client.") @@ -435,10 +421,10 @@ func getImagesViz(eng *engine.Engine, version version.Version, w http.ResponseWr return nil } -func getInfo(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getInfo(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { w.Header().Set("Content-Type", "application/json") - info, err := getDaemon(eng).SystemInfo() + info, err := s.daemon.SystemInfo() if err != nil { return err } @@ -446,7 +432,7 @@ func getInfo(eng *engine.Engine, version version.Version, w http.ResponseWriter, return writeJSON(w, http.StatusOK, info) } -func getEvents(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getEvents(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -497,7 +483,7 @@ func getEvents(eng *engine.Engine, version version.Version, w http.ResponseWrite return true } - d := getDaemon(eng) + d := s.daemon es := d.EventsService w.Header().Set("Content-Type", "application/json") enc := json.NewEncoder(utils.NewWriteFlusher(w)) @@ -550,13 +536,13 @@ func getEvents(eng *engine.Engine, version version.Version, w http.ResponseWrite } } -func getImagesHistory(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getImagesHistory(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } name := vars["name"] - history, err := getDaemon(eng).Repositories().History(name) + history, err := s.daemon.Repositories().History(name) if err != nil { return err } @@ -564,14 +550,13 @@ func getImagesHistory(eng *engine.Engine, version version.Version, w http.Respon return writeJSON(w, http.StatusOK, history) } -func getContainersChanges(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getContainersChanges(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } name := vars["name"] - d := getDaemon(eng) - cont, err := d.Get(name) + cont, err := s.daemon.Get(name) if err != nil { return err } @@ -584,7 +569,7 @@ func getContainersChanges(eng *engine.Engine, version version.Version, w http.Re return writeJSON(w, http.StatusOK, changes) } -func getContainersTop(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getContainersTop(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if version.LessThan("1.4") { return fmt.Errorf("top was improved a lot since 1.3, Please upgrade your docker client.") } @@ -597,7 +582,7 @@ func getContainersTop(eng *engine.Engine, version version.Version, w http.Respon return err } - procList, err := getDaemon(eng).ContainerTop(vars["name"], r.Form.Get("ps_args")) + procList, err := s.daemon.ContainerTop(vars["name"], r.Form.Get("ps_args")) if err != nil { return err } @@ -605,7 +590,7 @@ func getContainersTop(eng *engine.Engine, version version.Version, w http.Respon return writeJSON(w, http.StatusOK, procList) } -func getContainersJSON(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getContainersJSON(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -626,7 +611,7 @@ func getContainersJSON(eng *engine.Engine, version version.Version, w http.Respo config.Limit = limit } - containers, err := getDaemon(eng).Containers(config) + containers, err := s.daemon.Containers(config) if err != nil { return err } @@ -634,7 +619,7 @@ func getContainersJSON(eng *engine.Engine, version version.Version, w http.Respo return writeJSON(w, http.StatusOK, containers) } -func getContainersStats(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getContainersStats(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -642,12 +627,10 @@ func getContainersStats(eng *engine.Engine, version version.Version, w http.Resp return fmt.Errorf("Missing parameter") } - d := getDaemon(eng) - - return d.ContainerStats(vars["name"], utils.NewWriteFlusher(w)) + return s.daemon.ContainerStats(vars["name"], utils.NewWriteFlusher(w)) } -func getContainersLogs(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getContainersLogs(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -670,15 +653,14 @@ func getContainersLogs(eng *engine.Engine, version version.Version, w http.Respo OutStream: utils.NewWriteFlusher(w), } - d := getDaemon(eng) - if err := d.ContainerLogs(vars["name"], logsConfig); err != nil { + if err := s.daemon.ContainerLogs(vars["name"], logsConfig); err != nil { fmt.Fprintf(w, "Error running logs job: %s\n", err) } return nil } -func postImagesTag(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postImagesTag(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -686,18 +668,17 @@ func postImagesTag(eng *engine.Engine, version version.Version, w http.ResponseW return fmt.Errorf("Missing parameter") } - d := getDaemon(eng) repo := r.Form.Get("repo") tag := r.Form.Get("tag") force := toBool(r.Form.Get("force")) - if err := d.Repositories().Tag(repo, tag, vars["name"], force); err != nil { + if err := s.daemon.Repositories().Tag(repo, tag, vars["name"], force); err != nil { return err } w.WriteHeader(http.StatusCreated) return nil } -func postCommit(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postCommit(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -723,9 +704,7 @@ func postCommit(eng *engine.Engine, version version.Version, w http.ResponseWrit Config: r.Body, } - d := getDaemon(eng) - - imgID, err := d.ContainerCommit(cont, containerCommitConfig) + imgID, err := s.daemon.ContainerCommit(cont, containerCommitConfig) if err != nil { return err } @@ -736,7 +715,7 @@ func postCommit(eng *engine.Engine, version version.Version, w http.ResponseWrit } // Creates an image from Pull or from Import -func postImagesCreate(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postImagesCreate(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -757,8 +736,6 @@ func postImagesCreate(eng *engine.Engine, version version.Version, w http.Respon } } - d := getDaemon(eng) - if image != "" { //pull if tag == "" { image, tag = parsers.ParseRepositoryTag(image) @@ -783,7 +760,7 @@ func postImagesCreate(eng *engine.Engine, version version.Version, w http.Respon imagePullConfig.Json = false } - if err := d.Repositories().Pull(image, tag, imagePullConfig, eng); err != nil { + if err := s.daemon.Repositories().Pull(image, tag, imagePullConfig, eng); err != nil { return err } } else { //import @@ -804,7 +781,7 @@ func postImagesCreate(eng *engine.Engine, version version.Version, w http.Respon imageImportConfig.Json = false } - if err := d.Repositories().Import(src, repo, tag, imageImportConfig, eng); err != nil { + if err := s.daemon.Repositories().Import(src, repo, tag, imageImportConfig, eng); err != nil { return err } @@ -813,7 +790,7 @@ func postImagesCreate(eng *engine.Engine, version version.Version, w http.Respon return nil } -func getImagesSearch(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getImagesSearch(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -836,15 +813,14 @@ func getImagesSearch(eng *engine.Engine, version version.Version, w http.Respons headers[k] = v } } - d := getDaemon(eng) - query, err := d.RegistryService.Search(r.Form.Get("term"), config, headers) + query, err := s.daemon.RegistryService.Search(r.Form.Get("term"), config, headers) if err != nil { return err } return json.NewEncoder(w).Encode(query.Results) } -func postImagesPush(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postImagesPush(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -896,7 +872,7 @@ func postImagesPush(eng *engine.Engine, version version.Version, w http.Response return nil } -func getImagesGet(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getImagesGet(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -916,14 +892,14 @@ func getImagesGet(eng *engine.Engine, version version.Version, w http.ResponseWr return job.Run() } -func postImagesLoad(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postImagesLoad(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { job := eng.Job("load") job.Stdin.Add(r.Body) job.Stdout.Add(w) return job.Run() } -func postContainersCreate(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainersCreate(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return nil } @@ -940,7 +916,7 @@ func postContainersCreate(eng *engine.Engine, version version.Version, w http.Re return err } - containerId, warnings, err := getDaemon(eng).ContainerCreate(name, config, hostConfig) + containerId, warnings, err := s.daemon.ContainerCreate(name, config, hostConfig) if err != nil { return err } @@ -951,7 +927,7 @@ func postContainersCreate(eng *engine.Engine, version version.Version, w http.Re }) } -func postContainersRestart(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainersRestart(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -959,13 +935,12 @@ func postContainersRestart(eng *engine.Engine, version version.Version, w http.R return fmt.Errorf("Missing parameter") } - s, err := strconv.Atoi(r.Form.Get("t")) + timeout, err := strconv.Atoi(r.Form.Get("t")) if err != nil { return err } - d := getDaemon(eng) - if err := d.ContainerRestart(vars["name"], s); err != nil { + if err := s.daemon.ContainerRestart(vars["name"], timeout); err != nil { return err } @@ -974,7 +949,7 @@ func postContainersRestart(eng *engine.Engine, version version.Version, w http.R return nil } -func postContainerRename(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainerRename(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -982,17 +957,16 @@ func postContainerRename(eng *engine.Engine, version version.Version, w http.Res return fmt.Errorf("Missing parameter") } - d := getDaemon(eng) name := vars["name"] newName := r.Form.Get("name") - if err := d.ContainerRename(name, newName); err != nil { + if err := s.daemon.ContainerRename(name, newName); err != nil { return err } w.WriteHeader(http.StatusNoContent) return nil } -func deleteContainers(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) deleteContainers(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -1001,14 +975,13 @@ func deleteContainers(eng *engine.Engine, version version.Version, w http.Respon } name := vars["name"] - d := getDaemon(eng) config := &daemon.ContainerRmConfig{ ForceRemove: toBool(r.Form.Get("force")), RemoveVolume: toBool(r.Form.Get("v")), RemoveLink: toBool(r.Form.Get("link")), } - if err := d.ContainerRm(name, config); err != nil { + if err := s.daemon.ContainerRm(name, config); err != nil { // Force a 404 for the empty string if strings.Contains(strings.ToLower(err.Error()), "prefix can't be empty") { return fmt.Errorf("no such id: \"\"") @@ -1021,7 +994,7 @@ func deleteContainers(eng *engine.Engine, version version.Version, w http.Respon return nil } -func deleteImages(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) deleteImages(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -1029,12 +1002,11 @@ func deleteImages(eng *engine.Engine, version version.Version, w http.ResponseWr return fmt.Errorf("Missing parameter") } - d := getDaemon(eng) name := vars["name"] force := toBool(r.Form.Get("force")) noprune := toBool(r.Form.Get("noprune")) - list, err := d.ImageDelete(name, force, noprune) + list, err := s.daemon.ImageDelete(name, force, noprune) if err != nil { return err } @@ -1042,7 +1014,7 @@ func deleteImages(eng *engine.Engine, version version.Version, w http.ResponseWr return writeJSON(w, http.StatusOK, list) } -func postContainersStart(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainersStart(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -1067,7 +1039,7 @@ func postContainersStart(eng *engine.Engine, version version.Version, w http.Res hostConfig = c } - if err := getDaemon(eng).ContainerStart(vars["name"], hostConfig); err != nil { + if err := s.daemon.ContainerStart(vars["name"], hostConfig); err != nil { if err.Error() == "Container already started" { w.WriteHeader(http.StatusNotModified) return nil @@ -1078,7 +1050,7 @@ func postContainersStart(eng *engine.Engine, version version.Version, w http.Res return nil } -func postContainersStop(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainersStop(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -1086,13 +1058,12 @@ func postContainersStop(eng *engine.Engine, version version.Version, w http.Resp return fmt.Errorf("Missing parameter") } - d := getDaemon(eng) seconds, err := strconv.Atoi(r.Form.Get("t")) if err != nil { return err } - if err := d.ContainerStop(vars["name"], seconds); err != nil { + if err := s.daemon.ContainerStop(vars["name"], seconds); err != nil { if err.Error() == "Container already stopped" { w.WriteHeader(http.StatusNotModified) return nil @@ -1104,14 +1075,13 @@ func postContainersStop(eng *engine.Engine, version version.Version, w http.Resp return nil } -func postContainersWait(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainersWait(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } name := vars["name"] - d := getDaemon(eng) - cont, err := d.Get(name) + cont, err := s.daemon.Get(name) if err != nil { return err } @@ -1123,7 +1093,7 @@ func postContainersWait(eng *engine.Engine, version version.Version, w http.Resp }) } -func postContainersResize(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainersResize(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -1140,8 +1110,7 @@ func postContainersResize(eng *engine.Engine, version version.Version, w http.Re return err } - d := getDaemon(eng) - cont, err := d.Get(vars["name"]) + cont, err := s.daemon.Get(vars["name"]) if err != nil { return err } @@ -1149,7 +1118,7 @@ func postContainersResize(eng *engine.Engine, version version.Version, w http.Re return cont.Resize(height, width) } -func postContainersAttach(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainersAttach(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -1157,9 +1126,7 @@ func postContainersAttach(eng *engine.Engine, version version.Version, w http.Re return fmt.Errorf("Missing parameter") } - d := getDaemon(eng) - - cont, err := d.Get(vars["name"]) + cont, err := s.daemon.Get(vars["name"]) if err != nil { return err } @@ -1206,16 +1173,14 @@ func postContainersAttach(eng *engine.Engine, version version.Version, w http.Re return nil } -func wsContainersAttach(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) wsContainersAttach(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } if vars == nil { return fmt.Errorf("Missing parameter") } - d := getDaemon(eng) - - cont, err := d.Get(vars["name"]) + cont, err := s.daemon.Get(vars["name"]) if err != nil { return err } @@ -1234,7 +1199,7 @@ func wsContainersAttach(eng *engine.Engine, version version.Version, w http.Resp return nil } -func getContainersByName(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getContainersByName(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -1246,13 +1211,12 @@ func getContainersByName(eng *engine.Engine, version version.Version, w http.Res return job.Run() } -func getExecByID(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getExecByID(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter 'id'") } - d := getDaemon(eng) - eConfig, err := d.ContainerExecInspect(vars["id"]) + eConfig, err := s.daemon.ContainerExecInspect(vars["id"]) if err != nil { return err } @@ -1260,7 +1224,7 @@ func getExecByID(eng *engine.Engine, version version.Version, w http.ResponseWri return writeJSON(w, http.StatusOK, eConfig) } -func getImagesByName(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) getImagesByName(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -1272,7 +1236,7 @@ func getImagesByName(eng *engine.Engine, version version.Version, w http.Respons return job.Run() } -func postBuild(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postBuild(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if version.LessThan("1.3") { return fmt.Errorf("Multipart upload for build is no longer supported. Please upgrade your docker client.") } @@ -1362,7 +1326,7 @@ func postBuild(eng *engine.Engine, version version.Version, w http.ResponseWrite return nil } -func postContainersCopy(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainersCopy(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if vars == nil { return fmt.Errorf("Missing parameter") } @@ -1386,7 +1350,7 @@ func postContainersCopy(eng *engine.Engine, version version.Version, w http.Resp res = res[1:] } - cont, err := getDaemon(eng).Get(vars["name"]) + cont, err := s.daemon.Get(vars["name"]) if err != nil { logrus.Errorf("%v", err) if strings.Contains(strings.ToLower(err.Error()), "no such id") { @@ -1412,7 +1376,7 @@ func postContainersCopy(eng *engine.Engine, version version.Version, w http.Resp return nil } -func postContainerExecCreate(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainerExecCreate(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return nil } @@ -1449,7 +1413,7 @@ func postContainerExecCreate(eng *engine.Engine, version version.Version, w http } // TODO(vishh): Refactor the code to avoid having to specify stream config as part of both create and start. -func postContainerExecStart(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainerExecStart(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return nil } @@ -1500,7 +1464,7 @@ func postContainerExecStart(eng *engine.Engine, version version.Version, w http. return nil } -func postContainerExecResize(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) postContainerExecResize(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err } @@ -1517,12 +1481,10 @@ func postContainerExecResize(eng *engine.Engine, version version.Version, w http return err } - d := getDaemon(eng) - - return d.ContainerExecResize(vars["name"], height, width) + return s.daemon.ContainerExecResize(vars["name"], height, width) } -func optionsHandler(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) optionsHandler(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { w.WriteHeader(http.StatusOK) return nil } @@ -1533,7 +1495,7 @@ func writeCorsHeaders(w http.ResponseWriter, r *http.Request, corsHeaders string w.Header().Add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS") } -func ping(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { +func (s *Server) ping(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { _, err := w.Write([]byte{'O', 'K'}) return err } @@ -1574,71 +1536,72 @@ func makeHttpHandler(eng *engine.Engine, logging bool, localMethod string, local } // we keep enableCors just for legacy usage, need to be removed in the future -func createRouter(eng *engine.Engine, logging, enableCors bool, corsHeaders string, dockerVersion string) *mux.Router { +func createRouter(s *Server, eng *engine.Engine) *mux.Router { r := mux.NewRouter() if os.Getenv("DEBUG") != "" { ProfilerSetup(r, "/debug/") } m := map[string]map[string]HttpApiFunc{ "GET": { - "/_ping": ping, - "/events": getEvents, - "/info": getInfo, - "/version": getVersion, - "/images/json": getImagesJSON, - "/images/viz": getImagesViz, - "/images/search": getImagesSearch, - "/images/get": getImagesGet, - "/images/{name:.*}/get": getImagesGet, - "/images/{name:.*}/history": getImagesHistory, - "/images/{name:.*}/json": getImagesByName, - "/containers/ps": getContainersJSON, - "/containers/json": getContainersJSON, - "/containers/{name:.*}/export": getContainersExport, - "/containers/{name:.*}/changes": getContainersChanges, - "/containers/{name:.*}/json": getContainersByName, - "/containers/{name:.*}/top": getContainersTop, - "/containers/{name:.*}/logs": getContainersLogs, - "/containers/{name:.*}/stats": getContainersStats, - "/containers/{name:.*}/attach/ws": wsContainersAttach, - "/exec/{id:.*}/json": getExecByID, + "/_ping": s.ping, + "/events": s.getEvents, + "/info": s.getInfo, + "/version": s.getVersion, + "/images/json": s.getImagesJSON, + "/images/viz": s.getImagesViz, + "/images/search": s.getImagesSearch, + "/images/get": s.getImagesGet, + "/images/{name:.*}/get": s.getImagesGet, + "/images/{name:.*}/history": s.getImagesHistory, + "/images/{name:.*}/json": s.getImagesByName, + "/containers/ps": s.getContainersJSON, + "/containers/json": s.getContainersJSON, + "/containers/{name:.*}/export": s.getContainersExport, + "/containers/{name:.*}/changes": s.getContainersChanges, + "/containers/{name:.*}/json": s.getContainersByName, + "/containers/{name:.*}/top": s.getContainersTop, + "/containers/{name:.*}/logs": s.getContainersLogs, + "/containers/{name:.*}/stats": s.getContainersStats, + "/containers/{name:.*}/attach/ws": s.wsContainersAttach, + "/exec/{id:.*}/json": s.getExecByID, }, "POST": { - "/auth": postAuth, - "/commit": postCommit, - "/build": postBuild, - "/images/create": postImagesCreate, - "/images/load": postImagesLoad, - "/images/{name:.*}/push": postImagesPush, - "/images/{name:.*}/tag": postImagesTag, - "/containers/create": postContainersCreate, - "/containers/{name:.*}/kill": postContainersKill, - "/containers/{name:.*}/pause": postContainersPause, - "/containers/{name:.*}/unpause": postContainersUnpause, - "/containers/{name:.*}/restart": postContainersRestart, - "/containers/{name:.*}/start": postContainersStart, - "/containers/{name:.*}/stop": postContainersStop, - "/containers/{name:.*}/wait": postContainersWait, - "/containers/{name:.*}/resize": postContainersResize, - "/containers/{name:.*}/attach": postContainersAttach, - "/containers/{name:.*}/copy": postContainersCopy, - "/containers/{name:.*}/exec": postContainerExecCreate, - "/exec/{name:.*}/start": postContainerExecStart, - "/exec/{name:.*}/resize": postContainerExecResize, - "/containers/{name:.*}/rename": postContainerRename, + "/auth": s.postAuth, + "/commit": s.postCommit, + "/build": s.postBuild, + "/images/create": s.postImagesCreate, + "/images/load": s.postImagesLoad, + "/images/{name:.*}/push": s.postImagesPush, + "/images/{name:.*}/tag": s.postImagesTag, + "/containers/create": s.postContainersCreate, + "/containers/{name:.*}/kill": s.postContainersKill, + "/containers/{name:.*}/pause": s.postContainersPause, + "/containers/{name:.*}/unpause": s.postContainersUnpause, + "/containers/{name:.*}/restart": s.postContainersRestart, + "/containers/{name:.*}/start": s.postContainersStart, + "/containers/{name:.*}/stop": s.postContainersStop, + "/containers/{name:.*}/wait": s.postContainersWait, + "/containers/{name:.*}/resize": s.postContainersResize, + "/containers/{name:.*}/attach": s.postContainersAttach, + "/containers/{name:.*}/copy": s.postContainersCopy, + "/containers/{name:.*}/exec": s.postContainerExecCreate, + "/exec/{name:.*}/start": s.postContainerExecStart, + "/exec/{name:.*}/resize": s.postContainerExecResize, + "/containers/{name:.*}/rename": s.postContainerRename, }, "DELETE": { - "/containers/{name:.*}": deleteContainers, - "/images/{name:.*}": deleteImages, + "/containers/{name:.*}": s.deleteContainers, + "/images/{name:.*}": s.deleteImages, }, "OPTIONS": { - "": optionsHandler, + "": s.optionsHandler, }, } // If "api-cors-header" is not given, but "api-enable-cors" is true, we set cors to "*" // otherwise, all head values will be passed to HTTP handler - if corsHeaders == "" && enableCors { + corsHeaders := s.cfg.CorsHeaders + if corsHeaders == "" && s.cfg.EnableCors { corsHeaders = "*" } @@ -1651,7 +1614,7 @@ func createRouter(eng *engine.Engine, logging, enableCors bool, corsHeaders stri localMethod := method // build the handler function - f := makeHttpHandler(eng, logging, localMethod, localRoute, localFct, corsHeaders, version.Version(dockerVersion)) + f := makeHttpHandler(eng, s.cfg.Logging, localMethod, localRoute, localFct, corsHeaders, version.Version(s.cfg.Version)) // add the new route if localRoute == "" { @@ -1670,7 +1633,14 @@ func createRouter(eng *engine.Engine, logging, enableCors bool, corsHeaders stri // FIXME: refactor this to be part of Server and not require re-creating a new // router each time. This requires first moving ListenAndServe into Server. func ServeRequest(eng *engine.Engine, apiversion version.Version, w http.ResponseWriter, req *http.Request) { - router := createRouter(eng, false, true, "", "") + cfg := &ServerConfig{ + EnableCors: true, + Version: string(apiversion), + } + api := New(cfg, eng) + daemon, _ := eng.HackGetGlobalVar("httpapi.daemon").(*daemon.Daemon) + api.AcceptConnections(daemon) + router := createRouter(api, eng) // Insert APIVERSION into the request as a convenience req.URL.Path = fmt.Sprintf("/v%s%s", apiversion, req.URL.Path) router.ServeHTTP(w, req) diff --git a/integration/runtime_test.go b/integration/runtime_test.go index beb15b874..2e106972e 100644 --- a/integration/runtime_test.go +++ b/integration/runtime_test.go @@ -48,9 +48,7 @@ const ( ) var ( - // FIXME: globalDaemon is deprecated by globalEngine. All tests should be converted. globalDaemon *daemon.Daemon - globalEngine *engine.Engine globalHttpsEngine *engine.Engine globalRogueHttpsEngine *engine.Engine startFds int @@ -153,7 +151,6 @@ func spawnGlobalDaemon() { } t := std_log.New(os.Stderr, "", 0) eng := NewTestEngine(t) - globalEngine = eng globalDaemon = mkDaemonFromEngine(eng, t) serverConfig := &apiserver.ServerConfig{Logging: true}