From ff4a9b007549977442a0f1aca8dbe79eaa296884 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 4 Feb 2022 08:12:14 +0200 Subject: [PATCH 1/4] ami boot mode --- internal/service/ec2/ami.go | 25 ++++++++ internal/service/ec2/ami_test.go | 105 +++++++++++++++++++++++++++++++ website/docs/r/ami.html.markdown | 2 + 3 files changed, 132 insertions(+) diff --git a/internal/service/ec2/ami.go b/internal/service/ec2/ami.go index f72c11112c05..e6a9e38a4305 100644 --- a/internal/service/ec2/ami.go +++ b/internal/service/ec2/ami.go @@ -61,6 +61,12 @@ func ResourceAMI() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "boot_mode": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(ec2.BootModeValues_Values(), false), + }, "description": { Type: schema.TypeString, Optional: true, @@ -98,6 +104,12 @@ func ResourceAMI() *schema.Resource { Optional: true, ForceNew: true, }, + "outpost_arn": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: verify.ValidARN, + }, "snapshot_id": { Type: schema.TypeString, Optional: true, @@ -276,6 +288,10 @@ func resourceAMICreate(d *schema.ResourceData, meta interface{}) error { req.RamdiskId = aws.String(ramdiskId) } + if v := d.Get("boot_mode").(string); v != "" { + req.BootMode = aws.String(v) + } + if v, ok := d.GetOk("ebs_block_device"); ok && v.(*schema.Set).Len() > 0 { for _, tfMapRaw := range v.(*schema.Set).List() { tfMap, ok := tfMapRaw.(map[string]interface{}) @@ -407,6 +423,7 @@ func resourceAMIRead(d *schema.ResourceData, meta interface{}) error { } d.Set("architecture", image.Architecture) + d.Set("boot_mode", image.BootMode) d.Set("description", image.Description) d.Set("ena_support", image.EnaSupport) d.Set("hypervisor", image.Hypervisor) @@ -633,6 +650,10 @@ func expandEc2BlockDeviceMappingForAmiEbsBlockDevice(tfMap map[string]interface{ apiObject.Ebs.VolumeType = aws.String(v) } + if v, ok := tfMap["outpost_arn"].(string); ok && v != "" { + apiObject.Ebs.OutpostArn = aws.String(v) + } + return apiObject } @@ -705,6 +726,10 @@ func flattenEc2BlockDeviceMappingForAmiEbsBlockDevice(apiObject *ec2.BlockDevice tfMap["volume_type"] = aws.StringValue(v) } + if v := apiObject.Ebs.OutpostArn; v != nil { + tfMap["outpost_arn"] = aws.StringValue(v) + } + return tfMap } diff --git a/internal/service/ec2/ami_test.go b/internal/service/ec2/ami_test.go index 6cbaf571b3a4..9c0adfd436c4 100644 --- a/internal/service/ec2/ami_test.go +++ b/internal/service/ec2/ami_test.go @@ -45,6 +45,7 @@ func TestAccEC2AMI_basic(t *testing.T) { "iops": "0", "throughput": "0", "volume_size": "8", + "outpost_arn": "", "volume_type": "standard", }), resource.TestCheckTypeSetElemAttrPair(resourceName, "ebs_block_device.*.snapshot_id", snapshotResourceName, "id"), @@ -363,6 +364,66 @@ func TestAccEC2AMI_tags(t *testing.T) { }) } +func TestAccEC2AMI_outpost(t *testing.T) { + var ami ec2.Image + resourceName := "aws_ami.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckOutpostsOutposts(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckAmiDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAmiConfigOutpost(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAmiExists(resourceName, &ami), + resource.TestCheckTypeSetElemAttrPair(resourceName, "ebs_block_device.*.outpost_arn", " data.aws_outposts_outpost.test", "arn"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "manage_ebs_snapshots", + }, + }, + }, + }) +} + +func TestAccEC2AMI_boot(t *testing.T) { + var ami ec2.Image + resourceName := "aws_ami.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckAmiDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAmiConfigBoot(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAmiExists(resourceName, &ami), + resource.TestCheckResourceAttr(resourceName, "boot_mode", "uefi"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "manage_ebs_snapshots", + }, + }, + }, + }) +} + func testAccCheckAmiDestroy(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).EC2Conn @@ -597,3 +658,47 @@ resource "aws_ami" "test" { } `, rName, tagKey1, tagValue1, tagKey2, tagValue2)) } + +func testAccAmiConfigOutpost(rName string) string { + return acctest.ConfigCompose( + testAccAmiConfigBase(rName), + fmt.Sprintf(` +data "aws_outposts_outposts" "test" {} + +data "aws_outposts_outpost" "test" { + id = tolist(data.aws_outposts_outposts.test.ids)[0] +} + +resource "aws_ami" "test" { + ena_support = true + name = %[1]q + root_device_name = "/dev/sda1" + virtualization_type = "hvm" + + ebs_block_device { + device_name = "/dev/sda1" + snapshot_id = aws_ebs_snapshot.test.id + outpost_arn = data.aws_outposts_outpost.test.arn + } +} +`, rName)) +} + +func testAccAmiConfigBoot(rName string) string { + return acctest.ConfigCompose( + testAccAmiConfigBase(rName), + fmt.Sprintf(` +resource "aws_ami" "test" { + ena_support = true + name = %[1]q + root_device_name = "/dev/sda1" + virtualization_type = "hvm" + boot_mode = "uefi" + + ebs_block_device { + device_name = "/dev/sda1" + snapshot_id = aws_ebs_snapshot.test.id + } +} +`, rName)) +} diff --git a/website/docs/r/ami.html.markdown b/website/docs/r/ami.html.markdown index 0db7f7a66f33..47f8e11009ef 100644 --- a/website/docs/r/ami.html.markdown +++ b/website/docs/r/ami.html.markdown @@ -41,6 +41,7 @@ resource "aws_ami" "example" { The following arguments are supported: * `name` - (Required) A region-unique name for the AMI. +* `boot_mode` - (Optional) The boot mode of the AMI. For more information, see [Boot modes](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ami-boot.html) in the Amazon Elastic Compute Cloud User Guide. * `description` - (Optional) A longer, human-readable description for the AMI. * `ena_support` - (Optional) Specifies whether enhanced networking with ENA is enabled. Defaults to `false`. * `root_device_name` - (Optional) The name of the root device (for example, `/dev/sda1`, or `/dev/xvda`). @@ -87,6 +88,7 @@ Nested `ebs_block_device` blocks have the following structure: * `kms_key_id` - (Optional) The full ARN of the AWS Key Management Service (AWS KMS) CMK to use when encrypting the snapshots of an image during a copy operation. This parameter is only required if you want to use a non-default CMK; if this parameter is not specified, the default CMK for EBS is used +* `outpost_arn` - (Optional) The ARN of the Outpost on which the snapshot is stored. ~> **Note:** You can specify `encrypted` or `snapshot_id` but not both. From 45a5677810d32f944e6f1f0921ce1179cd35d399 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 4 Feb 2022 08:14:43 +0200 Subject: [PATCH 2/4] ami boot mode --- internal/service/ec2/ami_data_source.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/service/ec2/ami_data_source.go b/internal/service/ec2/ami_data_source.go index 753dd40d7917..88e1f982be9b 100644 --- a/internal/service/ec2/ami_data_source.go +++ b/internal/service/ec2/ami_data_source.go @@ -62,6 +62,10 @@ func DataSourceAMI() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "boot_mode": { + Type: schema.TypeString, + Computed: true, + }, "description": { Type: schema.TypeString, Computed: true, From edc265ccfd6131ba6d2b73dccb31066c4d862e93 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 4 Feb 2022 08:15:54 +0200 Subject: [PATCH 3/4] ami boot mode --- internal/service/ec2/ami_data_source.go | 1 + website/docs/d/ami.html.markdown | 1 + 2 files changed, 2 insertions(+) diff --git a/internal/service/ec2/ami_data_source.go b/internal/service/ec2/ami_data_source.go index 88e1f982be9b..998540e416f6 100644 --- a/internal/service/ec2/ami_data_source.go +++ b/internal/service/ec2/ami_data_source.go @@ -272,6 +272,7 @@ func amiDescriptionAttributes(d *schema.ResourceData, image *ec2.Image, meta int // Simple attributes first d.SetId(aws.StringValue(image.ImageId)) d.Set("architecture", image.Architecture) + d.Set("boot_mode", image.BootMode) d.Set("creation_date", image.CreationDate) if image.Description != nil { d.Set("description", image.Description) diff --git a/website/docs/d/ami.html.markdown b/website/docs/d/ami.html.markdown index 410e571b41de..9220e8545312 100644 --- a/website/docs/d/ami.html.markdown +++ b/website/docs/d/ami.html.markdown @@ -72,6 +72,7 @@ interpolation. * `arn` - The ARN of the AMI. * `architecture` - The OS architecture of the AMI (ie: `i386` or `x86_64`). +* `boot_mode` - The boot mode of the image. * `block_device_mappings` - Set of objects with block device mappings of the AMI. * `device_name` - The physical name of the device. * `ebs` - Map containing EBS information, if the device is EBS based. Unlike most object attributes, these are accessed directly (e.g., `ebs.volume_size` or `ebs["volume_size"]`) rather than accessed through the first element of a list (e.g., `ebs[0].volume_size`). From 321fdc7f1ac5192ffb969952308639696400e04c Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 4 Feb 2022 08:18:48 +0200 Subject: [PATCH 4/4] changelog --- .changelog/22939.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changelog/22939.txt diff --git a/.changelog/22939.txt b/.changelog/22939.txt new file mode 100644 index 000000000000..48476516ceee --- /dev/null +++ b/.changelog/22939.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_ami: Add `boot_mode` and `ebs_block_device.outpost_arn` arguments. +``` + +```release-note:enhancement +data-source/aws_ami: Add `boot_mode` attribute. +``` \ No newline at end of file