From 0592558289c354447d28903910f4165ac5acd71a Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 21 Nov 2018 13:09:17 +0000 Subject: Use also a struct to pass options to Restore() This is basically the same change as ff47a4c2d5485fc49f937f3ce0c4e2fd6bdb1956 (Use a struct to pass options to Checkpoint()) just for the Restore() function. It is used to pass multiple restore options to the API and down to conmon which is used to restore containers. This is for the upcoming changes to support checkpointing and restoring containers with '--tcp-established'. Signed-off-by: Adrian Reber --- libpod/container_api.go | 6 +++--- libpod/container_internal.go | 2 +- libpod/container_internal_linux.go | 6 +++--- libpod/oci.go | 4 ++-- libpod/oci_linux.go | 6 +++--- libpod/oci_unsupported.go | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) (limited to 'libpod') diff --git a/libpod/container_api.go b/libpod/container_api.go index df6b6e962..396f06c20 100644 --- a/libpod/container_api.go +++ b/libpod/container_api.go @@ -831,7 +831,7 @@ func (c *Container) Refresh(ctx context.Context) error { } // ContainerCheckpointOptions is a struct used to pass the parameters -// for checkpointing to corresponding functions +// for checkpointing (and restoring) to the corresponding functions type ContainerCheckpointOptions struct { Keep bool KeepRunning bool @@ -853,7 +853,7 @@ func (c *Container) Checkpoint(ctx context.Context, options ContainerCheckpointO } // Restore restores a container -func (c *Container) Restore(ctx context.Context, keep bool) (err error) { +func (c *Container) Restore(ctx context.Context, options ContainerCheckpointOptions) (err error) { logrus.Debugf("Trying to restore container %s", c) if !c.batched { c.lock.Lock() @@ -864,5 +864,5 @@ func (c *Container) Restore(ctx context.Context, keep bool) (err error) { } } - return c.restore(ctx, keep) + return c.restore(ctx, options) } diff --git a/libpod/container_internal.go b/libpod/container_internal.go index 051e0aeb7..da0456554 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -606,7 +606,7 @@ func (c *Container) init(ctx context.Context) error { } // With the spec complete, do an OCI create - if err := c.runtime.ociRuntime.createContainer(c, c.config.CgroupParent, false); err != nil { + if err := c.runtime.ociRuntime.createContainer(c, c.config.CgroupParent, nil); err != nil { return err } diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index ffb82cc94..99f8652df 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -514,7 +514,7 @@ func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointO return c.save() } -func (c *Container) restore(ctx context.Context, keep bool) (err error) { +func (c *Container) restore(ctx context.Context, options ContainerCheckpointOptions) (err error) { if !criu.CheckForCriu() { return errors.Errorf("restoring a container requires at least CRIU %d", criu.MinCriuVersion) @@ -602,7 +602,7 @@ func (c *Container) restore(ctx context.Context, keep bool) (err error) { // Cleanup for a working restore. c.removeConmonFiles() - if err := c.runtime.ociRuntime.createContainer(c, c.config.CgroupParent, true); err != nil { + if err := c.runtime.ociRuntime.createContainer(c, c.config.CgroupParent, &options); err != nil { return err } @@ -610,7 +610,7 @@ func (c *Container) restore(ctx context.Context, keep bool) (err error) { c.state.State = ContainerStateRunning - if !keep { + if !options.Keep { // Delete all checkpoint related files. At this point, in theory, all files // should exist. Still ignoring errors for now as the container should be // restored and running. Not erroring out just because some cleanup operation diff --git a/libpod/oci.go b/libpod/oci.go index a7aec06e5..6aedc5662 100644 --- a/libpod/oci.go +++ b/libpod/oci.go @@ -227,7 +227,7 @@ func bindPorts(ports []ocicni.PortMapping) ([]*os.File, error) { return files, nil } -func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string, restoreContainer bool) (err error) { +func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string, restoreOptions *ContainerCheckpointOptions) (err error) { var stderrBuf bytes.Buffer runtimeDir, err := util.GetRootlessRuntimeDir() @@ -289,7 +289,7 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string, res args = append(args, "--syslog") } - if restoreContainer { + if restoreOptions != nil { args = append(args, "--restore", ctr.CheckpointPath()) } diff --git a/libpod/oci_linux.go b/libpod/oci_linux.go index b159eae78..2737a641e 100644 --- a/libpod/oci_linux.go +++ b/libpod/oci_linux.go @@ -65,10 +65,10 @@ func newPipe() (parent *os.File, child *os.File, err error) { // CreateContainer creates a container in the OCI runtime // TODO terminal support for container // Presently just ignoring conmon opts related to it -func (r *OCIRuntime) createContainer(ctr *Container, cgroupParent string, restoreContainer bool) (err error) { +func (r *OCIRuntime) createContainer(ctr *Container, cgroupParent string, restoreOptions *ContainerCheckpointOptions) (err error) { if ctr.state.UserNSRoot == "" { // no need of an intermediate mount ns - return r.createOCIContainer(ctr, cgroupParent, restoreContainer) + return r.createOCIContainer(ctr, cgroupParent, restoreOptions) } var wg sync.WaitGroup wg.Add(1) @@ -106,7 +106,7 @@ func (r *OCIRuntime) createContainer(ctr *Container, cgroupParent string, restor if err != nil { return } - err = r.createOCIContainer(ctr, cgroupParent, restoreContainer) + err = r.createOCIContainer(ctr, cgroupParent, restoreOptions) }() wg.Wait() diff --git a/libpod/oci_unsupported.go b/libpod/oci_unsupported.go index b133eb402..8c084d1e2 100644 --- a/libpod/oci_unsupported.go +++ b/libpod/oci_unsupported.go @@ -15,7 +15,7 @@ func newPipe() (parent *os.File, child *os.File, err error) { return nil, nil, ErrNotImplemented } -func (r *OCIRuntime) createContainer(ctr *Container, cgroupParent string, restoreContainer bool) (err error) { +func (r *OCIRuntime) createContainer(ctr *Container, cgroupParent string, restoreOptions *ContainerCheckpointOptions) (err error) { return ErrNotImplemented } -- cgit v1.2.3-54-g00ecf From 03c88a3debf77780bdad2382d4c01ccedc6d27a5 Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Wed, 21 Nov 2018 14:40:43 +0000 Subject: Added tcp-established to checkpoint/restore CRIU can checkpoint and restore processes/containers with established TCP connections if the correct option is specified. To implement checkpoint and restore with support for established TCP connections with Podman this commit adds the necessary options to runc during checkpoint and also tells conmon during restore to use 'runc restore' with '--tcp-established'. For this Podman feature to work a corresponding conmon change is required. Example: $ podman run --tmpfs /tmp --name podman-criu-test -d docker://docker.io/yovfiatbeb/podman-criu-test $ nc `podman inspect -l | jq -r '.[0].NetworkSettings.IPAddress'` 8080 GET /examples/servlets/servlet/HelloWorldExample Connection: keep-alive 1 GET /examples/servlets/servlet/HelloWorldExample Connection: keep-alive 2 $ # Using HTTP keep-alive multiple requests are send to the server in the container $ # Different terminal: $ podman container checkpoint -l criu failed: type NOTIFY errno 0 $ # Looking at the log file would show errors because of established TCP connections $ podman container checkpoint -l --tcp-established $ # This works now and after the restore the same connection as above can be used for requests $ podman container restore -l --tcp-established The restore would fail without '--tcp-established' as the checkpoint image contains established TCP connections. Signed-off-by: Adrian Reber --- cmd/podman/checkpoint.go | 9 +++++++-- cmd/podman/restore.go | 7 ++++++- libpod/container_api.go | 8 +++++++- libpod/oci.go | 6 ++++++ 4 files changed, 26 insertions(+), 4 deletions(-) (limited to 'libpod') diff --git a/cmd/podman/checkpoint.go b/cmd/podman/checkpoint.go index ddfd12bc3..824c97662 100644 --- a/cmd/podman/checkpoint.go +++ b/cmd/podman/checkpoint.go @@ -27,6 +27,10 @@ var ( Name: "leave-running, R", Usage: "leave the container running after writing checkpoint to disk", }, + cli.BoolFlag{ + Name: "tcp-established", + Usage: "checkpoint a container with established TCP connections", + }, cli.BoolFlag{ Name: "all, a", Usage: "checkpoint all running containers", @@ -55,8 +59,9 @@ func checkpointCmd(c *cli.Context) error { defer runtime.Shutdown(false) options := libpod.ContainerCheckpointOptions{ - Keep: c.Bool("keep"), - KeepRunning: c.Bool("leave-running"), + Keep: c.Bool("keep"), + KeepRunning: c.Bool("leave-running"), + TCPEstablished: c.Bool("tcp-established"), } if err := checkAllAndLatest(c); err != nil { diff --git a/cmd/podman/restore.go b/cmd/podman/restore.go index 6383ebf0b..afdbc36e0 100644 --- a/cmd/podman/restore.go +++ b/cmd/podman/restore.go @@ -26,6 +26,10 @@ var ( // restore --all would make more sense if there would be // dedicated state for container which are checkpointed. // TODO: add ContainerStateCheckpointed + cli.BoolFlag{ + Name: "tcp-established", + Usage: "checkpoint a container with established TCP connections", + }, cli.BoolFlag{ Name: "all, a", Usage: "restore all checkpointed containers", @@ -54,7 +58,8 @@ func restoreCmd(c *cli.Context) error { defer runtime.Shutdown(false) options := libpod.ContainerCheckpointOptions{ - Keep: c.Bool("keep"), + Keep: c.Bool("keep"), + TCPEstablished: c.Bool("tcp-established"), } if err := checkAllAndLatest(c); err != nil { diff --git a/libpod/container_api.go b/libpod/container_api.go index 396f06c20..aee87cc04 100644 --- a/libpod/container_api.go +++ b/libpod/container_api.go @@ -833,8 +833,14 @@ func (c *Container) Refresh(ctx context.Context) error { // ContainerCheckpointOptions is a struct used to pass the parameters // for checkpointing (and restoring) to the corresponding functions type ContainerCheckpointOptions struct { - Keep bool + // Keep tells the API to not delete checkpoint artifacts + Keep bool + // KeepRunning tells the API to keep the container running + // after writing the checkpoint to disk KeepRunning bool + // TCPEstablished tells the API to checkpoint a container + // even if it contains established TCP connections + TCPEstablished bool } // Checkpoint checkpoints a container diff --git a/libpod/oci.go b/libpod/oci.go index 6aedc5662..5a041b7d6 100644 --- a/libpod/oci.go +++ b/libpod/oci.go @@ -291,6 +291,9 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string, res if restoreOptions != nil { args = append(args, "--restore", ctr.CheckpointPath()) + if restoreOptions.TCPEstablished { + args = append(args, "--restore-arg", "--tcp-established") + } } logrus.WithFields(logrus.Fields{ @@ -862,6 +865,9 @@ func (r *OCIRuntime) checkpointContainer(ctr *Container, options ContainerCheckp if options.KeepRunning { args = append(args, "--leave-running") } + if options.TCPEstablished { + args = append(args, "--tcp-established") + } args = append(args, ctr.ID()) return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, nil, r.path, args...) } -- cgit v1.2.3-54-g00ecf