mirror of
https://github.com/aljazceru/kata-containers.git
synced 2026-01-31 20:24:20 +01:00
Add a new hypervisor capability to tell if it supports device hotplug. If not, we should run prestart hooks before starting new VMs as nerdctl is using the prestart hooks to set up netns. To make nerdctl + FC to work, we need to run the prestart hooks before starting new VMs. Fixes: #6384 Signed-off-by: Peng Tao <bergwolf@hyper.sh>
306 lines
6.6 KiB
Go
306 lines
6.6 KiB
Go
// Copyright (c) 2019 Intel Corporation
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
//go:build linux
|
|
// +build linux
|
|
|
|
package virtcontainers
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/kata-containers/kata-containers/src/runtime/pkg/device/config"
|
|
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/persist/fs"
|
|
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/types"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
const (
|
|
acrnArchBaseAcrnPath = "/usr/bin/acrn"
|
|
acrnArchBaseAcrnCtlPath = "/usr/bin/acrnctl"
|
|
)
|
|
|
|
var acrnArchBaseKernelParamsNonDebug = []Param{
|
|
{"quiet", ""},
|
|
}
|
|
|
|
var acrnArchBaseKernelParamsDebug = []Param{
|
|
{"debug", ""},
|
|
}
|
|
|
|
var acrnArchBaseKernelParams = []Param{
|
|
{"root", "/dev/vda"},
|
|
}
|
|
|
|
func newAcrnArchBase() *acrnArchBase {
|
|
return &acrnArchBase{
|
|
path: acrnArchBaseAcrnPath,
|
|
ctlpath: acrnArchBaseAcrnCtlPath,
|
|
kernelParamsNonDebug: acrnArchBaseKernelParamsNonDebug,
|
|
kernelParamsDebug: acrnArchBaseKernelParamsDebug,
|
|
kernelParams: acrnArchBaseKernelParams,
|
|
}
|
|
}
|
|
|
|
func TestAcrnArchBaseAcrnPaths(t *testing.T) {
|
|
assert := assert.New(t)
|
|
acrnArchBase := newAcrnArchBase()
|
|
|
|
p, err := acrnArchBase.acrnPath()
|
|
assert.NoError(err)
|
|
assert.Equal(p, acrnArchBaseAcrnPath)
|
|
|
|
ctlp, err := acrnArchBase.acrnctlPath()
|
|
assert.NoError(err)
|
|
assert.Equal(ctlp, acrnArchBaseAcrnCtlPath)
|
|
}
|
|
|
|
func TestAcrnArchBaseKernelParameters(t *testing.T) {
|
|
assert := assert.New(t)
|
|
acrnArchBase := newAcrnArchBase()
|
|
|
|
// with debug params
|
|
expectedParams := acrnArchBaseKernelParams
|
|
debugParams := acrnArchBaseKernelParamsDebug
|
|
expectedParams = append(expectedParams, debugParams...)
|
|
p := acrnArchBase.kernelParameters(true)
|
|
assert.Equal(expectedParams, p)
|
|
|
|
// with non-debug params
|
|
expectedParams = acrnArchBaseKernelParams
|
|
nonDebugParams := acrnArchBaseKernelParamsNonDebug
|
|
expectedParams = append(expectedParams, nonDebugParams...)
|
|
p = acrnArchBase.kernelParameters(false)
|
|
assert.Equal(expectedParams, p)
|
|
}
|
|
|
|
func TestAcrnArchBaseCapabilities(t *testing.T) {
|
|
assert := assert.New(t)
|
|
acrnArchBase := newAcrnArchBase()
|
|
config := HypervisorConfig{}
|
|
|
|
c := acrnArchBase.capabilities(config)
|
|
assert.True(c.IsBlockDeviceSupported())
|
|
assert.True(c.IsBlockDeviceHotplugSupported())
|
|
assert.False(c.IsFsSharingSupported())
|
|
assert.True(c.IsNetworkDeviceHotplugSupported())
|
|
}
|
|
|
|
func TestAcrnArchBaseMemoryTopology(t *testing.T) {
|
|
assert := assert.New(t)
|
|
acrnArchBase := newAcrnArchBase()
|
|
|
|
mem := uint64(8192)
|
|
|
|
expectedMemory := Memory{
|
|
Size: fmt.Sprintf("%dM", mem),
|
|
}
|
|
|
|
m := acrnArchBase.memoryTopology(mem)
|
|
assert.Equal(expectedMemory, m)
|
|
}
|
|
|
|
func TestAcrnArchBaseAppendConsoles(t *testing.T) {
|
|
var devices []Device
|
|
assert := assert.New(t)
|
|
acrnArchBase := newAcrnArchBase()
|
|
|
|
path := filepath.Join(filepath.Join(fs.MockRunStoragePath(), "test"), consoleSocket)
|
|
|
|
expectedOut := []Device{
|
|
ConsoleDevice{
|
|
Name: "console0",
|
|
Backend: Socket,
|
|
PortType: ConsoleBE,
|
|
Path: path,
|
|
},
|
|
}
|
|
|
|
devices = acrnArchBase.appendConsole(devices, path)
|
|
assert.Equal(expectedOut, devices)
|
|
}
|
|
|
|
func TestAcrnArchBaseAppendImage(t *testing.T) {
|
|
var devices []Device
|
|
assert := assert.New(t)
|
|
acrnArchBase := newAcrnArchBase()
|
|
|
|
image, err := os.CreateTemp("", "img")
|
|
assert.NoError(err)
|
|
defer os.Remove(image.Name())
|
|
err = image.Close()
|
|
assert.NoError(err)
|
|
|
|
devices, err = acrnArchBase.appendImage(devices, image.Name())
|
|
assert.NoError(err)
|
|
assert.Len(devices, 1)
|
|
|
|
expectedOut := []Device{
|
|
BlockDevice{
|
|
FilePath: image.Name(),
|
|
Index: 0,
|
|
},
|
|
}
|
|
|
|
assert.Equal(expectedOut, devices)
|
|
}
|
|
|
|
func TestAcrnArchBaseAppendBridges(t *testing.T) {
|
|
function := 0
|
|
emul := acrnHostBridge
|
|
config := ""
|
|
|
|
var devices []Device
|
|
assert := assert.New(t)
|
|
acrnArchBase := newAcrnArchBase()
|
|
|
|
devices = acrnArchBase.appendBridges(devices)
|
|
assert.Len(devices, 1)
|
|
|
|
expectedOut := []Device{
|
|
BridgeDevice{
|
|
Function: function,
|
|
Emul: emul,
|
|
Config: config,
|
|
},
|
|
}
|
|
|
|
assert.Equal(expectedOut, devices)
|
|
}
|
|
|
|
func TestAcrnArchBaseAppendLpcDevice(t *testing.T) {
|
|
function := 0
|
|
emul := acrnLPCDev
|
|
|
|
var devices []Device
|
|
assert := assert.New(t)
|
|
acrnArchBase := newAcrnArchBase()
|
|
|
|
devices = acrnArchBase.appendLPC(devices)
|
|
assert.Len(devices, 1)
|
|
|
|
expectedOut := []Device{
|
|
LPCDevice{
|
|
Function: function,
|
|
Emul: emul,
|
|
},
|
|
}
|
|
|
|
assert.Equal(expectedOut, devices)
|
|
}
|
|
|
|
func testAcrnArchBaseAppend(t *testing.T, structure interface{}, expected []Device) {
|
|
var devices []Device
|
|
var err error
|
|
assert := assert.New(t)
|
|
acrnArchBase := newAcrnArchBase()
|
|
|
|
switch s := structure.(type) {
|
|
case types.Socket:
|
|
devices = acrnArchBase.appendSocket(devices, s)
|
|
case config.BlockDrive:
|
|
devices = acrnArchBase.appendBlockDevice(devices, s)
|
|
}
|
|
|
|
assert.NoError(err)
|
|
assert.Equal(devices, expected)
|
|
}
|
|
|
|
func TestAcrnArchBaseAppendSocket(t *testing.T) {
|
|
name := "archserial.test"
|
|
hostPath := "/tmp/archserial.sock"
|
|
|
|
expectedOut := []Device{
|
|
ConsoleDevice{
|
|
Name: name,
|
|
Backend: Socket,
|
|
PortType: SerialBE,
|
|
Path: hostPath,
|
|
},
|
|
}
|
|
|
|
socket := types.Socket{
|
|
HostPath: hostPath,
|
|
Name: name,
|
|
}
|
|
|
|
testAcrnArchBaseAppend(t, socket, expectedOut)
|
|
}
|
|
|
|
func TestAcrnArchBaseAppendBlockDevice(t *testing.T) {
|
|
path := "/tmp/archtest.img"
|
|
index := 5
|
|
|
|
expectedOut := []Device{
|
|
BlockDevice{
|
|
FilePath: path,
|
|
Index: index,
|
|
},
|
|
}
|
|
|
|
drive := config.BlockDrive{
|
|
File: path,
|
|
Index: index,
|
|
}
|
|
|
|
testAcrnArchBaseAppend(t, drive, expectedOut)
|
|
}
|
|
|
|
func TestAcrnArchBaseAppendNetwork(t *testing.T) {
|
|
var devices []Device
|
|
assert := assert.New(t)
|
|
acrnArchBase := newAcrnArchBase()
|
|
|
|
macAddr := net.HardwareAddr{0x02, 0x00, 0xCA, 0xFE, 0x00, 0x04}
|
|
|
|
vethEp := &VethEndpoint{
|
|
NetPair: NetworkInterfacePair{
|
|
TapInterface: TapInterface{
|
|
ID: "uniqueTestID0",
|
|
Name: "br0_kata",
|
|
TAPIface: NetworkInterface{
|
|
Name: "tap0_kata",
|
|
},
|
|
},
|
|
VirtIface: NetworkInterface{
|
|
Name: "eth0",
|
|
HardAddr: macAddr.String(),
|
|
},
|
|
NetInterworkingModel: DefaultNetInterworkingModel,
|
|
},
|
|
EndpointType: VethEndpointType,
|
|
}
|
|
|
|
macvtapEp := &MacvtapEndpoint{
|
|
EndpointType: MacvtapEndpointType,
|
|
EndpointProperties: NetworkInfo{
|
|
Iface: NetlinkIface{
|
|
Type: "macvtap",
|
|
},
|
|
},
|
|
}
|
|
|
|
expectedOut := []Device{
|
|
NetDevice{
|
|
Type: TAP,
|
|
IFName: vethEp.NetPair.TAPIface.Name,
|
|
MACAddress: vethEp.NetPair.TAPIface.HardAddr,
|
|
},
|
|
NetDevice{
|
|
Type: MACVTAP,
|
|
IFName: macvtapEp.Name(),
|
|
MACAddress: macvtapEp.HardwareAddr(),
|
|
},
|
|
}
|
|
|
|
devices = acrnArchBase.appendNetwork(devices, vethEp)
|
|
devices = acrnArchBase.appendNetwork(devices, macvtapEp)
|
|
assert.Equal(expectedOut, devices)
|
|
}
|