k8s.io/kubernetes@v1.29.3/pkg/util/node/node_test.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package node
    18  
    19  import (
    20  	"net"
    21  	"reflect"
    22  	"testing"
    23  
    24  	"github.com/stretchr/testify/assert"
    25  
    26  	v1 "k8s.io/api/core/v1"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	netutils "k8s.io/utils/net"
    29  )
    30  
    31  func TestGetPreferredAddress(t *testing.T) {
    32  	testcases := map[string]struct {
    33  		Labels      map[string]string
    34  		Addresses   []v1.NodeAddress
    35  		Preferences []v1.NodeAddressType
    36  
    37  		ExpectErr     string
    38  		ExpectAddress string
    39  	}{
    40  		"no addresses": {
    41  			ExpectErr: "no preferred addresses found; known addresses: []",
    42  		},
    43  		"missing address": {
    44  			Addresses: []v1.NodeAddress{
    45  				{Type: v1.NodeInternalIP, Address: "1.2.3.4"},
    46  			},
    47  			Preferences: []v1.NodeAddressType{v1.NodeHostName},
    48  			ExpectErr:   "no preferred addresses found; known addresses: [{InternalIP 1.2.3.4}]",
    49  		},
    50  		"found address": {
    51  			Addresses: []v1.NodeAddress{
    52  				{Type: v1.NodeInternalIP, Address: "1.2.3.4"},
    53  				{Type: v1.NodeExternalIP, Address: "1.2.3.5"},
    54  				{Type: v1.NodeExternalIP, Address: "1.2.3.7"},
    55  			},
    56  			Preferences:   []v1.NodeAddressType{v1.NodeHostName, v1.NodeExternalIP},
    57  			ExpectAddress: "1.2.3.5",
    58  		},
    59  		"found hostname address": {
    60  			Labels: map[string]string{v1.LabelHostname: "label-hostname"},
    61  			Addresses: []v1.NodeAddress{
    62  				{Type: v1.NodeExternalIP, Address: "1.2.3.5"},
    63  				{Type: v1.NodeHostName, Address: "status-hostname"},
    64  			},
    65  			Preferences:   []v1.NodeAddressType{v1.NodeHostName, v1.NodeExternalIP},
    66  			ExpectAddress: "status-hostname",
    67  		},
    68  		"label address ignored": {
    69  			Labels: map[string]string{v1.LabelHostname: "label-hostname"},
    70  			Addresses: []v1.NodeAddress{
    71  				{Type: v1.NodeExternalIP, Address: "1.2.3.5"},
    72  			},
    73  			Preferences:   []v1.NodeAddressType{v1.NodeHostName, v1.NodeExternalIP},
    74  			ExpectAddress: "1.2.3.5",
    75  		},
    76  	}
    77  
    78  	for k, tc := range testcases {
    79  		node := &v1.Node{
    80  			ObjectMeta: metav1.ObjectMeta{Labels: tc.Labels},
    81  			Status:     v1.NodeStatus{Addresses: tc.Addresses},
    82  		}
    83  		address, err := GetPreferredNodeAddress(node, tc.Preferences)
    84  		errString := ""
    85  		if err != nil {
    86  			errString = err.Error()
    87  		}
    88  		if errString != tc.ExpectErr {
    89  			t.Errorf("%s: expected err=%q, got %q", k, tc.ExpectErr, errString)
    90  		}
    91  		if address != tc.ExpectAddress {
    92  			t.Errorf("%s: expected address=%q, got %q", k, tc.ExpectAddress, address)
    93  		}
    94  	}
    95  }
    96  
    97  func TestGetNodeHostIPs(t *testing.T) {
    98  	testcases := []struct {
    99  		name      string
   100  		addresses []v1.NodeAddress
   101  
   102  		expectIPs []net.IP
   103  	}{
   104  		{
   105  			name:      "no addresses",
   106  			expectIPs: nil,
   107  		},
   108  		{
   109  			name: "no InternalIP/ExternalIP",
   110  			addresses: []v1.NodeAddress{
   111  				{Type: v1.NodeHostName, Address: "example.com"},
   112  			},
   113  			expectIPs: nil,
   114  		},
   115  		{
   116  			name: "IPv4-only, simple",
   117  			addresses: []v1.NodeAddress{
   118  				{Type: v1.NodeInternalIP, Address: "1.2.3.4"},
   119  				{Type: v1.NodeExternalIP, Address: "4.3.2.1"},
   120  				{Type: v1.NodeExternalIP, Address: "4.3.2.2"},
   121  			},
   122  			expectIPs: []net.IP{netutils.ParseIPSloppy("1.2.3.4")},
   123  		},
   124  		{
   125  			name: "IPv4-only, external-first",
   126  			addresses: []v1.NodeAddress{
   127  				{Type: v1.NodeExternalIP, Address: "4.3.2.1"},
   128  				{Type: v1.NodeExternalIP, Address: "4.3.2.2"},
   129  				{Type: v1.NodeInternalIP, Address: "1.2.3.4"},
   130  			},
   131  			expectIPs: []net.IP{netutils.ParseIPSloppy("1.2.3.4")},
   132  		},
   133  		{
   134  			name: "IPv4-only, no internal",
   135  			addresses: []v1.NodeAddress{
   136  				{Type: v1.NodeExternalIP, Address: "4.3.2.1"},
   137  				{Type: v1.NodeExternalIP, Address: "4.3.2.2"},
   138  			},
   139  			expectIPs: []net.IP{netutils.ParseIPSloppy("4.3.2.1")},
   140  		},
   141  		{
   142  			name: "dual-stack node",
   143  			addresses: []v1.NodeAddress{
   144  				{Type: v1.NodeInternalIP, Address: "1.2.3.4"},
   145  				{Type: v1.NodeExternalIP, Address: "4.3.2.1"},
   146  				{Type: v1.NodeExternalIP, Address: "4.3.2.2"},
   147  				{Type: v1.NodeInternalIP, Address: "a:b::c:d"},
   148  				{Type: v1.NodeExternalIP, Address: "d:c::b:a"},
   149  			},
   150  			expectIPs: []net.IP{netutils.ParseIPSloppy("1.2.3.4"), netutils.ParseIPSloppy("a:b::c:d")},
   151  		},
   152  		{
   153  			name: "dual-stack node, different order",
   154  			addresses: []v1.NodeAddress{
   155  				{Type: v1.NodeInternalIP, Address: "1.2.3.4"},
   156  				{Type: v1.NodeInternalIP, Address: "a:b::c:d"},
   157  				{Type: v1.NodeExternalIP, Address: "4.3.2.1"},
   158  				{Type: v1.NodeExternalIP, Address: "4.3.2.2"},
   159  				{Type: v1.NodeExternalIP, Address: "d:c::b:a"},
   160  			},
   161  			expectIPs: []net.IP{netutils.ParseIPSloppy("1.2.3.4"), netutils.ParseIPSloppy("a:b::c:d")},
   162  		},
   163  		{
   164  			name: "dual-stack node, IPv6-first, no internal IPv4, dual-stack cluster",
   165  			addresses: []v1.NodeAddress{
   166  				{Type: v1.NodeInternalIP, Address: "a:b::c:d"},
   167  				{Type: v1.NodeExternalIP, Address: "d:c::b:a"},
   168  				{Type: v1.NodeExternalIP, Address: "4.3.2.1"},
   169  				{Type: v1.NodeExternalIP, Address: "4.3.2.2"},
   170  			},
   171  			expectIPs: []net.IP{netutils.ParseIPSloppy("a:b::c:d"), netutils.ParseIPSloppy("4.3.2.1")},
   172  		},
   173  	}
   174  
   175  	for _, tc := range testcases {
   176  		t.Run(tc.name, func(t *testing.T) {
   177  			node := &v1.Node{
   178  				Status: v1.NodeStatus{Addresses: tc.addresses},
   179  			}
   180  			nodeIPs, err := GetNodeHostIPs(node)
   181  			nodeIP, err2 := GetNodeHostIP(node)
   182  
   183  			if (err == nil && err2 != nil) || (err != nil && err2 == nil) {
   184  				t.Errorf("GetNodeHostIPs() returned error=%q but GetNodeHostIP() returned error=%q", err, err2)
   185  			}
   186  			if err != nil {
   187  				if tc.expectIPs != nil {
   188  					t.Errorf("expected %v, got error (%v)", tc.expectIPs, err)
   189  				}
   190  			} else if tc.expectIPs == nil {
   191  				t.Errorf("expected error, got %v", nodeIPs)
   192  			} else if !reflect.DeepEqual(nodeIPs, tc.expectIPs) {
   193  				t.Errorf("expected %v, got %v", tc.expectIPs, nodeIPs)
   194  			} else if !nodeIP.Equal(nodeIPs[0]) {
   195  				t.Errorf("GetNodeHostIP did not return same primary (%s) as GetNodeHostIPs (%s)", nodeIP.String(), nodeIPs[0].String())
   196  			}
   197  		})
   198  	}
   199  }
   200  
   201  func TestIsNodeReady(t *testing.T) {
   202  	testCases := []struct {
   203  		name   string
   204  		Node   *v1.Node
   205  		expect bool
   206  	}{
   207  		{
   208  			name: "case that returns true",
   209  			Node: &v1.Node{
   210  				Status: v1.NodeStatus{
   211  					Conditions: []v1.NodeCondition{
   212  						{
   213  							Type:   v1.NodeReady,
   214  							Status: v1.ConditionTrue,
   215  						},
   216  					},
   217  				},
   218  			},
   219  			expect: true,
   220  		},
   221  		{
   222  			name: "case that returns false",
   223  			Node: &v1.Node{
   224  				Status: v1.NodeStatus{
   225  					Conditions: []v1.NodeCondition{
   226  						{
   227  							Type:   v1.NodeReady,
   228  							Status: v1.ConditionFalse,
   229  						},
   230  					},
   231  				},
   232  			},
   233  			expect: false,
   234  		},
   235  		{
   236  			name: "case that returns false",
   237  			Node: &v1.Node{
   238  				Status: v1.NodeStatus{
   239  					Conditions: []v1.NodeCondition{
   240  						{
   241  							Type:   v1.NodeMemoryPressure,
   242  							Status: v1.ConditionFalse,
   243  						},
   244  					},
   245  				},
   246  			},
   247  			expect: false,
   248  		},
   249  	}
   250  	for _, test := range testCases {
   251  		t.Run(test.name, func(t *testing.T) {
   252  			result := IsNodeReady(test.Node)
   253  			assert.Equal(t, test.expect, result)
   254  		})
   255  	}
   256  }