Enable 'podman run' for checkpoint images

This patch extends the podman run command with support for checkpoint
images. When `podman run` is invoked with an image that contains
a checkpoint, it would restore the container from that checkpoint.

Example:
    podman run -d --name looper busybox /bin/sh -c \
	    'i=0; while true; do echo $i; i=$(expr $i + 1); sleep 1; done'

    podman container checkpoint --create-image checkpoint-image-1 looper

    podman run checkpoint-image-1

Signed-off-by: Radostin Stoyanov <radostin@redhat.com>
This commit is contained in:
Radostin Stoyanov
2022-11-20 20:48:38 +00:00
parent 3a362462c1
commit f4401567cd
2 changed files with 64 additions and 0 deletions

View File

@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"os"
"reflect"
"strconv"
"sync"
"time"
@ -1110,6 +1111,44 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
fmt.Fprintf(os.Stderr, "%s\n", w)
}
if opts.Spec != nil && !reflect.ValueOf(opts.Spec).IsNil() {
// If this is a checkpoint image, restore it.
img, resolvedImageName := opts.Spec.GetImage()
if img != nil && resolvedImageName != "" {
imgData, err := img.Inspect(ctx, nil)
if err != nil {
return nil, err
}
if imgData != nil {
_, isCheckpointImage := imgData.Annotations[define.CheckpointAnnotationRuntimeName]
if isCheckpointImage {
var restoreOptions entities.RestoreOptions
restoreOptions.Name = opts.Spec.Name
restoreOptions.Pod = opts.Spec.Pod
responses, err := ic.ContainerRestore(ctx, []string{resolvedImageName}, restoreOptions)
if err != nil {
return nil, err
}
report := entities.ContainerRunReport{}
for _, r := range responses {
report.Id = r.Id
report.ExitCode = 0
if r.Err != nil {
logrus.Errorf("Failed to restore checkpoint image %s: %v", resolvedImageName, r.Err)
report.ExitCode = 126
}
if r.RawInput != "" {
logrus.Errorf("Failed to restore checkpoint image %s: %v", resolvedImageName, r.RawInput)
report.ExitCode = 126
}
}
return &report, nil
}
}
}
}
rtSpec, spec, optsN, err := generate.MakeContainer(ctx, ic.Libpod, opts.Spec, false, nil)
if err != nil {
return nil, err

View File

@ -6,6 +6,7 @@ import (
"fmt"
"io"
"os"
"reflect"
"strconv"
"strings"
"sync"
@ -790,6 +791,30 @@ func (ic *ContainerEngine) ContainerListExternal(ctx context.Context) ([]entitie
}
func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.ContainerRunOptions) (*entities.ContainerRunReport, error) {
if opts.Spec != nil && !reflect.ValueOf(opts.Spec).IsNil() && opts.Spec.RawImageName != "" {
// If this is a checkpoint image, restore it.
getImageOptions := new(images.GetOptions).WithSize(false)
inspectReport, err := images.GetImage(ic.ClientCtx, opts.Spec.RawImageName, getImageOptions)
if err != nil {
return nil, fmt.Errorf("no such container or image: %s", opts.Spec.RawImageName)
}
if inspectReport != nil {
_, isCheckpointImage := inspectReport.Annotations[define.CheckpointAnnotationRuntimeName]
if isCheckpointImage {
restoreOptions := new(containers.RestoreOptions)
restoreOptions.WithName(opts.Spec.Name)
restoreOptions.WithPod(opts.Spec.Pod)
restoreReport, err := containers.Restore(ic.ClientCtx, inspectReport.ID, restoreOptions)
if err != nil {
return nil, err
}
runReport := entities.ContainerRunReport{Id: restoreReport.Id}
return &runReport, nil
}
}
}
con, err := containers.CreateWithSpec(ic.ClientCtx, opts.Spec, nil)
if err != nil {
return nil, err