From 87d3ae25ee4947f1e4232aa59ba242e9c33ea96f Mon Sep 17 00:00:00 2001 From: Tsubasa Watanabe Date: Mon, 11 Dec 2023 18:36:28 +0900 Subject: [PATCH] remote: fix podman-remote container checkpoint --compress Fix `podman container checkpoint --compress` to work in remote environment. Signed-off-by: Tsubasa Watanabe --- pkg/api/handlers/libpod/containers.go | 23 ++++++++------- pkg/api/server/register_containers.go | 4 +++ pkg/bindings/containers/types.go | 2 ++ .../containers/types_checkpoint_options.go | 16 +++++++++++ pkg/domain/infra/tunnel/containers.go | 1 + test/e2e/checkpoint_test.go | 24 ++++++++++++++++ test/utils/utils.go | 28 +++++++++++++++++++ 7 files changed, 88 insertions(+), 10 deletions(-) diff --git a/pkg/api/handlers/libpod/containers.go b/pkg/api/handlers/libpod/containers.go index 5866d23117..470b3baec9 100644 --- a/pkg/api/handlers/libpod/containers.go +++ b/pkg/api/handlers/libpod/containers.go @@ -17,6 +17,7 @@ import ( "github.com/containers/podman/v4/pkg/domain/entities" "github.com/containers/podman/v4/pkg/domain/infra/abi" "github.com/containers/podman/v4/pkg/util" + "github.com/containers/storage/pkg/archive" "github.com/gorilla/schema" "github.com/opencontainers/runtime-spec/specs-go" "github.com/sirupsen/logrus" @@ -212,16 +213,17 @@ func Checkpoint(w http.ResponseWriter, r *http.Request) { decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder) query := struct { - Keep bool `schema:"keep"` - LeaveRunning bool `schema:"leaveRunning"` - TCPEstablished bool `schema:"tcpEstablished"` - Export bool `schema:"export"` - IgnoreRootFS bool `schema:"ignoreRootFS"` - PrintStats bool `schema:"printStats"` - PreCheckpoint bool `schema:"preCheckpoint"` - WithPrevious bool `schema:"withPrevious"` - FileLocks bool `schema:"fileLocks"` - CreateImage string `schema:"createImage"` + Keep bool `schema:"keep"` + LeaveRunning bool `schema:"leaveRunning"` + TCPEstablished bool `schema:"tcpEstablished"` + Export bool `schema:"export"` + IgnoreRootFS bool `schema:"ignoreRootFS"` + PrintStats bool `schema:"printStats"` + PreCheckpoint bool `schema:"preCheckpoint"` + WithPrevious bool `schema:"withPrevious"` + Compression archive.Compression `schema:"compression"` + FileLocks bool `schema:"fileLocks"` + CreateImage string `schema:"createImage"` }{ // override any golang type defaults } @@ -246,6 +248,7 @@ func Checkpoint(w http.ResponseWriter, r *http.Request) { PrintStats: query.PrintStats, PreCheckPoint: query.PreCheckpoint, WithPrevious: query.WithPrevious, + Compression: query.Compression, FileLocks: query.FileLocks, CreateImage: query.CreateImage, } diff --git a/pkg/api/server/register_containers.go b/pkg/api/server/register_containers.go index b4f0d8592c..e056daa7dc 100644 --- a/pkg/api/server/register_containers.go +++ b/pkg/api/server/register_containers.go @@ -1565,6 +1565,10 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // type: boolean // description: check out the container with previous criu image files in pre-dump. only works on runc 1.0-rc or higher // - in: query + // name: compression + // type: integer + // description: select compression algorithm (gzip, none, zstd) for checkpoint archive. (default "zstd") + // - in: query // name: fileLocks // type: boolean // description: checkpoint a container with filelocks diff --git a/pkg/bindings/containers/types.go b/pkg/bindings/containers/types.go index ee2fe4b94b..aba66360c4 100644 --- a/pkg/bindings/containers/types.go +++ b/pkg/bindings/containers/types.go @@ -5,6 +5,7 @@ import ( "io" "github.com/containers/podman/v4/libpod/define" + "github.com/containers/storage/pkg/archive" ) // LogOptions describe finer control of log content or @@ -61,6 +62,7 @@ type CheckpointOptions struct { PrintStats *bool PreCheckpoint *bool WithPrevious *bool + Compression *archive.Compression FileLocks *bool } diff --git a/pkg/bindings/containers/types_checkpoint_options.go b/pkg/bindings/containers/types_checkpoint_options.go index d5f6e541d1..b12dbfbbdd 100644 --- a/pkg/bindings/containers/types_checkpoint_options.go +++ b/pkg/bindings/containers/types_checkpoint_options.go @@ -5,6 +5,7 @@ import ( "net/url" "github.com/containers/podman/v4/pkg/bindings/internal/util" + "github.com/containers/storage/pkg/archive" ) // Changed returns true if named field has been set @@ -152,6 +153,21 @@ func (o *CheckpointOptions) GetWithPrevious() bool { return *o.WithPrevious } +// WithCompression set field Compression to given value +func (o *CheckpointOptions) WithCompression(value archive.Compression) *CheckpointOptions { + o.Compression = &value + return o +} + +// GetCompression returns value of field Compression +func (o *CheckpointOptions) GetCompression() archive.Compression { + if o.Compression == nil { + var z archive.Compression + return z + } + return *o.Compression +} + // WithFileLocks set field FileLocks to given value func (o *CheckpointOptions) WithFileLocks(value bool) *CheckpointOptions { o.FileLocks = &value diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index 93473263df..42eb9a45fa 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -387,6 +387,7 @@ func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds [ options.WithPreCheckpoint(opts.PreCheckPoint) options.WithLeaveRunning(opts.LeaveRunning) options.WithWithPrevious(opts.WithPrevious) + options.WithCompression(opts.Compression) if opts.All { allCtrs, err := getContainersByContext(ic.ClientCtx, true, false, []string{}) diff --git a/test/e2e/checkpoint_test.go b/test/e2e/checkpoint_test.go index 3e768c1574..13335166a7 100644 --- a/test/e2e/checkpoint_test.go +++ b/test/e2e/checkpoint_test.go @@ -561,6 +561,12 @@ var _ = Describe("Podman checkpoint", func() { Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.NumberOfContainers()).To(Equal(0)) + // Check the compression type of the exported file with checkpoint + // it should be "zstd" + compressionType, err := CheckCompressionType(fileName) + Expect(err).ShouldNot(HaveOccurred()) + Expect(compressionType).To(ContainSubstring("zstd")) + // Restore container result = podmanTest.Podman([]string{"container", "restore", "-i", fileName}) result.WaitWithDefaultTimeout() @@ -580,6 +586,12 @@ var _ = Describe("Podman checkpoint", func() { Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.NumberOfContainers()).To(Equal(0)) + // Check the compression type of the exported file with checkpoint + // it should be "zstd" + compressionType, err = CheckCompressionType(fileName) + Expect(err).ShouldNot(HaveOccurred()) + Expect(compressionType).To(ContainSubstring("zstd")) + // Restore container result = podmanTest.Podman([]string{"container", "restore", "-i", fileName}) result.WaitWithDefaultTimeout() @@ -599,6 +611,12 @@ var _ = Describe("Podman checkpoint", func() { Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.NumberOfContainers()).To(Equal(0)) + // Check the compression type of the exported file with checkpoint + // it should be "none" + compressionType, err = CheckCompressionType(fileName) + Expect(err).ShouldNot(HaveOccurred()) + Expect(compressionType).To(ContainSubstring("none")) + // Restore container result = podmanTest.Podman([]string{"container", "restore", "-i", fileName}) result.WaitWithDefaultTimeout() @@ -618,6 +636,12 @@ var _ = Describe("Podman checkpoint", func() { Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.NumberOfContainers()).To(Equal(0)) + // Check the compression type of the exported file with checkpoint + // it should be "gzip" + compressionType, err = CheckCompressionType(fileName) + Expect(err).ShouldNot(HaveOccurred()) + Expect(compressionType).To(ContainSubstring("gzip")) + // Restore container result = podmanTest.Podman([]string{"container", "restore", "-i", fileName}) result.WaitWithDefaultTimeout() diff --git a/test/utils/utils.go b/test/utils/utils.go index 205c4edd89..6173bc31fe 100644 --- a/test/utils/utils.go +++ b/test/utils/utils.go @@ -601,3 +601,31 @@ func WriteRSAKeyPair(fileName string, bitSize int) (string, string, error) { return publicKeyFileName, privateKeyFileName, nil } + +// Check a compression type for a file +func CheckCompressionType(fileName string) (string, error) { + file, err := os.Open(fileName) + + if err != nil { + return "", err + } + + defer file.Close() + + buff := make([]byte, 512) + + _, err = file.Read(buff) + + if err != nil { + return "", err + } + + switch string(buff[:3]) { + case "\x28\xb5\x2f": + return "zstd", nil + case "\x1f\x8b\x08": + return "gzip", nil + default: + return "none", nil + } +}