diff --git a/api/server/server.go b/api/server/server.go index d40413a4e8..f36f082f63 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -3,6 +3,7 @@ package server import ( "bufio" "bytes" + "runtime" "time" "encoding/base64" @@ -21,6 +22,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/docker/api" "github.com/docker/docker/api/types" + "github.com/docker/docker/autogen/dockerversion" "github.com/docker/docker/daemon" "github.com/docker/docker/daemon/networkdriver/bridge" "github.com/docker/docker/engine" @@ -28,6 +30,7 @@ import ( "github.com/docker/docker/pkg/jsonmessage" "github.com/docker/docker/pkg/parsers" "github.com/docker/docker/pkg/parsers/filters" + "github.com/docker/docker/pkg/parsers/kernel" "github.com/docker/docker/pkg/signal" "github.com/docker/docker/pkg/stdcopy" "github.com/docker/docker/pkg/streamformatter" @@ -41,6 +44,19 @@ var ( activationLock = make(chan struct{}) ) +type ServerConfig struct { + Logging bool + EnableCors bool + CorsHeaders string + Version string + SocketGroup string + Tls bool + TlsVerify bool + TlsCa string + TlsCert string + TlsKey string +} + type HttpServer struct { srv *http.Server l net.Listener @@ -187,8 +203,20 @@ 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 { w.Header().Set("Content-Type", "application/json") - eng.ServeHTTP(w, r) - return nil + + v := &types.Version{ + Version: dockerversion.VERSION, + ApiVersion: api.APIVERSION, + GitCommit: dockerversion.GITCOMMIT, + GoVersion: runtime.Version(), + Os: runtime.GOOS, + Arch: runtime.GOARCH, + } + if kernelVersion, err := kernel.GetKernelVersion(); err == nil { + v.KernelVersion = kernelVersion.String() + } + + 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 { @@ -1588,28 +1616,22 @@ type Server interface { // 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(job *engine.Job) error { - if len(job.Args) == 0 { - return fmt.Errorf("usage: %s PROTO://ADDR [PROTO://ADDR ...]", job.Name) - } - var ( - protoAddrs = job.Args - chErrors = make(chan error, len(protoAddrs)) - ) +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("usage: %s PROTO://ADDR [PROTO://ADDR ...]", job.Name) + 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], job) + srv, err := NewServer(protoAddrParts[0], protoAddrParts[1], conf, eng) if err != nil { chErrors <- err return } - job.Eng.OnShutdown(func() { + eng.OnShutdown(func() { if err := srv.Close(); err != nil { logrus.Error(err) } diff --git a/api/server/server_linux.go b/api/server/server_linux.go index 06e1a3717d..4d53a888ee 100644 --- a/api/server/server_linux.go +++ b/api/server/server_linux.go @@ -13,16 +13,16 @@ import ( ) // NewServer sets up the required Server and does protocol specific checking. -func NewServer(proto, addr string, job *engine.Job) (Server, error) { +func NewServer(proto, addr string, conf *ServerConfig, eng *engine.Engine) (Server, error) { var ( err error l net.Listener r = createRouter( - job.Eng, - job.GetenvBool("Logging"), - job.GetenvBool("EnableCors"), - job.Getenv("CorsHeaders"), - job.Getenv("Version"), + eng, + conf.Logging, + conf.EnableCors, + conf.CorsHeaders, + conf.Version, ) ) switch proto { @@ -52,17 +52,17 @@ func NewServer(proto, addr string, job *engine.Job) (Server, error) { } return nil, nil case "tcp": - if !job.GetenvBool("TlsVerify") { + if !conf.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(conf)); err != nil { return nil, err } if err := allocateDaemonPort(addr); err != nil { return nil, err } case "unix": - if l, err = NewUnixSocket(addr, job.Getenv("SocketGroup")); err != nil { + if l, err = NewUnixSocket(addr, conf.SocketGroup); err != nil { return nil, err } default: @@ -77,8 +77,7 @@ func NewServer(proto, addr string, job *engine.Job) (Server, error) { }, nil } -// Called through eng.Job("acceptconnections") -func AcceptConnections(job *engine.Job) error { +func AcceptConnections() { // Tell the init daemon we are accepting requests go systemd.SdNotify("READY=1") // close the lock so the listeners start accepting connections @@ -87,5 +86,4 @@ func AcceptConnections(job *engine.Job) error { default: close(activationLock) } - return nil } diff --git a/api/server/server_unit_test.go b/api/server/server_unit_test.go index 78b95b26bb..aca3af9fff 100644 --- a/api/server/server_unit_test.go +++ b/api/server/server_unit_test.go @@ -34,35 +34,6 @@ func TesthttpError(t *testing.T) { } } -func TestGetVersion(t *testing.T) { - eng := engine.New() - var called bool - eng.Register("version", func(job *engine.Job) error { - called = true - v := &engine.Env{} - v.SetJson("Version", "42.1") - v.Set("ApiVersion", "1.1.1.1.1") - v.Set("GoVersion", "2.42") - v.Set("Os", "Linux") - v.Set("Arch", "x86_64") - if _, err := v.WriteTo(job.Stdout); err != nil { - return err - } - return nil - }) - r := serveRequest("GET", "/version", nil, eng, t) - if !called { - t.Fatalf("handler was not called") - } - v := readEnv(r.Body, t) - if v.Get("Version") != "42.1" { - t.Fatalf("%#v\n", v) - } - if r.HeaderMap.Get("Content-Type") != "application/json" { - t.Fatalf("%#v\n", r) - } -} - func TestGetInfo(t *testing.T) { eng := engine.New() var called bool diff --git a/api/server/server_windows.go b/api/server/server_windows.go index c81313e258..e6b23b97ea 100644 --- a/api/server/server_windows.go +++ b/api/server/server_windows.go @@ -39,13 +39,11 @@ func NewServer(proto, addr string, job *engine.Job) (Server, error) { } } -// Called through eng.Job("acceptconnections") -func AcceptConnections(job *engine.Job) error { +func AcceptConnections() { // close the lock so the listeners start accepting connections select { case <-activationLock: default: close(activationLock) } - return nil } diff --git a/api/server/tcp_socket.go b/api/server/tcp_socket.go index 415542c143..8454e0c58b 100644 --- a/api/server/tcp_socket.go +++ b/api/server/tcp_socket.go @@ -8,7 +8,6 @@ import ( "net" "os" - "github.com/docker/docker/engine" "github.com/docker/docker/pkg/listenbuffer" ) @@ -19,16 +18,16 @@ type tlsConfig struct { Verify bool } -func tlsConfigFromJob(job *engine.Job) *tlsConfig { - verify := job.GetenvBool("TlsVerify") - if !job.GetenvBool("Tls") && !verify { +func tlsConfigFromServerConfig(conf *ServerConfig) *tlsConfig { + verify := conf.TlsVerify + if !conf.Tls && !conf.TlsVerify { return nil } return &tlsConfig{ Verify: verify, - Certificate: job.Getenv("TlsCert"), - Key: job.Getenv("TlsKey"), - CA: job.Getenv("TlsCa"), + Certificate: conf.TlsCert, + Key: conf.TlsKey, + CA: conf.TlsCa, } } diff --git a/api/types/types.go b/api/types/types.go index d7defaf85a..cdafe7e192 100644 --- a/api/types/types.go +++ b/api/types/types.go @@ -1,5 +1,7 @@ package types +import "github.com/docker/docker/pkg/version" + // ContainerCreateResponse contains the information returned to a client on the // creation of a new container. type ContainerCreateResponse struct { @@ -110,3 +112,13 @@ type ContainerProcessList struct { Processes [][]string Titles []string } + +type Version struct { + Version string + ApiVersion version.Version + GitCommit string + GoVersion string + Os string + Arch string + KernelVersion string `json:",omitempty"` +} diff --git a/builtins/builtins.go b/builtins/builtins.go deleted file mode 100644 index 8957b58332..0000000000 --- a/builtins/builtins.go +++ /dev/null @@ -1,48 +0,0 @@ -package builtins - -import ( - "runtime" - - "github.com/docker/docker/api" - apiserver "github.com/docker/docker/api/server" - "github.com/docker/docker/autogen/dockerversion" - "github.com/docker/docker/engine" - "github.com/docker/docker/pkg/parsers/kernel" -) - -func Register(eng *engine.Engine) error { - if err := remote(eng); err != nil { - return err - } - if err := eng.Register("version", dockerVersion); err != nil { - return err - } - - return nil -} - -// remote: a RESTful api for cross-docker communication -func remote(eng *engine.Engine) error { - if err := eng.Register("serveapi", apiserver.ServeApi); err != nil { - return err - } - return eng.Register("acceptconnections", apiserver.AcceptConnections) -} - -// builtins jobs independent of any subsystem -func dockerVersion(job *engine.Job) error { - v := &engine.Env{} - v.SetJson("Version", dockerversion.VERSION) - v.SetJson("ApiVersion", api.APIVERSION) - v.SetJson("GitCommit", dockerversion.GITCOMMIT) - v.Set("GoVersion", runtime.Version()) - v.Set("Os", runtime.GOOS) - v.Set("Arch", runtime.GOARCH) - if kernelVersion, err := kernel.GetKernelVersion(); err == nil { - v.Set("KernelVersion", kernelVersion.String()) - } - if _, err := v.WriteTo(job.Stdout); err != nil { - return err - } - return nil -} diff --git a/docker/daemon.go b/docker/daemon.go index b1a92c52e5..769b4f5bf6 100644 --- a/docker/daemon.go +++ b/docker/daemon.go @@ -10,9 +10,9 @@ import ( "strings" "github.com/Sirupsen/logrus" + apiserver "github.com/docker/docker/api/server" "github.com/docker/docker/autogen/dockerversion" "github.com/docker/docker/builder" - "github.com/docker/docker/builtins" "github.com/docker/docker/daemon" _ "github.com/docker/docker/daemon/execdriver/lxc" _ "github.com/docker/docker/daemon/execdriver/native" @@ -93,11 +93,6 @@ func mainDaemon() { } daemonCfg.TrustKeyPath = *flTrustKey - // Load builtins - if err := builtins.Register(eng); err != nil { - logrus.Fatal(err) - } - 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 @@ -127,33 +122,30 @@ func mainDaemon() { // after the daemon is done setting up we can tell the api to start // accepting connections - if err := eng.Job("acceptconnections").Run(); err != nil { - daemonInitWait <- err - return - } + apiserver.AcceptConnections() + daemonInitWait <- nil }() - // Serve api - job := eng.Job("serveapi", flHosts...) - job.SetenvBool("Logging", true) - job.SetenvBool("EnableCors", daemonCfg.EnableCors) - job.Setenv("CorsHeaders", daemonCfg.CorsHeaders) - job.Setenv("Version", dockerversion.VERSION) - job.Setenv("SocketGroup", daemonCfg.SocketGroup) + serverConfig := &apiserver.ServerConfig{ + Logging: true, + EnableCors: daemonCfg.EnableCors, + CorsHeaders: daemonCfg.CorsHeaders, + Version: dockerversion.VERSION, + SocketGroup: daemonCfg.SocketGroup, + Tls: *flTls, + TlsVerify: *flTlsVerify, + TlsCa: *flCa, + TlsCert: *flCert, + TlsKey: *flKey, + } - job.SetenvBool("Tls", *flTls) - job.SetenvBool("TlsVerify", *flTlsVerify) - job.Setenv("TlsCa", *flCa) - job.Setenv("TlsCert", *flCert) - job.Setenv("TlsKey", *flKey) - - // The serve API job never exits unless an error occurs + // 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 := job.Run(); err != nil { + if err := apiserver.ServeApi(flHosts, serverConfig, eng); err != nil { logrus.Errorf("ServeAPI error: %v", err) serveAPIWait <- err return diff --git a/integration-cli/docker_api_version_test.go b/integration-cli/docker_api_version_test.go new file mode 100644 index 0000000000..2846fb1d39 --- /dev/null +++ b/integration-cli/docker_api_version_test.go @@ -0,0 +1,24 @@ +package main + +import ( + "encoding/json" + "testing" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/autogen/dockerversion" +) + +func TestGetVersion(t *testing.T) { + _, body, err := sockRequest("GET", "/version", nil) + if err != nil { + t.Fatal(err) + } + var v types.Version + if err := json.Unmarshal(body, &v); err != nil { + t.Fatal(err) + } + + if v.Version != dockerversion.VERSION { + t.Fatal("Version mismatch") + } +} diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index e990f086ae..b3cd1c73a2 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -3363,7 +3363,7 @@ func TestRunRestartMaxRetries(t *testing.T) { t.Fatal(string(out), err) } id := strings.TrimSpace(string(out)) - if err := waitInspect(id, "{{ .State.Restarting }} {{ .State.Running }}", "false false", 5); err != nil { + if err := waitInspect(id, "{{ .State.Restarting }} {{ .State.Running }}", "false false", 10); err != nil { t.Fatal(err) } count, err := inspectField(id, "RestartCount") diff --git a/integration/runtime_test.go b/integration/runtime_test.go index 2e456eabfd..b399c37455 100644 --- a/integration/runtime_test.go +++ b/integration/runtime_test.go @@ -17,6 +17,7 @@ import ( "time" "github.com/Sirupsen/logrus" + apiserver "github.com/docker/docker/api/server" "github.com/docker/docker/daemon" "github.com/docker/docker/daemon/execdriver" "github.com/docker/docker/engine" @@ -157,9 +158,9 @@ func spawnGlobalDaemon() { Scheme: testDaemonProto, Host: testDaemonAddr, } - job := eng.Job("serveapi", listenURL.String()) - job.SetenvBool("Logging", true) - if err := job.Run(); err != nil { + + serverConfig := &apiserver.ServerConfig{Logging: true} + if err := apiserver.ServeApi([]string{listenURL.String()}, serverConfig, eng); err != nil { logrus.Fatalf("Unable to spawn the test daemon: %s", err) } }() @@ -168,9 +169,7 @@ func spawnGlobalDaemon() { // FIXME: use inmem transports instead of tcp time.Sleep(time.Second) - if err := eng.Job("acceptconnections").Run(); err != nil { - logrus.Fatalf("Unable to accept connections for test api: %s", err) - } + apiserver.AcceptConnections() } func spawnLegitHttpsDaemon() { @@ -207,14 +206,15 @@ func spawnHttpsDaemon(addr, cacert, cert, key string) *engine.Engine { Scheme: testDaemonHttpsProto, Host: addr, } - job := eng.Job("serveapi", listenURL.String()) - job.SetenvBool("Logging", true) - job.SetenvBool("Tls", true) - job.SetenvBool("TlsVerify", true) - job.Setenv("TlsCa", cacert) - job.Setenv("TlsCert", cert) - job.Setenv("TlsKey", key) - if err := job.Run(); err != nil { + 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 { logrus.Fatalf("Unable to spawn the test daemon: %s", err) } }() @@ -222,9 +222,8 @@ func spawnHttpsDaemon(addr, cacert, cert, key string) *engine.Engine { // Give some time to ListenAndServer to actually start time.Sleep(time.Second) - if err := eng.Job("acceptconnections").Run(); err != nil { - logrus.Fatalf("Unable to accept connections for test api: %s", err) - } + apiserver.AcceptConnections() + return eng } diff --git a/integration/utils_test.go b/integration/utils_test.go index befd924eaf..9479d4296c 100644 --- a/integration/utils_test.go +++ b/integration/utils_test.go @@ -17,7 +17,6 @@ import ( "github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar" "github.com/docker/docker/api/types" - "github.com/docker/docker/builtins" "github.com/docker/docker/daemon" "github.com/docker/docker/daemon/networkdriver/bridge" "github.com/docker/docker/engine" @@ -170,10 +169,6 @@ func newTestEngine(t Fataler, autorestart bool, root string) *engine.Engine { eng := engine.New() eng.Logging = false - // Load default plugins - if err := builtins.Register(eng); err != nil { - t.Fatal(err) - } // (This is manually copied and modified from main() until we have a more generic plugin system) cfg := &daemon.Config{