mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-08-27 12:08:58 +00:00
Merge pull request #1122 from sameo/topic/asset-types
virtcontainers: Add Asset, Capabilities and Bridge to the types package
This commit is contained in:
commit
e03caf6234
@ -137,7 +137,7 @@ type agent interface {
|
|||||||
|
|
||||||
// capabilities should return a structure that specifies the capabilities
|
// capabilities should return a structure that specifies the capabilities
|
||||||
// supported by the agent.
|
// supported by the agent.
|
||||||
capabilities() capabilities
|
capabilities() types.Capabilities
|
||||||
|
|
||||||
// check will check the agent liveness
|
// check will check the agent liveness
|
||||||
check() error
|
check() error
|
||||||
|
@ -1,58 +0,0 @@
|
|||||||
// Copyright (c) 2017 Intel Corporation
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
//
|
|
||||||
|
|
||||||
package virtcontainers
|
|
||||||
|
|
||||||
const (
|
|
||||||
blockDeviceSupport = 1 << iota
|
|
||||||
blockDeviceHotplugSupport
|
|
||||||
multiQueueSupport
|
|
||||||
fsSharingUnsupported
|
|
||||||
)
|
|
||||||
|
|
||||||
type capabilities struct {
|
|
||||||
flags uint
|
|
||||||
}
|
|
||||||
|
|
||||||
func (caps *capabilities) isBlockDeviceSupported() bool {
|
|
||||||
if caps.flags&blockDeviceSupport != 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (caps *capabilities) setBlockDeviceSupport() {
|
|
||||||
caps.flags = caps.flags | blockDeviceSupport
|
|
||||||
}
|
|
||||||
|
|
||||||
func (caps *capabilities) isBlockDeviceHotplugSupported() bool {
|
|
||||||
if caps.flags&blockDeviceHotplugSupport != 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (caps *capabilities) setBlockDeviceHotplugSupport() {
|
|
||||||
caps.flags |= blockDeviceHotplugSupport
|
|
||||||
}
|
|
||||||
|
|
||||||
func (caps *capabilities) isMultiQueueSupported() bool {
|
|
||||||
if caps.flags&multiQueueSupport != 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (caps *capabilities) setMultiQueueSupport() {
|
|
||||||
caps.flags |= multiQueueSupport
|
|
||||||
}
|
|
||||||
|
|
||||||
func (caps *capabilities) isFsSharingSupported() bool {
|
|
||||||
return caps.flags&fsSharingUnsupported == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (caps *capabilities) setFsSharingUnsupported() {
|
|
||||||
caps.flags |= fsSharingUnsupported
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
// Copyright (c) 2017 Intel Corporation
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
//
|
|
||||||
|
|
||||||
package virtcontainers
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func TestBlockDeviceCapability(t *testing.T) {
|
|
||||||
var caps capabilities
|
|
||||||
|
|
||||||
if caps.isBlockDeviceSupported() {
|
|
||||||
t.Fatal()
|
|
||||||
}
|
|
||||||
|
|
||||||
caps.setBlockDeviceSupport()
|
|
||||||
|
|
||||||
if !caps.isBlockDeviceSupported() {
|
|
||||||
t.Fatal()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBlockDeviceHotplugCapability(t *testing.T) {
|
|
||||||
var caps capabilities
|
|
||||||
|
|
||||||
if caps.isBlockDeviceHotplugSupported() {
|
|
||||||
t.Fatal()
|
|
||||||
}
|
|
||||||
|
|
||||||
caps.setBlockDeviceHotplugSupport()
|
|
||||||
|
|
||||||
if !caps.isBlockDeviceHotplugSupported() {
|
|
||||||
t.Fatal()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFsSharingCapability(t *testing.T) {
|
|
||||||
var caps capabilities
|
|
||||||
|
|
||||||
if !caps.isFsSharingSupported() {
|
|
||||||
t.Fatal()
|
|
||||||
}
|
|
||||||
|
|
||||||
caps.setFsSharingUnsupported()
|
|
||||||
|
|
||||||
if caps.isFsSharingSupported() {
|
|
||||||
t.Fatal()
|
|
||||||
}
|
|
||||||
}
|
|
@ -445,7 +445,7 @@ func (c *Container) shareFiles(m Mount, idx int, hostSharedDir, guestSharedDir s
|
|||||||
// copy file to contaier's rootfs if filesystem sharing is not supported, otherwise
|
// copy file to contaier's rootfs if filesystem sharing is not supported, otherwise
|
||||||
// bind mount it in the shared directory.
|
// bind mount it in the shared directory.
|
||||||
caps := c.sandbox.hypervisor.capabilities()
|
caps := c.sandbox.hypervisor.capabilities()
|
||||||
if !caps.isFsSharingSupported() {
|
if !caps.IsFsSharingSupported() {
|
||||||
c.Logger().Debug("filesystem sharing is not supported, files will be copied")
|
c.Logger().Debug("filesystem sharing is not supported, files will be copied")
|
||||||
|
|
||||||
fileInfo, err := os.Stat(m.Source)
|
fileInfo, err := os.Stat(m.Source)
|
||||||
@ -713,7 +713,7 @@ func (c *Container) checkBlockDeviceSupport() bool {
|
|||||||
agentCaps := c.sandbox.agent.capabilities()
|
agentCaps := c.sandbox.agent.capabilities()
|
||||||
hypervisorCaps := c.sandbox.hypervisor.capabilities()
|
hypervisorCaps := c.sandbox.hypervisor.capabilities()
|
||||||
|
|
||||||
if agentCaps.isBlockDeviceSupported() && hypervisorCaps.isBlockDeviceHotplugSupported() {
|
if agentCaps.IsBlockDeviceSupported() && hypervisorCaps.IsBlockDeviceHotplugSupported() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/kata-containers/runtime/virtcontainers/device/config"
|
"github.com/kata-containers/runtime/virtcontainers/device/config"
|
||||||
|
"github.com/kata-containers/runtime/virtcontainers/types"
|
||||||
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -656,12 +657,12 @@ func (fc *firecracker) disconnect() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Adds all capabilities supported by firecracker implementation of hypervisor interface
|
// Adds all capabilities supported by firecracker implementation of hypervisor interface
|
||||||
func (fc *firecracker) capabilities() capabilities {
|
func (fc *firecracker) capabilities() types.Capabilities {
|
||||||
span, _ := fc.trace("capabilities")
|
span, _ := fc.trace("capabilities")
|
||||||
defer span.Finish()
|
defer span.Finish()
|
||||||
var caps capabilities
|
var caps types.Capabilities
|
||||||
caps.setFsSharingUnsupported()
|
caps.SetFsSharingUnsupported()
|
||||||
caps.setBlockDeviceHotplugSupport()
|
caps.SetBlockDeviceHotplugSupport()
|
||||||
|
|
||||||
return caps
|
return caps
|
||||||
}
|
}
|
||||||
|
@ -330,11 +330,11 @@ func (h *hyper) createSandbox(sandbox *Sandbox) (err error) {
|
|||||||
return h.configure(sandbox.hypervisor, "", h.getSharePath(sandbox.id), false, nil)
|
return h.configure(sandbox.hypervisor, "", h.getSharePath(sandbox.id), false, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *hyper) capabilities() capabilities {
|
func (h *hyper) capabilities() types.Capabilities {
|
||||||
var caps capabilities
|
var caps types.Capabilities
|
||||||
|
|
||||||
// add all capabilities supported by agent
|
// add all capabilities supported by agent
|
||||||
caps.setBlockDeviceSupport()
|
caps.SetBlockDeviceSupport()
|
||||||
|
|
||||||
return caps
|
return caps
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/kata-containers/runtime/virtcontainers/device/config"
|
"github.com/kata-containers/runtime/virtcontainers/device/config"
|
||||||
|
"github.com/kata-containers/runtime/virtcontainers/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HypervisorType describes an hypervisor type.
|
// HypervisorType describes an hypervisor type.
|
||||||
@ -221,7 +222,7 @@ type HypervisorConfig struct {
|
|||||||
// Each value in that map takes precedence over the configured assets.
|
// Each value in that map takes precedence over the configured assets.
|
||||||
// For example, if there is a value for the "kernel" key in this map,
|
// For example, if there is a value for the "kernel" key in this map,
|
||||||
// it will be used for the sandbox's kernel path instead of KernelPath.
|
// it will be used for the sandbox's kernel path instead of KernelPath.
|
||||||
customAssets map[assetType]*asset
|
customAssets map[types.AssetType]*types.Asset
|
||||||
|
|
||||||
// BlockDeviceCacheSet specifies cache-related options will be set to block devices or not.
|
// BlockDeviceCacheSet specifies cache-related options will be set to block devices or not.
|
||||||
BlockDeviceCacheSet bool
|
BlockDeviceCacheSet bool
|
||||||
@ -357,53 +358,53 @@ func (conf *HypervisorConfig) AddKernelParam(p Param) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conf *HypervisorConfig) addCustomAsset(a *asset) error {
|
func (conf *HypervisorConfig) addCustomAsset(a *types.Asset) error {
|
||||||
if a == nil || a.path == "" {
|
if a == nil || a.Path() == "" {
|
||||||
// We did not get a custom asset, we will use the default one.
|
// We did not get a custom asset, we will use the default one.
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if !a.valid() {
|
if !a.Valid() {
|
||||||
return fmt.Errorf("Invalid %s at %s", a.kind, a.path)
|
return fmt.Errorf("Invalid %s at %s", a.Type(), a.Path())
|
||||||
}
|
}
|
||||||
|
|
||||||
virtLog.Debugf("Using custom %v asset %s", a.kind, a.path)
|
virtLog.Debugf("Using custom %v asset %s", a.Type(), a.Path())
|
||||||
|
|
||||||
if conf.customAssets == nil {
|
if conf.customAssets == nil {
|
||||||
conf.customAssets = make(map[assetType]*asset)
|
conf.customAssets = make(map[types.AssetType]*types.Asset)
|
||||||
}
|
}
|
||||||
|
|
||||||
conf.customAssets[a.kind] = a
|
conf.customAssets[a.Type()] = a
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conf *HypervisorConfig) assetPath(t assetType) (string, error) {
|
func (conf *HypervisorConfig) assetPath(t types.AssetType) (string, error) {
|
||||||
// Custom assets take precedence over the configured ones
|
// Custom assets take precedence over the configured ones
|
||||||
a, ok := conf.customAssets[t]
|
a, ok := conf.customAssets[t]
|
||||||
if ok {
|
if ok {
|
||||||
return a.path, nil
|
return a.Path(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// We could not find a custom asset for the given type, let's
|
// We could not find a custom asset for the given type, let's
|
||||||
// fall back to the configured ones.
|
// fall back to the configured ones.
|
||||||
switch t {
|
switch t {
|
||||||
case kernelAsset:
|
case types.KernelAsset:
|
||||||
return conf.KernelPath, nil
|
return conf.KernelPath, nil
|
||||||
case imageAsset:
|
case types.ImageAsset:
|
||||||
return conf.ImagePath, nil
|
return conf.ImagePath, nil
|
||||||
case initrdAsset:
|
case types.InitrdAsset:
|
||||||
return conf.InitrdPath, nil
|
return conf.InitrdPath, nil
|
||||||
case hypervisorAsset:
|
case types.HypervisorAsset:
|
||||||
return conf.HypervisorPath, nil
|
return conf.HypervisorPath, nil
|
||||||
case firmwareAsset:
|
case types.FirmwareAsset:
|
||||||
return conf.FirmwarePath, nil
|
return conf.FirmwarePath, nil
|
||||||
default:
|
default:
|
||||||
return "", fmt.Errorf("Unknown asset type %v", t)
|
return "", fmt.Errorf("Unknown asset type %v", t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conf *HypervisorConfig) isCustomAsset(t assetType) bool {
|
func (conf *HypervisorConfig) isCustomAsset(t types.AssetType) bool {
|
||||||
_, ok := conf.customAssets[t]
|
_, ok := conf.customAssets[t]
|
||||||
if ok {
|
if ok {
|
||||||
return true
|
return true
|
||||||
@ -414,52 +415,52 @@ func (conf *HypervisorConfig) isCustomAsset(t assetType) bool {
|
|||||||
|
|
||||||
// KernelAssetPath returns the guest kernel path
|
// KernelAssetPath returns the guest kernel path
|
||||||
func (conf *HypervisorConfig) KernelAssetPath() (string, error) {
|
func (conf *HypervisorConfig) KernelAssetPath() (string, error) {
|
||||||
return conf.assetPath(kernelAsset)
|
return conf.assetPath(types.KernelAsset)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CustomKernelAsset returns true if the kernel asset is a custom one, false otherwise.
|
// CustomKernelAsset returns true if the kernel asset is a custom one, false otherwise.
|
||||||
func (conf *HypervisorConfig) CustomKernelAsset() bool {
|
func (conf *HypervisorConfig) CustomKernelAsset() bool {
|
||||||
return conf.isCustomAsset(kernelAsset)
|
return conf.isCustomAsset(types.KernelAsset)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImageAssetPath returns the guest image path
|
// ImageAssetPath returns the guest image path
|
||||||
func (conf *HypervisorConfig) ImageAssetPath() (string, error) {
|
func (conf *HypervisorConfig) ImageAssetPath() (string, error) {
|
||||||
return conf.assetPath(imageAsset)
|
return conf.assetPath(types.ImageAsset)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CustomImageAsset returns true if the image asset is a custom one, false otherwise.
|
// CustomImageAsset returns true if the image asset is a custom one, false otherwise.
|
||||||
func (conf *HypervisorConfig) CustomImageAsset() bool {
|
func (conf *HypervisorConfig) CustomImageAsset() bool {
|
||||||
return conf.isCustomAsset(imageAsset)
|
return conf.isCustomAsset(types.ImageAsset)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitrdAssetPath returns the guest initrd path
|
// InitrdAssetPath returns the guest initrd path
|
||||||
func (conf *HypervisorConfig) InitrdAssetPath() (string, error) {
|
func (conf *HypervisorConfig) InitrdAssetPath() (string, error) {
|
||||||
return conf.assetPath(initrdAsset)
|
return conf.assetPath(types.InitrdAsset)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CustomInitrdAsset returns true if the initrd asset is a custom one, false otherwise.
|
// CustomInitrdAsset returns true if the initrd asset is a custom one, false otherwise.
|
||||||
func (conf *HypervisorConfig) CustomInitrdAsset() bool {
|
func (conf *HypervisorConfig) CustomInitrdAsset() bool {
|
||||||
return conf.isCustomAsset(initrdAsset)
|
return conf.isCustomAsset(types.InitrdAsset)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HypervisorAssetPath returns the VM hypervisor path
|
// HypervisorAssetPath returns the VM hypervisor path
|
||||||
func (conf *HypervisorConfig) HypervisorAssetPath() (string, error) {
|
func (conf *HypervisorConfig) HypervisorAssetPath() (string, error) {
|
||||||
return conf.assetPath(hypervisorAsset)
|
return conf.assetPath(types.HypervisorAsset)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CustomHypervisorAsset returns true if the hypervisor asset is a custom one, false otherwise.
|
// CustomHypervisorAsset returns true if the hypervisor asset is a custom one, false otherwise.
|
||||||
func (conf *HypervisorConfig) CustomHypervisorAsset() bool {
|
func (conf *HypervisorConfig) CustomHypervisorAsset() bool {
|
||||||
return conf.isCustomAsset(hypervisorAsset)
|
return conf.isCustomAsset(types.HypervisorAsset)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FirmwareAssetPath returns the guest firmware path
|
// FirmwareAssetPath returns the guest firmware path
|
||||||
func (conf *HypervisorConfig) FirmwareAssetPath() (string, error) {
|
func (conf *HypervisorConfig) FirmwareAssetPath() (string, error) {
|
||||||
return conf.assetPath(firmwareAsset)
|
return conf.assetPath(types.FirmwareAsset)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CustomFirmwareAsset returns true if the firmware asset is a custom one, false otherwise.
|
// CustomFirmwareAsset returns true if the firmware asset is a custom one, false otherwise.
|
||||||
func (conf *HypervisorConfig) CustomFirmwareAsset() bool {
|
func (conf *HypervisorConfig) CustomFirmwareAsset() bool {
|
||||||
return conf.isCustomAsset(firmwareAsset)
|
return conf.isCustomAsset(types.FirmwareAsset)
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendParam(params []Param, parameter string, value string) []Param {
|
func appendParam(params []Param, parameter string, value string) []Param {
|
||||||
@ -603,7 +604,7 @@ type hypervisor interface {
|
|||||||
resizeVCPUs(vcpus uint32) (uint32, uint32, error)
|
resizeVCPUs(vcpus uint32) (uint32, uint32, error)
|
||||||
getSandboxConsole(sandboxID string) (string, error)
|
getSandboxConsole(sandboxID string) (string, error)
|
||||||
disconnect()
|
disconnect()
|
||||||
capabilities() capabilities
|
capabilities() types.Capabilities
|
||||||
hypervisorConfig() HypervisorConfig
|
hypervisorConfig() HypervisorConfig
|
||||||
getThreadIDs() (*threadIDs, error)
|
getThreadIDs() (*threadIDs, error)
|
||||||
cleanup() error
|
cleanup() error
|
||||||
|
@ -211,11 +211,11 @@ func (k *kataAgent) agentURL() (string, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *kataAgent) capabilities() capabilities {
|
func (k *kataAgent) capabilities() types.Capabilities {
|
||||||
var caps capabilities
|
var caps types.Capabilities
|
||||||
|
|
||||||
// add all capabilities supported by agent
|
// add all capabilities supported by agent
|
||||||
caps.setBlockDeviceSupport()
|
caps.SetBlockDeviceSupport()
|
||||||
|
|
||||||
return caps
|
return caps
|
||||||
}
|
}
|
||||||
@ -261,7 +261,7 @@ func (k *kataAgent) configure(h hypervisor, id, sharePath string, builtin bool,
|
|||||||
// Neither create shared directory nor add 9p device if hypervisor
|
// Neither create shared directory nor add 9p device if hypervisor
|
||||||
// doesn't support filesystem sharing.
|
// doesn't support filesystem sharing.
|
||||||
caps := h.capabilities()
|
caps := h.capabilities()
|
||||||
if !caps.isFsSharingSupported() {
|
if !caps.IsFsSharingSupported() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -629,7 +629,7 @@ func (k *kataAgent) startSandbox(sandbox *Sandbox) error {
|
|||||||
caps := sandbox.hypervisor.capabilities()
|
caps := sandbox.hypervisor.capabilities()
|
||||||
|
|
||||||
// append 9p shared volume to storages only if filesystem sharing is supported
|
// append 9p shared volume to storages only if filesystem sharing is supported
|
||||||
if caps.isFsSharingSupported() {
|
if caps.IsFsSharingSupported() {
|
||||||
sharedDir9pOptions = append(sharedDir9pOptions, fmt.Sprintf("msize=%d", sandbox.config.HypervisorConfig.Msize9p))
|
sharedDir9pOptions = append(sharedDir9pOptions, fmt.Sprintf("msize=%d", sandbox.config.HypervisorConfig.Msize9p))
|
||||||
|
|
||||||
// We mount the shared directory in a predefined location
|
// We mount the shared directory in a predefined location
|
||||||
|
@ -8,13 +8,15 @@ package virtcontainers
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/kata-containers/runtime/virtcontainers/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mockHypervisor struct {
|
type mockHypervisor struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockHypervisor) capabilities() capabilities {
|
func (m *mockHypervisor) capabilities() types.Capabilities {
|
||||||
return capabilities{}
|
return types.Capabilities{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockHypervisor) hypervisorConfig() HypervisorConfig {
|
func (m *mockHypervisor) hypervisorConfig() HypervisorConfig {
|
||||||
|
@ -511,7 +511,7 @@ func xConnectVMNetwork(endpoint Endpoint, h hypervisor) error {
|
|||||||
|
|
||||||
queues := 0
|
queues := 0
|
||||||
caps := h.capabilities()
|
caps := h.capabilities()
|
||||||
if caps.isMultiQueueSupported() {
|
if caps.IsMultiQueueSupported() {
|
||||||
queues = int(h.hypervisorConfig().NumVCPUs)
|
queues = int(h.hypervisorConfig().NumVCPUs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,8 +37,8 @@ func (n *noopAgent) createSandbox(sandbox *Sandbox) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// capabilities returns empty capabilities, i.e no capabilties are supported.
|
// capabilities returns empty capabilities, i.e no capabilties are supported.
|
||||||
func (n *noopAgent) capabilities() capabilities {
|
func (n *noopAgent) capabilities() types.Capabilities {
|
||||||
return capabilities{}
|
return types.Capabilities{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// disconnect is the Noop agent connection closer. It does nothing.
|
// disconnect is the Noop agent connection closer. It does nothing.
|
||||||
|
@ -47,7 +47,7 @@ type CPUDevice struct {
|
|||||||
|
|
||||||
// QemuState keeps Qemu's state
|
// QemuState keeps Qemu's state
|
||||||
type QemuState struct {
|
type QemuState struct {
|
||||||
Bridges []Bridge
|
Bridges []types.PCIBridge
|
||||||
// HotpluggedCPUs is the list of CPUs that were hot-added
|
// HotpluggedCPUs is the list of CPUs that were hot-added
|
||||||
HotpluggedVCPUs []CPUDevice
|
HotpluggedVCPUs []CPUDevice
|
||||||
HotpluggedMemory int
|
HotpluggedMemory int
|
||||||
@ -162,7 +162,7 @@ func (q *qemu) kernelParameters() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Adds all capabilities supported by qemu implementation of hypervisor interface
|
// Adds all capabilities supported by qemu implementation of hypervisor interface
|
||||||
func (q *qemu) capabilities() capabilities {
|
func (q *qemu) capabilities() types.Capabilities {
|
||||||
span, _ := q.trace("capabilities")
|
span, _ := q.trace("capabilities")
|
||||||
defer span.Finish()
|
defer span.Finish()
|
||||||
|
|
||||||
@ -722,25 +722,25 @@ func (q *qemu) qmpShutdown() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *qemu) addDeviceToBridge(ID string) (string, Bridge, error) {
|
func (q *qemu) addDeviceToBridge(ID string) (string, types.PCIBridge, error) {
|
||||||
var err error
|
var err error
|
||||||
var addr uint32
|
var addr uint32
|
||||||
|
|
||||||
// looking for an empty address in the bridges
|
// looking for an empty address in the bridges
|
||||||
for _, b := range q.state.Bridges {
|
for _, b := range q.state.Bridges {
|
||||||
addr, err = b.addDevice(ID)
|
addr, err = b.AddDevice(ID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return fmt.Sprintf("%02x", addr), b, nil
|
return fmt.Sprintf("%02x", addr), b, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", Bridge{}, err
|
return "", types.PCIBridge{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *qemu) removeDeviceFromBridge(ID string) error {
|
func (q *qemu) removeDeviceFromBridge(ID string) error {
|
||||||
var err error
|
var err error
|
||||||
for _, b := range q.state.Bridges {
|
for _, b := range q.state.Bridges {
|
||||||
err = b.removeDevice(ID)
|
err = b.RemoveDevice(ID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// device was removed correctly
|
// device was removed correctly
|
||||||
return nil
|
return nil
|
||||||
@ -1377,7 +1377,7 @@ func (q *qemu) resizeMemory(reqMemMB uint32, memoryBlockSizeMB uint32) (uint32,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// genericAppendBridges appends to devices the given bridges
|
// genericAppendBridges appends to devices the given bridges
|
||||||
func genericAppendBridges(devices []govmmQemu.Device, bridges []Bridge, machineType string) []govmmQemu.Device {
|
func genericAppendBridges(devices []govmmQemu.Device, bridges []types.PCIBridge, machineType string) []govmmQemu.Device {
|
||||||
bus := defaultPCBridgeBus
|
bus := defaultPCBridgeBus
|
||||||
switch machineType {
|
switch machineType {
|
||||||
case QemuQ35, QemuVirt:
|
case QemuQ35, QemuVirt:
|
||||||
@ -1386,7 +1386,7 @@ func genericAppendBridges(devices []govmmQemu.Device, bridges []Bridge, machineT
|
|||||||
|
|
||||||
for idx, b := range bridges {
|
for idx, b := range bridges {
|
||||||
t := govmmQemu.PCIBridge
|
t := govmmQemu.PCIBridge
|
||||||
if b.Type == pcieBridge {
|
if b.Type == types.PCIE {
|
||||||
t = govmmQemu.PCIEBridge
|
t = govmmQemu.PCIEBridge
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1408,9 +1408,9 @@ func genericAppendBridges(devices []govmmQemu.Device, bridges []Bridge, machineT
|
|||||||
return devices
|
return devices
|
||||||
}
|
}
|
||||||
|
|
||||||
func genericBridges(number uint32, machineType string) []Bridge {
|
func genericBridges(number uint32, machineType string) []types.PCIBridge {
|
||||||
var bridges []Bridge
|
var bridges []types.PCIBridge
|
||||||
var bt bridgeType
|
var bt types.PCIType
|
||||||
|
|
||||||
switch machineType {
|
switch machineType {
|
||||||
case QemuQ35:
|
case QemuQ35:
|
||||||
@ -1418,19 +1418,19 @@ func genericBridges(number uint32, machineType string) []Bridge {
|
|||||||
// qemu-2.10 will introduce pcie bridges
|
// qemu-2.10 will introduce pcie bridges
|
||||||
fallthrough
|
fallthrough
|
||||||
case QemuPC:
|
case QemuPC:
|
||||||
bt = pciBridge
|
bt = types.PCI
|
||||||
case QemuVirt:
|
case QemuVirt:
|
||||||
bt = pcieBridge
|
bt = types.PCIE
|
||||||
case QemuPseries:
|
case QemuPseries:
|
||||||
bt = pciBridge
|
bt = types.PCI
|
||||||
case QemuCCWVirtio:
|
case QemuCCWVirtio:
|
||||||
bt = pciBridge
|
bt = types.PCI
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := uint32(0); i < number; i++ {
|
for i := uint32(0); i < number; i++ {
|
||||||
bridges = append(bridges, Bridge{
|
bridges = append(bridges, types.PCIBridge{
|
||||||
Type: bt,
|
Type: bt,
|
||||||
ID: fmt.Sprintf("%s-bridge-%d", bt, i),
|
ID: fmt.Sprintf("%s-bridge-%d", bt, i),
|
||||||
Address: make(map[uint32]string),
|
Address: make(map[uint32]string),
|
||||||
|
@ -8,6 +8,8 @@ package virtcontainers
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/kata-containers/runtime/virtcontainers/types"
|
||||||
|
|
||||||
govmmQemu "github.com/intel/govmm/qemu"
|
govmmQemu "github.com/intel/govmm/qemu"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -101,21 +103,21 @@ func newQemuArch(config HypervisorConfig) qemuArch {
|
|||||||
return q
|
return q
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *qemuAmd64) capabilities() capabilities {
|
func (q *qemuAmd64) capabilities() types.Capabilities {
|
||||||
var caps capabilities
|
var caps types.Capabilities
|
||||||
|
|
||||||
if q.machineType == QemuPC ||
|
if q.machineType == QemuPC ||
|
||||||
q.machineType == QemuQ35 ||
|
q.machineType == QemuQ35 ||
|
||||||
q.machineType == QemuVirt {
|
q.machineType == QemuVirt {
|
||||||
caps.setBlockDeviceHotplugSupport()
|
caps.SetBlockDeviceHotplugSupport()
|
||||||
}
|
}
|
||||||
|
|
||||||
caps.setMultiQueueSupport()
|
caps.SetMultiQueueSupport()
|
||||||
|
|
||||||
return caps
|
return caps
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *qemuAmd64) bridges(number uint32) []Bridge {
|
func (q *qemuAmd64) bridges(number uint32) []types.PCIBridge {
|
||||||
return genericBridges(number, q.machineType)
|
return genericBridges(number, q.machineType)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,6 +160,6 @@ func (q *qemuAmd64) appendImage(devices []govmmQemu.Device, path string) ([]govm
|
|||||||
}
|
}
|
||||||
|
|
||||||
// appendBridges appends to devices the given bridges
|
// appendBridges appends to devices the given bridges
|
||||||
func (q *qemuAmd64) appendBridges(devices []govmmQemu.Device, bridges []Bridge) []govmmQemu.Device {
|
func (q *qemuAmd64) appendBridges(devices []govmmQemu.Device, bridges []types.PCIBridge) []govmmQemu.Device {
|
||||||
return genericAppendBridges(devices, bridges, q.machineType)
|
return genericAppendBridges(devices, bridges, q.machineType)
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
govmmQemu "github.com/intel/govmm/qemu"
|
govmmQemu "github.com/intel/govmm/qemu"
|
||||||
|
"github.com/kata-containers/runtime/virtcontainers/types"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -27,11 +28,11 @@ func TestQemuAmd64Capabilities(t *testing.T) {
|
|||||||
|
|
||||||
amd64 := newTestQemu(QemuPC)
|
amd64 := newTestQemu(QemuPC)
|
||||||
caps := amd64.capabilities()
|
caps := amd64.capabilities()
|
||||||
assert.True(caps.isBlockDeviceHotplugSupported())
|
assert.True(caps.IsBlockDeviceHotplugSupported())
|
||||||
|
|
||||||
amd64 = newTestQemu(QemuQ35)
|
amd64 = newTestQemu(QemuQ35)
|
||||||
caps = amd64.capabilities()
|
caps = amd64.capabilities()
|
||||||
assert.True(caps.isBlockDeviceHotplugSupported())
|
assert.True(caps.IsBlockDeviceHotplugSupported())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestQemuAmd64Bridges(t *testing.T) {
|
func TestQemuAmd64Bridges(t *testing.T) {
|
||||||
@ -43,8 +44,8 @@ func TestQemuAmd64Bridges(t *testing.T) {
|
|||||||
assert.Len(bridges, len)
|
assert.Len(bridges, len)
|
||||||
|
|
||||||
for i, b := range bridges {
|
for i, b := range bridges {
|
||||||
id := fmt.Sprintf("%s-bridge-%d", pciBridge, i)
|
id := fmt.Sprintf("%s-bridge-%d", types.PCI, i)
|
||||||
assert.Equal(pciBridge, b.Type)
|
assert.Equal(types.PCI, b.Type)
|
||||||
assert.Equal(id, b.ID)
|
assert.Equal(id, b.ID)
|
||||||
assert.NotNil(b.Address)
|
assert.NotNil(b.Address)
|
||||||
}
|
}
|
||||||
@ -54,8 +55,8 @@ func TestQemuAmd64Bridges(t *testing.T) {
|
|||||||
assert.Len(bridges, len)
|
assert.Len(bridges, len)
|
||||||
|
|
||||||
for i, b := range bridges {
|
for i, b := range bridges {
|
||||||
id := fmt.Sprintf("%s-bridge-%d", pciBridge, i)
|
id := fmt.Sprintf("%s-bridge-%d", types.PCI, i)
|
||||||
assert.Equal(pciBridge, b.Type)
|
assert.Equal(types.PCI, b.Type)
|
||||||
assert.Equal(id, b.ID)
|
assert.Equal(id, b.ID)
|
||||||
assert.NotNil(b.Address)
|
assert.NotNil(b.Address)
|
||||||
}
|
}
|
||||||
|
@ -45,10 +45,10 @@ type qemuArch interface {
|
|||||||
kernelParameters(debug bool) []Param
|
kernelParameters(debug bool) []Param
|
||||||
|
|
||||||
//capabilities returns the capabilities supported by QEMU
|
//capabilities returns the capabilities supported by QEMU
|
||||||
capabilities() capabilities
|
capabilities() types.Capabilities
|
||||||
|
|
||||||
// bridges returns the number bridges for the machine type
|
// bridges returns the number bridges for the machine type
|
||||||
bridges(number uint32) []Bridge
|
bridges(number uint32) []types.PCIBridge
|
||||||
|
|
||||||
// cpuTopology returns the CPU topology for the given amount of vcpus
|
// cpuTopology returns the CPU topology for the given amount of vcpus
|
||||||
cpuTopology(vcpus, maxvcpus uint32) govmmQemu.SMP
|
cpuTopology(vcpus, maxvcpus uint32) govmmQemu.SMP
|
||||||
@ -69,7 +69,7 @@ type qemuArch interface {
|
|||||||
appendSCSIController(devices []govmmQemu.Device, enableIOThreads bool) ([]govmmQemu.Device, *govmmQemu.IOThread)
|
appendSCSIController(devices []govmmQemu.Device, enableIOThreads bool) ([]govmmQemu.Device, *govmmQemu.IOThread)
|
||||||
|
|
||||||
// appendBridges appends bridges to devices
|
// appendBridges appends bridges to devices
|
||||||
appendBridges(devices []govmmQemu.Device, bridges []Bridge) []govmmQemu.Device
|
appendBridges(devices []govmmQemu.Device, bridges []types.PCIBridge) []govmmQemu.Device
|
||||||
|
|
||||||
// append9PVolume appends a 9P volume to devices
|
// append9PVolume appends a 9P volume to devices
|
||||||
append9PVolume(devices []govmmQemu.Device, volume types.Volume) []govmmQemu.Device
|
append9PVolume(devices []govmmQemu.Device, volume types.Volume) []govmmQemu.Device
|
||||||
@ -228,20 +228,20 @@ func (q *qemuArchBase) kernelParameters(debug bool) []Param {
|
|||||||
return params
|
return params
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *qemuArchBase) capabilities() capabilities {
|
func (q *qemuArchBase) capabilities() types.Capabilities {
|
||||||
var caps capabilities
|
var caps types.Capabilities
|
||||||
caps.setBlockDeviceHotplugSupport()
|
caps.SetBlockDeviceHotplugSupport()
|
||||||
caps.setMultiQueueSupport()
|
caps.SetMultiQueueSupport()
|
||||||
return caps
|
return caps
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *qemuArchBase) bridges(number uint32) []Bridge {
|
func (q *qemuArchBase) bridges(number uint32) []types.PCIBridge {
|
||||||
var bridges []Bridge
|
var bridges []types.PCIBridge
|
||||||
|
|
||||||
for i := uint32(0); i < number; i++ {
|
for i := uint32(0); i < number; i++ {
|
||||||
bridges = append(bridges, Bridge{
|
bridges = append(bridges, types.PCIBridge{
|
||||||
Type: pciBridge,
|
Type: types.PCI,
|
||||||
ID: fmt.Sprintf("%s-bridge-%d", pciBridge, i),
|
ID: fmt.Sprintf("%s-bridge-%d", types.PCI, i),
|
||||||
Address: make(map[uint32]string),
|
Address: make(map[uint32]string),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -346,10 +346,10 @@ func (q *qemuArchBase) appendSCSIController(devices []govmmQemu.Device, enableIO
|
|||||||
}
|
}
|
||||||
|
|
||||||
// appendBridges appends to devices the given bridges
|
// appendBridges appends to devices the given bridges
|
||||||
func (q *qemuArchBase) appendBridges(devices []govmmQemu.Device, bridges []Bridge) []govmmQemu.Device {
|
func (q *qemuArchBase) appendBridges(devices []govmmQemu.Device, bridges []types.PCIBridge) []govmmQemu.Device {
|
||||||
for idx, b := range bridges {
|
for idx, b := range bridges {
|
||||||
t := govmmQemu.PCIBridge
|
t := govmmQemu.PCIBridge
|
||||||
if b.Type == pcieBridge {
|
if b.Type == types.PCIE {
|
||||||
t = govmmQemu.PCIEBridge
|
t = govmmQemu.PCIEBridge
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ func TestQemuArchBaseCapabilities(t *testing.T) {
|
|||||||
qemuArchBase := newQemuArchBase()
|
qemuArchBase := newQemuArchBase()
|
||||||
|
|
||||||
c := qemuArchBase.capabilities()
|
c := qemuArchBase.capabilities()
|
||||||
assert.True(c.isBlockDeviceHotplugSupported())
|
assert.True(c.IsBlockDeviceHotplugSupported())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestQemuArchBaseBridges(t *testing.T) {
|
func TestQemuArchBaseBridges(t *testing.T) {
|
||||||
@ -150,8 +150,8 @@ func TestQemuArchBaseBridges(t *testing.T) {
|
|||||||
assert.Len(bridges, len)
|
assert.Len(bridges, len)
|
||||||
|
|
||||||
for i, b := range bridges {
|
for i, b := range bridges {
|
||||||
id := fmt.Sprintf("%s-bridge-%d", pciBridge, i)
|
id := fmt.Sprintf("%s-bridge-%d", types.PCI, i)
|
||||||
assert.Equal(pciBridge, b.Type)
|
assert.Equal(types.PCI, b.Type)
|
||||||
assert.Equal(id, b.ID)
|
assert.Equal(id, b.ID)
|
||||||
assert.NotNil(b.Address)
|
assert.NotNil(b.Address)
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
|
|
||||||
govmmQemu "github.com/intel/govmm/qemu"
|
govmmQemu "github.com/intel/govmm/qemu"
|
||||||
deviceConfig "github.com/kata-containers/runtime/virtcontainers/device/config"
|
deviceConfig "github.com/kata-containers/runtime/virtcontainers/device/config"
|
||||||
|
"github.com/kata-containers/runtime/virtcontainers/types"
|
||||||
"github.com/kata-containers/runtime/virtcontainers/utils"
|
"github.com/kata-containers/runtime/virtcontainers/utils"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
@ -90,20 +91,20 @@ func newQemuArch(config HypervisorConfig) qemuArch {
|
|||||||
return q
|
return q
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *qemuPPC64le) capabilities() capabilities {
|
func (q *qemuPPC64le) capabilities() types.Capabilities {
|
||||||
var caps capabilities
|
var caps types.Capabilities
|
||||||
|
|
||||||
// pseries machine type supports hotplugging drives
|
// pseries machine type supports hotplugging drives
|
||||||
if q.machineType == QemuPseries {
|
if q.machineType == QemuPseries {
|
||||||
caps.setBlockDeviceHotplugSupport()
|
caps.SetBlockDeviceHotplugSupport()
|
||||||
}
|
}
|
||||||
|
|
||||||
caps.setMultiQueueSupport()
|
caps.SetMultiQueueSupport()
|
||||||
|
|
||||||
return caps
|
return caps
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *qemuPPC64le) bridges(number uint32) []Bridge {
|
func (q *qemuPPC64le) bridges(number uint32) []types.PCIBridge {
|
||||||
return genericBridges(number, q.machineType)
|
return genericBridges(number, q.machineType)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,6 +151,6 @@ func (q *qemuPPC64le) appendImage(devices []govmmQemu.Device, path string) ([]go
|
|||||||
}
|
}
|
||||||
|
|
||||||
// appendBridges appends to devices the given bridges
|
// appendBridges appends to devices the given bridges
|
||||||
func (q *qemuPPC64le) appendBridges(devices []govmmQemu.Device, bridges []Bridge) []govmmQemu.Device {
|
func (q *qemuPPC64le) appendBridges(devices []govmmQemu.Device, bridges []types.PCIBridge) []govmmQemu.Device {
|
||||||
return genericAppendBridges(devices, bridges, q.machineType)
|
return genericAppendBridges(devices, bridges, q.machineType)
|
||||||
}
|
}
|
||||||
|
@ -306,7 +306,7 @@ func TestQemuCapabilities(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
caps := q.capabilities()
|
caps := q.capabilities()
|
||||||
if !caps.isBlockDeviceHotplugSupported() {
|
if !caps.IsBlockDeviceHotplugSupported() {
|
||||||
t.Fatal("Block device hotplug should be supported")
|
t.Fatal("Block device hotplug should be supported")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -435,26 +435,26 @@ func createAssets(ctx context.Context, sandboxConfig *SandboxConfig) error {
|
|||||||
span, _ := trace(ctx, "createAssets")
|
span, _ := trace(ctx, "createAssets")
|
||||||
defer span.Finish()
|
defer span.Finish()
|
||||||
|
|
||||||
kernel, err := newAsset(sandboxConfig, kernelAsset)
|
kernel, err := types.NewAsset(sandboxConfig.Annotations, types.KernelAsset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
image, err := newAsset(sandboxConfig, imageAsset)
|
image, err := types.NewAsset(sandboxConfig.Annotations, types.ImageAsset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
initrd, err := newAsset(sandboxConfig, initrdAsset)
|
initrd, err := types.NewAsset(sandboxConfig.Annotations, types.InitrdAsset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if image != nil && initrd != nil {
|
if image != nil && initrd != nil {
|
||||||
return fmt.Errorf("%s and %s cannot be both set", imageAsset, initrdAsset)
|
return fmt.Errorf("%s and %s cannot be both set", types.ImageAsset, types.InitrdAsset)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, a := range []*asset{kernel, image, initrd} {
|
for _, a := range []*types.Asset{kernel, image, initrd} {
|
||||||
if err := sandboxConfig.HypervisorConfig.addCustomAsset(a); err != nil {
|
if err := sandboxConfig.HypervisorConfig.addCustomAsset(a); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1201,6 +1201,10 @@ func TestSandboxAttachDevicesVFIO(t *testing.T) {
|
|||||||
assert.Nil(t, err, "Error while detaching devices %s", err)
|
assert.Nil(t, err, "Error while detaching devices %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var assetContent = []byte("FakeAsset fake asset FAKE ASSET")
|
||||||
|
var assetContentHash = "92549f8d2018a95a294d28a65e795ed7d1a9d150009a28cea108ae10101178676f04ab82a6950d0099e4924f9c5e41dcba8ece56b75fc8b4e0a7492cb2a8c880"
|
||||||
|
var assetContentWrongHash = "92549f8d2018a95a294d28a65e795ed7d1a9d150009a28cea108ae10101178676f04ab82a6950d0099e4924f9c5e41dcba8ece56b75fc8b4e0a7492cb2a8c881"
|
||||||
|
|
||||||
func TestSandboxCreateAssets(t *testing.T) {
|
func TestSandboxCreateAssets(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
@ -1234,9 +1238,9 @@ func TestSandboxCreateAssets(t *testing.T) {
|
|||||||
err = createAssets(context.Background(), p)
|
err = createAssets(context.Background(), p)
|
||||||
assert.Nil(err)
|
assert.Nil(err)
|
||||||
|
|
||||||
a, ok := p.HypervisorConfig.customAssets[kernelAsset]
|
a, ok := p.HypervisorConfig.customAssets[types.KernelAsset]
|
||||||
assert.True(ok)
|
assert.True(ok)
|
||||||
assert.Equal(a.path, tmpfile.Name())
|
assert.Equal(a.Path(), tmpfile.Name())
|
||||||
|
|
||||||
p = &SandboxConfig{
|
p = &SandboxConfig{
|
||||||
Annotations: map[string]string{
|
Annotations: map[string]string{
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
//
|
//
|
||||||
|
|
||||||
package virtcontainers
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
@ -15,19 +15,21 @@ import (
|
|||||||
"github.com/kata-containers/runtime/virtcontainers/pkg/annotations"
|
"github.com/kata-containers/runtime/virtcontainers/pkg/annotations"
|
||||||
)
|
)
|
||||||
|
|
||||||
type assetType string
|
// AssetType describe a type of assets.
|
||||||
|
type AssetType string
|
||||||
|
|
||||||
func (t assetType) annotations() (string, string, error) {
|
// Annotations returns the path and hash annotations for a given Asset type.
|
||||||
|
func (t AssetType) Annotations() (string, string, error) {
|
||||||
switch t {
|
switch t {
|
||||||
case kernelAsset:
|
case KernelAsset:
|
||||||
return annotations.KernelPath, annotations.KernelHash, nil
|
return annotations.KernelPath, annotations.KernelHash, nil
|
||||||
case imageAsset:
|
case ImageAsset:
|
||||||
return annotations.ImagePath, annotations.ImageHash, nil
|
return annotations.ImagePath, annotations.ImageHash, nil
|
||||||
case initrdAsset:
|
case InitrdAsset:
|
||||||
return annotations.InitrdPath, annotations.InitrdHash, nil
|
return annotations.InitrdPath, annotations.InitrdHash, nil
|
||||||
case hypervisorAsset:
|
case HypervisorAsset:
|
||||||
return annotations.HypervisorPath, annotations.HypervisorHash, nil
|
return annotations.HypervisorPath, annotations.HypervisorHash, nil
|
||||||
case firmwareAsset:
|
case FirmwareAsset:
|
||||||
return annotations.FirmwarePath, annotations.FirmwareHash, nil
|
return annotations.FirmwarePath, annotations.FirmwareHash, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,42 +37,63 @@ func (t assetType) annotations() (string, string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
kernelAsset assetType = "kernel"
|
// KernelAsset is a kernel asset.
|
||||||
imageAsset assetType = "image"
|
KernelAsset AssetType = "kernel"
|
||||||
initrdAsset assetType = "initrd"
|
|
||||||
hypervisorAsset assetType = "hypervisor"
|
// ImageAsset is an image asset.
|
||||||
firmwareAsset assetType = "firmware"
|
ImageAsset AssetType = "image"
|
||||||
|
|
||||||
|
// InitrdAsset is an intird asset.
|
||||||
|
InitrdAsset AssetType = "initrd"
|
||||||
|
|
||||||
|
// HypervisorAsset is an hypervisor asset.
|
||||||
|
HypervisorAsset AssetType = "hypervisor"
|
||||||
|
|
||||||
|
// FirmwareAsset is a firmware asset.
|
||||||
|
FirmwareAsset AssetType = "firmware"
|
||||||
)
|
)
|
||||||
|
|
||||||
type asset struct {
|
// Asset represents a virtcontainers asset.
|
||||||
|
type Asset struct {
|
||||||
path string
|
path string
|
||||||
computedHash string
|
computedHash string
|
||||||
kind assetType
|
kind AssetType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *asset) valid() bool {
|
// Path returns an asset path.
|
||||||
|
func (a Asset) Path() string {
|
||||||
|
return a.path
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type returns an asset type.
|
||||||
|
func (a Asset) Type() AssetType {
|
||||||
|
return a.kind
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid checks if an asset is valid or not.
|
||||||
|
func (a *Asset) Valid() bool {
|
||||||
if !filepath.IsAbs(a.path) {
|
if !filepath.IsAbs(a.path) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
switch a.kind {
|
switch a.kind {
|
||||||
case kernelAsset:
|
case KernelAsset:
|
||||||
return true
|
return true
|
||||||
case imageAsset:
|
case ImageAsset:
|
||||||
return true
|
return true
|
||||||
case initrdAsset:
|
case InitrdAsset:
|
||||||
return true
|
return true
|
||||||
case hypervisorAsset:
|
case HypervisorAsset:
|
||||||
return true
|
return true
|
||||||
case firmwareAsset:
|
case FirmwareAsset:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash returns the hex encoded string for the asset hash
|
// Hash returns the hex encoded string for the asset hash
|
||||||
func (a *asset) hash(hashType string) (string, error) {
|
func (a *Asset) Hash(hashType string) (string, error) {
|
||||||
var hashEncodedLen int
|
var hashEncodedLen int
|
||||||
var hash string
|
var hash string
|
||||||
|
|
||||||
@ -88,13 +111,11 @@ func (a *asset) hash(hashType string) (string, error) {
|
|||||||
// We only support SHA512 for now.
|
// We only support SHA512 for now.
|
||||||
switch hashType {
|
switch hashType {
|
||||||
case annotations.SHA512:
|
case annotations.SHA512:
|
||||||
virtLog.Debugf("Computing %v hash", a.path)
|
|
||||||
hashComputed := sha512.Sum512(bytes)
|
hashComputed := sha512.Sum512(bytes)
|
||||||
hashEncodedLen = hex.EncodedLen(len(hashComputed))
|
hashEncodedLen = hex.EncodedLen(len(hashComputed))
|
||||||
hashEncoded := make([]byte, hashEncodedLen)
|
hashEncoded := make([]byte, hashEncodedLen)
|
||||||
hex.Encode(hashEncoded, hashComputed[:])
|
hex.Encode(hashEncoded, hashComputed[:])
|
||||||
hash = string(hashEncoded[:])
|
hash = string(hashEncoded[:])
|
||||||
virtLog.Debugf("%v hash: %s", a.path, hash)
|
|
||||||
default:
|
default:
|
||||||
return "", fmt.Errorf("Invalid hash type %s", hashType)
|
return "", fmt.Errorf("Invalid hash type %s", hashType)
|
||||||
}
|
}
|
||||||
@ -104,9 +125,9 @@ func (a *asset) hash(hashType string) (string, error) {
|
|||||||
return hash, nil
|
return hash, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// newAsset returns a new asset from the sandbox annotations.
|
// NewAsset returns a new asset from a slice of annotations.
|
||||||
func newAsset(sandboxConfig *SandboxConfig, t assetType) (*asset, error) {
|
func NewAsset(anno map[string]string, t AssetType) (*Asset, error) {
|
||||||
pathAnnotation, hashAnnotation, err := t.annotations()
|
pathAnnotation, hashAnnotation, err := t.Annotations()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -115,7 +136,7 @@ func newAsset(sandboxConfig *SandboxConfig, t assetType) (*asset, error) {
|
|||||||
return nil, fmt.Errorf("Missing annotation paths for %s", t)
|
return nil, fmt.Errorf("Missing annotation paths for %s", t)
|
||||||
}
|
}
|
||||||
|
|
||||||
path, ok := sandboxConfig.Annotations[pathAnnotation]
|
path, ok := anno[pathAnnotation]
|
||||||
if !ok || path == "" {
|
if !ok || path == "" {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@ -124,21 +145,20 @@ func newAsset(sandboxConfig *SandboxConfig, t assetType) (*asset, error) {
|
|||||||
return nil, fmt.Errorf("%s is not an absolute path", path)
|
return nil, fmt.Errorf("%s is not an absolute path", path)
|
||||||
}
|
}
|
||||||
|
|
||||||
a := &asset{path: path, kind: t}
|
a := &Asset{path: path, kind: t}
|
||||||
|
|
||||||
hash, ok := sandboxConfig.Annotations[hashAnnotation]
|
hash, ok := anno[hashAnnotation]
|
||||||
if !ok || hash == "" {
|
if !ok || hash == "" {
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have a hash annotation, we need to verify the asset against it.
|
// We have a hash annotation, we need to verify the asset against it.
|
||||||
hashType, ok := sandboxConfig.Annotations[annotations.AssetHashType]
|
hashType, ok := anno[annotations.AssetHashType]
|
||||||
if !ok {
|
if !ok {
|
||||||
virtLog.Warningf("Unrecognized hash type: %s, switching to %s", hashType, annotations.SHA512)
|
|
||||||
hashType = annotations.SHA512
|
hashType = annotations.SHA512
|
||||||
}
|
}
|
||||||
|
|
||||||
hashComputed, err := a.hash(hashType)
|
hashComputed, err := a.Hash(hashType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return a, err
|
return a, err
|
||||||
}
|
}
|
@ -3,7 +3,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
//
|
//
|
||||||
|
|
||||||
package virtcontainers
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@ -32,11 +32,11 @@ func TestAssetWrongHashType(t *testing.T) {
|
|||||||
_, err = tmpfile.Write(assetContent)
|
_, err = tmpfile.Write(assetContent)
|
||||||
assert.Nil(err)
|
assert.Nil(err)
|
||||||
|
|
||||||
a := &asset{
|
a := &Asset{
|
||||||
path: tmpfile.Name(),
|
path: tmpfile.Name(),
|
||||||
}
|
}
|
||||||
|
|
||||||
h, err := a.hash("shafoo")
|
h, err := a.Hash("shafoo")
|
||||||
assert.Equal(h, "")
|
assert.Equal(h, "")
|
||||||
assert.NotNil(err)
|
assert.NotNil(err)
|
||||||
}
|
}
|
||||||
@ -55,11 +55,11 @@ func TestAssetHash(t *testing.T) {
|
|||||||
_, err = tmpfile.Write(assetContent)
|
_, err = tmpfile.Write(assetContent)
|
||||||
assert.Nil(err)
|
assert.Nil(err)
|
||||||
|
|
||||||
a := &asset{
|
a := &Asset{
|
||||||
path: tmpfile.Name(),
|
path: tmpfile.Name(),
|
||||||
}
|
}
|
||||||
|
|
||||||
hash, err := a.hash(annotations.SHA512)
|
hash, err := a.Hash(annotations.SHA512)
|
||||||
assert.Nil(err)
|
assert.Nil(err)
|
||||||
assert.Equal(assetContentHash, hash)
|
assert.Equal(assetContentHash, hash)
|
||||||
assert.Equal(assetContentHash, a.computedHash)
|
assert.Equal(assetContentHash, a.computedHash)
|
||||||
@ -79,28 +79,23 @@ func TestAssetNew(t *testing.T) {
|
|||||||
_, err = tmpfile.Write(assetContent)
|
_, err = tmpfile.Write(assetContent)
|
||||||
assert.Nil(err)
|
assert.Nil(err)
|
||||||
|
|
||||||
p := &SandboxConfig{
|
anno := map[string]string{
|
||||||
Annotations: map[string]string{
|
|
||||||
annotations.KernelPath: tmpfile.Name(),
|
annotations.KernelPath: tmpfile.Name(),
|
||||||
annotations.KernelHash: assetContentHash,
|
annotations.KernelHash: assetContentHash,
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
a, err := NewAsset(anno, ImageAsset)
|
||||||
a, err := newAsset(p, imageAsset)
|
|
||||||
assert.Nil(err)
|
assert.Nil(err)
|
||||||
assert.Nil(a)
|
assert.Nil(a)
|
||||||
|
|
||||||
a, err = newAsset(p, kernelAsset)
|
a, err = NewAsset(anno, KernelAsset)
|
||||||
assert.Nil(err)
|
assert.Nil(err)
|
||||||
assert.Equal(assetContentHash, a.computedHash)
|
assert.Equal(assetContentHash, a.computedHash)
|
||||||
|
|
||||||
p = &SandboxConfig{
|
anno = map[string]string{
|
||||||
Annotations: map[string]string{
|
|
||||||
annotations.KernelPath: tmpfile.Name(),
|
annotations.KernelPath: tmpfile.Name(),
|
||||||
annotations.KernelHash: assetContentWrongHash,
|
annotations.KernelHash: assetContentWrongHash,
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = newAsset(p, kernelAsset)
|
_, err = NewAsset(anno, KernelAsset)
|
||||||
assert.NotNil(err)
|
assert.NotNil(err)
|
||||||
}
|
}
|
68
virtcontainers/types/capabilities.go
Normal file
68
virtcontainers/types/capabilities.go
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// Copyright (c) 2017 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
package types
|
||||||
|
|
||||||
|
const (
|
||||||
|
blockDeviceSupport = 1 << iota
|
||||||
|
blockDeviceHotplugSupport
|
||||||
|
multiQueueSupport
|
||||||
|
fsSharingUnsupported
|
||||||
|
)
|
||||||
|
|
||||||
|
// Capabilities describe a virtcontainers hypervisor capabilities
|
||||||
|
// through a bit mask.
|
||||||
|
type Capabilities struct {
|
||||||
|
flags uint
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsBlockDeviceSupported tells if an hypervisor supports block devices.
|
||||||
|
func (caps *Capabilities) IsBlockDeviceSupported() bool {
|
||||||
|
if caps.flags&blockDeviceSupport != 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBlockDeviceSupport sets the block device support capability to true.
|
||||||
|
func (caps *Capabilities) SetBlockDeviceSupport() {
|
||||||
|
caps.flags = caps.flags | blockDeviceSupport
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsBlockDeviceHotplugSupported tells if an hypervisor supports hotplugging block devices.
|
||||||
|
func (caps *Capabilities) IsBlockDeviceHotplugSupported() bool {
|
||||||
|
if caps.flags&blockDeviceHotplugSupport != 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBlockDeviceHotplugSupport sets the block device hotplugging capability to true.
|
||||||
|
func (caps *Capabilities) SetBlockDeviceHotplugSupport() {
|
||||||
|
caps.flags |= blockDeviceHotplugSupport
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsMultiQueueSupported tells if an hypervisor supports device multi queue support.
|
||||||
|
func (caps *Capabilities) IsMultiQueueSupported() bool {
|
||||||
|
if caps.flags&multiQueueSupport != 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMultiQueueSupport sets the device multi queue capability to true.
|
||||||
|
func (caps *Capabilities) SetMultiQueueSupport() {
|
||||||
|
caps.flags |= multiQueueSupport
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsFsSharingSupported tells if an hypervisor supports host filesystem sharing.
|
||||||
|
func (caps *Capabilities) IsFsSharingSupported() bool {
|
||||||
|
return caps.flags&fsSharingUnsupported == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFsSharingUnsupported sets the host filesystem sharing capability to true.
|
||||||
|
func (caps *Capabilities) SetFsSharingUnsupported() {
|
||||||
|
caps.flags |= fsSharingUnsupported
|
||||||
|
}
|
50
virtcontainers/types/capabilities_test.go
Normal file
50
virtcontainers/types/capabilities_test.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// Copyright (c) 2017 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
package types
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestBlockDeviceCapability(t *testing.T) {
|
||||||
|
var caps Capabilities
|
||||||
|
|
||||||
|
if caps.IsBlockDeviceSupported() {
|
||||||
|
t.Fatal()
|
||||||
|
}
|
||||||
|
|
||||||
|
caps.SetBlockDeviceSupport()
|
||||||
|
|
||||||
|
if !caps.IsBlockDeviceSupported() {
|
||||||
|
t.Fatal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBlockDeviceHotplugCapability(t *testing.T) {
|
||||||
|
var caps Capabilities
|
||||||
|
|
||||||
|
if caps.IsBlockDeviceHotplugSupported() {
|
||||||
|
t.Fatal()
|
||||||
|
}
|
||||||
|
|
||||||
|
caps.SetBlockDeviceHotplugSupport()
|
||||||
|
|
||||||
|
if !caps.IsBlockDeviceHotplugSupported() {
|
||||||
|
t.Fatal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFsSharingCapability(t *testing.T) {
|
||||||
|
var caps Capabilities
|
||||||
|
|
||||||
|
if !caps.IsFsSharingSupported() {
|
||||||
|
t.Fatal()
|
||||||
|
}
|
||||||
|
|
||||||
|
caps.SetFsSharingUnsupported()
|
||||||
|
|
||||||
|
if caps.IsFsSharingSupported() {
|
||||||
|
t.Fatal()
|
||||||
|
}
|
||||||
|
}
|
@ -3,37 +3,41 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
//
|
//
|
||||||
|
|
||||||
package virtcontainers
|
package types
|
||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
type bridgeType string
|
// PCIType represents a type of PCI bus and bridge.
|
||||||
|
type PCIType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
pciBridge bridgeType = "pci"
|
// PCI represents a PCI bus and bridge
|
||||||
pcieBridge bridgeType = "pcie"
|
PCI PCIType = "pci"
|
||||||
|
|
||||||
|
// PCIE represents a PCIe bus and bridge
|
||||||
|
PCIE PCIType = "pcie"
|
||||||
)
|
)
|
||||||
|
|
||||||
const pciBridgeMaxCapacity = 30
|
const pciBridgeMaxCapacity = 30
|
||||||
|
|
||||||
// Bridge is a bridge where devices can be hot plugged
|
// PCIBridge is a PCI or PCIe bridge where devices can be hot plugged
|
||||||
type Bridge struct {
|
type PCIBridge struct {
|
||||||
// Address contains information about devices plugged and its address in the bridge
|
// Address contains information about devices plugged and its address in the bridge
|
||||||
Address map[uint32]string
|
Address map[uint32]string
|
||||||
|
|
||||||
// Type is the type of the bridge (pci, pcie, etc)
|
// Type is the PCI type of the bridge (pci, pcie, etc)
|
||||||
Type bridgeType
|
Type PCIType
|
||||||
|
|
||||||
//ID is used to identify the bridge in the hypervisor
|
// ID is used to identify the bridge in the hypervisor
|
||||||
ID string
|
ID string
|
||||||
|
|
||||||
// Addr is the PCI/e slot of the bridge
|
// Addr is the PCI/e slot of the bridge
|
||||||
Addr int
|
Addr int
|
||||||
}
|
}
|
||||||
|
|
||||||
// addDevice on success adds the device ID to the bridge and return the address
|
// AddDevice on success adds the device ID to the PCI bridge and returns
|
||||||
// where the device was added, otherwise an error is returned
|
// the address where the device was added.
|
||||||
func (b *Bridge) addDevice(ID string) (uint32, error) {
|
func (b *PCIBridge) AddDevice(ID string) (uint32, error) {
|
||||||
var addr uint32
|
var addr uint32
|
||||||
|
|
||||||
// looking for the first available address
|
// looking for the first available address
|
||||||
@ -53,9 +57,8 @@ func (b *Bridge) addDevice(ID string) (uint32, error) {
|
|||||||
return addr, nil
|
return addr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// removeDevice on success removes the device ID from the bridge and return nil,
|
// RemoveDevice removes the device ID from the PCI bridge.
|
||||||
// otherwise an error is returned
|
func (b *PCIBridge) RemoveDevice(ID string) error {
|
||||||
func (b *Bridge) removeDevice(ID string) error {
|
|
||||||
// check if the device was hot plugged in the bridge
|
// check if the device was hot plugged in the bridge
|
||||||
for addr, devID := range b.Address {
|
for addr, devID := range b.Address {
|
||||||
if devID == ID {
|
if devID == ID {
|
@ -3,7 +3,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
//
|
//
|
||||||
|
|
||||||
package virtcontainers
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -16,22 +16,22 @@ func TestAddRemoveDevice(t *testing.T) {
|
|||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
// create a bridge
|
// create a bridge
|
||||||
bridges := []*Bridge{{make(map[uint32]string), pciBridge, "rgb123", 5}}
|
bridges := []*PCIBridge{{make(map[uint32]string), PCI, "rgb123", 5}}
|
||||||
|
|
||||||
// add device
|
// add device
|
||||||
devID := "abc123"
|
devID := "abc123"
|
||||||
b := bridges[0]
|
b := bridges[0]
|
||||||
addr, err := b.addDevice(devID)
|
addr, err := b.AddDevice(devID)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
if addr < 1 {
|
if addr < 1 {
|
||||||
assert.Fail("address cannot be less than 1")
|
assert.Fail("address cannot be less than 1")
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove device
|
// remove device
|
||||||
err = b.removeDevice("")
|
err = b.RemoveDevice("")
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
|
|
||||||
err = b.removeDevice(devID)
|
err = b.RemoveDevice(devID)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
|
|
||||||
// add device when the bridge is full
|
// add device when the bridge is full
|
||||||
@ -39,7 +39,7 @@ func TestAddRemoveDevice(t *testing.T) {
|
|||||||
for i := uint32(1); i <= pciBridgeMaxCapacity; i++ {
|
for i := uint32(1); i <= pciBridgeMaxCapacity; i++ {
|
||||||
bridges[0].Address[i] = fmt.Sprintf("%d", i)
|
bridges[0].Address[i] = fmt.Sprintf("%d", i)
|
||||||
}
|
}
|
||||||
addr, err = b.addDevice(devID)
|
addr, err = b.AddDevice(devID)
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
if addr != 0 {
|
if addr != 0 {
|
||||||
assert.Fail("address should be 0")
|
assert.Fail("address should be 0")
|
Loading…
Reference in New Issue
Block a user