wait.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. package backend
  2. import (
  3. "context"
  4. "fmt"
  5. "sort"
  6. "strings"
  7. "time"
  8. "github.com/aws/aws-sdk-go/aws"
  9. "github.com/docker/ecs-plugin/pkg/compose"
  10. "github.com/docker/ecs-plugin/pkg/progress"
  11. )
  12. func (b *Backend) WaitStackCompletion(ctx context.Context, name string, operation int) error {
  13. knownEvents := map[string]struct{}{}
  14. // progress writer
  15. w := progress.ContextWriter(ctx)
  16. // Get the unique Stack ID so we can collect events without getting some from previous deployments with same name
  17. stackID, err := b.api.GetStackID(ctx, name)
  18. if err != nil {
  19. return err
  20. }
  21. ticker := time.NewTicker(1 * time.Second)
  22. done := make(chan bool)
  23. go func() {
  24. b.api.WaitStackComplete(ctx, stackID, operation) //nolint:errcheck
  25. ticker.Stop()
  26. done <- true
  27. }()
  28. var completed bool
  29. var stackErr error
  30. for !completed {
  31. select {
  32. case <-done:
  33. completed = true
  34. case <-ticker.C:
  35. }
  36. events, err := b.api.DescribeStackEvents(ctx, stackID)
  37. if err != nil {
  38. return err
  39. }
  40. sort.Slice(events, func(i, j int) bool {
  41. return events[i].Timestamp.Before(*events[j].Timestamp)
  42. })
  43. for _, event := range events {
  44. if _, ok := knownEvents[*event.EventId]; ok {
  45. continue
  46. }
  47. knownEvents[*event.EventId] = struct{}{}
  48. resource := aws.StringValue(event.LogicalResourceId)
  49. reason := aws.StringValue(event.ResourceStatusReason)
  50. status := aws.StringValue(event.ResourceStatus)
  51. progressStatus := progress.Working
  52. switch status {
  53. case "CREATE_COMPLETE":
  54. if operation == compose.StackCreate {
  55. progressStatus = progress.Done
  56. }
  57. case "UPDATE_COMPLETE":
  58. if operation == compose.StackUpdate {
  59. progressStatus = progress.Done
  60. }
  61. case "DELETE_COMPLETE":
  62. if operation == compose.StackDelete {
  63. progressStatus = progress.Done
  64. }
  65. default:
  66. if strings.HasSuffix(status, "_FAILED") {
  67. progressStatus = progress.Error
  68. if stackErr == nil {
  69. operation = compose.StackDelete
  70. stackErr = fmt.Errorf(reason)
  71. }
  72. }
  73. }
  74. w.Event(progress.Event{
  75. ID: resource,
  76. Status: progressStatus,
  77. StatusText: status,
  78. })
  79. }
  80. }
  81. return stackErr
  82. }