mirror of
https://github.com/containers/podman.git
synced 2025-05-20 00:27:03 +08:00
fix remote checkpoint/restore
Nothing was working before, and it's too much to summarize. To make sure we're not regressing in the future again, enable the remote e2e tests. Fixes: #12007 Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
This commit is contained in:
@ -12,7 +12,6 @@ import (
|
|||||||
"github.com/containers/podman/v3/cmd/podman/validate"
|
"github.com/containers/podman/v3/cmd/podman/validate"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/rootless"
|
"github.com/containers/podman/v3/pkg/rootless"
|
||||||
"github.com/containers/podman/v3/pkg/specgenutil"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
@ -120,12 +119,7 @@ func restore(cmd *cobra.Command, args []string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(inputPorts) > 0 {
|
restoreOptions.PublishPorts = inputPorts
|
||||||
restoreOptions.PublishPorts, err = specgenutil.CreatePortBindings(inputPorts)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
argLen := len(args)
|
argLen := len(args)
|
||||||
if restoreOptions.Import != "" {
|
if restoreOptions.Import != "" {
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
package libpod
|
package libpod
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/libpod/define"
|
"github.com/containers/podman/v3/libpod/define"
|
||||||
@ -206,7 +208,9 @@ func ShowMountedContainers(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Checkpoint(w http.ResponseWriter, r *http.Request) {
|
func Checkpoint(w http.ResponseWriter, r *http.Request) {
|
||||||
var targetFile string
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
||||||
|
|
||||||
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
Keep bool `schema:"keep"`
|
Keep bool `schema:"keep"`
|
||||||
@ -224,66 +228,68 @@ func Checkpoint(w http.ResponseWriter, r *http.Request) {
|
|||||||
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
if _, err := runtime.LookupContainer(name); err != nil {
|
||||||
ctr, err := runtime.LookupContainer(name)
|
|
||||||
if err != nil {
|
|
||||||
utils.ContainerNotFound(w, name, err)
|
utils.ContainerNotFound(w, name, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if query.Export {
|
names := []string{name}
|
||||||
tmpFile, err := ioutil.TempFile("", "checkpoint")
|
|
||||||
if err != nil {
|
options := entities.CheckpointOptions{
|
||||||
utils.InternalServerError(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer os.Remove(tmpFile.Name())
|
|
||||||
if err := tmpFile.Close(); err != nil {
|
|
||||||
utils.InternalServerError(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
targetFile = tmpFile.Name()
|
|
||||||
}
|
|
||||||
options := libpod.ContainerCheckpointOptions{
|
|
||||||
Keep: query.Keep,
|
Keep: query.Keep,
|
||||||
KeepRunning: query.LeaveRunning,
|
LeaveRunning: query.LeaveRunning,
|
||||||
TCPEstablished: query.TCPEstablished,
|
TCPEstablished: query.TCPEstablished,
|
||||||
IgnoreRootfs: query.IgnoreRootFS,
|
IgnoreRootFS: query.IgnoreRootFS,
|
||||||
PrintStats: query.PrintStats,
|
PrintStats: query.PrintStats,
|
||||||
}
|
}
|
||||||
|
|
||||||
if query.Export {
|
if query.Export {
|
||||||
options.TargetFile = targetFile
|
f, err := ioutil.TempFile("", "checkpoint")
|
||||||
}
|
|
||||||
criuStatistics, runtimeCheckpointDuration, err := ctr.Checkpoint(r.Context(), options)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.InternalServerError(w, err)
|
utils.InternalServerError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if query.Export {
|
defer os.Remove(f.Name())
|
||||||
f, err := os.Open(targetFile)
|
if err := f.Close(); err != nil {
|
||||||
|
utils.InternalServerError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
options.Export = f.Name()
|
||||||
|
}
|
||||||
|
|
||||||
|
reports, err := containerEngine.ContainerCheckpoint(r.Context(), names, options)
|
||||||
|
if err != nil {
|
||||||
|
utils.InternalServerError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !query.Export {
|
||||||
|
if len(reports) != 1 {
|
||||||
|
utils.InternalServerError(w, fmt.Errorf("expected 1 restore report but got %d", len(reports)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if reports[0].Err != nil {
|
||||||
|
utils.InternalServerError(w, reports[0].Err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
utils.WriteResponse(w, http.StatusOK, reports[0])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Open(options.Export)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.InternalServerError(w, err)
|
utils.InternalServerError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
utils.WriteResponse(w, http.StatusOK, f)
|
utils.WriteResponse(w, http.StatusOK, f)
|
||||||
return
|
|
||||||
}
|
|
||||||
utils.WriteResponse(
|
|
||||||
w,
|
|
||||||
http.StatusOK,
|
|
||||||
entities.CheckpointReport{
|
|
||||||
Id: ctr.ID(),
|
|
||||||
RuntimeDuration: runtimeCheckpointDuration,
|
|
||||||
CRIUStatistics: criuStatistics,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Restore(w http.ResponseWriter, r *http.Request) {
|
func Restore(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
targetFile string
|
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
||||||
)
|
|
||||||
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
Keep bool `schema:"keep"`
|
Keep bool `schema:"keep"`
|
||||||
@ -295,6 +301,7 @@ func Restore(w http.ResponseWriter, r *http.Request) {
|
|||||||
IgnoreStaticIP bool `schema:"ignoreStaticIP"`
|
IgnoreStaticIP bool `schema:"ignoreStaticIP"`
|
||||||
IgnoreStaticMAC bool `schema:"ignoreStaticMAC"`
|
IgnoreStaticMAC bool `schema:"ignoreStaticMAC"`
|
||||||
PrintStats bool `schema:"printStats"`
|
PrintStats bool `schema:"printStats"`
|
||||||
|
PublishPorts string `schema:"publishPorts"`
|
||||||
}{
|
}{
|
||||||
// override any golang type defaults
|
// override any golang type defaults
|
||||||
}
|
}
|
||||||
@ -303,53 +310,55 @@ func Restore(w http.ResponseWriter, r *http.Request) {
|
|||||||
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
name := utils.GetName(r)
|
|
||||||
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
options := entities.RestoreOptions{
|
||||||
ctr, err := runtime.LookupContainer(name)
|
Name: query.Name,
|
||||||
if err != nil {
|
Keep: query.Keep,
|
||||||
utils.ContainerNotFound(w, name, err)
|
TCPEstablished: query.TCPEstablished,
|
||||||
return
|
IgnoreRootFS: query.IgnoreRootFS,
|
||||||
|
IgnoreVolumes: query.IgnoreVolumes,
|
||||||
|
IgnoreStaticIP: query.IgnoreStaticIP,
|
||||||
|
IgnoreStaticMAC: query.IgnoreStaticMAC,
|
||||||
|
PrintStats: query.PrintStats,
|
||||||
|
PublishPorts: strings.Fields(query.PublishPorts),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var names []string
|
||||||
if query.Import {
|
if query.Import {
|
||||||
t, err := ioutil.TempFile("", "restore")
|
t, err := ioutil.TempFile("", "restore")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.InternalServerError(w, err)
|
utils.InternalServerError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer t.Close()
|
defer os.Remove(t.Name())
|
||||||
if err := compat.SaveFromBody(t, r); err != nil {
|
if err := compat.SaveFromBody(t, r); err != nil {
|
||||||
utils.InternalServerError(w, err)
|
utils.InternalServerError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
targetFile = t.Name()
|
options.Import = t.Name()
|
||||||
|
} else {
|
||||||
|
name := utils.GetName(r)
|
||||||
|
if _, err := runtime.LookupContainer(name); err != nil {
|
||||||
|
utils.ContainerNotFound(w, name, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
names = []string{name}
|
||||||
}
|
}
|
||||||
|
|
||||||
options := libpod.ContainerCheckpointOptions{
|
reports, err := containerEngine.ContainerRestore(r.Context(), names, options)
|
||||||
Keep: query.Keep,
|
|
||||||
TCPEstablished: query.TCPEstablished,
|
|
||||||
IgnoreRootfs: query.IgnoreRootFS,
|
|
||||||
IgnoreStaticIP: query.IgnoreStaticIP,
|
|
||||||
IgnoreStaticMAC: query.IgnoreStaticMAC,
|
|
||||||
PrintStats: query.PrintStats,
|
|
||||||
}
|
|
||||||
if query.Import {
|
|
||||||
options.TargetFile = targetFile
|
|
||||||
options.Name = query.Name
|
|
||||||
}
|
|
||||||
criuStatistics, runtimeRestoreDuration, err := ctr.Restore(r.Context(), options)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.InternalServerError(w, err)
|
utils.InternalServerError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
utils.WriteResponse(
|
if len(reports) != 1 {
|
||||||
w,
|
utils.InternalServerError(w, fmt.Errorf("expected 1 restore report but got %d", len(reports)))
|
||||||
http.StatusOK,
|
return
|
||||||
entities.RestoreReport{
|
}
|
||||||
Id: ctr.ID(),
|
if reports[0].Err != nil {
|
||||||
RuntimeDuration: runtimeRestoreDuration,
|
utils.InternalServerError(w, reports[0].Err)
|
||||||
CRIUStatistics: criuStatistics,
|
return
|
||||||
},
|
}
|
||||||
)
|
utils.WriteResponse(w, http.StatusOK, reports[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitContainer(w http.ResponseWriter, r *http.Request) {
|
func InitContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -2,7 +2,9 @@ package containers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/containers/podman/v3/pkg/bindings"
|
"github.com/containers/podman/v3/pkg/bindings"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
@ -23,15 +25,36 @@ func Checkpoint(ctx context.Context, nameOrID string, options *CheckpointOptions
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// "export" is a bool for the server so override it in the parameters
|
||||||
|
// if set.
|
||||||
|
export := false
|
||||||
|
if options.Export != nil && *options.Export != "" {
|
||||||
|
export = true
|
||||||
|
params.Set("export", "true")
|
||||||
|
}
|
||||||
response, err := conn.DoRequest(ctx, nil, http.MethodPost, "/containers/%s/checkpoint", params, nil, nameOrID)
|
response, err := conn.DoRequest(ctx, nil, http.MethodPost, "/containers/%s/checkpoint", params, nil, nameOrID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
|
|
||||||
|
if !export {
|
||||||
return &report, response.Process(&report)
|
return &report, response.Process(&report)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f, err := os.OpenFile(*options.Export, os.O_RDWR|os.O_CREATE, 0600)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
if _, err := io.Copy(f, response.Body); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &entities.CheckpointReport{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Restore restores a checkpointed container to running. The container is identified by the nameOrID option. All
|
// Restore restores a checkpointed container to running. The container is identified by the nameOrID option. All
|
||||||
// additional options are optional and allow finer control of the restore process.
|
// additional options are optional and allow finer control of the restore process.
|
||||||
func Restore(ctx context.Context, nameOrID string, options *RestoreOptions) (*entities.RestoreReport, error) {
|
func Restore(ctx context.Context, nameOrID string, options *RestoreOptions) (*entities.RestoreReport, error) {
|
||||||
@ -47,12 +70,26 @@ func Restore(ctx context.Context, nameOrID string, options *RestoreOptions) (*en
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// The import key is a reserved golang term
|
|
||||||
params.Del("ImportArchive")
|
for _, p := range options.PublishPorts {
|
||||||
if i := options.GetImportAchive(); options.Changed("ImportArchive") {
|
params.Add("publishPorts", p)
|
||||||
params.Set("import", i)
|
|
||||||
}
|
}
|
||||||
response, err := conn.DoRequest(ctx, nil, http.MethodPost, "/containers/%s/restore", params, nil, nameOrID)
|
|
||||||
|
params.Del("ImportArchive") // The import key is a reserved golang term
|
||||||
|
|
||||||
|
// Open the to-be-imported archive if needed.
|
||||||
|
var r io.Reader
|
||||||
|
if i := options.GetImportAchive(); i != "" {
|
||||||
|
params.Set("import", "true")
|
||||||
|
r, err = os.Open(i)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Hard-code the name since it will be ignored in any case.
|
||||||
|
nameOrID = "import"
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := conn.DoRequest(ctx, r, http.MethodPost, "/containers/%s/restore", params, nil, nameOrID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -50,12 +50,14 @@ type CheckpointOptions struct {
|
|||||||
Keep *bool
|
Keep *bool
|
||||||
LeaveRunning *bool
|
LeaveRunning *bool
|
||||||
TCPEstablished *bool
|
TCPEstablished *bool
|
||||||
|
PrintStats *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:generate go run ../generator/generator.go RestoreOptions
|
//go:generate go run ../generator/generator.go RestoreOptions
|
||||||
// RestoreOptions are optional options for restoring containers
|
// RestoreOptions are optional options for restoring containers
|
||||||
type RestoreOptions struct {
|
type RestoreOptions struct {
|
||||||
IgnoreRootfs *bool
|
IgnoreRootfs *bool
|
||||||
|
IgnoreVolumes *bool
|
||||||
IgnoreStaticIP *bool
|
IgnoreStaticIP *bool
|
||||||
IgnoreStaticMAC *bool
|
IgnoreStaticMAC *bool
|
||||||
ImportAchive *string
|
ImportAchive *string
|
||||||
@ -63,6 +65,8 @@ type RestoreOptions struct {
|
|||||||
Name *string
|
Name *string
|
||||||
TCPEstablished *bool
|
TCPEstablished *bool
|
||||||
Pod *string
|
Pod *string
|
||||||
|
PrintStats *bool
|
||||||
|
PublishPorts []string
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:generate go run ../generator/generator.go CreateOptions
|
//go:generate go run ../generator/generator.go CreateOptions
|
||||||
@ -86,7 +90,8 @@ type ExecInspectOptions struct{}
|
|||||||
//go:generate go run ../generator/generator.go ExecStartOptions
|
//go:generate go run ../generator/generator.go ExecStartOptions
|
||||||
// ExecStartOptions are optional options for starting
|
// ExecStartOptions are optional options for starting
|
||||||
// exec sessions
|
// exec sessions
|
||||||
type ExecStartOptions struct{}
|
type ExecStartOptions struct {
|
||||||
|
}
|
||||||
|
|
||||||
//go:generate go run ../generator/generator.go HealthCheckOptions
|
//go:generate go run ../generator/generator.go HealthCheckOptions
|
||||||
// HealthCheckOptions are optional options for checking
|
// HealthCheckOptions are optional options for checking
|
||||||
|
@ -91,3 +91,18 @@ func (o *CheckpointOptions) GetTCPEstablished() bool {
|
|||||||
}
|
}
|
||||||
return *o.TCPEstablished
|
return *o.TCPEstablished
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithPrintStats set field PrintStats to given value
|
||||||
|
func (o *CheckpointOptions) WithPrintStats(value bool) *CheckpointOptions {
|
||||||
|
o.PrintStats = &value
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPrintStats returns value of field PrintStats
|
||||||
|
func (o *CheckpointOptions) GetPrintStats() bool {
|
||||||
|
if o.PrintStats == nil {
|
||||||
|
var z bool
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
return *o.PrintStats
|
||||||
|
}
|
||||||
|
@ -32,6 +32,21 @@ func (o *RestoreOptions) GetIgnoreRootfs() bool {
|
|||||||
return *o.IgnoreRootfs
|
return *o.IgnoreRootfs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithIgnoreVolumes set field IgnoreVolumes to given value
|
||||||
|
func (o *RestoreOptions) WithIgnoreVolumes(value bool) *RestoreOptions {
|
||||||
|
o.IgnoreVolumes = &value
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIgnoreVolumes returns value of field IgnoreVolumes
|
||||||
|
func (o *RestoreOptions) GetIgnoreVolumes() bool {
|
||||||
|
if o.IgnoreVolumes == nil {
|
||||||
|
var z bool
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
return *o.IgnoreVolumes
|
||||||
|
}
|
||||||
|
|
||||||
// WithIgnoreStaticIP set field IgnoreStaticIP to given value
|
// WithIgnoreStaticIP set field IgnoreStaticIP to given value
|
||||||
func (o *RestoreOptions) WithIgnoreStaticIP(value bool) *RestoreOptions {
|
func (o *RestoreOptions) WithIgnoreStaticIP(value bool) *RestoreOptions {
|
||||||
o.IgnoreStaticIP = &value
|
o.IgnoreStaticIP = &value
|
||||||
@ -136,3 +151,33 @@ func (o *RestoreOptions) GetPod() string {
|
|||||||
}
|
}
|
||||||
return *o.Pod
|
return *o.Pod
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithPrintStats set field PrintStats to given value
|
||||||
|
func (o *RestoreOptions) WithPrintStats(value bool) *RestoreOptions {
|
||||||
|
o.PrintStats = &value
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPrintStats returns value of field PrintStats
|
||||||
|
func (o *RestoreOptions) GetPrintStats() bool {
|
||||||
|
if o.PrintStats == nil {
|
||||||
|
var z bool
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
return *o.PrintStats
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithPublishPorts set field PublishPorts to given value
|
||||||
|
func (o *RestoreOptions) WithPublishPorts(value []string) *RestoreOptions {
|
||||||
|
o.PublishPorts = value
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPublishPorts returns value of field PublishPorts
|
||||||
|
func (o *RestoreOptions) GetPublishPorts() []string {
|
||||||
|
if o.PublishPorts == nil {
|
||||||
|
var z []string
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
return o.PublishPorts
|
||||||
|
}
|
||||||
|
@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/errorhandling"
|
"github.com/containers/podman/v3/pkg/errorhandling"
|
||||||
"github.com/containers/podman/v3/pkg/specgen/generate"
|
"github.com/containers/podman/v3/pkg/specgen/generate"
|
||||||
|
"github.com/containers/podman/v3/pkg/specgenutil"
|
||||||
"github.com/containers/storage/pkg/archive"
|
"github.com/containers/storage/pkg/archive"
|
||||||
spec "github.com/opencontainers/runtime-spec/specs-go"
|
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@ -195,7 +196,12 @@ func CRImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, restoreOpt
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(restoreOptions.PublishPorts) > 0 {
|
if len(restoreOptions.PublishPorts) > 0 {
|
||||||
ports, err := generate.ParsePortMapping(restoreOptions.PublishPorts, nil)
|
pubPorts, err := specgenutil.CreatePortBindings(restoreOptions.PublishPorts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ports, err := generate.ParsePortMapping(pubPorts, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -212,7 +212,7 @@ type RestoreOptions struct {
|
|||||||
Name string
|
Name string
|
||||||
TCPEstablished bool
|
TCPEstablished bool
|
||||||
ImportPrevious string
|
ImportPrevious string
|
||||||
PublishPorts []nettypes.PortMapping
|
PublishPorts []string
|
||||||
Pod string
|
Pod string
|
||||||
PrintStats bool
|
PrintStats bool
|
||||||
}
|
}
|
||||||
|
@ -302,6 +302,14 @@ func (ic *ContainerEngine) ContainerExport(ctx context.Context, nameOrID string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds []string, opts entities.CheckpointOptions) ([]*entities.CheckpointReport, error) {
|
func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds []string, opts entities.CheckpointOptions) ([]*entities.CheckpointReport, error) {
|
||||||
|
options := new(containers.CheckpointOptions)
|
||||||
|
options.WithIgnoreRootfs(opts.IgnoreRootFS)
|
||||||
|
options.WithKeep(opts.Keep)
|
||||||
|
options.WithExport(opts.Export)
|
||||||
|
options.WithTCPEstablished(opts.TCPEstablished)
|
||||||
|
options.WithPrintStats(opts.PrintStats)
|
||||||
|
options.WithLeaveRunning(opts.LeaveRunning)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
ctrs = []entities.ListContainer{}
|
ctrs = []entities.ListContainer{}
|
||||||
@ -325,19 +333,36 @@ func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds [
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
reports := make([]*entities.CheckpointReport, 0, len(ctrs))
|
reports := make([]*entities.CheckpointReport, 0, len(ctrs))
|
||||||
options := new(containers.CheckpointOptions).WithExport(opts.Export).WithIgnoreRootfs(opts.IgnoreRootFS).WithKeep(opts.Keep)
|
|
||||||
options.WithLeaveRunning(opts.LeaveRunning).WithTCPEstablished(opts.TCPEstablished)
|
|
||||||
for _, c := range ctrs {
|
for _, c := range ctrs {
|
||||||
report, err := containers.Checkpoint(ic.ClientCtx, c.ID, options)
|
report, err := containers.Checkpoint(ic.ClientCtx, c.ID, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
reports = append(reports, &entities.CheckpointReport{Id: c.ID, Err: err})
|
reports = append(reports, &entities.CheckpointReport{Id: c.ID, Err: err})
|
||||||
}
|
} else {
|
||||||
reports = append(reports, report)
|
reports = append(reports, report)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return reports, nil
|
return reports, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []string, opts entities.RestoreOptions) ([]*entities.RestoreReport, error) {
|
func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []string, opts entities.RestoreOptions) ([]*entities.RestoreReport, error) {
|
||||||
|
options := new(containers.RestoreOptions)
|
||||||
|
options.WithIgnoreRootfs(opts.IgnoreRootFS)
|
||||||
|
options.WithIgnoreVolumes(opts.IgnoreVolumes)
|
||||||
|
options.WithIgnoreStaticIP(opts.IgnoreStaticIP)
|
||||||
|
options.WithIgnoreStaticMAC(opts.IgnoreStaticMAC)
|
||||||
|
options.WithKeep(opts.Keep)
|
||||||
|
options.WithName(opts.Name)
|
||||||
|
options.WithTCPEstablished(opts.TCPEstablished)
|
||||||
|
options.WithPod(opts.Pod)
|
||||||
|
options.WithPrintStats(opts.PrintStats)
|
||||||
|
options.WithPublishPorts(opts.PublishPorts)
|
||||||
|
|
||||||
|
if opts.Import != "" {
|
||||||
|
options.WithImportAchive(opts.Import)
|
||||||
|
report, err := containers.Restore(ic.ClientCtx, "", options)
|
||||||
|
return []*entities.RestoreReport{report}, err
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
ctrs = []entities.ListContainer{}
|
ctrs = []entities.ListContainer{}
|
||||||
@ -360,7 +385,6 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
reports := make([]*entities.RestoreReport, 0, len(ctrs))
|
reports := make([]*entities.RestoreReport, 0, len(ctrs))
|
||||||
options := new(containers.RestoreOptions)
|
|
||||||
for _, c := range ctrs {
|
for _, c := range ctrs {
|
||||||
report, err := containers.Restore(ic.ClientCtx, c.ID, options)
|
report, err := containers.Restore(ic.ClientCtx, c.ID, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -35,7 +35,6 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
SkipIfRemote("checkpoint not supported in remote mode")
|
|
||||||
SkipIfRootless("checkpoint not supported in rootless mode")
|
SkipIfRootless("checkpoint not supported in rootless mode")
|
||||||
tempdir, err = CreateTempDirInTempDir()
|
tempdir, err = CreateTempDirInTempDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -183,7 +182,7 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
session2.WaitWithDefaultTimeout()
|
session2.WaitWithDefaultTimeout()
|
||||||
Expect(session2).Should(Exit(0))
|
Expect(session2).Should(Exit(0))
|
||||||
|
|
||||||
result := podmanTest.Podman([]string{"container", "checkpoint", "-l"})
|
result := podmanTest.Podman([]string{"container", "checkpoint", "second"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
|
|
||||||
Expect(result).Should(Exit(0))
|
Expect(result).Should(Exit(0))
|
||||||
@ -195,7 +194,7 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
Expect(ps.LineInOutputContains(session1.OutputToString())).To(BeTrue())
|
Expect(ps.LineInOutputContains(session1.OutputToString())).To(BeTrue())
|
||||||
Expect(ps.LineInOutputContains(session2.OutputToString())).To(BeFalse())
|
Expect(ps.LineInOutputContains(session2.OutputToString())).To(BeFalse())
|
||||||
|
|
||||||
result = podmanTest.Podman([]string{"container", "restore", "-l"})
|
result = podmanTest.Podman([]string{"container", "restore", "second"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
|
|
||||||
Expect(result).Should(Exit(0))
|
Expect(result).Should(Exit(0))
|
||||||
@ -258,7 +257,7 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
Fail("Container failed to get ready")
|
Fail("Container failed to get ready")
|
||||||
}
|
}
|
||||||
|
|
||||||
IP := podmanTest.Podman([]string{"inspect", "-l", "--format={{.NetworkSettings.IPAddress}}"})
|
IP := podmanTest.Podman([]string{"inspect", cid, "--format={{.NetworkSettings.IPAddress}}"})
|
||||||
IP.WaitWithDefaultTimeout()
|
IP.WaitWithDefaultTimeout()
|
||||||
Expect(IP).Should(Exit(0))
|
Expect(IP).Should(Exit(0))
|
||||||
|
|
||||||
@ -267,7 +266,7 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
|
|
||||||
// This should fail as the container has established TCP connections
|
// This should fail as the container has established TCP connections
|
||||||
result := podmanTest.Podman([]string{"container", "checkpoint", "-l"})
|
result := podmanTest.Podman([]string{"container", "checkpoint", cid})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
|
|
||||||
Expect(result).Should(Exit(125))
|
Expect(result).Should(Exit(125))
|
||||||
@ -275,7 +274,7 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
|
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
|
||||||
|
|
||||||
// Now it should work thanks to "--tcp-established"
|
// Now it should work thanks to "--tcp-established"
|
||||||
result = podmanTest.Podman([]string{"container", "checkpoint", "-l", "--tcp-established"})
|
result = podmanTest.Podman([]string{"container", "checkpoint", cid, "--tcp-established"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
|
|
||||||
Expect(result).Should(Exit(0))
|
Expect(result).Should(Exit(0))
|
||||||
@ -283,7 +282,7 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited"))
|
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited"))
|
||||||
|
|
||||||
// Restore should fail as the checkpoint image contains established TCP connections
|
// Restore should fail as the checkpoint image contains established TCP connections
|
||||||
result = podmanTest.Podman([]string{"container", "restore", "-l"})
|
result = podmanTest.Podman([]string{"container", "restore", cid})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
|
|
||||||
Expect(result).Should(Exit(125))
|
Expect(result).Should(Exit(125))
|
||||||
@ -291,7 +290,7 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited"))
|
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited"))
|
||||||
|
|
||||||
// Now it should work thanks to "--tcp-established"
|
// Now it should work thanks to "--tcp-established"
|
||||||
result = podmanTest.Podman([]string{"container", "restore", "-l", "--tcp-established"})
|
result = podmanTest.Podman([]string{"container", "restore", cid, "--tcp-established"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
|
|
||||||
Expect(result).Should(Exit(0))
|
Expect(result).Should(Exit(0))
|
||||||
@ -350,11 +349,11 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(session).Should(Exit(0))
|
Expect(session).Should(Exit(0))
|
||||||
|
|
||||||
IPBefore := podmanTest.Podman([]string{"inspect", "-l", "--format={{.NetworkSettings.IPAddress}}"})
|
IPBefore := podmanTest.Podman([]string{"inspect", "test_name", "--format={{.NetworkSettings.IPAddress}}"})
|
||||||
IPBefore.WaitWithDefaultTimeout()
|
IPBefore.WaitWithDefaultTimeout()
|
||||||
Expect(IPBefore).Should(Exit(0))
|
Expect(IPBefore).Should(Exit(0))
|
||||||
|
|
||||||
MACBefore := podmanTest.Podman([]string{"inspect", "-l", "--format={{.NetworkSettings.MacAddress}}"})
|
MACBefore := podmanTest.Podman([]string{"inspect", "test_name", "--format={{.NetworkSettings.MacAddress}}"})
|
||||||
MACBefore.WaitWithDefaultTimeout()
|
MACBefore.WaitWithDefaultTimeout()
|
||||||
Expect(MACBefore).Should(Exit(0))
|
Expect(MACBefore).Should(Exit(0))
|
||||||
|
|
||||||
@ -368,11 +367,11 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
result = podmanTest.Podman([]string{"container", "restore", "test_name"})
|
result = podmanTest.Podman([]string{"container", "restore", "test_name"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
|
|
||||||
IPAfter := podmanTest.Podman([]string{"inspect", "-l", "--format={{.NetworkSettings.IPAddress}}"})
|
IPAfter := podmanTest.Podman([]string{"inspect", "test_name", "--format={{.NetworkSettings.IPAddress}}"})
|
||||||
IPAfter.WaitWithDefaultTimeout()
|
IPAfter.WaitWithDefaultTimeout()
|
||||||
Expect(IPAfter).Should(Exit(0))
|
Expect(IPAfter).Should(Exit(0))
|
||||||
|
|
||||||
MACAfter := podmanTest.Podman([]string{"inspect", "-l", "--format={{.NetworkSettings.MacAddress}}"})
|
MACAfter := podmanTest.Podman([]string{"inspect", "test_name", "--format={{.NetworkSettings.MacAddress}}"})
|
||||||
MACAfter.WaitWithDefaultTimeout()
|
MACAfter.WaitWithDefaultTimeout()
|
||||||
Expect(MACAfter).Should(Exit(0))
|
Expect(MACAfter).Should(Exit(0))
|
||||||
|
|
||||||
@ -403,7 +402,7 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
cid := session.OutputToString()
|
cid := session.OutputToString()
|
||||||
fileName := "/tmp/checkpoint-" + cid + ".tar.gz"
|
fileName := "/tmp/checkpoint-" + cid + ".tar.gz"
|
||||||
|
|
||||||
result := podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", fileName})
|
result := podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", fileName})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
|
|
||||||
// As the container has been started with '--rm' it will be completely
|
// As the container has been started with '--rm' it will be completely
|
||||||
@ -455,7 +454,7 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
fileName := "/tmp/checkpoint-" + cid + ".tar"
|
fileName := "/tmp/checkpoint-" + cid + ".tar"
|
||||||
|
|
||||||
// Checkpoint with the default algorithm
|
// Checkpoint with the default algorithm
|
||||||
result := podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", fileName})
|
result := podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", fileName})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
|
|
||||||
// As the container has been started with '--rm' it will be completely
|
// As the container has been started with '--rm' it will be completely
|
||||||
@ -473,7 +472,7 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
|
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
|
||||||
|
|
||||||
// Checkpoint with the zstd algorithm
|
// Checkpoint with the zstd algorithm
|
||||||
result = podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", fileName, "--compress", "zstd"})
|
result = podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", fileName, "--compress", "zstd"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
|
|
||||||
// As the container has been started with '--rm' it will be completely
|
// As the container has been started with '--rm' it will be completely
|
||||||
@ -491,7 +490,7 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
|
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
|
||||||
|
|
||||||
// Checkpoint with the none algorithm
|
// Checkpoint with the none algorithm
|
||||||
result = podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", fileName, "-c", "none"})
|
result = podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", fileName, "-c", "none"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
|
|
||||||
// As the container has been started with '--rm' it will be completely
|
// As the container has been started with '--rm' it will be completely
|
||||||
@ -509,7 +508,7 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
|
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
|
||||||
|
|
||||||
// Checkpoint with the gzip algorithm
|
// Checkpoint with the gzip algorithm
|
||||||
result = podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", fileName, "-c", "gzip"})
|
result = podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", fileName, "-c", "gzip"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
|
|
||||||
// As the container has been started with '--rm' it will be completely
|
// As the container has been started with '--rm' it will be completely
|
||||||
@ -527,7 +526,7 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
|
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
|
||||||
|
|
||||||
// Checkpoint with the non-existing algorithm
|
// Checkpoint with the non-existing algorithm
|
||||||
result = podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", fileName, "-c", "non-existing"})
|
result = podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", fileName, "-c", "non-existing"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
|
|
||||||
Expect(result).Should(Exit(125))
|
Expect(result).Should(Exit(125))
|
||||||
@ -555,15 +554,15 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
fileName := "/tmp/checkpoint-" + cid + ".tar.gz"
|
fileName := "/tmp/checkpoint-" + cid + ".tar.gz"
|
||||||
|
|
||||||
// Change the container's root file-system
|
// Change the container's root file-system
|
||||||
result := podmanTest.Podman([]string{"exec", "-l", "/bin/sh", "-c", "echo test" + cid + "test > /test.output"})
|
result := podmanTest.Podman([]string{"exec", cid, "/bin/sh", "-c", "echo test" + cid + "test > /test.output"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(result).Should(Exit(0))
|
Expect(result).Should(Exit(0))
|
||||||
|
|
||||||
result = podmanTest.Podman([]string{"exec", "-l", "/bin/sh", "-c", "rm /etc/motd"})
|
result = podmanTest.Podman([]string{"exec", cid, "/bin/sh", "-c", "rm /etc/motd"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(result).Should(Exit(0))
|
Expect(result).Should(Exit(0))
|
||||||
|
|
||||||
result = podmanTest.Podman([]string{"diff", "-l"})
|
result = podmanTest.Podman([]string{"diff", cid})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(result).Should(Exit(0))
|
Expect(result).Should(Exit(0))
|
||||||
Expect(result.OutputToString()).To(ContainSubstring("C /etc"))
|
Expect(result.OutputToString()).To(ContainSubstring("C /etc"))
|
||||||
@ -572,7 +571,7 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
Expect(len(result.OutputToStringArray())).To(Equal(3))
|
Expect(len(result.OutputToStringArray())).To(Equal(3))
|
||||||
|
|
||||||
// Checkpoint the container
|
// Checkpoint the container
|
||||||
result = podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", fileName})
|
result = podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", fileName})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
|
|
||||||
Expect(result).Should(Exit(0))
|
Expect(result).Should(Exit(0))
|
||||||
@ -589,12 +588,12 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
|
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
|
||||||
|
|
||||||
// Verify the changes to the container's root file-system
|
// Verify the changes to the container's root file-system
|
||||||
result = podmanTest.Podman([]string{"exec", "-l", "cat", "/test.output"})
|
result = podmanTest.Podman([]string{"exec", cid, "cat", "/test.output"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(result).Should(Exit(0))
|
Expect(result).Should(Exit(0))
|
||||||
Expect(result.OutputToString()).To(ContainSubstring("test" + cid + "test"))
|
Expect(result.OutputToString()).To(ContainSubstring("test" + cid + "test"))
|
||||||
|
|
||||||
result = podmanTest.Podman([]string{"diff", "-l"})
|
result = podmanTest.Podman([]string{"diff", cid})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(result).Should(Exit(0))
|
Expect(result).Should(Exit(0))
|
||||||
Expect(result.OutputToString()).To(ContainSubstring("C /etc"))
|
Expect(result.OutputToString()).To(ContainSubstring("C /etc"))
|
||||||
@ -616,12 +615,12 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
fileName := "/tmp/checkpoint-" + cid + ".tar.gz"
|
fileName := "/tmp/checkpoint-" + cid + ".tar.gz"
|
||||||
|
|
||||||
// Change the container's root file-system
|
// Change the container's root file-system
|
||||||
result := podmanTest.Podman([]string{"exec", "-l", "/bin/sh", "-c", "echo test" + cid + "test > /test.output"})
|
result := podmanTest.Podman([]string{"exec", cid, "/bin/sh", "-c", "echo test" + cid + "test > /test.output"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(result).Should(Exit(0))
|
Expect(result).Should(Exit(0))
|
||||||
|
|
||||||
// Checkpoint the container
|
// Checkpoint the container
|
||||||
result = podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", fileName})
|
result = podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", fileName})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
|
|
||||||
Expect(result).Should(Exit(0))
|
Expect(result).Should(Exit(0))
|
||||||
@ -638,7 +637,7 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
|
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
|
||||||
|
|
||||||
// Verify the changes to the container's root file-system
|
// Verify the changes to the container's root file-system
|
||||||
result = podmanTest.Podman([]string{"exec", "-l", "cat", "/test.output"})
|
result = podmanTest.Podman([]string{"exec", cid, "cat", "/test.output"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(result).Should(Exit(1))
|
Expect(result).Should(Exit(1))
|
||||||
Expect(result.ErrorToString()).To(ContainSubstring("cat: can't open '/test.output': No such file or directory"))
|
Expect(result.ErrorToString()).To(ContainSubstring("cat: can't open '/test.output': No such file or directory"))
|
||||||
@ -657,12 +656,12 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
fileName := "/tmp/checkpoint-" + cid + ".tar.gz"
|
fileName := "/tmp/checkpoint-" + cid + ".tar.gz"
|
||||||
|
|
||||||
// Change the container's root file-system
|
// Change the container's root file-system
|
||||||
result := podmanTest.Podman([]string{"exec", "-l", "/bin/sh", "-c", "echo test" + cid + "test > /test.output"})
|
result := podmanTest.Podman([]string{"exec", cid, "/bin/sh", "-c", "echo test" + cid + "test > /test.output"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(result).Should(Exit(0))
|
Expect(result).Should(Exit(0))
|
||||||
|
|
||||||
// Checkpoint the container
|
// Checkpoint the container
|
||||||
result = podmanTest.Podman([]string{"container", "checkpoint", "--ignore-rootfs", "-l", "-e", fileName})
|
result = podmanTest.Podman([]string{"container", "checkpoint", "--ignore-rootfs", cid, "-e", fileName})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
|
|
||||||
Expect(result).Should(Exit(0))
|
Expect(result).Should(Exit(0))
|
||||||
@ -679,7 +678,7 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
|
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
|
||||||
|
|
||||||
// Verify the changes to the container's root file-system
|
// Verify the changes to the container's root file-system
|
||||||
result = podmanTest.Podman([]string{"exec", "-l", "cat", "/test.output"})
|
result = podmanTest.Podman([]string{"exec", cid, "cat", "/test.output"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(result).Should(Exit(1))
|
Expect(result).Should(Exit(1))
|
||||||
Expect(result.ErrorToString()).To(ContainSubstring("cat: can't open '/test.output': No such file or directory"))
|
Expect(result.ErrorToString()).To(ContainSubstring("cat: can't open '/test.output': No such file or directory"))
|
||||||
@ -699,7 +698,7 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
fileName := "/tmp/checkpoint-" + cid + ".tar.gz"
|
fileName := "/tmp/checkpoint-" + cid + ".tar.gz"
|
||||||
|
|
||||||
// Checkpoint the container
|
// Checkpoint the container
|
||||||
result := podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", fileName})
|
result := podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", fileName})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
|
|
||||||
Expect(result).Should(Exit(0))
|
Expect(result).Should(Exit(0))
|
||||||
@ -716,11 +715,11 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
|
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
|
||||||
|
|
||||||
// Exec in the container
|
// Exec in the container
|
||||||
result = podmanTest.Podman([]string{"exec", "-l", "/bin/sh", "-c", "echo " + cid + " > /test.output"})
|
result = podmanTest.Podman([]string{"exec", cid, "/bin/sh", "-c", "echo " + cid + " > /test.output"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(result).Should(Exit(0))
|
Expect(result).Should(Exit(0))
|
||||||
|
|
||||||
result = podmanTest.Podman([]string{"exec", "-l", "cat", "/test.output"})
|
result = podmanTest.Podman([]string{"exec", cid, "cat", "/test.output"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(result).Should(Exit(0))
|
Expect(result).Should(Exit(0))
|
||||||
Expect(result.OutputToString()).To(ContainSubstring(cid))
|
Expect(result.OutputToString()).To(ContainSubstring(cid))
|
||||||
@ -738,7 +737,7 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
|
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
|
||||||
|
|
||||||
// Checkpoint the container - this should fail as it was started with --rm
|
// Checkpoint the container - this should fail as it was started with --rm
|
||||||
result := podmanTest.Podman([]string{"container", "checkpoint", "-l"})
|
result := podmanTest.Podman([]string{"container", "checkpoint", cid})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(result).To(ExitWithError())
|
Expect(result).To(ExitWithError())
|
||||||
Expect(result.ErrorToString()).To(ContainSubstring("cannot checkpoint containers that have been started with '--rm'"))
|
Expect(result.ErrorToString()).To(ContainSubstring("cannot checkpoint containers that have been started with '--rm'"))
|
||||||
@ -746,7 +745,7 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
// Checkpointing with --export should still work
|
// Checkpointing with --export should still work
|
||||||
fileName := "/tmp/checkpoint-" + cid + ".tar.gz"
|
fileName := "/tmp/checkpoint-" + cid + ".tar.gz"
|
||||||
|
|
||||||
result = podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", fileName})
|
result = podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", fileName})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
|
|
||||||
// As the container has been started with '--rm' it will be completely
|
// As the container has been started with '--rm' it will be completely
|
||||||
@ -796,21 +795,21 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
|
|
||||||
// Add file in volume0
|
// Add file in volume0
|
||||||
result := podmanTest.Podman([]string{
|
result := podmanTest.Podman([]string{
|
||||||
"exec", "-l", "/bin/sh", "-c", "echo " + cid + " > /volume0/test.output",
|
"exec", cid, "/bin/sh", "-c", "echo " + cid + " > /volume0/test.output",
|
||||||
})
|
})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(result).Should(Exit(0))
|
Expect(result).Should(Exit(0))
|
||||||
|
|
||||||
// Add file in volume1
|
// Add file in volume1
|
||||||
result = podmanTest.Podman([]string{
|
result = podmanTest.Podman([]string{
|
||||||
"exec", "-l", "/bin/sh", "-c", "echo " + cid + " > /volume1/test.output",
|
"exec", cid, "/bin/sh", "-c", "echo " + cid + " > /volume1/test.output",
|
||||||
})
|
})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(result).Should(Exit(0))
|
Expect(result).Should(Exit(0))
|
||||||
|
|
||||||
// Add file in volume2
|
// Add file in volume2
|
||||||
result = podmanTest.Podman([]string{
|
result = podmanTest.Podman([]string{
|
||||||
"exec", "-l", "/bin/sh", "-c", "echo " + cid + " > /volume2/test.output",
|
"exec", cid, "/bin/sh", "-c", "echo " + cid + " > /volume2/test.output",
|
||||||
})
|
})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(result).Should(Exit(0))
|
Expect(result).Should(Exit(0))
|
||||||
@ -818,7 +817,7 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
checkpointFileName := "/tmp/checkpoint-" + cid + ".tar.gz"
|
checkpointFileName := "/tmp/checkpoint-" + cid + ".tar.gz"
|
||||||
|
|
||||||
// Checkpoint the container
|
// Checkpoint the container
|
||||||
result = podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", checkpointFileName})
|
result = podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", checkpointFileName})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(result).Should(Exit(0))
|
Expect(result).Should(Exit(0))
|
||||||
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
|
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
|
||||||
@ -846,19 +845,19 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
|
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
|
||||||
|
|
||||||
// Validate volume0 content
|
// Validate volume0 content
|
||||||
result = podmanTest.Podman([]string{"exec", "-l", "cat", "/volume0/test.output"})
|
result = podmanTest.Podman([]string{"exec", cid, "cat", "/volume0/test.output"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(result).Should(Exit(0))
|
Expect(result).Should(Exit(0))
|
||||||
Expect(result.OutputToString()).To(ContainSubstring(cid))
|
Expect(result.OutputToString()).To(ContainSubstring(cid))
|
||||||
|
|
||||||
// Validate volume1 content
|
// Validate volume1 content
|
||||||
result = podmanTest.Podman([]string{"exec", "-l", "cat", "/volume1/test.output"})
|
result = podmanTest.Podman([]string{"exec", cid, "cat", "/volume1/test.output"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(result).Should(Exit(0))
|
Expect(result).Should(Exit(0))
|
||||||
Expect(result.OutputToString()).To(ContainSubstring(cid))
|
Expect(result.OutputToString()).To(ContainSubstring(cid))
|
||||||
|
|
||||||
// Validate volume2 content
|
// Validate volume2 content
|
||||||
result = podmanTest.Podman([]string{"exec", "-l", "cat", "/volume2/test.output"})
|
result = podmanTest.Podman([]string{"exec", cid, "cat", "/volume2/test.output"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(result).Should(Exit(0))
|
Expect(result).Should(Exit(0))
|
||||||
Expect(result.OutputToString()).To(ContainSubstring(cid))
|
Expect(result.OutputToString()).To(ContainSubstring(cid))
|
||||||
@ -962,7 +961,7 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
conn.Close()
|
conn.Close()
|
||||||
|
|
||||||
// Checkpoint the container
|
// Checkpoint the container
|
||||||
result := podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", fileName})
|
result := podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", fileName})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
|
|
||||||
// As the container has been started with '--rm' it will be completely
|
// As the container has been started with '--rm' it will be completely
|
||||||
@ -984,6 +983,7 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
// Open a network connection to the redis server via initial port mapping
|
// Open a network connection to the redis server via initial port mapping
|
||||||
// This should fail
|
// This should fail
|
||||||
conn, err = net.DialTimeout("tcp4", fmt.Sprintf("localhost:%d", randomPort), time.Duration(3)*time.Second)
|
conn, err = net.DialTimeout("tcp4", fmt.Sprintf("localhost:%d", randomPort), time.Duration(3)*time.Second)
|
||||||
|
Expect(err).ToNot(BeNil())
|
||||||
Expect(err.Error()).To(ContainSubstring("connection refused"))
|
Expect(err.Error()).To(ContainSubstring("connection refused"))
|
||||||
// Open a network connection to the redis server via new port mapping
|
// Open a network connection to the redis server via new port mapping
|
||||||
fmt.Fprintf(os.Stderr, "Trying to reconnect to redis server at localhost:%d", newRandomPort)
|
fmt.Fprintf(os.Stderr, "Trying to reconnect to redis server at localhost:%d", newRandomPort)
|
||||||
@ -1023,7 +1023,7 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
Skip("CRIU is missing or too old.")
|
Skip("CRIU is missing or too old.")
|
||||||
}
|
}
|
||||||
if !crutils.CRRuntimeSupportsPodCheckpointRestore(podmanTest.OCIRuntime) {
|
if !crutils.CRRuntimeSupportsPodCheckpointRestore(podmanTest.OCIRuntime) {
|
||||||
Skip("runtime does not support pod restore")
|
Skip("runtime does not support pod restore: " + podmanTest.OCIRuntime)
|
||||||
}
|
}
|
||||||
// Create a pod
|
// Create a pod
|
||||||
session := podmanTest.Podman([]string{
|
session := podmanTest.Podman([]string{
|
||||||
@ -1170,7 +1170,7 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
cid := session.OutputToString()
|
cid := session.OutputToString()
|
||||||
fileName := "/tmp/checkpoint-" + cid + ".tar.gz"
|
fileName := "/tmp/checkpoint-" + cid + ".tar.gz"
|
||||||
|
|
||||||
result := podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", fileName})
|
result := podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", fileName})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
|
|
||||||
// As the container has been started with '--rm' it will be completely
|
// As the container has been started with '--rm' it will be completely
|
||||||
@ -1212,7 +1212,7 @@ var _ = Describe("Podman checkpoint", func() {
|
|||||||
result := podmanTest.Podman([]string{
|
result := podmanTest.Podman([]string{
|
||||||
"container",
|
"container",
|
||||||
"checkpoint",
|
"checkpoint",
|
||||||
"-l", "-e",
|
cid, "-e",
|
||||||
fileName,
|
fileName,
|
||||||
})
|
})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
|
Reference in New Issue
Block a user