diff --git a/cli/create.go b/cli/create.go index bf0116d16e..77d356a106 100644 --- a/cli/create.go +++ b/cli/create.go @@ -128,7 +128,7 @@ func create(ctx context.Context, containerID, bundlePath, console, pidFilePath s disableOutput := noNeedForOutput(detach, ociSpec.Process.Terminal) //rootfs has been mounted by containerd shim - rootFs := vc.Mount{Mounted: true} + rootFs := vc.RootFs{Mounted: true} var process vc.Process switch containerType { diff --git a/containerd-shim-v2/create.go b/containerd-shim-v2/create.go index d7ca971a34..b5fe278b42 100644 --- a/containerd-shim-v2/create.go +++ b/containerd-shim-v2/create.go @@ -10,13 +10,12 @@ package containerdshim import ( "context" "fmt" - "os" - "path/filepath" - "github.com/containerd/typeurl" vc "github.com/kata-containers/runtime/virtcontainers" "github.com/kata-containers/runtime/virtcontainers/pkg/oci" "github.com/pkg/errors" + "os" + "path/filepath" taskAPI "github.com/containerd/containerd/runtime/v2/task" @@ -32,7 +31,7 @@ import ( ) func create(ctx context.Context, s *service, r *taskAPI.CreateTaskRequest, netns string) (*container, error) { - rootFs := vc.Mount{Mounted: s.mount} + rootFs := vc.RootFs{Mounted: s.mount} if len(r.Rootfs) == 1 { m := r.Rootfs[0] rootFs.Source = m.Source diff --git a/pkg/katautils/create.go b/pkg/katautils/create.go index ef685d5b7d..90eacf3c7f 100644 --- a/pkg/katautils/create.go +++ b/pkg/katautils/create.go @@ -172,7 +172,7 @@ func SetEphemeralStorageType(ociSpec oci.CompatOCISpec) oci.CompatOCISpec { } // CreateSandbox create a sandbox container -func CreateSandbox(ctx context.Context, vci vc.VC, ociSpec oci.CompatOCISpec, runtimeConfig oci.RuntimeConfig, rootFs vc.Mount, +func CreateSandbox(ctx context.Context, vci vc.VC, ociSpec oci.CompatOCISpec, runtimeConfig oci.RuntimeConfig, rootFs vc.RootFs, containerID, bundlePath, console string, disableOutput, systemdCgroup, builtIn bool) (vc.VCSandbox, vc.Process, error) { span, ctx := Trace(ctx, "createSandbox") defer span.Finish() @@ -237,7 +237,7 @@ func CreateSandbox(ctx context.Context, vci vc.VC, ociSpec oci.CompatOCISpec, ru } // CreateContainer create a container -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) { +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) { var c vc.VCContainer span, ctx := Trace(ctx, "createContainer") diff --git a/pkg/katautils/create_test.go b/pkg/katautils/create_test.go index ea861bd879..0acb8121ec 100644 --- a/pkg/katautils/create_test.go +++ b/pkg/katautils/create_test.go @@ -306,7 +306,7 @@ func TestCreateSandboxConfigFail(t *testing.T) { Quota: "a, } - rootFs := vc.Mount{Mounted: true} + rootFs := vc.RootFs{Mounted: true} _, _, err = CreateSandbox(context.Background(), testingImpl, spec, runtimeConfig, rootFs, testContainerID, bundlePath, testConsole, true, true, false) assert.Error(err) @@ -342,7 +342,7 @@ func TestCreateSandboxFail(t *testing.T) { spec, err := readOCIConfigFile(ociConfigFile) assert.NoError(err) - rootFs := vc.Mount{Mounted: true} + rootFs := vc.RootFs{Mounted: true} _, _, err = CreateSandbox(context.Background(), testingImpl, spec, runtimeConfig, rootFs, testContainerID, bundlePath, testConsole, true, true, false) assert.Error(err) @@ -381,7 +381,7 @@ func TestCreateContainerContainerConfigFail(t *testing.T) { err = writeOCIConfigFile(spec, ociConfigFile) assert.NoError(err) - rootFs := vc.Mount{Mounted: true} + rootFs := vc.RootFs{Mounted: true} for _, disableOutput := range []bool{true, 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) assert.NoError(err) - rootFs := vc.Mount{Mounted: true} + rootFs := vc.RootFs{Mounted: true} for _, disableOutput := range []bool{true, 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) assert.NoError(err) - rootFs := vc.Mount{Mounted: true} + rootFs := vc.RootFs{Mounted: true} for _, disableOutput := range []bool{true, false} { _, err = CreateContainer(context.Background(), testingImpl, nil, spec, rootFs, testContainerID, bundlePath, testConsole, disableOutput, false) diff --git a/virtcontainers/api.go b/virtcontainers/api.go index f8f7b43e84..c3197c1c50 100644 --- a/virtcontainers/api.go +++ b/virtcontainers/api.go @@ -601,7 +601,7 @@ func statusContainer(sandbox *Sandbox, containerID string) (ContainerStatus, err State: container.state, PID: container.process.Pid, StartTime: container.process.StartTime, - RootFs: container.config.RootFs.Destination, + RootFs: container.config.RootFs.Target, Annotations: container.config.Annotations, }, nil } diff --git a/virtcontainers/api_test.go b/virtcontainers/api_test.go index e386364dea..b8e3c35bfc 100644 --- a/virtcontainers/api_test.go +++ b/virtcontainers/api_test.go @@ -62,7 +62,7 @@ func newTestSandboxConfigNoop() SandboxConfig { // Define the container command and bundle. container := ContainerConfig{ ID: containerID, - RootFs: Mount{Destination: filepath.Join(testDir, testBundle), Mounted: true}, + RootFs: RootFs{Target: filepath.Join(testDir, testBundle), Mounted: true}, Cmd: newBasicTestCmd(), Annotations: containerAnnotations, } @@ -751,7 +751,7 @@ func newTestContainerConfigNoop(contID string) ContainerConfig { // Define the container command and bundle. container := ContainerConfig{ ID: contID, - RootFs: Mount{Destination: filepath.Join(testDir, testBundle), Mounted: true}, + RootFs: RootFs{Target: filepath.Join(testDir, testBundle), Mounted: true}, Cmd: newBasicTestCmd(), Annotations: containerAnnotations, } diff --git a/virtcontainers/container.go b/virtcontainers/container.go index 5c2b4aee2b..6030d73550 100644 --- a/virtcontainers/container.go +++ b/virtcontainers/container.go @@ -209,7 +209,7 @@ type ContainerConfig struct { ID string // RootFs is the container workload image on the host. - RootFs Mount + RootFs RootFs // ReadOnlyRootfs indicates if the rootfs should be mounted readonly ReadonlyRootfs bool @@ -272,13 +272,27 @@ type ContainerDevice struct { 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. // A Container can be created, deleted, started, stopped, listed, entered, paused and restored. type Container struct { id string sandboxID string - rootFs Mount + rootFs RootFs config *ContainerConfig @@ -357,6 +371,19 @@ func (c *Container) SetPid(pid int) error { 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 func (c *Container) GetAnnotations() map[string]string { return c.config.Annotations @@ -384,6 +411,10 @@ func (c *Container) storeDevices() error { 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) { var mounts []Mount if err := c.store.Load(store.Mounts, &mounts); err != nil { @@ -1152,14 +1183,6 @@ func (c *Container) resume() 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 err error @@ -1169,7 +1192,7 @@ func (c *Container) hotplugRootfsDrive() error { // there is no "rootfs" dir on block device backed rootfs c.rootfsSuffix = "" } else { - dev, err = getDeviceForPath(c.rootFs.Destination) + dev, err = getDeviceForPath(c.rootFs.Target) } if err == errMountPointNotFound { @@ -1198,7 +1221,7 @@ func (c *Container) hotplugRootfsDrive() error { devicePath := c.rootFs.Source fsType := c.rootFs.Type if c.rootFs.Mounted { - if dev.mountPoint == c.rootFs.Destination { + if dev.mountPoint == c.rootFs.Target { c.rootfsSuffix = "" } // If device mapper device, then fetch the full path of the device @@ -1206,7 +1229,6 @@ func (c *Container) hotplugRootfsDrive() error { if err != nil { return err } - c.rootFs.Type = fsType } devicePath, err = filepath.EvalSymlinks(devicePath) @@ -1219,7 +1241,11 @@ func (c *Container) hotplugRootfsDrive() error { "fs-type": fsType, }).Info("Block device detected") - return c.plugDevice(devicePath) + if err = c.plugDevice(devicePath); err != nil { + return err + } + + return c.setStateFstype(fsType) } func (c *Container) plugDevice(devicePath string) error { @@ -1240,7 +1266,7 @@ func (c *Container) plugDevice(devicePath string) error { return fmt.Errorf("device manager failed to create rootfs device for %q: %v", devicePath, err) } - c.rootFs.BlockDeviceID = b.DeviceID() + c.state.BlockDeviceID = b.DeviceID() // attach rootfs device if err := c.sandbox.devManager.AttachDevice(b.DeviceID(), c.sandbox); err != nil { @@ -1254,11 +1280,16 @@ func (c *Container) plugDevice(devicePath string) error { 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) { - if c.rootFs.BlockDeviceID != "" { + if c.isDriveUsed() { c.Logger().Info("unplugging block device") - devID := c.rootFs.BlockDeviceID + devID := c.state.BlockDeviceID err := c.sandbox.devManager.DetachDevice(devID, c.sandbox) if err != nil && err != manager.ErrDeviceNotAttached { return err diff --git a/virtcontainers/container_test.go b/virtcontainers/container_test.go index 09545b19d5..333d2e4889 100644 --- a/virtcontainers/container_test.go +++ b/virtcontainers/container_test.go @@ -106,7 +106,7 @@ func TestContainerRemoveDrive(t *testing.T) { id: "testContainer", } - container.rootFs.Type = "" + container.state.Fstype = "" err = container.removeDrive() // hotplugRemoveDevice for hypervisor should not be called. @@ -131,8 +131,8 @@ func TestContainerRemoveDrive(t *testing.T) { err = sandbox.storeSandboxDevices() assert.Nil(t, err) - container.rootFs.Type = "xfs" - container.rootFs.BlockDeviceID = device.DeviceID() + container.state.Fstype = "xfs" + container.state.BlockDeviceID = device.DeviceID() err = container.removeDrive() assert.Nil(t, err, "remove drive should succeed") } @@ -245,7 +245,7 @@ func TestContainerAddDriveDir(t *testing.T) { container := Container{ sandbox: sandbox, id: contID, - rootFs: Mount{Destination: fakeRootfs, Mounted: true}, + rootFs: RootFs{Target: fakeRootfs, Mounted: true}, } containerStore, err := store.NewVCContainerStore(sandbox.ctx, sandbox.id, container.id) @@ -272,14 +272,14 @@ func TestContainerAddDriveDir(t *testing.T) { checkStorageDriver = savedFunc }() - container.rootFs.Type = "xfs" + container.state.Fstype = "" err = container.hotplugDrive() if err != nil { t.Fatalf("Error with hotplugDrive :%v", err) } - if container.rootFs.Type == "" { + if container.state.Fstype == "" { t.Fatal() } } @@ -315,7 +315,7 @@ func TestContainerRootfsPath(t *testing.T) { container := Container{ id: "rootfstestcontainerid", sandbox: sandbox, - rootFs: Mount{Destination: fakeRootfs, Mounted: true}, + rootFs: RootFs{Target: fakeRootfs, Mounted: true}, rootfsSuffix: "rootfs", } cvcstore, err := store.NewVCContainerStore(context.Background(), @@ -328,7 +328,7 @@ func TestContainerRootfsPath(t *testing.T) { assert.Empty(t, container.rootfsSuffix) // Reset the value to test the other case - container.rootFs = Mount{Destination: fakeRootfs + "/rootfs", Mounted: true} + container.rootFs = RootFs{Target: fakeRootfs + "/rootfs", Mounted: true} container.rootfsSuffix = "rootfs" container.hotplugDrive() diff --git a/virtcontainers/example_pod_run_test.go b/virtcontainers/example_pod_run_test.go index 6c20706d4d..86a6a13f0f 100644 --- a/virtcontainers/example_pod_run_test.go +++ b/virtcontainers/example_pod_run_test.go @@ -14,7 +14,7 @@ import ( "github.com/kata-containers/runtime/virtcontainers/types" ) -var containerRootfs = vc.Mount{Destination: "/var/lib/container/bundle/", Mounted: true} +var containerRootfs = vc.RootFs{Target: "/var/lib/container/bundle/", Mounted: true} // This example creates and starts a single container sandbox, // using qemu as the hypervisor and kata as the VM agent. diff --git a/virtcontainers/kata_agent.go b/virtcontainers/kata_agent.go index 0eefca10b6..082207ed8c 100644 --- a/virtcontainers/kata_agent.go +++ b/virtcontainers/kata_agent.go @@ -944,7 +944,7 @@ func (k *kataAgent) rollbackFailingContainerCreation(c *Container) { } func (k *kataAgent) buildContainerRootfs(sandbox *Sandbox, c *Container, rootPathParent string) (*grpc.Storage, error) { - if c.rootFs.BlockDeviceID != "" { + if c.state.Fstype != "" && c.state.BlockDeviceID != "" { // The rootfs storage volume represents the container rootfs // mount point inside the guest. // 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{} // This is a block based device rootfs. - device := sandbox.devManager.GetDeviceByID(c.rootFs.BlockDeviceID) + device := sandbox.devManager.GetDeviceByID(c.state.BlockDeviceID) if device == nil { - 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.rootFs.BlockDeviceID) + k.Logger().WithField("device", c.state.BlockDeviceID).Error("failed to find device by id") + return nil, fmt.Errorf("failed to find device by id %q", c.state.BlockDeviceID) } blockDrive, ok := device.GetDeviceInfo().(*config.BlockDrive) @@ -976,11 +976,10 @@ func (k *kataAgent) buildContainerRootfs(sandbox *Sandbox, c *Container, rootPat rootfs.Source = blockDrive.SCSIAddr } rootfs.MountPoint = rootPathParent - rootfs.Fstype = c.rootFs.Type - rootfs.Options = c.rootFs.Options + rootfs.Fstype = c.state.Fstype - if rootfs.Fstype == "xfs" { - rootfs.Options = append(rootfs.Options, "nouuid") + if c.state.Fstype == "xfs" { + rootfs.Options = []string{"nouuid"} } return rootfs, nil @@ -994,7 +993,7 @@ func (k *kataAgent) buildContainerRootfs(sandbox *Sandbox, c *Container, rootPat // (kataGuestSharedDir) is already mounted in the // guest. We only need to mount the rootfs from // the host and it will show up in the guest. - if err := bindMountContainerRootfs(k.ctx, kataHostSharedDir, sandbox.id, c.id, c.rootFs.Destination, false); err != nil { + if err := bindMountContainerRootfs(k.ctx, kataHostSharedDir, sandbox.id, c.id, c.rootFs.Target, false); err != nil { return nil, err } diff --git a/virtcontainers/kata_agent_test.go b/virtcontainers/kata_agent_test.go index dfab29ed3f..d450c27b30 100644 --- a/virtcontainers/kata_agent_test.go +++ b/virtcontainers/kata_agent_test.go @@ -735,7 +735,9 @@ func TestAgentCreateContainer(t *testing.T) { id: "barfoo", sandboxID: "foobar", sandbox: sandbox, - state: types.ContainerState{}, + state: types.ContainerState{ + Fstype: "xfs", + }, config: &ContainerConfig{ Annotations: map[string]string{}, }, diff --git a/virtcontainers/mount.go b/virtcontainers/mount.go index 0dec13e424..8d7a201549 100644 --- a/virtcontainers/mount.go +++ b/virtcontainers/mount.go @@ -304,10 +304,7 @@ func bindMountContainerRootfs(ctx context.Context, sharedDir, sandboxID, cID, cR // Mount describes a container mount. type Mount struct { - // Mount source - Source string - - // Mount destination in the guest + Source string Destination string // Type specifies the type of filesystem to mount. @@ -319,16 +316,13 @@ type Mount struct { // HostPath used to store host side bind mount path HostPath string + // ReadOnly specifies if the mount should be read only or not + ReadOnly bool + // BlockDeviceID represents block device that is attached to the // VM in case this mount is a block device file or a directory // backed by a block device. 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 { @@ -347,7 +341,7 @@ func bindUnmountAllRootfs(ctx context.Context, sharedDir string, sandbox *Sandbo for _, c := range sandbox.containers { c.unmountHostMounts() - if c.rootFs.Type == "" { + if c.state.Fstype == "" { // Need to check for error returned by this call. // See: https://github.com/containers/virtcontainers/issues/295 bindUnmountContainerRootfs(c.ctx, sharedDir, sandbox.id, c.id) diff --git a/virtcontainers/persist.go b/virtcontainers/persist.go index 4f6cee83b7..b6bc5814e9 100644 --- a/virtcontainers/persist.go +++ b/virtcontainers/persist.go @@ -31,9 +31,9 @@ func (s *Sandbox) dumpState(ss *persistapi.SandboxState, cs map[string]persistap state = v } state.State = string(cont.state.State) - state.Rootfs = persistapi.Mount{ - BlockDeviceID: cont.rootFs.BlockDeviceID, - Type: cont.rootFs.Type, + state.Rootfs = persistapi.RootfsState{ + BlockDeviceID: cont.state.BlockDeviceID, + FsType: cont.state.Fstype, } state.CgroupPath = cont.state.CgroupPath cs[id] = state @@ -152,8 +152,10 @@ func (c *Container) Restore() error { } c.state = types.ContainerState{ - State: types.StateString(cs[c.id].State), - CgroupPath: cs[c.id].CgroupPath, + State: types.StateString(cs[c.id].State), + BlockDeviceID: cs[c.id].Rootfs.BlockDeviceID, + Fstype: cs[c.id].Rootfs.FsType, + CgroupPath: cs[c.id].CgroupPath, } return nil diff --git a/virtcontainers/persist/api/container.go b/virtcontainers/persist/api/container.go index a1ad7ab518..6b98323476 100644 --- a/virtcontainers/persist/api/container.go +++ b/virtcontainers/persist/api/container.go @@ -47,16 +47,23 @@ type Mount struct { // HostPath used to store host side bind mount path HostPath string + // ReadOnly specifies if the mount should be read only or not + ReadOnly bool + // BlockDeviceID represents block device that is attached to the // VM in case this mount is a block device file or a directory // backed by a block device. BlockDeviceID string +} - // ReadOnly specifies if the mount should be read only or not - ReadOnly bool +// RootfsState saves state of container rootfs +type RootfsState struct { + // BlockDeviceID represents container rootfs block device ID + // when backed by devicemapper + BlockDeviceID string - // Mounted specifies if the target has been mounted on the host - Mounted bool + // RootFStype is file system of the rootfs incase it is block device + FsType string } // Process gathers data related to a container process. @@ -83,7 +90,7 @@ type ContainerState struct { State string // Rootfs contains information of container rootfs - Rootfs Mount + Rootfs RootfsState // CgroupPath is the cgroup hierarchy where sandbox's processes // including the hypervisor are placed. diff --git a/virtcontainers/pkg/oci/utils.go b/virtcontainers/pkg/oci/utils.go index 05c0d237cd..b901e8134f 100644 --- a/virtcontainers/pkg/oci/utils.go +++ b/virtcontainers/pkg/oci/utils.go @@ -183,7 +183,6 @@ func newMount(m spec.Mount) vc.Mount { Destination: m.Destination, Type: m.Type, Options: m.Options, - Mounted: true, // All OCI volumes are mounted on the host ATM. } } @@ -525,12 +524,12 @@ func ContainerConfig(ocispec CompatOCISpec, bundlePath, cid, console string, det return vc.ContainerConfig{}, err } - rootfs := vc.Mount{Destination: ocispec.Root.Path, Mounted: true} - if !filepath.IsAbs(rootfs.Destination) { - rootfs.Destination = filepath.Join(bundlePath, ocispec.Root.Path) + rootfs := vc.RootFs{Target: ocispec.Root.Path, Mounted: true} + if !filepath.IsAbs(rootfs.Target) { + rootfs.Target = filepath.Join(bundlePath, ocispec.Root.Path) } - ociLog.Debugf("container rootfs: %s", rootfs.Destination) + ociLog.Debugf("container rootfs: %s", rootfs.Target) cmd := types.Cmd{ Args: ocispec.Process.Args, diff --git a/virtcontainers/pkg/oci/utils_test.go b/virtcontainers/pkg/oci/utils_test.go index 172b29cbe3..700d4863b3 100644 --- a/virtcontainers/pkg/oci/utils_test.go +++ b/virtcontainers/pkg/oci/utils_test.go @@ -150,7 +150,6 @@ func TestMinimalSandboxConfig(t *testing.T) { Type: "proc", Options: nil, HostPath: "", - Mounted: true, }, { Source: "tmpfs", @@ -158,7 +157,6 @@ func TestMinimalSandboxConfig(t *testing.T) { Type: "tmpfs", Options: []string{"nosuid", "strictatime", "mode=755", "size=65536k"}, HostPath: "", - Mounted: true, }, { Source: "devpts", @@ -166,7 +164,6 @@ func TestMinimalSandboxConfig(t *testing.T) { Type: "devpts", Options: []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"}, HostPath: "", - Mounted: true, }, } @@ -203,7 +200,7 @@ func TestMinimalSandboxConfig(t *testing.T) { expectedContainerConfig := vc.ContainerConfig{ ID: containerID, - RootFs: vc.Mount{Destination: path.Join(tempBundlePath, "rootfs"), Mounted: true}, + RootFs: vc.RootFs{Target: path.Join(tempBundlePath, "rootfs"), Mounted: true}, ReadonlyRootfs: true, Cmd: expectedCmd, Annotations: map[string]string{ diff --git a/virtcontainers/sandbox.go b/virtcontainers/sandbox.go index 8d3046d46f..be161b6b4a 100644 --- a/virtcontainers/sandbox.go +++ b/virtcontainers/sandbox.go @@ -291,7 +291,7 @@ func (s *Sandbox) Status() SandboxStatus { for _, c := range s.containers { rootfs := c.config.RootFs.Source if c.config.RootFs.Mounted { - rootfs = c.config.RootFs.Destination + rootfs = c.config.RootFs.Target } contStatusList = append(contStatusList, ContainerStatus{ @@ -1241,7 +1241,7 @@ func (s *Sandbox) StatusContainer(containerID string) (ContainerStatus, error) { for id, c := range s.containers { rootfs := c.config.RootFs.Source if c.config.RootFs.Mounted { - rootfs = c.config.RootFs.Destination + rootfs = c.config.RootFs.Target } if id == containerID { return ContainerStatus{ diff --git a/virtcontainers/sandbox_test.go b/virtcontainers/sandbox_test.go index 49f0fcbadb..2188972d10 100644 --- a/virtcontainers/sandbox_test.go +++ b/virtcontainers/sandbox_test.go @@ -7,6 +7,7 @@ package virtcontainers import ( "context" + "encoding/json" "fmt" "io/ioutil" "os" @@ -749,6 +750,99 @@ 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/" func TestSandboxAttachDevicesVFIO(t *testing.T) { diff --git a/virtcontainers/types/container.go b/virtcontainers/types/container.go index 387d91aba2..3436f8afdc 100644 --- a/virtcontainers/types/container.go +++ b/virtcontainers/types/container.go @@ -9,6 +9,11 @@ package types type ContainerState struct { 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 // including the hypervisor are placed. CgroupPath string `json:"cgroupPath,omitempty"`