mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-10-22 20:39:41 +00:00
This patch enables the code responsible for starting and stopping the network monitor. Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
1751 lines
40 KiB
Go
1751 lines
40 KiB
Go
// Copyright (c) 2016 Intel Corporation
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
package virtcontainers
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"reflect"
|
|
"sync"
|
|
"syscall"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/kata-containers/runtime/virtcontainers/device/config"
|
|
"github.com/kata-containers/runtime/virtcontainers/device/drivers"
|
|
"github.com/kata-containers/runtime/virtcontainers/device/manager"
|
|
"github.com/kata-containers/runtime/virtcontainers/pkg/annotations"
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
func newHypervisorConfig(kernelParams []Param, hParams []Param) HypervisorConfig {
|
|
return HypervisorConfig{
|
|
KernelPath: filepath.Join(testDir, testKernel),
|
|
ImagePath: filepath.Join(testDir, testImage),
|
|
HypervisorPath: filepath.Join(testDir, testHypervisor),
|
|
KernelParams: kernelParams,
|
|
HypervisorParams: hParams,
|
|
}
|
|
|
|
}
|
|
|
|
func testCreateSandbox(t *testing.T, id string,
|
|
htype HypervisorType, hconfig HypervisorConfig, atype AgentType,
|
|
nmodel NetworkModel, nconfig NetworkConfig, containers []ContainerConfig,
|
|
volumes []Volume) (*Sandbox, error) {
|
|
|
|
sconfig := SandboxConfig{
|
|
ID: id,
|
|
HypervisorType: htype,
|
|
HypervisorConfig: hconfig,
|
|
AgentType: atype,
|
|
NetworkModel: nmodel,
|
|
NetworkConfig: nconfig,
|
|
Volumes: volumes,
|
|
Containers: containers,
|
|
}
|
|
|
|
sandbox, err := createSandbox(context.Background(), sconfig, nil)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Could not create sandbox: %s", err)
|
|
}
|
|
|
|
if err := sandbox.agent.startSandbox(sandbox); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := sandbox.createContainers(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if sandbox.id == "" {
|
|
return sandbox, fmt.Errorf("Invalid empty sandbox ID")
|
|
}
|
|
|
|
if id != "" && sandbox.id != id {
|
|
return sandbox, fmt.Errorf("Invalid ID %s vs %s", id, sandbox.id)
|
|
}
|
|
|
|
return sandbox, nil
|
|
}
|
|
|
|
func TestCreateEmtpySandbox(t *testing.T) {
|
|
_, err := testCreateSandbox(t, testSandboxID, MockHypervisor, HypervisorConfig{}, NoopAgentType, NoopNetworkModel, NetworkConfig{}, nil, nil)
|
|
if err == nil {
|
|
t.Fatalf("VirtContainers should not allow empty sandboxes")
|
|
}
|
|
defer cleanUp()
|
|
}
|
|
|
|
func TestCreateEmtpyHypervisorSandbox(t *testing.T) {
|
|
_, err := testCreateSandbox(t, testSandboxID, QemuHypervisor, HypervisorConfig{}, NoopAgentType, NoopNetworkModel, NetworkConfig{}, nil, nil)
|
|
if err == nil {
|
|
t.Fatalf("VirtContainers should not allow sandboxes with empty hypervisors")
|
|
}
|
|
defer cleanUp()
|
|
}
|
|
|
|
func TestCreateMockSandbox(t *testing.T) {
|
|
hConfig := newHypervisorConfig(nil, nil)
|
|
|
|
_, err := testCreateSandbox(t, testSandboxID, MockHypervisor, hConfig, NoopAgentType, NoopNetworkModel, NetworkConfig{}, nil, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer cleanUp()
|
|
}
|
|
|
|
func TestCreateSandboxEmtpyID(t *testing.T) {
|
|
hConfig := newHypervisorConfig(nil, nil)
|
|
|
|
p, err := testCreateSandbox(t, "", MockHypervisor, hConfig, NoopAgentType, NoopNetworkModel, NetworkConfig{}, nil, nil)
|
|
if err == nil {
|
|
t.Fatalf("Expected sandbox with empty ID to fail, but got sandbox %v", p)
|
|
}
|
|
defer cleanUp()
|
|
}
|
|
|
|
func testSandboxStateTransition(t *testing.T, state stateString, newState stateString) error {
|
|
hConfig := newHypervisorConfig(nil, nil)
|
|
|
|
p, err := testCreateSandbox(t, testSandboxID, MockHypervisor, hConfig, NoopAgentType, NoopNetworkModel, NetworkConfig{}, nil, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer cleanUp()
|
|
|
|
p.state = State{
|
|
State: state,
|
|
}
|
|
|
|
return p.state.validTransition(state, newState)
|
|
}
|
|
|
|
func TestSandboxStateReadyRunning(t *testing.T) {
|
|
err := testSandboxStateTransition(t, StateReady, StateRunning)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestSandboxStateRunningPaused(t *testing.T) {
|
|
err := testSandboxStateTransition(t, StateRunning, StatePaused)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestSandboxStatePausedRunning(t *testing.T) {
|
|
err := testSandboxStateTransition(t, StatePaused, StateRunning)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestSandboxStatePausedStopped(t *testing.T) {
|
|
err := testSandboxStateTransition(t, StatePaused, StateStopped)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestSandboxStateRunningStopped(t *testing.T) {
|
|
err := testSandboxStateTransition(t, StateRunning, StateStopped)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestSandboxStateReadyPaused(t *testing.T) {
|
|
err := testSandboxStateTransition(t, StateReady, StateStopped)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestSandboxStatePausedReady(t *testing.T) {
|
|
err := testSandboxStateTransition(t, StateStopped, StateReady)
|
|
if err == nil {
|
|
t.Fatal("Invalid transition from Ready to Paused")
|
|
}
|
|
}
|
|
|
|
func testSandboxDir(t *testing.T, resource sandboxResource, expected string) error {
|
|
fs := filesystem{}
|
|
_, dir, err := fs.sandboxURI(testSandboxID, resource)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if dir != expected {
|
|
return fmt.Errorf("Unexpected sandbox directory %s vs %s", dir, expected)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func testSandboxFile(t *testing.T, resource sandboxResource, expected string) error {
|
|
fs := filesystem{}
|
|
file, _, err := fs.sandboxURI(testSandboxID, resource)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if file != expected {
|
|
return fmt.Errorf("Unexpected sandbox file %s vs %s", file, expected)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func TestSandboxDirConfig(t *testing.T) {
|
|
err := testSandboxDir(t, configFileType, sandboxDirConfig)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestSandboxDirState(t *testing.T) {
|
|
err := testSandboxDir(t, stateFileType, sandboxDirState)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestSandboxDirLock(t *testing.T) {
|
|
err := testSandboxDir(t, lockFileType, sandboxDirLock)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestSandboxDirNegative(t *testing.T) {
|
|
fs := filesystem{}
|
|
_, _, err := fs.sandboxURI("", lockFileType)
|
|
if err == nil {
|
|
t.Fatal("Empty sandbox IDs should not be allowed")
|
|
}
|
|
}
|
|
|
|
func TestSandboxFileConfig(t *testing.T) {
|
|
err := testSandboxFile(t, configFileType, sandboxFileConfig)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestSandboxFileState(t *testing.T) {
|
|
err := testSandboxFile(t, stateFileType, sandboxFileState)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestSandboxFileLock(t *testing.T) {
|
|
err := testSandboxFile(t, lockFileType, sandboxFileLock)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestSandboxFileNegative(t *testing.T) {
|
|
fs := filesystem{}
|
|
_, _, err := fs.sandboxURI("", lockFileType)
|
|
if err == nil {
|
|
t.Fatal("Empty sandbox IDs should not be allowed")
|
|
}
|
|
}
|
|
|
|
func testStateValid(t *testing.T, stateStr stateString, expected bool) {
|
|
state := &State{
|
|
State: stateStr,
|
|
}
|
|
|
|
ok := state.valid()
|
|
if ok != expected {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func TestStateValidSuccessful(t *testing.T) {
|
|
testStateValid(t, StateReady, true)
|
|
testStateValid(t, StateRunning, true)
|
|
testStateValid(t, StatePaused, true)
|
|
testStateValid(t, StateStopped, true)
|
|
}
|
|
|
|
func TestStateValidFailing(t *testing.T) {
|
|
testStateValid(t, "", false)
|
|
}
|
|
|
|
func TestValidTransitionFailingOldStateMismatch(t *testing.T) {
|
|
state := &State{
|
|
State: StateReady,
|
|
}
|
|
|
|
err := state.validTransition(StateRunning, StateStopped)
|
|
if err == nil {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func TestVolumesSetSuccessful(t *testing.T) {
|
|
volumes := &Volumes{}
|
|
|
|
volStr := "mountTag1:hostPath1 mountTag2:hostPath2"
|
|
|
|
expected := Volumes{
|
|
{
|
|
MountTag: "mountTag1",
|
|
HostPath: "hostPath1",
|
|
},
|
|
{
|
|
MountTag: "mountTag2",
|
|
HostPath: "hostPath2",
|
|
},
|
|
}
|
|
|
|
err := volumes.Set(volStr)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if reflect.DeepEqual(*volumes, expected) == false {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func TestVolumesSetFailingTooFewArguments(t *testing.T) {
|
|
volumes := &Volumes{}
|
|
|
|
volStr := "mountTag1 mountTag2"
|
|
|
|
err := volumes.Set(volStr)
|
|
if err == nil {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func TestVolumesSetFailingTooManyArguments(t *testing.T) {
|
|
volumes := &Volumes{}
|
|
|
|
volStr := "mountTag1:hostPath1:Foo1 mountTag2:hostPath2:Foo2"
|
|
|
|
err := volumes.Set(volStr)
|
|
if err == nil {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func TestVolumesSetFailingVoidArguments(t *testing.T) {
|
|
volumes := &Volumes{}
|
|
|
|
volStr := ": : :"
|
|
|
|
err := volumes.Set(volStr)
|
|
if err == nil {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func TestVolumesStringSuccessful(t *testing.T) {
|
|
volumes := &Volumes{
|
|
{
|
|
MountTag: "mountTag1",
|
|
HostPath: "hostPath1",
|
|
},
|
|
{
|
|
MountTag: "mountTag2",
|
|
HostPath: "hostPath2",
|
|
},
|
|
}
|
|
|
|
expected := "mountTag1:hostPath1 mountTag2:hostPath2"
|
|
|
|
result := volumes.String()
|
|
if result != expected {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func TestSocketsSetSuccessful(t *testing.T) {
|
|
sockets := &Sockets{}
|
|
|
|
sockStr := "devID1:id1:hostPath1:Name1 devID2:id2:hostPath2:Name2"
|
|
|
|
expected := Sockets{
|
|
{
|
|
DeviceID: "devID1",
|
|
ID: "id1",
|
|
HostPath: "hostPath1",
|
|
Name: "Name1",
|
|
},
|
|
{
|
|
DeviceID: "devID2",
|
|
ID: "id2",
|
|
HostPath: "hostPath2",
|
|
Name: "Name2",
|
|
},
|
|
}
|
|
|
|
err := sockets.Set(sockStr)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if reflect.DeepEqual(*sockets, expected) == false {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func TestSocketsSetFailingWrongArgsAmount(t *testing.T) {
|
|
sockets := &Sockets{}
|
|
|
|
sockStr := "devID1:id1:hostPath1"
|
|
|
|
err := sockets.Set(sockStr)
|
|
if err == nil {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func TestSocketsSetFailingVoidArguments(t *testing.T) {
|
|
sockets := &Sockets{}
|
|
|
|
sockStr := ":::"
|
|
|
|
err := sockets.Set(sockStr)
|
|
if err == nil {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func TestSocketsStringSuccessful(t *testing.T) {
|
|
sockets := &Sockets{
|
|
{
|
|
DeviceID: "devID1",
|
|
ID: "id1",
|
|
HostPath: "hostPath1",
|
|
Name: "Name1",
|
|
},
|
|
{
|
|
DeviceID: "devID2",
|
|
ID: "id2",
|
|
HostPath: "hostPath2",
|
|
Name: "Name2",
|
|
},
|
|
}
|
|
|
|
expected := "devID1:id1:hostPath1:Name1 devID2:id2:hostPath2:Name2"
|
|
|
|
result := sockets.String()
|
|
if result != expected {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func TestSandboxListSuccessful(t *testing.T) {
|
|
sandbox := &Sandbox{}
|
|
|
|
sandboxList, err := sandbox.list()
|
|
if sandboxList != nil || err != nil {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func TestSandboxEnterSuccessful(t *testing.T) {
|
|
sandbox := &Sandbox{}
|
|
|
|
err := sandbox.enter([]string{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func testCheckInitSandboxAndContainerStates(p *Sandbox, initialSandboxState State, c *Container, initialContainerState State) error {
|
|
if p.state.State != initialSandboxState.State {
|
|
return fmt.Errorf("Expected sandbox state %v, got %v", initialSandboxState.State, p.state.State)
|
|
}
|
|
|
|
if c.state.State != initialContainerState.State {
|
|
return fmt.Errorf("Expected container state %v, got %v", initialContainerState.State, c.state.State)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func testForceSandboxStateChangeAndCheck(t *testing.T, p *Sandbox, newSandboxState State) error {
|
|
// force sandbox state change
|
|
if err := p.setSandboxState(newSandboxState.State); err != nil {
|
|
t.Fatalf("Unexpected error: %v (sandbox %+v)", err, p)
|
|
}
|
|
|
|
// check the in-memory state is correct
|
|
if p.state.State != newSandboxState.State {
|
|
return fmt.Errorf("Expected state %v, got %v", newSandboxState.State, p.state.State)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func testForceContainerStateChangeAndCheck(t *testing.T, p *Sandbox, c *Container, newContainerState State) error {
|
|
// force container state change
|
|
if err := c.setContainerState(newContainerState.State); err != nil {
|
|
t.Fatalf("Unexpected error: %v (sandbox %+v)", err, p)
|
|
}
|
|
|
|
// check the in-memory state is correct
|
|
if c.state.State != newContainerState.State {
|
|
return fmt.Errorf("Expected state %v, got %v", newContainerState.State, c.state.State)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func testCheckSandboxOnDiskState(p *Sandbox, sandboxState State) error {
|
|
// check on-disk state is correct
|
|
if p.state.State != sandboxState.State {
|
|
return fmt.Errorf("Expected state %v, got %v", sandboxState.State, p.state.State)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func testCheckContainerOnDiskState(c *Container, containerState State) error {
|
|
// check on-disk state is correct
|
|
if c.state.State != containerState.State {
|
|
return fmt.Errorf("Expected state %v, got %v", containerState.State, c.state.State)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func TestSandboxSetSandboxAndContainerState(t *testing.T) {
|
|
contID := "505"
|
|
contConfig := newTestContainerConfigNoop(contID)
|
|
hConfig := newHypervisorConfig(nil, nil)
|
|
|
|
// create a sandbox
|
|
p, err := testCreateSandbox(t, testSandboxID, MockHypervisor, hConfig, NoopAgentType, NoopNetworkModel, NetworkConfig{}, []ContainerConfig{contConfig}, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer cleanUp()
|
|
|
|
l := len(p.GetAllContainers())
|
|
if l != 1 {
|
|
t.Fatalf("Expected 1 container found %v", l)
|
|
}
|
|
|
|
initialSandboxState := State{
|
|
State: StateReady,
|
|
}
|
|
|
|
// After a sandbox creation, a container has a READY state
|
|
initialContainerState := State{
|
|
State: StateReady,
|
|
}
|
|
|
|
c, err := p.findContainer(contID)
|
|
if err != nil {
|
|
t.Fatalf("Failed to retrieve container %v: %v", contID, err)
|
|
}
|
|
|
|
// check initial sandbox and container states
|
|
if err := testCheckInitSandboxAndContainerStates(p, initialSandboxState, c, initialContainerState); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
// persist to disk
|
|
err = p.storeSandbox()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
newSandboxState := State{
|
|
State: StateRunning,
|
|
}
|
|
|
|
if err := testForceSandboxStateChangeAndCheck(t, p, newSandboxState); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
newContainerState := State{
|
|
State: StateStopped,
|
|
}
|
|
|
|
if err := testForceContainerStateChangeAndCheck(t, p, c, newContainerState); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
// force state to be read from disk
|
|
p2, err := fetchSandbox(context.Background(), p.ID())
|
|
if err != nil {
|
|
t.Fatalf("Failed to fetch sandbox %v: %v", p.ID(), err)
|
|
}
|
|
|
|
if err := testCheckSandboxOnDiskState(p2, newSandboxState); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
c2, err := p2.findContainer(contID)
|
|
if err != nil {
|
|
t.Fatalf("Failed to find container %v: %v", contID, err)
|
|
}
|
|
|
|
if err := testCheckContainerOnDiskState(c2, newContainerState); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
// revert sandbox state to allow it to be deleted
|
|
err = p.setSandboxState(initialSandboxState.State)
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error: %v (sandbox %+v)", err, p)
|
|
}
|
|
|
|
// clean up
|
|
err = p.Delete()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestSandboxSetSandboxStateFailingStoreSandboxResource(t *testing.T) {
|
|
fs := &filesystem{}
|
|
sandbox := &Sandbox{
|
|
storage: fs,
|
|
}
|
|
|
|
err := sandbox.setSandboxState(StateReady)
|
|
if err == nil {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func TestSandboxSetContainersStateFailingEmptySandboxID(t *testing.T) {
|
|
sandbox := &Sandbox{
|
|
storage: &filesystem{},
|
|
}
|
|
|
|
containers := map[string]*Container{
|
|
"100": {
|
|
id: "100",
|
|
sandbox: sandbox,
|
|
},
|
|
}
|
|
|
|
sandbox.containers = containers
|
|
|
|
err := sandbox.setContainersState(StateReady)
|
|
if err == nil {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func TestSandboxDeleteContainerStateSuccessful(t *testing.T) {
|
|
contID := "100"
|
|
|
|
fs := &filesystem{}
|
|
sandbox := &Sandbox{
|
|
id: testSandboxID,
|
|
storage: fs,
|
|
}
|
|
|
|
path := filepath.Join(runStoragePath, testSandboxID, contID)
|
|
err := os.MkdirAll(path, dirMode)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
stateFilePath := filepath.Join(path, stateFile)
|
|
|
|
os.Remove(stateFilePath)
|
|
|
|
_, err = os.Create(stateFilePath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, err = os.Stat(stateFilePath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
err = sandbox.deleteContainerState(contID)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, err = os.Stat(stateFilePath)
|
|
if err == nil {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func TestSandboxDeleteContainerStateFailingEmptySandboxID(t *testing.T) {
|
|
contID := "100"
|
|
|
|
fs := &filesystem{}
|
|
sandbox := &Sandbox{
|
|
storage: fs,
|
|
}
|
|
|
|
err := sandbox.deleteContainerState(contID)
|
|
if err == nil {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func TestSandboxDeleteContainersStateSuccessful(t *testing.T) {
|
|
var err error
|
|
|
|
containers := []ContainerConfig{
|
|
{
|
|
ID: "100",
|
|
},
|
|
{
|
|
ID: "200",
|
|
},
|
|
}
|
|
|
|
sandboxConfig := &SandboxConfig{
|
|
Containers: containers,
|
|
}
|
|
|
|
fs := &filesystem{}
|
|
sandbox := &Sandbox{
|
|
id: testSandboxID,
|
|
config: sandboxConfig,
|
|
storage: fs,
|
|
}
|
|
|
|
for _, c := range containers {
|
|
path := filepath.Join(runStoragePath, testSandboxID, c.ID)
|
|
err = os.MkdirAll(path, dirMode)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
stateFilePath := filepath.Join(path, stateFile)
|
|
|
|
os.Remove(stateFilePath)
|
|
|
|
_, err = os.Create(stateFilePath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, err = os.Stat(stateFilePath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
err = sandbox.deleteContainersState()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
for _, c := range containers {
|
|
stateFilePath := filepath.Join(runStoragePath, testSandboxID, c.ID, stateFile)
|
|
_, err = os.Stat(stateFilePath)
|
|
if err == nil {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSandboxDeleteContainersStateFailingEmptySandboxID(t *testing.T) {
|
|
containers := []ContainerConfig{
|
|
{
|
|
ID: "100",
|
|
},
|
|
}
|
|
|
|
sandboxConfig := &SandboxConfig{
|
|
Containers: containers,
|
|
}
|
|
|
|
fs := &filesystem{}
|
|
sandbox := &Sandbox{
|
|
config: sandboxConfig,
|
|
storage: fs,
|
|
}
|
|
|
|
err := sandbox.deleteContainersState()
|
|
if err == nil {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func TestGetContainer(t *testing.T) {
|
|
containerIDs := []string{"abc", "123", "xyz", "rgb"}
|
|
containers := map[string]*Container{}
|
|
|
|
for _, id := range containerIDs {
|
|
c := Container{id: id}
|
|
containers[id] = &c
|
|
}
|
|
|
|
sandbox := Sandbox{
|
|
containers: containers,
|
|
}
|
|
|
|
c := sandbox.GetContainer("noid")
|
|
if c != nil {
|
|
t.Fatal()
|
|
}
|
|
|
|
for _, id := range containerIDs {
|
|
c = sandbox.GetContainer(id)
|
|
if c == nil {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGetAllContainers(t *testing.T) {
|
|
containerIDs := []string{"abc", "123", "xyz", "rgb"}
|
|
containers := map[string]*Container{}
|
|
|
|
for _, id := range containerIDs {
|
|
c := &Container{id: id}
|
|
containers[id] = c
|
|
}
|
|
|
|
sandbox := Sandbox{
|
|
containers: containers,
|
|
}
|
|
|
|
list := sandbox.GetAllContainers()
|
|
|
|
for _, c := range list {
|
|
if containers[c.ID()] == nil {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSetAnnotations(t *testing.T) {
|
|
sandbox := Sandbox{
|
|
id: "abcxyz123",
|
|
storage: &filesystem{},
|
|
annotationsLock: &sync.RWMutex{},
|
|
config: &SandboxConfig{
|
|
Annotations: map[string]string{
|
|
"annotation1": "abc",
|
|
},
|
|
},
|
|
}
|
|
|
|
keyAnnotation := "annotation2"
|
|
valueAnnotation := "xyz"
|
|
newAnnotations := map[string]string{
|
|
keyAnnotation: valueAnnotation,
|
|
}
|
|
|
|
// Add a new annotation
|
|
sandbox.SetAnnotations(newAnnotations)
|
|
|
|
v, err := sandbox.Annotations(keyAnnotation)
|
|
if err != nil {
|
|
t.Fatal()
|
|
}
|
|
|
|
if v != valueAnnotation {
|
|
t.Fatal()
|
|
}
|
|
|
|
//Change the value of an annotation
|
|
valueAnnotation = "123"
|
|
newAnnotations[keyAnnotation] = valueAnnotation
|
|
|
|
sandbox.SetAnnotations(newAnnotations)
|
|
|
|
v, err = sandbox.Annotations(keyAnnotation)
|
|
if err != nil {
|
|
t.Fatal()
|
|
}
|
|
|
|
if v != valueAnnotation {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func TestSandboxGetContainer(t *testing.T) {
|
|
|
|
emptySandbox := Sandbox{}
|
|
_, err := emptySandbox.findContainer("")
|
|
if err == nil {
|
|
t.Fatal("Expected error for containerless sandbox")
|
|
}
|
|
|
|
_, err = emptySandbox.findContainer("foo")
|
|
if err == nil {
|
|
t.Fatal("Expected error for containerless sandbox and invalid containerID")
|
|
}
|
|
|
|
hConfig := newHypervisorConfig(nil, nil)
|
|
p, err := testCreateSandbox(t, testSandboxID, MockHypervisor, hConfig, NoopAgentType, NoopNetworkModel, NetworkConfig{}, nil, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer cleanUp()
|
|
|
|
contID := "999"
|
|
contConfig := newTestContainerConfigNoop(contID)
|
|
newContainer, err := createContainer(p, contConfig)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create container %+v in sandbox %+v: %v", contConfig, p, err)
|
|
}
|
|
|
|
if err := p.addContainer(newContainer); err != nil {
|
|
t.Fatalf("Could not add container to sandbox %v", err)
|
|
}
|
|
|
|
got := false
|
|
for _, c := range p.GetAllContainers() {
|
|
c2, err := p.findContainer(c.ID())
|
|
if err != nil {
|
|
t.Fatalf("Failed to find container %v: %v", c.ID(), err)
|
|
}
|
|
|
|
if c2.ID() != c.ID() {
|
|
t.Fatalf("Expected container %v but got %v", c.ID(), c2.ID())
|
|
}
|
|
|
|
if c2.ID() == contID {
|
|
got = true
|
|
}
|
|
}
|
|
|
|
if !got {
|
|
t.Fatalf("Failed to find container %v", contID)
|
|
}
|
|
}
|
|
|
|
func TestContainerSetStateBlockIndex(t *testing.T) {
|
|
containers := []ContainerConfig{
|
|
{
|
|
ID: "100",
|
|
},
|
|
}
|
|
|
|
hConfig := newHypervisorConfig(nil, nil)
|
|
sandbox, err := testCreateSandbox(t, testSandboxID, MockHypervisor, hConfig, NoopAgentType, NoopNetworkModel, NetworkConfig{}, containers, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer cleanUp()
|
|
|
|
fs := &filesystem{}
|
|
sandbox.storage = fs
|
|
|
|
c := sandbox.GetContainer("100")
|
|
if c == nil {
|
|
t.Fatal()
|
|
}
|
|
|
|
path := filepath.Join(runStoragePath, testSandboxID, c.ID())
|
|
err = os.MkdirAll(path, dirMode)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
stateFilePath := filepath.Join(path, stateFile)
|
|
|
|
os.Remove(stateFilePath)
|
|
|
|
f, err := os.Create(stateFilePath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
state := State{
|
|
State: "stopped",
|
|
Fstype: "vfs",
|
|
}
|
|
|
|
cImpl, ok := c.(*Container)
|
|
assert.True(t, ok)
|
|
|
|
cImpl.state = state
|
|
|
|
stateData := `{
|
|
"state":"stopped",
|
|
"fstype":"vfs"
|
|
}`
|
|
|
|
n, err := f.WriteString(stateData)
|
|
if err != nil || n != len(stateData) {
|
|
f.Close()
|
|
t.Fatal()
|
|
}
|
|
f.Close()
|
|
|
|
_, err = os.Stat(stateFilePath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
newIndex := 20
|
|
if err := cImpl.setStateBlockIndex(newIndex); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if cImpl.state.BlockIndex != newIndex {
|
|
t.Fatal()
|
|
}
|
|
|
|
fileData, err := ioutil.ReadFile(stateFilePath)
|
|
if err != nil {
|
|
t.Fatal()
|
|
}
|
|
|
|
var res State
|
|
err = json.Unmarshal([]byte(string(fileData)), &res)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if res.BlockIndex != newIndex {
|
|
t.Fatal()
|
|
}
|
|
|
|
if res.Fstype != state.Fstype {
|
|
t.Fatal()
|
|
}
|
|
|
|
if res.State != state.State {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func TestContainerStateSetFstype(t *testing.T) {
|
|
var err error
|
|
|
|
containers := []ContainerConfig{
|
|
{
|
|
ID: "100",
|
|
},
|
|
}
|
|
|
|
hConfig := newHypervisorConfig(nil, nil)
|
|
sandbox, err := testCreateSandbox(t, testSandboxID, MockHypervisor, hConfig, NoopAgentType, NoopNetworkModel, NetworkConfig{}, containers, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer cleanUp()
|
|
|
|
fs := &filesystem{}
|
|
sandbox.storage = fs
|
|
|
|
c := sandbox.GetContainer("100")
|
|
if c == nil {
|
|
t.Fatal()
|
|
}
|
|
|
|
path := filepath.Join(runStoragePath, testSandboxID, c.ID())
|
|
err = os.MkdirAll(path, dirMode)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
stateFilePath := filepath.Join(path, stateFile)
|
|
os.Remove(stateFilePath)
|
|
|
|
f, err := os.Create(stateFilePath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
state := State{
|
|
State: "ready",
|
|
Fstype: "vfs",
|
|
BlockIndex: 3,
|
|
}
|
|
|
|
cImpl, ok := c.(*Container)
|
|
assert.True(t, ok)
|
|
|
|
cImpl.state = state
|
|
|
|
stateData := `{
|
|
"state":"ready",
|
|
"fstype":"vfs",
|
|
"blockIndex": 3
|
|
}`
|
|
|
|
n, err := f.WriteString(stateData)
|
|
if err != nil || n != len(stateData) {
|
|
f.Close()
|
|
t.Fatal()
|
|
}
|
|
f.Close()
|
|
|
|
_, err = os.Stat(stateFilePath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
newFstype := "ext4"
|
|
if err := cImpl.setStateFstype(newFstype); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if cImpl.state.Fstype != newFstype {
|
|
t.Fatal()
|
|
}
|
|
|
|
fileData, err := ioutil.ReadFile(stateFilePath)
|
|
if err != nil {
|
|
t.Fatal()
|
|
}
|
|
|
|
var res State
|
|
err = json.Unmarshal([]byte(string(fileData)), &res)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if res.Fstype != newFstype {
|
|
t.Fatal()
|
|
}
|
|
|
|
if res.BlockIndex != state.BlockIndex {
|
|
t.Fatal()
|
|
}
|
|
|
|
if res.State != state.State {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
const vfioPath = "/dev/vfio/"
|
|
|
|
func TestSandboxAttachDevicesVFIO(t *testing.T) {
|
|
tmpDir, err := ioutil.TempDir("", "")
|
|
assert.Nil(t, err)
|
|
os.RemoveAll(tmpDir)
|
|
|
|
testFDIOGroup := "2"
|
|
testDeviceBDFPath := "0000:00:1c.0"
|
|
|
|
devicesDir := filepath.Join(tmpDir, testFDIOGroup, "devices")
|
|
err = os.MkdirAll(devicesDir, dirMode)
|
|
assert.Nil(t, err)
|
|
|
|
deviceFile := filepath.Join(devicesDir, testDeviceBDFPath)
|
|
_, err = os.Create(deviceFile)
|
|
assert.Nil(t, err)
|
|
|
|
savedIOMMUPath := config.SysIOMMUPath
|
|
config.SysIOMMUPath = tmpDir
|
|
|
|
defer func() {
|
|
config.SysIOMMUPath = savedIOMMUPath
|
|
}()
|
|
|
|
dm := manager.NewDeviceManager(manager.VirtioSCSI, nil)
|
|
path := filepath.Join(vfioPath, testFDIOGroup)
|
|
deviceInfo := config.DeviceInfo{
|
|
HostPath: path,
|
|
ContainerPath: path,
|
|
DevType: "c",
|
|
}
|
|
dev, err := dm.NewDevice(deviceInfo)
|
|
assert.Nil(t, err, "deviceManager.NewDevice return error: %v", err)
|
|
|
|
c := &Container{
|
|
id: "100",
|
|
devices: []ContainerDevice{
|
|
{
|
|
ID: dev.DeviceID(),
|
|
ContainerPath: path,
|
|
},
|
|
},
|
|
}
|
|
|
|
containers := map[string]*Container{}
|
|
containers[c.id] = c
|
|
|
|
sandbox := Sandbox{
|
|
id: "100",
|
|
containers: containers,
|
|
storage: &filesystem{},
|
|
hypervisor: &mockHypervisor{},
|
|
devManager: dm,
|
|
}
|
|
|
|
containers[c.id].sandbox = &sandbox
|
|
err = sandbox.storage.createAllResources(context.Background(), &sandbox)
|
|
assert.Nil(t, err, "Error while create all resources for sandbox")
|
|
|
|
err = sandbox.storeSandboxDevices()
|
|
assert.Nil(t, err, "Error while store sandbox devices %s", err)
|
|
err = containers[c.id].attachDevices()
|
|
assert.Nil(t, err, "Error while attaching devices %s", err)
|
|
|
|
err = containers[c.id].detachDevices()
|
|
assert.Nil(t, err, "Error while detaching devices %s", err)
|
|
}
|
|
|
|
func TestSandboxCreateAssets(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
tmpfile, err := ioutil.TempFile("", "virtcontainers-test-")
|
|
assert.Nil(err)
|
|
|
|
defer func() {
|
|
tmpfile.Close()
|
|
os.Remove(tmpfile.Name()) // clean up
|
|
}()
|
|
|
|
_, err = tmpfile.Write(assetContent)
|
|
assert.Nil(err)
|
|
|
|
originalKernelPath := filepath.Join(testDir, testKernel)
|
|
|
|
hc := HypervisorConfig{
|
|
KernelPath: originalKernelPath,
|
|
ImagePath: filepath.Join(testDir, testImage),
|
|
}
|
|
|
|
p := &SandboxConfig{
|
|
Annotations: map[string]string{
|
|
annotations.KernelPath: tmpfile.Name(),
|
|
annotations.KernelHash: assetContentHash,
|
|
},
|
|
|
|
HypervisorConfig: hc,
|
|
}
|
|
|
|
err = createAssets(context.Background(), p)
|
|
assert.Nil(err)
|
|
|
|
a, ok := p.HypervisorConfig.customAssets[kernelAsset]
|
|
assert.True(ok)
|
|
assert.Equal(a.path, tmpfile.Name())
|
|
|
|
p = &SandboxConfig{
|
|
Annotations: map[string]string{
|
|
annotations.KernelPath: tmpfile.Name(),
|
|
annotations.KernelHash: assetContentWrongHash,
|
|
},
|
|
|
|
HypervisorConfig: hc,
|
|
}
|
|
|
|
err = createAssets(context.Background(), p)
|
|
assert.NotNil(err)
|
|
}
|
|
|
|
func testFindContainerFailure(t *testing.T, sandbox *Sandbox, cid string) {
|
|
c, err := sandbox.findContainer(cid)
|
|
assert.Nil(t, c, "Container pointer should be nil")
|
|
assert.NotNil(t, err, "Should have returned an error")
|
|
}
|
|
|
|
func TestFindContainerSandboxNilFailure(t *testing.T) {
|
|
testFindContainerFailure(t, nil, testContainerID)
|
|
}
|
|
|
|
func TestFindContainerContainerIDEmptyFailure(t *testing.T) {
|
|
sandbox := &Sandbox{}
|
|
testFindContainerFailure(t, sandbox, "")
|
|
}
|
|
|
|
func TestFindContainerNoContainerMatchFailure(t *testing.T) {
|
|
sandbox := &Sandbox{}
|
|
testFindContainerFailure(t, sandbox, testContainerID)
|
|
}
|
|
|
|
func TestFindContainerSuccess(t *testing.T) {
|
|
sandbox := &Sandbox{
|
|
containers: map[string]*Container{
|
|
testContainerID: {id: testContainerID},
|
|
},
|
|
}
|
|
c, err := sandbox.findContainer(testContainerID)
|
|
assert.NotNil(t, c, "Container pointer should not be nil")
|
|
assert.Nil(t, err, "Should not have returned an error: %v", err)
|
|
|
|
assert.True(t, c == sandbox.containers[testContainerID], "Container pointers should point to the same address")
|
|
}
|
|
|
|
func TestRemoveContainerSandboxNilFailure(t *testing.T) {
|
|
testFindContainerFailure(t, nil, testContainerID)
|
|
}
|
|
|
|
func TestRemoveContainerContainerIDEmptyFailure(t *testing.T) {
|
|
sandbox := &Sandbox{}
|
|
testFindContainerFailure(t, sandbox, "")
|
|
}
|
|
|
|
func TestRemoveContainerNoContainerMatchFailure(t *testing.T) {
|
|
sandbox := &Sandbox{}
|
|
testFindContainerFailure(t, sandbox, testContainerID)
|
|
}
|
|
|
|
func TestRemoveContainerSuccess(t *testing.T) {
|
|
sandbox := &Sandbox{
|
|
containers: map[string]*Container{
|
|
testContainerID: {id: testContainerID},
|
|
},
|
|
}
|
|
err := sandbox.removeContainer(testContainerID)
|
|
assert.Nil(t, err, "Should not have returned an error: %v", err)
|
|
|
|
assert.Equal(t, len(sandbox.containers), 0, "Containers list from sandbox structure should be empty")
|
|
}
|
|
|
|
func TestCreateContainer(t *testing.T) {
|
|
s, err := testCreateSandbox(t, testSandboxID, MockHypervisor, newHypervisorConfig(nil, nil), NoopAgentType, NoopNetworkModel, NetworkConfig{}, nil, nil)
|
|
assert.Nil(t, err, "VirtContainers should not allow empty sandboxes")
|
|
defer cleanUp()
|
|
|
|
contID := "999"
|
|
contConfig := newTestContainerConfigNoop(contID)
|
|
_, err = s.CreateContainer(contConfig)
|
|
assert.Nil(t, err, "Failed to create container %+v in sandbox %+v: %v", contConfig, s, err)
|
|
}
|
|
|
|
func TestDeleteContainer(t *testing.T) {
|
|
s, err := testCreateSandbox(t, testSandboxID, MockHypervisor, newHypervisorConfig(nil, nil), NoopAgentType, NoopNetworkModel, NetworkConfig{}, nil, nil)
|
|
assert.Nil(t, err, "VirtContainers should not allow empty sandboxes")
|
|
defer cleanUp()
|
|
|
|
contID := "999"
|
|
_, err = s.DeleteContainer(contID)
|
|
assert.NotNil(t, err, "Deletng non-existing container should fail")
|
|
|
|
contConfig := newTestContainerConfigNoop(contID)
|
|
_, err = s.CreateContainer(contConfig)
|
|
assert.Nil(t, err, "Failed to create container %+v in sandbox %+v: %v", contConfig, s, err)
|
|
|
|
_, err = s.DeleteContainer(contID)
|
|
assert.Nil(t, err, "Failed to delete container %s in sandbox %s: %v", contID, s.ID(), err)
|
|
}
|
|
|
|
func TestStartContainer(t *testing.T) {
|
|
s, err := testCreateSandbox(t, testSandboxID, MockHypervisor, newHypervisorConfig(nil, nil), NoopAgentType, NoopNetworkModel, NetworkConfig{}, nil, nil)
|
|
assert.Nil(t, err, "VirtContainers should not allow empty sandboxes")
|
|
defer cleanUp()
|
|
|
|
contID := "999"
|
|
_, err = s.StartContainer(contID)
|
|
assert.NotNil(t, err, "Starting non-existing container should fail")
|
|
|
|
err = s.start()
|
|
assert.Nil(t, err, "Failed to start sandbox: %v", err)
|
|
|
|
contConfig := newTestContainerConfigNoop(contID)
|
|
_, err = s.CreateContainer(contConfig)
|
|
assert.Nil(t, err, "Failed to create container %+v in sandbox %+v: %v", contConfig, s, err)
|
|
|
|
_, err = s.StartContainer(contID)
|
|
assert.Nil(t, err, "Start container failed: %v", err)
|
|
}
|
|
|
|
func TestStatusContainer(t *testing.T) {
|
|
s, err := testCreateSandbox(t, testSandboxID, MockHypervisor, newHypervisorConfig(nil, nil), NoopAgentType, NoopNetworkModel, NetworkConfig{}, nil, nil)
|
|
assert.Nil(t, err, "VirtContainers should not allow empty sandboxes")
|
|
defer cleanUp()
|
|
|
|
contID := "999"
|
|
_, err = s.StatusContainer(contID)
|
|
assert.NotNil(t, err, "Status non-existing container should fail")
|
|
|
|
contConfig := newTestContainerConfigNoop(contID)
|
|
_, err = s.CreateContainer(contConfig)
|
|
assert.Nil(t, err, "Failed to create container %+v in sandbox %+v: %v", contConfig, s, err)
|
|
|
|
_, err = s.StatusContainer(contID)
|
|
assert.Nil(t, err, "Status container failed: %v", err)
|
|
|
|
_, err = s.DeleteContainer(contID)
|
|
assert.Nil(t, err, "Failed to delete container %s in sandbox %s: %v", contID, s.ID(), err)
|
|
}
|
|
|
|
func TestStatusSandbox(t *testing.T) {
|
|
s, err := testCreateSandbox(t, testSandboxID, MockHypervisor, newHypervisorConfig(nil, nil), NoopAgentType, NoopNetworkModel, NetworkConfig{}, nil, nil)
|
|
assert.Nil(t, err, "VirtContainers should not allow empty sandboxes")
|
|
defer cleanUp()
|
|
|
|
s.Status()
|
|
}
|
|
|
|
func TestEnterContainer(t *testing.T) {
|
|
s, err := testCreateSandbox(t, testSandboxID, MockHypervisor, newHypervisorConfig(nil, nil), NoopAgentType, NoopNetworkModel, NetworkConfig{}, nil, nil)
|
|
assert.Nil(t, err, "VirtContainers should not allow empty sandboxes")
|
|
defer cleanUp()
|
|
|
|
contID := "999"
|
|
cmd := Cmd{}
|
|
_, _, err = s.EnterContainer(contID, cmd)
|
|
assert.NotNil(t, err, "Entering non-existing container should fail")
|
|
|
|
contConfig := newTestContainerConfigNoop(contID)
|
|
_, err = s.CreateContainer(contConfig)
|
|
assert.Nil(t, err, "Failed to create container %+v in sandbox %+v: %v", contConfig, s, err)
|
|
|
|
_, _, err = s.EnterContainer(contID, cmd)
|
|
assert.NotNil(t, err, "Entering non-running container should fail")
|
|
|
|
err = s.start()
|
|
assert.Nil(t, err, "Failed to start sandbox: %v", err)
|
|
|
|
_, _, err = s.EnterContainer(contID, cmd)
|
|
assert.Nil(t, err, "Enter container failed: %v", err)
|
|
}
|
|
|
|
func TestMonitor(t *testing.T) {
|
|
s, err := testCreateSandbox(t, testSandboxID, MockHypervisor, newHypervisorConfig(nil, nil), NoopAgentType, NoopNetworkModel, NetworkConfig{}, nil, nil)
|
|
assert.Nil(t, err, "VirtContainers should not allow empty sandboxes")
|
|
defer cleanUp()
|
|
|
|
_, err = s.Monitor()
|
|
assert.NotNil(t, err, "Monitoring non-running container should fail")
|
|
|
|
err = s.start()
|
|
assert.Nil(t, err, "Failed to start sandbox: %v", err)
|
|
|
|
_, err = s.Monitor()
|
|
assert.Nil(t, err, "Monitor sandbox failed: %v", err)
|
|
|
|
_, err = s.Monitor()
|
|
assert.Nil(t, err, "Monitor sandbox again failed: %v", err)
|
|
|
|
s.monitor.stop()
|
|
}
|
|
|
|
func TestWaitProcess(t *testing.T) {
|
|
s, err := testCreateSandbox(t, testSandboxID, MockHypervisor, newHypervisorConfig(nil, nil), NoopAgentType, NoopNetworkModel, NetworkConfig{}, nil, nil)
|
|
assert.Nil(t, err, "VirtContainers should not allow empty sandboxes")
|
|
defer cleanUp()
|
|
|
|
contID := "foo"
|
|
execID := "bar"
|
|
_, err = s.WaitProcess(contID, execID)
|
|
assert.NotNil(t, err, "Wait process in stopped sandbox should fail")
|
|
|
|
err = s.start()
|
|
assert.Nil(t, err, "Failed to start sandbox: %v", err)
|
|
|
|
_, err = s.WaitProcess(contID, execID)
|
|
assert.NotNil(t, err, "Wait process in non-existing container should fail")
|
|
|
|
contConfig := newTestContainerConfigNoop(contID)
|
|
_, err = s.CreateContainer(contConfig)
|
|
assert.Nil(t, err, "Failed to create container %+v in sandbox %+v: %v", contConfig, s, err)
|
|
|
|
_, err = s.WaitProcess(contID, execID)
|
|
assert.Nil(t, err, "Wait process in ready container failed: %v", err)
|
|
|
|
_, err = s.StartContainer(contID)
|
|
assert.Nil(t, err, "Start container failed: %v", err)
|
|
|
|
_, err = s.WaitProcess(contID, execID)
|
|
assert.Nil(t, err, "Wait process failed: %v", err)
|
|
}
|
|
|
|
func TestSignalProcess(t *testing.T) {
|
|
s, err := testCreateSandbox(t, testSandboxID, MockHypervisor, newHypervisorConfig(nil, nil), NoopAgentType, NoopNetworkModel, NetworkConfig{}, nil, nil)
|
|
assert.Nil(t, err, "VirtContainers should not allow empty sandboxes")
|
|
defer cleanUp()
|
|
|
|
contID := "foo"
|
|
execID := "bar"
|
|
err = s.SignalProcess(contID, execID, syscall.SIGKILL, true)
|
|
assert.NotNil(t, err, "Wait process in stopped sandbox should fail")
|
|
|
|
err = s.start()
|
|
assert.Nil(t, err, "Failed to start sandbox: %v", err)
|
|
|
|
err = s.SignalProcess(contID, execID, syscall.SIGKILL, false)
|
|
assert.NotNil(t, err, "Wait process in non-existing container should fail")
|
|
|
|
contConfig := newTestContainerConfigNoop(contID)
|
|
_, err = s.CreateContainer(contConfig)
|
|
assert.Nil(t, err, "Failed to create container %+v in sandbox %+v: %v", contConfig, s, err)
|
|
|
|
err = s.SignalProcess(contID, execID, syscall.SIGKILL, true)
|
|
assert.Nil(t, err, "Wait process in ready container failed: %v", err)
|
|
|
|
_, err = s.StartContainer(contID)
|
|
assert.Nil(t, err, "Start container failed: %v", err)
|
|
|
|
err = s.SignalProcess(contID, execID, syscall.SIGKILL, false)
|
|
assert.Nil(t, err, "Wait process failed: %v", err)
|
|
}
|
|
|
|
func TestWinsizeProcess(t *testing.T) {
|
|
s, err := testCreateSandbox(t, testSandboxID, MockHypervisor, newHypervisorConfig(nil, nil), NoopAgentType, NoopNetworkModel, NetworkConfig{}, nil, nil)
|
|
assert.Nil(t, err, "VirtContainers should not allow empty sandboxes")
|
|
defer cleanUp()
|
|
|
|
contID := "foo"
|
|
execID := "bar"
|
|
err = s.WinsizeProcess(contID, execID, 100, 200)
|
|
assert.NotNil(t, err, "Winsize process in stopped sandbox should fail")
|
|
|
|
err = s.start()
|
|
assert.Nil(t, err, "Failed to start sandbox: %v", err)
|
|
|
|
err = s.WinsizeProcess(contID, execID, 100, 200)
|
|
assert.NotNil(t, err, "Winsize process in non-existing container should fail")
|
|
|
|
contConfig := newTestContainerConfigNoop(contID)
|
|
_, err = s.CreateContainer(contConfig)
|
|
assert.Nil(t, err, "Failed to create container %+v in sandbox %+v: %v", contConfig, s, err)
|
|
|
|
err = s.WinsizeProcess(contID, execID, 100, 200)
|
|
assert.Nil(t, err, "Winsize process in ready container failed: %v", err)
|
|
|
|
_, err = s.StartContainer(contID)
|
|
assert.Nil(t, err, "Start container failed: %v", err)
|
|
|
|
err = s.WinsizeProcess(contID, execID, 100, 200)
|
|
assert.Nil(t, err, "Winsize process failed: %v", err)
|
|
}
|
|
|
|
func TestContainerProcessIOStream(t *testing.T) {
|
|
s, err := testCreateSandbox(t, testSandboxID, MockHypervisor, newHypervisorConfig(nil, nil), NoopAgentType, NoopNetworkModel, NetworkConfig{}, nil, nil)
|
|
assert.Nil(t, err, "VirtContainers should not allow empty sandboxes")
|
|
defer cleanUp()
|
|
|
|
contID := "foo"
|
|
execID := "bar"
|
|
_, _, _, err = s.IOStream(contID, execID)
|
|
assert.NotNil(t, err, "Winsize process in stopped sandbox should fail")
|
|
|
|
err = s.start()
|
|
assert.Nil(t, err, "Failed to start sandbox: %v", err)
|
|
|
|
_, _, _, err = s.IOStream(contID, execID)
|
|
assert.NotNil(t, err, "Winsize process in non-existing container should fail")
|
|
|
|
contConfig := newTestContainerConfigNoop(contID)
|
|
_, err = s.CreateContainer(contConfig)
|
|
assert.Nil(t, err, "Failed to create container %+v in sandbox %+v: %v", contConfig, s, err)
|
|
|
|
_, _, _, err = s.IOStream(contID, execID)
|
|
assert.Nil(t, err, "Winsize process in ready container failed: %v", err)
|
|
|
|
_, err = s.StartContainer(contID)
|
|
assert.Nil(t, err, "Start container failed: %v", err)
|
|
|
|
_, _, _, err = s.IOStream(contID, execID)
|
|
assert.Nil(t, err, "Winsize process failed: %v", err)
|
|
}
|
|
|
|
func TestAttachBlockDevice(t *testing.T) {
|
|
fs := &filesystem{}
|
|
hypervisor := &mockHypervisor{}
|
|
|
|
hConfig := HypervisorConfig{
|
|
BlockDeviceDriver: VirtioBlock,
|
|
}
|
|
|
|
sconfig := &SandboxConfig{
|
|
HypervisorConfig: hConfig,
|
|
}
|
|
|
|
sandbox := &Sandbox{
|
|
id: testSandboxID,
|
|
storage: fs,
|
|
hypervisor: hypervisor,
|
|
config: sconfig,
|
|
}
|
|
|
|
contID := "100"
|
|
container := Container{
|
|
sandbox: sandbox,
|
|
id: contID,
|
|
}
|
|
|
|
// create state file
|
|
path := filepath.Join(runStoragePath, testSandboxID, container.ID())
|
|
err := os.MkdirAll(path, dirMode)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
defer os.RemoveAll(path)
|
|
|
|
stateFilePath := filepath.Join(path, stateFile)
|
|
os.Remove(stateFilePath)
|
|
|
|
_, err = os.Create(stateFilePath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.Remove(stateFilePath)
|
|
|
|
path = "/dev/hda"
|
|
deviceInfo := config.DeviceInfo{
|
|
HostPath: path,
|
|
ContainerPath: path,
|
|
DevType: "b",
|
|
}
|
|
|
|
dm := manager.NewDeviceManager(VirtioBlock, nil)
|
|
device, err := dm.NewDevice(deviceInfo)
|
|
assert.Nil(t, err)
|
|
_, ok := device.(*drivers.BlockDevice)
|
|
assert.True(t, ok)
|
|
|
|
container.state.State = ""
|
|
err = device.Attach(sandbox)
|
|
assert.Nil(t, err)
|
|
|
|
err = device.Detach(sandbox)
|
|
assert.Nil(t, err)
|
|
|
|
container.state.State = StateReady
|
|
err = device.Attach(sandbox)
|
|
assert.Nil(t, err)
|
|
|
|
err = device.Detach(sandbox)
|
|
assert.Nil(t, err)
|
|
|
|
container.sandbox.config.HypervisorConfig.BlockDeviceDriver = VirtioSCSI
|
|
err = device.Attach(sandbox)
|
|
assert.Nil(t, err)
|
|
|
|
err = device.Detach(sandbox)
|
|
assert.Nil(t, err)
|
|
|
|
container.state.State = StateReady
|
|
err = device.Attach(sandbox)
|
|
assert.Nil(t, err)
|
|
|
|
err = device.Detach(sandbox)
|
|
assert.Nil(t, err)
|
|
}
|
|
|
|
func TestPreAddDevice(t *testing.T) {
|
|
fs := &filesystem{}
|
|
hypervisor := &mockHypervisor{}
|
|
|
|
hConfig := HypervisorConfig{
|
|
BlockDeviceDriver: VirtioBlock,
|
|
}
|
|
|
|
sconfig := &SandboxConfig{
|
|
HypervisorConfig: hConfig,
|
|
}
|
|
|
|
dm := manager.NewDeviceManager(VirtioBlock, nil)
|
|
// create a sandbox first
|
|
sandbox := &Sandbox{
|
|
id: testSandboxID,
|
|
storage: fs,
|
|
hypervisor: hypervisor,
|
|
config: sconfig,
|
|
devManager: dm,
|
|
}
|
|
|
|
contID := "100"
|
|
container := Container{
|
|
sandbox: sandbox,
|
|
id: contID,
|
|
sandboxID: testSandboxID,
|
|
}
|
|
container.state.State = StateReady
|
|
|
|
// create state file
|
|
path := filepath.Join(runStoragePath, testSandboxID, container.ID())
|
|
err := os.MkdirAll(path, dirMode)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
defer os.RemoveAll(path)
|
|
|
|
stateFilePath := filepath.Join(path, stateFile)
|
|
os.Remove(stateFilePath)
|
|
|
|
_, err = os.Create(stateFilePath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.Remove(stateFilePath)
|
|
|
|
path = "/dev/hda"
|
|
deviceInfo := config.DeviceInfo{
|
|
HostPath: path,
|
|
ContainerPath: path,
|
|
DevType: "b",
|
|
}
|
|
|
|
// Add a mount device for a mountpoint before container's creation
|
|
dev, err := sandbox.AddDevice(deviceInfo)
|
|
assert.Nil(t, err)
|
|
|
|
// in Frakti use case, here we will create and start the container
|
|
// which will attach same device twice
|
|
container.mounts = []Mount{
|
|
{
|
|
Destination: path,
|
|
Source: path,
|
|
Type: "bind",
|
|
BlockDeviceID: dev.DeviceID(),
|
|
},
|
|
}
|
|
|
|
mounts, err := container.mountSharedDirMounts("", "")
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, len(mounts), 0,
|
|
"mounts should contain nothing because it only contains a block device")
|
|
}
|
|
|
|
func TestGetNetNs(t *testing.T) {
|
|
s := Sandbox{}
|
|
|
|
expected := ""
|
|
netNs := s.GetNetNs()
|
|
assert.Equal(t, netNs, expected)
|
|
|
|
expected = "/foo/bar/ns/net"
|
|
s.networkNS = NetworkNamespace{
|
|
NetNsPath: expected,
|
|
}
|
|
|
|
netNs = s.GetNetNs()
|
|
assert.Equal(t, netNs, expected)
|
|
}
|
|
|
|
func TestStartNetworkMonitor(t *testing.T) {
|
|
trueBinPath, err := exec.LookPath("true")
|
|
assert.Nil(t, err)
|
|
assert.NotEmpty(t, trueBinPath)
|
|
|
|
s := &Sandbox{
|
|
id: testSandboxID,
|
|
config: &SandboxConfig{
|
|
NetworkConfig: NetworkConfig{
|
|
NetmonConfig: NetmonConfig{
|
|
Path: trueBinPath,
|
|
},
|
|
},
|
|
},
|
|
network: &defNetwork{},
|
|
networkNS: NetworkNamespace{
|
|
NetNsPath: fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), unix.Gettid()),
|
|
},
|
|
}
|
|
|
|
err = s.startNetworkMonitor()
|
|
assert.Nil(t, err)
|
|
}
|