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  }