gitee.com/leisunstar/runtime@v0.0.0-20200521203717-5cef3e7b53f9/virtcontainers/container_test.go (about) 1 // Copyright (c) 2017 Intel Corporation 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 // 5 6 package virtcontainers 7 8 import ( 9 "context" 10 "io/ioutil" 11 "os" 12 "os/exec" 13 "path/filepath" 14 "strings" 15 "syscall" 16 "testing" 17 18 ktu "github.com/kata-containers/runtime/pkg/katatestutils" 19 "github.com/kata-containers/runtime/virtcontainers/device/api" 20 "github.com/kata-containers/runtime/virtcontainers/device/config" 21 "github.com/kata-containers/runtime/virtcontainers/device/drivers" 22 "github.com/kata-containers/runtime/virtcontainers/device/manager" 23 "github.com/kata-containers/runtime/virtcontainers/persist" 24 "github.com/kata-containers/runtime/virtcontainers/types" 25 "github.com/stretchr/testify/assert" 26 ) 27 28 func TestGetAnnotations(t *testing.T) { 29 annotations := map[string]string{ 30 "annotation1": "abc", 31 "annotation2": "xyz", 32 "annotation3": "123", 33 } 34 35 container := Container{ 36 config: &ContainerConfig{ 37 Annotations: annotations, 38 }, 39 } 40 41 containerAnnotations := container.GetAnnotations() 42 43 for k, v := range containerAnnotations { 44 assert.Equal(t, annotations[k], v) 45 } 46 } 47 48 func TestContainerSystemMountsInfo(t *testing.T) { 49 mounts := []Mount{ 50 { 51 Source: "/dev", 52 Destination: "/dev", 53 Type: "bind", 54 }, 55 { 56 Source: "procfs", 57 Destination: "/proc", 58 Type: "procfs", 59 }, 60 } 61 62 c := Container{ 63 mounts: mounts, 64 } 65 66 assert.False(t, c.systemMountsInfo.BindMountDev) 67 c.getSystemMountInfo() 68 assert.True(t, c.systemMountsInfo.BindMountDev) 69 70 c.mounts[0].Type = "tmpfs" 71 c.getSystemMountInfo() 72 assert.False(t, c.systemMountsInfo.BindMountDev) 73 } 74 75 func TestContainerSandbox(t *testing.T) { 76 expectedSandbox := &Sandbox{} 77 78 container := Container{ 79 sandbox: expectedSandbox, 80 } 81 82 sandbox := container.Sandbox() 83 assert.Exactly(t, sandbox, expectedSandbox) 84 } 85 86 func TestContainerRemoveDrive(t *testing.T) { 87 sandbox := &Sandbox{ 88 ctx: context.Background(), 89 id: "sandbox", 90 devManager: manager.NewDeviceManager(manager.VirtioSCSI, false, "", nil), 91 config: &SandboxConfig{}, 92 } 93 94 container := Container{ 95 sandbox: sandbox, 96 id: "testContainer", 97 } 98 99 container.state.Fstype = "" 100 err := container.removeDrive() 101 102 // hotplugRemoveDevice for hypervisor should not be called. 103 // test should pass without a hypervisor created for the container's sandbox. 104 assert.Nil(t, err, "remove drive should succeed") 105 106 sandbox.hypervisor = &mockHypervisor{} 107 path := "/dev/hda" 108 deviceInfo := config.DeviceInfo{ 109 HostPath: path, 110 ContainerPath: path, 111 DevType: "b", 112 } 113 devReceiver := &api.MockDeviceReceiver{} 114 115 device, err := sandbox.devManager.NewDevice(deviceInfo) 116 assert.Nil(t, err) 117 _, ok := device.(*drivers.BlockDevice) 118 assert.True(t, ok) 119 err = device.Attach(devReceiver) 120 assert.Nil(t, err) 121 122 container.state.Fstype = "xfs" 123 container.state.BlockDeviceID = device.DeviceID() 124 err = container.removeDrive() 125 assert.Nil(t, err, "remove drive should succeed") 126 } 127 128 func TestUnmountHostMountsRemoveBindHostPath(t *testing.T) { 129 if tc.NotValid(ktu.NeedRoot()) { 130 t.Skip(testDisabledAsNonRoot) 131 } 132 133 createFakeMountDir := func(t *testing.T, dir, prefix string) string { 134 name, err := ioutil.TempDir(dir, "test-mnt-"+prefix+"-") 135 if err != nil { 136 t.Fatal(err) 137 } 138 return name 139 } 140 141 createFakeMountFile := func(t *testing.T, dir, prefix string) string { 142 f, err := ioutil.TempFile(dir, "test-mnt-"+prefix+"-") 143 if err != nil { 144 t.Fatal(err) 145 } 146 f.Close() 147 return f.Name() 148 } 149 150 doUnmountCheck := func(src, dest, hostPath, nonEmptyHostpath, devPath string) { 151 mounts := []Mount{ 152 { 153 Source: src, 154 Destination: dest, 155 HostPath: hostPath, 156 Type: "bind", 157 }, 158 { 159 Source: src, 160 Destination: dest, 161 HostPath: nonEmptyHostpath, 162 Type: "bind", 163 }, 164 { 165 Source: src, 166 Destination: dest, 167 HostPath: devPath, 168 Type: "dev", 169 }, 170 } 171 172 c := Container{ 173 mounts: mounts, 174 ctx: context.Background(), 175 } 176 177 if err := bindMount(c.ctx, src, hostPath, false, "private"); err != nil { 178 t.Fatal(err) 179 } 180 defer syscall.Unmount(hostPath, 0) 181 if err := bindMount(c.ctx, src, nonEmptyHostpath, false, "private"); err != nil { 182 t.Fatal(err) 183 } 184 defer syscall.Unmount(nonEmptyHostpath, 0) 185 if err := bindMount(c.ctx, src, devPath, false, "private"); err != nil { 186 t.Fatal(err) 187 } 188 defer syscall.Unmount(devPath, 0) 189 190 err := c.unmountHostMounts() 191 if err != nil { 192 t.Fatal(err) 193 } 194 195 for _, path := range [3]string{src, dest, devPath} { 196 if _, err := os.Stat(path); err != nil { 197 if os.IsNotExist(err) { 198 t.Fatalf("path %s should not be removed", path) 199 } else { 200 t.Fatal(err) 201 } 202 } 203 } 204 205 if _, err := os.Stat(hostPath); err == nil { 206 t.Fatal("empty host-path should be removed") 207 } else if !os.IsNotExist(err) { 208 t.Fatal(err) 209 } 210 211 if _, err := os.Stat(nonEmptyHostpath); err != nil { 212 if os.IsNotExist(err) { 213 t.Fatal("non-empty host-path should not be removed") 214 } else { 215 t.Fatal(err) 216 } 217 } 218 } 219 220 src := createFakeMountDir(t, testDir, "src") 221 dest := createFakeMountDir(t, testDir, "dest") 222 hostPath := createFakeMountDir(t, testDir, "host-path") 223 nonEmptyHostpath := createFakeMountDir(t, testDir, "non-empty-host-path") 224 devPath := createFakeMountDir(t, testDir, "dev-hostpath") 225 createFakeMountDir(t, nonEmptyHostpath, "nop") 226 doUnmountCheck(src, dest, hostPath, nonEmptyHostpath, devPath) 227 228 src = createFakeMountFile(t, testDir, "src") 229 dest = createFakeMountFile(t, testDir, "dest") 230 hostPath = createFakeMountFile(t, testDir, "host-path") 231 nonEmptyHostpath = createFakeMountFile(t, testDir, "non-empty-host-path") 232 devPath = createFakeMountFile(t, testDir, "dev-host-path") 233 f, err := os.OpenFile(nonEmptyHostpath, os.O_WRONLY, os.FileMode(0640)) 234 if err != nil { 235 t.Fatal(err) 236 } 237 f.WriteString("nop\n") 238 f.Close() 239 doUnmountCheck(src, dest, hostPath, nonEmptyHostpath, devPath) 240 } 241 242 func testSetupFakeRootfs(t *testing.T) (testRawFile, loopDev, mntDir string, err error) { 243 assert := assert.New(t) 244 if tc.NotValid(ktu.NeedRoot()) { 245 t.Skip(testDisabledAsNonRoot) 246 } 247 248 tmpDir, err := ioutil.TempDir("", "") 249 assert.NoError(err) 250 251 testRawFile = filepath.Join(tmpDir, "raw.img") 252 _, err = os.Stat(testRawFile) 253 assert.True(os.IsNotExist(err)) 254 255 output, err := exec.Command("losetup", "-f").CombinedOutput() 256 assert.NoError(err) 257 loopDev = strings.TrimSpace(string(output[:])) 258 259 _, err = exec.Command("fallocate", "-l", "256K", testRawFile).CombinedOutput() 260 assert.NoError(err) 261 262 _, err = exec.Command("mkfs.ext4", "-F", testRawFile).CombinedOutput() 263 assert.NoError(err) 264 265 _, err = exec.Command("losetup", loopDev, testRawFile).CombinedOutput() 266 assert.NoError(err) 267 268 mntDir = filepath.Join(tmpDir, "rootfs") 269 err = os.Mkdir(mntDir, DirMode) 270 assert.NoError(err) 271 272 err = syscall.Mount(loopDev, mntDir, "ext4", uintptr(0), "") 273 assert.NoError(err) 274 return 275 } 276 277 func cleanupFakeRootfsSetup(testRawFile, loopDev, mntDir string) { 278 // unmount loop device 279 if mntDir != "" { 280 syscall.Unmount(mntDir, 0) 281 } 282 283 // detach loop device 284 if loopDev != "" { 285 exec.Command("losetup", "-d", loopDev).CombinedOutput() 286 } 287 288 if _, err := os.Stat(testRawFile); err == nil { 289 tmpDir := filepath.Dir(testRawFile) 290 os.RemoveAll(tmpDir) 291 } 292 } 293 294 func TestContainerAddDriveDir(t *testing.T) { 295 assert := assert.New(t) 296 if tc.NotValid(ktu.NeedRoot()) { 297 t.Skip(testDisabledAsNonRoot) 298 } 299 300 testRawFile, loopDev, fakeRootfs, err := testSetupFakeRootfs(t) 301 302 defer cleanupFakeRootfsSetup(testRawFile, loopDev, fakeRootfs) 303 304 assert.NoError(err) 305 306 sandbox := &Sandbox{ 307 ctx: context.Background(), 308 id: testSandboxID, 309 devManager: manager.NewDeviceManager(manager.VirtioSCSI, false, "", nil), 310 hypervisor: &mockHypervisor{}, 311 agent: &noopAgent{}, 312 config: &SandboxConfig{ 313 HypervisorConfig: HypervisorConfig{ 314 DisableBlockDeviceUse: false, 315 }, 316 }, 317 } 318 319 sandbox.newStore, err = persist.GetDriver() 320 assert.NoError(err) 321 assert.NotNil(sandbox.newStore) 322 323 defer sandbox.newStore.Destroy(sandbox.id) 324 325 contID := "100" 326 container := Container{ 327 sandbox: sandbox, 328 id: contID, 329 rootFs: RootFs{Target: fakeRootfs, Mounted: true}, 330 } 331 332 // Make the checkStorageDriver func variable point to a fake check function 333 savedFunc := checkStorageDriver 334 checkStorageDriver = func(major, minor int) (bool, error) { 335 return true, nil 336 } 337 338 defer func() { 339 checkStorageDriver = savedFunc 340 }() 341 342 container.state.Fstype = "" 343 344 err = container.hotplugDrive() 345 assert.NoError(err) 346 347 assert.NotEmpty(container.state.Fstype) 348 } 349 350 func TestContainerRootfsPath(t *testing.T) { 351 352 testRawFile, loopDev, fakeRootfs, err := testSetupFakeRootfs(t) 353 defer cleanupFakeRootfsSetup(testRawFile, loopDev, fakeRootfs) 354 assert.Nil(t, err) 355 356 truecheckstoragedriver := checkStorageDriver 357 checkStorageDriver = func(major, minor int) (bool, error) { 358 return true, nil 359 } 360 defer func() { 361 checkStorageDriver = truecheckstoragedriver 362 }() 363 364 sandbox := &Sandbox{ 365 ctx: context.Background(), 366 id: "rootfstestsandbox", 367 agent: &noopAgent{}, 368 hypervisor: &mockHypervisor{}, 369 config: &SandboxConfig{ 370 HypervisorConfig: HypervisorConfig{ 371 DisableBlockDeviceUse: false, 372 }, 373 }, 374 } 375 376 container := Container{ 377 id: "rootfstestcontainerid", 378 sandbox: sandbox, 379 rootFs: RootFs{Target: fakeRootfs, Mounted: true}, 380 rootfsSuffix: "rootfs", 381 } 382 383 container.hotplugDrive() 384 assert.Empty(t, container.rootfsSuffix) 385 386 // Reset the value to test the other case 387 container.rootFs = RootFs{Target: fakeRootfs + "/rootfs", Mounted: true} 388 container.rootfsSuffix = "rootfs" 389 390 container.hotplugDrive() 391 assert.Equal(t, container.rootfsSuffix, "rootfs") 392 } 393 394 func TestCheckSandboxRunningEmptyCmdFailure(t *testing.T) { 395 c := &Container{} 396 err := c.checkSandboxRunning("") 397 assert.NotNil(t, err, "Should fail because provided command is empty") 398 } 399 400 func TestCheckSandboxRunningNotRunningFailure(t *testing.T) { 401 c := &Container{ 402 sandbox: &Sandbox{}, 403 } 404 err := c.checkSandboxRunning("test_cmd") 405 assert.NotNil(t, err, "Should fail because sandbox state is empty") 406 } 407 408 func TestCheckSandboxRunningSuccessful(t *testing.T) { 409 c := &Container{ 410 sandbox: &Sandbox{ 411 state: types.SandboxState{ 412 State: types.StateRunning, 413 }, 414 }, 415 } 416 err := c.checkSandboxRunning("test_cmd") 417 assert.Nil(t, err, "%v", err) 418 } 419 420 func TestContainerEnterErrorsOnContainerStates(t *testing.T) { 421 assert := assert.New(t) 422 c := &Container{ 423 sandbox: &Sandbox{ 424 state: types.SandboxState{ 425 State: types.StateRunning, 426 }, 427 }, 428 } 429 cmd := types.Cmd{} 430 431 // Container state undefined 432 _, err := c.enter(cmd) 433 assert.Error(err) 434 435 // Container paused 436 c.state.State = types.StatePaused 437 _, err = c.enter(cmd) 438 assert.Error(err) 439 440 // Container stopped 441 c.state.State = types.StateStopped 442 _, err = c.enter(cmd) 443 assert.Error(err) 444 } 445 446 func TestContainerWaitErrorState(t *testing.T) { 447 assert := assert.New(t) 448 c := &Container{ 449 sandbox: &Sandbox{ 450 state: types.SandboxState{ 451 State: types.StateRunning, 452 }, 453 }, 454 } 455 processID := "foobar" 456 457 // Container state undefined 458 _, err := c.wait(processID) 459 assert.Error(err) 460 461 // Container paused 462 c.state.State = types.StatePaused 463 _, err = c.wait(processID) 464 assert.Error(err) 465 466 // Container stopped 467 c.state.State = types.StateStopped 468 _, err = c.wait(processID) 469 assert.Error(err) 470 } 471 472 func TestKillContainerErrorState(t *testing.T) { 473 assert := assert.New(t) 474 c := &Container{ 475 sandbox: &Sandbox{ 476 state: types.SandboxState{ 477 State: types.StateRunning, 478 }, 479 }, 480 } 481 // Container state undefined 482 err := c.kill(syscall.SIGKILL, true) 483 assert.Error(err) 484 485 // Container stopped 486 c.state.State = types.StateStopped 487 err = c.kill(syscall.SIGKILL, true) 488 assert.Error(err) 489 } 490 491 func TestWinsizeProcessErrorState(t *testing.T) { 492 assert := assert.New(t) 493 c := &Container{ 494 sandbox: &Sandbox{ 495 state: types.SandboxState{ 496 State: types.StateRunning, 497 }, 498 }, 499 } 500 processID := "foobar" 501 502 // Container state undefined 503 err := c.winsizeProcess(processID, 100, 200) 504 assert.Error(err) 505 506 // Container paused 507 c.state.State = types.StatePaused 508 err = c.winsizeProcess(processID, 100, 200) 509 assert.Error(err) 510 511 // Container stopped 512 c.state.State = types.StateStopped 513 err = c.winsizeProcess(processID, 100, 200) 514 assert.Error(err) 515 } 516 517 func TestProcessIOStream(t *testing.T) { 518 assert := assert.New(t) 519 c := &Container{ 520 sandbox: &Sandbox{ 521 state: types.SandboxState{ 522 State: types.StateRunning, 523 }, 524 }, 525 } 526 processID := "foobar" 527 528 // Container state undefined 529 _, _, _, err := c.ioStream(processID) 530 assert.Error(err) 531 532 // Container paused 533 c.state.State = types.StatePaused 534 _, _, _, err = c.ioStream(processID) 535 assert.Error(err) 536 537 // Container stopped 538 c.state.State = types.StateStopped 539 _, _, _, err = c.ioStream(processID) 540 assert.Error(err) 541 }