Skip to content

Commit

Permalink
Merge pull request #21509 from brenthc/lexslotversion
Browse files Browse the repository at this point in the history
r/aws_lex_slot_type: numeric version comparison for slot type
  • Loading branch information
ewbankkit authored Oct 27, 2021
2 parents 901d606 + 69acec2 commit 83448eb
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 157 deletions.
3 changes: 3 additions & 0 deletions .changelog/21509.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
aws/resource_aws_lex_slot_type: Correctly determine `version` attribute
```
5 changes: 3 additions & 2 deletions internal/service/lexmodelbuilding/enum.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package lexmodelbuilding

const (
BotVersionLatest = "$LATEST"
IntentVersionLatest = "$LATEST"
BotVersionLatest = "$LATEST"
IntentVersionLatest = "$LATEST"
SlotTypeVersionLatest = "$LATEST"
)
67 changes: 67 additions & 0 deletions internal/service/lexmodelbuilding/find.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,32 @@ func FindBotVersionByName(conn *lexmodelbuildingservice.LexModelBuildingService,
return output, nil
}

func FindSlotTypeVersionByName(conn *lexmodelbuildingservice.LexModelBuildingService, name, version string) (*lexmodelbuildingservice.GetSlotTypeOutput, error) {
input := &lexmodelbuildingservice.GetSlotTypeInput{
Name: aws.String(name),
Version: aws.String(version),
}

output, err := conn.GetSlotType(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
}

// FindLatestBotVersionByName 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 FindLatestBotVersionByName(conn *lexmodelbuildingservice.LexModelBuildingService, name string) (string, error) {
Expand Down Expand Up @@ -117,3 +143,44 @@ func FindLatestIntentVersionByName(conn *lexmodelbuildingservice.LexModelBuildin

return strconv.Itoa(latestVersion), nil
}

// FindLatestSlotTypeVersionByName returns the latest published version of a slot or $LATEST if the slot has never been published.
// See https://docs.aws.amazon.com/lex/latest/dg/versioning-aliases.html.
func FindLatestSlotTypeVersionByName(conn *lexmodelbuildingservice.LexModelBuildingService, name string) (string, error) {
input := &lexmodelbuildingservice.GetSlotTypeVersionsInput{
Name: aws.String(name),
}
var latestVersion int

err := conn.GetSlotTypeVersionsPages(input, func(page *lexmodelbuildingservice.GetSlotTypeVersionsOutput, lastPage bool) bool {
if page == nil {
return !lastPage
}

for _, slot := range page.SlotTypes {
version := aws.StringValue(slot.Version)

if version == SlotTypeVersionLatest {
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 SlotTypeVersionLatest, nil
}

return strconv.Itoa(latestVersion), nil
}
136 changes: 38 additions & 98 deletions internal/service/lexmodelbuilding/slot_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ package lexmodelbuilding
import (
"context"
"fmt"
"log"
"regexp"
"time"

"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"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
Expand All @@ -22,7 +22,6 @@ const (
LexSlotTypeCreateTimeout = 1 * time.Minute
LexSlotTypeUpdateTimeout = 1 * time.Minute
LexSlotTypeDeleteTimeout = 5 * time.Minute
SlotTypeVersionLatest = "$LATEST"
)

func ResourceSlotType() *schema.Resource {
Expand Down Expand Up @@ -136,8 +135,8 @@ func hasSlotTypeConfigChanges(d verify.ResourceDiffer) bool {

func resourceSlotTypeCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).LexModelBuildingConn
name := d.Get("name").(string)

name := d.Get("name").(string)
input := &lexmodelbuildingservice.PutSlotTypeInput{
CreateVersion: aws.Bool(d.Get("create_version").(bool)),
Description: aws.String(d.Get("description").(string)),
Expand All @@ -149,26 +148,20 @@ func resourceSlotTypeCreate(d *schema.ResourceData, meta interface{}) error {
input.EnumerationValues = expandLexEnumerationValues(v.(*schema.Set).List())
}

err := resource.Retry(d.Timeout(schema.TimeoutCreate), func() *resource.RetryError {
output, err := conn.PutSlotType(input)
var output *lexmodelbuildingservice.PutSlotTypeOutput
_, 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 slot type still creating, another operation is pending: %s", d.Id(), err))
}
if err != nil {
return resource.NonRetryableError(err)
}
output, err = conn.PutSlotType(input)

return nil
})

if tfresource.TimedOut(err) { // nosemgrep: helper-schema-TimeoutError-check-doesnt-return-output
_, err = conn.PutSlotType(input)
}
return output, err
}, lexmodelbuildingservice.ErrCodeConflictException)

if err != nil {
return fmt.Errorf("error creating slot type %s: %w", name, err)
return fmt.Errorf("error creating Lex Slot Type (%s): %w", name, err)
}

d.SetId(name)
Expand All @@ -179,72 +172,40 @@ func resourceSlotTypeCreate(d *schema.ResourceData, meta interface{}) error {
func resourceSlotTypeRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).LexModelBuildingConn

resp, err := conn.GetSlotType(&lexmodelbuildingservice.GetSlotTypeInput{
Name: aws.String(d.Id()),
Version: aws.String(SlotTypeVersionLatest),
})
if tfawserr.ErrCodeEquals(err, lexmodelbuildingservice.ErrCodeNotFoundException) {
output, err := FindSlotTypeVersionByName(conn, d.Id(), SlotTypeVersionLatest)

if !d.IsNewResource() && tfresource.NotFound(err) {
log.Printf("[WARN] Lex Slot Type (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

if err != nil {
return fmt.Errorf("error getting slot type %s: %w", d.Id(), err)
return fmt.Errorf("error reading Lex Slot Type (%s): %w", d.Id(), err)
}

d.Set("checksum", resp.Checksum)
d.Set("created_date", resp.CreatedDate.Format(time.RFC3339))
d.Set("description", resp.Description)
d.Set("last_updated_date", resp.LastUpdatedDate.Format(time.RFC3339))
d.Set("name", resp.Name)
d.Set("value_selection_strategy", resp.ValueSelectionStrategy)
d.Set("checksum", output.Checksum)
d.Set("created_date", output.CreatedDate.Format(time.RFC3339))
d.Set("description", output.Description)
d.Set("last_updated_date", output.LastUpdatedDate.Format(time.RFC3339))
d.Set("name", output.Name)
d.Set("value_selection_strategy", output.ValueSelectionStrategy)

if resp.EnumerationValues != nil {
d.Set("enumeration_value", flattenLexEnumerationValues(resp.EnumerationValues))
if output.EnumerationValues != nil {
d.Set("enumeration_value", flattenLexEnumerationValues(output.EnumerationValues))
}

version, err := getLatestLexSlotTypeVersion(conn, &lexmodelbuildingservice.GetSlotTypeVersionsInput{
Name: aws.String(d.Id()),
})
version, err := FindLatestSlotTypeVersionByName(conn, d.Id())

if err != nil {
return err
return fmt.Errorf("error reading Lex Slot Type (%s) latest version: %w", d.Id(), err)
}

d.Set("version", version)

return nil
}

func getLatestLexSlotTypeVersion(conn *lexmodelbuildingservice.LexModelBuildingService, input *lexmodelbuildingservice.GetSlotTypeVersionsInput) (string, error) {
version := SlotTypeVersionLatest

for {
page, err := conn.GetSlotTypeVersions(input)
if err != nil {
return "", err
}

// At least 1 version will always be returned.
if len(page.SlotTypes) == 1 {
break
}

for _, slotType := range page.SlotTypes {
if *slotType.Version == SlotTypeVersionLatest {
continue
}
if *slotType.Version > version {
version = *slotType.Version
}
}

if page.NextToken == nil {
break
}
input.NextToken = page.NextToken
}

return version, nil
}

func resourceSlotTypeUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).LexModelBuildingConn

Expand All @@ -260,25 +221,12 @@ func resourceSlotTypeUpdate(d *schema.ResourceData, meta interface{}) error {
input.EnumerationValues = expandLexEnumerationValues(v.(*schema.Set).List())
}

err := resource.Retry(d.Timeout(schema.TimeoutUpdate), func() *resource.RetryError {
_, err := conn.PutSlotType(input)

if tfawserr.ErrCodeEquals(err, lexmodelbuildingservice.ErrCodeConflictException) {
return resource.RetryableError(fmt.Errorf("%q: slot type still updating", d.Id()))
}
if err != nil {
return resource.NonRetryableError(err)
}

return nil
})

if tfresource.TimedOut(err) {
_, err = conn.PutSlotType(input)
}
_, err := tfresource.RetryWhenAWSErrCodeEquals(d.Timeout(schema.TimeoutUpdate), func() (interface{}, error) {
return conn.PutSlotType(input)
}, lexmodelbuildingservice.ErrCodeConflictException)

if err != nil {
return fmt.Errorf("error updating slot type %s: %w", d.Id(), err)
return fmt.Errorf("error updating Lex Slot Type (%s): %w", d.Id(), err)
}

return resourceSlotTypeRead(d, meta)
Expand All @@ -291,25 +239,17 @@ func resourceSlotTypeDelete(d *schema.ResourceData, meta interface{}) error {
Name: aws.String(d.Id()),
}

err := resource.Retry(d.Timeout(schema.TimeoutDelete), func() *resource.RetryError {
_, err := conn.DeleteSlotType(input)

if tfawserr.ErrCodeEquals(err, lexmodelbuildingservice.ErrCodeConflictException) {
return resource.RetryableError(fmt.Errorf("%q: there is a pending operation, slot type still deleting", d.Id()))
}
if err != nil {
return resource.NonRetryableError(err)
}
log.Printf("[DEBUG] Deleting Lex Slot Type: (%s)", d.Id())
_, err := tfresource.RetryWhenAWSErrCodeEquals(d.Timeout(schema.TimeoutDelete), func() (interface{}, error) {
return conn.DeleteSlotType(input)
}, lexmodelbuildingservice.ErrCodeConflictException)

if tfawserr.ErrCodeEquals(err, lexmodelbuildingservice.ErrCodeNotFoundException) {
return nil
})

if tfresource.TimedOut(err) {
_, err = conn.DeleteSlotType(input)
}

if err != nil {
return fmt.Errorf("error deleting slot type %s: %w", d.Id(), err)
return fmt.Errorf("error deleting Lex Slot Type (%s): %w", d.Id(), err)
}

_, err = waitLexSlotTypeDeleted(conn, d.Id())
Expand Down
33 changes: 14 additions & 19 deletions internal/service/lexmodelbuilding/slot_type_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import (
"regexp"
"time"

"github.com/aws/aws-sdk-go/aws"
"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"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
Expand Down Expand Up @@ -78,28 +76,25 @@ func DataSourceSlotType() *schema.Resource {
}

func dataSourceSlotTypeRead(d *schema.ResourceData, meta interface{}) error {
slotTypeName := d.Get("name").(string)

conn := meta.(*conns.AWSClient).LexModelBuildingConn

resp, err := conn.GetSlotType(&lexmodelbuildingservice.GetSlotTypeInput{
Name: aws.String(slotTypeName),
Version: aws.String(d.Get("version").(string)),
})
name := d.Get("name").(string)
version := d.Get("version").(string)
output, err := FindSlotTypeVersionByName(conn, name, version)

if err != nil {
return fmt.Errorf("error getting slot type %s: %w", slotTypeName, err)
return fmt.Errorf("error reading Lex Slot Type (%s/%s): %w", name, version, err)
}

d.Set("checksum", resp.Checksum)
d.Set("created_date", resp.CreatedDate.Format(time.RFC3339))
d.Set("description", resp.Description)
d.Set("enumeration_value", flattenLexEnumerationValues(resp.EnumerationValues))
d.Set("last_updated_date", resp.LastUpdatedDate.Format(time.RFC3339))
d.Set("name", resp.Name)
d.Set("value_selection_strategy", resp.ValueSelectionStrategy)
d.Set("version", resp.Version)

d.SetId(slotTypeName)
d.SetId(name)
d.Set("checksum", output.Checksum)
d.Set("created_date", output.CreatedDate.Format(time.RFC3339))
d.Set("description", output.Description)
d.Set("enumeration_value", flattenLexEnumerationValues(output.EnumerationValues))
d.Set("last_updated_date", output.LastUpdatedDate.Format(time.RFC3339))
d.Set("name", output.Name)
d.Set("value_selection_strategy", output.ValueSelectionStrategy)
d.Set("version", output.Version)

return nil
}
Loading

0 comments on commit 83448eb

Please sign in to comment.