func (u *Updater) isTaskDirty(t *api.Task) bool { return orchestrator.IsTaskDirty(u.newService, t) }
// reconcileServicesOneNode checks the specified services on one node func (g *Orchestrator) reconcileServicesOneNode(ctx context.Context, serviceIDs []string, nodeID string) { node, exists := g.nodes[nodeID] if !exists { return } // whether each service has completed on the node completed := make(map[string]bool) // tasks by service tasks := make(map[string][]*api.Task) var ( tasksOnNode []*api.Task err error ) g.store.View(func(tx store.ReadTx) { tasksOnNode, err = store.FindTasks(tx, store.ByNodeID(nodeID)) }) if err != nil { log.G(ctx).WithError(err).Errorf("global orchestrator: reconcile failed finding tasks on node %s", nodeID) return } for _, serviceID := range serviceIDs { for _, t := range tasksOnNode { if t.ServiceID != serviceID { continue } if isTaskRunning(t) { tasks[serviceID] = append(tasks[serviceID], t) } else { if isTaskCompleted(t, orchestrator.RestartCondition(t)) { completed[serviceID] = true } } } } _, err = g.store.Batch(func(batch *store.Batch) error { for _, serviceID := range serviceIDs { service, exists := g.globalServices[serviceID] if !exists { continue } if !constraint.NodeMatches(service.constraints, node) { continue } // if restart policy considers this node has finished its task // it should remove all running tasks if completed[serviceID] { g.removeTasks(ctx, batch, tasks[serviceID]) continue } if node.Spec.Availability == api.NodeAvailabilityPause { // the node is paused, so we won't add or update tasks continue } if len(tasks) == 0 { g.addTask(ctx, batch, service.Service, nodeID) } else { // If task is out of date, update it. This can happen // on node reconciliation if, for example, we pause a // node, update the service, and then activate the node // later. // We don't use g.updater here for two reasons: // - This is not a rolling update. Since it was not // triggered directly by updating the service, it // should not observe the rolling update parameters // or show status in UpdateStatus. // - Calling Update cancels any current rolling updates // for the service, such as one triggered by service // reconciliation. var ( dirtyTasks []*api.Task cleanTasks []*api.Task ) for _, t := range tasks[serviceID] { if orchestrator.IsTaskDirty(service.Service, t) { dirtyTasks = append(dirtyTasks, t) } else { cleanTasks = append(cleanTasks, t) } } if len(cleanTasks) == 0 { g.addTask(ctx, batch, service.Service, nodeID) } else { dirtyTasks = append(dirtyTasks, cleanTasks[1:]...) } g.removeTasks(ctx, batch, dirtyTasks) } } return nil }) if err != nil { log.G(ctx).WithError(err).Errorf("global orchestrator: reconcileServiceOneNode batch failed") } }