Skip to content

Commit

Permalink
Merge pull request #37977 from hashicorp/b-d/aws_ami.amiProductCodesH…
Browse files Browse the repository at this point in the history
…ash-crash

d/aws_ami: Fix `interface conversion: interface {} is types.ProductCodeValues, not string` panic
  • Loading branch information
ewbankkit committed Jun 14, 2024
2 parents ea4ad9b + 2c4bb43 commit cba256a
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 70 deletions.
3 changes: 3 additions & 0 deletions .changelog/#####.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
data-source/aws_ami: Fix `interface conversion: interface {} is types.ProductCodeValues, not string` panic
```
105 changes: 35 additions & 70 deletions internal/service/ec2/ec2_ami_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@
package ec2

import (
"bytes"
"context"
"fmt"
"log"
"sort"
"time"

Expand All @@ -20,7 +18,6 @@ import (
"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"
"github.com/hashicorp/terraform-provider-aws/internal/flex"
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
Expand Down Expand Up @@ -50,7 +47,6 @@ func dataSourceAMI() *schema.Resource {
"block_device_mappings": {
Type: schema.TypeSet,
Computed: true,
Set: amiBlockDeviceMappingHash,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
names.AttrDeviceName: {
Expand Down Expand Up @@ -170,7 +166,6 @@ func dataSourceAMI() *schema.Resource {
"product_codes": {
Type: schema.TypeSet,
Computed: true,
Set: amiProductCodesHash,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"product_code_id": {
Expand Down Expand Up @@ -349,48 +344,54 @@ func dataSourceAMIRead(ctx context.Context, d *schema.ResourceData, meta interfa
return diags
}

func flattenAMIBlockDeviceMappings(m []awstypes.BlockDeviceMapping) *schema.Set {
s := &schema.Set{
F: amiBlockDeviceMappingHash,
func flattenAMIBlockDeviceMappings(apiObjects []awstypes.BlockDeviceMapping) []interface{} {
if len(apiObjects) == 0 {
return nil
}
for _, v := range m {
mapping := map[string]interface{}{
names.AttrDeviceName: aws.ToString(v.DeviceName),
names.AttrVirtualName: aws.ToString(v.VirtualName),

var tfList []interface{}

for _, apiObject := range apiObjects {
tfMap := map[string]interface{}{
names.AttrDeviceName: aws.ToString(apiObject.DeviceName),
names.AttrVirtualName: aws.ToString(apiObject.VirtualName),
}

if v.Ebs != nil {
if apiObject := apiObject.Ebs; apiObject != nil {
ebs := map[string]interface{}{
names.AttrDeleteOnTermination: fmt.Sprintf("%t", aws.ToBool(v.Ebs.DeleteOnTermination)),
names.AttrEncrypted: fmt.Sprintf("%t", aws.ToBool(v.Ebs.Encrypted)),
names.AttrIOPS: fmt.Sprintf("%d", aws.ToInt32(v.Ebs.Iops)),
names.AttrThroughput: fmt.Sprintf("%d", aws.ToInt32(v.Ebs.Throughput)),
names.AttrVolumeSize: fmt.Sprintf("%d", aws.ToInt32(v.Ebs.VolumeSize)),
names.AttrSnapshotID: aws.ToString(v.Ebs.SnapshotId),
names.AttrVolumeType: v.Ebs.VolumeType,
names.AttrDeleteOnTermination: flex.BoolToStringValue(apiObject.DeleteOnTermination),
names.AttrEncrypted: flex.BoolToStringValue(apiObject.Encrypted),
names.AttrIOPS: flex.Int32ToStringValue(apiObject.Iops),
names.AttrSnapshotID: aws.ToString(apiObject.SnapshotId),
names.AttrThroughput: flex.Int32ToStringValue(apiObject.Throughput),
names.AttrVolumeSize: flex.Int32ToStringValue(apiObject.VolumeSize),
names.AttrVolumeType: apiObject.VolumeType,
}

mapping["ebs"] = ebs
tfMap["ebs"] = ebs
}

log.Printf("[DEBUG] aws_ami - adding block device mapping: %v", mapping)
s.Add(mapping)
tfList = append(tfList, tfMap)
}
return s

return tfList
}

func flattenAMIProductCodes(m []awstypes.ProductCode) *schema.Set {
s := &schema.Set{
F: amiProductCodesHash,
func flattenAMIProductCodes(apiObjects []awstypes.ProductCode) []interface{} {
if len(apiObjects) == 0 {
return nil
}
for _, v := range m {
code := map[string]interface{}{
"product_code_id": aws.ToString(v.ProductCodeId),
"product_code_type": v.ProductCodeType,
}
s.Add(code)

var tfList []interface{}

for _, apiObject := range apiObjects {
tfList = append(tfList, map[string]interface{}{
"product_code_id": aws.ToString(apiObject.ProductCodeId),
"product_code_type": apiObject.ProductCodeType,
})
}
return s

return tfList
}

func amiRootSnapshotId(image awstypes.Image) string {
Expand Down Expand Up @@ -420,39 +421,3 @@ func flattenAMIStateReason(m *awstypes.StateReason) map[string]interface{} {
}
return s
}

func amiBlockDeviceMappingHash(v interface{}) int {
var buf bytes.Buffer
// All keys added in alphabetical order.
m := v.(map[string]interface{})
buf.WriteString(fmt.Sprintf("%s-", m[names.AttrDeviceName].(string)))
if d, ok := m["ebs"]; ok {
if len(d.(map[string]interface{})) > 0 {
e := d.(map[string]interface{})
buf.WriteString(fmt.Sprintf("%s-", e[names.AttrDeleteOnTermination].(string)))
buf.WriteString(fmt.Sprintf("%s-", e[names.AttrEncrypted].(string)))
buf.WriteString(fmt.Sprintf("%s-", e[names.AttrIOPS].(string)))
buf.WriteString(fmt.Sprintf("%s-", e[names.AttrVolumeSize].(string)))
buf.WriteString(fmt.Sprintf("%s-", e[names.AttrVolumeType]))
}
}
if d, ok := m["no_device"]; ok {
buf.WriteString(fmt.Sprintf("%s-", d.(string)))
}
if d, ok := m[names.AttrVirtualName]; ok {
buf.WriteString(fmt.Sprintf("%s-", d.(string)))
}
if d, ok := m[names.AttrSnapshotID]; ok {
buf.WriteString(fmt.Sprintf("%s-", d.(string)))
}
return create.StringHashcode(buf.String())
}

func amiProductCodesHash(v interface{}) int {
var buf bytes.Buffer
m := v.(map[string]interface{})
// All keys added in alphabetical order.
buf.WriteString(fmt.Sprintf("%s-", m["product_code_id"].(string)))
buf.WriteString(fmt.Sprintf("%s-", m["product_code_type"].(string)))
return create.StringHashcode(buf.String())
}
32 changes: 32 additions & 0 deletions internal/service/ec2/ec2_ami_data_source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,25 @@ func TestAccEC2AMIDataSource_gp3BlockDevice(t *testing.T) {
})
}

func TestAccEC2AMIDataSource_productCode(t *testing.T) {
ctx := acctest.Context(t)
datasourceName := "data.aws_ami.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
Steps: []resource.TestStep{
{
Config: testAccAMIDataSourceConfig_productCode,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(datasourceName, "product_codes.#", acctest.Ct1),
),
},
},
})
}

// testAccAMIDataSourceConfig_latestUbuntuBionicHVMInstanceStore returns the configuration for a data source that
// describes the latest Ubuntu 18.04 AMI using HVM virtualization and an instance store root device.
// The data source is named 'ubuntu-bionic-ami-hvm-instance-store'.
Expand Down Expand Up @@ -322,3 +341,16 @@ data "aws_ami" "test" {
}
`)
}

// Image with product code.
const testAccAMIDataSourceConfig_productCode = `
data "aws_ami" "test" {
most_recent = true
owners = ["679593333241"]
filter {
name = "name"
values = ["AwsMarketPublished_IBM App Connect v12.0.12.0 and IBM MQ v9.3.0.16 with RapidDeploy 5.1.12 -422d2ddd-3288-4067-be37-4e2a69450606"]
}
}
`

0 comments on commit cba256a

Please sign in to comment.