From da599fd557429b6cdf1eb080d722e0f5caab14f7 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Fri, 19 Apr 2013 15:24:37 +0200 Subject: [PATCH] added: info, history, logs, ps, start, stop, restart, rm, rmi Upstream-commit: b295239de20f15620ee4149fcc7c13ce461cdaac Component: engine --- components/engine/api.go | 323 ++++++++++++++++++++++++++- components/engine/api_params.go | 43 ++++ components/engine/commands.go | 2 +- components/engine/commands2.go | 378 +++++++++++++++++++++++++++++--- components/engine/container.go | 7 +- 5 files changed, 714 insertions(+), 39 deletions(-) diff --git a/components/engine/api.go b/components/engine/api.go index 4e2750b332..948b48d8bb 100644 --- a/components/engine/api.go +++ b/components/engine/api.go @@ -2,14 +2,18 @@ package docker import ( "encoding/json" - _ "fmt" + "fmt" "github.com/gorilla/mux" + "io/ioutil" "log" "net/http" + "os" + "runtime" + "strings" "time" ) -func ListenAndServe(addr string, runtime *Runtime) error { +func ListenAndServe(addr string, rtime *Runtime) error { r := mux.NewRouter() log.Printf("Listening for HTTP on %s\n", addr) @@ -32,7 +36,7 @@ func ListenAndServe(addr string, runtime *Runtime) error { var ret SimpleMessage for _, name := range ids { - container := runtime.Get(name) + container := rtime.Get(name) if container == nil { ret.Message = "No such container: " + name + "\n" break @@ -63,22 +67,22 @@ func ListenAndServe(addr string, runtime *Runtime) error { var allImages map[string]*Image var err error if in.All { - allImages, err = runtime.graph.Map() + allImages, err = rtime.graph.Map() } else { - allImages, err = runtime.graph.Heads() + allImages, err = rtime.graph.Heads() } if err != nil { w.WriteHeader(500) return } var outs []ImagesOut - for name, repository := range runtime.repositories.Repositories { + for name, repository := range rtime.repositories.Repositories { if in.NameFilter != "" && name != in.NameFilter { continue } for tag, id := range repository { var out ImagesOut - image, err := runtime.graph.Get(id) + image, err := rtime.graph.Get(id) if err != nil { log.Printf("Warning: couldn't load %s from %s/%s: %s", id, name, tag, err) continue @@ -113,7 +117,310 @@ func ListenAndServe(addr string, runtime *Runtime) error { b, err := json.Marshal(outs) if err != nil { - w.WriteHeader(500) + http.Error(w, err.Error(), http.StatusInternalServerError) + } else { + w.Write(b) + } + + }) + + r.Path("/info").Methods("GET", "POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + images, _ := rtime.graph.All() + var imgcount int + if images == nil { + imgcount = 0 + } else { + imgcount = len(images) + } + var out InfoOut + out.Containers = len(rtime.List()) + out.Version = VERSION + out.Images = imgcount + if os.Getenv("DEBUG") == "1" { + out.Debug = true + out.NFd = getTotalUsedFds() + out.NGoroutines = runtime.NumGoroutine() + } + b, err := json.Marshal(out) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } else { + w.Write(b) + } + }) + + r.Path("/history").Methods("GET", "POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + log.Println(r.RequestURI) + + var in HistoryIn + json.NewDecoder(r.Body).Decode(&in) + + image, err := rtime.repositories.LookupImage(in.Name) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + var outs []HistoryOut + err = image.WalkHistory(func(img *Image) error { + var out HistoryOut + out.Id = rtime.repositories.ImageName(img.ShortId()) + out.Created = HumanDuration(time.Now().Sub(img.Created)) + " ago" + out.CreatedBy = strings.Join(img.ContainerConfig.Cmd, " ") + return nil + }) + + b, err := json.Marshal(outs) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } else { + w.Write(b) + } + + }) + + r.Path("/logs").Methods("GET", "POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + + var in LogsIn + json.NewDecoder(r.Body).Decode(&in) + + if container := rtime.Get(in.Name); container != nil { + var out LogsOut + + logStdout, err := container.ReadLog("stdout") + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + logStderr, err := container.ReadLog("stderr") + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + stdout, errStdout := ioutil.ReadAll(logStdout) + if errStdout != nil { + http.Error(w, errStdout.Error(), http.StatusInternalServerError) + return + } else { + out.Stdout = fmt.Sprintf("%s", stdout) + } + stderr, errStderr := ioutil.ReadAll(logStderr) + if errStderr != nil { + http.Error(w, errStderr.Error(), http.StatusInternalServerError) + return + } else { + out.Stderr = fmt.Sprintf("%s", stderr) + } + + b, err := json.Marshal(out) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } else { + w.Write(b) + } + + } else { + http.Error(w, "No such container: "+in.Name, http.StatusInternalServerError) + } + }) + + r.Path("/ps").Methods("GET", "POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var in PsIn + json.NewDecoder(r.Body).Decode(&in) + + var outs []PsOut + + for i, container := range rtime.List() { + if !container.State.Running && !in.All && in.Last == -1 { + continue + } + if i == in.Last { + break + } + var out PsOut + out.Id = container.ShortId() + if !in.Quiet { + command := fmt.Sprintf("%s %s", container.Path, strings.Join(container.Args, " ")) + if !in.Full { + command = Trunc(command, 20) + } + out.Image = rtime.repositories.ImageName(container.Image) + out.Command = command + out.Created = HumanDuration(time.Now().Sub(container.Created)) + " ago" + out.Status = container.State.String() + } + outs = append(outs, out) + } + + b, err := json.Marshal(outs) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } else { + w.Write(b) + } + + }) + + r.Path("/restart").Methods("GET", "POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var ins, outs []string + json.NewDecoder(r.Body).Decode(&ins) + + for _, name := range ins { + if container := rtime.Get(name); container != nil { + if err := container.Restart(); err != nil { + http.Error(w, "Error restaring container "+name+": "+err.Error(), http.StatusInternalServerError) + return + } + outs = append(outs, container.ShortId()) + } else { + http.Error(w, "No such container: "+name, http.StatusInternalServerError) + return + } + } + b, err := json.Marshal(outs) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } else { + w.Write(b) + } + }) + + r.Path("/rm").Methods("GET", "POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var ins, outs []string + json.NewDecoder(r.Body).Decode(&ins) + + for _, name := range ins { + if container := rtime.Get(name); container != nil { + if err := rtime.Destroy(container); err != nil { + http.Error(w, "Error destroying container "+name+": "+err.Error(), http.StatusInternalServerError) + return + } + outs = append(outs, container.ShortId()) + } else { + http.Error(w, "No such container: "+name, http.StatusInternalServerError) + return + } + } + b, err := json.Marshal(outs) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } else { + w.Write(b) + } + + }) + + r.Path("/rmi").Methods("GET", "POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var ins, outs []string + json.NewDecoder(r.Body).Decode(&ins) + + for _, name := range ins { + img, err := rtime.repositories.LookupImage(name) + if err != nil { + http.Error(w, "No such image: "+name, http.StatusInternalServerError) + return + } else { + if err := rtime.graph.Delete(img.Id); err != nil { + http.Error(w, "Error deleting image "+name+": "+err.Error(), http.StatusInternalServerError) + return + } + outs = append(outs, img.ShortId()) + } + } + b, err := json.Marshal(outs) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } else { + w.Write(b) + } + + }) + + r.Path("/run").Methods("GET", "POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + + var config Config + json.NewDecoder(r.Body).Decode(&config) + + hj, ok := w.(http.Hijacker) + if !ok { + http.Error(w, "webserver doesn't support hijacking", http.StatusInternalServerError) + return + } + conn, bufrw, err := hj.Hijack() + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer conn.Close() + + //TODO config.Tty + + // Create new container + container, err := rtime.Create(&config) + if err != nil { + // If container not found, try to pull it + if rtime.graph.IsNotExist(err) { + bufrw.WriteString("Image " + config.Image + " not found, trying to pull it from registry.\r\n") + bufrw.Flush() + //TODO if err = srv.CmdPull(stdin, stdout, config.Image); err != nil { + //return err + //} + if container, err = rtime.Create(&config); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + } else { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + } + container = container + }) + + r.Path("/start").Methods("GET", "POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var ins, outs []string + json.NewDecoder(r.Body).Decode(&ins) + + for _, name := range ins { + if container := rtime.Get(name); container != nil { + if err := container.Start(); err != nil { + http.Error(w, "Error starting container "+name+": "+err.Error(), http.StatusInternalServerError) + return + } + outs = append(outs, container.ShortId()) + } else { + http.Error(w, "No such container: "+name, http.StatusInternalServerError) + return + } + } + b, err := json.Marshal(outs) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } else { + w.Write(b) + } + + }) + + r.Path("/stop").Methods("GET", "POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var ins, outs []string + json.NewDecoder(r.Body).Decode(&ins) + + for _, name := range ins { + if container := rtime.Get(name); container != nil { + if err := container.Stop(); err != nil { + http.Error(w, "Error stopping container "+name+": "+err.Error(), http.StatusInternalServerError) + return + } + outs = append(outs, container.ShortId()) + } else { + http.Error(w, "No such container: "+name, http.StatusInternalServerError) + return + } + } + b, err := json.Marshal(outs) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) } else { w.Write(b) } diff --git a/components/engine/api_params.go b/components/engine/api_params.go index f882b353db..4a2bbee139 100644 --- a/components/engine/api_params.go +++ b/components/engine/api_params.go @@ -4,6 +4,16 @@ type SimpleMessage struct { Message string } +type HistoryIn struct { + Name string +} + +type HistoryOut struct { + Id string + Created string + CreatedBy string +} + type ImagesIn struct { NameFilter string Quiet bool @@ -17,6 +27,39 @@ type ImagesOut struct { Created string `json:",omitempty"` } +type InfoOut struct { + Containers int + Version string + Images int + Debug bool + NFd int `json:",omitempty"` + NGoroutines int `json:",omitempty"` +} + +type PsIn struct { + Quiet bool + All bool + Full bool + Last int +} + +type PsOut struct { + Id string + Image string `json:",omitempty"` + Command string `json:",omitempty"` + Created string `json:",omitempty"` + Status string `json:",omitempty"` +} + +type LogsIn struct { + Name string +} + +type LogsOut struct { + Stdout string + Stderr string +} + type VersionOut struct { Version string GitCommit string diff --git a/components/engine/commands.go b/components/engine/commands.go index 59bd87d573..f7361b1a13 100644 --- a/components/engine/commands.go +++ b/components/engine/commands.go @@ -906,7 +906,7 @@ func (srv *Server) CmdTag(stdin io.ReadCloser, stdout io.Writer, args ...string) } func (srv *Server) CmdRun(stdin io.ReadCloser, stdout rcli.DockerConn, args ...string) error { - config, err := ParseRun(args, stdout) + config, err := ParseRun(args) if err != nil { return err } diff --git a/components/engine/commands2.go b/components/engine/commands2.go index a2bdedeec6..02056f543f 100644 --- a/components/engine/commands2.go +++ b/components/engine/commands2.go @@ -5,6 +5,7 @@ import ( "encoding/json" "flag" "fmt" + "io" "io/ioutil" "net/http" "os" @@ -15,7 +16,17 @@ func ParseCommands(args []string) error { cmds := map[string]func(args []string) error{ "images": cmdImages, + "info": cmdInfo, + "history": cmdHistory, "kill": cmdKill, + "logs": cmdLogs, + "ps": cmdPs, + "restart": cmdRestart, + "rm": cmdRm, + "rmi": cmdRmi, + "run": cmdRun, + "start": cmdStart, + "stop": cmdStop, "version": cmdVersion, } @@ -37,24 +48,24 @@ func cmdHelp(args []string) error { // {"commit", "Create a new image from a container's changes"}, // {"diff", "Inspect changes on a container's filesystem"}, // {"export", "Stream the contents of a container as a tar archive"}, - // {"history", "Show the history of an image"}, + {"history", "Show the history of an image"}, {"images", "List images"}, // {"import", "Create a new filesystem image from the contents of a tarball"}, - // {"info", "Display system-wide information"}, + {"info", "Display system-wide information"}, // {"inspect", "Return low-level information on a container"}, {"kill", "Kill a running container"}, // {"login", "Register or Login to the docker registry server"}, - // {"logs", "Fetch the logs of a container"}, + {"logs", "Fetch the logs of a container"}, // {"port", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT"}, - // {"ps", "List containers"}, + {"ps", "List containers"}, // {"pull", "Pull an image or a repository from the docker registry server"}, // {"push", "Push an image or a repository to the docker registry server"}, - // {"restart", "Restart a running container"}, - // {"rm", "Remove a container"}, - // {"rmi", "Remove an image"}, - // {"run", "Run a command in a new container"}, - // {"start", "Start a stopped container"}, - // {"stop", "Stop a running container"}, + {"restart", "Restart a running container"}, + {"rm", "Remove a container"}, + {"rmi", "Remove an image"}, + {"run", "Run a command in a new container"}, + {"start", "Start a stopped container"}, + {"stop", "Stop a running container"}, // {"tag", "Tag an image into a repository"}, {"version", "Show the docker version information"}, // {"wait", "Block until a container stops, then print its exit code"}, @@ -66,9 +77,10 @@ func cmdHelp(args []string) error { } func cmdImages(args []string) error { - cmd := subcmd("images", "[OPTIONS] [NAME]", "List images") - quiet := cmd.Bool("q", false, "only show numeric IDs") - flAll := cmd.Bool("a", false, "show all images") + cmd := Subcmd("images", "[OPTIONS] [NAME]", "List images") + var in ImagesIn + cmd.BoolVar(&in.Quiet, "q", false, "only show numeric IDs") + cmd.BoolVar(&in.All, "a", false, "show all images") if err := cmd.Parse(args); err != nil { return nil } @@ -76,13 +88,10 @@ func cmdImages(args []string) error { cmd.Usage() return nil } - var nameFilter string if cmd.NArg() == 1 { - nameFilter = cmd.Arg(0) + in.NameFilter = cmd.Arg(0) } - in := ImagesIn{nameFilter, *quiet, *flAll} - body, err := apiPost("images", in) if err != nil { return err @@ -94,27 +103,86 @@ func cmdImages(args []string) error { return err } w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0) - if !*quiet { + if !in.Quiet { fmt.Fprintln(w, "REPOSITORY\tTAG\tID\tCREATED") } for _, out := range outs { - if !*quiet { + if !in.Quiet { fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", out.Repository, out.Tag, out.Id, out.Created) } else { fmt.Fprintln(w, out.Id) } } - if !*quiet { + if !in.Quiet { w.Flush() } return nil } +func cmdInfo(args []string) error { + cmd := Subcmd("info", "", "Display system-wide information") + if err := cmd.Parse(args); err != nil { + return nil + } + if cmd.NArg() > 0 { + cmd.Usage() + return nil + } + + body, err := apiGet("info") + if err != nil { + return err + } + + var out InfoOut + err = json.Unmarshal(body, &out) + if err != nil { + return err + } + fmt.Printf("containers: %d\nversion: %s\nimages: %d\n", out.Containers, out.Version, out.Images) + if out.Debug { + fmt.Println("debug mode enabled") + fmt.Printf("fds: %d\ngoroutines: %d\n", out.NFd, out.NGoroutines) + } + return nil + +} + +func cmdHistory(args []string) error { + cmd := Subcmd("history", "IMAGE", "Show the history of an image") + if err := cmd.Parse(args); err != nil { + return nil + } + if cmd.NArg() != 1 { + cmd.Usage() + return nil + } + + body, err := apiPost("history", HistoryIn{cmd.Arg(0)}) + if err != nil { + return err + } + + var outs []HistoryOut + err = json.Unmarshal(body, &outs) + if err != nil { + return err + } + w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0) + fmt.Fprintln(w, "ID\tCREATED\tCREATED BY") + + for _, out := range outs { + fmt.Fprintf(w, "%s\t%s\t%s\n", out.Id, out.Created, out.CreatedBy) + } + w.Flush() + return nil +} + func cmdKill(args []string) error { - cmd := subcmd("kill", "CONTAINER [CONTAINER...]", "Kill a running container") + cmd := Subcmd("kill", "CONTAINER [CONTAINER...]", "Kill a running container") if err := cmd.Parse(args); err != nil { return nil } @@ -137,7 +205,247 @@ func cmdKill(args []string) error { return nil } -func cmdVersion(_ []string) error { +func cmdLogs(args []string) error { + cmd := Subcmd("logs", "CONTAINER", "Fetch the logs of a container") + if err := cmd.Parse(args); err != nil { + return nil + } + if cmd.NArg() != 1 { + cmd.Usage() + return nil + } + body, err := apiPost("logs", LogsIn{cmd.Arg(0)}) + if err != nil { + return err + } + + var out LogsOut + err = json.Unmarshal(body, &out) + if err != nil { + return err + } + fmt.Fprintln(os.Stdout, out.Stdout) + fmt.Fprintln(os.Stderr, out.Stderr) + + return nil +} + +func cmdPs(args []string) error { + cmd := Subcmd("ps", "[OPTIONS]", "List containers") + var in PsIn + cmd.BoolVar(&in.Quiet, "q", false, "Only display numeric IDs") + cmd.BoolVar(&in.All, "a", false, "Show all containers. Only running containers are shown by default.") + cmd.BoolVar(&in.Full, "notrunc", false, "Don't truncate output") + nLatest := cmd.Bool("l", false, "Show only the latest created container, include non-running ones.") + cmd.IntVar(&in.Last, "n", -1, "Show n last created containers, include non-running ones.") + if err := cmd.Parse(args); err != nil { + return nil + } + if in.Last == -1 && *nLatest { + in.Last = 1 + } + + body, err := apiPost("ps", in) + if err != nil { + return err + } + + var outs []PsOut + err = json.Unmarshal(body, &outs) + if err != nil { + return err + } + w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0) + if !in.Quiet { + fmt.Fprintln(w, "ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS") + } + + for _, out := range outs { + if !in.Quiet { + fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", out.Id, out.Image, out.Command, out.Status, out.Created) + } else { + fmt.Fprintln(w, out.Id) + } + } + + if !in.Quiet { + w.Flush() + } + return nil +} + +func cmdRestart(args []string) error { + cmd := Subcmd("restart", "CONTAINER [CONTAINER...]", "Restart a running container") + if err := cmd.Parse(args); err != nil { + return nil + } + if cmd.NArg() < 1 { + cmd.Usage() + return nil + } + + body, err := apiPost("restart", cmd.Args()) + if err != nil { + return err + } + + var out []string + err = json.Unmarshal(body, &out) + if err != nil { + return err + } + for _, name := range out { + fmt.Println(name) + } + return nil +} + +func cmdRm(args []string) error { + cmd := Subcmd("rm", "CONTAINER [CONTAINER...]", "Remove a container") + if err := cmd.Parse(args); err != nil { + return nil + } + if cmd.NArg() < 1 { + cmd.Usage() + return nil + } + + body, err := apiPost("rm", cmd.Args()) + if err != nil { + return err + } + + var out []string + err = json.Unmarshal(body, &out) + if err != nil { + return err + } + for _, name := range out { + fmt.Println(name) + } + return nil +} + +func cmdRmi(args []string) error { + cmd := Subcmd("rmi", "IMAGE [IMAGE...]", "Remove an image") + if err := cmd.Parse(args); err != nil { + return nil + } + if cmd.NArg() < 1 { + cmd.Usage() + return nil + } + + body, err := apiPost("rmi", cmd.Args()) + if err != nil { + return err + } + + var out []string + err = json.Unmarshal(body, &out) + if err != nil { + return err + } + for _, name := range out { + fmt.Println(name) + } + return nil +} + +func cmdRun(args []string) error { + config, err := ParseRun(args) + if err != nil { + return err + } + if config.Image == "" { + fmt.Println("Error: Image not specified") + return fmt.Errorf("Image not specified") + } + if len(config.Cmd) == 0 { + fmt.Println("Error: Command not specified") + return fmt.Errorf("Command not specified") + } + + body, err := apiPostHijack("run", config) + if err != nil { + return err + } + defer body.Close() + + /*str, err2 := ioutil.ReadAll(body) + if err2 != nil { + return err2 + } + fmt.Println(str)*/ + return nil + +} + +func cmdStart(args []string) error { + cmd := Subcmd("start", "CONTAINER [CONTAINER...]", "Restart a stopped container") + if err := cmd.Parse(args); err != nil { + return nil + } + if cmd.NArg() < 1 { + cmd.Usage() + return nil + } + + body, err := apiPost("start", cmd.Args()) + if err != nil { + return err + } + + var out []string + err = json.Unmarshal(body, &out) + if err != nil { + return err + } + for _, name := range out { + fmt.Println(name) + } + + return nil + +} + +func cmdStop(args []string) error { + cmd := Subcmd("stop", "CONTAINER [CONTAINER...]", "Restart a running container") + if err := cmd.Parse(args); err != nil { + return nil + } + if cmd.NArg() < 1 { + cmd.Usage() + return nil + } + + body, err := apiPost("stop", cmd.Args()) + if err != nil { + return err + } + + var out []string + err = json.Unmarshal(body, &out) + if err != nil { + return err + } + for _, name := range out { + fmt.Println(name) + } + return nil + +} + +func cmdVersion(args []string) error { + cmd := Subcmd("version", "", "Show the docker version information.") + if err := cmd.Parse(args); err != nil { + return nil + } + if cmd.NArg() > 0 { + cmd.Usage() + return nil + } + body, err := apiGet("version") if err != nil { return err @@ -162,12 +470,14 @@ func apiGet(path string) ([]byte, error) { if err != nil { return nil, err } - //TODO check status code defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, err } + if resp.StatusCode != 200 { + return nil, fmt.Errorf("error: %s", body) + } return body, nil } @@ -182,17 +492,33 @@ func apiPost(path string, data interface{}) ([]byte, error) { if err != nil { return nil, err } - //TODO check status code defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, err } + if resp.StatusCode != 200 { + return nil, fmt.Errorf("[error] %s", body) + } return body, nil - } -func subcmd(name, signature, description string) *flag.FlagSet { +func apiPostHijack(path string, data interface{}) (io.ReadCloser, error) { + buf, err := json.Marshal(data) + if err != nil { + return nil, err + } + dataBuf := bytes.NewBuffer(buf) + resp, err := http.Post("http://0.0.0.0:4243/"+path, "application/json", dataBuf) + if err != nil { + return nil, err + } + //TODO check status code + + return resp.Body, nil +} + +func Subcmd(name, signature, description string) *flag.FlagSet { flags := flag.NewFlagSet(name, flag.ContinueOnError) flags.Usage = func() { fmt.Printf("\nUsage: docker %s %s\n\n%s\n\n", name, signature, description) diff --git a/components/engine/container.go b/components/engine/container.go index 74706a4079..96cd423a06 100644 --- a/components/engine/container.go +++ b/components/engine/container.go @@ -3,7 +3,6 @@ package docker import ( "encoding/json" "fmt" - "github.com/dotcloud/docker/rcli" "github.com/kr/pty" "io" "io/ioutil" @@ -66,8 +65,8 @@ type Config struct { Image string // Name of the image as it was passed by the operator (eg. could be symbolic) } -func ParseRun(args []string, stdout io.Writer) (*Config, error) { - cmd := rcli.Subcmd(stdout, "run", "[OPTIONS] IMAGE COMMAND [ARG...]", "Run a command in a new container") +func ParseRun(args []string) (*Config, error) { + cmd := Subcmd("run", "[OPTIONS] IMAGE COMMAND [ARG...]", "Run a command in a new container") if len(args) > 0 && args[0] != "--help" { cmd.SetOutput(ioutil.Discard) } @@ -82,7 +81,7 @@ func ParseRun(args []string, stdout io.Writer) (*Config, error) { flMemory := cmd.Int64("m", 0, "Memory limit (in bytes)") if *flMemory > 0 && NO_MEMORY_LIMIT { - fmt.Fprintf(stdout, "WARNING: This version of docker has been compiled without memory limit support. Discarding -m.") + fmt.Println("WARNING: This version of docker has been compiled without memory limit support. Discarding -m.") *flMemory = 0 }