diff --git a/.changelog/36897.txt b/.changelog/36897.txt new file mode 100644 index 00000000000..dc26d5adfe0 --- /dev/null +++ b/.changelog/36897.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_sesv2_configuration_set_event_destination: Change `event_destination.matching_event_types` from `TypeList` to `TypeSet` as order is not significant +``` \ No newline at end of file diff --git a/internal/service/sesv2/account_vdm_attributes.go b/internal/service/sesv2/account_vdm_attributes.go index 5d75f2196da..f8123c0852b 100644 --- a/internal/service/sesv2/account_vdm_attributes.go +++ b/internal/service/sesv2/account_vdm_attributes.go @@ -11,7 +11,6 @@ import ( "github.com/aws/aws-sdk-go-v2/service/sesv2" "github.com/aws/aws-sdk-go-v2/service/sesv2/types" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/create" @@ -21,7 +20,7 @@ import ( ) // @SDKResource("aws_sesv2_account_vdm_attributes", name="Account VDM Attributes") -func ResourceAccountVDMAttributes() *schema.Resource { +func resourceAccountVDMAttributes() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceAccountVDMAttributesUpdate, ReadWithoutTimeout: resourceAccountVDMAttributesRead, @@ -73,7 +72,7 @@ func ResourceAccountVDMAttributes() *schema.Resource { } const ( - ResNameAccountVDMAttributes = "Account VDM Attributes" + resNameAccountVDMAttributes = "Account VDM Attributes" ) func resourceAccountVDMAttributesUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { @@ -96,11 +95,11 @@ func resourceAccountVDMAttributesUpdate(ctx context.Context, d *schema.ResourceD out, err := conn.PutAccountVdmAttributes(ctx, in) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, ResNameAccountVDMAttributes, "", err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, resNameAccountVDMAttributes, "", err) } if out == nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, ResNameAccountVDMAttributes, "", errors.New("empty output")) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, resNameAccountVDMAttributes, "", errors.New("empty output")) } if d.IsNewResource() { @@ -114,7 +113,7 @@ func resourceAccountVDMAttributesRead(ctx context.Context, d *schema.ResourceDat var diags diag.Diagnostics conn := meta.(*conns.AWSClient).SESV2Client(ctx) - out, err := FindAccountVDMAttributes(ctx, conn) + out, err := findAccountVDMAttributes(ctx, conn) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] SESV2 AccountVDMAttributes (%s) not found, removing from state", d.Id()) @@ -123,21 +122,19 @@ func resourceAccountVDMAttributesRead(ctx context.Context, d *schema.ResourceDat } if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, ResNameAccountVDMAttributes, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, resNameAccountVDMAttributes, d.Id(), err) } if out.DashboardAttributes != nil { if err := d.Set("dashboard_attributes", []interface{}{flattenDashboardAttributes(out.DashboardAttributes)}); err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, ResNameAccountVDMAttributes, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, resNameAccountVDMAttributes, d.Id(), err) } } - if out.GuardianAttributes != nil { if err := d.Set("guardian_attributes", []interface{}{flattenGuardianAttributes(out.GuardianAttributes)}); err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, ResNameAccountVDMAttributes, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, resNameAccountVDMAttributes, d.Id(), err) } } - d.Set("vdm_enabled", out.VdmEnabled) return diags @@ -147,46 +144,47 @@ func resourceAccountVDMAttributesDelete(ctx context.Context, d *schema.ResourceD var diags diag.Diagnostics conn := meta.(*conns.AWSClient).SESV2Client(ctx) - log.Printf("[INFO] Deleting SESV2 AccountVDMAttributes %s", d.Id()) - + log.Printf("[INFO] Deleting SESV2 AccountVDMAttributes: %s", d.Id()) _, err := conn.PutAccountVdmAttributes(ctx, &sesv2.PutAccountVdmAttributesInput{ VdmAttributes: &types.VdmAttributes{ - VdmEnabled: "DISABLED", + VdmEnabled: types.FeatureStatusDisabled, }, }) if err != nil { - var nfe *types.NotFoundException - if errors.As(err, &nfe) { - return diags - } - - return create.AppendDiagError(diags, names.SESV2, create.ErrActionDeleting, ResNameAccountVDMAttributes, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionDeleting, resNameAccountVDMAttributes, d.Id(), err) } return diags } -func FindAccountVDMAttributes(ctx context.Context, conn *sesv2.Client) (*types.VdmAttributes, error) { - in := &sesv2.GetAccountInput{} - out, err := conn.GetAccount(ctx, in) +func findAccountVDMAttributes(ctx context.Context, conn *sesv2.Client) (*types.VdmAttributes, error) { + output, err := findAccount(ctx, conn) + if err != nil { - var nfe *types.NotFoundException - if errors.As(err, &nfe) { - return nil, &retry.NotFoundError{ - LastError: err, - LastRequest: in, - } - } + return nil, err + } + + if output.VdmAttributes == nil { + return nil, tfresource.NewEmptyResultError(nil) + } + return output.VdmAttributes, nil +} + +func findAccount(ctx context.Context, conn *sesv2.Client) (*sesv2.GetAccountOutput, error) { + input := &sesv2.GetAccountInput{} + output, err := conn.GetAccount(ctx, input) + + if err != nil { return nil, err } - if out == nil || out.VdmAttributes == nil { - return nil, tfresource.NewEmptyResultError(in) + if output == nil { + return nil, tfresource.NewEmptyResultError(input) } - return out.VdmAttributes, nil + return output, nil } func expandDashboardAttributes(tfMap map[string]interface{}) *types.DashboardAttributes { diff --git a/internal/service/sesv2/account_vdm_attributes_test.go b/internal/service/sesv2/account_vdm_attributes_test.go index 3b057a6a6c7..154b1d1d021 100644 --- a/internal/service/sesv2/account_vdm_attributes_test.go +++ b/internal/service/sesv2/account_vdm_attributes_test.go @@ -5,7 +5,6 @@ package sesv2_test import ( "context" - "errors" "fmt" "testing" @@ -14,8 +13,8 @@ import ( "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" - "github.com/hashicorp/terraform-provider-aws/internal/create" tfsesv2 "github.com/hashicorp/terraform-provider-aws/internal/service/sesv2" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -153,16 +152,21 @@ func testAccCheckAccountVDMAttributesDestroy(ctx context.Context) resource.TestC continue } - out, err := tfsesv2.FindAccountVDMAttributes(ctx, conn) + output, err := tfsesv2.FindAccountVDMAttributes(ctx, conn) + + if tfresource.NotFound(err) { + continue + } + if err != nil { return err } - if out.VdmEnabled == types.FeatureStatusDisabled { - return nil + if output.VdmEnabled == types.FeatureStatusDisabled { + continue } - return create.Error(names.SESV2, create.ErrActionCheckingDestroyed, tfsesv2.ResNameAccountVDMAttributes, rs.Primary.ID, errors.New("not destroyed")) + return fmt.Errorf("SESv2 Account VDM Attributes %s still exists", rs.Primary.ID) } return nil diff --git a/internal/service/sesv2/configuration_set.go b/internal/service/sesv2/configuration_set.go index eff1f1c7bea..20ef943f9c1 100644 --- a/internal/service/sesv2/configuration_set.go +++ b/internal/service/sesv2/configuration_set.go @@ -22,6 +22,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/create" "github.com/hashicorp/terraform-provider-aws/internal/enum" + "github.com/hashicorp/terraform-provider-aws/internal/errs" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" @@ -30,7 +31,7 @@ import ( // @SDKResource("aws_sesv2_configuration_set", name="Configuration Set") // @Tags(identifierAttribute="arn") -func ResourceConfigurationSet() *schema.Resource { +func resourceConfigurationSet() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceConfigurationSetCreate, ReadWithoutTimeout: resourceConfigurationSetRead, @@ -180,7 +181,7 @@ func ResourceConfigurationSet() *schema.Resource { } const ( - ResNameConfigurationSet = "Configuration Set" + resNameConfigurationSet = "Configuration Set" ) func resourceConfigurationSetCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { @@ -228,11 +229,11 @@ func resourceConfigurationSetCreate(ctx context.Context, d *schema.ResourceData, out, err := conn.CreateConfigurationSet(ctx, input) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, ResNameConfigurationSet, d.Get("configuration_set_name").(string), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, resNameConfigurationSet, d.Get("configuration_set_name").(string), err) } if out == nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, ResNameConfigurationSet, d.Get("configuration_set_name").(string), errors.New("empty output")) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, resNameConfigurationSet, d.Get("configuration_set_name").(string), errors.New("empty output")) } d.SetId(d.Get("configuration_set_name").(string)) @@ -244,7 +245,7 @@ func resourceConfigurationSetRead(ctx context.Context, d *schema.ResourceData, m var diags diag.Diagnostics conn := meta.(*conns.AWSClient).SESV2Client(ctx) - out, err := FindConfigurationSetByID(ctx, conn, d.Id()) + out, err := findConfigurationSetByID(ctx, conn, d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] SESV2 ConfigurationSet (%s) not found, removing from state", d.Id()) @@ -253,7 +254,7 @@ func resourceConfigurationSetRead(ctx context.Context, d *schema.ResourceData, m } if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, ResNameConfigurationSet, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, resNameConfigurationSet, d.Id(), err) } d.Set(names.AttrARN, configurationSetNameToARN(meta, aws.ToString(out.ConfigurationSetName))) @@ -261,7 +262,7 @@ func resourceConfigurationSetRead(ctx context.Context, d *schema.ResourceData, m if out.DeliveryOptions != nil { if err := d.Set("delivery_options", []interface{}{flattenDeliveryOptions(out.DeliveryOptions)}); err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, ResNameConfigurationSet, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, resNameConfigurationSet, d.Id(), err) } } else { d.Set("delivery_options", nil) @@ -269,7 +270,7 @@ func resourceConfigurationSetRead(ctx context.Context, d *schema.ResourceData, m if out.ReputationOptions != nil { if err := d.Set("reputation_options", []interface{}{flattenReputationOptions(out.ReputationOptions)}); err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, ResNameConfigurationSet, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, resNameConfigurationSet, d.Id(), err) } } else { d.Set("reputation_options", nil) @@ -277,7 +278,7 @@ func resourceConfigurationSetRead(ctx context.Context, d *schema.ResourceData, m if out.SendingOptions != nil { if err := d.Set("sending_options", []interface{}{flattenSendingOptions(out.SendingOptions)}); err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, ResNameConfigurationSet, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, resNameConfigurationSet, d.Id(), err) } } else { d.Set("sending_options", nil) @@ -285,7 +286,7 @@ func resourceConfigurationSetRead(ctx context.Context, d *schema.ResourceData, m if out.SuppressionOptions != nil { if err := d.Set("suppression_options", []interface{}{flattenSuppressionOptions(out.SuppressionOptions)}); err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, ResNameConfigurationSet, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, resNameConfigurationSet, d.Id(), err) } } else { d.Set("suppression_options", nil) @@ -293,7 +294,7 @@ func resourceConfigurationSetRead(ctx context.Context, d *schema.ResourceData, m if out.TrackingOptions != nil { if err := d.Set("tracking_options", []interface{}{flattenTrackingOptions(out.TrackingOptions)}); err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, ResNameConfigurationSet, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, resNameConfigurationSet, d.Id(), err) } } else { d.Set("tracking_options", nil) @@ -301,7 +302,7 @@ func resourceConfigurationSetRead(ctx context.Context, d *schema.ResourceData, m if out.VdmOptions != nil { if err := d.Set("vdm_options", []interface{}{flattenVDMOptions(out.VdmOptions)}); err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, ResNameConfigurationSet, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, resNameConfigurationSet, d.Id(), err) } } else { d.Set("vdm_options", nil) @@ -334,7 +335,7 @@ func resourceConfigurationSetUpdate(ctx context.Context, d *schema.ResourceData, log.Printf("[DEBUG] Updating SESV2 ConfigurationSet DeliveryOptions (%s): %#v", d.Id(), in) _, err := conn.PutConfigurationSetDeliveryOptions(ctx, in) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, ResNameConfigurationSet, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, resNameConfigurationSet, d.Id(), err) } } @@ -354,7 +355,7 @@ func resourceConfigurationSetUpdate(ctx context.Context, d *schema.ResourceData, log.Printf("[DEBUG] Updating SESV2 ConfigurationSet ReputationOptions (%s): %#v", d.Id(), in) _, err := conn.PutConfigurationSetReputationOptions(ctx, in) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, ResNameConfigurationSet, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, resNameConfigurationSet, d.Id(), err) } } @@ -373,7 +374,7 @@ func resourceConfigurationSetUpdate(ctx context.Context, d *schema.ResourceData, log.Printf("[DEBUG] Updating SESV2 ConfigurationSet SendingOptions (%s): %#v", d.Id(), in) _, err := conn.PutConfigurationSetSendingOptions(ctx, in) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, ResNameConfigurationSet, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, resNameConfigurationSet, d.Id(), err) } } } @@ -394,7 +395,7 @@ func resourceConfigurationSetUpdate(ctx context.Context, d *schema.ResourceData, log.Printf("[DEBUG] Updating SESV2 ConfigurationSet SuppressionOptions (%s): %#v", d.Id(), in) _, err := conn.PutConfigurationSetSuppressionOptions(ctx, in) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, ResNameConfigurationSet, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, resNameConfigurationSet, d.Id(), err) } } @@ -414,7 +415,7 @@ func resourceConfigurationSetUpdate(ctx context.Context, d *schema.ResourceData, log.Printf("[DEBUG] Updating SESV2 ConfigurationSet TrackingOptions (%s): %#v", d.Id(), in) _, err := conn.PutConfigurationSetTrackingOptions(ctx, in) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, ResNameConfigurationSet, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, resNameConfigurationSet, d.Id(), err) } } @@ -430,7 +431,7 @@ func resourceConfigurationSetUpdate(ctx context.Context, d *schema.ResourceData, log.Printf("[DEBUG] Updating SESV2 ConfigurationSet VdmOptions (%s): %#v", d.Id(), in) _, err := conn.PutConfigurationSetVdmOptions(ctx, in) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, ResNameConfigurationSet, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, resNameConfigurationSet, d.Id(), err) } } @@ -441,46 +442,49 @@ func resourceConfigurationSetDelete(ctx context.Context, d *schema.ResourceData, var diags diag.Diagnostics conn := meta.(*conns.AWSClient).SESV2Client(ctx) - log.Printf("[INFO] Deleting SESV2 ConfigurationSet %s", d.Id()) - + log.Printf("[INFO] Deleting SESV2 ConfigurationSet: %s", d.Id()) _, err := conn.DeleteConfigurationSet(ctx, &sesv2.DeleteConfigurationSetInput{ ConfigurationSetName: aws.String(d.Id()), }) - if err != nil { - var nfe *types.NotFoundException - if errors.As(err, &nfe) { - return diags - } + if errs.IsA[*types.NotFoundException](err) { + return diags + } - return create.AppendDiagError(diags, names.SESV2, create.ErrActionDeleting, ResNameConfigurationSet, d.Id(), err) + if err != nil { + return create.AppendDiagError(diags, names.SESV2, create.ErrActionDeleting, resNameConfigurationSet, d.Id(), err) } return diags } -func FindConfigurationSetByID(ctx context.Context, conn *sesv2.Client, id string) (*sesv2.GetConfigurationSetOutput, error) { - in := &sesv2.GetConfigurationSetInput{ +func findConfigurationSetByID(ctx context.Context, conn *sesv2.Client, id string) (*sesv2.GetConfigurationSetOutput, error) { + input := &sesv2.GetConfigurationSetInput{ ConfigurationSetName: aws.String(id), } - out, err := conn.GetConfigurationSet(ctx, in) - if err != nil { - var nfe *types.NotFoundException - if errors.As(err, &nfe) { - return nil, &retry.NotFoundError{ - LastError: err, - LastRequest: in, - } + + return findConfigurationSet(ctx, conn, input) +} + +func findConfigurationSet(ctx context.Context, conn *sesv2.Client, input *sesv2.GetConfigurationSetInput) (*sesv2.GetConfigurationSetOutput, error) { + output, err := conn.GetConfigurationSet(ctx, input) + + if errs.IsA[*types.NotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, } + } + if err != nil { return nil, err } - if out == nil { - return nil, tfresource.NewEmptyResultError(in) + if output == nil { + return nil, tfresource.NewEmptyResultError(input) } - return out, nil + return output, nil } func flattenDeliveryOptions(apiObject *types.DeliveryOptions) map[string]interface{} { diff --git a/internal/service/sesv2/configuration_set_data_source.go b/internal/service/sesv2/configuration_set_data_source.go index 13dd3537bd6..a8e67b3ba5d 100644 --- a/internal/service/sesv2/configuration_set_data_source.go +++ b/internal/service/sesv2/configuration_set_data_source.go @@ -16,8 +16,8 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -// @SDKDataSource("aws_sesv2_configuration_set") -func DataSourceConfigurationSet() *schema.Resource { +// @SDKDataSource("aws_sesv2_configuration_set", name="Configuration Set") +func dataSourceConfigurationSet() *schema.Resource { return &schema.Resource{ ReadWithoutTimeout: dataSourceConfigurationSetRead, @@ -140,7 +140,7 @@ func DataSourceConfigurationSet() *schema.Resource { } const ( - DSNameConfigurationSet = "Configuration Set Data Source" + dsNameConfigurationSet = "Configuration Set Data Source" ) func dataSourceConfigurationSetRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { @@ -149,9 +149,9 @@ func dataSourceConfigurationSetRead(ctx context.Context, d *schema.ResourceData, name := d.Get("configuration_set_name").(string) - out, err := FindConfigurationSetByID(ctx, conn, name) + out, err := findConfigurationSetByID(ctx, conn, name) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, DSNameConfigurationSet, name, err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, dsNameConfigurationSet, name, err) } d.SetId(aws.ToString(out.ConfigurationSetName)) @@ -161,7 +161,7 @@ func dataSourceConfigurationSetRead(ctx context.Context, d *schema.ResourceData, if out.DeliveryOptions != nil { if err := d.Set("delivery_options", []interface{}{flattenDeliveryOptions(out.DeliveryOptions)}); err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, DSNameConfigurationSet, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, dsNameConfigurationSet, d.Id(), err) } } else { d.Set("delivery_options", nil) @@ -169,7 +169,7 @@ func dataSourceConfigurationSetRead(ctx context.Context, d *schema.ResourceData, if out.ReputationOptions != nil { if err := d.Set("reputation_options", []interface{}{flattenReputationOptions(out.ReputationOptions)}); err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, DSNameConfigurationSet, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, dsNameConfigurationSet, d.Id(), err) } } else { d.Set("reputation_options", nil) @@ -177,7 +177,7 @@ func dataSourceConfigurationSetRead(ctx context.Context, d *schema.ResourceData, if out.SendingOptions != nil { if err := d.Set("sending_options", []interface{}{flattenSendingOptions(out.SendingOptions)}); err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, DSNameConfigurationSet, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, dsNameConfigurationSet, d.Id(), err) } } else { d.Set("sending_options", nil) @@ -185,7 +185,7 @@ func dataSourceConfigurationSetRead(ctx context.Context, d *schema.ResourceData, if out.SuppressionOptions != nil { if err := d.Set("suppression_options", []interface{}{flattenSuppressionOptions(out.SuppressionOptions)}); err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, DSNameConfigurationSet, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, dsNameConfigurationSet, d.Id(), err) } } else { d.Set("suppression_options", nil) @@ -193,7 +193,7 @@ func dataSourceConfigurationSetRead(ctx context.Context, d *schema.ResourceData, if out.TrackingOptions != nil { if err := d.Set("tracking_options", []interface{}{flattenTrackingOptions(out.TrackingOptions)}); err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, DSNameConfigurationSet, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, dsNameConfigurationSet, d.Id(), err) } } else { d.Set("tracking_options", nil) @@ -201,7 +201,7 @@ func dataSourceConfigurationSetRead(ctx context.Context, d *schema.ResourceData, if out.VdmOptions != nil { if err := d.Set("vdm_options", []interface{}{flattenVDMOptions(out.VdmOptions)}); err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, DSNameConfigurationSet, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, dsNameConfigurationSet, d.Id(), err) } } else { d.Set("vdm_options", nil) @@ -209,13 +209,13 @@ func dataSourceConfigurationSetRead(ctx context.Context, d *schema.ResourceData, tags, err := listTags(ctx, conn, d.Get(names.AttrARN).(string)) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, DSNameConfigurationSet, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, dsNameConfigurationSet, d.Id(), err) } ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig if err := d.Set(names.AttrTags, tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, DSNameConfigurationSet, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, dsNameConfigurationSet, d.Id(), err) } return diags diff --git a/internal/service/sesv2/configuration_set_event_destination.go b/internal/service/sesv2/configuration_set_event_destination.go index 33e42da5fc2..a6ef5c5d0a2 100644 --- a/internal/service/sesv2/configuration_set_event_destination.go +++ b/internal/service/sesv2/configuration_set_event_destination.go @@ -20,14 +20,17 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/create" "github.com/hashicorp/terraform-provider-aws/internal/enum" + "github.com/hashicorp/terraform-provider-aws/internal/errs" + "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/flex" + tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" ) -// @SDKResource("aws_sesv2_configuration_set_event_destination") -func ResourceConfigurationSetEventDestination() *schema.Resource { +// @SDKResource("aws_sesv2_configuration_set_event_destination", name="Configuration Set Event Destination") +func resourceConfigurationSetEventDestination() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceConfigurationSetEventDestinationCreate, ReadWithoutTimeout: resourceConfigurationSetEventDestinationRead, @@ -141,7 +144,7 @@ func ResourceConfigurationSetEventDestination() *schema.Resource { }, }, "matching_event_types": { - Type: schema.TypeList, + Type: schema.TypeSet, Required: true, Elem: &schema.Schema{ Type: schema.TypeString, @@ -203,7 +206,7 @@ func ResourceConfigurationSetEventDestination() *schema.Resource { } const ( - ResNameConfigurationSetEventDestination = "Configuration Set Event Destination" + resNameConfigurationSetEventDestination = "Configuration Set Event Destination" ) func resourceConfigurationSetEventDestinationCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { @@ -212,19 +215,19 @@ func resourceConfigurationSetEventDestinationCreate(ctx context.Context, d *sche in := &sesv2.CreateConfigurationSetEventDestinationInput{ ConfigurationSetName: aws.String(d.Get("configuration_set_name").(string)), - EventDestination: expandEventDestination(d.Get("event_destination").([]interface{})[0].(map[string]interface{})), + EventDestination: expandEventDestinationDefinition(d.Get("event_destination").([]interface{})[0].(map[string]interface{})), EventDestinationName: aws.String(d.Get("event_destination_name").(string)), } - configurationSetEventDestinationID := FormatConfigurationSetEventDestinationID(d.Get("configuration_set_name").(string), d.Get("event_destination_name").(string)) + configurationSetEventDestinationID := configurationSetEventDestinationCreateResourceID(d.Get("configuration_set_name").(string), d.Get("event_destination_name").(string)) out, err := conn.CreateConfigurationSetEventDestination(ctx, in) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, ResNameConfigurationSetEventDestination, configurationSetEventDestinationID, err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, resNameConfigurationSetEventDestination, configurationSetEventDestinationID, err) } if out == nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, ResNameConfigurationSetEventDestination, configurationSetEventDestinationID, errors.New("empty output")) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, resNameConfigurationSetEventDestination, configurationSetEventDestinationID, errors.New("empty output")) } d.SetId(configurationSetEventDestinationID) @@ -236,12 +239,12 @@ func resourceConfigurationSetEventDestinationRead(ctx context.Context, d *schema var diags diag.Diagnostics conn := meta.(*conns.AWSClient).SESV2Client(ctx) - configurationSetName, _, err := ParseConfigurationSetEventDestinationID(d.Id()) + configurationSetName, eventDestinationName, err := configurationSetEventDestinationParseResourceID(d.Id()) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, ResNameConfigurationSetEventDestination, d.Id(), err) + return sdkdiag.AppendFromErr(diags, err) } - out, err := FindConfigurationSetEventDestinationByID(ctx, conn, d.Id()) + out, err := findConfigurationSetEventDestinationByTwoPartKey(ctx, conn, configurationSetName, eventDestinationName) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] SESV2 ConfigurationSetEventDestination (%s) not found, removing from state", d.Id()) @@ -250,15 +253,14 @@ func resourceConfigurationSetEventDestinationRead(ctx context.Context, d *schema } if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, ResNameConfigurationSetEventDestination, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, resNameConfigurationSetEventDestination, d.Id(), err) } d.Set("configuration_set_name", configurationSetName) - d.Set("event_destination_name", out.Name) - if err := d.Set("event_destination", []interface{}{flattenEventDestination(out)}); err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, ResNameConfigurationSetEventDestination, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, resNameConfigurationSetEventDestination, d.Id(), err) } + d.Set("event_destination_name", out.Name) return diags } @@ -267,22 +269,22 @@ func resourceConfigurationSetEventDestinationUpdate(ctx context.Context, d *sche var diags diag.Diagnostics conn := meta.(*conns.AWSClient).SESV2Client(ctx) - configurationSetName, eventDestinationName, err := ParseConfigurationSetEventDestinationID(d.Id()) + configurationSetName, eventDestinationName, err := configurationSetEventDestinationParseResourceID(d.Id()) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, ResNameConfigurationSetEventDestination, d.Id(), err) + return sdkdiag.AppendFromErr(diags, err) } if d.HasChanges("event_destination") { in := &sesv2.UpdateConfigurationSetEventDestinationInput{ ConfigurationSetName: aws.String(configurationSetName), - EventDestination: expandEventDestination(d.Get("event_destination").([]interface{})[0].(map[string]interface{})), + EventDestination: expandEventDestinationDefinition(d.Get("event_destination").([]interface{})[0].(map[string]interface{})), EventDestinationName: aws.String(eventDestinationName), } log.Printf("[DEBUG] Updating SESV2 ConfigurationSetEventDestination (%s): %#v", d.Id(), in) _, err := conn.UpdateConfigurationSetEventDestination(ctx, in) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, ResNameConfigurationSetEventDestination, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, resNameConfigurationSetEventDestination, d.Id(), err) } } @@ -293,95 +295,122 @@ func resourceConfigurationSetEventDestinationDelete(ctx context.Context, d *sche var diags diag.Diagnostics conn := meta.(*conns.AWSClient).SESV2Client(ctx) - log.Printf("[INFO] Deleting SESV2 ConfigurationSetEventDestination %s", d.Id()) - - configurationSetName, eventDestinationName, err := ParseConfigurationSetEventDestinationID(d.Id()) + configurationSetName, eventDestinationName, err := configurationSetEventDestinationParseResourceID(d.Id()) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, ResNameConfigurationSetEventDestination, d.Id(), err) + return sdkdiag.AppendFromErr(diags, err) } + log.Printf("[INFO] Deleting SESV2 ConfigurationSetEventDestination: %s", d.Id()) _, err = conn.DeleteConfigurationSetEventDestination(ctx, &sesv2.DeleteConfigurationSetEventDestinationInput{ ConfigurationSetName: aws.String(configurationSetName), EventDestinationName: aws.String(eventDestinationName), }) - if err != nil { - var nfe *types.NotFoundException - if errors.As(err, &nfe) { - return diags - } + if errs.IsA[*types.NotFoundException](err) { + return diags + } - return create.AppendDiagError(diags, names.SESV2, create.ErrActionDeleting, ResNameConfigurationSetEventDestination, d.Id(), err) + if err != nil { + return create.AppendDiagError(diags, names.SESV2, create.ErrActionDeleting, resNameConfigurationSetEventDestination, d.Id(), err) } return diags } -func FindConfigurationSetEventDestinationByID(ctx context.Context, conn *sesv2.Client, id string) (types.EventDestination, error) { - configurationSetName, eventDestinationName, err := ParseConfigurationSetEventDestinationID(id) - if err != nil { - return types.EventDestination{}, err +const configurationSetEventDestinationResourceIDSeparator = "|" + +func configurationSetEventDestinationCreateResourceID(configurationSetName, eventDestinationName string) string { + parts := []string{configurationSetName, eventDestinationName} + id := strings.Join(parts, configurationSetEventDestinationResourceIDSeparator) + + return id +} + +func configurationSetEventDestinationParseResourceID(id string) (string, string, error) { + parts := strings.Split(id, configurationSetEventDestinationResourceIDSeparator) + + if len(parts) != 2 || parts[0] == "" || parts[1] == "" { + return "", "", fmt.Errorf("unexpected format of ID (%[1]s), expected CONFIGURATION_SET_NAME%[2]sEVENT_DESTINATION_NAME", id, configurationSetEventDestinationResourceIDSeparator) } - in := &sesv2.GetConfigurationSetEventDestinationsInput{ + return parts[0], parts[1], nil +} + +func findConfigurationSetEventDestinationByTwoPartKey(ctx context.Context, conn *sesv2.Client, configurationSetName, eventDestinationName string) (*types.EventDestination, error) { + input := &sesv2.GetConfigurationSetEventDestinationsInput{ ConfigurationSetName: aws.String(configurationSetName), } - out, err := conn.GetConfigurationSetEventDestinations(ctx, in) + + return findConfigurationSetEventDestination(ctx, conn, input, func(v *types.EventDestination) bool { + return aws.ToString(v.Name) == eventDestinationName + }) +} + +func findConfigurationSetEventDestination(ctx context.Context, conn *sesv2.Client, input *sesv2.GetConfigurationSetEventDestinationsInput, filter tfslices.Predicate[*types.EventDestination]) (*types.EventDestination, error) { + output, err := findConfigurationSetEventDestinations(ctx, conn, input, filter) + if err != nil { - var nfe *types.NotFoundException - if errors.As(err, &nfe) { - return types.EventDestination{}, &retry.NotFoundError{ - LastError: err, - LastRequest: in, - } - } + return nil, err + } + + return tfresource.AssertSingleValueResult(output) +} + +func findConfigurationSetEventDestinations(ctx context.Context, conn *sesv2.Client, input *sesv2.GetConfigurationSetEventDestinationsInput, filter tfslices.Predicate[*types.EventDestination]) ([]types.EventDestination, error) { + output, err := conn.GetConfigurationSetEventDestinations(ctx, input) - return types.EventDestination{}, err + if errs.IsA[*types.NotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, + } } - if out == nil { - return types.EventDestination{}, tfresource.NewEmptyResultError(in) + if err != nil { + return nil, err } - for _, eventDestination := range out.EventDestinations { - if aws.ToString(eventDestination.Name) == eventDestinationName { - return eventDestination, nil - } + if output == nil { + return nil, tfresource.NewEmptyResultError(input) } - return types.EventDestination{}, &retry.NotFoundError{} + return tfslices.Filter(output.EventDestinations, tfslices.PredicateValue(filter)), nil } -func flattenEventDestination(apiObject types.EventDestination) map[string]interface{} { - m := map[string]interface{}{ +func flattenEventDestination(apiObject *types.EventDestination) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{ names.AttrEnabled: apiObject.Enabled, } if v := apiObject.CloudWatchDestination; v != nil { - m["cloud_watch_destination"] = []interface{}{flattenCloudWatchDestination(v)} + tfMap["cloud_watch_destination"] = []interface{}{flattenCloudWatchDestination(v)} } if v := apiObject.EventBridgeDestination; v != nil { - m["event_bridge_destination"] = []interface{}{flattenEventBridgeDestination(v)} + tfMap["event_bridge_destination"] = []interface{}{flattenEventBridgeDestination(v)} } if v := apiObject.KinesisFirehoseDestination; v != nil { - m["kinesis_firehose_destination"] = []interface{}{flattenKinesisFirehoseDestination(v)} + tfMap["kinesis_firehose_destination"] = []interface{}{flattenKinesisFirehoseDestination(v)} } if v := apiObject.MatchingEventTypes; v != nil { - m["matching_event_types"] = enum.Slice(apiObject.MatchingEventTypes...) + tfMap["matching_event_types"] = enum.Slice(apiObject.MatchingEventTypes...) } if v := apiObject.PinpointDestination; v != nil { - m["pinpoint_destination"] = []interface{}{flattenPinpointDestination(v)} + tfMap["pinpoint_destination"] = []interface{}{flattenPinpointDestination(v)} } if v := apiObject.SnsDestination; v != nil { - m["sns_destination"] = []interface{}{flattenSNSDestination(v)} + tfMap["sns_destination"] = []interface{}{flattenSNSDestination(v)} } - return m + return tfMap } func flattenCloudWatchDestination(apiObject *types.CloudWatchDestination) map[string]interface{} { @@ -389,13 +418,13 @@ func flattenCloudWatchDestination(apiObject *types.CloudWatchDestination) map[st return nil } - m := map[string]interface{}{} + tfMap := map[string]interface{}{} if v := apiObject.DimensionConfigurations; v != nil { - m["dimension_configuration"] = flattenCloudWatchDimensionConfigurations(v) + tfMap["dimension_configuration"] = flattenCloudWatchDimensionConfigurations(v) } - return m + return tfMap } func flattenEventBridgeDestination(apiObject *types.EventBridgeDestination) map[string]interface{} { @@ -403,13 +432,13 @@ func flattenEventBridgeDestination(apiObject *types.EventBridgeDestination) map[ return nil } - m := map[string]interface{}{} + tfMap := map[string]interface{}{} if v := apiObject.EventBusArn; v != nil { - m["event_bus_arn"] = aws.ToString(v) + tfMap["event_bus_arn"] = aws.ToString(v) } - return m + return tfMap } func flattenKinesisFirehoseDestination(apiObject *types.KinesisFirehoseDestination) map[string]interface{} { @@ -417,17 +446,17 @@ func flattenKinesisFirehoseDestination(apiObject *types.KinesisFirehoseDestinati return nil } - m := map[string]interface{}{} + tfMap := map[string]interface{}{} if v := apiObject.DeliveryStreamArn; v != nil { - m["delivery_stream_arn"] = aws.ToString(v) + tfMap["delivery_stream_arn"] = aws.ToString(v) } if v := apiObject.IamRoleArn; v != nil { - m[names.AttrIAMRoleARN] = aws.ToString(v) + tfMap[names.AttrIAMRoleARN] = aws.ToString(v) } - return m + return tfMap } func flattenPinpointDestination(apiObject *types.PinpointDestination) map[string]interface{} { @@ -435,13 +464,13 @@ func flattenPinpointDestination(apiObject *types.PinpointDestination) map[string return nil } - m := map[string]interface{}{} + tfMap := map[string]interface{}{} if v := apiObject.ApplicationArn; v != nil { - m["application_arn"] = aws.ToString(v) + tfMap["application_arn"] = aws.ToString(v) } - return m + return tfMap } func flattenSNSDestination(apiObject *types.SnsDestination) map[string]interface{} { @@ -449,13 +478,13 @@ func flattenSNSDestination(apiObject *types.SnsDestination) map[string]interface return nil } - m := map[string]interface{}{} + tfMap := map[string]interface{}{} if v := apiObject.TopicArn; v != nil { - m[names.AttrTopicARN] = aws.ToString(v) + tfMap[names.AttrTopicARN] = aws.ToString(v) } - return m + return tfMap } func flattenCloudWatchDimensionConfigurations(apiObjects []types.CloudWatchDimensionConfiguration) []interface{} { @@ -463,67 +492,71 @@ func flattenCloudWatchDimensionConfigurations(apiObjects []types.CloudWatchDimen return nil } - var l []interface{} + var tfList []interface{} for _, apiObject := range apiObjects { - l = append(l, flattenCloudWatchDimensionConfiguration(apiObject)) + tfList = append(tfList, flattenCloudWatchDimensionConfiguration(&apiObject)) } - return l + return tfList } -func flattenCloudWatchDimensionConfiguration(apiObject types.CloudWatchDimensionConfiguration) map[string]interface{} { - m := map[string]interface{}{ +func flattenCloudWatchDimensionConfiguration(apiObject *types.CloudWatchDimensionConfiguration) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{ "dimension_value_source": string(apiObject.DimensionValueSource), } if v := apiObject.DefaultDimensionValue; v != nil { - m["default_dimension_value"] = aws.ToString(v) + tfMap["default_dimension_value"] = aws.ToString(v) } if v := apiObject.DimensionName; v != nil { - m["dimension_name"] = aws.ToString(v) + tfMap["dimension_name"] = aws.ToString(v) } - return m + return tfMap } -func expandEventDestination(tfMap map[string]interface{}) *types.EventDestinationDefinition { +func expandEventDestinationDefinition(tfMap map[string]interface{}) *types.EventDestinationDefinition { if tfMap == nil { return nil } - a := &types.EventDestinationDefinition{} + apiObject := &types.EventDestinationDefinition{} if v, ok := tfMap["cloud_watch_destination"].([]interface{}); ok && len(v) > 0 && v[0] != nil { - a.CloudWatchDestination = expandCloudWatchDestination(v[0].(map[string]interface{})) + apiObject.CloudWatchDestination = expandCloudWatchDestination(v[0].(map[string]interface{})) } if v, ok := tfMap[names.AttrEnabled].(bool); ok { - a.Enabled = v + apiObject.Enabled = v } if v, ok := tfMap["event_bridge_destination"].([]interface{}); ok && len(v) > 0 && v[0] != nil { - a.EventBridgeDestination = expandEventBridgeDestinaton(v[0].(map[string]interface{})) + apiObject.EventBridgeDestination = expandEventBridgeDestination(v[0].(map[string]interface{})) } if v, ok := tfMap["kinesis_firehose_destination"].([]interface{}); ok && len(v) > 0 && v[0] != nil { - a.KinesisFirehoseDestination = expandKinesisFirehoseDestination(v[0].(map[string]interface{})) + apiObject.KinesisFirehoseDestination = expandKinesisFirehoseDestination(v[0].(map[string]interface{})) } - if v, ok := tfMap["matching_event_types"].([]interface{}); ok && len(v) > 0 { - a.MatchingEventTypes = stringsToEventTypes(flex.ExpandStringList(v)) + if v, ok := tfMap["matching_event_types"].(*schema.Set); ok && v.Len() > 0 { + apiObject.MatchingEventTypes = flex.ExpandStringyValueSet[types.EventType](v) } if v, ok := tfMap["pinpoint_destination"].([]interface{}); ok && len(v) > 0 && v[0] != nil { - a.PinpointDestination = expandPinpointDestinaton(v[0].(map[string]interface{})) + apiObject.PinpointDestination = expandPinpointDestinaton(v[0].(map[string]interface{})) } if v, ok := tfMap["sns_destination"].([]interface{}); ok && len(v) > 0 && v[0] != nil { - a.SnsDestination = expandSNSDestination(v[0].(map[string]interface{})) + apiObject.SnsDestination = expandSNSDestination(v[0].(map[string]interface{})) } - return a + return apiObject } func expandCloudWatchDestination(tfMap map[string]interface{}) *types.CloudWatchDestination { @@ -531,27 +564,27 @@ func expandCloudWatchDestination(tfMap map[string]interface{}) *types.CloudWatch return nil } - a := &types.CloudWatchDestination{} + apiObject := &types.CloudWatchDestination{} if v, ok := tfMap["dimension_configuration"].([]interface{}); ok && len(v) > 0 { - a.DimensionConfigurations = expandCloudWatchDimensionConfigurations(v) + apiObject.DimensionConfigurations = expandCloudWatchDimensionConfigurations(v) } - return a + return apiObject } -func expandEventBridgeDestinaton(tfMap map[string]interface{}) *types.EventBridgeDestination { +func expandEventBridgeDestination(tfMap map[string]interface{}) *types.EventBridgeDestination { if tfMap == nil { return nil } - a := &types.EventBridgeDestination{} + apiObject := &types.EventBridgeDestination{} if v, ok := tfMap["event_bus_arn"].(string); ok && v != "" { - a.EventBusArn = aws.String(v) + apiObject.EventBusArn = aws.String(v) } - return a + return apiObject } func expandKinesisFirehoseDestination(tfMap map[string]interface{}) *types.KinesisFirehoseDestination { @@ -559,17 +592,17 @@ func expandKinesisFirehoseDestination(tfMap map[string]interface{}) *types.Kines return nil } - a := &types.KinesisFirehoseDestination{} + apiObject := &types.KinesisFirehoseDestination{} if v, ok := tfMap["delivery_stream_arn"].(string); ok && v != "" { - a.DeliveryStreamArn = aws.String(v) + apiObject.DeliveryStreamArn = aws.String(v) } if v, ok := tfMap[names.AttrIAMRoleARN].(string); ok && v != "" { - a.IamRoleArn = aws.String(v) + apiObject.IamRoleArn = aws.String(v) } - return a + return apiObject } func expandPinpointDestinaton(tfMap map[string]interface{}) *types.PinpointDestination { @@ -577,13 +610,13 @@ func expandPinpointDestinaton(tfMap map[string]interface{}) *types.PinpointDesti return nil } - a := &types.PinpointDestination{} + apiObject := &types.PinpointDestination{} if v, ok := tfMap["application_arn"].(string); ok && v != "" { - a.ApplicationArn = aws.String(v) + apiObject.ApplicationArn = aws.String(v) } - return a + return apiObject } func expandSNSDestination(tfMap map[string]interface{}) *types.SnsDestination { @@ -591,13 +624,13 @@ func expandSNSDestination(tfMap map[string]interface{}) *types.SnsDestination { return nil } - a := &types.SnsDestination{} + apiObject := &types.SnsDestination{} if v, ok := tfMap[names.AttrTopicARN].(string); ok && v != "" { - a.TopicArn = aws.String(v) + apiObject.TopicArn = aws.String(v) } - return a + return apiObject } func expandCloudWatchDimensionConfigurations(tfList []interface{}) []types.CloudWatchDimensionConfiguration { @@ -605,58 +638,39 @@ func expandCloudWatchDimensionConfigurations(tfList []interface{}) []types.Cloud return nil } - var s []types.CloudWatchDimensionConfiguration - - for _, r := range tfList { - m, ok := r.(map[string]interface{}) + var apiObjects []types.CloudWatchDimensionConfiguration + for _, tfMapRaw := range tfList { + tfMap, ok := tfMapRaw.(map[string]interface{}) if !ok { continue } - s = append(s, expandCloudWatchDimensionConfiguration(m)) + apiObject := expandCloudWatchDimensionConfiguration(tfMap) + if apiObject == nil { + continue + } + + apiObjects = append(apiObjects, *apiObject) } - return s + return apiObjects } -func expandCloudWatchDimensionConfiguration(tfMap map[string]interface{}) types.CloudWatchDimensionConfiguration { - a := types.CloudWatchDimensionConfiguration{} +func expandCloudWatchDimensionConfiguration(tfMap map[string]interface{}) *types.CloudWatchDimensionConfiguration { + apiObject := &types.CloudWatchDimensionConfiguration{} if v, ok := tfMap["default_dimension_value"].(string); ok && v != "" { - a.DefaultDimensionValue = aws.String(v) + apiObject.DefaultDimensionValue = aws.String(v) } if v, ok := tfMap["dimension_name"].(string); ok && v != "" { - a.DimensionName = aws.String(v) + apiObject.DimensionName = aws.String(v) } if v, ok := tfMap["dimension_value_source"].(string); ok && v != "" { - a.DimensionValueSource = types.DimensionValueSource(v) - } - - return a -} - -func FormatConfigurationSetEventDestinationID(configurationSetName, eventDestinationName string) string { - return fmt.Sprintf("%s|%s", configurationSetName, eventDestinationName) -} - -func ParseConfigurationSetEventDestinationID(id string) (string, string, error) { - idParts := strings.Split(id, "|") - if len(idParts) != 2 { - return "", "", errors.New("please make sure the ID is in the form CONFIGURATION_SET_NAME|EVENT_DESTINATION_NAME") - } - - return idParts[0], idParts[1], nil -} - -func stringsToEventTypes(values []*string) []types.EventType { - var eventTypes []types.EventType - - for _, eventType := range values { - eventTypes = append(eventTypes, types.EventType(aws.ToString(eventType))) + apiObject.DimensionValueSource = types.DimensionValueSource(v) } - return eventTypes + return apiObject } diff --git a/internal/service/sesv2/configuration_set_event_destination_test.go b/internal/service/sesv2/configuration_set_event_destination_test.go index bac4a0a9666..15e4315470f 100644 --- a/internal/service/sesv2/configuration_set_event_destination_test.go +++ b/internal/service/sesv2/configuration_set_event_destination_test.go @@ -5,18 +5,16 @@ package sesv2_test import ( "context" - "errors" "fmt" "testing" - "github.com/aws/aws-sdk-go-v2/service/sesv2/types" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" - "github.com/hashicorp/terraform-provider-aws/internal/create" tfsesv2 "github.com/hashicorp/terraform-provider-aws/internal/service/sesv2" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -285,42 +283,35 @@ func testAccCheckConfigurationSetEventDestinationDestroy(ctx context.Context) re continue } - _, err := tfsesv2.FindConfigurationSetEventDestinationByID(ctx, conn, rs.Primary.ID) + _, err := tfsesv2.FindConfigurationSetEventDestinationByTwoPartKey(ctx, conn, rs.Primary.Attributes["configuration_set_name"], rs.Primary.Attributes["event_destination_name"]) + + if tfresource.NotFound(err) { + continue + } + if err != nil { - var nfe *types.NotFoundException - if errors.As(err, &nfe) { - return nil - } return err } - return create.Error(names.SESV2, create.ErrActionCheckingDestroyed, tfsesv2.ResNameConfigurationSetEventDestination, rs.Primary.ID, errors.New("not destroyed")) + return fmt.Errorf("SESv2 Configuration Set Event Destination %s still exists", rs.Primary.ID) } return nil } } -func testAccCheckConfigurationSetEventDestinationExists(ctx context.Context, name string) resource.TestCheckFunc { +func testAccCheckConfigurationSetEventDestinationExists(ctx context.Context, n string) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[name] + rs, ok := s.RootModule().Resources[n] if !ok { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameConfigurationSetEventDestination, name, errors.New("not found")) - } - - if rs.Primary.ID == "" { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameConfigurationSetEventDestination, name, errors.New("not set")) + return fmt.Errorf("Not found: %s", n) } conn := acctest.Provider.Meta().(*conns.AWSClient).SESV2Client(ctx) - _, err := tfsesv2.FindConfigurationSetEventDestinationByID(ctx, conn, rs.Primary.ID) - - if err != nil { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameConfigurationSetEventDestination, rs.Primary.ID, err) - } + _, err := tfsesv2.FindConfigurationSetEventDestinationByTwoPartKey(ctx, conn, rs.Primary.Attributes["configuration_set_name"], rs.Primary.Attributes["event_destination_name"]) - return nil + return err } } diff --git a/internal/service/sesv2/configuration_set_test.go b/internal/service/sesv2/configuration_set_test.go index 8541faca73f..0ecd9011eba 100644 --- a/internal/service/sesv2/configuration_set_test.go +++ b/internal/service/sesv2/configuration_set_test.go @@ -5,7 +5,6 @@ package sesv2_test import ( "context" - "errors" "fmt" "testing" @@ -16,8 +15,8 @@ import ( "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" - "github.com/hashicorp/terraform-provider-aws/internal/create" tfsesv2 "github.com/hashicorp/terraform-provider-aws/internal/service/sesv2" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -389,41 +388,33 @@ func testAccCheckConfigurationSetDestroy(ctx context.Context) resource.TestCheck _, err := tfsesv2.FindConfigurationSetByID(ctx, conn, rs.Primary.ID) + if tfresource.NotFound(err) { + continue + } + if err != nil { - var nfe *types.NotFoundException - if errors.As(err, &nfe) { - return nil - } return err } - return create.Error(names.SESV2, create.ErrActionCheckingDestroyed, tfsesv2.ResNameConfigurationSet, rs.Primary.ID, errors.New("not destroyed")) + return fmt.Errorf("SESv2 Configuration Set %s still exists", rs.Primary.ID) } return nil } } -func testAccCheckConfigurationSetExists(ctx context.Context, name string) resource.TestCheckFunc { +func testAccCheckConfigurationSetExists(ctx context.Context, n string) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[name] + rs, ok := s.RootModule().Resources[n] if !ok { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameConfigurationSet, name, errors.New("not found")) - } - - if rs.Primary.ID == "" { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameConfigurationSet, name, errors.New("not set")) + return fmt.Errorf("Not found: %s", n) } conn := acctest.Provider.Meta().(*conns.AWSClient).SESV2Client(ctx) _, err := tfsesv2.FindConfigurationSetByID(ctx, conn, rs.Primary.ID) - if err != nil { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameConfigurationSet, rs.Primary.ID, err) - } - - return nil + return err } } diff --git a/internal/service/sesv2/contact_list.go b/internal/service/sesv2/contact_list.go index dd2a09adb14..abae65905b9 100644 --- a/internal/service/sesv2/contact_list.go +++ b/internal/service/sesv2/contact_list.go @@ -20,6 +20,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/create" "github.com/hashicorp/terraform-provider-aws/internal/enum" + "github.com/hashicorp/terraform-provider-aws/internal/errs" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" @@ -28,7 +29,7 @@ import ( // @SDKResource("aws_sesv2_contact_list", name="Contact List") // @Tags(identifierAttribute="arn") -func ResourceContactList() *schema.Resource { +func resourceContactList() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceContactListCreate, ReadWithoutTimeout: resourceContactListRead, @@ -95,7 +96,7 @@ func ResourceContactList() *schema.Resource { } const ( - ResNameContactList = "Contact List" + resNameContactList = "Contact List" ) func resourceContactListCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { @@ -117,11 +118,11 @@ func resourceContactListCreate(ctx context.Context, d *schema.ResourceData, meta out, err := conn.CreateContactList(ctx, in) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, ResNameContactList, d.Get("contact_list_name").(string), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, resNameContactList, d.Get("contact_list_name").(string), err) } if out == nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, ResNameContactList, d.Get("contact_list_name").(string), errors.New("empty output")) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, resNameContactList, d.Get("contact_list_name").(string), errors.New("empty output")) } d.SetId(d.Get("contact_list_name").(string)) @@ -133,7 +134,7 @@ func resourceContactListRead(ctx context.Context, d *schema.ResourceData, meta i var diags diag.Diagnostics conn := meta.(*conns.AWSClient).SESV2Client(ctx) - out, err := FindContactListByID(ctx, conn, d.Id()) + out, err := findContactListByID(ctx, conn, d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] SESV2 ContactList (%s) not found, removing from state", d.Id()) @@ -142,7 +143,7 @@ func resourceContactListRead(ctx context.Context, d *schema.ResourceData, meta i } if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, ResNameContactList, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, resNameContactList, d.Id(), err) } arn := arn.ARN{ @@ -160,7 +161,7 @@ func resourceContactListRead(ctx context.Context, d *schema.ResourceData, meta i d.Set("last_updated_timestamp", aws.ToTime(out.LastUpdatedTimestamp).Format(time.RFC3339)) if err := d.Set("topic", flattenTopics(out.Topics)); err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, ResNameContactList, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, resNameContactList, d.Id(), err) } return diags @@ -180,7 +181,7 @@ func resourceContactListUpdate(ctx context.Context, d *schema.ResourceData, meta log.Printf("[DEBUG] Updating SESV2 ContactList (%s): %#v", d.Id(), in) if _, err := conn.UpdateContactList(ctx, in); err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, ResNameContactList, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, resNameContactList, d.Id(), err) } } @@ -197,40 +198,44 @@ func resourceContactListDelete(ctx context.Context, d *schema.ResourceData, meta ContactListName: aws.String(d.Id()), }) - if err != nil { - var nfe *types.NotFoundException - if errors.As(err, &nfe) { - return diags - } + if errs.IsA[*types.NotFoundException](err) { + return diags + } - return create.AppendDiagError(diags, names.SESV2, create.ErrActionDeleting, ResNameContactList, d.Id(), err) + if err != nil { + return create.AppendDiagError(diags, names.SESV2, create.ErrActionDeleting, resNameContactList, d.Id(), err) } return diags } -func FindContactListByID(ctx context.Context, conn *sesv2.Client, id string) (*sesv2.GetContactListOutput, error) { - in := &sesv2.GetContactListInput{ +func findContactListByID(ctx context.Context, conn *sesv2.Client, id string) (*sesv2.GetContactListOutput, error) { + input := &sesv2.GetContactListInput{ ContactListName: aws.String(id), } - out, err := conn.GetContactList(ctx, in) - if err != nil { - var nfe *types.NotFoundException - if errors.As(err, &nfe) { - return nil, &retry.NotFoundError{ - LastError: err, - LastRequest: in, - } + + return findContactList(ctx, conn, input) +} + +func findContactList(ctx context.Context, conn *sesv2.Client, input *sesv2.GetContactListInput) (*sesv2.GetContactListOutput, error) { + output, err := conn.GetContactList(ctx, input) + + if errs.IsA[*types.NotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, } + } + if err != nil { return nil, err } - if out == nil { - return nil, tfresource.NewEmptyResultError(in) + if output == nil { + return nil, tfresource.NewEmptyResultError(input) } - return out, nil + return output, nil } func expandTopics(tfList []interface{}) []types.Topic { diff --git a/internal/service/sesv2/contact_list_test.go b/internal/service/sesv2/contact_list_test.go index 95d09abc01d..924773e905e 100644 --- a/internal/service/sesv2/contact_list_test.go +++ b/internal/service/sesv2/contact_list_test.go @@ -5,27 +5,38 @@ package sesv2_test import ( "context" - "errors" "fmt" "testing" - "github.com/aws/aws-sdk-go-v2/service/sesv2/types" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" - "github.com/hashicorp/terraform-provider-aws/internal/create" tfsesv2 "github.com/hashicorp/terraform-provider-aws/internal/service/sesv2" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" ) -func TestAccSESV2ContactList_basic(t *testing.T) { +func TestAccSESV2ContactList_serial(t *testing.T) { + t.Parallel() + + testCases := map[string]func(t *testing.T){ + acctest.CtBasic: testAccContactList_basic, + acctest.CtDisappears: testAccContactList_disappears, + "tags": testAccContactList_tags, + "description": testAccContactList_description, + "topic": testAccContactList_topic, + } + + acctest.RunSerialTests1Level(t, testCases, 0) +} + +func testAccContactList_basic(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_sesv2_contact_list.test" - // Only one contact list is allowed per AWS account. resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.SESV2ServiceID), @@ -52,12 +63,11 @@ func TestAccSESV2ContactList_basic(t *testing.T) { }) } -func TestAccSESV2ContactList_description(t *testing.T) { +func testAccContactList_description(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_sesv2_contact_list.test" - // Only one contact list is allowed per AWS account. resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.SESV2ServiceID), @@ -87,12 +97,11 @@ func TestAccSESV2ContactList_description(t *testing.T) { }) } -func TestAccSESV2ContactList_topic(t *testing.T) { +func testAccContactList_topic(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_sesv2_contact_list.test" - // Only one contact list is allowed per AWS account. resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.SESV2ServiceID), @@ -130,12 +139,11 @@ func TestAccSESV2ContactList_topic(t *testing.T) { }) } -func TestAccSESV2ContactList_tags(t *testing.T) { +func testAccContactList_tags(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_sesv2_contact_list.test" - // Only one contact list is allowed per AWS account. resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.SESV2ServiceID), @@ -168,12 +176,11 @@ func TestAccSESV2ContactList_tags(t *testing.T) { }) } -func TestAccSESV2ContactList_disappears(t *testing.T) { +func testAccContactList_disappears(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_sesv2_contact_list.test" - // Only one contact list is allowed per AWS account. resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.SESV2ServiceID), @@ -203,41 +210,33 @@ func testAccCheckContactListDestroy(ctx context.Context) resource.TestCheckFunc _, err := tfsesv2.FindContactListByID(ctx, conn, rs.Primary.ID) + if tfresource.NotFound(err) { + continue + } + if err != nil { - var nfe *types.NotFoundException - if errors.As(err, &nfe) { - return nil - } return err } - return create.Error(names.SESV2, create.ErrActionCheckingDestroyed, tfsesv2.ResNameContactList, rs.Primary.ID, errors.New("not destroyed")) + return fmt.Errorf("SESv2 Contact List %s still exists", rs.Primary.ID) } return nil } } -func testAccCheckContactListExists(ctx context.Context, name string) resource.TestCheckFunc { +func testAccCheckContactListExists(ctx context.Context, n string) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[name] + rs, ok := s.RootModule().Resources[n] if !ok { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameContactList, name, errors.New("not found")) - } - - if rs.Primary.ID == "" { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameContactList, name, errors.New("not set")) + return fmt.Errorf("Not found: %s", n) } conn := acctest.Provider.Meta().(*conns.AWSClient).SESV2Client(ctx) _, err := tfsesv2.FindContactListByID(ctx, conn, rs.Primary.ID) - if err != nil { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameContactList, rs.Primary.ID, err) - } - - return nil + return err } } diff --git a/internal/service/sesv2/dedicated_ip_assignment.go b/internal/service/sesv2/dedicated_ip_assignment.go index f34882d337f..1c2d401f89c 100644 --- a/internal/service/sesv2/dedicated_ip_assignment.go +++ b/internal/service/sesv2/dedicated_ip_assignment.go @@ -5,7 +5,6 @@ package sesv2 import ( "context" - "errors" "fmt" "log" "strings" @@ -20,12 +19,14 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/create" + "github.com/hashicorp/terraform-provider-aws/internal/errs" + "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" ) -// @SDKResource("aws_sesv2_dedicated_ip_assignment") -func ResourceDedicatedIPAssignment() *schema.Resource { +// @SDKResource("aws_sesv2_dedicated_ip_assignment", name="Dedicated IP Assignment") +func resourceDedicatedIPAssignment() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceDedicatedIPAssignmentCreate, ReadWithoutTimeout: resourceDedicatedIPAssignmentRead, @@ -57,24 +58,26 @@ func ResourceDedicatedIPAssignment() *schema.Resource { } const ( - ResNameDedicatedIPAssignment = "Dedicated IP Assignment" + resNameDedicatedIPAssignment = "Dedicated IP Assignment" ) func resourceDedicatedIPAssignmentCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics conn := meta.(*conns.AWSClient).SESV2Client(ctx) - in := &sesv2.PutDedicatedIpInPoolInput{ - Ip: aws.String(d.Get("ip").(string)), - DestinationPoolName: aws.String(d.Get("destination_pool_name").(string)), + ip, destinationPoolName := d.Get("ip").(string), d.Get("destination_pool_name").(string) + id := dedicatedIPAssignmentCreateResourceID(ip, destinationPoolName) + input := &sesv2.PutDedicatedIpInPoolInput{ + DestinationPoolName: aws.String(destinationPoolName), + Ip: aws.String(ip), } - _, err := conn.PutDedicatedIpInPool(ctx, in) + _, err := conn.PutDedicatedIpInPool(ctx, input) + if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, ResNameDedicatedIPAssignment, d.Get("ip").(string), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, resNameDedicatedIPAssignment, d.Get("ip").(string), err) } - id := toID(d.Get("ip").(string), d.Get("destination_pool_name").(string)) d.SetId(id) return append(diags, resourceDedicatedIPAssignmentRead(ctx, d, meta)...) @@ -84,18 +87,25 @@ func resourceDedicatedIPAssignmentRead(ctx context.Context, d *schema.ResourceDa var diags diag.Diagnostics conn := meta.(*conns.AWSClient).SESV2Client(ctx) - out, err := FindDedicatedIPAssignmentByID(ctx, conn, d.Id()) + ip, destinationPoolName, err := dedicatedIPAssignmentParseResourceID(d.Id()) + if err != nil { + return sdkdiag.AppendFromErr(diags, err) + } + + out, err := findDedicatedIPByTwoPartKey(ctx, conn, ip, destinationPoolName) + if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] SESV2 DedicatedIPAssignment (%s) not found, removing from state", d.Id()) d.SetId("") return diags } + if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, ResNameDedicatedIPAssignment, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, resNameDedicatedIPAssignment, d.Id(), err) } - d.Set("ip", out.Ip) d.Set("destination_pool_name", out.PoolName) + d.Set("ip", out.Ip) return diags } @@ -103,79 +113,93 @@ func resourceDedicatedIPAssignmentRead(ctx context.Context, d *schema.ResourceDa func resourceDedicatedIPAssignmentDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics conn := meta.(*conns.AWSClient).SESV2Client(ctx) - ip, _ := splitID(d.Id()) + + ip, _, err := dedicatedIPAssignmentParseResourceID(d.Id()) + if err != nil { + return sdkdiag.AppendFromErr(diags, err) + } log.Printf("[INFO] Deleting SESV2 DedicatedIPAssignment %s", d.Id()) - _, err := conn.PutDedicatedIpInPool(ctx, &sesv2.PutDedicatedIpInPoolInput{ + const ( + // defaultDedicatedPoolName contains the name of the standard pool managed by AWS + // where dedicated IP addresses with an assignment are stored + // + // When an assignment resource is removed from state, the delete function will re-assign + // the relevant IP to this pool. + defaultDedicatedPoolName = "ses-default-dedicated-pool" + ) + _, err = conn.PutDedicatedIpInPool(ctx, &sesv2.PutDedicatedIpInPoolInput{ Ip: aws.String(ip), DestinationPoolName: aws.String(defaultDedicatedPoolName), }) - if err != nil { - var nfe *types.NotFoundException - if errors.As(err, &nfe) { - return diags - } + if errs.IsA[*types.NotFoundException](err) { + return diags + } - return create.AppendDiagError(diags, names.SESV2, create.ErrActionDeleting, ResNameDedicatedIPAssignment, d.Id(), err) + if err != nil { + return create.AppendDiagError(diags, names.SESV2, create.ErrActionDeleting, resNameDedicatedIPAssignment, d.Id(), err) } return diags } -const ( - // defaultDedicatedPoolName contains the name of the standard pool managed by AWS - // where dedicated IP addresses with an assignment are stored - // - // When an assignment resource is removed from state, the delete function will re-assign - // the relevant IP to this pool. - defaultDedicatedPoolName = "ses-default-dedicated-pool" -) +const dedicatedIPAssignmentResourceIDSeparator = "," + +func dedicatedIPAssignmentCreateResourceID(ip, destinationPoolName string) string { + parts := []string{ip, destinationPoolName} + id := strings.Join(parts, dedicatedIPAssignmentResourceIDSeparator) -// ErrIncorrectPoolAssignment is returned when an IP is assigned to a pool different -// from what is specified in state -var ErrIncorrectPoolAssignment = errors.New("incorrect pool assignment") + return id +} + +func dedicatedIPAssignmentParseResourceID(id string) (string, string, error) { + parts := strings.Split(id, dedicatedIPAssignmentResourceIDSeparator) -func FindDedicatedIPAssignmentByID(ctx context.Context, conn *sesv2.Client, id string) (*types.DedicatedIp, error) { - ip, destinationPoolName := splitID(id) + if len(parts) != 2 || parts[0] == "" || parts[1] == "" { + return "", "", fmt.Errorf("unexpected format of ID (%[1]s), expected IP%[2]sDESTINATION_POOL_NAME", id, dedicatedIPAssignmentResourceIDSeparator) + } + + return parts[0], parts[1], nil +} - in := &sesv2.GetDedicatedIpInput{ +func findDedicatedIPByTwoPartKey(ctx context.Context, conn *sesv2.Client, ip, destinationPoolName string) (*types.DedicatedIp, error) { + input := &sesv2.GetDedicatedIpInput{ Ip: aws.String(ip), } - out, err := conn.GetDedicatedIp(ctx, in) - if err != nil { - var nfe *types.NotFoundException - if errors.As(err, &nfe) { - return nil, &retry.NotFoundError{ - LastError: err, - LastRequest: in, - } - } + output, err := findDedicatedIP(ctx, conn, input) + + if err != nil { return nil, err } - if out == nil || out.DedicatedIp == nil { - return nil, tfresource.NewEmptyResultError(in) - } - if out.DedicatedIp.PoolName == nil || aws.ToString(out.DedicatedIp.PoolName) != destinationPoolName { + if aws.ToString(output.PoolName) != destinationPoolName { return nil, &retry.NotFoundError{ - LastError: ErrIncorrectPoolAssignment, - LastRequest: in, + LastRequest: input, } } - return out.DedicatedIp, nil + return output, nil } -func toID(ip, destinationPoolName string) string { - return fmt.Sprintf("%s,%s", ip, destinationPoolName) -} +func findDedicatedIP(ctx context.Context, conn *sesv2.Client, input *sesv2.GetDedicatedIpInput) (*types.DedicatedIp, error) { + output, err := conn.GetDedicatedIp(ctx, input) + + if errs.IsA[*types.NotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, + } + } -func splitID(id string) (string, string) { - items := strings.Split(id, ",") - if len(items) == 2 { - return items[0], items[1] + if err != nil { + return nil, err } - return "", "" + + if output == nil || output.DedicatedIp == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return output.DedicatedIp, nil } diff --git a/internal/service/sesv2/dedicated_ip_assignment_test.go b/internal/service/sesv2/dedicated_ip_assignment_test.go index 907aa23ec10..cdaa5b13398 100644 --- a/internal/service/sesv2/dedicated_ip_assignment_test.go +++ b/internal/service/sesv2/dedicated_ip_assignment_test.go @@ -5,19 +5,17 @@ package sesv2_test import ( "context" - "errors" "fmt" "os" "testing" - "github.com/aws/aws-sdk-go-v2/service/sesv2/types" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" - "github.com/hashicorp/terraform-provider-aws/internal/create" tfsesv2 "github.com/hashicorp/terraform-provider-aws/internal/service/sesv2" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -102,44 +100,35 @@ func testAccCheckDedicatedIPAssignmentDestroy(ctx context.Context) resource.Test continue } - _, err := tfsesv2.FindDedicatedIPAssignmentByID(ctx, conn, rs.Primary.ID) + _, err := tfsesv2.FindDedicatedIPByTwoPartKey(ctx, conn, rs.Primary.Attributes["ip"], rs.Primary.Attributes["destination_pool_name"]) + + if tfresource.NotFound(err) { + continue + } + if err != nil { - var nfe *types.NotFoundException - if errors.As(err, &nfe) { - return nil - } - if errors.Is(err, tfsesv2.ErrIncorrectPoolAssignment) { - return nil - } return err } - return create.Error(names.SESV2, create.ErrActionCheckingDestroyed, tfsesv2.ResNameDedicatedIPAssignment, rs.Primary.ID, errors.New("not destroyed")) + return fmt.Errorf("SESv2 Dedicated IP Assignment %s still exists", rs.Primary.ID) } return nil } } -func testAccCheckDedicatedIPAssignmentExists(ctx context.Context, name string) resource.TestCheckFunc { +func testAccCheckDedicatedIPAssignmentExists(ctx context.Context, n string) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[name] + rs, ok := s.RootModule().Resources[n] if !ok { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameDedicatedIPAssignment, name, errors.New("not found")) - } - - if rs.Primary.ID == "" { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameDedicatedIPAssignment, name, errors.New("not set")) + return fmt.Errorf("Not found: %s", n) } conn := acctest.Provider.Meta().(*conns.AWSClient).SESV2Client(ctx) - _, err := tfsesv2.FindDedicatedIPAssignmentByID(ctx, conn, rs.Primary.ID) - if err != nil { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameDedicatedIPAssignment, rs.Primary.ID, err) - } + _, err := tfsesv2.FindDedicatedIPByTwoPartKey(ctx, conn, rs.Primary.Attributes["ip"], rs.Primary.Attributes["destination_pool_name"]) - return nil + return err } } diff --git a/internal/service/sesv2/dedicated_ip_pool.go b/internal/service/sesv2/dedicated_ip_pool.go index f0e71b1d9cc..0b699155554 100644 --- a/internal/service/sesv2/dedicated_ip_pool.go +++ b/internal/service/sesv2/dedicated_ip_pool.go @@ -8,7 +8,6 @@ import ( "errors" "fmt" "log" - "time" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/aws/arn" @@ -20,6 +19,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/create" "github.com/hashicorp/terraform-provider-aws/internal/enum" + "github.com/hashicorp/terraform-provider-aws/internal/errs" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" @@ -28,7 +28,7 @@ import ( // @SDKResource("aws_sesv2_dedicated_ip_pool", name="Dedicated IP Pool") // @Tags(identifierAttribute="arn") -func ResourceDedicatedIPPool() *schema.Resource { +func resourceDedicatedIPPool() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceDedicatedIPPoolCreate, ReadWithoutTimeout: resourceDedicatedIPPoolRead, @@ -39,12 +39,6 @@ func ResourceDedicatedIPPool() *schema.Resource { StateContext: schema.ImportStatePassthroughContext, }, - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(30 * time.Minute), - Update: schema.DefaultTimeout(30 * time.Minute), - Delete: schema.DefaultTimeout(30 * time.Minute), - }, - Schema: map[string]*schema.Schema{ names.AttrARN: { Type: schema.TypeString, @@ -71,7 +65,7 @@ func ResourceDedicatedIPPool() *schema.Resource { } const ( - ResNameDedicatedIPPool = "Dedicated IP Pool" + resNameDedicatedIPPool = "Dedicated IP Pool" ) func resourceDedicatedIPPoolCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { @@ -88,10 +82,10 @@ func resourceDedicatedIPPoolCreate(ctx context.Context, d *schema.ResourceData, out, err := conn.CreateDedicatedIpPool(ctx, in) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, ResNameDedicatedIPPool, d.Get("pool_name").(string), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, resNameDedicatedIPPool, d.Get("pool_name").(string), err) } if out == nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, ResNameDedicatedIPPool, d.Get("pool_name").(string), errors.New("empty output")) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, resNameDedicatedIPPool, d.Get("pool_name").(string), errors.New("empty output")) } d.SetId(d.Get("pool_name").(string)) @@ -102,19 +96,22 @@ func resourceDedicatedIPPoolRead(ctx context.Context, d *schema.ResourceData, me var diags diag.Diagnostics conn := meta.(*conns.AWSClient).SESV2Client(ctx) - out, err := FindDedicatedIPPoolByID(ctx, conn, d.Id()) + out, err := findDedicatedIPPoolByName(ctx, conn, d.Id()) + if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] SESV2 DedicatedIPPool (%s) not found, removing from state", d.Id()) d.SetId("") return diags } + if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, ResNameDedicatedIPPool, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, resNameDedicatedIPPool, d.Id(), err) } - poolName := aws.ToString(out.DedicatedIpPool.PoolName) + + poolName := aws.ToString(out.PoolName) d.Set("pool_name", poolName) - d.Set("scaling_mode", string(out.DedicatedIpPool.ScalingMode)) - d.Set(names.AttrARN, poolNameToARN(meta, poolName)) + d.Set("scaling_mode", string(out.ScalingMode)) + d.Set(names.AttrARN, dedicatedIPPoolARN(meta, poolName)) return diags } @@ -133,42 +130,47 @@ func resourceDedicatedIPPoolDelete(ctx context.Context, d *schema.ResourceData, PoolName: aws.String(d.Id()), }) + if errs.IsA[*types.NotFoundException](err) { + return diags + } + if err != nil { - var nfe *types.NotFoundException - if errors.As(err, &nfe) { - return diags - } - return create.AppendDiagError(diags, names.SESV2, create.ErrActionDeleting, ResNameDedicatedIPPool, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionDeleting, resNameDedicatedIPPool, d.Id(), err) } return diags } -func FindDedicatedIPPoolByID(ctx context.Context, conn *sesv2.Client, id string) (*sesv2.GetDedicatedIpPoolOutput, error) { - in := &sesv2.GetDedicatedIpPoolInput{ - PoolName: aws.String(id), +func findDedicatedIPPoolByName(ctx context.Context, conn *sesv2.Client, name string) (*types.DedicatedIpPool, error) { + input := &sesv2.GetDedicatedIpPoolInput{ + PoolName: aws.String(name), } - out, err := conn.GetDedicatedIpPool(ctx, in) - if err != nil { - var nfe *types.NotFoundException - if errors.As(err, &nfe) { - return nil, &retry.NotFoundError{ - LastError: err, - LastRequest: in, - } + + return findDedicatedIPPool(ctx, conn, input) +} + +func findDedicatedIPPool(ctx context.Context, conn *sesv2.Client, input *sesv2.GetDedicatedIpPoolInput) (*types.DedicatedIpPool, error) { + output, err := conn.GetDedicatedIpPool(ctx, input) + + if errs.IsA[*types.NotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, } + } + if err != nil { return nil, err } - if out == nil || out.DedicatedIpPool == nil { - return nil, tfresource.NewEmptyResultError(in) + if output == nil || output.DedicatedIpPool == nil { + return nil, tfresource.NewEmptyResultError(input) } - return out, nil + return output.DedicatedIpPool, nil } -func poolNameToARN(meta interface{}, poolName string) string { +func dedicatedIPPoolARN(meta interface{}, poolName string) string { return arn.ARN{ Partition: meta.(*conns.AWSClient).Partition, Service: "ses", diff --git a/internal/service/sesv2/dedicated_ip_pool_data_source.go b/internal/service/sesv2/dedicated_ip_pool_data_source.go index 3a2ecdbc3c7..25fe476ed9b 100644 --- a/internal/service/sesv2/dedicated_ip_pool_data_source.go +++ b/internal/service/sesv2/dedicated_ip_pool_data_source.go @@ -5,7 +5,6 @@ package sesv2 import ( "context" - "errors" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/sesv2" @@ -15,13 +14,13 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/create" + "github.com/hashicorp/terraform-provider-aws/internal/errs" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" - "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" ) -// @SDKDataSource("aws_sesv2_dedicated_ip_pool") -func DataSourceDedicatedIPPool() *schema.Resource { +// @SDKDataSource("aws_sesv2_dedicated_ip_pool", name="Dedicated IP Pool") +func dataSourceDedicatedIPPool() *schema.Resource { return &schema.Resource{ ReadWithoutTimeout: dataSourceDedicatedIPPoolRead, @@ -64,31 +63,32 @@ func DataSourceDedicatedIPPool() *schema.Resource { } const ( - DSNameDedicatedIPPool = "Dedicated IP Pool Data Source" + dsNameDedicatedIPPool = "Dedicated IP Pool Data Source" ) func dataSourceDedicatedIPPoolRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics conn := meta.(*conns.AWSClient).SESV2Client(ctx) - out, err := FindDedicatedIPPoolByID(ctx, conn, d.Get("pool_name").(string)) + out, err := findDedicatedIPPoolByName(ctx, conn, d.Get("pool_name").(string)) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, DSNameDedicatedIPPool, d.Get("pool_name").(string), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, dsNameDedicatedIPPool, d.Get("pool_name").(string), err) } - poolName := aws.ToString(out.DedicatedIpPool.PoolName) + + poolName := aws.ToString(out.PoolName) d.SetId(poolName) - d.Set("scaling_mode", string(out.DedicatedIpPool.ScalingMode)) - d.Set(names.AttrARN, poolNameToARN(meta, poolName)) + d.Set("scaling_mode", out.ScalingMode) + d.Set(names.AttrARN, dedicatedIPPoolARN(meta, poolName)) - outIP, err := findDedicatedIPPoolIPs(ctx, conn, poolName) + outIP, err := findDedicatedIPsByPoolName(ctx, conn, poolName) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, DSNameDedicatedIPPool, poolName, err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, dsNameDedicatedIPPool, poolName, err) } - d.Set("dedicated_ips", flattenDedicatedIPs(outIP.DedicatedIps)) + d.Set("dedicated_ips", flattenDedicatedIPs(outIP)) tags, err := listTags(ctx, conn, d.Get(names.AttrARN).(string)) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, DSNameDedicatedIPPool, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, dsNameDedicatedIPPool, d.Id(), err) } defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig @@ -96,7 +96,7 @@ func dataSourceDedicatedIPPoolRead(ctx context.Context, d *schema.ResourceData, tags = tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig) if err := d.Set(names.AttrTags, tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, DSNameDedicatedIPPool, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, dsNameDedicatedIPPool, d.Id(), err) } return diags @@ -121,26 +121,34 @@ func flattenDedicatedIPs(apiObjects []types.DedicatedIp) []interface{} { return dedicatedIps } -func findDedicatedIPPoolIPs(ctx context.Context, conn *sesv2.Client, poolName string) (*sesv2.GetDedicatedIpsOutput, error) { - in := &sesv2.GetDedicatedIpsInput{ +func findDedicatedIPsByPoolName(ctx context.Context, conn *sesv2.Client, poolName string) ([]types.DedicatedIp, error) { + input := &sesv2.GetDedicatedIpsInput{ PoolName: aws.String(poolName), } - out, err := conn.GetDedicatedIps(ctx, in) - if err != nil { - var nfe *types.NotFoundException - if errors.As(err, &nfe) { + + return findDedicatedIPs(ctx, conn, input) +} + +func findDedicatedIPs(ctx context.Context, conn *sesv2.Client, input *sesv2.GetDedicatedIpsInput) ([]types.DedicatedIp, error) { + var output []types.DedicatedIp + + pages := sesv2.NewGetDedicatedIpsPaginator(conn, input) + for pages.HasMorePages() { + page, err := pages.NextPage(ctx) + + if errs.IsA[*types.NotFoundException](err) { return nil, &retry.NotFoundError{ LastError: err, - LastRequest: in, + LastRequest: input, } } - return nil, err - } + if err != nil { + return nil, err + } - if out == nil { - return nil, tfresource.NewEmptyResultError(in) + output = append(output, page.DedicatedIps...) } - return out, nil + return output, nil } diff --git a/internal/service/sesv2/dedicated_ip_pool_test.go b/internal/service/sesv2/dedicated_ip_pool_test.go index 6ffd5c8be85..91d9074a09c 100644 --- a/internal/service/sesv2/dedicated_ip_pool_test.go +++ b/internal/service/sesv2/dedicated_ip_pool_test.go @@ -5,7 +5,6 @@ package sesv2_test import ( "context" - "errors" "fmt" "testing" @@ -17,8 +16,8 @@ import ( "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" - "github.com/hashicorp/terraform-provider-aws/internal/create" tfsesv2 "github.com/hashicorp/terraform-provider-aws/internal/service/sesv2" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -166,40 +165,35 @@ func testAccCheckDedicatedIPPoolDestroy(ctx context.Context) resource.TestCheckF continue } - _, err := tfsesv2.FindDedicatedIPPoolByID(ctx, conn, rs.Primary.ID) + _, err := tfsesv2.FindDedicatedIPPoolByName(ctx, conn, rs.Primary.ID) + + if tfresource.NotFound(err) { + continue + } + if err != nil { - var nfe *types.NotFoundException - if errors.As(err, &nfe) { - return nil - } return err } - return create.Error(names.SESV2, create.ErrActionCheckingDestroyed, tfsesv2.ResNameDedicatedIPPool, rs.Primary.ID, errors.New("not destroyed")) + return fmt.Errorf("SESv2 Dedicated IP Pool %s still exists", rs.Primary.ID) } return nil } } -func testAccCheckDedicatedIPPoolExists(ctx context.Context, name string) resource.TestCheckFunc { +func testAccCheckDedicatedIPPoolExists(ctx context.Context, n string) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[name] + rs, ok := s.RootModule().Resources[n] if !ok { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameDedicatedIPPool, name, errors.New("not found")) - } - if rs.Primary.ID == "" { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameDedicatedIPPool, name, errors.New("not set")) + return fmt.Errorf("Not found: %s", n) } conn := acctest.Provider.Meta().(*conns.AWSClient).SESV2Client(ctx) - _, err := tfsesv2.FindDedicatedIPPoolByID(ctx, conn, rs.Primary.ID) - if err != nil { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameDedicatedIPPool, rs.Primary.ID, err) - } + _, err := tfsesv2.FindDedicatedIPPoolByName(ctx, conn, rs.Primary.ID) - return nil + return err } } diff --git a/internal/service/sesv2/email_identity.go b/internal/service/sesv2/email_identity.go index 3be268a1098..b87d65ca63f 100644 --- a/internal/service/sesv2/email_identity.go +++ b/internal/service/sesv2/email_identity.go @@ -21,6 +21,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/create" "github.com/hashicorp/terraform-provider-aws/internal/enum" + "github.com/hashicorp/terraform-provider-aws/internal/errs" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" @@ -29,7 +30,7 @@ import ( // @SDKResource("aws_sesv2_email_identity", name="Email Identity") // @Tags(identifierAttribute="arn") -func ResourceEmailIdentity() *schema.Resource { +func resourceEmailIdentity() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceEmailIdentityCreate, ReadWithoutTimeout: resourceEmailIdentityRead, @@ -126,7 +127,7 @@ func ResourceEmailIdentity() *schema.Resource { } const ( - ResNameEmailIdentity = "Email Identity" + resNameEmailIdentity = "Email Identity" ) func resourceEmailIdentityCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { @@ -148,11 +149,11 @@ func resourceEmailIdentityCreate(ctx context.Context, d *schema.ResourceData, me out, err := conn.CreateEmailIdentity(ctx, in) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, ResNameEmailIdentity, d.Get("email_identity").(string), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, resNameEmailIdentity, d.Get("email_identity").(string), err) } if out == nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, ResNameEmailIdentity, d.Get("email_identity").(string), errors.New("empty output")) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, resNameEmailIdentity, d.Get("email_identity").(string), errors.New("empty output")) } d.SetId(d.Get("email_identity").(string)) @@ -160,21 +161,11 @@ func resourceEmailIdentityCreate(ctx context.Context, d *schema.ResourceData, me return append(diags, resourceEmailIdentityRead(ctx, d, meta)...) } -func emailIdentityNameToARN(meta interface{}, emailIdentityName string) string { - return arn.ARN{ - Partition: meta.(*conns.AWSClient).Partition, - Service: "ses", - Region: meta.(*conns.AWSClient).Region, - AccountID: meta.(*conns.AWSClient).AccountID, - Resource: fmt.Sprintf("identity/%s", emailIdentityName), - }.String() -} - func resourceEmailIdentityRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics conn := meta.(*conns.AWSClient).SESV2Client(ctx) - out, err := FindEmailIdentityByID(ctx, conn, d.Id()) + out, err := findEmailIdentityByID(ctx, conn, d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] SESV2 EmailIdentity (%s) not found, removing from state", d.Id()) @@ -183,10 +174,10 @@ func resourceEmailIdentityRead(ctx context.Context, d *schema.ResourceData, meta } if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, ResNameEmailIdentity, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, resNameEmailIdentity, d.Id(), err) } - arn := emailIdentityNameToARN(meta, d.Id()) + arn := emailIdentityARN(meta, d.Id()) d.Set(names.AttrARN, arn) d.Set("configuration_set_name", out.ConfigurationSetName) @@ -198,7 +189,7 @@ func resourceEmailIdentityRead(ctx context.Context, d *schema.ResourceData, meta tfMap["domain_signing_selector"] = d.Get("dkim_signing_attributes.0.domain_signing_selector").(string) if err := d.Set("dkim_signing_attributes", []interface{}{tfMap}); err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, ResNameEmailIdentity, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, resNameEmailIdentity, d.Id(), err) } } else { d.Set("dkim_signing_attributes", nil) @@ -223,10 +214,9 @@ func resourceEmailIdentityUpdate(ctx context.Context, d *schema.ResourceData, me in.ConfigurationSetName = aws.String(v.(string)) } - log.Printf("[DEBUG] Updating SESV2 EmailIdentity ConfigurationSetAttributes (%s): %#v", d.Id(), in) _, err := conn.PutEmailIdentityConfigurationSetAttributes(ctx, in) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, ResNameEmailIdentity, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, resNameEmailIdentity, d.Id(), err) } } @@ -241,10 +231,9 @@ func resourceEmailIdentityUpdate(ctx context.Context, d *schema.ResourceData, me in.SigningAttributesOrigin = getSigningAttributesOrigin(v.([]interface{})[0].(map[string]interface{})) } - log.Printf("[DEBUG] Updating SESV2 EmailIdentity DkimSigningAttributes (%s): %#v", d.Id(), in) _, err := conn.PutEmailIdentityDkimSigningAttributes(ctx, in) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, ResNameEmailIdentity, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, resNameEmailIdentity, d.Id(), err) } } @@ -255,46 +244,49 @@ func resourceEmailIdentityDelete(ctx context.Context, d *schema.ResourceData, me var diags diag.Diagnostics conn := meta.(*conns.AWSClient).SESV2Client(ctx) - log.Printf("[INFO] Deleting SESV2 EmailIdentity %s", d.Id()) - + log.Printf("[INFO] Deleting SESV2 EmailIdentity: %s", d.Id()) _, err := conn.DeleteEmailIdentity(ctx, &sesv2.DeleteEmailIdentityInput{ EmailIdentity: aws.String(d.Id()), }) - if err != nil { - var nfe *types.NotFoundException - if errors.As(err, &nfe) { - return diags - } + if errs.IsA[*types.NotFoundException](err) { + return diags + } - return create.AppendDiagError(diags, names.SESV2, create.ErrActionDeleting, ResNameEmailIdentity, d.Id(), err) + if err != nil { + return create.AppendDiagError(diags, names.SESV2, create.ErrActionDeleting, resNameEmailIdentity, d.Id(), err) } return diags } -func FindEmailIdentityByID(ctx context.Context, conn *sesv2.Client, id string) (*sesv2.GetEmailIdentityOutput, error) { - in := &sesv2.GetEmailIdentityInput{ +func findEmailIdentityByID(ctx context.Context, conn *sesv2.Client, id string) (*sesv2.GetEmailIdentityOutput, error) { + input := &sesv2.GetEmailIdentityInput{ EmailIdentity: aws.String(id), } - out, err := conn.GetEmailIdentity(ctx, in) - if err != nil { - var nfe *types.NotFoundException - if errors.As(err, &nfe) { - return nil, &retry.NotFoundError{ - LastError: err, - LastRequest: in, - } + + return findEmailIdentity(ctx, conn, input) +} + +func findEmailIdentity(ctx context.Context, conn *sesv2.Client, input *sesv2.GetEmailIdentityInput) (*sesv2.GetEmailIdentityOutput, error) { + output, err := conn.GetEmailIdentity(ctx, input) + + if errs.IsA[*types.NotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, } + } + if err != nil { return nil, err } - if out == nil { - return nil, tfresource.NewEmptyResultError(in) + if output == nil { + return nil, tfresource.NewEmptyResultError(input) } - return out, nil + return output, nil } func expandDKIMSigningAttributes(tfMap map[string]interface{}) *types.DkimSigningAttributes { @@ -361,3 +353,13 @@ func flattenDKIMAttributes(apiObject *types.DkimAttributes) map[string]interface return m } + +func emailIdentityARN(meta interface{}, emailIdentityName string) string { + return arn.ARN{ + Partition: meta.(*conns.AWSClient).Partition, + Service: "ses", + Region: meta.(*conns.AWSClient).Region, + AccountID: meta.(*conns.AWSClient).AccountID, + Resource: fmt.Sprintf("identity/%s", emailIdentityName), + }.String() +} diff --git a/internal/service/sesv2/email_identity_data_source.go b/internal/service/sesv2/email_identity_data_source.go index 988b34e3ef5..9c41939c56b 100644 --- a/internal/service/sesv2/email_identity_data_source.go +++ b/internal/service/sesv2/email_identity_data_source.go @@ -14,9 +14,9 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -// @SDKDataSource("aws_sesv2_email_identity") +// @SDKDataSource("aws_sesv2_email_identity", name="Email Identity") // @Tags(identifierAttribute="arn") -func DataSourceEmailIdentity() *schema.Resource { +func dataSourceEmailIdentity() *schema.Resource { return &schema.Resource{ ReadWithoutTimeout: dataSourceEmailIdentityRead, @@ -89,7 +89,7 @@ func DataSourceEmailIdentity() *schema.Resource { } const ( - DSNameEmailIdentity = "Email Identity Data Source" + dsNameEmailIdentity = "Email Identity Data Source" ) func dataSourceEmailIdentityRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { @@ -98,12 +98,12 @@ func dataSourceEmailIdentityRead(ctx context.Context, d *schema.ResourceData, me name := d.Get("email_identity").(string) - out, err := FindEmailIdentityByID(ctx, conn, name) + out, err := findEmailIdentityByID(ctx, conn, name) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, DSNameEmailIdentity, name, err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, dsNameEmailIdentity, name, err) } - arn := emailIdentityNameToARN(meta, name) + arn := emailIdentityARN(meta, name) d.SetId(name) d.Set(names.AttrARN, arn) @@ -116,7 +116,7 @@ func dataSourceEmailIdentityRead(ctx context.Context, d *schema.ResourceData, me tfMap["domain_signing_selector"] = d.Get("dkim_signing_attributes.0.domain_signing_selector").(string) if err := d.Set("dkim_signing_attributes", []interface{}{tfMap}); err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, ResNameEmailIdentity, name, err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, dsNameEmailIdentity, name, err) } } else { d.Set("dkim_signing_attributes", nil) diff --git a/internal/service/sesv2/email_identity_feedback_attributes.go b/internal/service/sesv2/email_identity_feedback_attributes.go index d4b6695952e..8276101e7ca 100644 --- a/internal/service/sesv2/email_identity_feedback_attributes.go +++ b/internal/service/sesv2/email_identity_feedback_attributes.go @@ -15,12 +15,13 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/create" + "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" ) -// @SDKResource("aws_sesv2_email_identity_feedback_attributes") -func ResourceEmailIdentityFeedbackAttributes() *schema.Resource { +// @SDKResource("aws_sesv2_email_identity_feedback_attributes", name="Email Identity Feedback Attributes") +func resourceEmailIdentityFeedbackAttributes() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceEmailIdentityFeedbackAttributesCreate, ReadWithoutTimeout: resourceEmailIdentityFeedbackAttributesRead, @@ -47,7 +48,7 @@ func ResourceEmailIdentityFeedbackAttributes() *schema.Resource { } const ( - ResNameEmailIdentityFeedbackAttributes = "Email Identity Feedback Attributes" + resNameEmailIdentityFeedbackAttributes = "Email Identity Feedback Attributes" ) func resourceEmailIdentityFeedbackAttributesCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { @@ -61,11 +62,11 @@ func resourceEmailIdentityFeedbackAttributesCreate(ctx context.Context, d *schem out, err := conn.PutEmailIdentityFeedbackAttributes(ctx, in) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, ResNameEmailIdentityFeedbackAttributes, d.Get("email_identity").(string), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, resNameEmailIdentityFeedbackAttributes, d.Get("email_identity").(string), err) } if out == nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, ResNameEmailIdentityFeedbackAttributes, d.Get("email_identity").(string), errors.New("empty output")) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, resNameEmailIdentityFeedbackAttributes, d.Get("email_identity").(string), errors.New("empty output")) } d.SetId(d.Get("email_identity").(string)) @@ -77,7 +78,7 @@ func resourceEmailIdentityFeedbackAttributesRead(ctx context.Context, d *schema. var diags diag.Diagnostics conn := meta.(*conns.AWSClient).SESV2Client(ctx) - out, err := FindEmailIdentityByID(ctx, conn, d.Id()) + out, err := findEmailIdentityByID(ctx, conn, d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] SESV2 EmailIdentityFeedbackAttributes (%s) not found, removing from state", d.Id()) @@ -86,7 +87,7 @@ func resourceEmailIdentityFeedbackAttributesRead(ctx context.Context, d *schema. } if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, ResNameEmailIdentityFeedbackAttributes, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, resNameEmailIdentityFeedbackAttributes, d.Id(), err) } d.Set("email_identity", d.Id()) @@ -117,7 +118,7 @@ func resourceEmailIdentityFeedbackAttributesUpdate(ctx context.Context, d *schem log.Printf("[DEBUG] Updating SESV2 EmailIdentityFeedbackAttributes (%s): %#v", d.Id(), in) _, err := conn.PutEmailIdentityFeedbackAttributes(ctx, in) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, ResNameEmailIdentityFeedbackAttributes, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, resNameEmailIdentityFeedbackAttributes, d.Id(), err) } return append(diags, resourceEmailIdentityFeedbackAttributesRead(ctx, d, meta)...) @@ -133,13 +134,16 @@ func resourceEmailIdentityFeedbackAttributesDelete(ctx context.Context, d *schem EmailIdentity: aws.String(d.Id()), }) - if err != nil { - var nfe *types.NotFoundException - if errors.As(err, &nfe) { - return diags - } + if errs.IsA[*types.NotFoundException](err) { + return diags + } - return create.AppendDiagError(diags, names.SESV2, create.ErrActionDeleting, ResNameEmailIdentityFeedbackAttributes, d.Id(), err) + if errs.IsAErrorMessageContains[*types.BadRequestException](err, "Must be a verified email address or domain") { + return diags + } + + if err != nil { + return create.AppendDiagError(diags, names.SESV2, create.ErrActionDeleting, resNameEmailIdentityFeedbackAttributes, d.Id(), err) } return diags diff --git a/internal/service/sesv2/email_identity_feedback_attributes_test.go b/internal/service/sesv2/email_identity_feedback_attributes_test.go index e2bc26f5e84..b37bf6dbb08 100644 --- a/internal/service/sesv2/email_identity_feedback_attributes_test.go +++ b/internal/service/sesv2/email_identity_feedback_attributes_test.go @@ -13,7 +13,6 @@ import ( "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" - "github.com/hashicorp/terraform-provider-aws/internal/create" tfsesv2 "github.com/hashicorp/terraform-provider-aws/internal/service/sesv2" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -130,25 +129,23 @@ func TestAccSESV2EmailIdentityFeedbackAttributes_emailForwardingEnabled(t *testi // testAccCheckEmailIdentityFeedbackAttributesExist verifies that both the email identity exists, // and that the email forwarding enabled setting is correct -func testAccCheckEmailIdentityFeedbackAttributesExist(ctx context.Context, name string, emailForwardingEnabled bool) resource.TestCheckFunc { +func testAccCheckEmailIdentityFeedbackAttributesExist(ctx context.Context, n string, emailForwardingEnabled bool) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[name] + rs, ok := s.RootModule().Resources[n] if !ok { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameEmailIdentity, name, errors.New("not found")) - } - - if rs.Primary.ID == "" { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameEmailIdentity, name, errors.New("not set")) + return fmt.Errorf("Not found: %s", n) } conn := acctest.Provider.Meta().(*conns.AWSClient).SESV2Client(ctx) out, err := tfsesv2.FindEmailIdentityByID(ctx, conn, rs.Primary.ID) + if err != nil { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameEmailIdentity, rs.Primary.ID, err) + return err } - if out == nil || out.FeedbackForwardingStatus != emailForwardingEnabled { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameEmailIdentityFeedbackAttributes, rs.Primary.ID, errors.New("feedback attributes not set")) + + if out.FeedbackForwardingStatus != emailForwardingEnabled { + return errors.New("feedback attributes not set") } return nil diff --git a/internal/service/sesv2/email_identity_mail_from_attributes.go b/internal/service/sesv2/email_identity_mail_from_attributes.go index 1824537ff9e..28a6ff6292f 100644 --- a/internal/service/sesv2/email_identity_mail_from_attributes.go +++ b/internal/service/sesv2/email_identity_mail_from_attributes.go @@ -16,14 +16,15 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/create" "github.com/hashicorp/terraform-provider-aws/internal/enum" + "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" ) -var ErrMailFromRequired = errors.New("mail from domain is required if behavior on MX failure is REJECT_MESSAGE") +var errMailFromRequired = errors.New("mail from domain is required if behavior on MX failure is REJECT_MESSAGE") -// @SDKResource("aws_sesv2_email_identity_mail_from_attributes") -func ResourceEmailIdentityMailFromAttributes() *schema.Resource { +// @SDKResource("aws_sesv2_email_identity_mail_from_attributes", name="Email Identity Mail From Attributes") +func resourceEmailIdentityMailFromAttributes() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceEmailIdentityMailFromAttributesCreate, ReadWithoutTimeout: resourceEmailIdentityMailFromAttributesRead, @@ -55,7 +56,7 @@ func ResourceEmailIdentityMailFromAttributes() *schema.Resource { } const ( - ResNameEmailIdentityMailFromAttributes = "Email Identity Mail From Attributes" + resNameEmailIdentityMailFromAttributes = "Email Identity Mail From Attributes" ) func resourceEmailIdentityMailFromAttributesCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { @@ -75,16 +76,16 @@ func resourceEmailIdentityMailFromAttributesCreate(ctx context.Context, d *schem } if in.BehaviorOnMxFailure == types.BehaviorOnMxFailureRejectMessage && (in.MailFromDomain == nil || aws.ToString(in.MailFromDomain) == "") { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, ResNameEmailIdentityMailFromAttributes, d.Get("email_identity").(string), ErrMailFromRequired) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, resNameEmailIdentityMailFromAttributes, d.Get("email_identity").(string), errMailFromRequired) } out, err := conn.PutEmailIdentityMailFromAttributes(ctx, in) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, ResNameEmailIdentityMailFromAttributes, d.Get("email_identity").(string), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, resNameEmailIdentityMailFromAttributes, d.Get("email_identity").(string), err) } if out == nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, ResNameEmailIdentityMailFromAttributes, d.Get("email_identity").(string), errors.New("empty output")) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, resNameEmailIdentityMailFromAttributes, d.Get("email_identity").(string), errors.New("empty output")) } d.SetId(d.Get("email_identity").(string)) @@ -96,7 +97,7 @@ func resourceEmailIdentityMailFromAttributesRead(ctx context.Context, d *schema. var diags diag.Diagnostics conn := meta.(*conns.AWSClient).SESV2Client(ctx) - out, err := FindEmailIdentityByID(ctx, conn, d.Id()) + out, err := findEmailIdentityByID(ctx, conn, d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] SESV2 EmailIdentityMailFromAttributes (%s) not found, removing from state", d.Id()) @@ -105,7 +106,7 @@ func resourceEmailIdentityMailFromAttributesRead(ctx context.Context, d *schema. } if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, ResNameEmailIdentityMailFromAttributes, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, resNameEmailIdentityMailFromAttributes, d.Id(), err) } d.Set("email_identity", d.Id()) @@ -136,7 +137,7 @@ func resourceEmailIdentityMailFromAttributesUpdate(ctx context.Context, d *schem in.MailFromDomain = aws.String(d.Get("mail_from_domain").(string)) if in.BehaviorOnMxFailure == types.BehaviorOnMxFailureRejectMessage && (in.MailFromDomain == nil || aws.ToString(in.MailFromDomain) == "") { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, ResNameEmailIdentityMailFromAttributes, d.Get("email_identity").(string), ErrMailFromRequired) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, resNameEmailIdentityMailFromAttributes, d.Get("email_identity").(string), errMailFromRequired) } update = true @@ -149,7 +150,7 @@ func resourceEmailIdentityMailFromAttributesUpdate(ctx context.Context, d *schem log.Printf("[DEBUG] Updating SESV2 EmailIdentityMailFromAttributes (%s): %#v", d.Id(), in) _, err := conn.PutEmailIdentityMailFromAttributes(ctx, in) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, ResNameEmailIdentityMailFromAttributes, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, resNameEmailIdentityMailFromAttributes, d.Id(), err) } return append(diags, resourceEmailIdentityMailFromAttributesRead(ctx, d, meta)...) @@ -159,19 +160,17 @@ func resourceEmailIdentityMailFromAttributesDelete(ctx context.Context, d *schem var diags diag.Diagnostics conn := meta.(*conns.AWSClient).SESV2Client(ctx) - log.Printf("[INFO] Deleting SESV2 EmailIdentityMailFromAttributes %s", d.Id()) - + log.Printf("[INFO] Deleting SESV2 EmailIdentityMailFromAttributes: %s", d.Id()) _, err := conn.PutEmailIdentityMailFromAttributes(ctx, &sesv2.PutEmailIdentityMailFromAttributesInput{ EmailIdentity: aws.String(d.Id()), }) - if err != nil { - var nfe *types.NotFoundException - if errors.As(err, &nfe) { - return diags - } + if errs.IsA[*types.NotFoundException](err) { + return diags + } - return create.AppendDiagError(diags, names.SESV2, create.ErrActionDeleting, ResNameEmailIdentityMailFromAttributes, d.Id(), err) + if err != nil { + return create.AppendDiagError(diags, names.SESV2, create.ErrActionDeleting, resNameEmailIdentityMailFromAttributes, d.Id(), err) } return diags diff --git a/internal/service/sesv2/email_identity_mail_from_attributes_data_source.go b/internal/service/sesv2/email_identity_mail_from_attributes_data_source.go index 8f093ad8d77..68686c8508c 100644 --- a/internal/service/sesv2/email_identity_mail_from_attributes_data_source.go +++ b/internal/service/sesv2/email_identity_mail_from_attributes_data_source.go @@ -13,8 +13,8 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -// @SDKDataSource("aws_sesv2_email_identity_mail_from_attributes") -func DataSourceEmailIdentityMailFromAttributes() *schema.Resource { +// @SDKDataSource("aws_sesv2_email_identity_mail_from_attributes", name="Email Identity Mail From Attributes") +func dataSourceEmailIdentityMailFromAttributes() *schema.Resource { return &schema.Resource{ ReadWithoutTimeout: dataSourceEmailIdentityMailFromAttributesRead, @@ -36,7 +36,7 @@ func DataSourceEmailIdentityMailFromAttributes() *schema.Resource { } const ( - DSNameEmailIdentityMailFromAttributes = "Email Identity Mail From Attributes Data Source" + dsNameEmailIdentityMailFromAttributes = "Email Identity Mail From Attributes Data Source" ) func dataSourceEmailIdentityMailFromAttributesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { @@ -45,10 +45,10 @@ func dataSourceEmailIdentityMailFromAttributesRead(ctx context.Context, d *schem name := d.Get("email_identity").(string) - out, err := FindEmailIdentityByID(ctx, conn, name) + out, err := findEmailIdentityByID(ctx, conn, name) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, ResNameEmailIdentityMailFromAttributes, name, err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, dsNameEmailIdentityMailFromAttributes, name, err) } d.SetId(name) diff --git a/internal/service/sesv2/email_identity_mail_from_attributes_test.go b/internal/service/sesv2/email_identity_mail_from_attributes_test.go index 50bb56d1c68..b664ea4f03e 100644 --- a/internal/service/sesv2/email_identity_mail_from_attributes_test.go +++ b/internal/service/sesv2/email_identity_mail_from_attributes_test.go @@ -5,7 +5,6 @@ package sesv2_test import ( "context" - "errors" "fmt" "testing" @@ -14,7 +13,6 @@ import ( "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" - "github.com/hashicorp/terraform-provider-aws/internal/create" tfsesv2 "github.com/hashicorp/terraform-provider-aws/internal/service/sesv2" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -172,30 +170,18 @@ func TestAccSESV2EmailIdentityMailFromAttributes_mailFromDomain(t *testing.T) { }) } -func testAccCheckEmailIdentityMailFromAttributesExists(ctx context.Context, name string) resource.TestCheckFunc { +func testAccCheckEmailIdentityMailFromAttributesExists(ctx context.Context, n string) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[name] + rs, ok := s.RootModule().Resources[n] if !ok { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameEmailIdentityMailFromAttributes, name, errors.New("not found")) - } - - if rs.Primary.ID == "" { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameEmailIdentityMailFromAttributes, name, errors.New("not set")) + return fmt.Errorf("Not found: %s", n) } conn := acctest.Provider.Meta().(*conns.AWSClient).SESV2Client(ctx) - out, err := tfsesv2.FindEmailIdentityByID(ctx, conn, rs.Primary.ID) - - if err != nil { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameEmailIdentityMailFromAttributes, rs.Primary.ID, err) - } - - if out == nil || out.MailFromAttributes == nil { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameEmailIdentityMailFromAttributes, rs.Primary.ID, errors.New("mail from attributes not set")) - } + _, err := tfsesv2.FindEmailIdentityByID(ctx, conn, rs.Primary.ID) - return nil + return err } } diff --git a/internal/service/sesv2/email_identity_policy.go b/internal/service/sesv2/email_identity_policy.go index db1866705b4..aa3ba7333ab 100644 --- a/internal/service/sesv2/email_identity_policy.go +++ b/internal/service/sesv2/email_identity_policy.go @@ -20,6 +20,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/create" + "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" @@ -27,7 +28,7 @@ import ( ) // @SDKResource("aws_sesv2_email_identity_policy", name="Email Identity Policy") -func ResourceEmailIdentityPolicy() *schema.Resource { +func resourceEmailIdentityPolicy() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceEmailIdentityPolicyCreate, ReadWithoutTimeout: resourceEmailIdentityPolicyRead, @@ -66,7 +67,7 @@ func ResourceEmailIdentityPolicy() *schema.Resource { } const ( - ResNameEmailIdentityPolicy = "Email Identity Policy" + resNameEmailIdentityPolicy = "Email Identity Policy" ) func resourceEmailIdentityPolicyCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { @@ -75,11 +76,11 @@ func resourceEmailIdentityPolicyCreate(ctx context.Context, d *schema.ResourceDa email_identity := d.Get("email_identity").(string) policy_name := d.Get("policy_name").(string) - emailIdentityPolicyID := FormatEmailIdentityPolicyID(email_identity, policy_name) + emailIdentityPolicyID := emailIdentityPolicyCreateResourceID(email_identity, policy_name) policy, err := structure.NormalizeJsonString(d.Get(names.AttrPolicy).(string)) if err != nil { - return sdkdiag.AppendErrorf(diags, "policy (%s) is invalid JSON: %s", d.Get(names.AttrPolicy).(string), err) + return sdkdiag.AppendFromErr(diags, err) } in := &sesv2.CreateEmailIdentityPolicyInput{ @@ -90,11 +91,11 @@ func resourceEmailIdentityPolicyCreate(ctx context.Context, d *schema.ResourceDa out, err := conn.CreateEmailIdentityPolicy(ctx, in) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, ResNameEmailIdentityPolicy, emailIdentityPolicyID, err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, resNameEmailIdentityPolicy, emailIdentityPolicyID, err) } if out == nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, ResNameEmailIdentityPolicy, emailIdentityPolicyID, errors.New("empty output")) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionCreating, resNameEmailIdentityPolicy, emailIdentityPolicyID, errors.New("empty output")) } d.SetId(emailIdentityPolicyID) @@ -106,12 +107,12 @@ func resourceEmailIdentityPolicyRead(ctx context.Context, d *schema.ResourceData var diags diag.Diagnostics conn := meta.(*conns.AWSClient).SESV2Client(ctx) - emailIdentity, policyName, err := ParseEmailIdentityPolicyID(d.Id()) + emailIdentity, policyName, err := emailIdentityPolicyParseResourceID(d.Id()) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, ResNameEmailIdentityPolicy, d.Id(), err) + return sdkdiag.AppendFromErr(diags, err) } - policy, err := FindEmailIdentityPolicyByID(ctx, conn, d.Id()) + out, err := findEmailIdentityPolicyByTwoPartKey(ctx, conn, emailIdentity, policyName) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] SESV2 EmailIdentityPolicy (%s) not found, removing from state", d.Id()) @@ -120,17 +121,17 @@ func resourceEmailIdentityPolicyRead(ctx context.Context, d *schema.ResourceData } if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, ResNameEmailIdentityPolicy, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, resNameEmailIdentityPolicy, d.Id(), err) } - policy, err = verify.SecondJSONUnlessEquivalent(d.Get(names.AttrPolicy).(string), policy) + policy, err := verify.SecondJSONUnlessEquivalent(d.Get(names.AttrPolicy).(string), aws.ToString(out)) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, ResNameEmailIdentityPolicy, d.Id(), err) + return sdkdiag.AppendFromErr(diags, err) } policy, err = structure.NormalizeJsonString(policy) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionSetting, ResNameEmailIdentityPolicy, d.Id(), err) + return sdkdiag.AppendFromErr(diags, err) } d.Set("email_identity", emailIdentity) @@ -144,21 +145,25 @@ func resourceEmailIdentityPolicyUpdate(ctx context.Context, d *schema.ResourceDa var diags diag.Diagnostics conn := meta.(*conns.AWSClient).SESV2Client(ctx) + emailIdentity, policyName, err := emailIdentityPolicyParseResourceID(d.Id()) + if err != nil { + return sdkdiag.AppendFromErr(diags, err) + } + policy, err := structure.NormalizeJsonString(d.Get(names.AttrPolicy).(string)) if err != nil { - return sdkdiag.AppendErrorf(diags, "policy (%s) is invalid JSON: %s", d.Get(names.AttrPolicy).(string), err) + return sdkdiag.AppendFromErr(diags, err) } in := &sesv2.UpdateEmailIdentityPolicyInput{ - EmailIdentity: aws.String(d.Get("email_identity").(string)), + EmailIdentity: aws.String(emailIdentity), Policy: aws.String(policy), - PolicyName: aws.String(d.Get("policy_name").(string)), + PolicyName: aws.String(policyName), } - log.Printf("[DEBUG] Updating SESV2 EmailIdentityPolicy (%s): %#v", d.Id(), in) _, err = conn.UpdateEmailIdentityPolicy(ctx, in) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, ResNameEmailIdentityPolicy, d.Id(), err) + return create.AppendDiagError(diags, names.SESV2, create.ErrActionUpdating, resNameEmailIdentityPolicy, d.Id(), err) } return append(diags, resourceEmailIdentityPolicyRead(ctx, d, meta)...) @@ -168,75 +173,81 @@ func resourceEmailIdentityPolicyDelete(ctx context.Context, d *schema.ResourceDa var diags diag.Diagnostics conn := meta.(*conns.AWSClient).SESV2Client(ctx) - log.Printf("[INFO] Deleting SESV2 EmailIdentityPolicy %s", d.Id()) - - emailIdentity, policyName, err := ParseEmailIdentityPolicyID(d.Id()) + emailIdentity, policyName, err := emailIdentityPolicyParseResourceID(d.Id()) if err != nil { - return create.AppendDiagError(diags, names.SESV2, create.ErrActionReading, ResNameEmailIdentityPolicy, d.Id(), err) + return sdkdiag.AppendFromErr(diags, err) } + log.Printf("[INFO] Deleting SESV2 EmailIdentityPolicy: %s", d.Id()) _, err = conn.DeleteEmailIdentityPolicy(ctx, &sesv2.DeleteEmailIdentityPolicyInput{ EmailIdentity: aws.String(emailIdentity), PolicyName: aws.String(policyName), }) - if err != nil { - var nfe *types.NotFoundException - if errors.As(err, &nfe) { - return diags - } + if errs.IsA[*types.NotFoundException](err) { + return diags + } - return create.AppendDiagError(diags, names.SESV2, create.ErrActionDeleting, ResNameEmailIdentityPolicy, d.Id(), err) + if err != nil { + return create.AppendDiagError(diags, names.SESV2, create.ErrActionDeleting, resNameEmailIdentityPolicy, d.Id(), err) } return diags } -func FindEmailIdentityPolicyByID(ctx context.Context, conn *sesv2.Client, id string) (string, error) { - emailIdentity, policyName, err := ParseEmailIdentityPolicyID(id) - if err != nil { - return "", err +const emailIdentityPolicyResourceIDSeparator = "|" + +func emailIdentityPolicyCreateResourceID(emailIdentity, policyName string) string { + parts := []string{emailIdentity, policyName} + id := strings.Join(parts, emailIdentityPolicyResourceIDSeparator) + + return id +} + +func emailIdentityPolicyParseResourceID(id string) (string, string, error) { + parts := strings.Split(id, emailIdentityPolicyResourceIDSeparator) + + if len(parts) != 2 || parts[0] == "" || parts[1] == "" { + return "", "", fmt.Errorf("unexpected format of ID (%[1]s), expected EMAIL_IDENTITY%[2]sPOLICY_NAME", id, emailIdentityPolicyResourceIDSeparator) } - in := &sesv2.GetEmailIdentityPoliciesInput{ + return parts[0], parts[1], nil +} + +func findEmailIdentityPolicyByTwoPartKey(ctx context.Context, conn *sesv2.Client, emailIdentity, policyName string) (*string, error) { + input := &sesv2.GetEmailIdentityPoliciesInput{ EmailIdentity: aws.String(emailIdentity), } + output, err := findEmailIdentityPolicies(ctx, conn, input) - out, err := conn.GetEmailIdentityPolicies(ctx, in) if err != nil { - var nfe *types.NotFoundException - if errors.As(err, &nfe) { - return "", &retry.NotFoundError{ - LastError: err, - LastRequest: in, - } - } - - return "", err + return nil, err } - if out == nil { - return "", tfresource.NewEmptyResultError(in) + if output, ok := output[policyName]; ok { + return aws.String(output), nil } - for name, policy := range out.Policies { - if policyName == name { - return policy, nil + return nil, tfresource.NewEmptyResultError(input) +} + +func findEmailIdentityPolicies(ctx context.Context, conn *sesv2.Client, input *sesv2.GetEmailIdentityPoliciesInput) (map[string]string, error) { + output, err := conn.GetEmailIdentityPolicies(ctx, input) + + if errs.IsA[*types.NotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, } } - return "", &retry.NotFoundError{} -} - -func FormatEmailIdentityPolicyID(emailIdentity, policyName string) string { - return fmt.Sprintf("%s|%s", emailIdentity, policyName) -} + if err != nil { + return nil, err + } -func ParseEmailIdentityPolicyID(id string) (string, string, error) { - idParts := strings.Split(id, "|") - if len(idParts) != 2 { - return "", "", errors.New("please make sure the ID is in the form EMAIL_IDENTITY|POLICY_NAME") + if output == nil || output.Policies == nil { + return nil, tfresource.NewEmptyResultError(input) } - return idParts[0], idParts[1], nil + return output.Policies, nil } diff --git a/internal/service/sesv2/email_identity_policy_test.go b/internal/service/sesv2/email_identity_policy_test.go index 7e511bdf303..bdf47bdb777 100644 --- a/internal/service/sesv2/email_identity_policy_test.go +++ b/internal/service/sesv2/email_identity_policy_test.go @@ -5,18 +5,16 @@ package sesv2_test import ( "context" - "errors" "fmt" "testing" - "github.com/aws/aws-sdk-go-v2/service/sesv2/types" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" - "github.com/hashicorp/terraform-provider-aws/internal/create" tfsesv2 "github.com/hashicorp/terraform-provider-aws/internal/service/sesv2" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -83,43 +81,35 @@ func testAccCheckEmailIdentityPolicyDestroy(ctx context.Context) resource.TestCh continue } - _, err := tfsesv2.FindEmailIdentityPolicyByID(ctx, conn, rs.Primary.ID) + _, err := tfsesv2.FindEmailIdentityPolicyByTwoPartKey(ctx, conn, rs.Primary.Attributes["email_identity"], rs.Primary.Attributes["policy_name"]) + + if tfresource.NotFound(err) { + continue + } if err != nil { - var nfe *types.NotFoundException - if errors.As(err, &nfe) { - return nil - } return err } - return create.Error(names.SESV2, create.ErrActionCheckingDestroyed, tfsesv2.ResNameEmailIdentityPolicy, rs.Primary.ID, errors.New("not destroyed")) + return fmt.Errorf("SESv2 Email Identity Policy %s still exists", rs.Primary.ID) } return nil } } -func testAccCheckEmailIdentityPolicyExists(ctx context.Context, name string) resource.TestCheckFunc { +func testAccCheckEmailIdentityPolicyExists(ctx context.Context, n string) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[name] + rs, ok := s.RootModule().Resources[n] if !ok { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameEmailIdentityPolicy, name, errors.New("not found")) - } - - if rs.Primary.ID == "" { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameEmailIdentityPolicy, name, errors.New("not set")) + return fmt.Errorf("Not found: %s", n) } conn := acctest.Provider.Meta().(*conns.AWSClient).SESV2Client(ctx) - _, err := tfsesv2.FindEmailIdentityPolicyByID(ctx, conn, rs.Primary.ID) - - if err != nil { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameEmailIdentityPolicy, rs.Primary.ID, err) - } + _, err := tfsesv2.FindEmailIdentityPolicyByTwoPartKey(ctx, conn, rs.Primary.Attributes["email_identity"], rs.Primary.Attributes["policy_name"]) - return nil + return err } } diff --git a/internal/service/sesv2/email_identity_test.go b/internal/service/sesv2/email_identity_test.go index b8cdc44ef73..c8e030ef82b 100644 --- a/internal/service/sesv2/email_identity_test.go +++ b/internal/service/sesv2/email_identity_test.go @@ -5,7 +5,6 @@ package sesv2_test import ( "context" - "errors" "fmt" "testing" @@ -16,8 +15,8 @@ import ( "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" - "github.com/hashicorp/terraform-provider-aws/internal/create" tfsesv2 "github.com/hashicorp/terraform-provider-aws/internal/service/sesv2" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" itypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -290,41 +289,33 @@ func testAccCheckEmailIdentityDestroy(ctx context.Context) resource.TestCheckFun _, err := tfsesv2.FindEmailIdentityByID(ctx, conn, rs.Primary.ID) + if tfresource.NotFound(err) { + continue + } + if err != nil { - var nfe *types.NotFoundException - if errors.As(err, &nfe) { - return nil - } return err } - return create.Error(names.SESV2, create.ErrActionCheckingDestroyed, tfsesv2.ResNameEmailIdentity, rs.Primary.ID, errors.New("not destroyed")) + return fmt.Errorf("SESv2 Email Identity %s still exists", rs.Primary.ID) } return nil } } -func testAccCheckEmailIdentityExists(ctx context.Context, name string) resource.TestCheckFunc { +func testAccCheckEmailIdentityExists(ctx context.Context, n string) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[name] + rs, ok := s.RootModule().Resources[n] if !ok { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameEmailIdentity, name, errors.New("not found")) - } - - if rs.Primary.ID == "" { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameEmailIdentity, name, errors.New("not set")) + return fmt.Errorf("Not found: %s", n) } conn := acctest.Provider.Meta().(*conns.AWSClient).SESV2Client(ctx) _, err := tfsesv2.FindEmailIdentityByID(ctx, conn, rs.Primary.ID) - if err != nil { - return create.Error(names.SESV2, create.ErrActionCheckingExistence, tfsesv2.ResNameEmailIdentity, rs.Primary.ID, err) - } - - return nil + return err } } diff --git a/internal/service/sesv2/exports_test.go b/internal/service/sesv2/exports_test.go new file mode 100644 index 00000000000..82cc43d99ab --- /dev/null +++ b/internal/service/sesv2/exports_test.go @@ -0,0 +1,27 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package sesv2 + +// Exports for use in tests only. +var ( + ResourceAccountVDMAttributes = resourceAccountVDMAttributes + ResourceConfigurationSet = resourceConfigurationSet + ResourceConfigurationSetEventDestination = resourceConfigurationSetEventDestination + ResourceContactList = resourceContactList + ResourceDedicatedIPAssignment = resourceDedicatedIPAssignment + ResourceDedicatedIPPool = resourceDedicatedIPPool + ResourceEmailIdentity = resourceEmailIdentity + ResourceEmailIdentityFeedbackAttributes = resourceEmailIdentityFeedbackAttributes + ResourceEmailIdentityMailFromAttributes = resourceEmailIdentityMailFromAttributes + ResourceEmailIdentityPolicy = resourceEmailIdentityPolicy + + FindAccountVDMAttributes = findAccountVDMAttributes + FindConfigurationSetByID = findConfigurationSetByID + FindConfigurationSetEventDestinationByTwoPartKey = findConfigurationSetEventDestinationByTwoPartKey + FindContactListByID = findContactListByID + FindDedicatedIPByTwoPartKey = findDedicatedIPByTwoPartKey + FindDedicatedIPPoolByName = findDedicatedIPPoolByName + FindEmailIdentityByID = findEmailIdentityByID + FindEmailIdentityPolicyByTwoPartKey = findEmailIdentityPolicyByTwoPartKey +) diff --git a/internal/service/sesv2/list.go b/internal/service/sesv2/list.go deleted file mode 100644 index 963655c957c..00000000000 --- a/internal/service/sesv2/list.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package sesv2 - -import ( - "context" - - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/sesv2" -) - -func listConfigurationSetsPages(ctx context.Context, conn *sesv2.Client, in *sesv2.ListConfigurationSetsInput, fn func(*sesv2.ListConfigurationSetsOutput, bool) bool) error { - for { - out, err := conn.ListConfigurationSets(ctx, in) - if err != nil { - return err - } - - lastPage := aws.ToString(out.NextToken) == "" - if !fn(out, lastPage) || lastPage { - break - } - - in.NextToken = out.NextToken - } - - return nil -} - -func listContactListsPages(ctx context.Context, conn *sesv2.Client, in *sesv2.ListContactListsInput, fn func(*sesv2.ListContactListsOutput, bool) bool) error { - for { - out, err := conn.ListContactLists(ctx, in) - if err != nil { - return err - } - - lastPage := aws.ToString(out.NextToken) == "" - if !fn(out, lastPage) || lastPage { - break - } - - in.NextToken = out.NextToken - } - - return nil -} diff --git a/internal/service/sesv2/service_package_gen.go b/internal/service/sesv2/service_package_gen.go index 4fb43b1fecb..9bcfb7b9064 100644 --- a/internal/service/sesv2/service_package_gen.go +++ b/internal/service/sesv2/service_package_gen.go @@ -25,23 +25,27 @@ func (p *servicePackage) FrameworkResources(ctx context.Context) []*types.Servic func (p *servicePackage) SDKDataSources(ctx context.Context) []*types.ServicePackageSDKDataSource { return []*types.ServicePackageSDKDataSource{ { - Factory: DataSourceConfigurationSet, + Factory: dataSourceConfigurationSet, TypeName: "aws_sesv2_configuration_set", + Name: "Configuration Set", }, { - Factory: DataSourceDedicatedIPPool, + Factory: dataSourceDedicatedIPPool, TypeName: "aws_sesv2_dedicated_ip_pool", + Name: "Dedicated IP Pool", }, { - Factory: DataSourceEmailIdentity, + Factory: dataSourceEmailIdentity, TypeName: "aws_sesv2_email_identity", + Name: "Email Identity", Tags: &types.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, }, }, { - Factory: DataSourceEmailIdentityMailFromAttributes, + Factory: dataSourceEmailIdentityMailFromAttributes, TypeName: "aws_sesv2_email_identity_mail_from_attributes", + Name: "Email Identity Mail From Attributes", }, } } @@ -49,12 +53,12 @@ func (p *servicePackage) SDKDataSources(ctx context.Context) []*types.ServicePac func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePackageSDKResource { return []*types.ServicePackageSDKResource{ { - Factory: ResourceAccountVDMAttributes, + Factory: resourceAccountVDMAttributes, TypeName: "aws_sesv2_account_vdm_attributes", Name: "Account VDM Attributes", }, { - Factory: ResourceConfigurationSet, + Factory: resourceConfigurationSet, TypeName: "aws_sesv2_configuration_set", Name: "Configuration Set", Tags: &types.ServicePackageResourceTags{ @@ -62,11 +66,12 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePacka }, }, { - Factory: ResourceConfigurationSetEventDestination, + Factory: resourceConfigurationSetEventDestination, TypeName: "aws_sesv2_configuration_set_event_destination", + Name: "Configuration Set Event Destination", }, { - Factory: ResourceContactList, + Factory: resourceContactList, TypeName: "aws_sesv2_contact_list", Name: "Contact List", Tags: &types.ServicePackageResourceTags{ @@ -74,11 +79,12 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePacka }, }, { - Factory: ResourceDedicatedIPAssignment, + Factory: resourceDedicatedIPAssignment, TypeName: "aws_sesv2_dedicated_ip_assignment", + Name: "Dedicated IP Assignment", }, { - Factory: ResourceDedicatedIPPool, + Factory: resourceDedicatedIPPool, TypeName: "aws_sesv2_dedicated_ip_pool", Name: "Dedicated IP Pool", Tags: &types.ServicePackageResourceTags{ @@ -86,7 +92,7 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePacka }, }, { - Factory: ResourceEmailIdentity, + Factory: resourceEmailIdentity, TypeName: "aws_sesv2_email_identity", Name: "Email Identity", Tags: &types.ServicePackageResourceTags{ @@ -94,15 +100,17 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePacka }, }, { - Factory: ResourceEmailIdentityFeedbackAttributes, + Factory: resourceEmailIdentityFeedbackAttributes, TypeName: "aws_sesv2_email_identity_feedback_attributes", + Name: "Email Identity Feedback Attributes", }, { - Factory: ResourceEmailIdentityMailFromAttributes, + Factory: resourceEmailIdentityMailFromAttributes, TypeName: "aws_sesv2_email_identity_mail_from_attributes", + Name: "Email Identity Mail From Attributes", }, { - Factory: ResourceEmailIdentityPolicy, + Factory: resourceEmailIdentityPolicy, TypeName: "aws_sesv2_email_identity_policy", Name: "Email Identity Policy", }, diff --git a/internal/service/sesv2/sweep.go b/internal/service/sesv2/sweep.go index 51b13d4778c..98b75f7afc2 100644 --- a/internal/service/sesv2/sweep.go +++ b/internal/service/sesv2/sweep.go @@ -9,7 +9,6 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/sesv2" - "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-provider-aws/internal/sweep" "github.com/hashicorp/terraform-provider-aws/internal/sweep/awsv2" @@ -30,93 +29,81 @@ func RegisterSweepers() { func sweepConfigurationSets(region string) error { ctx := sweep.Context(region) client, err := sweep.SharedRegionalSweepClient(ctx, region) - if err != nil { return fmt.Errorf("getting client: %w", err) } - conn := client.SESV2Client(ctx) + input := &sesv2.ListConfigurationSetsInput{} sweepResources := make([]sweep.Sweepable, 0) - var errs *multierror.Error - input := &sesv2.ListConfigurationSetsInput{} + pages := sesv2.NewListConfigurationSetsPaginator(conn, input) + for pages.HasMorePages() { + page, err := pages.NextPage(ctx) - err = listConfigurationSetsPages(ctx, conn, input, func(page *sesv2.ListConfigurationSetsOutput, lastPage bool) bool { - if page == nil { - return !lastPage + if awsv2.SkipSweepError(err) { + log.Printf("[WARN] Skipping SESv2 Configuration Set sweep for %s: %s", region, err) + return nil } - for _, configurationSet := range page.ConfigurationSets { - r := ResourceConfigurationSet() - d := r.Data(nil) + if err != nil { + return fmt.Errorf("error listing SESv2 Configuration Sets (%s): %w", region, err) + } - d.SetId(configurationSet) + for _, v := range page.ConfigurationSets { + r := resourceConfigurationSet() + d := r.Data(nil) + d.SetId(v) sweepResources = append(sweepResources, sweep.NewSweepResource(r, d, client)) } - - return !lastPage - }) - - if err != nil { - errs = multierror.Append(errs, fmt.Errorf("listing Configuration Sets for %s: %w", region, err)) } - if err := sweep.SweepOrchestrator(ctx, sweepResources); err != nil { - errs = multierror.Append(errs, fmt.Errorf("sweeping Configuration Sets for %s: %w", region, err)) - } + err = sweep.SweepOrchestrator(ctx, sweepResources) - if awsv2.SkipSweepError(err) { - log.Printf("[WARN] Skipping Configuration Sets sweep for %s: %s", region, errs) - return nil + if err != nil { + return fmt.Errorf("error sweeping SESv2 Configuration Sets (%s): %w", region, err) } - return errs.ErrorOrNil() + return nil } func sweepContactLists(region string) error { ctx := sweep.Context(region) client, err := sweep.SharedRegionalSweepClient(ctx, region) - if err != nil { return fmt.Errorf("getting client: %w", err) } - conn := client.SESV2Client(ctx) + input := &sesv2.ListContactListsInput{} sweepResources := make([]sweep.Sweepable, 0) - var errs *multierror.Error - input := &sesv2.ListContactListsInput{} + pages := sesv2.NewListContactListsPaginator(conn, input) + for pages.HasMorePages() { + page, err := pages.NextPage(ctx) - err = listContactListsPages(ctx, conn, input, func(page *sesv2.ListContactListsOutput, lastPage bool) bool { - if page == nil { - return !lastPage + if awsv2.SkipSweepError(err) { + log.Printf("[WARN] Skipping SESv2 Contact List sweep for %s: %s", region, err) + return nil } - for _, contactList := range page.ContactLists { - r := ResourceContactList() - d := r.Data(nil) + if err != nil { + return fmt.Errorf("error listing SESv2 Contact Lists (%s): %w", region, err) + } - d.SetId(aws.ToString(contactList.ContactListName)) + for _, v := range page.ContactLists { + r := resourceContactList() + d := r.Data(nil) + d.SetId(aws.ToString(v.ContactListName)) sweepResources = append(sweepResources, sweep.NewSweepResource(r, d, client)) } - - return !lastPage - }) - - if err != nil { - errs = multierror.Append(errs, fmt.Errorf("listing Contact Lists for %s: %w", region, err)) } - if err := sweep.SweepOrchestrator(ctx, sweepResources); err != nil { - errs = multierror.Append(errs, fmt.Errorf("sweeping Contact Lists for %s: %w", region, err)) - } + err = sweep.SweepOrchestrator(ctx, sweepResources) - if awsv2.SkipSweepError(err) { - log.Printf("[WARN] Skipping Contact Lists sweep for %s: %s", region, errs) - return nil + if err != nil { + return fmt.Errorf("error sweeping SESv2 Contact Lists (%s): %w", region, err) } - return errs.ErrorOrNil() + return nil } diff --git a/website/docs/r/sesv2_dedicated_ip_assignment.html.markdown b/website/docs/r/sesv2_dedicated_ip_assignment.html.markdown index acbf1c56b11..edb5bfc0ad5 100644 --- a/website/docs/r/sesv2_dedicated_ip_assignment.html.markdown +++ b/website/docs/r/sesv2_dedicated_ip_assignment.html.markdown @@ -36,13 +36,6 @@ This resource exports the following attributes in addition to the arguments abov * `id` - A comma-separated string made up of `ip` and `destination_pool_name`. -## Timeouts - -[Configuration options](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts): - -* `create` - (Default `30m`) -* `delete` - (Default `30m`) - ## Import In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import SESv2 (Simple Email V2) Dedicated IP Assignment using the `id`, which is a comma-separated string made up of `ip` and `destination_pool_name`. For example: diff --git a/website/docs/r/sesv2_dedicated_ip_pool.html.markdown b/website/docs/r/sesv2_dedicated_ip_pool.html.markdown index 74a5c7ab5d5..ea7b2f95969 100644 --- a/website/docs/r/sesv2_dedicated_ip_pool.html.markdown +++ b/website/docs/r/sesv2_dedicated_ip_pool.html.markdown @@ -46,14 +46,6 @@ This resource exports the following attributes in addition to the arguments abov * `arn` - ARN of the Dedicated IP Pool. -## Timeouts - -[Configuration options](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts): - -* `create` - (Default `30m`) -* `update` - (Default `30m`) -* `delete` - (Default `30m`) - ## Import In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import SESv2 (Simple Email V2) Dedicated IP Pool using the `pool_name`. For example: