Files
kata-containers/cli/create_test.go
Graham whaley e757a592c1 SPDX: update cli and arch files to use SPDX
Many cli and arch files were using the 'older style' fairly full
Apache license text. The project standard is the shorter SPDX style.
Convert them over.

Fixes: #225

Signed-off-by: Graham whaley <graham.whaley@intel.com>
2018-04-17 17:30:44 +01:00

1189 lines
29 KiB
Go

// Copyright (c) 2017 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
package main
import (
"errors"
"flag"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
vc "github.com/kata-containers/runtime/virtcontainers"
"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
"github.com/kata-containers/runtime/virtcontainers/pkg/vcmock"
specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/stretchr/testify/assert"
"github.com/urfave/cli"
)
const (
testPID = 100
testConsole = "/dev/pts/999"
testContainerTypeAnnotation = "io.kubernetes.cri-o.ContainerType"
testSandboxIDAnnotation = "io.kubernetes.cri-o.SandboxID"
testContainerTypeSandbox = "sandbox"
testContainerTypeContainer = "container"
)
var testStrPID = fmt.Sprintf("%d", testPID)
func mockCPUSetContent(contents map[string]string) error {
for filePath, data := range contents {
if err := writeFile(filePath, data, testFileMode); err != nil {
return err
}
}
return nil
}
func testCreateCgroupsFilesSuccessful(t *testing.T, cgroupsDirPath string, cgroupsPathList []string, pid int) {
if err := createCgroupsFiles("foo", cgroupsDirPath, cgroupsPathList, pid); err != nil {
t.Fatalf("This test should succeed (cgroupsPath %q, pid %d): %s", cgroupsPathList, pid, err)
}
}
// return the value of the *last* param with the specified key
func findLastParam(key string, params []vc.Param) (string, error) {
if key == "" {
return "", errors.New("ERROR: need non-nil key")
}
l := len(params)
if l == 0 {
return "", errors.New("ERROR: no params")
}
for i := l - 1; i >= 0; i-- {
p := params[i]
if key == p.Key {
return p.Value, nil
}
}
return "", fmt.Errorf("no param called %q found", name)
}
func TestCgroupsFilesEmptyCgroupsPathSuccessful(t *testing.T) {
testCreateCgroupsFilesSuccessful(t, "", []string{}, testPID)
}
func TestCreateCgroupsFilesFailToWriteFile(t *testing.T) {
if os.Geteuid() == 0 {
// The os.FileMode(0000) trick doesn't work for root.
t.Skip(testDisabledNeedNonRoot)
}
assert := assert.New(t)
tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
defer os.RemoveAll(tmpdir)
// create the file as a directory to force an error
file := filepath.Join(tmpdir, "cgroups-file")
err = os.MkdirAll(file, os.FileMode(0000))
assert.NoError(err)
files := []string{file}
err = createCgroupsFiles("foo", "cgroups-file", files, testPID)
assert.Error(err)
}
func TestCgroupsFilesNonEmptyCgroupsPathSuccessful(t *testing.T) {
cgroupsPath, err := ioutil.TempDir(testDir, "cgroups-path-")
if err != nil {
t.Fatalf("Could not create temporary cgroups directory: %s", err)
}
testCreateCgroupsFilesSuccessful(t, "cgroups-path-", []string{cgroupsPath}, testPID)
defer os.RemoveAll(cgroupsPath)
tasksPath := filepath.Join(cgroupsPath, cgroupsTasksFile)
procsPath := filepath.Join(cgroupsPath, cgroupsProcsFile)
for _, path := range []string{tasksPath, procsPath} {
if _, err := os.Stat(path); err != nil {
t.Fatalf("Path %q should have been created: %s", path, err)
}
fileBytes, err := ioutil.ReadFile(path)
if err != nil {
t.Fatalf("Could not read %q previously created: %s", path, err)
}
if string(fileBytes) != testStrPID {
t.Fatalf("PID %s read from %q different from expected PID %s", string(fileBytes), path, testStrPID)
}
}
}
func TestCreatePIDFileSuccessful(t *testing.T) {
pidDirPath, err := ioutil.TempDir(testDir, "pid-path-")
if err != nil {
t.Fatalf("Could not create temporary PID directory: %s", err)
}
pidFilePath := filepath.Join(pidDirPath, "pid-file-path")
if err := createPIDFile(pidFilePath, testPID); err != nil {
t.Fatal(err)
}
fileBytes, err := ioutil.ReadFile(pidFilePath)
if err != nil {
os.RemoveAll(pidFilePath)
t.Fatalf("Could not read %q: %s", pidFilePath, err)
}
if string(fileBytes) != testStrPID {
os.RemoveAll(pidFilePath)
t.Fatalf("PID %s read from %q different from expected PID %s", string(fileBytes), pidFilePath, testStrPID)
}
os.RemoveAll(pidFilePath)
}
func TestCreatePIDFileEmptyPathSuccessful(t *testing.T) {
file := ""
if err := createPIDFile(file, testPID); err != nil {
t.Fatalf("This test should not fail (pidFilePath %q, pid %d)", file, testPID)
}
}
func TestCreatePIDFileUnableToRemove(t *testing.T) {
if os.Geteuid() == 0 {
// The os.FileMode(0000) trick doesn't work for root.
t.Skip(testDisabledNeedNonRoot)
}
assert := assert.New(t)
tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
defer os.RemoveAll(tmpdir)
subdir := filepath.Join(tmpdir, "dir")
file := filepath.Join(subdir, "pidfile")
// stop non-root user from removing the directory later
err = os.MkdirAll(subdir, os.FileMode(0000))
assert.NoError(err)
err = createPIDFile(file, testPID)
assert.Error(err)
// let it be deleted
os.Chmod(subdir, testDirMode)
}
func TestCreatePIDFileUnableToCreate(t *testing.T) {
assert := assert.New(t)
tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
defer os.RemoveAll(tmpdir)
subdir := filepath.Join(tmpdir, "dir")
file := filepath.Join(subdir, "pidfile")
err = createPIDFile(file, testPID)
// subdir doesn't exist
assert.Error(err)
os.Chmod(subdir, testDirMode)
}
func TestCreateCLIFunctionNoRuntimeConfig(t *testing.T) {
assert := assert.New(t)
app := cli.NewApp()
ctx := cli.NewContext(app, nil, nil)
app.Name = "foo"
ctx.App.Metadata = map[string]interface{}{
"foo": "bar",
}
fn, ok := createCLICommand.Action.(func(context *cli.Context) error)
assert.True(ok)
err := fn(ctx)
// no runtime config in the Metadata
assert.Error(err)
}
func TestCreateCLIFunctionSetupConsoleFail(t *testing.T) {
assert := assert.New(t)
tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
defer os.RemoveAll(tmpdir)
runtimeConfig, err := newTestRuntimeConfig(tmpdir, testConsole, true)
assert.NoError(err)
subdir := filepath.Join(tmpdir, "dir")
// does not exist
consoleSocketPath := filepath.Join(subdir, "console")
set := flag.NewFlagSet("", 0)
set.String("console-socket", consoleSocketPath, "")
app := cli.NewApp()
ctx := cli.NewContext(app, set, nil)
app.Name = "foo"
ctx.App.Metadata = map[string]interface{}{
"runtimeConfig": runtimeConfig,
}
fn, ok := createCLICommand.Action.(func(context *cli.Context) error)
assert.True(ok)
err = fn(ctx)
// failed to setup console
assert.Error(err)
}
func TestCreateCLIFunctionCreateFail(t *testing.T) {
assert := assert.New(t)
tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
defer os.RemoveAll(tmpdir)
runtimeConfig, err := newTestRuntimeConfig(tmpdir, testConsole, true)
assert.NoError(err)
set := flag.NewFlagSet("", 0)
set.String("console-socket", "", "")
app := cli.NewApp()
ctx := cli.NewContext(app, set, nil)
app.Name = "foo"
ctx.App.Metadata = map[string]interface{}{
"runtimeConfig": runtimeConfig,
}
fn, ok := createCLICommand.Action.(func(context *cli.Context) error)
assert.True(ok)
err = fn(ctx)
// create() failed
assert.Error(err)
}
func TestCreateInvalidArgs(t *testing.T) {
assert := assert.New(t)
sandbox := &vcmock.Sandbox{
MockID: testSandboxID,
MockContainers: []*vcmock.Container{
{MockID: testContainerID},
{MockID: testContainerID},
{MockID: testContainerID},
},
}
testingImpl.CreateSandboxFunc = func(sandboxConfig vc.SandboxConfig) (vc.VCSandbox, error) {
return sandbox, nil
}
testingImpl.ListSandboxFunc = func() ([]vc.SandboxStatus, error) {
// No pre-existing sandboxes
return []vc.SandboxStatus{}, nil
}
defer func() {
testingImpl.CreateSandboxFunc = nil
testingImpl.ListSandboxFunc = nil
}()
tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
defer os.RemoveAll(tmpdir)
runtimeConfig, err := newTestRuntimeConfig(tmpdir, testConsole, true)
assert.NoError(err)
bundlePath := filepath.Join(tmpdir, "bundle")
err = makeOCIBundle(bundlePath)
assert.NoError(err)
pidFilePath := filepath.Join(tmpdir, "pidfile.txt")
type testData struct {
containerID string
bundlePath string
console string
pidFilePath string
detach bool
runtimeConfig oci.RuntimeConfig
}
data := []testData{
{"", "", "", "", false, oci.RuntimeConfig{}},
{"", "", "", "", true, oci.RuntimeConfig{}},
{"foo", "", "", "", true, oci.RuntimeConfig{}},
{testContainerID, bundlePath, testConsole, pidFilePath, false, runtimeConfig},
{testContainerID, bundlePath, testConsole, pidFilePath, true, runtimeConfig},
}
for i, d := range data {
err := create(d.containerID, d.bundlePath, d.console, d.pidFilePath, d.detach, d.runtimeConfig)
assert.Errorf(err, "test %d (%+v)", i, d)
}
}
func TestCreateInvalidConfigJSON(t *testing.T) {
assert := assert.New(t)
testingImpl.ListSandboxFunc = func() ([]vc.SandboxStatus, error) {
// No pre-existing sandboxes
return []vc.SandboxStatus{}, nil
}
defer func() {
testingImpl.ListSandboxFunc = nil
}()
tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
defer os.RemoveAll(tmpdir)
runtimeConfig, err := newTestRuntimeConfig(tmpdir, testConsole, true)
assert.NoError(err)
bundlePath := filepath.Join(tmpdir, "bundle")
err = makeOCIBundle(bundlePath)
assert.NoError(err)
pidFilePath := filepath.Join(tmpdir, "pidfile.txt")
ociConfigFile := filepath.Join(bundlePath, "config.json")
assert.True(fileExists(ociConfigFile))
f, err := os.OpenFile(ociConfigFile, os.O_APPEND|os.O_WRONLY, testFileMode)
assert.NoError(err)
// invalidate the JSON
_, err = f.WriteString("{")
assert.NoError(err)
f.Close()
for detach := range []bool{true, false} {
err := create(testContainerID, bundlePath, testConsole, pidFilePath, true, runtimeConfig)
assert.Errorf(err, "%+v", detach)
assert.False(vcmock.IsMockError(err))
}
}
func TestCreateInvalidContainerType(t *testing.T) {
assert := assert.New(t)
testingImpl.ListSandboxFunc = func() ([]vc.SandboxStatus, error) {
// No pre-existing sandboxes
return []vc.SandboxStatus{}, nil
}
defer func() {
testingImpl.ListSandboxFunc = nil
}()
tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
defer os.RemoveAll(tmpdir)
runtimeConfig, err := newTestRuntimeConfig(tmpdir, testConsole, true)
assert.NoError(err)
bundlePath := filepath.Join(tmpdir, "bundle")
err = makeOCIBundle(bundlePath)
assert.NoError(err)
pidFilePath := filepath.Join(tmpdir, "pidfile.txt")
ociConfigFile := filepath.Join(bundlePath, "config.json")
assert.True(fileExists(ociConfigFile))
spec, err := readOCIConfigFile(ociConfigFile)
assert.NoError(err)
// Force an invalid container type
spec.Annotations = make(map[string]string)
spec.Annotations[testContainerTypeAnnotation] = "I-am-not-a-valid-container-type"
// rewrite the file
err = writeOCIConfigFile(spec, ociConfigFile)
assert.NoError(err)
for detach := range []bool{true, false} {
err := create(testContainerID, bundlePath, testConsole, pidFilePath, true, runtimeConfig)
assert.Errorf(err, "%+v", detach)
assert.False(vcmock.IsMockError(err))
}
}
func TestCreateContainerInvalid(t *testing.T) {
assert := assert.New(t)
testingImpl.ListSandboxFunc = func() ([]vc.SandboxStatus, error) {
// No pre-existing sandboxes
return []vc.SandboxStatus{}, nil
}
defer func() {
testingImpl.ListSandboxFunc = nil
}()
tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
defer os.RemoveAll(tmpdir)
runtimeConfig, err := newTestRuntimeConfig(tmpdir, testConsole, true)
assert.NoError(err)
bundlePath := filepath.Join(tmpdir, "bundle")
err = makeOCIBundle(bundlePath)
assert.NoError(err)
pidFilePath := filepath.Join(tmpdir, "pidfile.txt")
ociConfigFile := filepath.Join(bundlePath, "config.json")
assert.True(fileExists(ociConfigFile))
spec, err := readOCIConfigFile(ociConfigFile)
assert.NoError(err)
// Force createContainer() to be called.
spec.Annotations = make(map[string]string)
spec.Annotations[testContainerTypeAnnotation] = testContainerTypeContainer
// rewrite the file
err = writeOCIConfigFile(spec, ociConfigFile)
assert.NoError(err)
for detach := range []bool{true, false} {
err := create(testContainerID, bundlePath, testConsole, pidFilePath, true, runtimeConfig)
assert.Errorf(err, "%+v", detach)
assert.False(vcmock.IsMockError(err))
}
}
func TestCreateProcessCgroupsPathSuccessful(t *testing.T) {
assert := assert.New(t)
sandbox := &vcmock.Sandbox{
MockID: testSandboxID,
MockContainers: []*vcmock.Container{
{MockID: testContainerID},
},
}
testingImpl.ListSandboxFunc = func() ([]vc.SandboxStatus, error) {
// No pre-existing sandboxes
return []vc.SandboxStatus{}, nil
}
testingImpl.CreateSandboxFunc = func(sandboxConfig vc.SandboxConfig) (vc.VCSandbox, error) {
return sandbox, nil
}
defer func() {
testingImpl.ListSandboxFunc = nil
testingImpl.CreateSandboxFunc = nil
}()
tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
defer os.RemoveAll(tmpdir)
runtimeConfig, err := newTestRuntimeConfig(tmpdir, testConsole, true)
assert.NoError(err)
bundlePath := filepath.Join(tmpdir, "bundle")
err = makeOCIBundle(bundlePath)
assert.NoError(err)
pidFilePath := filepath.Join(tmpdir, "pidfile.txt")
ociConfigFile := filepath.Join(bundlePath, "config.json")
assert.True(fileExists(ociConfigFile))
spec, err := readOCIConfigFile(ociConfigFile)
assert.NoError(err)
// Force sandbox-type container
spec.Annotations = make(map[string]string)
spec.Annotations[testContainerTypeAnnotation] = testContainerTypeSandbox
// Set a limit to ensure processCgroupsPath() considers the
// cgroup part of the spec
limit := int64(1024 * 1024)
spec.Linux.Resources.Memory = &specs.LinuxMemory{
Limit: &limit,
}
// Set an absolute path
spec.Linux.CgroupsPath = "/this/is/a/cgroup/path"
var mounts []specs.Mount
foundMount := false
// Replace the standard cgroup destination with a temporary one.
for _, mount := range spec.Mounts {
if mount.Type == "cgroup" {
foundMount = true
cgroupDir, err := ioutil.TempDir("", "cgroup")
assert.NoError(err)
defer os.RemoveAll(cgroupDir)
mount.Destination = cgroupDir
}
mounts = append(mounts, mount)
}
assert.True(foundMount)
// Replace mounts with the newly created one.
spec.Mounts = mounts
// Rewrite the file
err = writeOCIConfigFile(spec, ociConfigFile)
assert.NoError(err)
for _, detach := range []bool{true, false} {
err := create(testContainerID, bundlePath, testConsole, pidFilePath, detach, runtimeConfig)
assert.NoError(err, "detached: %+v", detach)
}
}
func TestCreateCreateCgroupsFilesFail(t *testing.T) {
if os.Geteuid() == 0 {
// The os.FileMode(0000) trick doesn't work for root.
t.Skip(testDisabledNeedNonRoot)
}
assert := assert.New(t)
sandbox := &vcmock.Sandbox{
MockID: testSandboxID,
MockContainers: []*vcmock.Container{
{MockID: testContainerID},
},
}
testingImpl.ListSandboxFunc = func() ([]vc.SandboxStatus, error) {
// No pre-existing sandboxes
return []vc.SandboxStatus{}, nil
}
testingImpl.CreateSandboxFunc = func(sandboxConfig vc.SandboxConfig) (vc.VCSandbox, error) {
return sandbox, nil
}
defer func() {
testingImpl.ListSandboxFunc = nil
testingImpl.CreateSandboxFunc = nil
}()
tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
defer os.RemoveAll(tmpdir)
runtimeConfig, err := newTestRuntimeConfig(tmpdir, testConsole, true)
assert.NoError(err)
bundlePath := filepath.Join(tmpdir, "bundle")
err = makeOCIBundle(bundlePath)
assert.NoError(err)
pidFilePath := filepath.Join(tmpdir, "pidfile.txt")
ociConfigFile := filepath.Join(bundlePath, "config.json")
assert.True(fileExists(ociConfigFile))
spec, err := readOCIConfigFile(ociConfigFile)
assert.NoError(err)
// Force sandbox-type container
spec.Annotations = make(map[string]string)
spec.Annotations[testContainerTypeAnnotation] = testContainerTypeSandbox
// Set a limit to ensure processCgroupsPath() considers the
// cgroup part of the spec
limit := int64(1024 * 1024)
spec.Linux.Resources.Memory = &specs.LinuxMemory{
Limit: &limit,
}
// Override
cgroupsDirPath = filepath.Join(tmpdir, "cgroups")
err = os.MkdirAll(cgroupsDirPath, testDirMode)
assert.NoError(err)
// Set a relative path
spec.Linux.CgroupsPath = "./a/relative/path"
dir := filepath.Join(cgroupsDirPath, "memory")
// Stop directory from being created
err = os.MkdirAll(dir, os.FileMode(0000))
assert.NoError(err)
// Rewrite the file
err = writeOCIConfigFile(spec, ociConfigFile)
assert.NoError(err)
for detach := range []bool{true, false} {
err := create(testContainerID, bundlePath, testConsole, pidFilePath, true, runtimeConfig)
assert.Errorf(err, "%+v", detach)
assert.False(vcmock.IsMockError(err))
}
}
func TestCreateCreateCreatePidFileFail(t *testing.T) {
if os.Geteuid() == 0 {
// The os.FileMode(0000) trick doesn't work for root.
t.Skip(testDisabledNeedNonRoot)
}
assert := assert.New(t)
sandbox := &vcmock.Sandbox{
MockID: testSandboxID,
MockContainers: []*vcmock.Container{
{MockID: testContainerID},
},
}
testingImpl.ListSandboxFunc = func() ([]vc.SandboxStatus, error) {
// No pre-existing sandboxes
return []vc.SandboxStatus{}, nil
}
testingImpl.CreateSandboxFunc = func(sandboxConfig vc.SandboxConfig) (vc.VCSandbox, error) {
return sandbox, nil
}
defer func() {
testingImpl.ListSandboxFunc = nil
testingImpl.CreateSandboxFunc = nil
}()
tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
defer os.RemoveAll(tmpdir)
runtimeConfig, err := newTestRuntimeConfig(tmpdir, testConsole, true)
assert.NoError(err)
bundlePath := filepath.Join(tmpdir, "bundle")
err = makeOCIBundle(bundlePath)
assert.NoError(err)
pidDir := filepath.Join(tmpdir, "pid")
pidFilePath := filepath.Join(pidDir, "pidfile.txt")
ociConfigFile := filepath.Join(bundlePath, "config.json")
assert.True(fileExists(ociConfigFile))
spec, err := readOCIConfigFile(ociConfigFile)
assert.NoError(err)
// Force sandbox-type container
spec.Annotations = make(map[string]string)
spec.Annotations[testContainerTypeAnnotation] = testContainerTypeSandbox
// Set a limit to ensure processCgroupsPath() considers the
// cgroup part of the spec
limit := int64(1024 * 1024)
spec.Linux.Resources.Memory = &specs.LinuxMemory{
Limit: &limit,
}
// Rewrite the file
err = writeOCIConfigFile(spec, ociConfigFile)
assert.NoError(err)
// stop the pidfile from being created
err = os.MkdirAll(pidDir, os.FileMode(0000))
assert.NoError(err)
for detach := range []bool{true, false} {
err := create(testContainerID, bundlePath, testConsole, pidFilePath, true, runtimeConfig)
assert.Errorf(err, "%+v", detach)
assert.False(vcmock.IsMockError(err))
}
}
func TestCreate(t *testing.T) {
assert := assert.New(t)
sandbox := &vcmock.Sandbox{
MockID: testSandboxID,
MockContainers: []*vcmock.Container{
{MockID: testContainerID},
},
}
testingImpl.ListSandboxFunc = func() ([]vc.SandboxStatus, error) {
// No pre-existing sandboxes
return []vc.SandboxStatus{}, nil
}
testingImpl.CreateSandboxFunc = func(sandboxConfig vc.SandboxConfig) (vc.VCSandbox, error) {
return sandbox, nil
}
defer func() {
testingImpl.ListSandboxFunc = nil
testingImpl.CreateSandboxFunc = nil
}()
tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
defer os.RemoveAll(tmpdir)
runtimeConfig, err := newTestRuntimeConfig(tmpdir, testConsole, true)
assert.NoError(err)
bundlePath := filepath.Join(tmpdir, "bundle")
err = makeOCIBundle(bundlePath)
assert.NoError(err)
pidFilePath := filepath.Join(tmpdir, "pidfile.txt")
ociConfigFile := filepath.Join(bundlePath, "config.json")
assert.True(fileExists(ociConfigFile))
spec, err := readOCIConfigFile(ociConfigFile)
assert.NoError(err)
// Force sandbox-type container
spec.Annotations = make(map[string]string)
spec.Annotations[testContainerTypeAnnotation] = testContainerTypeSandbox
// Set a limit to ensure processCgroupsPath() considers the
// cgroup part of the spec
limit := int64(1024 * 1024)
spec.Linux.Resources.Memory = &specs.LinuxMemory{
Limit: &limit,
}
// Rewrite the file
err = writeOCIConfigFile(spec, ociConfigFile)
assert.NoError(err)
for detach := range []bool{true, false} {
err := create(testContainerID, bundlePath, testConsole, pidFilePath, true, runtimeConfig)
assert.NoError(err, "%+v", detach)
}
}
func TestCreateInvalidKernelParams(t *testing.T) {
assert := assert.New(t)
testingImpl.ListSandboxFunc = func() ([]vc.SandboxStatus, error) {
// No pre-existing sandboxes
return []vc.SandboxStatus{}, nil
}
defer func() {
testingImpl.ListSandboxFunc = nil
}()
tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
defer os.RemoveAll(tmpdir)
runtimeConfig, err := newTestRuntimeConfig(tmpdir, testConsole, true)
assert.NoError(err)
bundlePath := filepath.Join(tmpdir, "bundle")
err = makeOCIBundle(bundlePath)
assert.NoError(err)
pidFilePath := filepath.Join(tmpdir, "pidfile.txt")
ociConfigFile := filepath.Join(bundlePath, "config.json")
assert.True(fileExists(ociConfigFile))
spec, err := readOCIConfigFile(ociConfigFile)
assert.NoError(err)
// Force createSandbox() to be called.
spec.Annotations = make(map[string]string)
spec.Annotations[testContainerTypeAnnotation] = testContainerTypeSandbox
// rewrite the file
err = writeOCIConfigFile(spec, ociConfigFile)
assert.NoError(err)
savedFunc := getKernelParamsFunc
defer func() {
getKernelParamsFunc = savedFunc
}()
getKernelParamsFunc = func(containerID string, needSystemd bool) []vc.Param {
return []vc.Param{
{
Key: "",
Value: "",
},
}
}
for detach := range []bool{true, false} {
err := create(testContainerID, bundlePath, testConsole, pidFilePath, true, runtimeConfig)
assert.Errorf(err, "%+v", detach)
assert.False(vcmock.IsMockError(err))
}
}
func TestCreateSandboxConfigFail(t *testing.T) {
assert := assert.New(t)
testingImpl.ListSandboxFunc = func() ([]vc.SandboxStatus, error) {
// No pre-existing sandboxes
return []vc.SandboxStatus{}, nil
}
defer func() {
testingImpl.ListSandboxFunc = nil
}()
tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
defer os.RemoveAll(tmpdir)
runtimeConfig, err := newTestRuntimeConfig(tmpdir, testConsole, true)
assert.NoError(err)
bundlePath := filepath.Join(tmpdir, "bundle")
err = makeOCIBundle(bundlePath)
assert.NoError(err)
ociConfigFile := filepath.Join(bundlePath, "config.json")
assert.True(fileExists(ociConfigFile))
spec, err := readOCIConfigFile(ociConfigFile)
assert.NoError(err)
quota := int64(0)
limit := int64(0)
spec.Linux.Resources.Memory = &specs.LinuxMemory{
Limit: &limit,
}
spec.Linux.Resources.CPU = &specs.LinuxCPU{
// specify an invalid value
Quota: &quota,
}
_, err = createSandbox(spec, runtimeConfig, testContainerID, bundlePath, testConsole, true)
assert.Error(err)
assert.False(vcmock.IsMockError(err))
}
func TestCreateCreateSandboxFail(t *testing.T) {
assert := assert.New(t)
testingImpl.ListSandboxFunc = func() ([]vc.SandboxStatus, error) {
// No pre-existing sandboxes
return []vc.SandboxStatus{}, nil
}
defer func() {
testingImpl.ListSandboxFunc = nil
}()
tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
defer os.RemoveAll(tmpdir)
runtimeConfig, err := newTestRuntimeConfig(tmpdir, testConsole, true)
assert.NoError(err)
bundlePath := filepath.Join(tmpdir, "bundle")
err = makeOCIBundle(bundlePath)
assert.NoError(err)
ociConfigFile := filepath.Join(bundlePath, "config.json")
assert.True(fileExists(ociConfigFile))
spec, err := readOCIConfigFile(ociConfigFile)
assert.NoError(err)
_, err = createSandbox(spec, runtimeConfig, testContainerID, bundlePath, testConsole, true)
assert.Error(err)
assert.True(vcmock.IsMockError(err))
}
func TestCreateCreateContainerContainerConfigFail(t *testing.T) {
assert := assert.New(t)
testingImpl.ListSandboxFunc = func() ([]vc.SandboxStatus, error) {
// No pre-existing sandboxes
return []vc.SandboxStatus{}, nil
}
defer func() {
testingImpl.ListSandboxFunc = nil
}()
tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
defer os.RemoveAll(tmpdir)
bundlePath := filepath.Join(tmpdir, "bundle")
err = makeOCIBundle(bundlePath)
assert.NoError(err)
ociConfigFile := filepath.Join(bundlePath, "config.json")
assert.True(fileExists(ociConfigFile))
spec, err := readOCIConfigFile(ociConfigFile)
assert.NoError(err)
// Set invalid container type
containerType := "你好,世界"
spec.Annotations = make(map[string]string)
spec.Annotations[testContainerTypeAnnotation] = containerType
// rewrite file
err = writeOCIConfigFile(spec, ociConfigFile)
assert.NoError(err)
for _, disableOutput := range []bool{true, false} {
_, err = createContainer(spec, testContainerID, bundlePath, testConsole, disableOutput)
assert.Error(err)
assert.False(vcmock.IsMockError(err))
assert.True(strings.Contains(err.Error(), containerType))
}
}
func TestCreateCreateContainerFail(t *testing.T) {
assert := assert.New(t)
testingImpl.ListSandboxFunc = func() ([]vc.SandboxStatus, error) {
// No pre-existing sandboxes
return []vc.SandboxStatus{}, nil
}
defer func() {
testingImpl.ListSandboxFunc = nil
}()
tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
defer os.RemoveAll(tmpdir)
bundlePath := filepath.Join(tmpdir, "bundle")
err = makeOCIBundle(bundlePath)
assert.NoError(err)
ociConfigFile := filepath.Join(bundlePath, "config.json")
assert.True(fileExists(ociConfigFile))
spec, err := readOCIConfigFile(ociConfigFile)
assert.NoError(err)
// set expected container type and sandboxID
spec.Annotations = make(map[string]string)
spec.Annotations[testContainerTypeAnnotation] = testContainerTypeContainer
spec.Annotations[testSandboxIDAnnotation] = testSandboxID
// rewrite file
err = writeOCIConfigFile(spec, ociConfigFile)
assert.NoError(err)
for _, disableOutput := range []bool{true, false} {
_, err = createContainer(spec, testContainerID, bundlePath, testConsole, disableOutput)
assert.Error(err)
assert.True(vcmock.IsMockError(err))
}
}
func TestCreateCreateContainer(t *testing.T) {
assert := assert.New(t)
testingImpl.ListSandboxFunc = func() ([]vc.SandboxStatus, error) {
// No pre-existing sandboxes
return []vc.SandboxStatus{}, nil
}
testingImpl.CreateContainerFunc = func(sandboxID string, containerConfig vc.ContainerConfig) (vc.VCSandbox, vc.VCContainer, error) {
return &vcmock.Sandbox{}, &vcmock.Container{}, nil
}
defer func() {
testingImpl.ListSandboxFunc = nil
testingImpl.CreateContainerFunc = nil
}()
tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
defer os.RemoveAll(tmpdir)
bundlePath := filepath.Join(tmpdir, "bundle")
err = makeOCIBundle(bundlePath)
assert.NoError(err)
ociConfigFile := filepath.Join(bundlePath, "config.json")
assert.True(fileExists(ociConfigFile))
spec, err := readOCIConfigFile(ociConfigFile)
assert.NoError(err)
// set expected container type and sandboxID
spec.Annotations = make(map[string]string)
spec.Annotations[testContainerTypeAnnotation] = testContainerTypeContainer
spec.Annotations[testSandboxIDAnnotation] = testSandboxID
// rewrite file
err = writeOCIConfigFile(spec, ociConfigFile)
assert.NoError(err)
for _, disableOutput := range []bool{true, false} {
_, err = createContainer(spec, testContainerID, bundlePath, testConsole, disableOutput)
assert.NoError(err)
}
}
func TestCopyParentCPUSetFail(t *testing.T) {
assert := assert.New(t)
cgroupsPath, err := ioutil.TempDir(testDir, "cgroups-path-")
assert.NoError(err)
defer os.RemoveAll(cgroupsPath)
err = copyParentCPUSet(cgroupsPath, testDir)
assert.Error(err)
}
func TestCopyParentCPUSetSuccessful(t *testing.T) {
assert := assert.New(t)
cgroupsPath, err := ioutil.TempDir(testDir, "cgroups-path-")
assert.NoError(err)
defer os.RemoveAll(cgroupsPath)
cgroupsSrcPath := filepath.Join(cgroupsPath, "src")
err = os.Mkdir(cgroupsSrcPath, testDirMode)
assert.NoError(err)
err = mockCPUSetContent(map[string]string{
filepath.Join(cgroupsSrcPath, "cpuset.cpus"): "0-1",
filepath.Join(cgroupsSrcPath, "cpuset.mems"): "0-1",
})
assert.NoError(err)
cgroupsDstPath := filepath.Join(cgroupsPath, "dst")
err = os.Mkdir(cgroupsDstPath, testDirMode)
assert.NoError(err)
fd, err := os.Create(filepath.Join(cgroupsDstPath, "cpuset.cpus"))
assert.NoError(err)
fd.Close()
fd, err = os.Create(filepath.Join(cgroupsDstPath, "cpuset.mems"))
assert.NoError(err)
fd.Close()
err = copyParentCPUSet(cgroupsDstPath, cgroupsSrcPath)
assert.NoError(err)
currentCpus, currentMems, err := getCPUSet(cgroupsDstPath)
assert.NoError(err)
assert.False(isEmptyString(currentCpus))
assert.False(isEmptyString(currentMems))
}
func TestSetKernelParams(t *testing.T) {
assert := assert.New(t)
config := oci.RuntimeConfig{}
assert.Empty(config.HypervisorConfig.KernelParams)
err := setKernelParams(testContainerID, &config)
assert.NoError(err)
assert.NotEmpty(config.HypervisorConfig.KernelParams)
}
func TestSetKernelParamsUserOptionTakesPriority(t *testing.T) {
assert := assert.New(t)
initName := "init"
initValue := "/sbin/myinit"
ipName := "ip"
ipValue := "127.0.0.1"
params := []vc.Param{
{Key: initName, Value: initValue},
{Key: ipName, Value: ipValue},
}
hypervisorConfig := vc.HypervisorConfig{
KernelParams: params,
}
// Config containing user-specified kernel parameters
config := oci.RuntimeConfig{
HypervisorConfig: hypervisorConfig,
}
assert.NotEmpty(config.HypervisorConfig.KernelParams)
err := setKernelParams(testContainerID, &config)
assert.NoError(err)
kernelParams := config.HypervisorConfig.KernelParams
init, err := findLastParam(initName, kernelParams)
assert.NoError(err)
assert.Equal(initValue, init)
ip, err := findLastParam(ipName, kernelParams)
assert.NoError(err)
assert.Equal(ipValue, ip)
}