1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

daemon/linux: Set console size on creation

On Linux the daemon was not respecting the HostConfig.ConsoleSize
property and relied on cli initializing the tty size after the container
was created. This caused a delay between container creation and
the tty actually being resized.

This is also a small change to the api description, because
HostConfig.ConsoleSize is no longer Windows-only.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
This commit is contained in:
Paweł Gronowski 2022-05-12 14:54:44 +02:00
parent 1a0587bd76
commit 85a7f5a09a
9 changed files with 92 additions and 13 deletions

View file

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"runtime"
"strconv" "strconv"
"github.com/containerd/containerd/platforms" "github.com/containerd/containerd/platforms"
@ -517,6 +518,11 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
hostConfig.KernelMemory = 0 hostConfig.KernelMemory = 0
} }
if hostConfig != nil && runtime.GOOS == "linux" && versions.LessThan(version, "1.42") {
// ConsoleSize is not respected by Linux daemon before API 1.42
hostConfig.ConsoleSize = [2]uint{0, 0}
}
var platform *specs.Platform var platform *specs.Platform
if versions.GreaterThanOrEqualTo(version, "1.41") { if versions.GreaterThanOrEqualTo(version, "1.41") {
if v := r.Form.Get("platform"); v != "" { if v := r.Form.Get("platform"); v != "" {

View file

@ -955,6 +955,15 @@ definitions:
type: "array" type: "array"
items: items:
$ref: "#/definitions/Mount" $ref: "#/definitions/Mount"
ConsoleSize:
type: "array"
description: |
Initial console size, as an `[height, width]` array.
minItems: 2
maxItems: 2
items:
type: "integer"
minimum: 0
# Applicable to UNIX platforms # Applicable to UNIX platforms
CapAdd: CapAdd:
@ -1119,15 +1128,6 @@ definitions:
type: "string" type: "string"
description: "Runtime to use with this container." description: "Runtime to use with this container."
# Applicable to Windows # Applicable to Windows
ConsoleSize:
type: "array"
description: |
Initial console size, as an `[height, width]` array. (Windows only)
minItems: 2
maxItems: 2
items:
type: "integer"
minimum: 0
Isolation: Isolation:
type: "string" type: "string"
description: | description: |

View file

@ -417,6 +417,7 @@ type HostConfig struct {
AutoRemove bool // Automatically remove container when it exits AutoRemove bool // Automatically remove container when it exits
VolumeDriver string // Name of the volume driver used to mount volumes VolumeDriver string // Name of the volume driver used to mount volumes
VolumesFrom []string // List of volumes to take from other container VolumesFrom []string // List of volumes to take from other container
ConsoleSize [2]uint // Initial console size (height,width)
// Applicable to UNIX platforms // Applicable to UNIX platforms
CapAdd strslice.StrSlice // List of kernel capabilities to add to the container CapAdd strslice.StrSlice // List of kernel capabilities to add to the container
@ -445,7 +446,6 @@ type HostConfig struct {
Runtime string `json:",omitempty"` // Runtime to use with this container Runtime string `json:",omitempty"` // Runtime to use with this container
// Applicable to Windows // Applicable to Windows
ConsoleSize [2]uint // Initial console size (height,width)
Isolation Isolation // Isolation technology of the container (e.g. default, hyperv) Isolation Isolation // Isolation technology of the container (e.g. default, hyperv)
// Contains container's resources (cgroups, ulimits) // Contains container's resources (cgroups, ulimits)

View file

@ -27,11 +27,18 @@ func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config
return response, err return response, err
} }
clientVersion := cli.ClientVersion()
// When using API 1.24 and under, the client is responsible for removing the container // When using API 1.24 and under, the client is responsible for removing the container
if hostConfig != nil && versions.LessThan(cli.ClientVersion(), "1.25") { if hostConfig != nil && versions.LessThan(clientVersion, "1.25") {
hostConfig.AutoRemove = false hostConfig.AutoRemove = false
} }
// When using API under 1.42, the Linux daemon doesn't respect the ConsoleSize
if hostConfig != nil && platform != nil && platform.OS == "linux" && versions.LessThan(clientVersion, "1.42") {
hostConfig.ConsoleSize = [2]uint{0, 0}
}
if err := cli.NewVersionError("1.41", "specify container image platform"); platform != nil && err != nil { if err := cli.NewVersionError("1.41", "specify container image platform"); platform != nil && err != nil {
return response, err return response, err
} }

View file

@ -1023,7 +1023,9 @@ func (daemon *Daemon) createSpec(c *container.Container) (retSpec *specs.Spec, e
if c.NoNewPrivileges { if c.NoNewPrivileges {
opts = append(opts, coci.WithNoNewPrivileges) opts = append(opts, coci.WithNoNewPrivileges)
} }
if c.Config.Tty {
opts = append(opts, WithConsoleSize(c))
}
// Set the masked and readonly paths with regard to the host config options if they are set. // Set the masked and readonly paths with regard to the host config options if they are set.
if c.HostConfig.MaskedPaths != nil { if c.HostConfig.MaskedPaths != nil {
opts = append(opts, coci.WithMaskedPaths(c.HostConfig.MaskedPaths)) opts = append(opts, coci.WithMaskedPaths(c.HostConfig.MaskedPaths))

23
daemon/oci_opts.go Normal file
View file

@ -0,0 +1,23 @@
package daemon
import (
"context"
"github.com/containerd/containerd/containers"
coci "github.com/containerd/containerd/oci"
"github.com/docker/docker/container"
specs "github.com/opencontainers/runtime-spec/specs-go"
)
// WithConsoleSize sets the initial console size
func WithConsoleSize(c *container.Container) coci.SpecOpts {
return func(ctx context.Context, _ coci.Client, _ *containers.Container, s *coci.Spec) error {
if c.HostConfig.ConsoleSize[0] > 0 || c.HostConfig.ConsoleSize[1] > 0 {
s.Process.ConsoleSize = &specs.Box{
Height: c.HostConfig.ConsoleSize[0],
Width: c.HostConfig.ConsoleSize[1],
}
}
return nil
}
}

View file

@ -94,6 +94,9 @@ keywords: "API, Docker, rcli, REST, documentation"
actually supported. API versions before v1.42 continue to ignore these parameters actually supported. API versions before v1.42 continue to ignore these parameters
and default to attaching to all streams. To preserve the pre-v1.42 behavior, and default to attaching to all streams. To preserve the pre-v1.42 behavior,
set all three query parameters (`?stdin=1,stdout=1,stderr=1`). set all three query parameters (`?stdin=1,stdout=1,stderr=1`).
* `POST /containers/create` on Linux now respects the `HostConfig.ConsoleSize` property.
Container is immediately created with the desired terminal size and clients no longer
need to set the desired size on their own.
## v1.41 API changes ## v1.41 API changes

View file

@ -1,13 +1,16 @@
package container // import "github.com/docker/docker/integration/container" package container // import "github.com/docker/docker/integration/container"
import ( import (
"bytes"
"context" "context"
"io"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"testing" "testing"
"time" "time"
"github.com/docker/docker/api/types"
containertypes "github.com/docker/docker/api/types/container" containertypes "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/versions" "github.com/docker/docker/api/types/versions"
"github.com/docker/docker/integration/internal/container" "github.com/docker/docker/integration/internal/container"
@ -183,3 +186,31 @@ func TestPrivilegedHostDevices(t *testing.T) {
assert.Check(t, is.Equal(strings.TrimSpace(res.Stdout()), devRootOnlyTest)) assert.Check(t, is.Equal(strings.TrimSpace(res.Stdout()), devRootOnlyTest))
} }
} }
func TestConsoleSize(t *testing.T) {
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.42"), "skip test from new feature")
defer setupTest(t)()
client := testEnv.APIClient()
ctx := context.Background()
cID := container.Run(ctx, t, client,
container.WithTty(true),
container.WithImage("busybox"),
container.WithCmd("stty", "size"),
container.WithConsoleSize(57, 123),
)
poll.WaitOn(t, container.IsStopped(ctx, client, cID), poll.WithDelay(100*time.Millisecond))
out, err := client.ContainerLogs(ctx, cID, types.ContainerLogsOptions{ShowStdout: true})
assert.NilError(t, err)
defer out.Close()
var b bytes.Buffer
_, err = io.Copy(&b, out)
assert.NilError(t, err)
assert.Equal(t, strings.TrimSpace(b.String()), "123 57")
}

View file

@ -227,3 +227,10 @@ func WithIsolation(isolation containertypes.Isolation) func(*TestContainerConfig
c.HostConfig.Isolation = isolation c.HostConfig.Isolation = isolation
} }
} }
// WithConsoleSize sets the initial console size of the container
func WithConsoleSize(width, height uint) func(*TestContainerConfig) {
return func(c *TestContainerConfig) {
c.HostConfig.ConsoleSize = [2]uint{height, width}
}
}