Explorar el Código

Merge pull request #25234 from yongtang/25228-service-ps-multiple-ID

Support multiple service IDs on "docker service ps"
Vincent Demeester hace 8 años
padre
commit
18265591c2

+ 47 - 9
cli/command/service/ps.go

@@ -1,7 +1,13 @@
 package service
 package service
 
 
 import (
 import (
+	"fmt"
+	"strings"
+
+	"golang.org/x/net/context"
+
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/filters"
 	"github.com/docker/docker/cli"
 	"github.com/docker/docker/cli"
 	"github.com/docker/docker/cli/command"
 	"github.com/docker/docker/cli/command"
 	"github.com/docker/docker/cli/command/idresolver"
 	"github.com/docker/docker/cli/command/idresolver"
@@ -9,11 +15,10 @@ import (
 	"github.com/docker/docker/cli/command/task"
 	"github.com/docker/docker/cli/command/task"
 	"github.com/docker/docker/opts"
 	"github.com/docker/docker/opts"
 	"github.com/spf13/cobra"
 	"github.com/spf13/cobra"
-	"golang.org/x/net/context"
 )
 )
 
 
 type psOptions struct {
 type psOptions struct {
-	serviceID string
+	services  []string
 	quiet     bool
 	quiet     bool
 	noResolve bool
 	noResolve bool
 	noTrunc   bool
 	noTrunc   bool
@@ -24,11 +29,11 @@ func newPsCommand(dockerCli *command.DockerCli) *cobra.Command {
 	opts := psOptions{filter: opts.NewFilterOpt()}
 	opts := psOptions{filter: opts.NewFilterOpt()}
 
 
 	cmd := &cobra.Command{
 	cmd := &cobra.Command{
-		Use:   "ps [OPTIONS] SERVICE",
-		Short: "List the tasks of a service",
-		Args:  cli.ExactArgs(1),
+		Use:   "ps [OPTIONS] SERVICE [SERVICE...]",
+		Short: "List the tasks of one or more services",
+		Args:  cli.RequiresMinArgs(1),
 		RunE: func(cmd *cobra.Command, args []string) error {
 		RunE: func(cmd *cobra.Command, args []string) error {
-			opts.serviceID = args[0]
+			opts.services = args
 			return runPS(dockerCli, opts)
 			return runPS(dockerCli, opts)
 		},
 		},
 	}
 	}
@@ -45,13 +50,46 @@ func runPS(dockerCli *command.DockerCli, opts psOptions) error {
 	client := dockerCli.Client()
 	client := dockerCli.Client()
 	ctx := context.Background()
 	ctx := context.Background()
 
 
-	service, _, err := client.ServiceInspectWithRaw(ctx, opts.serviceID)
+	filter := opts.filter.Value()
+
+	serviceIDFilter := filters.NewArgs()
+	serviceNameFilter := filters.NewArgs()
+	for _, service := range opts.services {
+		serviceIDFilter.Add("id", service)
+		serviceNameFilter.Add("name", service)
+	}
+	serviceByIDList, err := client.ServiceList(ctx, types.ServiceListOptions{Filters: serviceIDFilter})
+	if err != nil {
+		return err
+	}
+	serviceByNameList, err := client.ServiceList(ctx, types.ServiceListOptions{Filters: serviceNameFilter})
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	filter := opts.filter.Value()
-	filter.Add("service", service.ID)
+	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)
+				serviceCount++
+			}
+		}
+
+		// Lookup by Name/Prefix
+		for _, serviceEntry := range serviceByNameList {
+			if strings.HasPrefix(serviceEntry.Spec.Annotations.Name, service) {
+				filter.Add("service", serviceEntry.ID)
+				serviceCount++
+			}
+		}
+		// If nothing has been found, return immediately.
+		if serviceCount == 0 {
+			return fmt.Errorf("no such services: %s", service)
+		}
+	}
+
 	if filter.Include("node") {
 	if filter.Include("node") {
 		nodeFilters := filter.Get("node")
 		nodeFilters := filter.Get("node")
 		for _, nodeFilter := range nodeFilters {
 		for _, nodeFilter := range nodeFilters {

+ 2 - 2
docs/reference/commandline/service_ps.md

@@ -19,7 +19,7 @@ aliases: ["/engine/reference/commandline/service_tasks/"]
 ```Markdown
 ```Markdown
 Usage:  docker service ps [OPTIONS] SERVICE
 Usage:  docker service ps [OPTIONS] SERVICE
 
 
-List the tasks of a service
+List the tasks of one or more services
 
 
 Options:
 Options:
   -f, --filter filter   Filter output based on conditions provided
   -f, --filter filter   Filter output based on conditions provided
@@ -29,7 +29,7 @@ Options:
   -q, --quiet           Only display task IDs
   -q, --quiet           Only display task IDs
 ```
 ```
 
 
-Lists the tasks that are running as part of the specified service. This command
+Lists the tasks that are running as part of the specified services. This command
 has to be run targeting a manager node.
 has to be run targeting a manager node.
 
 
 ## Examples
 ## Examples

+ 70 - 0
integration-cli/docker_cli_swarm_test.go

@@ -1555,3 +1555,73 @@ func (s *DockerSwarmSuite) TestSwarmNetworkCreateDup(c *check.C) {
 		}
 		}
 	}
 	}
 }
 }
+
+func (s *DockerSwarmSuite) TestSwarmServicePsMultipleServiceIDs(c *check.C) {
+	d := s.AddDaemon(c, true, true)
+
+	name1 := "top1"
+	out, err := d.Cmd("service", "create", "--name", name1, "--replicas=3", "busybox", "top")
+	c.Assert(err, checker.IsNil)
+	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
+	id1 := strings.TrimSpace(out)
+
+	name2 := "top2"
+	out, err = d.Cmd("service", "create", "--name", name2, "--replicas=3", "busybox", "top")
+	c.Assert(err, checker.IsNil)
+	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
+	id2 := strings.TrimSpace(out)
+
+	// make sure task has been deployed.
+	waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 6)
+
+	out, err = d.Cmd("service", "ps", name1)
+	c.Assert(err, checker.IsNil)
+	c.Assert(out, checker.Contains, name1+".1")
+	c.Assert(out, checker.Contains, name1+".2")
+	c.Assert(out, checker.Contains, name1+".3")
+	c.Assert(out, checker.Not(checker.Contains), name2+".1")
+	c.Assert(out, checker.Not(checker.Contains), name2+".2")
+	c.Assert(out, checker.Not(checker.Contains), name2+".3")
+
+	out, err = d.Cmd("service", "ps", name1, name2)
+	c.Assert(err, checker.IsNil)
+	c.Assert(out, checker.Contains, name1+".1")
+	c.Assert(out, checker.Contains, name1+".2")
+	c.Assert(out, checker.Contains, name1+".3")
+	c.Assert(out, checker.Contains, name2+".1")
+	c.Assert(out, checker.Contains, name2+".2")
+	c.Assert(out, checker.Contains, name2+".3")
+
+	// Name Prefix
+	out, err = d.Cmd("service", "ps", "to")
+	c.Assert(err, checker.IsNil)
+	c.Assert(out, checker.Contains, name1+".1")
+	c.Assert(out, checker.Contains, name1+".2")
+	c.Assert(out, checker.Contains, name1+".3")
+	c.Assert(out, checker.Contains, name2+".1")
+	c.Assert(out, checker.Contains, name2+".2")
+	c.Assert(out, checker.Contains, name2+".3")
+
+	// Name Prefix (no hit)
+	out, err = d.Cmd("service", "ps", "noname")
+	c.Assert(err, checker.NotNil)
+	c.Assert(out, checker.Contains, "no such services: noname")
+
+	out, err = d.Cmd("service", "ps", id1)
+	c.Assert(err, checker.IsNil)
+	c.Assert(out, checker.Contains, name1+".1")
+	c.Assert(out, checker.Contains, name1+".2")
+	c.Assert(out, checker.Contains, name1+".3")
+	c.Assert(out, checker.Not(checker.Contains), name2+".1")
+	c.Assert(out, checker.Not(checker.Contains), name2+".2")
+	c.Assert(out, checker.Not(checker.Contains), name2+".3")
+
+	out, err = d.Cmd("service", "ps", id1, id2)
+	c.Assert(err, checker.IsNil)
+	c.Assert(out, checker.Contains, name1+".1")
+	c.Assert(out, checker.Contains, name1+".2")
+	c.Assert(out, checker.Contains, name1+".3")
+	c.Assert(out, checker.Contains, name2+".1")
+	c.Assert(out, checker.Contains, name2+".2")
+	c.Assert(out, checker.Contains, name2+".3")
+}