wait.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. package amazon
  2. import (
  3. "context"
  4. "fmt"
  5. "sort"
  6. "strings"
  7. "time"
  8. "github.com/aws/aws-sdk-go/aws"
  9. "github.com/aws/aws-sdk-go/service/cloudformation"
  10. "github.com/docker/ecs-plugin/pkg/console"
  11. )
  12. func (c *client) WaitStackCompletion(ctx context.Context, name string, operation int) error {
  13. w := console.NewProgressWriter()
  14. knownEvents := map[string]struct{}{}
  15. // Get the unique Stack ID so we can collect events without getting some from previous deployments with same name
  16. stackID, err := c.api.GetStackID(ctx, name)
  17. if err != nil {
  18. return err
  19. }
  20. ticker := time.NewTicker(1 * time.Second)
  21. done := make(chan bool)
  22. go func() {
  23. c.api.WaitStackComplete(ctx, stackID, operation) //nolint:errcheck
  24. ticker.Stop()
  25. done <- true
  26. }()
  27. var completed bool
  28. var stackErr error
  29. for !completed {
  30. select {
  31. case <-done:
  32. completed = true
  33. case <-ticker.C:
  34. }
  35. events, err := c.api.DescribeStackEvents(ctx, stackID)
  36. if err != nil {
  37. return err
  38. }
  39. sort.Slice(events, func(i, j int) bool {
  40. return events[i].Timestamp.Before(*events[j].Timestamp)
  41. })
  42. for _, event := range events {
  43. if _, ok := knownEvents[*event.EventId]; ok {
  44. continue
  45. }
  46. knownEvents[*event.EventId] = struct{}{}
  47. resource := fmt.Sprintf("%s %q", aws.StringValue(event.ResourceType), aws.StringValue(event.LogicalResourceId))
  48. reason := aws.StringValue(event.ResourceStatusReason)
  49. status := aws.StringValue(event.ResourceStatus)
  50. w.ResourceEvent(resource, status, reason)
  51. if stackErr == nil && strings.HasSuffix(status, "_FAILED") {
  52. stackErr = fmt.Errorf(reason)
  53. }
  54. }
  55. }
  56. return stackErr
  57. }
  58. type waitAPI interface {
  59. GetStackID(ctx context.Context, name string) (string, error)
  60. WaitStackComplete(ctx context.Context, name string, operation int) error
  61. DescribeStackEvents(ctx context.Context, stackID string) ([]*cloudformation.StackEvent, error)
  62. }
  63. const (
  64. StackCreate = iota
  65. StackDelete
  66. )