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  }