mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
Adds Support for Node Resource IPv6 Addressing
Adds support for the following: 1. A node resource to be assigned an IPv6 address. 2. Expands IPv4/v6 address validation checks. Which issue this PR fixes: fixes #44848 in combination with PR #45116 Special notes for your reviewer: Release note: With this PR, nodes can be assigned an IPv6 address. An IPv4 address is preferred over an IPv6 address. IP address validation has been expanded to check for multicast, link-local and unspecified addresses.
This commit is contained in:
parent
7c8596a95f
commit
7ac6fe9c5d
@ -359,8 +359,13 @@ func (kl *Kubelet) GetClusterDNS(pod *v1.Pod) ([]string, []string, []string, boo
|
|||||||
// local machine". A nameserver setting of localhost is equivalent to
|
// local machine". A nameserver setting of localhost is equivalent to
|
||||||
// this documented behavior.
|
// this documented behavior.
|
||||||
if kl.resolverConfig == "" {
|
if kl.resolverConfig == "" {
|
||||||
hostDNS = []string{"127.0.0.1"}
|
|
||||||
hostSearch = []string{"."}
|
hostSearch = []string{"."}
|
||||||
|
switch {
|
||||||
|
case kl.nodeIP == nil || kl.nodeIP.To4() != nil:
|
||||||
|
hostDNS = []string{"127.0.0.1"}
|
||||||
|
case kl.nodeIP.To16() != nil:
|
||||||
|
hostDNS = []string{"::1"}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
hostSearch = kl.formDNSSearchForDNSDefault(hostSearch, pod)
|
hostSearch = kl.formDNSSearchForDNSDefault(hostSearch, pod)
|
||||||
}
|
}
|
||||||
|
@ -99,28 +99,56 @@ func TestNoOpHostSupportsLegacyFeatures(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNodeIPParam(t *testing.T) {
|
func TestNodeIPParam(t *testing.T) {
|
||||||
testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
|
type test struct {
|
||||||
defer testKubelet.Cleanup()
|
|
||||||
kubelet := testKubelet.kubelet
|
|
||||||
tests := []struct {
|
|
||||||
nodeIP string
|
nodeIP string
|
||||||
success bool
|
success bool
|
||||||
testName string
|
testName string
|
||||||
}{
|
}
|
||||||
|
tests := []test{
|
||||||
{
|
{
|
||||||
nodeIP: "",
|
nodeIP: "",
|
||||||
success: true,
|
success: false,
|
||||||
testName: "IP not set",
|
testName: "IP not set",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
nodeIP: "127.0.0.1",
|
nodeIP: "127.0.0.1",
|
||||||
success: false,
|
success: false,
|
||||||
testName: "loopback address",
|
testName: "IPv4 loopback address",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
nodeIP: "FE80::0202:B3FF:FE1E:8329",
|
nodeIP: "::1",
|
||||||
success: false,
|
success: false,
|
||||||
testName: "IPv6 address",
|
testName: "IPv6 loopback address",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nodeIP: "224.0.0.1",
|
||||||
|
success: false,
|
||||||
|
testName: "multicast IPv4 address",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nodeIP: "ff00::1",
|
||||||
|
success: false,
|
||||||
|
testName: "multicast IPv6 address",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nodeIP: "169.254.0.1",
|
||||||
|
success: false,
|
||||||
|
testName: "IPv4 link-local unicast address",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nodeIP: "fe80::0202:b3ff:fe1e:8329",
|
||||||
|
success: false,
|
||||||
|
testName: "IPv6 link-local unicast address",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nodeIP: "0.0.0.0",
|
||||||
|
success: false,
|
||||||
|
testName: "Unspecified IPv4 address",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nodeIP: "::",
|
||||||
|
success: false,
|
||||||
|
testName: "Unspecified IPv6 address",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
nodeIP: "1.2.3.4",
|
nodeIP: "1.2.3.4",
|
||||||
@ -128,9 +156,31 @@ func TestNodeIPParam(t *testing.T) {
|
|||||||
testName: "IPv4 address that doesn't belong to host",
|
testName: "IPv4 address that doesn't belong to host",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
addrs, err := net.InterfaceAddrs()
|
||||||
|
if err != nil {
|
||||||
|
assert.Error(t, err, fmt.Sprintf(
|
||||||
|
"Unable to obtain a list of the node's unicast interface addresses."))
|
||||||
|
}
|
||||||
|
for _, addr := range addrs {
|
||||||
|
var ip net.IP
|
||||||
|
switch v := addr.(type) {
|
||||||
|
case *net.IPNet:
|
||||||
|
ip = v.IP
|
||||||
|
case *net.IPAddr:
|
||||||
|
ip = v.IP
|
||||||
|
}
|
||||||
|
if ip.IsLoopback() || ip.IsLinkLocalUnicast() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
successTest := test{
|
||||||
|
nodeIP: ip.String(),
|
||||||
|
success: true,
|
||||||
|
testName: fmt.Sprintf("Success test case for address %s", ip.String()),
|
||||||
|
}
|
||||||
|
tests = append(tests, successTest)
|
||||||
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
kubelet.nodeIP = net.ParseIP(test.nodeIP)
|
err := validateNodeIP(net.ParseIP(test.nodeIP))
|
||||||
err := kubelet.validateNodeIP()
|
|
||||||
if test.success {
|
if test.success {
|
||||||
assert.NoError(t, err, "test %s", test.testName)
|
assert.NoError(t, err, "test %s", test.testName)
|
||||||
} else {
|
} else {
|
||||||
|
@ -437,7 +437,7 @@ func (kl *Kubelet) recordNodeStatusEvent(eventType, event string) {
|
|||||||
// Set IP and hostname addresses for the node.
|
// Set IP and hostname addresses for the node.
|
||||||
func (kl *Kubelet) setNodeAddress(node *v1.Node) error {
|
func (kl *Kubelet) setNodeAddress(node *v1.Node) error {
|
||||||
if kl.nodeIP != nil {
|
if kl.nodeIP != nil {
|
||||||
if err := kl.validateNodeIP(); err != nil {
|
if err := validateNodeIP(kl.nodeIP); err != nil {
|
||||||
return fmt.Errorf("failed to validate nodeIP: %v", err)
|
return fmt.Errorf("failed to validate nodeIP: %v", err)
|
||||||
}
|
}
|
||||||
glog.V(2).Infof("Using node IP: %q", kl.nodeIP.String())
|
glog.V(2).Infof("Using node IP: %q", kl.nodeIP.String())
|
||||||
@ -503,7 +503,8 @@ func (kl *Kubelet) setNodeAddress(node *v1.Node) error {
|
|||||||
|
|
||||||
// 1) Use nodeIP if set
|
// 1) Use nodeIP if set
|
||||||
// 2) If the user has specified an IP to HostnameOverride, use it
|
// 2) If the user has specified an IP to HostnameOverride, use it
|
||||||
// 3) Lookup the IP from node name by DNS and use the first non-loopback ipv4 address
|
// 3) Lookup the IP from node name by DNS and use the first valid IPv4 address.
|
||||||
|
// If the node does not have a valid IPv4 address, use the first valid IPv6 address.
|
||||||
// 4) Try to get the IP from the network interface used as default gateway
|
// 4) Try to get the IP from the network interface used as default gateway
|
||||||
if kl.nodeIP != nil {
|
if kl.nodeIP != nil {
|
||||||
ipAddr = kl.nodeIP
|
ipAddr = kl.nodeIP
|
||||||
@ -511,11 +512,16 @@ func (kl *Kubelet) setNodeAddress(node *v1.Node) error {
|
|||||||
ipAddr = addr
|
ipAddr = addr
|
||||||
} else {
|
} else {
|
||||||
var addrs []net.IP
|
var addrs []net.IP
|
||||||
addrs, err = net.LookupIP(node.Name)
|
addrs, _ = net.LookupIP(node.Name)
|
||||||
for _, addr := range addrs {
|
for _, addr := range addrs {
|
||||||
if !addr.IsLoopback() && addr.To4() != nil {
|
if err = validateNodeIP(addr); err == nil {
|
||||||
ipAddr = addr
|
if addr.To4() != nil {
|
||||||
break
|
ipAddr = addr
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if addr.To16() != nil && ipAddr == nil {
|
||||||
|
ipAddr = addr
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -991,17 +997,22 @@ func (kl *Kubelet) defaultNodeStatusFuncs() []func(*v1.Node) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate given node IP belongs to the current host
|
// Validate given node IP belongs to the current host
|
||||||
func (kl *Kubelet) validateNodeIP() error {
|
func validateNodeIP(nodeIP net.IP) error {
|
||||||
if kl.nodeIP == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Honor IP limitations set in setNodeStatus()
|
// Honor IP limitations set in setNodeStatus()
|
||||||
if kl.nodeIP.IsLoopback() {
|
if nodeIP.To4() == nil && nodeIP.To16() == nil {
|
||||||
|
return fmt.Errorf("nodeIP must be a valid IP address")
|
||||||
|
}
|
||||||
|
if nodeIP.IsLoopback() {
|
||||||
return fmt.Errorf("nodeIP can't be loopback address")
|
return fmt.Errorf("nodeIP can't be loopback address")
|
||||||
}
|
}
|
||||||
if kl.nodeIP.To4() == nil {
|
if nodeIP.IsMulticast() {
|
||||||
return fmt.Errorf("nodeIP must be IPv4 address")
|
return fmt.Errorf("nodeIP can't be a multicast address")
|
||||||
|
}
|
||||||
|
if nodeIP.IsLinkLocalUnicast() {
|
||||||
|
return fmt.Errorf("nodeIP can't be a link-local unicast address")
|
||||||
|
}
|
||||||
|
if nodeIP.IsUnspecified() {
|
||||||
|
return fmt.Errorf("nodeIP can't be an all zeros address")
|
||||||
}
|
}
|
||||||
|
|
||||||
addrs, err := net.InterfaceAddrs()
|
addrs, err := net.InterfaceAddrs()
|
||||||
@ -1016,9 +1027,9 @@ func (kl *Kubelet) validateNodeIP() error {
|
|||||||
case *net.IPAddr:
|
case *net.IPAddr:
|
||||||
ip = v.IP
|
ip = v.IP
|
||||||
}
|
}
|
||||||
if ip != nil && ip.Equal(kl.nodeIP) {
|
if ip != nil && ip.Equal(nodeIP) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fmt.Errorf("Node IP: %q not found in the host's network interfaces", kl.nodeIP.String())
|
return fmt.Errorf("Node IP: %q not found in the host's network interfaces", nodeIP.String())
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,7 @@ func TestNodeStatusWithCloudProviderNodeIP(t *testing.T) {
|
|||||||
Spec: v1.NodeSpec{},
|
Spec: v1.NodeSpec{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO : is it possible to mock kubelet.validateNodeIP() to avoid relying on the host interface addresses ?
|
// TODO : is it possible to mock validateNodeIP() to avoid relying on the host interface addresses ?
|
||||||
addrs, err := net.InterfaceAddrs()
|
addrs, err := net.InterfaceAddrs()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
for _, addr := range addrs {
|
for _, addr := range addrs {
|
||||||
|
Loading…
Reference in New Issue
Block a user