@@ -507,9 +507,8 @@ func (s *Service) createSubnet(sn *infrav1.SubnetSpec) (*infrav1.SubnetSpec, err
507507 ),
508508 },
509509 }
510- if s . scope . VPC (). IsIPv6Enabled () {
510+ if sn . IsIPv6 {
511511 input .Ipv6CidrBlock = aws .String (sn .IPv6CidrBlock )
512- sn .IsIPv6 = true
513512 }
514513 out , err := s .EC2Client .CreateSubnet (context .TODO (), input )
515514 if err != nil {
@@ -521,7 +520,32 @@ func (s *Service) createSubnet(sn *infrav1.SubnetSpec) (*infrav1.SubnetSpec, err
521520 s .scope .Info ("Created subnet" , "id" , * out .Subnet .SubnetId , "public" , sn .IsPublic , "az" , sn .AvailabilityZone , "cidr" , sn .CidrBlock , "ipv6" , sn .IsIPv6 , "ipv6-cidr" , sn .IPv6CidrBlock )
522521
523522 wReq := & ec2.DescribeSubnetsInput {SubnetIds : []string {aws .ToString (out .Subnet .SubnetId )}}
524- if err := ec2 .NewSubnetAvailableWaiter (s .EC2Client ).Wait (context .TODO (), wReq , time .Minute * 5 ); err != nil {
523+ if err := ec2 .NewSubnetAvailableWaiter (s .EC2Client ).Wait (context .TODO (), wReq , time .Minute * 5 , func (sawo * ec2.SubnetAvailableWaiterOptions ) {
524+ // There is a brief period where the IPv6 CIDR is not yet associated with the subnets.
525+ // We need to additionally wait till the CIDR is associated.
526+ if sn .IsIPv6 {
527+ // Default handler will check for subnet state "available".
528+ subnetStateCheck := sawo .Retryable
529+ sawo .Retryable = func (ctx context.Context , dsi * ec2.DescribeSubnetsInput , dso * ec2.DescribeSubnetsOutput , err error ) (bool , error ) {
530+ available , err := subnetStateCheck (ctx , dsi , dso , err )
531+ if err != nil {
532+ return false , err
533+ }
534+
535+ cidrAssociated := true
536+ for _ , subnet := range dso .Subnets {
537+ for _ , set := range subnet .Ipv6CidrBlockAssociationSet {
538+ if set .Ipv6CidrBlockState .State != types .SubnetCidrBlockStateCodeAssociated {
539+ cidrAssociated = false
540+ break
541+ }
542+ }
543+ }
544+
545+ return available && cidrAssociated , nil
546+ }
547+ }
548+ }); err != nil {
525549 return nil , errors .Wrapf (err , "failed to wait for subnet %q" , * out .Subnet .SubnetId )
526550 }
527551
@@ -613,23 +637,23 @@ func (s *Service) createSubnet(sn *infrav1.SubnetSpec) (*infrav1.SubnetSpec, err
613637 ID : sn .ID ,
614638 ResourceID : * out .Subnet .SubnetId ,
615639 AvailabilityZone : * out .Subnet .AvailabilityZone ,
616- CidrBlock : * out .Subnet .CidrBlock , // TODO: this will panic in case of IPv6 only subnets...
617- IsPublic : sn .IsPublic ,
618- Tags : sn .Tags ,
640+ // In case of IPv6-only subnets, cidrBlock (IPv4) is empty.
641+ CidrBlock : aws .ToString (out .Subnet .CidrBlock ),
642+ IsPublic : sn .IsPublic ,
643+ Tags : sn .Tags ,
619644 }
620645 for _ , set := range out .Subnet .Ipv6CidrBlockAssociationSet {
621- if set .Ipv6CidrBlockState .State == types .SubnetCidrBlockStateCodeAssociated {
622- subnet .IPv6CidrBlock = aws .ToString (set .Ipv6CidrBlock )
623- subnet .IsIPv6 = true
624- }
646+ // The IPv6 CIDR is already ensured to be associated so we don't need to check for its association state.
647+ subnet .IPv6CidrBlock = aws .ToString (set .Ipv6CidrBlock )
648+ subnet .IsIPv6 = true
625649 }
626650
627651 s .scope .Debug ("Created new subnet in VPC with cidr and availability zone " ,
628- "subnet-id" , * out . Subnet . SubnetId ,
652+ "subnet-id" , subnet . ResourceID ,
629653 "vpc-id" , * out .Subnet .VpcId ,
630- "cidr-block" , * out . Subnet .CidrBlock ,
654+ "cidr-block" , subnet .CidrBlock ,
631655 "ipv6-cidr-block" , subnet .IPv6CidrBlock ,
632- "availability-zone" , * out . Subnet .AvailabilityZone )
656+ "availability-zone" , subnet .AvailabilityZone )
633657
634658 return subnet , nil
635659}
0 commit comments