diff --git a/api/client/lib/version.go b/api/client/lib/version.go new file mode 100644 index 0000000000..0164a05007 --- /dev/null +++ b/api/client/lib/version.go @@ -0,0 +1,50 @@ +package lib + +import ( + "encoding/json" + "runtime" + + "github.com/docker/docker/api" + "github.com/docker/docker/api/types" + "github.com/docker/docker/dockerversion" + "github.com/docker/docker/utils" +) + +// VersionResponse holds version information for the client and the server +type VersionResponse struct { + Client *types.Version + Server *types.Version +} + +// ServerOK return true when the client could connect to the docker server +// and parse the information received. It returns false otherwise. +func (v VersionResponse) ServerOK() bool { + return v.Server == nil +} + +// SystemVersion returns information of the docker client and server host. +func (cli *Client) SystemVersion() (VersionResponse, error) { + client := &types.Version{ + Version: dockerversion.Version, + APIVersion: api.Version, + GoVersion: runtime.Version(), + GitCommit: dockerversion.GitCommit, + BuildTime: dockerversion.BuildTime, + Os: runtime.GOOS, + Arch: runtime.GOARCH, + Experimental: utils.ExperimentalBuild(), + } + + resp, err := cli.GET("/version", nil, nil) + if err != nil { + return VersionResponse{Client: client}, err + } + defer ensureReaderClosed(resp) + + var server types.Version + err = json.NewDecoder(resp.body).Decode(&server) + if err != nil { + return VersionResponse{Client: client}, err + } + return types.VersionResponse{Client: client, Server: &server}, nil +} diff --git a/api/client/version.go b/api/client/version.go index 188d56684e..2f28feca3d 100644 --- a/api/client/version.go +++ b/api/client/version.go @@ -1,17 +1,11 @@ package client import ( - "encoding/json" - "runtime" "text/template" "time" - "github.com/docker/docker/api" - "github.com/docker/docker/api/types" Cli "github.com/docker/docker/cli" - "github.com/docker/docker/dockerversion" flag "github.com/docker/docker/pkg/mflag" - "github.com/docker/docker/utils" ) var versionTemplate = `Client: @@ -32,12 +26,6 @@ Server: OS/Arch: {{.Server.Os}}/{{.Server.Arch}}{{if .Server.Experimental}} Experimental: {{.Server.Experimental}}{{end}}{{end}}` -type versionData struct { - Client types.Version - ServerOK bool - Server types.Version -} - // CmdVersion shows Docker version information. // // Available version information is shown for: client Docker version, client API version, client Go version, client Git commit, client OS/Arch, server Docker version, server API version, server Go version, server Git commit, and server OS/Arch. @@ -49,59 +37,36 @@ func (cli *DockerCli) CmdVersion(args ...string) (err error) { cmd.Require(flag.Exact, 0) cmd.ParseFlags(args, true) - if *tmplStr == "" { - *tmplStr = versionTemplate + + templateFormat := versionTemplate + if *tmplStr != "" { + templateFormat = *tmplStr } var tmpl *template.Template - if tmpl, err = template.New("").Funcs(funcMap).Parse(*tmplStr); err != nil { + if tmpl, err = template.New("").Funcs(funcMap).Parse(templateFormat); err != nil { return Cli.StatusError{StatusCode: 64, Status: "Template parsing error: " + err.Error()} } - vd := versionData{ - Client: types.Version{ - Version: dockerversion.Version, - APIVersion: api.Version, - GoVersion: runtime.Version(), - GitCommit: dockerversion.GitCommit, - BuildTime: dockerversion.BuildTime, - Os: runtime.GOOS, - Arch: runtime.GOARCH, - Experimental: utils.ExperimentalBuild(), - }, + vd, err := cli.client.SystemVersion() + + // first we need to make BuildTime more human friendly + t, errTime := time.Parse(time.RFC3339Nano, vd.Client.BuildTime) + if errTime == nil { + vd.Client.BuildTime = t.Format(time.ANSIC) } - defer func() { - // first we need to make BuildTime more human friendly - t, errTime := time.Parse(time.RFC3339Nano, vd.Client.BuildTime) - if errTime == nil { - vd.Client.BuildTime = t.Format(time.ANSIC) - } + if vd.ServerOK() { t, errTime = time.Parse(time.RFC3339Nano, vd.Server.BuildTime) if errTime == nil { vd.Server.BuildTime = t.Format(time.ANSIC) } - - if err2 := tmpl.Execute(cli.out, vd); err2 != nil && err == nil { - err = err2 - } - cli.out.Write([]byte{'\n'}) - }() - - serverResp, err := cli.call("GET", "/version", nil, nil) - if err != nil { - return err } - defer serverResp.body.Close() - - if err = json.NewDecoder(serverResp.body).Decode(&vd.Server); err != nil { - return Cli.StatusError{StatusCode: 1, - Status: "Error reading remote version: " + err.Error()} + if err2 := tmpl.Execute(cli.out, vd); err2 != nil && err == nil { + err = err2 } - - vd.ServerOK = true - - return + cli.out.Write([]byte{'\n'}) + return err }