Browse Source

Merge pull request #31538 from yongtang/31325-service-ls-filter-mode

Support `--filter mode=global|replicated` for `docker service ls`
Sebastiaan van Stijn 8 năm trước cách đây
mục cha
commit
b36ce6f2f6

+ 1 - 0
api/swagger.yaml

@@ -7399,6 +7399,7 @@ paths:
 
             - `id=<service id>`
             - `label=<service label>`
+            - `mode=["replicated"|"global"]`
             - `name=<service name>`
       tags: ["Service"]
   /services/create:

+ 0 - 16
daemon/cluster/filters.go

@@ -45,22 +45,6 @@ func newListNodesFilters(filter filters.Args) (*swarmapi.ListNodesRequest_Filter
 	return f, nil
 }
 
-func newListServicesFilters(filter filters.Args) (*swarmapi.ListServicesRequest_Filters, error) {
-	accepted := map[string]bool{
-		"name":  true,
-		"id":    true,
-		"label": true,
-	}
-	if err := filter.Validate(accepted); err != nil {
-		return nil, err
-	}
-	return &swarmapi.ListServicesRequest_Filters{
-		NamePrefixes: filter.Get("name"),
-		IDPrefixes:   filter.Get("id"),
-		Labels:       runconfigopts.ConvertKVStringsToMap(filter.Get("label")),
-	}, nil
-}
-
 func newListTasksFilters(filter filters.Args, transformFunc func(filters.Args) error) (*swarmapi.ListTasksRequest_Filters, error) {
 	accepted := map[string]bool{
 		"name":          true,

+ 31 - 2
daemon/cluster/services.go

@@ -21,6 +21,7 @@ import (
 	"github.com/docker/docker/daemon/logger"
 	"github.com/docker/docker/pkg/ioutils"
 	"github.com/docker/docker/pkg/stdcopy"
+	runconfigopts "github.com/docker/docker/runconfig/opts"
 	swarmapi "github.com/docker/swarmkit/api"
 	gogotypes "github.com/gogo/protobuf/types"
 	"github.com/pkg/errors"
@@ -37,10 +38,25 @@ func (c *Cluster) GetServices(options apitypes.ServiceListOptions) ([]types.Serv
 		return nil, c.errNoManager(state)
 	}
 
-	filters, err := newListServicesFilters(options.Filters)
-	if err != nil {
+	// We move the accepted filter check here as "mode" filter
+	// is processed in the daemon, not in SwarmKit. So it might
+	// be good to have accepted file check in the same file as
+	// the filter processing (in the for loop below).
+	accepted := map[string]bool{
+		"name":  true,
+		"id":    true,
+		"label": true,
+		"mode":  true,
+	}
+	if err := options.Filters.Validate(accepted); err != nil {
 		return nil, err
 	}
+	filters := &swarmapi.ListServicesRequest_Filters{
+		NamePrefixes: options.Filters.Get("name"),
+		IDPrefixes:   options.Filters.Get("id"),
+		Labels:       runconfigopts.ConvertKVStringsToMap(options.Filters.Get("label")),
+	}
+
 	ctx, cancel := c.getRequestContext()
 	defer cancel()
 
@@ -54,6 +70,19 @@ func (c *Cluster) GetServices(options apitypes.ServiceListOptions) ([]types.Serv
 	services := []types.Service{}
 
 	for _, service := range r.Services {
+		if options.Filters.Include("mode") {
+			var mode string
+			switch service.Spec.GetMode().(type) {
+			case *swarmapi.ServiceSpec_Global:
+				mode = "global"
+			case *swarmapi.ServiceSpec_Replicated:
+				mode = "replicated"
+			}
+
+			if !options.Filters.ExactMatch("mode", mode) {
+				continue
+			}
+		}
 		services = append(services, convert.ServiceFromGRPC(*service))
 	}
 

+ 1 - 0
docs/api/version-history.md

@@ -27,6 +27,7 @@ keywords: "API, Docker, rcli, REST, documentation"
 * `POST /build` now accepts `extrahosts` parameter to specify a host to ip mapping to use during the build.
 * `POST /services/create` and `POST /services/(id or name)/update` now accept a `rollback` value for `FailureAction`.
 * `POST /services/create` and `POST /services/(id or name)/update` now accept an optional `RollbackConfig` object which specifies rollback options.
+* `GET /services` now supports a `mode` filter to filter services based on the service mode (either `global` or `replicated`).
 
 ## v1.27 API changes
 

+ 13 - 0
docs/reference/commandline/service_ls.md

@@ -60,6 +60,7 @@ The currently supported filters are:
 
 * [id](service_ls.md#id)
 * [label](service_ls.md#label)
+* [mode](service_ls.md#mode)
 * [name](service_ls.md#name)
 
 #### id
@@ -98,6 +99,18 @@ ID            NAME      MODE        REPLICAS  IMAGE
 74nzcxxjv6fq  backend   replicated  3/3       redis:3.0.6
 ```
 
+#### mode
+
+The `mode` filter matches on the mode (either `replicated` or `global`) of a service.
+
+The following filter matches only `global` services.
+
+```bash
+$ docker service ls --filter mode=global
+ID                  NAME                MODE                REPLICAS            IMAGE
+w7y0v2yrn620        top                 global              1/1                 busybox
+```
+
 #### name
 
 The `name` filter matches on all or part of a service's name.

+ 31 - 0
integration-cli/docker_cli_swarm_test.go

@@ -1797,3 +1797,34 @@ func (s *DockerSwarmSuite) TestSwarmStopSignal(c *check.C) {
 	c.Assert(err, checker.IsNil, check.Commentf(out))
 	c.Assert(strings.TrimSpace(out), checker.Equals, "SIGUSR1")
 }
+
+func (s *DockerSwarmSuite) TestSwarmServiceLsFilterMode(c *check.C) {
+	d := s.AddDaemon(c, true, true)
+
+	out, err := d.Cmd("service", "create", "--name", "top1", "busybox", "top")
+	c.Assert(err, checker.IsNil, check.Commentf(out))
+	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
+
+	out, err = d.Cmd("service", "create", "--name", "top2", "--mode=global", "busybox", "top")
+	c.Assert(err, checker.IsNil, check.Commentf(out))
+	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
+
+	// make sure task has been deployed.
+	waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 2)
+
+	out, err = d.Cmd("service", "ls")
+	c.Assert(err, checker.IsNil, check.Commentf(out))
+	c.Assert(out, checker.Contains, "top1")
+	c.Assert(out, checker.Contains, "top2")
+	c.Assert(out, checker.Not(checker.Contains), "localnet")
+
+	out, err = d.Cmd("service", "ls", "--filter", "mode=global")
+	c.Assert(out, checker.Not(checker.Contains), "top1")
+	c.Assert(out, checker.Contains, "top2")
+	c.Assert(err, checker.IsNil, check.Commentf(out))
+
+	out, err = d.Cmd("service", "ls", "--filter", "mode=replicated")
+	c.Assert(err, checker.IsNil, check.Commentf(out))
+	c.Assert(out, checker.Contains, "top1")
+	c.Assert(out, checker.Not(checker.Contains), "top2")
+}