Skip to content

Commit

Permalink
devices: add interface "sandbox.AddDevice"
Browse files Browse the repository at this point in the history
Fixes kata-containers#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 <[email protected]>
  • Loading branch information
WeiZhang555 committed Aug 15, 2018
1 parent dd2acd2 commit 6e6be98
Show file tree
Hide file tree
Showing 11 changed files with 182 additions and 6 deletions.
22 changes: 22 additions & 0 deletions virtcontainers/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"syscall"

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"
"github.com/sirupsen/logrus"
)
Expand Down Expand Up @@ -760,3 +761,24 @@ func PauseContainer(sandboxID, containerID string) error {
func ResumeContainer(sandboxID, containerID string) error {
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)
}
19 changes: 14 additions & 5 deletions virtcontainers/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -1133,13 +1133,22 @@ func (c *Container) attachDevices() error {

func (c *Container) detachDevices() error {
for _, dev := range c.devices {
if err := c.sandbox.devManager.DetachDevice(dev.ID, c.sandbox); err != nil {
if err == manager.ErrDeviceNotAttached {
// skip if device isn't attached
continue
}
err := c.sandbox.devManager.DetachDevice(dev.ID, c.sandbox)
if err != nil && err != manager.ErrDeviceNotAttached {
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 {
Expand Down
1 change: 1 addition & 0 deletions virtcontainers/device/api/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ type Device interface {
// device management object.
type DeviceManager interface {
NewDevice(config.DeviceInfo) (Device, error)
RemoveDevice(string) error
AttachDevice(string, DeviceReceiver) error
DetachDevice(string, DeviceReceiver) error
IsDeviceAttached(string) bool
Expand Down
13 changes: 12 additions & 1 deletion virtcontainers/device/manager/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
dm.Lock()
defer dm.Unlock()
Expand All @@ -104,6 +104,17 @@ func (dm *deviceManager) NewDevice(devInfo config.DeviceInfo) (api.Device, error
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) {
for i := 0; i < 5; i++ {
// generate an random ID
Expand Down
7 changes: 7 additions & 0 deletions virtcontainers/implementation.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ package virtcontainers
import (
"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"
"github.com/sirupsen/logrus"
)
Expand Down Expand Up @@ -141,3 +143,8 @@ func (impl *VCImpl) PauseContainer(sandboxID, containerID string) error {
func (impl *VCImpl) ResumeContainer(sandboxID, containerID string) error {
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)
}
6 changes: 6 additions & 0 deletions virtcontainers/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"io"
"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"
"github.com/sirupsen/logrus"
)
Expand Down Expand Up @@ -41,6 +43,8 @@ type VC interface {
UpdateContainer(sandboxID, containerID string, resources specs.LinuxResources) error
PauseContainer(sandboxID, containerID string) error
ResumeContainer(sandboxID, containerID string) error

AddDevice(sandboxID string, info config.DeviceInfo) (api.Device, error)
}

// VCSandbox is the Sandbox interface
Expand Down Expand Up @@ -70,6 +74,8 @@ type VCSandbox interface {
SignalProcess(containerID, processID string, signal syscall.Signal, all bool) error
WinsizeProcess(containerID, processID string, height, width uint32) error
IOStream(containerID, processID string) (io.WriteCloser, io.Reader, io.Reader, error)

AddDevice(info config.DeviceInfo) (api.Device, error)
}

// VCContainer is the Container interface
Expand Down
11 changes: 11 additions & 0 deletions virtcontainers/pkg/vcmock/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import (
"syscall"

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"
"github.com/sirupsen/logrus"
)
Expand Down Expand Up @@ -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)
}

// 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)
}
7 changes: 7 additions & 0 deletions virtcontainers/pkg/vcmock/sandbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"syscall"

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"
)

Expand Down Expand Up @@ -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) {
return nil, nil, nil, nil
}

// AddDevice adds a device to sandbox
func (s *Sandbox) AddDevice(info config.DeviceInfo) (api.Device, error) {
return nil, nil
}
4 changes: 4 additions & 0 deletions virtcontainers/pkg/vcmock/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"syscall"

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"
"github.com/sirupsen/logrus"
)
Expand Down Expand Up @@ -61,4 +63,6 @@ type VCMock struct {
UpdateContainerFunc func(sandboxID, containerID string, resources specs.LinuxResources) error
PauseContainerFunc func(sandboxID, containerID string) error
ResumeContainerFunc func(sandboxID, containerID string) error

AddDeviceFunc func(sandboxID string, info config.DeviceInfo) (api.Device, error)
}
22 changes: 22 additions & 0 deletions virtcontainers/sandbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -1546,3 +1546,25 @@ func (s *Sandbox) AppendDevice(device api.Device) error {
}
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
}
76 changes: 76 additions & 0 deletions virtcontainers/sandbox_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1629,3 +1629,79 @@ func TestAttachBlockDevice(t *testing.T) {
err = device.Detach(sandbox)
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")
}

0 comments on commit 6e6be98

Please sign in to comment.