github.com/vieux/docker@v0.6.3-0.20161004191708-e097c2a938c7/cli/command/cli.go (about) 1 package command 2 3 import ( 4 "errors" 5 "fmt" 6 "io" 7 "net/http" 8 "os" 9 "path/filepath" 10 "runtime" 11 12 "github.com/docker/docker/api" 13 cliflags "github.com/docker/docker/cli/flags" 14 "github.com/docker/docker/cliconfig" 15 "github.com/docker/docker/cliconfig/configfile" 16 "github.com/docker/docker/cliconfig/credentials" 17 "github.com/docker/docker/client" 18 "github.com/docker/docker/dockerversion" 19 dopts "github.com/docker/docker/opts" 20 "github.com/docker/go-connections/sockets" 21 "github.com/docker/go-connections/tlsconfig" 22 ) 23 24 // Streams is an interface which exposes the standard input and output streams 25 type Streams interface { 26 In() *InStream 27 Out() *OutStream 28 Err() io.Writer 29 } 30 31 // DockerCli represents the docker command line client. 32 // Instances of the client can be returned from NewDockerCli. 33 type DockerCli struct { 34 configFile *configfile.ConfigFile 35 in *InStream 36 out *OutStream 37 err io.Writer 38 keyFile string 39 client client.APIClient 40 } 41 42 // Client returns the APIClient 43 func (cli *DockerCli) Client() client.APIClient { 44 return cli.client 45 } 46 47 // Out returns the writer used for stdout 48 func (cli *DockerCli) Out() *OutStream { 49 return cli.out 50 } 51 52 // Err returns the writer used for stderr 53 func (cli *DockerCli) Err() io.Writer { 54 return cli.err 55 } 56 57 // In returns the reader used for stdin 58 func (cli *DockerCli) In() *InStream { 59 return cli.in 60 } 61 62 // ConfigFile returns the ConfigFile 63 func (cli *DockerCli) ConfigFile() *configfile.ConfigFile { 64 return cli.configFile 65 } 66 67 // CredentialsStore returns a new credentials store based 68 // on the settings provided in the configuration file. 69 func (cli *DockerCli) CredentialsStore() credentials.Store { 70 if cli.configFile.CredentialsStore != "" { 71 return credentials.NewNativeStore(cli.configFile) 72 } 73 return credentials.NewFileStore(cli.configFile) 74 } 75 76 // Initialize the dockerCli runs initialization that must happen after command 77 // line flags are parsed. 78 func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions) error { 79 cli.configFile = LoadDefaultConfigFile(cli.err) 80 81 var err error 82 cli.client, err = NewAPIClientFromFlags(opts.Common, cli.configFile) 83 if err != nil { 84 return err 85 } 86 if opts.Common.TrustKey == "" { 87 cli.keyFile = filepath.Join(cliconfig.ConfigDir(), cliflags.DefaultTrustKeyFile) 88 } else { 89 cli.keyFile = opts.Common.TrustKey 90 } 91 92 return nil 93 } 94 95 // NewDockerCli returns a DockerCli instance with IO output and error streams set by in, out and err. 96 func NewDockerCli(in io.ReadCloser, out, err io.Writer) *DockerCli { 97 return &DockerCli{in: NewInStream(in), out: NewOutStream(out), err: err} 98 } 99 100 // LoadDefaultConfigFile attempts to load the default config file and returns 101 // an initialized ConfigFile struct if none is found. 102 func LoadDefaultConfigFile(err io.Writer) *configfile.ConfigFile { 103 configFile, e := cliconfig.Load(cliconfig.ConfigDir()) 104 if e != nil { 105 fmt.Fprintf(err, "WARNING: Error loading config file:%v\n", e) 106 } 107 if !configFile.ContainsAuth() { 108 credentials.DetectDefaultStore(configFile) 109 } 110 return configFile 111 } 112 113 // NewAPIClientFromFlags creates a new APIClient from command line flags 114 func NewAPIClientFromFlags(opts *cliflags.CommonOptions, configFile *configfile.ConfigFile) (client.APIClient, error) { 115 host, err := getServerHost(opts.Hosts, opts.TLSOptions) 116 if err != nil { 117 return &client.Client{}, err 118 } 119 120 customHeaders := configFile.HTTPHeaders 121 if customHeaders == nil { 122 customHeaders = map[string]string{} 123 } 124 customHeaders["User-Agent"] = UserAgent() 125 126 verStr := api.DefaultVersion 127 if tmpStr := os.Getenv("DOCKER_API_VERSION"); tmpStr != "" { 128 verStr = tmpStr 129 } 130 131 httpClient, err := newHTTPClient(host, opts.TLSOptions) 132 if err != nil { 133 return &client.Client{}, err 134 } 135 136 return client.NewClient(host, verStr, httpClient, customHeaders) 137 } 138 139 func getServerHost(hosts []string, tlsOptions *tlsconfig.Options) (host string, err error) { 140 switch len(hosts) { 141 case 0: 142 host = os.Getenv("DOCKER_HOST") 143 case 1: 144 host = hosts[0] 145 default: 146 return "", errors.New("Please specify only one -H") 147 } 148 149 host, err = dopts.ParseHost(tlsOptions != nil, host) 150 return 151 } 152 153 func newHTTPClient(host string, tlsOptions *tlsconfig.Options) (*http.Client, error) { 154 if tlsOptions == nil { 155 // let the api client configure the default transport. 156 return nil, nil 157 } 158 159 config, err := tlsconfig.Client(*tlsOptions) 160 if err != nil { 161 return nil, err 162 } 163 tr := &http.Transport{ 164 TLSClientConfig: config, 165 } 166 proto, addr, _, err := client.ParseHost(host) 167 if err != nil { 168 return nil, err 169 } 170 171 sockets.ConfigureTransport(tr, proto, addr) 172 173 return &http.Client{ 174 Transport: tr, 175 }, nil 176 } 177 178 // UserAgent returns the user agent string used for making API requests 179 func UserAgent() string { 180 return "Docker-Client/" + dockerversion.Version + " (" + runtime.GOOS + ")" 181 }