Skip to content

Commit

Permalink
Add a --skip-idle-time flag to tsh play (#44013)
Browse files Browse the repository at this point in the history
This tells tsh to respect timing data (and the configured playback
speed) while there is active recording data, but to skip over larger
periods of idle time.
  • Loading branch information
zmb3 authored Jul 16, 2024
1 parent 8b54439 commit 2d628ff
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 18 deletions.
2 changes: 1 addition & 1 deletion e
Submodule e updated from b8d84d to 81b1b5
15 changes: 8 additions & 7 deletions lib/client/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -2123,7 +2123,7 @@ func (tc *TeleportClient) Join(ctx context.Context, mode types.SessionParticipan
}

// Play replays the recorded session.
func (tc *TeleportClient) Play(ctx context.Context, sessionID string, speed float64) error {
func (tc *TeleportClient) Play(ctx context.Context, sessionID string, speed float64, skipIdleTime bool) error {
ctx, span := tc.Tracer.Start(
ctx,
"teleportClient/Play",
Expand All @@ -2140,7 +2140,7 @@ func (tc *TeleportClient) Play(ctx context.Context, sessionID string, speed floa
}
defer clusterClient.Close()

return playSession(ctx, sessionID, speed, clusterClient.AuthClient)
return playSession(ctx, sessionID, speed, clusterClient.AuthClient, skipIdleTime)
}

const (
Expand All @@ -2153,7 +2153,7 @@ const (
keyDown = 66
)

func playSession(ctx context.Context, sessionID string, speed float64, streamer libplayer.Streamer) error {
func playSession(ctx context.Context, sessionID string, speed float64, streamer libplayer.Streamer, skipIdleTime bool) error {
sid, err := session.ParseID(sessionID)
if err != nil {
return trace.Wrap(err)
Expand All @@ -2177,8 +2177,9 @@ func playSession(ctx context.Context, sessionID string, speed float64, streamer
term.SetCursorPos(1, 1)

player, err := libplayer.New(&libplayer.Config{
SessionID: *sid,
Streamer: streamer,
SessionID: *sid,
Streamer: streamer,
SkipIdleTime: skipIdleTime,
})
if err != nil {
return trace.Wrap(err)
Expand Down Expand Up @@ -2273,9 +2274,9 @@ func setTermSize(w io.Writer, size string) error {
}

// PlayFile plays the recorded session from a file.
func PlayFile(ctx context.Context, filename, sid string, speed float64) error {
func PlayFile(ctx context.Context, filename, sid string, speed float64, skipIdleTime bool) error {
streamer := &playFromFileStreamer{filename: filename}
return playSession(ctx, sid, speed, streamer)
return playSession(ctx, sid, speed, streamer, skipIdleTime)
}

// SFTP securely copies files between Nodes or SSH servers using SFTP
Expand Down
21 changes: 13 additions & 8 deletions lib/player/player.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,11 @@ import (
// Player is used to stream recorded sessions over a channel.
type Player struct {
// read only config fields
clock clockwork.Clock
log logrus.FieldLogger
sessionID session.ID
streamer Streamer
clock clockwork.Clock
log logrus.FieldLogger
sessionID session.ID
streamer Streamer
skipIdleTime bool

speed atomic.Value // playback speed (1.0 for normal speed)
lastPlayed atomic.Int64 // timestamp of most recently played event
Expand Down Expand Up @@ -106,10 +107,11 @@ type sessionPrintTranslator interface {

// Config configures a session player.
type Config struct {
Clock clockwork.Clock
Log logrus.FieldLogger
SessionID session.ID
Streamer Streamer
Clock clockwork.Clock
Log logrus.FieldLogger
SessionID session.ID
Streamer Streamer
SkipIdleTime bool
}

func New(cfg *Config) (*Player, error) {
Expand Down Expand Up @@ -337,6 +339,9 @@ loop:
// will not apply until after the sleep completes
speed := p.speed.Load().(float64)
scaled := float64(currentDelay-lastDelay) / speed
if p.skipIdleTime {
scaled = min(scaled, 500.0*float64(time.Millisecond))
}

timer := p.clock.NewTimer(time.Duration(scaled) * time.Millisecond)
defer timer.Stop()
Expand Down
4 changes: 2 additions & 2 deletions tool/tsh/common/play.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func playSession(cf *CLIConf) error {
isLocalFile := path.Ext(cf.SessionID) == ".tar"
if isLocalFile {
sid := sessionIDFromPath(cf.SessionID)
if err := client.PlayFile(cf.Context, cf.SessionID, sid, speed); err != nil {
if err := client.PlayFile(cf.Context, cf.SessionID, sid, speed, cf.NoWait); err != nil {
return trace.Wrap(err)
}
return nil
Expand All @@ -89,7 +89,7 @@ func playSession(cf *CLIConf) error {
return trace.Wrap(err)
}

if err := tc.Play(cf.Context, cf.SessionID, speed); err != nil {
if err := tc.Play(cf.Context, cf.SessionID, speed, cf.NoWait); err != nil {
if trace.IsNotFound(err) {
log.WithError(err).Debug("error playing session")
return trace.NotFound("Recording for session %s not found.", cf.SessionID)
Expand Down
1 change: 1 addition & 0 deletions tool/tsh/common/tsh.go
Original file line number Diff line number Diff line change
Expand Up @@ -969,6 +969,7 @@ func Run(ctx context.Context, args []string, opts ...CliOption) error {
play := app.Command("play", "Replay the recorded session (SSH, Kubernetes, App, DB).")
play.Flag("cluster", clusterHelp).Short('c').StringVar(&cf.SiteName)
play.Flag("speed", "Playback speed, applicable when streaming SSH or Kubernetes sessions.").Default("1x").EnumVar(&cf.PlaySpeed, "0.5x", "1x", "2x", "4x", "8x")
play.Flag("skip-idle-time", "Quickly skip over idle time, applicable when streaming SSH or Kubernetes sessions.").BoolVar(&cf.NoWait)
play.Flag("format", defaults.FormatFlagDescription(
teleport.PTY, teleport.JSON, teleport.YAML,
)).Short('f').Default(teleport.PTY).EnumVar(&cf.Format, teleport.PTY, teleport.JSON, teleport.YAML)
Expand Down

0 comments on commit 2d628ff

Please sign in to comment.