Fix AWS DHCP option set domain names causing garbled InternalDNS or Hostname addresses on Node

k3s-v1.14.4
Matthew Wong 2019-06-26 14:54:00 -07:00
parent c5a761cc6e
commit 34170a18ae
2 changed files with 62 additions and 4 deletions

View File

@ -1351,14 +1351,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")
@ -1380,6 +1383,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

View File

@ -681,6 +681,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()