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:
parent
1a0587bd76
commit
85a7f5a09a
9 changed files with 92 additions and 13 deletions
|
@ -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 != "" {
|
||||||
|
|
|
@ -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: |
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
23
daemon/oci_opts.go
Normal 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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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")
|
||||||
|
}
|
||||||
|
|
|
@ -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}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue