diff --git a/virtcontainers/container.go b/virtcontainers/container.go index 7cbecb266e..46d205c946 100644 --- a/virtcontainers/container.go +++ b/virtcontainers/container.go @@ -442,6 +442,9 @@ func (c *Container) setContainerState(state types.StateString) error { return err } + if err = c.sandbox.newStore.Dump(); err != nil { + return err + } return nil } @@ -683,9 +686,14 @@ func newContainer(sandbox *Sandbox, contConfig ContainerConfig) (*Container, err c.store = ctrStore - state, err := c.store.LoadContainerState() + /*state, err := c.store.LoadContainerState() if err == nil { c.state = state + }*/ + + if err := c.Restore(); err != nil && + !os.IsNotExist(err) && err != errContainerPersistNotExist { + return nil, err } var process Process @@ -693,6 +701,18 @@ func newContainer(sandbox *Sandbox, contConfig ContainerConfig) (*Container, err c.process = process } + if err = c.createMounts(); err != nil { + return nil, err + } + + if err = c.createDevices(contConfig); err != nil { + return nil, err + } + + return c, nil +} + +func (c *Container) createMounts() error { mounts, err := c.loadMounts() if err == nil { // restore mounts from disk @@ -700,10 +720,14 @@ func newContainer(sandbox *Sandbox, contConfig ContainerConfig) (*Container, err } else { // Create block devices for newly created container if err := c.createBlockDevices(); err != nil { - return nil, err + return err } } + return nil +} + +func (c *Container) createDevices(contConfig ContainerConfig) error { // Devices will be found in storage after create stage has completed. // We load devices from storage at all other stages. storedDevices, err := c.loadDevices() @@ -713,9 +737,9 @@ func newContainer(sandbox *Sandbox, contConfig ContainerConfig) (*Container, err // If devices were not found in storage, create Device implementations // from the configuration. This should happen at create. for _, info := range contConfig.DeviceInfos { - dev, err := sandbox.devManager.NewDevice(info) + dev, err := c.sandbox.devManager.NewDevice(info) if err != nil { - return &Container{}, err + return err } storedDevices = append(storedDevices, ContainerDevice{ @@ -726,10 +750,9 @@ func newContainer(sandbox *Sandbox, contConfig ContainerConfig) (*Container, err GID: info.GID, }) } - c.devices = filterDevices(sandbox, c, storedDevices) + c.devices = filterDevices(c.sandbox, c, storedDevices) } - - return c, nil + return nil } // rollbackFailingContainerCreation rolls back important steps that might have diff --git a/virtcontainers/persist.go b/virtcontainers/persist.go index a47ceea9b2..6654f53318 100644 --- a/virtcontainers/persist.go +++ b/virtcontainers/persist.go @@ -6,19 +6,23 @@ package virtcontainers import ( - //"fmt" - - //"github.com/sirupsen/logrus" + "errors" "github.com/kata-containers/runtime/virtcontainers/device/api" persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api" "github.com/kata-containers/runtime/virtcontainers/types" ) +var ( + errSandboxPersistNotExist = errors.New("sandbox doesn't exist in persist data") + errContainerPersistNotExist = errors.New("container doesn't exist in persist data") +) + func (s *Sandbox) dumpState(ss *persistapi.SandboxState, cs map[string]persistapi.ContainerState) error { ss.SandboxContainer = s.id ss.GuestMemoryBlockSizeMB = s.state.GuestMemoryBlockSizeMB ss.State = string(s.state.State) + ss.CgroupPath = s.state.CgroupPath for id, cont := range s.containers { state := persistapi.ContainerState{} @@ -30,6 +34,7 @@ func (s *Sandbox) dumpState(ss *persistapi.SandboxState, cs map[string]persistap BlockDeviceID: cont.state.BlockDeviceID, FsType: cont.state.Fstype, } + state.CgroupPath = cont.state.CgroupPath cs[id] = state } @@ -111,43 +116,61 @@ func (s *Sandbox) persistDevices() { s.newStore.RegisterHook("devices", s.dumpDevices) } -// Restore will restore data from persist disk on disk -func (s *Sandbox) Restore() error { - if err := s.newStore.Restore(s.id); err != nil { - return err +func (s *Sandbox) getSbxAndCntStates() (*persistapi.SandboxState, map[string]persistapi.ContainerState, error) { + ss, cs, err := s.newStore.GetStates() + if err != nil { + return nil, nil, err } - ss, _, err := s.newStore.GetStates() + if len(cs) == 0 { + if err := s.newStore.Restore(s.id); err != nil { + return nil, nil, err + } + + ss, cs, err = s.newStore.GetStates() + if err != nil { + return nil, nil, err + } + + if len(cs) == 0 { + return nil, nil, errSandboxPersistNotExist + } + } + return ss, cs, nil +} + +// Restore will restore sandbox data from persist file on disk +func (s *Sandbox) Restore() error { + ss, _, err := s.getSbxAndCntStates() if err != nil { return err } - /* - // TODO: need more modifications, restoring containers - // will make sandbox.addContainer failing - if s.containers == nil { - s.containers = make(map[string]*Container) - } - - for id, cont := range cs { - s.containers[id] = &Container{ - state: State{ - State: stateString(cont.State), - BlockDeviceID: cont.Rootfs.BlockDeviceID, - Fstype: cont.Rootfs.FsType, - Pid: cont.ShimPid, - }, - } - } - - sbxCont, ok := s.containers[ss.SandboxContainer] - if !ok { - return fmt.Errorf("failed to get sandbox container state") - } - */ s.state.GuestMemoryBlockSizeMB = ss.GuestMemoryBlockSizeMB s.state.BlockIndex = ss.HypervisorState.BlockIndex s.state.State = types.StateString(ss.State) + s.state.CgroupPath = ss.CgroupPath + + return nil +} + +// Restore will restore container data from persist file on disk +func (c *Container) Restore() error { + _, cs, err := c.sandbox.getSbxAndCntStates() + if err != nil { + return err + } + + if _, ok := cs[c.id]; !ok { + return errContainerPersistNotExist + } + + c.state = types.ContainerState{ + 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 b1c74fe5b9..baf676e6bd 100644 --- a/virtcontainers/persist/api/container.go +++ b/virtcontainers/persist/api/container.go @@ -94,7 +94,7 @@ type ContainerState struct { // CgroupPath is the cgroup hierarchy where sandbox's processes // including the hypervisor are placed. - CgroupPath string `json:"cgroupPath,omitempty"` + CgroupPath string // DeviceMaps is mapping between sandbox device to dest in container DeviceMaps []DeviceMap diff --git a/virtcontainers/persist/api/sandbox.go b/virtcontainers/persist/api/sandbox.go index 2da4fada1d..cd2249c1f7 100644 --- a/virtcontainers/persist/api/sandbox.go +++ b/virtcontainers/persist/api/sandbox.go @@ -68,11 +68,12 @@ type SandboxState struct { SandboxContainer string // GuestMemoryHotplugProbe determines whether guest kernel supports memory hotplug probe interface - GuestMemoryHotplugProbe bool `json:"guestMemoryHotplugProbe"` + GuestMemoryHotplugProbe bool // CgroupPath is the cgroup hierarchy where sandbox's processes // including the hypervisor are placed. - CgroupPath string `json:"cgroupPath,omitempty"` + // FIXME: sandbox can reuse "SandboxContainer"'s CgroupPath so we can remove this field. + CgroupPath string // GuestMemoryBlockSizeMB is the size of memory block of guestos GuestMemoryBlockSizeMB uint32 diff --git a/virtcontainers/persist/fs/fs.go b/virtcontainers/persist/fs/fs.go index a6a3ebd60f..065a952aff 100644 --- a/virtcontainers/persist/fs/fs.go +++ b/virtcontainers/persist/fs/fs.go @@ -9,6 +9,7 @@ package fs import ( "encoding/json" "fmt" + "io/ioutil" "os" "path/filepath" "syscall" @@ -139,15 +140,12 @@ func (fs *FS) Restore(sid string) error { } fs.sandboxState.SandboxContainer = sid + sandboxDir, err := fs.sandboxDir() if err != nil { return err } - if err := os.MkdirAll(sandboxDir, dirMode); err != nil { - return err - } - if err := fs.lock(); err != nil { return err } @@ -166,13 +164,7 @@ func (fs *FS) Restore(sid string) error { } // walk sandbox dir and find container - d, err := os.OpenFile(sandboxDir, os.O_RDONLY, fileMode) - if err != nil { - return err - } - defer d.Close() - - files, err := d.Readdir(-1) + files, err := ioutil.ReadDir(sandboxDir) if err != nil { return err }