Commit Graph

33 Commits

Author SHA1 Message Date
Ian Campbell 941a493f49
Move subtests of TestGlobalHelp into actual subtests
Signed-off-by: Ian Campbell <ijc@docker.com>
(cherry picked from commit d57175aa2e)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2019-05-13 09:05:25 -07:00
Ian Campbell d32f3647b1 e2e: Add tests for #1801 (global args parsed multiple times)
These currently fail.

Signed-off-by: Ian Campbell <ijc@docker.com>
2019-04-03 15:07:38 +01:00
Ian Campbell ef40743669 e2e: Add a TestMain for cli plugins tests
This was omitted when these tests were added.

Adding this means that the tests now see the `$DOCKER_HOST` configured (via
`$TEST_DOCKER_HOST`) where they didn't before. In some cases (specifically the
`test-e2e-connhelper-ssh` case) this results in additional output on stderr
when `-D` (debug) is used:

    time="2019-04-03T11:10:27Z" level=debug msg="commandconn: starting ssh with [-l penguin 172.20.0.2 -- docker system dial-stdio]"

Address this by switching the affected test cases to use `-l info` instead of
`-D`, they all just require some option not specifically `-D`. Note that `info`
is the default log level so this is effectively a nop (which is good).

Signed-off-by: Ian Campbell <ijc@docker.com>
2019-04-03 15:06:34 +01:00
Ian Campbell add2da66c5 e2e: Use icmd.None in a couple more places
This checks for actual emptiness, while `""` means "don't care".

Signed-off-by: Ian Campbell <ijc@docker.com>
2019-04-03 11:07:52 +01:00
Ian Campbell 8f3798cf04 cli-plugins: Reinstate deprecated `-h` short form of `--help`.
In the initial implementation I thought it would be good to not pass on the
deprecation to plugins (since they are new). However it turns out this causes
`docker helloworld -h` to print a spurious "pflag: help requested" line:

    $ docker helloworld -h
    pflag: help requested
    See 'docker helloworld --help'.

    Usage:	docker helloworld [OPTIONS] COMMAND

    A basic Hello World plugin for tests
    ...

Compared with:

    $ docker ps -h
    Flag shorthand -h has been deprecated, please use --help

    Usage:	docker ps [OPTIONS]

This is in essence because having the flag undefined hits a different path
within cobra, causing `c.execute()` to return early due to getting an error
(`flag.ErrHelp`) from `c.ParseFlags`, which launders the error through our
`FlagErrorFunc` which wraps it in a `StatusError` which in turn defeats an `if
err == flag.ErrHelp` check further up the call chain. If the flag is defined we
instead hit a path which returns a bare `flag.ErrHelp` without wrapping it.

I considered updating our `FlagErrorFunc` to not wrap `flag.ErrHelp` (and then
following the chain to the next thing) however while doing that I realised that
the code for `-h` (and `--help`) is deeply embedded into cobra (and its flags
library) such that actually using `-h` as a plugin argument meaning something
other than `help` is basically impossible/impractical. Therefore we may as well
have plugins behave identically to the monolithic CLI and support (deprecated)
the `-h` argument.

With this changed the help related blocks of `SetupRootCommand` and
`SetupPluginRootCommand` are now identical, so consolidate into
`setupCommonRootCommand`.

Tests are updated to check `-h` in a variety of scenarios, including the happy
case here.

Signed-off-by: Ian Campbell <ijc@docker.com>
2019-03-28 17:18:20 +00:00
Ian Campbell 0b30592ee0 e2e/cli-plugins: improve checks for empty output by using `icmd.None`
In some cases this means switching to `icmd.Expected` rather than
`icmd.Success`, but this improves readability overall.

Signed-off-by: Ian Campbell <ijc@docker.com>
2019-03-28 14:30:51 +00:00
Silvin Lubecki cfd5b16ae0
Merge pull request #1745 from ijc/disable-dial-stdio-for-plugins
cli-plugins: disable use of dial-stdio
2019-03-18 12:29:41 +01:00
Ian Campbell ff2ed6efa8 cli-plugins: disable use of dial-stdio
Since #1654 so far we've had problems with it not working on Windows (npipe
lacked the `CloseRead` method) and problems with using tcp with tls (the tls
connection also lacks `CloseRead`). Both of these were workedaround in #1718
which added a nop `CloseRead` method.

However I am now seeing hangs (on Windows) where the `system dial-stdio`
subprocess is not exiting (I'm unsure why so far).

I think the 3rd problem found with this is an indication that `dial-stdio` is
not quite ready for wider use outside of its initial usecase (support for
`ssh://` URLs to connect to remote daemons).

This change simply disables the `dial-stdio` path for all plugins. However
rather than completely reverting 891b3d953e ("cli-plugins: use `docker system
dial-stdio` to call the daemon") I've just disabled the functionality at the
point of use and left in a trap door environment variable so that those who
want to experiment with this mode (and perhaps fully debug it) have an easier
path do doing so.

The e2e test for this case is disabled unless the trap door envvar is set. I
also renamed the test to clarify that it is about cli plugins.

Signed-off-by: Ian Campbell <ijc@docker.com>
2019-03-18 10:58:51 +00:00
Sebastiaan van Stijn 86a5a489f7
Merge pull request #1690 from jcsirot/fix-contextstore-for-plugins
Always initialize context store
2019-03-18 11:27:07 +01:00
Ian Campbell 0b794e0620 e2e/cli-plugins: explicitly check that PersistentPreRunE works
I regressed this in d4ced2ef77 ("allow plugins to have argument which match a
top-level flag.") by unconditionally overwriting any `PersistentRunE` that the
user may have supplied.

We need to ensure two things:

1. That the user can use `PersistentRunE` (or `PersistentRun`) for their own
   purposes.
2. That our initialisation always runs, even if the user has used
   `PersistentRun*`, since that will shadow the root.

To do this add a `PersistentRunE` to the helloworld plugin which logs (covers 1
above) and then use it when calling the `apiversion` subcommand (which covers 2
since that uses the client)

Signed-off-by: Ian Campbell <ijc@docker.com>
2019-03-14 14:20:19 +00:00
Jean-Christophe Sirot 37fcaf7a29 Resolve the docker Endpoint even if the client already exists. In that case the `TestDialStdio` e2e test had to be modified: the `--tls` option triggers an error since the endpoint resolution tries to read the `${DOCKER_CERT_PATH}/ca.pem` file which does not exist.
Signed-off-by: Jean-Christophe Sirot <jean-christophe.sirot@docker.com>
2019-03-13 14:18:41 +01:00
Ian Campbell 2c624e8984 Add e2e test for handling of `version`/`-v`/`--version` with plugins
Previous commits fixed the first issue on #1661, this simply adds a test for
it. Note that this is testing the current behaviour, without regard for the
second issue in #1661 which proposes a different behaviour.

Signed-off-by: Ian Campbell <ijc@docker.com>
2019-03-13 11:28:17 +00:00
Ian Campbell d4ced2ef77 allow plugins to have argument which match a top-level flag.
The issue with plugin options clashing with globals is that when cobra is
parsing the command line and it comes across an argument which doesn't start
with a `-` it (in the absence of plugins) distinguishes between "argument to
current command" and "new subcommand" based on the list of registered sub
commands.

Plugins breaks that model. When presented with `docker -D plugin -c foo` cobra
parses up to the `plugin`, sees it isn't a registered sub-command of the
top-level docker (because it isn't, it's a plugin) so it accumulates it as an
argument to the top-level `docker` command. Then it sees the `-c`, and thinks
it is the global `-c` (for AKA `--context`) option and tries to treat it as
that, which fails.

In the specific case of the top-level `docker` subcommand we know that it has
no arguments which aren't `--flags` (or `-f` short flags) and so anything which
doesn't start with a `-` must either be a (known) subcommand or an attempt to
execute a plugin.

We could simply scan for and register all installed plugins at start of day, so
that cobra can do the right thing, but we want to avoid that since it would
involve executing each plugin to fetch the metadata, even if the command wasn't
going to end up hitting a plugin.

Instead we can parse the initial set of global arguments separately before
hitting the main cobra `Execute` path, which works here exactly because we know
that the top-level has no non-flag arguments.

One slight wrinkle is that the top-level `PersistentPreRunE` is no longer
called on the plugins path (since it no longer goes via `Execute`), so we
arrange for the initialisation done there (which has to be done after global
flags are parsed to handle e.g. `--config`) to happen explictly after the
global flags are parsed. Rather than make `newDockerCommand` return the
complicated set of results needed to make this happen, instead return a closure
which achieves this.

The new functionality is introduced via a common `TopLevelCommand` abstraction
which lets us adjust the plugin entrypoint to use the same strategy for parsing
the global arguments. This isn't strictly required (in this case the stuff in
cobra's `Execute` works fine) but doing it this way avoids the possibility of
subtle differences in behaviour.

Fixes #1699, and also, as a side-effect, the first item in #1661.

Signed-off-by: Ian Campbell <ijc@docker.com>
2019-03-13 11:28:17 +00:00
Ian Campbell 8289ae03f8 Add e2e tests for plugin vs global argument issues
These won't pass right now due to https://github.com/docker/cli/issues/1699
("Plugins can't re-use the same flags as cli global flags") and the change in
935d47bbe9 ("Ignore unknown arguments on the top-level command."), but the
intention is to fix them now.

Signed-off-by: Ian Campbell <ijc@docker.com>
2019-03-13 10:54:31 +00:00
Ian Campbell 4e5f0af9cd e2e: start a new file for cli plugins arguments tests
`TestRunGoodArgument` fits here.

Signed-off-by: Ian Campbell <ijc@docker.com>
2019-03-13 10:54:31 +00:00
Sebastiaan van Stijn 79e1cabf17
Merge pull request #1680 from cquon/plugin_error_handling
Fix issue where plugin command error exit code is printed out
2019-03-05 09:22:47 +01:00
Akihiro Suda dbe7afbd04 connhelper: export functions for other projects
Exposed functions are planned to be used by `buildctl`:
https://github.com/moby/buildkit/issues/769

Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
2019-03-02 21:11:49 +09:00
Corey Quon d871451049
Fix issue where plugin command error exit code is printed out
Signed-off-by: Corey Quon <corey.quon@docker.com>
2019-02-26 09:39:07 -08:00
Sebastiaan van Stijn f8c5f5d9b8
Show plugins as Management commands
Plugins are expected to be management commands ("docker <object> <verb>").

This patch modified the usage output to shown plugins in the "Management commands"
section.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2019-02-26 00:28:41 +01:00
Silvin Lubecki cdba45bd8b
Merge pull request #1652 from ijc/plugins-config
Add a field to the config file for plugin use.
2019-02-25 12:01:41 +01:00
Silvin Lubecki 11985c6250
Merge pull request #1675 from ulyssessouza/format-plugin-vendor-version-help
Reformat plugin's vendor position and add version on --help
2019-02-25 11:47:09 +01:00
Ian Campbell 20439aa662 Simplify cli plugin config file entry
Make it a simple `map[string]string` for now.

Added a unit test for it.

Signed-off-by: Ian Campbell <ijc@docker.com>
2019-02-25 10:38:48 +00:00
Ulysses Souza 92013600f9 Refactor plugins' vendor location on --help
- The placement of the vendor is now in the end of the line.
- A '*' is now added as suffix of plugins' top level commands.

Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-02-21 17:54:11 +01:00
Ian Campbell 891b3d953e cli-plugins: use `docker system dial-stdio` to call the daemon
This means that plugins can use whatever methods the monolithic CLI supports,
which is good for consistency.

This relies on `os.Args[0]` being something which can be executed again to
reach the same binary, since it is propagated (via an envvar) to the plugin for
this purpose. This essentially requires that the current working directory and
path are not modified by the monolithic CLI before it launches the plugin nor
by the plugin before it initializes the client. This should be the case.

Previously the fake apiclient used by `TestExperimentalCLI` was not being used,
since `cli.Initialize` was unconditionally overwriting it with a real one
(talking to a real daemon during unit testing, it seems). This wasn't expected
nor desirable and no longer happens with the new arrangements, exposing the
fact that no `pingFunc` is provided, leading to a panic. Add a `pingFunc` to
the fake client to avoid this.

Signed-off-by: Ian Campbell <ijc@docker.com>
2019-02-18 11:53:37 +00:00
Ian Campbell baabf6e8ad Ensure that plugins are only listed once in help outputs.
They were listed twice in `docker --help` (but not `docker help`), since the
stubs were added in both `tryRunPluginHelp` and the `setHelpFunc` closure.

Calling `AddPluginStubCommands` earlier in `setHelpFunc` before the call to
`tryRunPluginHelp` is sufficient. Also it is no longer necessary to add just
valid plugins (`tryRunPluginHelp` handles invalid plugins correctly) so remove
that logic (which was in any case broken for e.g. `docker --help`).

Update the e2e test to check for duplicate entries and also to test `docker
--help` which was previously missed.

Signed-off-by: Ian Campbell <ijc@docker.com>
2019-01-30 13:55:42 +00:00
Ian Campbell 935d47bbe9 Ignore unknown arguments on the top-level command.
This allows passing argument to plugins, otherwise they are caught by the parse
loop, since cobra does not know about each plugin at this stage (to avoid
having to always scan for all plugins) this means that e.g. `docker plugin
--foo` would accumulate `plugin` as an arg to the `docker` command, then choke
on the unknown `--foo`.

This allows unknown global args only, unknown arguments on subcommands (e.g.
`docker ps --foo`) are still correctly caught.

Add an e2e test covering this case.

Signed-off-by: Ian Campbell <ijc@docker.com>
2019-01-30 13:45:26 +00:00
Ian Campbell 0ab8ec0e4c Output broken CLI plugins in `help` output.
Signed-off-by: Ian Campbell <ijc@docker.com>
2019-01-30 13:45:26 +00:00
Ian Campbell e5e578abc7 Allow plugins to make use of the cobra `PersistentPreRun` hooks.
Previously a plugin which used these hooks would overwrite the top-level plugin
command's use of this hook, resulting in the dockerCli object not being fully
initialised.

Provide a function which plugins can use to chain to the required behaviour.
This required some fairly ugly arrangements to preserve state (which was
previously in-scope in `newPluginCOmmand`) to be used by the new function.

Signed-off-by: Ian Campbell <ijc@docker.com>
2019-01-30 13:45:26 +00:00
Ian Campbell 53f018120a Integrate CLI plugins with `docker «plugin» --help`.
To achieve this we hook in at the beginning of our custom `HelpFunc` and detect
the plugin case by adding stub commands.

Signed-off-by: Ian Campbell <ijc@docker.com>
2019-01-30 13:45:25 +00:00
Ian Campbell 20a284721c Integrate CLI plugins with `docker help «foo»`
Signed-off-by: Ian Campbell <ijc@docker.com>
2019-01-30 13:45:18 +00:00
Ian Campbell c43da09188 Add stubs when calling help due to no arguments
e.g. the `docker` case which should act as `docker help`.

Signed-off-by: Ian Campbell <ijc@docker.com>
2019-01-30 13:44:06 +00:00
Ian Campbell f912b55bd1 Integrate CLI plugins into `docker help` output.
To do this we add a stub `cobra.Command` for each installed plugin (only when
invoking `help`, not for normal running).

This requires a function to list all available plugins so that is added here.

Signed-off-by: Ian Campbell <ijc@docker.com>
2019-01-30 13:44:06 +00:00
Ian Campbell 5db336798c Add some simple e2e tests for executing CLI plugins
To help with this add a bad plugin which produces invalid metadata and arrange
for it to be built in the e2e container.

Signed-off-by: Ian Campbell <ijc@docker.com>
2019-01-30 13:44:05 +00:00