|
4 | 4 | "context" |
5 | 5 | "io" |
6 | 6 | "io/ioutil" |
| 7 | + "net" |
7 | 8 | "os" |
8 | 9 | "path/filepath" |
9 | 10 | "runtime" |
@@ -38,6 +39,16 @@ import ( |
38 | 39 | "github.com/theupdateframework/notary/passphrase" |
39 | 40 | ) |
40 | 41 |
|
| 42 | +type contextNameSource int |
| 43 | + |
| 44 | +const ( |
| 45 | + contextFallbackToDockerHost contextNameSource = iota |
| 46 | + contextFromFlag |
| 47 | + contextFromEnv |
| 48 | + contextFromConfigFile |
| 49 | + contextDefault |
| 50 | +) |
| 51 | + |
41 | 52 | // Streams is an interface which exposes the standard input and output streams |
42 | 53 | type Streams interface { |
43 | 54 | In() *streams.In |
@@ -251,12 +262,25 @@ func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions, ops ...Initialize |
251 | 262 | return ResolveDefaultContext(opts.Common, cli.ConfigFile(), cli.contextStoreConfig, cli.Err()) |
252 | 263 | }, |
253 | 264 | } |
254 | | - cli.currentContext, err = resolveContextName(opts.Common, cli.configFile, cli.contextStore) |
| 265 | + var contextSource contextNameSource |
| 266 | + cli.currentContext, contextSource, err = resolveContextName(opts.Common, cli.configFile) |
255 | 267 | if err != nil { |
256 | 268 | return err |
257 | 269 | } |
258 | 270 | cli.dockerEndpoint, err = resolveDockerEndpoint(cli.contextStore, cli.currentContext) |
259 | | - if err != nil { |
| 271 | + if store.IsErrContextDoesNotExist(err) && contextSource == contextFromConfigFile { |
| 272 | + if cli.client == nil { |
| 273 | + // populate a client that always fails with "context not found" |
| 274 | + // this is to defer the context not found error until API is really used to allow |
| 275 | + // operations like `docker context use` or `docker context ls` |
| 276 | + cli.client, err = client.NewClientWithOpts(client.WithDialContext(func(ctx context.Context, network, addr string) (net.Conn, error) { |
| 277 | + return nil, errors.Errorf("Current context %q is not found on the file system, please check your config file at %s", cli.configFile.CurrentContext, cli.configFile.Filename) |
| 278 | + })) |
| 279 | + if err != nil { |
| 280 | + return err |
| 281 | + } |
| 282 | + } |
| 283 | + } else if err != nil { |
260 | 284 | return errors.Wrap(err, "unable to resolve docker endpoint") |
261 | 285 | } |
262 | 286 |
|
@@ -292,7 +316,7 @@ func NewAPIClientFromFlags(opts *cliflags.CommonOptions, configFile *configfile. |
292 | 316 | return ResolveDefaultContext(opts, configFile, storeConfig, ioutil.Discard) |
293 | 317 | }, |
294 | 318 | } |
295 | | - contextName, err := resolveContextName(opts, configFile, store) |
| 319 | + contextName, _, err := resolveContextName(opts, configFile) |
296 | 320 | if err != nil { |
297 | 321 | return nil, err |
298 | 322 | } |
@@ -530,30 +554,26 @@ func UserAgent() string { |
530 | 554 | // - if DOCKER_CONTEXT is set, use this value |
531 | 555 | // - if Config file has a globally set "CurrentContext", use this value |
532 | 556 | // - fallbacks to default HOST, uses TLS config from flags/env vars |
533 | | -func resolveContextName(opts *cliflags.CommonOptions, config *configfile.ConfigFile, contextstore store.Reader) (string, error) { |
| 557 | +func resolveContextName(opts *cliflags.CommonOptions, config *configfile.ConfigFile) (string, contextNameSource, error) { |
534 | 558 | if opts.Context != "" && len(opts.Hosts) > 0 { |
535 | | - return "", errors.New("Conflicting options: either specify --host or --context, not both") |
| 559 | + return "", contextDefault, errors.New("Conflicting options: either specify --host or --context, not both") |
536 | 560 | } |
537 | 561 | if opts.Context != "" { |
538 | | - return opts.Context, nil |
| 562 | + return opts.Context, contextFromFlag, nil |
539 | 563 | } |
540 | 564 | if len(opts.Hosts) > 0 { |
541 | | - return DefaultContextName, nil |
| 565 | + return DefaultContextName, contextFallbackToDockerHost, nil |
542 | 566 | } |
543 | 567 | if _, present := os.LookupEnv("DOCKER_HOST"); present { |
544 | | - return DefaultContextName, nil |
| 568 | + return DefaultContextName, contextFallbackToDockerHost, nil |
545 | 569 | } |
546 | 570 | if ctxName, ok := os.LookupEnv("DOCKER_CONTEXT"); ok { |
547 | | - return ctxName, nil |
| 571 | + return ctxName, contextFromEnv, nil |
548 | 572 | } |
549 | 573 | if config != nil && config.CurrentContext != "" { |
550 | | - _, err := contextstore.GetMetadata(config.CurrentContext) |
551 | | - if store.IsErrContextDoesNotExist(err) { |
552 | | - return "", errors.Errorf("Current context %q is not found on the file system, please check your config file at %s", config.CurrentContext, config.Filename) |
553 | | - } |
554 | | - return config.CurrentContext, err |
| 574 | + return config.CurrentContext, contextFromConfigFile, nil |
555 | 575 | } |
556 | | - return DefaultContextName, nil |
| 576 | + return DefaultContextName, contextDefault, nil |
557 | 577 | } |
558 | 578 |
|
559 | 579 | var defaultStoreEndpoints = []store.NamedTypeGetter{ |
|
0 commit comments