Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 54 additions & 12 deletions internal/lib/restore.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

metadata "github.com/checkpoint-restore/checkpointctl/lib"
"github.com/checkpoint-restore/go-criu/v6/stats"
"github.com/containers/podman/v4/pkg/annotations"
"github.com/containers/podman/v4/pkg/checkpoint/crutils"
"github.com/containers/storage/pkg/archive"
"github.com/cri-o/cri-o/internal/log"
Expand All @@ -31,8 +32,10 @@ func (c *ContainerServer) ContainerRestore(ctx context.Context, opts *ContainerC
}

// Get config.json
configFile := filepath.Join(ctr.Dir(), "config.json")
ctrSpec, err := generate.NewFromFile(configFile)
// This file is generated twice by earlier code. Once in BundlePath() and
// once in Dir(). This code takes the version from Dir(), modifies it and
// overwrites both versions (Dir() and BundlePath())
ctrSpec, err := generate.NewFromFile(filepath.Join(ctr.Dir(), "config.json"))
if err != nil {
return "", err
}
Expand All @@ -54,15 +57,6 @@ func (c *ContainerServer) ContainerRestore(ctx context.Context, opts *ContainerC
if err != nil {
return "", err
}
ic := sb.InfraContainer()
if ic == nil {
return "", fmt.Errorf("infra container of sandbox %v not found", sb.Name())
}
infraConfigFile := filepath.Join(ic.BundlePath(), "config.json")
specgen, err := generate.NewFromFile(infraConfigFile)
if err != nil {
return "", err
}

if ctr.RestoreArchive() != "" {
if ctr.RestoreIsOCIImage() {
Expand Down Expand Up @@ -209,7 +203,55 @@ func (c *ContainerServer) ContainerRestore(ctx context.Context, opts *ContainerC
}
}

if err := c.runtime.RestoreContainer(ctx, ctr, specgen.Config, ic.State().Pid, sb.CgroupParent()); err != nil {
// We need to adapt the to be restored container to the sandbox created for this container.

// The container will be restored in another sandbox. Adapt to
// namespaces of the new sandbox
for i, n := range ctrSpec.Config.Linux.Namespaces {
if n.Path == "" {
// The namespace in the original container did not point to
// an existing interface. Leave it as it is.
// CRIU will restore the namespace
continue
}
for _, np := range sb.NamespacePaths() {
if string(np.Type()) == string(n.Type) {
ctrSpec.Config.Linux.Namespaces[i].Path = np.Path()
break
}
}
}

// Update Sandbox Name
ctrSpec.AddAnnotation(annotations.SandboxName, sb.Name())
// Update Sandbox ID
ctrSpec.AddAnnotation(annotations.SandboxID, opts.Pod)

mData := fmt.Sprintf(
"k8s_%s_%s_%s_%s0",
ctr.Name(),
sb.KubeName(),
sb.Namespace(),
sb.Metadata().Uid,
)
ctrSpec.AddAnnotation(annotations.Name, mData)

ctr.SetSandbox(opts.Pod)

saveOptions := generate.ExportOptions{}
if err := ctrSpec.SaveToFile(filepath.Join(ctr.Dir(), "config.json"), saveOptions); err != nil {
return "", err
}
if err := ctrSpec.SaveToFile(filepath.Join(ctr.BundlePath(), "config.json"), saveOptions); err != nil {
return "", err
}

if err := c.runtime.RestoreContainer(
ctx,
ctr,
sb.CgroupParent(),
sb.MountLabel(),
); err != nil {
return "", fmt.Errorf("failed to restore container %s: %w", ctr.ID(), err)
}
if err := c.ContainerStateToDisk(ctx, ctr); err != nil {
Expand Down
2 changes: 1 addition & 1 deletion internal/lib/restore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ var _ = t.Describe("ContainerRestore", func() {
// Then
Expect(err).NotTo(BeNil())
Expect(res).To(Equal(""))
Expect(err.Error()).To(Equal(`infra container of sandbox not found`))
Expect(err.Error()).To(Equal(`failed to restore container containerID: a complete checkpoint for this container cannot be found, cannot restore: stat checkpoint/inventory.img: no such file or directory`))
})
})
t.Describe("ContainerRestore", func() {
Expand Down
6 changes: 3 additions & 3 deletions internal/oci/oci.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ type RuntimeImpl interface {
int32, io.ReadWriteCloser) error
ReopenContainerLog(context.Context, *Container) error
CheckpointContainer(context.Context, *Container, *rspec.Spec, bool) error
RestoreContainer(context.Context, *Container, *rspec.Spec, int, string) error
RestoreContainer(context.Context, *Container, string, string) error
}

// New creates a new Runtime with options provided
Expand Down Expand Up @@ -428,11 +428,11 @@ func (r *Runtime) CheckpointContainer(ctx context.Context, c *Container, specgen
}

// RestoreContainer restores a container.
func (r *Runtime) RestoreContainer(ctx context.Context, c *Container, sbSpec *rspec.Spec, infraPid int, cgroupParent string) error {
func (r *Runtime) RestoreContainer(ctx context.Context, c *Container, cgroupParent, mountLabel string) error {
impl, err := r.RuntimeImpl(c)
if err != nil {
return err
}

return impl.RestoreContainer(ctx, c, sbSpec, infraPid, cgroupParent)
return impl.RestoreContainer(ctx, c, cgroupParent, mountLabel)
}
58 changes: 19 additions & 39 deletions internal/oci/oci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ var _ = t.Describe("Oci", func() {
Skip("CRIU is missing or too old.")
}
// Given
beforeEach(sandboxID)
beforeEach()
defer os.RemoveAll("dump.log")
config.Runtimes["runc"] = &libconfig.RuntimeHandler{
RuntimePath: "/bin/true",
Expand All @@ -209,7 +209,7 @@ var _ = t.Describe("Oci", func() {
}
// Given
defer os.RemoveAll("dump.log")
beforeEach(sandboxID)
beforeEach()
config.Runtimes["runc"] = &libconfig.RuntimeHandler{
RuntimePath: "/bin/false",
}
Expand All @@ -235,57 +235,44 @@ var _ = t.Describe("Oci", func() {
Skip("CRIU is missing or too old.")
}
// Given
beforeEach(sandboxID)
beforeEach()
config.Runtimes["runc"] = &libconfig.RuntimeHandler{
RuntimePath: "/bin/true",
MonitorPath: "/bin/true",
}

specgen := &specs.Spec{
Version: "1.0.0",
}
err := os.Mkdir("checkpoint", 0o700)
Expect(err).To(BeNil())
defer os.RemoveAll("checkpoint")
inventory, err := os.OpenFile("checkpoint/inventory.img", os.O_RDONLY|os.O_CREATE, 0o644)
Expect(err).To(BeNil())
inventory.Close()

// When
err = sut.RestoreContainer(context.Background(), myContainer, specgen, 42, "no-parent-cgroup-exists")

// Then
Expect(err).NotTo(BeNil())
Expect(err.Error()).To(Equal("failed to detect destination sandbox of to be restored container containerID"))
})
It("RestoreContainer should fail with destination sandbox detection", func() {
if !criu.CheckForCriu(criu.PodCriuVersion) {
Skip("CRIU is missing or too old.")
}
// Given
beforeEach("")
specgen := &specs.Spec{
Version: "1.0.0",
Version: "1.0.0",
Annotations: map[string]string{"io.kubernetes.cri-o.SandboxID": "sandboxID"},
Linux: &specs.Linux{
MountLabel: ".",
},
Process: &specs.Process{
SelinuxLabel: "",
},
}
err := os.Mkdir("checkpoint", 0o700)
Expect(err).To(BeNil())
defer os.RemoveAll("checkpoint")
inventory, err := os.OpenFile("checkpoint/inventory.img", os.O_RDONLY|os.O_CREATE, 0o644)
Expect(err).To(BeNil())
inventory.Close()
myContainer.SetSpec(specgen)

// When
err = sut.RestoreContainer(context.Background(), myContainer, specgen, 42, "no-parent-cgroup-exists")
err = sut.RestoreContainer(context.Background(), myContainer, "no-parent-cgroup-exists", "label")

// Then
Expect(err).NotTo(BeNil())
Expect(err.Error()).To(Equal("failed to detect sandbox of to be restored container containerID"))
Expect(err.Error()).To(ContainSubstring("failed"))
})
It("RestoreContainer should fail", func() {
if !criu.CheckForCriu(criu.PodCriuVersion) {
Skip("CRIU is missing or too old.")
}
// Given
beforeEach(sandboxID)
beforeEach()
config.Runtimes["runc"] = &libconfig.RuntimeHandler{
RuntimePath: "/bin/true",
MonitorPath: "/bin/true",
Expand Down Expand Up @@ -325,7 +312,7 @@ var _ = t.Describe("Oci", func() {
config.Conmon = "/bin/true"

// When
err = sut.RestoreContainer(context.Background(), myContainer, specgen, 42, "no-parent-cgroup-exists")
err = sut.RestoreContainer(context.Background(), myContainer, "no-parent-cgroup-exists", "label")
defer os.RemoveAll("restore.log")

// Then
Expand All @@ -337,16 +324,9 @@ var _ = t.Describe("Oci", func() {
Skip("CRIU is missing or too old.")
}
// Given
beforeEach(sandboxID)
specgen := &specs.Spec{
Version: "1.0.0",
Annotations: map[string]string{"io.kubernetes.cri-o.SandboxID": "sandboxID"},
Linux: &specs.Linux{
MountLabel: ".",
},
}
beforeEach()
// When
err := sut.RestoreContainer(context.Background(), myContainer, specgen, 42, "no-parent-cgroup-exists")
err := sut.RestoreContainer(context.Background(), myContainer, "no-parent-cgroup-exists", "label")

// Then
Expect(err).NotTo(BeNil())
Expand Down
78 changes: 2 additions & 76 deletions internal/oci/runtime_oci.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (
metadata "github.com/checkpoint-restore/checkpointctl/lib"
"github.com/containernetworking/plugins/pkg/ns"
conmonconfig "github.com/containers/conmon/runner/config"
"github.com/containers/podman/v4/pkg/annotations"
"github.com/containers/podman/v4/pkg/checkpoint/crutils"
"github.com/containers/podman/v4/pkg/criu"
"github.com/containers/storage/pkg/pools"
Expand All @@ -30,7 +29,6 @@ import (
"github.com/fsnotify/fsnotify"
json "github.com/json-iterator/go"
rspec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
"github.com/sirupsen/logrus"
"golang.org/x/net/context"
"golang.org/x/sys/unix"
Expand Down Expand Up @@ -1528,7 +1526,7 @@ func (r *runtimeOCI) CheckpointContainer(ctx context.Context, c *Container, spec
}

// RestoreContainer restores a container.
func (r *runtimeOCI) RestoreContainer(ctx context.Context, c *Container, sbSpec *rspec.Spec, infraPid int, cgroupParent string) error {
func (r *runtimeOCI) RestoreContainer(ctx context.Context, c *Container, cgroupParent, mountLabel string) error {
if err := r.checkpointRestoreSupported(); err != nil {
return err
}
Expand All @@ -1555,78 +1553,6 @@ func (r *runtimeOCI) RestoreContainer(ctx context.Context, c *Container, sbSpec
return fmt.Errorf("error removing container %s winsz file: %w", c.ID(), err)
}

// Figure out if this container will be restored in another sandbox
oldSbID := c.Sandbox()
if oldSbID == "" {
return fmt.Errorf("failed to detect sandbox of to be restored container %s", c.ID())
}
newSbID := sbSpec.Annotations[annotations.SandboxID]
if newSbID == "" {
return fmt.Errorf("failed to detect destination sandbox of to be restored container %s", c.ID())
}

// Get config.json to adapt for restore (mostly annotations for restore in another sandbox)
configFile := filepath.Join(c.BundlePath(), "config.json")
specgen, err := generate.NewFromFile(configFile)
if err != nil {
return err
}

if oldSbID != newSbID {
// The container will be restored in another (not the original) sandbox
// Adapt to namespaces of the new sandbox
for i, n := range specgen.Config.Linux.Namespaces {
if n.Path == "" {
// The namespace in the original container did not point to
// an existing interface. Leave it as it is.
continue
}
for _, on := range sbSpec.Linux.Namespaces {
if on.Type == n.Type {
var nsPath string
if n.Type == rspec.NetworkNamespace {
// Type for network namespaces is 'network'.
// The kernel link is 'net'.
nsPath = fmt.Sprintf("/proc/%d/ns/%s", infraPid, "net")
} else {
nsPath = fmt.Sprintf("/proc/%d/ns/%s", infraPid, n.Type)
}
specgen.Config.Linux.Namespaces[i].Path = nsPath
break
}
}
}

// Update Sandbox Name
specgen.AddAnnotation(annotations.SandboxName, sbSpec.Annotations[annotations.Name])
// Update Sandbox ID
specgen.AddAnnotation(annotations.SandboxID, newSbID)

// Update Name
ctrMetadata := types.ContainerMetadata{}
err = json.Unmarshal([]byte(sbSpec.Annotations[annotations.Metadata]), &ctrMetadata)
if err != nil {
return err
}
ctrName := ctrMetadata.Name

podMetadata := types.PodSandboxMetadata{}
err = json.Unmarshal([]byte(specgen.Config.Annotations[annotations.Metadata]), &podMetadata)
if err != nil {
return err
}
uid := podMetadata.Uid
mData := fmt.Sprintf("k8s_%s_%s_%s_%s0", ctrName, sbSpec.Annotations[annotations.KubeName], sbSpec.Annotations[annotations.Namespace], uid)
specgen.AddAnnotation(annotations.Name, mData)

c.SetSandbox(newSbID)

saveOptions := generate.ExportOptions{}
if err := specgen.SaveToFile(configFile, saveOptions); err != nil {
return err
}
}

c.state.InitPid = 0
c.state.InitStartTime = ""

Expand All @@ -1639,7 +1565,7 @@ func (r *runtimeOCI) RestoreContainer(ctx context.Context, c *Container, sbSpec
if err := crutils.CRCreateFileWithLabel(
c.BundlePath(),
metadata.RestoreLogFile,
specgen.Config.Linux.MountLabel,
mountLabel,
); err != nil {
return err
}
Expand Down
5 changes: 2 additions & 3 deletions internal/oci/runtime_pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,10 @@ func (r *runtimePod) CheckpointContainer(
func (r *runtimePod) RestoreContainer(
ctx context.Context,
c *Container,
sbSpec *rspec.Spec,
infraPid int,
cgroupParent string,
mountLabel string,
) error {
return r.oci.RestoreContainer(ctx, c, sbSpec, infraPid, cgroupParent)
return r.oci.RestoreContainer(ctx, c, cgroupParent, mountLabel)
}

func (r *runtimePod) ExecContainer(ctx context.Context, c *Container, cmd []string, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resizeChan <-chan remotecommand.TerminalSize) error {
Expand Down
2 changes: 1 addition & 1 deletion internal/oci/runtime_vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -1050,7 +1050,7 @@ func (r *runtimeVM) CheckpointContainer(ctx context.Context, c *Container, specg
}

// RestoreContainer not implemented for runtimeVM
func (r *runtimeVM) RestoreContainer(ctx context.Context, c *Container, sbSpec *rspec.Spec, infraPid int, cgroupParent string) error {
func (r *runtimeVM) RestoreContainer(ctx context.Context, c *Container, cgroupParent, mountLabel string) error {
log.Debugf(ctx, "RuntimeVM.RestoreContainer() start")
defer log.Debugf(ctx, "RuntimeVM.RestoreContainer() end")

Expand Down
4 changes: 2 additions & 2 deletions internal/oci/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ const (
containerID = "containerID"
)

func beforeEach(sbID string) {
func beforeEach() {
var err error
myContainer, err = oci.NewContainer(containerID, "", "", "",
make(map[string]string), make(map[string]string),
make(map[string]string), "", "", "",
&types.ContainerMetadata{}, sbID, false,
&types.ContainerMetadata{}, sandboxID, false,
false, false, "", "", time.Now(), "")
Expect(err).To(BeNil())
}
Expand Down
Loading