Skip to content

Commit 9aefc46

Browse files
committed
Configure CLI in final step
This way we can show a message since right now when you click the next button it just mysteriously and silently hangs while configuring.
1 parent e69ffc0 commit 9aefc46

File tree

5 files changed

+57
-44
lines changed

5 files changed

+57
-44
lines changed

src/main/kotlin/com/coder/gateway/CoderGatewayConnectionProvider.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ class CoderGatewayConnectionProvider : GatewayConnectionProvider {
9393
cli.login(client.token)
9494

9595
indicator.text = "Configuring Coder CLI..."
96-
cli.configSsh(client.agentNames())
96+
cli.configSsh(client.agentNames(workspaces))
9797

9898
// TODO: Ask for these if missing. Maybe we can reuse the second
9999
// step of the wizard? Could also be nice if we automatically used
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
11
package com.coder.gateway.models
22

3+
import com.coder.gateway.cli.CoderCLIManager
4+
import com.coder.gateway.sdk.CoderRestClient
5+
import com.coder.gateway.sdk.v2.models.Workspace
6+
37
enum class TokenSource {
48
CONFIG, // Pulled from the Coder CLI config.
59
USER, // Input by the user.
610
QUERY, // From the Gateway link as a query parameter.
711
LAST_USED, // Last used token, either from storage or current run.
812
}
913

14+
/**
15+
* Used to pass data between steps.
16+
*/
1017
data class CoderWorkspacesWizardModel(
1118
var coderURL: String = "https://coder.example.com",
1219
var token: Pair<String, TokenSource>? = null,
1320
var selectedListItem: WorkspaceAgentListModel? = null,
1421
var useExistingToken: Boolean = false,
1522
var configDirectory: String = "",
23+
var client: CoderRestClient? = null,
24+
var cliManager: CoderCLIManager? = null,
25+
var workspaces: List<Workspace>? = null
1626
)

src/main/kotlin/com/coder/gateway/sdk/BaseCoderRestClient.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,8 @@ open class BaseCoderRestClient(
155155
* Retrieves all the agent names for all workspaces, including those that
156156
* are off. Meant to be used when configuring SSH.
157157
*/
158-
fun agentNames(): List<String> {
159-
return workspaces().flatMap { ws ->
158+
fun agentNames(workspaces: List<Workspace>): List<String> {
159+
return workspaces.flatMap { ws ->
160160
resources(ws).filter { it.agents != null }.flatMap { it.agents!! }.map {
161161
"${ws.name}.${it.name}"
162162
}

src/main/kotlin/com/coder/gateway/views/steps/CoderLocateRemoteProjectStepView.kt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,12 @@ class CoderLocateRemoteProjectStepView(private val setNextButtonEnabled: (Boolea
170170

171171
val deploymentURL = wizardModel.coderURL.toURL()
172172
val selectedItem = wizardModel.selectedListItem
173-
if (selectedItem?.agent == null) {
173+
val cli = wizardModel.cliManager
174+
val client = wizardModel.client
175+
val workspaces = wizardModel.workspaces
176+
if (selectedItem?.agent == null || cli == null || client == null || workspaces == null) {
174177
// TODO: Should be impossible, tweak the types/flow to enforce this.
175-
logger.warn("No agent was selected. Please go back to the previous step and select an agent")
178+
logger.warn("Failed to read data from previous step; this is a developer error")
176179
return
177180
}
178181

@@ -183,6 +186,12 @@ class CoderLocateRemoteProjectStepView(private val setNextButtonEnabled: (Boolea
183186

184187
ideResolvingJob = cs.launch(ModalityState.current().asContextElement()) {
185188
try {
189+
logger.info("Configuring Coder CLI...")
190+
cbIDE.renderer = IDECellRenderer("Configuring Coder CLI...")
191+
withContext(Dispatchers.IO) {
192+
cli.configSsh(client.agentNames(workspaces))
193+
}
194+
186195
val ides = suspendingRetryWithExponentialBackOff(
187196
action = { attempt ->
188197
logger.info("Connecting with SSH and uploading worker if missing... (attempt $attempt)")

src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspacesStepView.kt

Lines changed: 33 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package com.coder.gateway.views.steps
33
import com.coder.gateway.CoderGatewayBundle
44
import com.coder.gateway.CoderRemoteConnectionHandle
55
import com.coder.gateway.CoderSupportedVersions
6-
import com.coder.gateway.cli.CoderCLIManager
76
import com.coder.gateway.cli.ensureCLI
87
import com.coder.gateway.cli.ex.ResponseException
98
import com.coder.gateway.icons.CoderIcons
@@ -88,8 +87,6 @@ private const val SESSION_TOKEN = "session-token"
8887
class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : CoderWorkspacesWizardStep, Disposable {
8988
private val cs = CoroutineScope(Dispatchers.Main)
9089
private var localWizardModel = CoderWorkspacesWizardModel()
91-
private var client: CoderRestClient? = null
92-
private var cliManager: CoderCLIManager? = null
9390
private val settings: CoderSettingsService = service<CoderSettingsService>()
9491

9592
private val appPropertiesService: PropertiesComponent = service()
@@ -227,7 +224,7 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
227224
private inner class GoToDashboardAction :
228225
AnActionButton(CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.dashboard.text"), CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.dashboard.text"), CoderIcons.HOME) {
229226
override fun actionPerformed(p0: AnActionEvent) {
230-
val c = client
227+
val c = localWizardModel.client
231228
if (c != null) {
232229
BrowserUtil.browse(c.url)
233230
}
@@ -237,7 +234,7 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
237234
private inner class GoToTemplateAction :
238235
AnActionButton(CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.template.text"), CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.template.text"), AllIcons.Nodes.Template) {
239236
override fun actionPerformed(p0: AnActionEvent) {
240-
val c = client
237+
val c = localWizardModel.client
241238
if (tableOfWorkspaces.selectedObject != null && c != null) {
242239
val workspace = (tableOfWorkspaces.selectedObject as WorkspaceAgentListModel).workspace
243240
BrowserUtil.browse(c.url.toURI().resolve("/templates/${workspace.templateName}"))
@@ -248,7 +245,7 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
248245
private inner class StartWorkspaceAction :
249246
AnActionButton(CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.start.text"), CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.start.text"), CoderIcons.RUN) {
250247
override fun actionPerformed(p0: AnActionEvent) {
251-
val c = client
248+
val c = localWizardModel.client
252249
if (tableOfWorkspaces.selectedObject != null && c != null) {
253250
val workspace = (tableOfWorkspaces.selectedObject as WorkspaceAgentListModel).workspace
254251
cs.launch {
@@ -268,7 +265,7 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
268265
private inner class UpdateWorkspaceTemplateAction :
269266
AnActionButton(CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.update.text"), CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.update.text"), CoderIcons.UPDATE) {
270267
override fun actionPerformed(p0: AnActionEvent) {
271-
val c = client
268+
val c = localWizardModel.client
272269
if (tableOfWorkspaces.selectedObject != null && c != null) {
273270
val workspace = (tableOfWorkspaces.selectedObject as WorkspaceAgentListModel).workspace
274271
cs.launch {
@@ -290,7 +287,7 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
290287
private inner class StopWorkspaceAction :
291288
AnActionButton(CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.stop.text"), CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.stop.text"), CoderIcons.STOP) {
292289
override fun actionPerformed(p0: AnActionEvent) {
293-
val c = client
290+
val c = localWizardModel.client
294291
if (tableOfWorkspaces.selectedObject != null && c != null) {
295292
val workspace = (tableOfWorkspaces.selectedObject as WorkspaceAgentListModel).workspace
296293
cs.launch {
@@ -310,7 +307,7 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
310307
private inner class CreateWorkspaceAction :
311308
AnActionButton(CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.create.text"), CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.create.text"), CoderIcons.CREATE) {
312309
override fun actionPerformed(p0: AnActionEvent) {
313-
val c = client
310+
val c = localWizardModel.client
314311
if (c != null) {
315312
BrowserUtil.browse(c.url.toURI().resolve("/templates"))
316313
}
@@ -350,8 +347,8 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
350347
}
351348

352349
private fun updateWorkspaceActions() {
353-
goToDashboardAction.isEnabled = client != null
354-
createWorkspaceAction.isEnabled = client != null
350+
goToDashboardAction.isEnabled = localWizardModel.client != null
351+
createWorkspaceAction.isEnabled = localWizardModel.client != null
355352
goToTemplateAction.isEnabled = tableOfWorkspaces.selectedObject != null
356353
when (tableOfWorkspaces.selectedObject?.workspace?.latestBuild?.status) {
357354
WorkspaceStatus.RUNNING -> {
@@ -417,8 +414,8 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
417414
onAuthFailure: (() -> Unit)? = null,
418415
): Job {
419416
// Clear out old deployment details.
420-
cliManager = null
421-
client = null
417+
localWizardModel.cliManager = null
418+
localWizardModel.client = null
422419
poller?.cancel()
423420
tfUrlComment?.foreground = UIUtil.getContextHelpForeground()
424421
tfUrlComment?.text = CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.connect.text.connecting", deploymentURL.host)
@@ -430,7 +427,7 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
430427
try {
431428
this.indicator.text = "Authenticating client..."
432429
val authedClient = authenticate(deploymentURL, token.first)
433-
client = authedClient
430+
localWizardModel.client = authedClient
434431

435432
// Remember these in order to default to them for future attempts.
436433
appPropertiesService.setValue(CODER_URL_KEY, deploymentURL.toString())
@@ -452,7 +449,7 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
452449
updateWorkspaceActions()
453450
triggerWorkspacePolling(false)
454451

455-
cliManager = cli
452+
localWizardModel.cliManager = cli
456453
tableOfWorkspaces.setEmptyState(CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.connect.text.connected", deploymentURL.host))
457454
tfUrlComment?.text = CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.connect.text.connected", deploymentURL.host)
458455
} catch (e: Exception) {
@@ -575,7 +572,7 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
575572
private suspend fun loadWorkspaces() {
576573
val ws = withContext(Dispatchers.IO) {
577574
val timeBeforeRequestingWorkspaces = System.currentTimeMillis()
578-
val clientNow = client ?: return@withContext emptySet()
575+
val clientNow = localWizardModel.client ?: return@withContext emptySet()
579576
try {
580577
val ws = clientNow.workspaces()
581578
val ams = ws.flatMap { it.toAgentList() }
@@ -609,38 +606,35 @@ class CoderWorkspacesStepView(val setNextButtonEnabled: (Boolean) -> Unit) : Cod
609606
}
610607

611608
override fun onNext(wizardModel: CoderWorkspacesWizardModel): Boolean {
612-
wizardModel.apply {
613-
coderURL = localWizardModel.coderURL
614-
token = localWizardModel.token
615-
}
616-
617609
// These being null would be a developer error.
618610
val selected = tableOfWorkspaces.selectedObject
619-
val cli = cliManager
620-
val clientNow = client
621611
if (selected?.agent == null) {
622612
logger.error("No selected agent")
623613
return false
624-
} else if (cli == null) {
625-
logger.error("No configured CLI")
626-
return false
627-
} else if (clientNow == null) {
628-
logger.error("No configured client")
629-
return false
630614
}
631615

632-
wizardModel.selectedListItem = selected
616+
// Apply values that will be used in the next step.
617+
wizardModel.apply {
618+
coderURL = localWizardModel.coderURL
619+
token = localWizardModel.token
620+
selectedListItem = selected
621+
// The next step will use these to configure the CLI. We could do it
622+
// here but then we would need to show another progress indicator.
623+
// The next step already has one so might as well use it.
624+
cliManager = localWizardModel.cliManager
625+
client = localWizardModel.client
626+
// Pass along the latest workspaces so the next step can configure
627+
// the CLI a bit faster, otherwise it would have to fetch the
628+
// workspaces again.
629+
workspaces = tableOfWorkspaces.items.map { it.workspace }
630+
// The config directory can be used to pull the URL and token in
631+
// order to query this workspace's status in other flows, for
632+
// example from the recent connections screen.
633+
configDirectory = cliManager?.coderConfigPath?.toString() ?: ""
634+
}
633635
poller?.cancel()
634636

635-
logger.info("Configuring Coder CLI...")
636-
cli.configSsh(clientNow.agentNames())
637-
638-
// The config directory can be used to pull the URL and token in
639-
// order to query this workspace's status in other flows, for
640-
// example from the recent connections screen.
641-
wizardModel.configDirectory = cli.coderConfigPath.toString()
642-
643-
logger.info("Opening IDE and Project Location window for ${selected.name}")
637+
logger.info("Opening IDE selection window for ${selected.name}")
644638
return true
645639
}
646640

0 commit comments

Comments
 (0)