exec.go 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. package container
  2. import (
  3. "bytes"
  4. "context"
  5. "github.com/docker/docker/api/types"
  6. "github.com/docker/docker/client"
  7. )
  8. // ExecResult represents a result returned from Exec()
  9. type ExecResult struct {
  10. ExitCode int
  11. outBuffer *bytes.Buffer
  12. errBuffer *bytes.Buffer
  13. }
  14. // Stdout returns stdout output of a command run by Exec()
  15. func (res *ExecResult) Stdout() string {
  16. return res.outBuffer.String()
  17. }
  18. // Stderr returns stderr output of a command run by Exec()
  19. func (res *ExecResult) Stderr() string {
  20. return res.errBuffer.String()
  21. }
  22. // Combined returns combined stdout and stderr output of a command run by Exec()
  23. func (res *ExecResult) Combined() string {
  24. return res.outBuffer.String() + res.errBuffer.String()
  25. }
  26. // Exec executes a command inside a container, returning the result
  27. // containing stdout, stderr, and exit code. Note:
  28. // - this is a synchronous operation;
  29. // - cmd stdin is closed.
  30. func Exec(ctx context.Context, apiClient client.APIClient, id string, cmd []string, ops ...func(*types.ExecConfig)) (ExecResult, error) {
  31. // prepare exec
  32. execConfig := types.ExecConfig{
  33. AttachStdout: true,
  34. AttachStderr: true,
  35. Cmd: cmd,
  36. }
  37. for _, op := range ops {
  38. op(&execConfig)
  39. }
  40. cresp, err := apiClient.ContainerExecCreate(ctx, id, execConfig)
  41. if err != nil {
  42. return ExecResult{}, err
  43. }
  44. execID := cresp.ID
  45. // run it, with stdout/stderr attached
  46. aresp, err := apiClient.ContainerExecAttach(ctx, execID, types.ExecStartCheck{})
  47. if err != nil {
  48. return ExecResult{}, err
  49. }
  50. // read the output
  51. s, err := demultiplexStreams(ctx, aresp)
  52. if err != nil {
  53. return ExecResult{}, err
  54. }
  55. // get the exit code
  56. iresp, err := apiClient.ContainerExecInspect(ctx, execID)
  57. if err != nil {
  58. return ExecResult{}, err
  59. }
  60. return ExecResult{ExitCode: iresp.ExitCode, outBuffer: &s.stdout, errBuffer: &s.stderr}, nil
  61. }