diff --git a/api.go b/api.go index 782276740b..776a0e725b 100644 --- a/api.go +++ b/api.go @@ -42,12 +42,46 @@ func ListenAndServe(addr string, rtime *Runtime) error { return } } else { - http.Error(w, "No such container: "+name, http.StatusInternalServerError) + http.Error(w, "No such container: "+name, http.StatusNotFound) return } w.WriteHeader(200) }) + r.Path("/images/{name:.*}").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + log.Println(r.Method, r.RequestURI) + vars := mux.Vars(r) + name := vars["name"] + + if image, err := rtime.repositories.LookupImage(name); err == nil && image != nil { + b, err := json.Marshal(image) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } else { + w.Write(b) + } + return + } + http.Error(w, "No such image: "+name, http.StatusNotFound) + }) + + r.Path("/containers/{name:.*}").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + log.Println(r.Method, r.RequestURI) + vars := mux.Vars(r) + name := vars["name"] + + if container := rtime.Get(name); container != nil { + b, err := json.Marshal(container) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } else { + w.Write(b) + } + return + } + http.Error(w, "No such container: "+name, http.StatusNotFound) + }) + r.Path("/images").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { log.Println(r.Method, r.RequestURI) if err := r.ParseForm(); err != nil { @@ -211,7 +245,33 @@ func ListenAndServe(addr string, rtime *Runtime) error { } } else { - http.Error(w, "No such container: "+name, http.StatusInternalServerError) + http.Error(w, "No such container: "+name, http.StatusNotFound) + } + }) + + r.Path("/containers/{name:.*}/changes").Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + log.Println(r.Method, r.RequestURI) + vars := mux.Vars(r) + name := vars["name"] + + if container := rtime.Get(name); container != nil { + changes, err := container.Changes() + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + var changesStr []string + for _, name := range changes { + changesStr = append(changesStr, name.String()) + } + b, err := json.Marshal(changesStr) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } else { + w.Write(b) + } + } else { + http.Error(w, "No such container: "+name, http.StatusNotFound) } }) @@ -225,7 +285,7 @@ func ListenAndServe(addr string, rtime *Runtime) error { name := vars["name"] if container := rtime.Get(name); container == nil { - http.Error(w, "No such container: "+name, http.StatusInternalServerError) + http.Error(w, "No such container: "+name, http.StatusNotFound) return } else { if frontend, exists := container.NetworkSettings.PortMapping[privatePort]; !exists { @@ -423,7 +483,7 @@ func ListenAndServe(addr string, rtime *Runtime) error { return } } else { - http.Error(w, "No such container: "+name, http.StatusInternalServerError) + http.Error(w, "No such container: "+name, http.StatusNotFound) return } w.WriteHeader(200) @@ -439,7 +499,7 @@ func ListenAndServe(addr string, rtime *Runtime) error { return } } else { - http.Error(w, "No such container: "+name, http.StatusInternalServerError) + http.Error(w, "No such container: "+name, http.StatusNotFound) return } w.WriteHeader(200) @@ -452,7 +512,7 @@ func ListenAndServe(addr string, rtime *Runtime) error { img, err := rtime.repositories.LookupImage(name) if err != nil { - http.Error(w, "No such image: "+name, http.StatusInternalServerError) + http.Error(w, "No such image: "+name, http.StatusNotFound) return } else { if err := rtime.graph.Delete(img.Id); err != nil { @@ -473,7 +533,7 @@ func ListenAndServe(addr string, rtime *Runtime) error { return } } else { - http.Error(w, "No such container: "+name, http.StatusInternalServerError) + http.Error(w, "No such container: "+name, http.StatusNotFound) return } w.WriteHeader(200) @@ -489,11 +549,29 @@ func ListenAndServe(addr string, rtime *Runtime) error { return } } else { - http.Error(w, "No such container: "+name, http.StatusInternalServerError) + http.Error(w, "No such container: "+name, http.StatusNotFound) return } w.WriteHeader(200) }) + r.Path("/containers/{name:.*}/wait").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + log.Println(r.Method, r.RequestURI) + vars := mux.Vars(r) + name := vars["name"] + if container := rtime.Get(name); container != nil { + b, err := json.Marshal(ApiWait{container.Wait()}) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } else { + w.Write(b) + } + return + } else { + http.Error(w, "No such container: "+name, http.StatusNotFound) + return + } + }) + return http.ListenAndServe(addr, r) } diff --git a/api_params.go b/api_params.go index 0b0254d5e9..cd6c77d1b1 100644 --- a/api_params.go +++ b/api_params.go @@ -44,3 +44,7 @@ type ApiVersion struct { GitCommit string MemoryLimitDisabled bool } + +type ApiWait struct { + StatusCode int +} diff --git a/commands.go b/commands.go index 2549e3823f..3065bc5410 100644 --- a/commands.go +++ b/commands.go @@ -26,8 +26,10 @@ var ( func ParseCommands(args []string) error { cmds := map[string]func(args []string) error{ + "diff": CmdDiff, "images": CmdImages, "info": CmdInfo, + "inspect": CmdInspect, "history": CmdHistory, "kill": CmdKill, "logs": CmdLogs, @@ -42,6 +44,7 @@ func ParseCommands(args []string) error { "start": CmdStart, "stop": CmdStop, "version": CmdVersion, + "wait": CmdWait, } if len(args) > 0 { @@ -60,13 +63,13 @@ func cmdHelp(args []string) error { for _, cmd := range [][]string{ // {"attach", "Attach to a running container"}, // {"commit", "Create a new image from a container's changes"}, - // {"diff", "Inspect changes on a container's filesystem"}, + {"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"}, {"images", "List images"}, // {"import", "Create a new filesystem image from the contents of a tarball"}, {"info", "Display system-wide information"}, - // {"inspect", "Return low-level information on a container"}, + {"inspect", "Return low-level information on a container/image"}, {"kill", "Kill a running container"}, // {"login", "Register or Login to the docker registry server"}, {"logs", "Fetch the logs of a container"}, @@ -82,7 +85,7 @@ func cmdHelp(args []string) error { {"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"}, + {"wait", "Block until a container stops, then print its exit code"}, } { help += fmt.Sprintf(" %-10.10s%s\n", cmd[0], cmd[1]) } @@ -190,10 +193,9 @@ func (srv *Server) CmdLogin(stdin io.ReadCloser, stdout rcli.DockerConn, args .. } */ -/* // 'docker wait': block until a container stops -func (srv *Server) CmdWait(stdin io.ReadCloser, stdout io.Writer, args ...string) error { - cmd := rcli.Subcmd(stdout, "wait", "CONTAINER [CONTAINER...]", "Block until a container stops, then print its exit code.") +func CmdWait(args []string) error { + cmd := Subcmd("wait", "CONTAINER [CONTAINER...]", "Block until a container stops, then print its exit code.") if err := cmd.Parse(args); err != nil { return nil } @@ -202,15 +204,20 @@ func (srv *Server) CmdWait(stdin io.ReadCloser, stdout io.Writer, args ...string return nil } for _, name := range cmd.Args() { - if container := srv.runtime.Get(name); container != nil { - fmt.Fprintln(stdout, container.Wait()) + body, err := call("POST", "/containers/"+name+"/wait") + if err != nil { + fmt.Printf("%s", err) } else { - return fmt.Errorf("No such container: %s", name) + var out ApiWait + err = json.Unmarshal(body, &out) + if err != nil { + return err + } + fmt.Println(out.StatusCode) } } return nil } -*/ // 'docker version': show version information func CmdVersion(args []string) error { @@ -334,42 +341,31 @@ func CmdStart(args []string) error { return nil } -/* -func (srv *Server) CmdInspect(stdin io.ReadCloser, stdout io.Writer, args ...string) error { - cmd := rcli.Subcmd(stdout, "inspect", "CONTAINER", "Return low-level information on a container") +func CmdInspect(args []string) error { + cmd := Subcmd("inspect", "CONTAINER|IMAGE", "Return low-level information on a container/image") if err := cmd.Parse(args); err != nil { return nil } - if cmd.NArg() < 1 { + if cmd.NArg() != 1 { cmd.Usage() return nil } - name := cmd.Arg(0) var obj interface{} - if container := srv.runtime.Get(name); container != nil { - obj = container - } else if image, err := srv.runtime.repositories.LookupImage(name); err == nil && image != nil { - obj = image - } else { - // No output means the object does not exist - // (easier to script since stdout and stderr are not differentiated atm) - return nil + var err error + obj, err = call("GET", "/containers/"+cmd.Arg(0)) + if err != nil { + obj, err = call("GET", "/images/"+cmd.Arg(0)) + if err != nil { + return err + } } - data, err := json.Marshal(obj) + b, err := json.MarshalIndent(obj, "", " ") if err != nil { return err } - indented := new(bytes.Buffer) - if err = json.Indent(indented, data, "", " "); err != nil { - return err - } - if _, err := io.Copy(stdout, indented); err != nil { - return err - } - stdout.Write([]byte{'\n'}) + fmt.Printf("%s\n", b) return nil } -*/ func CmdPort(args []string) error { cmd := Subcmd("port", "CONTAINER PRIVATE_PORT", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT") @@ -778,32 +774,31 @@ func (srv *Server) CmdExport(stdin io.ReadCloser, stdout io.Writer, args ...stri } */ -/* -func (srv *Server) CmdDiff(stdin io.ReadCloser, stdout io.Writer, args ...string) error { - cmd := rcli.Subcmd(stdout, - "diff", "CONTAINER", - "Inspect changes on a container's filesystem") +func CmdDiff(args []string) error { + cmd := Subcmd("diff", "CONTAINER", "Inspect changes on a container's filesystem") if err := cmd.Parse(args); err != nil { return nil } - if cmd.NArg() < 1 { + if cmd.NArg() != 1 { cmd.Usage() return nil } - if container := srv.runtime.Get(cmd.Arg(0)); container == nil { - return fmt.Errorf("No such container") - } else { - changes, err := container.Changes() - if err != nil { - return err - } - for _, change := range changes { - fmt.Fprintln(stdout, change.String()) - } + + body, err := call("GET", "/containers/"+cmd.Arg(0)+"/changes") + if err != nil { + return err + } + + var changes []string + err = json.Unmarshal(body, &changes) + if err != nil { + return err + } + for _, change := range changes { + fmt.Println(change) } return nil } -*/ func CmdLogs(args []string) error { cmd := Subcmd("logs", "CONTAINER", "Fetch the logs of a container")