mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-10-21 20:08:54 +00:00
This is a virtcontainers 1.0.8 import into Kata Containers runtime. virtcontainers is a Go library designed to manage hardware virtualized pods and containers. It is the core Clear Containers framework and will become the core Kata Containers framework, as discussed at https://github.com/kata-containers/runtime/issues/33 Some more more pointers: virtcontainers README, including some design and architecure notes: https://github.com/containers/virtcontainers/blob/master/README.md virtcontainers 1.0 API: https://github.com/containers/virtcontainers/blob/master/documentation/api/1.0/api.md Fixes #40 Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
329 lines
7.0 KiB
Go
329 lines
7.0 KiB
Go
//
|
|
// Copyright (c) 2016 Intel Corporation
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
|
|
package virtcontainers
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"testing"
|
|
|
|
govmmQemu "github.com/intel/govmm/qemu"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func newQemuConfig() HypervisorConfig {
|
|
return HypervisorConfig{
|
|
KernelPath: testQemuKernelPath,
|
|
ImagePath: testQemuImagePath,
|
|
HypervisorPath: testQemuPath,
|
|
DefaultVCPUs: defaultVCPUs,
|
|
DefaultMemSz: defaultMemSzMiB,
|
|
DefaultBridges: defaultBridges,
|
|
BlockDeviceDriver: defaultBlockDriver,
|
|
DefaultMaxVCPUs: defaultMaxQemuVCPUs,
|
|
}
|
|
}
|
|
|
|
func testQemuKernelParameters(t *testing.T, kernelParams []Param, expected string, debug bool) {
|
|
qemuConfig := newQemuConfig()
|
|
qemuConfig.KernelParams = kernelParams
|
|
|
|
if debug == true {
|
|
qemuConfig.Debug = true
|
|
}
|
|
|
|
q := &qemu{
|
|
config: qemuConfig,
|
|
arch: &qemuArchBase{},
|
|
}
|
|
|
|
params := q.kernelParameters()
|
|
if params != expected {
|
|
t.Fatalf("Got: %v, Expecting: %v", params, expected)
|
|
}
|
|
}
|
|
|
|
func TestQemuKernelParameters(t *testing.T) {
|
|
expectedOut := "panic=1 initcall_debug foo=foo bar=bar"
|
|
params := []Param{
|
|
{
|
|
Key: "foo",
|
|
Value: "foo",
|
|
},
|
|
{
|
|
Key: "bar",
|
|
Value: "bar",
|
|
},
|
|
}
|
|
|
|
testQemuKernelParameters(t, params, expectedOut, true)
|
|
testQemuKernelParameters(t, params, expectedOut, false)
|
|
}
|
|
|
|
func TestQemuInit(t *testing.T) {
|
|
qemuConfig := newQemuConfig()
|
|
q := &qemu{}
|
|
|
|
pod := &Pod{
|
|
id: "testPod",
|
|
storage: &filesystem{},
|
|
config: &PodConfig{
|
|
HypervisorConfig: qemuConfig,
|
|
},
|
|
}
|
|
|
|
// Create parent dir path for hypervisor.json
|
|
parentDir := filepath.Join(runStoragePath, pod.id)
|
|
if err := os.MkdirAll(parentDir, dirMode); err != nil {
|
|
t.Fatalf("Could not create parent directory %s: %v", parentDir, err)
|
|
}
|
|
|
|
if err := q.init(pod); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := os.RemoveAll(parentDir); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if reflect.DeepEqual(qemuConfig, q.config) == false {
|
|
t.Fatalf("Got %v\nExpecting %v", q.config, qemuConfig)
|
|
}
|
|
}
|
|
|
|
func TestQemuInitMissingParentDirFail(t *testing.T) {
|
|
qemuConfig := newQemuConfig()
|
|
q := &qemu{}
|
|
|
|
pod := &Pod{
|
|
id: "testPod",
|
|
storage: &filesystem{},
|
|
config: &PodConfig{
|
|
HypervisorConfig: qemuConfig,
|
|
},
|
|
}
|
|
|
|
// Ensure parent dir path for hypervisor.json does not exist.
|
|
parentDir := filepath.Join(runStoragePath, pod.id)
|
|
if err := os.RemoveAll(parentDir); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := q.init(pod); err == nil {
|
|
t.Fatal("Qemu init() expected to fail because of missing parent directory for storage")
|
|
}
|
|
}
|
|
|
|
func TestQemuCPUTopology(t *testing.T) {
|
|
vcpus := 1
|
|
|
|
q := &qemu{
|
|
arch: &qemuArchBase{},
|
|
config: HypervisorConfig{
|
|
DefaultVCPUs: uint32(vcpus),
|
|
},
|
|
}
|
|
|
|
expectedOut := govmmQemu.SMP{
|
|
CPUs: uint32(vcpus),
|
|
Sockets: uint32(vcpus),
|
|
Cores: defaultCores,
|
|
Threads: defaultThreads,
|
|
MaxCPUs: defaultMaxQemuVCPUs,
|
|
}
|
|
|
|
smp := q.cpuTopology()
|
|
|
|
if reflect.DeepEqual(smp, expectedOut) == false {
|
|
t.Fatalf("Got %v\nExpecting %v", smp, expectedOut)
|
|
}
|
|
}
|
|
|
|
func TestQemuMemoryTopology(t *testing.T) {
|
|
mem := 1000
|
|
|
|
q := &qemu{
|
|
arch: &qemuArchBase{},
|
|
}
|
|
|
|
hostMemKb, err := getHostMemorySizeKb(procMemInfo)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
memMax := fmt.Sprintf("%dM", int(float64(hostMemKb)/1024))
|
|
|
|
expectedOut := govmmQemu.Memory{
|
|
Size: fmt.Sprintf("%dM", mem),
|
|
Slots: defaultMemSlots,
|
|
MaxMem: memMax,
|
|
}
|
|
|
|
vmConfig := Resources{
|
|
Memory: uint(mem),
|
|
}
|
|
|
|
podConfig := PodConfig{
|
|
VMConfig: vmConfig,
|
|
}
|
|
|
|
memory, err := q.memoryTopology(podConfig)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if reflect.DeepEqual(memory, expectedOut) == false {
|
|
t.Fatalf("Got %v\nExpecting %v", memory, expectedOut)
|
|
}
|
|
}
|
|
|
|
func testQemuAddDevice(t *testing.T, devInfo interface{}, devType deviceType, expected []govmmQemu.Device) {
|
|
q := &qemu{
|
|
arch: &qemuArchBase{},
|
|
}
|
|
|
|
err := q.addDevice(devInfo, devType)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if reflect.DeepEqual(q.qemuConfig.Devices, expected) == false {
|
|
t.Fatalf("Got %v\nExpecting %v", q.qemuConfig.Devices, expected)
|
|
}
|
|
}
|
|
|
|
func TestQemuAddDeviceFsDev(t *testing.T) {
|
|
mountTag := "testMountTag"
|
|
hostPath := "testHostPath"
|
|
|
|
expectedOut := []govmmQemu.Device{
|
|
govmmQemu.FSDevice{
|
|
Driver: govmmQemu.Virtio9P,
|
|
FSDriver: govmmQemu.Local,
|
|
ID: fmt.Sprintf("extra-9p-%s", mountTag),
|
|
Path: hostPath,
|
|
MountTag: mountTag,
|
|
SecurityModel: govmmQemu.None,
|
|
},
|
|
}
|
|
|
|
volume := Volume{
|
|
MountTag: mountTag,
|
|
HostPath: hostPath,
|
|
}
|
|
|
|
testQemuAddDevice(t, volume, fsDev, expectedOut)
|
|
}
|
|
|
|
func TestQemuAddDeviceSerialPortDev(t *testing.T) {
|
|
deviceID := "channelTest"
|
|
id := "charchTest"
|
|
hostPath := "/tmp/hyper_test.sock"
|
|
name := "sh.hyper.channel.test"
|
|
|
|
expectedOut := []govmmQemu.Device{
|
|
govmmQemu.CharDevice{
|
|
Driver: govmmQemu.VirtioSerialPort,
|
|
Backend: govmmQemu.Socket,
|
|
DeviceID: deviceID,
|
|
ID: id,
|
|
Path: hostPath,
|
|
Name: name,
|
|
},
|
|
}
|
|
|
|
socket := Socket{
|
|
DeviceID: deviceID,
|
|
ID: id,
|
|
HostPath: hostPath,
|
|
Name: name,
|
|
}
|
|
|
|
testQemuAddDevice(t, socket, serialPortDev, expectedOut)
|
|
}
|
|
|
|
func TestQemuGetPodConsole(t *testing.T) {
|
|
q := &qemu{}
|
|
podID := "testPodID"
|
|
expected := filepath.Join(runStoragePath, podID, defaultConsole)
|
|
|
|
if result := q.getPodConsole(podID); result != expected {
|
|
t.Fatalf("Got %s\nExpecting %s", result, expected)
|
|
}
|
|
}
|
|
|
|
func TestQemuCapabilities(t *testing.T) {
|
|
q := &qemu{
|
|
arch: &qemuArchBase{},
|
|
}
|
|
|
|
caps := q.capabilities()
|
|
if !caps.isBlockDeviceHotplugSupported() {
|
|
t.Fatal("Block device hotplug should be supported")
|
|
}
|
|
}
|
|
|
|
func TestQemuQemuPath(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
f, err := ioutil.TempFile("", "qemu")
|
|
assert.NoError(err)
|
|
defer func() { _ = f.Close() }()
|
|
defer func() { _ = os.Remove(f.Name()) }()
|
|
|
|
expectedPath := f.Name()
|
|
qemuConfig := newQemuConfig()
|
|
qemuConfig.HypervisorPath = expectedPath
|
|
qkvm := &qemuArchBase{
|
|
machineType: "pc",
|
|
qemuPaths: map[string]string{
|
|
"pc": expectedPath,
|
|
},
|
|
}
|
|
|
|
q := &qemu{
|
|
config: qemuConfig,
|
|
arch: qkvm,
|
|
}
|
|
|
|
// get config hypervisor path
|
|
path, err := q.qemuPath()
|
|
assert.NoError(err)
|
|
assert.Equal(path, expectedPath)
|
|
|
|
// config hypervisor path does not exist
|
|
q.config.HypervisorPath = "/abc/rgb/123"
|
|
path, err = q.qemuPath()
|
|
assert.Error(err)
|
|
assert.Equal(path, "")
|
|
|
|
// get arch hypervisor path
|
|
q.config.HypervisorPath = ""
|
|
path, err = q.qemuPath()
|
|
assert.NoError(err)
|
|
assert.Equal(path, expectedPath)
|
|
|
|
// bad machine type, arch should fail
|
|
qkvm.machineType = "rgb"
|
|
q.arch = qkvm
|
|
path, err = q.qemuPath()
|
|
assert.Error(err)
|
|
assert.Equal(path, "")
|
|
}
|