@@ -144,7 +144,7 @@ func (r *RootCmd) ssh() *clibase.Cmd {
144
144
}
145
145
}
146
146
147
- workspace , workspaceAgent , err := getWorkspaceAndAgent (ctx , inv , client , codersdk .Me , inv .Args [0 ])
147
+ workspace , workspaceAgent , err := getWorkspaceAndAgent (ctx , inv , client , ! disableAutostart , codersdk .Me , inv .Args [0 ])
148
148
if err != nil {
149
149
return err
150
150
}
@@ -538,9 +538,9 @@ startWatchLoop:
538
538
}
539
539
540
540
// getWorkspaceAgent returns the workspace and agent selected using either the
541
- // `<workspace>[.<agent>]` syntax via `in` or picks a random workspace and agent
542
- // if `shuffle` is true.
543
- func getWorkspaceAndAgent (ctx context.Context , inv * clibase.Invocation , client * codersdk.Client , userID string , in string ) (codersdk.Workspace , codersdk.WorkspaceAgent , error ) { //nolint:revive
541
+ // `<workspace>[.<agent>]` syntax via `in`.
542
+ // If autoStart is true, the workspace will be started if it is not already running .
543
+ func getWorkspaceAndAgent (ctx context.Context , inv * clibase.Invocation , client * codersdk.Client , autostart bool , userID string , in string ) (codersdk.Workspace , codersdk.WorkspaceAgent , error ) { //nolint:revive
544
544
var (
545
545
workspace codersdk.Workspace
546
546
workspaceParts = strings .Split (in , "." )
@@ -553,7 +553,35 @@ func getWorkspaceAndAgent(ctx context.Context, inv *clibase.Invocation, client *
553
553
}
554
554
555
555
if workspace .LatestBuild .Transition != codersdk .WorkspaceTransitionStart {
556
- return codersdk.Workspace {}, codersdk.WorkspaceAgent {}, xerrors .New ("workspace must be in start transition to ssh" )
556
+ if ! autostart {
557
+ return codersdk.Workspace {}, codersdk.WorkspaceAgent {}, xerrors .New ("workspace must be in start transition to ssh" )
558
+ }
559
+ // Autostart the workspace for the user.
560
+ // For some failure modes, return a better message.
561
+ if workspace .LatestBuild .Transition == codersdk .WorkspaceTransitionDelete {
562
+ // Any sort of deleting status, we should reject with a nicer error.
563
+ return codersdk.Workspace {}, codersdk.WorkspaceAgent {}, xerrors .Errorf ("workspace %q is deleted" , workspace .Name )
564
+ }
565
+ if workspace .LatestBuild .Job .Status == codersdk .ProvisionerJobFailed {
566
+ return codersdk.Workspace {}, codersdk.WorkspaceAgent {},
567
+ xerrors .Errorf ("workspace %q is in failed state, unable to autostart the workspace" , workspace .Name )
568
+ }
569
+ // The workspace needs to be stopped before we can start it.
570
+ // It cannot be in any pending or failed state.
571
+ if workspace .LatestBuild .Status != codersdk .WorkspaceStatusStopped {
572
+ return codersdk.Workspace {}, codersdk.WorkspaceAgent {},
573
+ xerrors .Errorf ("workspace must be in start transition to ssh, was unable to autostart as the last build job is %q, expected %q" ,
574
+ workspace .LatestBuild .Status ,
575
+ codersdk .WorkspaceStatusStopped ,
576
+ )
577
+ }
578
+ // startWorkspace based on the last build parameters.
579
+ _ , _ = fmt .Fprintf (inv .Stderr , "Workspace was stopped, starting workspace to allow connection %q...\n " , workspace .Name )
580
+ build , err := startWorkspace (inv , client , workspace , workspaceParameterFlags {}, WorkspaceStart )
581
+ if err != nil {
582
+ return codersdk.Workspace {}, codersdk.WorkspaceAgent {}, xerrors .Errorf ("workspace is stopped, failed to start: %w" , err )
583
+ }
584
+ workspace .LatestBuild = build
557
585
}
558
586
if workspace .LatestBuild .Job .CompletedAt == nil {
559
587
err := cliui .WorkspaceBuild (ctx , inv .Stderr , client , workspace .LatestBuild .ID )
0 commit comments