Explorar el Código

Merge pull request #27995 from vdemeester/vendor-swarmkit-for-templating

Update swarmkit to 4dfc88ccce14ced6f0a6ea82d46dca004c6de0e2
Alexander Morozov hace 8 años
padre
commit
197befe047

+ 1 - 1
hack/vendor.sh

@@ -147,7 +147,7 @@ clone git github.com/docker/containerd 52ef1ceb4b660c42cf4ea9013180a5663968d4c7
 clone git github.com/tonistiigi/fifo 8c56881ce5e63e19e2dfc495c8af0fb90916467d
 clone git github.com/tonistiigi/fifo 8c56881ce5e63e19e2dfc495c8af0fb90916467d
 
 
 # cluster
 # cluster
-clone git github.com/docker/swarmkit 72981f443024da2c57d54b915eae0477be6dada5
+clone git github.com/docker/swarmkit 4dfc88ccce14ced6f0a6ea82d46dca004c6de0e2
 clone git github.com/golang/mock bd3c8e81be01eef76d4b503f5e687d2d1354d2d9
 clone git github.com/golang/mock bd3c8e81be01eef76d4b503f5e687d2d1354d2d9
 clone git github.com/gogo/protobuf v0.3
 clone git github.com/gogo/protobuf v0.3
 clone git github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a
 clone git github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a

+ 1 - 1
vendor/src/github.com/docker/swarmkit/api/gen.go

@@ -1,3 +1,3 @@
 package api
 package api
 
 
-//go:generate protoc -I.:../protobuf:../vendor:../vendor/github.com/gogo/protobuf:../vendor/github.com/gogo/protobuf/protobuf --gogoswarm_out=plugins=grpc+deepcopy+raftproxy+authenticatedwrapper,import_path=github.com/docker/swarmkit/api,Mgogoproto/gogo.proto=github.com/gogo/protobuf/gogoproto,Mtimestamp/timestamp.proto=github.com/docker/swarmkit/api/timestamp,Mduration/duration.proto=github.com/docker/swarmkit/api/duration,Mgoogle/protobuf/descriptor.proto=github.com/gogo/protobuf/protoc-gen-gogo/descriptor,Mplugin/plugin.proto=github.com/docker/swarmkit/protobuf/plugin:. types.proto specs.proto objects.proto control.proto dispatcher.proto ca.proto snapshot.proto raft.proto health.proto resource.proto
+//go:generate protoc -I.:../protobuf:../vendor:../vendor/github.com/gogo/protobuf --gogoswarm_out=plugins=grpc+deepcopy+raftproxy+authenticatedwrapper,import_path=github.com/docker/swarmkit/api,Mgogoproto/gogo.proto=github.com/gogo/protobuf/gogoproto,Mtimestamp/timestamp.proto=github.com/docker/swarmkit/api/timestamp,Mduration/duration.proto=github.com/docker/swarmkit/api/duration,Mgoogle/protobuf/descriptor.proto=github.com/gogo/protobuf/protoc-gen-gogo/descriptor,Mplugin/plugin.proto=github.com/docker/swarmkit/protobuf/plugin:. types.proto specs.proto objects.proto control.proto dispatcher.proto ca.proto snapshot.proto raft.proto health.proto resource.proto

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 718 - 63
vendor/src/github.com/docker/swarmkit/api/types.pb.go


+ 35 - 18
vendor/src/github.com/docker/swarmkit/api/types.proto

@@ -117,6 +117,8 @@ message NodeStatus {
 
 
 	State state = 1;
 	State state = 1;
 	string message = 2;
 	string message = 2;
+	// Addr is the node's IP address as observed by the manager
+	string addr = 3;
 }
 }
 
 
 message Image {
 message Image {
@@ -200,7 +202,7 @@ message Mount {
 		int64 size_bytes = 1;
 		int64 size_bytes = 1;
 
 
 		// Mode of the tmpfs upon creation
 		// Mode of the tmpfs upon creation
-		int32 mode = 2 [(gogoproto.customtype) = "os.FileMode", (gogoproto.nullable) = false];
+		uint32 mode = 2 [(gogoproto.customtype) = "os.FileMode", (gogoproto.nullable) = false];
 
 
 		// TODO(stevvooe): There are several more tmpfs flags, specified in the
 		// TODO(stevvooe): There are several more tmpfs flags, specified in the
 		// daemon, that are accepted. Only the most basic are added for now.
 		// daemon, that are accepted. Only the most basic are added for now.
@@ -781,6 +783,7 @@ message ManagerStatus {
 	RaftMemberStatus.Reachability reachability = 4;
 	RaftMemberStatus.Reachability reachability = 4;
 }
 }
 
 
+
 // SecretReference is the linkage between a service and a secret that it uses.
 // SecretReference is the linkage between a service and a secret that it uses.
 message SecretReference {
 message SecretReference {
 	// SecretID represents the ID of the specific Secret that we're
 	// SecretID represents the ID of the specific Secret that we're
@@ -788,26 +791,29 @@ message SecretReference {
 	// any information about the secret contents.
 	// any information about the secret contents.
 	string secret_id = 1 [(gogoproto.customname) = "SecretID"];
 	string secret_id = 1 [(gogoproto.customname) = "SecretID"];
 
 
-	// Mode specifies how this secret should be exposed to the task.
-	enum Mode {
-		// SYSTEM means that it is not exposed inside to a task at all, but
-		// only available via direct access, usually at the agent-level
-		SYSTEM = 0;
-		// FILE means that it will be exposed to the task as a file
-		FILE = 1;
-		// ENV means that it will be exposed to the task as an environment variable
-		ENV = 2;
-	}
+	// SecretName is the name of the secret that this references, but this is just provided for
+	// lookup/display purposes.  The secret in the reference will be identified by its ID.
+	string secret_name = 2;
 
 
-	// Mode is the way the secret should be presented.
-	Mode mode = 2;
+	// FileTarget represents a specific target that is backed by a file
+	message FileTarget {
+		// Name represents the final filename in the filesystem
+		string name = 1;
 
 
-	// Target is the name by which the image accesses the secret.
-	string target = 3;
+		// UID represents the file UID
+		string uid = 2 [(gogoproto.customname) = "UID"];
 
 
-	// SecretName is the name of the secret that this references, but this is just provided for
-	// lookup/display purposes.  The secret in the reference will be identified by its ID.
-	string secret_name = 4;
+		// GID represents the file GID
+		string gid = 3 [(gogoproto.customname) = "GID"];
+
+		// Mode represents the FileMode of the file
+		uint32 mode = 4 [(gogoproto.customtype) = "os.FileMode", (gogoproto.nullable) = false];
+	}
+
+	// Target specifies how this secret should be exposed to the task.
+	oneof target {
+		FileTarget file = 3;
+	}
 }
 }
 
 
 // BlacklistedCertificate is a record for a blacklisted certificate. It does not
 // BlacklistedCertificate is a record for a blacklisted certificate. It does not
@@ -840,3 +846,14 @@ message HealthConfig {
 	// container as unhealthy. Zero means inherit.
 	// container as unhealthy. Zero means inherit.
 	int32 retries = 4;
 	int32 retries = 4;
 }
 }
+
+message MaybeEncryptedRecord {
+	enum Algorithm {
+		NONE = 0 [(gogoproto.enumvalue_customname) = "NotEncrypted"];
+		SECRETBOX_SALSA20_POLY1305 = 1 [(gogoproto.enumvalue_customname) = "NACLSecretboxSalsa20Poly1305"];
+	}
+
+	Algorithm algorithm = 1;
+	bytes data = 2;
+	bytes nonce = 3;
+}

+ 1 - 0
vendor/src/github.com/docker/swarmkit/ca/certificates.go

@@ -629,6 +629,7 @@ func GetRemoteSignedCertificate(ctx context.Context, csr []byte, token string, r
 	issueRequest := &api.IssueNodeCertificateRequest{CSR: csr, Token: token}
 	issueRequest := &api.IssueNodeCertificateRequest{CSR: csr, Token: token}
 	issueResponse, err := caClient.IssueNodeCertificate(ctx, issueRequest)
 	issueResponse, err := caClient.IssueNodeCertificate(ctx, issueRequest)
 	if err != nil {
 	if err != nil {
+		r.Observe(peer, -remotes.DefaultObservationWeight)
 		return nil, err
 		return nil, err
 	}
 	}
 
 

+ 3 - 3
vendor/src/github.com/docker/swarmkit/ca/external.go

@@ -8,7 +8,7 @@ import (
 	"net/http"
 	"net/http"
 	"sync"
 	"sync"
 
 
-	log "github.com/Sirupsen/logrus"
+	"github.com/Sirupsen/logrus"
 	"github.com/cloudflare/cfssl/api"
 	"github.com/cloudflare/cfssl/api"
 	"github.com/cloudflare/cfssl/signer"
 	"github.com/cloudflare/cfssl/signer"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
@@ -90,7 +90,7 @@ func (eca *ExternalCA) Sign(req signer.SignRequest) (cert []byte, err error) {
 			return eca.rootCA.AppendFirstRootPEM(cert)
 			return eca.rootCA.AppendFirstRootPEM(cert)
 		}
 		}
 
 
-		log.Debugf("unable to proxy certificate signing request to %s: %s", url, err)
+		logrus.Debugf("unable to proxy certificate signing request to %s: %s", url, err)
 	}
 	}
 
 
 	return nil, err
 	return nil, err
@@ -114,7 +114,7 @@ func makeExternalSignRequest(client *http.Client, url string, csrJSON []byte) (c
 
 
 	var apiResponse api.Response
 	var apiResponse api.Response
 	if err := json.Unmarshal(body, &apiResponse); err != nil {
 	if err := json.Unmarshal(body, &apiResponse); err != nil {
-		log.Debugf("unable to JSON-parse CFSSL API response body: %s", string(body))
+		logrus.Debugf("unable to JSON-parse CFSSL API response body: %s", string(body))
 		return nil, recoverableErr{err: errors.Wrap(err, "unable to parse JSON response")}
 		return nil, recoverableErr{err: errors.Wrap(err, "unable to parse JSON response")}
 	}
 	}
 
 

+ 42 - 10
vendor/src/github.com/docker/swarmkit/manager/allocator/networkallocator/portallocator.go

@@ -73,6 +73,17 @@ func newPortSpace(protocol api.PortConfig_Protocol) (*portSpace, error) {
 	}, nil
 	}, nil
 }
 }
 
 
+// getPortConfigkey returns a map key for doing set operations with
+// ports. The key consists of name, protocol and target port which
+// uniquely identifies a port within a single Endpoint.
+func getPortConfigKey(p *api.PortConfig) api.PortConfig {
+	return api.PortConfig{
+		Name:       p.Name,
+		Protocol:   p.Protocol,
+		TargetPort: p.TargetPort,
+	}
+}
+
 func reconcilePortConfigs(s *api.Service) []*api.PortConfig {
 func reconcilePortConfigs(s *api.Service) []*api.PortConfig {
 	// If runtime state hasn't been created or if port config has
 	// If runtime state hasn't been created or if port config has
 	// changed from port state return the port config from Spec.
 	// changed from port state return the port config from Spec.
@@ -80,15 +91,31 @@ func reconcilePortConfigs(s *api.Service) []*api.PortConfig {
 		return s.Spec.Endpoint.Ports
 		return s.Spec.Endpoint.Ports
 	}
 	}
 
 
+	allocatedPorts := make(map[api.PortConfig]*api.PortConfig)
+	for _, portState := range s.Endpoint.Ports {
+		if portState.PublishMode != api.PublishModeIngress {
+			continue
+		}
+
+		allocatedPorts[getPortConfigKey(portState)] = portState
+	}
+
 	var portConfigs []*api.PortConfig
 	var portConfigs []*api.PortConfig
-	for i, portConfig := range s.Spec.Endpoint.Ports {
-		portState := s.Endpoint.Ports[i]
+	for _, portConfig := range s.Spec.Endpoint.Ports {
+		// If the PublishMode is not Ingress simply pick up
+		// the port config.
+		if portConfig.PublishMode != api.PublishModeIngress {
+			portConfigs = append(portConfigs, portConfig)
+			continue
+		}
+
+		portState, ok := allocatedPorts[getPortConfigKey(portConfig)]
 
 
 		// If the portConfig is exactly the same as portState
 		// If the portConfig is exactly the same as portState
 		// except if SwarmPort is not user-define then prefer
 		// except if SwarmPort is not user-define then prefer
 		// portState to ensure sticky allocation of the same
 		// portState to ensure sticky allocation of the same
 		// port that was allocated before.
 		// port that was allocated before.
-		if portConfig.Name == portState.Name &&
+		if ok && portConfig.Name == portState.Name &&
 			portConfig.TargetPort == portState.TargetPort &&
 			portConfig.TargetPort == portState.TargetPort &&
 			portConfig.Protocol == portState.Protocol &&
 			portConfig.Protocol == portState.Protocol &&
 			portConfig.PublishedPort == 0 {
 			portConfig.PublishedPort == 0 {
@@ -186,21 +213,26 @@ func (pa *portAllocator) isPortsAllocated(s *api.Service) bool {
 		return false
 		return false
 	}
 	}
 
 
-	for i, portConfig := range s.Spec.Endpoint.Ports {
+	allocatedPorts := make(map[api.PortConfig]*api.PortConfig)
+	for _, portState := range s.Endpoint.Ports {
+		if portState.PublishMode != api.PublishModeIngress {
+			continue
+		}
+
+		allocatedPorts[getPortConfigKey(portState)] = portState
+	}
+
+	for _, portConfig := range s.Spec.Endpoint.Ports {
 		// Ignore ports which are not PublishModeIngress
 		// Ignore ports which are not PublishModeIngress
 		if portConfig.PublishMode != api.PublishModeIngress {
 		if portConfig.PublishMode != api.PublishModeIngress {
 			continue
 			continue
 		}
 		}
 
 
-		// The port configuration slice and port state slice
-		// are expected to be in the same order.
-		portState := s.Endpoint.Ports[i]
+		portState, ok := allocatedPorts[getPortConfigKey(portConfig)]
 
 
 		// If name, port, protocol values don't match then we
 		// If name, port, protocol values don't match then we
 		// are not allocated.
 		// are not allocated.
-		if portConfig.Name != portState.Name ||
-			portConfig.TargetPort != portState.TargetPort ||
-			portConfig.Protocol != portState.Protocol {
+		if !ok {
 			return false
 			return false
 		}
 		}
 
 

+ 18 - 0
vendor/src/github.com/docker/swarmkit/manager/controlapi/secret.go

@@ -3,9 +3,11 @@ package controlapi
 import (
 import (
 	"regexp"
 	"regexp"
 
 
+	"github.com/Sirupsen/logrus"
 	"github.com/docker/distribution/digest"
 	"github.com/docker/distribution/digest"
 	"github.com/docker/swarmkit/api"
 	"github.com/docker/swarmkit/api"
 	"github.com/docker/swarmkit/identity"
 	"github.com/docker/swarmkit/identity"
+	"github.com/docker/swarmkit/log"
 	"github.com/docker/swarmkit/manager/state/store"
 	"github.com/docker/swarmkit/manager/state/store"
 	"golang.org/x/net/context"
 	"golang.org/x/net/context"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc"
@@ -85,6 +87,12 @@ func (s *Server) UpdateSecret(ctx context.Context, request *api.UpdateSecretRequ
 		return nil, grpc.Errorf(codes.NotFound, "secret %s not found", request.SecretID)
 		return nil, grpc.Errorf(codes.NotFound, "secret %s not found", request.SecretID)
 	}
 	}
 
 
+	log.G(ctx).WithFields(logrus.Fields{
+		"secret.ID":   request.SecretID,
+		"secret.Name": request.Spec.Annotations.Name,
+		"method":      "UpdateSecret",
+	}).Debugf("secret updated")
+
 	// WARN: we should never return the actual secret data here. We need to redact the private fields first.
 	// WARN: we should never return the actual secret data here. We need to redact the private fields first.
 	secret.Spec.Data = nil
 	secret.Spec.Data = nil
 	return &api.UpdateSecretResponse{
 	return &api.UpdateSecretResponse{
@@ -169,6 +177,11 @@ func (s *Server) CreateSecret(ctx context.Context, request *api.CreateSecretRequ
 		return nil, grpc.Errorf(codes.AlreadyExists, "secret %s already exists", request.Spec.Annotations.Name)
 		return nil, grpc.Errorf(codes.AlreadyExists, "secret %s already exists", request.Spec.Annotations.Name)
 	case nil:
 	case nil:
 		secret.Spec.Data = nil // clean the actual secret data so it's never returned
 		secret.Spec.Data = nil // clean the actual secret data so it's never returned
+		log.G(ctx).WithFields(logrus.Fields{
+			"secret.Name": request.Spec.Annotations.Name,
+			"method":      "CreateSecret",
+		}).Debugf("secret created")
+
 		return &api.CreateSecretResponse{Secret: secret}, nil
 		return &api.CreateSecretResponse{Secret: secret}, nil
 	default:
 	default:
 		return nil, err
 		return nil, err
@@ -191,6 +204,11 @@ func (s *Server) RemoveSecret(ctx context.Context, request *api.RemoveSecretRequ
 	case store.ErrNotExist:
 	case store.ErrNotExist:
 		return nil, grpc.Errorf(codes.NotFound, "secret %s not found", request.SecretID)
 		return nil, grpc.Errorf(codes.NotFound, "secret %s not found", request.SecretID)
 	case nil:
 	case nil:
+		log.G(ctx).WithFields(logrus.Fields{
+			"secret.ID": request.SecretID,
+			"method":    "RemoveSecret",
+		}).Debugf("secret removed")
+
 		return &api.RemoveSecretResponse{}, nil
 		return &api.RemoveSecretResponse{}, nil
 	default:
 	default:
 		return nil, err
 		return nil, err

+ 30 - 7
vendor/src/github.com/docker/swarmkit/manager/controlapi/service.go

@@ -2,6 +2,7 @@ package controlapi
 
 
 import (
 import (
 	"errors"
 	"errors"
+	"path/filepath"
 	"reflect"
 	"reflect"
 	"regexp"
 	"regexp"
 	"strconv"
 	"strconv"
@@ -304,20 +305,42 @@ func (s *Server) checkPortConflicts(spec *api.ServiceSpec, serviceID string) err
 	return nil
 	return nil
 }
 }
 
 
-// checkSecretConflicts finds if the passed in spec has secrets with conflicting targets.
-func (s *Server) checkSecretConflicts(spec *api.ServiceSpec) error {
+// checkSecretValidity finds if the secrets passed in spec have any conflicting targets.
+func (s *Server) checkSecretValidity(spec *api.ServiceSpec) error {
 	container := spec.Task.GetContainer()
 	container := spec.Task.GetContainer()
 	if container == nil {
 	if container == nil {
 		return nil
 		return nil
 	}
 	}
 
 
+	// Keep a map to track all the targets that will be exposed
+	// The string returned is only used for logging. It could as well be struct{}{}
 	existingTargets := make(map[string]string)
 	existingTargets := make(map[string]string)
 	for _, secretRef := range container.Secrets {
 	for _, secretRef := range container.Secrets {
-		if prevSecretName, ok := existingTargets[secretRef.Target]; ok {
-			return grpc.Errorf(codes.InvalidArgument, "secret references '%s' and '%s' have a conflicting target: '%s'", prevSecretName, secretRef.SecretName, secretRef.Target)
+		// SecretID and SecretName are mandatory, we have invalid references without them
+		if secretRef.SecretID == "" || secretRef.SecretName == "" {
+			return grpc.Errorf(codes.InvalidArgument, "malformed secret reference")
 		}
 		}
 
 
-		existingTargets[secretRef.Target] = secretRef.SecretName
+		// Every secret referece requires a Target
+		if secretRef.GetTarget() == nil {
+			return grpc.Errorf(codes.InvalidArgument, "malformed secret reference, no target provided")
+		}
+
+		// If this is a file target, we will ensure filename uniqueness
+		if secretRef.GetFile() != nil {
+			fileName := secretRef.GetFile().Name
+			// Validate the file name
+			if fileName == "" || fileName != filepath.Base(filepath.Clean(fileName)) {
+				return grpc.Errorf(codes.InvalidArgument, "malformed file secret reference, invalid target file name provided")
+			}
+
+			// If this target is already in use, we have conflicting targets
+			if prevSecretName, ok := existingTargets[fileName]; ok {
+				return grpc.Errorf(codes.InvalidArgument, "secret references '%s' and '%s' have a conflicting target: '%s'", prevSecretName, secretRef.SecretName, fileName)
+			}
+
+			existingTargets[fileName] = secretRef.SecretName
+		}
 	}
 	}
 
 
 	return nil
 	return nil
@@ -341,7 +364,7 @@ func (s *Server) CreateService(ctx context.Context, request *api.CreateServiceRe
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	if err := s.checkSecretConflicts(request.Spec); err != nil {
+	if err := s.checkSecretValidity(request.Spec); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
@@ -412,7 +435,7 @@ func (s *Server) UpdateService(ctx context.Context, request *api.UpdateServiceRe
 		}
 		}
 	}
 	}
 
 
-	if err := s.checkSecretConflicts(request.Spec); err != nil {
+	if err := s.checkSecretValidity(request.Spec); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 
 

+ 87 - 30
vendor/src/github.com/docker/swarmkit/manager/dispatcher/dispatcher.go

@@ -2,6 +2,7 @@ package dispatcher
 
 
 import (
 import (
 	"fmt"
 	"fmt"
+	"net"
 	"strconv"
 	"strconv"
 	"sync"
 	"sync"
 	"time"
 	"time"
@@ -313,17 +314,16 @@ func (d *Dispatcher) markNodesUnknown(ctx context.Context) error {
 				if node.Status.State == api.NodeStatus_DOWN {
 				if node.Status.State == api.NodeStatus_DOWN {
 					return nil
 					return nil
 				}
 				}
-				node.Status = api.NodeStatus{
-					State:   api.NodeStatus_UNKNOWN,
-					Message: `Node moved to "unknown" state due to leadership change in cluster`,
-				}
+
+				node.Status.State = api.NodeStatus_UNKNOWN
+				node.Status.Message = `Node moved to "unknown" state due to leadership change in cluster`
+
 				nodeID := node.ID
 				nodeID := node.ID
 
 
 				expireFunc := func() {
 				expireFunc := func() {
 					log := log.WithField("node", nodeID)
 					log := log.WithField("node", nodeID)
-					nodeStatus := api.NodeStatus{State: api.NodeStatus_DOWN, Message: `heartbeat failure for node in "unknown" state`}
 					log.Debugf("heartbeat expiration for unknown node")
 					log.Debugf("heartbeat expiration for unknown node")
-					if err := d.nodeRemove(nodeID, nodeStatus); err != nil {
+					if err := d.markNodeNotReady(nodeID, api.NodeStatus_DOWN, `heartbeat failure for node in "unknown" state`); err != nil {
 						log.WithError(err).Errorf(`failed deregistering node after heartbeat expiration for node in "unknown" state`)
 						log.WithError(err).Errorf(`failed deregistering node after heartbeat expiration for node in "unknown" state`)
 					}
 					}
 				}
 				}
@@ -356,12 +356,18 @@ func (d *Dispatcher) isRunning() bool {
 	return true
 	return true
 }
 }
 
 
-// updateNode updates the description of a node and sets status to READY
+// markNodeReady updates the description of a node, updates its address, and sets status to READY
 // this is used during registration when a new node description is provided
 // this is used during registration when a new node description is provided
 // and during node updates when the node description changes
 // and during node updates when the node description changes
-func (d *Dispatcher) updateNode(nodeID string, description *api.NodeDescription) error {
+func (d *Dispatcher) markNodeReady(nodeID string, description *api.NodeDescription, addr string) error {
 	d.nodeUpdatesLock.Lock()
 	d.nodeUpdatesLock.Lock()
-	d.nodeUpdates[nodeID] = nodeUpdate{status: &api.NodeStatus{State: api.NodeStatus_READY}, description: description}
+	d.nodeUpdates[nodeID] = nodeUpdate{
+		status: &api.NodeStatus{
+			State: api.NodeStatus_READY,
+			Addr:  addr,
+		},
+		description: description,
+	}
 	numUpdates := len(d.nodeUpdates)
 	numUpdates := len(d.nodeUpdates)
 	d.nodeUpdatesLock.Unlock()
 	d.nodeUpdatesLock.Unlock()
 
 
@@ -387,6 +393,19 @@ func (d *Dispatcher) updateNode(nodeID string, description *api.NodeDescription)
 	return nil
 	return nil
 }
 }
 
 
+// gets the node IP from the context of a grpc call
+func nodeIPFromContext(ctx context.Context) (string, error) {
+	nodeInfo, err := ca.RemoteNode(ctx)
+	if err != nil {
+		return "", err
+	}
+	addr, _, err := net.SplitHostPort(nodeInfo.RemoteAddr)
+	if err != nil {
+		return "", errors.Wrap(err, "unable to get ip from addr:port")
+	}
+	return addr, nil
+}
+
 // register is used for registration of node with particular dispatcher.
 // register is used for registration of node with particular dispatcher.
 func (d *Dispatcher) register(ctx context.Context, nodeID string, description *api.NodeDescription) (string, error) {
 func (d *Dispatcher) register(ctx context.Context, nodeID string, description *api.NodeDescription) (string, error) {
 	// prevent register until we're ready to accept it
 	// prevent register until we're ready to accept it
@@ -407,14 +426,18 @@ func (d *Dispatcher) register(ctx context.Context, nodeID string, description *a
 		return "", ErrNodeNotFound
 		return "", ErrNodeNotFound
 	}
 	}
 
 
-	if err := d.updateNode(nodeID, description); err != nil {
+	addr, err := nodeIPFromContext(ctx)
+	if err != nil {
+		log.G(ctx).Debugf(err.Error())
+	}
+
+	if err := d.markNodeReady(nodeID, description, addr); err != nil {
 		return "", err
 		return "", err
 	}
 	}
 
 
 	expireFunc := func() {
 	expireFunc := func() {
-		nodeStatus := api.NodeStatus{State: api.NodeStatus_DOWN, Message: "heartbeat failure"}
 		log.G(ctx).Debugf("heartbeat expiration")
 		log.G(ctx).Debugf("heartbeat expiration")
-		if err := d.nodeRemove(nodeID, nodeStatus); err != nil {
+		if err := d.markNodeNotReady(nodeID, api.NodeStatus_DOWN, "heartbeat failure"); err != nil {
 			log.G(ctx).WithError(err).Errorf("failed deregistering node after heartbeat expiration")
 			log.G(ctx).WithError(err).Errorf("failed deregistering node after heartbeat expiration")
 		}
 		}
 	}
 	}
@@ -575,7 +598,11 @@ func (d *Dispatcher) processUpdates() {
 				}
 				}
 
 
 				if nodeUpdate.status != nil {
 				if nodeUpdate.status != nil {
-					node.Status = *nodeUpdate.status
+					node.Status.State = nodeUpdate.status.State
+					node.Status.Message = nodeUpdate.status.Message
+					if nodeUpdate.status.Addr != "" {
+						node.Status.Addr = nodeUpdate.status.Addr
+					}
 				}
 				}
 				if nodeUpdate.description != nil {
 				if nodeUpdate.description != nil {
 					node.Description = nodeUpdate.description
 					node.Description = nodeUpdate.description
@@ -782,13 +809,18 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche
 		}
 		}
 		var newSecrets []*api.Secret
 		var newSecrets []*api.Secret
 		for _, secretRef := range container.Secrets {
 		for _, secretRef := range container.Secrets {
+			// Empty ID prefix will return all secrets. Bail if there is no SecretID
+			if secretRef.SecretID == "" {
+				log.Debugf("invalid secret reference")
+				continue
+			}
 			secretID := secretRef.SecretID
 			secretID := secretRef.SecretID
 			log := log.WithFields(logrus.Fields{
 			log := log.WithFields(logrus.Fields{
 				"secret.id":   secretID,
 				"secret.id":   secretID,
 				"secret.name": secretRef.SecretName,
 				"secret.name": secretRef.SecretName,
 			})
 			})
 
 
-			if tasksUsingSecret[secretID] == nil {
+			if len(tasksUsingSecret[secretID]) == 0 {
 				tasksUsingSecret[secretID] = make(map[string]struct{})
 				tasksUsingSecret[secretID] = make(map[string]struct{})
 
 
 				secrets, err := store.FindSecrets(readTx, store.ByIDPrefix(secretID))
 				secrets, err := store.FindSecrets(readTx, store.ByIDPrefix(secretID))
@@ -1046,18 +1078,24 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche
 				}
 				}
 			}
 			}
 			for id, secret := range updateSecrets {
 			for id, secret := range updateSecrets {
-				if _, ok := removeSecrets[id]; !ok {
-					secretChange := &api.AssignmentChange{
-						Assignment: &api.Assignment{
-							Item: &api.Assignment_Secret{
-								Secret: secret,
-							},
+				// If, due to multiple updates, this secret is no longer in use,
+				// don't send it down.
+				if len(tasksUsingSecret[id]) == 0 {
+					// delete this secret for the secrets to be updated
+					// so that deleteSecrets knows the current list
+					delete(updateSecrets, id)
+					continue
+				}
+				secretChange := &api.AssignmentChange{
+					Assignment: &api.Assignment{
+						Item: &api.Assignment_Secret{
+							Secret: secret,
 						},
 						},
-						Action: api.AssignmentChange_AssignmentActionUpdate,
-					}
-
-					update.Changes = append(update.Changes, secretChange)
+					},
+					Action: api.AssignmentChange_AssignmentActionUpdate,
 				}
 				}
+
+				update.Changes = append(update.Changes, secretChange)
 			}
 			}
 			for id := range removeTasks {
 			for id := range removeTasks {
 				taskChange := &api.AssignmentChange{
 				taskChange := &api.AssignmentChange{
@@ -1072,6 +1110,12 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche
 				update.Changes = append(update.Changes, taskChange)
 				update.Changes = append(update.Changes, taskChange)
 			}
 			}
 			for id := range removeSecrets {
 			for id := range removeSecrets {
+				// If this secret is also being sent on the updated set
+				// don't also add it to the removed set
+				if _, ok := updateSecrets[id]; ok {
+					continue
+				}
+
 				secretChange := &api.AssignmentChange{
 				secretChange := &api.AssignmentChange{
 					Assignment: &api.Assignment{
 					Assignment: &api.Assignment{
 						Item: &api.Assignment_Secret{
 						Item: &api.Assignment_Secret{
@@ -1091,13 +1135,22 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche
 	}
 	}
 }
 }
 
 
-func (d *Dispatcher) nodeRemove(id string, status api.NodeStatus) error {
+// markNodeNotReady sets the node state to some state other than READY
+func (d *Dispatcher) markNodeNotReady(id string, state api.NodeStatus_State, message string) error {
 	if err := d.isRunningLocked(); err != nil {
 	if err := d.isRunningLocked(); err != nil {
 		return err
 		return err
 	}
 	}
 
 
+	status := &api.NodeStatus{
+		State:   state,
+		Message: message,
+	}
+
 	d.nodeUpdatesLock.Lock()
 	d.nodeUpdatesLock.Lock()
-	d.nodeUpdates[id] = nodeUpdate{status: status.Copy(), description: d.nodeUpdates[id].description}
+	// pluck the description out of nodeUpdates. this protects against a case
+	// where a node is marked ready and a description is added, but then the
+	// node is immediately marked not ready. this preserves that description
+	d.nodeUpdates[id] = nodeUpdate{status: status, description: d.nodeUpdates[id].description}
 	numUpdates := len(d.nodeUpdates)
 	numUpdates := len(d.nodeUpdates)
 	d.nodeUpdatesLock.Unlock()
 	d.nodeUpdatesLock.Unlock()
 
 
@@ -1159,14 +1212,19 @@ func (d *Dispatcher) Session(r *api.SessionRequest, stream api.Dispatcher_Sessio
 	var sessionID string
 	var sessionID string
 	if _, err := d.nodes.GetWithSession(nodeID, r.SessionID); err != nil {
 	if _, err := d.nodes.GetWithSession(nodeID, r.SessionID); err != nil {
 		// register the node.
 		// register the node.
-		sessionID, err = d.register(stream.Context(), nodeID, r.Description)
+		sessionID, err = d.register(ctx, nodeID, r.Description)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
 	} else {
 	} else {
 		sessionID = r.SessionID
 		sessionID = r.SessionID
+		// get the node IP addr
+		addr, err := nodeIPFromContext(stream.Context())
+		if err != nil {
+			log.G(ctx).Debugf(err.Error())
+		}
 		// update the node description
 		// update the node description
-		if err := d.updateNode(nodeID, r.Description); err != nil {
+		if err := d.markNodeReady(nodeID, r.Description, addr); err != nil {
 			return err
 			return err
 		}
 		}
 	}
 	}
@@ -1226,8 +1284,7 @@ func (d *Dispatcher) Session(r *api.SessionRequest, stream api.Dispatcher_Sessio
 			}
 			}
 		}
 		}
 
 
-		nodeStatus := api.NodeStatus{State: api.NodeStatus_DISCONNECTED, Message: "node is currently trying to find new manager"}
-		if err := d.nodeRemove(nodeID, nodeStatus); err != nil {
+		if err := d.markNodeNotReady(nodeID, api.NodeStatus_DISCONNECTED, "node is currently trying to find new manager"); err != nil {
 			log.WithError(err).Error("failed to remove node")
 			log.WithError(err).Error("failed to remove node")
 		}
 		}
 		// still return an abort if the transport closure was ineffective.
 		// still return an abort if the transport closure was ineffective.

+ 88 - 112
vendor/src/github.com/docker/swarmkit/manager/manager.go

@@ -7,6 +7,7 @@ import (
 	"net"
 	"net"
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
+	"runtime"
 	"sync"
 	"sync"
 	"syscall"
 	"syscall"
 	"time"
 	"time"
@@ -30,6 +31,7 @@ import (
 	"github.com/docker/swarmkit/manager/state/raft"
 	"github.com/docker/swarmkit/manager/state/raft"
 	"github.com/docker/swarmkit/manager/state/store"
 	"github.com/docker/swarmkit/manager/state/store"
 	"github.com/docker/swarmkit/protobuf/ptypes"
 	"github.com/docker/swarmkit/protobuf/ptypes"
+	"github.com/docker/swarmkit/xnet"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
 	"golang.org/x/net/context"
 	"golang.org/x/net/context"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc"
@@ -40,6 +42,16 @@ const (
 	defaultTaskHistoryRetentionLimit = 5
 	defaultTaskHistoryRetentionLimit = 5
 )
 )
 
 
+// RemoteAddrs provides an listening address and an optional advertise address
+// for serving the remote API.
+type RemoteAddrs struct {
+	// Address to bind
+	ListenAddr string
+
+	// Address to advertise to remote nodes (optional).
+	AdvertiseAddr string
+}
+
 // Config is used to tune the Manager.
 // Config is used to tune the Manager.
 type Config struct {
 type Config struct {
 	SecurityConfig *ca.SecurityConfig
 	SecurityConfig *ca.SecurityConfig
@@ -48,13 +60,12 @@ type Config struct {
 	// will make certificate signing requests for node certificates.
 	// will make certificate signing requests for node certificates.
 	ExternalCAs []*api.ExternalCA
 	ExternalCAs []*api.ExternalCA
 
 
-	ProtoAddr map[string]string
-	// ProtoListener will be used for grpc serving if it's not nil,
-	// ProtoAddr fields will be used to create listeners otherwise.
-	ProtoListener map[string]net.Listener
+	// ControlAPI is an address for serving the control API.
+	ControlAPI string
 
 
-	// AdvertiseAddr is a map of addresses to advertise, by protocol.
-	AdvertiseAddr string
+	// RemoteAPI is a listening address for serving the remote API, and
+	// an optional advertise address.
+	RemoteAPI RemoteAddrs
 
 
 	// JoinRaft is an optional address of a node in an existing raft
 	// JoinRaft is an optional address of a node in an existing raft
 	// cluster to join.
 	// cluster to join.
@@ -81,7 +92,7 @@ type Config struct {
 // subsystems.
 // subsystems.
 type Manager struct {
 type Manager struct {
 	config    *Config
 	config    *Config
-	listeners map[string]net.Listener
+	listeners []net.Listener
 
 
 	caserver               *ca.Server
 	caserver               *ca.Server
 	dispatcher             *dispatcher.Dispatcher
 	dispatcher             *dispatcher.Dispatcher
@@ -96,10 +107,11 @@ type Manager struct {
 	localserver            *grpc.Server
 	localserver            *grpc.Server
 	raftNode               *raft.Node
 	raftNode               *raft.Node
 
 
-	mu sync.Mutex
+	cancelFunc context.CancelFunc
 
 
+	mu      sync.Mutex
 	started chan struct{}
 	started chan struct{}
-	stopped chan struct{}
+	stopped bool
 }
 }
 
 
 type closeOnceListener struct {
 type closeOnceListener struct {
@@ -119,41 +131,28 @@ func (l *closeOnceListener) Close() error {
 func New(config *Config) (*Manager, error) {
 func New(config *Config) (*Manager, error) {
 	dispatcherConfig := dispatcher.DefaultConfig()
 	dispatcherConfig := dispatcher.DefaultConfig()
 
 
-	if config.ProtoAddr == nil {
-		config.ProtoAddr = make(map[string]string)
-	}
-
-	if config.ProtoListener != nil && config.ProtoListener["tcp"] != nil {
-		config.ProtoAddr["tcp"] = config.ProtoListener["tcp"].Addr().String()
-	}
-
 	// If an AdvertiseAddr was specified, we use that as our
 	// If an AdvertiseAddr was specified, we use that as our
 	// externally-reachable address.
 	// externally-reachable address.
-	tcpAddr := config.AdvertiseAddr
+	advertiseAddr := config.RemoteAPI.AdvertiseAddr
 
 
-	var tcpAddrPort string
-	if tcpAddr == "" {
+	var advertiseAddrPort string
+	if advertiseAddr == "" {
 		// Otherwise, we know we are joining an existing swarm. Use a
 		// Otherwise, we know we are joining an existing swarm. Use a
 		// wildcard address to trigger remote autodetection of our
 		// wildcard address to trigger remote autodetection of our
 		// address.
 		// address.
 		var err error
 		var err error
-		_, tcpAddrPort, err = net.SplitHostPort(config.ProtoAddr["tcp"])
+		_, advertiseAddrPort, err = net.SplitHostPort(config.RemoteAPI.ListenAddr)
 		if err != nil {
 		if err != nil {
-			return nil, fmt.Errorf("missing or invalid listen address %s", config.ProtoAddr["tcp"])
+			return nil, fmt.Errorf("missing or invalid listen address %s", config.RemoteAPI.ListenAddr)
 		}
 		}
 
 
 		// Even with an IPv6 listening address, it's okay to use
 		// Even with an IPv6 listening address, it's okay to use
 		// 0.0.0.0 here. Any "unspecified" (wildcard) IP will
 		// 0.0.0.0 here. Any "unspecified" (wildcard) IP will
 		// be substituted with the actual source address.
 		// be substituted with the actual source address.
-		tcpAddr = net.JoinHostPort("0.0.0.0", tcpAddrPort)
-	}
-
-	err := os.MkdirAll(filepath.Dir(config.ProtoAddr["unix"]), 0700)
-	if err != nil {
-		return nil, errors.Wrap(err, "failed to create socket directory")
+		advertiseAddr = net.JoinHostPort("0.0.0.0", advertiseAddrPort)
 	}
 	}
 
 
-	err = os.MkdirAll(config.StateDir, 0700)
+	err := os.MkdirAll(config.StateDir, 0700)
 	if err != nil {
 	if err != nil {
 		return nil, errors.Wrap(err, "failed to create state directory")
 		return nil, errors.Wrap(err, "failed to create state directory")
 	}
 	}
@@ -164,41 +163,49 @@ func New(config *Config) (*Manager, error) {
 		return nil, errors.Wrap(err, "failed to create raft state directory")
 		return nil, errors.Wrap(err, "failed to create raft state directory")
 	}
 	}
 
 
-	var listeners map[string]net.Listener
-	if len(config.ProtoListener) > 0 {
-		listeners = config.ProtoListener
-	} else {
-		listeners = make(map[string]net.Listener)
+	var listeners []net.Listener
 
 
-		for proto, addr := range config.ProtoAddr {
-			l, err := net.Listen(proto, addr)
+	// don't create a socket directory if we're on windows. we used named pipe
+	if runtime.GOOS != "windows" {
+		err := os.MkdirAll(filepath.Dir(config.ControlAPI), 0700)
+		if err != nil {
+			return nil, errors.Wrap(err, "failed to create socket directory")
+		}
+	}
 
 
-			// A unix socket may fail to bind if the file already
-			// exists. Try replacing the file.
-			unwrappedErr := err
-			if op, ok := unwrappedErr.(*net.OpError); ok {
-				unwrappedErr = op.Err
-			}
-			if sys, ok := unwrappedErr.(*os.SyscallError); ok {
-				unwrappedErr = sys.Err
-			}
-			if proto == "unix" && unwrappedErr == syscall.EADDRINUSE {
-				os.Remove(addr)
-				l, err = net.Listen(proto, addr)
-				if err != nil {
-					return nil, err
-				}
-			} else if err != nil {
-				return nil, err
-			}
-			if proto == "tcp" && tcpAddrPort == "0" {
-				// in case of 0 port
-				tcpAddr = l.Addr().String()
-			}
-			listeners[proto] = l
+	l, err := xnet.ListenLocal(config.ControlAPI)
+
+	// A unix socket may fail to bind if the file already
+	// exists. Try replacing the file.
+	if runtime.GOOS != "windows" {
+		unwrappedErr := err
+		if op, ok := unwrappedErr.(*net.OpError); ok {
+			unwrappedErr = op.Err
+		}
+		if sys, ok := unwrappedErr.(*os.SyscallError); ok {
+			unwrappedErr = sys.Err
 		}
 		}
+		if unwrappedErr == syscall.EADDRINUSE {
+			os.Remove(config.ControlAPI)
+			l, err = xnet.ListenLocal(config.ControlAPI)
+		}
+	}
+	if err != nil {
+		return nil, errors.Wrap(err, "failed to listen on control API address")
 	}
 	}
 
 
+	listeners = append(listeners, l)
+
+	l, err = net.Listen("tcp", config.RemoteAPI.ListenAddr)
+	if err != nil {
+		return nil, errors.Wrap(err, "failed to listen on remote API address")
+	}
+	if advertiseAddrPort == "0" {
+		advertiseAddr = l.Addr().String()
+		config.RemoteAPI.ListenAddr = advertiseAddr
+	}
+	listeners = append(listeners, l)
+
 	raftCfg := raft.DefaultNodeConfig()
 	raftCfg := raft.DefaultNodeConfig()
 
 
 	if config.ElectionTick > 0 {
 	if config.ElectionTick > 0 {
@@ -210,7 +217,7 @@ func New(config *Config) (*Manager, error) {
 
 
 	newNodeOpts := raft.NodeOptions{
 	newNodeOpts := raft.NodeOptions{
 		ID:              config.SecurityConfig.ClientTLSCreds.NodeID(),
 		ID:              config.SecurityConfig.ClientTLSCreds.NodeID(),
-		Addr:            tcpAddr,
+		Addr:            advertiseAddr,
 		JoinAddr:        config.JoinRaft,
 		JoinAddr:        config.JoinRaft,
 		Config:          raftCfg,
 		Config:          raftCfg,
 		StateDir:        raftStateDir,
 		StateDir:        raftStateDir,
@@ -231,18 +238,14 @@ func New(config *Config) (*Manager, error) {
 		localserver: grpc.NewServer(opts...),
 		localserver: grpc.NewServer(opts...),
 		raftNode:    raftNode,
 		raftNode:    raftNode,
 		started:     make(chan struct{}),
 		started:     make(chan struct{}),
-		stopped:     make(chan struct{}),
 	}
 	}
 
 
 	return m, nil
 	return m, nil
 }
 }
 
 
 // Addr returns tcp address on which remote api listens.
 // Addr returns tcp address on which remote api listens.
-func (m *Manager) Addr() net.Addr {
-	if l, ok := m.listeners["tcp"]; ok {
-		return l.Addr()
-	}
-	return nil
+func (m *Manager) Addr() string {
+	return m.config.RemoteAPI.ListenAddr
 }
 }
 
 
 // Run starts all manager sub-systems and the gRPC server at the configured
 // Run starts all manager sub-systems and the gRPC server at the configured
@@ -252,14 +255,7 @@ func (m *Manager) Run(parent context.Context) error {
 	ctx, ctxCancel := context.WithCancel(parent)
 	ctx, ctxCancel := context.WithCancel(parent)
 	defer ctxCancel()
 	defer ctxCancel()
 
 
-	// Harakiri.
-	go func() {
-		select {
-		case <-ctx.Done():
-		case <-m.stopped:
-			ctxCancel()
-		}
-	}()
+	m.cancelFunc = ctxCancel
 
 
 	leadershipCh, cancel := m.raftNode.SubscribeLeadership()
 	leadershipCh, cancel := m.raftNode.SubscribeLeadership()
 	defer cancel()
 	defer cancel()
@@ -336,8 +332,8 @@ func (m *Manager) Run(parent context.Context) error {
 	localHealthServer.SetServingStatus("ControlAPI", api.HealthCheckResponse_NOT_SERVING)
 	localHealthServer.SetServingStatus("ControlAPI", api.HealthCheckResponse_NOT_SERVING)
 
 
 	errServe := make(chan error, len(m.listeners))
 	errServe := make(chan error, len(m.listeners))
-	for proto, l := range m.listeners {
-		go m.serveListener(ctx, errServe, proto, l)
+	for _, lis := range m.listeners {
+		go m.serveListener(ctx, errServe, lis)
 	}
 	}
 
 
 	defer func() {
 	defer func() {
@@ -383,24 +379,14 @@ func (m *Manager) Run(parent context.Context) error {
 
 
 	// wait for an error in serving.
 	// wait for an error in serving.
 	err = <-errServe
 	err = <-errServe
-	select {
-	// check to see if stopped was posted to. if so, we're in the process of
-	// stopping, or done and that's why we got the error. if stopping is
-	// deliberate, stopped will ALWAYS be closed before the error is trigger,
-	// so this path will ALWAYS be taken if the stop was deliberate
-	case <-m.stopped:
-		// shutdown was requested, do not return an error
-		// but first, we wait to acquire a mutex to guarantee that stopping is
-		// finished. as long as we acquire the mutex BEFORE we return, we know
-		// that stopping is stopped.
-		m.mu.Lock()
+	m.mu.Lock()
+	if m.stopped {
 		m.mu.Unlock()
 		m.mu.Unlock()
 		return nil
 		return nil
-	// otherwise, we'll get something from errServe, which indicates that an
-	// error in serving has actually occurred and this isn't a planned shutdown
-	default:
-		return err
 	}
 	}
+	m.mu.Unlock()
+	m.Stop(ctx)
+	return err
 }
 }
 
 
 const stopTimeout = 8 * time.Second
 const stopTimeout = 8 * time.Second
@@ -417,13 +403,10 @@ func (m *Manager) Stop(ctx context.Context) {
 	// from returning before we've finished stopping.
 	// from returning before we've finished stopping.
 	m.mu.Lock()
 	m.mu.Lock()
 	defer m.mu.Unlock()
 	defer m.mu.Unlock()
-	select {
-	// check to see that we've already stopped
-	case <-m.stopped:
+	if m.stopped {
 		return
 		return
-	default:
-		// do nothing, we're stopping for the first time
 	}
 	}
+	m.stopped = true
 
 
 	srvDone, localSrvDone := make(chan struct{}), make(chan struct{})
 	srvDone, localSrvDone := make(chan struct{}), make(chan struct{})
 	go func() {
 	go func() {
@@ -460,11 +443,7 @@ func (m *Manager) Stop(ctx context.Context) {
 		m.keyManager.Stop()
 		m.keyManager.Stop()
 	}
 	}
 
 
-	// once we start stopping, send a signal that we're doing so. this tells
-	// Run that we've started stopping, when it gets the error from errServe
-	// it also prevents the loop from processing any more stuff.
-	close(m.stopped)
-
+	m.cancelFunc()
 	<-m.raftNode.Done()
 	<-m.raftNode.Done()
 
 
 	timer := time.AfterFunc(stopTimeout, func() {
 	timer := time.AfterFunc(stopTimeout, func() {
@@ -582,11 +561,9 @@ func (m *Manager) handleLeadershipEvents(ctx context.Context, leadershipCh chan
 		select {
 		select {
 		case leadershipEvent := <-leadershipCh:
 		case leadershipEvent := <-leadershipCh:
 			m.mu.Lock()
 			m.mu.Lock()
-			select {
-			case <-m.stopped:
+			if m.stopped {
 				m.mu.Unlock()
 				m.mu.Unlock()
 				return
 				return
-			default:
 			}
 			}
 			newState := leadershipEvent.(raft.LeadershipState)
 			newState := leadershipEvent.(raft.LeadershipState)
 
 
@@ -596,8 +573,6 @@ func (m *Manager) handleLeadershipEvents(ctx context.Context, leadershipCh chan
 				m.becomeFollower()
 				m.becomeFollower()
 			}
 			}
 			m.mu.Unlock()
 			m.mu.Unlock()
-		case <-m.stopped:
-			return
 		case <-ctx.Done():
 		case <-ctx.Done():
 			return
 			return
 		}
 		}
@@ -605,20 +580,21 @@ func (m *Manager) handleLeadershipEvents(ctx context.Context, leadershipCh chan
 }
 }
 
 
 // serveListener serves a listener for local and non local connections.
 // serveListener serves a listener for local and non local connections.
-func (m *Manager) serveListener(ctx context.Context, errServe chan error, proto string, lis net.Listener) {
+func (m *Manager) serveListener(ctx context.Context, errServe chan error, l net.Listener) {
 	ctx = log.WithLogger(ctx, log.G(ctx).WithFields(
 	ctx = log.WithLogger(ctx, log.G(ctx).WithFields(
 		logrus.Fields{
 		logrus.Fields{
-			"proto": lis.Addr().Network(),
-			"addr":  lis.Addr().String()}))
-	if proto == "unix" {
+			"proto": l.Addr().Network(),
+			"addr":  l.Addr().String(),
+		}))
+	if _, ok := l.(*net.TCPListener); !ok {
 		log.G(ctx).Info("Listening for local connections")
 		log.G(ctx).Info("Listening for local connections")
 		// we need to disallow double closes because UnixListener.Close
 		// we need to disallow double closes because UnixListener.Close
 		// can delete unix-socket file of newer listener. grpc calls
 		// can delete unix-socket file of newer listener. grpc calls
 		// Close twice indeed: in Serve and in Stop.
 		// Close twice indeed: in Serve and in Stop.
-		errServe <- m.localserver.Serve(&closeOnceListener{Listener: lis})
+		errServe <- m.localserver.Serve(&closeOnceListener{Listener: l})
 	} else {
 	} else {
 		log.G(ctx).Info("Listening for connections")
 		log.G(ctx).Info("Listening for connections")
-		errServe <- m.server.Serve(lis)
+		errServe <- m.server.Serve(l)
 	}
 	}
 }
 }
 
 

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

@@ -205,7 +205,7 @@ func (g *Orchestrator) removeTasksFromNode(ctx context.Context, node *api.Node)
 		return nil
 		return nil
 	})
 	})
 	if err != nil {
 	if err != nil {
-		log.G(ctx).WithError(err).Errorf("global orchestrator: removeTasksFromNode failed")
+		log.G(ctx).WithError(err).Errorf("global orchestrator: removeTasksFromNode failed batching tasks")
 	}
 	}
 }
 }
 
 

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

@@ -1689,7 +1689,7 @@ func getIDs(snap *raftpb.Snapshot, ents []raftpb.Entry) []uint64 {
 		case raftpb.ConfChangeUpdateNode:
 		case raftpb.ConfChangeUpdateNode:
 			// do nothing
 			// do nothing
 		default:
 		default:
-			log.L.Panic("ConfChange Type should be either ConfChangeAddNode or ConfChangeRemoveNode!")
+			log.L.Panic("ConfChange Type should be either ConfChangeAddNode, or ConfChangeRemoveNode, or ConfChangeUpdateNode!")
 		}
 		}
 	}
 	}
 	var sids []uint64
 	var sids []uint64

+ 8 - 9
vendor/src/github.com/docker/swarmkit/node/node.go

@@ -22,6 +22,7 @@ import (
 	"github.com/docker/swarmkit/log"
 	"github.com/docker/swarmkit/log"
 	"github.com/docker/swarmkit/manager"
 	"github.com/docker/swarmkit/manager"
 	"github.com/docker/swarmkit/remotes"
 	"github.com/docker/swarmkit/remotes"
+	"github.com/docker/swarmkit/xnet"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
 	"golang.org/x/net/context"
 	"golang.org/x/net/context"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc"
@@ -116,10 +117,10 @@ func (n *Node) RemoteAPIAddr() (string, error) {
 		return "", errors.Errorf("node is not manager")
 		return "", errors.Errorf("node is not manager")
 	}
 	}
 	addr := n.manager.Addr()
 	addr := n.manager.Addr()
-	if addr == nil {
+	if addr == "" {
 		return "", errors.Errorf("manager addr is not set")
 		return "", errors.Errorf("manager addr is not set")
 	}
 	}
-	return addr.String(), nil
+	return addr, nil
 }
 }
 
 
 // New returns new Node instance.
 // New returns new Node instance.
@@ -554,12 +555,10 @@ func (n *Node) initManagerConnection(ctx context.Context, ready chan<- struct{})
 	opts := []grpc.DialOption{}
 	opts := []grpc.DialOption{}
 	insecureCreds := credentials.NewTLS(&tls.Config{InsecureSkipVerify: true})
 	insecureCreds := credentials.NewTLS(&tls.Config{InsecureSkipVerify: true})
 	opts = append(opts, grpc.WithTransportCredentials(insecureCreds))
 	opts = append(opts, grpc.WithTransportCredentials(insecureCreds))
-	// Using listen address instead of advertised address because this is a
-	// local connection.
 	addr := n.config.ListenControlAPI
 	addr := n.config.ListenControlAPI
 	opts = append(opts, grpc.WithDialer(
 	opts = append(opts, grpc.WithDialer(
 		func(addr string, timeout time.Duration) (net.Conn, error) {
 		func(addr string, timeout time.Duration) (net.Conn, error) {
-			return net.DialTimeout("unix", addr, timeout)
+			return xnet.DialTimeoutLocal(addr, timeout)
 		}))
 		}))
 	conn, err := grpc.Dial(addr, opts...)
 	conn, err := grpc.Dial(addr, opts...)
 	if err != nil {
 	if err != nil {
@@ -623,11 +622,11 @@ func (n *Node) runManager(ctx context.Context, securityConfig *ca.SecurityConfig
 		remoteAddr, _ := n.remotes.Select(n.NodeID())
 		remoteAddr, _ := n.remotes.Select(n.NodeID())
 		m, err := manager.New(&manager.Config{
 		m, err := manager.New(&manager.Config{
 			ForceNewCluster: n.config.ForceNewCluster,
 			ForceNewCluster: n.config.ForceNewCluster,
-			ProtoAddr: map[string]string{
-				"tcp":  n.config.ListenRemoteAPI,
-				"unix": n.config.ListenControlAPI,
+			RemoteAPI: manager.RemoteAddrs{
+				ListenAddr:    n.config.ListenRemoteAPI,
+				AdvertiseAddr: n.config.AdvertiseRemoteAPI,
 			},
 			},
-			AdvertiseAddr:  n.config.AdvertiseRemoteAPI,
+			ControlAPI:     n.config.ListenControlAPI,
 			SecurityConfig: securityConfig,
 			SecurityConfig: securityConfig,
 			ExternalCAs:    n.config.ExternalCAs,
 			ExternalCAs:    n.config.ExternalCAs,
 			JoinRaft:       remoteAddr.Addr,
 			JoinRaft:       remoteAddr.Addr,

+ 1 - 1
vendor/src/github.com/docker/swarmkit/protobuf/plugin/gen.go

@@ -1,3 +1,3 @@
 package plugin
 package plugin
 
 
-//go:generate protoc -I.:../../vendor/github.com/gogo/protobuf/protobuf --gogoswarm_out=import_path=github.com/docker/swarmkit/protobuf/plugin,Mgoogle/protobuf/descriptor.proto=github.com/gogo/protobuf/protoc-gen-gogo/descriptor:. plugin.proto
+//go:generate protoc -I.:/usr/local --gogoswarm_out=import_path=github.com/docker/swarmkit/protobuf/plugin,Mgoogle/protobuf/descriptor.proto=github.com/gogo/protobuf/protoc-gen-gogo/descriptor:. plugin.proto

+ 20 - 0
vendor/src/github.com/docker/swarmkit/xnet/xnet_unix.go

@@ -0,0 +1,20 @@
+// +build !windows
+
+package xnet
+
+import (
+	"net"
+	"time"
+)
+
+// ListenLocal opens a local socket for control communication
+func ListenLocal(socket string) (net.Listener, error) {
+	// on unix it's just a unix socket
+	return net.Listen("unix", socket)
+}
+
+// DialTimeoutLocal is a DialTimeout function for local sockets
+func DialTimeoutLocal(socket string, timeout time.Duration) (net.Conn, error) {
+	// on unix, we dial a unix socket
+	return net.DialTimeout("unix", socket, timeout)
+}

+ 31 - 0
vendor/src/github.com/docker/swarmkit/xnet/xnet_windows.go

@@ -0,0 +1,31 @@
+// +build windows
+
+package xnet
+
+import (
+	"net"
+	"time"
+
+	"github.com/Microsoft/go-winio"
+)
+
+// ListenLocal opens a local socket for control communication
+func ListenLocal(socket string) (net.Listener, error) {
+	// set up ACL for the named pipe
+	// allow Administrators and SYSTEM
+	sddl := "D:P(A;;GA;;;BA)(A;;GA;;;SY)"
+	c := winio.PipeConfig{
+		SecurityDescriptor: sddl,
+		MessageMode:        true,  // Use message mode so that CloseWrite() is supported
+		InputBufferSize:    65536, // Use 64KB buffers to improve performance
+		OutputBufferSize:   65536,
+	}
+	// on windows, our socket is actually a named pipe
+	return winio.ListenPipe(socket, &c)
+}
+
+// DialTimeoutLocal is a DialTimeout function for local sockets
+func DialTimeoutLocal(socket string, timeout time.Duration) (net.Conn, error) {
+	// On windows, we dial a named pipe
+	return winio.DialPipe(socket, &timeout)
+}

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio