diff --git a/aws/resource_aws_vpc.go b/aws/resource_aws_vpc.go index f0a12162622..f540e8e45b7 100644 --- a/aws/resource_aws_vpc.go +++ b/aws/resource_aws_vpc.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/validation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) func resourceAwsVpc() *schema.Resource { @@ -171,8 +172,96 @@ func resourceAwsVpcCreate(d *schema.ResourceData, meta interface{}) error { } } - // Update our attributes and return - return resourceAwsVpcUpdate(d, meta) + // You cannot modify the DNS resolution and DNS hostnames attributes in the same request. Use separate requests for each attribute. + // Reference: https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_ModifyVpcAttribute.html + + if d.Get("enable_dns_hostnames").(bool) { + input := &ec2.ModifyVpcAttributeInput{ + EnableDnsHostnames: &ec2.AttributeBooleanValue{ + Value: aws.Bool(true), + }, + VpcId: aws.String(d.Id()), + } + + if _, err := conn.ModifyVpcAttribute(input); err != nil { + return fmt.Errorf("error enabling VPC (%s) DNS hostnames: %s", d.Id(), err) + } + + d.SetPartial("enable_dns_hostnames") + } + + // By default, only the enableDnsSupport attribute is set to true in a VPC created any other way. + // Reference: https://docs.aws.amazon.com/vpc/latest/userguide/vpc-dns.html#vpc-dns-support + + if !d.Get("enable_dns_support").(bool) { + input := &ec2.ModifyVpcAttributeInput{ + EnableDnsSupport: &ec2.AttributeBooleanValue{ + Value: aws.Bool(false), + }, + VpcId: aws.String(d.Id()), + } + + if _, err := conn.ModifyVpcAttribute(input); err != nil { + return fmt.Errorf("error disabling VPC (%s) DNS support: %s", d.Id(), err) + } + + d.SetPartial("enable_dns_support") + } + + if d.Get("enable_classiclink").(bool) { + input := &ec2.EnableVpcClassicLinkInput{ + VpcId: aws.String(d.Id()), + } + + if _, err := conn.EnableVpcClassicLink(input); err != nil { + return fmt.Errorf("error enabling VPC (%s) ClassicLink: %s", d.Id(), err) + } + + d.SetPartial("enable_classiclink") + } + + if d.Get("enable_classiclink_dns_support").(bool) { + input := &ec2.EnableVpcClassicLinkDnsSupportInput{ + VpcId: aws.String(d.Id()), + } + + if _, err := conn.EnableVpcClassicLinkDnsSupport(input); err != nil { + return fmt.Errorf("error enabling VPC (%s) ClassicLink DNS support: %s", d.Id(), err) + } + + d.SetPartial("enable_classiclink_dns_support") + } + + if v := d.Get("tags").(map[string]interface{}); len(v) > 0 { + // Handle EC2 eventual consistency on creation + err := resource.Retry(5*time.Minute, func() *resource.RetryError { + err := keyvaluetags.Ec2UpdateTags(conn, d.Id(), nil, v) + + if isAWSErr(err, "InvalidVpcID.NotFound", "") { + return resource.RetryableError(err) + } + + if err != nil { + return resource.NonRetryableError(err) + } + + return nil + }) + + if isResourceTimeoutError(err) { + err = keyvaluetags.Ec2UpdateTags(conn, d.Id(), nil, v) + } + + if err != nil { + return fmt.Errorf("error adding tags: %s", err) + } + + d.SetPartial("tags") + } + + d.Partial(false) + + return resourceAwsVpcRead(d, meta) } func resourceAwsVpcRead(d *schema.ResourceData, meta interface{}) error { @@ -205,8 +294,9 @@ func resourceAwsVpcRead(d *schema.ResourceData, meta interface{}) error { }.String() d.Set("arn", arn) - // Tags - d.Set("tags", tagsToMap(vpc.Tags)) + if err := d.Set("tags", keyvaluetags.Ec2KeyValueTags(vpc.Tags).IgnoreAws().Map()); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } d.Set("owner_id", vpc.OwnerId) @@ -404,7 +494,7 @@ func resourceAwsVpcUpdate(d *schema.ResourceData, meta interface{}) error { d.SetPartial("enable_classiclink_dns_support") } - if d.HasChange("assign_generated_ipv6_cidr_block") && !d.IsNewResource() { + if d.HasChange("assign_generated_ipv6_cidr_block") { toAssign := d.Get("assign_generated_ipv6_cidr_block").(bool) log.Printf("[INFO] Modifying assign_generated_ipv6_cidr_block to %#v", toAssign) @@ -445,7 +535,7 @@ func resourceAwsVpcUpdate(d *schema.ResourceData, meta interface{}) error { d.SetPartial("assign_generated_ipv6_cidr_block") } - if d.HasChange("instance_tenancy") && !d.IsNewResource() { + if d.HasChange("instance_tenancy") { modifyOpts := &ec2.ModifyVpcTenancyInput{ VpcId: aws.String(vpcid), InstanceTenancy: aws.String(d.Get("instance_tenancy").(string)), @@ -460,9 +550,13 @@ func resourceAwsVpcUpdate(d *schema.ResourceData, meta interface{}) error { d.SetPartial("instance_tenancy") } - if err := setTags(conn, d); err != nil { - return err - } else { + if d.HasChange("tags") { + o, n := d.GetChange("tags") + + if err := keyvaluetags.Ec2UpdateTags(conn, d.Id(), o, n); err != nil { + return fmt.Errorf("error updating tags: %s", err) + } + d.SetPartial("tags") }