top_unix.go 2.0 KB

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