From 615681f5177cef974d516d5814195c768e773dd2 Mon Sep 17 00:00:00 2001 From: John Howard Date: Thu, 9 Jul 2015 19:05:50 -0700 Subject: [PATCH] Windows: Remove meaningless warnings on docker info Signed-off-by: John Howard --- api/client/attach.go | 6 +++--- api/client/commit.go | 6 +++--- api/client/cp.go | 14 ++++++------- api/client/create.go | 10 +++++----- api/client/diff.go | 6 +++--- api/client/exec.go | 6 +++--- api/client/history.go | 6 +++--- api/client/images.go | 6 +++--- api/client/info.go | 41 ++++++++++++++++++++++---------------- api/client/login.go | 8 ++++---- api/client/logs.go | 4 ++-- api/client/network.go | 2 +- api/client/port.go | 6 +++--- api/client/ps.go | 6 +++--- api/client/rmi.go | 6 +++--- api/client/service.go | 2 +- api/client/start.go | 6 +++--- api/client/stats.go | 6 +++--- api/client/top.go | 6 +++--- api/client/utils.go | 46 ++++++++++++++++++++++++++----------------- api/client/version.go | 6 +++--- 21 files changed, 111 insertions(+), 94 deletions(-) diff --git a/api/client/attach.go b/api/client/attach.go index 389d342f7e..d851bfda34 100644 --- a/api/client/attach.go +++ b/api/client/attach.go @@ -23,15 +23,15 @@ func (cli *DockerCli) CmdAttach(args ...string) error { cmd.ParseFlags(args, true) - stream, _, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, nil) + serverResp, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, nil) if err != nil { return err } - defer stream.Close() + defer serverResp.body.Close() var c types.ContainerJSON - if err := json.NewDecoder(stream).Decode(&c); err != nil { + if err := json.NewDecoder(serverResp.body).Decode(&c); err != nil { return err } diff --git a/api/client/commit.go b/api/client/commit.go index 0f98c67182..2a14c084b8 100644 --- a/api/client/commit.go +++ b/api/client/commit.go @@ -67,14 +67,14 @@ func (cli *DockerCli) CmdCommit(args ...string) error { return err } } - stream, _, _, err := cli.call("POST", "/commit?"+v.Encode(), config, nil) + serverResp, err := cli.call("POST", "/commit?"+v.Encode(), config, nil) if err != nil { return err } - defer stream.Close() + defer serverResp.body.Close() - if err := json.NewDecoder(stream).Decode(&response); err != nil { + if err := json.NewDecoder(serverResp.body).Decode(&response); err != nil { return err } diff --git a/api/client/cp.go b/api/client/cp.go index 5cf72b9075..c838e12589 100644 --- a/api/client/cp.go +++ b/api/client/cp.go @@ -31,11 +31,11 @@ func (cli *DockerCli) CmdCp(args ...string) error { cfg := &types.CopyConfig{ Resource: info[1], } - stream, _, statusCode, err := cli.call("POST", "/containers/"+info[0]+"/copy", cfg, nil) - if stream != nil { - defer stream.Close() + serverResp, err := cli.call("POST", "/containers/"+info[0]+"/copy", cfg, nil) + if serverResp.body != nil { + defer serverResp.body.Close() } - if statusCode == 404 { + if serverResp.statusCode == 404 { return fmt.Errorf("No such container: %v", info[0]) } if err != nil { @@ -43,11 +43,11 @@ func (cli *DockerCli) CmdCp(args ...string) error { } hostPath := cmd.Arg(1) - if statusCode == 200 { + if serverResp.statusCode == 200 { if hostPath == "-" { - _, err = io.Copy(cli.out, stream) + _, err = io.Copy(cli.out, serverResp.body) } else { - err = archive.Untar(stream, hostPath, &archive.TarOptions{NoLchown: true}) + err = archive.Untar(serverResp.body, hostPath, &archive.TarOptions{NoLchown: true}) } if err != nil { return err diff --git a/api/client/create.go b/api/client/create.go index edd642f82e..d9df039785 100644 --- a/api/client/create.go +++ b/api/client/create.go @@ -95,9 +95,9 @@ func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runc } //create the container - stream, _, statusCode, err := cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, nil) + serverResp, err := cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, nil) //if image not found try to pull it - if statusCode == 404 && strings.Contains(err.Error(), config.Image) { + if serverResp.statusCode == 404 && strings.Contains(err.Error(), config.Image) { repo, tag := parsers.ParseRepositoryTag(config.Image) if tag == "" { tag = tags.DEFAULTTAG @@ -109,17 +109,17 @@ func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runc return nil, err } // Retry - if stream, _, _, err = cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, nil); err != nil { + if serverResp, err = cli.call("POST", "/containers/create?"+containerValues.Encode(), mergedConfig, nil); err != nil { return nil, err } } else if err != nil { return nil, err } - defer stream.Close() + defer serverResp.body.Close() var response types.ContainerCreateResponse - if err := json.NewDecoder(stream).Decode(&response); err != nil { + if err := json.NewDecoder(serverResp.body).Decode(&response); err != nil { return nil, err } for _, warning := range response.Warnings { diff --git a/api/client/diff.go b/api/client/diff.go index f3c3d319da..3dfbb00b98 100644 --- a/api/client/diff.go +++ b/api/client/diff.go @@ -26,15 +26,15 @@ func (cli *DockerCli) CmdDiff(args ...string) error { return fmt.Errorf("Container name cannot be empty") } - rdr, _, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/changes", nil, nil) + serverResp, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/changes", nil, nil) if err != nil { return err } - defer rdr.Close() + defer serverResp.body.Close() changes := []types.ContainerChange{} - if err := json.NewDecoder(rdr).Decode(&changes); err != nil { + if err := json.NewDecoder(serverResp.body).Decode(&changes); err != nil { return err } diff --git a/api/client/exec.go b/api/client/exec.go index 9b1b59ad8f..ec4d124c01 100644 --- a/api/client/exec.go +++ b/api/client/exec.go @@ -23,15 +23,15 @@ func (cli *DockerCli) CmdExec(args ...string) error { return StatusError{StatusCode: 1} } - stream, _, _, err := cli.call("POST", "/containers/"+execConfig.Container+"/exec", execConfig, nil) + serverResp, err := cli.call("POST", "/containers/"+execConfig.Container+"/exec", execConfig, nil) if err != nil { return err } - defer stream.Close() + defer serverResp.body.Close() var response types.ContainerExecCreateResponse - if err := json.NewDecoder(stream).Decode(&response); err != nil { + if err := json.NewDecoder(serverResp.body).Decode(&response); err != nil { return err } diff --git a/api/client/history.go b/api/client/history.go index ad40bb73bd..ca66524286 100644 --- a/api/client/history.go +++ b/api/client/history.go @@ -25,15 +25,15 @@ func (cli *DockerCli) CmdHistory(args ...string) error { cmd.ParseFlags(args, true) - rdr, _, _, err := cli.call("GET", "/images/"+cmd.Arg(0)+"/history", nil, nil) + serverResp, err := cli.call("GET", "/images/"+cmd.Arg(0)+"/history", nil, nil) if err != nil { return err } - defer rdr.Close() + defer serverResp.body.Close() history := []types.ImageHistory{} - if err := json.NewDecoder(rdr).Decode(&history); err != nil { + if err := json.NewDecoder(serverResp.body).Decode(&history); err != nil { return err } diff --git a/api/client/images.go b/api/client/images.go index a9740a4e74..93dc35bbca 100644 --- a/api/client/images.go +++ b/api/client/images.go @@ -62,15 +62,15 @@ func (cli *DockerCli) CmdImages(args ...string) error { v.Set("all", "1") } - rdr, _, _, err := cli.call("GET", "/images/json?"+v.Encode(), nil, nil) + serverResp, err := cli.call("GET", "/images/json?"+v.Encode(), nil, nil) if err != nil { return err } - defer rdr.Close() + defer serverResp.body.Close() images := []types.Image{} - if err := json.NewDecoder(rdr).Decode(&images); err != nil { + if err := json.NewDecoder(serverResp.body).Decode(&images); err != nil { return err } diff --git a/api/client/info.go b/api/client/info.go index 503dddd04d..985548ae70 100644 --- a/api/client/info.go +++ b/api/client/info.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/docker/docker/api/types" + "github.com/docker/docker/pkg/httputils" "github.com/docker/docker/pkg/ioutils" flag "github.com/docker/docker/pkg/mflag" "github.com/docker/docker/pkg/units" @@ -19,15 +20,15 @@ func (cli *DockerCli) CmdInfo(args ...string) error { cmd.ParseFlags(args, true) - rdr, _, _, err := cli.call("GET", "/info", nil, nil) + serverResp, err := cli.call("GET", "/info", nil, nil) if err != nil { return err } - defer rdr.Close() + defer serverResp.body.Close() info := &types.Info{} - if err := json.NewDecoder(rdr).Decode(info); err != nil { + if err := json.NewDecoder(serverResp.body).Decode(info); err != nil { return fmt.Errorf("Error reading remote info: %v", err) } @@ -70,21 +71,27 @@ func (cli *DockerCli) CmdInfo(args ...string) error { fmt.Fprintf(cli.out, "Registry: %v\n", info.IndexServerAddress) } } - if !info.MemoryLimit { - fmt.Fprintf(cli.err, "WARNING: No memory limit support\n") - } - if !info.SwapLimit { - fmt.Fprintf(cli.err, "WARNING: No swap limit support\n") - } - if !info.IPv4Forwarding { - fmt.Fprintf(cli.err, "WARNING: IPv4 forwarding is disabled.\n") - } - if !info.BridgeNfIptables { - fmt.Fprintf(cli.err, "WARNING: bridge-nf-call-iptables is disabled\n") - } - if !info.BridgeNfIp6tables { - fmt.Fprintf(cli.err, "WARNING: bridge-nf-call-ip6tables is disabled\n") + // Only output these warnings if the server supports these features + if h, err := httputils.ParseServerHeader(serverResp.header.Get("Server")); err == nil { + if h.OS != "windows" { + if !info.MemoryLimit { + fmt.Fprintf(cli.err, "WARNING: No memory limit support\n") + } + if !info.SwapLimit { + fmt.Fprintf(cli.err, "WARNING: No swap limit support\n") + } + if !info.IPv4Forwarding { + fmt.Fprintf(cli.err, "WARNING: IPv4 forwarding is disabled.\n") + } + if !info.BridgeNfIptables { + fmt.Fprintf(cli.err, "WARNING: bridge-nf-call-iptables is disabled\n") + } + if !info.BridgeNfIp6tables { + fmt.Fprintf(cli.err, "WARNING: bridge-nf-call-ip6tables is disabled\n") + } + } } + if info.Labels != nil { fmt.Fprintln(cli.out, "Labels:") for _, attribute := range info.Labels { diff --git a/api/client/login.go b/api/client/login.go index c88b6dac30..ea717a742e 100644 --- a/api/client/login.go +++ b/api/client/login.go @@ -113,8 +113,8 @@ func (cli *DockerCli) CmdLogin(args ...string) error { authconfig.ServerAddress = serverAddress cli.configFile.AuthConfigs[serverAddress] = authconfig - stream, _, statusCode, err := cli.call("POST", "/auth", cli.configFile.AuthConfigs[serverAddress], nil) - if statusCode == 401 { + serverResp, err := cli.call("POST", "/auth", cli.configFile.AuthConfigs[serverAddress], nil) + if serverResp.statusCode == 401 { delete(cli.configFile.AuthConfigs, serverAddress) if err2 := cli.configFile.Save(); err2 != nil { fmt.Fprintf(cli.out, "WARNING: could not save config file: %v\n", err2) @@ -125,10 +125,10 @@ func (cli *DockerCli) CmdLogin(args ...string) error { return err } - defer stream.Close() + defer serverResp.body.Close() var response types.AuthResponse - if err := json.NewDecoder(stream).Decode(&response); err != nil { + if err := json.NewDecoder(serverResp.body).Decode(&response); err != nil { // Upon error, remove entry delete(cli.configFile.AuthConfigs, serverAddress) return err diff --git a/api/client/logs.go b/api/client/logs.go index 2bcfb35cfd..0f4be3dac6 100644 --- a/api/client/logs.go +++ b/api/client/logs.go @@ -26,13 +26,13 @@ func (cli *DockerCli) CmdLogs(args ...string) error { name := cmd.Arg(0) - stream, _, _, err := cli.call("GET", "/containers/"+name+"/json", nil, nil) + serverResp, err := cli.call("GET", "/containers/"+name+"/json", nil, nil) if err != nil { return err } var c types.ContainerJSON - if err := json.NewDecoder(stream).Decode(&c); err != nil { + if err := json.NewDecoder(serverResp.body).Decode(&c); err != nil { return err } diff --git a/api/client/network.go b/api/client/network.go index f7c4e54f90..b550668be5 100644 --- a/api/client/network.go +++ b/api/client/network.go @@ -9,7 +9,7 @@ import ( ) func (cli *DockerCli) CmdNetwork(args ...string) error { - nCli := nwclient.NewNetworkCli(cli.out, cli.err, nwclient.CallFunc(cli.call)) + nCli := nwclient.NewNetworkCli(cli.out, cli.err, nwclient.CallFunc(cli.callWrapper)) args = append([]string{"network"}, args...) return nCli.Cmd(os.Args[0], args...) } diff --git a/api/client/port.go b/api/client/port.go index 5bbc920109..245bbfcc4c 100644 --- a/api/client/port.go +++ b/api/client/port.go @@ -19,12 +19,12 @@ func (cli *DockerCli) CmdPort(args ...string) error { cmd.ParseFlags(args, true) - stream, _, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, nil) + serverResp, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, nil) if err != nil { return err } - defer stream.Close() + defer serverResp.body.Close() var c struct { NetworkSettings struct { @@ -32,7 +32,7 @@ func (cli *DockerCli) CmdPort(args ...string) error { } } - if err := json.NewDecoder(stream).Decode(&c); err != nil { + if err := json.NewDecoder(serverResp.body).Decode(&c); err != nil { return err } diff --git a/api/client/ps.go b/api/client/ps.go index 10ac9db422..1a96c52d3d 100644 --- a/api/client/ps.go +++ b/api/client/ps.go @@ -86,15 +86,15 @@ func (cli *DockerCli) CmdPs(args ...string) error { v.Set("filters", filterJSON) } - rdr, _, _, err := cli.call("GET", "/containers/json?"+v.Encode(), nil, nil) + serverResp, err := cli.call("GET", "/containers/json?"+v.Encode(), nil, nil) if err != nil { return err } - defer rdr.Close() + defer serverResp.body.Close() containers := []types.Container{} - if err := json.NewDecoder(rdr).Decode(&containers); err != nil { + if err := json.NewDecoder(serverResp.body).Decode(&containers); err != nil { return err } diff --git a/api/client/rmi.go b/api/client/rmi.go index fc4629b76b..4bfbecc6e3 100644 --- a/api/client/rmi.go +++ b/api/client/rmi.go @@ -30,15 +30,15 @@ func (cli *DockerCli) CmdRmi(args ...string) error { var errNames []string for _, name := range cmd.Args() { - rdr, _, _, err := cli.call("DELETE", "/images/"+name+"?"+v.Encode(), nil, nil) + serverResp, err := cli.call("DELETE", "/images/"+name+"?"+v.Encode(), nil, nil) if err != nil { fmt.Fprintf(cli.err, "%s\n", err) errNames = append(errNames, name) } else { - defer rdr.Close() + defer serverResp.body.Close() dels := []types.ImageDelete{} - if err := json.NewDecoder(rdr).Decode(&dels); err != nil { + if err := json.NewDecoder(serverResp.body).Decode(&dels); err != nil { fmt.Fprintf(cli.err, "%s\n", err) errNames = append(errNames, name) continue diff --git a/api/client/service.go b/api/client/service.go index d7308449e0..6a1e3da87b 100644 --- a/api/client/service.go +++ b/api/client/service.go @@ -9,7 +9,7 @@ import ( ) func (cli *DockerCli) CmdService(args ...string) error { - nCli := nwclient.NewNetworkCli(cli.out, cli.err, nwclient.CallFunc(cli.call)) + nCli := nwclient.NewNetworkCli(cli.out, cli.err, nwclient.CallFunc(cli.callWrapper)) args = append([]string{"service"}, args...) return nCli.Cmd(os.Args[0], args...) } diff --git a/api/client/start.go b/api/client/start.go index 1639af1154..e78b45d58c 100644 --- a/api/client/start.go +++ b/api/client/start.go @@ -61,15 +61,15 @@ func (cli *DockerCli) CmdStart(args ...string) error { return fmt.Errorf("You cannot start and attach multiple containers at once.") } - stream, _, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, nil) + serverResp, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, nil) if err != nil { return err } - defer stream.Close() + defer serverResp.body.Close() var c types.ContainerJSON - if err := json.NewDecoder(stream).Decode(&c); err != nil { + if err := json.NewDecoder(serverResp.body).Decode(&c); err != nil { return err } diff --git a/api/client/stats.go b/api/client/stats.go index e76ca71547..a1fa37f51d 100644 --- a/api/client/stats.go +++ b/api/client/stats.go @@ -35,7 +35,7 @@ func (s *containerStats) Collect(cli *DockerCli, streamStats bool) { } else { v.Set("stream", "0") } - stream, _, _, err := cli.call("GET", "/containers/"+s.Name+"/stats?"+v.Encode(), nil, nil) + serverResp, err := cli.call("GET", "/containers/"+s.Name+"/stats?"+v.Encode(), nil, nil) if err != nil { s.mu.Lock() s.err = err @@ -43,12 +43,12 @@ func (s *containerStats) Collect(cli *DockerCli, streamStats bool) { return } - defer stream.Close() + defer serverResp.body.Close() var ( previousCPU uint64 previousSystem uint64 - dec = json.NewDecoder(stream) + dec = json.NewDecoder(serverResp.body) u = make(chan error, 1) ) go func() { diff --git a/api/client/top.go b/api/client/top.go index 736ba1a970..ac69a34c75 100644 --- a/api/client/top.go +++ b/api/client/top.go @@ -25,15 +25,15 @@ func (cli *DockerCli) CmdTop(args ...string) error { val.Set("ps_args", strings.Join(cmd.Args()[1:], " ")) } - stream, _, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/top?"+val.Encode(), nil, nil) + serverResp, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/top?"+val.Encode(), nil, nil) if err != nil { return err } - defer stream.Close() + defer serverResp.body.Close() procList := types.ContainerProcessList{} - if err := json.NewDecoder(stream).Decode(&procList); err != nil { + if err := json.NewDecoder(serverResp.body).Decode(&procList); err != nil { return err } diff --git a/api/client/utils.go b/api/client/utils.go index 8513fae383..cb25b94fef 100644 --- a/api/client/utils.go +++ b/api/client/utils.go @@ -170,10 +170,20 @@ func (cli *DockerCli) clientRequestAttemptLogin(method, path string, in io.Reade return body, statusCode, err } -func (cli *DockerCli) call(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, http.Header, int, error) { +func (cli *DockerCli) callWrapper(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, http.Header, int, error) { + sr, err := cli.call(method, path, data, headers) + return sr.body, sr.header, sr.statusCode, err +} + +func (cli *DockerCli) call(method, path string, data interface{}, headers map[string][]string) (*serverResponse, error) { params, err := cli.encodeData(data) if err != nil { - return nil, nil, -1, err + sr := &serverResponse{ + body: nil, + header: nil, + statusCode: -1, + } + return sr, nil } if data != nil { @@ -184,7 +194,7 @@ func (cli *DockerCli) call(method, path string, data interface{}, headers map[st } serverResp, err := cli.clientRequest(method, path, params, headers) - return serverResp.body, serverResp.header, serverResp.statusCode, err + return serverResp, err } type streamOpts struct { @@ -245,15 +255,15 @@ func (cli *DockerCli) resizeTty(id string, isExec bool) { } func waitForExit(cli *DockerCli, containerID string) (int, error) { - stream, _, _, err := cli.call("POST", "/containers/"+containerID+"/wait", nil, nil) + serverResp, err := cli.call("POST", "/containers/"+containerID+"/wait", nil, nil) if err != nil { return -1, err } - defer stream.Close() + defer serverResp.body.Close() var res types.ContainerWaitResponse - if err := json.NewDecoder(stream).Decode(&res); err != nil { + if err := json.NewDecoder(serverResp.body).Decode(&res); err != nil { return -1, err } @@ -263,7 +273,7 @@ func waitForExit(cli *DockerCli, containerID string) (int, error) { // getExitCode perform an inspect on the container. It returns // the running state and the exit code. func getExitCode(cli *DockerCli, containerID string) (bool, int, error) { - stream, _, _, err := cli.call("GET", "/containers/"+containerID+"/json", nil, nil) + serverResp, err := cli.call("GET", "/containers/"+containerID+"/json", nil, nil) if err != nil { // If we can't connect, then the daemon probably died. if err != errConnectionRefused { @@ -272,10 +282,10 @@ func getExitCode(cli *DockerCli, containerID string) (bool, int, error) { return false, -1, nil } - defer stream.Close() + defer serverResp.body.Close() var c types.ContainerJSON - if err := json.NewDecoder(stream).Decode(&c); err != nil { + if err := json.NewDecoder(serverResp.body).Decode(&c); err != nil { return false, -1, err } @@ -285,7 +295,7 @@ func getExitCode(cli *DockerCli, containerID string) (bool, int, error) { // getExecExitCode perform an inspect on the exec command. It returns // the running state and the exit code. func getExecExitCode(cli *DockerCli, execID string) (bool, int, error) { - stream, _, _, err := cli.call("GET", "/exec/"+execID+"/json", nil, nil) + serverResp, err := cli.call("GET", "/exec/"+execID+"/json", nil, nil) if err != nil { // If we can't connect, then the daemon probably died. if err != errConnectionRefused { @@ -294,7 +304,7 @@ func getExecExitCode(cli *DockerCli, execID string) (bool, int, error) { return false, -1, nil } - defer stream.Close() + defer serverResp.body.Close() //TODO: Should we reconsider having a type in api/types? //this is a response to exex/id/json not container @@ -303,7 +313,7 @@ func getExecExitCode(cli *DockerCli, execID string) (bool, int, error) { ExitCode int } - if err := json.NewDecoder(stream).Decode(&c); err != nil { + if err := json.NewDecoder(serverResp.body).Decode(&c); err != nil { return false, -1, err } @@ -353,16 +363,16 @@ func (cli *DockerCli) getTtySize() (int, int) { return int(ws.Height), int(ws.Width) } -func readBody(stream io.ReadCloser, hdr http.Header, statusCode int, err error) ([]byte, int, error) { - if stream != nil { - defer stream.Close() +func readBody(serverResp *serverResponse, err error) ([]byte, int, error) { + if serverResp.body != nil { + defer serverResp.body.Close() } if err != nil { - return nil, statusCode, err + return nil, serverResp.statusCode, err } - body, err := ioutil.ReadAll(stream) + body, err := ioutil.ReadAll(serverResp.body) if err != nil { return nil, -1, err } - return body, statusCode, nil + return body, serverResp.statusCode, nil } diff --git a/api/client/version.go b/api/client/version.go index c95608ee15..979e0c950c 100644 --- a/api/client/version.go +++ b/api/client/version.go @@ -40,15 +40,15 @@ func (cli *DockerCli) CmdVersion(args ...string) error { fmt.Fprintf(cli.out, " Experimental: true\n") } - stream, _, _, err := cli.call("GET", "/version", nil, nil) + serverResp, err := cli.call("GET", "/version", nil, nil) if err != nil { return err } - defer stream.Close() + defer serverResp.body.Close() var v types.Version - if err := json.NewDecoder(stream).Decode(&v); err != nil { + if err := json.NewDecoder(serverResp.body).Decode(&v); err != nil { fmt.Fprintf(cli.err, "Error reading remote version: %s\n", err) return err }