utils.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  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. func (cli *DockerCli) electAuthServer() string {
  22. // The daemon `/info` endpoint informs us of the default registry being
  23. // used. This is essential in cross-platforms environment, where for
  24. // example a Linux client might be interacting with a Windows daemon, hence
  25. // the default registry URL might be Windows specific.
  26. serverAddress := registry.IndexServer
  27. if info, err := cli.client.Info(); err != nil {
  28. fmt.Fprintf(cli.out, "Warning: failed to get default registry endpoint from daemon (%v). Using system default: %s\n", err, serverAddress)
  29. } else {
  30. serverAddress = info.IndexServerAddress
  31. }
  32. return serverAddress
  33. }
  34. // encodeAuthToBase64 serializes the auth configuration as JSON base64 payload
  35. func encodeAuthToBase64(authConfig types.AuthConfig) (string, error) {
  36. buf, err := json.Marshal(authConfig)
  37. if err != nil {
  38. return "", err
  39. }
  40. return base64.URLEncoding.EncodeToString(buf), nil
  41. }
  42. func (cli *DockerCli) registryAuthenticationPrivilegedFunc(index *registrytypes.IndexInfo, cmdName string) client.RequestPrivilegeFunc {
  43. return func() (string, error) {
  44. fmt.Fprintf(cli.out, "\nPlease login prior to %s:\n", cmdName)
  45. indexServer := registry.GetAuthConfigKey(index)
  46. authConfig, err := cli.configureAuth("", "", "", indexServer)
  47. if err != nil {
  48. return "", err
  49. }
  50. return encodeAuthToBase64(authConfig)
  51. }
  52. }
  53. func (cli *DockerCli) resizeTty(id string, isExec bool) {
  54. height, width := cli.getTtySize()
  55. cli.resizeTtyTo(id, height, width, isExec)
  56. }
  57. func (cli *DockerCli) resizeTtyTo(id string, height, width int, isExec bool) {
  58. if height == 0 && width == 0 {
  59. return
  60. }
  61. options := types.ResizeOptions{
  62. ID: id,
  63. Height: height,
  64. Width: width,
  65. }
  66. var err error
  67. if isExec {
  68. err = cli.client.ContainerExecResize(options)
  69. } else {
  70. err = cli.client.ContainerResize(options)
  71. }
  72. if err != nil {
  73. logrus.Debugf("Error resize: %s", err)
  74. }
  75. }
  76. // getExitCode perform an inspect on the container. It returns
  77. // the running state and the exit code.
  78. func getExitCode(cli *DockerCli, containerID string) (bool, int, error) {
  79. c, err := cli.client.ContainerInspect(containerID)
  80. if err != nil {
  81. // If we can't connect, then the daemon probably died.
  82. if err != client.ErrConnectionFailed {
  83. return false, -1, err
  84. }
  85. return false, -1, nil
  86. }
  87. return c.State.Running, c.State.ExitCode, nil
  88. }
  89. // getExecExitCode perform an inspect on the exec command. It returns
  90. // the running state and the exit code.
  91. func getExecExitCode(cli *DockerCli, execID string) (bool, int, error) {
  92. resp, err := cli.client.ContainerExecInspect(execID)
  93. if err != nil {
  94. // If we can't connect, then the daemon probably died.
  95. if err != client.ErrConnectionFailed {
  96. return false, -1, err
  97. }
  98. return false, -1, nil
  99. }
  100. return resp.Running, resp.ExitCode, nil
  101. }
  102. func (cli *DockerCli) monitorTtySize(id string, isExec bool) error {
  103. cli.resizeTty(id, isExec)
  104. if runtime.GOOS == "windows" {
  105. go func() {
  106. prevH, prevW := cli.getTtySize()
  107. for {
  108. time.Sleep(time.Millisecond * 250)
  109. h, w := cli.getTtySize()
  110. if prevW != w || prevH != h {
  111. cli.resizeTty(id, isExec)
  112. }
  113. prevH = h
  114. prevW = w
  115. }
  116. }()
  117. } else {
  118. sigchan := make(chan os.Signal, 1)
  119. gosignal.Notify(sigchan, signal.SIGWINCH)
  120. go func() {
  121. for range sigchan {
  122. cli.resizeTty(id, isExec)
  123. }
  124. }()
  125. }
  126. return nil
  127. }
  128. func (cli *DockerCli) getTtySize() (int, int) {
  129. if !cli.isTerminalOut {
  130. return 0, 0
  131. }
  132. ws, err := term.GetWinsize(cli.outFd)
  133. if err != nil {
  134. logrus.Debugf("Error getting size: %s", err)
  135. if ws == nil {
  136. return 0, 0
  137. }
  138. }
  139. return int(ws.Height), int(ws.Width)
  140. }
  141. func copyToFile(outfile string, r io.Reader) error {
  142. tmpFile, err := ioutil.TempFile(filepath.Dir(outfile), ".docker_temp_")
  143. if err != nil {
  144. return err
  145. }
  146. tmpPath := tmpFile.Name()
  147. _, err = io.Copy(tmpFile, r)
  148. tmpFile.Close()
  149. if err != nil {
  150. os.Remove(tmpPath)
  151. return err
  152. }
  153. if err = os.Rename(tmpPath, outfile); err != nil {
  154. os.Remove(tmpPath)
  155. return err
  156. }
  157. return nil
  158. }
  159. // resolveAuthConfig is like registry.ResolveAuthConfig, but if using the
  160. // default index, it uses the default index name for the daemon's platform,
  161. // not the client's platform.
  162. func (cli *DockerCli) resolveAuthConfig(index *registrytypes.IndexInfo) types.AuthConfig {
  163. configKey := index.Name
  164. if index.Official {
  165. configKey = cli.electAuthServer()
  166. }
  167. a, _ := getCredentials(cli.configFile, configKey)
  168. return a
  169. }