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