This commit is contained in:
Victor Vieux 2013-07-19 10:06:32 +00:00
Родитель d6fb313220
Коммит cfec1c3e1b
5 изменённых файлов: 50 добавлений и 35 удалений

6
api.go
Просмотреть файл

@ -255,8 +255,12 @@ func getContainersTop(srv *Server, version float64, w http.ResponseWriter, r *ht
if vars == nil { if vars == nil {
return fmt.Errorf("Missing parameter") return fmt.Errorf("Missing parameter")
} }
if err := parseForm(r); err != nil {
return err
}
name := vars["name"] name := vars["name"]
procsStr, err := srv.ContainerTop(name) ps_args := r.Form.Get("ps_args")
procsStr, err := srv.ContainerTop(name, ps_args)
if err != nil { if err != nil {
return err return err
} }

Просмотреть файл

@ -27,10 +27,8 @@ type APIInfo struct {
} }
type APITop struct { type APITop struct {
PID string Titles []string
Tty string Processes [][]string
Time string
Cmd string
} }
type APIRmi struct { type APIRmi struct {

Просмотреть файл

@ -444,24 +444,33 @@ func TestGetContainersTop(t *testing.T) {
} }
r := httptest.NewRecorder() r := httptest.NewRecorder()
if err := getContainersTop(srv, APIVERSION, r, nil, map[string]string{"name": container.ID}); err != nil { req, err := http.NewRequest("GET", "/"+container.ID+"/top?ps_args=u", bytes.NewReader([]byte{}))
if err != nil {
t.Fatal(err) t.Fatal(err)
} }
procs := []APITop{} if err := getContainersTop(srv, APIVERSION, r, req, map[string]string{"name": container.ID}); err != nil {
t.Fatal(err)
}
procs := APITop{}
if err := json.Unmarshal(r.Body.Bytes(), &procs); err != nil { if err := json.Unmarshal(r.Body.Bytes(), &procs); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if len(procs) != 2 { if len(procs.Titles) != 11 {
t.Fatalf("Expected 2 processes, found %d.", len(procs)) t.Fatalf("Expected 11 titles, found %d.", len(procs.Titles))
}
if procs.Titles[0] != "USER" || procs.Titles[10] != "COMMAND" {
t.Fatalf("Expected Titles[0] to be USER and Titles[10] to be COMMAND, found %s and %s.", procs.Titles[0], procs.Titles[10])
} }
if procs[0].Cmd != "sh" && procs[0].Cmd != "busybox" { if len(procs.Processes) != 2 {
t.Fatalf("Expected `busybox` or `sh`, found %s.", procs[0].Cmd) t.Fatalf("Expected 2 processes, found %d.", len(procs.Processes))
} }
if procs.Processes[0][10] != "/bin/sh" && procs.Processes[0][10] != "sleep" {
if procs[1].Cmd != "sh" && procs[1].Cmd != "busybox" { t.Fatalf("Expected `sleep` or `/bin/sh`, found %s.", procs.Processes[0][10])
t.Fatalf("Expected `busybox` or `sh`, found %s.", procs[1].Cmd) }
if procs.Processes[1][10] != "/bin/sh" && procs.Processes[1][10] != "sleep" {
t.Fatalf("Expected `sleep` or `/bin/sh`, found %s.", procs.Processes[1][10])
} }
} }

Просмотреть файл

@ -585,23 +585,28 @@ func (cli *DockerCli) CmdTop(args ...string) error {
if err := cmd.Parse(args); err != nil { if err := cmd.Parse(args); err != nil {
return nil return nil
} }
if cmd.NArg() != 1 { if cmd.NArg() == 0 {
cmd.Usage() cmd.Usage()
return nil return nil
} }
body, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/top", nil) val := url.Values{}
if cmd.NArg() > 1 {
val.Set("ps_args", strings.Join(cmd.Args()[1:], " "))
}
body, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/top?"+val.Encode(), nil)
if err != nil { if err != nil {
return err return err
} }
var procs []APITop procs := APITop{}
err = json.Unmarshal(body, &procs) err = json.Unmarshal(body, &procs)
if err != nil { if err != nil {
return err return err
} }
w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0) w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
fmt.Fprintln(w, "PID\tTTY\tTIME\tCMD") fmt.Fprintln(w, strings.Join(procs.Titles, "\t"))
for _, proc := range procs { for _, proc := range procs.Processes {
fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", proc.PID, proc.Tty, proc.Time, proc.Cmd) fmt.Fprintln(w, strings.Join(proc, "\t"))
} }
w.Flush() w.Flush()
return nil return nil

Просмотреть файл

@ -249,35 +249,34 @@ func (srv *Server) ImageHistory(name string) ([]APIHistory, error) {
} }
func (srv *Server) ContainerTop(name string) ([]APITop, error) { func (srv *Server) ContainerTop(name, ps_args string) (*APITop, error) {
if container := srv.runtime.Get(name); container != nil { if container := srv.runtime.Get(name); container != nil {
output, err := exec.Command("lxc-ps", "--name", container.ID).CombinedOutput() output, err := exec.Command("lxc-ps", "--name", container.ID, "--", ps_args).CombinedOutput()
if err != nil { if err != nil {
return nil, fmt.Errorf("Error trying to use lxc-ps: %s (%s)", err, output) return nil, fmt.Errorf("Error trying to use lxc-ps: %s (%s)", err, output)
} }
var procs []APITop procs := APITop{}
for i, line := range strings.Split(string(output), "\n") { for i, line := range strings.Split(string(output), "\n") {
if i == 0 || len(line) == 0 { if len(line) == 0 {
continue continue
} }
proc := APITop{} words := []string{}
scanner := bufio.NewScanner(strings.NewReader(line)) scanner := bufio.NewScanner(strings.NewReader(line))
scanner.Split(bufio.ScanWords) scanner.Split(bufio.ScanWords)
if !scanner.Scan() { if !scanner.Scan() {
return nil, fmt.Errorf("Error trying to use lxc-ps") return nil, fmt.Errorf("Error trying to use lxc-ps")
} }
// no scanner.Text because we skip container id // no scanner.Text because we skip container id
scanner.Scan() for scanner.Scan() {
proc.PID = scanner.Text() words = append(words, scanner.Text())
scanner.Scan() }
proc.Tty = scanner.Text() if i == 0 {
scanner.Scan() procs.Titles = words
proc.Time = scanner.Text() } else {
scanner.Scan() procs.Processes = append(procs.Processes, words)
proc.Cmd = scanner.Text() }
procs = append(procs, proc)
} }
return procs, nil return &procs, nil
} }
return nil, fmt.Errorf("No such container: %s", name) return nil, fmt.Errorf("No such container: %s", name)