mirror of
https://github.com/weaveworks/scope.git
synced 2026-07-28 09:41:57 +00:00
Implement App endpoint /pipe/{id}/resize_tty/{height}/{width} to resize ttys
This commit is contained in:
committed by
Simon Howe
parent
654ba35be6
commit
c2f2a90b61
51
app/pipes.go
51
app/pipes.go
@@ -2,6 +2,7 @@ package app
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/gorilla/mux"
|
||||
@@ -15,7 +16,12 @@ func RegisterPipeRoutes(router *mux.Router, pr PipeRouter) {
|
||||
router.Methods("GET").
|
||||
Name("api_pipe_pipeid_check").
|
||||
Path("/api/pipe/{pipeID}/check").
|
||||
HandlerFunc(requestContextDecorator(checkPipe(pr, UIEnd)))
|
||||
HandlerFunc(requestContextDecorator(checkPipe(pr)))
|
||||
|
||||
router.Methods("POST").
|
||||
Name("api_pipe_pipeid_resize_tty").
|
||||
Path("/api/pipe/{pipeID}/resize_tty/{height}/{width}").
|
||||
HandlerFunc(requestContextDecorator(resizeTTY(pr)))
|
||||
|
||||
router.Methods("GET").
|
||||
Name("api_pipe_pipeid").
|
||||
@@ -33,7 +39,7 @@ func RegisterPipeRoutes(router *mux.Router, pr PipeRouter) {
|
||||
HandlerFunc(requestContextDecorator(deletePipe(pr)))
|
||||
}
|
||||
|
||||
func checkPipe(pr PipeRouter, end End) CtxHandlerFunc {
|
||||
func checkPipe(pr PipeRouter) CtxHandlerFunc {
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
id := mux.Vars(r)["pipeID"]
|
||||
exists, err := pr.Exists(ctx, id)
|
||||
@@ -47,6 +53,47 @@ func checkPipe(pr PipeRouter, end End) CtxHandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
func resizeTTY(pr PipeRouter) CtxHandlerFunc {
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
height, width uint64
|
||||
err error
|
||||
)
|
||||
id := mux.Vars(r)["pipeID"]
|
||||
height, err = strconv.ParseUint(mux.Vars(r)["height"], 10, 32)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
width, err = strconv.ParseUint(mux.Vars(r)["width"], 10, 32)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
pipe, _, err := pr.Get(ctx, id, ProbeEnd)
|
||||
if err != nil {
|
||||
log.Debugf("Error getting pipe %s: %v", id, err)
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
tty := pipe.GetTTY()
|
||||
if tty == nil {
|
||||
// The pipe doesn't have a tty, nothing to do
|
||||
log.Debugf("Error getting terminal for pipe %s", id)
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
if err = tty.SetSize(uint(height), uint(width)); err != nil {
|
||||
log.Errorf("Error setting terminal size (%d, %d) of pipe %s: %v", height, width, id, err)
|
||||
respondWith(w, http.StatusInternalServerError, err)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func handlePipeWs(pr PipeRouter, end End) CtxHandlerFunc {
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
id := mux.Vars(r)["pipeID"]
|
||||
|
||||
@@ -7,12 +7,20 @@ import (
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
// Pipe is a bi-directional channel from someone thing in the probe
|
||||
// A TTY is a terminal with an associated height and width
|
||||
type TTY interface {
|
||||
SetSize(height, width uint) error
|
||||
}
|
||||
|
||||
// Pipe is a bi-directional channel from something in the probe
|
||||
// to the UI.
|
||||
type Pipe interface {
|
||||
Ends() (io.ReadWriter, io.ReadWriter)
|
||||
CopyToWebsocket(io.ReadWriter, Websocket) error
|
||||
|
||||
SetTTY(TTY)
|
||||
GetTTY() TTY
|
||||
|
||||
Close() error
|
||||
Closed() bool
|
||||
OnClose(func())
|
||||
@@ -26,6 +34,7 @@ type pipe struct {
|
||||
quit chan struct{}
|
||||
closed bool
|
||||
onClose func()
|
||||
tty TTY
|
||||
}
|
||||
|
||||
// NewPipeFromEnds makes a new pipe specifying its ends
|
||||
@@ -65,6 +74,13 @@ func (p *pipe) Ends() (io.ReadWriter, io.ReadWriter) {
|
||||
return p.port, p.starboard
|
||||
}
|
||||
|
||||
func (p *pipe) SetTTY(tty TTY) {
|
||||
p.tty = tty
|
||||
}
|
||||
func (p *pipe) GetTTY() TTY {
|
||||
return p.tty
|
||||
}
|
||||
|
||||
func (p *pipe) Close() error {
|
||||
p.mtx.Lock()
|
||||
var onClose func()
|
||||
|
||||
@@ -105,6 +105,15 @@ func (r *registry) attachContainer(containerID string, req xfer.Request) xfer.Re
|
||||
}
|
||||
}
|
||||
|
||||
type execTTY struct {
|
||||
client Client
|
||||
execID string
|
||||
}
|
||||
|
||||
func (e execTTY) SetSize(height, width uint) error {
|
||||
return e.client.ResizeExecTTY(e.execID, int(height), int(width))
|
||||
}
|
||||
|
||||
func (r *registry) execContainer(containerID string, req xfer.Request) xfer.Response {
|
||||
exec, err := r.client.CreateExec(docker_client.CreateExecOptions{
|
||||
AttachStdin: true,
|
||||
@@ -122,6 +131,8 @@ func (r *registry) execContainer(containerID string, req xfer.Request) xfer.Resp
|
||||
if err != nil {
|
||||
return xfer.ResponseError(err)
|
||||
}
|
||||
pipe.SetTTY(execTTY{r.client, exec.ID})
|
||||
|
||||
local, _ := pipe.Ends()
|
||||
cw, err := r.client.StartExecNonBlocking(exec.ID, docker_client.StartExecOptions{
|
||||
Tty: true,
|
||||
|
||||
@@ -47,6 +47,8 @@ func (mockPipe) CopyToWebsocket(io.ReadWriter, xfer.Websocket) error { return ni
|
||||
func (mockPipe) Close() error { return nil }
|
||||
func (mockPipe) Closed() bool { return false }
|
||||
func (mockPipe) OnClose(func()) {}
|
||||
func (mockPipe) GetTTY() xfer.TTY { return nil }
|
||||
func (mockPipe) SetTTY(xfer.TTY) {}
|
||||
|
||||
func TestPipes(t *testing.T) {
|
||||
oldNewPipe := controls.NewPipe
|
||||
|
||||
@@ -86,6 +86,7 @@ type Client interface {
|
||||
CreateExec(docker_client.CreateExecOptions) (*docker_client.Exec, error)
|
||||
StartExecNonBlocking(string, docker_client.StartExecOptions) (docker_client.CloseWaiter, error)
|
||||
Stats(docker_client.StatsOptions) error
|
||||
ResizeExecTTY(id string, height, width int) error
|
||||
}
|
||||
|
||||
func newDockerClient(endpoint string) (Client, error) {
|
||||
|
||||
@@ -167,6 +167,10 @@ func (m *mockDockerClient) Stats(_ client.StatsOptions) error {
|
||||
return fmt.Errorf("stats")
|
||||
}
|
||||
|
||||
func (m *mockDockerClient) ResizeExecTTY(id string, height, width int) error {
|
||||
return fmt.Errorf("resizeExecTTY")
|
||||
}
|
||||
|
||||
type mockCloseWaiter struct{}
|
||||
|
||||
func (mockCloseWaiter) Close() error { return nil }
|
||||
|
||||
Reference in New Issue
Block a user