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  }