summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/containers/checkpoint.go1
-rw-r--r--cmd/podman/containers/restore.go1
-rw-r--r--docs/source/markdown/podman-container-checkpoint.1.md8
-rw-r--r--docs/source/markdown/podman-container-restore.1.md9
-rw-r--r--libpod/container_api.go3
-rw-r--r--libpod/networking_linux.go20
-rw-r--r--libpod/oci_conmon_linux.go6
-rw-r--r--pkg/api/handlers/libpod/containers.go4
-rw-r--r--pkg/bindings/containers/types.go4
-rw-r--r--pkg/bindings/containers/types_checkpoint_options.go45
-rw-r--r--pkg/bindings/containers/types_restore_options.go15
-rw-r--r--pkg/domain/entities/containers.go2
-rw-r--r--pkg/domain/infra/abi/containers.go1
-rw-r--r--pkg/domain/infra/tunnel/containers.go8
-rw-r--r--pkg/machine/ignition.go2
-rw-r--r--test/e2e/checkpoint_test.go38
16 files changed, 159 insertions, 8 deletions
diff --git a/cmd/podman/containers/checkpoint.go b/cmd/podman/containers/checkpoint.go
index d92bc3e5e..e8dd25978 100644
--- a/cmd/podman/containers/checkpoint.go
+++ b/cmd/podman/containers/checkpoint.go
@@ -55,6 +55,7 @@ func init() {
flags.BoolVarP(&checkpointOptions.Keep, "keep", "k", false, "Keep all temporary checkpoint files")
flags.BoolVarP(&checkpointOptions.LeaveRunning, "leave-running", "R", false, "Leave the container running after writing checkpoint to disk")
flags.BoolVar(&checkpointOptions.TCPEstablished, "tcp-established", false, "Checkpoint a container with established TCP connections")
+ flags.BoolVar(&checkpointOptions.FileLocks, "file-locks", false, "Checkpoint a container with file locks")
flags.BoolVarP(&checkpointOptions.All, "all", "a", false, "Checkpoint all running containers")
exportFlagName := "export"
diff --git a/cmd/podman/containers/restore.go b/cmd/podman/containers/restore.go
index 4ac14001a..cf0ad5f80 100644
--- a/cmd/podman/containers/restore.go
+++ b/cmd/podman/containers/restore.go
@@ -53,6 +53,7 @@ func init() {
flags.BoolVarP(&restoreOptions.All, "all", "a", false, "Restore all checkpointed containers")
flags.BoolVarP(&restoreOptions.Keep, "keep", "k", false, "Keep all temporary checkpoint files")
flags.BoolVar(&restoreOptions.TCPEstablished, "tcp-established", false, "Restore a container with established TCP connections")
+ flags.BoolVar(&restoreOptions.FileLocks, "file-locks", false, "Restore a container with file locks")
importFlagName := "import"
flags.StringVarP(&restoreOptions.Import, importFlagName, "i", "", "Restore from exported checkpoint archive (tar.gz)")
diff --git a/docs/source/markdown/podman-container-checkpoint.1.md b/docs/source/markdown/podman-container-checkpoint.1.md
index 1faa40a94..200920ca9 100644
--- a/docs/source/markdown/podman-container-checkpoint.1.md
+++ b/docs/source/markdown/podman-container-checkpoint.1.md
@@ -110,6 +110,14 @@ restore. Defaults to not checkpointing *containers* with established TCP
connections.\
The default is **false**.
+#### **--file-locks**
+
+Checkpoint a *container* with file locks. If an application running in the container
+is using file locks, this OPTION is required during checkpoint and restore. Otherwise
+checkpointing *containers* with file locks is expected to fail. If file locks are not
+used, this option is ignored.\
+The default is **false**.
+
#### **--with-previous**
Check out the *container* with previous criu image files in pre-dump. It only works on `runc 1.0-rc3` or `higher`.\
diff --git a/docs/source/markdown/podman-container-restore.1.md b/docs/source/markdown/podman-container-restore.1.md
index 962770ea0..10477fc77 100644
--- a/docs/source/markdown/podman-container-restore.1.md
+++ b/docs/source/markdown/podman-container-restore.1.md
@@ -81,6 +81,7 @@ to import a checkpointed *container* from another host.\
Import a pre-checkpoint tar.gz file which was exported by Podman. This option
must be used with **-i** or **--import**. It only works on `runc 1.0-rc3` or `higher`.
+*IMPORTANT: This OPTION is not supported on the remote client.*
#### **--name**, **-n**=*name*
@@ -142,6 +143,14 @@ option is ignored. Defaults to not restoring *containers* with established TCP
connections.\
The default is **false**.
+#### **--file-locks**
+
+Restore a *container* with file locks. This option is required to
+restore file locks from a checkpoint image. If the checkpoint image
+does not contain file locks, this option is ignored. Defaults to not
+restoring file locks.\
+The default is **false**.
+
## EXAMPLE
Restores the container "mywebserver".
```
diff --git a/libpod/container_api.go b/libpod/container_api.go
index a41bb03df..7ae9f497c 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -798,6 +798,9 @@ type ContainerCheckpointOptions struct {
// how much time each component in the stack requires to
// checkpoint a container.
PrintStats bool
+ // FileLocks tells the API to checkpoint/restore a container
+ // with file-locks
+ FileLocks bool
}
// Checkpoint checkpoints a container
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index 9be600bb4..314a74427 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -4,6 +4,7 @@ package libpod
import (
"crypto/rand"
+ "crypto/sha1"
"fmt"
"io/ioutil"
"net"
@@ -400,10 +401,7 @@ func (r *Runtime) GetRootlessNetNs(new bool) (*RootlessNetNS, error) {
return nil, nil
}
var rootlessNetNS *RootlessNetNS
- runDir, err := util.GetRuntimeDir()
- if err != nil {
- return nil, err
- }
+ runDir := r.config.Engine.TmpDir
lfile := filepath.Join(runDir, "rootless-netns.lock")
lock, err := lockfile.GetLockfile(lfile)
@@ -429,7 +427,15 @@ func (r *Runtime) GetRootlessNetNs(new bool) (*RootlessNetNS, error) {
if err != nil {
return nil, err
}
- path := filepath.Join(nsDir, rootlessNetNsName)
+
+ // create a hash from the static dir
+ // the cleanup will check if there are running containers
+ // if you run a several libpod instances with different root/runroot directories this check will fail
+ // we want one netns for each libpod static dir so we use the hash to prevent name collisions
+ hash := sha1.Sum([]byte(r.config.Engine.StaticDir))
+ netnsName := fmt.Sprintf("%s-%x", rootlessNetNsName, hash[:10])
+
+ path := filepath.Join(nsDir, netnsName)
ns, err := ns.GetNS(path)
if err != nil {
if !new {
@@ -437,8 +443,8 @@ func (r *Runtime) GetRootlessNetNs(new bool) (*RootlessNetNS, error) {
return nil, errors.Wrap(err, "error getting rootless network namespace")
}
// create a new namespace
- logrus.Debug("creating rootless network namespace")
- ns, err = netns.NewNSWithName(rootlessNetNsName)
+ logrus.Debugf("creating rootless network namespace with name %q", netnsName)
+ ns, err = netns.NewNSWithName(netnsName)
if err != nil {
return nil, errors.Wrap(err, "error creating rootless network namespace")
}
diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go
index 533a0d78b..e007d0b92 100644
--- a/libpod/oci_conmon_linux.go
+++ b/libpod/oci_conmon_linux.go
@@ -794,6 +794,9 @@ func (r *ConmonOCIRuntime) CheckpointContainer(ctr *Container, options Container
if options.TCPEstablished {
args = append(args, "--tcp-established")
}
+ if options.FileLocks {
+ args = append(args, "--file-locks")
+ }
if !options.PreCheckPoint && options.KeepRunning {
args = append(args, "--leave-running")
}
@@ -1101,6 +1104,9 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
if restoreOptions.TCPEstablished {
args = append(args, "--runtime-opt", "--tcp-established")
}
+ if restoreOptions.FileLocks {
+ args = append(args, "--runtime-opt", "--file-locks")
+ }
if restoreOptions.Pod != "" {
mountLabel := ctr.config.MountLabel
processLabel := ctr.config.ProcessLabel
diff --git a/pkg/api/handlers/libpod/containers.go b/pkg/api/handlers/libpod/containers.go
index b0cec2b1f..d5da22a91 100644
--- a/pkg/api/handlers/libpod/containers.go
+++ b/pkg/api/handlers/libpod/containers.go
@@ -219,6 +219,8 @@ func Checkpoint(w http.ResponseWriter, r *http.Request) {
Export bool `schema:"export"`
IgnoreRootFS bool `schema:"ignoreRootFS"`
PrintStats bool `schema:"printStats"`
+ PreCheckpoint bool `schema:"preCheckpoint"`
+ WithPrevious bool `schema:"withPrevious"`
}{
// override any golang type defaults
}
@@ -242,6 +244,8 @@ func Checkpoint(w http.ResponseWriter, r *http.Request) {
TCPEstablished: query.TCPEstablished,
IgnoreRootFS: query.IgnoreRootFS,
PrintStats: query.PrintStats,
+ PreCheckPoint: query.PreCheckpoint,
+ WithPrevious: query.WithPrevious,
}
if query.Export {
diff --git a/pkg/bindings/containers/types.go b/pkg/bindings/containers/types.go
index 4bbb4a62b..81a53a549 100644
--- a/pkg/bindings/containers/types.go
+++ b/pkg/bindings/containers/types.go
@@ -51,6 +51,9 @@ type CheckpointOptions struct {
LeaveRunning *bool
TCPEstablished *bool
PrintStats *bool
+ PreCheckpoint *bool
+ WithPrevious *bool
+ FileLocks *bool
}
//go:generate go run ../generator/generator.go RestoreOptions
@@ -67,6 +70,7 @@ type RestoreOptions struct {
Pod *string
PrintStats *bool
PublishPorts []string
+ FileLocks *bool
}
//go:generate go run ../generator/generator.go CreateOptions
diff --git a/pkg/bindings/containers/types_checkpoint_options.go b/pkg/bindings/containers/types_checkpoint_options.go
index b606922e0..391748d76 100644
--- a/pkg/bindings/containers/types_checkpoint_options.go
+++ b/pkg/bindings/containers/types_checkpoint_options.go
@@ -106,3 +106,48 @@ func (o *CheckpointOptions) GetPrintStats() bool {
}
return *o.PrintStats
}
+
+// WithPreCheckpoint set field PreCheckpoint to given value
+func (o *CheckpointOptions) WithPreCheckpoint(value bool) *CheckpointOptions {
+ o.PreCheckpoint = &value
+ return o
+}
+
+// GetPreCheckpoint returns value of field PreCheckpoint
+func (o *CheckpointOptions) GetPreCheckpoint() bool {
+ if o.PreCheckpoint == nil {
+ var z bool
+ return z
+ }
+ return *o.PreCheckpoint
+}
+
+// WithWithPrevious set field WithPrevious to given value
+func (o *CheckpointOptions) WithWithPrevious(value bool) *CheckpointOptions {
+ o.WithPrevious = &value
+ return o
+}
+
+// GetWithPrevious returns value of field WithPrevious
+func (o *CheckpointOptions) GetWithPrevious() bool {
+ if o.WithPrevious == nil {
+ var z bool
+ return z
+ }
+ return *o.WithPrevious
+}
+
+// WithFileLocks set field FileLocks to given value
+func (o *CheckpointOptions) WithFileLocks(value bool) *CheckpointOptions {
+ o.FileLocks = &value
+ return o
+}
+
+// GetFileLocks returns value of field FileLocks
+func (o *CheckpointOptions) GetFileLocks() bool {
+ if o.FileLocks == nil {
+ var z bool
+ return z
+ }
+ return *o.FileLocks
+}
diff --git a/pkg/bindings/containers/types_restore_options.go b/pkg/bindings/containers/types_restore_options.go
index 8817b834b..7af2bba32 100644
--- a/pkg/bindings/containers/types_restore_options.go
+++ b/pkg/bindings/containers/types_restore_options.go
@@ -181,3 +181,18 @@ func (o *RestoreOptions) GetPublishPorts() []string {
}
return o.PublishPorts
}
+
+// WithFileLocks set field FileLocks to given value
+func (o *RestoreOptions) WithFileLocks(value bool) *RestoreOptions {
+ o.FileLocks = &value
+ return o
+}
+
+// GetFileLocks returns value of field FileLocks
+func (o *RestoreOptions) GetFileLocks() bool {
+ if o.FileLocks == nil {
+ var z bool
+ return z
+ }
+ return *o.FileLocks
+}
diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go
index 1a4019bb1..1677c067f 100644
--- a/pkg/domain/entities/containers.go
+++ b/pkg/domain/entities/containers.go
@@ -191,6 +191,7 @@ type CheckpointOptions struct {
WithPrevious bool
Compression archive.Compression
PrintStats bool
+ FileLocks bool
}
type CheckpointReport struct {
@@ -215,6 +216,7 @@ type RestoreOptions struct {
PublishPorts []string
Pod string
PrintStats bool
+ FileLocks bool
}
type RestoreReport struct {
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 69c628669..e04c7a38a 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -516,6 +516,7 @@ func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds [
WithPrevious: options.WithPrevious,
Compression: options.Compression,
PrintStats: options.PrintStats,
+ FileLocks: options.FileLocks,
}
if options.All {
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index 152e3c302..2127f8749 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -303,12 +303,15 @@ func (ic *ContainerEngine) ContainerExport(ctx context.Context, nameOrID string,
func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds []string, opts entities.CheckpointOptions) ([]*entities.CheckpointReport, error) {
options := new(containers.CheckpointOptions)
+ options.WithFileLocks(opts.FileLocks)
options.WithIgnoreRootfs(opts.IgnoreRootFS)
options.WithKeep(opts.Keep)
options.WithExport(opts.Export)
options.WithTCPEstablished(opts.TCPEstablished)
options.WithPrintStats(opts.PrintStats)
+ options.WithPreCheckpoint(opts.PreCheckPoint)
options.WithLeaveRunning(opts.LeaveRunning)
+ options.WithWithPrevious(opts.WithPrevious)
var (
err error
@@ -345,7 +348,12 @@ func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds [
}
func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []string, opts entities.RestoreOptions) ([]*entities.RestoreReport, error) {
+ if opts.ImportPrevious != "" {
+ return nil, fmt.Errorf("--import-previous is not supported on the remote client")
+ }
+
options := new(containers.RestoreOptions)
+ options.WithFileLocks(opts.FileLocks)
options.WithIgnoreRootfs(opts.IgnoreRootFS)
options.WithIgnoreVolumes(opts.IgnoreVolumes)
options.WithIgnoreStaticIP(opts.IgnoreStaticIP)
diff --git a/pkg/machine/ignition.go b/pkg/machine/ignition.go
index 42d729458..e19940b22 100644
--- a/pkg/machine/ignition.go
+++ b/pkg/machine/ignition.go
@@ -81,7 +81,7 @@ func NewIgnitionFile(ign DynamicIgnition) error {
// so a listening host knows it can being interacting with it
ready := `[Unit]
Requires=dev-virtio\\x2dports-%s.device
-After=remove-moby.service
+After=remove-moby.service sshd.socket sshd.service
OnFailure=emergency.target
OnFailureJobMode=isolate
[Service]
diff --git a/test/e2e/checkpoint_test.go b/test/e2e/checkpoint_test.go
index 37935fd38..4963b04fc 100644
--- a/test/e2e/checkpoint_test.go
+++ b/test/e2e/checkpoint_test.go
@@ -899,6 +899,7 @@ var _ = Describe("Podman checkpoint", func() {
})
It("podman checkpoint container with --pre-checkpoint and export (migration)", func() {
+ SkipIfRemote("--import-previous is not yet supported on the remote client")
if !strings.Contains(podmanTest.OCIRuntime, "runc") {
Skip("Test only works on runc 1.0-rc3 or higher.")
}
@@ -1339,4 +1340,41 @@ var _ = Describe("Podman checkpoint", func() {
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
})
+ It("podman checkpoint and restore container with --file-locks", func() {
+ if !strings.Contains(podmanTest.OCIRuntime, "runc") {
+ // TODO: Enable test for crun when this feature has been released
+ // https://github.com/containers/crun/pull/783
+ Skip("FIXME: requires crun >= 1.4")
+ }
+ localRunString := getRunString([]string{"--name", "test_name", ALPINE, "flock", "test.lock", "sleep", "100"})
+ session := podmanTest.Podman(localRunString)
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ // Checkpoint is expected to fail without --file-locks
+ result := podmanTest.Podman([]string{"container", "checkpoint", "test_name"})
+ result.WaitWithDefaultTimeout()
+ Expect(result).Should(Exit(125))
+ Expect(result.ErrorToString()).To(ContainSubstring("criu failed"))
+ Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
+
+ // Checkpoint is expected to succeed with --file-locks
+ result = podmanTest.Podman([]string{"container", "checkpoint", "--file-locks", "test_name"})
+ result.WaitWithDefaultTimeout()
+ Expect(result).Should(Exit(0))
+ Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
+ Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited"))
+
+ result = podmanTest.Podman([]string{"container", "restore", "--file-locks", "test_name"})
+ result.WaitWithDefaultTimeout()
+
+ Expect(result).Should(Exit(0))
+ Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
+ Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
+
+ result = podmanTest.Podman([]string{"rm", "-t", "0", "-f", "test_name"})
+ result.WaitWithDefaultTimeout()
+ Expect(result).Should(Exit(0))
+ Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
+ })
})