(service swarm.Service, tasks []swarm.Task, activeNodes map[string]struct{}, _ bool)
| 727 | } |
| 728 | |
| 729 | func (u *globalJobProgressUpdater) update(service swarm.Service, tasks []swarm.Task, activeNodes map[string]struct{}, _ bool) (bool, error) { |
| 730 | if !u.initialized { |
| 731 | // if there are not yet tasks, then return early. |
| 732 | if len(tasks) == 0 && len(activeNodes) != 0 { |
| 733 | _ = u.progressOut.WriteProgress(progress.Progress{ |
| 734 | ID: "job progress", |
| 735 | Action: "waiting for tasks", |
| 736 | }) |
| 737 | return false, nil |
| 738 | } |
| 739 | |
| 740 | // when a global job starts, all of its tasks are created at once, so |
| 741 | // we can use len(tasks) to know how many we're expecting. |
| 742 | u.taskNodes = map[string]struct{}{} |
| 743 | |
| 744 | for _, task := range tasks { |
| 745 | // skip any tasks not belonging to this job iteration. |
| 746 | if task.JobIteration == nil || task.JobIteration.Index != service.JobStatus.JobIteration.Index { |
| 747 | continue |
| 748 | } |
| 749 | |
| 750 | // collect the list of all node IDs for this service. |
| 751 | // |
| 752 | // basically, global jobs will execute on any new nodes that join |
| 753 | // the cluster in the future. to avoid making things complicated, |
| 754 | // we will only check the progress of the initial set of nodes. if |
| 755 | // any new nodes come online during the operation, we will ignore |
| 756 | // them. |
| 757 | u.taskNodes[task.NodeID] = struct{}{} |
| 758 | } |
| 759 | |
| 760 | u.total = len(u.taskNodes) |
| 761 | u.progressDigits = len(strconv.Itoa(u.total)) |
| 762 | |
| 763 | u.writeOverallProgress(0) |
| 764 | u.initialized = true |
| 765 | } |
| 766 | |
| 767 | // tasksByNodeID maps a NodeID to the latest task for that Node ID. this |
| 768 | // lets us pick only the latest task for any given node. |
| 769 | tasksByNodeID := map[string]swarm.Task{} |
| 770 | |
| 771 | for _, task := range tasks { |
| 772 | // skip any tasks not belonging to this job iteration |
| 773 | if task.JobIteration == nil || task.JobIteration.Index != service.JobStatus.JobIteration.Index { |
| 774 | continue |
| 775 | } |
| 776 | |
| 777 | // if the task is not on one of the initial set of nodes, ignore it. |
| 778 | if _, ok := u.taskNodes[task.NodeID]; !ok { |
| 779 | continue |
| 780 | } |
| 781 | |
| 782 | // if there is already a task recorded for this node, choose the one |
| 783 | // with the lower state |
| 784 | if oldtask, ok := tasksByNodeID[task.NodeID]; ok { |
| 785 | if numberedStates[oldtask.Status.State] > numberedStates[task.Status.State] { |
| 786 | tasksByNodeID[task.NodeID] = task |
nothing calls this directly
no test coverage detected