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

Commit23ebb16

Browse files
authored
Add the ability to disable autostart (#366)
On macOS this is checked by default for 2.5.0 and above.
1 parent0a0fb52 commit23ebb16

File tree

10 files changed

+146
-33
lines changed

10 files changed

+146
-33
lines changed

‎CHANGELOG.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44

55
##Unreleased
66

7+
###Changed
8+
9+
- Disable autostarting workspaces by default on macOS to prevent an issue where
10+
it wakes periodically and keeps the workspace on. This can be toggled via the
11+
"Disable autostart" setting.
12+
713
##2.9.3 - 2024-02-10
814

915
###Fixed

‎src/main/kotlin/com/coder/gateway/CoderSettingsConfigurable.kt‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
packagecom.coder.gateway
22

33
importcom.coder.gateway.services.CoderSettingsService
4-
importcom.coder.gateway.util.canCreateDirectory
54
importcom.coder.gateway.services.CoderSettingsState
5+
importcom.coder.gateway.util.canCreateDirectory
66
importcom.intellij.openapi.components.service
77
importcom.intellij.openapi.options.BoundConfigurable
88
importcom.intellij.openapi.ui.DialogPanel
@@ -102,6 +102,13 @@ class CoderSettingsConfigurable : BoundConfigurable("Coder") {
102102
CoderGatewayBundle.message("gateway.connector.settings.tls-alt-name.comment")
103103
)
104104
}.layout(RowLayout.PARENT_GRID)
105+
row(CoderGatewayBundle.message("gateway.connector.settings.disable-autostart.heading")) {
106+
checkBox(CoderGatewayBundle.message("gateway.connector.settings.disable-autostart.title"))
107+
.bindSelected(state::disableAutostart)
108+
.comment(
109+
CoderGatewayBundle.message("gateway.connector.settings.disable-autostart.comment")
110+
)
111+
}.layout(RowLayout.PARENT_GRID)
105112
}
106113
}
107114

‎src/main/kotlin/com/coder/gateway/cli/CoderCLIManager.kt‎

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,13 @@ fun ensureCLI(
9696
returnif (cliMatches==null&& dataCLIMatches!=null) dataCLIelse cli
9797
}
9898

99+
/**
100+
* The supported features of the CLI.
101+
*/
102+
data classFeatures (
103+
valdisableAutostart:Boolean =false,
104+
)
105+
99106
/**
100107
* Manage the CLI for a single deployment.
101108
*/
@@ -199,9 +206,11 @@ class CoderCLIManager(
199206

200207
/**
201208
* Configure SSH to use this binary.
209+
*
210+
* This can take supported features for testing purposes only.
202211
*/
203-
funconfigSsh(workspaceNames:List<String>) {
204-
writeSSHConfig(modifySSHConfig(readSSHConfig(), workspaceNames))
212+
funconfigSsh(workspaceNames:List<String>,feats:Features = features) {
213+
writeSSHConfig(modifySSHConfig(readSSHConfig(), workspaceNames, feats))
205214
}
206215

207216
/**
@@ -219,8 +228,11 @@ class CoderCLIManager(
219228
* Given an existing SSH config modify it to add or remove the config for
220229
* this deployment and return the modified config or null if it does not
221230
* need to be modified.
231+
*
232+
* If features are not provided, calculate them based on the binary
233+
* version.
222234
*/
223-
privatefunmodifySSHConfig(contents:String?,workspaceNames:List<String>):String? {
235+
privatefunmodifySSHConfig(contents:String?,workspaceNames:List<String>,feats:Features):String? {
224236
val host= deploymentURL.safeHost()
225237
val startBlock="# --- START CODER JETBRAINS$host"
226238
val endBlock="# --- END CODER JETBRAINS$host"
@@ -230,15 +242,16 @@ class CoderCLIManager(
230242
"--global-config", escape(coderConfigPath.toString()),
231243
if (settings.headerCommand.isNotBlank())"--header-command"elsenull,
232244
if (settings.headerCommand.isNotBlank()) escapeSubcommand(settings.headerCommand)elsenull,
233-
"ssh","--stdio")
245+
"ssh","--stdio",
246+
if (settings.disableAutostart&& feats.disableAutostart)"--disable-autostart"elsenull)
234247
val blockContent= workspaceNames.joinToString(
235248
System.lineSeparator(),
236249
startBlock+System.lineSeparator(),
237250
System.lineSeparator()+ endBlock,
238251
transform= {
239252
"""
240253
Host${getHostName(deploymentURL, it)}
241-
ProxyCommand${proxyArgs.joinToString("")}${it}
254+
ProxyCommand${proxyArgs.joinToString("")}$it
242255
ConnectTimeout 0
243256
StrictHostKeyChecking no
244257
UserKnownHostsFile /dev/null
@@ -333,31 +346,36 @@ class CoderCLIManager(
333346
}
334347

335348
/**
336-
* Returns true if the CLI has the same major/minor/patch version as the
337-
* provided version, false if it does not match, or null if the CLI version
338-
* could not be determined because the binary could not be executed or the
339-
* version could not be parsed.
349+
* Like version(), but logs errors instead of throwing them.
340350
*/
341-
funmatchesVersion(rawBuildVersion:String):Boolean? {
342-
val cliVersion=try {
351+
privatefuntryVersion():SemVer? {
352+
returntry {
343353
version()
344354
}catch (e:Exception) {
345355
when (e) {
346356
isJsonSyntaxException,
347357
isInvalidVersionException-> {
348358
logger.info("Got invalid version from$localBinaryPath:${e.message}")
349-
returnnull
350359
}
351360
else-> {
352361
// An error here most likely means the CLI does not exist or
353362
// it executed successfully but output no version which
354363
// suggests it is not the right binary.
355364
logger.info("Unable to determine$localBinaryPath version:${e.message}")
356-
returnnull
357365
}
358366
}
367+
null
359368
}
369+
}
360370

371+
/**
372+
* Returns true if the CLI has the same major/minor/patch version as the
373+
* provided version, false if it does not match, or null if the CLI version
374+
* could not be determined because the binary could not be executed or the
375+
* version could not be parsed.
376+
*/
377+
funmatchesVersion(rawBuildVersion:String):Boolean? {
378+
val cliVersion= tryVersion()?:returnnull
361379
val buildVersion=try {
362380
SemVer.parse(rawBuildVersion)
363381
}catch (e:InvalidVersionException) {
@@ -383,6 +401,18 @@ class CoderCLIManager(
383401
return stdout
384402
}
385403

404+
val features:Features
405+
get() {
406+
val version= tryVersion()
407+
returnif (version==null) {
408+
Features()
409+
}else {
410+
Features(
411+
// Autostart with SSH was added in 2.5.0.
412+
disableAutostart= version>=SemVer(2,5,0))
413+
}
414+
}
415+
386416
companionobject {
387417
val logger=Logger.getInstance(CoderCLIManager::class.java.simpleName)
388418

‎src/main/kotlin/com/coder/gateway/services/CoderSettingsState.kt‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
packagecom.coder.gateway.services
22

3+
importcom.coder.gateway.util.OS
4+
importcom.coder.gateway.util.getOS
35
importcom.intellij.openapi.components.PersistentStateComponent
46
importcom.intellij.openapi.components.RoamingType
57
importcom.intellij.openapi.components.Service
@@ -56,6 +58,10 @@ class CoderSettingsState(
5658
// connections. This is useful when the hostname used to connect to the
5759
// Coder service does not match the hostname in the TLS certificate.
5860
vartlsAlternateHostname:String ="",
61+
// Whether to add --disable-autostart to the proxy command. This works
62+
// around issues on macOS where it periodically wakes and Gateway
63+
// reconnects, keeping the workspace constantly up.
64+
vardisableAutostart:Boolean = getOS() ==OS.MAC,
5965
) : PersistentStateComponent<CoderSettingsState> {
6066
overridefungetState():CoderSettingsState {
6167
returnthis

‎src/main/kotlin/com/coder/gateway/settings/CoderSettings.kt‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ open class CoderSettings(
3535
val headerCommand:String
3636
get()= state.headerCommand
3737

38+
val disableAutostart:Boolean
39+
get()= state.disableAutostart
40+
3841
/**
3942
* Where the specified deployment should put its data.
4043
*/

‎src/main/resources/messages/CoderGatewayBundle.properties‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,9 @@ gateway.connector.settings.tls-alt-name.comment=Optionally set this to \
111111
an alternate hostname used for verifying TLS connections. This is useful \
112112
when the hostname used to connect to the Coder service does not match the \
113113
hostname in the TLS certificate.
114+
gateway.connector.settings.disable-autostart.heading=Autostart:
115+
gateway.connector.settings.disable-autostart.title=Disable autostart
116+
gateway.connector.settings.disable-autostart.comment=Checking this box will \
117+
cause the plugin to configure the CLI with --disable-autostart. You must go \
118+
through the IDE selection again for the plugin to reconfigure the CLI with \
119+
this setting.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# --- START CODER JETBRAINS test.coder.invalid
2+
Host coder-jetbrains--foo--test.coder.invalid
3+
ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio --disable-autostart foo
4+
ConnectTimeout 0
5+
StrictHostKeyChecking no
6+
UserKnownHostsFile /dev/null
7+
LogLevel ERROR
8+
SetEnv CODER_SSH_SESSION_TYPE=JetBrains
9+
# --- END CODER JETBRAINS test.coder.invalid
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# --- START CODER JETBRAINS test.coder.invalid
2+
Host coder-jetbrains--foo--test.coder.invalid
3+
ProxyCommand /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64 --global-config /tmp/coder-gateway/test.coder.invalid/config ssh --stdio foo
4+
ConnectTimeout 0
5+
StrictHostKeyChecking no
6+
UserKnownHostsFile /dev/null
7+
LogLevel ERROR
8+
SetEnv CODER_SSH_SESSION_TYPE=JetBrains
9+
# --- END CODER JETBRAINS test.coder.invalid

‎src/test/kotlin/com/coder/gateway/cli/CoderCLIManagerTest.kt‎

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,18 @@ import kotlin.test.assertTrue
3333

3434
internalclassCoderCLIManagerTest {
3535
privatefunmkbin(version:String):String {
36-
returnlistOf("#!/bin/sh","""echo '{"version": "${version}"}'""")
36+
returnlistOf("#!/bin/sh","""echo '{"version": "$version"}'""")
3737
.joinToString("\n")
3838
}
3939

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

237-
data classSSHTest(valworkspaces:List<String>,valinput:String?,valoutput:String,valremove:String,valheaderCommand:String?)
237+
data classSSHTest(
238+
valworkspaces:List<String>,
239+
valinput:String?,
240+
valoutput:String,
241+
valremove:String,
242+
valheaderCommand:String?,
243+
valdisableAutostart:Boolean =false,
244+
valfeatures:Features? =null,
245+
)
238246

239247
@Test
240248
funtestConfigureSSH() {
@@ -256,13 +264,16 @@ internal class CoderCLIManagerTest {
256264
SSHTest(listOf("header"),null,"header-command-windows","blank",""""C:\Program Files\My Header Command\HeaderCommand.exe" --url="%CODER_URL%" --test="foo bar"""")
257265
}else {
258266
SSHTest(listOf("header"),null,"header-command","blank","my-header-command --url=\"\$CODER_URL\" --test=\"foo bar\" --literal='\$CODER_URL'")
259-
}
267+
},
268+
SSHTest(listOf("foo"),null,"disable-autostart","blank",null,true,Features(true)),
269+
SSHTest(listOf("foo"),null,"no-disable-autostart","blank",null,true,Features(false)),
260270
)
261271

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

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

287298
// Add workspaces.
288-
ccm.configSsh(it.workspaces)
299+
ccm.configSsh(it.workspaces, it.features?:Features())
289300

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

292303
// Remove configuration.
293-
ccm.configSsh(emptyList())
304+
ccm.configSsh(emptyList(), it.features?:Features())
294305

295306
// Remove is the configuration we expect after removing.
296307
assertEquals(
@@ -540,6 +551,31 @@ internal class CoderCLIManagerTest {
540551
srv.stop(0)
541552
}
542553

554+
@Test
555+
funtestFeatures() {
556+
if (getOS()==OS.WINDOWS) {
557+
return// Cannot execute mock binaries on Windows.
558+
}
559+
560+
val tests=listOf(
561+
Pair("2.5.0",Features(true)),
562+
Pair("4.9.0",Features(true)),
563+
Pair("2.4.9",Features(false)),
564+
Pair("1.0.1",Features(false)),
565+
)
566+
567+
tests.forEach {
568+
val (srv, url)= mockServer(version= it.first)
569+
val ccm=CoderCLIManager(url,CoderSettings(CoderSettingsState(
570+
dataDirectory= tmpdir.resolve("features").toString()))
571+
)
572+
assertEquals(true, ccm.download())
573+
assertEquals(it.second, ccm.features,"version:${it.first}")
574+
575+
srv.stop(0)
576+
}
577+
}
578+
543579
companionobject {
544580
privateval tmpdir:Path=Path.of(System.getProperty("java.io.tmpdir")).resolve("coder-gateway-test/cli-manager")
545581

‎src/test/kotlin/com/coder/gateway/settings/CoderSettingsTest.kt‎

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
packagecom.coder.gateway.settings
22

33
importcom.coder.gateway.services.CoderSettingsState
4-
importkotlin.test.Test
5-
importkotlin.test.assertContains
6-
importkotlin.test.assertEquals
7-
84
importcom.coder.gateway.util.OS
95
importcom.coder.gateway.util.getOS
106
importcom.coder.gateway.util.withPath
117
importjava.net.URL
128
importjava.nio.file.Path
9+
importkotlin.test.Test
10+
importkotlin.test.assertContains
11+
importkotlin.test.assertEquals
1312

1413
internalclassCoderSettingsTest {
1514
@Test
@@ -179,14 +178,15 @@ internal class CoderSettingsTest {
179178
// Make sure the remaining settings are being conveyed.
180179
val settings=CoderSettings(
181180
CoderSettingsState(
182-
enableDownloads=false,
183-
enableBinaryDirectoryFallback=true,
184-
headerCommand="test header",
185-
tlsCertPath="tls cert path",
186-
tlsKeyPath="tls key path",
187-
tlsCAPath="tls ca path",
188-
tlsAlternateHostname="tls alt hostname",
189-
)
181+
enableDownloads=false,
182+
enableBinaryDirectoryFallback=true,
183+
headerCommand="test header",
184+
tlsCertPath="tls cert path",
185+
tlsKeyPath="tls key path",
186+
tlsCAPath="tls ca path",
187+
tlsAlternateHostname="tls alt hostname",
188+
disableAutostart=true,
189+
)
190190
)
191191

192192
assertEquals(false, settings.enableDownloads)
@@ -196,5 +196,6 @@ internal class CoderSettingsTest {
196196
assertEquals("tls key path", settings.tls.keyPath)
197197
assertEquals("tls ca path", settings.tls.caPath)
198198
assertEquals("tls alt hostname", settings.tls.altHostname)
199+
assertEquals(true, settings.disableAutostart)
199200
}
200201
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp