persist: merge more files with persist.json

Fixes #803

Merge more container storage files with `persist.json` including:
* devices.json
* mounts.json
* process.json

Signed-off-by: Wei Zhang <zhangwei555@huawei.com>
This commit is contained in:
Wei Zhang
2019-05-13 15:26:45 +08:00
parent bce1167c33
commit a6b3368469
5 changed files with 185 additions and 59 deletions

View File

@@ -372,8 +372,11 @@ func (c *Container) GetPid() int {
func (c *Container) SetPid(pid int) error { func (c *Container) SetPid(pid int) error {
c.process.Pid = pid c.process.Pid = pid
if !c.sandbox.supportNewStore() {
return c.storeProcess() return c.storeProcess()
} }
return nil
}
func (c *Container) setStateFstype(fstype string) error { func (c *Container) setStateFstype(fstype string) error {
c.state.Fstype = fstype c.state.Fstype = fstype
@@ -592,9 +595,11 @@ func (c *Container) mountSharedDirMounts(hostSharedDir, guestSharedDir string) (
sharedDirMounts = append(sharedDirMounts, sharedDirMount) sharedDirMounts = append(sharedDirMounts, sharedDirMount)
} }
if !c.sandbox.supportNewStore() {
if err := c.storeMounts(); err != nil { if err := c.storeMounts(); err != nil {
return nil, nil, err return nil, nil, err
} }
}
return sharedDirMounts, ignoredMounts, nil return sharedDirMounts, ignoredMounts, nil
} }
@@ -716,21 +721,28 @@ func newContainer(sandbox *Sandbox, contConfig ContainerConfig) (*Container, err
// experimental runtime use "persist.json" instead of legacy "state.json" as storage // experimental runtime use "persist.json" instead of legacy "state.json" as storage
if c.sandbox.supportNewStore() { if c.sandbox.supportNewStore() {
if err := c.Restore(); err != nil && err := c.Restore()
!os.IsNotExist(err) && err != errContainerPersistNotExist { if err == nil {
//container restored
return c, nil
}
// Unexpected error
if !os.IsNotExist(err) && err != errContainerPersistNotExist {
return nil, err return nil, err
} }
// Go to next step for first created container
} else { } else {
state, err := c.store.LoadContainerState() state, err := c.store.LoadContainerState()
if err == nil { if err == nil {
c.state = state c.state = state
} }
}
var process Process var process Process
if err := c.store.Load(store.Process, &process); err == nil { if err := c.store.Load(store.Process, &process); err == nil {
c.process = process c.process = process
} }
}
if err = c.createMounts(); err != nil { if err = c.createMounts(); err != nil {
return nil, err return nil, err
@@ -744,29 +756,41 @@ func newContainer(sandbox *Sandbox, contConfig ContainerConfig) (*Container, err
} }
func (c *Container) createMounts() error { func (c *Container) createMounts() error {
// If sandbox supports "newstore", only newly created container can reach this function,
// so we don't call restore when `supportNewStore` is true
if !c.sandbox.supportNewStore() {
mounts, err := c.loadMounts() mounts, err := c.loadMounts()
if err == nil { if err == nil {
// restore mounts from disk // restore mounts from disk
c.mounts = mounts c.mounts = mounts
} else { return nil
}
}
// Create block devices for newly created container // Create block devices for newly created container
if err := c.createBlockDevices(); err != nil { if err := c.createBlockDevices(); err != nil {
return err return err
} }
}
return nil return nil
} }
func (c *Container) createDevices(contConfig ContainerConfig) error { func (c *Container) createDevices(contConfig ContainerConfig) error {
// If sandbox supports "newstore", only newly created container can reach this function,
// so we don't call restore when `supportNewStore` is true
if !c.sandbox.supportNewStore() {
// Devices will be found in storage after create stage has completed. // Devices will be found in storage after create stage has completed.
// We load devices from storage at all other stages. // We load devices from storage at all other stages.
storedDevices, err := c.loadDevices() storedDevices, err := c.loadDevices()
if err == nil { if err == nil {
c.devices = storedDevices c.devices = storedDevices
} else { return nil
}
}
// If devices were not found in storage, create Device implementations // If devices were not found in storage, create Device implementations
// from the configuration. This should happen at create. // from the configuration. This should happen at create.
var storedDevices []ContainerDevice
for _, info := range contConfig.DeviceInfos { for _, info := range contConfig.DeviceInfos {
dev, err := c.sandbox.devManager.NewDevice(info) dev, err := c.sandbox.devManager.NewDevice(info)
if err != nil { if err != nil {
@@ -782,7 +806,6 @@ func (c *Container) createDevices(contConfig ContainerConfig) error {
}) })
} }
c.devices = filterDevices(c, storedDevices) c.devices = filterDevices(c, storedDevices)
}
return nil return nil
} }
@@ -838,9 +861,11 @@ func (c *Container) create() (err error) {
// inside the VM // inside the VM
c.getSystemMountInfo() c.getSystemMountInfo()
if !c.sandbox.supportNewStore() {
if err = c.storeDevices(); err != nil { if err = c.storeDevices(); err != nil {
return return
} }
}
process, err := c.sandbox.agent.createContainer(c.sandbox, c) process, err := c.sandbox.agent.createContainer(c.sandbox, c)
if err != nil { if err != nil {
@@ -852,10 +877,12 @@ func (c *Container) create() (err error) {
return return
} }
if !c.sandbox.supportNewStore() {
// Store the container process returned by the agent. // Store the container process returned by the agent.
if err = c.storeProcess(); err != nil { if err = c.storeProcess(); err != nil {
return return
} }
}
if err = c.setContainerState(types.StateReady); err != nil { if err = c.setContainerState(types.StateReady); err != nil {
return return

View File

@@ -1311,10 +1311,13 @@ func (k *kataAgent) handleBlockVolumes(c *Container) []*grpc.Storage {
// Add the block device to the list of container devices, to make sure the // Add the block device to the list of container devices, to make sure the
// device is detached with detachDevices() for a container. // device is detached with detachDevices() for a container.
c.devices = append(c.devices, ContainerDevice{ID: id, ContainerPath: m.Destination}) c.devices = append(c.devices, ContainerDevice{ID: id, ContainerPath: m.Destination})
if !c.sandbox.supportNewStore() {
if err := c.storeDevices(); err != nil { if err := c.storeDevices(); err != nil {
k.Logger().WithField("device", id).WithError(err).Error("store device failed") k.Logger().WithField("device", id).WithError(err).Error("store device failed")
return nil return nil
} }
}
vol := &grpc.Storage{} vol := &grpc.Storage{}

View File

@@ -99,6 +99,59 @@ func (s *Sandbox) dumpDevices(ss *persistapi.SandboxState, cs map[string]persist
} }
} }
func (s *Sandbox) dumpProcess(cs map[string]persistapi.ContainerState) {
for id, cont := range s.containers {
state := persistapi.ContainerState{}
if v, ok := cs[id]; ok {
state = v
}
state.Process = persistapi.Process{
Token: cont.process.Token,
Pid: cont.process.Pid,
StartTime: cont.process.StartTime,
}
cs[id] = state
}
// delete removed containers
for id := range cs {
if _, ok := s.containers[id]; !ok {
delete(cs, id)
}
}
}
func (s *Sandbox) dumpMounts(cs map[string]persistapi.ContainerState) {
for id, cont := range s.containers {
state := persistapi.ContainerState{}
if v, ok := cs[id]; ok {
state = v
}
for _, m := range cont.mounts {
state.Mounts = append(state.Mounts, persistapi.Mount{
Source: m.Source,
Destination: m.Destination,
Options: m.Options,
HostPath: m.HostPath,
ReadOnly: m.ReadOnly,
BlockDeviceID: m.BlockDeviceID,
})
}
cs[id] = state
}
// delete removed containers
for id := range cs {
if _, ok := s.containers[id]; !ok {
delete(cs, id)
}
}
}
func (s *Sandbox) Save() error { func (s *Sandbox) Save() error {
var ( var (
ss = persistapi.SandboxState{} ss = persistapi.SandboxState{}
@@ -109,6 +162,8 @@ func (s *Sandbox) Save() error {
s.dumpState(&ss, cs) s.dumpState(&ss, cs)
s.dumpHypervisor(&ss, cs) s.dumpHypervisor(&ss, cs)
s.dumpDevices(&ss, cs) s.dumpDevices(&ss, cs)
s.dumpProcess(cs)
s.dumpMounts(cs)
if err := s.newStore.ToDisk(ss, cs); err != nil { if err := s.newStore.ToDisk(ss, cs); err != nil {
return err return err
@@ -126,10 +181,54 @@ func (s *Sandbox) loadState(ss persistapi.SandboxState) {
s.state.GuestMemoryHotplugProbe = ss.GuestMemoryHotplugProbe s.state.GuestMemoryHotplugProbe = ss.GuestMemoryHotplugProbe
} }
func (c *Container) loadContState(cs persistapi.ContainerState) {
c.state = types.ContainerState{
State: types.StateString(cs.State),
BlockDeviceID: cs.Rootfs.BlockDeviceID,
Fstype: cs.Rootfs.FsType,
CgroupPath: cs.CgroupPath,
}
}
func (s *Sandbox) loadDevices(devStates []persistapi.DeviceState) { func (s *Sandbox) loadDevices(devStates []persistapi.DeviceState) {
s.devManager.LoadDevices(devStates) s.devManager.LoadDevices(devStates)
} }
func (c *Container) loadContDevices(cs persistapi.ContainerState) {
c.devices = nil
for _, dev := range cs.DeviceMaps {
c.devices = append(c.devices, ContainerDevice{
ID: dev.ID,
ContainerPath: dev.ContainerPath,
FileMode: dev.FileMode,
UID: dev.UID,
GID: dev.GID,
})
}
}
func (c *Container) loadContMounts(cs persistapi.ContainerState) {
c.mounts = nil
for _, m := range cs.Mounts {
c.mounts = append(c.mounts, Mount{
Source: m.Source,
Destination: m.Destination,
Options: m.Options,
HostPath: m.HostPath,
ReadOnly: m.ReadOnly,
BlockDeviceID: m.BlockDeviceID,
})
}
}
func (c *Container) loadContProcess(cs persistapi.ContainerState) {
c.process = Process{
Token: cs.Process.Token,
Pid: cs.Process.Pid,
StartTime: cs.Process.StartTime,
}
}
// Restore will restore sandbox data from persist file on disk // Restore will restore sandbox data from persist file on disk
func (s *Sandbox) Restore() error { func (s *Sandbox) Restore() error {
ss, _, err := s.newStore.FromDisk(s.id) ss, _, err := s.newStore.FromDisk(s.id)
@@ -144,22 +243,20 @@ func (s *Sandbox) Restore() error {
// Restore will restore container data from persist file on disk // Restore will restore container data from persist file on disk
func (c *Container) Restore() error { func (c *Container) Restore() error {
_, cs, err := c.sandbox.newStore.FromDisk(c.sandbox.id) _, css, err := c.sandbox.newStore.FromDisk(c.sandbox.id)
if err != nil { if err != nil {
return err return err
} }
if _, ok := cs[c.id]; !ok { cs, ok := css[c.id]
if !ok {
return errContainerPersistNotExist return errContainerPersistNotExist
} }
c.state = types.ContainerState{ c.loadContState(cs)
State: types.StateString(cs[c.id].State), c.loadContDevices(cs)
BlockDeviceID: cs[c.id].Rootfs.BlockDeviceID, c.loadContProcess(cs)
Fstype: cs[c.id].Rootfs.FsType, c.loadContMounts(cs)
CgroupPath: cs[c.id].CgroupPath,
}
return nil return nil
} }

View File

@@ -103,8 +103,7 @@ type ContainerState struct {
Mounts []Mount Mounts []Mount
// Process on host representing container process // Process on host representing container process
// FIXME: []Process or Process ? Process Process
Process []Process
// BundlePath saves container OCI config.json, which can be unmarshaled // BundlePath saves container OCI config.json, which can be unmarshaled
// and translated to "CompatOCISpec" // and translated to "CompatOCISpec"

View File

@@ -14,7 +14,7 @@ type SetFunc (func(*SandboxState, map[string]ContainerState) error)
// Bridge is a bridge where devices can be hot plugged // Bridge is a bridge where devices can be hot plugged
type Bridge struct { type Bridge struct {
// Address contains information about devices plugged and its address in the bridge // DeviceAddr contains information about devices plugged and its address in the bridge
DeviceAddr map[uint32]string DeviceAddr map[uint32]string
// Type is the type of the bridge (pci, pcie, etc) // Type is the type of the bridge (pci, pcie, etc)