mirror of
https://github.com/aljazceru/kata-containers.git
synced 2026-01-04 15:04:25 +01:00
VMCache is a new function that creates VMs as caches before using it. It helps speed up new container creation. The function consists of a server and some clients communicating through Unix socket. The protocol is gRPC in protocols/cache/cache.proto. The VMCache server will create some VMs and cache them by factory cache. It will convert the VM to gRPC format and transport it when gets requestion from clients. Factory grpccache is the VMCache client. It will request gRPC format VM and convert it back to a VM. If VMCache function is enabled, kata-runtime will request VM from factory grpccache when it creates a new sandbox. VMCache has two options. vm_cache_number specifies the number of caches of VMCache: unspecified or == 0 --> VMCache is disabled > 0 --> will be set to the specified number vm_cache_endpoint specifies the address of the Unix socket. This commit just includes the core and the client of VMCache. Currently, VM cache still cannot work with VM templating and vsock. And just support qemu. Fixes: #52 Signed-off-by: Hui Zhu <teawater@hyper.sh>
1632 lines
41 KiB
Go
1632 lines
41 KiB
Go
// Copyright (c) 2018 Intel Corporation
|
|
// Copyright (c) 2018 HyperHQ Inc.
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
package katautils
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"reflect"
|
|
goruntime "runtime"
|
|
"strconv"
|
|
"strings"
|
|
"syscall"
|
|
"testing"
|
|
|
|
vc "github.com/kata-containers/runtime/virtcontainers"
|
|
"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
|
|
"github.com/kata-containers/runtime/virtcontainers/utils"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
var (
|
|
hypervisorDebug = false
|
|
proxyDebug = false
|
|
runtimeDebug = false
|
|
shimDebug = false
|
|
netmonDebug = false
|
|
)
|
|
|
|
type testRuntimeConfig struct {
|
|
RuntimeConfig oci.RuntimeConfig
|
|
RuntimeConfigFile string
|
|
ConfigPath string
|
|
ConfigPathLink string
|
|
LogDir string
|
|
LogPath string
|
|
}
|
|
|
|
func makeRuntimeConfigFileData(hypervisor, hypervisorPath, kernelPath, imagePath, kernelParams, machineType, shimPath, proxyPath, netmonPath, logPath string, disableBlock bool, blockDeviceDriver string, enableIOThreads bool, hotplugVFIOOnRootBus, disableNewNetNs bool) string {
|
|
return `
|
|
# Runtime configuration file
|
|
|
|
[hypervisor.` + hypervisor + `]
|
|
path = "` + hypervisorPath + `"
|
|
kernel = "` + kernelPath + `"
|
|
block_device_driver = "` + blockDeviceDriver + `"
|
|
kernel_params = "` + kernelParams + `"
|
|
image = "` + imagePath + `"
|
|
machine_type = "` + machineType + `"
|
|
default_vcpus = ` + strconv.FormatUint(uint64(defaultVCPUCount), 10) + `
|
|
default_maxvcpus = ` + strconv.FormatUint(uint64(defaultMaxVCPUCount), 10) + `
|
|
default_memory = ` + strconv.FormatUint(uint64(defaultMemSize), 10) + `
|
|
disable_block_device_use = ` + strconv.FormatBool(disableBlock) + `
|
|
enable_iothreads = ` + strconv.FormatBool(enableIOThreads) + `
|
|
hotplug_vfio_on_root_bus = ` + strconv.FormatBool(hotplugVFIOOnRootBus) + `
|
|
msize_9p = ` + strconv.FormatUint(uint64(defaultMsize9p), 10) + `
|
|
enable_debug = ` + strconv.FormatBool(hypervisorDebug) + `
|
|
guest_hook_path = "` + defaultGuestHookPath + `"
|
|
|
|
[proxy.kata]
|
|
enable_debug = ` + strconv.FormatBool(proxyDebug) + `
|
|
path = "` + proxyPath + `"
|
|
|
|
[shim.kata]
|
|
path = "` + shimPath + `"
|
|
enable_debug = ` + strconv.FormatBool(shimDebug) + `
|
|
|
|
[agent.kata]
|
|
|
|
[netmon]
|
|
path = "` + netmonPath + `"
|
|
enable_debug = ` + strconv.FormatBool(netmonDebug) + `
|
|
|
|
[runtime]
|
|
enable_debug = ` + strconv.FormatBool(runtimeDebug) + `
|
|
disable_new_netns= ` + strconv.FormatBool(disableNewNetNs)
|
|
}
|
|
|
|
func createConfig(configPath string, fileData string) error {
|
|
|
|
err := ioutil.WriteFile(configPath, []byte(fileData), testFileMode)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "Unable to create config file %s %v\n", configPath, err)
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// createAllRuntimeConfigFiles creates all files necessary to call
|
|
// loadConfiguration().
|
|
func createAllRuntimeConfigFiles(dir, hypervisor string) (config testRuntimeConfig, err error) {
|
|
if dir == "" {
|
|
return config, fmt.Errorf("BUG: need directory")
|
|
}
|
|
|
|
if hypervisor == "" {
|
|
return config, fmt.Errorf("BUG: need hypervisor")
|
|
}
|
|
|
|
hypervisorPath := path.Join(dir, "hypervisor")
|
|
kernelPath := path.Join(dir, "kernel")
|
|
kernelParams := "foo=bar xyz"
|
|
imagePath := path.Join(dir, "image")
|
|
shimPath := path.Join(dir, "shim")
|
|
proxyPath := path.Join(dir, "proxy")
|
|
netmonPath := path.Join(dir, "netmon")
|
|
logDir := path.Join(dir, "logs")
|
|
logPath := path.Join(logDir, "runtime.log")
|
|
machineType := "machineType"
|
|
disableBlockDevice := true
|
|
blockDeviceDriver := "virtio-scsi"
|
|
enableIOThreads := true
|
|
hotplugVFIOOnRootBus := true
|
|
disableNewNetNs := false
|
|
|
|
runtimeConfigFileData := makeRuntimeConfigFileData(hypervisor, hypervisorPath, kernelPath, imagePath, kernelParams, machineType, shimPath, proxyPath, netmonPath, logPath, disableBlockDevice, blockDeviceDriver, enableIOThreads, hotplugVFIOOnRootBus, disableNewNetNs)
|
|
|
|
configPath := path.Join(dir, "runtime.toml")
|
|
err = createConfig(configPath, runtimeConfigFileData)
|
|
if err != nil {
|
|
return config, err
|
|
}
|
|
|
|
configPathLink := path.Join(filepath.Dir(configPath), "link-to-configuration.toml")
|
|
|
|
// create a link to the config file
|
|
err = syscall.Symlink(configPath, configPathLink)
|
|
if err != nil {
|
|
return config, err
|
|
}
|
|
|
|
files := []string{hypervisorPath, kernelPath, imagePath, shimPath, proxyPath}
|
|
|
|
for _, file := range files {
|
|
// create the resource (which must be >0 bytes)
|
|
err := WriteFile(file, "foo", testFileMode)
|
|
if err != nil {
|
|
return config, err
|
|
}
|
|
}
|
|
|
|
hypervisorConfig := vc.HypervisorConfig{
|
|
HypervisorPath: hypervisorPath,
|
|
KernelPath: kernelPath,
|
|
ImagePath: imagePath,
|
|
KernelParams: vc.DeserializeParams(strings.Fields(kernelParams)),
|
|
HypervisorMachineType: machineType,
|
|
NumVCPUs: defaultVCPUCount,
|
|
DefaultMaxVCPUs: uint32(goruntime.NumCPU()),
|
|
MemorySize: defaultMemSize,
|
|
DisableBlockDeviceUse: disableBlockDevice,
|
|
BlockDeviceDriver: defaultBlockDeviceDriver,
|
|
DefaultBridges: defaultBridgesCount,
|
|
Mlock: !defaultEnableSwap,
|
|
EnableIOThreads: enableIOThreads,
|
|
HotplugVFIOOnRootBus: hotplugVFIOOnRootBus,
|
|
Msize9p: defaultMsize9p,
|
|
MemSlots: defaultMemSlots,
|
|
EntropySource: defaultEntropySource,
|
|
GuestHookPath: defaultGuestHookPath,
|
|
}
|
|
|
|
agentConfig := vc.KataAgentConfig{}
|
|
|
|
proxyConfig := vc.ProxyConfig{
|
|
Path: proxyPath,
|
|
}
|
|
|
|
shimConfig := vc.ShimConfig{
|
|
Path: shimPath,
|
|
}
|
|
|
|
netmonConfig := vc.NetmonConfig{
|
|
Path: netmonPath,
|
|
Debug: false,
|
|
Enable: false,
|
|
}
|
|
|
|
factoryConfig := oci.FactoryConfig{
|
|
VMCacheEndpoint: defaultVMCacheEndpoint,
|
|
}
|
|
|
|
runtimeConfig := oci.RuntimeConfig{
|
|
HypervisorType: defaultHypervisor,
|
|
HypervisorConfig: hypervisorConfig,
|
|
|
|
AgentType: defaultAgent,
|
|
AgentConfig: agentConfig,
|
|
|
|
ProxyType: defaultProxy,
|
|
ProxyConfig: proxyConfig,
|
|
|
|
ShimType: defaultShim,
|
|
ShimConfig: shimConfig,
|
|
|
|
NetmonConfig: netmonConfig,
|
|
DisableNewNetNs: disableNewNetNs,
|
|
|
|
FactoryConfig: factoryConfig,
|
|
}
|
|
|
|
err = SetKernelParams(&runtimeConfig)
|
|
if err != nil {
|
|
return config, err
|
|
}
|
|
|
|
config = testRuntimeConfig{
|
|
RuntimeConfig: runtimeConfig,
|
|
RuntimeConfigFile: configPath,
|
|
ConfigPath: configPath,
|
|
ConfigPathLink: configPathLink,
|
|
LogDir: logDir,
|
|
LogPath: logPath,
|
|
}
|
|
|
|
return config, nil
|
|
}
|
|
|
|
// testLoadConfiguration accepts an optional function that can be used
|
|
// to modify the test: if a function is specified, it indicates if the
|
|
// subsequent call to loadConfiguration() is expected to fail by
|
|
// returning a bool. If the function itself fails, that is considered an
|
|
// error.
|
|
func testLoadConfiguration(t *testing.T, dir string,
|
|
fn func(config testRuntimeConfig, configFile string, ignoreLogging bool) (bool, error)) {
|
|
subDir := path.Join(dir, "test")
|
|
|
|
for _, hypervisor := range []string{"qemu"} {
|
|
Loop:
|
|
for _, ignoreLogging := range []bool{true, false} {
|
|
err := os.RemoveAll(subDir)
|
|
assert.NoError(t, err)
|
|
|
|
err = os.MkdirAll(subDir, testDirMode)
|
|
assert.NoError(t, err)
|
|
|
|
testConfig, err := createAllRuntimeConfigFiles(subDir, hypervisor)
|
|
assert.NoError(t, err)
|
|
|
|
configFiles := []string{testConfig.ConfigPath, testConfig.ConfigPathLink, ""}
|
|
|
|
// override
|
|
defaultRuntimeConfiguration = testConfig.ConfigPath
|
|
defaultSysConfRuntimeConfiguration = ""
|
|
|
|
for _, file := range configFiles {
|
|
var err error
|
|
expectFail := false
|
|
|
|
if fn != nil {
|
|
expectFail, err = fn(testConfig, file, ignoreLogging)
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
resolvedConfigPath, config, err := LoadConfiguration(file, ignoreLogging, false)
|
|
if expectFail {
|
|
assert.Error(t, err)
|
|
|
|
// no point proceeding in the error scenario.
|
|
break Loop
|
|
} else {
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
if file == "" {
|
|
assert.Equal(t, defaultRuntimeConfiguration, resolvedConfigPath)
|
|
} else {
|
|
assert.Equal(t, testConfig.ConfigPath, resolvedConfigPath)
|
|
}
|
|
|
|
assert.Equal(t, defaultRuntimeConfiguration, resolvedConfigPath)
|
|
result := reflect.DeepEqual(config, testConfig.RuntimeConfig)
|
|
if !result {
|
|
t.Fatalf("Expected\n%+v\nGot\n%+v", config, testConfig.RuntimeConfig)
|
|
}
|
|
assert.True(t, result)
|
|
|
|
err = os.RemoveAll(testConfig.LogDir)
|
|
assert.NoError(t, err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestConfigLoadConfiguration(t *testing.T) {
|
|
tmpdir, err := ioutil.TempDir(testDir, "load-config-")
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(tmpdir)
|
|
|
|
testLoadConfiguration(t, tmpdir, nil)
|
|
}
|
|
|
|
func TestConfigLoadConfigurationFailBrokenSymLink(t *testing.T) {
|
|
tmpdir, err := ioutil.TempDir(testDir, "runtime-config-")
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(tmpdir)
|
|
|
|
testLoadConfiguration(t, tmpdir,
|
|
func(config testRuntimeConfig, configFile string, ignoreLogging bool) (bool, error) {
|
|
expectFail := false
|
|
|
|
if configFile == config.ConfigPathLink {
|
|
// break the symbolic link
|
|
err = os.Remove(config.ConfigPathLink)
|
|
if err != nil {
|
|
return expectFail, err
|
|
}
|
|
|
|
expectFail = true
|
|
}
|
|
|
|
return expectFail, nil
|
|
})
|
|
}
|
|
|
|
func TestConfigLoadConfigurationFailSymLinkLoop(t *testing.T) {
|
|
tmpdir, err := ioutil.TempDir(testDir, "runtime-config-")
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(tmpdir)
|
|
|
|
testLoadConfiguration(t, tmpdir,
|
|
func(config testRuntimeConfig, configFile string, ignoreLogging bool) (bool, error) {
|
|
expectFail := false
|
|
|
|
if configFile == config.ConfigPathLink {
|
|
// remove the config file
|
|
err = os.Remove(config.ConfigPath)
|
|
if err != nil {
|
|
return expectFail, err
|
|
}
|
|
|
|
// now, create a sym-link loop
|
|
err := os.Symlink(config.ConfigPathLink, config.ConfigPath)
|
|
if err != nil {
|
|
return expectFail, err
|
|
}
|
|
|
|
expectFail = true
|
|
}
|
|
|
|
return expectFail, nil
|
|
})
|
|
}
|
|
|
|
func TestConfigLoadConfigurationFailMissingHypervisor(t *testing.T) {
|
|
tmpdir, err := ioutil.TempDir(testDir, "runtime-config-")
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(tmpdir)
|
|
|
|
testLoadConfiguration(t, tmpdir,
|
|
func(config testRuntimeConfig, configFile string, ignoreLogging bool) (bool, error) {
|
|
expectFail := true
|
|
|
|
err = os.Remove(config.RuntimeConfig.HypervisorConfig.HypervisorPath)
|
|
if err != nil {
|
|
return expectFail, err
|
|
}
|
|
|
|
return expectFail, nil
|
|
})
|
|
}
|
|
|
|
func TestConfigLoadConfigurationFailMissingImage(t *testing.T) {
|
|
tmpdir, err := ioutil.TempDir(testDir, "runtime-config-")
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(tmpdir)
|
|
|
|
testLoadConfiguration(t, tmpdir,
|
|
func(config testRuntimeConfig, configFile string, ignoreLogging bool) (bool, error) {
|
|
expectFail := true
|
|
|
|
err = os.Remove(config.RuntimeConfig.HypervisorConfig.ImagePath)
|
|
if err != nil {
|
|
return expectFail, err
|
|
}
|
|
|
|
return expectFail, nil
|
|
})
|
|
}
|
|
|
|
func TestConfigLoadConfigurationFailMissingKernel(t *testing.T) {
|
|
tmpdir, err := ioutil.TempDir(testDir, "runtime-config-")
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(tmpdir)
|
|
|
|
testLoadConfiguration(t, tmpdir,
|
|
func(config testRuntimeConfig, configFile string, ignoreLogging bool) (bool, error) {
|
|
expectFail := true
|
|
|
|
err = os.Remove(config.RuntimeConfig.HypervisorConfig.KernelPath)
|
|
if err != nil {
|
|
return expectFail, err
|
|
}
|
|
|
|
return expectFail, nil
|
|
})
|
|
}
|
|
|
|
func TestConfigLoadConfigurationFailMissingShim(t *testing.T) {
|
|
tmpdir, err := ioutil.TempDir(testDir, "runtime-config-")
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(tmpdir)
|
|
|
|
testLoadConfiguration(t, tmpdir,
|
|
func(config testRuntimeConfig, configFile string, ignoreLogging bool) (bool, error) {
|
|
expectFail := true
|
|
|
|
shimConfig, ok := config.RuntimeConfig.ShimConfig.(vc.ShimConfig)
|
|
if !ok {
|
|
return expectFail, fmt.Errorf("cannot determine shim config")
|
|
}
|
|
err = os.Remove(shimConfig.Path)
|
|
if err != nil {
|
|
return expectFail, err
|
|
}
|
|
|
|
return expectFail, nil
|
|
})
|
|
}
|
|
|
|
func TestConfigLoadConfigurationFailUnreadableConfig(t *testing.T) {
|
|
if os.Geteuid() == 0 {
|
|
t.Skip(testDisabledNeedNonRoot)
|
|
}
|
|
|
|
tmpdir, err := ioutil.TempDir(testDir, "runtime-config-")
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(tmpdir)
|
|
|
|
testLoadConfiguration(t, tmpdir,
|
|
func(config testRuntimeConfig, configFile string, ignoreLogging bool) (bool, error) {
|
|
expectFail := true
|
|
|
|
// make file unreadable by non-root user
|
|
err = os.Chmod(config.ConfigPath, 0000)
|
|
if err != nil {
|
|
return expectFail, err
|
|
}
|
|
|
|
return expectFail, nil
|
|
})
|
|
}
|
|
|
|
func TestConfigLoadConfigurationFailTOMLConfigFileInvalidContents(t *testing.T) {
|
|
if os.Geteuid() == 0 {
|
|
t.Skip(testDisabledNeedNonRoot)
|
|
}
|
|
|
|
tmpdir, err := ioutil.TempDir(testDir, "runtime-config-")
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(tmpdir)
|
|
|
|
testLoadConfiguration(t, tmpdir,
|
|
func(config testRuntimeConfig, configFile string, ignoreLogging bool) (bool, error) {
|
|
expectFail := true
|
|
|
|
err := createFile(config.ConfigPath,
|
|
`<?xml version="1.0"?>
|
|
<foo>I am not TOML! ;-)</foo>
|
|
<bar>I am invalid XML!`)
|
|
|
|
if err != nil {
|
|
return expectFail, err
|
|
}
|
|
|
|
return expectFail, nil
|
|
})
|
|
}
|
|
|
|
func TestConfigLoadConfigurationFailTOMLConfigFileDuplicatedData(t *testing.T) {
|
|
if os.Geteuid() == 0 {
|
|
t.Skip(testDisabledNeedNonRoot)
|
|
}
|
|
|
|
tmpdir, err := ioutil.TempDir(testDir, "runtime-config-")
|
|
assert.NoError(t, err)
|
|
defer os.RemoveAll(tmpdir)
|
|
|
|
testLoadConfiguration(t, tmpdir,
|
|
func(config testRuntimeConfig, configFile string, ignoreLogging bool) (bool, error) {
|
|
expectFail := true
|
|
|
|
text, err := GetFileContents(config.ConfigPath)
|
|
if err != nil {
|
|
return expectFail, err
|
|
}
|
|
|
|
// create a config file containing two sets of
|
|
// data.
|
|
err = createFile(config.ConfigPath, fmt.Sprintf("%s\n%s\n", text, text))
|
|
if err != nil {
|
|
return expectFail, err
|
|
}
|
|
|
|
return expectFail, nil
|
|
})
|
|
}
|
|
|
|
func TestMinimalRuntimeConfig(t *testing.T) {
|
|
dir, err := ioutil.TempDir(testDir, "minimal-runtime-config-")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.RemoveAll(dir)
|
|
|
|
shimPath := path.Join(dir, "shim")
|
|
proxyPath := path.Join(dir, "proxy")
|
|
hypervisorPath := path.Join(dir, "hypervisor")
|
|
defaultHypervisorPath = hypervisorPath
|
|
netmonPath := path.Join(dir, "netmon")
|
|
|
|
imagePath := path.Join(dir, "image.img")
|
|
initrdPath := path.Join(dir, "initrd.img")
|
|
|
|
kernelPath := path.Join(dir, "kernel")
|
|
|
|
savedDefaultImagePath := defaultImagePath
|
|
savedDefaultInitrdPath := defaultInitrdPath
|
|
savedDefaultHypervisorPath := defaultHypervisorPath
|
|
savedDefaultKernelPath := defaultKernelPath
|
|
|
|
defer func() {
|
|
defaultImagePath = savedDefaultImagePath
|
|
defaultInitrdPath = savedDefaultInitrdPath
|
|
defaultHypervisorPath = savedDefaultHypervisorPath
|
|
defaultKernelPath = savedDefaultKernelPath
|
|
}()
|
|
|
|
// Temporarily change the defaults to avoid this test using the real
|
|
// resource files that might be installed on the system!
|
|
defaultImagePath = imagePath
|
|
defaultInitrdPath = initrdPath
|
|
defaultHypervisorPath = hypervisorPath
|
|
defaultKernelPath = kernelPath
|
|
|
|
for _, file := range []string{defaultImagePath, defaultInitrdPath, defaultHypervisorPath, defaultKernelPath} {
|
|
err = WriteFile(file, "foo", testFileMode)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
runtimeMinimalConfig := `
|
|
# Runtime configuration file
|
|
|
|
[proxy.kata]
|
|
path = "` + proxyPath + `"
|
|
|
|
[shim.kata]
|
|
path = "` + shimPath + `"
|
|
|
|
[agent.kata]
|
|
|
|
[netmon]
|
|
path = "` + netmonPath + `"
|
|
`
|
|
|
|
configPath := path.Join(dir, "runtime.toml")
|
|
err = createConfig(configPath, runtimeMinimalConfig)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, config, err := LoadConfiguration(configPath, false, false)
|
|
if err == nil {
|
|
t.Fatalf("Expected loadConfiguration to fail as shim path does not exist: %+v", config)
|
|
}
|
|
|
|
err = createEmptyFile(shimPath)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
err = createEmptyFile(proxyPath)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
err = createEmptyFile(hypervisorPath)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
err = createEmptyFile(netmonPath)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
_, config, err = LoadConfiguration(configPath, false, false)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expectedHypervisorConfig := vc.HypervisorConfig{
|
|
HypervisorPath: defaultHypervisorPath,
|
|
KernelPath: defaultKernelPath,
|
|
ImagePath: defaultImagePath,
|
|
InitrdPath: defaultInitrdPath,
|
|
HypervisorMachineType: defaultMachineType,
|
|
NumVCPUs: defaultVCPUCount,
|
|
DefaultMaxVCPUs: defaultMaxVCPUCount,
|
|
MemorySize: defaultMemSize,
|
|
DisableBlockDeviceUse: defaultDisableBlockDeviceUse,
|
|
DefaultBridges: defaultBridgesCount,
|
|
Mlock: !defaultEnableSwap,
|
|
BlockDeviceDriver: defaultBlockDeviceDriver,
|
|
Msize9p: defaultMsize9p,
|
|
GuestHookPath: defaultGuestHookPath,
|
|
}
|
|
|
|
expectedAgentConfig := vc.KataAgentConfig{}
|
|
|
|
expectedProxyConfig := vc.ProxyConfig{
|
|
Path: proxyPath,
|
|
}
|
|
|
|
expectedShimConfig := vc.ShimConfig{
|
|
Path: shimPath,
|
|
}
|
|
|
|
expectedNetmonConfig := vc.NetmonConfig{
|
|
Path: netmonPath,
|
|
Debug: false,
|
|
Enable: false,
|
|
}
|
|
|
|
expectedFactoryConfig := oci.FactoryConfig{
|
|
VMCacheEndpoint: defaultVMCacheEndpoint,
|
|
}
|
|
|
|
expectedConfig := oci.RuntimeConfig{
|
|
HypervisorType: defaultHypervisor,
|
|
HypervisorConfig: expectedHypervisorConfig,
|
|
|
|
AgentType: defaultAgent,
|
|
AgentConfig: expectedAgentConfig,
|
|
|
|
ProxyType: defaultProxy,
|
|
ProxyConfig: expectedProxyConfig,
|
|
|
|
ShimType: defaultShim,
|
|
ShimConfig: expectedShimConfig,
|
|
|
|
NetmonConfig: expectedNetmonConfig,
|
|
|
|
FactoryConfig: expectedFactoryConfig,
|
|
}
|
|
err = SetKernelParams(&expectedConfig)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if reflect.DeepEqual(config, expectedConfig) == false {
|
|
t.Fatalf("Got %+v\n expecting %+v", config, expectedConfig)
|
|
}
|
|
}
|
|
|
|
func TestMinimalRuntimeConfigWithVsock(t *testing.T) {
|
|
dir, err := ioutil.TempDir(testDir, "minimal-runtime-config-")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.RemoveAll(dir)
|
|
|
|
imagePath := path.Join(dir, "image.img")
|
|
initrdPath := path.Join(dir, "initrd.img")
|
|
proxyPath := path.Join(dir, "proxy")
|
|
shimPath := path.Join(dir, "shim")
|
|
hypervisorPath := path.Join(dir, "hypervisor")
|
|
kernelPath := path.Join(dir, "kernel")
|
|
|
|
savedDefaultImagePath := defaultImagePath
|
|
savedDefaultInitrdPath := defaultInitrdPath
|
|
savedDefaultHypervisorPath := defaultHypervisorPath
|
|
savedDefaultKernelPath := defaultKernelPath
|
|
|
|
defer func() {
|
|
defaultImagePath = savedDefaultImagePath
|
|
defaultInitrdPath = savedDefaultInitrdPath
|
|
defaultHypervisorPath = savedDefaultHypervisorPath
|
|
defaultKernelPath = savedDefaultKernelPath
|
|
}()
|
|
|
|
// Temporarily change the defaults to avoid this test using the real
|
|
// resource files that might be installed on the system!
|
|
defaultImagePath = imagePath
|
|
defaultInitrdPath = initrdPath
|
|
defaultHypervisorPath = hypervisorPath
|
|
defaultKernelPath = kernelPath
|
|
|
|
for _, file := range []string{proxyPath, shimPath, hypervisorPath, kernelPath, imagePath} {
|
|
err = WriteFile(file, "foo", testFileMode)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
// minimal config with vsock enabled
|
|
runtimeMinimalConfig := `
|
|
# Runtime configuration file
|
|
[hypervisor.qemu]
|
|
use_vsock = true
|
|
image = "` + imagePath + `"
|
|
|
|
[proxy.kata]
|
|
path = "` + proxyPath + `"
|
|
|
|
[shim.kata]
|
|
path = "` + shimPath + `"
|
|
|
|
[agent.kata]
|
|
`
|
|
orgVHostVSockDevicePath := utils.VHostVSockDevicePath
|
|
orgVSockDevicePath := utils.VSockDevicePath
|
|
defer func() {
|
|
utils.VHostVSockDevicePath = orgVHostVSockDevicePath
|
|
utils.VSockDevicePath = orgVSockDevicePath
|
|
}()
|
|
utils.VHostVSockDevicePath = "/dev/null"
|
|
utils.VSockDevicePath = "/dev/null"
|
|
|
|
configPath := path.Join(dir, "runtime.toml")
|
|
err = createConfig(configPath, runtimeMinimalConfig)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, config, err := LoadConfiguration(configPath, false, false)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if config.ProxyType != vc.NoProxyType {
|
|
t.Fatalf("Proxy type must be NoProxy, got %+v", config.ProxyType)
|
|
}
|
|
|
|
if !reflect.DeepEqual(config.ProxyConfig, vc.ProxyConfig{}) {
|
|
t.Fatalf("Got %+v\n expecting %+v", config.ProxyConfig, vc.ProxyConfig{})
|
|
}
|
|
|
|
if config.HypervisorConfig.UseVSock != true {
|
|
t.Fatalf("use_vsock must be true, got %v", config.HypervisorConfig.UseVSock)
|
|
}
|
|
}
|
|
|
|
func TestNewQemuHypervisorConfig(t *testing.T) {
|
|
dir, err := ioutil.TempDir(testDir, "hypervisor-config-")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.RemoveAll(dir)
|
|
|
|
hypervisorPath := path.Join(dir, "hypervisor")
|
|
kernelPath := path.Join(dir, "kernel")
|
|
imagePath := path.Join(dir, "image")
|
|
machineType := "machineType"
|
|
disableBlock := true
|
|
enableIOThreads := true
|
|
hotplugVFIOOnRootBus := true
|
|
orgVSockDevicePath := utils.VSockDevicePath
|
|
orgVHostVSockDevicePath := utils.VHostVSockDevicePath
|
|
defer func() {
|
|
utils.VSockDevicePath = orgVSockDevicePath
|
|
utils.VHostVSockDevicePath = orgVHostVSockDevicePath
|
|
}()
|
|
utils.VSockDevicePath = "/dev/abc/xyz"
|
|
utils.VHostVSockDevicePath = "/dev/abc/xyz"
|
|
|
|
hypervisor := hypervisor{
|
|
Path: hypervisorPath,
|
|
Kernel: kernelPath,
|
|
Image: imagePath,
|
|
MachineType: machineType,
|
|
DisableBlockDeviceUse: disableBlock,
|
|
EnableIOThreads: enableIOThreads,
|
|
HotplugVFIOOnRootBus: hotplugVFIOOnRootBus,
|
|
UseVSock: true,
|
|
}
|
|
|
|
files := []string{hypervisorPath, kernelPath, imagePath}
|
|
filesLen := len(files)
|
|
|
|
for i, file := range files {
|
|
_, err := newQemuHypervisorConfig(hypervisor)
|
|
if err == nil {
|
|
t.Fatalf("Expected newQemuHypervisorConfig to fail as not all paths exist (not created %v)",
|
|
strings.Join(files[i:filesLen], ","))
|
|
}
|
|
|
|
// create the resource
|
|
err = createEmptyFile(file)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
// falling back to legacy serial port
|
|
config, err := newQemuHypervisorConfig(hypervisor)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
utils.VSockDevicePath = "/dev/null"
|
|
utils.VHostVSockDevicePath = "/dev/null"
|
|
|
|
// all paths exist now
|
|
config, err = newQemuHypervisorConfig(hypervisor)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if config.HypervisorPath != hypervisor.Path {
|
|
t.Errorf("Expected hypervisor path %v, got %v", hypervisor.Path, config.HypervisorPath)
|
|
}
|
|
|
|
if config.KernelPath != hypervisor.Kernel {
|
|
t.Errorf("Expected kernel path %v, got %v", hypervisor.Kernel, config.KernelPath)
|
|
}
|
|
|
|
if config.ImagePath != hypervisor.Image {
|
|
t.Errorf("Expected image path %v, got %v", hypervisor.Image, config.ImagePath)
|
|
}
|
|
|
|
if config.DisableBlockDeviceUse != disableBlock {
|
|
t.Errorf("Expected value for disable block usage %v, got %v", disableBlock, config.DisableBlockDeviceUse)
|
|
}
|
|
|
|
if config.EnableIOThreads != enableIOThreads {
|
|
t.Errorf("Expected value for enable IOThreads %v, got %v", enableIOThreads, config.EnableIOThreads)
|
|
}
|
|
|
|
if config.HotplugVFIOOnRootBus != hotplugVFIOOnRootBus {
|
|
t.Errorf("Expected value for HotplugVFIOOnRootBus %v, got %v", hotplugVFIOOnRootBus, config.HotplugVFIOOnRootBus)
|
|
}
|
|
}
|
|
|
|
func TestNewQemuHypervisorConfigImageAndInitrd(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
tmpdir, err := ioutil.TempDir(testDir, "")
|
|
assert.NoError(err)
|
|
defer os.RemoveAll(tmpdir)
|
|
|
|
imagePath := filepath.Join(tmpdir, "image")
|
|
initrdPath := filepath.Join(tmpdir, "initrd")
|
|
hypervisorPath := path.Join(tmpdir, "hypervisor")
|
|
kernelPath := path.Join(tmpdir, "kernel")
|
|
|
|
for _, file := range []string{imagePath, initrdPath, hypervisorPath, kernelPath} {
|
|
err = createEmptyFile(file)
|
|
assert.NoError(err)
|
|
}
|
|
|
|
machineType := "machineType"
|
|
disableBlock := true
|
|
enableIOThreads := true
|
|
hotplugVFIOOnRootBus := true
|
|
|
|
hypervisor := hypervisor{
|
|
Path: hypervisorPath,
|
|
Kernel: kernelPath,
|
|
Image: imagePath,
|
|
Initrd: initrdPath,
|
|
MachineType: machineType,
|
|
DisableBlockDeviceUse: disableBlock,
|
|
EnableIOThreads: enableIOThreads,
|
|
HotplugVFIOOnRootBus: hotplugVFIOOnRootBus,
|
|
}
|
|
|
|
_, err = newQemuHypervisorConfig(hypervisor)
|
|
|
|
// specifying both an image+initrd is invalid
|
|
assert.Error(err)
|
|
}
|
|
|
|
func TestNewShimConfig(t *testing.T) {
|
|
dir, err := ioutil.TempDir(testDir, "shim-config-")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.RemoveAll(dir)
|
|
|
|
shimPath := path.Join(dir, "shim")
|
|
|
|
shim := shim{
|
|
Path: shimPath,
|
|
}
|
|
|
|
_, err = newShimConfig(shim)
|
|
if err == nil {
|
|
t.Fatalf("Expected newShimConfig to fail as no paths exist")
|
|
}
|
|
|
|
err = createEmptyFile(shimPath)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
shConfig, err := newShimConfig(shim)
|
|
if err != nil {
|
|
t.Fatalf("newShimConfig failed unexpectedly: %v", err)
|
|
}
|
|
|
|
if shConfig.Path != shimPath {
|
|
t.Errorf("Expected shim path %v, got %v", shimPath, shConfig.Path)
|
|
}
|
|
}
|
|
|
|
func TestHypervisorDefaults(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
numCPUs := goruntime.NumCPU()
|
|
|
|
h := hypervisor{}
|
|
|
|
assert.Equal(h.machineType(), defaultMachineType, "default hypervisor machine type wrong")
|
|
assert.Equal(h.defaultVCPUs(), defaultVCPUCount, "default vCPU number is wrong")
|
|
assert.Equal(h.defaultMaxVCPUs(), uint32(numCPUs), "default max vCPU number is wrong")
|
|
assert.Equal(h.defaultMemSz(), defaultMemSize, "default memory size is wrong")
|
|
|
|
machineType := "foo"
|
|
h.MachineType = machineType
|
|
assert.Equal(h.machineType(), machineType, "custom hypervisor machine type wrong")
|
|
|
|
// auto inferring
|
|
h.NumVCPUs = -1
|
|
assert.Equal(h.defaultVCPUs(), uint32(numCPUs), "default vCPU number is wrong")
|
|
|
|
h.NumVCPUs = 2
|
|
assert.Equal(h.defaultVCPUs(), uint32(2), "default vCPU number is wrong")
|
|
|
|
h.NumVCPUs = int32(numCPUs) + 1
|
|
assert.Equal(h.defaultVCPUs(), uint32(numCPUs), "default vCPU number is wrong")
|
|
|
|
h.DefaultMaxVCPUs = 2
|
|
assert.Equal(h.defaultMaxVCPUs(), uint32(h.DefaultMaxVCPUs), "default max vCPU number is wrong")
|
|
|
|
h.DefaultMaxVCPUs = uint32(numCPUs) + 1
|
|
assert.Equal(h.defaultMaxVCPUs(), uint32(numCPUs), "default max vCPU number is wrong")
|
|
|
|
maxvcpus := vc.MaxQemuVCPUs()
|
|
h.DefaultMaxVCPUs = uint32(maxvcpus) + 1
|
|
assert.Equal(h.defaultMaxVCPUs(), uint32(numCPUs), "default max vCPU number is wrong")
|
|
|
|
h.MemorySize = 1024
|
|
assert.Equal(h.defaultMemSz(), uint32(1024), "default memory size is wrong")
|
|
}
|
|
|
|
func TestHypervisorDefaultsHypervisor(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
tmpdir, err := ioutil.TempDir(testDir, "")
|
|
assert.NoError(err)
|
|
defer os.RemoveAll(tmpdir)
|
|
|
|
testHypervisorPath := filepath.Join(tmpdir, "hypervisor")
|
|
testHypervisorLinkPath := filepath.Join(tmpdir, "hypervisor-link")
|
|
|
|
err = createEmptyFile(testHypervisorPath)
|
|
assert.NoError(err)
|
|
|
|
err = syscall.Symlink(testHypervisorPath, testHypervisorLinkPath)
|
|
assert.NoError(err)
|
|
|
|
savedHypervisorPath := defaultHypervisorPath
|
|
|
|
defer func() {
|
|
defaultHypervisorPath = savedHypervisorPath
|
|
}()
|
|
|
|
defaultHypervisorPath = testHypervisorPath
|
|
h := hypervisor{}
|
|
p, err := h.path()
|
|
assert.NoError(err)
|
|
assert.Equal(p, defaultHypervisorPath, "default hypervisor path wrong")
|
|
|
|
// test path resolution
|
|
defaultHypervisorPath = testHypervisorLinkPath
|
|
h = hypervisor{}
|
|
p, err = h.path()
|
|
assert.NoError(err)
|
|
assert.Equal(p, testHypervisorPath)
|
|
}
|
|
|
|
func TestHypervisorDefaultsKernel(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
tmpdir, err := ioutil.TempDir(testDir, "")
|
|
assert.NoError(err)
|
|
defer os.RemoveAll(tmpdir)
|
|
|
|
testKernelPath := filepath.Join(tmpdir, "kernel")
|
|
testKernelLinkPath := filepath.Join(tmpdir, "kernel-link")
|
|
|
|
err = createEmptyFile(testKernelPath)
|
|
assert.NoError(err)
|
|
|
|
err = syscall.Symlink(testKernelPath, testKernelLinkPath)
|
|
assert.NoError(err)
|
|
|
|
savedKernelPath := defaultKernelPath
|
|
|
|
defer func() {
|
|
defaultKernelPath = savedKernelPath
|
|
}()
|
|
|
|
defaultKernelPath = testKernelPath
|
|
|
|
h := hypervisor{}
|
|
p, err := h.kernel()
|
|
assert.NoError(err)
|
|
assert.Equal(p, defaultKernelPath, "default Kernel path wrong")
|
|
|
|
// test path resolution
|
|
defaultKernelPath = testKernelLinkPath
|
|
h = hypervisor{}
|
|
p, err = h.kernel()
|
|
assert.NoError(err)
|
|
assert.Equal(p, testKernelPath)
|
|
|
|
assert.Equal(h.kernelParams(), defaultKernelParams, "default hypervisor image wrong")
|
|
kernelParams := "foo=bar xyz"
|
|
h.KernelParams = kernelParams
|
|
assert.Equal(h.kernelParams(), kernelParams, "custom hypervisor kernel parameterms wrong")
|
|
}
|
|
|
|
// The default initrd path is not returned by h.initrd()
|
|
func TestHypervisorDefaultsInitrd(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
tmpdir, err := ioutil.TempDir(testDir, "")
|
|
assert.NoError(err)
|
|
defer os.RemoveAll(tmpdir)
|
|
|
|
testInitrdPath := filepath.Join(tmpdir, "initrd")
|
|
testInitrdLinkPath := filepath.Join(tmpdir, "initrd-link")
|
|
|
|
err = createEmptyFile(testInitrdPath)
|
|
assert.NoError(err)
|
|
|
|
err = syscall.Symlink(testInitrdPath, testInitrdLinkPath)
|
|
assert.NoError(err)
|
|
|
|
savedInitrdPath := defaultInitrdPath
|
|
|
|
defer func() {
|
|
defaultInitrdPath = savedInitrdPath
|
|
}()
|
|
|
|
defaultInitrdPath = testInitrdPath
|
|
h := hypervisor{}
|
|
p, err := h.initrd()
|
|
assert.Error(err)
|
|
assert.Equal(p, "", "default Image path wrong")
|
|
|
|
// test path resolution
|
|
defaultInitrdPath = testInitrdLinkPath
|
|
h = hypervisor{}
|
|
p, err = h.initrd()
|
|
assert.Error(err)
|
|
assert.Equal(p, "")
|
|
}
|
|
|
|
// The default image path is not returned by h.image()
|
|
func TestHypervisorDefaultsImage(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
tmpdir, err := ioutil.TempDir(testDir, "")
|
|
assert.NoError(err)
|
|
defer os.RemoveAll(tmpdir)
|
|
|
|
testImagePath := filepath.Join(tmpdir, "image")
|
|
testImageLinkPath := filepath.Join(tmpdir, "image-link")
|
|
|
|
err = createEmptyFile(testImagePath)
|
|
assert.NoError(err)
|
|
|
|
err = syscall.Symlink(testImagePath, testImageLinkPath)
|
|
assert.NoError(err)
|
|
|
|
savedImagePath := defaultImagePath
|
|
|
|
defer func() {
|
|
defaultImagePath = savedImagePath
|
|
}()
|
|
|
|
defaultImagePath = testImagePath
|
|
h := hypervisor{}
|
|
p, err := h.image()
|
|
assert.Error(err)
|
|
assert.Equal(p, "", "default Image path wrong")
|
|
|
|
// test path resolution
|
|
defaultImagePath = testImageLinkPath
|
|
h = hypervisor{}
|
|
p, err = h.image()
|
|
assert.Error(err)
|
|
assert.Equal(p, "")
|
|
}
|
|
|
|
func TestHypervisorDefaultsGuestHookPath(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
h := hypervisor{}
|
|
guestHookPath := h.guestHookPath()
|
|
assert.Equal(guestHookPath, defaultGuestHookPath, "default guest hook path wrong")
|
|
|
|
testGuestHookPath := "/test/guest/hook/path"
|
|
h = hypervisor{
|
|
GuestHookPath: testGuestHookPath,
|
|
}
|
|
guestHookPath = h.guestHookPath()
|
|
assert.Equal(guestHookPath, testGuestHookPath, "custom guest hook path wrong")
|
|
}
|
|
|
|
func TestProxyDefaults(t *testing.T) {
|
|
p := proxy{}
|
|
|
|
assert.Equal(t, p.path(), defaultProxyPath, "default proxy path wrong")
|
|
|
|
path := "/foo/bar/baz/proxy"
|
|
p.Path = path
|
|
assert.Equal(t, p.path(), path, "custom proxy path wrong")
|
|
}
|
|
|
|
func TestShimDefaults(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
tmpdir, err := ioutil.TempDir(testDir, "")
|
|
assert.NoError(err)
|
|
defer os.RemoveAll(tmpdir)
|
|
|
|
testShimPath := filepath.Join(tmpdir, "shim")
|
|
testShimLinkPath := filepath.Join(tmpdir, "shim-link")
|
|
|
|
err = createEmptyFile(testShimPath)
|
|
assert.NoError(err)
|
|
|
|
err = syscall.Symlink(testShimPath, testShimLinkPath)
|
|
assert.NoError(err)
|
|
|
|
savedShimPath := defaultShimPath
|
|
|
|
defer func() {
|
|
defaultShimPath = savedShimPath
|
|
}()
|
|
|
|
defaultShimPath = testShimPath
|
|
s := shim{}
|
|
p, err := s.path()
|
|
assert.NoError(err)
|
|
assert.Equal(p, defaultShimPath, "default shim path wrong")
|
|
|
|
// test path resolution
|
|
defaultShimPath = testShimLinkPath
|
|
s = shim{}
|
|
p, err = s.path()
|
|
assert.NoError(err)
|
|
assert.Equal(p, testShimPath)
|
|
|
|
assert.False(s.debug())
|
|
s.Debug = true
|
|
assert.True(s.debug())
|
|
|
|
assert.False(s.trace())
|
|
s.Tracing = true
|
|
assert.True(s.trace())
|
|
}
|
|
|
|
func TestGetDefaultConfigFilePaths(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
results := GetDefaultConfigFilePaths()
|
|
// There should be atleast two config file locations
|
|
assert.True(len(results) >= 2)
|
|
|
|
for _, f := range results {
|
|
// Paths cannot be empty
|
|
assert.NotNil(f)
|
|
}
|
|
}
|
|
|
|
func TestGetDefaultConfigFile(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
tmpdir, err := ioutil.TempDir(testDir, "")
|
|
assert.NoError(err)
|
|
defer os.RemoveAll(tmpdir)
|
|
|
|
hypervisor := "qemu"
|
|
confDir := filepath.Join(tmpdir, "conf")
|
|
sysConfDir := filepath.Join(tmpdir, "sysconf")
|
|
|
|
for _, dir := range []string{confDir, sysConfDir} {
|
|
err = os.MkdirAll(dir, testDirMode)
|
|
assert.NoError(err)
|
|
}
|
|
|
|
confDirConfig, err := createAllRuntimeConfigFiles(confDir, hypervisor)
|
|
assert.NoError(err)
|
|
|
|
sysConfDirConfig, err := createAllRuntimeConfigFiles(sysConfDir, hypervisor)
|
|
assert.NoError(err)
|
|
|
|
savedConf := defaultRuntimeConfiguration
|
|
savedSysConf := defaultSysConfRuntimeConfiguration
|
|
|
|
defaultRuntimeConfiguration = confDirConfig.ConfigPath
|
|
defaultSysConfRuntimeConfiguration = sysConfDirConfig.ConfigPath
|
|
|
|
defer func() {
|
|
defaultRuntimeConfiguration = savedConf
|
|
defaultSysConfRuntimeConfiguration = savedSysConf
|
|
|
|
}()
|
|
|
|
got, err := getDefaultConfigFile()
|
|
assert.NoError(err)
|
|
// defaultSysConfRuntimeConfiguration has priority over defaultRuntimeConfiguration
|
|
assert.Equal(got, defaultSysConfRuntimeConfiguration)
|
|
|
|
// force defaultRuntimeConfiguration to be returned
|
|
os.Remove(defaultSysConfRuntimeConfiguration)
|
|
|
|
got, err = getDefaultConfigFile()
|
|
assert.NoError(err)
|
|
assert.Equal(got, defaultRuntimeConfiguration)
|
|
|
|
// force error
|
|
os.Remove(defaultRuntimeConfiguration)
|
|
|
|
_, err = getDefaultConfigFile()
|
|
assert.Error(err)
|
|
}
|
|
|
|
func TestDefaultBridges(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
h := hypervisor{DefaultBridges: 0}
|
|
|
|
bridges := h.defaultBridges()
|
|
assert.Equal(defaultBridgesCount, bridges)
|
|
|
|
h.DefaultBridges = maxPCIBridges + 1
|
|
bridges = h.defaultBridges()
|
|
assert.Equal(maxPCIBridges, bridges)
|
|
|
|
h.DefaultBridges = maxPCIBridges
|
|
bridges = h.defaultBridges()
|
|
assert.Equal(maxPCIBridges, bridges)
|
|
}
|
|
|
|
func TestDefaultFirmware(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
// save default firmware path
|
|
oldDefaultFirmwarePath := defaultFirmwarePath
|
|
|
|
f, err := ioutil.TempFile(os.TempDir(), "qboot.bin")
|
|
assert.NoError(err)
|
|
assert.NoError(f.Close())
|
|
defer os.RemoveAll(f.Name())
|
|
|
|
h := hypervisor{}
|
|
defaultFirmwarePath = ""
|
|
p, err := h.firmware()
|
|
assert.NoError(err)
|
|
assert.Empty(p)
|
|
|
|
defaultFirmwarePath = f.Name()
|
|
p, err = h.firmware()
|
|
assert.NoError(err)
|
|
assert.NotEmpty(p)
|
|
|
|
// restore default firmware path
|
|
defaultFirmwarePath = oldDefaultFirmwarePath
|
|
}
|
|
|
|
func TestDefaultMachineAccelerators(t *testing.T) {
|
|
assert := assert.New(t)
|
|
machineAccelerators := "abc,123,rgb"
|
|
h := hypervisor{MachineAccelerators: machineAccelerators}
|
|
assert.Equal(machineAccelerators, h.machineAccelerators())
|
|
|
|
machineAccelerators = ""
|
|
h.MachineAccelerators = machineAccelerators
|
|
assert.Equal(machineAccelerators, h.machineAccelerators())
|
|
|
|
machineAccelerators = "abc"
|
|
h.MachineAccelerators = machineAccelerators
|
|
assert.Equal(machineAccelerators, h.machineAccelerators())
|
|
|
|
machineAccelerators = "abc,123"
|
|
h.MachineAccelerators = "abc,,123"
|
|
assert.Equal(machineAccelerators, h.machineAccelerators())
|
|
|
|
machineAccelerators = "abc,123"
|
|
h.MachineAccelerators = ",,abc,,123,,,"
|
|
assert.Equal(machineAccelerators, h.machineAccelerators())
|
|
|
|
machineAccelerators = "abc,123"
|
|
h.MachineAccelerators = "abc,,123,,,"
|
|
assert.Equal(machineAccelerators, h.machineAccelerators())
|
|
|
|
machineAccelerators = "abc"
|
|
h.MachineAccelerators = ",,abc,"
|
|
assert.Equal(machineAccelerators, h.machineAccelerators())
|
|
|
|
machineAccelerators = "abc"
|
|
h.MachineAccelerators = ", , abc , ,"
|
|
assert.Equal(machineAccelerators, h.machineAccelerators())
|
|
|
|
machineAccelerators = "abc"
|
|
h.MachineAccelerators = " abc "
|
|
assert.Equal(machineAccelerators, h.machineAccelerators())
|
|
|
|
machineAccelerators = "abc,123"
|
|
h.MachineAccelerators = ", abc , 123 ,"
|
|
assert.Equal(machineAccelerators, h.machineAccelerators())
|
|
|
|
machineAccelerators = "abc,123"
|
|
h.MachineAccelerators = ",, abc ,,, 123 ,,"
|
|
assert.Equal(machineAccelerators, h.machineAccelerators())
|
|
}
|
|
|
|
func TestUpdateRuntimeConfiguration(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
assert.NotEqual(defaultAgent, vc.HyperstartAgent)
|
|
|
|
config := oci.RuntimeConfig{}
|
|
|
|
tomlConf := tomlConfig{
|
|
Agent: map[string]agent{
|
|
// force a non-default value
|
|
kataAgentTableType: {},
|
|
},
|
|
}
|
|
|
|
assert.NotEqual(config.AgentType, vc.AgentType(kataAgentTableType))
|
|
assert.NotEqual(config.AgentConfig, vc.KataAgentConfig{})
|
|
|
|
err := updateRuntimeConfig("", tomlConf, &config, false)
|
|
assert.NoError(err)
|
|
|
|
assert.Equal(config.AgentType, vc.AgentType(kataAgentTableType))
|
|
assert.Equal(config.AgentConfig, vc.KataAgentConfig{})
|
|
}
|
|
|
|
func TestUpdateRuntimeConfigurationVMConfig(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
vcpus := uint(2)
|
|
mem := uint32(2048)
|
|
|
|
config := oci.RuntimeConfig{}
|
|
expectedVMConfig := mem
|
|
|
|
tomlConf := tomlConfig{
|
|
Hypervisor: map[string]hypervisor{
|
|
qemuHypervisorTableType: {
|
|
NumVCPUs: int32(vcpus),
|
|
MemorySize: uint32(mem),
|
|
Path: "/",
|
|
Kernel: "/",
|
|
Image: "/",
|
|
Firmware: "/",
|
|
},
|
|
},
|
|
}
|
|
|
|
err := updateRuntimeConfig("", tomlConf, &config, false)
|
|
assert.NoError(err)
|
|
|
|
assert.Equal(expectedVMConfig, config.HypervisorConfig.MemorySize)
|
|
}
|
|
|
|
func TestUpdateRuntimeConfigurationFactoryConfig(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
config := oci.RuntimeConfig{}
|
|
expectedFactoryConfig := oci.FactoryConfig{
|
|
Template: true,
|
|
VMCacheEndpoint: defaultVMCacheEndpoint,
|
|
}
|
|
|
|
tomlConf := tomlConfig{Factory: factory{Template: true}}
|
|
|
|
err := updateRuntimeConfig("", tomlConf, &config, false)
|
|
assert.NoError(err)
|
|
|
|
assert.Equal(expectedFactoryConfig, config.FactoryConfig)
|
|
}
|
|
|
|
func TestUpdateRuntimeConfigurationInvalidKernelParams(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
assert.NotEqual(defaultAgent, vc.HyperstartAgent)
|
|
|
|
config := oci.RuntimeConfig{}
|
|
|
|
tomlConf := tomlConfig{}
|
|
|
|
savedFunc := GetKernelParamsFunc
|
|
defer func() {
|
|
GetKernelParamsFunc = savedFunc
|
|
}()
|
|
|
|
GetKernelParamsFunc = func(needSystemd bool) []vc.Param {
|
|
return []vc.Param{
|
|
{
|
|
Key: "",
|
|
Value: "",
|
|
},
|
|
}
|
|
}
|
|
|
|
err := updateRuntimeConfig("", tomlConf, &config, false)
|
|
assert.EqualError(err, "Empty kernel parameter")
|
|
}
|
|
|
|
func TestCheckHypervisorConfig(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
dir, err := ioutil.TempDir(testDir, "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.RemoveAll(dir)
|
|
|
|
// Not created on purpose
|
|
imageENOENT := filepath.Join(dir, "image-ENOENT.img")
|
|
initrdENOENT := filepath.Join(dir, "initrd-ENOENT.img")
|
|
|
|
imageEmpty := filepath.Join(dir, "image-empty.img")
|
|
initrdEmpty := filepath.Join(dir, "initrd-empty.img")
|
|
|
|
for _, file := range []string{imageEmpty, initrdEmpty} {
|
|
err = createEmptyFile(file)
|
|
assert.NoError(err)
|
|
}
|
|
|
|
image := filepath.Join(dir, "image.img")
|
|
initrd := filepath.Join(dir, "initrd.img")
|
|
|
|
mb := uint32(1024 * 1024)
|
|
|
|
fileSizeMB := uint32(3)
|
|
fileSizeBytes := fileSizeMB * mb
|
|
|
|
fileData := strings.Repeat("X", int(fileSizeBytes))
|
|
|
|
for _, file := range []string{image, initrd} {
|
|
err = WriteFile(file, fileData, testFileMode)
|
|
assert.NoError(err)
|
|
}
|
|
|
|
type testData struct {
|
|
imagePath string
|
|
initrdPath string
|
|
memBytes uint32
|
|
expectError bool
|
|
expectLogWarning bool
|
|
}
|
|
|
|
// Note that checkHypervisorConfig() does not check to ensure an image
|
|
// or an initrd has been specified - that's handled by a separate
|
|
// function, hence no test for it here.
|
|
|
|
data := []testData{
|
|
{"", "", 0, true, false},
|
|
|
|
{imageENOENT, "", 2, true, false},
|
|
{"", initrdENOENT, 2, true, false},
|
|
|
|
{imageEmpty, "", 2, true, false},
|
|
{"", initrdEmpty, 2, true, false},
|
|
|
|
{image, "", fileSizeMB + 2, false, false},
|
|
{image, "", fileSizeMB + 1, false, false},
|
|
{image, "", fileSizeMB + 0, false, true},
|
|
{image, "", fileSizeMB - 1, false, true},
|
|
{image, "", fileSizeMB - 2, false, true},
|
|
|
|
{"", initrd, fileSizeMB + 2, false, false},
|
|
{"", initrd, fileSizeMB + 1, false, false},
|
|
{"", initrd, fileSizeMB + 0, true, false},
|
|
{"", initrd, fileSizeMB - 1, true, false},
|
|
{"", initrd, fileSizeMB - 2, true, false},
|
|
}
|
|
|
|
for i, d := range data {
|
|
savedOut := kataUtilsLogger.Logger.Out
|
|
|
|
// create buffer to save logger output
|
|
logBuf := &bytes.Buffer{}
|
|
|
|
// capture output to buffer
|
|
kataUtilsLogger.Logger.Out = logBuf
|
|
|
|
config := vc.HypervisorConfig{
|
|
ImagePath: d.imagePath,
|
|
InitrdPath: d.initrdPath,
|
|
MemorySize: d.memBytes,
|
|
}
|
|
|
|
err := checkHypervisorConfig(config)
|
|
|
|
if d.expectError {
|
|
assert.Error(err, "test %d (%+v)", i, d)
|
|
} else {
|
|
assert.NoError(err, "test %d (%+v)", i, d)
|
|
}
|
|
|
|
if d.expectLogWarning {
|
|
assert.True(strings.Contains(logBuf.String(), "warning"))
|
|
} else {
|
|
assert.Empty(logBuf.String())
|
|
}
|
|
|
|
// reset logger
|
|
kataUtilsLogger.Logger.Out = savedOut
|
|
}
|
|
}
|
|
|
|
func TestCheckNetNsConfig(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
config := oci.RuntimeConfig{
|
|
DisableNewNetNs: true,
|
|
NetmonConfig: vc.NetmonConfig{
|
|
Enable: true,
|
|
},
|
|
}
|
|
err := checkNetNsConfig(config)
|
|
assert.Error(err)
|
|
|
|
config = oci.RuntimeConfig{
|
|
DisableNewNetNs: true,
|
|
InterNetworkModel: vc.NetXConnectDefaultModel,
|
|
}
|
|
err = checkNetNsConfig(config)
|
|
assert.Error(err)
|
|
}
|
|
|
|
func TestCheckFactoryConfig(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
type testData struct {
|
|
factoryEnabled bool
|
|
imagePath string
|
|
initrdPath string
|
|
expectError bool
|
|
}
|
|
|
|
data := []testData{
|
|
{false, "", "", false},
|
|
{false, "image", "", false},
|
|
{false, "", "initrd", false},
|
|
|
|
{true, "", "initrd", false},
|
|
{true, "image", "", true},
|
|
}
|
|
|
|
for i, d := range data {
|
|
config := oci.RuntimeConfig{
|
|
HypervisorConfig: vc.HypervisorConfig{
|
|
ImagePath: d.imagePath,
|
|
InitrdPath: d.initrdPath,
|
|
},
|
|
|
|
FactoryConfig: oci.FactoryConfig{
|
|
Template: d.factoryEnabled,
|
|
},
|
|
}
|
|
|
|
err := checkFactoryConfig(config)
|
|
|
|
if d.expectError {
|
|
assert.Error(err, "test %d (%+v)", i, d)
|
|
} else {
|
|
assert.NoError(err, "test %d (%+v)", i, d)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCheckNetNsConfigShimTrace(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
type testData struct {
|
|
disableNetNs bool
|
|
networkModel vc.NetInterworkingModel
|
|
shimTrace bool
|
|
expectError bool
|
|
}
|
|
|
|
data := []testData{
|
|
{false, vc.NetXConnectMacVtapModel, false, false},
|
|
{false, vc.NetXConnectMacVtapModel, true, true},
|
|
{true, vc.NetXConnectMacVtapModel, true, true},
|
|
{true, vc.NetXConnectMacVtapModel, false, true},
|
|
{true, vc.NetXConnectNoneModel, false, false},
|
|
{true, vc.NetXConnectNoneModel, true, false},
|
|
}
|
|
|
|
for i, d := range data {
|
|
config := oci.RuntimeConfig{
|
|
DisableNewNetNs: d.disableNetNs,
|
|
InterNetworkModel: d.networkModel,
|
|
ShimConfig: vc.ShimConfig{
|
|
Trace: d.shimTrace,
|
|
},
|
|
}
|
|
|
|
err := checkNetNsConfig(config)
|
|
|
|
if d.expectError {
|
|
assert.Error(err, "test %d (%+v)", i, d)
|
|
} else {
|
|
assert.NoError(err, "test %d (%+v)", i, d)
|
|
}
|
|
}
|
|
}
|