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