github.com/Mirantis/virtlet@v1.5.2-0.20191204181327-1659b8a48e9b/pkg/manager/runtime_test.go (about) 1 /* 2 Copyright 2016-2017 Mirantis 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 manager 18 19 import ( 20 "context" 21 "encoding/json" 22 "fmt" 23 "io/ioutil" 24 "log" 25 "net" 26 "os" 27 "path/filepath" 28 "reflect" 29 "strings" 30 "testing" 31 "time" 32 33 cnitypes "github.com/containernetworking/cni/pkg/types" 34 cnicurrent "github.com/containernetworking/cni/pkg/types/current" 35 "github.com/davecgh/go-spew/spew" 36 "github.com/jonboulle/clockwork" 37 kubeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" 38 39 "github.com/Mirantis/virtlet/pkg/cni" 40 "github.com/Mirantis/virtlet/pkg/flexvolume" 41 "github.com/Mirantis/virtlet/pkg/fs" 42 fakefs "github.com/Mirantis/virtlet/pkg/fs/fake" 43 "github.com/Mirantis/virtlet/pkg/image" 44 fakeimage "github.com/Mirantis/virtlet/pkg/image/fake" 45 "github.com/Mirantis/virtlet/pkg/libvirttools" 46 "github.com/Mirantis/virtlet/pkg/metadata" 47 "github.com/Mirantis/virtlet/pkg/network" 48 "github.com/Mirantis/virtlet/pkg/tapmanager" 49 "github.com/Mirantis/virtlet/pkg/utils" 50 fakeutils "github.com/Mirantis/virtlet/pkg/utils/fake" 51 testutils "github.com/Mirantis/virtlet/pkg/utils/testing" 52 fakevirt "github.com/Mirantis/virtlet/pkg/virt/fake" 53 "github.com/Mirantis/virtlet/tests/criapi" 54 "github.com/Mirantis/virtlet/tests/gm" 55 ) 56 57 const ( 58 podTimestap = 1524648266720331175 59 ) 60 61 type fakeFDManager struct { 62 rec testutils.Recorder 63 items map[string]bool 64 lastIpOctet byte 65 } 66 67 var _ tapmanager.FDManager = &fakeFDManager{} 68 69 func newFakeFDManager(rec testutils.Recorder) *fakeFDManager { 70 return &fakeFDManager{ 71 rec: rec, 72 items: make(map[string]bool), 73 lastIpOctet: 5, 74 } 75 } 76 77 func (m *fakeFDManager) AddFDs(key string, data interface{}) ([]byte, error) { 78 m.rec.Rec("AddFDs", map[string]interface{}{ 79 "key": key, 80 "data": data, 81 }) 82 83 if m.items[key] { 84 return nil, fmt.Errorf("duplicate key: %q", key) 85 } 86 87 if strings.Contains(key, "should-fail-cni") { 88 return nil, fmt.Errorf("simulated cni failure on request") 89 } 90 91 fdPayload := data.(*tapmanager.GetFDPayload) 92 if fdPayload.Description == nil { 93 return nil, fmt.Errorf("AddFDs(): bad data: %#v", data) 94 } 95 macAddr := "42:a4:a6:22:80:2e" 96 parsedMacAddr, err := net.ParseMAC(macAddr) 97 if err != nil { 98 log.Panicf("Error parsing hwaddr %q: %v", macAddr, err) 99 } 100 nsPath := cni.PodNetNSPath(fdPayload.Description.PodID) 101 csn := &network.ContainerSideNetwork{ 102 Result: &cnicurrent.Result{ 103 Interfaces: []*cnicurrent.Interface{ 104 { 105 Name: "eth0", 106 Mac: macAddr, 107 Sandbox: nsPath, 108 }, 109 }, 110 IPs: []*cnicurrent.IPConfig{ 111 { 112 Version: "4", 113 Interface: 0, 114 Address: net.IPNet{ 115 IP: net.IP{10, 1, 90, m.lastIpOctet}, 116 Mask: net.IPMask{255, 255, 255, 0}, 117 }, 118 Gateway: net.IP{10, 1, 90, 1}, 119 }, 120 }, 121 Routes: []*cnitypes.Route{ 122 { 123 Dst: net.IPNet{ 124 IP: net.IP{0, 0, 0, 0}, 125 Mask: net.IPMask{0, 0, 0, 0}, 126 }, 127 GW: net.IP{10, 1, 90, 1}, 128 }, 129 }, 130 }, 131 NsPath: nsPath, 132 Interfaces: []*network.InterfaceDescription{ 133 { 134 Type: network.InterfaceTypeTap, 135 HardwareAddr: parsedMacAddr, 136 }, 137 }, 138 } 139 140 respData, err := json.Marshal(csn) 141 if err != nil { 142 return nil, fmt.Errorf("error marshalling net config: %v", err) 143 } 144 145 m.lastIpOctet++ 146 m.items[key] = true 147 return respData, nil 148 } 149 150 func (m *fakeFDManager) ReleaseFDs(key string) error { 151 m.rec.Rec("ReleaseFDs", key) 152 if !m.items[key] { 153 return fmt.Errorf("key not found: %q", key) 154 } 155 return nil 156 } 157 158 func (m *fakeFDManager) Recover(key string, data interface{}) error { 159 m.rec.Rec("Recover", key) 160 if m.items[key] { 161 return fmt.Errorf("duplicate key: %q", key) 162 } 163 return nil 164 } 165 166 type fakeStreamServer struct { 167 rec testutils.Recorder 168 } 169 170 var _ StreamServer = &fakeStreamServer{} 171 172 func newFakeStreamServer(rec testutils.Recorder) *fakeStreamServer { 173 return &fakeStreamServer{rec} 174 } 175 176 func (s *fakeStreamServer) GetAttach(req *kubeapi.AttachRequest) (*kubeapi.AttachResponse, error) { 177 s.rec.Rec("GetAttach", req) 178 return &kubeapi.AttachResponse{ 179 Url: "http://localhost:4242/", 180 }, nil 181 } 182 183 func (s *fakeStreamServer) GetPortForward(req *kubeapi.PortForwardRequest) (*kubeapi.PortForwardResponse, error) { 184 s.rec.Rec("GetPortForward", req) 185 return &kubeapi.PortForwardResponse{ 186 Url: "http://localhost:4242/", 187 }, nil 188 } 189 190 func TestPodSanboxConfigValidation(t *testing.T) { 191 invalidSandboxes := criapi.GetSandboxes(1) 192 193 // Now let's make generated configs to be invalid 194 invalidSandboxes[0].Metadata = nil 195 196 if err := validatePodSandboxConfig(invalidSandboxes[0]); err == nil { 197 t.Errorf("Invalid pod sandbox passed validation:\n%s", spew.Sdump(invalidSandboxes[0])) 198 } 199 } 200 201 func translateImageName(ctx context.Context, name string) image.Endpoint { 202 return image.Endpoint{URL: name, MaxRedirects: -1} 203 } 204 205 type criHandler struct { 206 *VirtletRuntimeService 207 *VirtletImageService 208 } 209 210 type virtletCRITester struct { 211 t *testing.T 212 rec *testutils.TopLevelRecorder 213 handler *criHandler 214 tmpDir string 215 kubeletRootDir string 216 } 217 218 func makeVirtletCRITester(t *testing.T) *virtletCRITester { 219 rec := testutils.NewToplevelRecorder() 220 tmpDir, err := ioutil.TempDir("", "virtualization-test-") 221 if err != nil { 222 t.Fatalf("TempDir(): %v", err) 223 } 224 // __config__ is a hint for fake libvirt domain to fix the path 225 libvirttools.SetConfigIsoDir(filepath.Join(tmpDir, "__config__")) 226 fdManager := newFakeFDManager(rec.Child("fdManager")) 227 imageStore := fakeimage.NewFakeStore(rec.Child("imageStore")) 228 metadataStore, err := metadata.NewFakeStore() 229 if err != nil { 230 t.Fatalf("Failed to create fake bolt client: %v", err) 231 } 232 domainConn := fakevirt.NewFakeDomainConnection(rec.Child("domain conn")) 233 storageConn := fakevirt.NewFakeStorageConnection(rec.Child("storage")) 234 clock := clockwork.NewFakeClockAt(time.Unix(0, podTimestap)) 235 kubeletRootDir := filepath.Join(tmpDir, "kubelet-root") 236 virtConfig := libvirttools.VirtualizationConfig{ 237 VolumePoolName: "volumes", 238 RawDevices: []string{"loop*"}, 239 KubeletRootDir: kubeletRootDir, 240 StreamerSocketPath: streamerSocketPath, 241 } 242 commander := fakeutils.NewCommander(rec, nil) 243 virtTool := libvirttools.NewVirtualizationTool( 244 domainConn, storageConn, imageStore, metadataStore, 245 libvirttools.GetDefaultVolumeSource(), virtConfig, 246 fakefs.NewFakeFileSystem(t, rec, "", nil), commander) 247 virtTool.SetClock(clock) 248 streamServer := newFakeStreamServer(rec.Child("streamServer")) 249 criHandler := &criHandler{ 250 VirtletRuntimeService: NewVirtletRuntimeService(virtTool, metadataStore, fdManager, streamServer, imageStore, clock), 251 VirtletImageService: NewVirtletImageService(imageStore, translateImageName, clock), 252 } 253 return &virtletCRITester{ 254 t: t, 255 rec: rec, 256 handler: criHandler, 257 tmpDir: tmpDir, 258 kubeletRootDir: kubeletRootDir, 259 } 260 } 261 262 func (tst *virtletCRITester) teardown() { 263 os.RemoveAll(tst.tmpDir) 264 } 265 266 func (tst *virtletCRITester) invoke(name string, req interface{}, failOnError bool) (interface{}, error) { 267 tst.rec.Rec("enter: "+name, req) 268 v := reflect.ValueOf(tst.handler) 269 method := v.MethodByName(name) 270 if method.Kind() == reflect.Invalid { 271 tst.t.Fatalf("bad method %q", name) 272 } 273 ctx := context.Background() 274 vals := method.Call([]reflect.Value{ 275 reflect.ValueOf(ctx), 276 reflect.ValueOf(req), 277 }) 278 if len(vals) != 2 { 279 tst.t.Fatalf("expected method %q to return 2 values but it returned %#v", name, vals) 280 } 281 if !vals[1].IsNil() { 282 err, ok := vals[1].Interface().(error) 283 if !ok { 284 tst.t.Fatalf("2nd returned value is %#v instead of error", vals[1].Interface()) 285 } else { 286 if failOnError { 287 tst.t.Errorf("method %q returned error: %v", name, err) 288 } 289 } 290 return nil, err 291 } 292 resp := vals[0].Interface() 293 tst.rec.Rec("leave: "+name, resp) 294 return resp, nil 295 } 296 297 func (tst *virtletCRITester) getSampleFlexvolMounts(podSandboxID string) []*kubeapi.Mount { 298 flexVolumeDriver := flexvolume.NewDriver(func() string { 299 return "abb67e3c-71b3-4ddd-5505-8c4215d5c4eb" 300 }, fs.NullFileSystem) 301 flexVolDir := filepath.Join(tst.kubeletRootDir, podSandboxID, "volumes/virtlet~flexvolume_driver", "vol1") 302 flexVolDef := map[string]interface{}{ 303 "type": "qcow2", 304 "capacity": "2MB", 305 } 306 resultStr := flexVolumeDriver.Run([]string{"mount", flexVolDir, utils.ToJSON(flexVolDef)}) 307 var r map[string]interface{} 308 if err := json.Unmarshal([]byte(resultStr), &r); err != nil { 309 tst.t.Fatalf("failed to unmarshal flexvolume definition") 310 } 311 if r["status"] != "Success" { 312 tst.t.Fatalf("mounting flexvolume vol1 failed: %s", r["message"]) 313 } 314 return []*kubeapi.Mount{ 315 { 316 ContainerPath: "/mnt", 317 HostPath: flexVolDir, 318 }, 319 } 320 } 321 322 func (tst *virtletCRITester) verify() { 323 verifier := gm.NewYamlVerifier(tst.rec.Content()) 324 gm.Verify(tst.t, gm.NewSubstVerifier(verifier, []gm.Replacement{ 325 { 326 Old: tst.tmpDir, 327 New: "__top__", 328 }, 329 })) 330 } 331 332 func (tst *virtletCRITester) listImages(filter *kubeapi.ImageFilter) { 333 tst.invoke("ListImages", &kubeapi.ListImagesRequest{Filter: filter}, true) 334 } 335 336 func (tst *virtletCRITester) pullImage(image *kubeapi.ImageSpec) { 337 tst.invoke("PullImage", &kubeapi.PullImageRequest{Image: image}, true) 338 } 339 340 func (tst *virtletCRITester) imageStatus(image *kubeapi.ImageSpec) { 341 tst.invoke("ImageStatus", &kubeapi.ImageStatusRequest{Image: image}, true) 342 } 343 344 func (tst *virtletCRITester) removeImage(image *kubeapi.ImageSpec) { 345 tst.invoke("RemoveImage", &kubeapi.RemoveImageRequest{Image: image}, true) 346 } 347 348 func (tst *virtletCRITester) listPodSandbox(filter *kubeapi.PodSandboxFilter) { 349 tst.invoke("ListPodSandbox", &kubeapi.ListPodSandboxRequest{Filter: filter}, true) 350 } 351 352 func (tst *virtletCRITester) runPodSandbox(config *kubeapi.PodSandboxConfig) { 353 tst.invoke("RunPodSandbox", &kubeapi.RunPodSandboxRequest{Config: config}, true) 354 } 355 356 func (tst *virtletCRITester) runPodSandboxAndExpectError(config *kubeapi.PodSandboxConfig) { 357 _, err := tst.invoke("RunPodSandbox", &kubeapi.RunPodSandboxRequest{Config: config}, false) 358 if err == nil { 359 tst.t.Errorf("didn't get an expected error from RunPodSandbox") 360 } 361 } 362 363 func (tst *virtletCRITester) podSandboxStatus(podSandboxID string) { 364 tst.invoke("PodSandboxStatus", &kubeapi.PodSandboxStatusRequest{PodSandboxId: podSandboxID}, true) 365 } 366 367 func (tst *virtletCRITester) stopPodSandox(podSandboxID string) { 368 tst.invoke("StopPodSandbox", &kubeapi.StopPodSandboxRequest{PodSandboxId: podSandboxID}, true) 369 } 370 371 func (tst *virtletCRITester) removePodSandox(podSandboxID string) { 372 tst.invoke("RemovePodSandbox", &kubeapi.RemovePodSandboxRequest{PodSandboxId: podSandboxID}, true) 373 } 374 375 func (tst *virtletCRITester) listContainers(filter *kubeapi.ContainerFilter) { 376 tst.invoke("ListContainers", &kubeapi.ListContainersRequest{Filter: filter}, true) 377 } 378 379 func (tst *virtletCRITester) listContainerStats(filter *kubeapi.ContainerStatsFilter) { 380 tst.invoke("ListContainerStats", &kubeapi.ListContainerStatsRequest{Filter: filter}, true) 381 } 382 383 func (tst *virtletCRITester) createContainer(sandbox *kubeapi.PodSandboxConfig, container *criapi.ContainerTestConfig, imageSpec *kubeapi.ImageSpec, mounts []*kubeapi.Mount) string { 384 req := createContainerRequest(sandbox, container, imageSpec, mounts) 385 resp, err := tst.invoke("CreateContainer", req, true) 386 if err != nil { 387 tst.t.Fatalf("CreateContainer returned an error: %v", err) 388 return "" // unreachable 389 } 390 if r, ok := resp.(*kubeapi.CreateContainerResponse); ok { 391 return r.ContainerId 392 } 393 tst.t.Fatalf("bad value returned by CreateContainer: %#v", resp) 394 return "" // unreachable 395 } 396 397 func (tst *virtletCRITester) containerStatus(containerID string) { 398 tst.invoke("ContainerStatus", &kubeapi.ContainerStatusRequest{ContainerId: containerID}, true) 399 } 400 401 func (tst *virtletCRITester) startContainer(containerID string) { 402 tst.invoke("StartContainer", &kubeapi.StartContainerRequest{ContainerId: containerID}, true) 403 } 404 405 func (tst *virtletCRITester) stopContainer(containerID string) { 406 tst.invoke("StopContainer", &kubeapi.StopContainerRequest{ContainerId: containerID}, true) 407 } 408 409 func (tst *virtletCRITester) containerStats(containerID string) { 410 tst.invoke("ContainerStats", &kubeapi.ContainerStatsRequest{ContainerId: containerID}, true) 411 } 412 413 func (tst *virtletCRITester) updateContainerResources(containerID, cpuSet string) { 414 tst.invoke("UpdateContainerResources", &kubeapi.UpdateContainerResourcesRequest{ 415 ContainerId: containerID, 416 Linux: &kubeapi.LinuxContainerResources{CpusetCpus: cpuSet}, 417 }, true) 418 } 419 420 func (tst *virtletCRITester) removeContainer(containerID string) { 421 tst.invoke("RemoveContainer", &kubeapi.RemoveContainerRequest{ContainerId: containerID}, true) 422 } 423 424 func (tst *virtletCRITester) attach(req *kubeapi.AttachRequest) { 425 tst.invoke("Attach", req, true) 426 } 427 428 func (tst *virtletCRITester) portForward(req *kubeapi.PortForwardRequest) { 429 tst.invoke("PortForward", req, true) 430 } 431 432 func (tst *virtletCRITester) imageFsInfo(req *kubeapi.ImageFsInfoRequest) { 433 tst.invoke("ImageFsInfo", req, true) 434 } 435 436 func cirrosImg() *kubeapi.ImageSpec { 437 // return new object each time b/c in theory it can be 438 // modified by the handler 439 return &kubeapi.ImageSpec{Image: "localhost/cirros.img"} 440 } 441 442 func ubuntuImg() *kubeapi.ImageSpec { 443 // return new object each time b/c in theory it can be 444 // modified by the handler 445 return &kubeapi.ImageSpec{Image: "localhost/ubuntu.img"} 446 } 447 448 func createContainerRequest(sandbox *kubeapi.PodSandboxConfig, container *criapi.ContainerTestConfig, imageSpec *kubeapi.ImageSpec, mounts []*kubeapi.Mount) *kubeapi.CreateContainerRequest { 449 return &kubeapi.CreateContainerRequest{ 450 PodSandboxId: sandbox.Metadata.Uid, 451 Config: &kubeapi.ContainerConfig{ 452 Image: imageSpec, 453 Labels: container.Labels, 454 Mounts: mounts, 455 Metadata: &kubeapi.ContainerMetadata{ 456 Name: container.Name, 457 }, 458 }, 459 SandboxConfig: sandbox, 460 } 461 } 462 463 func TestCRIPods(t *testing.T) { 464 tst := makeVirtletCRITester(t) 465 defer tst.teardown() 466 tst.listPodSandbox(nil) 467 tst.listContainers(nil) 468 469 sandboxes := criapi.GetSandboxes(2) 470 containers := criapi.GetContainersConfig(sandboxes) 471 tst.pullImage(cirrosImg()) 472 tst.runPodSandbox(sandboxes[0]) 473 tst.listPodSandbox(nil) 474 tst.podSandboxStatus(sandboxes[0].Metadata.Uid) 475 containerId1 := tst.createContainer(sandboxes[0], containers[0], cirrosImg(), nil) 476 tst.listContainers(nil) 477 tst.containerStatus(containerId1) 478 tst.startContainer(containerId1) 479 tst.containerStatus(containerId1) 480 tst.containerStats(containerId1) 481 tst.listContainerStats(nil) 482 483 tst.pullImage(ubuntuImg()) 484 tst.runPodSandbox(sandboxes[1]) 485 containerId2 := tst.createContainer(sandboxes[1], containers[1], ubuntuImg(), nil) 486 tst.listPodSandbox(nil) 487 tst.listContainers(nil) 488 tst.containerStatus(containerId2) 489 tst.startContainer(containerId2) 490 tst.containerStatus(containerId2) 491 492 tst.stopContainer(containerId1) 493 tst.stopContainer(containerId2) 494 // this should not cause an error 495 tst.stopContainer(containerId2) 496 497 tst.listContainers(nil) 498 tst.containerStatus(containerId1) 499 500 tst.removeContainer(containerId1) 501 tst.removeContainer(containerId2) 502 // this should not cause an error 503 tst.removeContainer(containerId2) 504 505 tst.stopPodSandox(sandboxes[0].Metadata.Uid) 506 tst.stopPodSandox(sandboxes[1].Metadata.Uid) 507 // this should not cause an error 508 tst.stopPodSandox(sandboxes[1].Metadata.Uid) 509 510 tst.listPodSandbox(nil) 511 tst.podSandboxStatus(sandboxes[0].Metadata.Uid) 512 513 tst.removePodSandox(sandboxes[0].Metadata.Uid) 514 tst.removePodSandox(sandboxes[1].Metadata.Uid) 515 // this should not cause an error 516 tst.removePodSandox(sandboxes[1].Metadata.Uid) 517 518 tst.listPodSandbox(nil) 519 tst.listContainers(nil) 520 521 tst.verify() 522 } 523 524 func TestRunPodSandboxWithFailingCNI(t *testing.T) { 525 tst := makeVirtletCRITester(t) 526 defer tst.teardown() 527 528 sandboxes := criapi.GetSandboxes(1) 529 sandboxes[0].Metadata.Uid = "should-fail-cni" 530 tst.runPodSandboxAndExpectError(sandboxes[0]) 531 tst.verify() 532 } 533 534 func TestCRIMounts(t *testing.T) { 535 tst := makeVirtletCRITester(t) 536 defer tst.teardown() 537 538 sandboxes := criapi.GetSandboxes(1) 539 containers := criapi.GetContainersConfig(sandboxes) 540 541 tst.pullImage(cirrosImg()) 542 tst.runPodSandbox(sandboxes[0]) 543 tst.podSandboxStatus(sandboxes[0].Metadata.Uid) 544 545 mounts := tst.getSampleFlexvolMounts(sandboxes[0].Metadata.Uid) 546 containerId1 := tst.createContainer(sandboxes[0], containers[0], cirrosImg(), mounts) 547 tst.containerStatus(containerId1) 548 tst.startContainer(containerId1) 549 tst.stopContainer(containerId1) 550 tst.removeContainer(containerId1) 551 tst.stopPodSandox(sandboxes[0].Metadata.Uid) 552 tst.removePodSandox(sandboxes[0].Metadata.Uid) 553 tst.verify() 554 } 555 556 func TestCRIPodFilters(t *testing.T) { 557 tst := makeVirtletCRITester(t) 558 tst.rec.AddFilter("ListPodSandbox") 559 defer tst.teardown() 560 561 sandboxes := criapi.GetSandboxes(2) 562 sandboxes[1].Labels["foo"] = "bar2" 563 tst.runPodSandbox(sandboxes[0]) 564 tst.runPodSandbox(sandboxes[1]) 565 566 tst.listPodSandbox(nil) 567 tst.listPodSandbox(&kubeapi.PodSandboxFilter{Id: sandboxes[0].Metadata.Uid}) 568 tst.listPodSandbox(&kubeapi.PodSandboxFilter{ 569 State: &kubeapi.PodSandboxStateValue{ 570 State: kubeapi.PodSandboxState_SANDBOX_READY, 571 }, 572 }) 573 tst.listPodSandbox(&kubeapi.PodSandboxFilter{ 574 State: &kubeapi.PodSandboxStateValue{ 575 State: kubeapi.PodSandboxState_SANDBOX_NOTREADY, 576 }, 577 }) 578 tst.listPodSandbox(&kubeapi.PodSandboxFilter{ 579 LabelSelector: map[string]string{ 580 "foo": "bar2", 581 }, 582 }) 583 584 tst.stopPodSandox(sandboxes[1].Metadata.Uid) 585 tst.listPodSandbox(&kubeapi.PodSandboxFilter{ 586 State: &kubeapi.PodSandboxStateValue{ 587 State: kubeapi.PodSandboxState_SANDBOX_READY, 588 }, 589 }) 590 tst.listPodSandbox(&kubeapi.PodSandboxFilter{ 591 State: &kubeapi.PodSandboxStateValue{ 592 State: kubeapi.PodSandboxState_SANDBOX_NOTREADY, 593 }, 594 }) 595 596 tst.verify() 597 } 598 599 func TestCRIContainerFilters(t *testing.T) { 600 tst := makeVirtletCRITester(t) 601 tst.rec.AddFilter("ListContainers") 602 defer tst.teardown() 603 604 sandboxes := criapi.GetSandboxes(2) 605 containers := criapi.GetContainersConfig(sandboxes) 606 tst.pullImage(cirrosImg()) 607 tst.runPodSandbox(sandboxes[0]) 608 containerId1 := tst.createContainer(sandboxes[0], containers[0], cirrosImg(), nil) 609 tst.startContainer(containerId1) 610 tst.pullImage(ubuntuImg()) 611 tst.runPodSandbox(sandboxes[1]) 612 containerId2 := tst.createContainer(sandboxes[1], containers[1], ubuntuImg(), nil) 613 tst.startContainer(containerId2) 614 615 tst.listContainers(nil) 616 tst.listContainers(&kubeapi.ContainerFilter{Id: containerId1}) 617 tst.listContainers(&kubeapi.ContainerFilter{ 618 State: &kubeapi.ContainerStateValue{ 619 State: kubeapi.ContainerState_CONTAINER_RUNNING, 620 }, 621 }) 622 tst.listContainers(&kubeapi.ContainerFilter{ 623 State: &kubeapi.ContainerStateValue{ 624 State: kubeapi.ContainerState_CONTAINER_EXITED, 625 }, 626 }) 627 tst.listContainers(&kubeapi.ContainerFilter{ 628 LabelSelector: map[string]string{ 629 "io.kubernetes.pod.name": "testName_1", 630 }, 631 }) 632 tst.listContainers(&kubeapi.ContainerFilter{ 633 PodSandboxId: sandboxes[0].Metadata.Uid, 634 }) 635 636 tst.stopContainer(containerId1) 637 tst.listContainers(&kubeapi.ContainerFilter{ 638 State: &kubeapi.ContainerStateValue{ 639 State: kubeapi.ContainerState_CONTAINER_RUNNING, 640 }, 641 }) 642 tst.listContainers(&kubeapi.ContainerFilter{ 643 State: &kubeapi.ContainerStateValue{ 644 State: kubeapi.ContainerState_CONTAINER_EXITED, 645 }, 646 }) 647 648 tst.verify() 649 } 650 651 func TestContainerListStats(t *testing.T) { 652 tst := makeVirtletCRITester(t) 653 tst.rec.AddFilter("ListContainers") 654 tst.rec.AddFilter("ListContainerStats") 655 defer tst.teardown() 656 657 sandboxes := criapi.GetSandboxes(2) 658 containers := criapi.GetContainersConfig(sandboxes) 659 tst.pullImage(cirrosImg()) 660 tst.runPodSandbox(sandboxes[0]) 661 containerId1 := tst.createContainer(sandboxes[0], containers[0], cirrosImg(), nil) 662 tst.startContainer(containerId1) 663 tst.pullImage(ubuntuImg()) 664 tst.runPodSandbox(sandboxes[1]) 665 containerId2 := tst.createContainer(sandboxes[1], containers[1], ubuntuImg(), nil) 666 tst.startContainer(containerId2) 667 668 tst.listContainerStats(nil) 669 tst.listContainerStats(&kubeapi.ContainerStatsFilter{Id: containerId1}) 670 tst.listContainerStats(&kubeapi.ContainerStatsFilter{ 671 LabelSelector: map[string]string{ 672 "io.kubernetes.pod.name": "testName_1", 673 }, 674 }) 675 tst.listContainerStats(&kubeapi.ContainerStatsFilter{ 676 PodSandboxId: sandboxes[0].Metadata.Uid, 677 }) 678 679 tst.verify() 680 } 681 682 func TestCRIAttachPortForward(t *testing.T) { 683 tst := makeVirtletCRITester(t) 684 tst.rec.AddFilter("Attach") 685 tst.rec.AddFilter("PortForward") 686 defer tst.teardown() 687 688 sandboxes := criapi.GetSandboxes(1) 689 containers := criapi.GetContainersConfig(sandboxes) 690 691 tst.pullImage(cirrosImg()) 692 tst.runPodSandbox(sandboxes[0]) 693 tst.podSandboxStatus(sandboxes[0].Metadata.Uid) 694 695 containerId1 := tst.createContainer(sandboxes[0], containers[0], cirrosImg(), nil) 696 tst.containerStatus(containerId1) 697 tst.startContainer(containerId1) 698 699 tst.attach(&kubeapi.AttachRequest{ 700 ContainerId: containerId1, 701 Stdin: true, 702 Stdout: true, 703 Stderr: true, 704 }) 705 tst.attach(&kubeapi.AttachRequest{ 706 ContainerId: containerId1, 707 Stdin: true, 708 }) 709 tst.portForward(&kubeapi.PortForwardRequest{ 710 PodSandboxId: sandboxes[0].Metadata.Uid, 711 Port: []int32{42000}, 712 }) 713 714 tst.verify() 715 } 716 717 func TestUpdateResources(t *testing.T) { 718 tst := makeVirtletCRITester(t) 719 tst.rec.AddFilter("UpdateContainerResources") 720 tst.rec.AddFilter("DefineDomain") 721 tst.rec.AddFilter("Undefine") 722 defer tst.teardown() 723 724 sandboxes := criapi.GetSandboxes(1) 725 containers := criapi.GetContainersConfig(sandboxes) 726 727 tst.pullImage(cirrosImg()) 728 tst.runPodSandbox(sandboxes[0]) 729 tst.podSandboxStatus(sandboxes[0].Metadata.Uid) 730 731 containerId1 := tst.createContainer(sandboxes[0], containers[0], cirrosImg(), nil) 732 733 tst.updateContainerResources(containerId1, "42") 734 735 tst.verify() 736 } 737 738 // TODO: make sure non-default Linux namespace settings cause pod startup to fail.