From 798e7089383a81fc67b2686319ae7b7a9d7d5de6 Mon Sep 17 00:00:00 2001 From: anthony Date: Mon, 30 Dec 2024 13:43:50 +0100 Subject: [PATCH 1/5] aws_instance not taking input for metadata_options --- internal/service/ec2/ec2_instance.go | 2 +- internal/service/ec2/ec2_instance_test.go | 38 +++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/internal/service/ec2/ec2_instance.go b/internal/service/ec2/ec2_instance.go index d4e25c7100c..cde231a291b 100644 --- a/internal/service/ec2/ec2_instance.go +++ b/internal/service/ec2/ec2_instance.go @@ -1974,13 +1974,13 @@ func resourceInstanceUpdate(ctx context.Context, d *schema.ResourceData, meta in input := &ec2.ModifyInstanceMetadataOptionsInput{ HttpEndpoint: awstypes.InstanceMetadataEndpointState(tfMap["http_endpoint"].(string)), InstanceId: aws.String(d.Id()), + HttpTokens: awstypes.HttpTokensState(tfMap["http_tokens"].(string)), } if tfMap["http_endpoint"].(string) == string(awstypes.InstanceMetadataEndpointStateEnabled) { // These parameters are not allowed unless HttpEndpoint is enabled. input.HttpProtocolIpv6 = awstypes.InstanceMetadataProtocolState(tfMap["http_protocol_ipv6"].(string)) input.HttpPutResponseHopLimit = aws.Int32(int32(tfMap["http_put_response_hop_limit"].(int))) - input.HttpTokens = awstypes.HttpTokensState(tfMap["http_tokens"].(string)) input.InstanceMetadataTags = awstypes.InstanceMetadataTagsState(tfMap["instance_metadata_tags"].(string)) } diff --git a/internal/service/ec2/ec2_instance_test.go b/internal/service/ec2/ec2_instance_test.go index 4208ac8706f..139be4417fa 100644 --- a/internal/service/ec2/ec2_instance_test.go +++ b/internal/service/ec2/ec2_instance_test.go @@ -5388,6 +5388,18 @@ func TestAccEC2Instance_metadataOptions(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "metadata_options.0.instance_metadata_tags", "disabled"), ), }, + { + Config: testAccInstanceConfig_metadataOptionsUpdatedWithOptionalTokensAndDisabledHttpEndPoint(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckInstanceExists(ctx, resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "metadata_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "metadata_options.0.http_endpoint", "disabled"), + resource.TestCheckResourceAttr(resourceName, "metadata_options.0.http_protocol_ipv6", "disabled"), + resource.TestCheckResourceAttr(resourceName, "metadata_options.0.http_tokens", "optional"), + resource.TestCheckResourceAttr(resourceName, "metadata_options.0.http_put_response_hop_limit", "1"), + resource.TestCheckResourceAttr(resourceName, "metadata_options.0.instance_metadata_tags", "disabled"), + ), + }, { ResourceName: resourceName, ImportState: true, @@ -9011,6 +9023,32 @@ resource "aws_instance" "test" { `, rName)) } +func testAccInstanceConfig_metadataOptionsUpdatedWithOptionalTokensAndDisabledHttpEndPoint(rName string) string { + return acctest.ConfigCompose( + acctest.ConfigLatestAmazonLinux2HVMEBSX8664AMI(), + testAccInstanceVPCConfig(rName, false, 0), + acctest.AvailableEC2InstanceTypeForRegion("t3.micro", "t2.micro"), + fmt.Sprintf(` +resource "aws_instance" "test" { + ami = data.aws_ami.amzn2-ami-minimal-hvm-ebs-x86_64.id + instance_type = data.aws_ec2_instance_type_offering.available.instance_type + subnet_id = aws_subnet.test.id + + tags = { + Name = %[1]q + } + + metadata_options { + http_endpoint = "disabled" + http_protocol_ipv6 = "disabled" + http_tokens = "optional" + http_put_response_hop_limit = 1 + instance_metadata_tags = "disabled" + } +} +`, rName)) +} + func testAccInstanceConfig_metadataOptionsUpdatedAgain(rName string) string { return acctest.ConfigCompose( acctest.ConfigLatestAmazonLinux2HVMEBSX8664AMI(), From 05597562fe0e6e5ed012190737c284563d66e28d Mon Sep 17 00:00:00 2001 From: anthony Date: Mon, 30 Dec 2024 14:10:17 +0100 Subject: [PATCH 2/5] add changelog --- .changelog/40727.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/40727.txt diff --git a/.changelog/40727.txt b/.changelog/40727.txt new file mode 100644 index 00000000000..468aac4f95b --- /dev/null +++ b/.changelog/40727.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_instance: Fix the updating of metadata options when setting http_endpoint to optional +``` \ No newline at end of file From 800c7bf97ca4ad5dc3df775cb745af2e3779a3ac Mon Sep 17 00:00:00 2001 From: anthony Date: Mon, 30 Dec 2024 14:12:05 +0100 Subject: [PATCH 3/5] fix naming according to linter --- internal/service/ec2/ec2_instance_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/ec2/ec2_instance_test.go b/internal/service/ec2/ec2_instance_test.go index 139be4417fa..760baa0c868 100644 --- a/internal/service/ec2/ec2_instance_test.go +++ b/internal/service/ec2/ec2_instance_test.go @@ -5389,7 +5389,7 @@ func TestAccEC2Instance_metadataOptions(t *testing.T) { ), }, { - Config: testAccInstanceConfig_metadataOptionsUpdatedWithOptionalTokensAndDisabledHttpEndPoint(rName), + Config: testAccInstanceConfig_metadataOptionsUpdatedWithOptionalTokensAndDisabledHTTPEndPoint(rName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckInstanceExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "metadata_options.#", "1"), @@ -9023,7 +9023,7 @@ resource "aws_instance" "test" { `, rName)) } -func testAccInstanceConfig_metadataOptionsUpdatedWithOptionalTokensAndDisabledHttpEndPoint(rName string) string { +func testAccInstanceConfig_metadataOptionsUpdatedWithOptionalTokensAndDisabledHTTPEndPoint(rName string) string { return acctest.ConfigCompose( acctest.ConfigLatestAmazonLinux2HVMEBSX8664AMI(), testAccInstanceVPCConfig(rName, false, 0), From 2eb06a5c2e38ceb1d1e63b496e9912d3fbd20a12 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 30 Dec 2024 13:22:55 -0500 Subject: [PATCH 4/5] Cosmetics. --- .changelog/40727.txt | 2 +- internal/service/ec2/ec2_instance.go | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.changelog/40727.txt b/.changelog/40727.txt index 468aac4f95b..48e1ac308a8 100644 --- a/.changelog/40727.txt +++ b/.changelog/40727.txt @@ -1,3 +1,3 @@ ```release-note:bug -resource/aws_instance: Fix the updating of metadata options when setting http_endpoint to optional +resource/aws_instance: Always set `http_tokens` when `metadata_options` is updated ``` \ No newline at end of file diff --git a/internal/service/ec2/ec2_instance.go b/internal/service/ec2/ec2_instance.go index cde231a291b..73717ed0557 100644 --- a/internal/service/ec2/ec2_instance.go +++ b/internal/service/ec2/ec2_instance.go @@ -1971,13 +1971,14 @@ func resourceInstanceUpdate(ctx context.Context, d *schema.ResourceData, meta in if d.HasChange("metadata_options") && !d.IsNewResource() { if v, ok := d.GetOk("metadata_options"); ok { if tfMap, ok := v.([]interface{})[0].(map[string]interface{}); ok { + httpEndpoint := awstypes.InstanceMetadataEndpointState(tfMap["http_endpoint"].(string)) input := &ec2.ModifyInstanceMetadataOptionsInput{ - HttpEndpoint: awstypes.InstanceMetadataEndpointState(tfMap["http_endpoint"].(string)), - InstanceId: aws.String(d.Id()), + HttpEndpoint: httpEndpoint, HttpTokens: awstypes.HttpTokensState(tfMap["http_tokens"].(string)), + InstanceId: aws.String(d.Id()), } - if tfMap["http_endpoint"].(string) == string(awstypes.InstanceMetadataEndpointStateEnabled) { + if httpEndpoint == awstypes.InstanceMetadataEndpointStateEnabled { // These parameters are not allowed unless HttpEndpoint is enabled. input.HttpProtocolIpv6 = awstypes.InstanceMetadataProtocolState(tfMap["http_protocol_ipv6"].(string)) input.HttpPutResponseHopLimit = aws.Int32(int32(tfMap["http_put_response_hop_limit"].(int))) @@ -1985,11 +1986,13 @@ func resourceInstanceUpdate(ctx context.Context, d *schema.ResourceData, meta in } _, err := conn.ModifyInstanceMetadataOptions(ctx, input) + if tfawserr.ErrMessageContains(err, errCodeUnsupportedOperation, "InstanceMetadataTags") { log.Printf("[WARN] updating EC2 Instance (%s) metadata options: %s. Retrying without instance metadata tags.", d.Id(), err) _, err = conn.ModifyInstanceMetadataOptions(ctx, input) } + if err != nil { return sdkdiag.AppendErrorf(diags, "updating EC2 Instance (%s) metadata options: %s", d.Id(), err) } From 585b70bcd29148b71b88b3ff2d273bfae3b76d96 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 31 Dec 2024 09:23:28 -0500 Subject: [PATCH 5/5] r/aws_instance: Tweak CustomizeDiffFunc to handle storage format of 'user_data'. --- internal/service/ec2/ec2_instance.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/internal/service/ec2/ec2_instance.go b/internal/service/ec2/ec2_instance.go index ca3ec517a46..647b1b32f52 100644 --- a/internal/service/ec2/ec2_instance.go +++ b/internal/service/ec2/ec2_instance.go @@ -910,6 +910,13 @@ func resourceInstance() *schema.Resource { // Set public_dns and public_ip to newly computed if the instance will be stopped and started // as part of Update and there is already a public_ip value in state. if diff.Id() != "" && diff.HasChanges(names.AttrInstanceType, "user_data", "user_data_base64") { + // user_data is stored in state as a hash. + if diff.HasChange("user_data") && !diff.HasChange(names.AttrInstanceType) { + if o, n := diff.GetChange("user_data"); userDataHashSum(n.(string)) == o.(string) { + return nil + } + } + if diff.Get("public_ip").(string) != "" { diff.SetNewComputed("public_dns") diff.SetNewComputed("public_ip")