(ctx context.Context, stackName, targetStatus string, timeout time.Duration)
| 226 | } |
| 227 | |
| 228 | func (s *StackDeployer) waitForStackOperation(ctx context.Context, stackName, targetStatus string, timeout time.Duration) error { |
| 229 | checkFn := func() (bool, error) { |
| 230 | input := &cloudformation.DescribeStacksInput{ |
| 231 | StackName: aws.String(stackName), |
| 232 | } |
| 233 | |
| 234 | result, err := s.clients.CloudFormation.DescribeStacksWithContext(ctx, input) |
| 235 | if err != nil { |
| 236 | // If stack is being deleted and we're waiting for DELETE_COMPLETE, |
| 237 | // a ValidationError means deletion succeeded |
| 238 | if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "ValidationError" { |
| 239 | if targetStatus == cloudformation.StackStatusDeleteComplete { |
| 240 | return true, nil |
| 241 | } |
| 242 | } |
| 243 | return false, err |
| 244 | } |
| 245 | |
| 246 | if len(result.Stacks) == 0 { |
| 247 | return false, fmt.Errorf("stack not found") |
| 248 | } |
| 249 | |
| 250 | stack := result.Stacks[0] |
| 251 | currentStatus := *stack.StackStatus |
| 252 | |
| 253 | log.Printf("Stack status: %s", currentStatus) |
| 254 | |
| 255 | // Check for failure states |
| 256 | if strings.Contains(currentStatus, "FAILED") || |
| 257 | strings.Contains(currentStatus, "ROLLBACK") { |
| 258 | return false, fmt.Errorf("stack operation failed with status: %s", currentStatus) |
| 259 | } |
| 260 | |
| 261 | return currentStatus == targetStatus, nil |
| 262 | } |
| 263 | |
| 264 | return awsclients.WaitForOperation(ctx, checkFn, timeout) |
| 265 | } |
| 266 | |
| 267 | func (s *StackDeployer) buildStackParameters() []*cloudformation.Parameter { |
| 268 | return []*cloudformation.Parameter{ |
no test coverage detected