feat(cli): add enterprise external-workspaces CLI command (#19287)

This pull request introduces support for external workspace management, allowing users to register and manage workspaces that are provisioned and managed outside of the Coder.

* coder external-workspaces create - Creates a new external workspace (this command extends coder create)
  * Example: coder external-workspaces create ext-workspace --template=externally-managed-workspace -y
  * Checks if template has coder_external_agent resource before creating a workspace
* coder external-workspaces list - Lists all external workspaces
* coder external-workspaces agent-instructions <workspace name> <agent name> - Retrieves agent connection instruction
  * Example: coder external-workspaces agent-instructions ext-workspace main --output=json
This commit is contained in:
Kacper Sawicki
2025-08-19 10:52:31 +02:00
committed by GitHub
parent 9edceef0bf
commit 7b1dcd9846
25 changed files with 1277 additions and 73 deletions
+4 -4
View File
@@ -754,7 +754,7 @@ func findWorkspaceAndAgentByHostname(
hostname = strings.TrimSuffix(hostname, qualifiedSuffix)
}
hostname = normalizeWorkspaceInput(hostname)
ws, agent, _, err := getWorkspaceAndAgent(ctx, inv, client, !disableAutostart, hostname)
ws, agent, _, err := GetWorkspaceAndAgent(ctx, inv, client, !disableAutostart, hostname)
return ws, agent, err
}
@@ -827,11 +827,11 @@ startWatchLoop:
}
}
// getWorkspaceAgent returns the workspace and agent selected using either the
// GetWorkspaceAndAgent returns the workspace and agent selected using either the
// `<workspace>[.<agent>]` 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.
func getWorkspaceAndAgent(ctx context.Context, inv *serpent.Invocation, client *codersdk.Client, autostart bool, input string) (codersdk.Workspace, codersdk.WorkspaceAgent, []codersdk.WorkspaceAgent, error) { //nolint:revive
func GetWorkspaceAndAgent(ctx context.Context, inv *serpent.Invocation, client *codersdk.Client, autostart bool, input string) (codersdk.Workspace, codersdk.WorkspaceAgent, []codersdk.WorkspaceAgent, error) { //nolint:revive
var (
workspace codersdk.Workspace
// The input will be `owner/name.agent`
@@ -880,7 +880,7 @@ func getWorkspaceAndAgent(ctx context.Context, inv *serpent.Invocation, client *
switch cerr.StatusCode() {
case http.StatusConflict:
_, _ = fmt.Fprintln(inv.Stderr, "Unable to start the workspace due to conflict, the workspace may be starting, retrying without autostart...")
return getWorkspaceAndAgent(ctx, inv, client, false, input)
return GetWorkspaceAndAgent(ctx, inv, client, false, input)
case http.StatusForbidden:
_, err = startWorkspace(inv, client, workspace, workspaceParameterFlags{}, buildFlags{}, WorkspaceUpdate)