Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Add the ability to disable autostart#366

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
code-asher merged 3 commits intomainfromasher/disable-autostart
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletionsCHANGELOG.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,12 @@

## Unreleased

### Changed

- Disable autostarting workspaces by default on macOS to prevent an issue where
it wakes periodically and keeps the workspace on. This can be toggled via the
"Disable autostart" setting.

## 2.9.3 - 2024-02-10

### Fixed
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
packagecom.coder.gateway

importcom.coder.gateway.services.CoderSettingsService
importcom.coder.gateway.util.canCreateDirectory
importcom.coder.gateway.services.CoderSettingsState
importcom.coder.gateway.util.canCreateDirectory
importcom.intellij.openapi.components.service
importcom.intellij.openapi.options.BoundConfigurable
importcom.intellij.openapi.ui.DialogPanel
Expand DownExpand Up@@ -102,6 +102,13 @@ class CoderSettingsConfigurable : BoundConfigurable("Coder") {
CoderGatewayBundle.message("gateway.connector.settings.tls-alt-name.comment")
)
}.layout(RowLayout.PARENT_GRID)
row(CoderGatewayBundle.message("gateway.connector.settings.disable-autostart.heading")) {
checkBox(CoderGatewayBundle.message("gateway.connector.settings.disable-autostart.title"))
.bindSelected(state::disableAutostart)
.comment(
CoderGatewayBundle.message("gateway.connector.settings.disable-autostart.comment")
)
}.layout(RowLayout.PARENT_GRID)
}
}

Expand Down
56 changes: 43 additions & 13 deletionssrc/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -96,6 +96,13 @@ fun ensureCLI(
return if (cliMatches == null && dataCLIMatches != null) dataCLI else cli
}

/**
* The supported features of the CLI.
*/
data class Features (
val disableAutostart: Boolean = false,
)

/**
* Manage the CLI for a single deployment.
*/
Expand DownExpand Up@@ -199,9 +206,11 @@ class CoderCLIManager(

/**
* Configure SSH to use this binary.
*
* This can take supported features for testing purposes only.
*/
fun configSsh(workspaceNames: List<String>) {
writeSSHConfig(modifySSHConfig(readSSHConfig(), workspaceNames))
fun configSsh(workspaceNames: List<String>, feats: Features = features) {
writeSSHConfig(modifySSHConfig(readSSHConfig(), workspaceNames, feats))
}

/**
Expand All@@ -219,8 +228,11 @@ class CoderCLIManager(
* Given an existing SSH config modify it to add or remove the config for
* this deployment and return the modified config or null if it does not
* need to be modified.
*
* If features are not provided, calculate them based on the binary
* version.
*/
private fun modifySSHConfig(contents: String?, workspaceNames: List<String>): String? {
private fun modifySSHConfig(contents: String?, workspaceNames: List<String>, feats: Features): String? {
val host = deploymentURL.safeHost()
val startBlock = "# --- START CODER JETBRAINS $host"
val endBlock = "# --- END CODER JETBRAINS $host"
Expand All@@ -230,15 +242,16 @@ class CoderCLIManager(
"--global-config", escape(coderConfigPath.toString()),
if (settings.headerCommand.isNotBlank()) "--header-command" else null,
if (settings.headerCommand.isNotBlank()) escapeSubcommand(settings.headerCommand) else null,
"ssh", "--stdio")
"ssh", "--stdio",
if (settings.disableAutostart && feats.disableAutostart) "--disable-autostart" else null)
val blockContent = workspaceNames.joinToString(
System.lineSeparator(),
startBlock + System.lineSeparator(),
System.lineSeparator() + endBlock,
transform = {
"""
Host ${getHostName(deploymentURL, it)}
ProxyCommand ${proxyArgs.joinToString(" ")} ${it}
ProxyCommand ${proxyArgs.joinToString(" ")} $it
ConnectTimeout 0
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
Expand DownExpand Up@@ -333,31 +346,36 @@ class CoderCLIManager(
}

/**
* Returns true if the CLI has the same major/minor/patch version as the
* provided version, false if it does not match, or null if the CLI version
* could not be determined because the binary could not be executed or the
* version could not be parsed.
* Like version(), but logs errors instead of throwing them.
*/
funmatchesVersion(rawBuildVersion: String):Boolean? {
val cliVersion = try {
privatefuntryVersion():SemVer? {
return try {
version()
} catch (e: Exception) {
when (e) {
is JsonSyntaxException,
is InvalidVersionException -> {
logger.info("Got invalid version from $localBinaryPath: ${e.message}")
return null
}
else -> {
// An error here most likely means the CLI does not exist or
// it executed successfully but output no version which
// suggests it is not the right binary.
logger.info("Unable to determine $localBinaryPath version: ${e.message}")
return null
}
}
null
}
}

/**
* Returns true if the CLI has the same major/minor/patch version as the
* provided version, false if it does not match, or null if the CLI version
* could not be determined because the binary could not be executed or the
* version could not be parsed.
*/
fun matchesVersion(rawBuildVersion: String): Boolean? {
val cliVersion = tryVersion() ?: return null
val buildVersion = try {
SemVer.parse(rawBuildVersion)
} catch (e: InvalidVersionException) {
Expand All@@ -383,6 +401,18 @@ class CoderCLIManager(
return stdout
}

val features: Features
get() {
val version = tryVersion()
return if (version == null) {
Features()
} else {
Features(
// Autostart with SSH was added in 2.5.0.
disableAutostart = version >= SemVer(2, 5, 0))
}
}

companion object {
val logger = Logger.getInstance(CoderCLIManager::class.java.simpleName)

Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
packagecom.coder.gateway.services

importcom.coder.gateway.util.OS
importcom.coder.gateway.util.getOS
importcom.intellij.openapi.components.PersistentStateComponent
importcom.intellij.openapi.components.RoamingType
importcom.intellij.openapi.components.Service
Expand DownExpand Up@@ -56,6 +58,10 @@ class CoderSettingsState(
// connections. This is useful when the hostname used to connect to the
// Coder service does not match the hostname in the TLS certificate.
vartlsAlternateHostname:String ="",
// Whether to add --disable-autostart to the proxy command. This works
// around issues on macOS where it periodically wakes and Gateway
// reconnects, keeping the workspace constantly up.
vardisableAutostart:Boolean = getOS() ==OS.MAC,
) : PersistentStateComponent<CoderSettingsState> {
overridefungetState():CoderSettingsState {
returnthis
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,6 +35,9 @@ open class CoderSettings(
val headerCommand:String
get()= state.headerCommand

val disableAutostart:Boolean
get()= state.disableAutostart

/**
* Where the specified deployment should put its data.
*/
Expand Down
6 changes: 6 additions & 0 deletionssrc/main/resources/messages/CoderGatewayBundle.properties
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -111,3 +111,9 @@ gateway.connector.settings.tls-alt-name.comment=Optionally set this to \
an alternate hostname used for verifying TLS connections. This is useful \
when the hostname used to connect to the Coder service does not match the \
hostname in the TLS certificate.
gateway.connector.settings.disable-autostart.heading=Autostart:
gateway.connector.settings.disable-autostart.title=Disable autostart
gateway.connector.settings.disable-autostart.comment=Checking this box will \
cause the plugin to configure the CLI with --disable-autostart. You must go \
through the IDE selection again for the plugin to reconfigure the CLI with \
this setting.
9 changes: 9 additions & 0 deletionssrc/test/fixtures/outputs/disable-autostart.conf
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
# --- START CODER JETBRAINS test.coder.invalid
Host coder-jetbrains--foo--test.coder.invalid
ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --disable-autostart foo
ConnectTimeout 0
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
LogLevel ERROR
SetEnv CODER_SSH_SESSION_TYPE=JetBrains
# --- END CODER JETBRAINS test.coder.invalid
9 changes: 9 additions & 0 deletionssrc/test/fixtures/outputs/no-disable-autostart.conf
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
# --- START CODER JETBRAINS test.coder.invalid
Host coder-jetbrains--foo--test.coder.invalid
ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo
ConnectTimeout 0
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
LogLevel ERROR
SetEnv CODER_SSH_SESSION_TYPE=JetBrains
# --- END CODER JETBRAINS test.coder.invalid
50 changes: 43 additions & 7 deletionssrc/test/kotlin/com/coder/gateway/cli/CoderCLIManagerTest.kt
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -33,18 +33,18 @@ import kotlin.test.assertTrue

internal class CoderCLIManagerTest {
private fun mkbin(version: String): String {
return listOf("#!/bin/sh", """echo '{"version": "${version}"}'""")
return listOf("#!/bin/sh", """echo '{"version": "$version"}'""")
.joinToString("\n")
}

private fun mockServer(errorCode: Int = 0): Pair<HttpServer, URL> {
private fun mockServer(errorCode: Int = 0, version: String? = null): Pair<HttpServer, URL> {
val srv = HttpServer.create(InetSocketAddress(0), 0)
srv.createContext("/") {exchange ->
var code = HttpURLConnection.HTTP_OK
// TODO: Is there some simple way to create an executable file on
// Windows without having to execute something to generate said
// executable or having to commit one to the repo?
var response = mkbin("${srv.address.port}.0.0")
var response = mkbin(version ?:"${srv.address.port}.0.0")
val eTags = exchange.requestHeaders["If-None-Match"]
if (exchange.requestURI.path == "/bin/override") {
code = HttpURLConnection.HTTP_OK
Expand DownExpand Up@@ -234,7 +234,15 @@ internal class CoderCLIManagerTest {
srv2.stop(0)
}

data class SSHTest(val workspaces: List<String>, val input: String?, val output: String, val remove: String, val headerCommand: String?)
data class SSHTest(
val workspaces: List<String>,
val input: String?,
val output: String,
val remove: String,
val headerCommand: String?,
val disableAutostart: Boolean = false,
val features: Features? = null,
)

@Test
fun testConfigureSSH() {
Expand All@@ -256,13 +264,16 @@ internal class CoderCLIManagerTest {
SSHTest(listOf("header"), null, "header-command-windows", "blank", """"C:\Program Files\My Header Command\HeaderCommand.exe" --url="%CODER_URL%" --test="foo bar"""")
} else {
SSHTest(listOf("header"), null, "header-command", "blank", "my-header-command --url=\"\$CODER_URL\" --test=\"foo bar\" --literal='\$CODER_URL'")
}
},
SSHTest(listOf("foo"), null, "disable-autostart", "blank", null, true, Features(true)),
SSHTest(listOf("foo"), null, "no-disable-autostart", "blank", null, true, Features(false)),
)

val newlineRe = "\r?\n".toRegex()

tests.forEach {
val settings = CoderSettings(CoderSettingsState(
disableAutostart = it.disableAutostart,
dataDirectory = tmpdir.resolve("configure-ssh").toString(),
headerCommand = it.headerCommand ?: ""),
sshConfigPath = tmpdir.resolve(it.input + "_to_" + it.output + ".conf"))
Expand All@@ -285,12 +296,12 @@ internal class CoderCLIManagerTest {
.replace("/tmp/coder-gateway/test.coder.invalid/coder-linux-amd64", escape(ccm.localBinaryPath.toString()))

// Add workspaces.
ccm.configSsh(it.workspaces)
ccm.configSsh(it.workspaces, it.features ?: Features())

assertEquals(expectedConf, settings.sshConfigPath.toFile().readText())

// Remove configuration.
ccm.configSsh(emptyList())
ccm.configSsh(emptyList(), it.features ?: Features())

// Remove is the configuration we expect after removing.
assertEquals(
Expand DownExpand Up@@ -540,6 +551,31 @@ internal class CoderCLIManagerTest {
srv.stop(0)
}

@Test
fun testFeatures() {
if (getOS() == OS.WINDOWS) {
return // Cannot execute mock binaries on Windows.
}

val tests = listOf(
Pair("2.5.0", Features(true)),
Pair("4.9.0", Features(true)),
Pair("2.4.9", Features(false)),
Pair("1.0.1", Features(false)),
)

tests.forEach {
val (srv, url) = mockServer(version = it.first)
val ccm = CoderCLIManager(url, CoderSettings(CoderSettingsState(
dataDirectory = tmpdir.resolve("features").toString()))
)
assertEquals(true, ccm.download())
assertEquals(it.second, ccm.features, "version: ${it.first}")

srv.stop(0)
}
}

companion object {
private val tmpdir: Path = Path.of(System.getProperty("java.io.tmpdir")).resolve("coder-gateway-test/cli-manager")

Expand Down
25 changes: 13 additions & 12 deletionssrc/test/kotlin/com/coder/gateway/settings/CoderSettingsTest.kt
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
package com.coder.gateway.settings

import com.coder.gateway.services.CoderSettingsState
import kotlin.test.Test
import kotlin.test.assertContains
import kotlin.test.assertEquals

import com.coder.gateway.util.OS
import com.coder.gateway.util.getOS
import com.coder.gateway.util.withPath
import java.net.URL
import java.nio.file.Path
import kotlin.test.Test
import kotlin.test.assertContains
import kotlin.test.assertEquals

internal class CoderSettingsTest {
@Test
Expand DownExpand Up@@ -179,14 +178,15 @@ internal class CoderSettingsTest {
// Make sure the remaining settings are being conveyed.
val settings = CoderSettings(
CoderSettingsState(
enableDownloads = false,
enableBinaryDirectoryFallback = true,
headerCommand = "test header",
tlsCertPath = "tls cert path",
tlsKeyPath = "tls key path",
tlsCAPath = "tls ca path",
tlsAlternateHostname = "tls alt hostname",
)
enableDownloads = false,
enableBinaryDirectoryFallback = true,
headerCommand = "test header",
tlsCertPath = "tls cert path",
tlsKeyPath = "tls key path",
tlsCAPath = "tls ca path",
tlsAlternateHostname = "tls alt hostname",
disableAutostart = true,
)
)

assertEquals(false, settings.enableDownloads)
Expand All@@ -196,5 +196,6 @@ internal class CoderSettingsTest {
assertEquals("tls key path", settings.tls.keyPath)
assertEquals("tls ca path", settings.tls.caPath)
assertEquals("tls alt hostname", settings.tls.altHostname)
assertEquals(true, settings.disableAutostart)
}
}

[8]ページ先頭

©2009-2025 Movatter.jp