mirror of
https://github.com/containers/podman.git
synced 2025-12-11 09:18:34 +08:00
attach: fix hang if control path is deleted
if the control path file is deleted, libpod hangs waiting for a reader to open it. Attempt to open it as non blocking until it returns an error different than EINTR or EAGAIN. Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
This commit is contained in:
@@ -575,13 +575,36 @@ func (r *ConmonOCIRuntime) HTTPAttach(ctr *Container, httpConn net.Conn, httpBuf
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isRetryable returns whether the error was caused by a blocked syscall or the
|
||||||
|
// specified operation on a non blocking file descriptor wasn't ready for completion.
|
||||||
|
func isRetryable(err error) bool {
|
||||||
|
if errno, isErrno := errors.Cause(err).(syscall.Errno); isErrno {
|
||||||
|
return errno == syscall.EINTR || errno == syscall.EAGAIN
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// openControlFile opens the terminal control file.
|
||||||
|
func openControlFile(ctr *Container, parentDir string) (*os.File, error) {
|
||||||
|
controlPath := filepath.Join(parentDir, "ctl")
|
||||||
|
for i := 0; i < 600; i++ {
|
||||||
|
controlFile, err := os.OpenFile(controlPath, unix.O_WRONLY|unix.O_NONBLOCK, 0)
|
||||||
|
if err == nil {
|
||||||
|
return controlFile, err
|
||||||
|
}
|
||||||
|
if !isRetryable(err) {
|
||||||
|
return nil, errors.Wrapf(err, "could not open ctl file for terminal resize for container %s", ctr.ID())
|
||||||
|
}
|
||||||
|
time.Sleep(time.Second / 10)
|
||||||
|
}
|
||||||
|
return nil, errors.Errorf("timeout waiting for %q", controlPath)
|
||||||
|
}
|
||||||
|
|
||||||
// AttachResize resizes the terminal used by the given container.
|
// AttachResize resizes the terminal used by the given container.
|
||||||
func (r *ConmonOCIRuntime) AttachResize(ctr *Container, newSize remotecommand.TerminalSize) error {
|
func (r *ConmonOCIRuntime) AttachResize(ctr *Container, newSize remotecommand.TerminalSize) error {
|
||||||
// TODO: probably want a dedicated function to get ctl file path?
|
controlFile, err := openControlFile(ctr, ctr.bundlePath())
|
||||||
controlPath := filepath.Join(ctr.bundlePath(), "ctl")
|
|
||||||
controlFile, err := os.OpenFile(controlPath, unix.O_WRONLY, 0)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "could not open ctl file for terminal resize")
|
return err
|
||||||
}
|
}
|
||||||
defer controlFile.Close()
|
defer controlFile.Close()
|
||||||
|
|
||||||
@@ -785,11 +808,9 @@ func (r *ConmonOCIRuntime) ExecContainer(c *Container, sessionID string, options
|
|||||||
|
|
||||||
// ExecAttachResize resizes the TTY of the given exec session.
|
// ExecAttachResize resizes the TTY of the given exec session.
|
||||||
func (r *ConmonOCIRuntime) ExecAttachResize(ctr *Container, sessionID string, newSize remotecommand.TerminalSize) error {
|
func (r *ConmonOCIRuntime) ExecAttachResize(ctr *Container, sessionID string, newSize remotecommand.TerminalSize) error {
|
||||||
// TODO: probably want a dedicated function to get ctl file path?
|
controlFile, err := openControlFile(ctr, ctr.execBundlePath(sessionID))
|
||||||
controlPath := filepath.Join(ctr.execBundlePath(sessionID), "ctl")
|
|
||||||
controlFile, err := os.OpenFile(controlPath, unix.O_WRONLY, 0)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "could not open ctl file for terminal resize for container %s exec session %s", ctr.ID(), sessionID)
|
return err
|
||||||
}
|
}
|
||||||
defer controlFile.Close()
|
defer controlFile.Close()
|
||||||
|
|
||||||
|
|||||||
@@ -122,6 +122,18 @@ var _ = Describe("Podman exec", func() {
|
|||||||
Expect(session.ExitCode()).To(Equal(100))
|
Expect(session.ExitCode()).To(Equal(100))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("podman exec terminal doesn't hang", func() {
|
||||||
|
setup := podmanTest.Podman([]string{"run", "-dti", fedoraMinimal, "sleep", "+Inf"})
|
||||||
|
setup.WaitWithDefaultTimeout()
|
||||||
|
Expect(setup.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
session := podmanTest.Podman([]string{"exec", "-lti", "true"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
It("podman exec pseudo-terminal sanity check", func() {
|
It("podman exec pseudo-terminal sanity check", func() {
|
||||||
setup := podmanTest.Podman([]string{"run", "--detach", "--name", "test1", fedoraMinimal, "sleep", "+Inf"})
|
setup := podmanTest.Podman([]string{"run", "--detach", "--name", "test1", fedoraMinimal, "sleep", "+Inf"})
|
||||||
setup.WaitWithDefaultTimeout()
|
setup.WaitWithDefaultTimeout()
|
||||||
|
|||||||
Reference in New Issue
Block a user