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

Automated cherry pick of #79446: Fix AWS DHCP option set domain names causing garbled #79619

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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
31 changes: 27 additions & 4 deletions pkg/cloudprovider/providers/aws/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -1237,14 +1237,17 @@ func (c *Cloud) NodeAddresses(ctx context.Context, name types.NodeName) ([]v1.No
addresses = append(addresses, v1.NodeAddress{Type: v1.NodeExternalIP, Address: externalIP})
}

internalDNS, err := c.metadata.GetMetadata("local-hostname")
if err != nil || len(internalDNS) == 0 {
localHostname, err := c.metadata.GetMetadata("local-hostname")
if err != nil || len(localHostname) == 0 {
//TODO: It would be nice to be able to determine the reason for the failure,
// but the AWS client masks all failures with the same error description.
klog.V(4).Info("Could not determine private DNS from AWS metadata.")
} else {
addresses = append(addresses, v1.NodeAddress{Type: v1.NodeInternalDNS, Address: internalDNS})
addresses = append(addresses, v1.NodeAddress{Type: v1.NodeHostName, Address: internalDNS})
hostname, internalDNS := parseMetadataLocalHostname(localHostname)
addresses = append(addresses, v1.NodeAddress{Type: v1.NodeHostName, Address: hostname})
for _, d := range internalDNS {
addresses = append(addresses, v1.NodeAddress{Type: v1.NodeInternalDNS, Address: d})
}
}

externalDNS, err := c.metadata.GetMetadata("public-hostname")
Expand All @@ -1266,6 +1269,26 @@ func (c *Cloud) NodeAddresses(ctx context.Context, name types.NodeName) ([]v1.No
return extractNodeAddresses(instance)
}

// parseMetadataLocalHostname parses the output of "local-hostname" metadata.
// If a DHCP option set is configured for a VPC and it has multiple domain names, GetMetadata
// returns a string containing first the hostname followed by additional domain names,
// space-separated. For example, if the DHCP option set has:
// domain-name = us-west-2.compute.internal a.a b.b c.c d.d;
// $ curl http://169.254.169.254/latest/meta-data/local-hostname
// ip-192-168-111-51.us-west-2.compute.internal a.a b.b c.c d.d
func parseMetadataLocalHostname(metadata string) (string, []string) {
localHostnames := strings.Fields(metadata)
hostname := localHostnames[0]
internalDNS := []string{hostname}

privateAddress := strings.Split(hostname, ".")[0]
for _, h := range localHostnames[1:] {
internalDNSAddress := privateAddress + "." + h
internalDNS = append(internalDNS, internalDNSAddress)
}
return hostname, internalDNS
}

// extractNodeAddresses maps the instance information from EC2 to an array of NodeAddresses
func extractNodeAddresses(instance *ec2.Instance) ([]v1.NodeAddress, error) {
// Not clear if the order matters here, but we might as well indicate a sensible preference order
Expand Down
35 changes: 35 additions & 0 deletions pkg/cloudprovider/providers/aws/aws_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,41 @@ func TestNodeAddressesWithMetadata(t *testing.T) {
testHasNodeAddress(t, addrs, v1.NodeExternalIP, "2.3.4.5")
}

func TestParseMetadataLocalHostname(t *testing.T) {
tests := []struct {
name string
metadata string
hostname string
internalDNS []string
}{
{
"single hostname",
"ip-172-31-16-168.us-west-2.compute.internal",
"ip-172-31-16-168.us-west-2.compute.internal",
[]string{"ip-172-31-16-168.us-west-2.compute.internal"},
},
{
"dhcp options set with three additional domain names",
"ip-172-31-16-168.us-west-2.compute.internal example.com example.ca example.org",
"ip-172-31-16-168.us-west-2.compute.internal",
[]string{"ip-172-31-16-168.us-west-2.compute.internal", "ip-172-31-16-168.example.com", "ip-172-31-16-168.example.ca", "ip-172-31-16-168.example.org"},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
hostname, internalDNS := parseMetadataLocalHostname(test.metadata)
if hostname != test.hostname {
t.Errorf("got hostname %v, expected %v", hostname, test.hostname)
}
for i, v := range internalDNS {
if v != test.internalDNS[i] {
t.Errorf("got an internalDNS %v, expected %v", v, test.internalDNS[i])
}
}
})
}
}

func TestGetRegion(t *testing.T) {
aws := mockAvailabilityZone("us-west-2e")
zones, ok := aws.Zones()
Expand Down