diff --git a/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt b/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt index ae1fd6a1..b4ee61e0 100644 --- a/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt +++ b/src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt @@ -451,6 +451,21 @@ class CoderCLIManager( return matches } + /** + * Start a workspace. + * + * Throws if the command execution fails. + */ + fun startWorkspace(workspaceOwner: String, workspaceName: String): String { + return exec( + "--global-config", + coderConfigPath.toString(), + "start", + "--yes", + workspaceOwner+"/"+workspaceName, + ) + } + private fun exec(vararg args: String): String { val stdout = ProcessExecutor() diff --git a/src/main/kotlin/com/coder/gateway/sdk/CoderRestClient.kt b/src/main/kotlin/com/coder/gateway/sdk/CoderRestClient.kt index 9108ed61..40d5934a 100644 --- a/src/main/kotlin/com/coder/gateway/sdk/CoderRestClient.kt +++ b/src/main/kotlin/com/coder/gateway/sdk/CoderRestClient.kt @@ -227,18 +227,6 @@ open class CoderRestClient( return templateResponse.body()!! } - /** - * @throws [APIResponseException]. - */ - fun startWorkspace(workspace: Workspace): WorkspaceBuild { - val buildRequest = CreateWorkspaceBuildRequest(null, WorkspaceTransition.START) - val buildResponse = retroRestClient.createWorkspaceBuild(workspace.id, buildRequest).execute() - if (buildResponse.code() != HttpURLConnection.HTTP_CREATED) { - throw APIResponseException("start workspace ${workspace.name}", url, buildResponse) - } - return buildResponse.body()!! - } - /** * @throws [APIResponseException]. */ diff --git a/src/main/kotlin/com/coder/gateway/views/CoderGatewayRecentWorkspaceConnectionsView.kt b/src/main/kotlin/com/coder/gateway/views/CoderGatewayRecentWorkspaceConnectionsView.kt index 027f291e..ded8edfa 100644 --- a/src/main/kotlin/com/coder/gateway/views/CoderGatewayRecentWorkspaceConnectionsView.kt +++ b/src/main/kotlin/com/coder/gateway/views/CoderGatewayRecentWorkspaceConnectionsView.kt @@ -5,6 +5,8 @@ package com.coder.gateway.views import com.coder.gateway.CoderGatewayBundle import com.coder.gateway.CoderGatewayConstants import com.coder.gateway.CoderRemoteConnectionHandle +import com.coder.gateway.cli.CoderCLIManager +import com.coder.gateway.cli.ensureCLI import com.coder.gateway.icons.CoderIcons import com.coder.gateway.models.WorkspaceAgentListModel import com.coder.gateway.models.WorkspaceProjectIDE @@ -73,6 +75,8 @@ data class DeploymentInfo( var items: List? = null, // Null if there have not been any errors yet. var error: String? = null, + // Null if unable to ensure the CLI is downloaded. + var cli: CoderCLIManager? = null, ) class CoderGatewayRecentWorkspaceConnectionsView(private val setContentCallback: (Component) -> Unit) : @@ -232,10 +236,10 @@ class CoderGatewayRecentWorkspaceConnectionsView(private val setContentCallback: if (enableLinks) { cell( ActionLink(workspaceProjectIDE.projectPathDisplay) { - withoutNull(deployment?.client, workspaceWithAgent?.workspace) { client, workspace -> + withoutNull(deployment?.cli, workspaceWithAgent?.workspace) { cli, workspace -> CoderRemoteConnectionHandle().connect { if (listOf(WorkspaceStatus.STOPPED, WorkspaceStatus.CANCELED, WorkspaceStatus.FAILED).contains(workspace.latestBuild.status)) { - client.startWorkspace(workspace) + cli.startWorkspace(workspace.ownerName, workspace.name) } workspaceProjectIDE } @@ -358,6 +362,19 @@ class CoderGatewayRecentWorkspaceConnectionsView(private val setContentCallback: throw Exception("Unable to make request; token was not found in CLI config.") } + val cli = ensureCLI( + deploymentURL.toURL(), + client.buildInfo().version, + settings, + ) + + // We only need to log the cli in if we have token-based auth. + // Otherwise, we assume it is set up in the same way the plugin + // is with mTLS. + if (client.token != null) { + cli.login(client.token) + } + // This is purely to populate the current user, which is // used to match workspaces that were not recorded with owner // information. @@ -378,6 +395,7 @@ class CoderGatewayRecentWorkspaceConnectionsView(private val setContentCallback: } deployment.client = client + deployment.cli = cli deployment.items = items deployment.error = null } catch (e: Exception) { diff --git a/src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspacesStepView.kt b/src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspacesStepView.kt index 45516507..53a67c37 100644 --- a/src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspacesStepView.kt +++ b/src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspacesStepView.kt @@ -303,13 +303,13 @@ class CoderWorkspacesStepView : CoderIcons.RUN, ) { override fun actionPerformed(p0: AnActionEvent) { - withoutNull(client, tableOfWorkspaces.selectedObject?.workspace) { c, workspace -> + withoutNull(cliManager, tableOfWorkspaces.selectedObject?.workspace) { cliManager, workspace -> jobs[workspace.id]?.cancel() jobs[workspace.id] = cs.launch(ModalityState.current().asContextElement()) { withContext(Dispatchers.IO) { try { - c.startWorkspace(workspace) + cliManager.startWorkspace(workspace.ownerName, workspace.name) loadWorkspaces() } catch (e: Exception) { logger.error("Could not start workspace ${workspace.name}", e) @@ -659,7 +659,7 @@ class CoderWorkspacesStepView : cs.launch(ModalityState.current().asContextElement()) { while (isActive) { loadWorkspaces() - delay(5000) + delay(1000) } } }