mirror of
https://github.com/aljazceru/kata-containers.git
synced 2026-01-09 01:14:20 +01:00
For kata containers, rootfs is used in the read-only way. EROFS can noticably decrease metadata overhead. On the basis of supporting the EROFS file system, it supports using the config parameter to switch the file system used by rootfs. Fixes: #6063 Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com> Signed-off-by: yaoyinnan <yaoyinnan@foxmail.com>
493 lines
11 KiB
Go
493 lines
11 KiB
Go
// Copyright (c) 2016 Intel Corporation
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
package virtcontainers
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/types"
|
|
"github.com/stretchr/testify/assert"
|
|
"os"
|
|
"testing"
|
|
)
|
|
|
|
func TestGetKernelRootParams(t *testing.T) {
|
|
assert := assert.New(t)
|
|
tests := []struct {
|
|
rootfstype string
|
|
expected []Param
|
|
disableNvdimm bool
|
|
dax bool
|
|
error bool
|
|
}{
|
|
// EXT4
|
|
{
|
|
rootfstype: string(EXT4),
|
|
expected: []Param{
|
|
{"root", string(Nvdimm)},
|
|
{"rootflags", "data=ordered,errors=remount-ro ro"},
|
|
{"rootfstype", string(EXT4)},
|
|
},
|
|
disableNvdimm: false,
|
|
dax: false,
|
|
error: false,
|
|
},
|
|
{
|
|
rootfstype: string(EXT4),
|
|
expected: []Param{
|
|
{"root", string(Nvdimm)},
|
|
{"rootflags", "dax,data=ordered,errors=remount-ro ro"},
|
|
{"rootfstype", string(EXT4)},
|
|
},
|
|
disableNvdimm: false,
|
|
dax: true,
|
|
error: false,
|
|
},
|
|
{
|
|
rootfstype: string(EXT4),
|
|
expected: []Param{
|
|
{"root", string(VirtioBlk)},
|
|
{"rootflags", "data=ordered,errors=remount-ro ro"},
|
|
{"rootfstype", string(EXT4)},
|
|
},
|
|
disableNvdimm: true,
|
|
dax: false,
|
|
error: false,
|
|
},
|
|
|
|
// XFS
|
|
{
|
|
rootfstype: string(XFS),
|
|
expected: []Param{
|
|
{"root", string(Nvdimm)},
|
|
{"rootflags", "data=ordered,errors=remount-ro ro"},
|
|
{"rootfstype", string(XFS)},
|
|
},
|
|
disableNvdimm: false,
|
|
dax: false,
|
|
error: false,
|
|
},
|
|
{
|
|
rootfstype: string(XFS),
|
|
expected: []Param{
|
|
{"root", string(Nvdimm)},
|
|
{"rootflags", "dax,data=ordered,errors=remount-ro ro"},
|
|
{"rootfstype", string(XFS)},
|
|
},
|
|
disableNvdimm: false,
|
|
dax: true,
|
|
error: false,
|
|
},
|
|
{
|
|
rootfstype: string(XFS),
|
|
expected: []Param{
|
|
{"root", string(VirtioBlk)},
|
|
{"rootflags", "data=ordered,errors=remount-ro ro"},
|
|
{"rootfstype", string(XFS)},
|
|
},
|
|
disableNvdimm: true,
|
|
dax: false,
|
|
error: false,
|
|
},
|
|
|
|
// EROFS
|
|
{
|
|
rootfstype: string(EROFS),
|
|
expected: []Param{
|
|
{"root", string(Nvdimm)},
|
|
{"rootflags", "ro"},
|
|
{"rootfstype", string(EROFS)},
|
|
},
|
|
disableNvdimm: false,
|
|
dax: false,
|
|
error: false,
|
|
},
|
|
{
|
|
rootfstype: string(EROFS),
|
|
expected: []Param{
|
|
{"root", string(Nvdimm)},
|
|
{"rootflags", "dax ro"},
|
|
{"rootfstype", string(EROFS)},
|
|
},
|
|
disableNvdimm: false,
|
|
dax: true,
|
|
error: false,
|
|
},
|
|
{
|
|
rootfstype: string(EROFS),
|
|
expected: []Param{
|
|
{"root", string(VirtioBlk)},
|
|
{"rootflags", "ro"},
|
|
{"rootfstype", string(EROFS)},
|
|
},
|
|
disableNvdimm: true,
|
|
dax: false,
|
|
error: false,
|
|
},
|
|
|
|
// Unsupported rootfs type
|
|
{
|
|
rootfstype: "foo",
|
|
expected: []Param{
|
|
{"root", string(VirtioBlk)},
|
|
{"rootflags", "data=ordered,errors=remount-ro ro"},
|
|
{"rootfstype", string(EXT4)},
|
|
},
|
|
disableNvdimm: false,
|
|
dax: false,
|
|
error: true,
|
|
},
|
|
|
|
// Nvdimm does not support DAX
|
|
{
|
|
rootfstype: string(EXT4),
|
|
expected: []Param{
|
|
{"root", string(VirtioBlk)},
|
|
{"rootflags", "dax,data=ordered,errors=remount-ro ro"},
|
|
{"rootfstype", string(EXT4)},
|
|
},
|
|
disableNvdimm: true,
|
|
dax: true,
|
|
error: true,
|
|
},
|
|
}
|
|
|
|
for _, t := range tests {
|
|
kernelRootParams, err := GetKernelRootParams(t.rootfstype, t.disableNvdimm, t.dax)
|
|
if t.error {
|
|
assert.Error(err)
|
|
continue
|
|
} else {
|
|
assert.NoError(err)
|
|
}
|
|
assert.Equal(t.expected, kernelRootParams,
|
|
"Invalid parameters rootfstype: %v, disableNvdimm: %v, dax: %v, "+
|
|
"unable to get kernel root params", t.rootfstype, t.disableNvdimm, t.dax)
|
|
}
|
|
}
|
|
|
|
func testSetHypervisorType(t *testing.T, value string, expected HypervisorType) {
|
|
var hypervisorType HypervisorType
|
|
assert := assert.New(t)
|
|
|
|
err := (&hypervisorType).Set(value)
|
|
assert.NoError(err)
|
|
assert.Equal(hypervisorType, expected)
|
|
}
|
|
|
|
func TestSetQemuHypervisorType(t *testing.T) {
|
|
testSetHypervisorType(t, "qemu", QemuHypervisor)
|
|
}
|
|
|
|
func TestSetMockHypervisorType(t *testing.T) {
|
|
testSetHypervisorType(t, "mock", MockHypervisor)
|
|
}
|
|
|
|
func TestSetUnknownHypervisorType(t *testing.T) {
|
|
var hypervisorType HypervisorType
|
|
assert := assert.New(t)
|
|
|
|
err := (&hypervisorType).Set("unknown")
|
|
assert.Error(err)
|
|
assert.NotEqual(hypervisorType, QemuHypervisor)
|
|
assert.NotEqual(hypervisorType, MockHypervisor)
|
|
}
|
|
|
|
func testStringFromHypervisorType(t *testing.T, hypervisorType HypervisorType, expected string) {
|
|
hypervisorTypeStr := (&hypervisorType).String()
|
|
assert := assert.New(t)
|
|
assert.Equal(hypervisorTypeStr, expected)
|
|
}
|
|
|
|
func TestStringFromQemuHypervisorType(t *testing.T) {
|
|
hypervisorType := QemuHypervisor
|
|
testStringFromHypervisorType(t, hypervisorType, "qemu")
|
|
}
|
|
|
|
func TestStringFromMockHypervisorType(t *testing.T) {
|
|
hypervisorType := MockHypervisor
|
|
testStringFromHypervisorType(t, hypervisorType, "mock")
|
|
}
|
|
|
|
func TestStringFromUnknownHypervisorType(t *testing.T) {
|
|
var hypervisorType HypervisorType
|
|
testStringFromHypervisorType(t, hypervisorType, "")
|
|
}
|
|
|
|
func testNewHypervisorFromHypervisorType(t *testing.T, hypervisorType HypervisorType, expected Hypervisor) {
|
|
assert := assert.New(t)
|
|
hy, err := NewHypervisor(hypervisorType)
|
|
assert.NoError(err)
|
|
assert.Exactly(hy, expected)
|
|
}
|
|
|
|
func TestNewHypervisorFromMockHypervisorType(t *testing.T) {
|
|
hypervisorType := MockHypervisor
|
|
expectedHypervisor := &mockHypervisor{}
|
|
testNewHypervisorFromHypervisorType(t, hypervisorType, expectedHypervisor)
|
|
}
|
|
|
|
func TestNewHypervisorFromUnknownHypervisorType(t *testing.T) {
|
|
var hypervisorType HypervisorType
|
|
assert := assert.New(t)
|
|
|
|
hy, err := NewHypervisor(hypervisorType)
|
|
assert.Error(err)
|
|
assert.Nil(hy)
|
|
}
|
|
|
|
func TestAppendParams(t *testing.T) {
|
|
assert := assert.New(t)
|
|
paramList := []Param{
|
|
{
|
|
Key: "param1",
|
|
Value: "value1",
|
|
},
|
|
}
|
|
|
|
expectedParams := []Param{
|
|
{
|
|
Key: "param1",
|
|
Value: "value1",
|
|
},
|
|
{
|
|
Key: "param2",
|
|
Value: "value2",
|
|
},
|
|
}
|
|
|
|
paramList = appendParam(paramList, "param2", "value2")
|
|
assert.Exactly(paramList, expectedParams)
|
|
}
|
|
|
|
func testSerializeParams(t *testing.T, params []Param, delim string, expected []string) {
|
|
assert := assert.New(t)
|
|
result := SerializeParams(params, delim)
|
|
assert.Exactly(result, expected)
|
|
}
|
|
|
|
func TestSerializeParamsNoParamNoValue(t *testing.T) {
|
|
params := []Param{
|
|
{
|
|
Key: "",
|
|
Value: "",
|
|
},
|
|
}
|
|
var expected []string
|
|
|
|
testSerializeParams(t, params, "", expected)
|
|
}
|
|
|
|
func TestSerializeParamsNoParam(t *testing.T) {
|
|
params := []Param{
|
|
{
|
|
Value: "value1",
|
|
},
|
|
}
|
|
|
|
expected := []string{"value1"}
|
|
|
|
testSerializeParams(t, params, "", expected)
|
|
}
|
|
|
|
func TestSerializeParamsNoValue(t *testing.T) {
|
|
params := []Param{
|
|
{
|
|
Key: "param1",
|
|
},
|
|
}
|
|
|
|
expected := []string{"param1"}
|
|
|
|
testSerializeParams(t, params, "", expected)
|
|
}
|
|
|
|
func TestSerializeParamsNoDelim(t *testing.T) {
|
|
params := []Param{
|
|
{
|
|
Key: "param1",
|
|
Value: "value1",
|
|
},
|
|
}
|
|
|
|
expected := []string{"param1", "value1"}
|
|
|
|
testSerializeParams(t, params, "", expected)
|
|
}
|
|
|
|
func TestSerializeParams(t *testing.T) {
|
|
params := []Param{
|
|
{
|
|
Key: "param1",
|
|
Value: "value1",
|
|
},
|
|
}
|
|
|
|
expected := []string{"param1=value1"}
|
|
|
|
testSerializeParams(t, params, "=", expected)
|
|
}
|
|
|
|
func testDeserializeParams(t *testing.T, parameters []string, expected []Param) {
|
|
assert := assert.New(t)
|
|
result := DeserializeParams(parameters)
|
|
assert.Exactly(result, expected)
|
|
}
|
|
|
|
func TestDeserializeParamsNil(t *testing.T) {
|
|
var parameters []string
|
|
var expected []Param
|
|
|
|
testDeserializeParams(t, parameters, expected)
|
|
}
|
|
|
|
func TestDeserializeParamsNoParamNoValue(t *testing.T) {
|
|
parameters := []string{
|
|
"",
|
|
}
|
|
|
|
var expected []Param
|
|
|
|
testDeserializeParams(t, parameters, expected)
|
|
}
|
|
|
|
func TestDeserializeParamsNoValue(t *testing.T) {
|
|
parameters := []string{
|
|
"param1",
|
|
}
|
|
expected := []Param{
|
|
{
|
|
Key: "param1",
|
|
},
|
|
}
|
|
|
|
testDeserializeParams(t, parameters, expected)
|
|
}
|
|
|
|
func TestDeserializeParams(t *testing.T) {
|
|
parameters := []string{
|
|
"param1=value1",
|
|
}
|
|
|
|
expected := []Param{
|
|
{
|
|
Key: "param1",
|
|
Value: "value1",
|
|
},
|
|
}
|
|
|
|
testDeserializeParams(t, parameters, expected)
|
|
}
|
|
|
|
func TestAddKernelParamValid(t *testing.T) {
|
|
var config HypervisorConfig
|
|
assert := assert.New(t)
|
|
|
|
expected := []Param{
|
|
{"foo", "bar"},
|
|
}
|
|
|
|
err := config.AddKernelParam(expected[0])
|
|
assert.NoError(err)
|
|
assert.Exactly(config.KernelParams, expected)
|
|
}
|
|
|
|
func TestAddKernelParamInvalid(t *testing.T) {
|
|
var config HypervisorConfig
|
|
assert := assert.New(t)
|
|
|
|
invalid := []Param{
|
|
{"", "bar"},
|
|
}
|
|
|
|
err := config.AddKernelParam(invalid[0])
|
|
assert.Error(err)
|
|
}
|
|
|
|
func TestCheckCmdline(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
cmdlineFp, err := os.CreateTemp("", "")
|
|
assert.NoError(err)
|
|
_, err = cmdlineFp.WriteString("quiet root=/dev/sda2")
|
|
assert.NoError(err)
|
|
cmdlinePath := cmdlineFp.Name()
|
|
defer os.Remove(cmdlinePath)
|
|
|
|
assert.True(CheckCmdline(cmdlinePath, "quiet", []string{}))
|
|
assert.True(CheckCmdline(cmdlinePath, "root", []string{"/dev/sda1", "/dev/sda2"}))
|
|
assert.False(CheckCmdline(cmdlinePath, "ro", []string{}))
|
|
}
|
|
|
|
// nolint: unused, deadcode
|
|
type testNestedVMMData struct {
|
|
content []byte
|
|
expectedErr bool
|
|
expected bool
|
|
}
|
|
|
|
// nolint: unused, deadcode
|
|
func genericTestRunningOnVMM(t *testing.T, data []testNestedVMMData) {
|
|
assert := assert.New(t)
|
|
for _, d := range data {
|
|
f, err := os.CreateTemp("", "cpuinfo")
|
|
assert.NoError(err)
|
|
defer os.Remove(f.Name())
|
|
defer f.Close()
|
|
|
|
n, err := f.Write(d.content)
|
|
assert.NoError(err)
|
|
assert.Equal(n, len(d.content))
|
|
|
|
running, err := RunningOnVMM(f.Name())
|
|
if !d.expectedErr && err != nil {
|
|
t.Fatalf("This test should succeed: %v", err)
|
|
} else if d.expectedErr && err == nil {
|
|
t.Fatalf("This test should fail")
|
|
}
|
|
|
|
assert.Equal(running, d.expected)
|
|
}
|
|
}
|
|
|
|
func TestAssetPath(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
// Minimal config containing values for all asset annotation options.
|
|
// The values are "paths" (start with a slash), but end with the
|
|
// annotation name.
|
|
cfg := HypervisorConfig{
|
|
HypervisorPath: "/" + "io.katacontainers.config.hypervisor.path",
|
|
HypervisorCtlPath: "/" + "io.katacontainers.config.hypervisor.ctlpath",
|
|
|
|
KernelPath: "/" + "io.katacontainers.config.hypervisor.kernel",
|
|
|
|
ImagePath: "/" + "io.katacontainers.config.hypervisor.image",
|
|
InitrdPath: "/" + "io.katacontainers.config.hypervisor.initrd",
|
|
|
|
FirmwarePath: "/" + "io.katacontainers.config.hypervisor.firmware",
|
|
FirmwareVolumePath: "/" + "io.katacontainers.config.hypervisor.firmware_volume",
|
|
JailerPath: "/" + "io.katacontainers.config.hypervisor.jailer_path",
|
|
}
|
|
|
|
for _, asset := range types.AssetTypes() {
|
|
msg := fmt.Sprintf("asset: %v", asset)
|
|
|
|
annoPath, annoHash, err := asset.Annotations()
|
|
assert.NoError(err, msg)
|
|
|
|
msg += fmt.Sprintf(", annotation path: %v, annotation hash: %v", annoPath, annoHash)
|
|
|
|
p, err := cfg.assetPath(asset)
|
|
assert.NoError(err, msg)
|
|
|
|
assert.NotEqual(p, annoPath, msg)
|
|
assert.NotEqual(p, annoHash, msg)
|
|
|
|
expected := fmt.Sprintf("/%s", annoPath)
|
|
assert.Equal(expected, p, msg)
|
|
}
|
|
}
|