From 62796124432c7e56e7dda226c3c53c8c2356a30c Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Wed, 31 May 2017 21:43:56 +0200 Subject: [PATCH] Fix prefix-matching for service ps The docker CLI matches objects either by ID _prefix_ or a full name match, but not partial name matches. The correct order of resolution is; - Full ID match (a name should not be able to mask an ID) - Full name - ID-prefix This patch changes the way services are matched. Also change to use the first matching service, if there's a full match (by ID or Name) instead of continue looking for other possible matches. Error handling changed; - Do not error early if multiple services were requested and one or more services were not found. Print the services that were not found after printing those that _were_ found instead - Print an error if ID-prefix matching is ambiguous Signed-off-by: Sebastiaan van Stijn --- cli/command/service/ps.go | 51 +++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/cli/command/service/ps.go b/cli/command/service/ps.go index 87b29d2043..7c744478ec 100644 --- a/cli/command/service/ps.go +++ b/cli/command/service/ps.go @@ -69,29 +69,43 @@ func runPS(dockerCli command.Cli, options psOptions) error { return err } + var errs []string + serviceCount := 0 +loop: + // Match services by 1. Full ID, 2. Full name, 3. ID prefix. An error is returned if the ID-prefix match is ambiguous for _, service := range options.services { - serviceCount := 0 - // Lookup by ID/Prefix - for _, serviceEntry := range serviceByIDList { - if strings.HasPrefix(serviceEntry.ID, service) { - filter.Add("service", serviceEntry.ID) + for _, s := range serviceByIDList { + if s.ID == service { + filter.Add("service", s.ID) serviceCount++ + continue loop } } - - // Lookup by Name/Prefix - for _, serviceEntry := range serviceByNameList { - if strings.HasPrefix(serviceEntry.Spec.Annotations.Name, service) { - filter.Add("service", serviceEntry.ID) + for _, s := range serviceByNameList { + if s.Spec.Annotations.Name == service { + filter.Add("service", s.ID) serviceCount++ + continue loop } } - // If nothing has been found, return immediately. - if serviceCount == 0 { - return errors.Errorf("no such services: %s", service) + found := false + for _, s := range serviceByIDList { + if strings.HasPrefix(s.ID, service) { + if found { + return errors.New("multiple services found with provided prefix: " + service) + } + filter.Add("service", s.ID) + serviceCount++ + found = true + } + } + if !found { + errs = append(errs, "no such service: "+service) } } - + if serviceCount == 0 { + return errors.New(strings.Join(errs, "\n")) + } if filter.Include("node") { nodeFilters := filter.Get("node") for _, nodeFilter := range nodeFilters { @@ -117,6 +131,11 @@ func runPS(dockerCli command.Cli, options psOptions) error { format = formatter.TableFormatKey } } - - return task.Print(ctx, dockerCli, tasks, idresolver.New(client, options.noResolve), !options.noTrunc, options.quiet, format) + if err := task.Print(ctx, dockerCli, tasks, idresolver.New(client, options.noResolve), !options.noTrunc, options.quiet, format); err != nil { + return err + } + if len(errs) != 0 { + return errors.New(strings.Join(errs, "\n")) + } + return nil }