Merge pull request #32848 from aaronlehmann/vendor-swarmkit-78db8a5

[17.05] Vendor swarmkit 78db8a5
diff --git a/vendor.conf b/vendor.conf
index e2d6d66..165c1b0 100644
--- a/vendor.conf
+++ b/vendor.conf
@@ -105,7 +105,7 @@
 github.com/tonistiigi/fifo 1405643975692217d6720f8b54aeee1bf2cd5cf4
 
 # cluster
-github.com/docker/swarmkit 78685cfc94de06f21d65d0d30b6f61e80d250c45
+github.com/docker/swarmkit 78db8a5fed39c637dcd136b9e16c29f135b41c94
 github.com/gogo/protobuf 8d70fb3182befc465c4a1eac8ad4d38ff49778e2
 github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a
 github.com/google/certificate-transparency d90e65c3a07988180c5b1ece71791c0b6506826e
diff --git a/vendor/github.com/docker/swarmkit/manager/allocator/network.go b/vendor/github.com/docker/swarmkit/manager/allocator/network.go
index 7231760..4a71117 100644
--- a/vendor/github.com/docker/swarmkit/manager/allocator/network.go
+++ b/vendor/github.com/docker/swarmkit/manager/allocator/network.go
@@ -164,7 +164,7 @@
 
 	var allocatedServices []*api.Service
 	for _, s := range services {
-		if nc.nwkAllocator.IsServiceAllocated(s, networkallocator.OnInit) {
+		if !nc.nwkAllocator.ServiceNeedsAllocation(s, networkallocator.OnInit) {
 			continue
 		}
 
@@ -317,7 +317,7 @@
 			break
 		}
 
-		if nc.nwkAllocator.IsServiceAllocated(s) {
+		if !nc.nwkAllocator.ServiceNeedsAllocation(s) {
 			break
 		}
 
@@ -345,7 +345,7 @@
 			break
 		}
 
-		if nc.nwkAllocator.IsServiceAllocated(s) {
+		if !nc.nwkAllocator.ServiceNeedsAllocation(s) {
 			if nc.nwkAllocator.PortsAllocatedInHostPublishMode(s) {
 				break
 			}
@@ -544,7 +544,7 @@
 	// network configured or service endpoints have been
 	// allocated.
 	return (len(t.Networks) == 0 || nc.nwkAllocator.IsTaskAllocated(t)) &&
-		(s == nil || nc.nwkAllocator.IsServiceAllocated(s))
+		(s == nil || !nc.nwkAllocator.ServiceNeedsAllocation(s))
 }
 
 func taskUpdateNetworks(t *api.Task, networks []*api.NetworkAttachment) {
@@ -886,7 +886,7 @@
 					return
 				}
 
-				if !nc.nwkAllocator.IsServiceAllocated(s) {
+				if nc.nwkAllocator.ServiceNeedsAllocation(s) {
 					err = fmt.Errorf("service %s to which this task %s belongs has pending allocations", s.ID, t.ID)
 					return
 				}
@@ -1000,7 +1000,7 @@
 	nc := a.netCtx
 	var allocatedServices []*api.Service
 	for _, s := range nc.unallocatedServices {
-		if !nc.nwkAllocator.IsServiceAllocated(s) {
+		if nc.nwkAllocator.ServiceNeedsAllocation(s) {
 			if err := a.allocateService(ctx, s); err != nil {
 				log.G(ctx).WithError(err).Debugf("Failed allocation of unallocated service %s", s.ID)
 				continue
diff --git a/vendor/github.com/docker/swarmkit/manager/allocator/networkallocator/networkallocator.go b/vendor/github.com/docker/swarmkit/manager/allocator/networkallocator/networkallocator.go
index d956c54..fafb3b1 100644
--- a/vendor/github.com/docker/swarmkit/manager/allocator/networkallocator/networkallocator.go
+++ b/vendor/github.com/docker/swarmkit/manager/allocator/networkallocator/networkallocator.go
@@ -186,19 +186,34 @@
 		return
 	}
 
-	// First allocate VIPs for all the pre-populated endpoint attachments
-	for _, eAttach := range s.Endpoint.VirtualIPs {
-		if err = na.allocateVIP(eAttach); err != nil {
-			return
-		}
-	}
-
 	// Always prefer NetworkAttachmentConfig in the TaskSpec
 	specNetworks := s.Spec.Task.Networks
 	if len(specNetworks) == 0 && s != nil && len(s.Spec.Networks) != 0 {
 		specNetworks = s.Spec.Networks
 	}
 
+	// Allocate VIPs for all the pre-populated endpoint attachments
+	eVIPs := s.Endpoint.VirtualIPs[:0]
+	for _, eAttach := range s.Endpoint.VirtualIPs {
+		match := false
+		for _, nAttach := range specNetworks {
+			if nAttach.Target == eAttach.NetworkID {
+				match = true
+				if err = na.allocateVIP(eAttach); err != nil {
+					return
+				}
+				eVIPs = append(eVIPs, eAttach)
+				break
+			}
+		}
+		//If the network of the VIP is not part of the service spec,
+		//deallocate the vip
+		if !match {
+			na.deallocateVIP(eAttach)
+		}
+	}
+	s.Endpoint.VirtualIPs = eVIPs
+
 outer:
 	for _, nAttach := range specNetworks {
 		for _, vip := range s.Endpoint.VirtualIPs {
@@ -215,7 +230,11 @@
 		s.Endpoint.VirtualIPs = append(s.Endpoint.VirtualIPs, vip)
 	}
 
-	na.services[s.ID] = struct{}{}
+	if len(s.Endpoint.VirtualIPs) > 0 {
+		na.services[s.ID] = struct{}{}
+	} else {
+		delete(na.services, s.ID)
+	}
 	return
 }
 
@@ -300,41 +319,79 @@
 	options.OnInit = true
 }
 
-// IsServiceAllocated returns if the passed service has its network resources allocated or not.
-// init bool indicates if the func is called during allocator initialization stage.
-func (na *NetworkAllocator) IsServiceAllocated(s *api.Service, flags ...func(*ServiceAllocationOpts)) bool {
+// ServiceNeedsAllocation returns true if the passed service needs to have network resources allocated/updated.
+func (na *NetworkAllocator) ServiceNeedsAllocation(s *api.Service, flags ...func(*ServiceAllocationOpts)) bool {
 	var options ServiceAllocationOpts
-
 	for _, flag := range flags {
 		flag(&options)
 	}
 
+	// Always prefer NetworkAttachmentConfig in the TaskSpec
+	specNetworks := s.Spec.Task.Networks
+	if len(specNetworks) == 0 && len(s.Spec.Networks) != 0 {
+		specNetworks = s.Spec.Networks
+	}
+
 	// If endpoint mode is VIP and allocator does not have the
-	// service in VIP allocated set then it is not allocated.
-	if (len(s.Spec.Task.Networks) != 0 || len(s.Spec.Networks) != 0) &&
+	// service in VIP allocated set then it needs to be allocated.
+	if len(specNetworks) != 0 &&
 		(s.Spec.Endpoint == nil ||
 			s.Spec.Endpoint.Mode == api.ResolutionModeVirtualIP) {
+
 		if _, ok := na.services[s.ID]; !ok {
-			return false
+			return true
+		}
+
+		if s.Endpoint == nil || len(s.Endpoint.VirtualIPs) == 0 {
+			return true
+		}
+
+		for _, net := range specNetworks {
+			match := false
+			for _, vip := range s.Endpoint.VirtualIPs {
+				if vip.NetworkID == net.Target {
+					match = true
+					break
+				}
+			}
+			if !match {
+				return true
+			}
+		}
+	}
+
+	//If the spec no longer has networks attached and has a vip allocated
+	//from previous spec the service needs to updated
+	if s.Endpoint != nil {
+		for _, vip := range s.Endpoint.VirtualIPs {
+			match := false
+			for _, net := range specNetworks {
+				if vip.NetworkID == net.Target {
+					match = true
+					break
+				}
+			}
+			if !match {
+				return true
+			}
 		}
 	}
 
 	// If the endpoint mode is DNSRR and allocator has the service
-	// in VIP allocated set then we return not allocated to make
+	// in VIP allocated set then we return to be allocated to make
 	// sure the allocator triggers networkallocator to free up the
 	// resources if any.
 	if s.Spec.Endpoint != nil && s.Spec.Endpoint.Mode == api.ResolutionModeDNSRoundRobin {
 		if _, ok := na.services[s.ID]; ok {
-			return false
+			return true
 		}
 	}
 
 	if (s.Spec.Endpoint != nil && len(s.Spec.Endpoint.Ports) != 0) ||
 		(s.Endpoint != nil && len(s.Endpoint.Ports) != 0) {
-		return na.portAllocator.isPortsAllocatedOnInit(s, options.OnInit)
+		return !na.portAllocator.isPortsAllocatedOnInit(s, options.OnInit)
 	}
-
-	return true
+	return false
 }
 
 // IsNodeAllocated returns if the passed node has its network resources allocated or not.