Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

resource/aws_vpc: Apply attribute waiter logic to enable_dns_hostnames and enable_dns_support attributes #17461

Merged
merged 1 commit into from
Feb 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions aws/data_source_aws_vpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder"
)

func dataSourceAwsVpc() *schema.Resource {
Expand Down Expand Up @@ -216,17 +217,21 @@ func dataSourceAwsVpcRead(d *schema.ResourceData, meta interface{}) error {
d.Set("ipv6_cidr_block", vpc.Ipv6CidrBlockAssociationSet[0].Ipv6CidrBlock)
}

attResp, err := awsVpcDescribeVpcAttribute("enableDnsSupport", aws.StringValue(vpc.VpcId), conn)
enableDnsHostnames, err := finder.VpcAttribute(conn, aws.StringValue(vpc.VpcId), ec2.VpcAttributeNameEnableDnsHostnames)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 I like the use of finder functions here


if err != nil {
return err
return fmt.Errorf("error reading EC2 VPC (%s) Attribute (%s): %w", aws.StringValue(vpc.VpcId), ec2.VpcAttributeNameEnableDnsHostnames, err)
}
d.Set("enable_dns_support", attResp.EnableDnsSupport.Value)

attResp, err = awsVpcDescribeVpcAttribute("enableDnsHostnames", aws.StringValue(vpc.VpcId), conn)
d.Set("enable_dns_hostnames", enableDnsHostnames)

enableDnsSupport, err := finder.VpcAttribute(conn, aws.StringValue(vpc.VpcId), ec2.VpcAttributeNameEnableDnsSupport)

if err != nil {
return err
return fmt.Errorf("error reading EC2 VPC (%s) Attribute (%s): %w", aws.StringValue(vpc.VpcId), ec2.VpcAttributeNameEnableDnsSupport, err)
}
d.Set("enable_dns_hostnames", attResp.EnableDnsHostnames.Value)

d.Set("enable_dns_support", enableDnsSupport)

routeTableId, err := resourceAwsVpcSetMainRouteTable(conn, aws.StringValue(vpc.VpcId))
if err != nil {
Expand Down
4 changes: 4 additions & 0 deletions aws/internal/service/ec2/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ const (
ErrCodeInvalidSubnetIDNotFound = "InvalidSubnetID.NotFound"
)

const (
ErrCodeInvalidVpcIDNotFound = "InvalidVpcID.NotFound"
)

const (
ErrCodeInvalidVpcEndpointIdNotFound = "InvalidVpcEndpointId.NotFound"
ErrCodeInvalidVpcEndpointServiceIdNotFound = "InvalidVpcEndpointServiceId.NotFound"
Expand Down
35 changes: 35 additions & 0 deletions aws/internal/service/ec2/finder/finder.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,41 @@ func TransitGatewayPrefixListReferenceByID(conn *ec2.EC2, resourceID string) (*e
return TransitGatewayPrefixListReference(conn, transitGatewayRouteTableID, prefixListID)
}

// VpcAttribute looks up a VPC attribute.
func VpcAttribute(conn *ec2.EC2, vpcID string, attribute string) (*bool, error) {
input := &ec2.DescribeVpcAttributeInput{
Attribute: aws.String(attribute),
VpcId: aws.String(vpcID),
}

output, err := conn.DescribeVpcAttribute(input)

if err != nil {
return nil, err
}

if output == nil {
return nil, nil
}

switch attribute {
case ec2.VpcAttributeNameEnableDnsHostnames:
if output.EnableDnsHostnames == nil {
return nil, nil
}

return output.EnableDnsHostnames.Value, nil
case ec2.VpcAttributeNameEnableDnsSupport:
if output.EnableDnsSupport == nil {
return nil, nil
}

return output.EnableDnsSupport.Value, nil
}

return nil, fmt.Errorf("unimplemented VPC attribute: %s", attribute)
}

// VpcPeeringConnectionByID returns the VPC peering connection corresponding to the specified identifier.
// Returns nil and potentially an error if no VPC peering connection is found.
func VpcPeeringConnectionByID(conn *ec2.EC2, id string) (*ec2.VpcPeeringConnection, error) {
Expand Down
21 changes: 21 additions & 0 deletions aws/internal/service/ec2/waiter/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,27 @@ func TransitGatewayPrefixListReferenceState(conn *ec2.EC2, transitGatewayRouteTa
}
}

// VpcAttribute fetches the Vpc and its attribute value
func VpcAttribute(conn *ec2.EC2, id string, attribute string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
attributeValue, err := finder.VpcAttribute(conn, id, attribute)

if tfawserr.ErrCodeEquals(err, tfec2.ErrCodeInvalidVpcIDNotFound) {
return nil, "", nil
}

if err != nil {
return nil, "", err
}

if attributeValue == nil {
return nil, "", nil
}

return attributeValue, strconv.FormatBool(aws.BoolValue(attributeValue)), nil
}
}

const (
vpcPeeringConnectionStatusNotFound = "NotFound"
vpcPeeringConnectionStatusUnknown = "Unknown"
Expand Down
22 changes: 22 additions & 0 deletions aws/internal/service/ec2/waiter/waiter.go
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,28 @@ func TransitGatewayPrefixListReferenceStateUpdated(conn *ec2.EC2, transitGateway
return nil, err
}

const (
VpcAttributePropagationTimeout = 5 * time.Minute
)

func VpcAttributeUpdated(conn *ec2.EC2, vpcID string, attribute string, expectedValue bool) (*ec2.Vpc, error) {
stateConf := &resource.StateChangeConf{
Target: []string{strconv.FormatBool(expectedValue)},
Refresh: VpcAttribute(conn, vpcID, attribute),
Timeout: VpcAttributePropagationTimeout,
Delay: 10 * time.Second,
MinTimeout: 3 * time.Second,
}

outputRaw, err := stateConf.WaitForState()

if output, ok := outputRaw.(*ec2.Vpc); ok {
return output, err
}

return nil, err
}

const (
VpnGatewayVpcAttachmentAttachedTimeout = 15 * time.Minute

Expand Down
79 changes: 40 additions & 39 deletions aws/resource_aws_vpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/waiter"
)

func resourceAwsVpc() *schema.Resource {
Expand Down Expand Up @@ -183,7 +185,11 @@ func resourceAwsVpcCreate(d *schema.ResourceData, meta interface{}) error {
}

if _, err := conn.ModifyVpcAttribute(input); err != nil {
return fmt.Errorf("error enabling VPC (%s) DNS hostnames: %s", d.Id(), err)
return fmt.Errorf("error enabling EC2 VPC (%s) DNS Hostnames: %w", d.Id(), err)
}

if _, err := waiter.VpcAttributeUpdated(conn, d.Id(), ec2.VpcAttributeNameEnableDnsHostnames, d.Get("enable_dns_hostnames").(bool)); err != nil {
return fmt.Errorf("error waiting for EC2 VPC (%s) DNS Hostnames to enable: %w", d.Id(), err)
}
}

Expand All @@ -199,7 +205,11 @@ func resourceAwsVpcCreate(d *schema.ResourceData, meta interface{}) error {
}

if _, err := conn.ModifyVpcAttribute(input); err != nil {
return fmt.Errorf("error disabling VPC (%s) DNS support: %s", d.Id(), err)
return fmt.Errorf("error disabling EC2 VPC (%s) DNS Support: %w", d.Id(), err)
}

if _, err := waiter.VpcAttributeUpdated(conn, d.Id(), ec2.VpcAttributeNameEnableDnsSupport, d.Get("enable_dns_support").(bool)); err != nil {
return fmt.Errorf("error waiting for EC2 VPC (%s) DNS Support to disable: %w", d.Id(), err)
}
}

Expand Down Expand Up @@ -276,17 +286,21 @@ func resourceAwsVpcRead(d *schema.ResourceData, meta interface{}) error {
}
}

resp, err := awsVpcDescribeVpcAttribute("enableDnsSupport", vpcid, conn)
enableDnsHostnames, err := finder.VpcAttribute(conn, aws.StringValue(vpc.VpcId), ec2.VpcAttributeNameEnableDnsHostnames)

if err != nil {
return err
return fmt.Errorf("error reading EC2 VPC (%s) Attribute (%s): %w", aws.StringValue(vpc.VpcId), ec2.VpcAttributeNameEnableDnsHostnames, err)
}
d.Set("enable_dns_support", resp.EnableDnsSupport.Value)

resp, err = awsVpcDescribeVpcAttribute("enableDnsHostnames", vpcid, conn)
d.Set("enable_dns_hostnames", enableDnsHostnames)

enableDnsSupport, err := finder.VpcAttribute(conn, aws.StringValue(vpc.VpcId), ec2.VpcAttributeNameEnableDnsSupport)

if err != nil {
return err
return fmt.Errorf("error reading EC2 VPC (%s) Attribute (%s): %w", aws.StringValue(vpc.VpcId), ec2.VpcAttributeNameEnableDnsSupport, err)
}
d.Set("enable_dns_hostnames", resp.EnableDnsHostnames.Value)

d.Set("enable_dns_support", enableDnsSupport)

describeClassiclinkOpts := &ec2.DescribeVpcClassicLinkInput{
VpcIds: []*string{&vpcid},
Expand Down Expand Up @@ -362,38 +376,38 @@ func resourceAwsVpcUpdate(d *schema.ResourceData, meta interface{}) error {

vpcid := d.Id()
if d.HasChange("enable_dns_hostnames") {
val := d.Get("enable_dns_hostnames").(bool)
modifyOpts := &ec2.ModifyVpcAttributeInput{
VpcId: &vpcid,
input := &ec2.ModifyVpcAttributeInput{
VpcId: aws.String(d.Id()),
EnableDnsHostnames: &ec2.AttributeBooleanValue{
Value: &val,
Value: aws.Bool(d.Get("enable_dns_hostnames").(bool)),
},
}

log.Printf(
"[INFO] Modifying enable_dns_hostnames vpc attribute for %s: %s",
d.Id(), modifyOpts)
if _, err := conn.ModifyVpcAttribute(modifyOpts); err != nil {
return err
if _, err := conn.ModifyVpcAttribute(input); err != nil {
return fmt.Errorf("error updating EC2 VPC (%s) DNS Hostnames: %w", d.Id(), err)
}

if _, err := waiter.VpcAttributeUpdated(conn, d.Id(), ec2.VpcAttributeNameEnableDnsHostnames, d.Get("enable_dns_hostnames").(bool)); err != nil {
return fmt.Errorf("error waiting for EC2 VPC (%s) DNS Hostnames update: %w", d.Id(), err)
}
}

_, hasEnableDnsSupportOption := d.GetOk("enable_dns_support")

if !hasEnableDnsSupportOption || d.HasChange("enable_dns_support") {
val := d.Get("enable_dns_support").(bool)
modifyOpts := &ec2.ModifyVpcAttributeInput{
VpcId: &vpcid,
input := &ec2.ModifyVpcAttributeInput{
VpcId: aws.String(d.Id()),
EnableDnsSupport: &ec2.AttributeBooleanValue{
Value: &val,
Value: aws.Bool(d.Get("enable_dns_support").(bool)),
},
}

log.Printf(
"[INFO] Modifying enable_dns_support vpc attribute for %s: %s",
d.Id(), modifyOpts)
if _, err := conn.ModifyVpcAttribute(modifyOpts); err != nil {
return err
if _, err := conn.ModifyVpcAttribute(input); err != nil {
return fmt.Errorf("error updating EC2 VPC (%s) DNS Support: %w", d.Id(), err)
}

if _, err := waiter.VpcAttributeUpdated(conn, d.Id(), ec2.VpcAttributeNameEnableDnsSupport, d.Get("enable_dns_support").(bool)); err != nil {
return fmt.Errorf("error waiting for EC2 VPC (%s) DNS Support update: %w", d.Id(), err)
}
}

Expand Down Expand Up @@ -733,19 +747,6 @@ func resourceAwsVpcInstanceImport(
return []*schema.ResourceData{d}, nil
}

func awsVpcDescribeVpcAttribute(attribute string, vpcId string, conn *ec2.EC2) (*ec2.DescribeVpcAttributeOutput, error) {
describeAttrOpts := &ec2.DescribeVpcAttributeInput{
Attribute: aws.String(attribute),
VpcId: aws.String(vpcId),
}
resp, err := conn.DescribeVpcAttribute(describeAttrOpts)
if err != nil {
return nil, err
}

return resp, nil
}

// vpcDescribe returns EC2 API information about the specified VPC.
// If the VPC doesn't exist, return nil.
func vpcDescribe(conn *ec2.EC2, vpcId string) (*ec2.Vpc, error) {
Expand Down