From 2b797248042480ed5de10cb89675179f8adab9a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Pelvet?= Date: Sun, 26 Oct 2025 18:36:46 +0100 Subject: [PATCH] opensearch: Add error handling for domain change progress failures - Add checkAndReturnChangeProgressError to detect validation failures and cancellations - Add getChangeProgressError to fetch detailed error information from DescribeDomainChangeProgress API - Integrate error checks into waitForDomainCreation, waitForDomainUpdate, and waitForDomainDelete - Replace deprecated tfresource.NotFound with retry.NotFound --- internal/service/opensearch/wait.go | 59 ++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/internal/service/opensearch/wait.go b/internal/service/opensearch/wait.go index 1c1a7a560851..c8bd1878d1ce 100644 --- a/internal/service/opensearch/wait.go +++ b/internal/service/opensearch/wait.go @@ -6,6 +6,7 @@ package opensearch import ( "context" "fmt" + "strings" "time" "github.com/aws/aws-sdk-go-v2/aws" @@ -13,6 +14,7 @@ import ( awstypes "github.com/aws/aws-sdk-go-v2/service/opensearch/types" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-provider-aws/internal/enum" + tfretry "github.com/hashicorp/terraform-provider-aws/internal/retry" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) @@ -21,6 +23,49 @@ const ( domainUpgradeSuccessDelay = 30 * time.Second ) +func checkAndReturnChangeProgressError(ctx context.Context, conn *opensearch.Client, domainName string, details *awstypes.ChangeProgressDetails) error { + if details != nil && (details.ConfigChangeStatus == awstypes.ConfigChangeStatusValidationFailed || details.ConfigChangeStatus == awstypes.ConfigChangeStatusCancelled) { + return getChangeProgressError(ctx, conn, domainName, details.ChangeId) + } + return nil +} + +func getChangeProgressError(ctx context.Context, conn *opensearch.Client, domainName string, changeId *string) error { + input := &opensearch.DescribeDomainChangeProgressInput{ + DomainName: aws.String(domainName), + } + if changeId != nil { + input.ChangeId = changeId + } + + output, err := conn.DescribeDomainChangeProgress(ctx, input) + if err != nil { + return fmt.Errorf("domain %s: unable to get change progress details: %w", domainName, err) + } + + if output.ChangeProgressStatus == nil { + return fmt.Errorf("domain %s: unexpected API response, ChangeProgressStatus is nil", domainName) + } + + status := output.ChangeProgressStatus + var failedStages []string + for _, stage := range status.ChangeProgressStages { + if stage.Status != nil && *stage.Status == "FAILED" { + desc := aws.ToString(stage.Description) + if desc == "" { + desc = aws.ToString(stage.Name) + } + failedStages = append(failedStages, desc) + } + } + + if len(failedStages) > 0 { + return fmt.Errorf("domain %s: %s: %s", domainName, status.ConfigChangeStatus, strings.Join(failedStages, "; ")) + } + + return fmt.Errorf("domain %s: %s", domainName, status.ConfigChangeStatus) +} + func waitUpgradeSucceeded(ctx context.Context, conn *opensearch.Client, name string, timeout time.Duration) (*opensearch.GetUpgradeStatusOutput, error) { stateConf := &retry.StateChangeConf{ Pending: enum.Slice(awstypes.UpgradeStatusInProgress), @@ -52,6 +97,10 @@ func waitForDomainCreation(ctx context.Context, conn *opensearch.Client, domainN return tfresource.NonRetryableError(err) } + if err := checkAndReturnChangeProgressError(ctx, conn, domainName, out.ChangeProgressDetails); err != nil { + return tfresource.NonRetryableError(err) + } + if !aws.ToBool(out.Processing) && (out.Endpoint != nil || out.Endpoints != nil) { return nil } @@ -76,6 +125,10 @@ func waitForDomainUpdate(ctx context.Context, conn *opensearch.Client, domainNam return tfresource.NonRetryableError(err) } + if err := checkAndReturnChangeProgressError(ctx, conn, domainName, out.ChangeProgressDetails); err != nil { + return tfresource.NonRetryableError(err) + } + if !aws.ToBool(out.Processing) { return nil } @@ -98,12 +151,16 @@ func waitForDomainDelete(ctx context.Context, conn *opensearch.Client, domainNam out, err = findDomainByName(ctx, conn, domainName) if err != nil { - if tfresource.NotFound(err) { + if tfretry.NotFound(err) { return nil } return tfresource.NonRetryableError(err) } + if err := checkAndReturnChangeProgressError(ctx, conn, domainName, out.ChangeProgressDetails); err != nil { + return tfresource.NonRetryableError(err) + } + if out != nil && !aws.ToBool(out.Processing) { return nil }