| package container |
| |
| import ( |
| "fmt" |
| "os" |
| gosignal "os/signal" |
| "runtime" |
| "time" |
| |
| "github.com/Sirupsen/logrus" |
| "github.com/docker/docker/api/types" |
| "github.com/docker/docker/cli/command" |
| "github.com/docker/docker/client" |
| "github.com/docker/docker/pkg/signal" |
| "golang.org/x/net/context" |
| ) |
| |
| // resizeTtyTo resizes tty to specific height and width |
| func resizeTtyTo(ctx context.Context, client client.ContainerAPIClient, id string, height, width uint, 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 *command.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 *command.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 |
| } |