mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-07-05 11:36:56 +00:00
devices: add interface "sandbox.AddDevice"
Fixes #50 . Add new interface sandbox.AddDevice, then for Frakti use case, a device can be attached to sandbox before container is created. Signed-off-by: Wei Zhang <zhangwei555@huawei.com>
This commit is contained in:
parent
dd2acd26eb
commit
6e6be98b15
@ -11,6 +11,7 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
deviceApi "github.com/kata-containers/runtime/virtcontainers/device/api"
|
deviceApi "github.com/kata-containers/runtime/virtcontainers/device/api"
|
||||||
|
deviceConfig "github.com/kata-containers/runtime/virtcontainers/device/config"
|
||||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
@ -760,3 +761,24 @@ func PauseContainer(sandboxID, containerID string) error {
|
|||||||
func ResumeContainer(sandboxID, containerID string) error {
|
func ResumeContainer(sandboxID, containerID string) error {
|
||||||
return togglePauseContainer(sandboxID, containerID, false)
|
return togglePauseContainer(sandboxID, containerID, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddDevice will add a device to sandbox
|
||||||
|
func AddDevice(sandboxID string, info deviceConfig.DeviceInfo) (deviceApi.Device, error) {
|
||||||
|
if sandboxID == "" {
|
||||||
|
return nil, errNeedSandboxID
|
||||||
|
}
|
||||||
|
|
||||||
|
lockFile, err := rwLockSandbox(sandboxID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer unlockSandbox(lockFile)
|
||||||
|
|
||||||
|
s, err := fetchSandbox(sandboxID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer s.releaseStatelessSandbox()
|
||||||
|
|
||||||
|
return s.AddDevice(info)
|
||||||
|
}
|
||||||
|
@ -1133,13 +1133,22 @@ func (c *Container) attachDevices() error {
|
|||||||
|
|
||||||
func (c *Container) detachDevices() error {
|
func (c *Container) detachDevices() error {
|
||||||
for _, dev := range c.devices {
|
for _, dev := range c.devices {
|
||||||
if err := c.sandbox.devManager.DetachDevice(dev.ID, c.sandbox); err != nil {
|
err := c.sandbox.devManager.DetachDevice(dev.ID, c.sandbox)
|
||||||
if err == manager.ErrDeviceNotAttached {
|
if err != nil && err != manager.ErrDeviceNotAttached {
|
||||||
// skip if device isn't attached
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err = c.sandbox.devManager.RemoveDevice(dev.ID); err != nil {
|
||||||
|
c.Logger().WithFields(logrus.Fields{
|
||||||
|
"container": c.id,
|
||||||
|
"device-id": dev.ID,
|
||||||
|
}).WithError(err).Error("remove device failed")
|
||||||
|
|
||||||
|
// ignore the device not exist error
|
||||||
|
if err != manager.ErrDeviceNotExist {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.sandbox.storeSandboxDevices(); err != nil {
|
if err := c.sandbox.storeSandboxDevices(); err != nil {
|
||||||
|
@ -62,6 +62,7 @@ type Device interface {
|
|||||||
// device management object.
|
// device management object.
|
||||||
type DeviceManager interface {
|
type DeviceManager interface {
|
||||||
NewDevice(config.DeviceInfo) (Device, error)
|
NewDevice(config.DeviceInfo) (Device, error)
|
||||||
|
RemoveDevice(string) error
|
||||||
AttachDevice(string, DeviceReceiver) error
|
AttachDevice(string, DeviceReceiver) error
|
||||||
DetachDevice(string, DeviceReceiver) error
|
DetachDevice(string, DeviceReceiver) error
|
||||||
IsDeviceAttached(string) bool
|
IsDeviceAttached(string) bool
|
||||||
|
@ -93,7 +93,7 @@ func (dm *deviceManager) createDevice(devInfo config.DeviceInfo) (api.Device, er
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDevice creates bundles of devices based on array of DeviceInfo
|
// NewDevice creates a device based on specified DeviceInfo
|
||||||
func (dm *deviceManager) NewDevice(devInfo config.DeviceInfo) (api.Device, error) {
|
func (dm *deviceManager) NewDevice(devInfo config.DeviceInfo) (api.Device, error) {
|
||||||
dm.Lock()
|
dm.Lock()
|
||||||
defer dm.Unlock()
|
defer dm.Unlock()
|
||||||
@ -104,6 +104,17 @@ func (dm *deviceManager) NewDevice(devInfo config.DeviceInfo) (api.Device, error
|
|||||||
return dev, err
|
return dev, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RemoveDevice deletes the device from list based on specified device id
|
||||||
|
func (dm *deviceManager) RemoveDevice(id string) error {
|
||||||
|
dm.Lock()
|
||||||
|
defer dm.Unlock()
|
||||||
|
if _, ok := dm.devices[id]; !ok {
|
||||||
|
return ErrDeviceNotExist
|
||||||
|
}
|
||||||
|
delete(dm.devices, id)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (dm *deviceManager) newDeviceID() (string, error) {
|
func (dm *deviceManager) newDeviceID() (string, error) {
|
||||||
for i := 0; i < 5; i++ {
|
for i := 0; i < 5; i++ {
|
||||||
// generate an random ID
|
// generate an random ID
|
||||||
|
@ -12,6 +12,8 @@ package virtcontainers
|
|||||||
import (
|
import (
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/kata-containers/runtime/virtcontainers/device/api"
|
||||||
|
"github.com/kata-containers/runtime/virtcontainers/device/config"
|
||||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
@ -141,3 +143,8 @@ func (impl *VCImpl) PauseContainer(sandboxID, containerID string) error {
|
|||||||
func (impl *VCImpl) ResumeContainer(sandboxID, containerID string) error {
|
func (impl *VCImpl) ResumeContainer(sandboxID, containerID string) error {
|
||||||
return ResumeContainer(sandboxID, containerID)
|
return ResumeContainer(sandboxID, containerID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddDevice will add a device to sandbox
|
||||||
|
func (impl *VCImpl) AddDevice(sandboxID string, info config.DeviceInfo) (api.Device, error) {
|
||||||
|
return AddDevice(sandboxID, info)
|
||||||
|
}
|
||||||
|
@ -9,6 +9,8 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/kata-containers/runtime/virtcontainers/device/api"
|
||||||
|
"github.com/kata-containers/runtime/virtcontainers/device/config"
|
||||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
@ -41,6 +43,8 @@ type VC interface {
|
|||||||
UpdateContainer(sandboxID, containerID string, resources specs.LinuxResources) error
|
UpdateContainer(sandboxID, containerID string, resources specs.LinuxResources) error
|
||||||
PauseContainer(sandboxID, containerID string) error
|
PauseContainer(sandboxID, containerID string) error
|
||||||
ResumeContainer(sandboxID, containerID string) error
|
ResumeContainer(sandboxID, containerID string) error
|
||||||
|
|
||||||
|
AddDevice(sandboxID string, info config.DeviceInfo) (api.Device, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// VCSandbox is the Sandbox interface
|
// VCSandbox is the Sandbox interface
|
||||||
@ -70,6 +74,8 @@ type VCSandbox interface {
|
|||||||
SignalProcess(containerID, processID string, signal syscall.Signal, all bool) error
|
SignalProcess(containerID, processID string, signal syscall.Signal, all bool) error
|
||||||
WinsizeProcess(containerID, processID string, height, width uint32) error
|
WinsizeProcess(containerID, processID string, height, width uint32) error
|
||||||
IOStream(containerID, processID string) (io.WriteCloser, io.Reader, io.Reader, error)
|
IOStream(containerID, processID string) (io.WriteCloser, io.Reader, io.Reader, error)
|
||||||
|
|
||||||
|
AddDevice(info config.DeviceInfo) (api.Device, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// VCContainer is the Container interface
|
// VCContainer is the Container interface
|
||||||
|
@ -20,6 +20,8 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
vc "github.com/kata-containers/runtime/virtcontainers"
|
vc "github.com/kata-containers/runtime/virtcontainers"
|
||||||
|
"github.com/kata-containers/runtime/virtcontainers/device/api"
|
||||||
|
"github.com/kata-containers/runtime/virtcontainers/device/config"
|
||||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
@ -239,3 +241,12 @@ func (m *VCMock) ResumeContainer(sandboxID, containerID string) error {
|
|||||||
|
|
||||||
return fmt.Errorf("%s: %s (%+v): sandboxID: %v, containerID: %v", mockErrorPrefix, getSelf(), m, sandboxID, containerID)
|
return fmt.Errorf("%s: %s (%+v): sandboxID: %v, containerID: %v", mockErrorPrefix, getSelf(), m, sandboxID, containerID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddDevice implements the VC function of the same name.
|
||||||
|
func (m *VCMock) AddDevice(sandboxID string, info config.DeviceInfo) (api.Device, error) {
|
||||||
|
if m.AddDeviceFunc != nil {
|
||||||
|
return m.AddDeviceFunc(sandboxID, info)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("%s: %s (%+v): sandboxID: %v", mockErrorPrefix, getSelf(), m, sandboxID)
|
||||||
|
}
|
||||||
|
@ -10,6 +10,8 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
vc "github.com/kata-containers/runtime/virtcontainers"
|
vc "github.com/kata-containers/runtime/virtcontainers"
|
||||||
|
"github.com/kata-containers/runtime/virtcontainers/device/api"
|
||||||
|
"github.com/kata-containers/runtime/virtcontainers/device/config"
|
||||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -138,3 +140,8 @@ func (s *Sandbox) WinsizeProcess(containerID, processID string, height, width ui
|
|||||||
func (s *Sandbox) IOStream(containerID, processID string) (io.WriteCloser, io.Reader, io.Reader, error) {
|
func (s *Sandbox) IOStream(containerID, processID string) (io.WriteCloser, io.Reader, io.Reader, error) {
|
||||||
return nil, nil, nil, nil
|
return nil, nil, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddDevice adds a device to sandbox
|
||||||
|
func (s *Sandbox) AddDevice(info config.DeviceInfo) (api.Device, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
@ -9,6 +9,8 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
vc "github.com/kata-containers/runtime/virtcontainers"
|
vc "github.com/kata-containers/runtime/virtcontainers"
|
||||||
|
"github.com/kata-containers/runtime/virtcontainers/device/api"
|
||||||
|
"github.com/kata-containers/runtime/virtcontainers/device/config"
|
||||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
@ -61,4 +63,6 @@ type VCMock struct {
|
|||||||
UpdateContainerFunc func(sandboxID, containerID string, resources specs.LinuxResources) error
|
UpdateContainerFunc func(sandboxID, containerID string, resources specs.LinuxResources) error
|
||||||
PauseContainerFunc func(sandboxID, containerID string) error
|
PauseContainerFunc func(sandboxID, containerID string) error
|
||||||
ResumeContainerFunc func(sandboxID, containerID string) error
|
ResumeContainerFunc func(sandboxID, containerID string) error
|
||||||
|
|
||||||
|
AddDeviceFunc func(sandboxID string, info config.DeviceInfo) (api.Device, error)
|
||||||
}
|
}
|
||||||
|
@ -1546,3 +1546,25 @@ func (s *Sandbox) AppendDevice(device api.Device) error {
|
|||||||
}
|
}
|
||||||
return fmt.Errorf("unsupported device type")
|
return fmt.Errorf("unsupported device type")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddDevice will add a device to sandbox
|
||||||
|
func (s *Sandbox) AddDevice(info config.DeviceInfo) (api.Device, error) {
|
||||||
|
if s.devManager == nil {
|
||||||
|
return nil, fmt.Errorf("device manager isn't initialized")
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := s.devManager.NewDevice(info)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.devManager.AttachDevice(b.DeviceID(), s); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.storeSandboxDevices(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
@ -1629,3 +1629,79 @@ func TestAttachBlockDevice(t *testing.T) {
|
|||||||
err = device.Detach(sandbox)
|
err = device.Detach(sandbox)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPreAddDevice(t *testing.T) {
|
||||||
|
fs := &filesystem{}
|
||||||
|
hypervisor := &mockHypervisor{}
|
||||||
|
|
||||||
|
hConfig := HypervisorConfig{
|
||||||
|
BlockDeviceDriver: VirtioBlock,
|
||||||
|
}
|
||||||
|
|
||||||
|
sconfig := &SandboxConfig{
|
||||||
|
HypervisorConfig: hConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
dm := manager.NewDeviceManager(VirtioBlock, nil)
|
||||||
|
// create a sandbox first
|
||||||
|
sandbox := &Sandbox{
|
||||||
|
id: testSandboxID,
|
||||||
|
storage: fs,
|
||||||
|
hypervisor: hypervisor,
|
||||||
|
config: sconfig,
|
||||||
|
devManager: dm,
|
||||||
|
}
|
||||||
|
|
||||||
|
contID := "100"
|
||||||
|
container := Container{
|
||||||
|
sandbox: sandbox,
|
||||||
|
id: contID,
|
||||||
|
sandboxID: testSandboxID,
|
||||||
|
}
|
||||||
|
container.state.State = StateReady
|
||||||
|
|
||||||
|
// create state file
|
||||||
|
path := filepath.Join(runStoragePath, testSandboxID, container.ID())
|
||||||
|
err := os.MkdirAll(path, dirMode)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer os.RemoveAll(path)
|
||||||
|
|
||||||
|
stateFilePath := filepath.Join(path, stateFile)
|
||||||
|
os.Remove(stateFilePath)
|
||||||
|
|
||||||
|
_, err = os.Create(stateFilePath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.Remove(stateFilePath)
|
||||||
|
|
||||||
|
path = "/dev/hda"
|
||||||
|
deviceInfo := config.DeviceInfo{
|
||||||
|
HostPath: path,
|
||||||
|
ContainerPath: path,
|
||||||
|
DevType: "b",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a mount device for a mountpoint before container's creation
|
||||||
|
dev, err := sandbox.AddDevice(deviceInfo)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
// in Frakti use case, here we will create and start the container
|
||||||
|
// which will attach same device twice
|
||||||
|
container.mounts = []Mount{
|
||||||
|
{
|
||||||
|
Destination: path,
|
||||||
|
Source: path,
|
||||||
|
Type: "bind",
|
||||||
|
BlockDeviceID: dev.DeviceID(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
mounts, err := container.mountSharedDirMounts("", "")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, len(mounts), 0,
|
||||||
|
"mounts should contain nothing because it only contains a block device")
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user