top_unix.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. //+build !windows
  2. package daemon
  3. import (
  4. "fmt"
  5. "os/exec"
  6. "strconv"
  7. "strings"
  8. "github.com/docker/engine-api/types"
  9. )
  10. // ContainerTop lists the processes running inside of the given
  11. // container by calling ps with the given args, or with the flags
  12. // "-ef" if no args are given. An error is returned if the container
  13. // is not found, or is not running, or if there are any problems
  14. // running ps, or parsing the output.
  15. func (daemon *Daemon) ContainerTop(name string, psArgs string) (*types.ContainerProcessList, error) {
  16. if psArgs == "" {
  17. psArgs = "-ef"
  18. }
  19. container, err := daemon.GetContainer(name)
  20. if err != nil {
  21. return nil, err
  22. }
  23. if !container.IsRunning() {
  24. return nil, errNotRunning{container.ID}
  25. }
  26. if container.IsRestarting() {
  27. return nil, errContainerIsRestarting(container.ID)
  28. }
  29. pids, err := daemon.ExecutionDriver().GetPidsForContainer(container.ID)
  30. if err != nil {
  31. return nil, err
  32. }
  33. output, err := exec.Command("ps", strings.Split(psArgs, " ")...).Output()
  34. if err != nil {
  35. return nil, fmt.Errorf("Error running ps: %v", err)
  36. }
  37. procList := &types.ContainerProcessList{}
  38. lines := strings.Split(string(output), "\n")
  39. procList.Titles = strings.Fields(lines[0])
  40. pidIndex := -1
  41. for i, name := range procList.Titles {
  42. if name == "PID" {
  43. pidIndex = i
  44. }
  45. }
  46. if pidIndex == -1 {
  47. return nil, fmt.Errorf("Couldn't find PID field in ps output")
  48. }
  49. // loop through the output and extract the PID from each line
  50. for _, line := range lines[1:] {
  51. if len(line) == 0 {
  52. continue
  53. }
  54. fields := strings.Fields(line)
  55. p, err := strconv.Atoi(fields[pidIndex])
  56. if err != nil {
  57. return nil, fmt.Errorf("Unexpected pid '%s': %s", fields[pidIndex], err)
  58. }
  59. for _, pid := range pids {
  60. if pid == p {
  61. // Make sure number of fields equals number of header titles
  62. // merging "overhanging" fields
  63. process := fields[:len(procList.Titles)-1]
  64. process = append(process, strings.Join(fields[len(procList.Titles)-1:], " "))
  65. procList.Processes = append(procList.Processes, process)
  66. }
  67. }
  68. }
  69. daemon.LogContainerEvent(container, "top")
  70. return procList, nil
  71. }