From d5e6e2ec6ee251a30d3f00e424d0d6bd68a597c0 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Thu, 20 Feb 2025 12:31:03 +0100 Subject: [PATCH] completion: add completion for node names Change completion for nodes to use names by default, and bring back support for the `DOCKER_COMPLETION_SHOW_NODE_IDS` env-var https://github.com/docker/cli/blob/f9ced58158d5e0b358052432244b483774a1983d/contrib/completion/bash/docker#L38 With this patch: docker node ps docker-desktop self export DOCKER_COMPLETION_SHOW_NODE_IDS=yes docker node ps docker-desktop qyeriqk20al6hy4y869d08ff5 self Signed-off-by: Sebastiaan van Stijn --- cli/command/node/completion.go | 37 ++++++++++++++++++++++++++++++++++ cli/command/node/demote.go | 1 + cli/command/node/inspect.go | 1 + cli/command/node/promote.go | 1 + cli/command/node/ps.go | 3 +-- cli/command/node/remove.go | 1 + cli/command/node/update.go | 1 + 7 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 cli/command/node/completion.go diff --git a/cli/command/node/completion.go b/cli/command/node/completion.go new file mode 100644 index 0000000000..3b07b801e7 --- /dev/null +++ b/cli/command/node/completion.go @@ -0,0 +1,37 @@ +package node + +import ( + "os" + + "github.com/docker/cli/cli/command/completion" + "github.com/docker/docker/api/types" + "github.com/spf13/cobra" +) + +// completeNodeNames offers completion for swarm node (host)names and optional IDs. +// By default, only names are returned. +// Set DOCKER_COMPLETION_SHOW_NODE_IDS=yes to also complete IDs. +// +// TODO(thaJeztah): add support for filters. +func completeNodeNames(dockerCLI completion.APIClientProvider) completion.ValidArgsFn { + // https://github.com/docker/cli/blob/f9ced58158d5e0b358052432244b483774a1983d/contrib/completion/bash/docker#L41-L43 + showIDs := os.Getenv("DOCKER_COMPLETION_SHOW_NODE_IDS") == "yes" + return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + list, err := dockerCLI.Client().NodeList(cmd.Context(), types.NodeListOptions{}) + if err != nil { + return nil, cobra.ShellCompDirectiveError + } + + names := make([]string, 0, len(list)+1) + for _, node := range list { + if showIDs { + names = append(names, node.Description.Hostname, node.ID) + } else { + names = append(names, node.Description.Hostname) + } + } + // Nodes allow "self" as magic word for the current node. + names = append(names, "self") + return names, cobra.ShellCompDirectiveNoFileComp + } +} diff --git a/cli/command/node/demote.go b/cli/command/node/demote.go index 9f6b25ac96..5ede173cd1 100644 --- a/cli/command/node/demote.go +++ b/cli/command/node/demote.go @@ -18,6 +18,7 @@ func newDemoteCommand(dockerCli command.Cli) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { return runDemote(cmd.Context(), dockerCli, args) }, + ValidArgsFunction: completeNodeNames(dockerCli), } } diff --git a/cli/command/node/inspect.go b/cli/command/node/inspect.go index 270a14bd2b..2feb8dc138 100644 --- a/cli/command/node/inspect.go +++ b/cli/command/node/inspect.go @@ -32,6 +32,7 @@ func newInspectCommand(dockerCli command.Cli) *cobra.Command { opts.nodeIds = args return runInspect(cmd.Context(), dockerCli, opts) }, + ValidArgsFunction: completeNodeNames(dockerCli), } flags := cmd.Flags() diff --git a/cli/command/node/promote.go b/cli/command/node/promote.go index 2257273972..9832295264 100644 --- a/cli/command/node/promote.go +++ b/cli/command/node/promote.go @@ -18,6 +18,7 @@ func newPromoteCommand(dockerCli command.Cli) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { return runPromote(cmd.Context(), dockerCli, args) }, + ValidArgsFunction: completeNodeNames(dockerCli), } } diff --git a/cli/command/node/ps.go b/cli/command/node/ps.go index 207ecff575..e999a36c1f 100644 --- a/cli/command/node/ps.go +++ b/cli/command/node/ps.go @@ -6,7 +6,6 @@ import ( "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" - "github.com/docker/cli/cli/command/completion" "github.com/docker/cli/cli/command/idresolver" "github.com/docker/cli/cli/command/task" "github.com/docker/cli/opts" @@ -41,7 +40,7 @@ func newPsCommand(dockerCli command.Cli) *cobra.Command { return runPs(cmd.Context(), dockerCli, options) }, - ValidArgsFunction: completion.NoComplete, + ValidArgsFunction: completeNodeNames(dockerCli), } flags := cmd.Flags() flags.BoolVar(&options.noTrunc, "no-trunc", false, "Do not truncate output") diff --git a/cli/command/node/remove.go b/cli/command/node/remove.go index 8e9460c95a..6ded0add42 100644 --- a/cli/command/node/remove.go +++ b/cli/command/node/remove.go @@ -26,6 +26,7 @@ func newRemoveCommand(dockerCli command.Cli) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { return runRemove(cmd.Context(), dockerCli, args, opts) }, + ValidArgsFunction: completeNodeNames(dockerCli), } flags := cmd.Flags() flags.BoolVarP(&opts.force, "force", "f", false, "Force remove a node from the swarm") diff --git a/cli/command/node/update.go b/cli/command/node/update.go index 2083aeaf5d..cb46cf37f9 100644 --- a/cli/command/node/update.go +++ b/cli/command/node/update.go @@ -25,6 +25,7 @@ func newUpdateCommand(dockerCli command.Cli) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { return runUpdate(cmd.Context(), dockerCli, cmd.Flags(), args[0]) }, + ValidArgsFunction: completeNodeNames(dockerCli), } flags := cmd.Flags()