From 57641cd47b1ea187a840d8fba3d1bc5e6d25eb38 Mon Sep 17 00:00:00 2001 From: jaysiyani Date: Tue, 15 Dec 2020 02:02:59 +0000 Subject: [PATCH] resource/aws_launch_configuration: Add metadata_options configuration block (#14637) Output from acceptance testing: ``` --- PASS: TestAccAWSLaunchConfiguration_basic (73.44s) --- PASS: TestAccAWSLaunchConfiguration_ebs_noDevice (52.92s) --- PASS: TestAccAWSLaunchConfiguration_encryptedRootBlockDevice (52.90s) --- PASS: TestAccAWSLaunchConfiguration_metadataOptions (55.79s) --- PASS: TestAccAWSLaunchConfiguration_RootBlockDevice_AmiDisappears (373.76s) --- PASS: TestAccAWSLaunchConfiguration_RootBlockDevice_VolumeSize (76.39s) --- PASS: TestAccAWSLaunchConfiguration_updateEbsBlockDevices (74.31s) --- PASS: TestAccAWSLaunchConfiguration_userData (75.41s) --- PASS: TestAccAWSLaunchConfiguration_withBlockDevices (55.41s) --- PASS: TestAccAWSLaunchConfiguration_withEncryption (55.17s) --- PASS: TestAccAWSLaunchConfiguration_withIAMProfile (60.63s) --- PASS: TestAccAWSLaunchConfiguration_withInstanceStoreAMI (57.10s) --- PASS: TestAccAWSLaunchConfiguration_withSpotPrice (55.55s) --- PASS: TestAccAWSLaunchConfigurationDataSource_basic (53.40s) --- PASS: TestAccAWSLaunchConfigurationDataSource_ebsNoDevice (52.04s) --- PASS: TestAccAWSLaunchConfigurationDataSource_securityGroups (49.80s) --- PASS: TestAccLaunchConfigurationDataSource_metadataOptions (54.83s) ``` --- aws/data_source_aws_launch_configuration.go | 25 ++++++ ...ta_source_aws_launch_configuration_test.go | 44 ++++++++++ aws/resource_aws_launch_configuration.go | 81 +++++++++++++++++++ aws/resource_aws_launch_configuration_test.go | 46 +++++++++++ .../docs/d/launch_configuration.html.markdown | 4 + .../docs/r/launch_configuration.html.markdown | 4 + 6 files changed, 204 insertions(+) diff --git a/aws/data_source_aws_launch_configuration.go b/aws/data_source_aws_launch_configuration.go index 932cba6db92e..b6b0c290085f 100644 --- a/aws/data_source_aws_launch_configuration.go +++ b/aws/data_source_aws_launch_configuration.go @@ -156,6 +156,27 @@ func dataSourceAwsLaunchConfiguration() *schema.Resource { }, }, + "metadata_options": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "http_endpoint": { + Type: schema.TypeString, + Computed: true, + }, + "http_tokens": { + Type: schema.TypeString, + Computed: true, + }, + "http_put_response_hop_limit": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + "root_block_device": { Type: schema.TypeList, Computed: true, @@ -245,6 +266,10 @@ func dataSourceAwsLaunchConfigurationRead(d *schema.ResourceData, meta interface return fmt.Errorf("error setting security_groups: %s", err) } + if err := d.Set("metadata_options", flattenLaunchConfigInstanceMetadataOptions(lc.MetadataOptions)); err != nil { + return fmt.Errorf("error setting metadata_options: %s", err) + } + classicSGs := make([]string, 0, len(lc.ClassicLinkVPCSecurityGroups)) for _, sg := range lc.ClassicLinkVPCSecurityGroups { classicSGs = append(classicSGs, *sg) diff --git a/aws/data_source_aws_launch_configuration_test.go b/aws/data_source_aws_launch_configuration_test.go index 05fa7b1415aa..5c7d826acfff 100644 --- a/aws/data_source_aws_launch_configuration_test.go +++ b/aws/data_source_aws_launch_configuration_test.go @@ -77,6 +77,29 @@ func TestAccAWSLaunchConfigurationDataSource_ebsNoDevice(t *testing.T) { }) } +func TestAccLaunchConfigurationDataSource_metadataOptions(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + dataSourceName := "data.aws_launch_configuration.test" + resourceName := "aws_launch_configuration.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLaunchConfigurationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLaunchConfigurationDataSourceConfig_metadataOptions(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "metadata_options.#", resourceName, "metadata_options.#"), + resource.TestCheckResourceAttrPair(dataSourceName, "metadata_options.0.http_endpoint", resourceName, "metadata_options.0.http_endpoint"), + resource.TestCheckResourceAttrPair(dataSourceName, "metadata_options.0.http_tokens", resourceName, "metadata_options.0.http_tokens"), + resource.TestCheckResourceAttrPair(dataSourceName, "metadata_options.0.http_put_response_hop_limit", resourceName, "metadata_options.0.http_put_response_hop_limit"), + ), + }, + }, + }) +} + func testAccLaunchConfigurationDataSourceConfig_basic(rName string) string { return composeConfig(testAccLatestAmazonLinuxHvmEbsAmiConfig(), fmt.Sprintf(` resource "aws_launch_configuration" "test" { @@ -139,6 +162,27 @@ data "aws_launch_configuration" "foo" { `, rInt, rInt) } +func testAccLaunchConfigurationDataSourceConfig_metadataOptions(rName string) string { + return composeConfig( + testAccLatestAmazonLinuxHvmEbsAmiConfig(), + fmt.Sprintf(` +resource "aws_launch_configuration" "test" { + image_id = data.aws_ami.amzn-ami-minimal-hvm-ebs.id + instance_type = "t3.nano" + name = %[1]q + metadata_options { + http_endpoint = "enabled" + http_tokens = "required" + http_put_response_hop_limit = 2 + } +} + +data "aws_launch_configuration" "test" { + name = aws_launch_configuration.test.name +} +`, rName)) +} + func testAccLaunchConfigurationDataSourceConfigEbsNoDevice(rName string) string { return composeConfig( testAccLatestAmazonLinuxHvmEbsAmiConfig(), diff --git a/aws/resource_aws_launch_configuration.go b/aws/resource_aws_launch_configuration.go index 3cd99e88a936..f9e4f2789c04 100644 --- a/aws/resource_aws_launch_configuration.go +++ b/aws/resource_aws_launch_configuration.go @@ -247,6 +247,39 @@ func resourceAwsLaunchConfiguration() *schema.Resource { }, }, + "metadata_options": { + Type: schema.TypeList, + Optional: true, + Computed: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "http_endpoint": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{autoscaling.InstanceMetadataEndpointStateEnabled, autoscaling.InstanceMetadataEndpointStateDisabled}, false), + }, + "http_tokens": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{autoscaling.InstanceMetadataHttpTokensStateOptional, autoscaling.InstanceMetadataHttpTokensStateRequired}, false), + }, + "http_put_response_hop_limit": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: validation.IntBetween(1, 64), + }, + }, + }, + }, + "root_block_device": { Type: schema.TypeList, Optional: true, @@ -349,6 +382,10 @@ func resourceAwsLaunchConfigurationCreate(d *schema.ResourceData, meta interface createLaunchConfigurationOpts.ClassicLinkVPCId = aws.String(v.(string)) } + if v, ok := d.GetOk("metadata_options"); ok { + createLaunchConfigurationOpts.MetadataOptions = expandLaunchConfigInstanceMetadataOptions(v.([]interface{})) + } + if v, ok := d.GetOk("vpc_classic_link_security_groups"); ok { createLaunchConfigurationOpts.ClassicLinkVPCSecurityGroups = expandStringList( v.(*schema.Set).List(), @@ -564,6 +601,10 @@ func resourceAwsLaunchConfigurationRead(d *schema.ResourceData, meta interface{} return fmt.Errorf("error setting vpc_classic_link_security_groups: %s", err) } + if err := d.Set("metadata_options", flattenLaunchConfigInstanceMetadataOptions(lc.MetadataOptions)); err != nil { + return fmt.Errorf("error setting metadata_options: %s", err) + } + if err := readLCBlockDevices(d, lc, ec2conn); err != nil { return err } @@ -631,6 +672,46 @@ func readLCBlockDevices(d *schema.ResourceData, lc *autoscaling.LaunchConfigurat return nil } +func expandLaunchConfigInstanceMetadataOptions(l []interface{}) *autoscaling.InstanceMetadataOptions { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + opts := &autoscaling.InstanceMetadataOptions{ + HttpEndpoint: aws.String(m["http_endpoint"].(string)), + } + + if m["http_endpoint"].(string) == autoscaling.InstanceMetadataEndpointStateEnabled { + // These parameters are not allowed unless HttpEndpoint is enabled + + if v, ok := m["http_tokens"].(string); ok && v != "" { + opts.HttpTokens = aws.String(v) + } + + if v, ok := m["http_put_response_hop_limit"].(int); ok && v != 0 { + opts.HttpPutResponseHopLimit = aws.Int64(int64(v)) + } + } + + return opts +} + +func flattenLaunchConfigInstanceMetadataOptions(opts *autoscaling.InstanceMetadataOptions) []interface{} { + if opts == nil { + return nil + } + + m := map[string]interface{}{ + "http_endpoint": aws.StringValue(opts.HttpEndpoint), + "http_put_response_hop_limit": aws.Int64Value(opts.HttpPutResponseHopLimit), + "http_tokens": aws.StringValue(opts.HttpTokens), + } + + return []interface{}{m} +} + func readBlockDevicesFromLaunchConfiguration(d *schema.ResourceData, lc *autoscaling.LaunchConfiguration, ec2conn *ec2.EC2) ( map[string]interface{}, error) { blockDevices := make(map[string]interface{}) diff --git a/aws/resource_aws_launch_configuration_test.go b/aws/resource_aws_launch_configuration_test.go index d043cfd1f786..28a699e37915 100644 --- a/aws/resource_aws_launch_configuration_test.go +++ b/aws/resource_aws_launch_configuration_test.go @@ -389,6 +389,35 @@ func TestAccAWSLaunchConfiguration_updateEbsBlockDevices(t *testing.T) { }) } +func TestAccAWSLaunchConfiguration_metadataOptions(t *testing.T) { + var conf autoscaling.LaunchConfiguration + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_launch_configuration.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLaunchConfigurationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLaunchConfigurationConfigMetadataOptions(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLaunchConfigurationExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "metadata_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "metadata_options.0.http_endpoint", "enabled"), + resource.TestCheckResourceAttr(resourceName, "metadata_options.0.http_tokens", "required"), + resource.TestCheckResourceAttr(resourceName, "metadata_options.0.http_put_response_hop_limit", "2"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccAWSLaunchConfiguration_ebs_noDevice(t *testing.T) { var conf autoscaling.LaunchConfiguration rInt := acctest.RandInt() @@ -685,6 +714,23 @@ resource "aws_launch_configuration" "test" { `, rInt)) } +func testAccAWSLaunchConfigurationConfigMetadataOptions(rName string) string { + return composeConfig( + testAccLatestAmazonLinuxHvmEbsAmiConfig(), + fmt.Sprintf(` +resource "aws_launch_configuration" "test" { + image_id = data.aws_ami.amzn-ami-minimal-hvm-ebs.id + instance_type = "t3.nano" + name = %[1]q + metadata_options { + http_endpoint = "enabled" + http_tokens = "required" + http_put_response_hop_limit = 2 + } +} +`, rName)) +} + func testAccAWSLaunchConfigurationConfig() string { return composeConfig(testAccLatestAmazonLinuxHvmEbsAmiConfig(), fmt.Sprintf(` resource "aws_launch_configuration" "test" { diff --git a/website/docs/d/launch_configuration.html.markdown b/website/docs/d/launch_configuration.html.markdown index 7b1169294f50..68702126a222 100644 --- a/website/docs/d/launch_configuration.html.markdown +++ b/website/docs/d/launch_configuration.html.markdown @@ -35,6 +35,10 @@ In addition to all arguments above, the following attributes are exported: * `instance_type` - The Instance Type of the instance to launch. * `iam_instance_profile` - The IAM Instance Profile to associate with launched instances. * `key_name` - The Key Name that should be used for the instance. +* `metadata_options` - The metadata options for the instance. + * `http_endpoint` - The state of the metadata service: `enabled`, `disabled`. + * `http_tokens` - If session tokens are required: `optional`, `required`. + * `http_put_response_hop_limit` - The desired HTTP PUT response hop limit for instance metadata requests. * `security_groups` - A list of associated Security Group IDS. * `associate_public_ip_address` - Whether a Public IP address is associated with the instance. * `vpc_classic_link_id` - The ID of a ClassicLink-enabled VPC. diff --git a/website/docs/r/launch_configuration.html.markdown b/website/docs/r/launch_configuration.html.markdown index d96ee73ea453..ddd47210a359 100644 --- a/website/docs/r/launch_configuration.html.markdown +++ b/website/docs/r/launch_configuration.html.markdown @@ -144,6 +144,10 @@ The following arguments are supported: * `iam_instance_profile` - (Optional) The name attribute of the IAM instance profile to associate with launched instances. * `key_name` - (Optional) The key name that should be used for the instance. +* `metadata_options` - The metadata options for the instance. + * `http_endpoint` - The state of the metadata service: `enabled`, `disabled`. + * `http_tokens` - If session tokens are required: `optional`, `required`. + * `http_put_response_hop_limit` - The desired HTTP PUT response hop limit for instance metadata requests. * `security_groups` - (Optional) A list of associated security group IDS. * `associate_public_ip_address` - (Optional) Associate a public ip address with an instance in a VPC. * `vpc_classic_link_id` - (Optional) The ID of a ClassicLink-enabled VPC. Only applies to EC2-Classic instances. (eg. `vpc-2730681a`)