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

Add support for enabling primary ipv6 address on EC2 instance #36425

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
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
61 changes: 60 additions & 1 deletion internal/service/ec2/ec2_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,16 @@ func ResourceInstance() *schema.Resource {
},
},
},
"enable_primary_ipv6": {
Type: schema.TypeBool,
Optional: true,
Computed: true,
ForceNew: true, // TODO: this can be set on an existing instance but not unset after. don't know how to model that?
AtLeastOneOf: []string{
"ipv6_address_count",
"ipv6_addresses",
},
},
"ephemeral_block_device": {
Type: schema.TypeSet,
Optional: true,
Expand Down Expand Up @@ -582,7 +592,7 @@ func ResourceInstance() *schema.Resource {
Computed: true,
},
"network_interface": {
ConflictsWith: []string{"associate_public_ip_address", "subnet_id", "private_ip", "secondary_private_ips", "vpc_security_group_ids", "security_groups", "ipv6_addresses", "ipv6_address_count", "source_dest_check"},
ConflictsWith: []string{"associate_public_ip_address", "enable_primary_ipv6", "subnet_id", "private_ip", "secondary_private_ips", "vpc_security_group_ids", "security_groups", "ipv6_addresses", "ipv6_address_count", "source_dest_check"},
Type: schema.TypeSet,
Optional: true,
Computed: true,
Expand Down Expand Up @@ -957,6 +967,7 @@ func resourceInstanceCreate(ctx context.Context, d *schema.ResourceData, meta in
DisableApiTermination: instanceOpts.DisableAPITermination,
EbsOptimized: instanceOpts.EBSOptimized,
EnclaveOptions: instanceOpts.EnclaveOptions,
EnablePrimaryIpv6: instanceOpts.EnablePrimaryIpv6,
HibernationOptions: instanceOpts.HibernationOptions,
IamInstanceProfile: instanceOpts.IAMInstanceProfile,
ImageId: instanceOpts.ImageID,
Expand Down Expand Up @@ -1266,6 +1277,12 @@ func resourceInstanceRead(ctx context.Context, d *schema.ResourceData, meta inte
for _, address := range primaryNetworkInterface.Ipv6Addresses {
ipv6Addresses = append(ipv6Addresses, aws.StringValue(address.Ipv6Address))
}

if len(primaryNetworkInterface.Ipv6Addresses) > 0 {
if err := d.Set("enable_primary_ipv6", primaryNetworkInterface.Ipv6Addresses[0].IsPrimaryIpv6); err != nil {
return sdkdiag.AppendErrorf(diags, "setting enable_primary_ipv6: %s", err)
}
}
}
} else {
d.Set("associate_public_ip_address", instance.PublicIpAddress != nil)
Expand Down Expand Up @@ -1578,6 +1595,10 @@ func resourceInstanceUpdate(ctx context.Context, d *schema.ResourceData, meta in
}
}

if d.HasChange("enable_primary_ipv6") && !d.IsNewResource() {

}

// SourceDestCheck can only be modified on an instance without manually specified network interfaces.
// SourceDestCheck, in that case, is configured at the network interface level
if _, ok := d.GetOk("network_interface"); !ok {
Expand All @@ -1603,6 +1624,39 @@ func resourceInstanceUpdate(ctx context.Context, d *schema.ResourceData, meta in
}
}

if d.HasChange("enable_primary_ipv6") && !d.IsNewResource() {
instance, err := FindInstanceByID(ctx, conn, d.Id())

if err != nil {
return sdkdiag.AppendErrorf(diags, "reading EC2 Instance (%s): %s", d.Id(), err)
}

var primaryInterface *ec2.InstanceNetworkInterface
for _, ni := range instance.NetworkInterfaces {
if aws.Int64Value(ni.Attachment.DeviceIndex) == 0 {
primaryInterface = ni
}
}

if primaryInterface == nil {
return sdkdiag.AppendErrorf(diags, "Failed to update enable_primary_ipv6 on %q, which does not contain a primary network interface", d.Id())
}

enablePrimaryIpv6 := d.Get("enable_primary_ipv6").(bool)

input := ec2.ModifyNetworkInterfaceAttributeInput{
NetworkInterfaceId: primaryInterface.NetworkInterfaceId,
EnablePrimaryIpv6: aws.Bool(enablePrimaryIpv6),
}

_, err = conn.ModifyNetworkInterfaceAttributeWithContext(ctx, &input)

if err != nil {
return sdkdiag.AppendErrorf(diags, "modifying EC2 Instance (%s) primary network interface: %s", d.Id(), err)
}

}

if d.HasChange("ipv6_address_count") && !d.IsNewResource() {
instance, err := FindInstanceByID(ctx, conn, d.Id())
if err != nil {
Expand Down Expand Up @@ -2833,6 +2887,7 @@ type instanceOpts struct {
DisableAPITermination *bool
EBSOptimized *bool
EnclaveOptions *ec2.EnclaveOptionsRequest
EnablePrimaryIpv6 *bool
HibernationOptions *ec2.HibernationOptionsRequest
IAMInstanceProfile *ec2.IamInstanceProfileSpecification
ImageID *string
Expand Down Expand Up @@ -3042,6 +3097,10 @@ func buildInstanceOpts(ctx context.Context, d *schema.ResourceData, meta interfa
opts.SecurityGroups = groups
}

if v, ok := d.GetOk("enable_primary_ipv6"); ok {
opts.EnablePrimaryIpv6 = aws.Bool(v.(bool))
}

if v, ok := d.GetOk("ipv6_address_count"); ok {
opts.Ipv6AddressCount = aws.Int64(int64(v.(int)))
}
Expand Down
14 changes: 14 additions & 0 deletions internal/service/ec2/ec2_launch_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,12 @@ func ResourceLaunchTemplate() *schema.Resource {
Type: schema.TypeInt,
Optional: true,
},
"enable_primary_ipv6": {
Type: nullable.TypeNullableBool,
Optional: true,
DiffSuppressFunc: nullable.DiffSuppressNullableBool,
ValidateFunc: nullable.ValidateTypeStringNullableBool,
},
"interface_type": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -1989,6 +1995,10 @@ func expandLaunchTemplateInstanceNetworkInterfaceSpecificationRequest(tfMap map[
apiObject.DeviceIndex = aws.Int64(int64(v))
}

if v, null, _ := nullable.Bool(tfMap["enable_primary_ipv6"].(string)).Value(); !null {
apiObject.PrimaryIpv6 = aws.Bool(v)
arianvp marked this conversation as resolved.
Show resolved Hide resolved
}

if v, ok := tfMap["interface_type"].(string); ok && v != "" {
apiObject.InterfaceType = aws.String(v)
}
Expand Down Expand Up @@ -2980,6 +2990,10 @@ func flattenLaunchTemplateInstanceNetworkInterfaceSpecification(apiObject *ec2.L
tfMap["device_index"] = aws.Int64Value(v)
}

if v := apiObject.PrimaryIpv6; v != nil {
tfMap["enable_primary_ipv6"] = strconv.FormatBool(aws.BoolValue(v))
}

if v := apiObject.InterfaceType; v != nil {
tfMap["interface_type"] = aws.StringValue(v)
}
Expand Down
32 changes: 32 additions & 0 deletions internal/service/ec2/vpc_network_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,17 @@ func ResourceNetworkInterface() *schema.Resource {
Type: schema.TypeString,
Optional: true,
},
"enable_primary_ipv6": {
Type: schema.TypeBool,
Optional: true,
Computed: true,
ForceNew: true, // TODO: this can be set on an existing instance but not unset after. don't know how to model that?
AtLeastOneOf: []string{
"ipv6_address_count",
"ipv6_addresses",
"ipv6_address_list",
},
},
"interface_type": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -348,6 +359,10 @@ func resourceNetworkInterfaceCreate(ctx context.Context, d *schema.ResourceData,
input.Description = aws.String(v.(string))
}

if v, ok := d.GetOk("enable_primary_ipv6"); ok {
input.EnablePrimaryIpv6 = aws.Bool(v.(bool))
}

if v, ok := d.GetOk("interface_type"); ok {
input.InterfaceType = aws.String(v.(string))
}
Expand Down Expand Up @@ -529,6 +544,11 @@ func resourceNetworkInterfaceRead(ctx context.Context, d *schema.ResourceData, m
}
d.Set("ipv4_prefix_count", len(eni.Ipv4Prefixes))
d.Set("ipv6_address_count", len(eni.Ipv6Addresses))
if len(eni.Ipv6Addresses) > 0 {
if err := d.Set("enable_primary_ipv6", eni.Ipv6Addresses[0].IsPrimaryIpv6); err != nil {
return sdkdiag.AppendErrorf(diags, "setting enable_primary_ipv6: %s", err)
}
}
if err := d.Set("ipv6_address_list", flattenNetworkInterfaceIPv6Addresses(eni.Ipv6Addresses)); err != nil {
return sdkdiag.AppendErrorf(diags, "setting ipv6 address list: %s", err)
}
Expand Down Expand Up @@ -804,6 +824,18 @@ func resourceNetworkInterfaceUpdate(ctx context.Context, d *schema.ResourceData,
}
}

if d.HasChange("enable_primary_ipv6") {
input := &ec2.ModifyNetworkInterfaceAttributeInput{
NetworkInterfaceId: aws.String(d.Id()),
EnablePrimaryIpv6: aws.Bool(d.Get("source_dest_check").(bool)),
}

_, err := conn.ModifyNetworkInterfaceAttributeWithContext(ctx, input)

if err != nil {
return sdkdiag.AppendErrorf(diags, "modifying EC2 Network Interface (%s) EnablePrimaryIpv6: %s", d.Id(), err)
}
}
if d.HasChange("ipv6_addresses") && !d.Get("ipv6_address_list_enabled").(bool) {
o, n := d.GetChange("ipv6_addresses")
if o == nil {
Expand Down