github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/container-collection/match_test.go (about) 1 // Copyright 2019-2021 The Inspektor Gadget authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package containercollection 16 17 import ( 18 "fmt" 19 "reflect" 20 "testing" 21 22 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 23 k8sTypes "k8s.io/apimachinery/pkg/types" 24 25 "github.com/inspektor-gadget/inspektor-gadget/pkg/types" 26 ) 27 28 func TestSelector(t *testing.T) { 29 table := []struct { 30 description string 31 match bool 32 selector *ContainerSelector 33 container *Container 34 }{ 35 { 36 description: "Selector without filter", 37 match: true, 38 selector: &ContainerSelector{}, 39 container: &Container{ 40 K8s: K8sMetadata{ 41 BasicK8sMetadata: types.BasicK8sMetadata{ 42 Namespace: "this-namespace", 43 PodName: "this-pod", 44 ContainerName: "this-container", 45 }, 46 }, 47 }, 48 }, 49 { 50 description: "Selector with all filters", 51 match: true, 52 selector: &ContainerSelector{ 53 K8s: K8sSelector{ 54 BasicK8sMetadata: types.BasicK8sMetadata{ 55 Namespace: "this-namespace", 56 PodName: "this-pod", 57 ContainerName: "this-container", 58 PodLabels: map[string]string{ 59 "key1": "value1", 60 "key2": "value2", 61 }, 62 }, 63 }, 64 }, 65 container: &Container{ 66 K8s: K8sMetadata{ 67 BasicK8sMetadata: types.BasicK8sMetadata{ 68 Namespace: "this-namespace", 69 PodName: "this-pod", 70 ContainerName: "this-container", 71 PodLabels: map[string]string{ 72 "unrelated-label": "here", 73 "key1": "value1", 74 "key2": "value2", 75 }, 76 }, 77 }, 78 }, 79 }, 80 { 81 description: "Podname does not match", 82 match: false, 83 selector: &ContainerSelector{ 84 K8s: K8sSelector{ 85 BasicK8sMetadata: types.BasicK8sMetadata{ 86 Namespace: "this-namespace", 87 PodName: "this-pod", 88 }, 89 }, 90 }, 91 container: &Container{ 92 K8s: K8sMetadata{ 93 BasicK8sMetadata: types.BasicK8sMetadata{ 94 Namespace: "this-namespace", 95 PodName: "a-misnamed-pod", 96 ContainerName: "this-container", 97 }, 98 }, 99 }, 100 }, 101 { 102 description: "One label doesn't match", 103 match: false, 104 selector: &ContainerSelector{ 105 K8s: K8sSelector{ 106 BasicK8sMetadata: types.BasicK8sMetadata{ 107 Namespace: "this-namespace", 108 PodName: "this-pod", 109 ContainerName: "this-container", 110 PodLabels: map[string]string{ 111 "key1": "value1", 112 "key2": "value2", 113 }, 114 }, 115 }, 116 }, 117 container: &Container{ 118 K8s: K8sMetadata{ 119 BasicK8sMetadata: types.BasicK8sMetadata{ 120 Namespace: "this-namespace", 121 PodName: "this-pod", 122 ContainerName: "this-container", 123 PodLabels: map[string]string{ 124 "key1": "value1", 125 "key2": "something-else", 126 }, 127 }, 128 }, 129 }, 130 }, 131 { 132 description: "Several namespaces without match", 133 match: false, 134 selector: &ContainerSelector{ 135 K8s: K8sSelector{ 136 BasicK8sMetadata: types.BasicK8sMetadata{ 137 Namespace: "ns1,ns2,ns3", 138 PodName: "this-pod", 139 }, 140 }, 141 }, 142 container: &Container{ 143 K8s: K8sMetadata{ 144 BasicK8sMetadata: types.BasicK8sMetadata{ 145 Namespace: "this-namespace", 146 PodName: "this-pod", 147 ContainerName: "this-container", 148 }, 149 }, 150 }, 151 }, 152 { 153 description: "Several namespaces with match", 154 match: true, 155 selector: &ContainerSelector{ 156 K8s: K8sSelector{ 157 BasicK8sMetadata: types.BasicK8sMetadata{ 158 Namespace: "ns1,ns2,ns3", 159 PodName: "this-pod", 160 }, 161 }, 162 }, 163 container: &Container{ 164 K8s: K8sMetadata{ 165 BasicK8sMetadata: types.BasicK8sMetadata{ 166 Namespace: "ns2", 167 PodName: "this-pod", 168 ContainerName: "this-container", 169 }, 170 }, 171 }, 172 }, 173 } 174 175 for i, entry := range table { 176 result := ContainerSelectorMatches(entry.selector, entry.container) 177 if entry.match != result { 178 t.Fatalf("Failed test %q (index %d): result %v expected %v", 179 entry.description, i, result, entry.match) 180 } 181 } 182 } 183 184 func TestContainerResolver(t *testing.T) { 185 opts := []ContainerCollectionOption{} 186 187 cc := &ContainerCollection{} 188 err := cc.Initialize(opts...) 189 if err != nil { 190 t.Fatalf("Failed to initialize container collection: %s", err) 191 } 192 193 // Add 3 Containers 194 for i := 0; i < 3; i++ { 195 cc.AddContainer(&Container{ 196 Runtime: RuntimeMetadata{ 197 BasicRuntimeMetadata: types.BasicRuntimeMetadata{ 198 ContainerID: fmt.Sprintf("abcde%d", i), 199 }, 200 }, 201 Mntns: 55555 + uint64(i), 202 Pid: uint32(100 + i), 203 CgroupPath: "/none", 204 CgroupID: 1, 205 K8s: K8sMetadata{ 206 BasicK8sMetadata: types.BasicK8sMetadata{ 207 Namespace: "this-namespace", 208 PodName: "my-pod", 209 ContainerName: fmt.Sprintf("container%d", i), 210 }, 211 ownerReference: &metav1.OwnerReference{ 212 UID: k8sTypes.UID(fmt.Sprintf("abcde%d", i)), 213 }, 214 }, 215 }) 216 } 217 218 // Remove 1 Container 219 cc.RemoveContainer("abcde1") 220 221 // Remove non-existent Container 222 cc.RemoveContainer("abcde99") 223 224 // Check content 225 if cc.ContainerLen() != 2 { 226 t.Fatalf("Error while checking containers: len %d", cc.ContainerLen()) 227 } 228 if cc.GetContainer("abcde0") == nil { 229 t.Fatalf("Error while checking container %s: not found", "abcde0") 230 } 231 if cc.GetContainer("abcde2") == nil { 232 t.Fatalf("Error while checking container %s: not found", "abcde2") 233 } 234 235 // Check content using LookupMntnsByPod 236 mntnsByContainer := cc.LookupMntnsByPod("this-namespace", "my-pod") 237 if !reflect.DeepEqual(mntnsByContainer, map[string]uint64{"container0": 55555, "container2": 55557}) { 238 t.Fatalf("Error while looking up mount ns by Pod: unexpected %v", mntnsByContainer) 239 } 240 mntnsByContainer = cc.LookupMntnsByPod("this-namespace", "this-other-pod") 241 if !reflect.DeepEqual(mntnsByContainer, map[string]uint64{}) { 242 t.Fatalf("Error while looking up mount ns by Pod: unexpected %v", mntnsByContainer) 243 } 244 245 // Check content using LookupMntnsByContainer 246 mntns := cc.LookupMntnsByContainer("this-namespace", "my-pod", "container0") 247 if mntns != 55555 { 248 t.Fatalf("Error while looking up container0: unexpected mntns %v", mntns) 249 } 250 mntns = cc.LookupMntnsByContainer("this-namespace", "my-pod", "container1") 251 if mntns != 0 { 252 t.Fatalf("Error while looking up container1: unexpected mntns %v", mntns) 253 } 254 mntns = cc.LookupMntnsByContainer("this-namespace", "my-pod", "container2") 255 if mntns != 55557 { 256 t.Fatalf("Error while looking up container2: unexpected mntns %v", mntns) 257 } 258 259 // Check content using LookupPIDByPod 260 pidByContainer := cc.LookupPIDByPod("this-namespace", "my-pod") 261 if !reflect.DeepEqual(pidByContainer, map[string]uint32{"container0": 100, "container2": 102}) { 262 t.Fatalf("Error while looking up PID by Pod: unexpected %v", pidByContainer) 263 } 264 pidByContainer = cc.LookupPIDByPod("this-namespace", "this-other-pod") 265 if !reflect.DeepEqual(pidByContainer, map[string]uint32{}) { 266 t.Fatalf("Error while looking up PID by Pod: unexpected %v", pidByContainer) 267 } 268 269 // Check content using LookupPIDByContainer 270 pid := cc.LookupPIDByContainer("this-namespace", "my-pod", "container0") 271 if pid != 100 { 272 t.Fatalf("Error while looking up container0: unexpected pid %v", pid) 273 } 274 pid = cc.LookupPIDByContainer("this-namespace", "my-pod", "container1") 275 if pid != 0 { 276 t.Fatalf("Error while looking up container1: unexpected pid %v", pid) 277 } 278 pid = cc.LookupPIDByContainer("this-namespace", "my-pod", "container2") 279 if pid != 102 { 280 t.Fatalf("Error while looking up container2: unexpected pid %v", pid) 281 } 282 283 // Check content using LookupOwnerReferenceByMntns 284 ownerRef := cc.LookupOwnerReferenceByMntns(55555) 285 if ownerRef == nil || ownerRef.UID != "abcde0" { 286 t.Fatalf("Error while looking up owner reference: unexpected %v", ownerRef) 287 } 288 289 ownerRef = cc.LookupOwnerReferenceByMntns(55557) 290 if ownerRef == nil || ownerRef.UID != "abcde2" { 291 t.Fatalf("Error while looking up owner reference: unexpected %v", ownerRef) 292 } 293 294 // Non-existent mntns 295 ownerRef = cc.LookupOwnerReferenceByMntns(55556) 296 if ownerRef != nil { 297 t.Fatalf("Error while looking up owner reference: unexpected %v", ownerRef) 298 } 299 300 // Check LookupContainerByMntns 301 containerByMntns0 := cc.LookupContainerByMntns(55555) 302 if containerByMntns0.K8s.ContainerName != "container0" { 303 t.Fatalf("Error in LookupContainerByMntns: expected %s, found %s", "container0", 304 containerByMntns0.K8s.ContainerName) 305 } 306 307 // Check LookupContainerByMntns 308 containerByMntns2 := cc.LookupContainerByMntns(55555 + 2) 309 if containerByMntns2.K8s.ContainerName != "container2" { 310 t.Fatalf("Error in LookupContainerByMntns: expected %s, found %s", "container2", 311 containerByMntns2.K8s.ContainerName) 312 } 313 314 containerByMntnsNotFound := cc.LookupContainerByMntns(989898) 315 if containerByMntnsNotFound != nil { 316 t.Fatalf("Error in LookupContainerByMntns: returned non nil") 317 } 318 319 // Add new container with same pod and container name of container0 but in different namespace 320 cc.AddContainer(&Container{ 321 Runtime: RuntimeMetadata{ 322 BasicRuntimeMetadata: types.BasicRuntimeMetadata{ 323 ContainerID: "abcde0-different", 324 }, 325 }, 326 K8s: K8sMetadata{ 327 BasicK8sMetadata: types.BasicK8sMetadata{ 328 Namespace: "another-namespace", 329 PodName: "my-pod", 330 ContainerName: "container0", 331 PodLabels: map[string]string{ 332 "key1": "value1", 333 "key2": "value2", 334 }, 335 }, 336 }, 337 }) 338 339 // Look up containers with label 'key1=value1' 340 selectedContainers := cc.GetContainersBySelector(&ContainerSelector{ 341 K8s: K8sSelector{ 342 BasicK8sMetadata: types.BasicK8sMetadata{ 343 PodLabels: map[string]string{ 344 "key1": "value1", 345 }, 346 }, 347 }, 348 }) 349 if len(selectedContainers) != 1 { 350 t.Fatalf("Error while looking up containers by one label: invalid number of matches") 351 } 352 if v, found := selectedContainers[0].K8s.PodLabels["key1"]; !found || v != "value1" { 353 t.Fatalf("Error while looking up containers by one label: unexpected container %+v", 354 selectedContainers[0]) 355 } 356 357 // Look up containers with label 'key1=value1' and 'key2=value2' 358 selector := ContainerSelector{ 359 K8s: K8sSelector{ 360 BasicK8sMetadata: types.BasicK8sMetadata{ 361 PodLabels: map[string]string{ 362 "key1": "value1", 363 "key2": "value2", 364 }, 365 }, 366 }, 367 } 368 selectedContainers = cc.GetContainersBySelector(&selector) 369 if len(selectedContainers) != 1 { 370 t.Fatalf("Error while looking up containers by multiple labels: invalid number of matches") 371 } 372 for sk, sv := range selector.K8s.PodLabels { 373 if v, found := selectedContainers[0].K8s.PodLabels[sk]; !found || v != sv { 374 t.Fatalf("Error while looking up containers by multiple labels: unexpected container %+v", 375 selectedContainers[0]) 376 } 377 } 378 379 // Look up containers in 'this-namespace' 380 selectedContainers = cc.GetContainersBySelector(&ContainerSelector{ 381 K8s: K8sSelector{ 382 BasicK8sMetadata: types.BasicK8sMetadata{ 383 Namespace: "this-namespace", 384 }, 385 }, 386 }) 387 if len(selectedContainers) != 2 { 388 t.Fatalf("Error while looking up containers by namespace: invalid number of matches") 389 } 390 for _, container := range selectedContainers { 391 if container.K8s.Namespace != "this-namespace" { 392 t.Fatalf("Error while looking up containers by namespace: unexpected container %+v", 393 container) 394 } 395 } 396 397 // Look up containers in 'this-namespace' and 'my-pod' 398 selectedContainers = cc.GetContainersBySelector(&ContainerSelector{ 399 K8s: K8sSelector{ 400 BasicK8sMetadata: types.BasicK8sMetadata{ 401 Namespace: "this-namespace", 402 PodName: "my-pod", 403 }, 404 }, 405 }) 406 if len(selectedContainers) != 2 { 407 t.Fatalf("Error while looking up containers by namespace and pod: invalid number of matches") 408 } 409 for _, container := range selectedContainers { 410 if container.K8s.Namespace != "this-namespace" || container.K8s.PodName != "my-pod" { 411 t.Fatalf("Error while looking up containers by namespace and pod: unexpected container %+v", 412 container) 413 } 414 } 415 416 // Look up containers named 'container0' anywhere 417 selectedContainers = cc.GetContainersBySelector(&ContainerSelector{ 418 K8s: K8sSelector{ 419 BasicK8sMetadata: types.BasicK8sMetadata{ 420 ContainerName: "container0", 421 }, 422 }, 423 }) 424 if len(selectedContainers) != 2 { 425 t.Fatalf("Error while looking up containers by name: invalid number of matches") 426 } 427 for _, container := range selectedContainers { 428 if container.K8s.ContainerName != "container0" { 429 t.Fatalf("Error while looking up containers by name: unexpected container %+v", 430 container) 431 } 432 } 433 434 // Look up containers named 'container0' in 'my-pod' but any namespace 435 selectedContainers = cc.GetContainersBySelector(&ContainerSelector{ 436 K8s: K8sSelector{ 437 BasicK8sMetadata: types.BasicK8sMetadata{ 438 PodName: "my-pod", 439 ContainerName: "container0", 440 }, 441 }, 442 }) 443 if len(selectedContainers) != 2 { 444 t.Fatalf("Error while looking up containers by name and pod: invalid number of matches") 445 } 446 for _, container := range selectedContainers { 447 if container.K8s.PodName != "my-pod" || container.K8s.ContainerName != "container0" { 448 t.Fatalf("Error while looking up containers by name and pod: unexpected container %+v", 449 container) 450 } 451 } 452 453 // Look up container0 in 'this-namespace' and 'my-pod' 454 selectedContainers = cc.GetContainersBySelector(&ContainerSelector{ 455 K8s: K8sSelector{ 456 BasicK8sMetadata: types.BasicK8sMetadata{ 457 Namespace: "this-namespace", 458 PodName: "my-pod", 459 ContainerName: "container0", 460 }, 461 }, 462 }) 463 if len(selectedContainers) != 1 { 464 t.Fatalf("Error while looking up specific container: invalid number of matches") 465 } 466 if selectedContainers[0].K8s.Namespace != "this-namespace" || selectedContainers[0].K8s.PodName != "my-pod" || selectedContainers[0].K8s.ContainerName != "container0" { 467 t.Fatalf("Error while looking up specific container: unexpected container %+v", 468 selectedContainers[0]) 469 } 470 471 // Look up container0 in 'another-namespace' and 'my-pod' 472 selectedContainers = cc.GetContainersBySelector(&ContainerSelector{ 473 K8s: K8sSelector{ 474 BasicK8sMetadata: types.BasicK8sMetadata{ 475 Namespace: "another-namespace", 476 PodName: "my-pod", 477 ContainerName: "container0", 478 }, 479 }, 480 }) 481 if len(selectedContainers) != 1 { 482 t.Fatalf("Error while looking up specific container: invalid number of matches") 483 } 484 if selectedContainers[0].K8s.Namespace != "another-namespace" || selectedContainers[0].K8s.PodName != "my-pod" || selectedContainers[0].K8s.ContainerName != "container0" { 485 t.Fatalf("Error while looking up specific container: unexpected container %+v", 486 selectedContainers[0]) 487 } 488 489 // Look up container2 in 'this-namespace' and 'my-pod' 490 selectedContainers = cc.GetContainersBySelector(&ContainerSelector{ 491 K8s: K8sSelector{ 492 BasicK8sMetadata: types.BasicK8sMetadata{ 493 Namespace: "this-namespace", 494 PodName: "my-pod", 495 ContainerName: "container2", 496 }, 497 }, 498 }) 499 if len(selectedContainers) != 1 { 500 t.Fatalf("Error while looking up specific container: invalid number of matches") 501 } 502 if selectedContainers[0].K8s.Namespace != "this-namespace" || selectedContainers[0].K8s.PodName != "my-pod" || selectedContainers[0].K8s.ContainerName != "container2" { 503 t.Fatalf("Error while looking up specific container: unexpected container %+v", 504 selectedContainers[0]) 505 } 506 507 // Look up a non-existent container 508 selectedContainers = cc.GetContainersBySelector(&ContainerSelector{ 509 K8s: K8sSelector{ 510 BasicK8sMetadata: types.BasicK8sMetadata{ 511 Namespace: "this-namespace", 512 PodName: "my-pod", 513 ContainerName: "non-existent", 514 }, 515 }, 516 }) 517 if len(selectedContainers) != 0 { 518 t.Fatalf("Error while looking up a non-existent container") 519 } 520 521 // Look up containers in a non-existent pod 522 selectedContainers = cc.GetContainersBySelector(&ContainerSelector{ 523 K8s: K8sSelector{ 524 BasicK8sMetadata: types.BasicK8sMetadata{ 525 Namespace: "this-namespace", 526 PodName: "non-existent", 527 }, 528 }, 529 }) 530 if len(selectedContainers) != 0 { 531 t.Fatalf("Error while looking up containers in a non-existent pod") 532 } 533 534 // Look up containers in a non-existent pod 535 selectedContainers = cc.GetContainersBySelector(&ContainerSelector{ 536 K8s: K8sSelector{ 537 BasicK8sMetadata: types.BasicK8sMetadata{ 538 Namespace: "this-namespace", 539 PodName: "non-existent", 540 ContainerName: "container0", 541 }, 542 }, 543 }) 544 if len(selectedContainers) != 0 { 545 t.Fatalf("Error while looking up containers in a non-existent namespace") 546 } 547 548 // Look up containers in a non-existent namespace 549 selectedContainers = cc.GetContainersBySelector(&ContainerSelector{ 550 K8s: K8sSelector{ 551 BasicK8sMetadata: types.BasicK8sMetadata{ 552 Namespace: "non-existent", 553 }, 554 }, 555 }) 556 if len(selectedContainers) != 0 { 557 t.Fatalf("Error while looking up containers in a non-existent namespace") 558 } 559 560 // Look up containers in a non-existent namespace 561 selectedContainers = cc.GetContainersBySelector(&ContainerSelector{ 562 K8s: K8sSelector{ 563 BasicK8sMetadata: types.BasicK8sMetadata{ 564 Namespace: "non-existent", 565 PodName: "my-pod", 566 ContainerName: "container0", 567 }, 568 }, 569 }) 570 if len(selectedContainers) != 0 { 571 t.Fatalf("Error while looking up containers in a non-existent namespace") 572 } 573 }