mirror of
https://github.com/tailscale/tailscale.git
synced 2025-12-24 17:47:30 +00:00
cmd/k8s-operator,k8s-operator/sessionrecording: ensure recording header contains terminal size for terminal sessions (#12965)
* cmd/k8s-operator,k8s-operator/sessonrecording: ensure CastHeader contains terminal size For tsrecorder to be able to play session recordings, the recording's CastHeader must have '.Width' and '.Height' fields set to non-zero. Kubectl (or whoever is the client that initiates the 'kubectl exec' session recording) sends the terminal dimensions in a resize message that the API server proxy can intercept, however that races with the first server message that we need to record. This PR ensures we wait for the terminal dimensions to be processed from the first resize message before any other data is sent, so that for all sessions with terminal attached, the header of the session recording contains the terminal dimensions and the recording can be played by tsrecorder. Updates tailscale/tailscale#19821 Signed-off-by: Irbe Krumina <irbe@tailscale.com>
This commit is contained in:
@@ -65,6 +65,7 @@ func Test_conn_Read(t *testing.T) {
|
||||
log: zl.Sugar(),
|
||||
}
|
||||
for i, input := range tt.inputs {
|
||||
c.initialTermSizeSet = make(chan struct{})
|
||||
if err := tc.WriteReadBufBytes(input); err != nil {
|
||||
t.Fatalf("writing bytes to test conn: %v", err)
|
||||
}
|
||||
@@ -93,13 +94,15 @@ func Test_conn_Write(t *testing.T) {
|
||||
}
|
||||
cl := tstest.NewClock(tstest.ClockOpts{})
|
||||
tests := []struct {
|
||||
name string
|
||||
inputs [][]byte
|
||||
wantForwarded []byte
|
||||
wantRecorded []byte
|
||||
firstWrite bool
|
||||
width int
|
||||
height int
|
||||
name string
|
||||
inputs [][]byte
|
||||
wantForwarded []byte
|
||||
wantRecorded []byte
|
||||
firstWrite bool
|
||||
width int
|
||||
height int
|
||||
hasTerm bool
|
||||
sendInitialResize bool
|
||||
}{
|
||||
{
|
||||
name: "single_write_control_frame",
|
||||
@@ -144,12 +147,23 @@ func Test_conn_Write(t *testing.T) {
|
||||
wantForwarded: []byte{0x2, 0x3, 0x1, 0x7, 0x8, 0x80, 0x6, 0x1, 0x1, 0x2, 0x3, 0x4, 0x5},
|
||||
wantRecorded: fakes.CastLine(t, []byte{0x7, 0x8, 0x1, 0x2, 0x3, 0x4, 0x5}, cl),
|
||||
},
|
||||
{
|
||||
name: "three_writes_stdout_data_message_with_split_fragment_cast_header_with_terminal",
|
||||
inputs: [][]byte{{0x2, 0x3, 0x1, 0x7, 0x8}, {0x80, 0x6, 0x1, 0x1, 0x2, 0x3}, {0x4, 0x5}},
|
||||
wantForwarded: []byte{0x2, 0x3, 0x1, 0x7, 0x8, 0x80, 0x6, 0x1, 0x1, 0x2, 0x3, 0x4, 0x5},
|
||||
wantRecorded: append(fakes.AsciinemaResizeMsg(t, 10, 20), fakes.CastLine(t, []byte{0x7, 0x8, 0x1, 0x2, 0x3, 0x4, 0x5}, cl)...),
|
||||
height: 20,
|
||||
width: 10,
|
||||
hasTerm: true,
|
||||
firstWrite: true,
|
||||
sendInitialResize: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tc := &fakes.TestConn{}
|
||||
sr := &fakes.TestSessionRecorder{}
|
||||
rec := tsrecorder.New(sr, cl, cl.Now(), true)
|
||||
rec := tsrecorder.New(sr, cl, cl.Now(), true, zl.Sugar())
|
||||
c := &conn{
|
||||
Conn: tc,
|
||||
log: zl.Sugar(),
|
||||
@@ -157,12 +171,17 @@ func Test_conn_Write(t *testing.T) {
|
||||
Width: tt.width,
|
||||
Height: tt.height,
|
||||
},
|
||||
rec: rec,
|
||||
rec: rec,
|
||||
initialTermSizeSet: make(chan struct{}),
|
||||
hasTerm: tt.hasTerm,
|
||||
}
|
||||
if !tt.firstWrite {
|
||||
// This test case does not intend to test that cast header gets written once.
|
||||
c.writeCastHeaderOnce.Do(func() {})
|
||||
}
|
||||
if tt.sendInitialResize {
|
||||
close(c.initialTermSizeSet)
|
||||
}
|
||||
for i, input := range tt.inputs {
|
||||
_, err := c.Write(input)
|
||||
if err != nil {
|
||||
@@ -221,7 +240,7 @@ func Test_conn_WriteRand(t *testing.T) {
|
||||
}
|
||||
cl := tstest.NewClock(tstest.ClockOpts{})
|
||||
sr := &fakes.TestSessionRecorder{}
|
||||
rec := tsrecorder.New(sr, cl, cl.Now(), true)
|
||||
rec := tsrecorder.New(sr, cl, cl.Now(), true, zl.Sugar())
|
||||
for i := range 100 {
|
||||
tc := &fakes.TestConn{}
|
||||
c := &conn{
|
||||
|
||||
Reference in New Issue
Block a user