From 72d08d4c61c1466a4e10fc46c29cb0a14893f923 Mon Sep 17 00:00:00 2001
From: baude <bbaude@redhat.com>
Date: Tue, 2 Apr 2019 08:37:11 -0500
Subject: [PATCH] remote-client checkpoint/restore

add the ability for the remote client to be able to checkpoint and
restore containers.

Signed-off-by: baude <bbaude@redhat.com>
---
 cmd/podman/checkpoint.go         | 22 ++--------
 cmd/podman/restore.go            | 23 ++--------
 pkg/adapter/containers.go        | 64 ++++++++++++++++++++++++++++
 pkg/adapter/containers_remote.go | 72 ++++++++++++++++++++++++++++++++
 4 files changed, 142 insertions(+), 39 deletions(-)

diff --git a/cmd/podman/checkpoint.go b/cmd/podman/checkpoint.go
index dbf72c2cd6..5b8d00ff9d 100644
--- a/cmd/podman/checkpoint.go
+++ b/cmd/podman/checkpoint.go
@@ -1,13 +1,9 @@
 package main
 
 import (
-	"context"
-	"fmt"
-	"os"
-
 	"github.com/containers/libpod/cmd/podman/cliconfig"
-	"github.com/containers/libpod/cmd/podman/libpodruntime"
 	"github.com/containers/libpod/libpod"
+	"github.com/containers/libpod/pkg/adapter"
 	"github.com/containers/libpod/pkg/rootless"
 	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
@@ -57,7 +53,7 @@ func checkpointCmd(c *cliconfig.CheckpointValues) error {
 		return errors.New("checkpointing a container requires root")
 	}
 
-	runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
+	runtime, err := adapter.GetRuntime(&c.PodmanCommand)
 	if err != nil {
 		return errors.Wrapf(err, "could not get runtime")
 	}
@@ -68,17 +64,5 @@ func checkpointCmd(c *cliconfig.CheckpointValues) error {
 		KeepRunning:    c.LeaveRunning,
 		TCPEstablished: c.TcpEstablished,
 	}
-	containers, lastError := getAllOrLatestContainers(&c.PodmanCommand, runtime, libpod.ContainerStateRunning, "running")
-
-	for _, ctr := range containers {
-		if err = ctr.Checkpoint(context.TODO(), options); err != nil {
-			if lastError != nil {
-				fmt.Fprintln(os.Stderr, lastError)
-			}
-			lastError = errors.Wrapf(err, "failed to checkpoint container %v", ctr.ID())
-		} else {
-			fmt.Println(ctr.ID())
-		}
-	}
-	return lastError
+	return runtime.Checkpoint(c, options)
 }
diff --git a/cmd/podman/restore.go b/cmd/podman/restore.go
index 0f68284320..0f0150644c 100644
--- a/cmd/podman/restore.go
+++ b/cmd/podman/restore.go
@@ -1,13 +1,9 @@
 package main
 
 import (
-	"context"
-	"fmt"
-	"os"
-
 	"github.com/containers/libpod/cmd/podman/cliconfig"
-	"github.com/containers/libpod/cmd/podman/libpodruntime"
 	"github.com/containers/libpod/libpod"
+	"github.com/containers/libpod/pkg/adapter"
 	"github.com/containers/libpod/pkg/rootless"
 	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
@@ -57,7 +53,7 @@ func restoreCmd(c *cliconfig.RestoreValues) error {
 		return errors.New("restoring a container requires root")
 	}
 
-	runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
+	runtime, err := adapter.GetRuntime(&c.PodmanCommand)
 	if err != nil {
 		return errors.Wrapf(err, "could not get runtime")
 	}
@@ -67,18 +63,5 @@ func restoreCmd(c *cliconfig.RestoreValues) error {
 		Keep:           c.Keep,
 		TCPEstablished: c.TcpEstablished,
 	}
-
-	containers, lastError := getAllOrLatestContainers(&c.PodmanCommand, runtime, libpod.ContainerStateExited, "checkpointed")
-
-	for _, ctr := range containers {
-		if err = ctr.Restore(context.TODO(), options); err != nil {
-			if lastError != nil {
-				fmt.Fprintln(os.Stderr, lastError)
-			}
-			lastError = errors.Wrapf(err, "failed to restore container %v", ctr.ID())
-		} else {
-			fmt.Println(ctr.ID())
-		}
-	}
-	return lastError
+	return runtime.Restore(c, options)
 }
diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go
index a9b3232e70..1bb1aab873 100644
--- a/pkg/adapter/containers.go
+++ b/pkg/adapter/containers.go
@@ -443,3 +443,67 @@ func (r *LocalRuntime) Attach(ctx context.Context, c *cliconfig.AttachValues) er
 	}
 	return nil
 }
+
+// Checkpoint one or more containers
+func (r *LocalRuntime) Checkpoint(c *cliconfig.CheckpointValues, options libpod.ContainerCheckpointOptions) error {
+	var (
+		containers     []*libpod.Container
+		err, lastError error
+	)
+
+	if c.All {
+		containers, err = r.Runtime.GetRunningContainers()
+	} else {
+		containers, err = shortcuts.GetContainersByContext(false, c.Latest, c.InputArgs, r.Runtime)
+	}
+	if err != nil {
+		return err
+	}
+
+	for _, ctr := range containers {
+		if err = ctr.Checkpoint(context.TODO(), options); err != nil {
+			if lastError != nil {
+				fmt.Fprintln(os.Stderr, lastError)
+			}
+			lastError = errors.Wrapf(err, "failed to checkpoint container %v", ctr.ID())
+		} else {
+			fmt.Println(ctr.ID())
+		}
+	}
+	return lastError
+}
+
+// Restore one or more containers
+func (r *LocalRuntime) Restore(c *cliconfig.RestoreValues, options libpod.ContainerCheckpointOptions) error {
+	var (
+		containers     []*libpod.Container
+		err, lastError error
+		filterFuncs    []libpod.ContainerFilter
+	)
+
+	filterFuncs = append(filterFuncs, func(c *libpod.Container) bool {
+		state, _ := c.State()
+		return state == libpod.ContainerStateExited
+	})
+
+	if c.All {
+		containers, err = r.GetContainers(filterFuncs...)
+	} else {
+		containers, err = shortcuts.GetContainersByContext(false, c.Latest, c.InputArgs, r.Runtime)
+	}
+	if err != nil {
+		return err
+	}
+
+	for _, ctr := range containers {
+		if err = ctr.Restore(context.TODO(), options); err != nil {
+			if lastError != nil {
+				fmt.Fprintln(os.Stderr, lastError)
+			}
+			lastError = errors.Wrapf(err, "failed to restore container %v", ctr.ID())
+		} else {
+			fmt.Println(ctr.ID())
+		}
+	}
+	return lastError
+}
diff --git a/pkg/adapter/containers_remote.go b/pkg/adapter/containers_remote.go
index 1ae39749f2..31727fd0e8 100644
--- a/pkg/adapter/containers_remote.go
+++ b/pkg/adapter/containers_remote.go
@@ -539,3 +539,75 @@ func (r *LocalRuntime) Attach(ctx context.Context, c *cliconfig.AttachValues) er
 	}
 	return <-errChan
 }
+
+// Checkpoint one or more containers
+func (r *LocalRuntime) Checkpoint(c *cliconfig.CheckpointValues, options libpod.ContainerCheckpointOptions) error {
+	var lastError error
+	ids, err := iopodman.GetContainersByContext().Call(r.Conn, c.All, c.Latest, c.InputArgs)
+	if err != nil {
+		return err
+	}
+	if c.All {
+		// We dont have a great way to get all the running containers, so need to get all and then
+		// check status on them bc checkpoint considers checkpointing a stopped container an error
+		var runningIds []string
+		for _, id := range ids {
+			ctr, err := r.LookupContainer(id)
+			if err != nil {
+				return err
+			}
+			if ctr.state.State == libpod.ContainerStateRunning {
+				runningIds = append(runningIds, id)
+			}
+		}
+		ids = runningIds
+	}
+
+	for _, id := range ids {
+		if _, err := iopodman.ContainerCheckpoint().Call(r.Conn, id, options.Keep, options.KeepRunning, options.TCPEstablished); err != nil {
+			if lastError != nil {
+				fmt.Fprintln(os.Stderr, lastError)
+			}
+			lastError = errors.Wrapf(err, "failed to checkpoint container %v", id)
+		} else {
+			fmt.Println(id)
+		}
+	}
+	return lastError
+}
+
+// Restore one or more containers
+func (r *LocalRuntime) Restore(c *cliconfig.RestoreValues, options libpod.ContainerCheckpointOptions) error {
+	var lastError error
+	ids, err := iopodman.GetContainersByContext().Call(r.Conn, c.All, c.Latest, c.InputArgs)
+	if err != nil {
+		return err
+	}
+	if c.All {
+		// We dont have a great way to get all the exited containers, so need to get all and then
+		// check status on them bc checkpoint considers restoring a running container an error
+		var exitedIDs []string
+		for _, id := range ids {
+			ctr, err := r.LookupContainer(id)
+			if err != nil {
+				return err
+			}
+			if ctr.state.State != libpod.ContainerStateRunning {
+				exitedIDs = append(exitedIDs, id)
+			}
+		}
+		ids = exitedIDs
+	}
+
+	for _, id := range ids {
+		if _, err := iopodman.ContainerRestore().Call(r.Conn, id, options.Keep, options.TCPEstablished); err != nil {
+			if lastError != nil {
+				fmt.Fprintln(os.Stderr, lastError)
+			}
+			lastError = errors.Wrapf(err, "failed to restore container %v", id)
+		} else {
+			fmt.Println(id)
+		}
+	}
+	return lastError
+}