mirror of
https://github.com/podman-container-tools/podman.git
synced 2026-08-05 00:15:44 +00:00
Merge pull request #28957 from shuaiyuanxx/exec-honor-console-size
exec: honor ConsoleSize so the terminal is sized at creation
This commit is contained in:
commit
eb3c0f4c1a
9 changed files with 63 additions and 7 deletions
|
|
@ -11,6 +11,7 @@ import (
|
|||
|
||||
"github.com/spf13/cobra"
|
||||
"go.podman.io/common/pkg/completion"
|
||||
"go.podman.io/common/pkg/resize"
|
||||
"go.podman.io/podman/v6/cmd/podman/common"
|
||||
"go.podman.io/podman/v6/cmd/podman/registry"
|
||||
"go.podman.io/podman/v6/cmd/podman/validate"
|
||||
|
|
@ -18,6 +19,7 @@ import (
|
|||
"go.podman.io/podman/v6/pkg/domain/entities"
|
||||
envLib "go.podman.io/podman/v6/pkg/env"
|
||||
"go.podman.io/podman/v6/pkg/rootless"
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -189,6 +191,16 @@ func exec(cmd *cobra.Command, args []string) error {
|
|||
streams.AttachOutput = true
|
||||
streams.AttachError = true
|
||||
|
||||
// When allocating a TTY, capture the current terminal size up front so the
|
||||
// exec pseudo-terminal is created at the right size, rather than relying on
|
||||
// the asynchronous resize that follows attach. This matters for short-lived
|
||||
// commands that read their window size at startup (e.g. `stty size`).
|
||||
if execOpts.Tty {
|
||||
if w, h, err := term.GetSize(int(os.Stdin.Fd())); err == nil {
|
||||
execOpts.ConsoleSize = &resize.TerminalSize{Width: uint16(w), Height: uint16(h)}
|
||||
}
|
||||
}
|
||||
|
||||
if execNoSession {
|
||||
exitCode, err := registry.ContainerEngine().ContainerExecNoSession(registry.Context(), nameOrID, execOpts, streams)
|
||||
registry.SetExitCode(exitCode)
|
||||
|
|
|
|||
|
|
@ -29,6 +29,12 @@ type ExecConfig struct {
|
|||
Command []string `json:"command"`
|
||||
// Terminal is whether the exec session will allocate a pseudoterminal.
|
||||
Terminal bool `json:"terminal,omitempty"`
|
||||
// ConsoleSize is an optional initial size for the exec session's
|
||||
// pseudoterminal, applied at creation when Terminal is true. This lets a
|
||||
// one-shot exec read the correct window size immediately instead of
|
||||
// relying on an asynchronous resize that may arrive after the process has
|
||||
// already started.
|
||||
ConsoleSize *resize.TerminalSize `json:"consoleSize,omitempty"`
|
||||
// AttachStdin is whether the STDIN stream will be forwarded to the exec
|
||||
// session's first process when attaching. Only available if Terminal is
|
||||
// false.
|
||||
|
|
@ -1180,6 +1186,7 @@ func prepareForExec(c *Container, session *ExecSession) (*ExecOptions, error) {
|
|||
opts.ExitCommand = session.Config.ExitCommand
|
||||
opts.ExitCommandDelay = session.Config.ExitCommandDelay
|
||||
opts.Privileged = session.Config.Privileged
|
||||
opts.ConsoleSize = session.Config.ConsoleSize
|
||||
|
||||
return opts, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -201,6 +201,9 @@ type ExecOptions struct {
|
|||
Env map[string]string
|
||||
// Terminal is whether to create a new TTY for the exec session.
|
||||
Terminal bool
|
||||
// ConsoleSize is an optional initial size for the exec session's TTY,
|
||||
// applied at creation when Terminal is true.
|
||||
ConsoleSize *resize.TerminalSize
|
||||
// Cwd is the working directory for the executed command. If unset, the
|
||||
// working directory of the container will be used.
|
||||
Cwd string
|
||||
|
|
|
|||
|
|
@ -704,6 +704,16 @@ func (c *Container) prepareProcessExec(options *ExecOptions, env []string, sessi
|
|||
pspec.Terminal = false
|
||||
if options.Terminal {
|
||||
pspec.Terminal = true
|
||||
// Size the exec PTY at creation so the process reads the correct
|
||||
// window size immediately. Without this the PTY starts at 0x0 and is
|
||||
// only corrected by an asynchronous resize, which can arrive after a
|
||||
// one-shot process has already read its size.
|
||||
if options.ConsoleSize != nil {
|
||||
pspec.ConsoleSize = &spec.Box{
|
||||
Height: uint(options.ConsoleSize.Height),
|
||||
Width: uint(options.ConsoleSize.Width),
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(env) > 0 {
|
||||
pspec.Env = append(pspec.Env, env...)
|
||||
|
|
|
|||
|
|
@ -42,6 +42,14 @@ func ExecCreateHandler(w http.ResponseWriter, r *http.Request) {
|
|||
libpodConfig := new(libpod.ExecConfig)
|
||||
libpodConfig.Command = input.Cmd
|
||||
libpodConfig.Terminal = input.Tty
|
||||
// Preserve the requested initial terminal size so the exec PTY can be sized
|
||||
// at creation (docker sends ConsoleSize as [height, width]).
|
||||
if input.ConsoleSize != nil {
|
||||
libpodConfig.ConsoleSize = &resize.TerminalSize{
|
||||
Height: uint16(input.ConsoleSize[0]),
|
||||
Width: uint16(input.ConsoleSize[1]),
|
||||
}
|
||||
}
|
||||
libpodConfig.AttachStdin = input.AttachStdin
|
||||
libpodConfig.AttachStderr = input.AttachStderr
|
||||
libpodConfig.AttachStdout = input.AttachStdout
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"time"
|
||||
|
||||
nettypes "go.podman.io/common/libnetwork/types"
|
||||
"go.podman.io/common/pkg/resize"
|
||||
imageTypes "go.podman.io/image/v5/types"
|
||||
"go.podman.io/podman/v6/libpod/define"
|
||||
"go.podman.io/podman/v6/pkg/domain/entities/types"
|
||||
|
|
@ -283,6 +284,7 @@ type ContainerLogsOptions struct {
|
|||
// a container
|
||||
type ExecOptions struct {
|
||||
Cmd []string
|
||||
ConsoleSize *resize.TerminalSize
|
||||
DetachKeys string
|
||||
Envs map[string]string
|
||||
Interactive bool
|
||||
|
|
|
|||
|
|
@ -890,6 +890,13 @@ func makeExecConfig(options entities.ExecOptions, rt *libpod.Runtime, noSession
|
|||
execConfig.PreserveFD = options.PreserveFD
|
||||
execConfig.AttachStdin = options.Interactive
|
||||
|
||||
// Size the exec terminal at creation so a process that reads its window size
|
||||
// at startup (e.g. `stty size`) observes the right value, rather than relying
|
||||
// on the asynchronous resize that follows attach.
|
||||
if options.Tty {
|
||||
execConfig.ConsoleSize = options.ConsoleSize
|
||||
}
|
||||
|
||||
// Only set up exit command for regular exec sessions, not no-session mode
|
||||
if !noSession {
|
||||
// Make an exit command
|
||||
|
|
|
|||
|
|
@ -618,6 +618,12 @@ func makeExecConfig(options entities.ExecOptions) *handlers.ExecCreateConfig {
|
|||
createConfig.Env = env
|
||||
createConfig.WorkingDir = options.WorkDir
|
||||
createConfig.Cmd = options.Cmd
|
||||
// Size the exec terminal at creation, mirroring the local path, so the
|
||||
// service does not have to rely on the asynchronous resize that follows
|
||||
// attach. ConsoleSize is ordered [height, width].
|
||||
if options.Tty && options.ConsoleSize != nil {
|
||||
createConfig.ConsoleSize = &[2]uint{uint(options.ConsoleSize.Height), uint(options.ConsoleSize.Width)}
|
||||
}
|
||||
|
||||
return createConfig
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,14 +70,15 @@ function teardown() {
|
|||
|
||||
run_podman rm -t 0 -f mystty
|
||||
|
||||
# FIXME: the checks below are flaking a lot (see #10710).
|
||||
# The same must hold for podman exec. The exec pseudo-terminal is now sized
|
||||
# at creation (honoring the requested ConsoleSize), so stty reads the right
|
||||
# dimensions immediately instead of racing the asynchronous resize that
|
||||
# previously followed attach (see #10710).
|
||||
run_podman run -d --name mystty $IMAGE top
|
||||
run_podman exec -it mystty stty size <$PODMAN_TEST_PTY
|
||||
is "$output" "$rows $cols$CR" "stty under podman exec reads the correct dimensions"
|
||||
|
||||
# check that the same works for podman exec
|
||||
# run_podman run -d --name mystty $IMAGE top
|
||||
# run_podman exec -it mystty stty size <$PODMAN_TEST_PTY
|
||||
# is "$output" "$rows $cols" "stty under podman exec reads the correct dimensions"
|
||||
#
|
||||
# run_podman rm -t 0 -f mystty
|
||||
run_podman rm -t 0 -f mystty
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue