diff --git a/cloudmock/aws/mockec2/subnets.go b/cloudmock/aws/mockec2/subnets.go index df59371ee1..0eda3d351f 100644 --- a/cloudmock/aws/mockec2/subnets.go +++ b/cloudmock/aws/mockec2/subnets.go @@ -257,6 +257,9 @@ func (m *MockEC2) DeleteSubnetRequest(*ec2.DeleteSubnetInput) (*request.Request, func (m *MockEC2) ModifySubnetAttribute(request *ec2.ModifySubnetAttributeInput) (*ec2.ModifySubnetAttributeOutput, error) { subnet := m.subnets[*request.SubnetId] + if request.AssignIpv6AddressOnCreation != nil { + subnet.main.AssignIpv6AddressOnCreation = request.AssignIpv6AddressOnCreation.Value + } if request.EnableResourceNameDnsAAAARecordOnLaunch != nil { subnet.main.PrivateDnsNameOptionsOnLaunch.EnableResourceNameDnsAAAARecord = request.EnableResourceNameDnsAAAARecordOnLaunch.Value } diff --git a/upup/pkg/fi/cloudup/awstasks/subnet.go b/upup/pkg/fi/cloudup/awstasks/subnet.go index a914264250..753b72c9e5 100644 --- a/upup/pkg/fi/cloudup/awstasks/subnet.go +++ b/upup/pkg/fi/cloudup/awstasks/subnet.go @@ -43,14 +43,15 @@ type Subnet struct { Lifecycle fi.Lifecycle - ID *string - VPC *VPC - AmazonIPv6CIDR *VPCAmazonIPv6CIDRBlock - AvailabilityZone *string - CIDR *string - IPv6CIDR *string - ResourceBasedNaming *bool - Shared *bool + ID *string + VPC *VPC + AmazonIPv6CIDR *VPCAmazonIPv6CIDRBlock + AvailabilityZone *string + CIDR *string + IPv6CIDR *string + ResourceBasedNaming *bool + AssignIPv6AddressOnCreation *bool + Shared *bool Tags map[string]string } @@ -71,6 +72,8 @@ func (a OrderSubnetsById) Less(i, j int) bool { } func (e *Subnet) Find(c *fi.Context) (*Subnet, error) { + e.AssignIPv6AddressOnCreation = fi.PtrTo(e.IPv6CIDR != nil) + subnet, err := e.findEc2Subnet(c) if err != nil { return nil, err @@ -104,6 +107,8 @@ func (e *Subnet) Find(c *fi.Context) (*Subnet, error) { break } + actual.AssignIPv6AddressOnCreation = subnet.AssignIpv6AddressOnCreation + actual.ResourceBasedNaming = fi.PtrTo(aws.StringValue(subnet.PrivateDnsNameOptionsOnLaunch.HostnameType) == ec2.HostnameTypeResourceName) if *actual.ResourceBasedNaming { if fi.ValueOf(actual.CIDR) != "" && !aws.BoolValue(subnet.PrivateDnsNameOptionsOnLaunch.EnableResourceNameDnsARecord) { @@ -289,6 +294,17 @@ func (_ *Subnet) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *Subnet) error { } } + if a == nil || changes.AssignIPv6AddressOnCreation != nil { + request := &ec2.ModifySubnetAttributeInput{ + SubnetId: e.ID, + AssignIpv6AddressOnCreation: &ec2.AttributeBooleanValue{Value: e.AssignIPv6AddressOnCreation}, + } + _, err := t.Cloud.EC2().ModifySubnetAttribute(request) + if err != nil { + return fmt.Errorf("error modifying AssignIPv6AddressOnCreation: %w", err) + } + } + if changes.ResourceBasedNaming != nil { hostnameType := ec2.HostnameTypeIpName if *changes.ResourceBasedNaming { @@ -359,6 +375,7 @@ type terraformSubnet struct { CIDR *string `cty:"cidr_block"` IPv6CIDR *string `cty:"ipv6_cidr_block"` IPv6Native *bool `cty:"ipv6_native"` + AssignIPv6AddressOnCreation *bool `cty:"assign_ipv6_address_on_creation"` AvailabilityZone *string `cty:"availability_zone"` EnableDNS64 *bool `cty:"enable_dns64"` EnableResourceNameDNSAAAARecordOnLaunch *bool `cty:"enable_resource_name_dns_aaaa_record_on_launch"` @@ -403,6 +420,9 @@ func (_ *Subnet) RenderTerraform(t *terraform.TerraformTarget, a, e, changes *Su tf.EnableDNS64 = fi.PtrTo(true) tf.IPv6Native = fi.PtrTo(true) } + if fi.ValueOf(e.IPv6CIDR) != "" { + tf.AssignIPv6AddressOnCreation = fi.PtrTo(true) + } if e.ResourceBasedNaming != nil { hostnameType := ec2.HostnameTypeIpName if *e.ResourceBasedNaming { diff --git a/upup/pkg/fi/cloudup/awstasks/subnet_test.go b/upup/pkg/fi/cloudup/awstasks/subnet_test.go index 6b86494e4e..d322dfd581 100644 --- a/upup/pkg/fi/cloudup/awstasks/subnet_test.go +++ b/upup/pkg/fi/cloudup/awstasks/subnet_test.go @@ -118,7 +118,8 @@ func TestSubnetCreate(t *testing.T) { } expected := &ec2.Subnet{ - CidrBlock: aws.String("172.20.1.0/24"), + AssignIpv6AddressOnCreation: aws.Bool(false), + CidrBlock: aws.String("172.20.1.0/24"), PrivateDnsNameOptionsOnLaunch: &ec2.PrivateDnsNameOptionsOnLaunch{ EnableResourceNameDnsAAAARecord: aws.Bool(false), EnableResourceNameDnsARecord: aws.Bool(true), @@ -208,7 +209,8 @@ func TestSubnetCreateIPv6(t *testing.T) { } expected := &ec2.Subnet{ - CidrBlock: aws.String("172.20.1.0/24"), + AssignIpv6AddressOnCreation: aws.Bool(true), + CidrBlock: aws.String("172.20.1.0/24"), Ipv6CidrBlockAssociationSet: []*ec2.SubnetIpv6CidrBlockAssociation{ { AssociationId: aws.String("subnet-cidr-assoc-ipv6-subnet-1"), @@ -306,7 +308,8 @@ func TestSubnetCreateIPv6NetNum(t *testing.T) { } expected := &ec2.Subnet{ - CidrBlock: aws.String("172.20.1.0/24"), + AssignIpv6AddressOnCreation: aws.Bool(true), + CidrBlock: aws.String("172.20.1.0/24"), Ipv6CidrBlockAssociationSet: []*ec2.SubnetIpv6CidrBlockAssociation{ { AssociationId: aws.String("subnet-cidr-assoc-ipv6-subnet-1"), @@ -442,7 +445,8 @@ func TestSharedSubnetCreateDoesNotCreateNew(t *testing.T) { t.Fatalf("Subnet created but then not found") } expected := &ec2.Subnet{ - CidrBlock: aws.String("172.20.1.0/24"), + AssignIpv6AddressOnCreation: aws.Bool(false), + CidrBlock: aws.String("172.20.1.0/24"), PrivateDnsNameOptionsOnLaunch: &ec2.PrivateDnsNameOptionsOnLaunch{ EnableResourceNameDnsAAAARecord: aws.Bool(false), EnableResourceNameDnsARecord: aws.Bool(false),