소스 검색

Merge pull request #43593 from vvoland/3554-initial-console-size

daemon/linux: Set console size on creation
Sebastiaan van Stijn 3 년 전
부모
커밋
b6dab55339

+ 6 - 0
api/server/router/container/container_routes.go

@@ -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 != "" {

+ 9 - 9
api/swagger.yaml

@@ -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: |

+ 2 - 2
api/types/container/host_config.go

@@ -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,8 +446,7 @@ 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)
 	Resources
 	Resources

+ 8 - 1
client/container_create.go

@@ -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
 	}
 	}

+ 3 - 1
daemon/oci_linux.go

@@ -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 - 0
daemon/oci_opts.go

@@ -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
+	}
+}

+ 3 - 0
docs/api/version-history.md

@@ -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
 
 

+ 31 - 0
integration/container/run_linux_test.go

@@ -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")
+}

+ 7 - 0
integration/internal/container/ops.go

@@ -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}
+	}
+}