diff --git a/api.go b/api.go index de4113231c..fb7bbc4614 100644 --- a/api.go +++ b/api.go @@ -250,6 +250,23 @@ func getContainersChanges(srv *Server, version float64, w http.ResponseWriter, r return nil } +func getContainersProc(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { + if vars == nil { + return fmt.Errorf("Missing parameter") + } + name := vars["name"] + procsStr, err := srv.ContainerProc(name) + if err != nil { + return err + } + b, err := json.Marshal(procsStr) + if err != nil { + return err + } + writeJSON(w, b) + return nil +} + func getContainersJSON(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := parseForm(r); err != nil { return err @@ -842,6 +859,7 @@ func createRouter(srv *Server, logging bool) (*mux.Router, error) { "/containers/{name:.*}/export": getContainersExport, "/containers/{name:.*}/changes": getContainersChanges, "/containers/{name:.*}/json": getContainersByName, + "/containers/{name:.*}/proc": getContainersProc, }, "POST": { "/auth": postAuth, diff --git a/api_params.go b/api_params.go index b8af690c7f..89fe180d02 100644 --- a/api_params.go +++ b/api_params.go @@ -26,6 +26,13 @@ type APIInfo struct { SwapLimit bool `json:",omitempty"` } +type APIProc struct { + PID string + Tty string + Time string + Cmd string +} + type APIRmi struct { Deleted string `json:",omitempty"` Untagged string `json:",omitempty"` diff --git a/commands.go b/commands.go index 6ada02d552..73f9b949a9 100644 --- a/commands.go +++ b/commands.go @@ -90,6 +90,7 @@ func (cli *DockerCli) CmdHelp(args ...string) error { {"login", "Register or Login to the docker registry server"}, {"logs", "Fetch the logs of a container"}, {"port", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT"}, + {"proc", "Lookup the running processes of a container"}, {"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"}, @@ -555,6 +556,33 @@ func (cli *DockerCli) CmdInspect(args ...string) error { return nil } +func (cli *DockerCli) CmdProc(args ...string) error { + cmd := Subcmd("proc", "CONTAINER", "Lookup the running processes of a container") + if err := cmd.Parse(args); err != nil { + return nil + } + if cmd.NArg() != 1 { + cmd.Usage() + return nil + } + body, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/proc", nil) + if err != nil { + return err + } + var procs []APIProc + err = json.Unmarshal(body, &procs) + if err != nil { + return err + } + w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0) + fmt.Fprintln(w, "PID\tTTY\tTIME\tCMD") + for _, proc := range procs { + fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", proc.PID, proc.Tty, proc.Time, proc.Cmd) + } + w.Flush() + return nil +} + func (cli *DockerCli) CmdPort(args ...string) error { cmd := Subcmd("port", "CONTAINER PRIVATE_PORT", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT") if err := cmd.Parse(args); err != nil { diff --git a/server.go b/server.go index cdc01c6b09..7d292fc645 100644 --- a/server.go +++ b/server.go @@ -1,6 +1,7 @@ package docker import ( + "bufio" "errors" "fmt" "github.com/dotcloud/docker/auth" @@ -12,6 +13,7 @@ import ( "net/http" "net/url" "os" + "os/exec" "path" "runtime" "strings" @@ -247,6 +249,40 @@ func (srv *Server) ImageHistory(name string) ([]APIHistory, error) { } +func (srv *Server) ContainerProc(name string) ([]APIProc, error) { + if container := srv.runtime.Get(name); container != nil { + output, err := exec.Command("lxc-ps", "--name", container.ID).CombinedOutput() + if err != nil { + return nil, fmt.Errorf("Error trying to use lxc-ps: %s (%s)", err, output) + } + var procs []APIProc + for i, line := range strings.Split(string(output), "\n") { + if i == 0 || len(line) == 0 { + continue + } + proc := APIProc{} + scanner := bufio.NewScanner(strings.NewReader(line)) + scanner.Split(bufio.ScanWords) + if !scanner.Scan() { + return nil, fmt.Errorf("Error trying to use lxc-ps") + } + // no scanner.Text because we skip container id + scanner.Scan() + proc.PID = scanner.Text() + scanner.Scan() + proc.Tty = scanner.Text() + scanner.Scan() + proc.Time = scanner.Text() + scanner.Scan() + proc.Cmd = scanner.Text() + procs = append(procs, proc) + } + return procs, nil + + } + return nil, fmt.Errorf("No such container: %s", name) +} + func (srv *Server) ContainerChanges(name string) ([]Change, error) { if container := srv.runtime.Get(name); container != nil { return container.Changes() diff --git a/utils/utils.go b/utils/utils.go index e5b2a0f4fd..2f2a52867e 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -78,7 +78,7 @@ func (r *progressReader) Read(p []byte) (n int, err error) { read, err := io.ReadCloser(r.reader).Read(p) r.readProgress += read - updateEvery := 1024*512 //512kB + updateEvery := 1024 * 512 //512kB if r.readTotal > 0 { // Update progress for every 1% read if 1% < 512kB if increment := int(0.01 * float64(r.readTotal)); increment < updateEvery {