wait.go 2.1 KB

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