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 <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2017-05-31 21:43:56 +02:00
parent 6c59636498
commit 6279612443
No known key found for this signature in database
GPG Key ID: 76698F39D527CE8C
1 changed files with 35 additions and 16 deletions

View File

@ -69,29 +69,43 @@ func runPS(dockerCli command.Cli, options psOptions) error {
return err return err
} }
for _, service := range options.services { var errs []string
serviceCount := 0 serviceCount := 0
// Lookup by ID/Prefix loop:
for _, serviceEntry := range serviceByIDList { // Match services by 1. Full ID, 2. Full name, 3. ID prefix. An error is returned if the ID-prefix match is ambiguous
if strings.HasPrefix(serviceEntry.ID, service) { for _, service := range options.services {
filter.Add("service", serviceEntry.ID) for _, s := range serviceByIDList {
if s.ID == service {
filter.Add("service", s.ID)
serviceCount++ serviceCount++
continue loop
} }
} }
for _, s := range serviceByNameList {
// Lookup by Name/Prefix if s.Spec.Annotations.Name == service {
for _, serviceEntry := range serviceByNameList { filter.Add("service", s.ID)
if strings.HasPrefix(serviceEntry.Spec.Annotations.Name, service) {
filter.Add("service", serviceEntry.ID)
serviceCount++ serviceCount++
continue loop
}
}
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 nothing has been found, return immediately.
if serviceCount == 0 { if serviceCount == 0 {
return errors.Errorf("no such services: %s", service) return errors.New(strings.Join(errs, "\n"))
} }
}
if filter.Include("node") { if filter.Include("node") {
nodeFilters := filter.Get("node") nodeFilters := filter.Get("node")
for _, nodeFilter := range nodeFilters { for _, nodeFilter := range nodeFilters {
@ -117,6 +131,11 @@ func runPS(dockerCli command.Cli, options psOptions) error {
format = formatter.TableFormatKey format = formatter.TableFormatKey
} }
} }
if err := task.Print(ctx, dockerCli, tasks, idresolver.New(client, options.noResolve), !options.noTrunc, options.quiet, format); err != nil {
return task.Print(ctx, dockerCli, tasks, idresolver.New(client, options.noResolve), !options.noTrunc, options.quiet, format) return err
}
if len(errs) != 0 {
return errors.New(strings.Join(errs, "\n"))
}
return nil
} }