in internal/pkg/term/progress/ecs.go [203:291]
func (c *rollingUpdateComponent) renderStoppedTasks(out io.Writer) (numLines int, err error) {
if len(c.stoppedTasks) == 0 {
return 0, nil
}
header := []string{"TaskId", "CurrentStatus", "DesiredStatus"}
var rows [][]string
title := fmt.Sprintf("Latest %d %s stopped reason", len(c.stoppedTasks), english.PluralWord(len(c.stoppedTasks), "task", "tasks"))
title = fmt.Sprintf("%s%s", color.DullRed.Sprintf("✘ "), color.Faint.Sprintf(title))
childComponents := []Renderer{
&singleLineComponent{}, // Add an empty line before rendering task stopped events.
&singleLineComponent{
Text: title,
Padding: c.padding,
},
}
type stoppedTasksInfo struct {
ids []string
latestStoppingAt time.Time
}
stopReason2Tasks := make(map[string]*stoppedTasksInfo, len(c.stoppedTasks))
for _, st := range c.stoppedTasks {
id, err := ecs.TaskID(aws.StringValue(st.TaskArn))
if err != nil {
return 0, err
}
tasks, ok := stopReason2Tasks[aws.StringValue(st.StoppedReason)]
if ok {
tasks.ids = append(tasks.ids, ecs.ShortTaskID(id))
tasks.latestStoppingAt = aws.TimeValue(st.StoppingAt)
stopReason2Tasks[aws.StringValue(st.StoppedReason)] = tasks
} else {
stopReason2Tasks[aws.StringValue(st.StoppedReason)] = &stoppedTasksInfo{
ids: []string{ecs.ShortTaskID(id)},
latestStoppingAt: aws.TimeValue(st.StoppingAt),
}
}
rows = append(rows, []string{
ecs.ShortTaskID(id),
aws.StringValue(st.LastStatus),
aws.StringValue(st.DesiredStatus),
})
}
var sortedReasons []string
for reason := range stopReason2Tasks {
sortedReasons = append(sortedReasons, reason)
}
sort.SliceStable(sortedReasons, func(i, j int) bool {
return stopReason2Tasks[sortedReasons[i]].latestStoppingAt.After(stopReason2Tasks[sortedReasons[j]].latestStoppingAt)
})
for _, reason := range sortedReasons {
for i, truncatedReason := range splitByLength(fmt.Sprintf("[%s]: %s", strings.Join(stopReason2Tasks[reason].ids, ","), reason), maxCellLength) {
pretty := fmt.Sprintf(" %s", truncatedReason)
if i == 0 {
pretty = fmt.Sprintf("- %s", truncatedReason)
}
childComponents = append(childComponents, &singleLineComponent{
Text: pretty,
Padding: c.padding + nestedComponentPadding,
})
}
}
table := newTableComponent(color.Faint.Sprintf("Latest %d stopped %s", len(c.stoppedTasks), english.PluralWord(len(c.stoppedTasks), "task", "tasks")), header, rows)
table.Padding = c.padding
childComponents = append(childComponents,
&singleLineComponent{},
&singleLineComponent{
Text: color.Faint.Sprintf("Troubleshoot task stopped reason"),
Padding: c.padding,
},
&singleLineComponent{
Text: fmt.Sprintf("1. You can run %s to see the logs of the last stopped task.",
color.HighlightCode("copilot svc logs --previous")),
Padding: c.padding + nestedComponentPadding,
},
&singleLineComponent{
Text: fmt.Sprintf("2. You can visit this article: %s.",
color.Emphasize("https://repost.aws/knowledge-center/ecs-task-stopped")),
Padding: c.padding + nestedComponentPadding,
})
treeComponent := treeComponent{
Root: table,
Children: childComponents,
}
nl, err := treeComponent.Render(out)
if err != nil {
return 0, fmt.Errorf("render deployments table: %w", err)
}
return nl, err
}