mirror of
https://github.com/aljazceru/kata-containers.git
synced 2025-12-27 11:04:21 +01:00
1. support qemu migration save operation 2. setup vm templating parameters per hypervisor config 3. create vm storage path when it does not exist. This can happen when an empty guest is created without a sandbox. Signed-off-by: Peng Tao <bergwolf@gmail.com>
521 lines
12 KiB
Go
521 lines
12 KiB
Go
// Copyright (c) 2016 Intel Corporation
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
package virtcontainers
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
func testSetHypervisorType(t *testing.T, value string, expected HypervisorType) {
|
|
var hypervisorType HypervisorType
|
|
|
|
err := (&hypervisorType).Set(value)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if hypervisorType != expected {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
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
|
|
|
|
err := (&hypervisorType).Set("unknown")
|
|
if err == nil {
|
|
t.Fatal()
|
|
}
|
|
|
|
if hypervisorType == QemuHypervisor ||
|
|
hypervisorType == MockHypervisor {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func testStringFromHypervisorType(t *testing.T, hypervisorType HypervisorType, expected string) {
|
|
hypervisorTypeStr := (&hypervisorType).String()
|
|
if hypervisorTypeStr != expected {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
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) {
|
|
hy, err := newHypervisor(hypervisorType)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if reflect.DeepEqual(hy, expected) == false {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func TestNewHypervisorFromQemuHypervisorType(t *testing.T) {
|
|
hypervisorType := QemuHypervisor
|
|
expectedHypervisor := &qemu{}
|
|
testNewHypervisorFromHypervisorType(t, hypervisorType, expectedHypervisor)
|
|
}
|
|
|
|
func TestNewHypervisorFromMockHypervisorType(t *testing.T) {
|
|
hypervisorType := MockHypervisor
|
|
expectedHypervisor := &mockHypervisor{}
|
|
testNewHypervisorFromHypervisorType(t, hypervisorType, expectedHypervisor)
|
|
}
|
|
|
|
func TestNewHypervisorFromUnknownHypervisorType(t *testing.T) {
|
|
var hypervisorType HypervisorType
|
|
|
|
hy, err := newHypervisor(hypervisorType)
|
|
if err == nil {
|
|
t.Fatal()
|
|
}
|
|
|
|
if hy != nil {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func testHypervisorConfigValid(t *testing.T, hypervisorConfig *HypervisorConfig, success bool) {
|
|
err := hypervisorConfig.valid()
|
|
if success && err != nil {
|
|
t.Fatal()
|
|
}
|
|
if !success && err == nil {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func TestHypervisorConfigNoKernelPath(t *testing.T) {
|
|
hypervisorConfig := &HypervisorConfig{
|
|
KernelPath: "",
|
|
ImagePath: fmt.Sprintf("%s/%s", testDir, testImage),
|
|
HypervisorPath: fmt.Sprintf("%s/%s", testDir, testHypervisor),
|
|
}
|
|
|
|
testHypervisorConfigValid(t, hypervisorConfig, false)
|
|
}
|
|
|
|
func TestHypervisorConfigNoImagePath(t *testing.T) {
|
|
hypervisorConfig := &HypervisorConfig{
|
|
KernelPath: fmt.Sprintf("%s/%s", testDir, testKernel),
|
|
ImagePath: "",
|
|
HypervisorPath: fmt.Sprintf("%s/%s", testDir, testHypervisor),
|
|
}
|
|
|
|
testHypervisorConfigValid(t, hypervisorConfig, false)
|
|
}
|
|
|
|
func TestHypervisorConfigNoHypervisorPath(t *testing.T) {
|
|
hypervisorConfig := &HypervisorConfig{
|
|
KernelPath: fmt.Sprintf("%s/%s", testDir, testKernel),
|
|
ImagePath: fmt.Sprintf("%s/%s", testDir, testImage),
|
|
HypervisorPath: "",
|
|
}
|
|
|
|
testHypervisorConfigValid(t, hypervisorConfig, true)
|
|
}
|
|
|
|
func TestHypervisorConfigIsValid(t *testing.T) {
|
|
hypervisorConfig := &HypervisorConfig{
|
|
KernelPath: fmt.Sprintf("%s/%s", testDir, testKernel),
|
|
ImagePath: fmt.Sprintf("%s/%s", testDir, testImage),
|
|
HypervisorPath: fmt.Sprintf("%s/%s", testDir, testHypervisor),
|
|
}
|
|
|
|
testHypervisorConfigValid(t, hypervisorConfig, true)
|
|
}
|
|
|
|
func TestHypervisorConfigValidTemplateConfig(t *testing.T) {
|
|
hypervisorConfig := &HypervisorConfig{
|
|
KernelPath: fmt.Sprintf("%s/%s", testDir, testKernel),
|
|
ImagePath: fmt.Sprintf("%s/%s", testDir, testImage),
|
|
HypervisorPath: fmt.Sprintf("%s/%s", testDir, testHypervisor),
|
|
BootToBeTemplate: true,
|
|
BootFromTemplate: true,
|
|
}
|
|
testHypervisorConfigValid(t, hypervisorConfig, false)
|
|
|
|
hypervisorConfig.BootToBeTemplate = false
|
|
testHypervisorConfigValid(t, hypervisorConfig, false)
|
|
hypervisorConfig.MemoryPath = "foobar"
|
|
testHypervisorConfigValid(t, hypervisorConfig, false)
|
|
hypervisorConfig.DevicesStatePath = "foobar"
|
|
testHypervisorConfigValid(t, hypervisorConfig, true)
|
|
|
|
hypervisorConfig.BootFromTemplate = false
|
|
hypervisorConfig.BootToBeTemplate = true
|
|
testHypervisorConfigValid(t, hypervisorConfig, true)
|
|
hypervisorConfig.MemoryPath = ""
|
|
testHypervisorConfigValid(t, hypervisorConfig, false)
|
|
}
|
|
|
|
func TestHypervisorConfigDefaults(t *testing.T) {
|
|
hypervisorConfig := &HypervisorConfig{
|
|
KernelPath: fmt.Sprintf("%s/%s", testDir, testKernel),
|
|
ImagePath: fmt.Sprintf("%s/%s", testDir, testImage),
|
|
HypervisorPath: "",
|
|
}
|
|
testHypervisorConfigValid(t, hypervisorConfig, true)
|
|
|
|
hypervisorConfigDefaultsExpected := &HypervisorConfig{
|
|
KernelPath: fmt.Sprintf("%s/%s", testDir, testKernel),
|
|
ImagePath: fmt.Sprintf("%s/%s", testDir, testImage),
|
|
HypervisorPath: "",
|
|
DefaultVCPUs: defaultVCPUs,
|
|
DefaultMemSz: defaultMemSzMiB,
|
|
DefaultBridges: defaultBridges,
|
|
BlockDeviceDriver: defaultBlockDriver,
|
|
DefaultMaxVCPUs: defaultMaxQemuVCPUs,
|
|
Msize9p: defaultMsize9p,
|
|
}
|
|
|
|
if reflect.DeepEqual(hypervisorConfig, hypervisorConfigDefaultsExpected) == false {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func TestAppendParams(t *testing.T) {
|
|
paramList := []Param{
|
|
{
|
|
Key: "param1",
|
|
Value: "value1",
|
|
},
|
|
}
|
|
|
|
expectedParams := []Param{
|
|
{
|
|
Key: "param1",
|
|
Value: "value1",
|
|
},
|
|
{
|
|
Key: "param2",
|
|
Value: "value2",
|
|
},
|
|
}
|
|
|
|
paramList = appendParam(paramList, "param2", "value2")
|
|
if reflect.DeepEqual(paramList, expectedParams) == false {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func testSerializeParams(t *testing.T, params []Param, delim string, expected []string) {
|
|
result := SerializeParams(params, delim)
|
|
if reflect.DeepEqual(result, expected) == false {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
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) {
|
|
result := DeserializeParams(parameters)
|
|
if reflect.DeepEqual(result, expected) == false {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
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
|
|
|
|
expected := []Param{
|
|
{"foo", "bar"},
|
|
}
|
|
|
|
err := config.AddKernelParam(expected[0])
|
|
if err != nil || reflect.DeepEqual(config.KernelParams, expected) == false {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func TestAddKernelParamInvalid(t *testing.T) {
|
|
var config HypervisorConfig
|
|
|
|
invalid := []Param{
|
|
{"", "bar"},
|
|
}
|
|
|
|
err := config.AddKernelParam(invalid[0])
|
|
if err == nil {
|
|
t.Fatal()
|
|
}
|
|
}
|
|
|
|
func TestGetHostMemorySizeKb(t *testing.T) {
|
|
|
|
type testData struct {
|
|
contents string
|
|
expectedResult int
|
|
expectError bool
|
|
}
|
|
|
|
data := []testData{
|
|
{
|
|
`
|
|
MemTotal: 1 kB
|
|
MemFree: 2 kB
|
|
SwapTotal: 3 kB
|
|
SwapFree: 4 kB
|
|
`,
|
|
1024,
|
|
false,
|
|
},
|
|
{
|
|
`
|
|
MemFree: 2 kB
|
|
SwapTotal: 3 kB
|
|
SwapFree: 4 kB
|
|
`,
|
|
0,
|
|
true,
|
|
},
|
|
}
|
|
|
|
dir, err := ioutil.TempDir("", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.RemoveAll(dir)
|
|
|
|
file := filepath.Join(dir, "meminfo")
|
|
if _, err := getHostMemorySizeKb(file); err == nil {
|
|
t.Fatalf("expected failure as file %q does not exist", file)
|
|
}
|
|
|
|
for _, d := range data {
|
|
if err := ioutil.WriteFile(file, []byte(d.contents), os.FileMode(0640)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.Remove(file)
|
|
|
|
hostMemKb, err := getHostMemorySizeKb(file)
|
|
|
|
if (d.expectError && err == nil) || (!d.expectError && err != nil) {
|
|
t.Fatalf("got %d, input %v", hostMemKb, d)
|
|
}
|
|
|
|
if reflect.DeepEqual(hostMemKb, d.expectedResult) {
|
|
t.Fatalf("got %d, input %v", hostMemKb, d)
|
|
}
|
|
}
|
|
}
|
|
|
|
var dataFlagsFieldWithoutHypervisor = []byte(`
|
|
fpu_exception : yes
|
|
cpuid level : 20
|
|
wp : yes
|
|
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology eagerfpu pni pclmulqdq vmx ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch tpr_shadow vnmi ept vpid fsgsbase bmi1 hle avx2 smep bmi2 erms rtm rdseed adx smap xsaveopt
|
|
bugs :
|
|
bogomips : 4589.35
|
|
`)
|
|
|
|
var dataFlagsFieldWithHypervisor = []byte(`
|
|
fpu_exception : yes
|
|
cpuid level : 20
|
|
wp : yes
|
|
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology eagerfpu pni pclmulqdq vmx ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch tpr_shadow vnmi ept vpid fsgsbase bmi1 hle avx2 smep bmi2 erms rtm rdseed adx smap xsaveopt
|
|
bugs :
|
|
bogomips : 4589.35
|
|
`)
|
|
|
|
var dataWithoutFlagsField = []byte(`
|
|
fpu_exception : yes
|
|
cpuid level : 20
|
|
wp : yes
|
|
bugs :
|
|
bogomips : 4589.35
|
|
`)
|
|
|
|
func testRunningOnVMMSuccessful(t *testing.T, cpuInfoContent []byte, expectedErr bool, expected bool) {
|
|
f, err := ioutil.TempFile("", "cpuinfo")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.Remove(f.Name())
|
|
defer f.Close()
|
|
|
|
n, err := f.Write(cpuInfoContent)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if n != len(cpuInfoContent) {
|
|
t.Fatalf("Only %d bytes written out of %d expected", n, len(cpuInfoContent))
|
|
}
|
|
|
|
running, err := RunningOnVMM(f.Name())
|
|
if !expectedErr && err != nil {
|
|
t.Fatalf("This test should succeed: %v", err)
|
|
} else if expectedErr && err == nil {
|
|
t.Fatalf("This test should fail")
|
|
}
|
|
|
|
if running != expected {
|
|
t.Fatalf("Expecting running on VMM = %t, Got %t", expected, running)
|
|
}
|
|
}
|
|
|
|
func TestRunningOnVMMFalseSuccessful(t *testing.T) {
|
|
testRunningOnVMMSuccessful(t, dataFlagsFieldWithoutHypervisor, false, false)
|
|
}
|
|
|
|
func TestRunningOnVMMTrueSuccessful(t *testing.T) {
|
|
testRunningOnVMMSuccessful(t, dataFlagsFieldWithHypervisor, false, true)
|
|
}
|
|
|
|
func TestRunningOnVMMNoFlagsFieldFailure(t *testing.T) {
|
|
testRunningOnVMMSuccessful(t, dataWithoutFlagsField, true, false)
|
|
}
|
|
|
|
func TestRunningOnVMMNotExistingCPUInfoPathFailure(t *testing.T) {
|
|
f, err := ioutil.TempFile("", "cpuinfo")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
filePath := f.Name()
|
|
|
|
f.Close()
|
|
os.Remove(filePath)
|
|
|
|
if _, err := RunningOnVMM(filePath); err == nil {
|
|
t.Fatalf("Should fail because %q file path does not exist", filePath)
|
|
}
|
|
}
|