k8s.io/kubernetes@v1.29.3/pkg/proxy/ipvs/graceful_termination_test.go (about) 1 //go:build !windows 2 // +build !windows 3 4 /* 5 Copyright 2019 The Kubernetes Authors. 6 7 Licensed under the Apache License, Version 2.0 (the "License"); 8 you may not use this file except in compliance with the License. 9 You may obtain a copy of the License at 10 11 http://www.apache.org/licenses/LICENSE-2.0 12 13 Unless required by applicable law or agreed to in writing, software 14 distributed under the License is distributed on an "AS IS" BASIS, 15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 See the License for the specific language governing permissions and 17 limitations under the License. 18 */ 19 20 package ipvs 21 22 import ( 23 "fmt" 24 "reflect" 25 "testing" 26 27 netutils "k8s.io/utils/net" 28 29 utilipvs "k8s.io/kubernetes/pkg/proxy/ipvs/util" 30 utilipvstest "k8s.io/kubernetes/pkg/proxy/ipvs/util/testing" 31 ) 32 33 func Test_GracefulDeleteRS(t *testing.T) { 34 tests := []struct { 35 name string 36 vs *utilipvs.VirtualServer 37 rs *utilipvs.RealServer 38 existingIPVS *utilipvstest.FakeIPVS 39 expectedIPVS *utilipvstest.FakeIPVS 40 err error 41 }{ 42 { 43 name: "graceful delete, no connections results in deleting the real server immediatetly", 44 vs: &utilipvs.VirtualServer{ 45 Address: netutils.ParseIPSloppy("1.1.1.1"), 46 Protocol: "tcp", 47 Port: uint16(80), 48 }, 49 rs: &utilipvs.RealServer{ 50 Address: netutils.ParseIPSloppy("10.0.0.1"), 51 Port: uint16(80), 52 Weight: 100, 53 ActiveConn: 0, 54 InactiveConn: 0, 55 }, 56 existingIPVS: &utilipvstest.FakeIPVS{ 57 Services: map[utilipvstest.ServiceKey]*utilipvs.VirtualServer{ 58 { 59 IP: "1.1.1.1", 60 Port: 80, 61 Protocol: "tcp", 62 }: { 63 Address: netutils.ParseIPSloppy("1.1.1.1"), 64 Protocol: "tcp", 65 Port: uint16(80), 66 }, 67 }, 68 Destinations: map[utilipvstest.ServiceKey][]*utilipvs.RealServer{ 69 { 70 IP: "1.1.1.1", 71 Port: 80, 72 Protocol: "tcp", 73 }: { 74 { 75 Address: netutils.ParseIPSloppy("10.0.0.1"), 76 Port: uint16(80), 77 Weight: 100, 78 ActiveConn: 0, 79 InactiveConn: 0, 80 }, 81 }, 82 }, 83 }, 84 expectedIPVS: &utilipvstest.FakeIPVS{ 85 Services: map[utilipvstest.ServiceKey]*utilipvs.VirtualServer{ 86 { 87 IP: "1.1.1.1", 88 Port: 80, 89 Protocol: "tcp", 90 }: { 91 Address: netutils.ParseIPSloppy("1.1.1.1"), 92 Protocol: "tcp", 93 Port: uint16(80), 94 }, 95 }, 96 Destinations: map[utilipvstest.ServiceKey][]*utilipvs.RealServer{ 97 { 98 IP: "1.1.1.1", 99 Port: 80, 100 Protocol: "tcp", 101 }: {}, 102 }, 103 }, 104 err: nil, 105 }, 106 { 107 name: "graceful delete, real server has active connections, weight should be 0 but don't delete", 108 vs: &utilipvs.VirtualServer{ 109 Address: netutils.ParseIPSloppy("1.1.1.1"), 110 Protocol: "tcp", 111 Port: uint16(80), 112 }, 113 rs: &utilipvs.RealServer{ 114 Address: netutils.ParseIPSloppy("10.0.0.1"), 115 Port: uint16(80), 116 Weight: 100, 117 ActiveConn: 10, 118 InactiveConn: 0, 119 }, 120 existingIPVS: &utilipvstest.FakeIPVS{ 121 Services: map[utilipvstest.ServiceKey]*utilipvs.VirtualServer{ 122 { 123 IP: "1.1.1.1", 124 Port: 80, 125 Protocol: "tcp", 126 }: { 127 Address: netutils.ParseIPSloppy("1.1.1.1"), 128 Protocol: "tcp", 129 Port: uint16(80), 130 }, 131 }, 132 Destinations: map[utilipvstest.ServiceKey][]*utilipvs.RealServer{ 133 { 134 IP: "1.1.1.1", 135 Port: 80, 136 Protocol: "tcp", 137 }: { 138 { 139 Address: netutils.ParseIPSloppy("10.0.0.1"), 140 Port: uint16(80), 141 Weight: 100, 142 ActiveConn: 10, 143 InactiveConn: 0, 144 }, 145 }, 146 }, 147 }, 148 expectedIPVS: &utilipvstest.FakeIPVS{ 149 Services: map[utilipvstest.ServiceKey]*utilipvs.VirtualServer{ 150 { 151 IP: "1.1.1.1", 152 Port: 80, 153 Protocol: "tcp", 154 }: { 155 Address: netutils.ParseIPSloppy("1.1.1.1"), 156 Protocol: "tcp", 157 Port: uint16(80), 158 }, 159 }, 160 Destinations: map[utilipvstest.ServiceKey][]*utilipvs.RealServer{ 161 { 162 IP: "1.1.1.1", 163 Port: 80, 164 Protocol: "tcp", 165 }: { 166 { 167 Address: netutils.ParseIPSloppy("10.0.0.1"), 168 Port: uint16(80), 169 Weight: 0, 170 ActiveConn: 10, 171 InactiveConn: 0, 172 }, 173 }, 174 }, 175 }, 176 err: nil, 177 }, 178 { 179 name: "graceful delete, real server has in-active connections, weight should be 0 but don't delete", 180 vs: &utilipvs.VirtualServer{ 181 Address: netutils.ParseIPSloppy("1.1.1.1"), 182 Protocol: "tcp", 183 Port: uint16(80), 184 }, 185 rs: &utilipvs.RealServer{ 186 Address: netutils.ParseIPSloppy("10.0.0.1"), 187 Port: uint16(80), 188 Weight: 100, 189 ActiveConn: 0, 190 InactiveConn: 10, 191 }, 192 existingIPVS: &utilipvstest.FakeIPVS{ 193 Services: map[utilipvstest.ServiceKey]*utilipvs.VirtualServer{ 194 { 195 IP: "1.1.1.1", 196 Port: 80, 197 Protocol: "tcp", 198 }: { 199 Address: netutils.ParseIPSloppy("1.1.1.1"), 200 Protocol: "tcp", 201 Port: uint16(80), 202 }, 203 }, 204 Destinations: map[utilipvstest.ServiceKey][]*utilipvs.RealServer{ 205 { 206 IP: "1.1.1.1", 207 Port: 80, 208 Protocol: "tcp", 209 }: { 210 { 211 Address: netutils.ParseIPSloppy("10.0.0.1"), 212 Port: uint16(80), 213 Weight: 100, 214 ActiveConn: 0, 215 InactiveConn: 10, 216 }, 217 }, 218 }, 219 }, 220 expectedIPVS: &utilipvstest.FakeIPVS{ 221 Services: map[utilipvstest.ServiceKey]*utilipvs.VirtualServer{ 222 { 223 IP: "1.1.1.1", 224 Port: 80, 225 Protocol: "tcp", 226 }: { 227 Address: netutils.ParseIPSloppy("1.1.1.1"), 228 Protocol: "tcp", 229 Port: uint16(80), 230 }, 231 }, 232 Destinations: map[utilipvstest.ServiceKey][]*utilipvs.RealServer{ 233 { 234 IP: "1.1.1.1", 235 Port: 80, 236 Protocol: "tcp", 237 }: { 238 { 239 Address: netutils.ParseIPSloppy("10.0.0.1"), 240 Port: uint16(80), 241 Weight: 0, 242 ActiveConn: 0, 243 InactiveConn: 10, 244 }, 245 }, 246 }, 247 }, 248 err: nil, 249 }, 250 { 251 name: "graceful delete, real server has connections, but udp connections are deleted immediately", 252 vs: &utilipvs.VirtualServer{ 253 Address: netutils.ParseIPSloppy("1.1.1.1"), 254 Protocol: "udp", 255 Port: uint16(80), 256 }, 257 rs: &utilipvs.RealServer{ 258 Address: netutils.ParseIPSloppy("10.0.0.1"), 259 Port: uint16(80), 260 Weight: 100, 261 ActiveConn: 10, 262 InactiveConn: 10, 263 }, 264 existingIPVS: &utilipvstest.FakeIPVS{ 265 Services: map[utilipvstest.ServiceKey]*utilipvs.VirtualServer{ 266 { 267 IP: "1.1.1.1", 268 Port: 80, 269 Protocol: "udp", 270 }: { 271 Address: netutils.ParseIPSloppy("1.1.1.1"), 272 Protocol: "udp", 273 Port: uint16(80), 274 }, 275 }, 276 Destinations: map[utilipvstest.ServiceKey][]*utilipvs.RealServer{ 277 { 278 IP: "1.1.1.1", 279 Port: 80, 280 Protocol: "udp", 281 }: { 282 { 283 Address: netutils.ParseIPSloppy("10.0.0.1"), 284 Port: uint16(80), 285 Weight: 100, 286 ActiveConn: 10, 287 InactiveConn: 10, 288 }, 289 }, 290 }, 291 }, 292 expectedIPVS: &utilipvstest.FakeIPVS{ 293 Services: map[utilipvstest.ServiceKey]*utilipvs.VirtualServer{ 294 { 295 IP: "1.1.1.1", 296 Port: 80, 297 Protocol: "udp", 298 }: { 299 Address: netutils.ParseIPSloppy("1.1.1.1"), 300 Protocol: "udp", 301 Port: uint16(80), 302 }, 303 }, 304 Destinations: map[utilipvstest.ServiceKey][]*utilipvs.RealServer{ 305 { 306 IP: "1.1.1.1", 307 Port: 80, 308 Protocol: "udp", 309 }: {}, // udp real server deleted immediately 310 }, 311 }, 312 err: nil, 313 }, 314 { 315 name: "graceful delete, real server mismatch should be no-op", 316 vs: &utilipvs.VirtualServer{ 317 Address: netutils.ParseIPSloppy("1.1.1.1"), 318 Protocol: "tcp", 319 Port: uint16(80), 320 }, 321 rs: &utilipvs.RealServer{ 322 Address: netutils.ParseIPSloppy("10.0.0.1"), 323 Port: uint16(81), // port mismatched 324 Weight: 100, 325 ActiveConn: 0, 326 InactiveConn: 10, 327 }, 328 existingIPVS: &utilipvstest.FakeIPVS{ 329 Services: map[utilipvstest.ServiceKey]*utilipvs.VirtualServer{ 330 { 331 IP: "1.1.1.1", 332 Port: 80, 333 Protocol: "tcp", 334 }: { 335 Address: netutils.ParseIPSloppy("1.1.1.1"), 336 Protocol: "tcp", 337 Port: uint16(80), 338 }, 339 }, 340 Destinations: map[utilipvstest.ServiceKey][]*utilipvs.RealServer{ 341 { 342 IP: "1.1.1.1", 343 Port: 80, 344 Protocol: "tcp", 345 }: { 346 { 347 Address: netutils.ParseIPSloppy("10.0.0.1"), 348 Port: uint16(80), 349 Weight: 100, 350 ActiveConn: 0, 351 InactiveConn: 10, 352 }, 353 }, 354 }, 355 }, 356 expectedIPVS: &utilipvstest.FakeIPVS{ 357 Services: map[utilipvstest.ServiceKey]*utilipvs.VirtualServer{ 358 { 359 IP: "1.1.1.1", 360 Port: 80, 361 Protocol: "tcp", 362 }: { 363 Address: netutils.ParseIPSloppy("1.1.1.1"), 364 Protocol: "tcp", 365 Port: uint16(80), 366 }, 367 }, 368 Destinations: map[utilipvstest.ServiceKey][]*utilipvs.RealServer{ 369 { 370 IP: "1.1.1.1", 371 Port: 80, 372 Protocol: "tcp", 373 }: { 374 { 375 Address: netutils.ParseIPSloppy("10.0.0.1"), 376 Port: uint16(80), 377 Weight: 100, 378 ActiveConn: 0, 379 InactiveConn: 10, 380 }, 381 }, 382 }, 383 }, 384 err: nil, 385 }, 386 } 387 388 for _, test := range tests { 389 t.Run(test.name, func(t *testing.T) { 390 ipvs := test.existingIPVS 391 gracefulTerminationManager := NewGracefulTerminationManager(ipvs) 392 393 err := gracefulTerminationManager.GracefulDeleteRS(test.vs, test.rs) 394 if err != test.err { 395 t.Logf("actual err: %v", err) 396 t.Logf("expected err: %v", test.err) 397 t.Errorf("unexpected error") 398 } 399 400 if !reflect.DeepEqual(ipvs, test.expectedIPVS) { 401 t.Logf("actual: %+v", ipvs) 402 t.Logf("expected : %+v", test.expectedIPVS) 403 t.Errorf("unexpected IPVS servers") 404 } 405 }) 406 } 407 } 408 409 func Test_RaceTerminateRSList(t *testing.T) { 410 ipvs := utilipvstest.NewFake() 411 gracefulTerminationManager := NewGracefulTerminationManager(ipvs) 412 413 // run in parallel to cause the race 414 go func() { 415 for i := 1; i <= 10; i++ { 416 for j := 1; j <= 100; j++ { 417 item := makeListItem(i, j) 418 gracefulTerminationManager.rsList.add(item) 419 } 420 } 421 }() 422 423 // wait until the list has some elements 424 for gracefulTerminationManager.rsList.len() < 20 { 425 } 426 427 // fake the handler to avoid the check against the IPVS virtual servers 428 fakeHandler := func(rsToDelete *listItem) (bool, error) { 429 return true, nil 430 } 431 if !gracefulTerminationManager.rsList.flushList(fakeHandler) { 432 t.Error("failed to flush entries") 433 } 434 } 435 436 func makeListItem(i, j int) *listItem { 437 vs := fmt.Sprintf("%d.%d.%d.%d", 1, 1, i, i) 438 rs := fmt.Sprintf("%d.%d.%d.%d", 1, 1, i, j) 439 return &listItem{ 440 VirtualServer: &utilipvs.VirtualServer{ 441 Address: netutils.ParseIPSloppy(vs), 442 Protocol: "tcp", 443 Port: uint16(80), 444 }, 445 RealServer: &utilipvs.RealServer{ 446 Address: netutils.ParseIPSloppy(rs), 447 Port: uint16(80), 448 }, 449 } 450 }