Skip to content

Commit 4505915

Browse files
authored
Merge pull request #5993 from jiaqiluo/add-ipv6
🐛 Expose IPv6 addresses on AWSMachine Status
2 parents 6faac03 + 781bb25 commit 4505915

2 files changed

Lines changed: 212 additions & 0 deletions

File tree

pkg/cloud/services/ec2/instances.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"context"
2121
"encoding/base64"
2222
"fmt"
23+
"net"
2324
"sort"
2425
"strings"
2526
"time"
@@ -1068,6 +1069,20 @@ func (s *Service) getInstanceAddresses(instance types.Instance) []clusterv1beta1
10681069
addresses = append(addresses, publicIPAddress)
10691070
}
10701071
}
1072+
1073+
for _, ipv6 := range eni.Ipv6Addresses {
1074+
if addr := aws.ToString(ipv6.Ipv6Address); addr != "" {
1075+
ip := net.ParseIP(addr)
1076+
if ip == nil || ip.IsLinkLocalUnicast() {
1077+
continue
1078+
}
1079+
ipv6Address := clusterv1beta1.MachineAddress{
1080+
Type: clusterv1beta1.MachineInternalIP,
1081+
Address: ip.String(),
1082+
}
1083+
addresses = append(addresses, ipv6Address)
1084+
}
1085+
}
10711086
}
10721087

10731088
return addresses

pkg/cloud/services/ec2/instances_test.go

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6539,6 +6539,203 @@ func TestGetDHCPOptionSetDomainName(t *testing.T) {
65396539
}
65406540
}
65416541

6542+
func TestGetInstanceAddresses(t *testing.T) {
6543+
testCases := []struct {
6544+
name string
6545+
networkInterfaces []types.InstanceNetworkInterface
6546+
expectedAddresses []clusterv1beta1.MachineAddress
6547+
}{
6548+
{
6549+
name: "IPv4 only instance returns IPv4 internal and external addresses",
6550+
networkInterfaces: []types.InstanceNetworkInterface{
6551+
{
6552+
PrivateDnsName: aws.String("ip-10-0-1-5.us-west-2.compute.internal"),
6553+
PrivateIpAddress: aws.String("10.0.1.5"),
6554+
Association: &types.InstanceNetworkInterfaceAssociation{
6555+
PublicDnsName: aws.String("ec2-1-2-3-4.us-west-2.compute.amazonaws.com"),
6556+
PublicIp: aws.String("1.2.3.4"),
6557+
},
6558+
},
6559+
},
6560+
expectedAddresses: []clusterv1beta1.MachineAddress{
6561+
{Type: clusterv1beta1.MachineInternalDNS, Address: "ip-10-0-1-5.us-west-2.compute.internal"},
6562+
{Type: clusterv1beta1.MachineInternalIP, Address: "10.0.1.5"},
6563+
{Type: clusterv1beta1.MachineExternalDNS, Address: "ec2-1-2-3-4.us-west-2.compute.amazonaws.com"},
6564+
{Type: clusterv1beta1.MachineExternalIP, Address: "1.2.3.4"},
6565+
},
6566+
},
6567+
{
6568+
name: "IPv6-only instance returns IPv6 address as InternalIP",
6569+
networkInterfaces: []types.InstanceNetworkInterface{
6570+
{
6571+
Ipv6Addresses: []types.InstanceIpv6Address{
6572+
{Ipv6Address: aws.String("2600:1f13:abc:de00::1")},
6573+
},
6574+
},
6575+
},
6576+
expectedAddresses: []clusterv1beta1.MachineAddress{
6577+
{Type: clusterv1beta1.MachineInternalIP, Address: "2600:1f13:abc:de00::1"},
6578+
},
6579+
},
6580+
{
6581+
name: "dual-stack instance returns both IPv4 and IPv6 addresses",
6582+
networkInterfaces: []types.InstanceNetworkInterface{
6583+
{
6584+
PrivateDnsName: aws.String("ip-10-0-1-5.us-west-2.compute.internal"),
6585+
PrivateIpAddress: aws.String("10.0.1.5"),
6586+
Ipv6Addresses: []types.InstanceIpv6Address{
6587+
{Ipv6Address: aws.String("2600:1f13:abc:de00::1")},
6588+
},
6589+
},
6590+
},
6591+
expectedAddresses: []clusterv1beta1.MachineAddress{
6592+
{Type: clusterv1beta1.MachineInternalDNS, Address: "ip-10-0-1-5.us-west-2.compute.internal"},
6593+
{Type: clusterv1beta1.MachineInternalIP, Address: "10.0.1.5"},
6594+
{Type: clusterv1beta1.MachineInternalIP, Address: "2600:1f13:abc:de00::1"},
6595+
},
6596+
},
6597+
{
6598+
name: "multiple IPv6 addresses in the same ENI are all included",
6599+
networkInterfaces: []types.InstanceNetworkInterface{
6600+
{
6601+
Ipv6Addresses: []types.InstanceIpv6Address{
6602+
{Ipv6Address: aws.String("2600:1f13:abc:de00::1")},
6603+
{Ipv6Address: aws.String("2600:1f13:abc:de00::2")},
6604+
},
6605+
},
6606+
},
6607+
expectedAddresses: []clusterv1beta1.MachineAddress{
6608+
{Type: clusterv1beta1.MachineInternalIP, Address: "2600:1f13:abc:de00::1"},
6609+
{Type: clusterv1beta1.MachineInternalIP, Address: "2600:1f13:abc:de00::2"},
6610+
},
6611+
},
6612+
{
6613+
name: "link-local unicast IPv6 address is skipped",
6614+
networkInterfaces: []types.InstanceNetworkInterface{
6615+
{
6616+
PrivateIpAddress: aws.String("10.0.1.5"),
6617+
Ipv6Addresses: []types.InstanceIpv6Address{
6618+
{Ipv6Address: aws.String("fe80::1")},
6619+
},
6620+
},
6621+
},
6622+
expectedAddresses: []clusterv1beta1.MachineAddress{
6623+
{Type: clusterv1beta1.MachineInternalIP, Address: "10.0.1.5"},
6624+
},
6625+
},
6626+
{
6627+
name: "invalid IPv6 address is skipped",
6628+
networkInterfaces: []types.InstanceNetworkInterface{
6629+
{
6630+
PrivateIpAddress: aws.String("10.0.1.5"),
6631+
Ipv6Addresses: []types.InstanceIpv6Address{
6632+
{Ipv6Address: aws.String("not-an-ip")},
6633+
},
6634+
},
6635+
},
6636+
expectedAddresses: []clusterv1beta1.MachineAddress{
6637+
{Type: clusterv1beta1.MachineInternalIP, Address: "10.0.1.5"},
6638+
},
6639+
},
6640+
{
6641+
name: "only link-local IPv6 address present yields no IPv6 entry",
6642+
networkInterfaces: []types.InstanceNetworkInterface{
6643+
{
6644+
Ipv6Addresses: []types.InstanceIpv6Address{
6645+
{Ipv6Address: aws.String("fe80::abcd:ef01")},
6646+
},
6647+
},
6648+
},
6649+
expectedAddresses: []clusterv1beta1.MachineAddress{},
6650+
},
6651+
{
6652+
name: "mix of link-local and global IPv6 addresses: only global is included",
6653+
networkInterfaces: []types.InstanceNetworkInterface{
6654+
{
6655+
Ipv6Addresses: []types.InstanceIpv6Address{
6656+
{Ipv6Address: aws.String("fe80::1")},
6657+
{Ipv6Address: aws.String("2600:1f13:abc:de00::1")},
6658+
},
6659+
},
6660+
},
6661+
expectedAddresses: []clusterv1beta1.MachineAddress{
6662+
{Type: clusterv1beta1.MachineInternalIP, Address: "2600:1f13:abc:de00::1"},
6663+
},
6664+
},
6665+
{
6666+
name: "empty IPv6 address in ENI is skipped",
6667+
networkInterfaces: []types.InstanceNetworkInterface{
6668+
{
6669+
PrivateIpAddress: aws.String("10.0.1.5"),
6670+
Ipv6Addresses: []types.InstanceIpv6Address{
6671+
{Ipv6Address: aws.String("")},
6672+
},
6673+
},
6674+
},
6675+
expectedAddresses: []clusterv1beta1.MachineAddress{
6676+
{Type: clusterv1beta1.MachineInternalIP, Address: "10.0.1.5"},
6677+
},
6678+
},
6679+
{
6680+
name: "multiple ENIs with IPv6 addresses",
6681+
networkInterfaces: []types.InstanceNetworkInterface{
6682+
{
6683+
PrivateDnsName: aws.String("ip-10-0-1-5.us-west-2.compute.internal"),
6684+
PrivateIpAddress: aws.String("10.0.1.5"),
6685+
Ipv6Addresses: []types.InstanceIpv6Address{
6686+
{Ipv6Address: aws.String("2600:1f13:abc:de00::1")},
6687+
},
6688+
},
6689+
{
6690+
PrivateDnsName: aws.String("ip-10-0-2-5.us-west-2.compute.internal"),
6691+
PrivateIpAddress: aws.String("10.0.2.5"),
6692+
Ipv6Addresses: []types.InstanceIpv6Address{
6693+
{Ipv6Address: aws.String("2600:1f13:abc:de00::2")},
6694+
},
6695+
},
6696+
},
6697+
expectedAddresses: []clusterv1beta1.MachineAddress{
6698+
{Type: clusterv1beta1.MachineInternalDNS, Address: "ip-10-0-1-5.us-west-2.compute.internal"},
6699+
{Type: clusterv1beta1.MachineInternalIP, Address: "10.0.1.5"},
6700+
{Type: clusterv1beta1.MachineInternalIP, Address: "2600:1f13:abc:de00::1"},
6701+
{Type: clusterv1beta1.MachineInternalDNS, Address: "ip-10-0-2-5.us-west-2.compute.internal"},
6702+
{Type: clusterv1beta1.MachineInternalIP, Address: "10.0.2.5"},
6703+
{Type: clusterv1beta1.MachineInternalIP, Address: "2600:1f13:abc:de00::2"},
6704+
},
6705+
},
6706+
}
6707+
6708+
for _, tc := range testCases {
6709+
t.Run(tc.name, func(t *testing.T) {
6710+
g := NewWithT(t)
6711+
mockCtrl := gomock.NewController(t)
6712+
defer mockCtrl.Finish()
6713+
ec2Mock := mocks.NewMockEC2API(mockCtrl)
6714+
scheme, err := setupScheme()
6715+
g.Expect(err).ToNot(HaveOccurred())
6716+
6717+
client := fake.NewClientBuilder().WithScheme(scheme).Build()
6718+
cs, err := scope.NewClusterScope(scope.ClusterScopeParams{
6719+
Client: client,
6720+
Cluster: &clusterv1.Cluster{},
6721+
AWSCluster: &infrav1.AWSCluster{
6722+
ObjectMeta: metav1.ObjectMeta{Name: "test"},
6723+
},
6724+
})
6725+
g.Expect(err).ToNot(HaveOccurred())
6726+
6727+
ec2Svc := NewService(cs)
6728+
ec2Svc.EC2Client = ec2Mock
6729+
6730+
instance := types.Instance{
6731+
NetworkInterfaces: tc.networkInterfaces,
6732+
}
6733+
addresses := ec2Svc.getInstanceAddresses(instance)
6734+
g.Expect(addresses).To(ConsistOf(tc.expectedAddresses))
6735+
})
6736+
}
6737+
}
6738+
65426739
func mockedGetPrivateDNSDomainNameFromDHCPOptionsCalls(m *mocks.MockEC2APIMockRecorder) {
65436740
m.DescribeVpcs(context.TODO(), &ec2.DescribeVpcsInput{
65446741
VpcIds: []string{"vpc-exists"},

0 commit comments

Comments
 (0)