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: &quota}
   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: &quota, 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  }