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 }