github.com/kata-containers/runtime@v0.0.0-20210505125100-04f29832a923/virtcontainers/sandbox_test.go (about) 1 // Copyright (c) 2016 Intel Corporation 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 // 5 6 package virtcontainers 7 8 import ( 9 "context" 10 "fmt" 11 "io/ioutil" 12 "os" 13 "os/exec" 14 "path" 15 "path/filepath" 16 "strings" 17 "sync" 18 "syscall" 19 "testing" 20 21 ktu "github.com/kata-containers/runtime/pkg/katatestutils" 22 "github.com/kata-containers/runtime/virtcontainers/device/config" 23 "github.com/kata-containers/runtime/virtcontainers/device/drivers" 24 "github.com/kata-containers/runtime/virtcontainers/device/manager" 25 exp "github.com/kata-containers/runtime/virtcontainers/experimental" 26 "github.com/kata-containers/runtime/virtcontainers/persist/fs" 27 "github.com/kata-containers/runtime/virtcontainers/pkg/annotations" 28 "github.com/kata-containers/runtime/virtcontainers/store" 29 "github.com/kata-containers/runtime/virtcontainers/types" 30 specs "github.com/opencontainers/runtime-spec/specs-go" 31 "github.com/stretchr/testify/assert" 32 "golang.org/x/sys/unix" 33 ) 34 35 // dirMode is the permission bits used for creating a directory 36 const dirMode = os.FileMode(0750) | os.ModeDir 37 38 func newHypervisorConfig(kernelParams []Param, hParams []Param) HypervisorConfig { 39 return HypervisorConfig{ 40 KernelPath: filepath.Join(testDir, testKernel), 41 ImagePath: filepath.Join(testDir, testImage), 42 HypervisorPath: filepath.Join(testDir, testHypervisor), 43 KernelParams: kernelParams, 44 HypervisorParams: hParams, 45 } 46 47 } 48 49 func testCreateSandbox(t *testing.T, id string, 50 htype HypervisorType, hconfig HypervisorConfig, atype AgentType, 51 nconfig NetworkConfig, containers []ContainerConfig, 52 volumes []types.Volume) (*Sandbox, error) { 53 54 sconfig := SandboxConfig{ 55 ID: id, 56 HypervisorType: htype, 57 HypervisorConfig: hconfig, 58 AgentType: atype, 59 NetworkConfig: nconfig, 60 Volumes: volumes, 61 Containers: containers, 62 Annotations: sandboxAnnotations, 63 } 64 65 sandbox, err := createSandbox(context.Background(), sconfig, nil) 66 if err != nil { 67 return nil, fmt.Errorf("Could not create sandbox: %s", err) 68 } 69 70 if err := sandbox.agent.startSandbox(sandbox); err != nil { 71 return nil, err 72 } 73 74 if err := sandbox.createContainers(); err != nil { 75 return nil, err 76 } 77 78 if sandbox.id == "" { 79 return sandbox, fmt.Errorf("Invalid empty sandbox ID") 80 } 81 82 if id != "" && sandbox.id != id { 83 return sandbox, fmt.Errorf("Invalid ID %s vs %s", id, sandbox.id) 84 } 85 86 return sandbox, nil 87 } 88 89 func TestCreateEmptySandbox(t *testing.T) { 90 _, err := testCreateSandbox(t, testSandboxID, MockHypervisor, HypervisorConfig{}, NoopAgentType, NetworkConfig{}, nil, nil) 91 assert.Error(t, err) 92 defer cleanUp() 93 } 94 95 func TestCreateEmptyHypervisorSandbox(t *testing.T) { 96 _, err := testCreateSandbox(t, testSandboxID, QemuHypervisor, HypervisorConfig{}, NoopAgentType, NetworkConfig{}, nil, nil) 97 assert.Error(t, err) 98 defer cleanUp() 99 } 100 101 func TestCreateMockSandbox(t *testing.T) { 102 hConfig := newHypervisorConfig(nil, nil) 103 _, err := testCreateSandbox(t, testSandboxID, MockHypervisor, hConfig, NoopAgentType, NetworkConfig{}, nil, nil) 104 assert.NoError(t, err) 105 defer cleanUp() 106 } 107 108 func TestCalculateSandboxCPUs(t *testing.T) { 109 sandbox := &Sandbox{} 110 sandbox.config = &SandboxConfig{} 111 112 unconstrained := newTestContainerConfigNoop("cont-00001") 113 constrained := newTestContainerConfigNoop("cont-00002") 114 unconstrainedCpusets0_1 := newTestContainerConfigNoop("cont-00003") 115 unconstrainedCpusets2 := newTestContainerConfigNoop("cont-00004") 116 constrainedCpusets0_7 := newTestContainerConfigNoop("cont-00005") 117 quota := int64(4000) 118 period := uint64(1000) 119 constrained.Resources.CPU = &specs.LinuxCPU{Period: &period, Quota: "a} 120 unconstrainedCpusets0_1.Resources.CPU = &specs.LinuxCPU{Cpus: "0-1"} 121 unconstrainedCpusets2.Resources.CPU = &specs.LinuxCPU{Cpus: "2"} 122 constrainedCpusets0_7.Resources.CPU = &specs.LinuxCPU{Period: &period, Quota: "a, Cpus: "0-7"} 123 tests := []struct { 124 name string 125 containers []ContainerConfig 126 want uint32 127 }{ 128 {"1-unconstrained", []ContainerConfig{unconstrained}, 0}, 129 {"2-unconstrained", []ContainerConfig{unconstrained, unconstrained}, 0}, 130 {"1-constrained", []ContainerConfig{constrained}, 4}, 131 {"2-constrained", []ContainerConfig{constrained, constrained}, 8}, 132 {"3-mix-constraints", []ContainerConfig{unconstrained, constrained, constrained}, 8}, 133 {"3-constrained", []ContainerConfig{constrained, constrained, constrained}, 12}, 134 {"unconstrained-1-cpuset", []ContainerConfig{unconstrained, unconstrained, unconstrainedCpusets0_1}, 2}, 135 {"unconstrained-2-cpuset", []ContainerConfig{unconstrainedCpusets0_1, unconstrainedCpusets2}, 3}, 136 {"constrained-cpuset", []ContainerConfig{constrainedCpusets0_7}, 4}, 137 } 138 for _, tt := range tests { 139 t.Run(tt.name, func(t *testing.T) { 140 sandbox.config.Containers = tt.containers 141 got, _ := sandbox.calculateSandboxCPUs() 142 assert.Equal(t, got, tt.want) 143 }) 144 } 145 } 146 147 func TestCalculateSandboxMem(t *testing.T) { 148 sandbox := &Sandbox{} 149 sandbox.config = &SandboxConfig{} 150 unconstrained := newTestContainerConfigNoop("cont-00001") 151 constrained := newTestContainerConfigNoop("cont-00001") 152 mlimit := int64(4000) 153 limit := uint64(4000) 154 constrained.Resources.Memory = &specs.LinuxMemory{Limit: &mlimit} 155 156 tests := []struct { 157 name string 158 containers []ContainerConfig 159 want uint64 160 }{ 161 {"1-unconstrained", []ContainerConfig{unconstrained}, 0}, 162 {"2-unconstrained", []ContainerConfig{unconstrained, unconstrained}, 0}, 163 {"1-constrained", []ContainerConfig{constrained}, limit}, 164 {"2-constrained", []ContainerConfig{constrained, constrained}, limit * 2}, 165 {"3-mix-constraints", []ContainerConfig{unconstrained, constrained, constrained}, limit * 2}, 166 {"3-constrained", []ContainerConfig{constrained, constrained, constrained}, limit * 3}, 167 } 168 for _, tt := range tests { 169 t.Run(tt.name, func(t *testing.T) { 170 sandbox.config.Containers = tt.containers 171 got := sandbox.calculateSandboxMemory() 172 assert.Equal(t, got, tt.want) 173 }) 174 } 175 } 176 177 func TestSandboxHugepageLimit(t *testing.T) { 178 contConfig1 := newTestContainerConfigNoop("cont-00001") 179 contConfig2 := newTestContainerConfigNoop("cont-00002") 180 limit := int64(4000) 181 contConfig1.Resources.Memory = &specs.LinuxMemory{Limit: &limit} 182 contConfig2.Resources.Memory = &specs.LinuxMemory{Limit: &limit} 183 hConfig := newHypervisorConfig(nil, nil) 184 185 defer cleanUp() 186 // create a sandbox 187 s, err := testCreateSandbox(t, 188 testSandboxID, 189 MockHypervisor, 190 hConfig, 191 NoopAgentType, 192 NetworkConfig{}, 193 []ContainerConfig{contConfig1, contConfig2}, 194 nil) 195 196 assert.NoError(t, err) 197 198 hugepageLimits := []specs.LinuxHugepageLimit{ 199 { 200 Pagesize: "1GB", 201 Limit: 322122547, 202 }, 203 { 204 Pagesize: "2MB", 205 Limit: 134217728, 206 }, 207 } 208 209 for i := range s.config.Containers { 210 s.config.Containers[i].Resources.HugepageLimits = hugepageLimits 211 } 212 err = s.updateResources() 213 assert.NoError(t, err) 214 } 215 216 func TestCreateSandboxEmptyID(t *testing.T) { 217 hConfig := newHypervisorConfig(nil, nil) 218 _, err := testCreateSandbox(t, "", MockHypervisor, hConfig, NoopAgentType, NetworkConfig{}, nil, nil) 219 assert.Error(t, err) 220 defer cleanUp() 221 } 222 223 func TestSandboxListSuccessful(t *testing.T) { 224 sandbox := &Sandbox{} 225 226 sandboxList, err := sandbox.list() 227 assert.NoError(t, err) 228 assert.Nil(t, sandboxList) 229 } 230 231 func TestSandboxEnterSuccessful(t *testing.T) { 232 sandbox := &Sandbox{} 233 234 err := sandbox.enter([]string{}) 235 assert.NoError(t, err) 236 } 237 238 func testCheckInitSandboxAndContainerStates(p *Sandbox, initialSandboxState types.SandboxState, c *Container, initialContainerState types.ContainerState) error { 239 if p.state.State != initialSandboxState.State { 240 return fmt.Errorf("Expected sandbox state %v, got %v", initialSandboxState.State, p.state.State) 241 } 242 243 if c.state.State != initialContainerState.State { 244 return fmt.Errorf("Expected container state %v, got %v", initialContainerState.State, c.state.State) 245 } 246 247 return nil 248 } 249 250 func testForceSandboxStateChangeAndCheck(t *testing.T, p *Sandbox, newSandboxState types.SandboxState) error { 251 // force sandbox state change 252 err := p.setSandboxState(newSandboxState.State) 253 assert.NoError(t, err) 254 // check the in-memory state is correct 255 if p.state.State != newSandboxState.State { 256 return fmt.Errorf("Expected state %v, got %v", newSandboxState.State, p.state.State) 257 } 258 259 return nil 260 } 261 262 func testForceContainerStateChangeAndCheck(t *testing.T, p *Sandbox, c *Container, newContainerState types.ContainerState) error { 263 // force container state change 264 err := c.setContainerState(newContainerState.State) 265 assert.NoError(t, err) 266 267 // check the in-memory state is correct 268 if c.state.State != newContainerState.State { 269 return fmt.Errorf("Expected state %v, got %v", newContainerState.State, c.state.State) 270 } 271 272 return nil 273 } 274 275 func testCheckSandboxOnDiskState(p *Sandbox, sandboxState types.SandboxState) error { 276 // check on-disk state is correct 277 if p.state.State != sandboxState.State { 278 return fmt.Errorf("Expected state %v, got %v", sandboxState.State, p.state.State) 279 } 280 281 return nil 282 } 283 284 func testCheckContainerOnDiskState(c *Container, containerState types.ContainerState) error { 285 // check on-disk state is correct 286 if c.state.State != containerState.State { 287 return fmt.Errorf("Expected state %v, got %v", containerState.State, c.state.State) 288 } 289 290 return nil 291 } 292 293 func TestSandboxSetSandboxAndContainerState(t *testing.T) { 294 contID := "505" 295 contConfig := newTestContainerConfigNoop(contID) 296 hConfig := newHypervisorConfig(nil, nil) 297 assert := assert.New(t) 298 299 // create a sandbox 300 p, err := testCreateSandbox(t, testSandboxID, MockHypervisor, hConfig, NoopAgentType, NetworkConfig{}, []ContainerConfig{contConfig}, nil) 301 assert.NoError(err) 302 defer cleanUp() 303 304 l := len(p.GetAllContainers()) 305 assert.Equal(l, 1) 306 307 initialSandboxState := types.SandboxState{ 308 State: types.StateReady, 309 } 310 311 // After a sandbox creation, a container has a READY state 312 initialContainerState := types.ContainerState{ 313 State: types.StateReady, 314 } 315 316 c, err := p.findContainer(contID) 317 assert.NoError(err) 318 319 // check initial sandbox and container states 320 if err := testCheckInitSandboxAndContainerStates(p, initialSandboxState, c, initialContainerState); err != nil { 321 t.Error(err) 322 } 323 324 // persist to disk 325 err = p.storeSandbox() 326 assert.NoError(err) 327 328 newSandboxState := types.SandboxState{ 329 State: types.StateRunning, 330 } 331 332 if err := testForceSandboxStateChangeAndCheck(t, p, newSandboxState); err != nil { 333 t.Error(err) 334 } 335 336 newContainerState := types.ContainerState{ 337 State: types.StateStopped, 338 } 339 340 if err := testForceContainerStateChangeAndCheck(t, p, c, newContainerState); err != nil { 341 t.Error(err) 342 } 343 344 // force state to be read from disk 345 p2, err := fetchSandbox(context.Background(), p.ID()) 346 assert.NoError(err) 347 348 if err := testCheckSandboxOnDiskState(p2, newSandboxState); err != nil { 349 t.Error(err) 350 } 351 352 c2, err := p2.findContainer(contID) 353 assert.NoError(err) 354 355 if err := testCheckContainerOnDiskState(c2, newContainerState); err != nil { 356 t.Error(err) 357 } 358 359 // revert sandbox state to allow it to be deleted 360 err = p.setSandboxState(initialSandboxState.State) 361 assert.NoError(err) 362 363 // clean up 364 err = p.Delete() 365 assert.NoError(err) 366 } 367 368 func TestGetContainer(t *testing.T) { 369 containerIDs := []string{"abc", "123", "xyz", "rgb"} 370 containers := map[string]*Container{} 371 372 for _, id := range containerIDs { 373 c := Container{id: id} 374 containers[id] = &c 375 } 376 377 sandbox := Sandbox{ 378 containers: containers, 379 } 380 381 c := sandbox.GetContainer("noid") 382 assert.Nil(t, c) 383 384 for _, id := range containerIDs { 385 c = sandbox.GetContainer(id) 386 assert.NotNil(t, c) 387 } 388 } 389 390 func TestGetAllContainers(t *testing.T) { 391 containerIDs := []string{"abc", "123", "xyz", "rgb"} 392 containers := map[string]*Container{} 393 394 for _, id := range containerIDs { 395 c := &Container{id: id} 396 containers[id] = c 397 } 398 399 sandbox := Sandbox{ 400 containers: containers, 401 } 402 403 list := sandbox.GetAllContainers() 404 405 for _, c := range list { 406 assert.NotNil(t, containers[c.ID()], nil) 407 } 408 } 409 410 func TestSetAnnotations(t *testing.T) { 411 assert := assert.New(t) 412 sandbox := Sandbox{ 413 ctx: context.Background(), 414 id: "abcxyz123", 415 annotationsLock: &sync.RWMutex{}, 416 config: &SandboxConfig{ 417 Annotations: map[string]string{ 418 "annotation1": "abc", 419 }, 420 }, 421 } 422 423 keyAnnotation := "annotation2" 424 valueAnnotation := "xyz" 425 newAnnotations := map[string]string{ 426 keyAnnotation: valueAnnotation, 427 } 428 429 // Add a new annotation 430 sandbox.SetAnnotations(newAnnotations) 431 432 v, err := sandbox.Annotations(keyAnnotation) 433 assert.NoError(err) 434 assert.Equal(v, valueAnnotation) 435 436 //Change the value of an annotation 437 valueAnnotation = "123" 438 newAnnotations[keyAnnotation] = valueAnnotation 439 440 sandbox.SetAnnotations(newAnnotations) 441 442 v, err = sandbox.Annotations(keyAnnotation) 443 assert.NoError(err) 444 assert.Equal(v, valueAnnotation) 445 } 446 447 func TestSandboxGetContainer(t *testing.T) { 448 assert := assert.New(t) 449 450 emptySandbox := Sandbox{} 451 _, err := emptySandbox.findContainer("") 452 assert.Error(err) 453 454 _, err = emptySandbox.findContainer("foo") 455 assert.Error(err) 456 457 hConfig := newHypervisorConfig(nil, nil) 458 p, err := testCreateSandbox(t, testSandboxID, MockHypervisor, hConfig, NoopAgentType, NetworkConfig{}, nil, nil) 459 assert.NoError(err) 460 defer cleanUp() 461 462 contID := "999" 463 contConfig := newTestContainerConfigNoop(contID) 464 nc, err := newContainer(p, &contConfig) 465 assert.NoError(err) 466 467 err = p.addContainer(nc) 468 assert.NoError(err) 469 470 got := false 471 for _, c := range p.GetAllContainers() { 472 c2, err := p.findContainer(c.ID()) 473 assert.NoError(err) 474 assert.Equal(c2.ID(), c.ID()) 475 476 if c2.ID() == contID { 477 got = true 478 } 479 } 480 481 assert.True(got) 482 } 483 484 func TestContainerStateSetFstype(t *testing.T) { 485 var err error 486 assert := assert.New(t) 487 488 containers := []ContainerConfig{ 489 { 490 ID: "100", 491 Annotations: containerAnnotations, 492 CustomSpec: newEmptySpec(), 493 }, 494 } 495 496 hConfig := newHypervisorConfig(nil, nil) 497 sandbox, err := testCreateSandbox(t, testSandboxID, MockHypervisor, hConfig, NoopAgentType, NetworkConfig{}, containers, nil) 498 assert.Nil(err) 499 defer cleanUp() 500 501 c := sandbox.GetContainer("100") 502 assert.NotNil(c) 503 504 cImpl, ok := c.(*Container) 505 assert.True(ok) 506 507 state := types.ContainerState{ 508 State: "ready", 509 Fstype: "vfs", 510 } 511 512 cImpl.state = state 513 514 newFstype := "ext4" 515 err = cImpl.setStateFstype(newFstype) 516 assert.NoError(err) 517 assert.Equal(cImpl.state.Fstype, newFstype) 518 } 519 520 func TestSandboxAttachDevicesVFIO(t *testing.T) { 521 tmpDir, err := ioutil.TempDir("", "") 522 assert.Nil(t, err) 523 os.RemoveAll(tmpDir) 524 525 testFDIOGroup := "2" 526 testDeviceBDFPath := "0000:00:1c.0" 527 528 devicesDir := filepath.Join(tmpDir, testFDIOGroup, "devices") 529 err = os.MkdirAll(devicesDir, DirMode) 530 assert.Nil(t, err) 531 532 deviceFile := filepath.Join(devicesDir, testDeviceBDFPath) 533 _, err = os.Create(deviceFile) 534 assert.Nil(t, err) 535 536 savedIOMMUPath := config.SysIOMMUPath 537 config.SysIOMMUPath = tmpDir 538 539 defer func() { 540 config.SysIOMMUPath = savedIOMMUPath 541 }() 542 543 dm := manager.NewDeviceManager(manager.VirtioSCSI, false, "", nil) 544 path := filepath.Join(vfioPath, testFDIOGroup) 545 deviceInfo := config.DeviceInfo{ 546 HostPath: path, 547 ContainerPath: path, 548 DevType: "c", 549 } 550 dev, err := dm.NewDevice(deviceInfo) 551 assert.Nil(t, err, "deviceManager.NewDevice return error: %v", err) 552 553 c := &Container{ 554 id: "100", 555 devices: []ContainerDevice{ 556 { 557 ID: dev.DeviceID(), 558 ContainerPath: path, 559 }, 560 }, 561 } 562 563 containers := map[string]*Container{} 564 containers[c.id] = c 565 566 sandbox := Sandbox{ 567 id: "100", 568 containers: containers, 569 hypervisor: &mockHypervisor{}, 570 devManager: dm, 571 ctx: context.Background(), 572 config: &SandboxConfig{}, 573 } 574 575 containers[c.id].sandbox = &sandbox 576 577 err = containers[c.id].attachDevices(c.devices) 578 assert.Nil(t, err, "Error while attaching devices %s", err) 579 580 err = containers[c.id].detachDevices() 581 assert.Nil(t, err, "Error while detaching devices %s", err) 582 } 583 584 func TestSandboxAttachDevicesVhostUserBlk(t *testing.T) { 585 rootEnabled := true 586 tc := ktu.NewTestConstraint(false) 587 if tc.NotValid(ktu.NeedRoot()) { 588 rootEnabled = false 589 } 590 591 tmpDir, err := ioutil.TempDir("", "") 592 assert.Nil(t, err) 593 os.RemoveAll(tmpDir) 594 dm := manager.NewDeviceManager(manager.VirtioSCSI, true, tmpDir, nil) 595 596 vhostUserDevNodePath := filepath.Join(tmpDir, "/block/devices/") 597 vhostUserSockPath := filepath.Join(tmpDir, "/block/sockets/") 598 deviceNodePath := filepath.Join(vhostUserDevNodePath, "vhostblk0") 599 deviceSockPath := filepath.Join(vhostUserSockPath, "vhostblk0") 600 601 err = os.MkdirAll(vhostUserDevNodePath, dirMode) 602 assert.Nil(t, err) 603 err = os.MkdirAll(vhostUserSockPath, dirMode) 604 assert.Nil(t, err) 605 _, err = os.Create(deviceSockPath) 606 assert.Nil(t, err) 607 608 // mknod requires root privilege, call mock function for non-root to 609 // get VhostUserBlk device type. 610 if rootEnabled == true { 611 err = unix.Mknod(deviceNodePath, unix.S_IFBLK, int(unix.Mkdev(config.VhostUserBlkMajor, 0))) 612 assert.Nil(t, err) 613 } else { 614 savedFunc := config.GetVhostUserNodeStatFunc 615 616 _, err = os.Create(deviceNodePath) 617 assert.Nil(t, err) 618 619 config.GetVhostUserNodeStatFunc = func(devNodePath string, 620 devNodeStat *unix.Stat_t) error { 621 if deviceNodePath != devNodePath { 622 return fmt.Errorf("mock GetVhostUserNodeStatFunc error") 623 } 624 625 devNodeStat.Rdev = unix.Mkdev(config.VhostUserBlkMajor, 0) 626 return nil 627 } 628 629 defer func() { 630 config.GetVhostUserNodeStatFunc = savedFunc 631 }() 632 } 633 634 path := "/dev/vda" 635 deviceInfo := config.DeviceInfo{ 636 HostPath: deviceNodePath, 637 ContainerPath: path, 638 DevType: "b", 639 Major: config.VhostUserBlkMajor, 640 Minor: 0, 641 } 642 643 device, err := dm.NewDevice(deviceInfo) 644 assert.Nil(t, err) 645 _, ok := device.(*drivers.VhostUserBlkDevice) 646 assert.True(t, ok) 647 648 c := &Container{ 649 id: "100", 650 devices: []ContainerDevice{ 651 { 652 ID: device.DeviceID(), 653 ContainerPath: path, 654 }, 655 }, 656 } 657 658 containers := map[string]*Container{} 659 containers[c.id] = c 660 661 sandbox := Sandbox{ 662 id: "100", 663 containers: containers, 664 hypervisor: &mockHypervisor{}, 665 devManager: dm, 666 ctx: context.Background(), 667 config: &SandboxConfig{}, 668 } 669 670 containers[c.id].sandbox = &sandbox 671 672 err = containers[c.id].attachDevices(c.devices) 673 assert.Nil(t, err, "Error while attaching vhost-user-blk devices %s", err) 674 675 err = containers[c.id].detachDevices() 676 assert.Nil(t, err, "Error while detaching vhost-user-blk devices %s", err) 677 } 678 679 var assetContent = []byte("FakeAsset fake asset FAKE ASSET") 680 var assetContentHash = "92549f8d2018a95a294d28a65e795ed7d1a9d150009a28cea108ae10101178676f04ab82a6950d0099e4924f9c5e41dcba8ece56b75fc8b4e0a7492cb2a8c880" 681 var assetContentWrongHash = "92549f8d2018a95a294d28a65e795ed7d1a9d150009a28cea108ae10101178676f04ab82a6950d0099e4924f9c5e41dcba8ece56b75fc8b4e0a7492cb2a8c881" 682 683 func TestSandboxCreateAssets(t *testing.T) { 684 assert := assert.New(t) 685 686 type testData struct { 687 assetType types.AssetType 688 annotations map[string]string 689 } 690 691 tmpfile, err := ioutil.TempFile("", "virtcontainers-test-") 692 assert.Nil(err) 693 694 filename := tmpfile.Name() 695 696 defer func() { 697 tmpfile.Close() 698 os.Remove(filename) // clean up 699 }() 700 701 _, err = tmpfile.Write(assetContent) 702 assert.Nil(err) 703 704 originalKernelPath := filepath.Join(testDir, testKernel) 705 originalImagePath := filepath.Join(testDir, testImage) 706 originalInitrdPath := filepath.Join(testDir, testInitrd) 707 originalFirmwarePath := filepath.Join(testDir, testFirmware) 708 originalHypervisorPath := filepath.Join(testDir, testHypervisor) 709 originalHypervisorCtlPath := filepath.Join(testDir, testHypervisorCtl) 710 originalJailerPath := filepath.Join(testDir, testJailer) 711 712 hc := HypervisorConfig{ 713 KernelPath: originalKernelPath, 714 ImagePath: originalImagePath, 715 InitrdPath: originalInitrdPath, 716 FirmwarePath: originalFirmwarePath, 717 HypervisorPath: originalHypervisorPath, 718 HypervisorCtlPath: originalHypervisorCtlPath, 719 JailerPath: originalJailerPath, 720 } 721 722 data := []testData{ 723 { 724 types.FirmwareAsset, 725 map[string]string{ 726 annotations.FirmwarePath: filename, 727 annotations.FirmwareHash: assetContentHash, 728 }, 729 }, 730 { 731 types.HypervisorAsset, 732 map[string]string{ 733 annotations.HypervisorPath: filename, 734 annotations.HypervisorHash: assetContentHash, 735 }, 736 }, 737 { 738 types.HypervisorCtlAsset, 739 map[string]string{ 740 annotations.HypervisorCtlPath: filename, 741 annotations.HypervisorCtlHash: assetContentHash, 742 }, 743 }, 744 { 745 types.ImageAsset, 746 map[string]string{ 747 annotations.ImagePath: filename, 748 annotations.ImageHash: assetContentHash, 749 }, 750 }, 751 { 752 types.InitrdAsset, 753 map[string]string{ 754 annotations.InitrdPath: filename, 755 annotations.InitrdHash: assetContentHash, 756 }, 757 }, 758 { 759 types.JailerAsset, 760 map[string]string{ 761 annotations.JailerPath: filename, 762 annotations.JailerHash: assetContentHash, 763 }, 764 }, 765 { 766 types.KernelAsset, 767 map[string]string{ 768 annotations.KernelPath: filename, 769 annotations.KernelHash: assetContentHash, 770 }, 771 }, 772 } 773 774 for i, d := range data { 775 msg := fmt.Sprintf("test[%d]: %+v", i, d) 776 777 config := &SandboxConfig{ 778 Annotations: d.annotations, 779 HypervisorConfig: hc, 780 } 781 782 err = createAssets(context.Background(), config) 783 assert.NoError(err, msg) 784 785 a, ok := config.HypervisorConfig.customAssets[d.assetType] 786 assert.True(ok, msg) 787 assert.Equal(a.Path(), filename, msg) 788 789 // Now test with invalid hashes 790 badHashAnnotations := make(map[string]string) 791 for k, v := range d.annotations { 792 if strings.HasSuffix(k, "_hash") { 793 badHashAnnotations[k] = assetContentWrongHash 794 } else { 795 badHashAnnotations[k] = v 796 } 797 } 798 799 config = &SandboxConfig{ 800 Annotations: badHashAnnotations, 801 HypervisorConfig: hc, 802 } 803 804 err = createAssets(context.Background(), config) 805 assert.Error(err, msg) 806 } 807 } 808 809 func testFindContainerFailure(t *testing.T, sandbox *Sandbox, cid string) { 810 c, err := sandbox.findContainer(cid) 811 assert.Nil(t, c, "Container pointer should be nil") 812 assert.NotNil(t, err, "Should have returned an error") 813 } 814 815 func TestFindContainerSandboxNilFailure(t *testing.T) { 816 testFindContainerFailure(t, nil, testContainerID) 817 } 818 819 func TestFindContainerContainerIDEmptyFailure(t *testing.T) { 820 sandbox := &Sandbox{} 821 testFindContainerFailure(t, sandbox, "") 822 } 823 824 func TestFindContainerNoContainerMatchFailure(t *testing.T) { 825 sandbox := &Sandbox{} 826 testFindContainerFailure(t, sandbox, testContainerID) 827 } 828 829 func TestFindContainerSuccess(t *testing.T) { 830 sandbox := &Sandbox{ 831 containers: map[string]*Container{ 832 testContainerID: {id: testContainerID}, 833 }, 834 } 835 c, err := sandbox.findContainer(testContainerID) 836 assert.NotNil(t, c, "Container pointer should not be nil") 837 assert.Nil(t, err, "Should not have returned an error: %v", err) 838 839 assert.True(t, c == sandbox.containers[testContainerID], "Container pointers should point to the same address") 840 } 841 842 func TestRemoveContainerSandboxNilFailure(t *testing.T) { 843 testFindContainerFailure(t, nil, testContainerID) 844 } 845 846 func TestRemoveContainerContainerIDEmptyFailure(t *testing.T) { 847 sandbox := &Sandbox{} 848 testFindContainerFailure(t, sandbox, "") 849 } 850 851 func TestRemoveContainerNoContainerMatchFailure(t *testing.T) { 852 sandbox := &Sandbox{} 853 testFindContainerFailure(t, sandbox, testContainerID) 854 } 855 856 func TestRemoveContainerSuccess(t *testing.T) { 857 sandbox := &Sandbox{ 858 containers: map[string]*Container{ 859 testContainerID: {id: testContainerID}, 860 }, 861 } 862 err := sandbox.removeContainer(testContainerID) 863 assert.Nil(t, err, "Should not have returned an error: %v", err) 864 865 assert.Equal(t, len(sandbox.containers), 0, "Containers list from sandbox structure should be empty") 866 } 867 868 func TestCreateContainer(t *testing.T) { 869 s, err := testCreateSandbox(t, testSandboxID, MockHypervisor, newHypervisorConfig(nil, nil), NoopAgentType, NetworkConfig{}, nil, nil) 870 assert.Nil(t, err, "VirtContainers should not allow empty sandboxes") 871 defer cleanUp() 872 873 contID := "999" 874 contConfig := newTestContainerConfigNoop(contID) 875 _, err = s.CreateContainer(contConfig) 876 assert.Nil(t, err, "Failed to create container %+v in sandbox %+v: %v", contConfig, s, err) 877 878 assert.Equal(t, len(s.config.Containers), 1, "Container config list length from sandbox structure should be 1") 879 880 _, err = s.CreateContainer(contConfig) 881 assert.NotNil(t, err, "Should failed to create a duplicated container") 882 assert.Equal(t, len(s.config.Containers), 1, "Container config list length from sandbox structure should be 1") 883 } 884 885 func TestDeleteContainer(t *testing.T) { 886 s, err := testCreateSandbox(t, testSandboxID, MockHypervisor, newHypervisorConfig(nil, nil), NoopAgentType, NetworkConfig{}, nil, nil) 887 assert.Nil(t, err, "VirtContainers should not allow empty sandboxes") 888 defer cleanUp() 889 890 contID := "999" 891 _, err = s.DeleteContainer(contID) 892 assert.NotNil(t, err, "Deletng non-existing container should fail") 893 894 contConfig := newTestContainerConfigNoop(contID) 895 _, err = s.CreateContainer(contConfig) 896 assert.Nil(t, err, "Failed to create container %+v in sandbox %+v: %v", contConfig, s, err) 897 898 _, err = s.DeleteContainer(contID) 899 assert.Nil(t, err, "Failed to delete container %s in sandbox %s: %v", contID, s.ID(), err) 900 } 901 902 func TestStartContainer(t *testing.T) { 903 s, err := testCreateSandbox(t, testSandboxID, MockHypervisor, newHypervisorConfig(nil, nil), NoopAgentType, NetworkConfig{}, nil, nil) 904 assert.Nil(t, err, "VirtContainers should not allow empty sandboxes") 905 defer cleanUp() 906 907 contID := "999" 908 _, err = s.StartContainer(contID) 909 assert.NotNil(t, err, "Starting non-existing container should fail") 910 911 err = s.Start() 912 assert.Nil(t, err, "Failed to start sandbox: %v", err) 913 914 contConfig := newTestContainerConfigNoop(contID) 915 _, err = s.CreateContainer(contConfig) 916 assert.Nil(t, err, "Failed to create container %+v in sandbox %+v: %v", contConfig, s, err) 917 918 _, err = s.StartContainer(contID) 919 assert.Nil(t, err, "Start container failed: %v", err) 920 } 921 922 func TestStatusContainer(t *testing.T) { 923 s, err := testCreateSandbox(t, testSandboxID, MockHypervisor, newHypervisorConfig(nil, nil), NoopAgentType, NetworkConfig{}, nil, nil) 924 assert.Nil(t, err, "VirtContainers should not allow empty sandboxes") 925 defer cleanUp() 926 927 contID := "999" 928 _, err = s.StatusContainer(contID) 929 assert.NotNil(t, err, "Status non-existing container should fail") 930 931 contConfig := newTestContainerConfigNoop(contID) 932 _, err = s.CreateContainer(contConfig) 933 assert.Nil(t, err, "Failed to create container %+v in sandbox %+v: %v", contConfig, s, err) 934 935 _, err = s.StatusContainer(contID) 936 assert.Nil(t, err, "Status container failed: %v", err) 937 938 _, err = s.DeleteContainer(contID) 939 assert.Nil(t, err, "Failed to delete container %s in sandbox %s: %v", contID, s.ID(), err) 940 } 941 942 func TestStatusSandbox(t *testing.T) { 943 s, err := testCreateSandbox(t, testSandboxID, MockHypervisor, newHypervisorConfig(nil, nil), NoopAgentType, NetworkConfig{}, nil, nil) 944 assert.Nil(t, err, "VirtContainers should not allow empty sandboxes") 945 defer cleanUp() 946 947 s.Status() 948 } 949 950 func TestEnterContainer(t *testing.T) { 951 s, err := testCreateSandbox(t, testSandboxID, MockHypervisor, newHypervisorConfig(nil, nil), NoopAgentType, NetworkConfig{}, nil, nil) 952 assert.Nil(t, err, "VirtContainers should not allow empty sandboxes") 953 defer cleanUp() 954 955 contID := "999" 956 cmd := types.Cmd{} 957 _, _, err = s.EnterContainer(contID, cmd) 958 assert.NotNil(t, err, "Entering non-existing container should fail") 959 960 contConfig := newTestContainerConfigNoop(contID) 961 _, err = s.CreateContainer(contConfig) 962 assert.Nil(t, err, "Failed to create container %+v in sandbox %+v: %v", contConfig, s, err) 963 964 _, _, err = s.EnterContainer(contID, cmd) 965 assert.NotNil(t, err, "Entering non-running container should fail") 966 967 err = s.Start() 968 assert.Nil(t, err, "Failed to start sandbox: %v", err) 969 970 _, _, err = s.EnterContainer(contID, cmd) 971 assert.Nil(t, err, "Enter container failed: %v", err) 972 } 973 974 func TestDeleteStoreWhenCreateContainerFail(t *testing.T) { 975 hypervisorConfig := newHypervisorConfig(nil, nil) 976 s, err := testCreateSandbox(t, testSandboxID, MockHypervisor, hypervisorConfig, NoopAgentType, NetworkConfig{}, nil, nil) 977 if err != nil { 978 t.Fatal(err) 979 } 980 defer cleanUp() 981 982 contID := "999" 983 contConfig := newTestContainerConfigNoop(contID) 984 contConfig.RootFs = RootFs{Target: "", Mounted: true} 985 s.state.CgroupPath = filepath.Join(testDir, "bad-cgroup") 986 _, err = s.CreateContainer(contConfig) 987 assert.NotNil(t, err, "Should fail to create container due to wrong cgroup") 988 } 989 990 func TestDeleteStoreWhenNewContainerFail(t *testing.T) { 991 hConfig := newHypervisorConfig(nil, nil) 992 p, err := testCreateSandbox(t, testSandboxID, MockHypervisor, hConfig, NoopAgentType, NetworkConfig{}, nil, nil) 993 if err != nil { 994 t.Fatal(err) 995 } 996 defer cleanUp() 997 998 contID := "999" 999 contConfig := newTestContainerConfigNoop(contID) 1000 contConfig.DeviceInfos = []config.DeviceInfo{ 1001 { 1002 ContainerPath: "", 1003 DevType: "", 1004 }, 1005 } 1006 _, err = newContainer(p, &contConfig) 1007 assert.NotNil(t, err, "New container with invalid device info should fail") 1008 storePath := filepath.Join(p.newStore.RunStoragePath(), testSandboxID, contID) 1009 _, err = os.Stat(storePath) 1010 assert.NotNil(t, err, "Should delete configuration root after failed to create a container") 1011 } 1012 1013 func TestMonitor(t *testing.T) { 1014 s, err := testCreateSandbox(t, testSandboxID, MockHypervisor, newHypervisorConfig(nil, nil), NoopAgentType, NetworkConfig{}, nil, nil) 1015 assert.Nil(t, err, "VirtContainers should not allow empty sandboxes") 1016 defer cleanUp() 1017 1018 _, err = s.Monitor() 1019 assert.NotNil(t, err, "Monitoring non-running container should fail") 1020 1021 err = s.Start() 1022 assert.Nil(t, err, "Failed to start sandbox: %v", err) 1023 1024 _, err = s.Monitor() 1025 assert.Nil(t, err, "Monitor sandbox failed: %v", err) 1026 1027 _, err = s.Monitor() 1028 assert.Nil(t, err, "Monitor sandbox again failed: %v", err) 1029 1030 s.monitor.stop() 1031 } 1032 1033 func TestWaitProcess(t *testing.T) { 1034 s, err := testCreateSandbox(t, testSandboxID, MockHypervisor, newHypervisorConfig(nil, nil), NoopAgentType, NetworkConfig{}, nil, nil) 1035 assert.Nil(t, err, "VirtContainers should not allow empty sandboxes") 1036 defer cleanUp() 1037 1038 contID := "foo" 1039 execID := "bar" 1040 _, err = s.WaitProcess(contID, execID) 1041 assert.NotNil(t, err, "Wait process in stopped sandbox should fail") 1042 1043 err = s.Start() 1044 assert.Nil(t, err, "Failed to start sandbox: %v", err) 1045 1046 _, err = s.WaitProcess(contID, execID) 1047 assert.NotNil(t, err, "Wait process in non-existing container should fail") 1048 1049 contConfig := newTestContainerConfigNoop(contID) 1050 _, err = s.CreateContainer(contConfig) 1051 assert.Nil(t, err, "Failed to create container %+v in sandbox %+v: %v", contConfig, s, err) 1052 1053 _, err = s.WaitProcess(contID, execID) 1054 assert.Nil(t, err, "Wait process in ready container failed: %v", err) 1055 1056 _, err = s.StartContainer(contID) 1057 assert.Nil(t, err, "Start container failed: %v", err) 1058 1059 _, err = s.WaitProcess(contID, execID) 1060 assert.Nil(t, err, "Wait process failed: %v", err) 1061 } 1062 1063 func TestSignalProcess(t *testing.T) { 1064 s, err := testCreateSandbox(t, testSandboxID, MockHypervisor, newHypervisorConfig(nil, nil), NoopAgentType, NetworkConfig{}, nil, nil) 1065 assert.Nil(t, err, "VirtContainers should not allow empty sandboxes") 1066 defer cleanUp() 1067 1068 contID := "foo" 1069 execID := "bar" 1070 err = s.SignalProcess(contID, execID, syscall.SIGKILL, true) 1071 assert.NotNil(t, err, "Wait process in stopped sandbox should fail") 1072 1073 err = s.Start() 1074 assert.Nil(t, err, "Failed to start sandbox: %v", err) 1075 1076 err = s.SignalProcess(contID, execID, syscall.SIGKILL, false) 1077 assert.NotNil(t, err, "Wait process in non-existing container should fail") 1078 1079 contConfig := newTestContainerConfigNoop(contID) 1080 _, err = s.CreateContainer(contConfig) 1081 assert.Nil(t, err, "Failed to create container %+v in sandbox %+v: %v", contConfig, s, err) 1082 1083 err = s.SignalProcess(contID, execID, syscall.SIGKILL, true) 1084 assert.Nil(t, err, "Wait process in ready container failed: %v", err) 1085 1086 _, err = s.StartContainer(contID) 1087 assert.Nil(t, err, "Start container failed: %v", err) 1088 1089 err = s.SignalProcess(contID, execID, syscall.SIGKILL, false) 1090 assert.Nil(t, err, "Wait process failed: %v", err) 1091 } 1092 1093 func TestWinsizeProcess(t *testing.T) { 1094 s, err := testCreateSandbox(t, testSandboxID, MockHypervisor, newHypervisorConfig(nil, nil), NoopAgentType, NetworkConfig{}, nil, nil) 1095 assert.Nil(t, err, "VirtContainers should not allow empty sandboxes") 1096 defer cleanUp() 1097 1098 contID := "foo" 1099 execID := "bar" 1100 err = s.WinsizeProcess(contID, execID, 100, 200) 1101 assert.NotNil(t, err, "Winsize process in stopped sandbox should fail") 1102 1103 err = s.Start() 1104 assert.Nil(t, err, "Failed to start sandbox: %v", err) 1105 1106 err = s.WinsizeProcess(contID, execID, 100, 200) 1107 assert.NotNil(t, err, "Winsize process in non-existing container should fail") 1108 1109 contConfig := newTestContainerConfigNoop(contID) 1110 _, err = s.CreateContainer(contConfig) 1111 assert.Nil(t, err, "Failed to create container %+v in sandbox %+v: %v", contConfig, s, err) 1112 1113 err = s.WinsizeProcess(contID, execID, 100, 200) 1114 assert.Nil(t, err, "Winsize process in ready container failed: %v", err) 1115 1116 _, err = s.StartContainer(contID) 1117 assert.Nil(t, err, "Start container failed: %v", err) 1118 1119 err = s.WinsizeProcess(contID, execID, 100, 200) 1120 assert.Nil(t, err, "Winsize process failed: %v", err) 1121 } 1122 1123 func TestContainerProcessIOStream(t *testing.T) { 1124 s, err := testCreateSandbox(t, testSandboxID, MockHypervisor, newHypervisorConfig(nil, nil), NoopAgentType, NetworkConfig{}, nil, nil) 1125 assert.Nil(t, err, "VirtContainers should not allow empty sandboxes") 1126 defer cleanUp() 1127 1128 contID := "foo" 1129 execID := "bar" 1130 _, _, _, err = s.IOStream(contID, execID) 1131 assert.NotNil(t, err, "Winsize process in stopped sandbox should fail") 1132 1133 err = s.Start() 1134 assert.Nil(t, err, "Failed to start sandbox: %v", err) 1135 1136 _, _, _, err = s.IOStream(contID, execID) 1137 assert.NotNil(t, err, "Winsize process in non-existing container should fail") 1138 1139 contConfig := newTestContainerConfigNoop(contID) 1140 _, err = s.CreateContainer(contConfig) 1141 assert.Nil(t, err, "Failed to create container %+v in sandbox %+v: %v", contConfig, s, err) 1142 1143 _, _, _, err = s.IOStream(contID, execID) 1144 assert.Nil(t, err, "Winsize process in ready container failed: %v", err) 1145 1146 _, err = s.StartContainer(contID) 1147 assert.Nil(t, err, "Start container failed: %v", err) 1148 1149 _, _, _, err = s.IOStream(contID, execID) 1150 assert.Nil(t, err, "Winsize process failed: %v", err) 1151 } 1152 1153 func TestAttachBlockDevice(t *testing.T) { 1154 hypervisor := &mockHypervisor{} 1155 1156 hConfig := HypervisorConfig{ 1157 BlockDeviceDriver: config.VirtioBlock, 1158 } 1159 1160 sconfig := &SandboxConfig{ 1161 HypervisorConfig: hConfig, 1162 } 1163 1164 sandbox := &Sandbox{ 1165 id: testSandboxID, 1166 hypervisor: hypervisor, 1167 config: sconfig, 1168 ctx: context.Background(), 1169 state: types.SandboxState{BlockIndexMap: make(map[int]struct{})}, 1170 } 1171 1172 contID := "100" 1173 container := Container{ 1174 sandbox: sandbox, 1175 id: contID, 1176 } 1177 1178 // create state file 1179 path := filepath.Join(fs.MockRunStoragePath(), testSandboxID, container.ID()) 1180 err := os.MkdirAll(path, DirMode) 1181 assert.NoError(t, err) 1182 1183 defer os.RemoveAll(path) 1184 1185 path = "/dev/hda" 1186 deviceInfo := config.DeviceInfo{ 1187 HostPath: path, 1188 ContainerPath: path, 1189 DevType: "b", 1190 } 1191 1192 dm := manager.NewDeviceManager(config.VirtioBlock, false, "", nil) 1193 device, err := dm.NewDevice(deviceInfo) 1194 assert.Nil(t, err) 1195 _, ok := device.(*drivers.BlockDevice) 1196 assert.True(t, ok) 1197 1198 container.state.State = "" 1199 index, err := sandbox.getAndSetSandboxBlockIndex() 1200 assert.Nil(t, err) 1201 assert.Equal(t, index, 0) 1202 1203 err = device.Attach(sandbox) 1204 assert.Nil(t, err) 1205 index, err = sandbox.getAndSetSandboxBlockIndex() 1206 assert.Nil(t, err) 1207 assert.Equal(t, index, 2) 1208 1209 err = device.Detach(sandbox) 1210 assert.Nil(t, err) 1211 index, err = sandbox.getAndSetSandboxBlockIndex() 1212 assert.Nil(t, err) 1213 assert.Equal(t, index, 1) 1214 1215 container.state.State = types.StateReady 1216 err = device.Attach(sandbox) 1217 assert.Nil(t, err) 1218 1219 err = device.Detach(sandbox) 1220 assert.Nil(t, err) 1221 1222 container.sandbox.config.HypervisorConfig.BlockDeviceDriver = config.VirtioSCSI 1223 err = device.Attach(sandbox) 1224 assert.Nil(t, err) 1225 1226 err = device.Detach(sandbox) 1227 assert.Nil(t, err) 1228 1229 container.state.State = types.StateReady 1230 err = device.Attach(sandbox) 1231 assert.Nil(t, err) 1232 1233 err = device.Detach(sandbox) 1234 assert.Nil(t, err) 1235 } 1236 1237 func TestPreAddDevice(t *testing.T) { 1238 hypervisor := &mockHypervisor{} 1239 1240 hConfig := HypervisorConfig{ 1241 BlockDeviceDriver: config.VirtioBlock, 1242 } 1243 1244 sconfig := &SandboxConfig{ 1245 HypervisorConfig: hConfig, 1246 } 1247 1248 dm := manager.NewDeviceManager(config.VirtioBlock, false, "", nil) 1249 // create a sandbox first 1250 sandbox := &Sandbox{ 1251 id: testSandboxID, 1252 hypervisor: hypervisor, 1253 config: sconfig, 1254 devManager: dm, 1255 ctx: context.Background(), 1256 state: types.SandboxState{BlockIndexMap: make(map[int]struct{})}, 1257 } 1258 1259 contID := "100" 1260 container := Container{ 1261 sandbox: sandbox, 1262 id: contID, 1263 sandboxID: testSandboxID, 1264 } 1265 container.state.State = types.StateReady 1266 1267 // create state file 1268 path := filepath.Join(fs.MockRunStoragePath(), testSandboxID, container.ID()) 1269 err := os.MkdirAll(path, DirMode) 1270 assert.NoError(t, err) 1271 1272 defer os.RemoveAll(path) 1273 1274 path = "/dev/hda" 1275 deviceInfo := config.DeviceInfo{ 1276 HostPath: path, 1277 ContainerPath: path, 1278 DevType: "b", 1279 } 1280 1281 // Add a mount device for a mountpoint before container's creation 1282 dev, err := sandbox.AddDevice(deviceInfo) 1283 assert.Nil(t, err) 1284 1285 // in Frakti use case, here we will create and start the container 1286 // which will attach same device twice 1287 container.mounts = []Mount{ 1288 { 1289 Destination: path, 1290 Source: path, 1291 Type: "bind", 1292 BlockDeviceID: dev.DeviceID(), 1293 }, 1294 } 1295 1296 mounts, ignoreMounts, err := container.mountSharedDirMounts("", "", "") 1297 assert.Nil(t, err) 1298 assert.Equal(t, len(mounts), 0, 1299 "mounts should contain nothing because it only contains a block device") 1300 assert.Equal(t, len(ignoreMounts), 0, 1301 "ignoreMounts should contain nothing because it only contains a block device") 1302 } 1303 1304 func TestGetNetNs(t *testing.T) { 1305 s := Sandbox{} 1306 1307 expected := "" 1308 netNs := s.GetNetNs() 1309 assert.Equal(t, netNs, expected) 1310 1311 expected = "/foo/bar/ns/net" 1312 s.networkNS = NetworkNamespace{ 1313 NetNsPath: expected, 1314 } 1315 1316 netNs = s.GetNetNs() 1317 assert.Equal(t, netNs, expected) 1318 } 1319 1320 func TestStartNetworkMonitor(t *testing.T) { 1321 if os.Getuid() != 0 { 1322 t.Skip("Test disabled as requires root user") 1323 } 1324 trueBinPath, err := exec.LookPath("true") 1325 assert.Nil(t, err) 1326 assert.NotEmpty(t, trueBinPath) 1327 1328 s := &Sandbox{ 1329 id: testSandboxID, 1330 config: &SandboxConfig{ 1331 NetworkConfig: NetworkConfig{ 1332 NetmonConfig: NetmonConfig{ 1333 Path: trueBinPath, 1334 }, 1335 }, 1336 }, 1337 networkNS: NetworkNamespace{ 1338 NetNsPath: fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), unix.Gettid()), 1339 }, 1340 ctx: context.Background(), 1341 } 1342 1343 err = s.startNetworkMonitor() 1344 assert.Nil(t, err) 1345 } 1346 1347 func TestSandboxStopStopped(t *testing.T) { 1348 s := &Sandbox{ 1349 ctx: context.Background(), 1350 state: types.SandboxState{State: types.StateStopped}, 1351 } 1352 err := s.Stop(false) 1353 1354 assert.Nil(t, err) 1355 } 1356 1357 func checkDirNotExist(path string) error { 1358 if _, err := os.Stat(path); os.IsExist(err) { 1359 return fmt.Errorf("%s is still exists", path) 1360 } 1361 return nil 1362 } 1363 1364 func checkSandboxRemains() error { 1365 var err error 1366 if err = checkDirNotExist(sandboxDirState); err != nil { 1367 return fmt.Errorf("%s still exists", sandboxDirState) 1368 } 1369 if err = checkDirNotExist(path.Join(kataHostSharedDir(), testSandboxID)); err != nil { 1370 return fmt.Errorf("%s still exists", path.Join(kataHostSharedDir(), testSandboxID)) 1371 } 1372 if _, err = globalSandboxList.lookupSandbox(testSandboxID); err == nil { 1373 return fmt.Errorf("globalSandboxList for %s stil exists", testSandboxID) 1374 } 1375 1376 return nil 1377 } 1378 1379 func TestSandboxCreationFromConfigRollbackFromCreateSandbox(t *testing.T) { 1380 defer cleanUp() 1381 assert := assert.New(t) 1382 ctx := context.Background() 1383 hConf := newHypervisorConfig(nil, nil) 1384 sConf := SandboxConfig{ 1385 ID: testSandboxID, 1386 HypervisorType: QemuHypervisor, 1387 HypervisorConfig: hConf, 1388 AgentType: KataContainersAgent, 1389 NetworkConfig: NetworkConfig{}, 1390 Volumes: nil, 1391 Containers: nil, 1392 } 1393 1394 // Ensure hypervisor doesn't exist 1395 assert.NoError(os.Remove(hConf.HypervisorPath)) 1396 1397 _, err := createSandboxFromConfig(ctx, sConf, nil) 1398 // Fail at createSandbox: QEMU path does not exist, it is expected. Then rollback is called 1399 assert.Error(err) 1400 1401 // check dirs 1402 err = checkSandboxRemains() 1403 assert.NoError(err) 1404 } 1405 1406 func TestSandboxUpdateResources(t *testing.T) { 1407 contConfig1 := newTestContainerConfigNoop("cont-00001") 1408 contConfig2 := newTestContainerConfigNoop("cont-00002") 1409 hConfig := newHypervisorConfig(nil, nil) 1410 1411 defer cleanUp() 1412 // create a sandbox 1413 s, err := testCreateSandbox(t, 1414 testSandboxID, 1415 MockHypervisor, 1416 hConfig, 1417 NoopAgentType, 1418 NetworkConfig{}, 1419 []ContainerConfig{contConfig1, contConfig2}, 1420 nil) 1421 1422 assert.NoError(t, err) 1423 err = s.updateResources() 1424 assert.NoError(t, err) 1425 1426 containerMemLimit := int64(1000) 1427 containerCPUPeriod := uint64(1000) 1428 containerCPUQouta := int64(5) 1429 for _, c := range s.config.Containers { 1430 c.Resources.Memory = &specs.LinuxMemory{ 1431 Limit: new(int64), 1432 } 1433 c.Resources.CPU = &specs.LinuxCPU{ 1434 Period: new(uint64), 1435 Quota: new(int64), 1436 } 1437 c.Resources.Memory.Limit = &containerMemLimit 1438 c.Resources.CPU.Period = &containerCPUPeriod 1439 c.Resources.CPU.Quota = &containerCPUQouta 1440 } 1441 err = s.updateResources() 1442 assert.NoError(t, err) 1443 } 1444 1445 func TestSandboxExperimentalFeature(t *testing.T) { 1446 testFeature := exp.Feature{ 1447 Name: "mock", 1448 Description: "exp feature for test", 1449 ExpRelease: "1.8.0", 1450 } 1451 sconfig := SandboxConfig{ 1452 ID: testSandboxID, 1453 Experimental: []exp.Feature{testFeature}, 1454 } 1455 1456 assert.Nil(t, exp.Get(testFeature.Name)) 1457 assert.False(t, sconfig.valid()) 1458 1459 exp.Register(testFeature) 1460 assert.NotNil(t, exp.Get(testFeature.Name)) 1461 assert.True(t, sconfig.valid()) 1462 } 1463 1464 func TestSandbox_SetupSandboxCgroup(t *testing.T) { 1465 sandboxContainer := ContainerConfig{} 1466 sandboxContainer.Annotations = make(map[string]string) 1467 sandboxContainer.Annotations[annotations.ContainerTypeKey] = string(PodSandbox) 1468 1469 emptyJSONLinux := ContainerConfig{ 1470 CustomSpec: newEmptySpec(), 1471 } 1472 emptyJSONLinux.Annotations = make(map[string]string) 1473 emptyJSONLinux.Annotations[annotations.ContainerTypeKey] = string(PodSandbox) 1474 1475 cloneSpec1 := newEmptySpec() 1476 cloneSpec1.Linux.CgroupsPath = "/myRuntime/myContainer" 1477 successfulContainer := ContainerConfig{ 1478 CustomSpec: cloneSpec1, 1479 } 1480 successfulContainer.Annotations = make(map[string]string) 1481 successfulContainer.Annotations[annotations.ContainerTypeKey] = string(PodSandbox) 1482 1483 tests := []struct { 1484 name string 1485 s *Sandbox 1486 wantErr bool 1487 needRoot bool 1488 }{ 1489 { 1490 "New sandbox", 1491 &Sandbox{}, 1492 true, 1493 false, 1494 }, 1495 { 1496 "New sandbox, new config", 1497 &Sandbox{config: &SandboxConfig{}}, 1498 true, 1499 false, 1500 }, 1501 { 1502 "sandbox, container no sandbox type", 1503 &Sandbox{ 1504 config: &SandboxConfig{Containers: []ContainerConfig{ 1505 {}, 1506 }}}, 1507 true, 1508 false, 1509 }, 1510 { 1511 "sandbox, container sandbox type", 1512 &Sandbox{ 1513 config: &SandboxConfig{Containers: []ContainerConfig{ 1514 sandboxContainer, 1515 }}}, 1516 true, 1517 false, 1518 }, 1519 { 1520 "sandbox, empty linux json", 1521 &Sandbox{ 1522 config: &SandboxConfig{Containers: []ContainerConfig{ 1523 emptyJSONLinux, 1524 }}}, 1525 false, 1526 true, 1527 }, 1528 { 1529 "sandbox, successful config", 1530 &Sandbox{ 1531 config: &SandboxConfig{Containers: []ContainerConfig{ 1532 successfulContainer, 1533 }}}, 1534 false, 1535 true, 1536 }, 1537 } 1538 for _, tt := range tests { 1539 if tt.needRoot && os.Getuid() != 0 { 1540 t.Skip(tt.name + "needs root") 1541 } 1542 1543 t.Run(tt.name, func(t *testing.T) { 1544 tt.s.createCgroupManager() 1545 if err := tt.s.setupSandboxCgroup(); (err != nil) != tt.wantErr { 1546 t.Errorf("Sandbox.SetupSandboxCgroupOnly() error = %v, wantErr %v", err, tt.wantErr) 1547 } 1548 }) 1549 } 1550 } 1551 1552 func getContainerConfigWithCPUSet(cpuset, memset string) ContainerConfig { 1553 return ContainerConfig{ 1554 Resources: specs.LinuxResources{ 1555 CPU: &specs.LinuxCPU{ 1556 Cpus: cpuset, 1557 Mems: memset, 1558 }, 1559 }, 1560 } 1561 } 1562 1563 func getSimpleSandbox(cpusets, memsets [3]string) *Sandbox { 1564 sandbox := Sandbox{} 1565 1566 sandbox.config = &SandboxConfig{ 1567 Containers: []ContainerConfig{ 1568 getContainerConfigWithCPUSet(cpusets[0], memsets[0]), 1569 getContainerConfigWithCPUSet(cpusets[1], memsets[1]), 1570 getContainerConfigWithCPUSet(cpusets[2], memsets[2]), 1571 }, 1572 } 1573 1574 return &sandbox 1575 } 1576 1577 func TestGetSandboxCpuSet(t *testing.T) { 1578 1579 tests := []struct { 1580 name string 1581 cpusets [3]string 1582 memsets [3]string 1583 cpuResult string 1584 memResult string 1585 wantErr bool 1586 }{ 1587 { 1588 "single, no cpuset", 1589 [3]string{"", "", ""}, 1590 [3]string{"", "", ""}, 1591 "", 1592 "", 1593 false, 1594 }, 1595 { 1596 "single cpuset", 1597 [3]string{"0", "", ""}, 1598 [3]string{"", "", ""}, 1599 "0", 1600 "", 1601 false, 1602 }, 1603 { 1604 "two duplicate cpuset", 1605 [3]string{"0", "0", ""}, 1606 [3]string{"", "", ""}, 1607 "0", 1608 "", 1609 false, 1610 }, 1611 { 1612 "3 cpusets", 1613 [3]string{"0-3", "5-7", "1"}, 1614 [3]string{"", "", ""}, 1615 "0-3,5-7", 1616 "", 1617 false, 1618 }, 1619 1620 { 1621 "weird, but should be okay", 1622 [3]string{"0-3", "99999", ""}, 1623 [3]string{"", "", ""}, 1624 "0-3,99999", 1625 "", 1626 false, 1627 }, 1628 { 1629 "two, overlapping cpuset", 1630 [3]string{"0-3", "1-2", ""}, 1631 [3]string{"", "", ""}, 1632 "0-3", 1633 "", 1634 false, 1635 }, 1636 { 1637 "garbage, should fail", 1638 [3]string{"7 beard-seconds", "Audrey + 7", "Elliott - 17"}, 1639 [3]string{"", "", ""}, 1640 "", 1641 "", 1642 true, 1643 }, 1644 { 1645 "cpuset and memset", 1646 [3]string{"0-3", "1-2", ""}, 1647 [3]string{"0", "1", "0-1"}, 1648 "0-3", 1649 "0-1", 1650 false, 1651 }, 1652 { 1653 "memset", 1654 [3]string{"0-3", "1-2", ""}, 1655 [3]string{"0", "3", ""}, 1656 "0-3", 1657 "0,3", 1658 false, 1659 }, 1660 } 1661 for _, tt := range tests { 1662 1663 t.Run(tt.name, func(t *testing.T) { 1664 s := getSimpleSandbox(tt.cpusets, tt.memsets) 1665 res, _, err := s.getSandboxCPUSet() 1666 if (err != nil) != tt.wantErr { 1667 t.Errorf("getSandboxCPUSet() error = %v, wantErr %v", err, tt.wantErr) 1668 } 1669 if res != tt.cpuResult { 1670 t.Errorf("getSandboxCPUSet() result = %s, wanted result %s", res, tt.cpuResult) 1671 } 1672 }) 1673 } 1674 } 1675 1676 func TestSandboxStoreClean(t *testing.T) { 1677 ctx := context.Background() 1678 contID := "SandboxStore" 1679 contConfig := newTestContainerConfigNoop(contID) 1680 hConfig := newHypervisorConfig(nil, nil) 1681 assert := assert.New(t) 1682 1683 // create a sandbox 1684 p, err := testCreateSandbox(t, testSandboxID, MockHypervisor, hConfig, NoopAgentType, NetworkConfig{}, []ContainerConfig{contConfig}, nil) 1685 assert.NoError(err) 1686 defer cleanUp() 1687 1688 l := len(p.GetAllContainers()) 1689 assert.Equal(l, 1) 1690 1691 // persist to disk 1692 err = p.storeSandbox() 1693 assert.NoError(err) 1694 1695 loadSandboxConfigFromOldStore(ctx, p.ID()) 1696 1697 runtimeSidPath := store.SandboxConfigurationRoot(p.ID()) 1698 runtimeSidPath = strings.TrimPrefix(runtimeSidPath, "file://") 1699 1700 p.store, err = store.NewVCSandboxStore(ctx, testSandboxID) 1701 assert.Nil(err) 1702 1703 p.ctx = context.WithValue(ctx, oldstoreKey, true) 1704 err = p.Delete() 1705 assert.NoError(err) 1706 1707 // expect runtimeSidPath not exist, if exist, it means this case failed. 1708 _, err = os.Stat(runtimeSidPath) 1709 assert.Error(err) 1710 assert.True(os.IsNotExist(err)) 1711 }