persist: save and restore state from persist.json

Save and restore state from persist.json instead of state.json

Signed-off-by: Wei Zhang <zhangwei555@huawei.com>
This commit is contained in:
Wei Zhang 2019-02-08 15:03:57 +08:00
parent 039ed4eeb8
commit 6e4149d86c
5 changed files with 91 additions and 52 deletions

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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
}