Skip to content

Commit cdde8e4

Browse files
committed
Fix: no such host is known errors
- this can happen if there is a new workspace created after the plugin authenticates and runs the coder cli config-ssh - the solution is to run the config-ssh one more time before moving to the next step, i.e. IDE&Project location setup. - resolves #66
1 parent 8636fe7 commit cdde8e4

File tree

5 files changed

+60
-31
lines changed

5 files changed

+60
-31
lines changed

src/main/kotlin/com/coder/gateway/models/CoderWorkspacesWizardModel.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ data class CoderWorkspacesWizardModel(
44
var coderURL: String = "https://localhost",
55
var token: String = "",
66
var buildVersion: String = "",
7-
var workspaceAgents: List<WorkspaceAgentModel> = mutableListOf(),
7+
var localCliPath: String = "",
88
var selectedWorkspace: WorkspaceAgentModel? = null
99
)

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

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,20 @@ import java.io.InputStream
55
import java.net.URL
66
import java.nio.file.Files
77
import java.nio.file.Path
8-
import java.nio.file.Paths
98
import java.nio.file.StandardCopyOption
109

11-
class CoderCLIDownloader(private val buildVersion: String) {
10+
class CoderCLIDownloader {
1211

13-
fun downloadCLI(url: URL, outputName: String, ext: String): Path {
14-
val filename = if (ext.isBlank()) "${outputName}-$buildVersion" else "${outputName}-${buildVersion}.${ext}"
15-
val cliPath = Paths.get(System.getProperty("java.io.tmpdir"), filename)
12+
fun downloadCLI(url: URL, cliPath: Path): Boolean {
1613
if (Files.exists(cliPath)) {
1714
logger.info("${cliPath.toAbsolutePath()} already exists, skipping download")
18-
return cliPath
15+
return false
1916
}
2017
logger.info("Starting Coder CLI download to ${cliPath.toAbsolutePath()}")
2118
url.openStream().use {
2219
Files.copy(it as InputStream, cliPath, StandardCopyOption.REPLACE_EXISTING)
2320
}
24-
return cliPath
21+
return true
2522
}
2623

2724
companion object {

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

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,20 @@ package com.coder.gateway.sdk
33
import com.intellij.openapi.diagnostic.Logger
44
import java.net.URL
55
import java.nio.file.Path
6+
import java.nio.file.Paths
67

7-
class CoderCLIManager(private val url: URL, buildVersion: String) {
8-
private val coderCLIDownloader = CoderCLIDownloader(buildVersion)
8+
class CoderCLIManager(url: URL, buildVersion: String) {
9+
var remoteCliPath: URL
10+
var localCliPath: Path
911

10-
fun download(): Path? {
12+
init {
1113
val os = getOS()
12-
val cliName = getCoderCLIForOS(os, getArch()) ?: return null
13-
val cliNameWitExt = if (os == OS.WINDOWS) "$cliName.exe" else cliName
14-
return coderCLIDownloader.downloadCLI(URL(url.protocol, url.host, url.port, "/bin/$cliNameWitExt"), cliName, if (os == OS.WINDOWS) "exe" else "")
14+
val ext = if (os == OS.WINDOWS) "exe" else ""
15+
val cliName = getCoderCLIForOS(os, getArch())
16+
val filename = if (ext.isBlank()) "${cliName}-${buildVersion}" else "${cliName}-${buildVersion}.${ext}"
17+
18+
remoteCliPath = URL(url.protocol, url.host, url.port, "/bin/$cliName")
19+
localCliPath = Paths.get(System.getProperty("java.io.tmpdir"), filename)
1520
}
1621

1722
private fun getCoderCLIForOS(os: OS?, arch: Arch?): String? {
@@ -25,12 +30,14 @@ class CoderCLIManager(private val url: URL, buildVersion: String) {
2530
Arch.ARM64 -> "coder-windows-arm64"
2631
else -> "coder-windows-amd64"
2732
}
33+
2834
OS.LINUX -> when (arch) {
2935
Arch.AMD64 -> "coder-linux-amd64"
3036
Arch.ARM64 -> "coder-linux-arm64"
3137
Arch.ARMV7 -> "coder-linux-armv7"
3238
else -> "coder-linux-amd64"
3339
}
40+
3441
OS.MAC -> when (arch) {
3542
Arch.AMD64 -> "coder-darwin-amd64"
3643
Arch.ARM64 -> "coder-darwin-arm64"

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

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import com.coder.gateway.models.WorkspaceAgentStatus.STOPPED
1313
import com.coder.gateway.models.WorkspaceAgentStatus.STOPPING
1414
import com.coder.gateway.models.WorkspaceVersionStatus
1515
import com.coder.gateway.sdk.Arch
16+
import com.coder.gateway.sdk.CoderCLIDownloader
1617
import com.coder.gateway.sdk.CoderCLIManager
1718
import com.coder.gateway.sdk.CoderRestClientService
1819
import com.coder.gateway.sdk.OS
@@ -76,7 +77,7 @@ import javax.swing.table.TableCellRenderer
7677

7778
class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) : CoderWorkspacesWizardStep, Disposable {
7879
private val cs = CoroutineScope(Dispatchers.Main)
79-
private var wizardModel = CoderWorkspacesWizardModel()
80+
private var localWizardModel = CoderWorkspacesWizardModel()
8081
private val coderClient: CoderRestClientService = ApplicationManager.getApplication().getService(CoderRestClientService::class.java)
8182

8283
private var listTableModelOfWorkspaces = ListTableModel<WorkspaceAgentModel>(
@@ -135,7 +136,7 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
135136
browserLink(CoderGatewayBundle.message("gateway.connector.view.login.documentation.action"), "https://coder.com/docs/coder-oss/latest/workspaces")
136137
}.bottomGap(BottomGap.MEDIUM)
137138
row(CoderGatewayBundle.message("gateway.connector.view.login.url.label")) {
138-
textField().resizableColumn().horizontalAlign(HorizontalAlign.FILL).gap(RightGap.SMALL).bindText(wizardModel::coderURL).applyToComponent {
139+
textField().resizableColumn().horizontalAlign(HorizontalAlign.FILL).gap(RightGap.SMALL).bindText(localWizardModel::coderURL).applyToComponent {
139140
addActionListener {
140141
poller?.cancel()
141142
loginAndLoadWorkspace()
@@ -255,21 +256,26 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
255256
// force bindings to be filled
256257
component.apply()
257258

258-
BrowserUtil.browse(wizardModel.coderURL.toURL().withPath("/login?redirect=%2Fcli-auth"))
259+
BrowserUtil.browse(localWizardModel.coderURL.toURL().withPath("/login?redirect=%2Fcli-auth"))
259260
val pastedToken = askToken()
260261

261262
if (pastedToken.isNullOrBlank()) {
262263
return
263264
}
264265
try {
265-
coderClient.initClientSession(wizardModel.coderURL.toURL(), pastedToken)
266+
coderClient.initClientSession(localWizardModel.coderURL.toURL(), pastedToken)
266267
} catch (e: AuthenticationResponseException) {
267-
logger.error("Could not authenticate on ${wizardModel.coderURL}. Reason $e")
268+
logger.error("Could not authenticate on ${localWizardModel.coderURL}. Reason $e")
268269
return
269270
}
270-
wizardModel.apply {
271+
272+
val cliManager = CoderCLIManager(localWizardModel.coderURL.toURL(), coderClient.buildVersion)
273+
274+
275+
localWizardModel.apply {
271276
token = pastedToken
272277
buildVersion = coderClient.buildVersion
278+
localCliPath = cliManager.localCliPath.toAbsolutePath().toString()
273279
}
274280

275281
val authTask = object : Task.Modal(null, CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.cli.downloader.dialog.title"), false) {
@@ -281,31 +287,26 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
281287
fraction = 0.1
282288
}
283289

284-
val cliManager = CoderCLIManager(wizardModel.coderURL.toURL(), wizardModel.buildVersion)
285-
val cli = cliManager.download() ?: throw IllegalStateException("Could not download coder binary")
290+
CoderCLIDownloader().downloadCLI(cliManager.remoteCliPath, cliManager.localCliPath)
286291
if (getOS() != OS.WINDOWS) {
287292
pi.fraction = 0.4
288-
val chmodOutput = ProcessExecutor().command("chmod", "+x", cli.toAbsolutePath().toString()).readOutput(true).execute().outputUTF8()
289-
logger.info("chmod +x ${cli.toAbsolutePath()} $chmodOutput")
293+
val chmodOutput = ProcessExecutor().command("chmod", "+x", localWizardModel.localCliPath).readOutput(true).execute().outputUTF8()
294+
logger.info("chmod +x ${cliManager.localCliPath.toAbsolutePath()} $chmodOutput")
290295
}
291296
pi.apply {
292297
text = "Configuring coder cli..."
293298
fraction = 0.5
294299
}
295300

296-
val loginOutput = ProcessExecutor().command(cli.toAbsolutePath().toString(), "login", wizardModel.coderURL, "--token", wizardModel.token).readOutput(true).execute().outputUTF8()
301+
val loginOutput = ProcessExecutor().command(localWizardModel.localCliPath, "login", localWizardModel.coderURL, "--token", localWizardModel.token).readOutput(true).execute().outputUTF8()
297302
logger.info("coder-cli login output: $loginOutput")
298303
pi.fraction = 0.8
299-
val sshConfigOutput = ProcessExecutor().command(cli.toAbsolutePath().toString(), "config-ssh", "--yes", "--use-previous-options").readOutput(true).execute().outputUTF8()
300-
logger.info("Result of `${cli.toAbsolutePath()} config-ssh --yes --use-previous-options`: $sshConfigOutput")
304+
val sshConfigOutput = ProcessExecutor().command(localWizardModel.localCliPath, "config-ssh", "--yes", "--use-previous-options").readOutput(true).execute().outputUTF8()
305+
logger.info("Result of `${localWizardModel.localCliPath} config-ssh --yes --use-previous-options`: $sshConfigOutput")
301306
pi.fraction = 1.0
302307
}
303308
}
304309

305-
wizardModel.apply {
306-
coderURL = wizardModel.coderURL
307-
token = wizardModel.token
308-
}
309310
ProgressManager.getInstance().run(authTask)
310311
triggerWorkspacePolling()
311312
}
@@ -430,6 +431,29 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
430431
}
431432

432433
override fun onNext(wizardModel: CoderWorkspacesWizardModel): Boolean {
434+
if (localWizardModel.localCliPath.isNotBlank()) {
435+
val configSSHTask = object : Task.Modal(null, CoderGatewayBundle.message("gateway.connector.view.coder.workspaces.cli.configssh.dialog.title"), false) {
436+
override fun run(pi: ProgressIndicator) {
437+
pi.apply {
438+
text = "Configuring coder cli..."
439+
fraction = 0.1
440+
}
441+
val sshConfigOutput = ProcessExecutor().command(localWizardModel.localCliPath, "config-ssh", "--yes", "--use-previous-options").readOutput(true).execute().outputUTF8()
442+
pi.fraction = 0.8
443+
logger.info("Result of `${localWizardModel.localCliPath} config-ssh --yes --use-previous-options`: $sshConfigOutput")
444+
pi.fraction = 1.0
445+
}
446+
}
447+
ProgressManager.getInstance().run(configSSHTask)
448+
}
449+
450+
wizardModel.apply {
451+
coderURL = localWizardModel.coderURL
452+
token = localWizardModel.token
453+
buildVersion = localWizardModel.buildVersion
454+
localCliPath = localWizardModel.localCliPath
455+
}
456+
433457
val workspace = tableOfWorkspaces.selectedObject
434458
if (workspace != null) {
435459
wizardModel.selectedWorkspace = workspace

src/main/resources/messages/CoderGatewayBundle.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ gateway.connector.view.coder.workspaces.header.text=Coder Workspaces
99
gateway.connector.view.coder.workspaces.comment=Self-hosted developer workspaces in the cloud or on premise. Coder Workspaces empower developers with secure, consistent, and fast developer workspaces.
1010
gateway.connector.view.coder.workspaces.connect.text=Connect
1111
gateway.connector.view.coder.workspaces.cli.downloader.dialog.title=Authenticate and setup coder
12+
gateway.connector.view.coder.workspaces.cli.configssh.dialog.title=Coder Config SSH
1213
gateway.connector.view.coder.workspaces.next.text=Select IDE and Project
1314
gateway.connector.view.coder.workspaces.start.text=Start Workspace
1415
gateway.connector.view.coder.workspaces.stop.text=Stop Workspace

0 commit comments

Comments
 (0)