wait.go 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  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/console"
  10. )
  11. func (b *Backend) WaitStackCompletion(ctx context.Context, name string, operation int) error {
  12. w := console.NewProgressWriter()
  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 := fmt.Sprintf("%s %q", aws.StringValue(event.ResourceType), aws.StringValue(event.LogicalResourceId))
  47. reason := aws.StringValue(event.ResourceStatusReason)
  48. status := aws.StringValue(event.ResourceStatus)
  49. w.ResourceEvent(resource, status, reason)
  50. if stackErr == nil && strings.HasSuffix(status, "_FAILED") {
  51. stackErr = fmt.Errorf(reason)
  52. }
  53. }
  54. }
  55. return stackErr
  56. }