mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Move container util methods to the container package.
Signed-off-by: Daniel Nephin <dnephin@docker.com>
This commit is contained in:
parent
bec81075bf
commit
31d8c27e70
6 changed files with 136 additions and 130 deletions
|
@ -46,8 +46,9 @@ func NewAttachCommand(dockerCli *client.DockerCli) *cobra.Command {
|
|||
|
||||
func runAttach(dockerCli *client.DockerCli, opts *attachOptions) error {
|
||||
ctx := context.Background()
|
||||
client := dockerCli.Client()
|
||||
|
||||
c, err := dockerCli.Client().ContainerInspect(ctx, opts.container)
|
||||
c, err := client.ContainerInspect(ctx, opts.container)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -82,11 +83,11 @@ func runAttach(dockerCli *client.DockerCli, opts *attachOptions) error {
|
|||
}
|
||||
|
||||
if opts.proxy && !c.Config.Tty {
|
||||
sigc := dockerCli.ForwardAllSignals(ctx, opts.container)
|
||||
sigc := ForwardAllSignals(ctx, dockerCli, opts.container)
|
||||
defer signal.StopCatch(sigc)
|
||||
}
|
||||
|
||||
resp, errAttach := dockerCli.Client().ContainerAttach(ctx, opts.container, options)
|
||||
resp, errAttach := client.ContainerAttach(ctx, opts.container, options)
|
||||
if errAttach != nil && errAttach != httputil.ErrPersistEOF {
|
||||
// ContainerAttach returns an ErrPersistEOF (connection closed)
|
||||
// means server met an error and put it in Hijacked connection
|
||||
|
@ -101,11 +102,11 @@ func runAttach(dockerCli *client.DockerCli, opts *attachOptions) error {
|
|||
// terminal, the only way to get the shell prompt to display for attaches 2+ is to artificially
|
||||
// resize it, then go back to normal. Without this, every attach after the first will
|
||||
// require the user to manually resize or hit enter.
|
||||
dockerCli.ResizeTtyTo(ctx, opts.container, height+1, width+1, false)
|
||||
resizeTtyTo(ctx, client, opts.container, height+1, width+1, false)
|
||||
|
||||
// After the above resizing occurs, the call to MonitorTtySize below will handle resetting back
|
||||
// to the actual size.
|
||||
if err := dockerCli.MonitorTtySize(ctx, opts.container, false); err != nil {
|
||||
if err := MonitorTtySize(ctx, dockerCli, opts.container, false); err != nil {
|
||||
logrus.Debugf("Error monitoring TTY size: %s", err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ import (
|
|||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/pkg/promise"
|
||||
apiclient "github.com/docker/docker/client"
|
||||
"github.com/docker/engine-api/types"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
@ -66,8 +68,9 @@ func runExec(dockerCli *client.DockerCli, opts *execOptions, container string, e
|
|||
execConfig.DetachKeys = dockerCli.ConfigFile().DetachKeys
|
||||
|
||||
ctx := context.Background()
|
||||
client := dockerCli.Client()
|
||||
|
||||
response, err := dockerCli.Client().ContainerExecCreate(ctx, container, *execConfig)
|
||||
response, err := client.ContainerExecCreate(ctx, container, *execConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -89,7 +92,7 @@ func runExec(dockerCli *client.DockerCli, opts *execOptions, container string, e
|
|||
Tty: execConfig.Tty,
|
||||
}
|
||||
|
||||
if err := dockerCli.Client().ContainerExecStart(ctx, execID, execStartCheck); err != nil {
|
||||
if err := client.ContainerExecStart(ctx, execID, execStartCheck); err != nil {
|
||||
return err
|
||||
}
|
||||
// For now don't print this - wait for when we support exec wait()
|
||||
|
@ -118,7 +121,7 @@ func runExec(dockerCli *client.DockerCli, opts *execOptions, container string, e
|
|||
}
|
||||
}
|
||||
|
||||
resp, err := dockerCli.Client().ContainerExecAttach(ctx, execID, *execConfig)
|
||||
resp, err := client.ContainerExecAttach(ctx, execID, *execConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -128,7 +131,7 @@ func runExec(dockerCli *client.DockerCli, opts *execOptions, container string, e
|
|||
})
|
||||
|
||||
if execConfig.Tty && dockerCli.In().IsTerminal() {
|
||||
if err := dockerCli.MonitorTtySize(ctx, execID, true); err != nil {
|
||||
if err := MonitorTtySize(ctx, dockerCli, execID, true); err != nil {
|
||||
fmt.Fprintf(dockerCli.Err(), "Error monitoring TTY size: %s\n", err)
|
||||
}
|
||||
}
|
||||
|
@ -139,7 +142,7 @@ func runExec(dockerCli *client.DockerCli, opts *execOptions, container string, e
|
|||
}
|
||||
|
||||
var status int
|
||||
if _, status, err = dockerCli.GetExecExitCode(ctx, execID); err != nil {
|
||||
if _, status, err = getExecExitCode(ctx, client, execID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -150,6 +153,21 @@ func runExec(dockerCli *client.DockerCli, opts *execOptions, container string, e
|
|||
return nil
|
||||
}
|
||||
|
||||
// getExecExitCode perform an inspect on the exec command. It returns
|
||||
// the running state and the exit code.
|
||||
func getExecExitCode(ctx context.Context, client apiclient.ContainerAPIClient, execID string) (bool, int, error) {
|
||||
resp, err := client.ContainerExecInspect(ctx, execID)
|
||||
if err != nil {
|
||||
// If we can't connect, then the daemon probably died.
|
||||
if err != apiclient.ErrConnectionFailed {
|
||||
return false, -1, err
|
||||
}
|
||||
return false, -1, nil
|
||||
}
|
||||
|
||||
return resp.Running, resp.ExitCode, nil
|
||||
}
|
||||
|
||||
// parseExec parses the specified args for the specified command and generates
|
||||
// an ExecConfig from it.
|
||||
func parseExec(opts *execOptions, container string, execCmd []string) (*types.ExecConfig, error) {
|
||||
|
|
|
@ -146,7 +146,7 @@ func runRun(dockerCli *client.DockerCli, flags *pflag.FlagSet, opts *runOptions,
|
|||
return runStartContainerErr(err)
|
||||
}
|
||||
if opts.sigProxy {
|
||||
sigc := dockerCli.ForwardAllSignals(ctx, createResponse.ID)
|
||||
sigc := ForwardAllSignals(ctx, dockerCli, createResponse.ID)
|
||||
defer signal.StopCatch(sigc)
|
||||
}
|
||||
var (
|
||||
|
@ -235,7 +235,7 @@ func runRun(dockerCli *client.DockerCli, flags *pflag.FlagSet, opts *runOptions,
|
|||
}
|
||||
|
||||
if (config.AttachStdin || config.AttachStdout || config.AttachStderr) && config.Tty && dockerCli.Out().IsTerminal() {
|
||||
if err := dockerCli.MonitorTtySize(ctx, createResponse.ID, false); err != nil {
|
||||
if err := MonitorTtySize(ctx, dockerCli, createResponse.ID, false); err != nil {
|
||||
fmt.Fprintf(stderr, "Error monitoring TTY size: %s\n", err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ func runStart(dockerCli *client.DockerCli, opts *startOptions) error {
|
|||
|
||||
// We always use c.ID instead of container to maintain consistency during `docker start`
|
||||
if !c.Config.Tty {
|
||||
sigc := dockerCli.ForwardAllSignals(ctx, c.ID)
|
||||
sigc := ForwardAllSignals(ctx, dockerCli, c.ID)
|
||||
defer signal.StopCatch(sigc)
|
||||
}
|
||||
|
||||
|
@ -119,7 +119,7 @@ func runStart(dockerCli *client.DockerCli, opts *startOptions) error {
|
|||
|
||||
// 5. Wait for attachment to break.
|
||||
if c.Config.Tty && dockerCli.Out().IsTerminal() {
|
||||
if err := dockerCli.MonitorTtySize(ctx, c.ID, false); err != nil {
|
||||
if err := MonitorTtySize(ctx, dockerCli, c.ID, false); err != nil {
|
||||
fmt.Fprintf(dockerCli.Err(), "Error monitoring TTY size: %s\n", err)
|
||||
}
|
||||
}
|
||||
|
|
103
api/client/container/tty.go
Normal file
103
api/client/container/tty.go
Normal file
|
@ -0,0 +1,103 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
gosignal "os/signal"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/client"
|
||||
"github.com/docker/docker/pkg/signal"
|
||||
apiclient "github.com/docker/engine-api/client"
|
||||
"github.com/docker/engine-api/types"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// ResizeTtyTo resizes tty to specific height and width
|
||||
func resizeTtyTo(ctx context.Context, client apiclient.ContainerAPIClient, id string, height, width int, isExec bool) {
|
||||
if height == 0 && width == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
options := types.ResizeOptions{
|
||||
Height: height,
|
||||
Width: width,
|
||||
}
|
||||
|
||||
var err error
|
||||
if isExec {
|
||||
err = client.ContainerExecResize(ctx, id, options)
|
||||
} else {
|
||||
err = client.ContainerResize(ctx, id, options)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
logrus.Debugf("Error resize: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// MonitorTtySize updates the container tty size when the terminal tty changes size
|
||||
func MonitorTtySize(ctx context.Context, cli *client.DockerCli, id string, isExec bool) error {
|
||||
resizeTty := func() {
|
||||
height, width := cli.Out().GetTtySize()
|
||||
resizeTtyTo(ctx, cli.Client(), id, height, width, isExec)
|
||||
}
|
||||
|
||||
resizeTty()
|
||||
|
||||
if runtime.GOOS == "windows" {
|
||||
go func() {
|
||||
prevH, prevW := cli.Out().GetTtySize()
|
||||
for {
|
||||
time.Sleep(time.Millisecond * 250)
|
||||
h, w := cli.Out().GetTtySize()
|
||||
|
||||
if prevW != w || prevH != h {
|
||||
resizeTty()
|
||||
}
|
||||
prevH = h
|
||||
prevW = w
|
||||
}
|
||||
}()
|
||||
} else {
|
||||
sigchan := make(chan os.Signal, 1)
|
||||
gosignal.Notify(sigchan, signal.SIGWINCH)
|
||||
go func() {
|
||||
for range sigchan {
|
||||
resizeTty()
|
||||
}
|
||||
}()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ForwardAllSignals forwards signals to the container
|
||||
func ForwardAllSignals(ctx context.Context, cli *client.DockerCli, cid string) chan os.Signal {
|
||||
sigc := make(chan os.Signal, 128)
|
||||
signal.CatchAll(sigc)
|
||||
go func() {
|
||||
for s := range sigc {
|
||||
if s == signal.SIGCHLD || s == signal.SIGPIPE {
|
||||
continue
|
||||
}
|
||||
var sig string
|
||||
for sigStr, sigN := range signal.SignalMap {
|
||||
if sigN == s {
|
||||
sig = sigStr
|
||||
break
|
||||
}
|
||||
}
|
||||
if sig == "" {
|
||||
fmt.Fprintf(cli.Err(), "Unsupported signal: %v. Discarding.\n", s)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := cli.Client().ContainerKill(ctx, cid, sig); err != nil {
|
||||
logrus.Debugf("Error sending signal: %s", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
return sigc
|
||||
}
|
|
@ -5,95 +5,10 @@ import (
|
|||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
gosignal "os/signal"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/pkg/signal"
|
||||
"github.com/docker/engine-api/types"
|
||||
)
|
||||
|
||||
func (cli *DockerCli) resizeTty(ctx context.Context, id string, isExec bool) {
|
||||
height, width := cli.Out().GetTtySize()
|
||||
cli.ResizeTtyTo(ctx, id, height, width, isExec)
|
||||
}
|
||||
|
||||
// ResizeTtyTo resizes tty to specific height and width
|
||||
// TODO: this can be unexported again once all container related commands move to package container
|
||||
func (cli *DockerCli) ResizeTtyTo(ctx context.Context, id string, height, width int, isExec bool) {
|
||||
if height == 0 && width == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
options := types.ResizeOptions{
|
||||
Height: height,
|
||||
Width: width,
|
||||
}
|
||||
|
||||
var err error
|
||||
if isExec {
|
||||
err = cli.client.ContainerExecResize(ctx, id, options)
|
||||
} else {
|
||||
err = cli.client.ContainerResize(ctx, id, options)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
logrus.Debugf("Error resize: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// GetExecExitCode perform an inspect on the exec command. It returns
|
||||
// the running state and the exit code.
|
||||
func (cli *DockerCli) GetExecExitCode(ctx context.Context, execID string) (bool, int, error) {
|
||||
resp, err := cli.client.ContainerExecInspect(ctx, execID)
|
||||
if err != nil {
|
||||
// If we can't connect, then the daemon probably died.
|
||||
if err != client.ErrConnectionFailed {
|
||||
return false, -1, err
|
||||
}
|
||||
return false, -1, nil
|
||||
}
|
||||
|
||||
return resp.Running, resp.ExitCode, nil
|
||||
}
|
||||
|
||||
// MonitorTtySize updates the container tty size when the terminal tty changes size
|
||||
func (cli *DockerCli) MonitorTtySize(ctx context.Context, id string, isExec bool) error {
|
||||
cli.resizeTty(ctx, id, isExec)
|
||||
|
||||
if runtime.GOOS == "windows" {
|
||||
go func() {
|
||||
prevH, prevW := cli.Out().GetTtySize()
|
||||
for {
|
||||
time.Sleep(time.Millisecond * 250)
|
||||
h, w := cli.Out().GetTtySize()
|
||||
|
||||
if prevW != w || prevH != h {
|
||||
cli.resizeTty(ctx, id, isExec)
|
||||
}
|
||||
prevH = h
|
||||
prevW = w
|
||||
}
|
||||
}()
|
||||
} else {
|
||||
sigchan := make(chan os.Signal, 1)
|
||||
gosignal.Notify(sigchan, signal.SIGWINCH)
|
||||
go func() {
|
||||
for range sigchan {
|
||||
cli.resizeTty(ctx, id, isExec)
|
||||
}
|
||||
}()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CopyToFile writes the content of the reader to the specified file
|
||||
func CopyToFile(outfile string, r io.Reader) error {
|
||||
tmpFile, err := ioutil.TempFile(filepath.Dir(outfile), ".docker_temp_")
|
||||
|
@ -119,37 +34,6 @@ func CopyToFile(outfile string, r io.Reader) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ForwardAllSignals forwards signals to the container
|
||||
// TODO: this can be unexported again once all container commands are under
|
||||
// api/client/container
|
||||
func (cli *DockerCli) ForwardAllSignals(ctx context.Context, cid string) chan os.Signal {
|
||||
sigc := make(chan os.Signal, 128)
|
||||
signal.CatchAll(sigc)
|
||||
go func() {
|
||||
for s := range sigc {
|
||||
if s == signal.SIGCHLD || s == signal.SIGPIPE {
|
||||
continue
|
||||
}
|
||||
var sig string
|
||||
for sigStr, sigN := range signal.SignalMap {
|
||||
if sigN == s {
|
||||
sig = sigStr
|
||||
break
|
||||
}
|
||||
}
|
||||
if sig == "" {
|
||||
fmt.Fprintf(cli.err, "Unsupported signal: %v. Discarding.\n", s)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := cli.client.ContainerKill(ctx, cid, sig); err != nil {
|
||||
logrus.Debugf("Error sending signal: %s", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
return sigc
|
||||
}
|
||||
|
||||
// capitalizeFirst capitalizes the first character of string
|
||||
func capitalizeFirst(s string) string {
|
||||
switch l := len(s); l {
|
||||
|
|
Loading…
Add table
Reference in a new issue