@@ -20,8 +20,6 @@ import (
2020 breverrors "github.com/brevdev/brev-cli/pkg/errors"
2121 "github.com/brevdev/brev-cli/pkg/store"
2222 "github.com/brevdev/brev-cli/pkg/terminal"
23- "github.com/brevdev/brev-cli/pkg/writeconnectionevent"
24-
2523 "github.com/spf13/cobra"
2624)
2725
@@ -100,10 +98,26 @@ func runShellCommand(t *terminal.Terminal, sstore ShellStore, workspaceNameOrID
10098 return breverrors .WrapAndTrace (err )
10199 }
102100 }
103- err = util .PollUntil (s , workspace .ID , "RUNNING" , sstore , " waiting for instance to be ready..." , pollTimeout )
101+ if workspace .Status != "RUNNING" {
102+ err = util .PollUntil (s , workspace .ID , "RUNNING" , sstore , " waiting for instance to be ready..." , pollTimeout )
103+ }
104104 if err != nil {
105105 return breverrors .WrapAndTrace (err )
106106 }
107+
108+ localIdentifier := workspace .GetLocalIdentifier ()
109+ if host {
110+ localIdentifier = workspace .GetHostIdentifier ()
111+ }
112+ sshName := string (localIdentifier )
113+
114+ err = runSSHWithOptions (sshName , host , false )
115+ if err == nil {
116+ trackShellAnalytics (sstore , workspace )
117+ return nil
118+ }
119+ _ , _ = fmt .Fprintln (os .Stderr , "\n Connection failed, refreshing SSH config and retrying..." )
120+
107121 refreshRes := refresh .RunRefreshAsync (sstore )
108122
109123 workspace , err = util .GetUserWorkspaceByNameOrIDErr (sstore , workspaceNameOrID )
@@ -114,13 +128,6 @@ func runShellCommand(t *terminal.Terminal, sstore ShellStore, workspaceNameOrID
114128 return breverrors .New ("Instance is not running" )
115129 }
116130
117- localIdentifier := workspace .GetLocalIdentifier ()
118- if host {
119- localIdentifier = workspace .GetHostIdentifier ()
120- }
121-
122- sshName := string (localIdentifier )
123-
124131 err = refreshRes .Await ()
125132 if err != nil {
126133 return breverrors .WrapAndTrace (err )
@@ -129,15 +136,16 @@ func runShellCommand(t *terminal.Terminal, sstore ShellStore, workspaceNameOrID
129136 if err != nil {
130137 return breverrors .WrapAndTrace (err )
131138 }
132- // we don't care about the error here but should log with sentry
133- // legacy environments wont support this and cause errrors,
134- // but we don't want to block the user from using the shell
135- _ = writeconnectionevent .WriteWCEOnEnv (sstore , workspace .DNS )
136139 err = runSSH (sshName , host )
137140 if err != nil {
138141 return breverrors .WrapAndTrace (err )
139142 }
140- // Call analytics for shell
143+ trackShellAnalytics (sstore , workspace )
144+
145+ return nil
146+ }
147+
148+ func trackShellAnalytics (sstore ShellStore , workspace * entity.Workspace ) {
141149 userID := ""
142150 user , err := sstore .GetCurrentUser ()
143151 if err != nil {
@@ -146,15 +154,13 @@ func runShellCommand(t *terminal.Terminal, sstore ShellStore, workspaceNameOrID
146154 userID = user .ID
147155 }
148156 data := analytics.EventData {
149- EventName : "Brev Open " ,
157+ EventName : "Brev Shell " ,
150158 UserID : userID ,
151159 Properties : map [string ]string {
152160 "instanceId" : workspace .ID ,
153161 },
154162 }
155163 _ = analytics .TrackEvent (data )
156-
157- return nil
158164}
159165
160166func shellIntoExternalNode (t * terminal.Terminal , sstore ShellStore , node * nodev1.ExternalNode ) error {
@@ -180,7 +186,7 @@ func shellIntoExternalNode(t *terminal.Terminal, sstore ShellStore, node *nodev1
180186}
181187
182188func runSSHWithPort (target string , port int32 , identityFile string ) error {
183- sshAgentEval := " eval $(ssh-agent -s)"
189+ sshAgentEval := `if [ -z "$SSH_AUTH_SOCK" ]; then eval $(ssh-agent -s) > /dev/null; fi`
184190 cmd := fmt .Sprintf ("%s && ssh -i %q -o StrictHostKeyChecking=no -p %d %s" , sshAgentEval , identityFile , port , target )
185191
186192 sshCmd := exec .Command ("bash" , "-c" , cmd ) //nolint:gosec //cmd is constructed from API data
@@ -201,13 +207,17 @@ func runSSHWithPort(target string, port int32, identityFile string) error {
201207}
202208
203209func runSSH (sshAlias string , host bool ) error {
204- sshAgentEval := "eval $(ssh-agent -s)"
210+ return runSSHWithOptions (sshAlias , host , true )
211+ }
212+
213+ func runSSHWithOptions (sshAlias string , host bool , printFailureAdvice bool ) error {
214+ sshAgentEval := `if [ -z "$SSH_AUTH_SOCK" ]; then eval $(ssh-agent -s) > /dev/null; fi`
205215 var cmd string
206216 if host {
207- cmd = fmt .Sprintf ("%s && ssh %s" , sshAgentEval , sshAlias )
217+ cmd = fmt .Sprintf ("%s && ssh -o ConnectTimeout=5 %s" , sshAgentEval , sshAlias )
208218 } else {
209219 // SSH into VM and respect container WORKDIR if containerized, otherwise use default directory
210- cmd = fmt .Sprintf ("%s && ssh -t %s 'DIR=$(readlink -f /proc/1/cwd 2>/dev/null || pwd); cd \" $DIR\" || echo \" Warning: Could not access container directory\" >&2; exec -l ${SHELL:-/bin/sh}'" , sshAgentEval , sshAlias )
220+ cmd = fmt .Sprintf ("%s && ssh -t -o ConnectTimeout=5 %s 'DIR=$(readlink -f /proc/1/cwd 2>/dev/null || pwd); cd \" $DIR\" || echo \" Warning: Could not access container directory\" >&2; exec -l ${SHELL:-/bin/sh}'" , sshAgentEval , sshAlias )
211221 }
212222
213223 var stderrBuf bytes.Buffer
@@ -223,6 +233,9 @@ func runSSH(sshAlias string, host bool) error {
223233
224234 err = sshCmd .Run ()
225235 if err != nil {
236+ if ! printFailureAdvice {
237+ return breverrors .WrapAndTrace (err )
238+ }
226239 stderrStr := stderrBuf .String ()
227240 if strings .Contains (stderrStr , "unix_listener" ) || strings .Contains (stderrStr , "path too long" ) {
228241 fmt .Fprintf (os .Stderr , "\n brev shell failed: SSH ControlPath socket path is too long for this system.\n " )
0 commit comments