Merge pull request #26895 from intirix/tcp-close

Add support for criu's tcp-close functionality.
This commit is contained in:
openshift-merge-bot[bot]
2025-08-28 10:40:59 +00:00
committed by GitHub
12 changed files with 89 additions and 1 deletions

View File

@@ -52,6 +52,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.TCPClose, "tcp-close", false, "Restore a container and close all TCP connections")
flags.BoolVar(&restoreOptions.FileLocks, "file-locks", false, "Restore a container with file locks")
importFlagName := "import"

View File

@@ -150,6 +150,14 @@ initial *container* start, with a new set of port forwarding rules.
For more details, see **[podman run --publish](podman-run.1.md#--publish)**.
#### **--tcp-close**
Restore a *container* and close all TCP connections. This option is useful
when TCP connections are not needed after restore or when connections
will be reestablished by the application. If the checkpoint image was created with
**--tcp-close**, this option should be used during restore.\
The default is **false**.
#### **--tcp-established**
Restore a *container* with established TCP connections. If the checkpoint image

View File

@@ -965,6 +965,8 @@ type ContainerCheckpointOptions struct {
// TCPEstablished tells the API to checkpoint a container
// even if it contains established TCP connections
TCPEstablished bool
// TCPClose tells the API to close all TCP connections during restore
TCPClose bool
// TargetFile tells the API to read (or write) the checkpoint image
// from (or to) the filename set in TargetFile
TargetFile string

View File

@@ -1082,6 +1082,9 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
if restoreOptions.TCPEstablished {
args = append(args, "--runtime-opt", "--tcp-established")
}
if restoreOptions.TCPClose {
args = append(args, "--runtime-opt", "--tcp-close")
}
if restoreOptions.FileLocks {
args = append(args, "--runtime-opt", "--file-locks")
}

View File

@@ -307,6 +307,7 @@ func Restore(w http.ResponseWriter, r *http.Request) {
query := struct {
Keep bool `schema:"keep"`
TCPEstablished bool `schema:"tcpEstablished"`
TCPClose bool `schema:"tcpClose"`
Import bool `schema:"import"`
Name string `schema:"name"`
IgnoreRootFS bool `schema:"ignoreRootFS"`
@@ -329,6 +330,7 @@ func Restore(w http.ResponseWriter, r *http.Request) {
Name: query.Name,
Keep: query.Keep,
TCPEstablished: query.TCPEstablished,
TCPClose: query.TCPClose,
IgnoreRootFS: query.IgnoreRootFS,
IgnoreVolumes: query.IgnoreVolumes,
IgnoreStaticIP: query.IgnoreStaticIP,

View File

@@ -1636,7 +1636,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
// - in: query
// name: tcpEstablished
// type: boolean
// description: checkpoint a container with established TCP connections
// description: restore a container with established TCP connections
// - in: query
// name: tcpClose
// type: boolean
// description: restore a container but close the TCP connections
// - in: query
// name: import
// type: boolean

View File

@@ -83,6 +83,7 @@ type RestoreOptions struct {
Keep *bool
Name *string
TCPEstablished *bool
TCPClose *bool
Pod *string
PrintStats *bool
PublishPorts []string

View File

@@ -152,6 +152,21 @@ func (o *RestoreOptions) GetTCPEstablished() bool {
return *o.TCPEstablished
}
// WithTCPClose set field TCPClose to given value
func (o *RestoreOptions) WithTCPClose(value bool) *RestoreOptions {
o.TCPClose = &value
return o
}
// GetTCPClose returns value of field TCPClose
func (o *RestoreOptions) GetTCPClose() bool {
if o.TCPClose == nil {
var z bool
return z
}
return *o.TCPClose
}
// WithPod set field Pod to given value
func (o *RestoreOptions) WithPod(value string) *RestoreOptions {
o.Pod = &value

View File

@@ -227,6 +227,7 @@ type RestoreOptions struct {
Latest bool
Name string
TCPEstablished bool
TCPClose bool
ImportPrevious string
PublishPorts []string
Pod string

View File

@@ -738,6 +738,7 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st
restoreOptions := libpod.ContainerCheckpointOptions{
Keep: options.Keep,
TCPEstablished: options.TCPEstablished,
TCPClose: options.TCPClose,
TargetFile: options.Import,
Name: options.Name,
IgnoreRootfs: options.IgnoreRootFS,

View File

@@ -472,6 +472,7 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st
options.WithKeep(opts.Keep)
options.WithName(opts.Name)
options.WithTCPEstablished(opts.TCPEstablished)
options.WithTCPClose(opts.TCPClose)
options.WithPod(opts.Pod)
options.WithPrintStats(opts.PrintStats)
options.WithPublishPorts(opts.PublishPorts)

View File

@@ -402,6 +402,55 @@ var _ = Describe("Podman checkpoint", func() {
conn.Close()
})
It("podman restore container with tcp-close", func() {
Skip("FIXME: #26289 - Rawhide only issue, skip for now")
// Start a container with redis (which listens on tcp port)
localRunString := getRunString([]string{REDIS_IMAGE})
session := podmanTest.Podman(localRunString)
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
cid := session.OutputToString()
if !WaitContainerReady(podmanTest, cid, "Ready to accept connections", 20, 1) {
Fail("Container failed to get ready")
}
// Get container IP
IP := podmanTest.PodmanExitCleanly("inspect", cid, fmt.Sprintf("--format={{(index .NetworkSettings.Networks \"%s\").IPAddress}}", netname))
// Open a network connection to the redis server
conn, err := net.DialTimeout("tcp4", IP.OutputToString()+":6379", time.Duration(3)*time.Second)
Expect(err).ToNot(HaveOccurred())
defer conn.Close()
// Checkpoint with --tcp-established since we have an open connection
podmanTest.PodmanExitCleanly("container", "checkpoint", cid, "--tcp-established")
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited"))
// Restore should fail as the checkpoint image contains established TCP connections
result := podmanTest.Podman([]string{"container", "restore", cid})
result.WaitWithDefaultTimeout()
// default message when using crun
expectStderr := "crun: CRIU restoring failed -52. Please check CRIU logfile"
if podmanTest.OCIRuntime == "runc" {
expectStderr = "runc: criu failed: type NOTIFY errno 0"
}
if !IsRemote() {
// This part is only seen with podman local, never remote
expectStderr = "OCI runtime error: " + expectStderr
}
Expect(result).Should(ExitWithError(125, expectStderr))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited"))
// Now it should work thanks to "--tcp-close"
podmanTest.PodmanExitCleanly("container", "restore", cid, "--tcp-close")
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
})
It("podman checkpoint with --leave-running", func() {
localRunString := getRunString([]string{ALPINE, "top"})
session := podmanTest.Podman(localRunString)