-
Notifications
You must be signed in to change notification settings - Fork 928
feat: show agent version in UI and CLI #3709
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
bef419c
8dd44fc
38957d3
396eaaa
b2888f4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ import ( | |
"strconv" | ||
|
||
"github.com/jedib0t/go-pretty/v6/table" | ||
"golang.org/x/mod/semver" | ||
|
||
"github.com/coder/coder/coderd/database" | ||
|
||
|
@@ -18,6 +19,7 @@ type WorkspaceResourcesOptions struct { | |
HideAgentState bool | ||
HideAccess bool | ||
Title string | ||
ServerVersion string | ||
} | ||
|
||
// WorkspaceResources displays the connection status and tree-view of provided resources. | ||
|
@@ -48,6 +50,7 @@ func WorkspaceResources(writer io.Writer, resources []codersdk.WorkspaceResource | |
row := table.Row{"Resource"} | ||
if !options.HideAgentState { | ||
row = append(row, "Status") | ||
row = append(row, "Version") | ||
} | ||
if !options.HideAccess { | ||
row = append(row, "Access") | ||
|
@@ -91,21 +94,12 @@ func WorkspaceResources(writer io.Writer, resources []codersdk.WorkspaceResource | |
} | ||
if !options.HideAgentState { | ||
var agentStatus string | ||
var agentVersion string | ||
if !options.HideAgentState { | ||
switch agent.Status { | ||
case codersdk.WorkspaceAgentConnecting: | ||
since := database.Now().Sub(agent.CreatedAt) | ||
agentStatus = Styles.Warn.Render("⦾ connecting") + " " + | ||
Styles.Placeholder.Render("["+strconv.Itoa(int(since.Seconds()))+"s]") | ||
case codersdk.WorkspaceAgentDisconnected: | ||
since := database.Now().Sub(*agent.DisconnectedAt) | ||
agentStatus = Styles.Error.Render("⦾ disconnected") + " " + | ||
Styles.Placeholder.Render("["+strconv.Itoa(int(since.Seconds()))+"s]") | ||
case codersdk.WorkspaceAgentConnected: | ||
agentStatus = Styles.Keyword.Render("⦿ connected") | ||
} | ||
agentStatus = renderAgentStatus(agent) | ||
agentVersion = renderAgentVersion(agent.Version, options.ServerVersion) | ||
} | ||
row = append(row, agentStatus) | ||
row = append(row, agentStatus, agentVersion) | ||
} | ||
if !options.HideAccess { | ||
sshCommand := "coder ssh " + options.WorkspaceName | ||
|
@@ -122,3 +116,34 @@ func WorkspaceResources(writer io.Writer, resources []codersdk.WorkspaceResource | |
_, err := fmt.Fprintln(writer, tableWriter.Render()) | ||
return err | ||
} | ||
|
||
func renderAgentStatus(agent codersdk.WorkspaceAgent) string { | ||
switch agent.Status { | ||
case codersdk.WorkspaceAgentConnecting: | ||
since := database.Now().Sub(agent.CreatedAt) | ||
return Styles.Warn.Render("⦾ connecting") + " " + | ||
Styles.Placeholder.Render("["+strconv.Itoa(int(since.Seconds()))+"s]") | ||
case codersdk.WorkspaceAgentDisconnected: | ||
since := database.Now().Sub(*agent.DisconnectedAt) | ||
return Styles.Error.Render("⦾ disconnected") + " " + | ||
Styles.Placeholder.Render("["+strconv.Itoa(int(since.Seconds()))+"s]") | ||
case codersdk.WorkspaceAgentConnected: | ||
return Styles.Keyword.Render("⦿ connected") | ||
default: | ||
return Styles.Warn.Render("○ unknown") | ||
} | ||
} | ||
|
||
func renderAgentVersion(agentVersion, serverVersion string) string { | ||
if agentVersion == "" { | ||
agentVersion = "(unknown)" | ||
} | ||
if !semver.IsValid(serverVersion) || !semver.IsValid(agentVersion) { | ||
return Styles.Placeholder.Render(agentVersion) | ||
} | ||
outdated := semver.Compare(agentVersion, serverVersion) < 0 | ||
if outdated { | ||
return Styles.Warn.Render(agentVersion + " (outdated)") | ||
} | ||
return Styles.Keyword.Render(agentVersion) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In theory, the agent could be newer than the server too. Should we show this somehow? (This will be more relevant if users are using a server version without bundled agent binaries #3593, but could also happen on server downgrades.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That'll be apparent by comparing the version shown here with the version shown in the footer. |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package cliui | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestRenderAgentVersion(t *testing.T) { | ||
t.Parallel() | ||
testCases := []struct { | ||
name string | ||
agentVersion string | ||
serverVersion string | ||
expected string | ||
}{ | ||
{ | ||
name: "OK", | ||
agentVersion: "v1.2.3", | ||
serverVersion: "v1.2.3", | ||
expected: "v1.2.3", | ||
}, | ||
{ | ||
name: "Outdated", | ||
agentVersion: "v1.2.3", | ||
serverVersion: "v1.2.4", | ||
expected: "v1.2.3 (outdated)", | ||
}, | ||
{ | ||
name: "AgentUnknown", | ||
agentVersion: "", | ||
serverVersion: "v1.2.4", | ||
expected: "(unknown)", | ||
}, | ||
{ | ||
name: "ServerUnknown", | ||
agentVersion: "v1.2.3", | ||
serverVersion: "", | ||
expected: "v1.2.3", | ||
}, | ||
} | ||
for _, testCase := range testCases { | ||
testCase := testCase | ||
t.Run(testCase.name, func(t *testing.T) { | ||
t.Parallel() | ||
actual := renderAgentVersion(testCase.agentVersion, testCase.serverVersion) | ||
assert.Equal(t, testCase.expected, actual) | ||
}) | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
ALTER TABLE ONLY workspace_agents DROP COLUMN version; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
ALTER TABLE ONLY workspace_agents ADD COLUMN version text DEFAULT ''::text NOT NULL; | ||
COMMENT ON COLUMN workspace_agents.version IS 'Version tracks the version of the currently running workspace agent. Workspace agents register their version upon start.'; |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: We could consider discarding this API endpoint and make the version a part of the connect-to-server process. This way the version would only be updated on successful connects. I don't really see a need to be able to post an update for the version any other time during an agents lifecycle.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UploadWorkspaceAgentKeys
uses an endpointPOST /api/v2/workspaceagents/me/keys
as well and I believe we only upload keys once per agent. This feels like a separate refactor.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that scenario (
UploadWorkspaceAgentKeys
) is slightly different since it's a pre-requisite for establishing the connection over WireGuard (I could be wrong, though). But I won't push for this change so feel free to omit.My motivation behind the suggestion was simply to ensure that the version tracked in the DB is consistent with "the last version of the agent that connected to the server". With the pre-post, in essence, it becomes "the last version that tried to talk to the server", but connection could've failed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ammario has a PR open for metrics to be pushed to coderd. It could be done as apart of that process. Version reporting is a sort of metric?