Merge pull request #572 from hyperhq/shimv2

Implement containerd shim v2 API for Kata Containers
This commit is contained in:
Sebastien Boeuf
2018-11-28 16:37:10 +00:00
committed by GitHub
358 changed files with 44605 additions and 1207 deletions

View File

@@ -0,0 +1,15 @@
// Copyright (c) 2018 HyperHQ Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
package main
import (
"github.com/containerd/containerd/runtime/v2/shim"
"github.com/kata-containers/runtime/containerd-shim-v2"
)
func main() {
shim.Run("io.containerd.kata.v2", containerdshim.New)
}

View File

@@ -11,10 +11,9 @@ import (
"errors"
"fmt"
"os"
"strings"
"github.com/kata-containers/runtime/pkg/katautils"
vc "github.com/kata-containers/runtime/virtcontainers"
vf "github.com/kata-containers/runtime/virtcontainers/factory"
"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
"github.com/urfave/cli"
)
@@ -87,44 +86,11 @@ var createCLICommand = cli.Command{
},
}
// Use a variable to allow tests to modify its value
var getKernelParamsFunc = getKernelParams
func handleFactory(ctx context.Context, runtimeConfig oci.RuntimeConfig) {
if !runtimeConfig.FactoryConfig.Template {
return
}
factoryConfig := vf.Config{
Template: true,
VMConfig: vc.VMConfig{
HypervisorType: runtimeConfig.HypervisorType,
HypervisorConfig: runtimeConfig.HypervisorConfig,
AgentType: runtimeConfig.AgentType,
AgentConfig: runtimeConfig.AgentConfig,
},
}
kataLog.WithField("factory", factoryConfig).Info("load vm factory")
f, err := vf.NewFactory(ctx, factoryConfig, true)
if err != nil {
kataLog.WithError(err).Warn("load vm factory failed, about to create new one")
f, err = vf.NewFactory(ctx, factoryConfig, false)
if err != nil {
kataLog.WithError(err).Warn("create vm factory failed")
return
}
}
vci.SetFactory(ctx, f)
}
func create(ctx context.Context, containerID, bundlePath, console, pidFilePath string, detach, systemdCgroup bool,
runtimeConfig oci.RuntimeConfig) error {
var err error
span, ctx := trace(ctx, "create")
span, ctx := katautils.Trace(ctx, "create")
defer span.Finish()
kataLog = kataLog.WithField("container", containerID)
@@ -157,19 +123,19 @@ func create(ctx context.Context, containerID, bundlePath, console, pidFilePath s
return err
}
handleFactory(ctx, runtimeConfig)
katautils.HandleFactory(ctx, vci, &runtimeConfig)
disableOutput := noNeedForOutput(detach, ociSpec.Process.Terminal)
var process vc.Process
switch containerType {
case vc.PodSandbox:
process, err = createSandbox(ctx, ociSpec, runtimeConfig, containerID, bundlePath, console, disableOutput, systemdCgroup)
_, process, err = katautils.CreateSandbox(ctx, vci, ociSpec, runtimeConfig, containerID, bundlePath, console, disableOutput, systemdCgroup, false)
if err != nil {
return err
}
case vc.PodContainer:
process, err = createContainer(ctx, ociSpec, containerID, bundlePath, console, disableOutput)
process, err = katautils.CreateContainer(ctx, vci, nil, ociSpec, containerID, bundlePath, console, disableOutput, false)
if err != nil {
return err
}
@@ -181,184 +147,8 @@ func create(ctx context.Context, containerID, bundlePath, console, pidFilePath s
return createPIDFile(ctx, pidFilePath, process.Pid)
}
var systemdKernelParam = []vc.Param{
{
Key: "init",
Value: "/usr/lib/systemd/systemd",
},
{
Key: "systemd.unit",
Value: systemdUnitName,
},
{
Key: "systemd.mask",
Value: "systemd-networkd.service",
},
{
Key: "systemd.mask",
Value: "systemd-networkd.socket",
},
}
func getKernelParams(needSystemd bool) []vc.Param {
p := []vc.Param{}
if needSystemd {
p = append(p, systemdKernelParam...)
}
return p
}
func needSystemd(config vc.HypervisorConfig) bool {
return config.ImagePath != ""
}
// setKernelParams adds the user-specified kernel parameters (from the
// configuration file) to the defaults so that the former take priority.
func setKernelParams(containerID string, runtimeConfig *oci.RuntimeConfig) error {
defaultKernelParams := getKernelParamsFunc(needSystemd(runtimeConfig.HypervisorConfig))
if runtimeConfig.HypervisorConfig.Debug {
strParams := vc.SerializeParams(defaultKernelParams, "=")
formatted := strings.Join(strParams, " ")
kataLog.WithField("default-kernel-parameters", formatted).Debug()
}
// retrieve the parameters specified in the config file
userKernelParams := runtimeConfig.HypervisorConfig.KernelParams
// reset
runtimeConfig.HypervisorConfig.KernelParams = []vc.Param{}
// first, add default values
for _, p := range defaultKernelParams {
if err := (runtimeConfig).AddKernelParam(p); err != nil {
return err
}
}
// now re-add the user-specified values so that they take priority.
for _, p := range userKernelParams {
if err := (runtimeConfig).AddKernelParam(p); err != nil {
return err
}
}
return nil
}
func createSandbox(ctx context.Context, ociSpec oci.CompatOCISpec, runtimeConfig oci.RuntimeConfig,
containerID, bundlePath, console string, disableOutput, systemdCgroup bool) (vc.Process, error) {
span, ctx := trace(ctx, "createSandbox")
defer span.Finish()
err := setKernelParams(containerID, &runtimeConfig)
if err != nil {
return vc.Process{}, err
}
sandboxConfig, err := oci.SandboxConfig(ociSpec, runtimeConfig, bundlePath, containerID, console, disableOutput, systemdCgroup)
if err != nil {
return vc.Process{}, err
}
// Important to create the network namespace before the sandbox is
// created, because it is not responsible for the creation of the
// netns if it does not exist.
if err := setupNetworkNamespace(&sandboxConfig.NetworkConfig); err != nil {
return vc.Process{}, err
}
// Run pre-start OCI hooks.
err = enterNetNS(sandboxConfig.NetworkConfig.NetNSPath, func() error {
return preStartHooks(ctx, ociSpec, containerID, bundlePath)
})
if err != nil {
return vc.Process{}, err
}
sandbox, err := vci.CreateSandbox(ctx, sandboxConfig)
if err != nil {
return vc.Process{}, err
}
sid := sandbox.ID()
kataLog = kataLog.WithField("sandbox", sid)
setExternalLoggers(ctx, kataLog)
span.SetTag("sandbox", sid)
containers := sandbox.GetAllContainers()
if len(containers) != 1 {
return vc.Process{}, fmt.Errorf("BUG: Container list from sandbox is wrong, expecting only one container, found %d containers", len(containers))
}
if err := addContainerIDMapping(ctx, containerID, sandbox.ID()); err != nil {
return vc.Process{}, err
}
return containers[0].Process(), nil
}
// setEphemeralStorageType sets the mount type to 'ephemeral'
// if the mount source path is provisioned by k8s for ephemeral storage.
// For the given pod ephemeral volume is created only once
// backed by tmpfs inside the VM. For successive containers
// of the same pod the already existing volume is reused.
func setEphemeralStorageType(ociSpec oci.CompatOCISpec) oci.CompatOCISpec {
for idx, mnt := range ociSpec.Mounts {
if IsEphemeralStorage(mnt.Source) {
ociSpec.Mounts[idx].Type = "ephemeral"
}
}
return ociSpec
}
func createContainer(ctx context.Context, ociSpec oci.CompatOCISpec, containerID, bundlePath,
console string, disableOutput bool) (vc.Process, error) {
span, ctx := trace(ctx, "createContainer")
defer span.Finish()
ociSpec = setEphemeralStorageType(ociSpec)
contConfig, err := oci.ContainerConfig(ociSpec, bundlePath, containerID, console, disableOutput)
if err != nil {
return vc.Process{}, err
}
sandboxID, err := ociSpec.SandboxID()
if err != nil {
return vc.Process{}, err
}
kataLog = kataLog.WithField("sandbox", sandboxID)
setExternalLoggers(ctx, kataLog)
span.SetTag("sandbox", sandboxID)
s, c, err := vci.CreateContainer(ctx, sandboxID, contConfig)
if err != nil {
return vc.Process{}, err
}
// Run pre-start OCI hooks.
err = enterNetNS(s.GetNetNs(), func() error {
return preStartHooks(ctx, ociSpec, containerID, bundlePath)
})
if err != nil {
return vc.Process{}, err
}
if err := addContainerIDMapping(ctx, containerID, sandboxID); err != nil {
return vc.Process{}, err
}
return c.Process(), nil
}
func createPIDFile(ctx context.Context, pidFilePath string, pid int) error {
span, _ := trace(ctx, "createPIDFile")
span, _ := katautils.Trace(ctx, "createPIDFile")
defer span.Finish()
if pidFilePath == "" {

View File

@@ -7,16 +7,15 @@ package main
import (
"context"
"errors"
"flag"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"strings"
"testing"
"github.com/kata-containers/runtime/pkg/katautils"
vc "github.com/kata-containers/runtime/virtcontainers"
"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
"github.com/kata-containers/runtime/virtcontainers/pkg/vcmock"
@@ -29,34 +28,14 @@ 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)
// 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)
}
var (
testStrPID = fmt.Sprintf("%d", testPID)
ctrsMapTreePath = "/var/run/kata-containers/containers-mapping"
)
func TestCreatePIDFileSuccessful(t *testing.T) {
pidDirPath, err := ioutil.TempDir(testDir, "pid-path-")
@@ -230,6 +209,7 @@ func TestCreateInvalidArgs(t *testing.T) {
assert.NoError(err)
defer os.RemoveAll(path)
ctrsMapTreePath = path
katautils.SetCtrsMapTreePath(ctrsMapTreePath)
defer func() {
testingImpl.CreateSandboxFunc = nil
@@ -280,6 +260,7 @@ func TestCreateInvalidConfigJSON(t *testing.T) {
assert.NoError(err)
defer os.RemoveAll(path)
ctrsMapTreePath = path
katautils.SetCtrsMapTreePath(ctrsMapTreePath)
tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
@@ -296,7 +277,7 @@ func TestCreateInvalidConfigJSON(t *testing.T) {
pidFilePath := filepath.Join(tmpdir, "pidfile.txt")
ociConfigFile := filepath.Join(bundlePath, "config.json")
assert.True(fileExists(ociConfigFile))
assert.True(katautils.FileExists(ociConfigFile))
f, err := os.OpenFile(ociConfigFile, os.O_APPEND|os.O_WRONLY, testFileMode)
assert.NoError(err)
@@ -321,6 +302,7 @@ func TestCreateInvalidContainerType(t *testing.T) {
assert.NoError(err)
defer os.RemoveAll(path)
ctrsMapTreePath = path
katautils.SetCtrsMapTreePath(ctrsMapTreePath)
tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
@@ -337,7 +319,7 @@ func TestCreateInvalidContainerType(t *testing.T) {
pidFilePath := filepath.Join(tmpdir, "pidfile.txt")
ociConfigFile := filepath.Join(bundlePath, "config.json")
assert.True(fileExists(ociConfigFile))
assert.True(katautils.FileExists(ociConfigFile))
spec, err := readOCIConfigFile(ociConfigFile)
assert.NoError(err)
@@ -365,6 +347,7 @@ func TestCreateContainerInvalid(t *testing.T) {
assert.NoError(err)
defer os.RemoveAll(path)
ctrsMapTreePath = path
katautils.SetCtrsMapTreePath(ctrsMapTreePath)
tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
@@ -381,7 +364,7 @@ func TestCreateContainerInvalid(t *testing.T) {
pidFilePath := filepath.Join(tmpdir, "pidfile.txt")
ociConfigFile := filepath.Join(bundlePath, "config.json")
assert.True(fileExists(ociConfigFile))
assert.True(katautils.FileExists(ociConfigFile))
spec, err := readOCIConfigFile(ociConfigFile)
@@ -421,6 +404,7 @@ func TestCreateProcessCgroupsPathSuccessful(t *testing.T) {
assert.NoError(err)
defer os.RemoveAll(path)
ctrsMapTreePath = path
katautils.SetCtrsMapTreePath(ctrsMapTreePath)
testingImpl.CreateSandboxFunc = func(ctx context.Context, sandboxConfig vc.SandboxConfig) (vc.VCSandbox, error) {
return sandbox, nil
@@ -445,7 +429,7 @@ func TestCreateProcessCgroupsPathSuccessful(t *testing.T) {
pidFilePath := filepath.Join(tmpdir, "pidfile.txt")
ociConfigFile := filepath.Join(bundlePath, "config.json")
assert.True(fileExists(ociConfigFile))
assert.True(katautils.FileExists(ociConfigFile))
spec, err := readOCIConfigFile(ociConfigFile)
assert.NoError(err)
@@ -523,6 +507,7 @@ func TestCreateCreateCgroupsFilesFail(t *testing.T) {
assert.NoError(err)
defer os.RemoveAll(path)
ctrsMapTreePath = path
katautils.SetCtrsMapTreePath(ctrsMapTreePath)
testingImpl.CreateSandboxFunc = func(ctx context.Context, sandboxConfig vc.SandboxConfig) (vc.VCSandbox, error) {
return sandbox, nil
@@ -547,7 +532,7 @@ func TestCreateCreateCgroupsFilesFail(t *testing.T) {
pidFilePath := filepath.Join(tmpdir, "pidfile.txt")
ociConfigFile := filepath.Join(bundlePath, "config.json")
assert.True(fileExists(ociConfigFile))
assert.True(katautils.FileExists(ociConfigFile))
spec, err := readOCIConfigFile(ociConfigFile)
assert.NoError(err)
@@ -608,6 +593,7 @@ func TestCreateCreateCreatePidFileFail(t *testing.T) {
assert.NoError(err)
defer os.RemoveAll(path)
ctrsMapTreePath = path
katautils.SetCtrsMapTreePath(ctrsMapTreePath)
testingImpl.CreateSandboxFunc = func(ctx context.Context, sandboxConfig vc.SandboxConfig) (vc.VCSandbox, error) {
return sandbox, nil
@@ -633,7 +619,7 @@ func TestCreateCreateCreatePidFileFail(t *testing.T) {
pidFilePath := filepath.Join(pidDir, "pidfile.txt")
ociConfigFile := filepath.Join(bundlePath, "config.json")
assert.True(fileExists(ociConfigFile))
assert.True(katautils.FileExists(ociConfigFile))
spec, err := readOCIConfigFile(ociConfigFile)
assert.NoError(err)
@@ -683,6 +669,7 @@ func TestCreate(t *testing.T) {
assert.NoError(err)
defer os.RemoveAll(path)
ctrsMapTreePath = path
katautils.SetCtrsMapTreePath(ctrsMapTreePath)
testingImpl.CreateSandboxFunc = func(ctx context.Context, sandboxConfig vc.SandboxConfig) (vc.VCSandbox, error) {
return sandbox, nil
@@ -707,7 +694,7 @@ func TestCreate(t *testing.T) {
pidFilePath := filepath.Join(tmpdir, "pidfile.txt")
ociConfigFile := filepath.Join(bundlePath, "config.json")
assert.True(fileExists(ociConfigFile))
assert.True(katautils.FileExists(ociConfigFile))
spec, err := readOCIConfigFile(ociConfigFile)
assert.NoError(err)
@@ -741,6 +728,7 @@ func TestCreateInvalidKernelParams(t *testing.T) {
assert.NoError(err)
defer os.RemoveAll(path)
ctrsMapTreePath = path
katautils.SetCtrsMapTreePath(ctrsMapTreePath)
tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
@@ -757,7 +745,7 @@ func TestCreateInvalidKernelParams(t *testing.T) {
pidFilePath := filepath.Join(tmpdir, "pidfile.txt")
ociConfigFile := filepath.Join(bundlePath, "config.json")
assert.True(fileExists(ociConfigFile))
assert.True(katautils.FileExists(ociConfigFile))
spec, err := readOCIConfigFile(ociConfigFile)
assert.NoError(err)
@@ -770,12 +758,12 @@ func TestCreateInvalidKernelParams(t *testing.T) {
err = writeOCIConfigFile(spec, ociConfigFile)
assert.NoError(err)
savedFunc := getKernelParamsFunc
savedFunc := katautils.GetKernelParamsFunc
defer func() {
getKernelParamsFunc = savedFunc
katautils.GetKernelParamsFunc = savedFunc
}()
getKernelParamsFunc = func(needSystemd bool) []vc.Param {
katautils.GetKernelParamsFunc = func(needSystemd bool) []vc.Param {
return []vc.Param{
{
Key: "",
@@ -791,281 +779,3 @@ func TestCreateInvalidKernelParams(t *testing.T) {
os.RemoveAll(path)
}
}
func TestCreateSandboxConfigFail(t *testing.T) {
assert := assert.New(t)
path, err := ioutil.TempDir("", "containers-mapping")
assert.NoError(err)
defer os.RemoveAll(path)
ctrsMapTreePath = path
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(context.Background(), spec, runtimeConfig, testContainerID, bundlePath, testConsole, true, true)
assert.Error(err)
}
func TestCreateCreateSandboxFail(t *testing.T) {
if os.Geteuid() != 0 {
t.Skip(testDisabledNeedNonRoot)
}
assert := assert.New(t)
path, err := ioutil.TempDir("", "containers-mapping")
assert.NoError(err)
defer os.RemoveAll(path)
ctrsMapTreePath = path
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(context.Background(), spec, runtimeConfig, testContainerID, bundlePath, testConsole, true, true)
assert.Error(err)
assert.True(vcmock.IsMockError(err))
}
func TestCreateCreateContainerContainerConfigFail(t *testing.T) {
assert := assert.New(t)
path, err := ioutil.TempDir("", "containers-mapping")
assert.NoError(err)
defer os.RemoveAll(path)
ctrsMapTreePath = path
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(context.Background(), spec, testContainerID, bundlePath, testConsole, disableOutput)
assert.Error(err)
assert.False(vcmock.IsMockError(err))
assert.True(strings.Contains(err.Error(), containerType))
os.RemoveAll(path)
}
}
func TestCreateCreateContainerFail(t *testing.T) {
assert := assert.New(t)
path, err := ioutil.TempDir("", "containers-mapping")
assert.NoError(err)
defer os.RemoveAll(path)
ctrsMapTreePath = path
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(context.Background(), spec, testContainerID, bundlePath, testConsole, disableOutput)
assert.Error(err)
assert.True(vcmock.IsMockError(err))
os.RemoveAll(path)
}
}
func TestSetEphemeralStorageType(t *testing.T) {
assert := assert.New(t)
ociSpec := oci.CompatOCISpec{}
var ociMounts []specs.Mount
mount := specs.Mount{
Source: "/var/lib/kubelet/pods/366c3a77-4869-11e8-b479-507b9ddd5ce4/volumes/kubernetes.io~empty-dir/cache-volume",
}
ociMounts = append(ociMounts, mount)
ociSpec.Mounts = ociMounts
ociSpec = setEphemeralStorageType(ociSpec)
mountType := ociSpec.Mounts[0].Type
assert.Equal(mountType, "ephemeral",
"Unexpected mount type, got %s expected ephemeral", mountType)
}
func TestCreateCreateContainer(t *testing.T) {
assert := assert.New(t)
path, err := ioutil.TempDir("", "containers-mapping")
assert.NoError(err)
defer os.RemoveAll(path)
ctrsMapTreePath = path
testingImpl.CreateContainerFunc = func(ctx context.Context, sandboxID string, containerConfig vc.ContainerConfig) (vc.VCSandbox, vc.VCContainer, error) {
return &vcmock.Sandbox{}, &vcmock.Container{}, nil
}
defer func() {
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(context.Background(), spec, testContainerID, bundlePath, testConsole, disableOutput)
assert.NoError(err)
os.RemoveAll(path)
}
}
func TestSetKernelParams(t *testing.T) {
assert := assert.New(t)
config := oci.RuntimeConfig{}
assert.Empty(config.HypervisorConfig.KernelParams)
err := setKernelParams(testContainerID, &config)
assert.NoError(err)
if needSystemd(config.HypervisorConfig) {
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)
}

View File

@@ -11,6 +11,7 @@ import (
"fmt"
"os"
"github.com/kata-containers/runtime/pkg/katautils"
vc "github.com/kata-containers/runtime/virtcontainers"
vcAnnot "github.com/kata-containers/runtime/virtcontainers/pkg/annotations"
"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
@@ -60,7 +61,7 @@ EXAMPLE:
}
func delete(ctx context.Context, containerID string, force bool) error {
span, ctx := trace(ctx, "delete")
span, ctx := katautils.Trace(ctx, "delete")
defer span.Finish()
kataLog = kataLog.WithField("container", containerID)
@@ -119,15 +120,15 @@ func delete(ctx context.Context, containerID string, force bool) error {
}
// Run post-stop OCI hooks.
if err := postStopHooks(ctx, ociSpec, sandboxID, status.Annotations[vcAnnot.BundlePathKey]); err != nil {
if err := katautils.PostStopHooks(ctx, ociSpec, sandboxID, status.Annotations[vcAnnot.BundlePathKey]); err != nil {
return err
}
return delContainerIDMapping(ctx, containerID)
return katautils.DelContainerIDMapping(ctx, containerID)
}
func deleteSandbox(ctx context.Context, sandboxID string) error {
span, _ := trace(ctx, "deleteSandbox")
span, _ := katautils.Trace(ctx, "deleteSandbox")
defer span.Finish()
status, err := vci.StatusSandbox(ctx, sandboxID)
@@ -149,7 +150,7 @@ func deleteSandbox(ctx context.Context, sandboxID string) error {
}
func deleteContainer(ctx context.Context, sandboxID, containerID string, forceStop bool) error {
span, _ := trace(ctx, "deleteContainer")
span, _ := katautils.Trace(ctx, "deleteContainer")
defer span.Finish()
if forceStop {
@@ -166,7 +167,7 @@ func deleteContainer(ctx context.Context, sandboxID, containerID string, forceSt
}
func removeCgroupsPath(ctx context.Context, containerID string, cgroupsPathList []string) error {
span, _ := trace(ctx, "removeCgroupsPath")
span, _ := katautils.Trace(ctx, "removeCgroupsPath")
defer span.Finish()
if len(cgroupsPathList) == 0 {

View File

@@ -15,6 +15,7 @@ import (
vc "github.com/kata-containers/runtime/virtcontainers"
"github.com/kata-containers/runtime/pkg/katautils"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
)
@@ -141,7 +142,7 @@ information is displayed once every 5 seconds.`,
return err
}
span, _ := trace(ctx, "events")
span, _ := katautils.Trace(ctx, "events")
defer span.Finish()
containerID := context.Args().First()

View File

@@ -14,6 +14,7 @@ import (
"os"
"syscall"
"github.com/kata-containers/runtime/pkg/katautils"
vc "github.com/kata-containers/runtime/virtcontainers"
"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
specs "github.com/opencontainers/runtime-spec/specs-go"
@@ -188,7 +189,7 @@ func generateExecParams(context *cli.Context, specProcess *oci.CompatOCIProcess)
}
func execute(ctx context.Context, context *cli.Context) error {
span, ctx := trace(ctx, "execute")
span, ctx := katautils.Trace(ctx, "execute")
defer span.Finish()
containerID := context.Args().First()

View File

@@ -1,138 +0,0 @@
// Copyright (c) 2018 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
"os"
"os/exec"
"strings"
"syscall"
"time"
"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/opentracing/opentracing-go/log"
"github.com/sirupsen/logrus"
)
// Logger returns a logrus logger appropriate for logging hook messages
func hookLogger() *logrus.Entry {
return kataLog.WithField("subsystem", "hook")
}
func runHook(ctx context.Context, hook specs.Hook, cid, bundlePath string) error {
span, _ := trace(ctx, "hook")
defer span.Finish()
span.SetTag("subsystem", "runHook")
span.LogFields(
log.String("hook-name", hook.Path),
log.String("hook-args", strings.Join(hook.Args, " ")))
state := specs.State{
Pid: os.Getpid(),
Bundle: bundlePath,
ID: cid,
}
stateJSON, err := json.Marshal(state)
if err != nil {
return err
}
var stdout, stderr bytes.Buffer
cmd := &exec.Cmd{
Path: hook.Path,
Args: hook.Args,
Env: hook.Env,
Stdin: bytes.NewReader(stateJSON),
Stdout: &stdout,
Stderr: &stderr,
}
if err := cmd.Start(); err != nil {
return err
}
if hook.Timeout == nil {
if err := cmd.Wait(); err != nil {
return fmt.Errorf("%s: stdout: %s, stderr: %s", err, stdout.String(), stderr.String())
}
} else {
done := make(chan error, 1)
go func() {
done <- cmd.Wait()
close(done)
}()
select {
case err := <-done:
if err != nil {
return fmt.Errorf("%s: stdout: %s, stderr: %s", err, stdout.String(), stderr.String())
}
case <-time.After(time.Duration(*hook.Timeout) * time.Second):
if err := syscall.Kill(cmd.Process.Pid, syscall.SIGKILL); err != nil {
return err
}
return fmt.Errorf("Hook timeout")
}
}
return nil
}
func runHooks(ctx context.Context, hooks []specs.Hook, cid, bundlePath, hookType string) error {
span, _ := trace(ctx, "hooks")
defer span.Finish()
span.SetTag("subsystem", hookType)
for _, hook := range hooks {
if err := runHook(ctx, hook, cid, bundlePath); err != nil {
hookLogger().WithFields(logrus.Fields{
"hook-type": hookType,
"error": err,
}).Error("hook error")
return err
}
}
return nil
}
func preStartHooks(ctx context.Context, spec oci.CompatOCISpec, cid, bundlePath string) error {
// If no hook available, nothing needs to be done.
if spec.Hooks == nil {
return nil
}
return runHooks(ctx, spec.Hooks.Prestart, cid, bundlePath, "pre-start")
}
func postStartHooks(ctx context.Context, spec oci.CompatOCISpec, cid, bundlePath string) error {
// If no hook available, nothing needs to be done.
if spec.Hooks == nil {
return nil
}
return runHooks(ctx, spec.Hooks.Poststart, cid, bundlePath, "post-start")
}
func postStopHooks(ctx context.Context, spec oci.CompatOCISpec, cid, bundlePath string) error {
// If no hook available, nothing needs to be done.
if spec.Hooks == nil {
return nil
}
return runHooks(ctx, spec.Hooks.Poststop, cid, bundlePath, "post-stop")
}

View File

@@ -1,229 +0,0 @@
// Copyright (c) 2018 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
package main
import (
"context"
"os"
"testing"
. "github.com/kata-containers/runtime/virtcontainers/pkg/mock"
"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/stretchr/testify/assert"
)
// Important to keep these values in sync with hook test binary
var testKeyHook = "test-key"
var testContainerIDHook = "test-container-id"
var testControllerIDHook = "test-controller-id"
var testBinHookPath = "/usr/bin/virtcontainers/bin/test/hook"
var testBundlePath = "/test/bundle"
func getMockHookBinPath() string {
if DefaultMockHookBinPath == "" {
return testBinHookPath
}
return DefaultMockHookBinPath
}
func createHook(timeout int) specs.Hook {
to := &timeout
if timeout == 0 {
to = nil
}
return specs.Hook{
Path: getMockHookBinPath(),
Args: []string{testKeyHook, testContainerIDHook, testControllerIDHook},
Env: os.Environ(),
Timeout: to,
}
}
func createWrongHook() specs.Hook {
return specs.Hook{
Path: getMockHookBinPath(),
Args: []string{"wrong-args"},
Env: os.Environ(),
}
}
func TestRunHook(t *testing.T) {
if os.Geteuid() != 0 {
t.Skip(testDisabledNeedNonRoot)
}
assert := assert.New(t)
ctx := context.Background()
// Run with timeout 0
hook := createHook(0)
err := runHook(ctx, hook, testSandboxID, testBundlePath)
assert.NoError(err)
// Run with timeout 1
hook = createHook(1)
err = runHook(ctx, hook, testSandboxID, testBundlePath)
assert.NoError(err)
// Run timeout failure
hook = createHook(1)
hook.Args = append(hook.Args, "2")
err = runHook(ctx, hook, testSandboxID, testBundlePath)
assert.Error(err)
// Failure due to wrong hook
hook = createWrongHook()
err = runHook(ctx, hook, testSandboxID, testBundlePath)
assert.Error(err)
}
func TestPreStartHooks(t *testing.T) {
if os.Geteuid() != 0 {
t.Skip(testDisabledNeedNonRoot)
}
assert := assert.New(t)
ctx := context.Background()
// Hooks field is nil
spec := oci.CompatOCISpec{}
err := preStartHooks(ctx, spec, "", "")
assert.NoError(err)
// Hooks list is empty
spec = oci.CompatOCISpec{
Spec: specs.Spec{
Hooks: &specs.Hooks{},
},
}
err = preStartHooks(ctx, spec, "", "")
assert.NoError(err)
// Run with timeout 0
hook := createHook(0)
spec = oci.CompatOCISpec{
Spec: specs.Spec{
Hooks: &specs.Hooks{
Prestart: []specs.Hook{hook},
},
},
}
err = preStartHooks(ctx, spec, testSandboxID, testBundlePath)
assert.NoError(err)
// Failure due to wrong hook
hook = createWrongHook()
spec = oci.CompatOCISpec{
Spec: specs.Spec{
Hooks: &specs.Hooks{
Prestart: []specs.Hook{hook},
},
},
}
err = preStartHooks(ctx, spec, testSandboxID, testBundlePath)
assert.Error(err)
}
func TestPostStartHooks(t *testing.T) {
if os.Geteuid() != 0 {
t.Skip(testDisabledNeedNonRoot)
}
assert := assert.New(t)
ctx := context.Background()
// Hooks field is nil
spec := oci.CompatOCISpec{}
err := postStartHooks(ctx, spec, "", "")
assert.NoError(err)
// Hooks list is empty
spec = oci.CompatOCISpec{
Spec: specs.Spec{
Hooks: &specs.Hooks{},
},
}
err = postStartHooks(ctx, spec, "", "")
assert.NoError(err)
// Run with timeout 0
hook := createHook(0)
spec = oci.CompatOCISpec{
Spec: specs.Spec{
Hooks: &specs.Hooks{
Poststart: []specs.Hook{hook},
},
},
}
err = postStartHooks(ctx, spec, testSandboxID, testBundlePath)
assert.NoError(err)
// Failure due to wrong hook
hook = createWrongHook()
spec = oci.CompatOCISpec{
Spec: specs.Spec{
Hooks: &specs.Hooks{
Poststart: []specs.Hook{hook},
},
},
}
err = postStartHooks(ctx, spec, testSandboxID, testBundlePath)
assert.Error(err)
}
func TestPostStopHooks(t *testing.T) {
if os.Geteuid() != 0 {
t.Skip(testDisabledNeedNonRoot)
}
assert := assert.New(t)
ctx := context.Background()
// Hooks field is nil
spec := oci.CompatOCISpec{}
err := postStopHooks(ctx, spec, "", "")
assert.NoError(err)
// Hooks list is empty
spec = oci.CompatOCISpec{
Spec: specs.Spec{
Hooks: &specs.Hooks{},
},
}
err = postStopHooks(ctx, spec, "", "")
assert.NoError(err)
// Run with timeout 0
hook := createHook(0)
spec = oci.CompatOCISpec{
Spec: specs.Spec{
Hooks: &specs.Hooks{
Poststop: []specs.Hook{hook},
},
},
}
err = postStopHooks(ctx, spec, testSandboxID, testBundlePath)
assert.NoError(err)
// Failure due to wrong hook
hook = createWrongHook()
spec = oci.CompatOCISpec{
Spec: specs.Spec{
Hooks: &specs.Hooks{
Poststop: []specs.Hook{hook},
},
},
}
err = postStopHooks(ctx, spec, testSandboxID, testBundlePath)
assert.Error(err)
}

View File

@@ -117,7 +117,7 @@ func getCPUFlags(cpuinfo string) string {
func haveKernelModule(module string) bool {
// First, check to see if the module is already loaded
path := filepath.Join(sysModuleDir, module)
if fileExists(path) {
if katautils.FileExists(path) {
return true
}
@@ -289,7 +289,7 @@ var kataCheckCLICommand = cli.Command{
return err
}
span, _ := trace(ctx, "kata-check")
span, _ := katautils.Trace(ctx, "kata-check")
defer span.Finish()
err = setCPUtype()

View File

@@ -15,6 +15,7 @@ import (
"path/filepath"
"testing"
"github.com/kata-containers/runtime/pkg/katautils"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
"github.com/urfave/cli"
@@ -59,7 +60,7 @@ func createModules(assert *assert.Assertions, cpuInfoFile string, moduleData []t
}
err = hostIsVMContainerCapable(details)
if fileExists(cpuInfoFile) {
if katautils.FileExists(cpuInfoFile) {
assert.NoError(err)
} else {
assert.Error(err)

View File

@@ -14,6 +14,7 @@ import (
runtim "runtime"
"github.com/BurntSushi/toml"
"github.com/kata-containers/runtime/pkg/katautils"
vc "github.com/kata-containers/runtime/virtcontainers"
"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
vcUtils "github.com/kata-containers/runtime/virtcontainers/utils"
@@ -276,7 +277,7 @@ func getNetmonInfo(config oci.RuntimeConfig) (NetmonInfo, error) {
}
func getCommandVersion(cmd string) (string, error) {
return runCommand([]string{cmd, "--version"})
return katautils.RunCommand([]string{cmd, "--version"})
}
func getShimInfo(config oci.RuntimeConfig) (ShimInfo, error) {
@@ -456,7 +457,7 @@ var kataEnvCLICommand = cli.Command{
return err
}
span, _ := trace(ctx, "kata-env")
span, _ := katautils.Trace(ctx, "kata-env")
defer span.Finish()
return handleSettings(defaultOutputFile, context)

View File

@@ -196,7 +196,7 @@ func makeRuntimeConfig(prefixDir string) (configFile string, config oci.RuntimeC
return "", oci.RuntimeConfig{}, err
}
_, config, _, err = katautils.LoadConfiguration(configFile, true, false)
_, config, err = katautils.LoadConfiguration(configFile, true, false)
if err != nil {
return "", oci.RuntimeConfig{}, err
}

View File

@@ -12,6 +12,7 @@ import (
"strconv"
"syscall"
"github.com/kata-containers/runtime/pkg/katautils"
vc "github.com/kata-containers/runtime/virtcontainers"
"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
"github.com/sirupsen/logrus"
@@ -97,7 +98,7 @@ var signalList = map[string]syscall.Signal{
}
func kill(ctx context.Context, containerID, signal string, all bool) error {
span, _ := trace(ctx, "kill")
span, _ := katautils.Trace(ctx, "kill")
defer span.Finish()
kataLog = kataLog.WithField("container", containerID)

View File

@@ -19,6 +19,7 @@ import (
"github.com/urfave/cli"
"github.com/kata-containers/runtime/pkg/katautils"
vc "github.com/kata-containers/runtime/virtcontainers"
oci "github.com/kata-containers/runtime/virtcontainers/pkg/oci"
)
@@ -114,7 +115,7 @@ To list containers created using a non-default value for "--root":
return err
}
span, ctx := trace(ctx, "list")
span, ctx := katautils.Trace(ctx, "list")
defer span.Finish()
s, err := getContainers(ctx, context)

View File

@@ -60,9 +60,6 @@ var originalLoggerLevel logrus.Level
var debug = false
// if true, enable opentracing support.
var tracing = false
// if true, coredump when an internal error occurs or a fatal signal is received
var crashOnError = false
@@ -193,7 +190,7 @@ func setupSignalHandler(ctx context.Context) {
}
dieCb := func() {
stopTracing(ctx)
katautils.StopTracing(ctx)
}
go func() {
@@ -229,7 +226,7 @@ func setExternalLoggers(ctx context.Context, logger *logrus.Entry) {
// created.
if opentracing.SpanFromContext(ctx) != nil {
span, ctx = trace(ctx, "setExternalLoggers")
span, ctx = katautils.Trace(ctx, "setExternalLoggers")
defer span.Finish()
}
@@ -307,7 +304,7 @@ func beforeSubcommands(c *cli.Context) error {
katautils.SetConfigOptions(name, defaultRuntimeConfiguration, defaultSysConfRuntimeConfiguration)
configFile, runtimeConfig, tracing, err = katautils.LoadConfiguration(c.GlobalString(configFilePathOption), ignoreLogging, false)
configFile, runtimeConfig, err = katautils.LoadConfiguration(c.GlobalString(configFilePathOption), ignoreLogging, false)
if err != nil {
fatal(err)
}
@@ -360,7 +357,7 @@ func handleShowConfig(context *cli.Context) {
}
func setupTracing(context *cli.Context, rootSpanName string) error {
tracer, err := createTracer(name)
tracer, err := katautils.CreateTracer(name)
if err != nil {
fatal(err)
}
@@ -397,7 +394,7 @@ func afterSubcommands(c *cli.Context) error {
return err
}
stopTracing(ctx)
katautils.StopTracing(ctx)
return nil
}
@@ -546,7 +543,7 @@ func main() {
ctx := context.Background()
dieCb := func() {
stopTracing(ctx)
katautils.StopTracing(ctx)
}
defer signals.HandlePanic(dieCb)

View File

@@ -33,7 +33,6 @@ import (
)
const (
testDisabledNeedRoot = "Test disabled as requires root user"
testDisabledNeedNonRoot = "Test disabled as requires non-root user"
testDirMode = os.FileMode(0750)
testFileMode = os.FileMode(0640)
@@ -90,7 +89,7 @@ func init() {
fmt.Printf("INFO: test directory is %v\n", testDir)
fmt.Printf("INFO: ensuring docker is running\n")
output, err := runCommandFull([]string{"docker", "version"}, true)
output, err := katautils.RunCommandFull([]string{"docker", "version"}, true)
if err != nil {
panic(fmt.Sprintf("ERROR: docker daemon is not installed, not running, or not accessible to current user: %v (error %v)",
output, err))
@@ -101,11 +100,11 @@ func init() {
fmt.Printf("INFO: ensuring required docker image (%v) is available\n", testDockerImage)
// Only hit the network if the image doesn't exist locally
_, err = runCommand([]string{"docker", "inspect", "--type=image", testDockerImage})
_, err = katautils.RunCommand([]string{"docker", "inspect", "--type=image", testDockerImage})
if err == nil {
fmt.Printf("INFO: docker image %v already exists locally\n", testDockerImage)
} else {
_, err = runCommand([]string{"docker", "pull", testDockerImage})
_, err = katautils.RunCommand([]string{"docker", "pull", testDockerImage})
if err != nil {
panic(err)
}
@@ -256,7 +255,7 @@ func createOCIConfig(bundleDir string) error {
return errors.New("BUG: Need bundle directory")
}
if !fileExists(bundleDir) {
if !katautils.FileExists(bundleDir) {
return fmt.Errorf("BUG: Bundle directory %s does not exist", bundleDir)
}
@@ -276,13 +275,13 @@ func createOCIConfig(bundleDir string) error {
return errors.New("Cannot find command to generate OCI config file")
}
_, err := runCommand([]string{configCmd, "spec", "--bundle", bundleDir})
_, err := katautils.RunCommand([]string{configCmd, "spec", "--bundle", bundleDir})
if err != nil {
return err
}
specFile := filepath.Join(bundleDir, specConfig)
if !fileExists(specFile) {
if !katautils.FileExists(specFile) {
return fmt.Errorf("generated OCI config file does not exist: %v", specFile)
}
@@ -297,7 +296,7 @@ func createRootfs(dir string) error {
return err
}
container, err := runCommand([]string{"docker", "create", testDockerImage})
container, err := katautils.RunCommand([]string{"docker", "create", testDockerImage})
if err != nil {
return err
}
@@ -328,7 +327,7 @@ func createRootfs(dir string) error {
}
// Clean up
_, err = runCommand([]string{"docker", "rm", container})
_, err = katautils.RunCommand([]string{"docker", "rm", container})
if err != nil {
return err
}
@@ -346,7 +345,7 @@ func realMakeOCIBundle(bundleDir string) error {
return errors.New("BUG: Need bundle directory")
}
if !fileExists(bundleDir) {
if !katautils.FileExists(bundleDir) {
return fmt.Errorf("BUG: Bundle directory %v does not exist", bundleDir)
}
@@ -396,12 +395,12 @@ func makeOCIBundle(bundleDir string) error {
base := filepath.Dir(bundleDir)
for _, dir := range []string{from, base} {
if !fileExists(dir) {
if !katautils.FileExists(dir) {
return fmt.Errorf("BUG: directory %v should exist", dir)
}
}
output, err := runCommandFull([]string{"cp", "-a", from, to}, true)
output, err := katautils.RunCommandFull([]string{"cp", "-a", from, to}, true)
if err != nil {
return fmt.Errorf("failed to copy test OCI bundle from %v to %v: %v (output: %v)", from, to, err, output)
}
@@ -501,7 +500,7 @@ func TestMakeOCIBundle(t *testing.T) {
assert.NoError(err)
specFile := filepath.Join(bundleDir, specConfig)
assert.True(fileExists(specFile))
assert.True(katautils.FileExists(specFile))
}
func TestCreateOCIConfig(t *testing.T) {
@@ -524,7 +523,7 @@ func TestCreateOCIConfig(t *testing.T) {
assert.NoError(err)
specFile := filepath.Join(bundleDir, specConfig)
assert.True(fileExists(specFile))
assert.True(katautils.FileExists(specFile))
}
func TestCreateRootfs(t *testing.T) {
@@ -535,7 +534,7 @@ func TestCreateRootfs(t *testing.T) {
defer os.RemoveAll(tmpdir)
rootfsDir := filepath.Join(tmpdir, "rootfs")
assert.False(fileExists(rootfsDir))
assert.False(katautils.FileExists(rootfsDir))
err = createRootfs(rootfsDir)
assert.NoError(err)
@@ -543,11 +542,11 @@ func TestCreateRootfs(t *testing.T) {
// non-comprehensive list of expected directories
expectedDirs := []string{"bin", "dev", "etc", "usr", "var"}
assert.True(fileExists(rootfsDir))
assert.True(katautils.FileExists(rootfsDir))
for _, dir := range expectedDirs {
dirPath := filepath.Join(rootfsDir, dir)
assert.True(fileExists(dirPath))
assert.True(katautils.FileExists(dirPath))
}
}
@@ -1122,5 +1121,6 @@ func createTempContainerIDMapping(containerID, sandboxID string) (string, error)
return "", err
}
katautils.SetCtrsMapTreePath(ctrsMapTreePath)
return tmpDir, nil
}

View File

@@ -6,17 +6,11 @@
package main
import (
"bufio"
"context"
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
"golang.org/x/sys/unix"
"github.com/containernetworking/plugins/pkg/ns"
vc "github.com/kata-containers/runtime/virtcontainers"
"github.com/kata-containers/runtime/virtcontainers/pkg/types"
"github.com/sirupsen/logrus"
@@ -233,133 +227,3 @@ func networkListCommand(ctx context.Context, containerID string, opType networkT
}
return err
}
const procMountInfoFile = "/proc/self/mountinfo"
// getNetNsFromBindMount returns the network namespace for the bind-mounted path
func getNetNsFromBindMount(nsPath string, procMountFile string) (string, error) {
netNsMountType := "nsfs"
// Resolve all symlinks in the path as the mountinfo file contains
// resolved paths.
nsPath, err := filepath.EvalSymlinks(nsPath)
if err != nil {
return "", err
}
f, err := os.Open(procMountFile)
if err != nil {
return "", err
}
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
text := scanner.Text()
// Scan the mountinfo file to search for the network namespace path
// This file contains mounts in the eg format:
// "711 26 0:3 net:[4026532009] /run/docker/netns/default rw shared:535 - nsfs nsfs rw"
//
// Reference: https://www.kernel.org/doc/Documentation/filesystems/proc.txt
// We are interested in the first 9 fields of this file,
// to check for the correct mount type.
fields := strings.Split(text, " ")
if len(fields) < 9 {
continue
}
// We check here if the mount type is a network namespace mount type, namely "nsfs"
mountTypeFieldIdx := 8
if fields[mountTypeFieldIdx] != netNsMountType {
continue
}
// This is the mount point/destination for the mount
mntDestIdx := 4
if fields[mntDestIdx] != nsPath {
continue
}
// This is the root/source of the mount
return fields[3], nil
}
return "", nil
}
// hostNetworkingRequested checks if the network namespace requested is the
// same as the current process.
func hostNetworkingRequested(configNetNs string) (bool, error) {
var evalNS, nsPath, currentNsPath string
var err error
// Net namespace provided as "/proc/pid/ns/net" or "/proc/<pid>/task/<tid>/ns/net"
if strings.HasPrefix(configNetNs, "/proc") && strings.HasSuffix(configNetNs, "/ns/net") {
if _, err := os.Stat(configNetNs); err != nil {
return false, err
}
// Here we are trying to resolve the path but it fails because
// namespaces links don't really exist. For this reason, the
// call to EvalSymlinks will fail when it will try to stat the
// resolved path found. As we only care about the path, we can
// retrieve it from the PathError structure.
if _, err = filepath.EvalSymlinks(configNetNs); err != nil {
nsPath = err.(*os.PathError).Path
} else {
return false, fmt.Errorf("Net namespace path %s is not a symlink", configNetNs)
}
_, evalNS = filepath.Split(nsPath)
} else {
// Bind-mounted path provided
evalNS, _ = getNetNsFromBindMount(configNetNs, procMountInfoFile)
}
currentNS := fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), unix.Gettid())
if _, err = filepath.EvalSymlinks(currentNS); err != nil {
currentNsPath = err.(*os.PathError).Path
} else {
return false, fmt.Errorf("Unexpected: Current network namespace path is not a symlink")
}
_, evalCurrentNS := filepath.Split(currentNsPath)
if evalNS == evalCurrentNS {
return true, nil
}
return false, nil
}
func setupNetworkNamespace(config *vc.NetworkConfig) error {
if config.DisableNewNetNs {
kataLog.Info("DisableNewNetNs is on, shim and hypervisor are running in the host netns")
return nil
}
if config.NetNSPath == "" {
n, err := ns.NewNS()
if err != nil {
return err
}
config.NetNSPath = n.Path()
config.NetNsCreated = true
return nil
}
isHostNs, err := hostNetworkingRequested(config.NetNSPath)
if err != nil {
return err
}
if isHostNs {
return fmt.Errorf("Host networking requested, not supported by runtime")
}
return nil
}

View File

@@ -8,16 +8,10 @@ package main
import (
"context"
"flag"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"syscall"
"testing"
"golang.org/x/sys/unix"
"github.com/containernetworking/plugins/pkg/ns"
vc "github.com/kata-containers/runtime/virtcontainers"
"github.com/kata-containers/runtime/virtcontainers/pkg/types"
"github.com/stretchr/testify/assert"
@@ -93,133 +87,3 @@ func TestNetworkCliFunction(t *testing.T) {
f.Close()
execCLICommandFunc(assert, updateRoutesCommand, set, false)
}
func TestGetNetNsFromBindMount(t *testing.T) {
assert := assert.New(t)
tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
defer os.RemoveAll(tmpdir)
mountFile := filepath.Join(tmpdir, "mountInfo")
nsPath := filepath.Join(tmpdir, "ns123")
// Non-existent namespace path
_, err = getNetNsFromBindMount(nsPath, mountFile)
assert.NotNil(err)
tmpNSPath := filepath.Join(tmpdir, "testNetNs")
f, err := os.Create(tmpNSPath)
assert.NoError(err)
defer f.Close()
type testData struct {
contents string
expectedResult string
}
data := []testData{
{fmt.Sprintf("711 26 0:3 net:[4026532008] %s rw shared:535 - nsfs nsfs rw", tmpNSPath), "net:[4026532008]"},
{"711 26 0:3 net:[4026532008] /run/netns/ns123 rw shared:535 - tmpfs tmpfs rw", ""},
{"a a a a a a a - b c d", ""},
{"", ""},
}
for i, d := range data {
err := ioutil.WriteFile(mountFile, []byte(d.contents), 0640)
assert.NoError(err)
path, err := getNetNsFromBindMount(tmpNSPath, mountFile)
assert.NoError(err, fmt.Sprintf("got %q, test data: %+v", path, d))
assert.Equal(d.expectedResult, path, "Test %d, expected %s, got %s", i, d.expectedResult, path)
}
}
func TestHostNetworkingRequested(t *testing.T) {
assert := assert.New(t)
if os.Geteuid() != 0 {
t.Skip(testDisabledNeedRoot)
}
// Network namespace same as the host
selfNsPath := "/proc/self/ns/net"
isHostNs, err := hostNetworkingRequested(selfNsPath)
assert.NoError(err)
assert.True(isHostNs)
// Non-existent netns path
nsPath := "/proc/123456789/ns/net"
_, err = hostNetworkingRequested(nsPath)
assert.Error(err)
// Bind-mounted Netns
tmpdir, err := ioutil.TempDir("", "")
assert.NoError(err)
defer os.RemoveAll(tmpdir)
// Create a bind mount to the current network namespace.
tmpFile := filepath.Join(tmpdir, "testNetNs")
f, err := os.Create(tmpFile)
assert.NoError(err)
defer f.Close()
err = syscall.Mount(selfNsPath, tmpFile, "bind", syscall.MS_BIND, "")
assert.Nil(err)
isHostNs, err = hostNetworkingRequested(tmpFile)
assert.NoError(err)
assert.True(isHostNs)
syscall.Unmount(tmpFile, 0)
}
func TestSetupNetworkNamespace(t *testing.T) {
if os.Geteuid() != 0 {
t.Skip(testDisabledNeedNonRoot)
}
assert := assert.New(t)
// Network namespace same as the host
config := &vc.NetworkConfig{
NetNSPath: "/proc/self/ns/net",
}
err := setupNetworkNamespace(config)
assert.Error(err)
// Non-existent netns path
config = &vc.NetworkConfig{
NetNSPath: "/proc/123456789/ns/net",
}
err = setupNetworkNamespace(config)
assert.Error(err)
// Existent netns path
n, err := ns.NewNS()
assert.NoError(err)
config = &vc.NetworkConfig{
NetNSPath: n.Path(),
}
err = setupNetworkNamespace(config)
assert.NoError(err)
n.Close()
// Empty netns path
config = &vc.NetworkConfig{}
err = setupNetworkNamespace(config)
assert.NoError(err)
n, err = ns.GetNS(config.NetNSPath)
assert.NoError(err)
assert.NotNil(n)
assert.True(config.NetNsCreated)
n.Close()
unix.Unmount(config.NetNSPath, unix.MNT_DETACH)
os.RemoveAll(config.NetNSPath)
// Config with DisableNewNetNs
config = &vc.NetworkConfig{DisableNewNetNs: true}
err = setupNetworkNamespace(config)
assert.NoError(err)
}

View File

@@ -9,15 +9,12 @@ import (
"bufio"
"context"
"fmt"
"io/ioutil"
"net"
"os"
"path/filepath"
goruntime "runtime"
"strings"
"syscall"
"github.com/containernetworking/plugins/pkg/ns"
"github.com/kata-containers/runtime/pkg/katautils"
vc "github.com/kata-containers/runtime/virtcontainers"
"github.com/opencontainers/runc/libcontainer/utils"
@@ -25,8 +22,6 @@ import (
// Contants related to cgroup memory directory
const (
ctrsMappingDirMode = os.FileMode(0750)
// Filesystem type corresponding to CGROUP_SUPER_MAGIC as listed
// here: http://man7.org/linux/man-pages/man2/statfs.2.html
cgroupFsType = 0x27e0eb
@@ -36,8 +31,6 @@ var cgroupsDirPath string
var procMountInfo = "/proc/self/mountinfo"
var ctrsMapTreePath = "/var/run/kata-containers/containers-mapping"
// getContainerInfo returns the container status and its sandbox ID.
func getContainerInfo(ctx context.Context, containerID string) (vc.ContainerStatus, string, error) {
// container ID MUST be provided.
@@ -45,7 +38,7 @@ func getContainerInfo(ctx context.Context, containerID string) (vc.ContainerStat
return vc.ContainerStatus{}, "", fmt.Errorf("Missing container ID")
}
sandboxID, err := fetchContainerIDMapping(containerID)
sandboxID, err := katautils.FetchContainerIDMapping(containerID)
if err != nil {
return vc.ContainerStatus{}, "", err
}
@@ -218,100 +211,3 @@ func getCgroupsDirPath(mountInfoFile string) (string, error) {
return cgroupRootPath, nil
}
// This function assumes it should find only one file inside the container
// ID directory. If there are several files, we could not determine which
// file name corresponds to the sandbox ID associated, and this would throw
// an error.
func fetchContainerIDMapping(containerID string) (string, error) {
if containerID == "" {
return "", fmt.Errorf("Missing container ID")
}
dirPath := filepath.Join(ctrsMapTreePath, containerID)
files, err := ioutil.ReadDir(dirPath)
if err != nil {
if os.IsNotExist(err) {
return "", nil
}
return "", err
}
if len(files) != 1 {
return "", fmt.Errorf("Too many files (%d) in %q", len(files), dirPath)
}
return files[0].Name(), nil
}
func addContainerIDMapping(ctx context.Context, containerID, sandboxID string) error {
span, _ := trace(ctx, "addContainerIDMapping")
defer span.Finish()
if containerID == "" {
return fmt.Errorf("Missing container ID")
}
if sandboxID == "" {
return fmt.Errorf("Missing sandbox ID")
}
parentPath := filepath.Join(ctrsMapTreePath, containerID)
if err := os.RemoveAll(parentPath); err != nil {
return err
}
path := filepath.Join(parentPath, sandboxID)
if err := os.MkdirAll(path, ctrsMappingDirMode); err != nil {
return err
}
return nil
}
func delContainerIDMapping(ctx context.Context, containerID string) error {
span, _ := trace(ctx, "delContainerIDMapping")
defer span.Finish()
if containerID == "" {
return fmt.Errorf("Missing container ID")
}
path := filepath.Join(ctrsMapTreePath, containerID)
return os.RemoveAll(path)
}
// enterNetNS is free from any call to a go routine, and it calls
// into runtime.LockOSThread(), meaning it won't be executed in a
// different thread than the one expected by the caller.
func enterNetNS(netNSPath string, cb func() error) error {
if netNSPath == "" {
return cb()
}
goruntime.LockOSThread()
defer goruntime.UnlockOSThread()
currentNS, err := ns.GetCurrentNS()
if err != nil {
return err
}
defer currentNS.Close()
targetNS, err := ns.GetNS(netNSPath)
if err != nil {
return err
}
if err := targetNS.Set(); err != nil {
return err
}
defer currentNS.Set()
return cb()
}

View File

@@ -317,106 +317,3 @@ func TestGetCgroupsDirPath(t *testing.T) {
assert.Equal(d.expectedResult, path)
}
}
func TestFetchContainerIDMappingContainerIDEmptyFailure(t *testing.T) {
assert := assert.New(t)
sandboxID, err := fetchContainerIDMapping("")
assert.Error(err)
assert.Empty(sandboxID)
}
func TestFetchContainerIDMappingEmptyMappingSuccess(t *testing.T) {
assert := assert.New(t)
path, err := ioutil.TempDir("", "containers-mapping")
assert.NoError(err)
defer os.RemoveAll(path)
ctrsMapTreePath = path
sandboxID, err := fetchContainerIDMapping(testContainerID)
assert.NoError(err)
assert.Empty(sandboxID)
}
func TestFetchContainerIDMappingTooManyFilesFailure(t *testing.T) {
assert := assert.New(t)
path, err := createTempContainerIDMapping(testContainerID, testSandboxID)
assert.NoError(err)
defer os.RemoveAll(path)
err = os.MkdirAll(filepath.Join(ctrsMapTreePath, testContainerID, testSandboxID+"2"), ctrsMappingDirMode)
assert.NoError(err)
sandboxID, err := fetchContainerIDMapping(testContainerID)
assert.Error(err)
assert.Empty(sandboxID)
}
func TestFetchContainerIDMappingSuccess(t *testing.T) {
assert := assert.New(t)
path, err := createTempContainerIDMapping(testContainerID, testSandboxID)
assert.NoError(err)
defer os.RemoveAll(path)
sandboxID, err := fetchContainerIDMapping(testContainerID)
assert.NoError(err)
assert.Equal(sandboxID, testSandboxID)
}
func TestAddContainerIDMappingContainerIDEmptyFailure(t *testing.T) {
assert := assert.New(t)
err := addContainerIDMapping(context.Background(), "", testSandboxID)
assert.Error(err)
}
func TestAddContainerIDMappingSandboxIDEmptyFailure(t *testing.T) {
assert := assert.New(t)
err := addContainerIDMapping(context.Background(), testContainerID, "")
assert.Error(err)
}
func TestAddContainerIDMappingSuccess(t *testing.T) {
assert := assert.New(t)
path, err := ioutil.TempDir("", "containers-mapping")
assert.NoError(err)
defer os.RemoveAll(path)
ctrsMapTreePath = path
_, err = os.Stat(filepath.Join(ctrsMapTreePath, testContainerID, testSandboxID))
assert.True(os.IsNotExist(err))
err = addContainerIDMapping(context.Background(), testContainerID, testSandboxID)
assert.NoError(err)
_, err = os.Stat(filepath.Join(ctrsMapTreePath, testContainerID, testSandboxID))
assert.NoError(err)
}
func TestDelContainerIDMappingContainerIDEmptyFailure(t *testing.T) {
assert := assert.New(t)
err := delContainerIDMapping(context.Background(), "")
assert.Error(err)
}
func TestDelContainerIDMappingSuccess(t *testing.T) {
assert := assert.New(t)
path, err := createTempContainerIDMapping(testContainerID, testSandboxID)
assert.NoError(err)
defer os.RemoveAll(path)
_, err = os.Stat(filepath.Join(ctrsMapTreePath, testContainerID, testSandboxID))
assert.NoError(err)
err = delContainerIDMapping(context.Background(), testContainerID)
assert.NoError(err)
_, err = os.Stat(filepath.Join(ctrsMapTreePath, testContainerID, testSandboxID))
assert.True(os.IsNotExist(err))
}

View File

@@ -9,6 +9,7 @@ package main
import (
"context"
"github.com/kata-containers/runtime/pkg/katautils"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
)
@@ -57,7 +58,7 @@ func toggle(c *cli.Context, pause bool) error {
}
func toggleContainerPause(ctx context.Context, containerID string, pause bool) (err error) {
span, _ := trace(ctx, "pause")
span, _ := katautils.Trace(ctx, "pause")
defer span.Finish()
span.SetTag("pause", pause)

View File

@@ -10,6 +10,7 @@ import (
"context"
"fmt"
"github.com/kata-containers/runtime/pkg/katautils"
vc "github.com/kata-containers/runtime/virtcontainers"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
@@ -50,7 +51,7 @@ var psCLICommand = cli.Command{
}
func ps(ctx context.Context, containerID, format string, args []string) error {
span, _ := trace(ctx, "ps")
span, _ := katautils.Trace(ctx, "ps")
defer span.Finish()
if containerID == "" {

View File

@@ -13,6 +13,7 @@ import (
"os"
"syscall"
"github.com/kata-containers/runtime/pkg/katautils"
"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
"github.com/urfave/cli"
)
@@ -82,7 +83,7 @@ var runCLICommand = cli.Command{
func run(ctx context.Context, containerID, bundle, console, consoleSocket, pidFile string, detach, systemdCgroup bool,
runtimeConfig oci.RuntimeConfig) error {
span, ctx := trace(ctx, "run")
span, ctx := katautils.Trace(ctx, "run")
defer span.Finish()
consolePath, err := setupConsole(console, consoleSocket)

View File

@@ -12,6 +12,7 @@ import (
"io/ioutil"
"os"
"github.com/kata-containers/runtime/pkg/katautils"
"github.com/opencontainers/runc/libcontainer/specconv"
"github.com/urfave/cli"
)
@@ -77,7 +78,7 @@ generate a proper rootless spec file.`,
return err
}
span, _ := trace(ctx, "spec")
span, _ := katautils.Trace(ctx, "spec")
defer span.Finish()
spec := specconv.Example()

View File

@@ -10,6 +10,7 @@ import (
"context"
"fmt"
"github.com/kata-containers/runtime/pkg/katautils"
vc "github.com/kata-containers/runtime/virtcontainers"
vcAnnot "github.com/kata-containers/runtime/virtcontainers/pkg/annotations"
"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
@@ -48,7 +49,7 @@ var startCLICommand = cli.Command{
}
func start(ctx context.Context, containerID string) (vc.VCSandbox, error) {
span, _ := trace(ctx, "start")
span, _ := katautils.Trace(ctx, "start")
defer span.Finish()
kataLog = kataLog.WithField("container", containerID)
@@ -101,8 +102,8 @@ func start(ctx context.Context, containerID string) (vc.VCSandbox, error) {
}
// Run post-start OCI hooks.
err = enterNetNS(sandbox.GetNetNs(), func() error {
return postStartHooks(ctx, ociSpec, sandboxID, status.Annotations[vcAnnot.BundlePathKey])
err = katautils.EnterNetNS(sandbox.GetNetNs(), func() error {
return katautils.PostStartHooks(ctx, ociSpec, sandboxID, status.Annotations[vcAnnot.BundlePathKey])
})
if err != nil {
return nil, err

View File

@@ -13,6 +13,7 @@ import (
"os"
"testing"
"github.com/kata-containers/runtime/pkg/katautils"
vc "github.com/kata-containers/runtime/virtcontainers"
vcAnnotations "github.com/kata-containers/runtime/virtcontainers/pkg/annotations"
"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
@@ -41,7 +42,7 @@ func TestStartInvalidArgs(t *testing.T) {
path, err = ioutil.TempDir("", "containers-mapping")
assert.NoError(err)
defer os.RemoveAll(path)
ctrsMapTreePath = path
katautils.SetCtrsMapTreePath(path)
// Container missing in container mapping
_, err = start(context.Background(), testContainerID)

View File

@@ -12,6 +12,7 @@ import (
"fmt"
"os"
"github.com/kata-containers/runtime/pkg/katautils"
"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
"github.com/urfave/cli"
)
@@ -40,7 +41,7 @@ instance of a container.`,
}
func state(ctx context.Context, containerID string) error {
span, _ := trace(ctx, "state")
span, _ := katautils.Trace(ctx, "state")
defer span.Finish()
kataLog = kataLog.WithField("container", containerID)

View File

@@ -1,89 +0,0 @@
// Copyright (c) 2018 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
package main
import (
"context"
"io"
opentracing "github.com/opentracing/opentracing-go"
"github.com/uber/jaeger-client-go/config"
)
// Implements jaeger-client-go.Logger interface
type traceLogger struct {
}
// tracerCloser contains a copy of the closer returned by createTracer() which
// is used by stopTracing().
var tracerCloser io.Closer
func (t traceLogger) Error(msg string) {
kataLog.Error(msg)
}
func (t traceLogger) Infof(msg string, args ...interface{}) {
kataLog.Infof(msg, args...)
}
func createTracer(name string) (opentracing.Tracer, error) {
cfg := &config.Configuration{
ServiceName: name,
// If tracing is disabled, use a NOP trace implementation
Disabled: !tracing,
// Note that span logging reporter option cannot be enabled as
// it pollutes the output stream which causes (atleast) the
// "state" command to fail under Docker.
Sampler: &config.SamplerConfig{
Type: "const",
Param: 1,
},
}
logger := traceLogger{}
tracer, closer, err := cfg.NewTracer(config.Logger(logger))
if err != nil {
return nil, err
}
// save for stopTracing()'s exclusive use
tracerCloser = closer
// Seems to be essential to ensure non-root spans are logged
opentracing.SetGlobalTracer(tracer)
return tracer, nil
}
// stopTracing() ends all tracing, reporting the spans to the collector.
func stopTracing(ctx context.Context) {
if !tracing {
return
}
span := opentracing.SpanFromContext(ctx)
if span != nil {
span.Finish()
}
// report all possible spans to the collector
tracerCloser.Close()
}
// trace creates a new tracing span based on the specified name and parent
// context.
func trace(parent context.Context, name string) (opentracing.Span, context.Context) {
span, ctx := opentracing.StartSpanFromContext(parent, name)
span.SetTag("source", "runtime")
span.SetTag("component", "cli")
return span, ctx
}

View File

@@ -13,6 +13,7 @@ import (
"strconv"
"github.com/docker/go-units"
"github.com/kata-containers/runtime/pkg/katautils"
vc "github.com/kata-containers/runtime/virtcontainers"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/sirupsen/logrus"
@@ -132,7 +133,7 @@ other options are ignored.
return err
}
span, _ := trace(ctx, "update")
span, _ := katautils.Trace(ctx, "update")
defer span.Finish()
if context.Args().Present() == false {

View File

@@ -8,15 +8,13 @@ package main
import (
"fmt"
"os"
"os/exec"
"strings"
"github.com/kata-containers/runtime/pkg/katautils"
)
const (
unknown = "<<unknown>>"
k8sEmptyDir = "kubernetes.io~empty-dir"
unknown = "<<unknown>>"
)
// variables to allow tests to modify the values
@@ -28,34 +26,6 @@ var (
osReleaseClr = "/usr/lib/os-release"
)
func fileExists(path string) bool {
if _, err := os.Stat(path); os.IsNotExist(err) {
return false
}
return true
}
// IsEphemeralStorage returns true if the given path
// to the storage belongs to kubernetes ephemeral storage
//
// This method depends on a specific path used by k8s
// to detect if it's of type ephemeral. As of now,
// this is a very k8s specific solution that works
// but in future there should be a better way for this
// method to determine if the path is for ephemeral
// volume type
func IsEphemeralStorage(path string) bool {
splitSourceSlice := strings.Split(path, "/")
if len(splitSourceSlice) > 1 {
storageType := splitSourceSlice[len(splitSourceSlice)-2]
if storageType == k8sEmptyDir {
return true
}
}
return false
}
func getKernelVersion() (string, error) {
contents, err := katautils.GetFileContents(procVersion)
if err != nil {
@@ -151,27 +121,3 @@ func genericGetCPUDetails() (vendor, model string, err error) {
return vendor, model, nil
}
// runCommandFull returns the commands space-trimmed standard output and
// error on success. Note that if the command fails, the requested output will
// still be returned, along with an error.
func runCommandFull(args []string, includeStderr bool) (string, error) {
cmd := exec.Command(args[0], args[1:]...)
var err error
var bytes []byte
if includeStderr {
bytes, err = cmd.CombinedOutput()
} else {
bytes, err = cmd.Output()
}
trimmed := strings.TrimSpace(string(bytes))
return trimmed, err
}
// runCommand returns the commands space-trimmed standard output on success
func runCommand(args []string) (string, error) {
return runCommandFull(args, false)
}

View File

@@ -12,6 +12,7 @@ import (
"path/filepath"
"testing"
"github.com/kata-containers/runtime/pkg/katautils"
"github.com/stretchr/testify/assert"
)
@@ -24,7 +25,7 @@ func TestFileExists(t *testing.T) {
file := filepath.Join(dir, "foo")
assert.False(t, fileExists(file),
assert.False(t, katautils.FileExists(file),
fmt.Sprintf("File %q should not exist", file))
err = createEmptyFile(file)
@@ -32,24 +33,10 @@ func TestFileExists(t *testing.T) {
t.Fatal(err)
}
assert.True(t, fileExists(file),
assert.True(t, katautils.FileExists(file),
fmt.Sprintf("File %q should exist", file))
}
func TestIsEphemeralStorage(t *testing.T) {
sampleEphePath := "/var/lib/kubelet/pods/366c3a75-4869-11e8-b479-507b9ddd5ce4/volumes/kubernetes.io~empty-dir/cache-volume"
isEphe := IsEphemeralStorage(sampleEphePath)
if !isEphe {
t.Fatalf("Unable to correctly determine volume type")
}
sampleEphePath = "/var/lib/kubelet/pods/366c3a75-4869-11e8-b479-507b9ddd5ce4/volumes/cache-volume"
isEphe = IsEphemeralStorage(sampleEphePath)
if isEphe {
t.Fatalf("Unable to correctly determine volume type")
}
}
func TestGetKernelVersion(t *testing.T) {
type testData struct {
contents string
@@ -187,13 +174,13 @@ VERSION_ID="%s"
}
func TestUtilsRunCommand(t *testing.T) {
output, err := runCommand([]string{"true"})
output, err := katautils.RunCommand([]string{"true"})
assert.NoError(t, err)
assert.Equal(t, "", output)
}
func TestUtilsRunCommandCaptureStdout(t *testing.T) {
output, err := runCommand([]string{"echo", "hello"})
output, err := katautils.RunCommand([]string{"echo", "hello"})
assert.NoError(t, err)
assert.Equal(t, "hello", output)
}
@@ -201,7 +188,7 @@ func TestUtilsRunCommandCaptureStdout(t *testing.T) {
func TestUtilsRunCommandIgnoreStderr(t *testing.T) {
args := []string{"/bin/sh", "-c", "echo foo >&2;exit 0"}
output, err := runCommand(args)
output, err := katautils.RunCommand(args)
assert.NoError(t, err)
assert.Equal(t, "", output)
}
@@ -224,7 +211,7 @@ func TestUtilsRunCommandInvalidCmds(t *testing.T) {
}
for _, args := range invalidCommands {
output, err := runCommand(args)
output, err := katautils.RunCommand(args)
assert.Error(t, err)
assert.Equal(t, "", output)
}

View File

@@ -6,6 +6,7 @@
package main
import (
"github.com/kata-containers/runtime/pkg/katautils"
"github.com/urfave/cli"
)
@@ -18,7 +19,7 @@ var versionCLICommand = cli.Command{
return err
}
span, _ := trace(ctx, "version")
span, _ := katautils.Trace(ctx, "version")
defer span.Finish()
cli.VersionPrinter(context)