-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Makes the default docker context behavior consistent #1719
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
cd25dd7 to
396d333
Compare
Codecov Report
@@ Coverage Diff @@
## master #1719 +/- ##
==========================================
+ Coverage 56.1% 56.23% +0.12%
==========================================
Files 306 307 +1
Lines 21049 21125 +76
==========================================
+ Hits 11810 11880 +70
Misses 8382 8382
- Partials 857 863 +6 |
396d333 to
955bcb3
Compare
simonferquel
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a foundational aspect I dislike about the implementation: the context store package is all about storing (and retrieving) contexts to disk. The 'default' context is not stored, so the store should have no knowledge about it.
Something you might want to do though, is to implement a separate "defaultContextStore" of the store.Store interface for allowing to dynamically resolve the "default" context when needed by operations like list, inspect and export (which would consume both the on-disk context store and this "defaultContextStore". If it makes sense, feel free to introduce an interface that is a subset of store.Store that satisfies the requirements of list/inspect/export only to make it easier to implement that.
|
@simonferquel understood. Actually I was more considering the metadatastore and tlsstore as the real storage backend and the store as a proxy in front of these implementations. I also considered adding another implementation of Store for the default context and create a sort of multiplexer but I was wondering if it wasn't over-engineering for little gains. But ok, I'm going to refactor that. |
93d455c to
541d780
Compare
simonferquel
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few things to fix, but looks good overall
Really like that you managed to make a "virtual store exposing the default context" available for all client code, including plugins.
cli/command/cli.go
Outdated
|
|
||
| func resolveDockerEndpoint(s store.Store, contextName string, opts *cliflags.CommonOptions) (docker.Endpoint, error) { | ||
| if contextName != "" { | ||
| if contextName != "" || contextName == DefaultContextName { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
feels like the comparison here is wrong. should be:
| if contextName != "" || contextName == DefaultContextName { | |
| if contextName != "" && contextName != DefaultContextName { |
cli/command/context/list.go
Outdated
| desc := formatter.ClientContext{ | ||
| Name: rawMeta.Name, | ||
| Current: rawMeta.Name == curContext, | ||
| Current: rawMeta.Name == curContext || (curContext == "" && rawMeta.Name == command.DefaultContextName), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be simplified by putting a simpler
if curContext == ""{
curContext = command.DefaultContextName
}
on top of the loop
cli/command/defaultcontextstore.go
Outdated
| kubeconfig = filepath.Join(homedir.Get(), ".kube/config") | ||
| } | ||
| kubeEP, err := kubernetes.FromKubeConfig(kubeconfig, "", "") | ||
| if stackOrchestrator == OrchestratorKubernetes && err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we also handle OrchestratorAll ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use stackOrchestrator.HasKubernetes then (see code here)
cli/command/defaultcontextstore.go
Outdated
| return nil, err | ||
| } | ||
| if defaultContext.TLS.Endpoints[endpointName].Files[fileName] == nil { | ||
| return nil, errors.Errorf("tls data for %s/%s/%s does not exist", DefaultContextName, endpointName, fileName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there is a typed error interface for not-found cases in the store package. It should return an error satisfying this interface
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So just checked, there is no error interface but a specific error type (see here: https://github.com/docker/cli/blob/master/cli/context/store/store.go#L324). I suggest you introduce a tlsDataNotExistError interface in store package, and modify IsErrTLSDataDoesNotExist to check this interface, and makes this code return an error satisfying this interface.
thaJeztah
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
left some suggestions/questions; I haven't checked all the cases, but I think some of the special cases would not be needed if ContextStoreWithDefault indeed implements the interface (and abstracts the "default" context to act as a "real" context)
cli/command/cli.go
Outdated
|
|
||
| func resolveDockerEndpoint(s store.Store, contextName string, opts *cliflags.CommonOptions) (docker.Endpoint, error) { | ||
| if contextName != "" { | ||
| if contextName != "" || contextName == DefaultContextName { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this logic flipped? i.e. should this be
| if contextName != "" || contextName == DefaultContextName { | |
| if contextName != "" && contextName != DefaultContextName { |
But perhaps better to return early for the special case;
| if contextName != "" || contextName == DefaultContextName { | |
| if contextName == "" || contextName == DefaultContextName { | |
| return resolveDefaultDockerEndpoint(opts) | |
| } |
cli/command/cli.go
Outdated
| currentContext = configFile.CurrentContext | ||
| } | ||
| if currentContext != "" { | ||
| if currentContext != "" && currentContext != DefaultContextName { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doesn't ContextStoreWithDefault now also implement GetContextMetadata()? IOW; do we need to still have this special case?
cli/command/cli.go
Outdated
| if cli.client == nil { | ||
| cli.contextStore = store.New(cliconfig.ContextStoreDir(), cli.contextStoreConfig) | ||
| baseContextSore := store.New(cliconfig.ContextStoreDir(), cli.contextStoreConfig) | ||
| cli.contextStore = &ContextStoreWithDefault{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should ContextStoreWithDefault be in its own package? So that we could do something like;
storewithdefault.New(...)Perhaps even integrate with the default store (but not sure if there's situations where we want that to be used separate)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ContextStoreWithDefault needs things defined in package command (related to resolving the docker context based on "legacy" cli flags and env var). That would:
- either introduce a cycling dependency (dockerCli.Initialize needs this ContextStoreWithDefault)
- or move much of the command package code in a separate package
- implementing that in
storepackage might introduce many new dependencies to thestorepackage (and I don't feel like it is a good idea)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we pass those options in the constructor?
| if kubernetesEndpoint != nil { | ||
| kubEndpointText = fmt.Sprintf("%s (%s)", kubernetesEndpoint.Host, kubernetesEndpoint.DefaultNamespace) | ||
| } | ||
| if rawMeta.Name == command.DefaultContextName { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If dockerCli.ContextStore().ListContexts() is handled by ContextStoreWithDefault.ListContexts (), is this special case still needed, or would it already return the right information?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@thaJeztah I didn't want to add specific code for import/export command to avoid, when importing an exported default context, having a second context with the "Current DOCKER_HOST based configuration" description. Therefore I decided to leave the description empty for the default context and add handle that case here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still a bit on the fence on this one (i.e., the same applies to other contexts, which also by default copy the description), but not a blocker
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed. I think it is less confusing for other contexts. Maybe it would be nice to add a --description flag to import command in order to override the imported context description
|
After rebasing #1690, can you rebase on this PR (we have pending work on docker-app requiring both) |
| srcFileList, err := s.ListContextTLSFiles("default") | ||
| assert.NilError(t, err) | ||
| destFileList, err := s.ListContextTLSFiles("dest") | ||
| assert.NilError(t, err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: can you add some space in this block? I mean divide into logical sub-blocks, add an empty line between them and/or a comment explaining what you assert?
|
I like this default context store proxy on top of the context store 👍 |
2cefc17 to
8a38bf8
Compare
|
PR #1690 have been rebased on this branch |
8a38bf8 to
2ac5810
Compare
simonferquel
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One small change to do (to make sure IsTLSDataNotFound works for default context as well), and I think we are good.
cli/command/defaultcontextstore.go
Outdated
| return nil, err | ||
| } | ||
| if defaultContext.TLS.Endpoints[endpointName].Files[fileName] == nil { | ||
| return nil, errors.Errorf("tls data for %s/%s/%s does not exist", DefaultContextName, endpointName, fileName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So just checked, there is no error interface but a specific error type (see here: https://github.com/docker/cli/blob/master/cli/context/store/store.go#L324). I suggest you introduce a tlsDataNotExistError interface in store package, and modify IsErrTLSDataDoesNotExist to check this interface, and makes this code return an error satisfying this interface.
2ac5810 to
2067049
Compare
simonferquel
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
@thaJeztah can you PTAL alongside #1690 ? those are very important fixes for github.com/docker/app
- when using "--context default" parameter - when printing the list of contexts - when exporting the default context to a tarball Signed-off-by: Jean-Christophe Sirot <[email protected]> (+1 squashed commit) Squashed commits: [2067049] Fix CLI initialization for the `docker stack deploy --help` command and ensure that the dockerCli.CurrentContext() always returns a non empty context name (default as a fallback) Remove now obsolete code handling empty string context name Minor code cleanup Signed-off-by: Jean-Christophe Sirot <[email protected]>
2067049 to
b3aa171
Compare
thaJeztah
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks!
| currentContext = configFile.CurrentContext | ||
| ctxRaw, err := cli.ContextStore().GetContextMetadata(currentContext) | ||
| if store.IsErrContextDoesNotExist(err) { | ||
| // case where the currentContext has been removed (CLI behavior is to fallback to using DOCKER_HOST based resolution) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not for this PR, but something similar came up in another discussion with @simonferquel - I think this should be an error; we should not silently fall back to DOCKER_HOST (because then I may be running commands against the wrong environment, which is likely not what you want)
| if kubernetesEndpoint != nil { | ||
| kubEndpointText = fmt.Sprintf("%s (%s)", kubernetesEndpoint.Host, kubernetesEndpoint.DefaultNamespace) | ||
| } | ||
| if rawMeta.Name == command.DefaultContextName { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still a bit on the fence on this one (i.e., the same applies to other contexts, which also by default copy the description), but not a blocker
silvin-lubecki
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
- What I did
Make default context behaves like a real context
- A picture of a cute animal (not mandatory but encouraged)