utils.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. package client
  2. import (
  3. "encoding/base64"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "io/ioutil"
  8. "os"
  9. gosignal "os/signal"
  10. "path/filepath"
  11. "runtime"
  12. "time"
  13. "github.com/Sirupsen/logrus"
  14. "github.com/docker/docker/pkg/signal"
  15. "github.com/docker/docker/pkg/term"
  16. "github.com/docker/docker/registry"
  17. "github.com/docker/engine-api/client"
  18. "github.com/docker/engine-api/types"
  19. registrytypes "github.com/docker/engine-api/types/registry"
  20. )
  21. // encodeAuthToBase64 serializes the auth configuration as JSON base64 payload
  22. func encodeAuthToBase64(authConfig types.AuthConfig) (string, error) {
  23. buf, err := json.Marshal(authConfig)
  24. if err != nil {
  25. return "", err
  26. }
  27. return base64.URLEncoding.EncodeToString(buf), nil
  28. }
  29. func (cli *DockerCli) encodeRegistryAuth(index *registrytypes.IndexInfo) (string, error) {
  30. authConfig := registry.ResolveAuthConfig(cli.configFile.AuthConfigs, index)
  31. return encodeAuthToBase64(authConfig)
  32. }
  33. func (cli *DockerCli) registryAuthenticationPrivilegedFunc(index *registrytypes.IndexInfo, cmdName string) client.RequestPrivilegeFunc {
  34. return func() (string, error) {
  35. fmt.Fprintf(cli.out, "\nPlease login prior to %s:\n", cmdName)
  36. indexServer := registry.GetAuthConfigKey(index)
  37. authConfig, err := cli.configureAuth("", "", "", indexServer)
  38. if err != nil {
  39. return "", err
  40. }
  41. return encodeAuthToBase64(authConfig)
  42. }
  43. }
  44. func (cli *DockerCli) resizeTty(id string, isExec bool) {
  45. height, width := cli.getTtySize()
  46. cli.resizeTtyTo(id, height, width, isExec)
  47. }
  48. func (cli *DockerCli) resizeTtyTo(id string, height, width int, isExec bool) {
  49. if height == 0 && width == 0 {
  50. return
  51. }
  52. options := types.ResizeOptions{
  53. ID: id,
  54. Height: height,
  55. Width: width,
  56. }
  57. var err error
  58. if isExec {
  59. err = cli.client.ContainerExecResize(options)
  60. } else {
  61. err = cli.client.ContainerResize(options)
  62. }
  63. if err != nil {
  64. logrus.Debugf("Error resize: %s", err)
  65. }
  66. }
  67. // getExitCode perform an inspect on the container. It returns
  68. // the running state and the exit code.
  69. func getExitCode(cli *DockerCli, containerID string) (bool, int, error) {
  70. c, err := cli.client.ContainerInspect(containerID)
  71. if err != nil {
  72. // If we can't connect, then the daemon probably died.
  73. if err != client.ErrConnectionFailed {
  74. return false, -1, err
  75. }
  76. return false, -1, nil
  77. }
  78. return c.State.Running, c.State.ExitCode, nil
  79. }
  80. // getExecExitCode perform an inspect on the exec command. It returns
  81. // the running state and the exit code.
  82. func getExecExitCode(cli *DockerCli, execID string) (bool, int, error) {
  83. resp, err := cli.client.ContainerExecInspect(execID)
  84. if err != nil {
  85. // If we can't connect, then the daemon probably died.
  86. if err != client.ErrConnectionFailed {
  87. return false, -1, err
  88. }
  89. return false, -1, nil
  90. }
  91. return resp.Running, resp.ExitCode, nil
  92. }
  93. func (cli *DockerCli) monitorTtySize(id string, isExec bool) error {
  94. cli.resizeTty(id, isExec)
  95. if runtime.GOOS == "windows" {
  96. go func() {
  97. prevH, prevW := cli.getTtySize()
  98. for {
  99. time.Sleep(time.Millisecond * 250)
  100. h, w := cli.getTtySize()
  101. if prevW != w || prevH != h {
  102. cli.resizeTty(id, isExec)
  103. }
  104. prevH = h
  105. prevW = w
  106. }
  107. }()
  108. } else {
  109. sigchan := make(chan os.Signal, 1)
  110. gosignal.Notify(sigchan, signal.SIGWINCH)
  111. go func() {
  112. for range sigchan {
  113. cli.resizeTty(id, isExec)
  114. }
  115. }()
  116. }
  117. return nil
  118. }
  119. func (cli *DockerCli) getTtySize() (int, int) {
  120. if !cli.isTerminalOut {
  121. return 0, 0
  122. }
  123. ws, err := term.GetWinsize(cli.outFd)
  124. if err != nil {
  125. logrus.Debugf("Error getting size: %s", err)
  126. if ws == nil {
  127. return 0, 0
  128. }
  129. }
  130. return int(ws.Height), int(ws.Width)
  131. }
  132. func copyToFile(outfile string, r io.Reader) error {
  133. tmpFile, err := ioutil.TempFile(filepath.Dir(outfile), ".docker_temp_")
  134. if err != nil {
  135. return err
  136. }
  137. tmpPath := tmpFile.Name()
  138. _, err = io.Copy(tmpFile, r)
  139. tmpFile.Close()
  140. if err != nil {
  141. os.Remove(tmpPath)
  142. return err
  143. }
  144. if err = os.Rename(tmpPath, outfile); err != nil {
  145. os.Remove(tmpPath)
  146. return err
  147. }
  148. return nil
  149. }