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