// NewDockerCli returns a DockerCli instance with IO output and error streams set by in, out and err. // The key file, protocol (i.e. unix) and address are passed in as strings, along with the tls.Config. If the tls.Config // is set the client scheme will be set to https. // The client will be given a 32-second timeout (see https://github.com/docker/docker/pull/8035). func NewDockerCli(in io.ReadCloser, out, err io.Writer, clientFlags *cli.ClientFlags) *DockerCli { //创建cli对象 cli := &DockerCli{ in: in, out: out, err: err, keyFile: clientFlags.Common.TrustKey, } //docker客户端模式的创建过程,如果需要安全认证,需要加载安全认证的证书。 cli.init = func() error { clientFlags.PostParse() configFile, e := cliconfig.Load(cliconfig.ConfigDir()) if e != nil { fmt.Fprintf(cli.err, "WARNING: Error loading config file:%v\n", e) } if !configFile.ContainsAuth() { credentials.DetectDefaultStore(configFile) } cli.configFile = configFile host, err := getServerHost(clientFlags.Common.Hosts, clientFlags.Common.TLSOptions) if err != nil { return err } customHeaders := cli.configFile.HTTPHeaders if customHeaders == nil { customHeaders = map[string]string{} } customHeaders["User-Agent"] = clientUserAgent() verStr := api.DefaultVersion.String() if tmpStr := os.Getenv("DOCKER_API_VERSION"); tmpStr != "" { verStr = tmpStr } httpClient, err := newHTTPClient(host, clientFlags.Common.TLSOptions) if err != nil { return err } client, err := client.NewClient(host, verStr, httpClient, customHeaders) if err != nil { return err } cli.client = client if cli.in != nil { cli.inFd, cli.isTerminalIn = term.GetFdInfo(cli.in) } if cli.out != nil { cli.outFd, cli.isTerminalOut = term.GetFdInfo(cli.out) } return nil } return cli }
func NewHyperClient(proto, addr string, tlsConfig *tls.Config) *HyperClient { var ( inFd uintptr outFd uintptr isTerminalIn = false isTerminalOut = false ) clifile, err := cliconfig.Load(filepath.Join(homedir.Get(), ".docker")) if err != nil { fmt.Fprintf(os.Stdout, "WARNING: Error loading config file %v\n", err) } inFd, isTerminalIn = term.GetFdInfo(os.Stdin) outFd, isTerminalOut = term.GetFdInfo(os.Stdout) return &HyperClient{ client: api.NewClient(proto, addr, tlsConfig), in: os.Stdin, out: os.Stdout, err: os.Stdout, inFd: inFd, outFd: outFd, isTerminalIn: isTerminalIn, isTerminalOut: isTerminalOut, configFile: clifile, } }
func getAuthConfig(c *cli.Context, index *registryTypes.IndexInfo) (engineTypes.AuthConfig, error) { var ( username = c.GlobalString("username") password = c.GlobalString("password") cfg = c.GlobalString("docker-cfg") defAuthConfig = engineTypes.AuthConfig{ Username: c.GlobalString("username"), Password: c.GlobalString("password"), Email: "*****@*****.**", } ) // // FINAL TODO(runcom): avoid returning empty config! just fallthrough and return // the first useful authconfig // // TODO(runcom): ??? atomic needs this // TODO(runcom): implement this to opt-in for docker-cfg, no need to make this // work by default with docker's conf //useDockerConf := c.GlobalString("use-docker-cfg") if username != "" && password != "" { return defAuthConfig, nil } confFile, err := cliconfig.Load(cfg) if err != nil { return engineTypes.AuthConfig{}, err } authConfig := registry.ResolveAuthConfig(confFile.AuthConfigs, index) logrus.Debugf("authConfig for %s: %v", index.Name, authConfig) return authConfig, nil }
// LoadDefaultConfigFile attempts to load the default config file and returns // an initialized ConfigFile struct if none is found. func LoadDefaultConfigFile(err io.Writer) *configfile.ConfigFile { configFile, e := cliconfig.Load(cliconfig.ConfigDir()) if e != nil { fmt.Fprintf(err, "WARNING: Error loading config file:%v\n", e) } if !configFile.ContainsAuth() { credentials.DetectDefaultStore(configFile) } return configFile }
// NewDockerCli returns a DockerCli instance with IO output and error streams set by in, out and err. // The key file, protocol (i.e. unix) and address are passed in as strings, along with the tls.Config. If the tls.Config // is set the client scheme will be set to https. // The client will be given a 32-second timeout (see https://github.com/docker/docker/pull/8035). func NewDockerCli(in io.ReadCloser, out, err io.Writer, clientFlags *cli.ClientFlags) *DockerCli { cli := &DockerCli{ in: in, out: out, err: err, keyFile: clientFlags.Common.TrustKey, } cli.init = func() error { clientFlags.PostParse() configFile, e := cliconfig.Load(cliconfig.ConfigDir()) if e != nil { fmt.Fprintf(cli.err, "WARNING: Error loading config file:%v\n", e) } cli.configFile = configFile host, err := getServerHost(clientFlags.Common.Hosts, clientFlags.Common.TLSOptions) if err != nil { return err } customHeaders := cli.configFile.HTTPHeaders if customHeaders == nil { customHeaders = map[string]string{} } customHeaders["User-Agent"] = "Docker-Client/" + dockerversion.Version + " (" + runtime.GOOS + ")" verStr := api.DefaultVersion.String() if tmpStr := os.Getenv("DOCKER_API_VERSION"); tmpStr != "" { verStr = tmpStr } clientTransport, err := newClientTransport(clientFlags.Common.TLSOptions) if err != nil { return err } client, err := client.NewClient(host, verStr, clientTransport, customHeaders) if err != nil { return err } cli.client = client if cli.in != nil { cli.inFd, cli.isTerminalIn = term.GetFdInfo(cli.in) } if cli.out != nil { cli.outFd, cli.isTerminalOut = term.GetFdInfo(cli.out) } return nil } return cli }
// ReadConfig fetches docker config from ConfigDir func ReadConfig() error { if !strings.Contains(Host, "://") { Host = "https://" + Host } // if --user / --password are in args, take them. if User != "" && Password != "" { return nil } // otherwise try to take from docker config.json file c, err := cliconfig.Load(ConfigDir) if err != nil { fmt.Fprintf(os.Stderr, "Error while reading config file in %s\n", ConfigDir) return err } if len(c.AuthConfigs) <= 0 { return fmt.Errorf("No Auth found in config file in %s", ConfigDir) } url, err := url.ParseRequestURI(Host) if err != nil { fmt.Fprintf(os.Stderr, "Invalid URL %s\n", Host) return err } for authHost, a := range c.AuthConfigs { if authHost == url.Host { if Verbose { fmt.Fprintf(os.Stderr, "Found in config file: Host %s Username:%s Password:<notShow>\n", authHost, a.Username) } if User == "" { User = a.Username } if Password == "" { Password = a.Password } if Verbose { fmt.Fprintf(os.Stderr, "Computed configuration: Host %s Username:%s Password:<notShow>\n", authHost, a.Username) } break } } if User == "" || Password == "" || Host == "" { return fmt.Errorf("Missing user, password or host in configuration. Did you forget to 'docker login %s' ?", url.Host) } expandRegistryURL() return nil }
func NewHyperClient(proto, addr string, tlsConfig *tls.Config) *HyperClient { var ( inFd uintptr outFd uintptr isTerminalIn = false isTerminalOut = false scheme = "http" ) if tlsConfig != nil { scheme = "https" } // The transport is created here for reuse during the client session tran := &http.Transport{ TLSClientConfig: tlsConfig, } // Why 32? See issue 8035 timeout := 32 * time.Second if proto == "unix" { // no need in compressing for local communications tran.DisableCompression = true tran.Dial = func(_, _ string) (net.Conn, error) { return net.DialTimeout(proto, addr, timeout) } } else { tran.Proxy = http.ProxyFromEnvironment tran.Dial = (&net.Dialer{Timeout: timeout}).Dial } inFd, isTerminalIn = term.GetFdInfo(os.Stdin) outFd, isTerminalOut = term.GetFdInfo(os.Stdout) clifile, err := cliconfig.Load(filepath.Join(homedir.Get(), ".docker")) if err != nil { fmt.Fprintf(os.Stdout, "WARNING: Error loading config file %v\n", err) } return &HyperClient{ proto: proto, addr: addr, configFile: clifile, in: os.Stdin, out: os.Stdout, err: os.Stdout, inFd: inFd, outFd: outFd, isTerminalIn: isTerminalIn, isTerminalOut: isTerminalOut, scheme: scheme, transport: tran, } }
// NewDockerCli returns a DockerCli instance with IO output and error streams set by in, out and err. // The key file, protocol (i.e. unix) and address are passed in as strings, along with the tls.Config. If the tls.Config // is set the client scheme will be set to https. // The client will be given a 32-second timeout (see https://github.com/docker/docker/pull/8035). func NewDockerCli(in io.ReadCloser, out, err io.Writer, keyFile string, proto, addr string, tlsConfig *tls.Config) *DockerCli { var ( inFd uintptr outFd uintptr isTerminalIn = false isTerminalOut = false scheme = "http" ) if tlsConfig != nil { scheme = "https" } if in != nil { inFd, isTerminalIn = term.GetFdInfo(in) } if out != nil { outFd, isTerminalOut = term.GetFdInfo(out) } if err == nil { err = out } // The transport is created here for reuse during the client session. tr := &http.Transport{ TLSClientConfig: tlsConfig, } utils.ConfigureTCPTransport(tr, proto, addr) configFile, e := cliconfig.Load(filepath.Join(homedir.Get(), ".docker")) if e != nil { fmt.Fprintf(err, "WARNING: Error loading config file:%v\n", e) } return &DockerCli{ proto: proto, addr: addr, configFile: configFile, in: in, out: out, err: err, keyFile: keyFile, inFd: inFd, outFd: outFd, isTerminalIn: isTerminalIn, isTerminalOut: isTerminalOut, tlsConfig: tlsConfig, scheme: scheme, transport: tr, } }
func (c *Context) LookupConfig() error { if c.ConfigFile != nil { return nil } config, err := cliconfig.Load(c.ConfigDir) if err != nil { return err } c.ConfigFile = config return nil }
//getAuthConfig return the auth config if it exists. Nil and false otherwise func getAuthConfig(remoteRepo string) (*types.AuthConfig, bool) { configFile, e := cliconfig.Load(cliconfig.ConfigDir()) //ou if e != nil { LogWarn.Printf("Error loading config file:%v\n", e) //no auth, return an empty auth return nil, false } for hostName, config := range configFile.AuthConfigs { if strings.Contains(hostName, remoteRepo) { return &config, true } } return nil, false }
func getAuthConfig(c *cli.Context, index *registryTypes.IndexInfo) (types.AuthConfig, error) { var ( username = c.GlobalString("username") password = c.GlobalString("password") cfg = c.GlobalString("docker-cfg") ) if _, err := os.Stat(cfg); err != nil { logrus.Infof("Docker cli config file %q not found: %v, falling back to --username and --password if needed", cfg, err) return types.AuthConfig{ Username: username, Password: password, Email: "*****@*****.**", }, nil } confFile, err := cliconfig.Load(cfg) if err != nil { return types.AuthConfig{}, err } authConfig := registry.ResolveAuthConfig(confFile.AuthConfigs, index) logrus.Debugf("authConfig for %s: %v", index.Name, authConfig) return authConfig, nil }
//docker client 创建函数 // NewDockerCli returns a DockerCli instance with IO output and error streams set by in, out and err. // The key file, protocol (i.e. unix) and address are passed in as strings, along with the tls.Config. If the tls.Config // is set the client scheme will be set to https. // The client will be given a 32-second timeout (see https://github.com/docker/docker/pull/8035). func NewDockerCli(in io.ReadCloser, out, err io.Writer, clientFlags *cli.ClientFlags) *DockerCli { cli := &DockerCli{ in: in, out: out, err: err, keyFile: clientFlags.Common.TrustKey, } cli.init = func() error { clientFlags.PostParse() hosts := clientFlags.Common.Hosts switch len(hosts) { case 0: hosts = []string{os.Getenv("DOCKER_HOST")} case 1: // only accept one host to talk to default: return errors.New("Please specify only one -H") } defaultHost := opts.DefaultTCPHost if clientFlags.Common.TLSOptions != nil { defaultHost = opts.DefaultTLSHost } var e error if hosts[0], e = opts.ParseHost(defaultHost, hosts[0]); e != nil { return e } protoAddrParts := strings.SplitN(hosts[0], "://", 2) cli.proto, cli.addr = protoAddrParts[0], protoAddrParts[1] if cli.proto == "tcp" { // error is checked in pkg/parsers already parsed, _ := url.Parse("tcp://" + cli.addr) cli.addr = parsed.Host cli.basePath = parsed.Path } if clientFlags.Common.TLSOptions != nil { cli.scheme = "https" //启用HTTPS var e error cli.tlsConfig, e = tlsconfig.Client(*clientFlags.Common.TLSOptions) if e != nil { return e } } else { cli.scheme = "http" } if cli.in != nil { cli.inFd, cli.isTerminalIn = term.GetFdInfo(cli.in) } if cli.out != nil { cli.outFd, cli.isTerminalOut = term.GetFdInfo(cli.out) } // The transport is created here for reuse during the client session. cli.transport = &http.Transport{ TLSClientConfig: cli.tlsConfig, } sockets.ConfigureTCPTransport(cli.transport, cli.proto, cli.addr) configFile, e := cliconfig.Load(cliconfig.ConfigDir()) if e != nil { fmt.Fprintf(cli.err, "WARNING: Error loading config file:%v\n", e) } cli.configFile = configFile return nil } return cli }
// NewDockerCli returns a DockerCli instance with IO output and error streams set by in, out and err. // The key file, protocol (i.e. unix) and address are passed in as strings, along with the tls.Config. If the tls.Config // is set the client scheme will be set to https. // The client will be given a 32-second timeout (see https://github.com/docker/docker/pull/8035). func NewDockerCli(in io.ReadCloser, out, err io.Writer, keyFile string, proto, addr string, tlsConfig *tls.Config) *DockerCli { var ( inFd uintptr outFd uintptr isTerminalIn = false isTerminalOut = false scheme = "http" ) if tlsConfig != nil { scheme = "https" } if in != nil { inFd, isTerminalIn = term.GetFdInfo(in) } if out != nil { outFd, isTerminalOut = term.GetFdInfo(out) } if err == nil { err = out } // The transport is created here for reuse during the client session. tr := &http.Transport{ TLSClientConfig: tlsConfig, } // Why 32? See https://github.com/docker/docker/pull/8035. timeout := 32 * time.Second if proto == "unix" { // No need for compression in local communications. tr.DisableCompression = true tr.Dial = func(_, _ string) (net.Conn, error) { return net.DialTimeout(proto, addr, timeout) } } else { tr.Proxy = http.ProxyFromEnvironment tr.Dial = (&net.Dialer{Timeout: timeout}).Dial } configFile, e := cliconfig.Load(filepath.Join(homedir.Get(), ".docker")) if e != nil { fmt.Fprintf(err, "WARNING: Error loading config file:%v\n", e) } return &DockerCli{ proto: proto, addr: addr, configFile: configFile, in: in, out: out, err: err, keyFile: keyFile, inFd: inFd, outFd: outFd, isTerminalIn: isTerminalIn, isTerminalOut: isTerminalOut, tlsConfig: tlsConfig, scheme: scheme, transport: tr, } }
// NewDockerCli returns a DockerCli instance with IO output and error streams set by in, out and err. // The key file, protocol (i.e. unix) and address are passed in as strings, along with the tls.Config. If the tls.Config // is set the client scheme will be set to https. // The client will be given a 32-second timeout (see https://github.com/docker/docker/pull/8035). func NewDockerCli(in io.ReadCloser, out, err io.Writer, keyFile string, proto, addr string, tlsConfig *tls.Config) *DockerCli { var ( inFd uintptr outFd uintptr isTerminalIn = false isTerminalOut = false scheme = "http" basePath = "" ) if tlsConfig != nil { scheme = "https" } if in != nil { inFd, isTerminalIn = term.GetFdInfo(in) } if out != nil { outFd, isTerminalOut = term.GetFdInfo(out) } if err == nil { err = out } // The transport is created here for reuse during the client session. tr := &http.Transport{ TLSClientConfig: tlsConfig, } sockets.ConfigureTCPTransport(tr, proto, addr) configFile, e := cliconfig.Load(cliconfig.ConfigDir()) if e != nil { fmt.Fprintf(err, "WARNING: Error loading config file:%v\n", e) } if proto == "tcp" { // error is checked in pkg/parsers already parsed, _ := url.Parse("tcp://" + addr) addr = parsed.Host basePath = parsed.Path } return &DockerCli{ proto: proto, addr: addr, basePath: basePath, configFile: configFile, in: in, out: out, err: err, keyFile: keyFile, inFd: inFd, outFd: outFd, isTerminalIn: isTerminalIn, isTerminalOut: isTerminalOut, tlsConfig: tlsConfig, scheme: scheme, transport: tr, } }