Browse Source

Merge pull request #24620 from yongtang/24270-service-list-filter

Allow partial name match for service ls --filter, node ls --filter, node tasks --filter
Sebastiaan van Stijn 9 years ago
parent
commit
7d84c71500
23 changed files with 810 additions and 250 deletions
  1. 11 11
      daemon/cluster/filters.go
  2. 1 1
      hack/vendor.sh
  3. 84 0
      integration-cli/docker_cli_swarm_test.go
  4. 104 86
      vendor/src/github.com/docker/swarmkit/agent/node.go
  5. 399 93
      vendor/src/github.com/docker/swarmkit/api/control.pb.go
  6. 10 0
      vendor/src/github.com/docker/swarmkit/api/control.proto
  7. 31 31
      vendor/src/github.com/docker/swarmkit/manager/allocator/network.go
  8. 50 2
      vendor/src/github.com/docker/swarmkit/manager/allocator/networkallocator/networkallocator.go
  9. 5 0
      vendor/src/github.com/docker/swarmkit/manager/controlapi/cluster.go
  10. 5 0
      vendor/src/github.com/docker/swarmkit/manager/controlapi/network.go
  11. 19 12
      vendor/src/github.com/docker/swarmkit/manager/controlapi/node.go
  12. 5 0
      vendor/src/github.com/docker/swarmkit/manager/controlapi/service.go
  13. 5 0
      vendor/src/github.com/docker/swarmkit/manager/controlapi/task.go
  14. 17 1
      vendor/src/github.com/docker/swarmkit/manager/manager.go
  15. 6 7
      vendor/src/github.com/docker/swarmkit/manager/state/raft/membership/cluster.go
  16. 17 1
      vendor/src/github.com/docker/swarmkit/manager/state/raft/raft.go
  17. 10 0
      vendor/src/github.com/docker/swarmkit/manager/state/store/by.go
  18. 5 1
      vendor/src/github.com/docker/swarmkit/manager/state/store/clusters.go
  19. 6 0
      vendor/src/github.com/docker/swarmkit/manager/state/store/memory.go
  20. 5 1
      vendor/src/github.com/docker/swarmkit/manager/state/store/networks.go
  21. 5 1
      vendor/src/github.com/docker/swarmkit/manager/state/store/nodes.go
  22. 5 1
      vendor/src/github.com/docker/swarmkit/manager/state/store/services.go
  23. 5 1
      vendor/src/github.com/docker/swarmkit/manager/state/store/tasks.go

+ 11 - 11
daemon/cluster/filters.go

@@ -21,9 +21,9 @@ func newListNodesFilters(filter filters.Args) (*swarmapi.ListNodesRequest_Filter
 		return nil, err
 	}
 	f := &swarmapi.ListNodesRequest_Filters{
-		Names:      filter.Get("name"),
-		IDPrefixes: filter.Get("id"),
-		Labels:     runconfigopts.ConvertKVStringsToMap(filter.Get("label")),
+		NamePrefixes: filter.Get("name"),
+		IDPrefixes:   filter.Get("id"),
+		Labels:       runconfigopts.ConvertKVStringsToMap(filter.Get("label")),
 	}
 
 	for _, r := range filter.Get("role") {
@@ -55,9 +55,9 @@ func newListServicesFilters(filter filters.Args) (*swarmapi.ListServicesRequest_
 		return nil, err
 	}
 	return &swarmapi.ListServicesRequest_Filters{
-		Names:      filter.Get("name"),
-		IDPrefixes: filter.Get("id"),
-		Labels:     runconfigopts.ConvertKVStringsToMap(filter.Get("label")),
+		NamePrefixes: filter.Get("name"),
+		IDPrefixes:   filter.Get("id"),
+		Labels:       runconfigopts.ConvertKVStringsToMap(filter.Get("label")),
 	}, nil
 }
 
@@ -79,11 +79,11 @@ func newListTasksFilters(filter filters.Args, transformFunc func(filters.Args) e
 		}
 	}
 	f := &swarmapi.ListTasksRequest_Filters{
-		Names:      filter.Get("name"),
-		IDPrefixes: filter.Get("id"),
-		Labels:     runconfigopts.ConvertKVStringsToMap(filter.Get("label")),
-		ServiceIDs: filter.Get("service"),
-		NodeIDs:    filter.Get("node"),
+		NamePrefixes: filter.Get("name"),
+		IDPrefixes:   filter.Get("id"),
+		Labels:       runconfigopts.ConvertKVStringsToMap(filter.Get("label")),
+		ServiceIDs:   filter.Get("service"),
+		NodeIDs:      filter.Get("node"),
 	}
 
 	for _, s := range filter.Get("desired-state") {

+ 1 - 1
hack/vendor.sh

@@ -139,7 +139,7 @@ clone git github.com/docker/docker-credential-helpers v0.3.0
 clone git github.com/docker/containerd 0ac3cd1be170d180b2baed755e8f0da547ceb267
 
 # cluster
-clone git github.com/docker/swarmkit 6478bc19cf4bc1d7ba2d6f04ccaacf099508f4a0
+clone git github.com/docker/swarmkit 9ee5fc3b8db5de8c8593a57bc45fc178f74ceee1
 clone git github.com/golang/mock bd3c8e81be01eef76d4b503f5e687d2d1354d2d9
 clone git github.com/gogo/protobuf 43a2e0b1c32252bfbbdf81f7faa7a88fb3fa4028
 clone git github.com/cloudflare/cfssl b895b0549c0ff676f92cf09ba971ae02bb41367b

+ 84 - 0
integration-cli/docker_cli_swarm_test.go

@@ -169,3 +169,87 @@ func (s *DockerSwarmSuite) TestSwarmNodeListHostname(c *check.C) {
 	c.Assert(err, checker.IsNil)
 	c.Assert(strings.Split(out, "\n")[0], checker.Contains, "HOSTNAME")
 }
+
+// Test case for #24270
+func (s *DockerSwarmSuite) TestSwarmServiceListFilter(c *check.C) {
+	d := s.AddDaemon(c, true, true)
+
+	name1 := "redis-cluster-md5"
+	name2 := "redis-cluster"
+	name3 := "other-cluster"
+	out, err := d.Cmd("service", "create", "--name", name1, "busybox", "top")
+	c.Assert(err, checker.IsNil)
+	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
+
+	out, err = d.Cmd("service", "create", "--name", name2, "busybox", "top")
+	c.Assert(err, checker.IsNil)
+	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
+
+	out, err = d.Cmd("service", "create", "--name", name3, "busybox", "top")
+	c.Assert(err, checker.IsNil)
+	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
+
+	filter1 := "name=redis-cluster-md5"
+	filter2 := "name=redis-cluster"
+
+	// We search checker.Contains with `name+" "` to prevent prefix only.
+	out, err = d.Cmd("service", "ls", "--filter", filter1)
+	c.Assert(err, checker.IsNil)
+	c.Assert(out, checker.Contains, name1+" ")
+	c.Assert(out, checker.Not(checker.Contains), name2+" ")
+	c.Assert(out, checker.Not(checker.Contains), name3+" ")
+
+	out, err = d.Cmd("service", "ls", "--filter", filter2)
+	c.Assert(err, checker.IsNil)
+	c.Assert(out, checker.Contains, name1+" ")
+	c.Assert(out, checker.Contains, name2+" ")
+	c.Assert(out, checker.Not(checker.Contains), name3+" ")
+
+	out, err = d.Cmd("service", "ls")
+	c.Assert(err, checker.IsNil)
+	c.Assert(out, checker.Contains, name1+" ")
+	c.Assert(out, checker.Contains, name2+" ")
+	c.Assert(out, checker.Contains, name3+" ")
+}
+
+func (s *DockerSwarmSuite) TestSwarmNodeListFilter(c *check.C) {
+	d := s.AddDaemon(c, true, true)
+
+	out, err := d.Cmd("node", "inspect", "--format", "{{ .Description.Hostname }}", "self")
+	c.Assert(err, checker.IsNil)
+	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
+	name := strings.TrimSpace(out)
+
+	filter := "name=" + name[:4]
+
+	out, err = d.Cmd("node", "ls", "--filter", filter)
+	c.Assert(err, checker.IsNil)
+	c.Assert(out, checker.Contains, name)
+
+	out, err = d.Cmd("node", "ls", "--filter", "name=none")
+	c.Assert(err, checker.IsNil)
+	c.Assert(out, checker.Not(checker.Contains), name)
+}
+
+func (s *DockerSwarmSuite) TestSwarmNodeTaskListFilter(c *check.C) {
+	d := s.AddDaemon(c, true, true)
+
+	name := "redis-cluster-md5"
+	out, err := d.Cmd("service", "create", "--name", name, "--replicas=3", "busybox", "top")
+	c.Assert(err, checker.IsNil)
+	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
+
+	filter := "name=redis-cluster"
+
+	out, err = d.Cmd("node", "tasks", "--filter", filter, "self")
+	c.Assert(err, checker.IsNil)
+	c.Assert(out, checker.Contains, name+".1")
+	c.Assert(out, checker.Contains, name+".2")
+	c.Assert(out, checker.Contains, name+".3")
+
+	out, err = d.Cmd("node", "tasks", "--filter", "name=none", "self")
+	c.Assert(err, checker.IsNil)
+	c.Assert(out, checker.Not(checker.Contains), name+".1")
+	c.Assert(out, checker.Not(checker.Contains), name+".2")
+	c.Assert(out, checker.Not(checker.Contains), name+".3")
+}

+ 104 - 86
vendor/src/github.com/docker/swarmkit/agent/node.go

@@ -85,6 +85,7 @@ type Node struct {
 	config               *NodeConfig
 	remotes              *persistentRemotes
 	role                 string
+	roleCond             *sync.Cond
 	conn                 *grpc.ClientConn
 	connCond             *sync.Cond
 	nodeID               string
@@ -98,7 +99,6 @@ type Node struct {
 	agent                *Agent
 	manager              *manager.Manager
 	roleChangeReq        chan api.NodeRole // used to send role updates from the dispatcher api on promotion/demotion
-	managerRoleCh        chan struct{}
 }
 
 // NewNode returns new Node instance.
@@ -128,8 +128,8 @@ func NewNode(c *NodeConfig) (*Node, error) {
 		ready:                make(chan struct{}),
 		certificateRequested: make(chan struct{}),
 		roleChangeReq:        make(chan api.NodeRole, 1),
-		managerRoleCh:        make(chan struct{}, 32), // 32 just for the case
 	}
+	n.roleCond = sync.NewCond(n.RLocker())
 	n.connCond = sync.NewCond(n.RLocker())
 	if err := n.loadCertificates(); err != nil {
 		return nil, err
@@ -240,28 +240,34 @@ func (n *Node) run(ctx context.Context) (err error) {
 		return err
 	}
 
-	if n.role == ca.ManagerRole {
-		n.managerRoleCh <- struct{}{}
-	}
-
 	forceCertRenewal := make(chan struct{})
 	go func() {
-		n.RLock()
-		lastRole := n.role
-		n.RUnlock()
 		for {
 			select {
 			case <-ctx.Done():
 				return
 			case apirole := <-n.roleChangeReq:
+				n.Lock()
+				lastRole := n.role
 				role := ca.AgentRole
 				if apirole == api.NodeRoleManager {
 					role = ca.ManagerRole
 				}
-				if lastRole != role {
-					forceCertRenewal <- struct{}{}
+				if lastRole == role {
+					n.Unlock()
+					continue
+				}
+				// switch role to agent immediately to shutdown manager early
+				if role == ca.AgentRole {
+					n.role = role
+					n.roleCond.Broadcast()
+				}
+				n.Unlock()
+				select {
+				case forceCertRenewal <- struct{}{}:
+				case <-ctx.Done():
+					return
 				}
-				lastRole = role
 			}
 		}
 	}()
@@ -271,18 +277,13 @@ func (n *Node) run(ctx context.Context) (err error) {
 		for {
 			select {
 			case certUpdate := <-updates:
-				if ctx.Err() != nil {
-					return
-				}
 				if certUpdate.Err != nil {
 					logrus.Warnf("error renewing TLS certificate: %v", certUpdate.Err)
 					continue
 				}
 				n.Lock()
 				n.role = certUpdate.Role
-				if n.role == ca.ManagerRole {
-					n.managerRoleCh <- struct{}{}
-				}
+				n.roleCond.Broadcast()
 				n.Unlock()
 			case <-ctx.Done():
 				return
@@ -535,6 +536,7 @@ func (n *Node) loadCertificates() error {
 	n.role = clientTLSCreds.Role()
 	n.nodeID = clientTLSCreds.NodeID()
 	n.nodeMembership = api.NodeMembershipAccepted
+	n.roleCond.Broadcast()
 	n.Unlock()
 
 	return nil
@@ -571,8 +573,8 @@ func (n *Node) initManagerConnection(ctx context.Context, ready chan<- struct{})
 			n.setControlSocket(conn)
 			if ready != nil {
 				close(ready)
+				ready = nil
 			}
-			ready = nil
 		} else if state == grpc.Shutdown {
 			n.setControlSocket(nil)
 		}
@@ -580,85 +582,101 @@ func (n *Node) initManagerConnection(ctx context.Context, ready chan<- struct{})
 	}
 }
 
-func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig, ready chan struct{}) error {
-	for {
+func (n *Node) waitRole(ctx context.Context, role string) error {
+	n.roleCond.L.Lock()
+	if role == n.role {
+		n.roleCond.L.Unlock()
+		return nil
+	}
+	finishCh := make(chan struct{})
+	defer close(finishCh)
+	go func() {
 		select {
+		case <-finishCh:
 		case <-ctx.Done():
+			// call broadcast to shutdown this function
+			n.roleCond.Broadcast()
+		}
+	}()
+	defer n.roleCond.L.Unlock()
+	for role != n.role {
+		n.roleCond.Wait()
+		if ctx.Err() != nil {
 			return ctx.Err()
-		case <-n.managerRoleCh:
-			if ctx.Err() != nil {
-				return ctx.Err()
-			}
-			n.Lock()
-			// in case if we missed some notifications
-			if n.role != ca.ManagerRole {
-				n.Unlock()
-				continue
-			}
-			n.Unlock()
-			remoteAddr, _ := n.remotes.Select(n.nodeID)
-			m, err := manager.New(&manager.Config{
-				ForceNewCluster: n.config.ForceNewCluster,
-				ProtoAddr: map[string]string{
-					"tcp":  n.config.ListenRemoteAPI,
-					"unix": n.config.ListenControlAPI,
-				},
-				SecurityConfig: securityConfig,
-				ExternalCAs:    n.config.ExternalCAs,
-				JoinRaft:       remoteAddr.Addr,
-				StateDir:       n.config.StateDir,
-				HeartbeatTick:  n.config.HeartbeatTick,
-				ElectionTick:   n.config.ElectionTick,
-			})
-			if err != nil {
-				return err
-			}
-			done := make(chan struct{})
-			go func() {
-				m.Run(context.Background()) // todo: store error
-				close(done)
-			}()
+		}
+	}
+	return nil
+}
 
-			n.Lock()
-			n.manager = m
-			n.Unlock()
+func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig, ready chan struct{}) error {
+	for {
+		if err := n.waitRole(ctx, ca.ManagerRole); err != nil {
+			return err
+		}
+		if ctx.Err() != nil {
+			return ctx.Err()
+		}
+		remoteAddr, _ := n.remotes.Select(n.nodeID)
+		m, err := manager.New(&manager.Config{
+			ForceNewCluster: n.config.ForceNewCluster,
+			ProtoAddr: map[string]string{
+				"tcp":  n.config.ListenRemoteAPI,
+				"unix": n.config.ListenControlAPI,
+			},
+			SecurityConfig: securityConfig,
+			ExternalCAs:    n.config.ExternalCAs,
+			JoinRaft:       remoteAddr.Addr,
+			StateDir:       n.config.StateDir,
+			HeartbeatTick:  n.config.HeartbeatTick,
+			ElectionTick:   n.config.ElectionTick,
+		})
+		if err != nil {
+			return err
+		}
+		done := make(chan struct{})
+		go func() {
+			m.Run(context.Background()) // todo: store error
+			close(done)
+		}()
 
-			connCtx, connCancel := context.WithCancel(ctx)
-			go n.initManagerConnection(connCtx, ready)
+		n.Lock()
+		n.manager = m
+		n.Unlock()
 
-			// this happens only on initial start
-			if ready != nil {
-				go func(ready chan struct{}) {
-					select {
-					case <-ready:
-						n.remotes.Observe(api.Peer{NodeID: n.nodeID, Addr: n.config.ListenRemoteAPI}, 5)
-					case <-connCtx.Done():
-					}
-				}(ready)
-			}
+		connCtx, connCancel := context.WithCancel(ctx)
+		go n.initManagerConnection(connCtx, ready)
 
+		// this happens only on initial start
+		if ready != nil {
+			go func(ready chan struct{}) {
+				select {
+				case <-ready:
+					n.remotes.Observe(api.Peer{NodeID: n.nodeID, Addr: n.config.ListenRemoteAPI}, 5)
+				case <-connCtx.Done():
+				}
+			}(ready)
 			ready = nil
+		}
 
-			select {
-			case <-ctx.Done():
-				m.Stop(context.Background()) // todo: this should be sync like other components
-				<-done
-			// in case of demotion manager will stop itself
-			case <-done:
-			}
-			connCancel()
+		if err := n.waitRole(ctx, ca.AgentRole); err != nil {
+			m.Stop(context.Background())
+		}
 
-			n.Lock()
-			n.manager = nil
-			if n.conn != nil {
-				n.conn.Close()
-			}
-			n.Unlock()
+		select {
+		case <-done:
+		case <-ctx.Done():
+			m.Stop(context.Background())
+			return ctx.Err()
+		}
 
-			if ctx.Err() != nil {
-				return err
-			}
+		connCancel()
+
+		n.Lock()
+		n.manager = nil
+		if n.conn != nil {
+			n.conn.Close()
 		}
+		n.Unlock()
 	}
 }
 

+ 399 - 93
vendor/src/github.com/docker/swarmkit/api/control.pb.go

@@ -64,6 +64,8 @@ type ListNodesRequest_Filters struct {
 	Labels      map[string]string     `protobuf:"bytes,3,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
 	Memberships []NodeSpec_Membership `protobuf:"varint,4,rep,name=memberships,enum=docker.swarmkit.v1.NodeSpec_Membership" json:"memberships,omitempty"`
 	Roles       []NodeRole            `protobuf:"varint,5,rep,name=roles,enum=docker.swarmkit.v1.NodeRole" json:"roles,omitempty"`
+	// NamePrefixes matches all objects with the given prefixes
+	NamePrefixes []string `protobuf:"bytes,6,rep,name=name_prefixes,json=namePrefixes" json:"name_prefixes,omitempty"`
 }
 
 func (m *ListNodesRequest_Filters) Reset()      { *m = ListNodesRequest_Filters{} }
@@ -163,6 +165,8 @@ type ListTasksRequest_Filters struct {
 	ServiceIDs    []string          `protobuf:"bytes,4,rep,name=service_ids,json=serviceIds" json:"service_ids,omitempty"`
 	NodeIDs       []string          `protobuf:"bytes,5,rep,name=node_ids,json=nodeIds" json:"node_ids,omitempty"`
 	DesiredStates []TaskState       `protobuf:"varint,6,rep,name=desired_states,json=desiredStates,enum=docker.swarmkit.v1.TaskState" json:"desired_states,omitempty"`
+	// NamePrefixes matches all objects with the given prefixes
+	NamePrefixes []string `protobuf:"bytes,7,rep,name=name_prefixes,json=namePrefixes" json:"name_prefixes,omitempty"`
 }
 
 func (m *ListTasksRequest_Filters) Reset()      { *m = ListTasksRequest_Filters{} }
@@ -256,6 +260,8 @@ type ListServicesRequest_Filters struct {
 	Names      []string          `protobuf:"bytes,1,rep,name=names" json:"names,omitempty"`
 	IDPrefixes []string          `protobuf:"bytes,2,rep,name=id_prefixes,json=idPrefixes" json:"id_prefixes,omitempty"`
 	Labels     map[string]string `protobuf:"bytes,3,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+	// NamePrefixes matches all objects with the given prefixes
+	NamePrefixes []string `protobuf:"bytes,4,rep,name=name_prefixes,json=namePrefixes" json:"name_prefixes,omitempty"`
 }
 
 func (m *ListServicesRequest_Filters) Reset()      { *m = ListServicesRequest_Filters{} }
@@ -333,6 +339,8 @@ type ListNetworksRequest_Filters struct {
 	Names      []string          `protobuf:"bytes,1,rep,name=names" json:"names,omitempty"`
 	IDPrefixes []string          `protobuf:"bytes,2,rep,name=id_prefixes,json=idPrefixes" json:"id_prefixes,omitempty"`
 	Labels     map[string]string `protobuf:"bytes,3,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+	// NamePrefixes matches all objects with the given prefixes
+	NamePrefixes []string `protobuf:"bytes,4,rep,name=name_prefixes,json=namePrefixes" json:"name_prefixes,omitempty"`
 }
 
 func (m *ListNetworksRequest_Filters) Reset()      { *m = ListNetworksRequest_Filters{} }
@@ -377,6 +385,8 @@ type ListClustersRequest_Filters struct {
 	Names      []string          `protobuf:"bytes,1,rep,name=names" json:"names,omitempty"`
 	IDPrefixes []string          `protobuf:"bytes,2,rep,name=id_prefixes,json=idPrefixes" json:"id_prefixes,omitempty"`
 	Labels     map[string]string `protobuf:"bytes,3,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+	// NamePrefixes matches all objects with the given prefixes
+	NamePrefixes []string `protobuf:"bytes,4,rep,name=name_prefixes,json=namePrefixes" json:"name_prefixes,omitempty"`
 }
 
 func (m *ListClustersRequest_Filters) Reset()      { *m = ListClustersRequest_Filters{} }
@@ -702,6 +712,13 @@ func (m *ListNodesRequest_Filters) Copy() *ListNodesRequest_Filters {
 		}
 	}
 
+	if m.NamePrefixes != nil {
+		o.NamePrefixes = make([]string, 0, len(m.NamePrefixes))
+		for _, v := range m.NamePrefixes {
+			o.NamePrefixes = append(o.NamePrefixes, v)
+		}
+	}
+
 	return o
 }
 
@@ -877,6 +894,13 @@ func (m *ListTasksRequest_Filters) Copy() *ListTasksRequest_Filters {
 		}
 	}
 
+	if m.NamePrefixes != nil {
+		o.NamePrefixes = make([]string, 0, len(m.NamePrefixes))
+		for _, v := range m.NamePrefixes {
+			o.NamePrefixes = append(o.NamePrefixes, v)
+		}
+	}
+
 	return o
 }
 
@@ -1033,6 +1057,13 @@ func (m *ListServicesRequest_Filters) Copy() *ListServicesRequest_Filters {
 		}
 	}
 
+	if m.NamePrefixes != nil {
+		o.NamePrefixes = make([]string, 0, len(m.NamePrefixes))
+		for _, v := range m.NamePrefixes {
+			o.NamePrefixes = append(o.NamePrefixes, v)
+		}
+	}
+
 	return o
 }
 
@@ -1165,6 +1196,13 @@ func (m *ListNetworksRequest_Filters) Copy() *ListNetworksRequest_Filters {
 		}
 	}
 
+	if m.NamePrefixes != nil {
+		o.NamePrefixes = make([]string, 0, len(m.NamePrefixes))
+		for _, v := range m.NamePrefixes {
+			o.NamePrefixes = append(o.NamePrefixes, v)
+		}
+	}
+
 	return o
 }
 
@@ -1249,6 +1287,13 @@ func (m *ListClustersRequest_Filters) Copy() *ListClustersRequest_Filters {
 		}
 	}
 
+	if m.NamePrefixes != nil {
+		o.NamePrefixes = make([]string, 0, len(m.NamePrefixes))
+		for _, v := range m.NamePrefixes {
+			o.NamePrefixes = append(o.NamePrefixes, v)
+		}
+	}
+
 	return o
 }
 
@@ -1333,7 +1378,7 @@ func (this *ListNodesRequest_Filters) GoString() string {
 	if this == nil {
 		return "nil"
 	}
-	s := make([]string, 0, 9)
+	s := make([]string, 0, 10)
 	s = append(s, "&api.ListNodesRequest_Filters{")
 	s = append(s, "Names: "+fmt.Sprintf("%#v", this.Names)+",\n")
 	s = append(s, "IDPrefixes: "+fmt.Sprintf("%#v", this.IDPrefixes)+",\n")
@@ -1352,6 +1397,7 @@ func (this *ListNodesRequest_Filters) GoString() string {
 	}
 	s = append(s, "Memberships: "+fmt.Sprintf("%#v", this.Memberships)+",\n")
 	s = append(s, "Roles: "+fmt.Sprintf("%#v", this.Roles)+",\n")
+	s = append(s, "NamePrefixes: "+fmt.Sprintf("%#v", this.NamePrefixes)+",\n")
 	s = append(s, "}")
 	return strings.Join(s, "")
 }
@@ -1471,7 +1517,7 @@ func (this *ListTasksRequest_Filters) GoString() string {
 	if this == nil {
 		return "nil"
 	}
-	s := make([]string, 0, 10)
+	s := make([]string, 0, 11)
 	s = append(s, "&api.ListTasksRequest_Filters{")
 	s = append(s, "Names: "+fmt.Sprintf("%#v", this.Names)+",\n")
 	s = append(s, "IDPrefixes: "+fmt.Sprintf("%#v", this.IDPrefixes)+",\n")
@@ -1491,6 +1537,7 @@ func (this *ListTasksRequest_Filters) GoString() string {
 	s = append(s, "ServiceIDs: "+fmt.Sprintf("%#v", this.ServiceIDs)+",\n")
 	s = append(s, "NodeIDs: "+fmt.Sprintf("%#v", this.NodeIDs)+",\n")
 	s = append(s, "DesiredStates: "+fmt.Sprintf("%#v", this.DesiredStates)+",\n")
+	s = append(s, "NamePrefixes: "+fmt.Sprintf("%#v", this.NamePrefixes)+",\n")
 	s = append(s, "}")
 	return strings.Join(s, "")
 }
@@ -1615,7 +1662,7 @@ func (this *ListServicesRequest_Filters) GoString() string {
 	if this == nil {
 		return "nil"
 	}
-	s := make([]string, 0, 7)
+	s := make([]string, 0, 8)
 	s = append(s, "&api.ListServicesRequest_Filters{")
 	s = append(s, "Names: "+fmt.Sprintf("%#v", this.Names)+",\n")
 	s = append(s, "IDPrefixes: "+fmt.Sprintf("%#v", this.IDPrefixes)+",\n")
@@ -1632,6 +1679,7 @@ func (this *ListServicesRequest_Filters) GoString() string {
 	if this.Labels != nil {
 		s = append(s, "Labels: "+mapStringForLabels+",\n")
 	}
+	s = append(s, "NamePrefixes: "+fmt.Sprintf("%#v", this.NamePrefixes)+",\n")
 	s = append(s, "}")
 	return strings.Join(s, "")
 }
@@ -1730,7 +1778,7 @@ func (this *ListNetworksRequest_Filters) GoString() string {
 	if this == nil {
 		return "nil"
 	}
-	s := make([]string, 0, 7)
+	s := make([]string, 0, 8)
 	s = append(s, "&api.ListNetworksRequest_Filters{")
 	s = append(s, "Names: "+fmt.Sprintf("%#v", this.Names)+",\n")
 	s = append(s, "IDPrefixes: "+fmt.Sprintf("%#v", this.IDPrefixes)+",\n")
@@ -1747,6 +1795,7 @@ func (this *ListNetworksRequest_Filters) GoString() string {
 	if this.Labels != nil {
 		s = append(s, "Labels: "+mapStringForLabels+",\n")
 	}
+	s = append(s, "NamePrefixes: "+fmt.Sprintf("%#v", this.NamePrefixes)+",\n")
 	s = append(s, "}")
 	return strings.Join(s, "")
 }
@@ -1800,7 +1849,7 @@ func (this *ListClustersRequest_Filters) GoString() string {
 	if this == nil {
 		return "nil"
 	}
-	s := make([]string, 0, 7)
+	s := make([]string, 0, 8)
 	s = append(s, "&api.ListClustersRequest_Filters{")
 	s = append(s, "Names: "+fmt.Sprintf("%#v", this.Names)+",\n")
 	s = append(s, "IDPrefixes: "+fmt.Sprintf("%#v", this.IDPrefixes)+",\n")
@@ -1817,6 +1866,7 @@ func (this *ListClustersRequest_Filters) GoString() string {
 	if this.Labels != nil {
 		s = append(s, "Labels: "+mapStringForLabels+",\n")
 	}
+	s = append(s, "NamePrefixes: "+fmt.Sprintf("%#v", this.NamePrefixes)+",\n")
 	s = append(s, "}")
 	return strings.Join(s, "")
 }
@@ -2707,6 +2757,21 @@ func (m *ListNodesRequest_Filters) MarshalTo(data []byte) (int, error) {
 			i = encodeVarintControl(data, i, uint64(num))
 		}
 	}
+	if len(m.NamePrefixes) > 0 {
+		for _, s := range m.NamePrefixes {
+			data[i] = 0x32
+			i++
+			l = len(s)
+			for l >= 1<<7 {
+				data[i] = uint8(uint64(l)&0x7f | 0x80)
+				l >>= 7
+				i++
+			}
+			data[i] = uint8(l)
+			i++
+			i += copy(data[i:], s)
+		}
+	}
 	return i, nil
 }
 
@@ -3075,6 +3140,21 @@ func (m *ListTasksRequest_Filters) MarshalTo(data []byte) (int, error) {
 			i = encodeVarintControl(data, i, uint64(num))
 		}
 	}
+	if len(m.NamePrefixes) > 0 {
+		for _, s := range m.NamePrefixes {
+			data[i] = 0x3a
+			i++
+			l = len(s)
+			for l >= 1<<7 {
+				data[i] = uint8(uint64(l)&0x7f | 0x80)
+				l >>= 7
+				i++
+			}
+			data[i] = uint8(l)
+			i++
+			i += copy(data[i:], s)
+		}
+	}
 	return i, nil
 }
 
@@ -3420,6 +3500,21 @@ func (m *ListServicesRequest_Filters) MarshalTo(data []byte) (int, error) {
 			i += copy(data[i:], v)
 		}
 	}
+	if len(m.NamePrefixes) > 0 {
+		for _, s := range m.NamePrefixes {
+			data[i] = 0x22
+			i++
+			l = len(s)
+			for l >= 1<<7 {
+				data[i] = uint8(uint64(l)&0x7f | 0x80)
+				l >>= 7
+				i++
+			}
+			data[i] = uint8(l)
+			i++
+			i += copy(data[i:], s)
+		}
+	}
 	return i, nil
 }
 
@@ -3705,6 +3800,21 @@ func (m *ListNetworksRequest_Filters) MarshalTo(data []byte) (int, error) {
 			i += copy(data[i:], v)
 		}
 	}
+	if len(m.NamePrefixes) > 0 {
+		for _, s := range m.NamePrefixes {
+			data[i] = 0x22
+			i++
+			l = len(s)
+			for l >= 1<<7 {
+				data[i] = uint8(uint64(l)&0x7f | 0x80)
+				l >>= 7
+				i++
+			}
+			data[i] = uint8(l)
+			i++
+			i += copy(data[i:], s)
+		}
+	}
 	return i, nil
 }
 
@@ -3880,6 +3990,21 @@ func (m *ListClustersRequest_Filters) MarshalTo(data []byte) (int, error) {
 			i += copy(data[i:], v)
 		}
 	}
+	if len(m.NamePrefixes) > 0 {
+		for _, s := range m.NamePrefixes {
+			data[i] = 0x22
+			i++
+			l = len(s)
+			for l >= 1<<7 {
+				data[i] = uint8(uint64(l)&0x7f | 0x80)
+				l >>= 7
+				i++
+			}
+			data[i] = uint8(l)
+			i++
+			i += copy(data[i:], s)
+		}
+	}
 	return i, nil
 }
 
@@ -4425,6 +4550,12 @@ func (m *ListNodesRequest_Filters) Size() (n int) {
 			n += 1 + sovControl(uint64(e))
 		}
 	}
+	if len(m.NamePrefixes) > 0 {
+		for _, s := range m.NamePrefixes {
+			l = len(s)
+			n += 1 + l + sovControl(uint64(l))
+		}
+	}
 	return n
 }
 
@@ -4570,6 +4701,12 @@ func (m *ListTasksRequest_Filters) Size() (n int) {
 			n += 1 + sovControl(uint64(e))
 		}
 	}
+	if len(m.NamePrefixes) > 0 {
+		for _, s := range m.NamePrefixes {
+			l = len(s)
+			n += 1 + l + sovControl(uint64(l))
+		}
+	}
 	return n
 }
 
@@ -4702,6 +4839,12 @@ func (m *ListServicesRequest_Filters) Size() (n int) {
 			n += mapEntrySize + 1 + sovControl(uint64(mapEntrySize))
 		}
 	}
+	if len(m.NamePrefixes) > 0 {
+		for _, s := range m.NamePrefixes {
+			l = len(s)
+			n += 1 + l + sovControl(uint64(l))
+		}
+	}
 	return n
 }
 
@@ -4814,6 +4957,12 @@ func (m *ListNetworksRequest_Filters) Size() (n int) {
 			n += mapEntrySize + 1 + sovControl(uint64(mapEntrySize))
 		}
 	}
+	if len(m.NamePrefixes) > 0 {
+		for _, s := range m.NamePrefixes {
+			l = len(s)
+			n += 1 + l + sovControl(uint64(l))
+		}
+	}
 	return n
 }
 
@@ -4882,6 +5031,12 @@ func (m *ListClustersRequest_Filters) Size() (n int) {
 			n += mapEntrySize + 1 + sovControl(uint64(mapEntrySize))
 		}
 	}
+	if len(m.NamePrefixes) > 0 {
+		for _, s := range m.NamePrefixes {
+			l = len(s)
+			n += 1 + l + sovControl(uint64(l))
+		}
+	}
 	return n
 }
 
@@ -4988,6 +5143,7 @@ func (this *ListNodesRequest_Filters) String() string {
 		`Labels:` + mapStringForLabels + `,`,
 		`Memberships:` + fmt.Sprintf("%v", this.Memberships) + `,`,
 		`Roles:` + fmt.Sprintf("%v", this.Roles) + `,`,
+		`NamePrefixes:` + fmt.Sprintf("%v", this.NamePrefixes) + `,`,
 		`}`,
 	}, "")
 	return s
@@ -5113,6 +5269,7 @@ func (this *ListTasksRequest_Filters) String() string {
 		`ServiceIDs:` + fmt.Sprintf("%v", this.ServiceIDs) + `,`,
 		`NodeIDs:` + fmt.Sprintf("%v", this.NodeIDs) + `,`,
 		`DesiredStates:` + fmt.Sprintf("%v", this.DesiredStates) + `,`,
+		`NamePrefixes:` + fmt.Sprintf("%v", this.NamePrefixes) + `,`,
 		`}`,
 	}, "")
 	return s
@@ -5236,6 +5393,7 @@ func (this *ListServicesRequest_Filters) String() string {
 		`Names:` + fmt.Sprintf("%v", this.Names) + `,`,
 		`IDPrefixes:` + fmt.Sprintf("%v", this.IDPrefixes) + `,`,
 		`Labels:` + mapStringForLabels + `,`,
+		`NamePrefixes:` + fmt.Sprintf("%v", this.NamePrefixes) + `,`,
 		`}`,
 	}, "")
 	return s
@@ -5339,6 +5497,7 @@ func (this *ListNetworksRequest_Filters) String() string {
 		`Names:` + fmt.Sprintf("%v", this.Names) + `,`,
 		`IDPrefixes:` + fmt.Sprintf("%v", this.IDPrefixes) + `,`,
 		`Labels:` + mapStringForLabels + `,`,
+		`NamePrefixes:` + fmt.Sprintf("%v", this.NamePrefixes) + `,`,
 		`}`,
 	}, "")
 	return s
@@ -5401,6 +5560,7 @@ func (this *ListClustersRequest_Filters) String() string {
 		`Names:` + fmt.Sprintf("%v", this.Names) + `,`,
 		`IDPrefixes:` + fmt.Sprintf("%v", this.IDPrefixes) + `,`,
 		`Labels:` + mapStringForLabels + `,`,
+		`NamePrefixes:` + fmt.Sprintf("%v", this.NamePrefixes) + `,`,
 		`}`,
 	}, "")
 	return s
@@ -5928,6 +6088,35 @@ func (m *ListNodesRequest_Filters) Unmarshal(data []byte) error {
 				}
 			}
 			m.Roles = append(m.Roles, v)
+		case 6:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field NamePrefixes", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowControl
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthControl
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.NamePrefixes = append(m.NamePrefixes, string(data[iNdEx:postIndex]))
+			iNdEx = postIndex
 		default:
 			iNdEx = preIndex
 			skippy, err := skipControl(data[iNdEx:])
@@ -7037,6 +7226,35 @@ func (m *ListTasksRequest_Filters) Unmarshal(data []byte) error {
 				}
 			}
 			m.DesiredStates = append(m.DesiredStates, v)
+		case 7:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field NamePrefixes", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowControl
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthControl
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.NamePrefixes = append(m.NamePrefixes, string(data[iNdEx:postIndex]))
+			iNdEx = postIndex
 		default:
 			iNdEx = preIndex
 			skippy, err := skipControl(data[iNdEx:])
@@ -8105,6 +8323,35 @@ func (m *ListServicesRequest_Filters) Unmarshal(data []byte) error {
 			}
 			m.Labels[mapkey] = mapvalue
 			iNdEx = postIndex
+		case 4:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field NamePrefixes", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowControl
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthControl
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.NamePrefixes = append(m.NamePrefixes, string(data[iNdEx:postIndex]))
+			iNdEx = postIndex
 		default:
 			iNdEx = preIndex
 			skippy, err := skipControl(data[iNdEx:])
@@ -9003,6 +9250,35 @@ func (m *ListNetworksRequest_Filters) Unmarshal(data []byte) error {
 			}
 			m.Labels[mapkey] = mapvalue
 			iNdEx = postIndex
+		case 4:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field NamePrefixes", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowControl
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthControl
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.NamePrefixes = append(m.NamePrefixes, string(data[iNdEx:postIndex]))
+			iNdEx = postIndex
 		default:
 			iNdEx = preIndex
 			skippy, err := skipControl(data[iNdEx:])
@@ -9548,6 +9824,35 @@ func (m *ListClustersRequest_Filters) Unmarshal(data []byte) error {
 			}
 			m.Labels[mapkey] = mapvalue
 			iNdEx = postIndex
+		case 4:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field NamePrefixes", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowControl
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthControl
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.NamePrefixes = append(m.NamePrefixes, string(data[iNdEx:postIndex]))
+			iNdEx = postIndex
 		default:
 			iNdEx = preIndex
 			skippy, err := skipControl(data[iNdEx:])
@@ -9984,92 +10289,93 @@ var (
 )
 
 var fileDescriptorControl = []byte{
-	// 1384 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xcc, 0x59, 0xcf, 0x6f, 0x1b, 0xc5,
-	0x17, 0xff, 0xda, 0x69, 0xe2, 0xfa, 0xb9, 0x4e, 0x9a, 0xa9, 0xa3, 0x6f, 0xe4, 0x86, 0x14, 0x6d,
-	0x21, 0x4d, 0xa4, 0xe0, 0x80, 0xa3, 0x8a, 0x00, 0x12, 0x88, 0x24, 0x14, 0x59, 0x94, 0x50, 0x6d,
-	0x28, 0xe2, 0x16, 0x39, 0xf6, 0x34, 0x2c, 0xb1, 0xbd, 0x66, 0x77, 0x93, 0x36, 0xe2, 0xc2, 0x9f,
-	0xc1, 0xdf, 0xc0, 0x81, 0x3b, 0x27, 0x0e, 0x5c, 0x2a, 0x4e, 0x5c, 0x90, 0x40, 0x42, 0xa8, 0xed,
-	0x1f, 0x80, 0xf8, 0x03, 0x38, 0x30, 0xb3, 0xf3, 0x66, 0x77, 0x3d, 0x9e, 0x9d, 0xb5, 0xe3, 0x54,
-	0xf4, 0x60, 0xd5, 0x3b, 0xfb, 0x79, 0xbf, 0xe6, 0x7d, 0xde, 0xcb, 0x7b, 0x2e, 0x94, 0x5b, 0x6e,
-	0x2f, 0xf0, 0xdc, 0x4e, 0xad, 0xef, 0xb9, 0x81, 0x4b, 0x48, 0xdb, 0x6d, 0x1d, 0x53, 0xaf, 0xe6,
-	0x3f, 0x6c, 0x7a, 0xdd, 0x63, 0x27, 0xa8, 0x9d, 0xbe, 0x51, 0x2d, 0xf9, 0x7d, 0xda, 0xf2, 0x05,
-	0xa0, 0x5a, 0x76, 0x0f, 0xbf, 0xa4, 0xad, 0x40, 0x3e, 0x96, 0x82, 0xb3, 0x3e, 0x95, 0x0f, 0x95,
-	0x23, 0xf7, 0xc8, 0x0d, 0xbf, 0x6e, 0xf0, 0x6f, 0x78, 0x7a, 0xad, 0xdf, 0x39, 0x39, 0x72, 0x7a,
-	0x1b, 0xe2, 0x1f, 0x71, 0x68, 0xdd, 0x86, 0xd9, 0x0f, 0x69, 0xb0, 0xe7, 0xb6, 0xa9, 0x4d, 0xbf,
-	0x3a, 0xa1, 0x7e, 0x40, 0x6e, 0x42, 0xa1, 0xc7, 0x1e, 0x0f, 0x9c, 0xf6, 0x62, 0xee, 0xe5, 0xdc,
-	0x6a, 0x71, 0x1b, 0x9e, 0xfd, 0x79, 0x63, 0x86, 0x23, 0x1a, 0xbb, 0xf6, 0x0c, 0x7f, 0xd5, 0x68,
-	0x5b, 0xef, 0xc1, 0x5c, 0x24, 0xe6, 0xf7, 0xdd, 0x9e, 0x4f, 0xc9, 0x3a, 0x5c, 0xe2, 0x2f, 0x43,
-	0xa1, 0x52, 0x7d, 0xb1, 0x36, 0x1c, 0x40, 0x2d, 0xc4, 0x87, 0x28, 0xeb, 0x87, 0x29, 0xb8, 0x7a,
-	0xd7, 0xf1, 0x43, 0x15, 0xbe, 0x34, 0x7d, 0x07, 0x0a, 0x0f, 0x9c, 0x4e, 0x40, 0x3d, 0x1f, 0xb5,
-	0xac, 0xeb, 0xb4, 0xa8, 0x62, 0xb5, 0x3b, 0x42, 0xc6, 0x96, 0xc2, 0xd5, 0x3f, 0xf2, 0x50, 0xc0,
-	0x43, 0x52, 0x81, 0xe9, 0x5e, 0xb3, 0x4b, 0xb9, 0xc6, 0xa9, 0xd5, 0xa2, 0x2d, 0x1e, 0xc8, 0x06,
-	0x94, 0x9c, 0xf6, 0x41, 0xdf, 0xa3, 0x0f, 0x9c, 0x47, 0xec, 0x5d, 0x9e, 0xbf, 0xdb, 0x9e, 0x65,
-	0x81, 0x42, 0x63, 0xf7, 0x1e, 0x9e, 0xda, 0xe0, 0xb4, 0xe5, 0x77, 0x72, 0x0f, 0x66, 0x3a, 0xcd,
-	0x43, 0xda, 0xf1, 0x17, 0xa7, 0x18, 0xb6, 0x54, 0xdf, 0x1a, 0xc7, 0xb3, 0xda, 0xdd, 0x50, 0xf4,
-	0x03, 0x96, 0xe0, 0x33, 0x1b, 0xf5, 0x90, 0x06, 0x94, 0xba, 0xb4, 0x7b, 0xc8, 0x5e, 0x7f, 0xe1,
-	0xf4, 0xfd, 0xc5, 0x4b, 0x4c, 0xed, 0x6c, 0xfd, 0x56, 0xda, 0xb5, 0xed, 0xb3, 0xd4, 0xd7, 0x3e,
-	0x8e, 0xf0, 0x76, 0x52, 0x96, 0xd4, 0x61, 0x9a, 0x31, 0x87, 0xc5, 0x31, 0x1d, 0x2a, 0x59, 0x4a,
-	0xbd, 0x7b, 0x06, 0xb2, 0x05, 0xb4, 0xfa, 0x16, 0x94, 0x12, 0x5e, 0x91, 0xab, 0x30, 0x75, 0x4c,
-	0xcf, 0x44, 0xc6, 0x6d, 0xfe, 0x95, 0x5f, 0xdc, 0x69, 0xb3, 0x73, 0x42, 0xd9, 0xe5, 0xf0, 0x33,
-	0xf1, 0xf0, 0x76, 0x7e, 0x2b, 0x67, 0xed, 0xc0, 0x7c, 0x22, 0x52, 0x4c, 0x7f, 0x8d, 0xdd, 0x33,
-	0x3f, 0x08, 0xef, 0xd9, 0x94, 0x7f, 0x01, 0xb3, 0xbe, 0xcb, 0xc1, 0xfc, 0xfd, 0x7e, 0xbb, 0x19,
-	0xd0, 0x71, 0xc9, 0x47, 0xde, 0x85, 0x2b, 0x21, 0xe8, 0x94, 0xc5, 0xef, 0xb8, 0xbd, 0xd0, 0xc1,
-	0x52, 0xfd, 0xba, 0xce, 0xe2, 0x67, 0x02, 0x62, 0x97, 0xb8, 0x00, 0x3e, 0x90, 0xd7, 0xe1, 0x12,
-	0xaf, 0x24, 0x96, 0x49, 0x2e, 0xb7, 0x64, 0xba, 0x72, 0x3b, 0x44, 0x5a, 0xdb, 0x40, 0x92, 0xbe,
-	0x9e, 0x8b, 0xf1, 0x5b, 0x30, 0x6f, 0xd3, 0xae, 0x7b, 0x3a, 0x76, 0xbc, 0x56, 0x05, 0x48, 0x52,
-	0x52, 0x58, 0xc7, 0xca, 0xfd, 0xb4, 0xe9, 0x1f, 0x27, 0x94, 0x05, 0xec, 0x51, 0x51, 0xc6, 0x11,
-	0x5c, 0x19, 0x7f, 0x15, 0x55, 0xae, 0x10, 0x8b, 0xe3, 0xe0, 0x2f, 0x4d, 0x71, 0x84, 0xf8, 0x10,
-	0x15, 0xc7, 0x31, 0xb6, 0xe9, 0x28, 0x8e, 0xa4, 0x75, 0xeb, 0x77, 0xec, 0x04, 0xfc, 0xf0, 0x1c,
-	0x9d, 0x20, 0x29, 0x36, 0xdc, 0x09, 0xfe, 0xf9, 0x0f, 0x3b, 0x81, 0xce, 0x33, 0x6d, 0x27, 0x60,
-	0x2e, 0xf8, 0xd4, 0x3b, 0x75, 0x5a, 0x9c, 0x07, 0xa2, 0x13, 0xa0, 0x0b, 0xfb, 0xe2, 0xb8, 0xb1,
-	0xcb, 0x5c, 0x40, 0x48, 0xa3, 0xed, 0x93, 0x15, 0xb8, 0x8c, 0xac, 0x11, 0x25, 0x5f, 0xdc, 0x2e,
-	0x31, 0x74, 0x41, 0xd0, 0x86, 0x45, 0x2f, 0x78, 0xe3, 0x93, 0x5d, 0x98, 0x65, 0xa5, 0xe6, 0x78,
-	0xb4, 0x7d, 0xe0, 0x07, 0x8c, 0xbd, 0xfe, 0xe2, 0x4c, 0xd8, 0x20, 0x5e, 0x4a, 0x4b, 0xf1, 0x3e,
-	0x47, 0xd9, 0x65, 0x14, 0x0a, 0x9f, 0x2e, 0xa2, 0x53, 0xe0, 0x4d, 0xc4, 0x9d, 0x82, 0x13, 0xc2,
-	0xd8, 0x29, 0x42, 0x86, 0x08, 0x98, 0xf5, 0x11, 0x54, 0x76, 0x3c, 0xca, 0x5c, 0xc1, 0xdb, 0x90,
-	0x1c, 0xd9, 0xc4, 0x32, 0x16, 0x04, 0xb9, 0xa1, 0x53, 0x83, 0x12, 0x89, 0x4a, 0xde, 0x83, 0x05,
-	0x45, 0x19, 0x7a, 0x75, 0x1b, 0x0a, 0x78, 0xc3, 0xa8, 0xf0, 0xba, 0x41, 0xa1, 0x2d, 0xb1, 0xd6,
-	0xfb, 0x30, 0xcf, 0xca, 0x49, 0xf1, 0x6c, 0x1d, 0x20, 0x4e, 0x28, 0x16, 0x44, 0x99, 0x65, 0xa8,
-	0x18, 0xe5, 0xd3, 0x2e, 0x46, 0xe9, 0x64, 0xf1, 0x91, 0xa4, 0x8a, 0xc9, 0xfc, 0xf9, 0x31, 0x07,
-	0x15, 0xd1, 0xaa, 0x26, 0xf1, 0x89, 0x31, 0x67, 0x4e, 0xa2, 0xc7, 0xe8, 0xb2, 0xb3, 0x28, 0x23,
-	0x1b, 0xed, 0xe6, 0x40, 0xa3, 0x1d, 0x3d, 0x43, 0x4a, 0x00, 0x93, 0xdd, 0xc8, 0x2e, 0x54, 0x44,
-	0xd7, 0x99, 0x28, 0x49, 0xff, 0x87, 0x05, 0x45, 0x0b, 0xb6, 0xaf, 0x9f, 0xf2, 0x70, 0x8d, 0x73,
-	0x1c, 0xcf, 0xa3, 0x0e, 0xd6, 0x50, 0x3b, 0xd8, 0x46, 0x5a, 0x9f, 0x50, 0x24, 0x87, 0x9b, 0xd8,
-	0x93, 0xdc, 0x85, 0x37, 0xb1, 0x7d, 0xa5, 0x89, 0xbd, 0x33, 0xa6, 0x73, 0xba, 0x3e, 0x36, 0x49,
-	0xa3, 0xf8, 0x04, 0x2a, 0x83, 0xd6, 0x30, 0xe7, 0x6f, 0xc2, 0x65, 0xcc, 0x81, 0x6c, 0x17, 0xc6,
-	0xa4, 0x47, 0xe0, 0xb8, 0x69, 0xec, 0xd1, 0xe0, 0xa1, 0xeb, 0x1d, 0x8f, 0xd1, 0x34, 0x50, 0x42,
-	0xd7, 0x34, 0x22, 0x65, 0x31, 0x25, 0x7b, 0xe2, 0xc8, 0x44, 0x49, 0x29, 0x25, 0xb1, 0xd6, 0xfd,
-	0xb0, 0x69, 0x28, 0x9e, 0x11, 0x36, 0x4d, 0xb0, 0x64, 0xe2, 0x7d, 0x85, 0xdf, 0x39, 0x47, 0x51,
-	0x86, 0x73, 0x34, 0x1f, 0x73, 0x14, 0x65, 0x39, 0x47, 0x11, 0x10, 0x35, 0x92, 0x0b, 0xf2, 0xf1,
-	0x73, 0x59, 0x36, 0x17, 0xee, 0x66, 0x54, 0x4a, 0x8a, 0xa7, 0x51, 0x29, 0xe1, 0xf9, 0x39, 0x4a,
-	0x49, 0x91, 0x7c, 0xb1, 0x4a, 0x29, 0xc5, 0xb9, 0xe7, 0x54, 0x4a, 0xb1, 0xb5, 0xb8, 0x94, 0x30,
-	0x07, 0xc6, 0x52, 0x92, 0x49, 0x89, 0xc0, 0xf8, 0x27, 0x6e, 0xa7, 0x73, 0xe2, 0x33, 0x77, 0x13,
-	0xdd, 0xb3, 0x25, 0x4e, 0x94, 0xee, 0x89, 0x38, 0x9e, 0x72, 0x04, 0x44, 0xcc, 0x8c, 0x54, 0xc4,
-	0xcc, 0x44, 0x88, 0x89, 0x99, 0x52, 0x4a, 0x62, 0x23, 0x9a, 0xe0, 0x8b, 0x73, 0xd0, 0x44, 0x91,
-	0x7c, 0xb1, 0x68, 0x92, 0xe2, 0xdc, 0x73, 0xa2, 0x49, 0x6c, 0x2d, 0xa6, 0x09, 0x5e, 0xb4, 0x91,
-	0x26, 0x32, 0x2b, 0x11, 0x38, 0x31, 0x79, 0x4c, 0x42, 0x15, 0x3e, 0x79, 0x48, 0xf4, 0x38, 0x93,
-	0x07, 0xca, 0x8c, 0x31, 0x79, 0xa0, 0x75, 0xdd, 0xe4, 0x71, 0x31, 0x44, 0xad, 0xff, 0x3a, 0x0f,
-	0x85, 0x1d, 0xf1, 0xab, 0x0e, 0x71, 0xa0, 0x80, 0x3f, 0x98, 0x10, 0x4b, 0x27, 0x3c, 0xf8, 0x23,
-	0x4c, 0xf5, 0xa6, 0x11, 0x83, 0xfd, 0x72, 0xe1, 0xe7, 0xef, 0xff, 0xfa, 0x36, 0x3f, 0x07, 0xe5,
-	0x10, 0xf4, 0x5a, 0xb7, 0xd9, 0x6b, 0x1e, 0x51, 0x8f, 0xb8, 0x50, 0x8c, 0xd6, 0x73, 0xf2, 0xca,
-	0x28, 0xbf, 0x53, 0x54, 0x5f, 0xcd, 0x40, 0x99, 0x0d, 0x7a, 0x00, 0xf1, 0x76, 0x4c, 0xb4, 0xba,
-	0x86, 0x36, 0xfd, 0xea, 0x4a, 0x16, 0x2c, 0xd3, 0x66, 0xbc, 0x13, 0xeb, 0x6d, 0x0e, 0x6d, 0xdb,
-	0x7a, 0x9b, 0x9a, 0xd5, 0x3a, 0xc5, 0xa6, 0xc8, 0x21, 0x5f, 0x4d, 0x52, 0x73, 0x98, 0xd8, 0x89,
-	0x53, 0x73, 0x38, 0xb0, 0xfd, 0x9a, 0x73, 0x18, 0x2e, 0x4e, 0xe9, 0x39, 0x4c, 0x6e, 0x98, 0xe9,
-	0x39, 0x1c, 0xd8, 0xbe, 0x32, 0xef, 0x33, 0x0c, 0xcf, 0x70, 0x9f, 0xc9, 0x08, 0x57, 0xb2, 0x60,
-	0x99, 0x36, 0xe3, 0xc5, 0x47, 0x6f, 0x73, 0x68, 0xb7, 0xd2, 0xdb, 0x1c, 0xde, 0x9f, 0xd2, 0x6c,
-	0x3e, 0x82, 0x2b, 0xc9, 0x41, 0x93, 0xdc, 0x1a, 0x71, 0xf0, 0xad, 0xae, 0x66, 0x03, 0xcd, 0x96,
-	0xbf, 0x86, 0xf2, 0xc0, 0xe6, 0x49, 0xb4, 0x1a, 0x75, 0x9b, 0x6e, 0x75, 0x6d, 0x04, 0x64, 0xa6,
-	0xf1, 0x81, 0xa5, 0x4a, 0x6f, 0x5c, 0xb7, 0x38, 0xea, 0x8d, 0x6b, 0x37, 0x34, 0x83, 0xf1, 0x81,
-	0xdd, 0x49, 0x6f, 0x5c, 0xb7, 0xa4, 0xe9, 0x8d, 0xeb, 0x17, 0x31, 0x23, 0xc9, 0x70, 0xaa, 0x49,
-	0x25, 0xd9, 0xe0, 0x90, 0x9b, 0x4a, 0x32, 0x75, 0x62, 0x35, 0x93, 0x4c, 0x8e, 0x60, 0xe9, 0x24,
-	0x53, 0x46, 0xc2, 0x74, 0x92, 0xa9, 0xd3, 0x5c, 0x26, 0xc9, 0x64, 0xc0, 0x06, 0x92, 0x29, 0x31,
-	0xaf, 0x8d, 0x80, 0x1c, 0x31, 0xcf, 0x46, 0xe3, 0xba, 0xad, 0xc2, 0x94, 0xe7, 0x11, 0x8d, 0x8b,
-	0x3c, 0xe3, 0xdf, 0xe0, 0xd4, 0x3c, 0x0f, 0x8e, 0x26, 0xa9, 0x79, 0x56, 0x06, 0x80, 0x8c, 0x3c,
-	0xcb, 0x19, 0x2a, 0x3d, 0xcf, 0xca, 0x4c, 0x97, 0x9e, 0x67, 0x75, 0x1c, 0xcb, 0xac, 0x67, 0x19,
-	0xb0, 0xa1, 0x9e, 0x95, 0x98, 0xd7, 0x46, 0x40, 0x1a, 0x8d, 0x6f, 0x2f, 0x3d, 0x7e, 0xba, 0xfc,
-	0xbf, 0xdf, 0xd8, 0xe7, 0xef, 0xa7, 0xcb, 0xb9, 0x6f, 0x9e, 0x2d, 0xe7, 0x1e, 0xb3, 0xcf, 0x2f,
-	0xec, 0xf3, 0x84, 0x7d, 0x0e, 0x67, 0xc2, 0xff, 0x58, 0xda, 0xfc, 0x37, 0x00, 0x00, 0xff, 0xff,
-	0x35, 0x0f, 0xc7, 0x5a, 0xd1, 0x1a, 0x00, 0x00,
+	// 1406 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xcc, 0x59, 0x4f, 0x6f, 0x1b, 0x45,
+	0x14, 0xc7, 0xce, 0x1f, 0xd7, 0xcf, 0xb1, 0xd3, 0x4c, 0x1d, 0x11, 0xb9, 0x21, 0x45, 0x5b, 0x48,
+	0x13, 0x29, 0x38, 0xe0, 0xa8, 0x22, 0x80, 0x04, 0x22, 0x09, 0x45, 0x16, 0x25, 0x54, 0x1b, 0x8a,
+	0xb8, 0x45, 0x8e, 0x3d, 0x0d, 0x4b, 0x6c, 0xaf, 0xd9, 0xdd, 0xa4, 0x8d, 0xb8, 0xc0, 0x81, 0xef,
+	0xc0, 0x95, 0x2b, 0x07, 0xbe, 0x02, 0xd7, 0x8a, 0x13, 0x17, 0x24, 0x4e, 0x15, 0xed, 0x89, 0x13,
+	0xe2, 0x13, 0x20, 0x66, 0x76, 0xde, 0xec, 0xae, 0xc7, 0xb3, 0x63, 0x3b, 0x49, 0x95, 0x1e, 0xac,
+	0xee, 0xce, 0xfc, 0xde, 0x9f, 0x99, 0xf7, 0x7b, 0x2f, 0xef, 0x6d, 0xa1, 0xd8, 0x74, 0xbb, 0x81,
+	0xe7, 0xb6, 0xab, 0x3d, 0xcf, 0x0d, 0x5c, 0x42, 0x5a, 0x6e, 0xf3, 0x88, 0x7a, 0x55, 0xff, 0x61,
+	0xc3, 0xeb, 0x1c, 0x39, 0x41, 0xf5, 0xe4, 0xad, 0x4a, 0xc1, 0xef, 0xd1, 0xa6, 0x2f, 0x00, 0x95,
+	0xa2, 0x7b, 0xf0, 0x35, 0x6d, 0x06, 0xf2, 0xb5, 0x10, 0x9c, 0xf6, 0xa8, 0x7c, 0x29, 0x1f, 0xba,
+	0x87, 0x6e, 0xf8, 0xb8, 0xce, 0x9f, 0x70, 0xf5, 0x5a, 0xaf, 0x7d, 0x7c, 0xe8, 0x74, 0xd7, 0xc5,
+	0x3f, 0x62, 0xd1, 0xba, 0x0d, 0xa5, 0x8f, 0x69, 0xb0, 0xeb, 0xb6, 0xa8, 0x4d, 0xbf, 0x39, 0xa6,
+	0x7e, 0x40, 0x6e, 0x42, 0xae, 0xcb, 0x5e, 0xf7, 0x9d, 0xd6, 0x42, 0xe6, 0xd5, 0xcc, 0x4a, 0x7e,
+	0x0b, 0x9e, 0x3d, 0xb9, 0x31, 0xcd, 0x11, 0xf5, 0x1d, 0x7b, 0x9a, 0x6f, 0xd5, 0x5b, 0xd6, 0x07,
+	0x30, 0x1b, 0x89, 0xf9, 0x3d, 0xb7, 0xeb, 0x53, 0xb2, 0x06, 0x93, 0x7c, 0x33, 0x14, 0x2a, 0xd4,
+	0x16, 0xaa, 0x83, 0x07, 0xa8, 0x86, 0xf8, 0x10, 0x65, 0x3d, 0x99, 0x80, 0xab, 0x77, 0x1d, 0x3f,
+	0x54, 0xe1, 0x4b, 0xd3, 0x77, 0x20, 0xf7, 0xc0, 0x69, 0x07, 0xd4, 0xf3, 0x51, 0xcb, 0x9a, 0x4e,
+	0x8b, 0x2a, 0x56, 0xbd, 0x23, 0x64, 0x6c, 0x29, 0x5c, 0xf9, 0x7e, 0x02, 0x72, 0xb8, 0x48, 0xca,
+	0x30, 0xd5, 0x6d, 0x74, 0x28, 0xd7, 0x38, 0xb1, 0x92, 0xb7, 0xc5, 0x0b, 0x59, 0x87, 0x82, 0xd3,
+	0xda, 0xef, 0x79, 0xf4, 0x81, 0xf3, 0x88, 0xed, 0x65, 0xf9, 0xde, 0x56, 0x89, 0x1d, 0x14, 0xea,
+	0x3b, 0xf7, 0x70, 0xd5, 0x06, 0xa7, 0x25, 0x9f, 0xc9, 0x3d, 0x98, 0x6e, 0x37, 0x0e, 0x68, 0xdb,
+	0x5f, 0x98, 0x60, 0xd8, 0x42, 0x6d, 0x73, 0x1c, 0xcf, 0xaa, 0x77, 0x43, 0xd1, 0x8f, 0x58, 0x80,
+	0x4f, 0x6d, 0xd4, 0x43, 0xea, 0x50, 0xe8, 0xd0, 0xce, 0x01, 0xdb, 0xfe, 0xca, 0xe9, 0xf9, 0x0b,
+	0x93, 0x4c, 0x6d, 0xa9, 0x76, 0x2b, 0xed, 0xda, 0xf6, 0x58, 0xe8, 0xab, 0x9f, 0x46, 0x78, 0x3b,
+	0x29, 0x4b, 0x6a, 0x30, 0xc5, 0x98, 0xc3, 0xce, 0x31, 0x15, 0x2a, 0x59, 0x4c, 0xbd, 0x7b, 0x06,
+	0xb2, 0x05, 0x94, 0x85, 0xb9, 0xc8, 0xaf, 0x22, 0xbe, 0x83, 0xe9, 0xf0, 0x7e, 0x66, 0xf8, 0xa2,
+	0x3c, 0x75, 0xe5, 0x1d, 0x28, 0x24, 0x5c, 0x27, 0x57, 0x61, 0xe2, 0x88, 0x9e, 0x0a, 0x5a, 0xd8,
+	0xfc, 0x91, 0xdf, 0xee, 0x49, 0xa3, 0x7d, 0x4c, 0xd9, 0x0d, 0xf2, 0x35, 0xf1, 0xf2, 0x6e, 0x76,
+	0x33, 0x63, 0x6d, 0xc3, 0x5c, 0xe2, 0x3a, 0x90, 0x23, 0x55, 0x16, 0x0c, 0xbe, 0x10, 0x06, 0xc3,
+	0x44, 0x12, 0x01, 0xb3, 0x7e, 0xce, 0xc0, 0xdc, 0xfd, 0x5e, 0xab, 0x11, 0xd0, 0x71, 0x19, 0x4a,
+	0xde, 0x87, 0x99, 0x10, 0x74, 0xc2, 0x2e, 0xc9, 0x71, 0xbb, 0xa1, 0x83, 0x85, 0xda, 0x75, 0x9d,
+	0xc5, 0x2f, 0x04, 0xc4, 0x2e, 0x70, 0x01, 0x7c, 0x21, 0x6f, 0xc2, 0x24, 0x4f, 0x37, 0x16, 0x6e,
+	0x2e, 0xb7, 0x68, 0x8a, 0x8b, 0x1d, 0x22, 0xad, 0x2d, 0x20, 0x49, 0x5f, 0xcf, 0x94, 0x16, 0x9b,
+	0x30, 0x67, 0xd3, 0x8e, 0x7b, 0x32, 0xf6, 0x79, 0xad, 0x32, 0x90, 0xa4, 0xa4, 0xb0, 0x8e, 0xe9,
+	0xfd, 0x79, 0xc3, 0x3f, 0x4a, 0x28, 0x0b, 0xd8, 0xab, 0xa2, 0x8c, 0x23, 0xb8, 0x32, 0xbe, 0x15,
+	0xa5, 0xb7, 0x10, 0x8b, 0xcf, 0xc1, 0x37, 0x4d, 0xe7, 0x08, 0xf1, 0x21, 0x2a, 0x3e, 0xc7, 0xd8,
+	0xa6, 0xa3, 0x73, 0x24, 0xad, 0x5b, 0xff, 0x61, 0xb9, 0xe0, 0x8b, 0x67, 0x28, 0x17, 0x49, 0xb1,
+	0xc1, 0x72, 0xf1, 0xd3, 0x25, 0x96, 0x0b, 0x9d, 0x67, 0xda, 0x72, 0xc1, 0x5c, 0xf0, 0xa9, 0x77,
+	0xe2, 0x34, 0x39, 0x0f, 0x44, 0xb9, 0x40, 0x17, 0xf6, 0xc4, 0x72, 0x7d, 0x87, 0xb9, 0x80, 0x90,
+	0x7a, 0xcb, 0x27, 0xcb, 0x70, 0x05, 0x59, 0x23, 0xea, 0x42, 0x7e, 0xab, 0xc0, 0xd0, 0x39, 0x41,
+	0x1b, 0x76, 0x7a, 0xc1, 0x1b, 0x9f, 0xec, 0x40, 0x89, 0xa5, 0x9a, 0xe3, 0xd1, 0xd6, 0xbe, 0x1f,
+	0x30, 0xf6, 0x8a, 0x4a, 0x50, 0xaa, 0xbd, 0x92, 0x16, 0xe2, 0x3d, 0x8e, 0xb2, 0x8b, 0x28, 0x14,
+	0xbe, 0x69, 0xca, 0x49, 0xee, 0xb9, 0x94, 0x13, 0xbc, 0xae, 0xb8, 0x9c, 0x70, 0xd6, 0x18, 0xcb,
+	0x49, 0x48, 0x23, 0x01, 0xb3, 0x3e, 0x81, 0xf2, 0xb6, 0x47, 0x99, 0xbf, 0x78, 0x65, 0x92, 0x48,
+	0x1b, 0x98, 0xeb, 0x82, 0x45, 0x37, 0x74, 0x6a, 0x50, 0x22, 0x91, 0xee, 0xbb, 0x30, 0xaf, 0x28,
+	0x43, 0xaf, 0x6e, 0x43, 0x0e, 0xc3, 0x80, 0x0a, 0xaf, 0x1b, 0x14, 0xda, 0x12, 0x6b, 0x7d, 0x08,
+	0x73, 0x2c, 0xe7, 0x14, 0xcf, 0xd6, 0x00, 0xe2, 0xa8, 0x63, 0xd6, 0x14, 0x59, 0x18, 0xf3, 0x51,
+	0xd0, 0xed, 0x7c, 0x14, 0x73, 0x76, 0x3e, 0x92, 0x54, 0x71, 0x3e, 0x7f, 0x7e, 0xcd, 0x40, 0x59,
+	0xd4, 0xb3, 0xf3, 0xf8, 0xc4, 0xe8, 0x35, 0x2b, 0xd1, 0x63, 0x94, 0xe2, 0x12, 0xca, 0xc8, 0x6a,
+	0xbc, 0xd1, 0x57, 0x8d, 0x47, 0x8f, 0x90, 0x72, 0x80, 0xf3, 0xdd, 0xc8, 0x0e, 0x94, 0x45, 0x69,
+	0x3a, 0x57, 0x90, 0x5e, 0x86, 0x79, 0x45, 0x0b, 0xd6, 0xb8, 0xbf, 0xb3, 0x70, 0x8d, 0x73, 0x1c,
+	0xd7, 0xa3, 0x32, 0x57, 0x57, 0xcb, 0xdc, 0x7a, 0x5a, 0x31, 0x51, 0x24, 0x07, 0x2b, 0xdd, 0x0f,
+	0xd9, 0x0b, 0xaf, 0x74, 0x7b, 0x4a, 0xa5, 0x7b, 0x6f, 0x4c, 0xe7, 0xb4, 0xc5, 0x6e, 0xa0, 0x9a,
+	0x4c, 0x5e, 0x6c, 0x35, 0xf9, 0x0c, 0xca, 0xfd, 0x2e, 0x21, 0x31, 0xde, 0x86, 0x2b, 0x18, 0x28,
+	0x59, 0x53, 0x8c, 0xcc, 0x88, 0xc0, 0x71, 0x65, 0xd9, 0xa5, 0xc1, 0x43, 0xd7, 0x3b, 0x1a, 0xa3,
+	0xb2, 0xa0, 0x84, 0xae, 0xb2, 0x44, 0xca, 0x62, 0xde, 0x76, 0xc5, 0x92, 0x89, 0xb7, 0x52, 0x4a,
+	0x62, 0xad, 0xfb, 0x61, 0x65, 0x51, 0x3c, 0x23, 0xac, 0x2f, 0x61, 0xb7, 0x89, 0xf7, 0x15, 0x3e,
+	0x73, 0x22, 0xa3, 0x0c, 0x27, 0x72, 0x36, 0x26, 0x32, 0xca, 0x72, 0x22, 0x23, 0x20, 0xaa, 0x36,
+	0x17, 0xe4, 0xe3, 0x97, 0x32, 0xb7, 0x2e, 0xdc, 0xcd, 0x28, 0xdf, 0x14, 0x4f, 0xa3, 0x7c, 0xc3,
+	0xf5, 0x33, 0xe4, 0x9b, 0x22, 0xf9, 0x62, 0xe5, 0x5b, 0x8a, 0x73, 0x97, 0x99, 0x6f, 0xb1, 0x4b,
+	0x71, 0xbe, 0x61, 0xa0, 0x8c, 0xf9, 0x26, 0x23, 0x17, 0x81, 0xf1, 0x8f, 0xe5, 0x76, 0xfb, 0xd8,
+	0x67, 0x67, 0x4a, 0xd4, 0xe1, 0xa6, 0x58, 0x51, 0xea, 0x30, 0xe2, 0x38, 0x2f, 0x10, 0x10, 0xd1,
+	0x37, 0x52, 0x11, 0xd3, 0x17, 0x21, 0x26, 0xfa, 0x4a, 0x29, 0x89, 0x8d, 0xb8, 0x84, 0x1b, 0x67,
+	0xe0, 0x92, 0x22, 0xf9, 0x62, 0x71, 0x29, 0xc5, 0xb9, 0xcb, 0xe4, 0x52, 0xec, 0x52, 0xcc, 0x25,
+	0x8c, 0x86, 0x91, 0x4b, 0x32, 0x74, 0x11, 0x38, 0xd1, 0xe8, 0x9c, 0x87, 0x4f, 0xbc, 0xd1, 0x91,
+	0xe8, 0x71, 0x1a, 0x1d, 0x94, 0x19, 0xa3, 0xd1, 0x41, 0xeb, 0xba, 0x46, 0xe7, 0x62, 0xd8, 0x5c,
+	0xfb, 0x63, 0x0e, 0x72, 0xdb, 0xe2, 0x73, 0x14, 0x71, 0x20, 0x87, 0x5f, 0x7a, 0x88, 0xa5, 0x13,
+	0xee, 0xff, 0x7a, 0x54, 0xb9, 0x69, 0xc4, 0x60, 0xe5, 0x9d, 0xff, 0xed, 0x97, 0x7f, 0x7e, 0xcc,
+	0xce, 0x42, 0x31, 0x04, 0xbd, 0xd1, 0x69, 0x74, 0x1b, 0x87, 0xd4, 0x23, 0x2e, 0xe4, 0xa3, 0x4f,
+	0x06, 0xe4, 0xb5, 0x51, 0x3e, 0xb0, 0x54, 0x5e, 0x1f, 0x82, 0x32, 0x1b, 0xf4, 0x00, 0xe2, 0x89,
+	0x9d, 0x68, 0x75, 0x0d, 0x7c, 0x7d, 0xa8, 0x2c, 0x0f, 0x83, 0x0d, 0xb5, 0x19, 0xcf, 0xe9, 0x7a,
+	0x9b, 0x03, 0x5f, 0x00, 0xf4, 0x36, 0x35, 0xe3, 0x7e, 0x8a, 0x4d, 0x11, 0x43, 0x3e, 0x09, 0xa5,
+	0xc6, 0x30, 0x31, 0xa7, 0xa7, 0xc6, 0xb0, 0x6f, 0x22, 0x37, 0xc7, 0x30, 0x9c, 0xd3, 0xd2, 0x63,
+	0x98, 0x9c, 0x7a, 0xd3, 0x63, 0xd8, 0x37, 0xec, 0x0d, 0xbd, 0xcf, 0xf0, 0x78, 0x86, 0xfb, 0x4c,
+	0x9e, 0x70, 0x79, 0x18, 0x6c, 0xa8, 0xcd, 0x78, 0xce, 0xd2, 0xdb, 0x1c, 0x18, 0xe5, 0xf4, 0x36,
+	0x07, 0xc7, 0xb5, 0x34, 0x9b, 0x8f, 0x60, 0x26, 0xd9, 0xb2, 0x92, 0x5b, 0x23, 0xf6, 0xd9, 0x95,
+	0x95, 0xe1, 0x40, 0xb3, 0xe5, 0x6f, 0xa1, 0xd8, 0x37, 0xe8, 0x12, 0xad, 0x46, 0xdd, 0x60, 0x5d,
+	0x59, 0x1d, 0x01, 0x39, 0xd4, 0x78, 0xdf, 0x0c, 0xa7, 0x37, 0xae, 0x9b, 0x53, 0xf5, 0xc6, 0xb5,
+	0x03, 0xa1, 0xc1, 0x78, 0xdf, 0xa8, 0xa6, 0x37, 0xae, 0x9b, 0x09, 0xf5, 0xc6, 0xf5, 0x73, 0x9f,
+	0x91, 0x64, 0xd8, 0xfa, 0xa4, 0x92, 0xac, 0xbf, 0x5d, 0x4e, 0x25, 0x99, 0xda, 0xfb, 0x9a, 0x49,
+	0x26, 0xfb, 0xb4, 0x74, 0x92, 0x29, 0xcd, 0x65, 0x3a, 0xc9, 0xd4, 0x96, 0x6f, 0x28, 0xc9, 0xe4,
+	0x81, 0x0d, 0x24, 0x53, 0xce, 0xbc, 0x3a, 0x02, 0x72, 0xc4, 0x38, 0x1b, 0x8d, 0xeb, 0xe6, 0x13,
+	0x53, 0x9c, 0x47, 0x34, 0x2e, 0xe2, 0x8c, 0x7f, 0x83, 0x53, 0xe3, 0xdc, 0xdf, 0x9a, 0xa4, 0xc6,
+	0x59, 0x69, 0x00, 0x86, 0xc4, 0x59, 0xf6, 0x50, 0xe9, 0x71, 0x56, 0x1a, 0xbf, 0xf4, 0x38, 0xab,
+	0xed, 0xd8, 0xd0, 0x7c, 0x96, 0x07, 0x36, 0xe4, 0xb3, 0x72, 0xe6, 0xd5, 0x11, 0x90, 0x46, 0xe3,
+	0x5b, 0x8b, 0x8f, 0x9f, 0x2e, 0xbd, 0xf4, 0x27, 0xfb, 0xfd, 0xfb, 0x74, 0x29, 0xf3, 0xdd, 0xb3,
+	0xa5, 0xcc, 0x63, 0xf6, 0xfb, 0x9d, 0xfd, 0xfe, 0x62, 0xbf, 0x83, 0xe9, 0xf0, 0x7f, 0xc4, 0x36,
+	0xfe, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x53, 0x9c, 0xb7, 0x2f, 0x8a, 0x1b, 0x00, 0x00,
 }

+ 10 - 0
vendor/src/github.com/docker/swarmkit/api/control.proto

@@ -88,6 +88,8 @@ message ListNodesRequest {
 		map<string, string> labels = 3;
 		repeated NodeSpec.Membership memberships = 4;
 		repeated NodeRole roles = 5;
+		// NamePrefixes matches all objects with the given prefixes
+		repeated string name_prefixes = 6;
 	}
 
 	Filters filters = 1;
@@ -141,6 +143,8 @@ message ListTasksRequest {
 		repeated string service_ids = 4 [(gogoproto.customname) = "ServiceIDs"];
 		repeated string node_ids = 5 [(gogoproto.customname) = "NodeIDs"];
 		repeated docker.swarmkit.v1.TaskState desired_states = 6;
+		// NamePrefixes matches all objects with the given prefixes
+		repeated string name_prefixes = 7;
 	}
 
 	Filters filters = 1;
@@ -188,6 +192,8 @@ message ListServicesRequest {
 		repeated string names = 1;
 		repeated string id_prefixes = 2 [(gogoproto.customname) = "IDPrefixes"];
 		map<string, string> labels = 3;
+		// NamePrefixes matches all objects with the given prefixes
+		repeated string name_prefixes = 4;
 	}
 
 	Filters filters = 1;
@@ -226,6 +232,8 @@ message ListNetworksRequest {
 		repeated string names = 1;
 		repeated string id_prefixes = 2 [(gogoproto.customname) = "IDPrefixes"];
 		map<string, string> labels = 3;
+		// NamePrefixes matches all objects with the given prefixes
+		repeated string name_prefixes = 4;
 	}
 
 	Filters filters = 1;
@@ -248,6 +256,8 @@ message ListClustersRequest {
 		repeated string names = 1;
 		repeated string id_prefixes = 2 [(gogoproto.customname) = "IDPrefixes"];
 		map<string, string> labels = 3;
+		// NamePrefixes matches all objects with the given prefixes
+		repeated string name_prefixes = 4;
 	}
 
 	Filters filters = 1;

+ 31 - 31
vendor/src/github.com/docker/swarmkit/manager/allocator/network.go

@@ -23,28 +23,31 @@ const (
 	ingressSubnet      = "10.255.0.0/16"
 )
 
-var ingressNetwork = &api.Network{
-	Spec: api.NetworkSpec{
-		Annotations: api.Annotations{
-			Name: ingressNetworkName,
-			Labels: map[string]string{
-				"com.docker.swarm.internal": "true",
+func newIngressNetwork() *api.Network {
+	return &api.Network{
+		Spec: api.NetworkSpec{
+			Annotations: api.Annotations{
+				Name: ingressNetworkName,
+				Labels: map[string]string{
+					"com.docker.swarm.internal": "true",
+				},
 			},
-		},
-		DriverConfig: &api.Driver{},
-		IPAM: &api.IPAMOptions{
-			Driver: &api.Driver{},
-			Configs: []*api.IPAMConfig{
-				{
-					Subnet: ingressSubnet,
+			DriverConfig: &api.Driver{},
+			IPAM: &api.IPAMOptions{
+				Driver: &api.Driver{},
+				Configs: []*api.IPAMConfig{
+					{
+						Subnet: ingressSubnet,
+					},
 				},
 			},
 		},
-	},
+	}
 }
 
 // Network context information which is used throughout the network allocation code.
 type networkContext struct {
+	ingressNetwork *api.Network
 	// Instance of the low-level network allocator which performs
 	// the actual network allocation.
 	nwkAllocator *networkallocator.NetworkAllocator
@@ -75,6 +78,7 @@ func (a *Allocator) doNetworkInit(ctx context.Context) error {
 		unallocatedTasks:    make(map[string]*api.Task),
 		unallocatedServices: make(map[string]*api.Service),
 		unallocatedNetworks: make(map[string]*api.Network),
+		ingressNetwork:      newIngressNetwork(),
 	}
 
 	// Check if we have the ingress network. If not found create
@@ -83,7 +87,7 @@ func (a *Allocator) doNetworkInit(ctx context.Context) error {
 	a.store.View(func(tx store.ReadTx) {
 		networks, err = store.FindNetworks(tx, store.ByName(ingressNetworkName))
 		if len(networks) > 0 {
-			ingressNetwork = networks[0]
+			nc.ingressNetwork = networks[0]
 		}
 	})
 	if err != nil {
@@ -94,8 +98,8 @@ func (a *Allocator) doNetworkInit(ctx context.Context) error {
 	// using the predefined template.
 	if len(networks) == 0 {
 		if err := a.store.Update(func(tx store.Tx) error {
-			ingressNetwork.ID = identity.NewID()
-			if err := store.CreateNetwork(tx, ingressNetwork); err != nil {
+			nc.ingressNetwork.ID = identity.NewID()
+			if err := store.CreateNetwork(tx, nc.ingressNetwork); err != nil {
 				return err
 			}
 
@@ -107,7 +111,7 @@ func (a *Allocator) doNetworkInit(ctx context.Context) error {
 		a.store.View(func(tx store.ReadTx) {
 			networks, err = store.FindNetworks(tx, store.ByName(ingressNetworkName))
 			if len(networks) > 0 {
-				ingressNetwork = networks[0]
+				nc.ingressNetwork = networks[0]
 			}
 		})
 		if err != nil {
@@ -119,14 +123,14 @@ func (a *Allocator) doNetworkInit(ctx context.Context) error {
 	// Try to complete ingress network allocation before anything else so
 	// that the we can get the preferred subnet for ingress
 	// network.
-	if !na.IsAllocated(ingressNetwork) {
-		if err := a.allocateNetwork(ctx, nc, ingressNetwork); err != nil {
+	if !na.IsAllocated(nc.ingressNetwork) {
+		if err := a.allocateNetwork(ctx, nc, nc.ingressNetwork); err != nil {
 			log.G(ctx).Errorf("failed allocating ingress network during init: %v", err)
 		}
 
 		// Update store after allocation
 		if err := a.store.Update(func(tx store.Tx) error {
-			if err := store.UpdateNetwork(tx, ingressNetwork); err != nil {
+			if err := store.UpdateNetwork(tx, nc.ingressNetwork); err != nil {
 				return err
 			}
 
@@ -173,7 +177,7 @@ func (a *Allocator) doNetworkInit(ctx context.Context) error {
 			node.Attachment = &api.NetworkAttachment{}
 		}
 
-		node.Attachment.Network = ingressNetwork.Copy()
+		node.Attachment.Network = nc.ingressNetwork.Copy()
 		if err := a.allocateNode(ctx, nc, node); err != nil {
 			log.G(ctx).Errorf("Failed to allocate network resources for node %s during init: %v", node.ID, err)
 		}
@@ -189,11 +193,7 @@ func (a *Allocator) doNetworkInit(ctx context.Context) error {
 	}
 
 	for _, s := range services {
-		if s.Spec.Endpoint == nil {
-			continue
-		}
-
-		if na.IsServiceAllocated(s) {
+		if !serviceAllocationNeeded(s, nc) {
 			continue
 		}
 
@@ -375,7 +375,7 @@ func (a *Allocator) doNodeAlloc(ctx context.Context, nc *networkContext, ev even
 			node.Attachment = &api.NetworkAttachment{}
 		}
 
-		node.Attachment.Network = ingressNetwork.Copy()
+		node.Attachment.Network = nc.ingressNetwork.Copy()
 		if err := a.allocateNode(ctx, nc, node); err != nil {
 			log.G(ctx).Errorf("Fauled to allocate network resources for node %s: %v", node.ID, err)
 		}
@@ -449,7 +449,7 @@ func (a *Allocator) taskCreateNetworkAttachments(t *api.Task, s *api.Service) {
 	// ports to the external world. Automatically attach the task
 	// to the ingress network.
 	if s.Spec.Endpoint != nil && len(s.Spec.Endpoint.Ports) != 0 {
-		networks = append(networks, &api.NetworkAttachment{Network: ingressNetwork})
+		networks = append(networks, &api.NetworkAttachment{Network: a.netCtx.ingressNetwork})
 	}
 
 	a.store.View(func(tx store.ReadTx) {
@@ -581,7 +581,7 @@ func (a *Allocator) allocateService(ctx context.Context, nc *networkContext, s *
 		if len(s.Spec.Endpoint.Ports) != 0 {
 			var found bool
 			for _, vip := range s.Endpoint.VirtualIPs {
-				if vip.NetworkID == ingressNetwork.ID {
+				if vip.NetworkID == nc.ingressNetwork.ID {
 					found = true
 					break
 				}
@@ -589,7 +589,7 @@ func (a *Allocator) allocateService(ctx context.Context, nc *networkContext, s *
 
 			if !found {
 				s.Endpoint.VirtualIPs = append(s.Endpoint.VirtualIPs,
-					&api.Endpoint_VirtualIP{NetworkID: ingressNetwork.ID})
+					&api.Endpoint_VirtualIP{NetworkID: nc.ingressNetwork.ID})
 			}
 		}
 	}

+ 50 - 2
vendor/src/github.com/docker/swarmkit/manager/allocator/networkallocator/networkallocator.go

@@ -43,6 +43,14 @@ type NetworkAllocator struct {
 	// Allocator state to indicate if allocation has been
 	// successfully completed for this service.
 	services map[string]struct{}
+
+	// Allocator state to indicate if allocation has been
+	// successfully completed for this task.
+	tasks map[string]struct{}
+
+	// Allocator state to indicate if allocation has been
+	// successfully completed for this node.
+	nodes map[string]struct{}
 }
 
 // Local in-memory state related to netwok that need to be tracked by NetworkAllocator
@@ -64,6 +72,8 @@ func New() (*NetworkAllocator, error) {
 	na := &NetworkAllocator{
 		networks: make(map[string]*network),
 		services: make(map[string]struct{}),
+		tasks:    make(map[string]struct{}),
+		nodes:    make(map[string]struct{}),
 	}
 
 	// There are no driver configurations and notification
@@ -188,6 +198,7 @@ outer:
 
 		s.Endpoint.VirtualIPs = append(s.Endpoint.VirtualIPs, vip)
 	}
+	s.Endpoint.Spec = s.Spec.Endpoint.Copy()
 
 	na.services[s.ID] = struct{}{}
 	return
@@ -223,6 +234,12 @@ func (na *NetworkAllocator) IsAllocated(n *api.Network) bool {
 
 // IsTaskAllocated returns if the passed task has it's network resources allocated or not.
 func (na *NetworkAllocator) IsTaskAllocated(t *api.Task) bool {
+	// If the task is not found in the allocated set, then it is
+	// not allocated.
+	if _, ok := na.tasks[t.ID]; !ok {
+		return false
+	}
+
 	// If Networks is empty there is no way this Task is allocated.
 	if len(t.Networks) == 0 {
 		return false
@@ -267,6 +284,12 @@ func (na *NetworkAllocator) IsServiceAllocated(s *api.Service) bool {
 
 // IsNodeAllocated returns if the passed node has its network resources allocated or not.
 func (na *NetworkAllocator) IsNodeAllocated(node *api.Node) bool {
+	// If the node is not found in the allocated set, then it is
+	// not allocated.
+	if _, ok := na.nodes[node.ID]; !ok {
+		return false
+	}
+
 	// If no attachment, not allocated.
 	if node.Attachment == nil {
 		return false
@@ -294,12 +317,18 @@ func (na *NetworkAllocator) IsNodeAllocated(node *api.Node) bool {
 // AllocateNode allocates the IP addresses for the network to which
 // the node is attached.
 func (na *NetworkAllocator) AllocateNode(node *api.Node) error {
-	return na.allocateNetworkIPs(node.Attachment)
+	if err := na.allocateNetworkIPs(node.Attachment); err != nil {
+		return err
+	}
+
+	na.nodes[node.ID] = struct{}{}
+	return nil
 }
 
 // DeallocateNode deallocates the IP addresses for the network to
 // which the node is attached.
 func (na *NetworkAllocator) DeallocateNode(node *api.Node) error {
+	delete(na.nodes, node.ID)
 	return na.releaseEndpoints([]*api.NetworkAttachment{node.Attachment})
 }
 
@@ -315,12 +344,15 @@ func (na *NetworkAllocator) AllocateTask(t *api.Task) error {
 		}
 	}
 
+	na.tasks[t.ID] = struct{}{}
+
 	return nil
 }
 
 // DeallocateTask releases all the endpoint resources for all the
 // networks that a task is attached to.
 func (na *NetworkAllocator) DeallocateTask(t *api.Task) error {
+	delete(na.tasks, t.ID)
 	return na.releaseEndpoints(t.Networks)
 }
 
@@ -371,13 +403,29 @@ func (na *NetworkAllocator) allocateVIP(vip *api.Endpoint_VirtualIP) error {
 		return fmt.Errorf("networkallocator: could not find local network state")
 	}
 
+	// If this IP is already allocated in memory we don't need to
+	// do anything.
+	if _, ok := localNet.endpoints[vip.Addr]; ok {
+		return nil
+	}
+
 	ipam, _, err := na.resolveIPAM(localNet.nw)
 	if err != nil {
 		return fmt.Errorf("failed to resolve IPAM while allocating : %v", err)
 	}
 
+	var addr net.IP
+	if vip.Addr != "" {
+		var err error
+
+		addr, _, err = net.ParseCIDR(vip.Addr)
+		if err != nil {
+			return err
+		}
+	}
+
 	for _, poolID := range localNet.pools {
-		ip, _, err := ipam.RequestAddress(poolID, nil, nil)
+		ip, _, err := ipam.RequestAddress(poolID, addr, nil)
 		if err != nil && err != ipamapi.ErrNoAvailableIPs && err != ipamapi.ErrIPOutOfRange {
 			return fmt.Errorf("could not allocate VIP from IPAM: %v", err)
 		}

+ 5 - 0
vendor/src/github.com/docker/swarmkit/manager/controlapi/cluster.go

@@ -143,6 +143,8 @@ func (s *Server) ListClusters(ctx context.Context, request *api.ListClustersRequ
 		switch {
 		case request.Filters != nil && len(request.Filters.Names) > 0:
 			clusters, err = store.FindClusters(tx, buildFilters(store.ByName, request.Filters.Names))
+		case request.Filters != nil && len(request.Filters.NamePrefixes) > 0:
+			clusters, err = store.FindClusters(tx, buildFilters(store.ByNamePrefix, request.Filters.NamePrefixes))
 		case request.Filters != nil && len(request.Filters.IDPrefixes) > 0:
 			clusters, err = store.FindClusters(tx, buildFilters(store.ByIDPrefix, request.Filters.IDPrefixes))
 		default:
@@ -158,6 +160,9 @@ func (s *Server) ListClusters(ctx context.Context, request *api.ListClustersRequ
 			func(e *api.Cluster) bool {
 				return filterContains(e.Spec.Annotations.Name, request.Filters.Names)
 			},
+			func(e *api.Cluster) bool {
+				return filterContainsPrefix(e.Spec.Annotations.Name, request.Filters.NamePrefixes)
+			},
 			func(e *api.Cluster) bool {
 				return filterContainsPrefix(e.ID, request.Filters.IDPrefixes)
 			},

+ 5 - 0
vendor/src/github.com/docker/swarmkit/manager/controlapi/network.go

@@ -224,6 +224,8 @@ func (s *Server) ListNetworks(ctx context.Context, request *api.ListNetworksRequ
 		switch {
 		case request.Filters != nil && len(request.Filters.Names) > 0:
 			networks, err = store.FindNetworks(tx, buildFilters(store.ByName, request.Filters.Names))
+		case request.Filters != nil && len(request.Filters.NamePrefixes) > 0:
+			networks, err = store.FindNetworks(tx, buildFilters(store.ByNamePrefix, request.Filters.NamePrefixes))
 		case request.Filters != nil && len(request.Filters.IDPrefixes) > 0:
 			networks, err = store.FindNetworks(tx, buildFilters(store.ByIDPrefix, request.Filters.IDPrefixes))
 		default:
@@ -239,6 +241,9 @@ func (s *Server) ListNetworks(ctx context.Context, request *api.ListNetworksRequ
 			func(e *api.Network) bool {
 				return filterContains(e.Spec.Annotations.Name, request.Filters.Names)
 			},
+			func(e *api.Network) bool {
+				return filterContainsPrefix(e.Spec.Annotations.Name, request.Filters.NamePrefixes)
+			},
 			func(e *api.Network) bool {
 				return filterContainsPrefix(e.ID, request.Filters.IDPrefixes)
 			},

+ 19 - 12
vendor/src/github.com/docker/swarmkit/manager/controlapi/node.go

@@ -81,6 +81,8 @@ func (s *Server) ListNodes(ctx context.Context, request *api.ListNodesRequest) (
 		switch {
 		case request.Filters != nil && len(request.Filters.Names) > 0:
 			nodes, err = store.FindNodes(tx, buildFilters(store.ByName, request.Filters.Names))
+		case request.Filters != nil && len(request.Filters.NamePrefixes) > 0:
+			nodes, err = store.FindNodes(tx, buildFilters(store.ByNamePrefix, request.Filters.NamePrefixes))
 		case request.Filters != nil && len(request.Filters.IDPrefixes) > 0:
 			nodes, err = store.FindNodes(tx, buildFilters(store.ByIDPrefix, request.Filters.IDPrefixes))
 		case request.Filters != nil && len(request.Filters.Roles) > 0:
@@ -114,6 +116,15 @@ func (s *Server) ListNodes(ctx context.Context, request *api.ListNodesRequest) (
 				}
 				return filterContains(e.Description.Hostname, request.Filters.Names)
 			},
+			func(e *api.Node) bool {
+				if len(request.Filters.NamePrefixes) == 0 {
+					return true
+				}
+				if e.Description == nil {
+					return false
+				}
+				return filterContainsPrefix(e.Description.Hostname, request.Filters.NamePrefixes)
+			},
 			func(e *api.Node) bool {
 				return filterContainsPrefix(e.ID, request.Filters.IDPrefixes)
 			},
@@ -249,24 +260,15 @@ func (s *Server) UpdateNode(ctx context.Context, request *api.UpdateNodeRequest)
 	}, nil
 }
 
-// RemoveNode updates a Node referenced by NodeID with the given NodeSpec.
+// RemoveNode removes a Node referenced by NodeID with the given NodeSpec.
 // - Returns NotFound if the Node is not found.
-// - Returns FailedPrecondition if the Node has manager role or not shut down.
+// - Returns FailedPrecondition if the Node has manager role (and is part of the memberlist) or is not shut down.
 // - Returns InvalidArgument if NodeID or NodeVersion is not valid.
 // - Returns an error if the delete fails.
 func (s *Server) RemoveNode(ctx context.Context, request *api.RemoveNodeRequest) (*api.RemoveNodeResponse, error) {
 	if request.NodeID == "" {
 		return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
 	}
-	if s.raft != nil {
-		memberlist := s.raft.GetMemberlist()
-
-		for _, member := range memberlist {
-			if member.NodeID == request.NodeID {
-				return nil, grpc.Errorf(codes.FailedPrecondition, "node %s is a cluster manager and is part of the quorum. It must be demoted to worker before removal", request.NodeID)
-			}
-		}
-	}
 
 	err := s.store.Update(func(tx store.Tx) error {
 		node := store.GetNode(tx, request.NodeID)
@@ -274,7 +276,12 @@ func (s *Server) RemoveNode(ctx context.Context, request *api.RemoveNodeRequest)
 			return grpc.Errorf(codes.NotFound, "node %s not found", request.NodeID)
 		}
 		if node.Spec.Role == api.NodeRoleManager {
-			return grpc.Errorf(codes.FailedPrecondition, "node %s role is set to manager. It should be demoted to worker for safe removal", request.NodeID)
+			if s.raft == nil {
+				return grpc.Errorf(codes.FailedPrecondition, "node %s is a manager but cannot access node information from the raft memberlist", request.NodeID)
+			}
+			if member := s.raft.GetMemberByNodeID(request.NodeID); member != nil {
+				return grpc.Errorf(codes.FailedPrecondition, "node %s is a cluster manager and is a member of the raft cluster. It must be demoted to worker before removal", request.NodeID)
+			}
 		}
 		if node.Status.State == api.NodeStatus_READY {
 			return grpc.Errorf(codes.FailedPrecondition, "node %s is not down and can't be removed", request.NodeID)

+ 5 - 0
vendor/src/github.com/docker/swarmkit/manager/controlapi/service.go

@@ -321,6 +321,8 @@ func (s *Server) ListServices(ctx context.Context, request *api.ListServicesRequ
 		switch {
 		case request.Filters != nil && len(request.Filters.Names) > 0:
 			services, err = store.FindServices(tx, buildFilters(store.ByName, request.Filters.Names))
+		case request.Filters != nil && len(request.Filters.NamePrefixes) > 0:
+			services, err = store.FindServices(tx, buildFilters(store.ByNamePrefix, request.Filters.NamePrefixes))
 		case request.Filters != nil && len(request.Filters.IDPrefixes) > 0:
 			services, err = store.FindServices(tx, buildFilters(store.ByIDPrefix, request.Filters.IDPrefixes))
 		default:
@@ -336,6 +338,9 @@ func (s *Server) ListServices(ctx context.Context, request *api.ListServicesRequ
 			func(e *api.Service) bool {
 				return filterContains(e.Spec.Annotations.Name, request.Filters.Names)
 			},
+			func(e *api.Service) bool {
+				return filterContainsPrefix(e.Spec.Annotations.Name, request.Filters.NamePrefixes)
+			},
 			func(e *api.Service) bool {
 				return filterContainsPrefix(e.ID, request.Filters.IDPrefixes)
 			},

+ 5 - 0
vendor/src/github.com/docker/swarmkit/manager/controlapi/task.go

@@ -79,6 +79,8 @@ func (s *Server) ListTasks(ctx context.Context, request *api.ListTasksRequest) (
 		switch {
 		case request.Filters != nil && len(request.Filters.Names) > 0:
 			tasks, err = store.FindTasks(tx, buildFilters(store.ByName, request.Filters.Names))
+		case request.Filters != nil && len(request.Filters.NamePrefixes) > 0:
+			tasks, err = store.FindTasks(tx, buildFilters(store.ByNamePrefix, request.Filters.NamePrefixes))
 		case request.Filters != nil && len(request.Filters.IDPrefixes) > 0:
 			tasks, err = store.FindTasks(tx, buildFilters(store.ByIDPrefix, request.Filters.IDPrefixes))
 		case request.Filters != nil && len(request.Filters.ServiceIDs) > 0:
@@ -104,6 +106,9 @@ func (s *Server) ListTasks(ctx context.Context, request *api.ListTasksRequest) (
 			func(e *api.Task) bool {
 				return filterContains(e.ServiceAnnotations.Name, request.Filters.Names)
 			},
+			func(e *api.Task) bool {
+				return filterContainsPrefix(e.ServiceAnnotations.Name, request.Filters.NamePrefixes)
+			},
 			func(e *api.Task) bool {
 				return filterContainsPrefix(e.ID, request.Filters.IDPrefixes)
 			},

+ 17 - 1
vendor/src/github.com/docker/swarmkit/manager/manager.go

@@ -93,6 +93,19 @@ type Manager struct {
 	stopped chan struct{}
 }
 
+type closeOnceListener struct {
+	once sync.Once
+	net.Listener
+}
+
+func (l *closeOnceListener) Close() error {
+	var err error
+	l.once.Do(func() {
+		err = l.Listener.Close()
+	})
+	return err
+}
+
 // New creates a Manager which has not started to accept requests yet.
 func New(config *Config) (*Manager, error) {
 	dispatcherConfig := dispatcher.DefaultConfig()
@@ -481,7 +494,10 @@ func (m *Manager) Run(parent context.Context) error {
 					"addr":  lis.Addr().String()}))
 			if proto == "unix" {
 				log.G(ctx).Info("Listening for local connections")
-				errServe <- m.localserver.Serve(lis)
+				// we need to disallow double closes because UnixListener.Close
+				// can delete unix-socket file of newer listener. grpc calls
+				// Close twice indeed: in Serve and in Stop.
+				errServe <- m.localserver.Serve(&closeOnceListener{Listener: lis})
 			} else {
 				log.G(ctx).Info("Listening for connections")
 				errServe <- m.server.Serve(lis)

+ 6 - 7
vendor/src/github.com/docker/swarmkit/manager/state/raft/membership/cluster.go

@@ -187,9 +187,13 @@ func (c *Cluster) ValidateConfigurationChange(cc raftpb.ConfChange) error {
 // that might block or harm the Cluster on Member recovery
 func (c *Cluster) CanRemoveMember(from uint64, id uint64) bool {
 	members := c.Members()
-	nreachable := 0
+	nreachable := 0 // reachable managers after removal
 
 	for _, m := range members {
+		if m.RaftID == id {
+			continue
+		}
+
 		// Local node from where the remove is issued
 		if m.RaftID == from {
 			nreachable++
@@ -202,12 +206,7 @@ func (c *Cluster) CanRemoveMember(from uint64, id uint64) bool {
 		}
 	}
 
-	// Special case of 2 managers
-	if nreachable == 1 && len(members) <= 2 {
-		return false
-	}
-
-	nquorum := (len(members)+1)/2 + 1
+	nquorum := (len(members)-1)/2 + 1
 	if nreachable < nquorum {
 		return false
 	}

+ 17 - 1
vendor/src/github.com/docker/swarmkit/manager/state/raft/raft.go

@@ -1206,12 +1206,28 @@ func (n *Node) applyRemoveNode(cc raftpb.ConfChange) (err error) {
 	// If the node from where the remove is issued is
 	// a follower and the leader steps down, Campaign
 	// to be the leader.
-	if cc.NodeID == n.Leader() {
+
+	if cc.NodeID == n.Leader() && !n.IsLeader() {
 		if err = n.Campaign(n.Ctx); err != nil {
 			return err
 		}
 	}
 
+	if cc.NodeID == n.Config.ID {
+		// wait the commit ack to be sent before closing connection
+		n.asyncTasks.Wait()
+
+		// if there are only 2 nodes in the cluster, and leader is leaving
+		// before closing the connection, leader has to ensure that follower gets
+		// noticed about this raft conf change commit. Otherwise, follower would
+		// assume there are still 2 nodes in the cluster and won't get elected
+		// into the leader by acquiring the majority (2 nodes)
+
+		// while n.asyncTasks.Wait() could be helpful in this case
+		// it's the best-effort strategy, because this send could be fail due to some errors (such as time limit exceeds)
+		// TODO(Runshen Zhu): use leadership transfer to solve this case, after vendoring raft 3.0+
+	}
+
 	return n.cluster.RemoveMember(cc.NodeID)
 }
 

+ 10 - 0
vendor/src/github.com/docker/swarmkit/manager/state/store/by.go

@@ -19,6 +19,16 @@ func (a byAll) isBy() {
 // set.
 var All byAll
 
+type byNamePrefix string
+
+func (b byNamePrefix) isBy() {
+}
+
+// ByNamePrefix creates an object to pass to Find to select by query.
+func ByNamePrefix(namePrefix string) By {
+	return byNamePrefix(namePrefix)
+}
+
 type byIDPrefix string
 
 func (b byIDPrefix) isBy() {

+ 5 - 1
vendor/src/github.com/docker/swarmkit/manager/state/store/clusters.go

@@ -173,7 +173,7 @@ func GetCluster(tx ReadTx, id string) *api.Cluster {
 func FindClusters(tx ReadTx, by By) ([]*api.Cluster, error) {
 	checkType := func(by By) error {
 		switch by.(type) {
-		case byName, byIDPrefix:
+		case byName, byNamePrefix, byIDPrefix:
 			return nil
 		default:
 			return ErrInvalidFindBy
@@ -225,3 +225,7 @@ func (ci clusterIndexerByName) FromObject(obj interface{}) (bool, []byte, error)
 	// Add the null character as a terminator
 	return true, []byte(strings.ToLower(c.Spec.Annotations.Name) + "\x00"), nil
 }
+
+func (ci clusterIndexerByName) PrefixFromArgs(args ...interface{}) ([]byte, error) {
+	return prefixFromArgs(args...)
+}

+ 6 - 0
vendor/src/github.com/docker/swarmkit/manager/state/store/memory.go

@@ -577,6 +577,12 @@ func (tx readTx) findIterators(table string, by By, checkType func(By) error) ([
 			return nil, err
 		}
 		return []memdb.ResultIterator{it}, nil
+	case byNamePrefix:
+		it, err := tx.memDBTx.Get(table, indexName+prefix, strings.ToLower(string(v)))
+		if err != nil {
+			return nil, err
+		}
+		return []memdb.ResultIterator{it}, nil
 	case byNode:
 		it, err := tx.memDBTx.Get(table, indexNodeID, string(v))
 		if err != nil {

+ 5 - 1
vendor/src/github.com/docker/swarmkit/manager/state/store/networks.go

@@ -167,7 +167,7 @@ func GetNetwork(tx ReadTx, id string) *api.Network {
 func FindNetworks(tx ReadTx, by By) ([]*api.Network, error) {
 	checkType := func(by By) error {
 		switch by.(type) {
-		case byName, byIDPrefix:
+		case byName, byNamePrefix, byIDPrefix:
 			return nil
 		default:
 			return ErrInvalidFindBy
@@ -219,3 +219,7 @@ func (ni networkIndexerByName) FromObject(obj interface{}) (bool, []byte, error)
 	// Add the null character as a terminator
 	return true, []byte(strings.ToLower(n.Spec.Annotations.Name) + "\x00"), nil
 }
+
+func (ni networkIndexerByName) PrefixFromArgs(args ...interface{}) ([]byte, error) {
+	return prefixFromArgs(args...)
+}

+ 5 - 1
vendor/src/github.com/docker/swarmkit/manager/state/store/nodes.go

@@ -165,7 +165,7 @@ func GetNode(tx ReadTx, id string) *api.Node {
 func FindNodes(tx ReadTx, by By) ([]*api.Node, error) {
 	checkType := func(by By) error {
 		switch by.(type) {
-		case byName, byIDPrefix, byRole, byMembership:
+		case byName, byNamePrefix, byIDPrefix, byRole, byMembership:
 			return nil
 		default:
 			return ErrInvalidFindBy
@@ -221,6 +221,10 @@ func (ni nodeIndexerByHostname) FromObject(obj interface{}) (bool, []byte, error
 	return true, []byte(strings.ToLower(n.Description.Hostname) + "\x00"), nil
 }
 
+func (ni nodeIndexerByHostname) PrefixFromArgs(args ...interface{}) ([]byte, error) {
+	return prefixFromArgs(args...)
+}
+
 type nodeIndexerByRole struct{}
 
 func (ni nodeIndexerByRole) FromArgs(args ...interface{}) ([]byte, error) {

+ 5 - 1
vendor/src/github.com/docker/swarmkit/manager/state/store/services.go

@@ -167,7 +167,7 @@ func GetService(tx ReadTx, id string) *api.Service {
 func FindServices(tx ReadTx, by By) ([]*api.Service, error) {
 	checkType := func(by By) error {
 		switch by.(type) {
-		case byName, byIDPrefix:
+		case byName, byNamePrefix, byIDPrefix:
 			return nil
 		default:
 			return ErrInvalidFindBy
@@ -219,3 +219,7 @@ func (si serviceIndexerByName) FromObject(obj interface{}) (bool, []byte, error)
 	// Add the null character as a terminator
 	return true, []byte(strings.ToLower(s.Spec.Annotations.Name) + "\x00"), nil
 }
+
+func (si serviceIndexerByName) PrefixFromArgs(args ...interface{}) ([]byte, error) {
+	return prefixFromArgs(args...)
+}

+ 5 - 1
vendor/src/github.com/docker/swarmkit/manager/state/store/tasks.go

@@ -175,7 +175,7 @@ func GetTask(tx ReadTx, id string) *api.Task {
 func FindTasks(tx ReadTx, by By) ([]*api.Task, error) {
 	checkType := func(by By) error {
 		switch by.(type) {
-		case byName, byIDPrefix, byDesiredState, byNode, byService, bySlot:
+		case byName, byNamePrefix, byIDPrefix, byDesiredState, byNode, byService, bySlot:
 			return nil
 		default:
 			return ErrInvalidFindBy
@@ -228,6 +228,10 @@ func (ti taskIndexerByName) FromObject(obj interface{}) (bool, []byte, error) {
 	return true, []byte(strings.ToLower(t.ServiceAnnotations.Name) + "\x00"), nil
 }
 
+func (ti taskIndexerByName) PrefixFromArgs(args ...interface{}) ([]byte, error) {
+	return prefixFromArgs(args...)
+}
+
 type taskIndexerByServiceID struct{}
 
 func (ti taskIndexerByServiceID) FromArgs(args ...interface{}) ([]byte, error) {