@@ -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 )