Skip to content

Commit

Permalink
Merge pull request #34012 from hashicorp/b-d/aws_dms_certificate-crash
Browse files Browse the repository at this point in the history
d/aws_dms_certificate: Fix crash when certificate not found
  • Loading branch information
ewbankkit authored Oct 19, 2023
2 parents 023b53c + fbc36b8 commit 5a8446d
Show file tree
Hide file tree
Showing 10 changed files with 287 additions and 344 deletions.
3 changes: 3 additions & 0 deletions .changelog/34012.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
data-source/aws_dms_certificate: Fix crash when certificate not found
```
137 changes: 86 additions & 51 deletions internal/service/dms/certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ import (
dms "github.com/aws/aws-sdk-go/service/databasemigrationservice"
"github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr"
"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-plugin-sdk/v2/helper/validation"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag"
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"
"github.com/hashicorp/terraform-provider-aws/names"
)
Expand Down Expand Up @@ -52,16 +54,18 @@ func ResourceCertificate() *schema.Resource {
),
},
"certificate_pem": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Sensitive: true,
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Sensitive: true,
ExactlyOneOf: []string{"certificate_pem", "certificate_wallet"},
},
"certificate_wallet": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Sensitive: true,
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Sensitive: true,
ExactlyOneOf: []string{"certificate_pem", "certificate_wallet"},
},
names.AttrTags: tftags.TagsSchema(),
names.AttrTagsAll: tftags.TagsSchemaComputed(),
Expand All @@ -76,55 +80,41 @@ func resourceCertificateCreate(ctx context.Context, d *schema.ResourceData, meta
conn := meta.(*conns.AWSClient).DMSConn(ctx)

certificateID := d.Get("certificate_id").(string)
request := &dms.ImportCertificateInput{
input := &dms.ImportCertificateInput{
CertificateIdentifier: aws.String(certificateID),
Tags: getTagsIn(ctx),
}

pem, pemSet := d.GetOk("certificate_pem")
wallet, walletSet := d.GetOk("certificate_wallet")

if !pemSet && !walletSet {
return sdkdiag.AppendErrorf(diags, "Must set either certificate_pem or certificate_wallet for DMS Certificate (%s)", certificateID)
}
if pemSet && walletSet {
return sdkdiag.AppendErrorf(diags, "Cannot set both certificate_pem and certificate_wallet for DMS Certificate (%s)", certificateID)
if v, ok := d.GetOk("certificate_pem"); ok {
input.CertificatePem = aws.String(v.(string))
}

if pemSet {
request.CertificatePem = aws.String(pem.(string))
}
if walletSet {
certWallet, err := base64.StdEncoding.DecodeString(wallet.(string))
if v, ok := d.GetOk("certificate_wallet"); ok {
certWallet, err := base64.StdEncoding.DecodeString(v.(string))
if err != nil {
return sdkdiag.AppendErrorf(diags, "Base64 decoding certificate_wallet for DMS Certificate (%s): %s", certificateID, err)
return sdkdiag.AppendFromErr(diags, err)
}
request.CertificateWallet = certWallet
input.CertificateWallet = certWallet
}

_, err := conn.ImportCertificateWithContext(ctx, request)
_, err := conn.ImportCertificateWithContext(ctx, input)

if err != nil {
return sdkdiag.AppendErrorf(diags, "creating DMS certificate (%s): %s", certificateID, err)
return sdkdiag.AppendErrorf(diags, "creating DMS Certificate (%s): %s", certificateID, err)
}

d.SetId(certificateID)

return append(diags, resourceCertificateRead(ctx, d, meta)...)
}

func resourceCertificateRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).DMSConn(ctx)

response, err := conn.DescribeCertificatesWithContext(ctx, &dms.DescribeCertificatesInput{
Filters: []*dms.Filter{
{
Name: aws.String("certificate-id"),
Values: []*string{aws.String(d.Id())}, // Must use d.Id() to work with import.
},
},
})
certificate, err := FindCertificateByID(ctx, conn, d.Id())

if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, dms.ErrCodeResourceNotFoundFault) {
if !d.IsNewResource() && tfresource.NotFound(err) {
log.Printf("[WARN] DMS Certificate (%s) not found, removing from state", d.Id())
d.SetId("")
return diags
Expand All @@ -134,16 +124,7 @@ func resourceCertificateRead(ctx context.Context, d *schema.ResourceData, meta i
return sdkdiag.AppendErrorf(diags, "reading DMS Certificate (%s): %s", d.Id(), err)
}

if response == nil || len(response.Certificates) == 0 || response.Certificates[0] == nil {
if d.IsNewResource() {
return sdkdiag.AppendErrorf(diags, "reading DMS Certificate (%s): not found", d.Id())
}
log.Printf("[WARN] DMS Certificate (%s) not found, removing from state", d.Id())
d.SetId("")
return diags
}

resourceCertificateSetState(d, response.Certificates[0])
resourceCertificateSetState(d, certificate)

return diags
}
Expand All @@ -160,16 +141,16 @@ func resourceCertificateDelete(ctx context.Context, d *schema.ResourceData, meta
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).DMSConn(ctx)

request := &dms.DeleteCertificateInput{
log.Printf("[DEBUG] Deleting DMS Certificate: %s", d.Id())
_, err := conn.DeleteCertificateWithContext(ctx, &dms.DeleteCertificateInput{
CertificateArn: aws.String(d.Get("certificate_arn").(string)),
}
})

_, err := conn.DeleteCertificateWithContext(ctx, request)
if tfawserr.ErrCodeEquals(err, dms.ErrCodeResourceNotFoundFault) {
return diags
}

if err != nil {
if tfawserr.ErrCodeEquals(err, dms.ErrCodeResourceNotFoundFault) {
return diags
}
return sdkdiag.AppendErrorf(diags, "deleting DMS Certificate (%s): %s", d.Id(), err)
}

Expand All @@ -189,3 +170,57 @@ func resourceCertificateSetState(d *schema.ResourceData, cert *dms.Certificate)
d.Set("certificate_wallet", verify.Base64Encode(cert.CertificateWallet))
}
}

func FindCertificateByID(ctx context.Context, conn *dms.DatabaseMigrationService, id string) (*dms.Certificate, error) {
input := &dms.DescribeCertificatesInput{
Filters: []*dms.Filter{
{
Name: aws.String("certificate-id"),
Values: []*string{aws.String(id)},
},
},
}

return findCertificate(ctx, conn, input)
}

func findCertificate(ctx context.Context, conn *dms.DatabaseMigrationService, input *dms.DescribeCertificatesInput) (*dms.Certificate, error) {
output, err := findCertificates(ctx, conn, input)

if err != nil {
return nil, err
}

return tfresource.AssertSinglePtrResult(output)
}

func findCertificates(ctx context.Context, conn *dms.DatabaseMigrationService, input *dms.DescribeCertificatesInput) ([]*dms.Certificate, error) {
var output []*dms.Certificate

err := conn.DescribeCertificatesPagesWithContext(ctx, input, func(page *dms.DescribeCertificatesOutput, lastPage bool) bool {
if page == nil {
return !lastPage
}

for _, v := range page.Certificates {
if v != nil {
output = append(output, v)
}
}

return !lastPage
})

if tfawserr.ErrCodeEquals(err, dms.ErrCodeResourceNotFoundFault) {
return nil, &retry.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

return output, nil
}
59 changes: 12 additions & 47 deletions internal/service/dms/certificate_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,13 @@ import (

"github.com/YakDriver/regexache"
"github.com/aws/aws-sdk-go/aws"
dms "github.com/aws/aws-sdk-go/service/databasemigrationservice"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/create"
"github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag"
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"
"github.com/hashicorp/terraform-provider-aws/names"
)

// @SDKDataSource("aws_dms_certificate")
Expand Down Expand Up @@ -66,6 +63,7 @@ func DataSourceCertificate() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"tags": tftags.TagsSchemaComputed(),
"valid_from_date": {
Type: schema.TypeString,
Computed: true,
Expand All @@ -74,80 +72,47 @@ func DataSourceCertificate() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"tags": tftags.TagsSchemaComputed(),
},
}
}

const (
DSNameCertificate = "Certificate Data Source"
)

func dataSourceCertificateRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).DMSConn(ctx)
defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig
ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig

certificateID := d.Get("certificate_id").(string)

out, err := FindCertificateByID(ctx, conn, certificateID)

if err != nil {
create.DiagError(names.DMS, create.ErrActionReading, DSNameCertificate, d.Id(), err)
return sdkdiag.AppendErrorf(diags, "reading DMS Certificate (%s): %s", certificateID, err)
}

d.SetId(aws.StringValue(out.CertificateIdentifier))

arn := aws.StringValue(out.CertificateArn)
d.Set("certificate_arn", arn)
d.Set("certificate_id", out.CertificateIdentifier)
d.Set("certificate_arn", out.CertificateArn)
d.Set("certificate_pem", out.CertificatePem)

if out.CertificateWallet != nil && len(out.CertificateWallet) != 0 {
if len(out.CertificateWallet) != 0 {
d.Set("certificate_wallet", verify.Base64Encode(out.CertificateWallet))
}

d.Set("key_length", out.KeyLength)
d.Set("signing_algorithm", out.SigningAlgorithm)
d.Set("valid_from_date", out.ValidFromDate.String())
d.Set("valid_to_date", out.ValidToDate.String())

from_date := out.ValidFromDate.String()
d.Set("valid_from_date", from_date)
to_date := out.ValidToDate.String()
d.Set("valid_to_date", to_date)

tags, err := listTags(ctx, conn, aws.StringValue(out.CertificateArn))

tags, err := listTags(ctx, conn, arn)
if err != nil {
return create.DiagError(names.DMS, create.ErrActionReading, DSNameCertificate, d.Id(), err)
return sdkdiag.AppendErrorf(diags, "listing tags for DMS Certificate (%s): %s", arn, err)
}

tags = tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig)

//lintignore:AWSR002
if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil {
return create.DiagError(names.DMS, create.ErrActionSetting, DSNameCertificate, d.Id(), err)
return sdkdiag.AppendErrorf(diags, "setting tags: %s", err)
}

return nil
}

func FindCertificateByID(ctx context.Context, conn *dms.DatabaseMigrationService, id string) (*dms.Certificate, error) {
input := &dms.DescribeCertificatesInput{
Filters: []*dms.Filter{
{
Name: aws.String("certificate-id"),
Values: []*string{aws.String(id)},
},
},
}
response, err := conn.DescribeCertificatesWithContext(ctx, input)

if err != nil {
return nil, err
}

if response == nil || len(response.Certificates) == 0 || response.Certificates[0] == nil {
return nil, tfresource.NewEmptyResultError(input)
}

return response.Certificates[0], nil
}
6 changes: 3 additions & 3 deletions internal/service/dms/certificate_data_source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ func TestAccDMSCertificateDataSource_basic(t *testing.T) {
})
}

func testAccCertificateDataSourceConfig_basic(certId string) string {
func testAccCertificateDataSourceConfig_basic(rName string) string {
return fmt.Sprintf(`
resource "aws_dms_certificate" "test" {
certificate_id = "%[1]s"
certificate_id = %[1]q
certificate_pem = "-----BEGIN CERTIFICATE-----\nMIID2jCCAsKgAwIBAgIJAJ58TJVjU7G1MA0GCSqGSIb3DQEBBQUAMFExCzAJBgNV\nBAYTAlVTMREwDwYDVQQIEwhDb2xvcmFkbzEPMA0GA1UEBxMGRGVudmVyMRAwDgYD\nVQQKEwdDaGFydGVyMQwwCgYDVQQLEwNDU0UwHhcNMTcwMTMwMTkyMDA4WhcNMjYx\nMjA5MTkyMDA4WjBRMQswCQYDVQQGEwJVUzERMA8GA1UECBMIQ29sb3JhZG8xDzAN\nBgNVBAcTBkRlbnZlcjEQMA4GA1UEChMHQ2hhcnRlcjEMMAoGA1UECxMDQ1NFMIIB\nIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv6dq6VLIImlAaTrckb5w3X6J\nWP7EGz2ChGAXlkEYto6dPCba0v5+f+8UlMOpeB25XGoai7gdItqNWVFpYsgmndx3\nvTad3ukO1zeElKtw5oHPH2plOaiv/gVJaDa9NTeINj0EtGZs74fCOclAzGFX5vBc\nb08ESWBceRgGjGv3nlij4JzHfqTkCKQz6P6pBivQBfk62rcOkkH5rKoaGltRHROS\nMbkwOhu2hN0KmSYTXRvts0LXnZU4N0l2ms39gmr7UNNNlKYINL2JoTs9dNBc7APD\ndZvlEHd+/FjcLCI8hC3t4g4AbfW0okIBCNG0+oVjqGb2DeONSJKsThahXt89MQID\nAQABo4G0MIGxMB0GA1UdDgQWBBQKq8JxjY1GmeZXJjfOMfW0kBIzPDCBgQYDVR0j\nBHoweIAUCqvCcY2NRpnmVyY3zjH1tJASMzyhVaRTMFExCzAJBgNVBAYTAlVTMREw\nDwYDVQQIEwhDb2xvcmFkbzEPMA0GA1UEBxMGRGVudmVyMRAwDgYDVQQKEwdDaGFy\ndGVyMQwwCgYDVQQLEwNDU0WCCQCefEyVY1OxtTAMBgNVHRMEBTADAQH/MA0GCSqG\nSIb3DQEBBQUAA4IBAQAWifoMk5kbv+yuWXvFwHiB4dWUUmMlUlPU/E300yVTRl58\np6DfOgJs7MMftd1KeWqTO+uW134QlTt7+jwI8Jq0uyKCu/O2kJhVtH/Ryog14tGl\n+wLcuIPLbwJI9CwZX4WMBrq4DnYss+6F47i8NCc+Z3MAiG4vtq9ytBmaod0dj2bI\ng4/Lac0e00dql9RnqENh1+dF0V+QgTJCoPkMqDNAlSB8vOodBW81UAb2z12t+IFi\n3X9J3WtCK2+T5brXL6itzewWJ2ALvX3QpmZx7fMHJ3tE+SjjyivE1BbOlzYHx83t\nTeYnm7pS9un7A/UzTDHbs7hPUezLek+H3xTPAnnq\n-----END CERTIFICATE-----\n"
}
data "aws_dms_certificate" "test" {
certificate_id = aws_dms_certificate.test.certificate_id
}
`, certId)
`, rName)
}
Loading

0 comments on commit 5a8446d

Please sign in to comment.