utils.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. package client
  2. import (
  3. "encoding/base64"
  4. "encoding/json"
  5. "fmt"
  6. "os"
  7. gosignal "os/signal"
  8. "runtime"
  9. "strings"
  10. "time"
  11. "github.com/Sirupsen/logrus"
  12. "github.com/docker/docker/pkg/signal"
  13. "github.com/docker/docker/pkg/term"
  14. "github.com/docker/docker/registry"
  15. "github.com/docker/engine-api/client"
  16. "github.com/docker/engine-api/types"
  17. registrytypes "github.com/docker/engine-api/types/registry"
  18. )
  19. func (cli *DockerCli) electAuthServer() string {
  20. // The daemon `/info` endpoint informs us of the default registry being
  21. // used. This is essential in cross-platforms environment, where for
  22. // example a Linux client might be interacting with a Windows daemon, hence
  23. // the default registry URL might be Windows specific.
  24. serverAddress := registry.IndexServer
  25. if info, err := cli.client.Info(); err != nil {
  26. fmt.Fprintf(cli.out, "Warning: failed to get default registry endpoint from daemon (%v). Using system default: %s\n", err, serverAddress)
  27. } else {
  28. serverAddress = info.IndexServerAddress
  29. }
  30. return serverAddress
  31. }
  32. // encodeAuthToBase64 serializes the auth configuration as JSON base64 payload
  33. func encodeAuthToBase64(authConfig types.AuthConfig) (string, error) {
  34. buf, err := json.Marshal(authConfig)
  35. if err != nil {
  36. return "", err
  37. }
  38. return base64.URLEncoding.EncodeToString(buf), nil
  39. }
  40. func (cli *DockerCli) encodeRegistryAuth(index *registrytypes.IndexInfo) (string, error) {
  41. authConfig := registry.ResolveAuthConfig(cli.configFile.AuthConfigs, index)
  42. return encodeAuthToBase64(authConfig)
  43. }
  44. func (cli *DockerCli) registryAuthenticationPrivilegedFunc(index *registrytypes.IndexInfo, cmdName string) client.RequestPrivilegeFunc {
  45. return func() (string, error) {
  46. fmt.Fprintf(cli.out, "\nPlease login prior to %s:\n", cmdName)
  47. indexServer := registry.GetAuthConfigKey(index)
  48. authConfig, err := cli.configureAuth("", "", "", indexServer)
  49. if err != nil {
  50. return "", err
  51. }
  52. return encodeAuthToBase64(authConfig)
  53. }
  54. }
  55. func (cli *DockerCli) resizeTty(id string, isExec bool) {
  56. height, width := cli.getTtySize()
  57. if height == 0 && width == 0 {
  58. return
  59. }
  60. options := types.ResizeOptions{
  61. ID: id,
  62. Height: height,
  63. Width: width,
  64. }
  65. var err error
  66. if isExec {
  67. err = cli.client.ContainerExecResize(options)
  68. } else {
  69. err = cli.client.ContainerResize(options)
  70. }
  71. if err != nil {
  72. logrus.Debugf("Error resize: %s", err)
  73. }
  74. }
  75. // getExitCode perform an inspect on the container. It returns
  76. // the running state and the exit code.
  77. func getExitCode(cli *DockerCli, containerID string) (bool, int, error) {
  78. c, err := cli.client.ContainerInspect(containerID)
  79. if err != nil {
  80. // If we can't connect, then the daemon probably died.
  81. if err != client.ErrConnectionFailed {
  82. return false, -1, err
  83. }
  84. return false, -1, nil
  85. }
  86. return c.State.Running, c.State.ExitCode, nil
  87. }
  88. // getExecExitCode perform an inspect on the exec command. It returns
  89. // the running state and the exit code.
  90. func getExecExitCode(cli *DockerCli, execID string) (bool, int, error) {
  91. resp, err := cli.client.ContainerExecInspect(execID)
  92. if err != nil {
  93. // If we can't connect, then the daemon probably died.
  94. if err != client.ErrConnectionFailed {
  95. return false, -1, err
  96. }
  97. return false, -1, nil
  98. }
  99. return resp.Running, resp.ExitCode, nil
  100. }
  101. func (cli *DockerCli) monitorTtySize(id string, isExec bool) error {
  102. cli.resizeTty(id, isExec)
  103. if runtime.GOOS == "windows" {
  104. go func() {
  105. prevH, prevW := cli.getTtySize()
  106. for {
  107. time.Sleep(time.Millisecond * 250)
  108. h, w := cli.getTtySize()
  109. if prevW != w || prevH != h {
  110. cli.resizeTty(id, isExec)
  111. }
  112. prevH = h
  113. prevW = w
  114. }
  115. }()
  116. } else {
  117. sigchan := make(chan os.Signal, 1)
  118. gosignal.Notify(sigchan, signal.SIGWINCH)
  119. go func() {
  120. for range sigchan {
  121. cli.resizeTty(id, isExec)
  122. }
  123. }()
  124. }
  125. return nil
  126. }
  127. func (cli *DockerCli) getTtySize() (int, int) {
  128. if !cli.isTerminalOut {
  129. return 0, 0
  130. }
  131. ws, err := term.GetWinsize(cli.outFd)
  132. if err != nil {
  133. logrus.Debugf("Error getting size: %s", err)
  134. if ws == nil {
  135. return 0, 0
  136. }
  137. }
  138. return int(ws.Height), int(ws.Width)
  139. }
  140. // resolveAuthConfig is like registry.ResolveAuthConfig, but if using the
  141. // default index, it uses the default index name for the daemon's platform,
  142. // not the client's platform.
  143. func (cli *DockerCli) resolveAuthConfig(authConfigs map[string]types.AuthConfig, index *registrytypes.IndexInfo) types.AuthConfig {
  144. configKey := index.Name
  145. if index.Official {
  146. configKey = cli.electAuthServer()
  147. }
  148. // First try the happy case
  149. if c, found := authConfigs[configKey]; found || index.Official {
  150. return c
  151. }
  152. convertToHostname := func(url string) string {
  153. stripped := url
  154. if strings.HasPrefix(url, "http://") {
  155. stripped = strings.Replace(url, "http://", "", 1)
  156. } else if strings.HasPrefix(url, "https://") {
  157. stripped = strings.Replace(url, "https://", "", 1)
  158. }
  159. nameParts := strings.SplitN(stripped, "/", 2)
  160. return nameParts[0]
  161. }
  162. // Maybe they have a legacy config file, we will iterate the keys converting
  163. // them to the new format and testing
  164. for registry, ac := range authConfigs {
  165. if configKey == convertToHostname(registry) {
  166. return ac
  167. }
  168. }
  169. // When all else fails, return an empty auth config
  170. return types.AuthConfig{}
  171. }