Skip to content

Commit

Permalink
Fix prefix-matching for service ps
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
thaJeztah committed May 11, 2017
1 parent 3d58c3f commit d564621
Showing 1 changed file with 36 additions and 18 deletions.
54 changes: 36 additions & 18 deletions cli/command/service/ps.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package service
import (
"strings"

"golang.org/x/net/context"

"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/formatter"
Expand All @@ -16,6 +14,7 @@ import (
"github.com/docker/docker/opts"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"golang.org/x/net/context"
)

type psOptions struct {
Expand Down Expand Up @@ -70,29 +69,43 @@ func runPS(dockerCli command.Cli, opts 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 opts.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
}
}
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 nothing has been found, return immediately.
if serviceCount == 0 {
return errors.Errorf("no such services: %s", service)
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 {
Expand All @@ -118,6 +131,11 @@ func runPS(dockerCli command.Cli, opts psOptions) error {
format = formatter.TableFormatKey
}
}

return task.Print(ctx, dockerCli, tasks, idresolver.New(client, opts.noResolve), !opts.noTrunc, opts.quiet, format)
if err := task.Print(ctx, dockerCli, tasks, idresolver.New(client, opts.noResolve), !opts.noTrunc, opts.quiet, format); err != nil {
return err
}
if len(errs) != 0 {
return errors.New(strings.Join(errs, "\n"))
}
return nil
}

0 comments on commit d564621

Please sign in to comment.