set secondary address on host-network pods

host-network pods IPs are obtained from the reported kubelet nodeIPs.

Historically, host-network podIPs are immutable once set, but when
we've added dual-stack support, we didn't consider that the secondary
IP address may not be present at the same time that the primary nodeIP.

If a secondary IP address is added to a node after the host-network pods
IPs are set, we can add the secondary host-network pod IP address
maintaining the current behavior of not updating the current podIPs on
host-network pods.
This commit is contained in:
Antonio Ojea 2021-11-29 15:10:54 +01:00
parent e8b177cfc1
commit a20b2088ac
2 changed files with 123 additions and 4 deletions

View File

@ -1520,10 +1520,16 @@ func (kl *Kubelet) generateAPIPodStatus(pod *v1.Pod, podStatus *kubecontainer.Po
klog.V(4).InfoS("Cannot get host IPs", "err", err)
} else {
s.HostIP = hostIPs[0].String()
if kubecontainer.IsHostNetworkPod(pod) && s.PodIP == "" {
s.PodIP = hostIPs[0].String()
s.PodIPs = []v1.PodIP{{IP: s.PodIP}}
if len(hostIPs) == 2 {
// HostNetwork Pods inherit the node IPs as PodIPs. They are immutable once set,
// other than that if the node becomes dual-stack, we add the secondary IP.
if kubecontainer.IsHostNetworkPod(pod) {
// Primary IP is not set
if s.PodIP == "" {
s.PodIP = hostIPs[0].String()
s.PodIPs = []v1.PodIP{{IP: s.PodIP}}
}
// Secondary IP is not set #105320
if len(hostIPs) == 2 && len(s.PodIPs) == 1 {
s.PodIPs = append(s.PodIPs, v1.PodIP{IP: hostIPs[1].String()})
}
}

View File

@ -3349,6 +3349,119 @@ func TestGenerateAPIPodStatusHostNetworkPodIPs(t *testing.T) {
}
}
func TestNodeAddressUpdatesGenerateAPIPodStatusHostNetworkPodIPs(t *testing.T) {
testcases := []struct {
name string
nodeIPs []string
nodeAddresses []v1.NodeAddress
expectedPodIPs []v1.PodIP
}{
{
name: "Immutable after update node addresses single-stack",
nodeIPs: []string{"10.0.0.1"},
nodeAddresses: []v1.NodeAddress{
{Type: v1.NodeInternalIP, Address: "1.1.1.1"},
},
expectedPodIPs: []v1.PodIP{
{IP: "10.0.0.1"},
},
},
{
name: "Immutable after update node addresses dual-stack - primary address",
nodeIPs: []string{"10.0.0.1", "2001:db8::2"},
nodeAddresses: []v1.NodeAddress{
{Type: v1.NodeInternalIP, Address: "1.1.1.1"},
{Type: v1.NodeInternalIP, Address: "2001:db8::2"},
},
expectedPodIPs: []v1.PodIP{
{IP: "10.0.0.1"},
{IP: "2001:db8::2"},
},
},
{
name: "Immutable after update node addresses dual-stack - secondary address",
nodeIPs: []string{"10.0.0.1", "2001:db8::2"},
nodeAddresses: []v1.NodeAddress{
{Type: v1.NodeInternalIP, Address: "10.0.0.1"},
{Type: v1.NodeInternalIP, Address: "2001:db8:1:2:3::2"},
},
expectedPodIPs: []v1.PodIP{
{IP: "10.0.0.1"},
{IP: "2001:db8::2"},
},
},
{
name: "Immutable after update node addresses dual-stack - primary and secondary address",
nodeIPs: []string{"10.0.0.1", "2001:db8::2"},
nodeAddresses: []v1.NodeAddress{
{Type: v1.NodeInternalIP, Address: "1.1.1.1"},
{Type: v1.NodeInternalIP, Address: "2001:db8:1:2:3::2"},
},
expectedPodIPs: []v1.PodIP{
{IP: "10.0.0.1"},
{IP: "2001:db8::2"},
},
},
{
name: "Update secondary after new secondary address dual-stack",
nodeIPs: []string{"10.0.0.1"},
nodeAddresses: []v1.NodeAddress{
{Type: v1.NodeInternalIP, Address: "10.0.0.1"},
{Type: v1.NodeInternalIP, Address: "2001:db8::2"},
},
expectedPodIPs: []v1.PodIP{
{IP: "10.0.0.1"},
{IP: "2001:db8::2"},
},
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
defer testKubelet.Cleanup()
kl := testKubelet.kubelet
for _, ip := range tc.nodeIPs {
kl.nodeIPs = append(kl.nodeIPs, netutils.ParseIPSloppy(ip))
}
kl.nodeLister = testNodeLister{nodes: []*v1.Node{
{
ObjectMeta: metav1.ObjectMeta{Name: string(kl.nodeName)},
Status: v1.NodeStatus{
Addresses: tc.nodeAddresses,
},
},
}}
pod := podWithUIDNameNs("12345", "test-pod", "test-namespace")
pod.Spec.HostNetwork = true
for _, ip := range tc.nodeIPs {
pod.Status.PodIPs = append(pod.Status.PodIPs, v1.PodIP{IP: ip})
}
if len(pod.Status.PodIPs) > 0 {
pod.Status.PodIP = pod.Status.PodIPs[0].IP
}
// set old status
podStatus := &kubecontainer.PodStatus{
ID: pod.UID,
Name: pod.Name,
Namespace: pod.Namespace,
}
podStatus.IPs = tc.nodeIPs
status := kl.generateAPIPodStatus(pod, podStatus)
if !reflect.DeepEqual(status.PodIPs, tc.expectedPodIPs) {
t.Fatalf("Expected PodIPs %#v, got %#v", tc.expectedPodIPs, status.PodIPs)
}
if kl.nodeIPs[0].String() != status.PodIPs[0].IP {
t.Fatalf("Expected HostIP %q to equal PodIPs[0].IP %q", status.HostIP, status.PodIPs[0].IP)
}
})
}
}
func TestGenerateAPIPodStatusPodIPs(t *testing.T) {
testcases := []struct {
name string