virtcontainers: change container's rootfs from string to mount alike struct

container's rootfs is a string type, which cannot represent a
block storage backed rootfs which hasn't been mounted.
Change it to a mount alike struct as below:
    RootFs struct {
            // Source specify the BlockDevice path
            Source string
            // Target specify where the rootfs is mounted if it has been mounted
            Target string
            // Type specifies the type of filesystem to mount.
            Type string
            // Options specifies zero or more fstab style mount options.
            Options []string
            // Mounted specifies whether the rootfs has be mounted or not
            Mounted bool
     }

If the container's rootfs has been mounted as before, then this struct can be
initialized as: RootFs{Target: <rootfs>, Mounted: true} to be compatible with
previous case.

Fixes:#1158

Signed-off-by: lifupan <lifupan@gmail.com>
This commit is contained in:
lifupan
2019-04-02 10:54:05 +08:00
parent 8e72cf15e6
commit 628ea46c58
16 changed files with 174 additions and 50 deletions

View File

@@ -164,7 +164,7 @@ func SetEphemeralStorageType(ociSpec oci.CompatOCISpec) oci.CompatOCISpec {
}
// CreateSandbox create a sandbox container
func CreateSandbox(ctx context.Context, vci vc.VC, ociSpec oci.CompatOCISpec, runtimeConfig oci.RuntimeConfig,
func CreateSandbox(ctx context.Context, vci vc.VC, ociSpec oci.CompatOCISpec, runtimeConfig oci.RuntimeConfig, rootFs vc.RootFs,
containerID, bundlePath, console string, disableOutput, systemdCgroup, builtIn bool) (vc.VCSandbox, vc.Process, error) {
span, ctx := Trace(ctx, "createSandbox")
defer span.Finish()
@@ -178,6 +178,17 @@ func CreateSandbox(ctx context.Context, vci vc.VC, ociSpec oci.CompatOCISpec, ru
sandboxConfig.Stateful = true
}
if !rootFs.Mounted && len(sandboxConfig.Containers) == 1 {
if rootFs.Source != "" {
realPath, err := ResolvePath(rootFs.Source)
if err != nil {
return nil, vc.Process{}, err
}
rootFs.Source = realPath
}
sandboxConfig.Containers[0].RootFs = rootFs
}
// 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.
@@ -218,7 +229,7 @@ func CreateSandbox(ctx context.Context, vci vc.VC, ociSpec oci.CompatOCISpec, ru
}
// CreateContainer create a container
func CreateContainer(ctx context.Context, vci vc.VC, sandbox vc.VCSandbox, ociSpec oci.CompatOCISpec, containerID, bundlePath, console string, disableOutput, builtIn bool) (vc.Process, error) {
func CreateContainer(ctx context.Context, vci vc.VC, sandbox vc.VCSandbox, ociSpec oci.CompatOCISpec, rootFs vc.RootFs, containerID, bundlePath, console string, disableOutput, builtIn bool) (vc.Process, error) {
var c vc.VCContainer
span, ctx := Trace(ctx, "createContainer")
@@ -231,6 +242,17 @@ func CreateContainer(ctx context.Context, vci vc.VC, sandbox vc.VCSandbox, ociSp
return vc.Process{}, err
}
if !rootFs.Mounted {
if rootFs.Source != "" {
realPath, err := ResolvePath(rootFs.Source)
if err != nil {
return vc.Process{}, err
}
rootFs.Source = realPath
}
contConfig.RootFs = rootFs
}
sandboxID, err := ociSpec.SandboxID()
if err != nil {
return vc.Process{}, err

View File

@@ -306,7 +306,9 @@ func TestCreateSandboxConfigFail(t *testing.T) {
Quota: &quota,
}
_, _, err = CreateSandbox(context.Background(), testingImpl, spec, runtimeConfig, testContainerID, bundlePath, testConsole, true, true, false)
rootFs := vc.RootFs{Mounted: true}
_, _, err = CreateSandbox(context.Background(), testingImpl, spec, runtimeConfig, rootFs, testContainerID, bundlePath, testConsole, true, true, false)
assert.Error(err)
}
@@ -340,7 +342,9 @@ func TestCreateSandboxFail(t *testing.T) {
spec, err := readOCIConfigFile(ociConfigFile)
assert.NoError(err)
_, _, err = CreateSandbox(context.Background(), testingImpl, spec, runtimeConfig, testContainerID, bundlePath, testConsole, true, true, false)
rootFs := vc.RootFs{Mounted: true}
_, _, err = CreateSandbox(context.Background(), testingImpl, spec, runtimeConfig, rootFs, testContainerID, bundlePath, testConsole, true, true, false)
assert.Error(err)
assert.True(vcmock.IsMockError(err))
}
@@ -377,8 +381,10 @@ func TestCreateContainerContainerConfigFail(t *testing.T) {
err = writeOCIConfigFile(spec, ociConfigFile)
assert.NoError(err)
rootFs := vc.RootFs{Mounted: true}
for _, disableOutput := range []bool{true, false} {
_, err = CreateContainer(context.Background(), testingImpl, nil, spec, testContainerID, bundlePath, testConsole, disableOutput, false)
_, err = CreateContainer(context.Background(), testingImpl, nil, spec, rootFs, testContainerID, bundlePath, testConsole, disableOutput, false)
assert.Error(err)
assert.False(vcmock.IsMockError(err))
assert.True(strings.Contains(err.Error(), containerType))
@@ -418,8 +424,10 @@ func TestCreateContainerFail(t *testing.T) {
err = writeOCIConfigFile(spec, ociConfigFile)
assert.NoError(err)
rootFs := vc.RootFs{Mounted: true}
for _, disableOutput := range []bool{true, false} {
_, err = CreateContainer(context.Background(), testingImpl, nil, spec, testContainerID, bundlePath, testConsole, disableOutput, false)
_, err = CreateContainer(context.Background(), testingImpl, nil, spec, rootFs, testContainerID, bundlePath, testConsole, disableOutput, false)
assert.Error(err)
assert.True(vcmock.IsMockError(err))
os.RemoveAll(path)
@@ -466,8 +474,10 @@ func TestCreateContainer(t *testing.T) {
err = writeOCIConfigFile(spec, ociConfigFile)
assert.NoError(err)
rootFs := vc.RootFs{Mounted: true}
for _, disableOutput := range []bool{true, false} {
_, err = CreateContainer(context.Background(), testingImpl, nil, spec, testContainerID, bundlePath, testConsole, disableOutput, false)
_, err = CreateContainer(context.Background(), testingImpl, nil, spec, rootFs, testContainerID, bundlePath, testConsole, disableOutput, false)
assert.NoError(err)
os.RemoveAll(path)
}

View File

@@ -8,6 +8,7 @@ package katautils
import (
"fmt"
"golang.org/x/sys/unix"
"io/ioutil"
"os"
"os/exec"
@@ -78,6 +79,29 @@ func ResolvePath(path string) (string, error) {
return resolved, nil
}
// IsBlockDevice returns true if the give path is a block device
func IsBlockDevice(filePath string) bool {
var stat unix.Stat_t
if filePath == "" {
return false
}
devicePath, err := ResolvePath(filePath)
if err != nil {
return false
}
if err := unix.Stat(devicePath, &stat); err != nil {
return false
}
if stat.Mode&unix.S_IFBLK == unix.S_IFBLK {
return true
}
return false
}
// fileSize returns the number of bytes in the specified file
func fileSize(file string) (int64, error) {
st := syscall.Stat_t{}