mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-06-30 01:02:33 +00:00
vc: change container rootfs to be a mount
We can use the same data structure to describe both of them. So that we can handle them similarly. Fixes: #1566 Signed-off-by: Peng Tao <bergwolf@hyper.sh>
This commit is contained in:
parent
b218229589
commit
196661bc0d
@ -128,7 +128,7 @@ func create(ctx context.Context, containerID, bundlePath, console, pidFilePath s
|
|||||||
disableOutput := noNeedForOutput(detach, ociSpec.Process.Terminal)
|
disableOutput := noNeedForOutput(detach, ociSpec.Process.Terminal)
|
||||||
|
|
||||||
//rootfs has been mounted by containerd shim
|
//rootfs has been mounted by containerd shim
|
||||||
rootFs := vc.RootFs{Mounted: true}
|
rootFs := vc.Mount{Mounted: true}
|
||||||
|
|
||||||
var process vc.Process
|
var process vc.Process
|
||||||
switch containerType {
|
switch containerType {
|
||||||
|
@ -10,12 +10,13 @@ package containerdshim
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/containerd/typeurl"
|
"github.com/containerd/typeurl"
|
||||||
vc "github.com/kata-containers/runtime/virtcontainers"
|
vc "github.com/kata-containers/runtime/virtcontainers"
|
||||||
"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
|
"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
taskAPI "github.com/containerd/containerd/runtime/v2/task"
|
taskAPI "github.com/containerd/containerd/runtime/v2/task"
|
||||||
|
|
||||||
@ -31,7 +32,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func create(ctx context.Context, s *service, r *taskAPI.CreateTaskRequest, netns string) (*container, error) {
|
func create(ctx context.Context, s *service, r *taskAPI.CreateTaskRequest, netns string) (*container, error) {
|
||||||
rootFs := vc.RootFs{Mounted: s.mount}
|
rootFs := vc.Mount{Mounted: s.mount}
|
||||||
if len(r.Rootfs) == 1 {
|
if len(r.Rootfs) == 1 {
|
||||||
m := r.Rootfs[0]
|
m := r.Rootfs[0]
|
||||||
rootFs.Source = m.Source
|
rootFs.Source = m.Source
|
||||||
|
@ -172,7 +172,7 @@ func SetEphemeralStorageType(ociSpec oci.CompatOCISpec) oci.CompatOCISpec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateSandbox create a sandbox container
|
// CreateSandbox create a sandbox container
|
||||||
func CreateSandbox(ctx context.Context, vci vc.VC, ociSpec oci.CompatOCISpec, runtimeConfig oci.RuntimeConfig, rootFs vc.RootFs,
|
func CreateSandbox(ctx context.Context, vci vc.VC, ociSpec oci.CompatOCISpec, runtimeConfig oci.RuntimeConfig, rootFs vc.Mount,
|
||||||
containerID, bundlePath, console string, disableOutput, systemdCgroup, builtIn bool) (vc.VCSandbox, vc.Process, error) {
|
containerID, bundlePath, console string, disableOutput, systemdCgroup, builtIn bool) (vc.VCSandbox, vc.Process, error) {
|
||||||
span, ctx := Trace(ctx, "createSandbox")
|
span, ctx := Trace(ctx, "createSandbox")
|
||||||
defer span.Finish()
|
defer span.Finish()
|
||||||
@ -237,7 +237,7 @@ func CreateSandbox(ctx context.Context, vci vc.VC, ociSpec oci.CompatOCISpec, ru
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateContainer create a container
|
// CreateContainer create a container
|
||||||
func CreateContainer(ctx context.Context, vci vc.VC, sandbox vc.VCSandbox, ociSpec oci.CompatOCISpec, rootFs vc.RootFs, containerID, bundlePath, console string, disableOutput, builtIn bool) (vc.Process, error) {
|
func CreateContainer(ctx context.Context, vci vc.VC, sandbox vc.VCSandbox, ociSpec oci.CompatOCISpec, rootFs vc.Mount, containerID, bundlePath, console string, disableOutput, builtIn bool) (vc.Process, error) {
|
||||||
var c vc.VCContainer
|
var c vc.VCContainer
|
||||||
|
|
||||||
span, ctx := Trace(ctx, "createContainer")
|
span, ctx := Trace(ctx, "createContainer")
|
||||||
|
@ -306,7 +306,7 @@ func TestCreateSandboxConfigFail(t *testing.T) {
|
|||||||
Quota: "a,
|
Quota: "a,
|
||||||
}
|
}
|
||||||
|
|
||||||
rootFs := vc.RootFs{Mounted: true}
|
rootFs := vc.Mount{Mounted: true}
|
||||||
|
|
||||||
_, _, err = CreateSandbox(context.Background(), testingImpl, spec, runtimeConfig, rootFs, testContainerID, bundlePath, testConsole, true, true, false)
|
_, _, err = CreateSandbox(context.Background(), testingImpl, spec, runtimeConfig, rootFs, testContainerID, bundlePath, testConsole, true, true, false)
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
@ -342,7 +342,7 @@ func TestCreateSandboxFail(t *testing.T) {
|
|||||||
spec, err := readOCIConfigFile(ociConfigFile)
|
spec, err := readOCIConfigFile(ociConfigFile)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
|
|
||||||
rootFs := vc.RootFs{Mounted: true}
|
rootFs := vc.Mount{Mounted: true}
|
||||||
|
|
||||||
_, _, err = CreateSandbox(context.Background(), testingImpl, spec, runtimeConfig, rootFs, testContainerID, bundlePath, testConsole, true, true, false)
|
_, _, err = CreateSandbox(context.Background(), testingImpl, spec, runtimeConfig, rootFs, testContainerID, bundlePath, testConsole, true, true, false)
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
@ -381,7 +381,7 @@ func TestCreateContainerContainerConfigFail(t *testing.T) {
|
|||||||
err = writeOCIConfigFile(spec, ociConfigFile)
|
err = writeOCIConfigFile(spec, ociConfigFile)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
|
|
||||||
rootFs := vc.RootFs{Mounted: true}
|
rootFs := vc.Mount{Mounted: true}
|
||||||
|
|
||||||
for _, disableOutput := range []bool{true, false} {
|
for _, disableOutput := range []bool{true, false} {
|
||||||
_, err = CreateContainer(context.Background(), testingImpl, nil, spec, rootFs, testContainerID, bundlePath, testConsole, disableOutput, false)
|
_, err = CreateContainer(context.Background(), testingImpl, nil, spec, rootFs, testContainerID, bundlePath, testConsole, disableOutput, false)
|
||||||
@ -424,7 +424,7 @@ func TestCreateContainerFail(t *testing.T) {
|
|||||||
err = writeOCIConfigFile(spec, ociConfigFile)
|
err = writeOCIConfigFile(spec, ociConfigFile)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
|
|
||||||
rootFs := vc.RootFs{Mounted: true}
|
rootFs := vc.Mount{Mounted: true}
|
||||||
|
|
||||||
for _, disableOutput := range []bool{true, false} {
|
for _, disableOutput := range []bool{true, false} {
|
||||||
_, err = CreateContainer(context.Background(), testingImpl, nil, spec, rootFs, testContainerID, bundlePath, testConsole, disableOutput, false)
|
_, err = CreateContainer(context.Background(), testingImpl, nil, spec, rootFs, testContainerID, bundlePath, testConsole, disableOutput, false)
|
||||||
@ -474,7 +474,7 @@ func TestCreateContainer(t *testing.T) {
|
|||||||
err = writeOCIConfigFile(spec, ociConfigFile)
|
err = writeOCIConfigFile(spec, ociConfigFile)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
|
|
||||||
rootFs := vc.RootFs{Mounted: true}
|
rootFs := vc.Mount{Mounted: true}
|
||||||
|
|
||||||
for _, disableOutput := range []bool{true, false} {
|
for _, disableOutput := range []bool{true, false} {
|
||||||
_, err = CreateContainer(context.Background(), testingImpl, nil, spec, rootFs, testContainerID, bundlePath, testConsole, disableOutput, false)
|
_, err = CreateContainer(context.Background(), testingImpl, nil, spec, rootFs, testContainerID, bundlePath, testConsole, disableOutput, false)
|
||||||
|
@ -601,7 +601,7 @@ func statusContainer(sandbox *Sandbox, containerID string) (ContainerStatus, err
|
|||||||
State: container.state,
|
State: container.state,
|
||||||
PID: container.process.Pid,
|
PID: container.process.Pid,
|
||||||
StartTime: container.process.StartTime,
|
StartTime: container.process.StartTime,
|
||||||
RootFs: container.config.RootFs.Target,
|
RootFs: container.config.RootFs.Destination,
|
||||||
Annotations: container.config.Annotations,
|
Annotations: container.config.Annotations,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ func newTestSandboxConfigNoop() SandboxConfig {
|
|||||||
// Define the container command and bundle.
|
// Define the container command and bundle.
|
||||||
container := ContainerConfig{
|
container := ContainerConfig{
|
||||||
ID: containerID,
|
ID: containerID,
|
||||||
RootFs: RootFs{Target: filepath.Join(testDir, testBundle), Mounted: true},
|
RootFs: Mount{Destination: filepath.Join(testDir, testBundle), Mounted: true},
|
||||||
Cmd: newBasicTestCmd(),
|
Cmd: newBasicTestCmd(),
|
||||||
Annotations: containerAnnotations,
|
Annotations: containerAnnotations,
|
||||||
}
|
}
|
||||||
@ -751,7 +751,7 @@ func newTestContainerConfigNoop(contID string) ContainerConfig {
|
|||||||
// Define the container command and bundle.
|
// Define the container command and bundle.
|
||||||
container := ContainerConfig{
|
container := ContainerConfig{
|
||||||
ID: contID,
|
ID: contID,
|
||||||
RootFs: RootFs{Target: filepath.Join(testDir, testBundle), Mounted: true},
|
RootFs: Mount{Destination: filepath.Join(testDir, testBundle), Mounted: true},
|
||||||
Cmd: newBasicTestCmd(),
|
Cmd: newBasicTestCmd(),
|
||||||
Annotations: containerAnnotations,
|
Annotations: containerAnnotations,
|
||||||
}
|
}
|
||||||
|
@ -209,7 +209,7 @@ type ContainerConfig struct {
|
|||||||
ID string
|
ID string
|
||||||
|
|
||||||
// RootFs is the container workload image on the host.
|
// RootFs is the container workload image on the host.
|
||||||
RootFs RootFs
|
RootFs Mount
|
||||||
|
|
||||||
// ReadOnlyRootfs indicates if the rootfs should be mounted readonly
|
// ReadOnlyRootfs indicates if the rootfs should be mounted readonly
|
||||||
ReadonlyRootfs bool
|
ReadonlyRootfs bool
|
||||||
@ -272,27 +272,13 @@ type ContainerDevice struct {
|
|||||||
GID uint32
|
GID uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
// RootFs describes the container's rootfs.
|
|
||||||
type RootFs struct {
|
|
||||||
// Source specifies the BlockDevice path
|
|
||||||
Source string
|
|
||||||
// Target specify where the rootfs is mounted if it has been mounted
|
|
||||||
Target string
|
|
||||||
// Type specifies the type of filesystem to mount.
|
|
||||||
Type string
|
|
||||||
// Options specifies zero or more fstab style mount options.
|
|
||||||
Options []string
|
|
||||||
// Mounted specifies whether the rootfs has be mounted or not
|
|
||||||
Mounted bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 {
|
||||||
id string
|
id string
|
||||||
sandboxID string
|
sandboxID string
|
||||||
|
|
||||||
rootFs RootFs
|
rootFs Mount
|
||||||
|
|
||||||
config *ContainerConfig
|
config *ContainerConfig
|
||||||
|
|
||||||
@ -371,19 +357,6 @@ func (c *Container) SetPid(pid int) error {
|
|||||||
return c.storeProcess()
|
return c.storeProcess()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Container) setStateFstype(fstype string) error {
|
|
||||||
c.state.Fstype = fstype
|
|
||||||
|
|
||||||
if !c.sandbox.supportNewStore() {
|
|
||||||
// experimental runtime use "persist.json" which doesn't need "state.json" anymore
|
|
||||||
if err := c.storeState(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAnnotations returns container's annotations
|
// GetAnnotations returns container's annotations
|
||||||
func (c *Container) GetAnnotations() map[string]string {
|
func (c *Container) GetAnnotations() map[string]string {
|
||||||
return c.config.Annotations
|
return c.config.Annotations
|
||||||
@ -411,10 +384,6 @@ func (c *Container) storeDevices() error {
|
|||||||
return c.store.Store(store.DeviceIDs, c.devices)
|
return c.store.Store(store.DeviceIDs, c.devices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Container) storeState() error {
|
|
||||||
return c.store.Store(store.State, c.state)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Container) loadMounts() ([]Mount, error) {
|
func (c *Container) loadMounts() ([]Mount, error) {
|
||||||
var mounts []Mount
|
var mounts []Mount
|
||||||
if err := c.store.Load(store.Mounts, &mounts); err != nil {
|
if err := c.store.Load(store.Mounts, &mounts); err != nil {
|
||||||
@ -1183,6 +1152,14 @@ func (c *Container) resume() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Container) hotplugDrive() error {
|
func (c *Container) hotplugDrive() error {
|
||||||
|
if err := c.hotplugRootfsDrive(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Container) hotplugRootfsDrive() error {
|
||||||
var dev device
|
var dev device
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
@ -1192,7 +1169,7 @@ func (c *Container) hotplugDrive() error {
|
|||||||
// there is no "rootfs" dir on block device backed rootfs
|
// there is no "rootfs" dir on block device backed rootfs
|
||||||
c.rootfsSuffix = ""
|
c.rootfsSuffix = ""
|
||||||
} else {
|
} else {
|
||||||
dev, err = getDeviceForPath(c.rootFs.Target)
|
dev, err = getDeviceForPath(c.rootFs.Destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == errMountPointNotFound {
|
if err == errMountPointNotFound {
|
||||||
@ -1221,7 +1198,7 @@ func (c *Container) hotplugDrive() error {
|
|||||||
devicePath := c.rootFs.Source
|
devicePath := c.rootFs.Source
|
||||||
fsType := c.rootFs.Type
|
fsType := c.rootFs.Type
|
||||||
if c.rootFs.Mounted {
|
if c.rootFs.Mounted {
|
||||||
if dev.mountPoint == c.rootFs.Target {
|
if dev.mountPoint == c.rootFs.Destination {
|
||||||
c.rootfsSuffix = ""
|
c.rootfsSuffix = ""
|
||||||
}
|
}
|
||||||
// If device mapper device, then fetch the full path of the device
|
// If device mapper device, then fetch the full path of the device
|
||||||
@ -1229,6 +1206,7 @@ func (c *Container) hotplugDrive() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
c.rootFs.Type = fsType
|
||||||
}
|
}
|
||||||
|
|
||||||
devicePath, err = filepath.EvalSymlinks(devicePath)
|
devicePath, err = filepath.EvalSymlinks(devicePath)
|
||||||
@ -1241,11 +1219,7 @@ func (c *Container) hotplugDrive() error {
|
|||||||
"fs-type": fsType,
|
"fs-type": fsType,
|
||||||
}).Info("Block device detected")
|
}).Info("Block device detected")
|
||||||
|
|
||||||
if err = c.plugDevice(devicePath); err != nil {
|
return c.plugDevice(devicePath)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.setStateFstype(fsType)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Container) plugDevice(devicePath string) error {
|
func (c *Container) plugDevice(devicePath string) error {
|
||||||
@ -1266,7 +1240,7 @@ func (c *Container) plugDevice(devicePath string) error {
|
|||||||
return fmt.Errorf("device manager failed to create rootfs device for %q: %v", devicePath, err)
|
return fmt.Errorf("device manager failed to create rootfs device for %q: %v", devicePath, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.state.BlockDeviceID = b.DeviceID()
|
c.rootFs.BlockDeviceID = b.DeviceID()
|
||||||
|
|
||||||
// attach rootfs device
|
// attach rootfs device
|
||||||
if err := c.sandbox.devManager.AttachDevice(b.DeviceID(), c.sandbox); err != nil {
|
if err := c.sandbox.devManager.AttachDevice(b.DeviceID(), c.sandbox); err != nil {
|
||||||
@ -1280,16 +1254,11 @@ func (c *Container) plugDevice(devicePath string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// isDriveUsed checks if a drive has been used for container rootfs
|
|
||||||
func (c *Container) isDriveUsed() bool {
|
|
||||||
return !(c.state.Fstype == "")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Container) removeDrive() (err error) {
|
func (c *Container) removeDrive() (err error) {
|
||||||
if c.isDriveUsed() {
|
if c.rootFs.BlockDeviceID != "" {
|
||||||
c.Logger().Info("unplugging block device")
|
c.Logger().Info("unplugging block device")
|
||||||
|
|
||||||
devID := c.state.BlockDeviceID
|
devID := c.rootFs.BlockDeviceID
|
||||||
err := c.sandbox.devManager.DetachDevice(devID, c.sandbox)
|
err := c.sandbox.devManager.DetachDevice(devID, c.sandbox)
|
||||||
if err != nil && err != manager.ErrDeviceNotAttached {
|
if err != nil && err != manager.ErrDeviceNotAttached {
|
||||||
return err
|
return err
|
||||||
|
@ -106,7 +106,7 @@ func TestContainerRemoveDrive(t *testing.T) {
|
|||||||
id: "testContainer",
|
id: "testContainer",
|
||||||
}
|
}
|
||||||
|
|
||||||
container.state.Fstype = ""
|
container.rootFs.Type = ""
|
||||||
err = container.removeDrive()
|
err = container.removeDrive()
|
||||||
|
|
||||||
// hotplugRemoveDevice for hypervisor should not be called.
|
// hotplugRemoveDevice for hypervisor should not be called.
|
||||||
@ -131,8 +131,8 @@ func TestContainerRemoveDrive(t *testing.T) {
|
|||||||
err = sandbox.storeSandboxDevices()
|
err = sandbox.storeSandboxDevices()
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
container.state.Fstype = "xfs"
|
container.rootFs.Type = "xfs"
|
||||||
container.state.BlockDeviceID = device.DeviceID()
|
container.rootFs.BlockDeviceID = device.DeviceID()
|
||||||
err = container.removeDrive()
|
err = container.removeDrive()
|
||||||
assert.Nil(t, err, "remove drive should succeed")
|
assert.Nil(t, err, "remove drive should succeed")
|
||||||
}
|
}
|
||||||
@ -245,7 +245,7 @@ func TestContainerAddDriveDir(t *testing.T) {
|
|||||||
container := Container{
|
container := Container{
|
||||||
sandbox: sandbox,
|
sandbox: sandbox,
|
||||||
id: contID,
|
id: contID,
|
||||||
rootFs: RootFs{Target: fakeRootfs, Mounted: true},
|
rootFs: Mount{Destination: fakeRootfs, Mounted: true},
|
||||||
}
|
}
|
||||||
|
|
||||||
containerStore, err := store.NewVCContainerStore(sandbox.ctx, sandbox.id, container.id)
|
containerStore, err := store.NewVCContainerStore(sandbox.ctx, sandbox.id, container.id)
|
||||||
@ -272,14 +272,14 @@ func TestContainerAddDriveDir(t *testing.T) {
|
|||||||
checkStorageDriver = savedFunc
|
checkStorageDriver = savedFunc
|
||||||
}()
|
}()
|
||||||
|
|
||||||
container.state.Fstype = ""
|
container.rootFs.Type = "xfs"
|
||||||
|
|
||||||
err = container.hotplugDrive()
|
err = container.hotplugDrive()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error with hotplugDrive :%v", err)
|
t.Fatalf("Error with hotplugDrive :%v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if container.state.Fstype == "" {
|
if container.rootFs.Type == "" {
|
||||||
t.Fatal()
|
t.Fatal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -315,7 +315,7 @@ func TestContainerRootfsPath(t *testing.T) {
|
|||||||
container := Container{
|
container := Container{
|
||||||
id: "rootfstestcontainerid",
|
id: "rootfstestcontainerid",
|
||||||
sandbox: sandbox,
|
sandbox: sandbox,
|
||||||
rootFs: RootFs{Target: fakeRootfs, Mounted: true},
|
rootFs: Mount{Destination: fakeRootfs, Mounted: true},
|
||||||
rootfsSuffix: "rootfs",
|
rootfsSuffix: "rootfs",
|
||||||
}
|
}
|
||||||
cvcstore, err := store.NewVCContainerStore(context.Background(),
|
cvcstore, err := store.NewVCContainerStore(context.Background(),
|
||||||
@ -328,7 +328,7 @@ func TestContainerRootfsPath(t *testing.T) {
|
|||||||
assert.Empty(t, container.rootfsSuffix)
|
assert.Empty(t, container.rootfsSuffix)
|
||||||
|
|
||||||
// Reset the value to test the other case
|
// Reset the value to test the other case
|
||||||
container.rootFs = RootFs{Target: fakeRootfs + "/rootfs", Mounted: true}
|
container.rootFs = Mount{Destination: fakeRootfs + "/rootfs", Mounted: true}
|
||||||
container.rootfsSuffix = "rootfs"
|
container.rootfsSuffix = "rootfs"
|
||||||
|
|
||||||
container.hotplugDrive()
|
container.hotplugDrive()
|
||||||
|
@ -14,7 +14,7 @@ import (
|
|||||||
"github.com/kata-containers/runtime/virtcontainers/types"
|
"github.com/kata-containers/runtime/virtcontainers/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
var containerRootfs = vc.RootFs{Target: "/var/lib/container/bundle/", Mounted: true}
|
var containerRootfs = vc.Mount{Destination: "/var/lib/container/bundle/", Mounted: true}
|
||||||
|
|
||||||
// This example creates and starts a single container sandbox,
|
// This example creates and starts a single container sandbox,
|
||||||
// using qemu as the hypervisor and kata as the VM agent.
|
// using qemu as the hypervisor and kata as the VM agent.
|
||||||
|
@ -944,7 +944,7 @@ func (k *kataAgent) rollbackFailingContainerCreation(c *Container) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (k *kataAgent) buildContainerRootfs(sandbox *Sandbox, c *Container, rootPathParent string) (*grpc.Storage, error) {
|
func (k *kataAgent) buildContainerRootfs(sandbox *Sandbox, c *Container, rootPathParent string) (*grpc.Storage, error) {
|
||||||
if c.state.Fstype != "" && c.state.BlockDeviceID != "" {
|
if c.rootFs.BlockDeviceID != "" {
|
||||||
// The rootfs storage volume represents the container rootfs
|
// The rootfs storage volume represents the container rootfs
|
||||||
// mount point inside the guest.
|
// mount point inside the guest.
|
||||||
// It can be a block based device (when using block based container
|
// It can be a block based device (when using block based container
|
||||||
@ -953,10 +953,10 @@ func (k *kataAgent) buildContainerRootfs(sandbox *Sandbox, c *Container, rootPat
|
|||||||
rootfs := &grpc.Storage{}
|
rootfs := &grpc.Storage{}
|
||||||
|
|
||||||
// This is a block based device rootfs.
|
// This is a block based device rootfs.
|
||||||
device := sandbox.devManager.GetDeviceByID(c.state.BlockDeviceID)
|
device := sandbox.devManager.GetDeviceByID(c.rootFs.BlockDeviceID)
|
||||||
if device == nil {
|
if device == nil {
|
||||||
k.Logger().WithField("device", c.state.BlockDeviceID).Error("failed to find device by id")
|
k.Logger().WithField("device", c.rootFs.BlockDeviceID).Error("failed to find device by id")
|
||||||
return nil, fmt.Errorf("failed to find device by id %q", c.state.BlockDeviceID)
|
return nil, fmt.Errorf("failed to find device by id %q", c.rootFs.BlockDeviceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
blockDrive, ok := device.GetDeviceInfo().(*config.BlockDrive)
|
blockDrive, ok := device.GetDeviceInfo().(*config.BlockDrive)
|
||||||
@ -976,10 +976,11 @@ func (k *kataAgent) buildContainerRootfs(sandbox *Sandbox, c *Container, rootPat
|
|||||||
rootfs.Source = blockDrive.SCSIAddr
|
rootfs.Source = blockDrive.SCSIAddr
|
||||||
}
|
}
|
||||||
rootfs.MountPoint = rootPathParent
|
rootfs.MountPoint = rootPathParent
|
||||||
rootfs.Fstype = c.state.Fstype
|
rootfs.Fstype = c.rootFs.Type
|
||||||
|
rootfs.Options = c.rootFs.Options
|
||||||
|
|
||||||
if c.state.Fstype == "xfs" {
|
if rootfs.Fstype == "xfs" {
|
||||||
rootfs.Options = []string{"nouuid"}
|
rootfs.Options = append(rootfs.Options, "nouuid")
|
||||||
}
|
}
|
||||||
|
|
||||||
return rootfs, nil
|
return rootfs, nil
|
||||||
@ -993,7 +994,7 @@ func (k *kataAgent) buildContainerRootfs(sandbox *Sandbox, c *Container, rootPat
|
|||||||
// (kataGuestSharedDir) is already mounted in the
|
// (kataGuestSharedDir) is already mounted in the
|
||||||
// guest. We only need to mount the rootfs from
|
// guest. We only need to mount the rootfs from
|
||||||
// the host and it will show up in the guest.
|
// the host and it will show up in the guest.
|
||||||
if err := bindMountContainerRootfs(k.ctx, kataHostSharedDir, sandbox.id, c.id, c.rootFs.Target, false); err != nil {
|
if err := bindMountContainerRootfs(k.ctx, kataHostSharedDir, sandbox.id, c.id, c.rootFs.Destination, false); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -735,9 +735,7 @@ func TestAgentCreateContainer(t *testing.T) {
|
|||||||
id: "barfoo",
|
id: "barfoo",
|
||||||
sandboxID: "foobar",
|
sandboxID: "foobar",
|
||||||
sandbox: sandbox,
|
sandbox: sandbox,
|
||||||
state: types.ContainerState{
|
state: types.ContainerState{},
|
||||||
Fstype: "xfs",
|
|
||||||
},
|
|
||||||
config: &ContainerConfig{
|
config: &ContainerConfig{
|
||||||
Annotations: map[string]string{},
|
Annotations: map[string]string{},
|
||||||
},
|
},
|
||||||
|
@ -304,7 +304,10 @@ func bindMountContainerRootfs(ctx context.Context, sharedDir, sandboxID, cID, cR
|
|||||||
|
|
||||||
// Mount describes a container mount.
|
// Mount describes a container mount.
|
||||||
type Mount struct {
|
type Mount struct {
|
||||||
Source string
|
// Mount source
|
||||||
|
Source string
|
||||||
|
|
||||||
|
// Mount destination in the guest
|
||||||
Destination string
|
Destination string
|
||||||
|
|
||||||
// Type specifies the type of filesystem to mount.
|
// Type specifies the type of filesystem to mount.
|
||||||
@ -316,13 +319,16 @@ type Mount struct {
|
|||||||
// HostPath used to store host side bind mount path
|
// HostPath used to store host side bind mount path
|
||||||
HostPath string
|
HostPath string
|
||||||
|
|
||||||
// ReadOnly specifies if the mount should be read only or not
|
|
||||||
ReadOnly bool
|
|
||||||
|
|
||||||
// BlockDeviceID represents block device that is attached to the
|
// BlockDeviceID 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
|
BlockDeviceID string
|
||||||
|
|
||||||
|
// ReadOnly specifies if the mount should be read only or not
|
||||||
|
ReadOnly bool
|
||||||
|
|
||||||
|
// Mounted specifies if the target has been mounted on the host
|
||||||
|
Mounted bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func bindUnmountContainerRootfs(ctx context.Context, sharedDir, sandboxID, cID string) error {
|
func bindUnmountContainerRootfs(ctx context.Context, sharedDir, sandboxID, cID string) error {
|
||||||
@ -341,7 +347,7 @@ func bindUnmountAllRootfs(ctx context.Context, sharedDir string, sandbox *Sandbo
|
|||||||
|
|
||||||
for _, c := range sandbox.containers {
|
for _, c := range sandbox.containers {
|
||||||
c.unmountHostMounts()
|
c.unmountHostMounts()
|
||||||
if c.state.Fstype == "" {
|
if c.rootFs.Type == "" {
|
||||||
// Need to check for error returned by this call.
|
// Need to check for error returned by this call.
|
||||||
// See: https://github.com/containers/virtcontainers/issues/295
|
// See: https://github.com/containers/virtcontainers/issues/295
|
||||||
bindUnmountContainerRootfs(c.ctx, sharedDir, sandbox.id, c.id)
|
bindUnmountContainerRootfs(c.ctx, sharedDir, sandbox.id, c.id)
|
||||||
|
@ -31,9 +31,9 @@ func (s *Sandbox) dumpState(ss *persistapi.SandboxState, cs map[string]persistap
|
|||||||
state = v
|
state = v
|
||||||
}
|
}
|
||||||
state.State = string(cont.state.State)
|
state.State = string(cont.state.State)
|
||||||
state.Rootfs = persistapi.RootfsState{
|
state.Rootfs = persistapi.Mount{
|
||||||
BlockDeviceID: cont.state.BlockDeviceID,
|
BlockDeviceID: cont.rootFs.BlockDeviceID,
|
||||||
FsType: cont.state.Fstype,
|
Type: cont.rootFs.Type,
|
||||||
}
|
}
|
||||||
state.CgroupPath = cont.state.CgroupPath
|
state.CgroupPath = cont.state.CgroupPath
|
||||||
cs[id] = state
|
cs[id] = state
|
||||||
@ -152,10 +152,8 @@ func (c *Container) Restore() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.state = types.ContainerState{
|
c.state = types.ContainerState{
|
||||||
State: types.StateString(cs[c.id].State),
|
State: types.StateString(cs[c.id].State),
|
||||||
BlockDeviceID: cs[c.id].Rootfs.BlockDeviceID,
|
CgroupPath: cs[c.id].CgroupPath,
|
||||||
Fstype: cs[c.id].Rootfs.FsType,
|
|
||||||
CgroupPath: cs[c.id].CgroupPath,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -47,23 +47,16 @@ type Mount struct {
|
|||||||
// HostPath used to store host side bind mount path
|
// HostPath used to store host side bind mount path
|
||||||
HostPath string
|
HostPath string
|
||||||
|
|
||||||
// ReadOnly specifies if the mount should be read only or not
|
|
||||||
ReadOnly bool
|
|
||||||
|
|
||||||
// BlockDeviceID represents block device that is attached to the
|
// BlockDeviceID 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
|
BlockDeviceID string
|
||||||
}
|
|
||||||
|
|
||||||
// RootfsState saves state of container rootfs
|
// ReadOnly specifies if the mount should be read only or not
|
||||||
type RootfsState struct {
|
ReadOnly bool
|
||||||
// BlockDeviceID represents container rootfs block device ID
|
|
||||||
// when backed by devicemapper
|
|
||||||
BlockDeviceID string
|
|
||||||
|
|
||||||
// RootFStype is file system of the rootfs incase it is block device
|
// Mounted specifies if the target has been mounted on the host
|
||||||
FsType string
|
Mounted bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process gathers data related to a container process.
|
// Process gathers data related to a container process.
|
||||||
@ -90,7 +83,7 @@ type ContainerState struct {
|
|||||||
State string
|
State string
|
||||||
|
|
||||||
// Rootfs contains information of container rootfs
|
// Rootfs contains information of container rootfs
|
||||||
Rootfs RootfsState
|
Rootfs Mount
|
||||||
|
|
||||||
// CgroupPath is the cgroup hierarchy where sandbox's processes
|
// CgroupPath is the cgroup hierarchy where sandbox's processes
|
||||||
// including the hypervisor are placed.
|
// including the hypervisor are placed.
|
||||||
|
@ -183,6 +183,7 @@ func newMount(m spec.Mount) vc.Mount {
|
|||||||
Destination: m.Destination,
|
Destination: m.Destination,
|
||||||
Type: m.Type,
|
Type: m.Type,
|
||||||
Options: m.Options,
|
Options: m.Options,
|
||||||
|
Mounted: true, // All OCI volumes are mounted on the host ATM.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -524,12 +525,12 @@ func ContainerConfig(ocispec CompatOCISpec, bundlePath, cid, console string, det
|
|||||||
return vc.ContainerConfig{}, err
|
return vc.ContainerConfig{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
rootfs := vc.RootFs{Target: ocispec.Root.Path, Mounted: true}
|
rootfs := vc.Mount{Destination: ocispec.Root.Path, Mounted: true}
|
||||||
if !filepath.IsAbs(rootfs.Target) {
|
if !filepath.IsAbs(rootfs.Destination) {
|
||||||
rootfs.Target = filepath.Join(bundlePath, ocispec.Root.Path)
|
rootfs.Destination = filepath.Join(bundlePath, ocispec.Root.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
ociLog.Debugf("container rootfs: %s", rootfs.Target)
|
ociLog.Debugf("container rootfs: %s", rootfs.Destination)
|
||||||
|
|
||||||
cmd := types.Cmd{
|
cmd := types.Cmd{
|
||||||
Args: ocispec.Process.Args,
|
Args: ocispec.Process.Args,
|
||||||
|
@ -150,6 +150,7 @@ func TestMinimalSandboxConfig(t *testing.T) {
|
|||||||
Type: "proc",
|
Type: "proc",
|
||||||
Options: nil,
|
Options: nil,
|
||||||
HostPath: "",
|
HostPath: "",
|
||||||
|
Mounted: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Source: "tmpfs",
|
Source: "tmpfs",
|
||||||
@ -157,6 +158,7 @@ func TestMinimalSandboxConfig(t *testing.T) {
|
|||||||
Type: "tmpfs",
|
Type: "tmpfs",
|
||||||
Options: []string{"nosuid", "strictatime", "mode=755", "size=65536k"},
|
Options: []string{"nosuid", "strictatime", "mode=755", "size=65536k"},
|
||||||
HostPath: "",
|
HostPath: "",
|
||||||
|
Mounted: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Source: "devpts",
|
Source: "devpts",
|
||||||
@ -164,6 +166,7 @@ func TestMinimalSandboxConfig(t *testing.T) {
|
|||||||
Type: "devpts",
|
Type: "devpts",
|
||||||
Options: []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"},
|
Options: []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"},
|
||||||
HostPath: "",
|
HostPath: "",
|
||||||
|
Mounted: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,7 +203,7 @@ func TestMinimalSandboxConfig(t *testing.T) {
|
|||||||
|
|
||||||
expectedContainerConfig := vc.ContainerConfig{
|
expectedContainerConfig := vc.ContainerConfig{
|
||||||
ID: containerID,
|
ID: containerID,
|
||||||
RootFs: vc.RootFs{Target: path.Join(tempBundlePath, "rootfs"), Mounted: true},
|
RootFs: vc.Mount{Destination: path.Join(tempBundlePath, "rootfs"), Mounted: true},
|
||||||
ReadonlyRootfs: true,
|
ReadonlyRootfs: true,
|
||||||
Cmd: expectedCmd,
|
Cmd: expectedCmd,
|
||||||
Annotations: map[string]string{
|
Annotations: map[string]string{
|
||||||
|
@ -291,7 +291,7 @@ func (s *Sandbox) Status() SandboxStatus {
|
|||||||
for _, c := range s.containers {
|
for _, c := range s.containers {
|
||||||
rootfs := c.config.RootFs.Source
|
rootfs := c.config.RootFs.Source
|
||||||
if c.config.RootFs.Mounted {
|
if c.config.RootFs.Mounted {
|
||||||
rootfs = c.config.RootFs.Target
|
rootfs = c.config.RootFs.Destination
|
||||||
}
|
}
|
||||||
|
|
||||||
contStatusList = append(contStatusList, ContainerStatus{
|
contStatusList = append(contStatusList, ContainerStatus{
|
||||||
@ -1241,7 +1241,7 @@ func (s *Sandbox) StatusContainer(containerID string) (ContainerStatus, error) {
|
|||||||
for id, c := range s.containers {
|
for id, c := range s.containers {
|
||||||
rootfs := c.config.RootFs.Source
|
rootfs := c.config.RootFs.Source
|
||||||
if c.config.RootFs.Mounted {
|
if c.config.RootFs.Mounted {
|
||||||
rootfs = c.config.RootFs.Target
|
rootfs = c.config.RootFs.Destination
|
||||||
}
|
}
|
||||||
if id == containerID {
|
if id == containerID {
|
||||||
return ContainerStatus{
|
return ContainerStatus{
|
||||||
|
@ -7,7 +7,6 @@ package virtcontainers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
@ -750,99 +749,6 @@ func TestSandboxGetContainer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContainerStateSetFstype(t *testing.T) {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
containers := []ContainerConfig{
|
|
||||||
{
|
|
||||||
ID: "100",
|
|
||||||
Annotations: containerAnnotations,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
hConfig := newHypervisorConfig(nil, nil)
|
|
||||||
sandbox, err := testCreateSandbox(t, testSandboxID, MockHypervisor, hConfig, NoopAgentType, NetworkConfig{}, containers, nil)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
defer cleanUp()
|
|
||||||
|
|
||||||
vcStore, err := store.NewVCSandboxStore(sandbox.ctx, sandbox.id)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
sandbox.store = vcStore
|
|
||||||
|
|
||||||
c := sandbox.GetContainer("100")
|
|
||||||
if c == nil {
|
|
||||||
t.Fatal()
|
|
||||||
}
|
|
||||||
cImpl, ok := c.(*Container)
|
|
||||||
assert.True(t, ok)
|
|
||||||
|
|
||||||
containerStore, err := store.NewVCContainerStore(sandbox.ctx, sandbox.id, c.ID())
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
cImpl.store = containerStore
|
|
||||||
|
|
||||||
path := store.ContainerRuntimeRootPath(testSandboxID, c.ID())
|
|
||||||
stateFilePath := filepath.Join(path, store.StateFile)
|
|
||||||
|
|
||||||
f, err := os.Create(stateFilePath)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
state := types.ContainerState{
|
|
||||||
State: "ready",
|
|
||||||
Fstype: "vfs",
|
|
||||||
}
|
|
||||||
|
|
||||||
cImpl.state = state
|
|
||||||
|
|
||||||
stateData := `{
|
|
||||||
"state":"ready",
|
|
||||||
"fstype":"vfs",
|
|
||||||
}`
|
|
||||||
|
|
||||||
n, err := f.WriteString(stateData)
|
|
||||||
if err != nil || n != len(stateData) {
|
|
||||||
f.Close()
|
|
||||||
t.Fatal()
|
|
||||||
}
|
|
||||||
f.Close()
|
|
||||||
|
|
||||||
newFstype := "ext4"
|
|
||||||
if err := cImpl.setStateFstype(newFstype); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if cImpl.state.Fstype != newFstype {
|
|
||||||
t.Fatal()
|
|
||||||
}
|
|
||||||
|
|
||||||
fileData, err := ioutil.ReadFile(stateFilePath)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal()
|
|
||||||
}
|
|
||||||
|
|
||||||
// experimental features doesn't write state.json
|
|
||||||
if sandbox.supportNewStore() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var res types.ContainerState
|
|
||||||
err = json.Unmarshal([]byte(string(fileData)), &res)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if res.Fstype != newFstype {
|
|
||||||
t.Fatal()
|
|
||||||
}
|
|
||||||
|
|
||||||
if res.State != state.State {
|
|
||||||
t.Fatal()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const vfioPath = "/dev/vfio/"
|
const vfioPath = "/dev/vfio/"
|
||||||
|
|
||||||
func TestSandboxAttachDevicesVFIO(t *testing.T) {
|
func TestSandboxAttachDevicesVFIO(t *testing.T) {
|
||||||
|
@ -9,11 +9,6 @@ package types
|
|||||||
type ContainerState struct {
|
type ContainerState struct {
|
||||||
State StateString `json:"state"`
|
State StateString `json:"state"`
|
||||||
|
|
||||||
BlockDeviceID string
|
|
||||||
|
|
||||||
// File system of the rootfs incase it is block device
|
|
||||||
Fstype string `json:"fstype"`
|
|
||||||
|
|
||||||
// CgroupPath is the cgroup hierarchy where sandbox's processes
|
// CgroupPath is the cgroup hierarchy where sandbox's processes
|
||||||
// including the hypervisor are placed.
|
// including the hypervisor are placed.
|
||||||
CgroupPath string `json:"cgroupPath,omitempty"`
|
CgroupPath string `json:"cgroupPath,omitempty"`
|
||||||
|
Loading…
Reference in New Issue
Block a user