GetWorkspaceAndAgent returns the workspace and agent selected using either the ` [. ]` syntax via `in`. It will also return any other agents in the workspace as a slice for use in child->parent lookups. If autoStart is true, the workspace will be started if it is not already running.
(ctx context.Context, inv *serpent.Invocation, client *codersdk.Client, autostart bool, input string)
| 1001 | // in the workspace as a slice for use in child->parent lookups. |
| 1002 | // If autoStart is true, the workspace will be started if it is not already running. |
| 1003 | func GetWorkspaceAndAgent(ctx context.Context, inv *serpent.Invocation, client *codersdk.Client, autostart bool, input string) (codersdk.Workspace, codersdk.WorkspaceAgent, []codersdk.WorkspaceAgent, error) { //nolint:revive |
| 1004 | var ( |
| 1005 | workspace codersdk.Workspace |
| 1006 | // The input will be `owner/name.agent` |
| 1007 | // The agent is optional. |
| 1008 | workspaceParts = strings.Split(input, ".") |
| 1009 | err error |
| 1010 | ) |
| 1011 | |
| 1012 | workspace, err = client.ResolveWorkspace(ctx, workspaceParts[0]) |
| 1013 | if err != nil { |
| 1014 | return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, nil, err |
| 1015 | } |
| 1016 | |
| 1017 | if workspace.LatestBuild.Transition != codersdk.WorkspaceTransitionStart { |
| 1018 | if !autostart { |
| 1019 | return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, nil, xerrors.New("workspace must be started") |
| 1020 | } |
| 1021 | // Autostart the workspace for the user. |
| 1022 | // For some failure modes, return a better message. |
| 1023 | if workspace.LatestBuild.Transition == codersdk.WorkspaceTransitionDelete { |
| 1024 | // Any sort of deleting status, we should reject with a nicer error. |
| 1025 | return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, nil, xerrors.Errorf("workspace %q is deleted", workspace.Name) |
| 1026 | } |
| 1027 | if workspace.LatestBuild.Job.Status == codersdk.ProvisionerJobFailed { |
| 1028 | return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, nil, |
| 1029 | xerrors.Errorf("workspace %q is in failed state, unable to autostart the workspace", workspace.Name) |
| 1030 | } |
| 1031 | // The workspace needs to be stopped before we can start it. |
| 1032 | // It cannot be in any pending or failed state. |
| 1033 | if workspace.LatestBuild.Status != codersdk.WorkspaceStatusStopped { |
| 1034 | return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, nil, |
| 1035 | xerrors.Errorf("workspace must be started; was unable to autostart as the last build job is %q, expected %q", |
| 1036 | workspace.LatestBuild.Status, |
| 1037 | codersdk.WorkspaceStatusStopped, |
| 1038 | ) |
| 1039 | } |
| 1040 | |
| 1041 | // Start workspace based on the last build parameters. |
| 1042 | // It's possible for a workspace build to fail due to the template requiring starting |
| 1043 | // workspaces with the active version. |
| 1044 | _, _ = fmt.Fprintf(inv.Stderr, "Workspace was stopped, starting workspace to allow connecting to %q...\n", workspace.Name) |
| 1045 | _, err = startWorkspace(inv, client, workspace, workspaceParameterFlags{ |
| 1046 | useParameterDefaults: true, |
| 1047 | }, buildFlags{ |
| 1048 | reason: string(codersdk.BuildReasonSSHConnection), |
| 1049 | }, WorkspaceStart) |
| 1050 | if cerr, ok := codersdk.AsError(err); ok { |
| 1051 | switch cerr.StatusCode() { |
| 1052 | case http.StatusConflict: |
| 1053 | _, _ = fmt.Fprintln(inv.Stderr, "Unable to start the workspace due to conflict, the workspace may be starting, retrying without autostart...") |
| 1054 | return GetWorkspaceAndAgent(ctx, inv, client, false, input) |
| 1055 | |
| 1056 | case http.StatusForbidden: |
| 1057 | _, err = startWorkspace(inv, client, workspace, workspaceParameterFlags{ |
| 1058 | useParameterDefaults: true, |
| 1059 | }, buildFlags{}, WorkspaceUpdate) |
| 1060 | if err != nil { |
no test coverage detected