revert: "virtcontainers: support pre-add storage for frakti"

This PR got merged while it had some issues with some shim processes
being left behind after k8s testing. And because those issues were
real issues introduced by this PR (not some random failures), now
the master branch is broken and new pull requests cannot get the
CI passing. That's the reason why this commit revert the changes
introduced by this PR so that we can fix the master branch.

Fixes #529

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2018-07-27 09:18:29 -07:00
parent cfbc974fec
commit 927487c142
26 changed files with 384 additions and 892 deletions

View File

@ -20,8 +20,9 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
"github.com/kata-containers/runtime/virtcontainers/device/api"
"github.com/kata-containers/runtime/virtcontainers/device/config" "github.com/kata-containers/runtime/virtcontainers/device/config"
"github.com/kata-containers/runtime/virtcontainers/device/manager" "github.com/kata-containers/runtime/virtcontainers/device/drivers"
"github.com/kata-containers/runtime/virtcontainers/utils" "github.com/kata-containers/runtime/virtcontainers/utils"
) )
@ -228,14 +229,6 @@ type SystemMountsInfo struct {
DevShmSize uint DevShmSize uint
} }
// ContainerDevice describes a device associated with container
type ContainerDevice struct {
// ID is device id referencing the device from sandbox's device manager
ID string
// ContainerPath is device path displayed in container
ContainerPath string
}
// Container is composed of a set of containers and a runtime environment. // Container is composed of a set of containers and a runtime environment.
// A Container can be created, deleted, started, stopped, listed, entered, paused and restored. // A Container can be created, deleted, started, stopped, listed, entered, paused and restored.
type Container struct { type Container struct {
@ -258,7 +251,7 @@ type Container struct {
mounts []Mount mounts []Mount
devices []ContainerDevice devices []api.Device
systemMountsInfo SystemMountsInfo systemMountsInfo SystemMountsInfo
} }
@ -369,7 +362,7 @@ func (c *Container) storeDevices() error {
return c.sandbox.storage.storeContainerDevices(c.sandboxID, c.id, c.devices) return c.sandbox.storage.storeContainerDevices(c.sandboxID, c.id, c.devices)
} }
func (c *Container) fetchDevices() ([]ContainerDevice, error) { func (c *Container) fetchDevices() ([]api.Device, error) {
return c.sandbox.storage.fetchContainerDevices(c.sandboxID, c.id) return c.sandbox.storage.fetchContainerDevices(c.sandboxID, c.id)
} }
@ -437,19 +430,30 @@ func (c *Container) mountSharedDirMounts(hostSharedDir, guestSharedDir string) (
continue continue
} }
// Check if mount is a block device file. If it is, the block device will be attached to the host var stat unix.Stat_t
// instead of passing this as a shared mount. if err := unix.Stat(m.Source, &stat); err != nil {
if len(m.BlockDeviceID) > 0 {
// Attach this block device, all other devices passed in the config have been attached at this point
if err := c.sandbox.devManager.AttachDevice(m.BlockDeviceID, c.sandbox); err != nil &&
err != manager.ErrDeviceAttached {
return nil, err return nil, err
} }
if err := c.sandbox.storeSandboxDevices(); err != nil { // Check if mount is a block device file. If it is, the block device will be attached to the host
//TODO: roll back? // instead of passing this as a shared mount.
if c.checkBlockDeviceSupport() && stat.Mode&unix.S_IFBLK == unix.S_IFBLK {
// TODO: remove dependency of package drivers
b := &drivers.BlockDevice{
DevType: config.DeviceBlock,
DeviceInfo: config.DeviceInfo{
HostPath: m.Source,
ContainerPath: m.Destination,
DevType: "b",
},
}
// Attach this block device, all other devices passed in the config have been attached at this point
if err := b.Attach(c.sandbox); err != nil {
return nil, err return nil, err
} }
c.mounts[idx].BlockDevice = b
continue continue
} }
@ -562,38 +566,6 @@ func newContainer(sandbox *Sandbox, contConfig ContainerConfig) (*Container, err
c.mounts = mounts c.mounts = mounts
} }
// iterate all mounts and create block device if it's block based.
for i, m := range c.mounts {
if len(m.BlockDeviceID) > 0 || m.Type != "bind" {
// Non-empty m.BlockDeviceID indicates there's already one device
// associated with the mount,so no need to create a new device for it
// and we only create block device for bind mount
continue
}
var stat unix.Stat_t
if err := unix.Stat(m.Source, &stat); err != nil {
return nil, fmt.Errorf("stat %q failed: %v", m.Source, err)
}
// Check if mount is a block device file. If it is, the block device will be attached to the host
// instead of passing this as a shared mount.
if c.checkBlockDeviceSupport() && stat.Mode&unix.S_IFBLK == unix.S_IFBLK {
b, err := c.sandbox.devManager.NewDevice(config.DeviceInfo{
HostPath: m.Source,
ContainerPath: m.Destination,
DevType: "b",
Major: int64(unix.Major(stat.Rdev)),
Minor: int64(unix.Minor(stat.Rdev)),
})
if err != nil {
return nil, fmt.Errorf("device manager failed to create new device for %q: %v", m.Source, err)
}
c.mounts[i].BlockDeviceID = b.DeviceID()
}
}
// Devices will be found in storage after create stage has completed. // Devices will be found in storage after create stage has completed.
// We fetch devices from storage at all other stages. // We fetch devices from storage at all other stages.
storedDevices, err := c.fetchDevices() storedDevices, err := c.fetchDevices()
@ -602,19 +574,13 @@ func newContainer(sandbox *Sandbox, contConfig ContainerConfig) (*Container, err
} else { } else {
// If devices were not found in storage, create Device implementations // If devices were not found in storage, create Device implementations
// from the configuration. This should happen at create. // from the configuration. This should happen at create.
for _, info := range contConfig.DeviceInfos {
dev, err := sandbox.devManager.NewDevice(info) devices, err := sandbox.devManager.NewDevices(contConfig.DeviceInfos)
if err != nil { if err != nil {
return &Container{}, err return &Container{}, err
} }
c.devices = devices
c.devices = append(c.devices, ContainerDevice{
ID: dev.DeviceID(),
ContainerPath: info.ContainerPath,
})
} }
}
return c, nil return c, nil
} }
@ -1054,10 +1020,9 @@ func (c *Container) hotplugDrive() error {
return err return err
} }
// TODO: use general device manager instead of BlockDrive directly
// Add drive with id as container id // Add drive with id as container id
devID := utils.MakeNameID("drive", c.id, maxDevIDSize) devID := utils.MakeNameID("drive", c.id, maxDevIDSize)
drive := config.BlockDrive{ drive := drivers.Drive{
File: devicePath, File: devicePath,
Format: "raw", Format: "raw",
ID: devID, ID: devID,
@ -1094,7 +1059,7 @@ func (c *Container) removeDrive() (err error) {
c.Logger().Info("unplugging block device") c.Logger().Info("unplugging block device")
devID := utils.MakeNameID("drive", c.id, maxDevIDSize) devID := utils.MakeNameID("drive", c.id, maxDevIDSize)
drive := &config.BlockDrive{ drive := &drivers.Drive{
ID: devID, ID: devID,
} }
@ -1111,39 +1076,22 @@ func (c *Container) removeDrive() (err error) {
} }
func (c *Container) attachDevices() error { func (c *Container) attachDevices() error {
// there's no need to do rollback when error happens, for _, device := range c.devices {
// because if attachDevices fails, container creation will fail too, if err := device.Attach(c.sandbox); err != nil {
// and rollbackFailingContainerCreation could do all the rollbacks
for _, dev := range c.devices {
if err := c.sandbox.devManager.AttachDevice(dev.ID, c.sandbox); err != nil {
if err == manager.ErrDeviceAttached {
// skip if device is already attached before
continue
}
return err return err
} }
} }
if err := c.sandbox.storeSandboxDevices(); err != nil {
return err
}
return nil return nil
} }
func (c *Container) detachDevices() error { func (c *Container) detachDevices() error {
for _, dev := range c.devices { for _, device := range c.devices {
if err := c.sandbox.devManager.DetachDevice(dev.ID, c.sandbox); err != nil { if err := device.Detach(c.sandbox); err != nil {
if err == manager.ErrDeviceNotAttached {
// skip if device isn't attached
continue
}
return err return err
} }
} }
if err := c.sandbox.storeSandboxDevices(); err != nil {
return err
}
return nil return nil
} }

View File

@ -27,7 +27,6 @@ func DeviceLogger() *logrus.Entry {
// DeviceReceiver is an interface used for accepting devices // DeviceReceiver is an interface used for accepting devices
// a device should be attached/added/plugged to a DeviceReceiver // a device should be attached/added/plugged to a DeviceReceiver
type DeviceReceiver interface { type DeviceReceiver interface {
// these are for hotplug/hot-unplug devices to/from hypervisor
HotplugAddDevice(Device, config.DeviceType) error HotplugAddDevice(Device, config.DeviceType) error
HotplugRemoveDevice(Device, config.DeviceType) error HotplugRemoveDevice(Device, config.DeviceType) error
@ -35,35 +34,28 @@ type DeviceReceiver interface {
GetAndSetSandboxBlockIndex() (int, error) GetAndSetSandboxBlockIndex() (int, error)
DecrementSandboxBlockIndex() error DecrementSandboxBlockIndex() error
// this is for appending device to hypervisor boot params // this is for vhost_user devices
AppendDevice(Device) error AddVhostUserDevice(VhostUserDevice, config.DeviceType) error
}
// VhostUserDevice represents a vhost-user device. Shared
// attributes of a vhost-user device can be retrieved using
// the Attrs() method. Unique data can be obtained by casting
// the object to the proper type.
type VhostUserDevice interface {
Attrs() *config.VhostUserDeviceAttrs
Type() config.DeviceType
} }
// Device is the virtcontainers device interface. // Device is the virtcontainers device interface.
type Device interface { type Device interface {
Attach(DeviceReceiver) error Attach(DeviceReceiver) error
Detach(DeviceReceiver) error Detach(DeviceReceiver) error
// ID returns device identifier
DeviceID() string
// DeviceType indicates which kind of device it is
// e.g. block, vfio or vhost user
DeviceType() config.DeviceType DeviceType() config.DeviceType
// GetDeviceInfo returns device specific data used for hotplugging by hypervisor
// Caller could cast the return value to device specific struct
// e.g. Block device returns *config.BlockDrive and
// vfio device returns []*config.VFIODev
GetDeviceInfo() interface{}
// IsAttached checks if the device is attached
IsAttached() bool
} }
// DeviceManager can be used to create a new device, this can be used as single // DeviceManager can be used to create a new device, this can be used as single
// device management object. // device management object.
type DeviceManager interface { type DeviceManager interface {
NewDevice(config.DeviceInfo) (Device, error) NewDevices(devInfos []config.DeviceInfo) ([]Device, error)
AttachDevice(string, DeviceReceiver) error
DetachDevice(string, DeviceReceiver) error
IsDeviceAttached(string) bool
GetDeviceByID(string) Device
GetAllDevices() []Device
} }

View File

@ -32,7 +32,7 @@ func (mockDC *MockDeviceReceiver) DecrementSandboxBlockIndex() error {
return nil return nil
} }
// AppendDevice adds new vhost user device // AddVhostUserDevice adds new vhost user device
func (mockDC *MockDeviceReceiver) AppendDevice(Device) error { func (mockDC *MockDeviceReceiver) AddVhostUserDevice(VhostUserDevice, config.DeviceType) error {
return nil return nil
} }

View File

@ -49,10 +49,10 @@ var SysIOMMUPath = "/sys/kernel/iommu_groups"
// DeviceInfo is an embedded type that contains device data common to all types of devices. // DeviceInfo is an embedded type that contains device data common to all types of devices.
type DeviceInfo struct { type DeviceInfo struct {
// Hostpath is device path on host // Device path on host
HostPath string HostPath string
// ContainerPath is device path inside container // Device path inside the container
ContainerPath string ContainerPath string
// Type of device: c, b, u or p // Type of device: c, b, u or p
@ -87,48 +87,12 @@ type DeviceInfo struct {
DriverOptions map[string]string DriverOptions map[string]string
} }
// BlockDrive represents a block storage drive which may be used in case the storage
// driver has an underlying block storage device.
type BlockDrive struct {
// File is the path to the disk-image/device which will be used with this drive
File string
// Format of the drive
Format string
// ID is used to identify this drive in the hypervisor options.
ID string
// Index assigned to the drive. In case of virtio-scsi, this is used as SCSI LUN index
Index int
// PCIAddr is the PCI address used to identify the slot at which the drive is attached.
PCIAddr string
// SCSI Address of the block device, in case the device is attached using SCSI driver
// SCSI address is in the format SCSI-Id:LUN
SCSIAddr string
// VirtPath at which the device appears inside the VM, outside of the container mount namespace
VirtPath string
}
// VFIODev represents a VFIO drive used for hotplugging
type VFIODev struct {
// ID is used to identify this drive in the hypervisor options.
ID string
// BDF (Bus:Device.Function) of the PCI address
BDF string
}
// VhostUserDeviceAttrs represents data shared by most vhost-user devices // VhostUserDeviceAttrs represents data shared by most vhost-user devices
type VhostUserDeviceAttrs struct { type VhostUserDeviceAttrs struct {
ID string DevType DeviceType
DeviceInfo DeviceInfo
SocketPath string SocketPath string
Type DeviceType ID string
// MacAddress is only meaningful for vhost user net device
MacAddress string
} }
// GetHostPathFunc is function pointer used to mock GetHostPath in tests. // GetHostPathFunc is function pointer used to mock GetHostPath in tests.

View File

@ -7,6 +7,7 @@
package drivers package drivers
import ( import (
"encoding/hex"
"path/filepath" "path/filepath"
"github.com/kata-containers/runtime/virtcontainers/device/api" "github.com/kata-containers/runtime/virtcontainers/device/api"
@ -16,17 +17,48 @@ import (
const maxDevIDSize = 31 const maxDevIDSize = 31
// Drive represents a block storage drive which may be used in case the storage
// driver has an underlying block storage device.
type Drive struct {
// Path to the disk-image/device which will be used with this drive
File string
// Format of the drive
Format string
// ID is used to identify this drive in the hypervisor options.
ID string
// Index assigned to the drive. In case of virtio-scsi, this is used as SCSI LUN index
Index int
// PCIAddr is the PCI address used to identify the slot at which the drive is attached.
PCIAddr string
}
// BlockDevice refers to a block storage device implementation. // BlockDevice refers to a block storage device implementation.
type BlockDevice struct { type BlockDevice struct {
ID string DevType config.DeviceType
DeviceInfo *config.DeviceInfo DeviceInfo config.DeviceInfo
BlockDrive *config.BlockDrive
// SCSI Address of the block device, in case the device is attached using SCSI driver
// SCSI address is in the format SCSI-Id:LUN
SCSIAddr string
// Path at which the device appears inside the VM, outside of the container mount namespace
VirtPath string
// PCI Slot of the block device
PCIAddr string
BlockDrive *Drive
} }
// NewBlockDevice creates a new block device based on DeviceInfo // NewBlockDevice creates a new block device based on DeviceInfo
func NewBlockDevice(devInfo *config.DeviceInfo) *BlockDevice { func NewBlockDevice(devInfo config.DeviceInfo) *BlockDevice {
return &BlockDevice{ return &BlockDevice{
ID: devInfo.ID, DevType: config.DeviceBlock,
DeviceInfo: devInfo, DeviceInfo: devInfo,
} }
} }
@ -34,10 +66,13 @@ func NewBlockDevice(devInfo *config.DeviceInfo) *BlockDevice {
// Attach is standard interface of api.Device, it's used to add device to some // Attach is standard interface of api.Device, it's used to add device to some
// DeviceReceiver // DeviceReceiver
func (device *BlockDevice) Attach(devReceiver api.DeviceReceiver) (err error) { func (device *BlockDevice) Attach(devReceiver api.DeviceReceiver) (err error) {
if device.DeviceInfo.Hotplugged { randBytes, err := utils.GenerateRandomBytes(8)
return nil if err != nil {
return err
} }
device.DeviceInfo.ID = hex.EncodeToString(randBytes)
// Increment the block index for the sandbox. This is used to determine the name // Increment the block index for the sandbox. This is used to determine the name
// for the block device in the case where the block device is used as container // for the block device in the case where the block device is used as container
// rootfs and the predicted block device name needs to be provided to the agent. // rootfs and the predicted block device name needs to be provided to the agent.
@ -53,13 +88,21 @@ func (device *BlockDevice) Attach(devReceiver api.DeviceReceiver) (err error) {
return err return err
} }
drive := &config.BlockDrive{ drive := Drive{
File: device.DeviceInfo.HostPath, File: device.DeviceInfo.HostPath,
Format: "raw", Format: "raw",
ID: utils.MakeNameID("drive", device.DeviceInfo.ID, maxDevIDSize), ID: utils.MakeNameID("drive", device.DeviceInfo.ID, maxDevIDSize),
Index: index, Index: index,
} }
deviceLogger().WithField("device", device.DeviceInfo.HostPath).Info("Attaching block device")
device.BlockDrive = &drive
if err = devReceiver.HotplugAddDevice(device, config.DeviceBlock); err != nil {
return err
}
device.DeviceInfo.Hotplugged = true
driveName, err := utils.GetVirtDriveName(index) driveName, err := utils.GetVirtDriveName(index)
if err != nil { if err != nil {
return err return err
@ -67,60 +110,36 @@ func (device *BlockDevice) Attach(devReceiver api.DeviceReceiver) (err error) {
customOptions := device.DeviceInfo.DriverOptions customOptions := device.DeviceInfo.DriverOptions
if customOptions != nil && customOptions["block-driver"] == "virtio-blk" { if customOptions != nil && customOptions["block-driver"] == "virtio-blk" {
drive.VirtPath = filepath.Join("/dev", driveName) device.VirtPath = filepath.Join("/dev", driveName)
device.PCIAddr = drive.PCIAddr
} else { } else {
scsiAddr, err := utils.GetSCSIAddress(index) scsiAddr, err := utils.GetSCSIAddress(index)
if err != nil { if err != nil {
return err return err
} }
drive.SCSIAddr = scsiAddr device.SCSIAddr = scsiAddr
} }
deviceLogger().WithField("device", device.DeviceInfo.HostPath).Info("Attaching block device")
device.BlockDrive = drive
if err = devReceiver.HotplugAddDevice(device, config.DeviceBlock); err != nil {
return err
}
device.DeviceInfo.Hotplugged = true
return nil return nil
} }
// Detach is standard interface of api.Device, it's used to remove device from some // Detach is standard interface of api.Device, it's used to remove device from some
// DeviceReceiver // DeviceReceiver
func (device *BlockDevice) Detach(devReceiver api.DeviceReceiver) error { func (device *BlockDevice) Detach(devReceiver api.DeviceReceiver) error {
if !device.DeviceInfo.Hotplugged { if device.DeviceInfo.Hotplugged {
return nil
}
deviceLogger().WithField("device", device.DeviceInfo.HostPath).Info("Unplugging block device") deviceLogger().WithField("device", device.DeviceInfo.HostPath).Info("Unplugging block device")
if err := devReceiver.HotplugRemoveDevice(device, config.DeviceBlock); err != nil { if err := devReceiver.HotplugRemoveDevice(device, config.DeviceBlock); err != nil {
deviceLogger().WithError(err).Error("Failed to unplug block device") deviceLogger().WithError(err).Error("Failed to unplug block device")
return err return err
} }
device.DeviceInfo.Hotplugged = false
return nil
}
// IsAttached checks if the device is attached }
func (device *BlockDevice) IsAttached() bool { return nil
return device.DeviceInfo.Hotplugged
} }
// DeviceType is standard interface of api.Device, it returns device type // DeviceType is standard interface of api.Device, it returns device type
func (device *BlockDevice) DeviceType() config.DeviceType { func (device *BlockDevice) DeviceType() config.DeviceType {
return config.DeviceBlock return device.DevType
}
// DeviceID returns device ID
func (device *BlockDevice) DeviceID() string {
return device.ID
}
// GetDeviceInfo returns device information used for creating
func (device *BlockDevice) GetDeviceInfo() interface{} {
return device.BlockDrive
} }

View File

@ -13,52 +13,29 @@ import (
// GenericDevice refers to a device that is neither a VFIO device or block device. // GenericDevice refers to a device that is neither a VFIO device or block device.
type GenericDevice struct { type GenericDevice struct {
ID string DevType config.DeviceType
DeviceInfo *config.DeviceInfo DeviceInfo config.DeviceInfo
} }
// NewGenericDevice creates a new GenericDevice // NewGenericDevice creates a new GenericDevice
func NewGenericDevice(devInfo *config.DeviceInfo) *GenericDevice { func NewGenericDevice(devInfo config.DeviceInfo) *GenericDevice {
return &GenericDevice{ return &GenericDevice{
ID: devInfo.ID, DevType: config.DeviceGeneric,
DeviceInfo: devInfo, DeviceInfo: devInfo,
} }
} }
// Attach is standard interface of api.Device // Attach is standard interface of api.Device
func (device *GenericDevice) Attach(devReceiver api.DeviceReceiver) error { func (device *GenericDevice) Attach(devReceiver api.DeviceReceiver) error {
if device.DeviceInfo.Hotplugged {
return nil
}
return nil return nil
} }
// Detach is standard interface of api.Device // Detach is standard interface of api.Device
func (device *GenericDevice) Detach(devReceiver api.DeviceReceiver) error { func (device *GenericDevice) Detach(devReceiver api.DeviceReceiver) error {
if !device.DeviceInfo.Hotplugged {
return nil return nil
} }
return nil
}
// IsAttached checks if the device is attached
func (device *GenericDevice) IsAttached() bool {
return device.DeviceInfo.Hotplugged
}
// DeviceID returns device ID
func (device *GenericDevice) DeviceID() string {
return device.ID
}
// DeviceType is standard interface of api.Device, it returns device type // DeviceType is standard interface of api.Device, it returns device type
func (device *GenericDevice) DeviceType() config.DeviceType { func (device *GenericDevice) DeviceType() config.DeviceType {
return config.DeviceGeneric return device.DevType
}
// GetDeviceInfo returns device information used for creating
func (device *GenericDevice) GetDeviceInfo() interface{} {
return device.DeviceInfo
} }

View File

@ -7,6 +7,7 @@
package drivers package drivers
import ( import (
"encoding/hex"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"path/filepath" "path/filepath"
@ -30,15 +31,15 @@ const (
// VFIODevice is a vfio device meant to be passed to the hypervisor // VFIODevice is a vfio device meant to be passed to the hypervisor
// to be used by the Virtual Machine. // to be used by the Virtual Machine.
type VFIODevice struct { type VFIODevice struct {
ID string DevType config.DeviceType
DeviceInfo *config.DeviceInfo DeviceInfo config.DeviceInfo
vfioDevs []*config.VFIODev BDF string
} }
// NewVFIODevice create a new VFIO device // NewVFIODevice create a new VFIO device
func NewVFIODevice(devInfo *config.DeviceInfo) *VFIODevice { func NewVFIODevice(devInfo config.DeviceInfo) *VFIODevice {
return &VFIODevice{ return &VFIODevice{
ID: devInfo.ID, DevType: config.DeviceVFIO,
DeviceInfo: devInfo, DeviceInfo: devInfo,
} }
} }
@ -46,10 +47,6 @@ func NewVFIODevice(devInfo *config.DeviceInfo) *VFIODevice {
// Attach is standard interface of api.Device, it's used to add device to some // Attach is standard interface of api.Device, it's used to add device to some
// DeviceReceiver // DeviceReceiver
func (device *VFIODevice) Attach(devReceiver api.DeviceReceiver) error { func (device *VFIODevice) Attach(devReceiver api.DeviceReceiver) error {
if device.DeviceInfo.Hotplugged {
return nil
}
vfioGroup := filepath.Base(device.DeviceInfo.HostPath) vfioGroup := filepath.Base(device.DeviceInfo.HostPath)
iommuDevicesPath := filepath.Join(config.SysIOMMUPath, vfioGroup, "devices") iommuDevicesPath := filepath.Join(config.SysIOMMUPath, vfioGroup, "devices")
@ -60,19 +57,21 @@ func (device *VFIODevice) Attach(devReceiver api.DeviceReceiver) error {
// Pass all devices in iommu group // Pass all devices in iommu group
for _, deviceFile := range deviceFiles { for _, deviceFile := range deviceFiles {
//Get bdf of device eg 0000:00:1c.0 //Get bdf of device eg 0000:00:1c.0
deviceBDF, err := getBDF(deviceFile.Name()) deviceBDF, err := getBDF(deviceFile.Name())
if err != nil { if err != nil {
return err return err
} }
vfio := &config.VFIODev{
ID: utils.MakeNameID("vfio", device.DeviceInfo.ID, maxDevIDSize),
BDF: deviceBDF,
}
device.vfioDevs = append(device.vfioDevs, vfio)
}
// hotplug a VFIO device is actually hotplugging a group of iommu devices device.BDF = deviceBDF
randBytes, err := utils.GenerateRandomBytes(8)
if err != nil {
return err
}
device.DeviceInfo.ID = hex.EncodeToString(randBytes)
if err := devReceiver.HotplugAddDevice(device, config.DeviceVFIO); err != nil { if err := devReceiver.HotplugAddDevice(device, config.DeviceVFIO); err != nil {
deviceLogger().WithError(err).Error("Failed to add device") deviceLogger().WithError(err).Error("Failed to add device")
return err return err
@ -82,49 +81,20 @@ func (device *VFIODevice) Attach(devReceiver api.DeviceReceiver) error {
"device-group": device.DeviceInfo.HostPath, "device-group": device.DeviceInfo.HostPath,
"device-type": "vfio-passthrough", "device-type": "vfio-passthrough",
}).Info("Device group attached") }).Info("Device group attached")
device.DeviceInfo.Hotplugged = true }
return nil return nil
} }
// Detach is standard interface of api.Device, it's used to remove device from some // Detach is standard interface of api.Device, it's used to remove device from some
// DeviceReceiver // DeviceReceiver
func (device *VFIODevice) Detach(devReceiver api.DeviceReceiver) error { func (device *VFIODevice) Detach(devReceiver api.DeviceReceiver) error {
if !device.DeviceInfo.Hotplugged {
return nil return nil
} }
// hotplug a VFIO device is actually hotplugging a group of iommu devices
if err := devReceiver.HotplugRemoveDevice(device, config.DeviceVFIO); err != nil {
deviceLogger().WithError(err).Error("Failed to remove device")
return err
}
deviceLogger().WithFields(logrus.Fields{
"device-group": device.DeviceInfo.HostPath,
"device-type": "vfio-passthrough",
}).Info("Device group detached")
device.DeviceInfo.Hotplugged = false
return nil
}
// IsAttached checks if the device is attached
func (device *VFIODevice) IsAttached() bool {
return device.DeviceInfo.Hotplugged
}
// DeviceType is standard interface of api.Device, it returns device type // DeviceType is standard interface of api.Device, it returns device type
func (device *VFIODevice) DeviceType() config.DeviceType { func (device *VFIODevice) DeviceType() config.DeviceType {
return config.DeviceVFIO return device.DevType
}
// DeviceID returns device ID
func (device *VFIODevice) DeviceID() string {
return device.ID
}
// GetDeviceInfo returns device information used for creating
func (device *VFIODevice) GetDeviceInfo() interface{} {
return device.vfioDevs
} }
// getBDF returns the BDF of pci device // getBDF returns the BDF of pci device

View File

@ -0,0 +1,29 @@
// Copyright (c) 2017-2018 Intel Corporation
// Copyright (c) 2018 Huawei Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
package drivers
import (
"encoding/hex"
"github.com/kata-containers/runtime/virtcontainers/device/api"
"github.com/kata-containers/runtime/virtcontainers/utils"
)
// vhostUserAttach handles the common logic among all of the vhost-user device's
// attach functions
func vhostUserAttach(device api.VhostUserDevice, devReceiver api.DeviceReceiver) error {
// generate a unique ID to be used for hypervisor commandline fields
randBytes, err := utils.GenerateRandomBytes(8)
if err != nil {
return err
}
id := hex.EncodeToString(randBytes)
device.Attrs().ID = id
return devReceiver.AddVhostUserDevice(device, device.Type())
}

View File

@ -7,17 +7,23 @@
package drivers package drivers
import ( import (
"encoding/hex"
"github.com/kata-containers/runtime/virtcontainers/device/api" "github.com/kata-containers/runtime/virtcontainers/device/api"
"github.com/kata-containers/runtime/virtcontainers/device/config" "github.com/kata-containers/runtime/virtcontainers/device/config"
"github.com/kata-containers/runtime/virtcontainers/utils"
) )
// VhostUserBlkDevice is a block vhost-user based device // VhostUserBlkDevice is a block vhost-user based device
type VhostUserBlkDevice struct { type VhostUserBlkDevice struct {
config.VhostUserDeviceAttrs config.VhostUserDeviceAttrs
DeviceInfo *config.DeviceInfo }
// Attrs returns the VhostUserDeviceAttrs associated with the vhost-user device
func (vhostUserBlkDevice *VhostUserBlkDevice) Attrs() *config.VhostUserDeviceAttrs {
return &vhostUserBlkDevice.VhostUserDeviceAttrs
}
// Type returns the type associated with the vhost-user device
func (vhostUserBlkDevice *VhostUserBlkDevice) Type() config.DeviceType {
return config.VhostUserBlk
} }
// //
@ -26,57 +32,17 @@ type VhostUserBlkDevice struct {
// Attach is standard interface of api.Device, it's used to add device to some // Attach is standard interface of api.Device, it's used to add device to some
// DeviceReceiver // DeviceReceiver
func (device *VhostUserBlkDevice) Attach(devReceiver api.DeviceReceiver) (err error) { func (vhostUserBlkDevice *VhostUserBlkDevice) Attach(devReceiver api.DeviceReceiver) (err error) {
if device.DeviceInfo.Hotplugged { return vhostUserAttach(vhostUserBlkDevice, devReceiver)
return nil
}
// generate a unique ID to be used for hypervisor commandline fields
randBytes, err := utils.GenerateRandomBytes(8)
if err != nil {
return err
}
id := hex.EncodeToString(randBytes)
device.ID = id
device.Type = device.DeviceType()
defer func() {
if err == nil {
device.DeviceInfo.Hotplugged = true
}
}()
return devReceiver.AppendDevice(device)
} }
// Detach is standard interface of api.Device, it's used to remove device from some // Detach is standard interface of api.Device, it's used to remove device from some
// DeviceReceiver // DeviceReceiver
func (device *VhostUserBlkDevice) Detach(devReceiver api.DeviceReceiver) error { func (vhostUserBlkDevice *VhostUserBlkDevice) Detach(devReceiver api.DeviceReceiver) error {
if !device.DeviceInfo.Hotplugged {
return nil return nil
} }
device.DeviceInfo.Hotplugged = false
return nil
}
// IsAttached checks if the device is attached
func (device *VhostUserBlkDevice) IsAttached() bool {
return device.DeviceInfo.Hotplugged
}
// DeviceID returns device ID
func (device *VhostUserBlkDevice) DeviceID() string {
return device.ID
}
// DeviceType is standard interface of api.Device, it returns device type // DeviceType is standard interface of api.Device, it returns device type
func (device *VhostUserBlkDevice) DeviceType() config.DeviceType { func (vhostUserBlkDevice *VhostUserBlkDevice) DeviceType() config.DeviceType {
return config.VhostUserBlk return vhostUserBlkDevice.DevType
}
// GetDeviceInfo returns device information used for creating
func (device *VhostUserBlkDevice) GetDeviceInfo() interface{} {
device.Type = device.DeviceType()
return &device.VhostUserDeviceAttrs
} }

View File

@ -7,17 +7,24 @@
package drivers package drivers
import ( import (
"encoding/hex"
"github.com/kata-containers/runtime/virtcontainers/device/api" "github.com/kata-containers/runtime/virtcontainers/device/api"
"github.com/kata-containers/runtime/virtcontainers/device/config" "github.com/kata-containers/runtime/virtcontainers/device/config"
"github.com/kata-containers/runtime/virtcontainers/utils"
) )
// VhostUserNetDevice is a network vhost-user based device // VhostUserNetDevice is a network vhost-user based device
type VhostUserNetDevice struct { type VhostUserNetDevice struct {
config.VhostUserDeviceAttrs config.VhostUserDeviceAttrs
DeviceInfo *config.DeviceInfo MacAddress string
}
// Attrs returns the VhostUserDeviceAttrs associated with the vhost-user device
func (vhostUserNetDevice *VhostUserNetDevice) Attrs() *config.VhostUserDeviceAttrs {
return &vhostUserNetDevice.VhostUserDeviceAttrs
}
// Type returns the type associated with the vhost-user device
func (vhostUserNetDevice *VhostUserNetDevice) Type() config.DeviceType {
return config.VhostUserNet
} }
// //
@ -26,57 +33,17 @@ type VhostUserNetDevice struct {
// Attach is standard interface of api.Device, it's used to add device to some // Attach is standard interface of api.Device, it's used to add device to some
// DeviceReceiver // DeviceReceiver
func (device *VhostUserNetDevice) Attach(devReceiver api.DeviceReceiver) (err error) { func (vhostUserNetDevice *VhostUserNetDevice) Attach(devReceiver api.DeviceReceiver) (err error) {
if device.DeviceInfo.Hotplugged { return vhostUserAttach(vhostUserNetDevice, devReceiver)
return nil
}
// generate a unique ID to be used for hypervisor commandline fields
randBytes, err := utils.GenerateRandomBytes(8)
if err != nil {
return err
}
id := hex.EncodeToString(randBytes)
device.ID = id
device.Type = device.DeviceType()
defer func() {
if err == nil {
device.DeviceInfo.Hotplugged = true
}
}()
return devReceiver.AppendDevice(device)
} }
// Detach is standard interface of api.Device, it's used to remove device from some // Detach is standard interface of api.Device, it's used to remove device from some
// DeviceReceiver // DeviceReceiver
func (device *VhostUserNetDevice) Detach(devReceiver api.DeviceReceiver) error { func (vhostUserNetDevice *VhostUserNetDevice) Detach(devReceiver api.DeviceReceiver) error {
if !device.DeviceInfo.Hotplugged {
return nil return nil
} }
device.DeviceInfo.Hotplugged = false
return nil
}
// IsAttached checks if the device is attached
func (device *VhostUserNetDevice) IsAttached() bool {
return device.DeviceInfo.Hotplugged
}
// DeviceID returns device ID
func (device *VhostUserNetDevice) DeviceID() string {
return device.ID
}
// DeviceType is standard interface of api.Device, it returns device type // DeviceType is standard interface of api.Device, it returns device type
func (device *VhostUserNetDevice) DeviceType() config.DeviceType { func (vhostUserNetDevice *VhostUserNetDevice) DeviceType() config.DeviceType {
return config.VhostUserNet return vhostUserNetDevice.DevType
}
// GetDeviceInfo returns device information used for creating
func (device *VhostUserNetDevice) GetDeviceInfo() interface{} {
device.Type = device.DeviceType()
return &device.VhostUserDeviceAttrs
} }

View File

@ -7,17 +7,23 @@
package drivers package drivers
import ( import (
"encoding/hex"
"github.com/kata-containers/runtime/virtcontainers/device/api" "github.com/kata-containers/runtime/virtcontainers/device/api"
"github.com/kata-containers/runtime/virtcontainers/device/config" "github.com/kata-containers/runtime/virtcontainers/device/config"
"github.com/kata-containers/runtime/virtcontainers/utils"
) )
// VhostUserSCSIDevice is a SCSI vhost-user based device // VhostUserSCSIDevice is a SCSI vhost-user based device
type VhostUserSCSIDevice struct { type VhostUserSCSIDevice struct {
config.VhostUserDeviceAttrs config.VhostUserDeviceAttrs
DeviceInfo *config.DeviceInfo }
// Attrs returns the VhostUserDeviceAttrs associated with the vhost-user device
func (vhostUserSCSIDevice *VhostUserSCSIDevice) Attrs() *config.VhostUserDeviceAttrs {
return &vhostUserSCSIDevice.VhostUserDeviceAttrs
}
// Type returns the type associated with the vhost-user device
func (vhostUserSCSIDevice *VhostUserSCSIDevice) Type() config.DeviceType {
return config.VhostUserSCSI
} }
// //
@ -26,57 +32,17 @@ type VhostUserSCSIDevice struct {
// Attach is standard interface of api.Device, it's used to add device to some // Attach is standard interface of api.Device, it's used to add device to some
// DeviceReceiver // DeviceReceiver
func (device *VhostUserSCSIDevice) Attach(devReceiver api.DeviceReceiver) (err error) { func (vhostUserSCSIDevice *VhostUserSCSIDevice) Attach(devReceiver api.DeviceReceiver) (err error) {
if device.DeviceInfo.Hotplugged { return vhostUserAttach(vhostUserSCSIDevice, devReceiver)
return nil
}
// generate a unique ID to be used for hypervisor commandline fields
randBytes, err := utils.GenerateRandomBytes(8)
if err != nil {
return err
}
id := hex.EncodeToString(randBytes)
device.ID = id
device.Type = device.DeviceType()
defer func() {
if err == nil {
device.DeviceInfo.Hotplugged = true
}
}()
return devReceiver.AppendDevice(device)
} }
// Detach is standard interface of api.Device, it's used to remove device from some // Detach is standard interface of api.Device, it's used to remove device from some
// DeviceReceiver // DeviceReceiver
func (device *VhostUserSCSIDevice) Detach(devReceiver api.DeviceReceiver) error { func (vhostUserSCSIDevice *VhostUserSCSIDevice) Detach(devReceiver api.DeviceReceiver) error {
if !device.DeviceInfo.Hotplugged {
return nil return nil
} }
device.DeviceInfo.Hotplugged = false
return nil
}
// IsAttached checks if the device is attached
func (device *VhostUserSCSIDevice) IsAttached() bool {
return device.DeviceInfo.Hotplugged
}
// DeviceID returns device ID
func (device *VhostUserSCSIDevice) DeviceID() string {
return device.ID
}
// DeviceType is standard interface of api.Device, it returns device type // DeviceType is standard interface of api.Device, it returns device type
func (device *VhostUserSCSIDevice) DeviceType() config.DeviceType { func (vhostUserSCSIDevice *VhostUserSCSIDevice) DeviceType() config.DeviceType {
return config.VhostUserSCSI return vhostUserSCSIDevice.DevType
}
// GetDeviceInfo returns device information used for creating
func (device *VhostUserSCSIDevice) GetDeviceInfo() interface{} {
device.Type = device.DeviceType()
return &device.VhostUserDeviceAttrs
} }

View File

@ -7,16 +7,11 @@
package manager package manager
import ( import (
"encoding/hex"
"errors"
"sync"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/kata-containers/runtime/virtcontainers/device/api" "github.com/kata-containers/runtime/virtcontainers/device/api"
"github.com/kata-containers/runtime/virtcontainers/device/config" "github.com/kata-containers/runtime/virtcontainers/device/config"
"github.com/kata-containers/runtime/virtcontainers/device/drivers" "github.com/kata-containers/runtime/virtcontainers/device/drivers"
"github.com/kata-containers/runtime/virtcontainers/utils"
) )
const ( const (
@ -26,162 +21,59 @@ const (
VirtioSCSI string = "virtio-scsi" VirtioSCSI string = "virtio-scsi"
) )
var (
// ErrIDExhausted represents that devices are too many
// and no more IDs can be generated
ErrIDExhausted = errors.New("IDs are exhausted")
// ErrDeviceNotExist represents device hasn't been created before
ErrDeviceNotExist = errors.New("device with specified ID hasn't been created")
// ErrDeviceAttached represents the device is already attached
ErrDeviceAttached = errors.New("device is already attached")
// ErrDeviceNotAttached represents the device isn't attached
ErrDeviceNotAttached = errors.New("device isn't attached")
)
type deviceManager struct { type deviceManager struct {
blockDriver string blockDriver string
devices map[string]api.Device
sync.RWMutex
} }
func deviceLogger() *logrus.Entry { func deviceLogger() *logrus.Entry {
return api.DeviceLogger().WithField("subsystem", "device") return api.DeviceLogger().WithField("subsystem", "device")
} }
// NewDeviceManager creates a deviceManager object behaved as api.DeviceManager
func NewDeviceManager(blockDriver string, devices []api.Device) api.DeviceManager {
dm := &deviceManager{
devices: make(map[string]api.Device),
}
if blockDriver == VirtioBlock {
dm.blockDriver = VirtioBlock
} else {
dm.blockDriver = VirtioSCSI
}
for _, dev := range devices {
dm.devices[dev.DeviceID()] = dev
}
return dm
}
// createDevice creates one device based on DeviceInfo // createDevice creates one device based on DeviceInfo
func (dm *deviceManager) createDevice(devInfo config.DeviceInfo) (api.Device, error) { func (dm *deviceManager) createDevice(devInfo config.DeviceInfo) (api.Device, error) {
path, err := config.GetHostPathFunc(devInfo) path, err := config.GetHostPathFunc(devInfo)
if err != nil { if err != nil {
return nil, err return nil, err
} }
devInfo.HostPath = path
// device ID must be generated by manager instead of device itself devInfo.HostPath = path
// in case of ID collision
if devInfo.ID, err = dm.newDeviceID(); err != nil {
return nil, err
}
if isVFIO(path) { if isVFIO(path) {
return drivers.NewVFIODevice(&devInfo), nil return drivers.NewVFIODevice(devInfo), nil
} else if isBlock(devInfo) { } else if isBlock(devInfo) {
if devInfo.DriverOptions == nil { if devInfo.DriverOptions == nil {
devInfo.DriverOptions = make(map[string]string) devInfo.DriverOptions = make(map[string]string)
} }
devInfo.DriverOptions["block-driver"] = dm.blockDriver devInfo.DriverOptions["block-driver"] = dm.blockDriver
return drivers.NewBlockDevice(&devInfo), nil return drivers.NewBlockDevice(devInfo), nil
} else { } else {
deviceLogger().WithField("device", path).Info("Device has not been passed to the container") deviceLogger().WithField("device", path).Info("Device has not been passed to the container")
return drivers.NewGenericDevice(&devInfo), nil return drivers.NewGenericDevice(devInfo), nil
} }
} }
// NewDevice creates bundles of devices based on array of DeviceInfo // NewDevices creates bundles of devices based on array of DeviceInfo
func (dm *deviceManager) NewDevice(devInfo config.DeviceInfo) (api.Device, error) { func (dm *deviceManager) NewDevices(devInfos []config.DeviceInfo) ([]api.Device, error) {
dm.Lock() var devices []api.Device
defer dm.Unlock()
dev, err := dm.createDevice(devInfo)
if err == nil {
dm.devices[dev.DeviceID()] = dev
}
return dev, err
}
func (dm *deviceManager) newDeviceID() (string, error) { for _, devInfo := range devInfos {
for i := 0; i < 5; i++ { device, err := dm.createDevice(devInfo)
// generate an random ID
randBytes, err := utils.GenerateRandomBytes(8)
if err != nil { if err != nil {
return "", err return nil, err
} }
id := hex.EncodeToString(randBytes) devices = append(devices, device)
// check ID collision, choose another one if ID is in use
if _, ok := dm.devices[id]; !ok {
return id, nil
}
}
return "", ErrIDExhausted
} }
func (dm *deviceManager) AttachDevice(id string, dr api.DeviceReceiver) error { return devices, nil
dm.Lock()
defer dm.Unlock()
d, ok := dm.devices[id]
if !ok {
return ErrDeviceNotExist
} }
if d.IsAttached() { // NewDeviceManager creates a deviceManager object behaved as api.DeviceManager
return ErrDeviceAttached func NewDeviceManager(blockDriver string) api.DeviceManager {
dm := &deviceManager{}
if blockDriver == VirtioBlock {
dm.blockDriver = VirtioBlock
} else {
dm.blockDriver = VirtioSCSI
} }
if err := d.Attach(dr); err != nil { return dm
return err
}
return nil
}
func (dm *deviceManager) DetachDevice(id string, dr api.DeviceReceiver) error {
dm.Lock()
defer dm.Unlock()
d, ok := dm.devices[id]
if !ok {
return ErrDeviceNotExist
}
if !d.IsAttached() {
return ErrDeviceNotAttached
}
if err := d.Detach(dr); err != nil {
return err
}
return nil
}
func (dm *deviceManager) GetDeviceByID(id string) api.Device {
dm.RLock()
defer dm.RUnlock()
if d, ok := dm.devices[id]; ok {
return d
}
return nil
}
func (dm *deviceManager) GetAllDevices() []api.Device {
dm.RLock()
defer dm.RUnlock()
devices := []api.Device{}
for _, v := range dm.devices {
devices = append(devices, v)
}
return devices
}
func (dm *deviceManager) IsDeviceAttached(id string) bool {
dm.RLock()
defer dm.RUnlock()
d, ok := dm.devices[id]
if !ok {
return false
}
return d.IsAttached()
} }

View File

@ -25,10 +25,9 @@ const fileMode0640 = os.FileMode(0640)
// dirMode is the permission bits used for creating a directory // dirMode is the permission bits used for creating a directory
const dirMode = os.FileMode(0750) | os.ModeDir const dirMode = os.FileMode(0750) | os.ModeDir
func TestNewDevice(t *testing.T) { func TestNewDevices(t *testing.T) {
dm := &deviceManager{ dm := &deviceManager{
blockDriver: VirtioBlock, blockDriver: VirtioBlock,
devices: make(map[string]api.Device),
} }
savedSysDevPrefix := config.SysDevPrefix savedSysDevPrefix := config.SysDevPrefix
@ -54,7 +53,7 @@ func TestNewDevice(t *testing.T) {
DevType: "c", DevType: "c",
} }
_, err = dm.NewDevice(deviceInfo) _, err = dm.NewDevices([]config.DeviceInfo{deviceInfo})
assert.NotNil(t, err) assert.NotNil(t, err)
format := strconv.FormatInt(major, 10) + ":" + strconv.FormatInt(minor, 10) format := strconv.FormatInt(major, 10) + ":" + strconv.FormatInt(minor, 10)
@ -63,7 +62,7 @@ func TestNewDevice(t *testing.T) {
// Return true for non-existent /sys/dev path. // Return true for non-existent /sys/dev path.
deviceInfo.ContainerPath = path deviceInfo.ContainerPath = path
_, err = dm.NewDevice(deviceInfo) _, err = dm.NewDevices([]config.DeviceInfo{deviceInfo})
assert.Nil(t, err) assert.Nil(t, err)
err = os.MkdirAll(ueventPathPrefix, dirMode) err = os.MkdirAll(ueventPathPrefix, dirMode)
@ -74,17 +73,18 @@ func TestNewDevice(t *testing.T) {
err = ioutil.WriteFile(ueventPath, content, fileMode0640) err = ioutil.WriteFile(ueventPath, content, fileMode0640)
assert.Nil(t, err) assert.Nil(t, err)
_, err = dm.NewDevice(deviceInfo) _, err = dm.NewDevices([]config.DeviceInfo{deviceInfo})
assert.NotNil(t, err) assert.NotNil(t, err)
content = []byte("MAJOR=252\nMINOR=3\nDEVNAME=vfio/2") content = []byte("MAJOR=252\nMINOR=3\nDEVNAME=vfio/2")
err = ioutil.WriteFile(ueventPath, content, fileMode0640) err = ioutil.WriteFile(ueventPath, content, fileMode0640)
assert.Nil(t, err) assert.Nil(t, err)
device, err := dm.NewDevice(deviceInfo) devices, err := dm.NewDevices([]config.DeviceInfo{deviceInfo})
assert.Nil(t, err) assert.Nil(t, err)
vfioDev, ok := device.(*drivers.VFIODevice) assert.Equal(t, len(devices), 1)
vfioDev, ok := devices[0].(*drivers.VFIODevice)
assert.True(t, ok) assert.True(t, ok)
assert.Equal(t, vfioDev.DeviceInfo.HostPath, path) assert.Equal(t, vfioDev.DeviceInfo.HostPath, path)
assert.Equal(t, vfioDev.DeviceInfo.ContainerPath, path) assert.Equal(t, vfioDev.DeviceInfo.ContainerPath, path)
@ -98,7 +98,6 @@ func TestNewDevice(t *testing.T) {
func TestAttachVFIODevice(t *testing.T) { func TestAttachVFIODevice(t *testing.T) {
dm := &deviceManager{ dm := &deviceManager{
blockDriver: VirtioBlock, blockDriver: VirtioBlock,
devices: make(map[string]api.Device),
} }
tmpDir, err := ioutil.TempDir("", "") tmpDir, err := ioutil.TempDir("", "")
assert.Nil(t, err) assert.Nil(t, err)
@ -129,7 +128,7 @@ func TestAttachVFIODevice(t *testing.T) {
DevType: "c", DevType: "c",
} }
device, err := dm.NewDevice(deviceInfo) device, err := dm.createDevice(deviceInfo)
assert.Nil(t, err) assert.Nil(t, err)
_, ok := device.(*drivers.VFIODevice) _, ok := device.(*drivers.VFIODevice)
assert.True(t, ok) assert.True(t, ok)
@ -145,7 +144,6 @@ func TestAttachVFIODevice(t *testing.T) {
func TestAttachGenericDevice(t *testing.T) { func TestAttachGenericDevice(t *testing.T) {
dm := &deviceManager{ dm := &deviceManager{
blockDriver: VirtioBlock, blockDriver: VirtioBlock,
devices: make(map[string]api.Device),
} }
path := "/dev/tty2" path := "/dev/tty2"
deviceInfo := config.DeviceInfo{ deviceInfo := config.DeviceInfo{
@ -154,7 +152,7 @@ func TestAttachGenericDevice(t *testing.T) {
DevType: "c", DevType: "c",
} }
device, err := dm.NewDevice(deviceInfo) device, err := dm.createDevice(deviceInfo)
assert.Nil(t, err) assert.Nil(t, err)
_, ok := device.(*drivers.GenericDevice) _, ok := device.(*drivers.GenericDevice)
assert.True(t, ok) assert.True(t, ok)
@ -170,7 +168,6 @@ func TestAttachGenericDevice(t *testing.T) {
func TestAttachBlockDevice(t *testing.T) { func TestAttachBlockDevice(t *testing.T) {
dm := &deviceManager{ dm := &deviceManager{
blockDriver: VirtioBlock, blockDriver: VirtioBlock,
devices: make(map[string]api.Device),
} }
path := "/dev/hda" path := "/dev/hda"
deviceInfo := config.DeviceInfo{ deviceInfo := config.DeviceInfo{
@ -180,7 +177,7 @@ func TestAttachBlockDevice(t *testing.T) {
} }
devReceiver := &api.MockDeviceReceiver{} devReceiver := &api.MockDeviceReceiver{}
device, err := dm.NewDevice(deviceInfo) device, err := dm.createDevice(deviceInfo)
assert.Nil(t, err) assert.Nil(t, err)
_, ok := device.(*drivers.BlockDevice) _, ok := device.(*drivers.BlockDevice)
assert.True(t, ok) assert.True(t, ok)
@ -193,7 +190,7 @@ func TestAttachBlockDevice(t *testing.T) {
// test virtio SCSI driver // test virtio SCSI driver
dm.blockDriver = VirtioSCSI dm.blockDriver = VirtioSCSI
device, err = dm.NewDevice(deviceInfo) device, err = dm.createDevice(deviceInfo)
assert.Nil(t, err) assert.Nil(t, err)
err = device.Attach(devReceiver) err = device.Attach(devReceiver)
assert.Nil(t, err) assert.Nil(t, err)
@ -201,41 +198,3 @@ func TestAttachBlockDevice(t *testing.T) {
err = device.Detach(devReceiver) err = device.Detach(devReceiver)
assert.Nil(t, err) assert.Nil(t, err)
} }
func TestAttachDetachDevice(t *testing.T) {
dm := NewDeviceManager(VirtioSCSI, nil)
path := "/dev/hda"
deviceInfo := config.DeviceInfo{
HostPath: path,
ContainerPath: path,
DevType: "b",
}
devReceiver := &api.MockDeviceReceiver{}
device, err := dm.NewDevice(deviceInfo)
assert.Nil(t, err)
// attach device
err = dm.AttachDevice(device.DeviceID(), devReceiver)
assert.Nil(t, err)
// attach device again(twice)
err = dm.AttachDevice(device.DeviceID(), devReceiver)
assert.NotNil(t, err)
assert.Equal(t, err, ErrDeviceAttached, "attach device twice should report error %q", ErrDeviceAttached)
attached := dm.IsDeviceAttached(device.DeviceID())
assert.True(t, attached)
// detach device
err = dm.DetachDevice(device.DeviceID(), devReceiver)
assert.Nil(t, err)
// detach device again(twice)
err = dm.DetachDevice(device.DeviceID(), devReceiver)
assert.NotNil(t, err)
assert.Equal(t, err, ErrDeviceNotAttached, "attach device twice should report error %q", ErrDeviceNotAttached)
attached = dm.IsDeviceAttached(device.DeviceID())
assert.False(t, attached)
}

View File

@ -52,9 +52,6 @@ const (
// devicesFileType represents a device file type // devicesFileType represents a device file type
devicesFileType devicesFileType
// devicesIDFileType saves reference IDs to file, e.g. device IDs
devicesIDFileType
) )
// configFile is the file name used for every JSON sandbox configuration. // configFile is the file name used for every JSON sandbox configuration.
@ -129,8 +126,6 @@ type resourceStorage interface {
fetchSandboxState(sandboxID string) (State, error) fetchSandboxState(sandboxID string) (State, error)
fetchSandboxNetwork(sandboxID string) (NetworkNamespace, error) fetchSandboxNetwork(sandboxID string) (NetworkNamespace, error)
storeSandboxNetwork(sandboxID string, networkNS NetworkNamespace) error storeSandboxNetwork(sandboxID string, networkNS NetworkNamespace) error
fetchSandboxDevices(sandboxID string) ([]api.Device, error)
storeSandboxDevices(sandboxID string, devices []api.Device) error
// Hypervisor resources // Hypervisor resources
fetchHypervisorState(sandboxID string, state interface{}) error fetchHypervisorState(sandboxID string, state interface{}) error
@ -149,8 +144,8 @@ type resourceStorage interface {
storeContainerProcess(sandboxID, containerID string, process Process) error storeContainerProcess(sandboxID, containerID string, process Process) error
fetchContainerMounts(sandboxID, containerID string) ([]Mount, error) fetchContainerMounts(sandboxID, containerID string) ([]Mount, error)
storeContainerMounts(sandboxID, containerID string, mounts []Mount) error storeContainerMounts(sandboxID, containerID string, mounts []Mount) error
fetchContainerDevices(sandboxID, containerID string) ([]ContainerDevice, error) fetchContainerDevices(sandboxID, containerID string) ([]api.Device, error)
storeContainerDevices(sandboxID, containerID string, devices []ContainerDevice) error storeContainerDevices(sandboxID, containerID string, devices []api.Device) error
} }
// filesystem is a resourceStorage interface implementation for a local filesystem. // filesystem is a resourceStorage interface implementation for a local filesystem.
@ -232,35 +227,6 @@ type TypedDevice struct {
Data json.RawMessage Data json.RawMessage
} }
// storeDeviceIDFile is used to marshal and store device IDs to disk.
func (fs *filesystem) storeDeviceIDFile(file string, data interface{}) error {
if file == "" {
return errNeedFile
}
f, err := os.Create(file)
if err != nil {
return err
}
defer f.Close()
devices, ok := data.([]ContainerDevice)
if !ok {
return fmt.Errorf("Incorrect data type received, Expected []string")
}
jsonOut, err := json.Marshal(devices)
if err != nil {
return fmt.Errorf("Could not marshal devices: %s", err)
}
if _, err := f.Write(jsonOut); err != nil {
return err
}
return nil
}
// storeDeviceFile is used to provide custom marshalling for Device objects. // storeDeviceFile is used to provide custom marshalling for Device objects.
// Device is first marshalled into TypedDevice to include the type // Device is first marshalled into TypedDevice to include the type
// of the Device object. // of the Device object.
@ -381,7 +347,7 @@ func (fs *filesystem) fetchDeviceFile(fileData []byte, devices *[]api.Device) er
func resourceNeedsContainerID(sandboxSpecific bool, resource sandboxResource) bool { func resourceNeedsContainerID(sandboxSpecific bool, resource sandboxResource) bool {
switch resource { switch resource {
case lockFileType, networkFileType, hypervisorFileType, agentFileType, devicesFileType: case lockFileType, networkFileType, hypervisorFileType, agentFileType:
// sandbox-specific resources // sandbox-specific resources
return false return false
default: default:
@ -404,7 +370,7 @@ func resourceDir(sandboxSpecific bool, sandboxID, containerID string, resource s
case configFileType: case configFileType:
path = configStoragePath path = configStoragePath
break break
case stateFileType, networkFileType, processFileType, lockFileType, mountsFileType, devicesFileType, devicesIDFileType, hypervisorFileType, agentFileType: case stateFileType, networkFileType, processFileType, lockFileType, mountsFileType, devicesFileType, hypervisorFileType, agentFileType:
path = runStoragePath path = runStoragePath
break break
default: default:
@ -455,9 +421,6 @@ func (fs *filesystem) resourceURI(sandboxSpecific bool, sandboxID, containerID s
case devicesFileType: case devicesFileType:
filename = devicesFile filename = devicesFile
break break
case devicesIDFileType:
filename = devicesFile
break
default: default:
return "", "", errInvalidResource return "", "", errInvalidResource
} }
@ -503,7 +466,6 @@ func (fs *filesystem) commonResourceChecks(sandboxSpecific bool, sandboxID, cont
case processFileType: case processFileType:
case mountsFileType: case mountsFileType:
case devicesFileType: case devicesFileType:
case devicesIDFileType:
default: default:
return errInvalidResource return errInvalidResource
} }
@ -590,19 +552,6 @@ func (fs *filesystem) storeDeviceResource(sandboxSpecific bool, sandboxID, conta
return fs.storeDeviceFile(devicesFile, file) return fs.storeDeviceFile(devicesFile, file)
} }
func (fs *filesystem) storeDevicesIDResource(sandboxSpecific bool, sandboxID, containerID string, resource sandboxResource, file interface{}) error {
if resource != devicesIDFileType {
return errInvalidResource
}
devicesFile, _, err := fs.resourceURI(sandboxSpecific, sandboxID, containerID, resource)
if err != nil {
return err
}
return fs.storeDeviceIDFile(devicesFile, file)
}
func (fs *filesystem) storeResource(sandboxSpecific bool, sandboxID, containerID string, resource sandboxResource, data interface{}) error { func (fs *filesystem) storeResource(sandboxSpecific bool, sandboxID, containerID string, resource sandboxResource, data interface{}) error {
if err := fs.commonResourceChecks(sandboxSpecific, sandboxID, containerID, resource); err != nil { if err := fs.commonResourceChecks(sandboxSpecific, sandboxID, containerID, resource); err != nil {
return err return err
@ -626,8 +575,6 @@ func (fs *filesystem) storeResource(sandboxSpecific bool, sandboxID, containerID
case []api.Device: case []api.Device:
return fs.storeDeviceResource(sandboxSpecific, sandboxID, containerID, resource, file) return fs.storeDeviceResource(sandboxSpecific, sandboxID, containerID, resource, file)
case []ContainerDevice:
return fs.storeDevicesIDResource(sandboxSpecific, sandboxID, containerID, resource, file)
default: default:
return fmt.Errorf("Invalid resource data type") return fmt.Errorf("Invalid resource data type")
@ -681,18 +628,6 @@ func (fs *filesystem) fetchSandboxNetwork(sandboxID string) (NetworkNamespace, e
return networkNS, nil return networkNS, nil
} }
func (fs *filesystem) fetchSandboxDevices(sandboxID string) ([]api.Device, error) {
var devices []api.Device
if err := fs.fetchResource(true, sandboxID, "", devicesFileType, &devices); err != nil {
return []api.Device{}, err
}
return devices, nil
}
func (fs *filesystem) storeSandboxDevices(sandboxID string, devices []api.Device) error {
return fs.storeSandboxResource(sandboxID, devicesFileType, devices)
}
func (fs *filesystem) fetchHypervisorState(sandboxID string, state interface{}) error { func (fs *filesystem) fetchHypervisorState(sandboxID string, state interface{}) error {
return fs.fetchResource(true, sandboxID, "", hypervisorFileType, state) return fs.fetchResource(true, sandboxID, "", hypervisorFileType, state)
} }
@ -799,11 +734,11 @@ func (fs *filesystem) fetchContainerMounts(sandboxID, containerID string) ([]Mou
return mounts, nil return mounts, nil
} }
func (fs *filesystem) fetchContainerDevices(sandboxID, containerID string) ([]ContainerDevice, error) { func (fs *filesystem) fetchContainerDevices(sandboxID, containerID string) ([]api.Device, error) {
var devices []ContainerDevice var devices []api.Device
if err := fs.fetchResource(false, sandboxID, containerID, devicesIDFileType, &devices); err != nil { if err := fs.fetchResource(false, sandboxID, containerID, devicesFileType, &devices); err != nil {
return nil, err return []api.Device{}, err
} }
return devices, nil return devices, nil
@ -813,8 +748,8 @@ func (fs *filesystem) storeContainerMounts(sandboxID, containerID string, mounts
return fs.storeContainerResource(sandboxID, containerID, mountsFileType, mounts) return fs.storeContainerResource(sandboxID, containerID, mountsFileType, mounts)
} }
func (fs *filesystem) storeContainerDevices(sandboxID, containerID string, devices []ContainerDevice) error { func (fs *filesystem) storeContainerDevices(sandboxID, containerID string, devices []api.Device) error {
return fs.storeContainerResource(sandboxID, containerID, devicesIDFileType, devices) return fs.storeContainerResource(sandboxID, containerID, devicesFileType, devices)
} }
func (fs *filesystem) deleteContainerResources(sandboxID, containerID string, resources []sandboxResource) error { func (fs *filesystem) deleteContainerResources(sandboxID, containerID string, resources []sandboxResource) error {

View File

@ -33,7 +33,7 @@ func TestFilesystemCreateAllResourcesSuccessful(t *testing.T) {
id: testSandboxID, id: testSandboxID,
storage: fs, storage: fs,
config: sandboxConfig, config: sandboxConfig,
devManager: manager.NewDeviceManager(manager.VirtioBlock, nil), devManager: manager.NewDeviceManager(manager.VirtioBlock),
containers: map[string]*Container{}, containers: map[string]*Container{},
} }

View File

@ -14,15 +14,15 @@ import (
"syscall" "syscall"
"time" "time"
"github.com/sirupsen/logrus"
"github.com/vishvananda/netlink"
proxyClient "github.com/clearcontainers/proxy/client" proxyClient "github.com/clearcontainers/proxy/client"
"github.com/kata-containers/runtime/virtcontainers/device/config" "github.com/kata-containers/runtime/virtcontainers/device/drivers"
"github.com/kata-containers/runtime/virtcontainers/pkg/hyperstart" "github.com/kata-containers/runtime/virtcontainers/pkg/hyperstart"
ns "github.com/kata-containers/runtime/virtcontainers/pkg/nsenter" ns "github.com/kata-containers/runtime/virtcontainers/pkg/nsenter"
"github.com/kata-containers/runtime/virtcontainers/utils" "github.com/kata-containers/runtime/virtcontainers/utils"
specs "github.com/opencontainers/runtime-spec/specs-go" specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/sirupsen/logrus"
"github.com/vishvananda/netlink"
) )
var defaultSockPathTemplates = []string{"%s/%s/hyper.sock", "%s/%s/tty.sock"} var defaultSockPathTemplates = []string{"%s/%s/hyper.sock", "%s/%s/tty.sock"}
@ -231,31 +231,6 @@ func fsMapFromMounts(mounts []Mount) []*hyperstart.FsmapDescriptor {
return fsmap return fsmap
} }
func fsMapFromDevices(c *Container) ([]*hyperstart.FsmapDescriptor, error) {
var fsmap []*hyperstart.FsmapDescriptor
for _, dev := range c.devices {
device := c.sandbox.devManager.GetDeviceByID(dev.ID)
if device == nil {
return nil, fmt.Errorf("can't find device: %#v", dev)
}
d, ok := device.GetDeviceInfo().(*config.BlockDrive)
if !ok || d == nil {
return nil, fmt.Errorf("can't retrieve block device information")
}
fsmapDesc := &hyperstart.FsmapDescriptor{
Source: d.VirtPath,
Path: dev.ContainerPath,
AbsolutePath: true,
DockerVolume: false,
SCSIAddr: d.SCSIAddr,
}
fsmap = append(fsmap, fsmapDesc)
}
return fsmap, nil
}
// init is the agent initialization implementation for hyperstart. // init is the agent initialization implementation for hyperstart.
func (h *hyper) init(sandbox *Sandbox, config interface{}) (err error) { func (h *hyper) init(sandbox *Sandbox, config interface{}) (err error) {
switch c := config.(type) { switch c := config.(type) {
@ -462,8 +437,8 @@ func (h *hyper) stopSandbox(sandbox *Sandbox) error {
// container. // container.
func (h *hyper) handleBlockVolumes(c *Container) { func (h *hyper) handleBlockVolumes(c *Container) {
for _, m := range c.mounts { for _, m := range c.mounts {
if len(m.BlockDeviceID) > 0 { if m.BlockDevice != nil {
c.devices = append(c.devices, ContainerDevice{ID: m.BlockDeviceID}) c.devices = append(c.devices, m.BlockDevice)
} }
} }
} }
@ -522,11 +497,20 @@ func (h *hyper) startOneContainer(sandbox *Sandbox, c *Container) error {
h.handleBlockVolumes(c) h.handleBlockVolumes(c)
// Append container mounts for block devices passed with --device. // Append container mounts for block devices passed with --device.
fsmapDev, err := fsMapFromDevices(c) for _, device := range c.devices {
if err != nil { d, ok := device.(*drivers.BlockDevice)
return err
if ok {
fsmapDesc := &hyperstart.FsmapDescriptor{
Source: d.VirtPath,
Path: d.DeviceInfo.ContainerPath,
AbsolutePath: true,
DockerVolume: false,
SCSIAddr: d.SCSIAddr,
}
fsmap = append(fsmap, fsmapDesc)
}
} }
fsmap = append(fsmap, fsmapDev...)
// Assign fsmap for hyperstart to mount these at the correct location within the container // Assign fsmap for hyperstart to mount these at the correct location within the container
container.Fsmap = fsmap container.Fsmap = fsmap

View File

@ -19,7 +19,8 @@ import (
kataclient "github.com/kata-containers/agent/protocols/client" kataclient "github.com/kata-containers/agent/protocols/client"
"github.com/kata-containers/agent/protocols/grpc" "github.com/kata-containers/agent/protocols/grpc"
"github.com/kata-containers/runtime/virtcontainers/device/config" "github.com/kata-containers/runtime/virtcontainers/device/api"
"github.com/kata-containers/runtime/virtcontainers/device/drivers"
vcAnnotations "github.com/kata-containers/runtime/virtcontainers/pkg/annotations" vcAnnotations "github.com/kata-containers/runtime/virtcontainers/pkg/annotations"
ns "github.com/kata-containers/runtime/virtcontainers/pkg/nsenter" ns "github.com/kata-containers/runtime/virtcontainers/pkg/nsenter"
"github.com/kata-containers/runtime/virtcontainers/pkg/uuid" "github.com/kata-containers/runtime/virtcontainers/pkg/uuid"
@ -722,26 +723,15 @@ func (k *kataAgent) handleShm(grpcSpec *grpc.Spec, sandbox *Sandbox) {
} }
} }
func (k *kataAgent) appendDevices(deviceList []*grpc.Device, c *Container) []*grpc.Device { func (k *kataAgent) appendDevices(deviceList []*grpc.Device, devices []api.Device) []*grpc.Device {
for _, dev := range c.devices { for _, device := range devices {
device := c.sandbox.devManager.GetDeviceByID(dev.ID) d, ok := device.(*drivers.BlockDevice)
if device == nil { if !ok {
k.Logger().WithField("device", dev.ID).Error("failed to find device by id")
return nil
}
if device.DeviceType() != config.DeviceBlock {
continue
}
d, ok := device.GetDeviceInfo().(*config.BlockDrive)
if !ok || d == nil {
k.Logger().WithField("device", device).Error("malformed block drive")
continue continue
} }
kataDevice := &grpc.Device{ kataDevice := &grpc.Device{
ContainerPath: dev.ContainerPath, ContainerPath: d.DeviceInfo.ContainerPath,
} }
if d.SCSIAddr == "" { if d.SCSIAddr == "" {
@ -878,7 +868,7 @@ func (k *kataAgent) createContainer(sandbox *Sandbox, c *Container) (p *Process,
} }
// Append container devices for block devices passed with --device. // Append container devices for block devices passed with --device.
ctrDevices = k.appendDevices(ctrDevices, c) ctrDevices = k.appendDevices(ctrDevices, c.devices)
// Handle all the volumes that are block device files. // Handle all the volumes that are block device files.
// Note this call modifies the list of container devices to make sure // Note this call modifies the list of container devices to make sure
@ -967,41 +957,27 @@ func (k *kataAgent) handleBlockVolumes(c *Container) []*grpc.Storage {
var volumeStorages []*grpc.Storage var volumeStorages []*grpc.Storage
for _, m := range c.mounts { for _, m := range c.mounts {
id := m.BlockDeviceID b := m.BlockDevice
if len(id) == 0 { if b == nil {
continue continue
} }
// Add the block device to the list of container devices, to make sure the // Add the block device to the list of container devices, to make sure the
// device is detached with detachDevices() for a container. // device is detached with detachDevices() for a container.
c.devices = append(c.devices, ContainerDevice{ID: id}) c.devices = append(c.devices, b)
if err := c.storeDevices(); err != nil {
k.Logger().WithField("device", id).WithError(err).Error("store device failed")
return nil
}
vol := &grpc.Storage{} vol := &grpc.Storage{}
device := c.sandbox.devManager.GetDeviceByID(id)
if device == nil {
k.Logger().WithField("device", id).Error("failed to find device by id")
return nil
}
blockDrive, ok := device.GetDeviceInfo().(*config.BlockDrive)
if !ok || blockDrive == nil {
k.Logger().Error("malformed block drive")
continue
}
if c.sandbox.config.HypervisorConfig.BlockDeviceDriver == VirtioBlock { if c.sandbox.config.HypervisorConfig.BlockDeviceDriver == VirtioBlock {
vol.Driver = kataBlkDevType vol.Driver = kataBlkDevType
vol.Source = blockDrive.VirtPath vol.Source = b.VirtPath
} else { } else {
vol.Driver = kataSCSIDevType vol.Driver = kataSCSIDevType
vol.Source = blockDrive.SCSIAddr vol.Source = b.SCSIAddr
} }
vol.MountPoint = m.Destination vol.MountPoint = b.DeviceInfo.ContainerPath
vol.Fstype = "bind" vol.Fstype = "bind"
vol.Options = []string{"bind"} vol.Options = []string{"bind"}

View File

@ -28,12 +28,11 @@ import (
"github.com/kata-containers/runtime/virtcontainers/device/api" "github.com/kata-containers/runtime/virtcontainers/device/api"
"github.com/kata-containers/runtime/virtcontainers/device/config" "github.com/kata-containers/runtime/virtcontainers/device/config"
"github.com/kata-containers/runtime/virtcontainers/device/drivers" "github.com/kata-containers/runtime/virtcontainers/device/drivers"
"github.com/kata-containers/runtime/virtcontainers/device/manager"
vcAnnotations "github.com/kata-containers/runtime/virtcontainers/pkg/annotations" vcAnnotations "github.com/kata-containers/runtime/virtcontainers/pkg/annotations"
"github.com/kata-containers/runtime/virtcontainers/pkg/mock" "github.com/kata-containers/runtime/virtcontainers/pkg/mock"
) )
var ( const (
testKataProxyURLTempl = "unix://%s/kata-proxy-test.sock" testKataProxyURLTempl = "unix://%s/kata-proxy-test.sock"
testBlockDeviceCtrPath = "testBlockDeviceCtrPath" testBlockDeviceCtrPath = "testBlockDeviceCtrPath"
testPCIAddr = "04/02" testPCIAddr = "04/02"
@ -445,15 +444,9 @@ func TestAppendDevicesEmptyContainerDeviceList(t *testing.T) {
devList := []*pb.Device{} devList := []*pb.Device{}
expected := []*pb.Device{} expected := []*pb.Device{}
ctrDevices := []ContainerDevice{} ctrDevices := []api.Device{}
c := &Container{ updatedDevList := k.appendDevices(devList, ctrDevices)
sandbox: &Sandbox{
devManager: manager.NewDeviceManager("virtio-scsi", nil),
},
devices: ctrDevices,
}
updatedDevList := k.appendDevices(devList, c)
assert.True(t, reflect.DeepEqual(updatedDevList, expected), assert.True(t, reflect.DeepEqual(updatedDevList, expected),
"Device lists didn't match: got %+v, expecting %+v", "Device lists didn't match: got %+v, expecting %+v",
updatedDevList, expected) updatedDevList, expected)
@ -462,26 +455,6 @@ func TestAppendDevicesEmptyContainerDeviceList(t *testing.T) {
func TestAppendDevices(t *testing.T) { func TestAppendDevices(t *testing.T) {
k := kataAgent{} k := kataAgent{}
id := "test-append-block"
ctrDevices := []api.Device{
&drivers.BlockDevice{
ID: id,
BlockDrive: &config.BlockDrive{
PCIAddr: testPCIAddr,
},
},
}
c := &Container{
sandbox: &Sandbox{
devManager: manager.NewDeviceManager("virtio-scsi", ctrDevices),
},
}
c.devices = append(c.devices, ContainerDevice{
ID: id,
ContainerPath: testBlockDeviceCtrPath,
})
devList := []*pb.Device{} devList := []*pb.Device{}
expected := []*pb.Device{ expected := []*pb.Device{
{ {
@ -490,7 +463,16 @@ func TestAppendDevices(t *testing.T) {
Id: testPCIAddr, Id: testPCIAddr,
}, },
} }
updatedDevList := k.appendDevices(devList, c) ctrDevices := []api.Device{
&drivers.BlockDevice{
DeviceInfo: config.DeviceInfo{
ContainerPath: testBlockDeviceCtrPath,
},
PCIAddr: testPCIAddr,
},
}
updatedDevList := k.appendDevices(devList, ctrDevices)
assert.True(t, reflect.DeepEqual(updatedDevList, expected), assert.True(t, reflect.DeepEqual(updatedDevList, expected),
"Device lists didn't match: got %+v, expecting %+v", "Device lists didn't match: got %+v, expecting %+v",
updatedDevList, expected) updatedDevList, expected)

View File

@ -14,6 +14,8 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"syscall" "syscall"
"github.com/kata-containers/runtime/virtcontainers/device/drivers"
) )
// DefaultShmSize is the default shm size to be used in case host // DefaultShmSize is the default shm size to be used in case host
@ -282,10 +284,10 @@ type Mount struct {
// ReadOnly specifies if the mount should be read only or not // ReadOnly specifies if the mount should be read only or not
ReadOnly bool ReadOnly bool
// BlockDeviceID represents block device that is attached to the // BlockDevice represents block device that is attached to the
// VM in case this mount is a block device file or a directory // VM in case this mount is a block device file or a directory
// backed by a block device. // backed by a block device.
BlockDeviceID string BlockDevice *drivers.BlockDevice
} }
func bindUnmountContainerRootfs(sharedDir, sandboxID, cID string) error { func bindUnmountContainerRootfs(sharedDir, sandboxID, cID string) error {

View File

@ -25,7 +25,6 @@ import (
"github.com/vishvananda/netns" "github.com/vishvananda/netns"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
"github.com/kata-containers/runtime/virtcontainers/device/config"
"github.com/kata-containers/runtime/virtcontainers/device/drivers" "github.com/kata-containers/runtime/virtcontainers/device/drivers"
"github.com/kata-containers/runtime/virtcontainers/pkg/uuid" "github.com/kata-containers/runtime/virtcontainers/pkg/uuid"
"github.com/kata-containers/runtime/virtcontainers/utils" "github.com/kata-containers/runtime/virtcontainers/utils"
@ -281,11 +280,11 @@ func (endpoint *VhostUserEndpoint) Attach(h hypervisor) error {
} }
id := hex.EncodeToString(randBytes) id := hex.EncodeToString(randBytes)
d := config.VhostUserDeviceAttrs{ d := &drivers.VhostUserNetDevice{
ID: id,
SocketPath: endpoint.SocketPath,
MacAddress: endpoint.HardAddr, MacAddress: endpoint.HardAddr,
} }
d.SocketPath = endpoint.SocketPath
d.ID = id
return h.addDevice(d, vhostuserDev) return h.addDevice(d, vhostuserDev)
} }
@ -344,8 +343,7 @@ func (endpoint *PhysicalEndpoint) Attach(h hypervisor) error {
return err return err
} }
// TODO: use device manager as general device management entrance d := drivers.VFIODevice{
d := config.VFIODev{
BDF: endpoint.BDF, BDF: endpoint.BDF,
} }

View File

@ -19,7 +19,8 @@ import (
"github.com/kata-containers/runtime/virtcontainers/pkg/uuid" "github.com/kata-containers/runtime/virtcontainers/pkg/uuid"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/kata-containers/runtime/virtcontainers/device/config" "github.com/kata-containers/runtime/virtcontainers/device/api"
deviceDrivers "github.com/kata-containers/runtime/virtcontainers/device/drivers"
"github.com/kata-containers/runtime/virtcontainers/utils" "github.com/kata-containers/runtime/virtcontainers/utils"
) )
@ -655,7 +656,7 @@ func (q *qemu) removeDeviceFromBridge(ID string) error {
return err return err
} }
func (q *qemu) hotplugBlockDevice(drive *config.BlockDrive, op operation) error { func (q *qemu) hotplugBlockDevice(drive *deviceDrivers.Drive, op operation) error {
err := q.qmpSetup() err := q.qmpSetup()
if err != nil { if err != nil {
return err return err
@ -716,13 +717,13 @@ func (q *qemu) hotplugBlockDevice(drive *config.BlockDrive, op operation) error
return nil return nil
} }
func (q *qemu) hotplugVFIODevice(device *config.VFIODev, op operation) error { func (q *qemu) hotplugVFIODevice(device deviceDrivers.VFIODevice, op operation) error {
err := q.qmpSetup() err := q.qmpSetup()
if err != nil { if err != nil {
return err return err
} }
devID := device.ID devID := "vfio-" + device.DeviceInfo.ID
if op == addDevice { if op == addDevice {
addr, bridge, err := q.addDeviceToBridge(devID) addr, bridge, err := q.addDeviceToBridge(devID)
@ -749,13 +750,15 @@ func (q *qemu) hotplugVFIODevice(device *config.VFIODev, op operation) error {
func (q *qemu) hotplugDevice(devInfo interface{}, devType deviceType, op operation) (interface{}, error) { func (q *qemu) hotplugDevice(devInfo interface{}, devType deviceType, op operation) (interface{}, error) {
switch devType { switch devType {
case blockDev: case blockDev:
drive := devInfo.(*config.BlockDrive) // TODO: find a way to remove dependency of deviceDrivers lib @weizhang555
drive := devInfo.(*deviceDrivers.Drive)
return nil, q.hotplugBlockDevice(drive, op) return nil, q.hotplugBlockDevice(drive, op)
case cpuDev: case cpuDev:
vcpus := devInfo.(uint32) vcpus := devInfo.(uint32)
return q.hotplugCPUs(vcpus, op) return q.hotplugCPUs(vcpus, op)
case vfioDev: case vfioDev:
device := devInfo.(*config.VFIODev) // TODO: find a way to remove dependency of deviceDrivers lib @weizhang555
device := devInfo.(deviceDrivers.VFIODevice)
return nil, q.hotplugVFIODevice(device, op) return nil, q.hotplugVFIODevice(device, op)
case memoryDev: case memoryDev:
memdev := devInfo.(*memoryDevice) memdev := devInfo.(*memoryDevice)
@ -941,6 +944,13 @@ func (q *qemu) resumeSandbox() error {
// addDevice will add extra devices to Qemu command line. // addDevice will add extra devices to Qemu command line.
func (q *qemu) addDevice(devInfo interface{}, devType deviceType) error { func (q *qemu) addDevice(devInfo interface{}, devType deviceType) error {
switch devType {
case vhostuserDev:
vhostDev := devInfo.(api.VhostUserDevice)
q.qemuConfig.Devices = q.arch.appendVhostUserDevice(q.qemuConfig.Devices, vhostDev)
return nil
}
switch v := devInfo.(type) { switch v := devInfo.(type) {
case Volume: case Volume:
q.qemuConfig.Devices = q.arch.append9PVolume(q.qemuConfig.Devices, v) q.qemuConfig.Devices = q.arch.append9PVolume(q.qemuConfig.Devices, v)
@ -948,11 +958,10 @@ func (q *qemu) addDevice(devInfo interface{}, devType deviceType) error {
q.qemuConfig.Devices = q.arch.appendSocket(q.qemuConfig.Devices, v) q.qemuConfig.Devices = q.arch.appendSocket(q.qemuConfig.Devices, v)
case Endpoint: case Endpoint:
q.qemuConfig.Devices = q.arch.appendNetwork(q.qemuConfig.Devices, v) q.qemuConfig.Devices = q.arch.appendNetwork(q.qemuConfig.Devices, v)
case config.BlockDrive: case deviceDrivers.Drive:
q.qemuConfig.Devices = q.arch.appendBlockDevice(q.qemuConfig.Devices, v) q.qemuConfig.Devices = q.arch.appendBlockDevice(q.qemuConfig.Devices, v)
case config.VhostUserDeviceAttrs:
q.qemuConfig.Devices = q.arch.appendVhostUserDevice(q.qemuConfig.Devices, v) case deviceDrivers.VFIODevice:
case config.VFIODev:
q.qemuConfig.Devices = q.arch.appendVFIODevice(q.qemuConfig.Devices, v) q.qemuConfig.Devices = q.arch.appendVFIODevice(q.qemuConfig.Devices, v)
default: default:
break break

View File

@ -13,7 +13,8 @@ import (
govmmQemu "github.com/intel/govmm/qemu" govmmQemu "github.com/intel/govmm/qemu"
"github.com/kata-containers/runtime/virtcontainers/device/config" "github.com/kata-containers/runtime/virtcontainers/device/api"
"github.com/kata-containers/runtime/virtcontainers/device/drivers"
"github.com/kata-containers/runtime/virtcontainers/utils" "github.com/kata-containers/runtime/virtcontainers/utils"
) )
@ -71,13 +72,13 @@ type qemuArch interface {
appendNetwork(devices []govmmQemu.Device, endpoint Endpoint) []govmmQemu.Device appendNetwork(devices []govmmQemu.Device, endpoint Endpoint) []govmmQemu.Device
// appendBlockDevice appends a block drive to devices // appendBlockDevice appends a block drive to devices
appendBlockDevice(devices []govmmQemu.Device, drive config.BlockDrive) []govmmQemu.Device appendBlockDevice(devices []govmmQemu.Device, drive drivers.Drive) []govmmQemu.Device
// appendVhostUserDevice appends a vhost user device to devices // appendVhostUserDevice appends a vhost user device to devices
appendVhostUserDevice(devices []govmmQemu.Device, drive config.VhostUserDeviceAttrs) []govmmQemu.Device appendVhostUserDevice(devices []govmmQemu.Device, vhostUserDevice api.VhostUserDevice) []govmmQemu.Device
// appendVFIODevice appends a VFIO device to devices // appendVFIODevice appends a VFIO device to devices
appendVFIODevice(devices []govmmQemu.Device, vfioDevice config.VFIODev) []govmmQemu.Device appendVFIODevice(devices []govmmQemu.Device, vfioDevice drivers.VFIODevice) []govmmQemu.Device
// handleImagePath handles the Hypervisor Config image path // handleImagePath handles the Hypervisor Config image path
handleImagePath(config HypervisorConfig) handleImagePath(config HypervisorConfig)
@ -285,7 +286,7 @@ func (q *qemuArchBase) appendImage(devices []govmmQemu.Device, path string) ([]g
id := utils.MakeNameID("image", hex.EncodeToString(randBytes), maxDevIDSize) id := utils.MakeNameID("image", hex.EncodeToString(randBytes), maxDevIDSize)
drive := config.BlockDrive{ drive := drivers.Drive{
File: path, File: path,
Format: "raw", Format: "raw",
ID: id, ID: id,
@ -429,7 +430,7 @@ func (q *qemuArchBase) appendNetwork(devices []govmmQemu.Device, endpoint Endpoi
return devices return devices
} }
func (q *qemuArchBase) appendBlockDevice(devices []govmmQemu.Device, drive config.BlockDrive) []govmmQemu.Device { func (q *qemuArchBase) appendBlockDevice(devices []govmmQemu.Device, drive drivers.Drive) []govmmQemu.Device {
if drive.File == "" || drive.ID == "" || drive.Format == "" { if drive.File == "" || drive.ID == "" || drive.Format == "" {
return devices return devices
} }
@ -453,36 +454,36 @@ func (q *qemuArchBase) appendBlockDevice(devices []govmmQemu.Device, drive confi
return devices return devices
} }
func (q *qemuArchBase) appendVhostUserDevice(devices []govmmQemu.Device, attr config.VhostUserDeviceAttrs) []govmmQemu.Device { func (q *qemuArchBase) appendVhostUserDevice(devices []govmmQemu.Device, vhostUserDevice api.VhostUserDevice) []govmmQemu.Device {
qemuVhostUserDevice := govmmQemu.VhostUserDevice{} qemuVhostUserDevice := govmmQemu.VhostUserDevice{}
// TODO: find a way to remove dependency of drivers package // TODO: find a way to remove dependency of drivers package
switch attr.Type { switch vhostUserDevice := vhostUserDevice.(type) {
case config.VhostUserNet: case *drivers.VhostUserNetDevice:
qemuVhostUserDevice.TypeDevID = utils.MakeNameID("net", attr.ID, maxDevIDSize) qemuVhostUserDevice.TypeDevID = utils.MakeNameID("net", vhostUserDevice.ID, maxDevIDSize)
qemuVhostUserDevice.Address = attr.MacAddress qemuVhostUserDevice.Address = vhostUserDevice.MacAddress
case config.VhostUserSCSI: case *drivers.VhostUserSCSIDevice:
qemuVhostUserDevice.TypeDevID = utils.MakeNameID("scsi", attr.ID, maxDevIDSize) qemuVhostUserDevice.TypeDevID = utils.MakeNameID("scsi", vhostUserDevice.ID, maxDevIDSize)
case config.VhostUserBlk: case *drivers.VhostUserBlkDevice:
} }
qemuVhostUserDevice.VhostUserType = govmmQemu.VhostUserDeviceType(attr.Type) qemuVhostUserDevice.VhostUserType = govmmQemu.VhostUserDeviceType(vhostUserDevice.Type())
qemuVhostUserDevice.SocketPath = attr.SocketPath qemuVhostUserDevice.SocketPath = vhostUserDevice.Attrs().SocketPath
qemuVhostUserDevice.CharDevID = utils.MakeNameID("char", attr.ID, maxDevIDSize) qemuVhostUserDevice.CharDevID = utils.MakeNameID("char", vhostUserDevice.Attrs().ID, maxDevIDSize)
devices = append(devices, qemuVhostUserDevice) devices = append(devices, qemuVhostUserDevice)
return devices return devices
} }
func (q *qemuArchBase) appendVFIODevice(devices []govmmQemu.Device, vfioDev config.VFIODev) []govmmQemu.Device { func (q *qemuArchBase) appendVFIODevice(devices []govmmQemu.Device, vfioDevice drivers.VFIODevice) []govmmQemu.Device {
if vfioDev.BDF == "" { if vfioDevice.BDF == "" {
return devices return devices
} }
devices = append(devices, devices = append(devices,
govmmQemu.VFIODevice{ govmmQemu.VFIODevice{
BDF: vfioDev.BDF, BDF: vfioDevice.BDF,
}, },
) )

View File

@ -15,6 +15,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/kata-containers/runtime/virtcontainers/device/config" "github.com/kata-containers/runtime/virtcontainers/device/config"
"github.com/kata-containers/runtime/virtcontainers/device/drivers"
) )
const ( const (
@ -205,12 +206,12 @@ func testQemuArchBaseAppend(t *testing.T, structure interface{}, expected []govm
devices = qemuArchBase.append9PVolume(devices, s) devices = qemuArchBase.append9PVolume(devices, s)
case Socket: case Socket:
devices = qemuArchBase.appendSocket(devices, s) devices = qemuArchBase.appendSocket(devices, s)
case config.BlockDrive: case drivers.Drive:
devices = qemuArchBase.appendBlockDevice(devices, s) devices = qemuArchBase.appendBlockDevice(devices, s)
case config.VFIODev: case drivers.VFIODevice:
devices = qemuArchBase.appendVFIODevice(devices, s) devices = qemuArchBase.appendVFIODevice(devices, s)
case config.VhostUserDeviceAttrs: case drivers.VhostUserNetDevice:
devices = qemuArchBase.appendVhostUserDevice(devices, s) devices = qemuArchBase.appendVhostUserDevice(devices, &s)
} }
assert.Equal(devices, expected) assert.Equal(devices, expected)
@ -363,7 +364,7 @@ func TestQemuArchBaseAppendBlockDevice(t *testing.T) {
}, },
} }
drive := config.BlockDrive{ drive := drivers.Drive{
File: file, File: file,
Format: format, Format: format,
ID: id, ID: id,
@ -387,8 +388,7 @@ func TestQemuArchBaseAppendVhostUserDevice(t *testing.T) {
}, },
} }
vhostUserDevice := config.VhostUserDeviceAttrs{ vhostUserDevice := drivers.VhostUserNetDevice{
Type: config.VhostUserNet,
MacAddress: macAddress, MacAddress: macAddress,
} }
vhostUserDevice.ID = id vhostUserDevice.ID = id
@ -406,7 +406,7 @@ func TestQemuArchBaseAppendVFIODevice(t *testing.T) {
}, },
} }
vfDevice := config.VFIODev{ vfDevice := drivers.VFIODevice{
BDF: bdf, BDF: bdf,
} }

View File

@ -10,7 +10,7 @@ import (
"os" "os"
govmmQemu "github.com/intel/govmm/qemu" govmmQemu "github.com/intel/govmm/qemu"
deviceConfig "github.com/kata-containers/runtime/virtcontainers/device/config" "github.com/kata-containers/runtime/virtcontainers/device/drivers"
"github.com/kata-containers/runtime/virtcontainers/utils" "github.com/kata-containers/runtime/virtcontainers/utils"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@ -134,7 +134,7 @@ func (q *qemuPPC64le) appendImage(devices []govmmQemu.Device, path string) ([]go
id := utils.MakeNameID("image", hex.EncodeToString(randBytes), maxDevIDSize) id := utils.MakeNameID("image", hex.EncodeToString(randBytes), maxDevIDSize)
drive := deviceConfig.BlockDrive{ drive := drivers.Drive{
File: path, File: path,
Format: "raw", Format: "raw",
ID: id, ID: id,

View File

@ -713,12 +713,6 @@ func createSandbox(sandboxConfig SandboxConfig, factory Factory) (*Sandbox, erro
s.networkNS = networkNS s.networkNS = networkNS
} }
devices, err := s.storage.fetchSandboxDevices(s.id)
if err != nil {
s.Logger().WithError(err).WithField("sandboxid", s.id).Warning("fetch sandbox device failed")
}
s.devManager = deviceManager.NewDeviceManager(sandboxConfig.HypervisorConfig.BlockDeviceDriver, devices)
// We first try to fetch the sandbox state from storage. // We first try to fetch the sandbox state from storage.
// If it exists, this means this is a re-creation, i.e. // If it exists, this means this is a re-creation, i.e.
// we don't need to talk to the guest's agent, but only // we don't need to talk to the guest's agent, but only
@ -764,6 +758,7 @@ func newSandbox(sandboxConfig SandboxConfig, factory Factory) (*Sandbox, error)
storage: &filesystem{}, storage: &filesystem{},
network: network, network: network,
config: &sandboxConfig, config: &sandboxConfig,
devManager: deviceManager.NewDeviceManager(sandboxConfig.HypervisorConfig.BlockDeviceDriver),
volumes: sandboxConfig.Volumes, volumes: sandboxConfig.Volumes,
containers: map[string]*Container{}, containers: map[string]*Container{},
runPath: filepath.Join(runStoragePath, sandboxConfig.ID), runPath: filepath.Join(runStoragePath, sandboxConfig.ID),
@ -813,10 +808,6 @@ func newSandbox(sandboxConfig SandboxConfig, factory Factory) (*Sandbox, error)
return s, nil return s, nil
} }
func (s *Sandbox) storeSandboxDevices() error {
return s.storage.storeSandboxDevices(s.id, s.devManager.GetAllDevices())
}
// storeSandbox stores a sandbox config. // storeSandbox stores a sandbox config.
func (s *Sandbox) storeSandbox() error { func (s *Sandbox) storeSandbox() error {
err := s.storage.storeSandboxResource(s.id, configFileType, *(s.config)) err := s.storage.storeSandboxResource(s.id, configFileType, *(s.config))
@ -1455,24 +1446,12 @@ func togglePauseSandbox(sandboxID string, pause bool) (*Sandbox, error) {
func (s *Sandbox) HotplugAddDevice(device api.Device, devType config.DeviceType) error { func (s *Sandbox) HotplugAddDevice(device api.Device, devType config.DeviceType) error {
switch devType { switch devType {
case config.DeviceVFIO: case config.DeviceVFIO:
vfioDevices, ok := device.GetDeviceInfo().([]*config.VFIODev) vfioDevice, ok := device.(*drivers.VFIODevice)
if !ok { if !ok {
return fmt.Errorf("device type mismatch, expect device type to be %s", devType) return fmt.Errorf("device type mismatch, expect device type to be %s", devType)
} }
_, err := s.hypervisor.hotplugAddDevice(*vfioDevice, vfioDev)
// adding a group of VFIO devices
for _, dev := range vfioDevices {
if _, err := s.hypervisor.hotplugAddDevice(dev, vfioDev); err != nil {
s.Logger().
WithFields(logrus.Fields{
"sandboxid": s.id,
"vfio device ID": dev.ID,
"vfio device BDF": dev.BDF,
}).WithError(err).Error("failed to hotplug VFIO device")
return err return err
}
}
return nil
case config.DeviceBlock: case config.DeviceBlock:
blockDevice, ok := device.(*drivers.BlockDevice) blockDevice, ok := device.(*drivers.BlockDevice)
if !ok { if !ok {
@ -1492,30 +1471,18 @@ func (s *Sandbox) HotplugAddDevice(device api.Device, devType config.DeviceType)
func (s *Sandbox) HotplugRemoveDevice(device api.Device, devType config.DeviceType) error { func (s *Sandbox) HotplugRemoveDevice(device api.Device, devType config.DeviceType) error {
switch devType { switch devType {
case config.DeviceVFIO: case config.DeviceVFIO:
vfioDevices, ok := device.GetDeviceInfo().([]*config.VFIODev) vfioDevice, ok := device.(*drivers.VFIODevice)
if !ok { if !ok {
return fmt.Errorf("device type mismatch, expect device type to be %s", devType) return fmt.Errorf("device type mismatch, expect device type to be %s", devType)
} }
_, err := s.hypervisor.hotplugRemoveDevice(*vfioDevice, vfioDev)
// remove a group of VFIO devices
for _, dev := range vfioDevices {
if _, err := s.hypervisor.hotplugRemoveDevice(dev, vfioDev); err != nil {
s.Logger().WithError(err).
WithFields(logrus.Fields{
"sandboxid": s.id,
"vfio device ID": dev.ID,
"vfio device BDF": dev.BDF,
}).Error("failed to hot unplug VFIO device")
return err return err
}
}
return nil
case config.DeviceBlock: case config.DeviceBlock:
blockDrive, ok := device.GetDeviceInfo().(*config.BlockDrive) blockDevice, ok := device.(*drivers.BlockDevice)
if !ok { if !ok {
return fmt.Errorf("device type mismatch, expect device type to be %s", devType) return fmt.Errorf("device type mismatch, expect device type to be %s", devType)
} }
_, err := s.hypervisor.hotplugRemoveDevice(blockDrive, blockDev) _, err := s.hypervisor.hotplugRemoveDevice(blockDevice.BlockDrive, blockDev)
return err return err
case config.DeviceGeneric: case config.DeviceGeneric:
// TODO: what? // TODO: what?
@ -1536,13 +1503,12 @@ func (s *Sandbox) DecrementSandboxBlockIndex() error {
return s.decrementSandboxBlockIndex() return s.decrementSandboxBlockIndex()
} }
// AppendDevice can only handle vhost user device currently, it adds a // AddVhostUserDevice adds a vhost user device to sandbox
// vhost user device to sandbox
// Sandbox implement DeviceReceiver interface from device/api/interface.go // Sandbox implement DeviceReceiver interface from device/api/interface.go
func (s *Sandbox) AppendDevice(device api.Device) error { func (s *Sandbox) AddVhostUserDevice(devInfo api.VhostUserDevice, devType config.DeviceType) error {
switch device.DeviceType() { switch devType {
case config.VhostUserSCSI, config.VhostUserNet, config.VhostUserBlk: case config.VhostUserSCSI, config.VhostUserNet, config.VhostUserBlk:
return s.hypervisor.addDevice(device.GetDeviceInfo().(*config.VhostUserDeviceAttrs), vhostuserDev) return s.hypervisor.addDevice(devInfo, vhostuserDev)
} }
return fmt.Errorf("unsupported device type") return fmt.Errorf("unsupported device type")
} }

View File

@ -18,6 +18,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/kata-containers/runtime/virtcontainers/device/api"
"github.com/kata-containers/runtime/virtcontainers/device/config" "github.com/kata-containers/runtime/virtcontainers/device/config"
"github.com/kata-containers/runtime/virtcontainers/device/drivers" "github.com/kata-containers/runtime/virtcontainers/device/drivers"
"github.com/kata-containers/runtime/virtcontainers/device/manager" "github.com/kata-containers/runtime/virtcontainers/device/manager"
@ -1152,23 +1153,18 @@ func TestSandboxAttachDevicesVFIO(t *testing.T) {
config.SysIOMMUPath = savedIOMMUPath config.SysIOMMUPath = savedIOMMUPath
}() }()
dm := manager.NewDeviceManager(manager.VirtioSCSI, nil)
path := filepath.Join(vfioPath, testFDIOGroup) path := filepath.Join(vfioPath, testFDIOGroup)
deviceInfo := config.DeviceInfo{ deviceInfo := config.DeviceInfo{
HostPath: path, HostPath: path,
ContainerPath: path, ContainerPath: path,
DevType: "c", DevType: "c",
} }
dev, err := dm.NewDevice(deviceInfo) vfioDevice := drivers.NewVFIODevice(deviceInfo)
assert.Nil(t, err, "deviceManager.NewDevice return error: %v", err)
c := &Container{ c := &Container{
id: "100", id: "100",
devices: []ContainerDevice{ devices: []api.Device{
{ vfioDevice,
ID: dev.DeviceID(),
ContainerPath: path,
},
}, },
} }
@ -1176,19 +1172,12 @@ func TestSandboxAttachDevicesVFIO(t *testing.T) {
containers[c.id] = c containers[c.id] = c
sandbox := Sandbox{ sandbox := Sandbox{
id: "100",
containers: containers, containers: containers,
storage: &filesystem{},
hypervisor: &mockHypervisor{}, hypervisor: &mockHypervisor{},
devManager: dm,
} }
containers[c.id].sandbox = &sandbox containers[c.id].sandbox = &sandbox
err = sandbox.storage.createAllResources(&sandbox)
assert.Nil(t, err, "Error while create all resources for sandbox")
err = sandbox.storeSandboxDevices()
assert.Nil(t, err, "Error while store sandbox devices %s", err)
err = containers[c.id].attachDevices() err = containers[c.id].attachDevices()
assert.Nil(t, err, "Error while attaching devices %s", err) assert.Nil(t, err, "Error while attaching devices %s", err)
@ -1595,9 +1584,10 @@ func TestAttachBlockDevice(t *testing.T) {
DevType: "b", DevType: "b",
} }
dm := manager.NewDeviceManager(VirtioBlock, nil) dm := manager.NewDeviceManager(VirtioBlock)
device, err := dm.NewDevice(deviceInfo) devices, err := dm.NewDevices([]config.DeviceInfo{deviceInfo})
assert.Nil(t, err) assert.Nil(t, err)
device := devices[0]
_, ok := device.(*drivers.BlockDevice) _, ok := device.(*drivers.BlockDevice)
assert.True(t, ok) assert.True(t, ok)