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

Commit 66e470f

Browse files
authored
fix: don't create new api keys each time we do workspace polling (#568)
* fix: don't create new api keys each time we do workspace polling The default behavior for `coder login --token <token>` is to: - use the provided token temporarily to authenticate the login process - generate a new session token and stores that for future CLI use - the original token provided is not stored or reused The Coder `Recent projects` view polls every 5 seconds for workspaces from multiple Coder deployment. The polling process also involves a call to the `cli.login`. The cli is later used start workspaces if user clicks on a project for which the workspace is stopped. Instead of generating a new token each time we login we can use the `coder login --use-token-as-session --token <token>` which: - uses the provided token directly as the session token - stores the original token for future CLI commands - no new token is generated * refactor: only login the cli when starting workspaces The Coder `Recent projects` view polls every 5 seconds for workspaces from multiple Coder deployment. The polling process also involves a call to the `cli.login`. The cli is later used to start workspaces if a user clicks on a project for which the workspace is stopped. The login can be called on demand, only when a "recent" project is stopped and the user wants to start it. This commit reduces a lot of overhead associated with spawning cli commands every 5 seconds. * chore: next version is 2.22.2
1 parent 35f4ef9 commit 66e470f

File tree

4 files changed

+69
-45
lines changed

4 files changed

+69
-45
lines changed

‎CHANGELOG.md‎

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

55
## Unreleased
66

7+
### Fixed
8+
9+
- api keys are no longer created each time workspaces are polled
10+
711
## 2.22.1 - 2025年07月30日
812

913
### Added

‎gradle.properties‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ pluginGroup=com.coder.gateway
55
artifactName=coder-gateway
66
pluginName=Coder
77
# SemVer format -> https://semver.org
8-
pluginVersion=2.22.1
8+
pluginVersion=2.22.2
99
# See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
1010
# for insight into build numbers and IntelliJ Platform versions.
1111
pluginSinceBuild=243.26574

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ class CoderCLIManager(
288288
return exec(
289289
"login",
290290
deploymentURL.toString(),
291+
"--use-token-as-session",
291292
"--token",
292293
token,
293294
"--global-config",

‎src/main/kotlin/com/coder/gateway/views/CoderGatewayRecentWorkspaceConnectionsView.kt‎

Lines changed: 63 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ package com.coder.gateway.views
55
import com.coder.gateway.CoderGatewayBundle
66
import com.coder.gateway.CoderGatewayConstants
77
import com.coder.gateway.CoderRemoteConnectionHandle
8-
import com.coder.gateway.cli.CoderCLIManager
98
import com.coder.gateway.cli.ensureCLI
109
import com.coder.gateway.icons.CoderIcons
1110
import com.coder.gateway.models.WorkspaceAgentListModel
@@ -75,8 +74,6 @@ data class DeploymentInfo(
7574
var items: List<WorkspaceAgentListModel>? = null,
7675
// Null if there have not been any errors yet.
7776
var error: String? = null,
78-
// Null if unable to ensure the CLI is downloaded.
79-
var cli: CoderCLIManager? = null,
8077
)
8178

8279
class CoderGatewayRecentWorkspaceConnectionsView(private val setContentCallback: (Component) -> Unit) :
@@ -178,13 +175,18 @@ class CoderGatewayRecentWorkspaceConnectionsView(private val setContentCallback:
178175
val me = deployment?.client?.me?.username
179176
val workspaceWithAgent = deployment?.items?.firstOrNull {
180177
it.workspace.ownerName + "/" + it.workspace.name == workspaceName ||
181-
(it.workspace.ownerName == me && it.workspace.name == workspaceName)
178+
(it.workspace.ownerName == me && it.workspace.name == workspaceName)
182179
}
183180
val status =
184181
if (deploymentError != null) {
185182
Triple(UIUtil.getErrorForeground(), deploymentError, UIUtil.getBalloonErrorIcon())
186183
} else if (workspaceWithAgent != null) {
187-
val inLoadingState = listOf(WorkspaceStatus.STARTING, WorkspaceStatus.CANCELING, WorkspaceStatus.DELETING, WorkspaceStatus.STOPPING).contains(workspaceWithAgent.workspace.latestBuild.status)
184+
val inLoadingState = listOf(
185+
WorkspaceStatus.STARTING,
186+
WorkspaceStatus.CANCELING,
187+
WorkspaceStatus.DELETING,
188+
WorkspaceStatus.STOPPING
189+
).contains(workspaceWithAgent.workspace.latestBuild.status)
188190

189191
Triple(
190192
workspaceWithAgent.status.statusColor(),
@@ -196,7 +198,11 @@ class CoderGatewayRecentWorkspaceConnectionsView(private val setContentCallback:
196198
},
197199
)
198200
} else {
199-
Triple(UIUtil.getContextHelpForeground(), "Querying workspace status...", AnimatedIcon.Default())
201+
Triple(
202+
UIUtil.getContextHelpForeground(),
203+
"Querying workspace status...",
204+
AnimatedIcon.Default()
205+
)
200206
}
201207
val gap =
202208
if (top) {
@@ -216,7 +222,13 @@ class CoderGatewayRecentWorkspaceConnectionsView(private val setContentCallback:
216222
label("").resizableColumn().align(AlignX.FILL)
217223
}.topGap(gap)
218224

219-
val enableLinks = listOf(WorkspaceStatus.STOPPED, WorkspaceStatus.CANCELED, WorkspaceStatus.FAILED, WorkspaceStatus.STARTING, WorkspaceStatus.RUNNING).contains(workspaceWithAgent?.workspace?.latestBuild?.status)
225+
val enableLinks = listOf(
226+
WorkspaceStatus.STOPPED,
227+
WorkspaceStatus.CANCELED,
228+
WorkspaceStatus.FAILED,
229+
WorkspaceStatus.STARTING,
230+
WorkspaceStatus.RUNNING
231+
).contains(workspaceWithAgent?.workspace?.latestBuild?.status)
220232

221233
// We only display an API error on the first workspace rather than duplicating it on each workspace.
222234
if (deploymentError == null || showError) {
@@ -236,9 +248,29 @@ class CoderGatewayRecentWorkspaceConnectionsView(private val setContentCallback:
236248
if (enableLinks) {
237249
cell(
238250
ActionLink(workspaceProjectIDE.projectPathDisplay) {
239-
withoutNull(deployment?.cli, workspaceWithAgent?.workspace) { cli, workspace ->
251+
withoutNull(
252+
deployment?.client,
253+
workspaceWithAgent?.workspace
254+
) { client, workspace ->
240255
CoderRemoteConnectionHandle().connect {
241-
if (listOf(WorkspaceStatus.STOPPED, WorkspaceStatus.CANCELED, WorkspaceStatus.FAILED).contains(workspace.latestBuild.status)) {
256+
if (listOf(
257+
WorkspaceStatus.STOPPED,
258+
WorkspaceStatus.CANCELED,
259+
WorkspaceStatus.FAILED
260+
).contains(workspace.latestBuild.status)
261+
) {
262+
val cli = ensureCLI(
263+
deploymentURL.toURL(),
264+
client.buildInfo().version,
265+
settings,
266+
)
267+
// We only need to log the cli in if we have token-based auth.
268+
// Otherwise, we assume it is set up in the same way the plugin
269+
// is with mTLS.
270+
if (client.token != null) {
271+
cli.login(client.token)
272+
}
273+
242274
cli.startWorkspace(workspace.ownerName, workspace.name)
243275
}
244276
workspaceProjectIDE
@@ -289,33 +321,34 @@ class CoderGatewayRecentWorkspaceConnectionsView(private val setContentCallback:
289321
* name, or just `workspace`, if the connection predates when we added owner
290322
* information, in which case it belongs to the current user.
291323
*/
292-
private fun getConnectionsByDeployment(filter: Boolean): Map<String, Map<String, List<WorkspaceProjectIDE>>> = recentConnectionsService.getAllRecentConnections()
293-
// Validate and parse connections.
294-
.mapNotNull {
295-
try {
296-
it.toWorkspaceProjectIDE()
297-
} catch (e: Exception) {
298-
logger.warn("Removing invalid recent connection $it", e)
299-
recentConnectionsService.removeConnection(it)
300-
null
324+
private fun getConnectionsByDeployment(filter: Boolean): Map<String, Map<String, List<WorkspaceProjectIDE>>> =
325+
recentConnectionsService.getAllRecentConnections()
326+
// Validate and parse connections.
327+
.mapNotNull {
328+
try {
329+
it.toWorkspaceProjectIDE()
330+
} catch (e: Exception) {
331+
logger.warn("Removing invalid recent connection $it", e)
332+
recentConnectionsService.removeConnection(it)
333+
null
334+
}
335+
}
336+
.filter { !filter || matchesFilter(it) }
337+
// Group by the deployment.
338+
.groupBy { it.deploymentURL.toString() }
339+
// Group the connections in each deployment by workspace.
340+
.mapValues { (_, connections) ->
341+
connections
342+
.groupBy { it.name.split(".", limit = 2).first() }
301343
}
302-
}
303-
.filter { !filter || matchesFilter(it) }
304-
// Group by the deployment.
305-
.groupBy { it.deploymentURL.toString() }
306-
// Group the connections in each deployment by workspace.
307-
.mapValues { (_, connections) ->
308-
connections
309-
.groupBy { it.name.split(".", limit = 2).first() }
310-
}
311344

312345
/**
313346
* Return true if the connection matches the current filter.
314347
*/
315348
private fun matchesFilter(connection: WorkspaceProjectIDE): Boolean = filterString.let {
316349
it.isNullOrBlank() ||
317-
connection.hostname.lowercase(Locale.getDefault()).contains(it) ||
318-
connection.projectPath.lowercase(Locale.getDefault()).contains(it)
350+
connection.hostname.lowercase(Locale.getDefault()).contains(it) ||
351+
connection.projectPath.lowercase(Locale.getDefault()).contains(it)
319352
}
320353

321354
/**
@@ -362,19 +395,6 @@ class CoderGatewayRecentWorkspaceConnectionsView(private val setContentCallback:
362395
throw Exception("Unable to make request; token was not found in CLI config.")
363396
}
364397

365-
val cli = ensureCLI(
366-
deploymentURL.toURL(),
367-
client.buildInfo().version,
368-
settings,
369-
)
370-
371-
// We only need to log the cli in if we have token-based auth.
372-
// Otherwise, we assume it is set up in the same way the plugin
373-
// is with mTLS.
374-
if (client.token != null) {
375-
cli.login(client.token)
376-
}
377-
378398
// This is purely to populate the current user, which is
379399
// used to match workspaces that were not recorded with owner
380400
// information.
@@ -386,7 +406,7 @@ class CoderGatewayRecentWorkspaceConnectionsView(private val setContentCallback:
386406
connectionsByWorkspace.forEach { (name, connections) ->
387407
if (items.firstOrNull {
388408
it.workspace.ownerName + "/" + it.workspace.name == name ||
389-
(it.workspace.ownerName == me && it.workspace.name == name)
409+
(it.workspace.ownerName == me && it.workspace.name == name)
390410
} == null
391411
) {
392412
logger.info("Removing recent connections for deleted workspace $name (found ${connections.size})")
@@ -395,7 +415,6 @@ class CoderGatewayRecentWorkspaceConnectionsView(private val setContentCallback:
395415
}
396416

397417
deployment.client = client
398-
deployment.cli = cli
399418
deployment.items = items
400419
deployment.error = null
401420
} catch (e: Exception) {

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /