diff --git a/.changelog/20383.txt b/.changelog/20383.txt new file mode 100644 index 00000000000..1ef2c212c18 --- /dev/null +++ b/.changelog/20383.txt @@ -0,0 +1,7 @@ +```release-note:bug +aws/resource_aws_lex_bot: Correctly determine `version` attribute +``` + +```release-note:bug +aws/resource_aws_lex_intent: Correctly determine `version` attribute +``` \ No newline at end of file diff --git a/.changelog/21122.txt b/.changelog/21122.txt new file mode 100644 index 00000000000..9457d04124d --- /dev/null +++ b/.changelog/21122.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_lex_bot: Added waiter support to account for `BUILDING` status +``` \ No newline at end of file diff --git a/aws/data_source_aws_lex_bot.go b/aws/data_source_aws_lex_bot.go index 99987b04b77..3513cbca509 100644 --- a/aws/data_source_aws_lex_bot.go +++ b/aws/data_source_aws_lex_bot.go @@ -4,10 +4,10 @@ import ( "fmt" "time" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" - "github.com/aws/aws-sdk-go/service/lexmodelbuildingservice" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + tflex "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/lex" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/lex/finder" ) func dataSourceAwsLexBot() *schema.Resource { @@ -75,7 +75,7 @@ func dataSourceAwsLexBot() *schema.Resource { "version": { Type: schema.TypeString, Optional: true, - Default: LexBotVersionLatest, + Default: tflex.LexBotVersionLatest, ValidateFunc: validateLexBotVersion, }, "voice_id": { @@ -89,13 +89,12 @@ func dataSourceAwsLexBot() *schema.Resource { func dataSourceAwsLexBotRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).lexmodelconn - botName := d.Get("name").(string) - resp, err := conn.GetBot(&lexmodelbuildingservice.GetBotInput{ - Name: aws.String(botName), - VersionOrAlias: aws.String(d.Get("version").(string)), - }) + name := d.Get("name").(string) + version := d.Get("version").(string) + output, err := finder.BotVersionByName(conn, name, version) + if err != nil { - return fmt.Errorf("error reading bot %s: %w", botName, err) + return fmt.Errorf("error reading Lex Bot (%s/%s): %w", name, version, err) } arn := arn.ARN{ @@ -103,27 +102,26 @@ func dataSourceAwsLexBotRead(d *schema.ResourceData, meta interface{}) error { Region: meta.(*AWSClient).region, Service: "lex", AccountID: meta.(*AWSClient).accountid, - Resource: fmt.Sprintf("bot:%s", d.Get("name").(string)), + Resource: fmt.Sprintf("bot:%s", name), } d.Set("arn", arn.String()) + d.Set("checksum", output.Checksum) + d.Set("child_directed", output.ChildDirected) + d.Set("created_date", output.CreatedDate.Format(time.RFC3339)) + d.Set("description", output.Description) + d.Set("detect_sentiment", output.DetectSentiment) + d.Set("enable_model_improvements", output.EnableModelImprovements) + d.Set("failure_reason", output.FailureReason) + d.Set("idle_session_ttl_in_seconds", output.IdleSessionTTLInSeconds) + d.Set("last_updated_date", output.LastUpdatedDate.Format(time.RFC3339)) + d.Set("locale", output.Locale) + d.Set("name", output.Name) + d.Set("nlu_intent_confidence_threshold", output.NluIntentConfidenceThreshold) + d.Set("status", output.Status) + d.Set("version", output.Version) + d.Set("voice_id", output.VoiceId) - d.Set("checksum", resp.Checksum) - d.Set("child_directed", resp.ChildDirected) - d.Set("created_date", resp.CreatedDate.Format(time.RFC3339)) - d.Set("description", resp.Description) - d.Set("detect_sentiment", resp.DetectSentiment) - d.Set("enable_model_improvements", resp.EnableModelImprovements) - d.Set("failure_reason", resp.FailureReason) - d.Set("idle_session_ttl_in_seconds", resp.IdleSessionTTLInSeconds) - d.Set("last_updated_date", resp.LastUpdatedDate.Format(time.RFC3339)) - d.Set("locale", resp.Locale) - d.Set("name", resp.Name) - d.Set("nlu_intent_confidence_threshold", resp.NluIntentConfidenceThreshold) - d.Set("status", resp.Status) - d.Set("version", resp.Version) - d.Set("voice_id", resp.VoiceId) - - d.SetId(botName) + d.SetId(name) return nil } diff --git a/aws/data_source_aws_lex_bot_test.go b/aws/data_source_aws_lex_bot_test.go index a89236f27d2..e89ceaa3eeb 100644 --- a/aws/data_source_aws_lex_bot_test.go +++ b/aws/data_source_aws_lex_bot_test.go @@ -67,17 +67,19 @@ func testAccDataSourceAwsLexBot_withVersion(t *testing.T) { resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"), resource.TestCheckResourceAttrPair(dataSourceName, "checksum", resourceName, "checksum"), resource.TestCheckResourceAttrPair(dataSourceName, "child_directed", resourceName, "child_directed"), - resource.TestCheckResourceAttrPair(dataSourceName, "created_date", resourceName, "created_date"), resource.TestCheckResourceAttrPair(dataSourceName, "description", resourceName, "description"), resource.TestCheckResourceAttrPair(dataSourceName, "detect_sentiment", resourceName, "detect_sentiment"), resource.TestCheckResourceAttrPair(dataSourceName, "enable_model_improvements", resourceName, "enable_model_improvements"), resource.TestCheckResourceAttrPair(dataSourceName, "failure_reason", resourceName, "failure_reason"), resource.TestCheckResourceAttrPair(dataSourceName, "idle_session_ttl_in_seconds", resourceName, "idle_session_ttl_in_seconds"), - resource.TestCheckResourceAttrPair(dataSourceName, "last_updated_date", resourceName, "last_updated_date"), + //Removed due to race condition when bots build/read/not_ready. Modified the bot status to read true status: + //https://github.com/hashicorp/terraform-provider-aws/issues/21107 + //resource.TestCheckResourceAttrPair(dataSourceName, "created_date", resourceName, "created_date"), + //resource.TestCheckResourceAttrPair(dataSourceName, "last_updated_date", resourceName, "last_updated_date"), + //resource.TestCheckResourceAttrPair(dataSourceName, "status", resourceName, "status"), resource.TestCheckResourceAttrPair(dataSourceName, "locale", resourceName, "locale"), resource.TestCheckResourceAttrPair(dataSourceName, "name", resourceName, "name"), resource.TestCheckResourceAttrPair(dataSourceName, "nlu_intent_confidence_threshold", resourceName, "nlu_intent_confidence_threshold"), - resource.TestCheckResourceAttrPair(dataSourceName, "status", resourceName, "status"), resource.TestCheckResourceAttrPair(dataSourceName, "version", resourceName, "version"), ), }, diff --git a/aws/data_source_aws_lex_intent.go b/aws/data_source_aws_lex_intent.go index aadc71b1918..d53979e5bea 100644 --- a/aws/data_source_aws_lex_intent.go +++ b/aws/data_source_aws_lex_intent.go @@ -10,6 +10,7 @@ import ( "github.com/aws/aws-sdk-go/service/lexmodelbuildingservice" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + tflex "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/lex" ) func dataSourceAwsLexIntent() *schema.Resource { @@ -52,7 +53,7 @@ func dataSourceAwsLexIntent() *schema.Resource { "version": { Type: schema.TypeString, Optional: true, - Default: LexIntentVersionLatest, + Default: tflex.LexIntentVersionLatest, ValidateFunc: validation.All( validation.StringLenBetween(1, 64), validation.StringMatch(regexp.MustCompile(`\$LATEST|[0-9]+`), ""), diff --git a/aws/internal/service/lex/enum.go b/aws/internal/service/lex/enum.go new file mode 100644 index 00000000000..97133eceeed --- /dev/null +++ b/aws/internal/service/lex/enum.go @@ -0,0 +1,6 @@ +package lex + +const ( + LexBotVersionLatest = "$LATEST" + LexIntentVersionLatest = "$LATEST" +) diff --git a/aws/internal/service/lex/finder/finder.go b/aws/internal/service/lex/finder/finder.go new file mode 100644 index 00000000000..9e9a643cd78 --- /dev/null +++ b/aws/internal/service/lex/finder/finder.go @@ -0,0 +1,120 @@ +package finder + +import ( + "strconv" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/lexmodelbuildingservice" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + tflex "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/lex" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" +) + +func BotVersionByName(conn *lexmodelbuildingservice.LexModelBuildingService, name, version string) (*lexmodelbuildingservice.GetBotOutput, error) { + input := &lexmodelbuildingservice.GetBotInput{ + Name: aws.String(name), + VersionOrAlias: aws.String(version), + } + + output, err := conn.GetBot(input) + + if tfawserr.ErrCodeEquals(err, lexmodelbuildingservice.ErrCodeNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return output, nil +} + +// LatestBotVersionByName returns the latest published version of a bot or $LATEST if the bot has never been published. +// See https://docs.aws.amazon.com/lex/latest/dg/versioning-aliases.html. +func LatestBotVersionByName(conn *lexmodelbuildingservice.LexModelBuildingService, name string) (string, error) { + input := &lexmodelbuildingservice.GetBotVersionsInput{ + Name: aws.String(name), + } + var latestVersion int + + err := conn.GetBotVersionsPages(input, func(page *lexmodelbuildingservice.GetBotVersionsOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, bot := range page.Bots { + version := aws.StringValue(bot.Version) + + if version == tflex.LexBotVersionLatest { + continue + } + + if version, err := strconv.Atoi(version); err != nil { + continue + } else if version > latestVersion { + latestVersion = version + } + } + + return !lastPage + }) + + if err != nil { + return "", err + } + + if latestVersion == 0 { + return tflex.LexBotVersionLatest, nil + } + + return strconv.Itoa(latestVersion), nil +} + +// LatestIntentVersionByName returns the latest published version of an intent or $LATEST if the intent has never been published. +// See https://docs.aws.amazon.com/lex/latest/dg/versioning-aliases.html. +func LatestIntentVersionByName(conn *lexmodelbuildingservice.LexModelBuildingService, name string) (string, error) { + input := &lexmodelbuildingservice.GetIntentVersionsInput{ + Name: aws.String(name), + } + var latestVersion int + + err := conn.GetIntentVersionsPages(input, func(page *lexmodelbuildingservice.GetIntentVersionsOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, intent := range page.Intents { + version := aws.StringValue(intent.Version) + + if version == tflex.LexIntentVersionLatest { + continue + } + + if version, err := strconv.Atoi(version); err != nil { + continue + } else if version > latestVersion { + latestVersion = version + } + } + + return !lastPage + }) + + if err != nil { + return "", err + } + + if latestVersion == 0 { + return tflex.LexIntentVersionLatest, nil + } + + return strconv.Itoa(latestVersion), nil +} diff --git a/aws/internal/service/lex/waiter/status.go b/aws/internal/service/lex/waiter/status.go index 3fa9d3d31d2..4e83775ba8e 100644 --- a/aws/internal/service/lex/waiter/status.go +++ b/aws/internal/service/lex/waiter/status.go @@ -5,37 +5,42 @@ import ( "github.com/aws/aws-sdk-go/service/lexmodelbuildingservice" "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/lex/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) const ( - LexModelBuildingServiceStatusCreated = "Created" - LexModelBuildingServiceStatusNotFound = "NotFound" - LexModelBuildingServiceStatusUnknown = "Unknown" + //Lex Bot Statuses + LexModeBuildingServicesStatusBuilding = "BUILDING" + LexModeBuildingServicesStatusFailed = "FAILED" + LexModeBuildingServicesStatusNotBuilt = "NOT_BUILT" + LexModeBuildingServicesStatusReady = "READY" + LexModeBuildingServicesStatusReadyBasicTesting = "READY_BASIC_TESTING" + + LexModelBuildingServiceStatusCreated = "CREATED" + LexModelBuildingServiceStatusNotFound = "NOTFOUND" + LexModelBuildingServiceStatusUnknown = "UNKNOWN" ) -func LexSlotTypeStatus(conn *lexmodelbuildingservice.LexModelBuildingService, id string) resource.StateRefreshFunc { +func BotVersionStatus(conn *lexmodelbuildingservice.LexModelBuildingService, name, version string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - output, err := conn.GetSlotTypeVersions(&lexmodelbuildingservice.GetSlotTypeVersionsInput{ - Name: aws.String(id), - }) - if tfawserr.ErrCodeEquals(err, lexmodelbuildingservice.ErrCodeNotFoundException) { - return nil, LexModelBuildingServiceStatusNotFound, nil - } - if err != nil { - return nil, LexModelBuildingServiceStatusUnknown, err + output, err := finder.BotVersionByName(conn, name, version) + + if tfresource.NotFound(err) { + return nil, "", nil } - if output == nil || len(output.SlotTypes) == 0 { - return nil, LexModelBuildingServiceStatusNotFound, nil + if err != nil { + return nil, "", err } - return output, LexModelBuildingServiceStatusCreated, nil + return output, aws.StringValue(output.Status), nil } } -func LexIntentStatus(conn *lexmodelbuildingservice.LexModelBuildingService, id string) resource.StateRefreshFunc { +func LexSlotTypeStatus(conn *lexmodelbuildingservice.LexModelBuildingService, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - output, err := conn.GetIntentVersions(&lexmodelbuildingservice.GetIntentVersionsInput{ + output, err := conn.GetSlotTypeVersions(&lexmodelbuildingservice.GetSlotTypeVersionsInput{ Name: aws.String(id), }) if tfawserr.ErrCodeEquals(err, lexmodelbuildingservice.ErrCodeNotFoundException) { @@ -45,7 +50,7 @@ func LexIntentStatus(conn *lexmodelbuildingservice.LexModelBuildingService, id s return nil, LexModelBuildingServiceStatusUnknown, err } - if output == nil || len(output.Intents) == 0 { + if output == nil || len(output.SlotTypes) == 0 { return nil, LexModelBuildingServiceStatusNotFound, nil } @@ -53,9 +58,9 @@ func LexIntentStatus(conn *lexmodelbuildingservice.LexModelBuildingService, id s } } -func LexBotStatus(conn *lexmodelbuildingservice.LexModelBuildingService, id string) resource.StateRefreshFunc { +func LexIntentStatus(conn *lexmodelbuildingservice.LexModelBuildingService, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - output, err := conn.GetBotVersions(&lexmodelbuildingservice.GetBotVersionsInput{ + output, err := conn.GetIntentVersions(&lexmodelbuildingservice.GetIntentVersionsInput{ Name: aws.String(id), }) if tfawserr.ErrCodeEquals(err, lexmodelbuildingservice.ErrCodeNotFoundException) { @@ -65,7 +70,7 @@ func LexBotStatus(conn *lexmodelbuildingservice.LexModelBuildingService, id stri return nil, LexModelBuildingServiceStatusUnknown, err } - if output == nil || len(output.Bots) == 0 { + if output == nil || len(output.Intents) == 0 { return nil, LexModelBuildingServiceStatusNotFound, nil } @@ -85,7 +90,6 @@ func LexBotAliasStatus(conn *lexmodelbuildingservice.LexModelBuildingService, bo if err != nil { return nil, LexModelBuildingServiceStatusUnknown, err } - if output == nil { return nil, LexModelBuildingServiceStatusNotFound, nil } diff --git a/aws/internal/service/lex/waiter/waiter.go b/aws/internal/service/lex/waiter/waiter.go index 1dedcd644f7..501acbf3f6a 100644 --- a/aws/internal/service/lex/waiter/waiter.go +++ b/aws/internal/service/lex/waiter/waiter.go @@ -1,29 +1,67 @@ package waiter import ( + "errors" "time" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/lexmodelbuildingservice" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + tflex "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/lex" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) const ( - LexBotDeleteTimeout = 5 * time.Minute - LexIntentDeleteTimeout = 5 * time.Minute - LexSlotTypeDeleteTimeout = 5 * time.Minute + LexBotAliasDeletedTimeout = 5 * time.Minute + LexIntentDeletedTimeout = 5 * time.Minute + LexSlotTypeDeletedTimeout = 5 * time.Minute ) -func LexBotDeleted(conn *lexmodelbuildingservice.LexModelBuildingService, botId string) (*lexmodelbuildingservice.GetBotVersionsOutput, error) { +func BotVersionCreated(conn *lexmodelbuildingservice.LexModelBuildingService, name, version string, timeout time.Duration) (*lexmodelbuildingservice.GetBotOutput, error) { stateChangeConf := &resource.StateChangeConf{ - Pending: []string{LexModelBuildingServiceStatusCreated}, - Target: []string{}, // An empty slice indicates that the resource is gone - Refresh: LexBotStatus(conn, botId), - Timeout: LexBotDeleteTimeout, + Pending: []string{lexmodelbuildingservice.StatusBuilding}, + Target: []string{ + lexmodelbuildingservice.StatusNotBuilt, + lexmodelbuildingservice.StatusReady, + lexmodelbuildingservice.StatusReadyBasicTesting, + }, + Refresh: BotVersionStatus(conn, name, version), + Timeout: timeout, } + outputRaw, err := stateChangeConf.WaitForState() - if v, ok := outputRaw.(*lexmodelbuildingservice.GetBotVersionsOutput); ok { - return v, err + if output, ok := outputRaw.(*lexmodelbuildingservice.GetBotOutput); ok { + if status := aws.StringValue(output.Status); status == lexmodelbuildingservice.StatusFailed { + tfresource.SetLastError(err, errors.New(aws.StringValue(output.FailureReason))) + } + + return output, err + } + + return nil, err +} + +func BotDeleted(conn *lexmodelbuildingservice.LexModelBuildingService, name string, timeout time.Duration) (*lexmodelbuildingservice.GetBotOutput, error) { + stateChangeConf := &resource.StateChangeConf{ + Pending: []string{ + lexmodelbuildingservice.StatusNotBuilt, + lexmodelbuildingservice.StatusReady, + lexmodelbuildingservice.StatusReadyBasicTesting, + }, + Target: []string{}, + Refresh: BotVersionStatus(conn, name, tflex.LexBotVersionLatest), + Timeout: timeout, + } + + outputRaw, err := stateChangeConf.WaitForState() + + if output, ok := outputRaw.(*lexmodelbuildingservice.GetBotOutput); ok { + if status := aws.StringValue(output.Status); status == lexmodelbuildingservice.StatusFailed { + tfresource.SetLastError(err, errors.New(aws.StringValue(output.FailureReason))) + } + + return output, err } return nil, err @@ -34,7 +72,7 @@ func LexBotAliasDeleted(conn *lexmodelbuildingservice.LexModelBuildingService, b Pending: []string{LexModelBuildingServiceStatusCreated}, Target: []string{}, // An empty slice indicates that the resource is gone Refresh: LexBotAliasStatus(conn, botAliasName, botName), - Timeout: LexBotDeleteTimeout, + Timeout: LexBotAliasDeletedTimeout, } outputRaw, err := stateChangeConf.WaitForState() @@ -50,7 +88,7 @@ func LexIntentDeleted(conn *lexmodelbuildingservice.LexModelBuildingService, int Pending: []string{LexModelBuildingServiceStatusCreated}, Target: []string{}, // An empty slice indicates that the resource is gone Refresh: LexIntentStatus(conn, intentId), - Timeout: LexIntentDeleteTimeout, + Timeout: LexIntentDeletedTimeout, } outputRaw, err := stateChangeConf.WaitForState() @@ -66,7 +104,7 @@ func LexSlotTypeDeleted(conn *lexmodelbuildingservice.LexModelBuildingService, s Pending: []string{LexModelBuildingServiceStatusCreated}, Target: []string{}, // An empty slice indicates that the resource is gone Refresh: LexSlotTypeStatus(conn, slotTypeId), - Timeout: LexSlotTypeDeleteTimeout, + Timeout: LexSlotTypeDeletedTimeout, } outputRaw, err := stateChangeConf.WaitForState() diff --git a/aws/resource_aws_lex_bot.go b/aws/resource_aws_lex_bot.go index a9f47d6943b..b541ec2a501 100644 --- a/aws/resource_aws_lex_bot.go +++ b/aws/resource_aws_lex_bot.go @@ -11,20 +11,14 @@ import ( "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/lexmodelbuildingservice" "github.com/hashicorp/aws-sdk-go-base/tfawserr" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + tflex "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/lex" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/lex/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/lex/waiter" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) -const ( - LexBotCreateTimeout = 1 * time.Minute - LexBotUpdateTimeout = 1 * time.Minute - LexBotDeleteTimeout = 5 * time.Minute - LexBotVersionLatest = "$LATEST" -) - func resourceAwsLexBot() *schema.Resource { return &schema.Resource{ Create: resourceAwsLexBotCreate, @@ -43,9 +37,9 @@ func resourceAwsLexBot() *schema.Resource { }, Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(LexBotCreateTimeout), - Update: schema.DefaultTimeout(LexBotUpdateTimeout), - Delete: schema.DefaultTimeout(LexBotDeleteTimeout), + Create: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(5 * time.Minute), + Delete: schema.DefaultTimeout(5 * time.Minute), }, Schema: map[string]*schema.Schema{ @@ -225,8 +219,8 @@ var validateLexBotVersion = validation.All( func resourceAwsLexBotCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).lexmodelconn - name := d.Get("name").(string) + name := d.Get("name").(string) input := &lexmodelbuildingservice.PutBotInput{ AbortStatement: expandLexStatement(d.Get("abort_statement")), ChildDirected: aws.Bool(d.Get("child_directed").(bool)), @@ -254,29 +248,27 @@ func resourceAwsLexBotCreate(d *schema.ResourceData, meta interface{}) error { input.VoiceId = aws.String(v.(string)) } - err := resource.Retry(d.Timeout(schema.TimeoutCreate), func() *resource.RetryError { - output, err := conn.PutBot(input) + var output *lexmodelbuildingservice.PutBotOutput + _, err := tfresource.RetryWhenAwsErrCodeEquals(d.Timeout(schema.TimeoutCreate), func() (interface{}, error) { + var err error - if tfawserr.ErrCodeEquals(err, lexmodelbuildingservice.ErrCodeConflictException) { + if output != nil { input.Checksum = output.Checksum - return resource.RetryableError(fmt.Errorf("%q bot still creating, another operation is pending: %s", d.Id(), err)) - } - if err != nil { - return resource.NonRetryableError(err) } + output, err = conn.PutBot(input) - return nil - }) - - if tfresource.TimedOut(err) { // nosemgrep: helper-schema-TimeoutError-check-doesnt-return-output - _, err = conn.PutBot(input) - } + return output, err + }, lexmodelbuildingservice.ErrCodeConflictException) if err != nil { - return fmt.Errorf("error creating bot %s: %w", name, err) + return fmt.Errorf("error creating Lex Bot (%s): %w", name, err) } - d.SetId(name) + d.SetId(aws.StringValue(output.Name)) + + if _, err := waiter.BotVersionCreated(conn, name, tflex.LexBotVersionLatest, d.Timeout(schema.TimeoutCreate)); err != nil { + return fmt.Errorf("error waiting for Lex Bot (%s) create: %w", d.Id(), err) + } return resourceAwsLexBotRead(d, meta) } @@ -284,17 +276,16 @@ func resourceAwsLexBotCreate(d *schema.ResourceData, meta interface{}) error { func resourceAwsLexBotRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).lexmodelconn - resp, err := conn.GetBot(&lexmodelbuildingservice.GetBotInput{ - Name: aws.String(d.Id()), - VersionOrAlias: aws.String(LexBotVersionLatest), - }) - if isAWSErr(err, lexmodelbuildingservice.ErrCodeNotFoundException, "") { - log.Printf("[WARN] Bot (%s) not found, removing from state", d.Id()) + output, err := finder.BotVersionByName(conn, d.Id(), tflex.LexBotVersionLatest) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] Lex Bot (%s) not found, removing from state", d.Id()) d.SetId("") return nil } + if err != nil { - return fmt.Errorf("error getting intent %s: %w", d.Id(), err) + return fmt.Errorf("error reading Lex Bot (%s): %w", d.Id(), err) } arn := arn.ARN{ @@ -313,40 +304,40 @@ func resourceAwsLexBotRead(d *schema.ResourceData, meta interface{}) error { processBehavior = v.(string) } - d.Set("checksum", resp.Checksum) - d.Set("child_directed", resp.ChildDirected) - d.Set("created_date", resp.CreatedDate.Format(time.RFC3339)) - d.Set("description", resp.Description) - d.Set("detect_sentiment", resp.DetectSentiment) - d.Set("enable_model_improvements", resp.EnableModelImprovements) - d.Set("failure_reason", resp.FailureReason) - d.Set("idle_session_ttl_in_seconds", resp.IdleSessionTTLInSeconds) - d.Set("intent", flattenLexIntents(resp.Intents)) - d.Set("last_updated_date", resp.LastUpdatedDate.Format(time.RFC3339)) - d.Set("locale", resp.Locale) - d.Set("name", resp.Name) - d.Set("nlu_intent_confidence_threshold", resp.NluIntentConfidenceThreshold) + d.Set("checksum", output.Checksum) + d.Set("child_directed", output.ChildDirected) + d.Set("created_date", output.CreatedDate.Format(time.RFC3339)) + d.Set("description", output.Description) + d.Set("detect_sentiment", output.DetectSentiment) + d.Set("enable_model_improvements", output.EnableModelImprovements) + d.Set("failure_reason", output.FailureReason) + d.Set("idle_session_ttl_in_seconds", output.IdleSessionTTLInSeconds) + d.Set("intent", flattenLexIntents(output.Intents)) + d.Set("last_updated_date", output.LastUpdatedDate.Format(time.RFC3339)) + d.Set("locale", output.Locale) + d.Set("name", output.Name) + d.Set("nlu_intent_confidence_threshold", output.NluIntentConfidenceThreshold) d.Set("process_behavior", processBehavior) - d.Set("status", resp.Status) + d.Set("status", output.Status) - if resp.AbortStatement != nil { - d.Set("abort_statement", flattenLexStatement(resp.AbortStatement)) + if output.AbortStatement != nil { + d.Set("abort_statement", flattenLexStatement(output.AbortStatement)) } - if resp.ClarificationPrompt != nil { - d.Set("clarification_prompt", flattenLexPrompt(resp.ClarificationPrompt)) + if output.ClarificationPrompt != nil { + d.Set("clarification_prompt", flattenLexPrompt(output.ClarificationPrompt)) } - version, err := getLatestLexBotVersion(conn, &lexmodelbuildingservice.GetBotVersionsInput{ - Name: aws.String(d.Id()), - }) + version, err := finder.LatestBotVersionByName(conn, d.Id()) + if err != nil { - return fmt.Errorf("error reading Lex Bot (%s) version: %w", d.Id(), err) + return fmt.Errorf("error reading Lex Bot (%s) latest version: %w", d.Id(), err) } + d.Set("version", version) - if resp.VoiceId != nil { - d.Set("voice_id", resp.VoiceId) + if output.VoiceId != nil { + d.Set("voice_id", output.VoiceId) } return nil @@ -382,25 +373,16 @@ func resourceAwsLexBotUpdate(d *schema.ResourceData, meta interface{}) error { input.VoiceId = aws.String(v.(string)) } - err := resource.Retry(d.Timeout(schema.TimeoutUpdate), func() *resource.RetryError { - _, err := conn.PutBot(input) - - if isAWSErr(err, lexmodelbuildingservice.ErrCodeConflictException, "") { - return resource.RetryableError(fmt.Errorf("%q: bot still updating", d.Id())) - } - if err != nil { - return resource.NonRetryableError(err) - } - - return nil - }) + _, err := tfresource.RetryWhenAwsErrCodeEquals(d.Timeout(schema.TimeoutUpdate), func() (interface{}, error) { + return conn.PutBot(input) + }, lexmodelbuildingservice.ErrCodeConflictException) - if tfresource.TimedOut(err) { - _, err = conn.PutBot(input) + if err != nil { + return fmt.Errorf("error updating Lex Bot (%s): %w", d.Id(), err) } - if err != nil { - return fmt.Errorf("error updating bot %s: %w", d.Id(), err) + if _, err = waiter.BotVersionCreated(conn, d.Id(), tflex.LexBotVersionLatest, d.Timeout(schema.TimeoutUpdate)); err != nil { + return fmt.Errorf("error waiting for Lex Bot (%s) update: %w", d.Id(), err) } return resourceAwsLexBotRead(d, meta) @@ -413,62 +395,24 @@ func resourceAwsLexBotDelete(d *schema.ResourceData, meta interface{}) error { Name: aws.String(d.Id()), } - err := resource.Retry(d.Timeout(schema.TimeoutDelete), func() *resource.RetryError { - _, err := conn.DeleteBot(input) - - if isAWSErr(err, lexmodelbuildingservice.ErrCodeConflictException, "") { - return resource.RetryableError(fmt.Errorf("%q: there is a pending operation, bot still deleting", d.Id())) - } - if err != nil { - return resource.NonRetryableError(err) - } + log.Printf("[DEBUG] Deleting Lex Bot: (%s)", d.Id()) + _, err := tfresource.RetryWhenAwsErrCodeEquals(d.Timeout(schema.TimeoutDelete), func() (interface{}, error) { + return conn.DeleteBot(input) + }, lexmodelbuildingservice.ErrCodeConflictException) + if tfawserr.ErrCodeEquals(err, lexmodelbuildingservice.ErrCodeNotFoundException) { return nil - }) - - if tfresource.TimedOut(err) { - _, err = conn.DeleteBot(input) } if err != nil { - return fmt.Errorf("error deleting bot %s: %w", d.Id(), err) + return fmt.Errorf("error deleting Lex Bot (%s): %w", d.Id(), err) } - _, err = waiter.LexBotDeleted(conn, d.Id()) - - return err -} - -func getLatestLexBotVersion(conn *lexmodelbuildingservice.LexModelBuildingService, input *lexmodelbuildingservice.GetBotVersionsInput) (string, error) { - version := LexBotVersionLatest - - for { - page, err := conn.GetBotVersions(input) - if err != nil { - return "", err - } - - // At least 1 version will always be returned. - if len(page.Bots) == 1 { - break - } - - for _, bot := range page.Bots { - if *bot.Version == LexBotVersionLatest { - continue - } - if *bot.Version > version { - version = *bot.Version - } - } - - if page.NextToken == nil { - break - } - input.NextToken = page.NextToken + if _, err = waiter.BotDeleted(conn, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil { + return fmt.Errorf("error waiting for Lex Bot (%s) delete: %w", d.Id(), err) } - return version, nil + return nil } func flattenLexIntents(intents []*lexmodelbuildingservice.Intent) (flattenedIntents []map[string]interface{}) { diff --git a/aws/resource_aws_lex_bot_alias_test.go b/aws/resource_aws_lex_bot_alias_test.go index 0aba580c5cb..d79c74aee84 100644 --- a/aws/resource_aws_lex_bot_alias_test.go +++ b/aws/resource_aws_lex_bot_alias_test.go @@ -13,6 +13,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + tflex "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/lex" ) func init() { @@ -121,7 +122,7 @@ func TestAccAwsLexBotAlias_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "description", "Testing lex bot alias create."), testAccCheckResourceAttrRfc3339(resourceName, "last_updated_date"), resource.TestCheckResourceAttr(resourceName, "bot_name", testBotAliasID), - resource.TestCheckResourceAttr(resourceName, "bot_version", LexBotVersionLatest), + resource.TestCheckResourceAttr(resourceName, "bot_version", tflex.LexBotVersionLatest), resource.TestCheckResourceAttr(resourceName, "name", testBotAliasID), resource.TestCheckResourceAttr(resourceName, "conversation_logs.#", "0"), ), @@ -155,13 +156,14 @@ func testAccAwsLexBotAlias_botVersion(t *testing.T) { ), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAwsLexBotAliasExists(resourceName, &v), - resource.TestCheckResourceAttr(resourceName, "bot_version", LexBotVersionLatest), + resource.TestCheckResourceAttr(resourceName, "bot_version", tflex.LexBotVersionLatest), ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"created_date"}, }, { Config: composeConfig( @@ -175,9 +177,10 @@ func testAccAwsLexBotAlias_botVersion(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"created_date"}, }, }, }) @@ -206,7 +209,7 @@ func TestAccAwsLexBotAlias_conversationLogsText(t *testing.T) { ), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAwsLexBotAliasExists(resourceName, &v), - resource.TestCheckResourceAttr(resourceName, "bot_version", LexBotVersionLatest), + resource.TestCheckResourceAttr(resourceName, "bot_version", tflex.LexBotVersionLatest), resource.TestCheckResourceAttrPair(resourceName, "conversation_logs.0.iam_role_arn", iamRoleResourceName, "arn"), resource.TestCheckResourceAttr(resourceName, "conversation_logs.0.log_settings.#", "1"), resource.TestCheckTypeSetElemNestedAttrs(resourceName, "conversation_logs.0.log_settings.*", map[string]string{ @@ -216,7 +219,7 @@ func TestAccAwsLexBotAlias_conversationLogsText(t *testing.T) { }), resource.TestCheckTypeSetElemAttrPair(resourceName, "conversation_logs.0.log_settings.*.resource_arn", cloudwatchLogGroupResourceName, "arn"), resource.TestMatchTypeSetElemNestedAttrs(resourceName, "conversation_logs.0.log_settings.*", map[string]*regexp.Regexp{ - "resource_prefix": regexp.MustCompile(regexp.QuoteMeta(fmt.Sprintf(`aws/lex/%s/%s/%s/`, testBotID, testBotAliasID, LexBotVersionLatest))), + "resource_prefix": regexp.MustCompile(regexp.QuoteMeta(fmt.Sprintf(`aws/lex/%s/%s/%s/`, testBotID, testBotAliasID, tflex.LexBotVersionLatest))), }), ), }, @@ -253,7 +256,7 @@ func TestAccAwsLexBotAlias_conversationLogsAudio(t *testing.T) { ), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAwsLexBotAliasExists(resourceName, &v), - resource.TestCheckResourceAttr(resourceName, "bot_version", LexBotVersionLatest), + resource.TestCheckResourceAttr(resourceName, "bot_version", tflex.LexBotVersionLatest), resource.TestCheckResourceAttrPair(resourceName, "conversation_logs.0.iam_role_arn", iamRoleResourceName, "arn"), resource.TestCheckResourceAttr(resourceName, "conversation_logs.0.log_settings.#", "1"), resource.TestCheckTypeSetElemNestedAttrs(resourceName, "conversation_logs.0.log_settings.*", map[string]string{ @@ -263,7 +266,7 @@ func TestAccAwsLexBotAlias_conversationLogsAudio(t *testing.T) { resource.TestCheckTypeSetElemAttrPair(resourceName, "conversation_logs.0.log_settings.*.resource_arn", s3BucketResourceName, "arn"), resource.TestCheckTypeSetElemAttrPair(resourceName, "conversation_logs.0.log_settings.*.kms_key_arn", kmsKeyResourceName, "arn"), resource.TestMatchTypeSetElemNestedAttrs(resourceName, "conversation_logs.0.log_settings.*", map[string]*regexp.Regexp{ - "resource_prefix": regexp.MustCompile(regexp.QuoteMeta(fmt.Sprintf(`aws/lex/%s/%s/%s/`, testBotID, testBotAliasID, LexBotVersionLatest))), + "resource_prefix": regexp.MustCompile(regexp.QuoteMeta(fmt.Sprintf(`aws/lex/%s/%s/%s/`, testBotID, testBotAliasID, tflex.LexBotVersionLatest))), }), ), }, @@ -301,7 +304,7 @@ func TestAccAwsLexBotAlias_conversationLogsBoth(t *testing.T) { ), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAwsLexBotAliasExists(resourceName, &v), - resource.TestCheckResourceAttr(resourceName, "bot_version", LexBotVersionLatest), + resource.TestCheckResourceAttr(resourceName, "bot_version", tflex.LexBotVersionLatest), resource.TestCheckResourceAttrPair(resourceName, "conversation_logs.0.iam_role_arn", iamRoleResourceName, "arn"), resource.TestCheckResourceAttr(resourceName, "conversation_logs.0.log_settings.#", "2"), diff --git a/aws/resource_aws_lex_bot_test.go b/aws/resource_aws_lex_bot_test.go index 02f01771914..210accf705d 100644 --- a/aws/resource_aws_lex_bot_test.go +++ b/aws/resource_aws_lex_bot_test.go @@ -7,14 +7,18 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/lexmodelbuildingservice" - "github.com/hashicorp/aws-sdk-go-base/tfawserr" multierror "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + tflex "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/lex" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/lex/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func init() { + RegisterServiceErrorCheckFunc(lexmodelbuildingservice.EndpointsID, testAccErrorCheckSkipLex) + resource.AddTestSweepers("aws_lex_bot", &resource.Sweeper{ Name: "aws_lex_bot", F: testSweepLexBots, @@ -68,6 +72,12 @@ func testSweepLexBots(region string) error { return errs.ErrorOrNil() } +func testAccErrorCheckSkipLex(t *testing.T) resource.ErrorCheckFunc { + return testAccErrorCheckSkipMessagesContaining(t, + "You can't set the enableModelImprovements field to false", + ) +} + func TestAccAwsLexBot_basic(t *testing.T) { var v lexmodelbuildingservice.GetBotOutput rName := "aws_lex_bot.test" @@ -107,7 +117,7 @@ func TestAccAwsLexBot_basic(t *testing.T) { resource.TestCheckResourceAttr(rName, "nlu_intent_confidence_threshold", "0"), resource.TestCheckResourceAttr(rName, "process_behavior", "SAVE"), resource.TestCheckResourceAttr(rName, "status", "NOT_BUILT"), - resource.TestCheckResourceAttr(rName, "version", LexBotVersionLatest), + resource.TestCheckResourceAttr(rName, "version", tflex.LexBotVersionLatest), resource.TestCheckNoResourceAttr(rName, "voice_id"), ), }, @@ -156,27 +166,26 @@ func testAccAwsLexBot_createVersion(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAwsLexBotExists(rName, &v1), testAccCheckAwsLexBotNotExists(testBotID, "1"), - resource.TestCheckResourceAttr(rName, "version", LexBotVersionLatest), + resource.TestCheckResourceAttr(rName, "version", tflex.LexBotVersionLatest), resource.TestCheckResourceAttr(rName, "description", "Bot to order flowers on the behalf of a user"), ), }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, { Config: composeConfig( testAccAwsLexBotConfig_intent(testBotID), testAccAwsLexBotConfig_createVersion(testBotID), ), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAwsLexBotExists(rName, &v2), testAccCheckAwsLexBotExistsWithVersion(rName, "1", &v2), resource.TestCheckResourceAttr(rName, "version", "1"), resource.TestCheckResourceAttr(rName, "description", "Bot to order flowers on the behalf of a user"), ), }, - { - ResourceName: rName, - ImportState: true, - ImportStateVerify: true, - }, }, }) } @@ -727,7 +736,7 @@ func TestAccAwsLexBot_disappears(t *testing.T) { }) } -func testAccCheckAwsLexBotExistsWithVersion(rName, botVersion string, output *lexmodelbuildingservice.GetBotOutput) resource.TestCheckFunc { +func testAccCheckAwsLexBotExistsWithVersion(rName, botVersion string, v *lexmodelbuildingservice.GetBotOutput) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[rName] if !ok { @@ -735,47 +744,42 @@ func testAccCheckAwsLexBotExistsWithVersion(rName, botVersion string, output *le } if rs.Primary.ID == "" { - return fmt.Errorf("No Lex bot ID is set") + return fmt.Errorf("No Lex Bot ID is set") } - var err error conn := testAccProvider.Meta().(*AWSClient).lexmodelconn - output, err = conn.GetBot(&lexmodelbuildingservice.GetBotInput{ - Name: aws.String(rs.Primary.ID), - VersionOrAlias: aws.String(botVersion), - }) - if tfawserr.ErrCodeEquals(err, lexmodelbuildingservice.ErrCodeNotFoundException) { - return fmt.Errorf("error bot %q version %s not found", rs.Primary.ID, botVersion) - } + output, err := finder.BotVersionByName(conn, rs.Primary.ID, botVersion) + if err != nil { - return fmt.Errorf("error getting bot %q version %s: %w", rs.Primary.ID, botVersion, err) + return err } + *v = *output + return nil } } func testAccCheckAwsLexBotExists(rName string, output *lexmodelbuildingservice.GetBotOutput) resource.TestCheckFunc { - return testAccCheckAwsLexBotExistsWithVersion(rName, LexBotVersionLatest, output) + return testAccCheckAwsLexBotExistsWithVersion(rName, tflex.LexBotVersionLatest, output) } func testAccCheckAwsLexBotNotExists(botName, botVersion string) resource.TestCheckFunc { return func(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).lexmodelconn - _, err := conn.GetBot(&lexmodelbuildingservice.GetBotInput{ - Name: aws.String(botName), - VersionOrAlias: aws.String(botVersion), - }) - if tfawserr.ErrCodeEquals(err, lexmodelbuildingservice.ErrCodeNotFoundException) { + _, err := finder.BotVersionByName(conn, botName, botVersion) + + if tfresource.NotFound(err) { return nil } + if err != nil { - return fmt.Errorf("error getting bot %s version %s: %s", botName, botVersion, err) + return err } - return fmt.Errorf("error bot %s version %s exists", botName, botVersion) + return fmt.Errorf("Lex Box %s/%s still exists", botName, botVersion) } } @@ -790,9 +794,7 @@ func testAccCheckAwsLexBotDestroy(s *terraform.State) error { output, err := conn.GetBotVersions(&lexmodelbuildingservice.GetBotVersionsInput{ Name: aws.String(rs.Primary.ID), }) - if tfawserr.ErrCodeEquals(err, lexmodelbuildingservice.ErrCodeNotFoundException) { - continue - } + if err != nil { return err } @@ -801,7 +803,7 @@ func testAccCheckAwsLexBotDestroy(s *terraform.State) error { return nil } - return fmt.Errorf("Lex bot %q still exists", rs.Primary.ID) + return fmt.Errorf("Lex Bot %s still exists", rs.Primary.ID) } return nil diff --git a/aws/resource_aws_lex_intent.go b/aws/resource_aws_lex_intent.go index 1d03bed08ae..e99122a9d60 100644 --- a/aws/resource_aws_lex_intent.go +++ b/aws/resource_aws_lex_intent.go @@ -14,6 +14,8 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + tflex "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/lex" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/lex/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/lex/waiter" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) @@ -22,7 +24,6 @@ const ( LexIntentCreateTimeout = 1 * time.Minute LexIntentUpdateTimeout = 1 * time.Minute LexIntentDeleteTimeout = 5 * time.Minute - LexIntentVersionLatest = "$LATEST" ) func resourceAwsLexIntent() *schema.Resource { @@ -358,7 +359,7 @@ func resourceAwsLexIntentRead(d *schema.ResourceData, meta interface{}) error { resp, err := conn.GetIntent(&lexmodelbuildingservice.GetIntentInput{ Name: aws.String(d.Id()), - Version: aws.String(LexIntentVersionLatest), + Version: aws.String(tflex.LexIntentVersionLatest), }) if isAWSErr(err, lexmodelbuildingservice.ErrCodeNotFoundException, "") { log.Printf("[WARN] Intent (%s) not found, removing from state", d.Id()) @@ -384,12 +385,12 @@ func resourceAwsLexIntentRead(d *schema.ResourceData, meta interface{}) error { d.Set("last_updated_date", resp.LastUpdatedDate.Format(time.RFC3339)) d.Set("name", resp.Name) - version, err := getLatestLexIntentVersion(conn, &lexmodelbuildingservice.GetIntentVersionsInput{ - Name: aws.String(d.Id()), - }) + version, err := finder.LatestIntentVersionByName(conn, d.Id()) + if err != nil { - return fmt.Errorf("error reading version of intent %s: %w", d.Id(), err) + return fmt.Errorf("error reading Lex Intent (%s) latest version: %w", d.Id(), err) } + d.Set("version", version) if resp.ConclusionStatement != nil { @@ -608,38 +609,6 @@ var lexStatementResource = &schema.Resource{ }, } -func getLatestLexIntentVersion(conn *lexmodelbuildingservice.LexModelBuildingService, input *lexmodelbuildingservice.GetIntentVersionsInput) (string, error) { - version := LexIntentVersionLatest - - for { - page, err := conn.GetIntentVersions(input) - if err != nil { - return "", err - } - - // At least 1 version will always be returned. - if len(page.Intents) == 1 { - break - } - - for _, intent := range page.Intents { - if *intent.Version == LexIntentVersionLatest { - continue - } - if *intent.Version > version { - version = *intent.Version - } - } - - if page.NextToken == nil { - break - } - input.NextToken = page.NextToken - } - - return version, nil -} - func flattenLexCodeHook(hook *lexmodelbuildingservice.CodeHook) (flattened []map[string]interface{}) { return []map[string]interface{}{ { diff --git a/aws/resource_aws_lex_intent_test.go b/aws/resource_aws_lex_intent_test.go index dff289e8dae..9028ba5c1ba 100644 --- a/aws/resource_aws_lex_intent_test.go +++ b/aws/resource_aws_lex_intent_test.go @@ -14,6 +14,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + tflex "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/lex" ) func init() { @@ -103,7 +104,7 @@ func TestAccAwsLexIntent_basic(t *testing.T) { resource.TestCheckNoResourceAttr(rName, "rejection_statement"), resource.TestCheckNoResourceAttr(rName, "sample_utterances"), resource.TestCheckNoResourceAttr(rName, "slot"), - resource.TestCheckResourceAttr(rName, "version", LexIntentVersionLatest), + resource.TestCheckResourceAttr(rName, "version", tflex.LexIntentVersionLatest), ), }, { @@ -658,12 +659,14 @@ func TestAccAwsLexIntent_computeVersion(t *testing.T) { Steps: []resource.TestStep{ { Config: composeConfig( - testAccAwsLexIntentConfig_createVersion(testIntentID), + testAccAwsLexBotConfig_intent(testIntentID), testAccAwsLexBotConfig_createVersion(testIntentID), ), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAwsLexIntentExistsWithVersion(intentResourceName, version, &v1), resource.TestCheckResourceAttr(intentResourceName, "version", version), + resource.TestCheckResourceAttr(intentResourceName, "sample_utterances.#", "1"), + resource.TestCheckResourceAttr(intentResourceName, "sample_utterances.0", "I would like to pick up flowers"), testAccCheckAwsLexBotExistsWithVersion(botResourceName, version, &v2), resource.TestCheckResourceAttr(botResourceName, "version", version), resource.TestCheckResourceAttr(botResourceName, "intent.0.intent_version", version), @@ -678,7 +681,7 @@ func TestAccAwsLexIntent_computeVersion(t *testing.T) { testAccCheckAwsLexIntentExistsWithVersion(intentResourceName, updatedVersion, &v1), resource.TestCheckResourceAttr(intentResourceName, "version", updatedVersion), resource.TestCheckResourceAttr(intentResourceName, "sample_utterances.#", "1"), - resource.TestCheckResourceAttr(intentResourceName, "sample_utterances.0", "I would like to pick up flowers"), + resource.TestCheckResourceAttr(intentResourceName, "sample_utterances.0", "I would not like to pick up flowers"), testAccCheckAwsLexBotExistsWithVersion(botResourceName, updatedVersion, &v2), resource.TestCheckResourceAttr(botResourceName, "version", updatedVersion), resource.TestCheckResourceAttr(botResourceName, "intent.0.intent_version", updatedVersion), @@ -718,7 +721,7 @@ func testAccCheckAwsLexIntentExistsWithVersion(rName, intentVersion string, outp } func testAccCheckAwsLexIntentExists(rName string, output *lexmodelbuildingservice.GetIntentOutput) resource.TestCheckFunc { - return testAccCheckAwsLexIntentExistsWithVersion(rName, LexIntentVersionLatest, output) + return testAccCheckAwsLexIntentExistsWithVersion(rName, tflex.LexIntentVersionLatest, output) } func testAccCheckAwsLexIntentNotExists(intentName, intentVersion string) resource.TestCheckFunc { @@ -1161,7 +1164,7 @@ resource "aws_lex_intent" "test" { type = "ReturnIntent" } sample_utterances = [ - "I would like to pick up flowers", + "I would not like to pick up flowers", ] } `, rName) diff --git a/website/docs/r/lex_bot.html.markdown b/website/docs/r/lex_bot.html.markdown index ec65a4d2ac1..c0c66aadd3f 100644 --- a/website/docs/r/lex_bot.html.markdown +++ b/website/docs/r/lex_bot.html.markdown @@ -114,8 +114,8 @@ slot values into the response card. For more information, see The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/blocks/resources/syntax.html#operation-timeouts) for certain actions: -* `create` - (Defaults to 1 mins) Used when creating the bot -* `update` - (Defaults to 1 mins) Used when updating the bot +* `create` - (Defaults to 5 mins) Used when creating the bot +* `update` - (Defaults to 5 mins) Used when updating the bot * `delete` - (Defaults to 5 mins) Used when deleting the bot ## Attributes Reference