mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-09-28 20:15:51 +00:00
Address some comments for code readability, also add some unit tests. Signed-off-by: Wei Zhang <weizhang555.zw@gmail.com>
338 lines
8.2 KiB
Go
338 lines
8.2 KiB
Go
// Copyright (c) 2019 Huawei Corporation
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
package virtcontainers
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"github.com/kata-containers/runtime/virtcontainers/device/api"
|
|
exp "github.com/kata-containers/runtime/virtcontainers/experimental"
|
|
"github.com/kata-containers/runtime/virtcontainers/persist"
|
|
persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api"
|
|
"github.com/kata-containers/runtime/virtcontainers/types"
|
|
)
|
|
|
|
var (
|
|
errContainerPersistNotExist = errors.New("container doesn't exist in persist data")
|
|
)
|
|
|
|
func (s *Sandbox) dumpVersion(ss *persistapi.SandboxState) {
|
|
// New created sandbox has a uninitialized `PersistVersion` which should be set to current version when do the first saving;
|
|
// Old restored sandbox should keep its original version and shouldn't be modified any more after it's initialized.
|
|
ss.PersistVersion = s.state.PersistVersion
|
|
if ss.PersistVersion == 0 {
|
|
ss.PersistVersion = persistapi.CurPersistVersion
|
|
}
|
|
}
|
|
|
|
func (s *Sandbox) dumpState(ss *persistapi.SandboxState, cs map[string]persistapi.ContainerState) {
|
|
ss.SandboxContainer = s.id
|
|
ss.GuestMemoryBlockSizeMB = s.state.GuestMemoryBlockSizeMB
|
|
ss.GuestMemoryHotplugProbe = s.state.GuestMemoryHotplugProbe
|
|
ss.State = string(s.state.State)
|
|
ss.CgroupPath = s.state.CgroupPath
|
|
|
|
for id, cont := range s.containers {
|
|
state := persistapi.ContainerState{}
|
|
if v, ok := cs[id]; ok {
|
|
state = v
|
|
}
|
|
state.State = string(cont.state.State)
|
|
state.Rootfs = persistapi.RootfsState{
|
|
BlockDeviceID: cont.state.BlockDeviceID,
|
|
FsType: cont.state.Fstype,
|
|
}
|
|
state.CgroupPath = cont.state.CgroupPath
|
|
cs[id] = state
|
|
}
|
|
|
|
// delete removed containers
|
|
for id := range cs {
|
|
if _, ok := s.containers[id]; !ok {
|
|
delete(cs, id)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Sandbox) dumpHypervisor(ss *persistapi.SandboxState) {
|
|
ss.HypervisorState = s.hypervisor.save()
|
|
// BlockIndex will be moved from sandbox state to hypervisor state later
|
|
ss.HypervisorState.BlockIndex = s.state.BlockIndex
|
|
}
|
|
|
|
func deviceToDeviceState(devices []api.Device) (dss []persistapi.DeviceState) {
|
|
for _, dev := range devices {
|
|
dss = append(dss, dev.Save())
|
|
}
|
|
return
|
|
}
|
|
|
|
func (s *Sandbox) dumpDevices(ss *persistapi.SandboxState, cs map[string]persistapi.ContainerState) {
|
|
ss.Devices = deviceToDeviceState(s.devManager.GetAllDevices())
|
|
|
|
for id, cont := range s.containers {
|
|
state := persistapi.ContainerState{}
|
|
if v, ok := cs[id]; ok {
|
|
state = v
|
|
}
|
|
|
|
state.DeviceMaps = nil
|
|
for _, dev := range cont.devices {
|
|
state.DeviceMaps = append(state.DeviceMaps, persistapi.DeviceMap{
|
|
ID: dev.ID,
|
|
ContainerPath: dev.ContainerPath,
|
|
FileMode: dev.FileMode,
|
|
UID: dev.UID,
|
|
GID: dev.GID,
|
|
})
|
|
}
|
|
|
|
cs[id] = state
|
|
}
|
|
|
|
// delete removed containers
|
|
for id := range cs {
|
|
if _, ok := s.containers[id]; !ok {
|
|
delete(cs, id)
|
|
}
|
|
}
|
|
}
|
|
|
|
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) dumpAgent(ss *persistapi.SandboxState) {
|
|
if s.agent != nil {
|
|
ss.AgentState = s.agent.save()
|
|
}
|
|
}
|
|
|
|
func (s *Sandbox) dumpNetwork(ss *persistapi.SandboxState) {
|
|
ss.Network = persistapi.NetworkInfo{
|
|
NetNsPath: s.networkNS.NetNsPath,
|
|
NetmonPID: s.networkNS.NetmonPID,
|
|
NetNsCreated: s.networkNS.NetNsCreated,
|
|
}
|
|
for _, e := range s.networkNS.Endpoints {
|
|
ss.Network.Endpoints = append(ss.Network.Endpoints, e.save())
|
|
}
|
|
}
|
|
|
|
func (s *Sandbox) Save() error {
|
|
var (
|
|
ss = persistapi.SandboxState{}
|
|
cs = make(map[string]persistapi.ContainerState)
|
|
)
|
|
|
|
s.dumpVersion(&ss)
|
|
s.dumpState(&ss, cs)
|
|
s.dumpHypervisor(&ss)
|
|
s.dumpDevices(&ss, cs)
|
|
s.dumpProcess(cs)
|
|
s.dumpMounts(cs)
|
|
s.dumpAgent(&ss)
|
|
s.dumpNetwork(&ss)
|
|
|
|
if err := s.newStore.ToDisk(ss, cs); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *Sandbox) loadState(ss persistapi.SandboxState) {
|
|
s.state.PersistVersion = ss.PersistVersion
|
|
s.state.GuestMemoryBlockSizeMB = ss.GuestMemoryBlockSizeMB
|
|
s.state.BlockIndex = ss.HypervisorState.BlockIndex
|
|
s.state.State = types.StateString(ss.State)
|
|
s.state.CgroupPath = ss.CgroupPath
|
|
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) loadHypervisor(hs persistapi.HypervisorState) {
|
|
s.hypervisor.load(hs)
|
|
}
|
|
|
|
func (s *Sandbox) loadAgent(as persistapi.AgentState) {
|
|
if s.agent != nil {
|
|
s.agent.load(as)
|
|
}
|
|
}
|
|
|
|
func (s *Sandbox) loadDevices(devStates []persistapi.DeviceState) {
|
|
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,
|
|
}
|
|
}
|
|
|
|
func (s *Sandbox) loadNetwork(netInfo persistapi.NetworkInfo) {
|
|
s.networkNS = NetworkNamespace{
|
|
NetNsPath: netInfo.NetNsPath,
|
|
NetmonPID: netInfo.NetmonPID,
|
|
NetNsCreated: netInfo.NetNsCreated,
|
|
}
|
|
|
|
for _, e := range netInfo.Endpoints {
|
|
var ep Endpoint
|
|
switch EndpointType(e.Type) {
|
|
case PhysicalEndpointType:
|
|
ep = &PhysicalEndpoint{}
|
|
case VethEndpointType:
|
|
ep = &VethEndpoint{}
|
|
case VhostUserEndpointType:
|
|
ep = &VhostUserEndpoint{}
|
|
case BridgedMacvlanEndpointType:
|
|
ep = &BridgedMacvlanEndpoint{}
|
|
case MacvtapEndpointType:
|
|
ep = &MacvtapEndpoint{}
|
|
case TapEndpointType:
|
|
ep = &TapEndpoint{}
|
|
case IPVlanEndpointType:
|
|
ep = &IPVlanEndpoint{}
|
|
default:
|
|
s.Logger().WithField("endpoint-type", e.Type).Error("unknown endpoint type")
|
|
continue
|
|
}
|
|
ep.load(e)
|
|
s.networkNS.Endpoints = append(s.networkNS.Endpoints, ep)
|
|
}
|
|
}
|
|
|
|
// Restore will restore sandbox data from persist file on disk
|
|
func (s *Sandbox) Restore() error {
|
|
ss, _, err := s.newStore.FromDisk(s.id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
s.loadState(ss)
|
|
s.loadHypervisor(ss.HypervisorState)
|
|
s.loadDevices(ss.Devices)
|
|
s.loadAgent(ss.AgentState)
|
|
s.loadNetwork(ss.Network)
|
|
return nil
|
|
}
|
|
|
|
// Restore will restore container data from persist file on disk
|
|
func (c *Container) Restore() error {
|
|
_, css, err := c.sandbox.newStore.FromDisk(c.sandbox.id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
cs, ok := css[c.id]
|
|
if !ok {
|
|
return errContainerPersistNotExist
|
|
}
|
|
|
|
c.loadContState(cs)
|
|
c.loadContDevices(cs)
|
|
c.loadContProcess(cs)
|
|
c.loadContMounts(cs)
|
|
return nil
|
|
}
|
|
|
|
func (s *Sandbox) supportNewStore() bool {
|
|
for _, f := range s.config.Experimental {
|
|
if f == persist.NewStoreFeature && exp.Get("newstore") != nil {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|