From a27bd926b326f2937e7dcb1b2c82510345eb68d3 Mon Sep 17 00:00:00 2001 From: Justinas Stankevicius Date: Thu, 29 Jun 2023 16:25:47 +0300 Subject: [PATCH 1/7] Mark nodes as done when command finishes in Assist --- lib/benchmark/web.go | 2 +- lib/web/command.go | 7 +++- lib/web/terminal.go | 17 ++++++++-- .../src/Assist/context/AssistContext.tsx | 34 ++++++------------- 4 files changed, 32 insertions(+), 28 deletions(-) diff --git a/lib/benchmark/web.go b/lib/benchmark/web.go index 6be3bfc559891..cbf4184d6ab3a 100644 --- a/lib/benchmark/web.go +++ b/lib/benchmark/web.go @@ -99,7 +99,7 @@ func (s WebSSHBenchmark) runCommand(ctx context.Context, tc *client.TeleportClie if err != nil { return trace.Wrap(err) } - defer stream.Close() + defer stream.Close("{}") if _, err := io.WriteString(stream, command); err != nil { return trace.Wrap(err) diff --git a/lib/web/command.go b/lib/web/command.go index 7a92ca483513d..f6e3c5bef06a7 100644 --- a/lib/web/command.go +++ b/lib/web/command.go @@ -550,7 +550,12 @@ func (t *commandHandler) streamOutput(ctx context.Context, tc *client.TeleportCl return } - if err := t.stream.Close(); err != nil { + sessionMetadataPayload, err := json.Marshal(siteSessionGenerateResponse{Session: t.sessionData}) + if err != nil { + t.log.WithError(err).Warn("Could not marshal session metadata for the close event") + return + } + if err := t.stream.Close(string(sessionMetadataPayload)); err != nil { t.log.WithError(err).Error("Unable to send close event to web client.") return } diff --git a/lib/web/terminal.go b/lib/web/terminal.go index 09d1c3f96b9c1..56c6617ad54af 100644 --- a/lib/web/terminal.go +++ b/lib/web/terminal.go @@ -357,10 +357,15 @@ func (t *TerminalHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (t *TerminalHandler) Close() error { var err error t.closeOnce.Do(func() { + sessionMetadataPayload, err := json.Marshal(siteSessionGenerateResponse{Session: t.sessionData}) + if err != nil { + t.log.WithError(err).Warn("Could not marshal session metadata for the close event") + return + } // If the terminal handler was closed (most likely due to the *SessionContext // closing) then the stream should be closed as well. if t.stream != nil { - err = t.stream.Close() + err = t.stream.Close(string(sessionMetadataPayload)) } }) return trace.Wrap(err) @@ -744,7 +749,12 @@ func (t *TerminalHandler) streamTerminal(ctx context.Context, tc *client.Telepor return } - if err := t.stream.Close(); err != nil { + sessionMetadataPayload, err := json.Marshal(siteSessionGenerateResponse{Session: t.sessionData}) + if err != nil { + t.log.WithError(err).Warn("Could not marshal session metadata for the close event") + return + } + if err := t.stream.Close(string(sessionMetadataPayload)); err != nil { t.log.WithError(err).Error("Unable to send close event to web client.") return } @@ -1296,7 +1306,7 @@ func (t *WSStream) Read(out []byte) (n int, err error) { } // Close sends a close message on the web socket and closes the web socket. -func (t *WSStream) Close() error { +func (t *WSStream) Close(payload string) error { var closeErr error t.once.Do(func() { defer func() { @@ -1310,6 +1320,7 @@ func (t *WSStream) Close() error { envelope := &Envelope{ Version: defaults.WebsocketVersion, Type: defaults.WebsocketClose, + Payload: payload, } envelopeBytes, err := proto.Marshal(envelope) if err != nil { diff --git a/web/packages/teleport/src/Assist/context/AssistContext.tsx b/web/packages/teleport/src/Assist/context/AssistContext.tsx index 942fe036c7c34..b2cbf5562110a 100644 --- a/web/packages/teleport/src/Assist/context/AssistContext.tsx +++ b/web/packages/teleport/src/Assist/context/AssistContext.tsx @@ -31,7 +31,7 @@ import useStickyClusterId from 'teleport/useStickyClusterId'; import cfg from 'teleport/config'; import { getAccessToken, getHostName } from 'teleport/services/api'; -import { RawPayload, ServerMessageType } from 'teleport/Assist/types'; +import { RawPayload, SessionData, ServerMessageType } from 'teleport/Assist/types'; import { MessageTypeEnum, Protobuf } from 'teleport/lib/term/protobuf'; @@ -409,15 +409,13 @@ export function AssistContextProvider(props: PropsWithChildren) { executeCommandWebSocket.current = new WebSocket(url); executeCommandWebSocket.current.binaryType = 'arraybuffer'; - let sessionsEnded = 0; - executeCommandWebSocket.current.onmessage = event => { const uintArray = new Uint8Array(event.data); const msg = proto.decode(uintArray); switch (msg.type) { - case MessageTypeEnum.RAW: + case MessageTypeEnum.RAW: { const data = JSON.parse(msg.payload) as RawPayload; const payload = atob(data.payload); @@ -429,6 +427,7 @@ export function AssistContextProvider(props: PropsWithChildren) { }); break; + } case MessageTypeEnum.WEBAUTHN_CHALLENGE: const challenge = JSON.parse(msg.payload); @@ -448,28 +447,17 @@ export function AssistContextProvider(props: PropsWithChildren) { break; - case MessageTypeEnum.SESSION_END: - // we don't know the nodeId of the session that ended, so we have to - // count the finished sessions and then mark them all as done once - // they've all finished - sessionsEnded += 1; - - if (sessionsEnded === nodeIdToResultId.size) { - for (const nodeId of nodeIdToResultId.keys()) { - dispatch({ - type: AssistStateActionType.FinishCommandResult, - conversationId: state.conversations.selectedId, - commandResultId: nodeIdToResultId.get(nodeId), - }); - } - - nodeIdToResultId.clear(); + case MessageTypeEnum.SESSION_END: { + const data = JSON.parse(msg.payload) as SessionData; - // TODO(ryan): move this to after the summary is sent once it's implemented - executeCommandWebSocket.current.close(); - } + dispatch({ + type: AssistStateActionType.FinishCommandResult, + conversationId: state.conversations.selectedId, + commandResultId: nodeIdToResultId.get(data.session.server_id), + }); break; + } } }; } From 2586e01f536ce4a06e835a02fec7b5ec1447dfcb Mon Sep 17 00:00:00 2001 From: Justinas Stankevicius Date: Fri, 30 Jun 2023 14:57:31 +0300 Subject: [PATCH 2/7] Split Close/CloseWithPayload --- lib/benchmark/web.go | 2 +- lib/web/command.go | 2 +- lib/web/terminal.go | 30 ++++++++++++++++-------------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/lib/benchmark/web.go b/lib/benchmark/web.go index cbf4184d6ab3a..6be3bfc559891 100644 --- a/lib/benchmark/web.go +++ b/lib/benchmark/web.go @@ -99,7 +99,7 @@ func (s WebSSHBenchmark) runCommand(ctx context.Context, tc *client.TeleportClie if err != nil { return trace.Wrap(err) } - defer stream.Close("{}") + defer stream.Close() if _, err := io.WriteString(stream, command); err != nil { return trace.Wrap(err) diff --git a/lib/web/command.go b/lib/web/command.go index 203f0cea75412..0b76d37f79fe0 100644 --- a/lib/web/command.go +++ b/lib/web/command.go @@ -679,7 +679,7 @@ func (t *commandHandler) streamOutput(ctx context.Context, tc *client.TeleportCl t.log.WithError(err).Warn("Could not marshal session metadata for the close event") return } - if err := t.stream.Close(string(sessionMetadataPayload)); err != nil { + if err := t.stream.CloseWithPayload(string(sessionMetadataPayload)); err != nil { t.log.WithError(err).Error("Unable to send close event to web client.") return } diff --git a/lib/web/terminal.go b/lib/web/terminal.go index 56c6617ad54af..8685213ebece6 100644 --- a/lib/web/terminal.go +++ b/lib/web/terminal.go @@ -357,15 +357,10 @@ func (t *TerminalHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (t *TerminalHandler) Close() error { var err error t.closeOnce.Do(func() { - sessionMetadataPayload, err := json.Marshal(siteSessionGenerateResponse{Session: t.sessionData}) - if err != nil { - t.log.WithError(err).Warn("Could not marshal session metadata for the close event") - return - } // If the terminal handler was closed (most likely due to the *SessionContext // closing) then the stream should be closed as well. if t.stream != nil { - err = t.stream.Close(string(sessionMetadataPayload)) + err = t.stream.Close() } }) return trace.Wrap(err) @@ -749,12 +744,7 @@ func (t *TerminalHandler) streamTerminal(ctx context.Context, tc *client.Telepor return } - sessionMetadataPayload, err := json.Marshal(siteSessionGenerateResponse{Session: t.sessionData}) - if err != nil { - t.log.WithError(err).Warn("Could not marshal session metadata for the close event") - return - } - if err := t.stream.Close(string(sessionMetadataPayload)); err != nil { + if err := t.stream.Close(); err != nil { t.log.WithError(err).Error("Unable to send close event to web client.") return } @@ -1305,8 +1295,7 @@ func (t *WSStream) Read(out []byte) (n int, err error) { } } -// Close sends a close message on the web socket and closes the web socket. -func (t *WSStream) Close(payload string) error { +func (t *WSStream) close(payload string) error { var closeErr error t.once.Do(func() { defer func() { @@ -1336,6 +1325,19 @@ func (t *WSStream) Close(payload string) error { return trace.Wrap(closeErr) } +// Close sends a close message on the web socket and closes the web socket. +func (t *WSStream) Close() error { + return t.close("") +} + +// CloseWithPayload sends a close message with additional payload on the web socket and then closes the stream. +// This is necessary for Assist, which multiplexes multiple node connections over one websocket, +// and needs additional metadata to know which session was closed. +// Additionally, in Assist Close() does not actually close the underlying websocket for this stream due to the use of noopCloserWS. +func (t *WSStream) CloseWithPayload(payload string) error { + return t.close(payload) +} + // deadlineForInterval returns a suitable network read deadline for a given ping interval. // We chose to take the current time plus twice the interval to allow the timeframe of one interval // to wait for a returned pong message. From e5fa2eb97ae688419eeedf82a3b59ca31e0a7236 Mon Sep 17 00:00:00 2001 From: Justinas Stankevicius Date: Fri, 30 Jun 2023 15:47:11 +0300 Subject: [PATCH 3/7] Expect a close message before the summary in test --- lib/web/command_test.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/web/command_test.go b/lib/web/command_test.go index 5ae2d888d25c4..5b20d41983138 100644 --- a/lib/web/command_test.go +++ b/lib/web/command_test.go @@ -180,8 +180,14 @@ func TestExecuteCommandSummary(t *testing.T) { // Wait for command execution to complete require.NoError(t, waitForCommandOutput(stream, "teleport")) - var env Envelope dec := json.NewDecoder(stream) + + // Consume close message + err = dec.Decode(&struct{}{}) + require.NoError(t, err) + + // Consume summary message + var env Envelope err = dec.Decode(&env) require.NoError(t, err) require.Equal(t, envelopeTypeSummary, env.GetType()) From 630370994c1f6f6e39b4075a8e2e0d8c7ee7360c Mon Sep 17 00:00:00 2001 From: Justinas Stankevicius Date: Fri, 30 Jun 2023 16:13:15 +0300 Subject: [PATCH 4/7] Remediate confusing type usage in test `Envelope` is the outer layer used (in protobuf format) for execution / terminal sessions. Meanwhile `outEnvelope` is the inner layer used (in JSON) spefically with assist (execution), when outer envelope is of "raw" type Using `Envelope` where decoding `outEnvelope` in tests previously worked "by accident" due to matching field names --- lib/web/command_test.go | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/lib/web/command_test.go b/lib/web/command_test.go index 5b20d41983138..c991dbb805434 100644 --- a/lib/web/command_test.go +++ b/lib/web/command_test.go @@ -19,7 +19,6 @@ package web import ( "context" "crypto/tls" - "encoding/base64" "encoding/json" "fmt" "io" @@ -187,11 +186,11 @@ func TestExecuteCommandSummary(t *testing.T) { require.NoError(t, err) // Consume summary message - var env Envelope + var env outEnvelope err = dec.Decode(&env) require.NoError(t, err) - require.Equal(t, envelopeTypeSummary, env.GetType()) - require.NotEmpty(t, env.GetPayload()) + require.Equal(t, envelopeTypeSummary, env.Type) + require.NotEmpty(t, env.Payload) // Wait for the command execution history to be saved var messages *assist.GetAssistantMessagesResponse @@ -298,18 +297,13 @@ func waitForCommandOutput(stream io.Reader, substr string) error { default: } - var env Envelope + var env outEnvelope dec := json.NewDecoder(stream) if err := dec.Decode(&env); err != nil { return trace.Wrap(err, "decoding envelope JSON from stream") } - d, err := base64.StdEncoding.DecodeString(env.Payload) - if err != nil { - return trace.Wrap(err, "decoding b64 payload") - } - - data := removeSpace(string(d)) + data := removeSpace(string(env.Payload)) if strings.Contains(data, substr) { return nil } From 09848ccfcdab1191a1d02363930769c8b298c15c Mon Sep 17 00:00:00 2001 From: Justinas Stankevicius Date: Fri, 30 Jun 2023 16:22:26 +0300 Subject: [PATCH 5/7] Assert that server ID is set in the close message --- lib/web/command_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/web/command_test.go b/lib/web/command_test.go index c991dbb805434..40aea04227d27 100644 --- a/lib/web/command_test.go +++ b/lib/web/command_test.go @@ -182,8 +182,10 @@ func TestExecuteCommandSummary(t *testing.T) { dec := json.NewDecoder(stream) // Consume close message - err = dec.Decode(&struct{}{}) + var sessionMetadata siteSessionGenerateResponse + err = dec.Decode(&sessionMetadata) require.NoError(t, err) + require.Equal(t, "node", sessionMetadata.Session.ServerID) // Consume summary message var env outEnvelope From 849835f1aee146122858fc3b68a94b986ceefd78 Mon Sep 17 00:00:00 2001 From: Jakub Nyckowski Date: Thu, 6 Jul 2023 16:39:39 -0400 Subject: [PATCH 6/7] Refactor command execution logic and adjust WebSocket handling This commit changes how command execution and WebSocket handling are performed in the code. Instead of manually managing session close signals and command execution notifications via WebSocket, we have wrapped it into more easily manageable form. Changed parts: assist and websocket libraries, test and several components of 'teleport'. Why: This allows cleaner command management and error handling, leading to more reliable and maintainable application. Also made code more readable and easy to understand. Made WebSocket more precise with its handling to prevent cases where stale or incorrect data might interrupt the session. Details: Instead of sending a close signal after all commands have been executed, we now send individual session end updates for each command. Sessions no longer remain active unnecessarily. Message handling in command execution has been refactored for better error propagation. All these changes were also adjusted and reflected in the associated test cases. Also, names and types of various data structures are edited to reflect their actual usage. --- lib/web/command.go | 15 +++-- lib/web/command_test.go | 8 +-- lib/web/terminal.go | 11 +++- .../src/Assist/context/AssistContext.tsx | 64 ++++++++++--------- web/packages/teleport/src/Assist/types.ts | 10 +++ 5 files changed, 64 insertions(+), 44 deletions(-) diff --git a/lib/web/command.go b/lib/web/command.go index e743081357f44..9cd1553f3f03a 100644 --- a/lib/web/command.go +++ b/lib/web/command.go @@ -86,6 +86,12 @@ type commandExecResult struct { SessionID string `json:"session_id"` } +// sessionEndEvent is an event that is sent when a session ends. +type sessionEndEvent struct { + // ServerID is the ID of the server where the session was created. + ServerID string `json:"server_id"` +} + // Check checks if the request is valid. func (c *CommandRequest) Check() error { if c.Command == "" { @@ -336,7 +342,7 @@ func (h *Handler) computeAndSendSummary( return trace.Wrap(err) } - // Add the summary message to the backend so it is persisted on chat + // Add the summary message to the backend, so it is persisted on chat // reload. messagePayload, err := json.Marshal(&assistlib.CommandExecSummary{ ExecutionID: req.executionID, @@ -668,12 +674,7 @@ func (t *commandHandler) streamOutput(ctx context.Context, tc *client.TeleportCl return } - sessionMetadataPayload, err := json.Marshal(siteSessionGenerateResponse{Session: t.sessionData}) - if err != nil { - t.log.WithError(err).Warn("Could not marshal session metadata for the close event") - return - } - if err := t.stream.SendCloseMessage(string(sessionMetadataPayload)); err != nil { + if err := t.stream.SendCloseMessage(sessionEndEvent{ServerID: t.sessionData.ServerID}); err != nil { t.log.WithError(err).Error("Unable to send close event to web client.") return } diff --git a/lib/web/command_test.go b/lib/web/command_test.go index a820600ba2dba..ea67a99830f09 100644 --- a/lib/web/command_test.go +++ b/lib/web/command_test.go @@ -181,13 +181,13 @@ func TestExecuteCommandSummary(t *testing.T) { dec := json.NewDecoder(stream) - // Consume close message - var sessionMetadata siteSessionGenerateResponse + // Consume the close message + var sessionMetadata sessionEndEvent err = dec.Decode(&sessionMetadata) require.NoError(t, err) - require.Equal(t, "node", sessionMetadata.Session.ServerID) + require.Equal(t, "node", sessionMetadata.ServerID) - // Consume summary message + // Consume the summary message var env outEnvelope err = dec.Decode(&env) require.NoError(t, err) diff --git a/lib/web/terminal.go b/lib/web/terminal.go index b4b6d8e5c6fdc..fd9c159ef8f25 100644 --- a/lib/web/terminal.go +++ b/lib/web/terminal.go @@ -745,7 +745,7 @@ func (t *TerminalHandler) streamTerminal(ctx context.Context, tc *client.Telepor } // Send close envelope to web terminal upon exit without an error. - if err := t.stream.SendCloseMessage(""); err != nil { + if err := t.stream.SendCloseMessage(sessionEndEvent{ServerID: t.sessionData.ServerID}); err != nil { t.log.WithError(err).Error("Unable to send close event to web client.") } @@ -1297,11 +1297,16 @@ func (t *WSStream) Read(out []byte) (int, error) { } // SendCloseMessage sends a close message on the web socket. -func (t *WSStream) SendCloseMessage(payload string) error { +func (t *WSStream) SendCloseMessage(event sessionEndEvent) error { + sessionMetadataPayload, err := json.Marshal(&event) + if err != nil { + return trace.Wrap(err) + } + envelope := &Envelope{ Version: defaults.WebsocketVersion, Type: defaults.WebsocketClose, - Payload: payload, + Payload: string(sessionMetadataPayload), } envelopeBytes, err := proto.Marshal(envelope) if err != nil { diff --git a/web/packages/teleport/src/Assist/context/AssistContext.tsx b/web/packages/teleport/src/Assist/context/AssistContext.tsx index 3daa93aa3228f..636cc5ef563c8 100644 --- a/web/packages/teleport/src/Assist/context/AssistContext.tsx +++ b/web/packages/teleport/src/Assist/context/AssistContext.tsx @@ -33,9 +33,10 @@ import { getAccessToken, getHostName } from 'teleport/services/api'; import { ExecutionEnvelopeType, + ExecutionTeleportErrorType, RawPayload, ServerMessageType, - SessionData, + SessionEndData, } from 'teleport/Assist/types'; import { MessageTypeEnum, Protobuf } from 'teleport/lib/term/protobuf'; @@ -430,12 +431,9 @@ export function AssistContextProvider(props: PropsWithChildren) { ); const proto = new Protobuf(); - executeCommandWebSocket.current = new WebSocket(url); executeCommandWebSocket.current.binaryType = 'arraybuffer'; - let sessionsEnded = 0; - executeCommandWebSocket.current.onmessage = event => { const uintArray = new Uint8Array(event.data); @@ -446,22 +444,36 @@ export function AssistContextProvider(props: PropsWithChildren) { const data = JSON.parse(msg.payload) as RawPayload; const payload = atob(data.payload); - if (data.type === ExecutionEnvelopeType) { - dispatch({ - type: AssistStateActionType.AddCommandResultSummary, - conversationId: state.conversations.selectedId, - summary: payload, - executionId: execParams.execution_id, - command: execParams.command, - }); - } else { - dispatch({ - type: AssistStateActionType.UpdateCommandResult, - conversationId: state.conversations.selectedId, - commandResultId: nodeIdToResultId.get(data.node_id), - output: payload, - }); + switch (data.type) { + case ExecutionTeleportErrorType: + dispatch({ + type: AssistStateActionType.FinishCommandResult, + conversationId: state.conversations.selectedId, + commandResultId: nodeIdToResultId.get(data.node_id), + }); + + nodeIdToResultId.delete(data.node_id); + break; + + case ExecutionEnvelopeType: + dispatch({ + type: AssistStateActionType.AddCommandResultSummary, + conversationId: state.conversations.selectedId, + summary: payload, + executionId: execParams.execution_id, + command: execParams.command, + }); + break; + + default: + dispatch({ + type: AssistStateActionType.UpdateCommandResult, + conversationId: state.conversations.selectedId, + commandResultId: nodeIdToResultId.get(data.node_id), + output: payload, + }); } + break; } @@ -484,23 +496,15 @@ export function AssistContextProvider(props: PropsWithChildren) { break; case MessageTypeEnum.SESSION_END: { - const data = JSON.parse(msg.payload) as SessionData; + const data = JSON.parse(msg.payload) as SessionEndData; dispatch({ type: AssistStateActionType.FinishCommandResult, conversationId: state.conversations.selectedId, - commandResultId: nodeIdToResultId.get(data.session.server_id), + commandResultId: nodeIdToResultId.get(data.server_id), }); - sessionsEnded += 1; - - if (sessionsEnded === nodeIdToResultId.size) { - const message = proto.encodeCloseMessage(); - const bytearray = new Uint8Array(message); - - executeCommandWebSocket.current.send(bytearray.buffer); - nodeIdToResultId.clear(); - } + nodeIdToResultId.delete(data.server_id); break; } diff --git a/web/packages/teleport/src/Assist/types.ts b/web/packages/teleport/src/Assist/types.ts index 5e205d3a0c5e7..c0203de6df7da 100644 --- a/web/packages/teleport/src/Assist/types.ts +++ b/web/packages/teleport/src/Assist/types.ts @@ -28,8 +28,14 @@ export enum ServerMessageType { AssistThought = 'CHAT_MESSAGE_PROGRESS_UPDATE', } +// ExecutionEnvelopeType is the type of message that is returned when +// the command summary is returned. export const ExecutionEnvelopeType = 'summary'; +// ExecutionTeleportErrorType is the type of error that is returned when +// Teleport returns an error (failed to execute command, failed to connect, etc.) +export const ExecutionTeleportErrorType = 'teleport-error'; + export interface Conversation { id: string; title?: string; @@ -192,6 +198,10 @@ export interface SessionData { session: { server_id: string }; } +export interface SessionEndData { + server_id: string; +} + export interface ExecuteRemoteCommandPayload { command: string; login?: string; From d5d2770ebc0e6af8336f0a7ab69b99e2a85b9947 Mon Sep 17 00:00:00 2001 From: Jakub Nyckowski Date: Fri, 7 Jul 2023 11:50:53 -0400 Subject: [PATCH 7/7] Change ServerID to NodeID to improve code consistency This commit replaces occurrences of `ServerID` with `NodeID` across several files. `ServerID` was misleading and causing confusion as it was serving as an identifier for nodes, so to improve comprehension and consistency in the codebase, all instances of `ServerID` have been replaced with `NodeID`. Tests have also been updated to reflect this change. --- lib/web/command.go | 6 +++--- lib/web/command_test.go | 2 +- lib/web/terminal.go | 2 +- web/packages/teleport/src/Assist/context/AssistContext.tsx | 4 ++-- web/packages/teleport/src/Assist/types.ts | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/web/command.go b/lib/web/command.go index 9cd1553f3f03a..fc8a3fc7b9087 100644 --- a/lib/web/command.go +++ b/lib/web/command.go @@ -88,8 +88,8 @@ type commandExecResult struct { // sessionEndEvent is an event that is sent when a session ends. type sessionEndEvent struct { - // ServerID is the ID of the server where the session was created. - ServerID string `json:"server_id"` + // NodeID is the ID of the server where the session was created. + NodeID string `json:"node_id"` } // Check checks if the request is valid. @@ -674,7 +674,7 @@ func (t *commandHandler) streamOutput(ctx context.Context, tc *client.TeleportCl return } - if err := t.stream.SendCloseMessage(sessionEndEvent{ServerID: t.sessionData.ServerID}); err != nil { + if err := t.stream.SendCloseMessage(sessionEndEvent{NodeID: t.sessionData.ServerID}); err != nil { t.log.WithError(err).Error("Unable to send close event to web client.") return } diff --git a/lib/web/command_test.go b/lib/web/command_test.go index ea67a99830f09..37a242f550b4b 100644 --- a/lib/web/command_test.go +++ b/lib/web/command_test.go @@ -185,7 +185,7 @@ func TestExecuteCommandSummary(t *testing.T) { var sessionMetadata sessionEndEvent err = dec.Decode(&sessionMetadata) require.NoError(t, err) - require.Equal(t, "node", sessionMetadata.ServerID) + require.Equal(t, "node", sessionMetadata.NodeID) // Consume the summary message var env outEnvelope diff --git a/lib/web/terminal.go b/lib/web/terminal.go index fd9c159ef8f25..befa5fa4b7fb9 100644 --- a/lib/web/terminal.go +++ b/lib/web/terminal.go @@ -745,7 +745,7 @@ func (t *TerminalHandler) streamTerminal(ctx context.Context, tc *client.Telepor } // Send close envelope to web terminal upon exit without an error. - if err := t.stream.SendCloseMessage(sessionEndEvent{ServerID: t.sessionData.ServerID}); err != nil { + if err := t.stream.SendCloseMessage(sessionEndEvent{NodeID: t.sessionData.ServerID}); err != nil { t.log.WithError(err).Error("Unable to send close event to web client.") } diff --git a/web/packages/teleport/src/Assist/context/AssistContext.tsx b/web/packages/teleport/src/Assist/context/AssistContext.tsx index 636cc5ef563c8..784464cdf3549 100644 --- a/web/packages/teleport/src/Assist/context/AssistContext.tsx +++ b/web/packages/teleport/src/Assist/context/AssistContext.tsx @@ -501,10 +501,10 @@ export function AssistContextProvider(props: PropsWithChildren) { dispatch({ type: AssistStateActionType.FinishCommandResult, conversationId: state.conversations.selectedId, - commandResultId: nodeIdToResultId.get(data.server_id), + commandResultId: nodeIdToResultId.get(data.node_id), }); - nodeIdToResultId.delete(data.server_id); + nodeIdToResultId.delete(data.node_id); break; } diff --git a/web/packages/teleport/src/Assist/types.ts b/web/packages/teleport/src/Assist/types.ts index c0203de6df7da..ade6da6cd08b2 100644 --- a/web/packages/teleport/src/Assist/types.ts +++ b/web/packages/teleport/src/Assist/types.ts @@ -199,7 +199,7 @@ export interface SessionData { } export interface SessionEndData { - server_id: string; + node_id: string; } export interface ExecuteRemoteCommandPayload {