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: Wait for IPv6 association on Create #6394

Merged
merged 1 commit into from
Nov 8, 2018
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
99 changes: 56 additions & 43 deletions aws/resource_aws_vpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,13 @@ func resourceAwsVpcCreate(d *schema.ResourceData, meta interface{}) error {
d.Id(), err)
}

if len(vpc.Ipv6CidrBlockAssociationSet) > 0 && vpc.Ipv6CidrBlockAssociationSet[0] != nil {
log.Printf("[DEBUG] Waiting for EC2 VPC (%s) IPv6 CIDR to become associated", d.Id())
if err := waitForEc2VpcIpv6CidrBlockAssociationCreate(conn, d.Id(), aws.StringValue(vpcResp.Vpc.Ipv6CidrBlockAssociationSet[0].AssociationId)); err != nil {
return fmt.Errorf("error waiting for EC2 VPC (%s) IPv6 CIDR to become associated: %s", d.Id(), err)
}
}

// Update our attributes and return
return resourceAwsVpcUpdate(d, meta)
}
Expand Down Expand Up @@ -202,7 +209,7 @@ func resourceAwsVpcRead(d *schema.ResourceData, meta interface{}) error {
d.Set("ipv6_cidr_block", "")

for _, a := range vpc.Ipv6CidrBlockAssociationSet {
if *a.Ipv6CidrBlockState.State == "associated" { //we can only ever have 1 IPv6 block associated at once
if aws.StringValue(a.Ipv6CidrBlockState.State) == ec2.VpcCidrBlockStateCodeAssociated { //we can only ever have 1 IPv6 block associated at once
d.Set("assign_generated_ipv6_cidr_block", true)
d.Set("ipv6_association_id", a.AssociationId)
d.Set("ipv6_cidr_block", a.Ipv6CidrBlock)
Expand Down Expand Up @@ -407,45 +414,24 @@ func resourceAwsVpcUpdate(d *schema.ResourceData, meta interface{}) error {
return err
}

// Wait for the CIDR to become available
log.Printf(
"[DEBUG] Waiting for IPv6 CIDR (%s) to become associated",
d.Id())
stateConf := &resource.StateChangeConf{
Pending: []string{"associating", "disassociated"},
Target: []string{"associated"},
Refresh: Ipv6CidrStateRefreshFunc(conn, d.Id(), *resp.Ipv6CidrBlockAssociation.AssociationId),
Timeout: 1 * time.Minute,
}
if _, err := stateConf.WaitForState(); err != nil {
return fmt.Errorf(
"Error waiting for IPv6 CIDR (%s) to become associated: %s",
d.Id(), err)
log.Printf("[DEBUG] Waiting for EC2 VPC (%s) IPv6 CIDR to become associated", d.Id())
if err := waitForEc2VpcIpv6CidrBlockAssociationCreate(conn, d.Id(), aws.StringValue(resp.Ipv6CidrBlockAssociation.AssociationId)); err != nil {
return fmt.Errorf("error waiting for EC2 VPC (%s) IPv6 CIDR to become associated: %s", d.Id(), err)
}
} else {
associationID := d.Get("ipv6_association_id").(string)
modifyOpts := &ec2.DisassociateVpcCidrBlockInput{
AssociationId: aws.String(d.Get("ipv6_association_id").(string)),
AssociationId: aws.String(associationID),
}
log.Printf("[INFO] Disabling assign_generated_ipv6_cidr_block vpc attribute for %s: %#v",
d.Id(), modifyOpts)
if _, err := conn.DisassociateVpcCidrBlock(modifyOpts); err != nil {
return err
}

// Wait for the CIDR to become available
log.Printf(
"[DEBUG] Waiting for IPv6 CIDR (%s) to become disassociated",
d.Id())
stateConf := &resource.StateChangeConf{
Pending: []string{"disassociating", "associated"},
Target: []string{"disassociated"},
Refresh: Ipv6CidrStateRefreshFunc(conn, d.Id(), d.Get("ipv6_association_id").(string)),
Timeout: 1 * time.Minute,
}
if _, err := stateConf.WaitForState(); err != nil {
return fmt.Errorf(
"Error waiting for IPv6 CIDR (%s) to become disassociated: %s",
d.Id(), err)
log.Printf("[DEBUG] Waiting for EC2 VPC (%s) IPv6 CIDR to become disassociated", d.Id())
if err := waitForEc2VpcIpv6CidrBlockAssociationDelete(conn, d.Id(), associationID); err != nil {
return fmt.Errorf("error waiting for EC2 VPC (%s) IPv6 CIDR to become disassociated: %s", d.Id(), err)
}
}

Expand Down Expand Up @@ -552,28 +538,24 @@ func Ipv6CidrStateRefreshFunc(conn *ec2.EC2, id string, associationId string) re
VpcIds: []*string{aws.String(id)},
}
resp, err := conn.DescribeVpcs(describeVpcOpts)

if isAWSErr(err, "InvalidVpcID.NotFound", "") {
return nil, "", nil
}

if err != nil {
if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidVpcID.NotFound" {
resp = nil
} else {
log.Printf("Error on VPCStateRefresh: %s", err)
return nil, "", err
}
return nil, "", err
}

if resp == nil {
if resp == nil || len(resp.Vpcs) == 0 || resp.Vpcs[0] == nil || resp.Vpcs[0].Ipv6CidrBlockAssociationSet == nil {
// Sometimes AWS just has consistency issues and doesn't see
// our instance yet. Return an empty state.
return nil, "", nil
}

if resp.Vpcs[0].Ipv6CidrBlockAssociationSet == nil {
return nil, "", nil
}

for _, association := range resp.Vpcs[0].Ipv6CidrBlockAssociationSet {
if *association.AssociationId == associationId {
return association, *association.Ipv6CidrBlockState.State, nil
if aws.StringValue(association.AssociationId) == associationId {
return association, aws.StringValue(association.Ipv6CidrBlockState.State), nil
}
}

Expand Down Expand Up @@ -733,3 +715,34 @@ func vpcDescribe(conn *ec2.EC2, vpcId string) (*ec2.Vpc, error) {
return nil, fmt.Errorf("Found %d VPCs for %s, expected 1", n, vpcId)
}
}

func waitForEc2VpcIpv6CidrBlockAssociationCreate(conn *ec2.EC2, vpcID, associationID string) error {
stateConf := &resource.StateChangeConf{
Pending: []string{
ec2.VpcCidrBlockStateCodeAssociating,
ec2.VpcCidrBlockStateCodeDisassociated,
},
Target: []string{ec2.VpcCidrBlockStateCodeAssociated},
Refresh: Ipv6CidrStateRefreshFunc(conn, vpcID, associationID),
Timeout: 1 * time.Minute,
}
_, err := stateConf.WaitForState()

return err
}

func waitForEc2VpcIpv6CidrBlockAssociationDelete(conn *ec2.EC2, vpcID, associationID string) error {
stateConf := &resource.StateChangeConf{
Pending: []string{
ec2.VpcCidrBlockStateCodeAssociated,
ec2.VpcCidrBlockStateCodeDisassociating,
},
Target: []string{ec2.VpcCidrBlockStateCodeDisassociated},
Refresh: Ipv6CidrStateRefreshFunc(conn, vpcID, associationID),
Timeout: 1 * time.Minute,
NotFoundChecks: 1,
}
_, err := stateConf.WaitForState()

return err
}
Loading