diff --git a/pkg/kubelet/BUILD b/pkg/kubelet/BUILD index e6395c8717..cd8c207bd4 100644 --- a/pkg/kubelet/BUILD +++ b/pkg/kubelet/BUILD @@ -170,6 +170,7 @@ go_test( "//pkg/api:go_default_library", "//pkg/api/install:go_default_library", "//pkg/capabilities:go_default_library", + "//pkg/cloudprovider/providers/fake:go_default_library", "//pkg/kubelet/apis:go_default_library", "//pkg/kubelet/apis/cri/v1alpha1/runtime:go_default_library", "//pkg/kubelet/apis/kubeletconfig:go_default_library", diff --git a/pkg/kubelet/kubelet_node_status.go b/pkg/kubelet/kubelet_node_status.go index 4817e6d68e..59b77a4893 100644 --- a/pkg/kubelet/kubelet_node_status.go +++ b/pkg/kubelet/kubelet_node_status.go @@ -469,15 +469,17 @@ func (kl *Kubelet) setNodeAddress(node *v1.Node) error { return fmt.Errorf("failed to get node address from cloud provider: %v", err) } if kl.nodeIP != nil { + enforcedNodeAddresses := []v1.NodeAddress{} for _, nodeAddress := range nodeAddresses { if nodeAddress.Address == kl.nodeIP.String() { - node.Status.Addresses = []v1.NodeAddress{ - {Type: nodeAddress.Type, Address: nodeAddress.Address}, - {Type: v1.NodeHostName, Address: kl.GetHostname()}, - } - return nil + enforcedNodeAddresses = append(enforcedNodeAddresses, v1.NodeAddress{Type: nodeAddress.Type, Address: nodeAddress.Address}) } } + if len(enforcedNodeAddresses) > 0 { + enforcedNodeAddresses = append(enforcedNodeAddresses, v1.NodeAddress{Type: v1.NodeHostName, Address: kl.GetHostname()}) + node.Status.Addresses = enforcedNodeAddresses + return nil + } return fmt.Errorf("failed to get node address from cloud provider that matches ip: %v", kl.nodeIP) } diff --git a/pkg/kubelet/kubelet_node_status_test.go b/pkg/kubelet/kubelet_node_status_test.go index ae005ea20e..e12ddc56d0 100644 --- a/pkg/kubelet/kubelet_node_status_test.go +++ b/pkg/kubelet/kubelet_node_status_test.go @@ -19,6 +19,7 @@ package kubelet import ( "encoding/json" "fmt" + "net" goruntime "runtime" "sort" "strconv" @@ -43,6 +44,7 @@ import ( "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/kubernetes/fake" core "k8s.io/client-go/testing" + fakecloud "k8s.io/kubernetes/pkg/cloudprovider/providers/fake" kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis" "k8s.io/kubernetes/pkg/kubelet/cm" kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" @@ -127,6 +129,85 @@ func (lcm *localCM) GetCapacity() v1.ResourceList { return lcm.capacity } +func TestNodeStatusWithCloudProviderNodeIP(t *testing.T) { + testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */) + defer testKubelet.Cleanup() + kubelet := testKubelet.kubelet + kubelet.hostname = testKubeletHostname + + existingNode := v1.Node{ + ObjectMeta: metav1.ObjectMeta{Name: testKubeletHostname, Annotations: make(map[string]string)}, + Spec: v1.NodeSpec{}, + } + + // TODO : is it possible to mock kubelet.validateNodeIP() to avoid relying on the host interface addresses ? + addrs, err := net.InterfaceAddrs() + assert.NoError(t, err) + 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 != nil && !ip.IsLoopback() && ip.To4() != nil { + kubelet.nodeIP = ip + break + } + } + assert.NotNil(t, kubelet.nodeIP) + + fakeCloud := &fakecloud.FakeCloud{ + Addresses: []v1.NodeAddress{ + { + Type: v1.NodeExternalIP, + Address: "132.143.154.163", + }, + { + Type: v1.NodeExternalIP, + Address: kubelet.nodeIP.String(), + }, + { + Type: v1.NodeInternalIP, + Address: "132.143.154.164", + }, + { + Type: v1.NodeInternalIP, + Address: kubelet.nodeIP.String(), + }, + { + Type: v1.NodeInternalIP, + Address: "132.143.154.165", + }, + { + Type: v1.NodeHostName, + Address: testKubeletHostname, + }, + }, + Err: nil, + } + kubelet.cloud = fakeCloud + + kubelet.setNodeAddress(&existingNode) + + expectedAddresses := []v1.NodeAddress{ + { + Type: v1.NodeExternalIP, + Address: kubelet.nodeIP.String(), + }, + { + Type: v1.NodeInternalIP, + Address: kubelet.nodeIP.String(), + }, + { + Type: v1.NodeHostName, + Address: testKubeletHostname, + }, + } + assert.True(t, apiequality.Semantic.DeepEqual(expectedAddresses, existingNode.Status.Addresses), "%s", diff.ObjectDiff(expectedAddresses, existingNode.Status.Addresses)) +} + func TestUpdateNewNodeStatus(t *testing.T) { // generate one more than maxImagesInNodeStatus in inputImageList inputImageList, expectedImageList := generateTestingImageList(maxImagesInNodeStatus + 1)