Skip to content

Commit 93b1425

Browse files
authored
Stop showing persistent vs ephemeral for resources (#2333)
Signed-off-by: Spike Curtis <spike@coder.com>
1 parent 552dad6 commit 93b1425

File tree

5 files changed

+147
-61
lines changed

5 files changed

+147
-61
lines changed

cli/cliui/resources.go

+33-50
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/jedib0t/go-pretty/v6/table"
1010

1111
"github.com/coder/coder/coderd/database"
12+
1213
"github.com/coder/coder/codersdk"
1314
)
1415

@@ -23,12 +24,12 @@ type WorkspaceResourcesOptions struct {
2324
// ┌────────────────────────────────────────────────────────────────────────────┐
2425
// │ RESOURCE STATUS ACCESS │
2526
// ├────────────────────────────────────────────────────────────────────────────┤
26-
// │ google_compute_disk.root persistent
27+
// │ google_compute_disk.root
2728
// ├────────────────────────────────────────────────────────────────────────────┤
28-
// │ google_compute_instance.dev ephemeral
29+
// │ google_compute_instance.dev
2930
// │ └─ dev (linux, amd64) ⦾ connecting [10s] coder ssh dev.dev │
3031
// ├────────────────────────────────────────────────────────────────────────────┤
31-
// │ kubernetes_pod.dev ephemeral
32+
// │ kubernetes_pod.dev
3233
// │ ├─ go (linux, amd64) ⦿ connected coder ssh dev.go │
3334
// │ └─ postgres (linux, amd64) ⦾ disconnected [4s] coder ssh dev.postgres │
3435
// └────────────────────────────────────────────────────────────────────────────┘
@@ -38,26 +39,16 @@ func WorkspaceResources(writer io.Writer, resources []codersdk.WorkspaceResource
3839
return resources[i].Type < resources[j].Type
3940
})
4041

41-
// Address on stop indexes whether a resource still exists when in the stopped transition.
42-
addressOnStop := map[string]codersdk.WorkspaceResource{}
43-
for _, resource := range resources {
44-
if resource.Transition != codersdk.WorkspaceTransitionStop {
45-
continue
46-
}
47-
addressOnStop[resource.Type+"."+resource.Name] = resource
48-
}
49-
// Displayed stores whether a resource has already been shown.
50-
// Resources can be stored with numerous states, which we
51-
// process prior to display.
52-
displayed := map[string]struct{}{}
53-
5442
tableWriter := table.NewWriter()
5543
if options.Title != "" {
5644
tableWriter.SetTitle(options.Title)
5745
}
5846
tableWriter.SetStyle(table.StyleLight)
5947
tableWriter.Style().Options.SeparateColumns = false
60-
row := table.Row{"Resource", "Status"}
48+
row := table.Row{"Resource"}
49+
if !options.HideAgentState {
50+
row = append(row, "Status")
51+
}
6152
if !options.HideAccess {
6253
row = append(row, "Access")
6354
}
@@ -76,60 +67,52 @@ func WorkspaceResources(writer io.Writer, resources []codersdk.WorkspaceResource
7667
continue
7768
}
7869
resourceAddress := resource.Type + "." + resource.Name
79-
if _, shown := displayed[resourceAddress]; shown {
80-
// The same resource can have multiple transitions.
81-
continue
82-
}
83-
displayed[resourceAddress] = struct{}{}
8470

8571
// Sort agents by name for consistent output.
8672
sort.Slice(resource.Agents, func(i, j int) bool {
8773
return resource.Agents[i].Name < resource.Agents[j].Name
8874
})
89-
_, existsOnStop := addressOnStop[resourceAddress]
90-
resourceState := "ephemeral"
91-
if existsOnStop {
92-
resourceState = "persistent"
93-
}
75+
9476
// Display a line for the resource.
9577
tableWriter.AppendRow(table.Row{
9678
Styles.Bold.Render(resourceAddress),
97-
Styles.Placeholder.Render(resourceState),
79+
"",
9880
"",
9981
})
10082
// Display all agents associated with the resource.
10183
for index, agent := range resource.Agents {
102-
sshCommand := "coder ssh " + options.WorkspaceName
103-
if totalAgents > 1 {
104-
sshCommand += "." + agent.Name
105-
}
106-
sshCommand = Styles.Code.Render(sshCommand)
107-
var agentStatus string
108-
if !options.HideAgentState {
109-
switch agent.Status {
110-
case codersdk.WorkspaceAgentConnecting:
111-
since := database.Now().Sub(agent.CreatedAt)
112-
agentStatus = Styles.Warn.Render("⦾ connecting") + " " +
113-
Styles.Placeholder.Render("["+strconv.Itoa(int(since.Seconds()))+"s]")
114-
case codersdk.WorkspaceAgentDisconnected:
115-
since := database.Now().Sub(*agent.DisconnectedAt)
116-
agentStatus = Styles.Error.Render("⦾ disconnected") + " " +
117-
Styles.Placeholder.Render("["+strconv.Itoa(int(since.Seconds()))+"s]")
118-
case codersdk.WorkspaceAgentConnected:
119-
agentStatus = Styles.Keyword.Render("⦿ connected")
120-
}
121-
}
122-
12384
pipe := "├"
12485
if index == len(resource.Agents)-1 {
12586
pipe = "└"
12687
}
12788
row := table.Row{
12889
// These tree from a resource!
12990
fmt.Sprintf("%s─ %s (%s, %s)", pipe, agent.Name, agent.OperatingSystem, agent.Architecture),
130-
agentStatus,
91+
}
92+
if !options.HideAgentState {
93+
var agentStatus string
94+
if !options.HideAgentState {
95+
switch agent.Status {
96+
case codersdk.WorkspaceAgentConnecting:
97+
since := database.Now().Sub(agent.CreatedAt)
98+
agentStatus = Styles.Warn.Render("⦾ connecting") + " " +
99+
Styles.Placeholder.Render("["+strconv.Itoa(int(since.Seconds()))+"s]")
100+
case codersdk.WorkspaceAgentDisconnected:
101+
since := database.Now().Sub(*agent.DisconnectedAt)
102+
agentStatus = Styles.Error.Render("⦾ disconnected") + " " +
103+
Styles.Placeholder.Render("["+strconv.Itoa(int(since.Seconds()))+"s]")
104+
case codersdk.WorkspaceAgentConnected:
105+
agentStatus = Styles.Keyword.Render("⦿ connected")
106+
}
107+
}
108+
row = append(row, agentStatus)
131109
}
132110
if !options.HideAccess {
111+
sshCommand := "coder ssh " + options.WorkspaceName
112+
if totalAgents > 1 {
113+
sshCommand += "." + agent.Name
114+
}
115+
sshCommand = Styles.Code.Render(sshCommand)
133116
row = append(row, sshCommand)
134117
}
135118
tableWriter.AppendRow(row)

cli/create_test.go

+17-8
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ func TestCreate(t *testing.T) {
2727
t.Parallel()
2828
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerD: true})
2929
user := coderdtest.CreateFirstUser(t, client)
30-
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
30+
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
31+
Parse: echo.ParseComplete,
32+
Provision: provisionCompleteWithAgent,
33+
ProvisionDryRun: provisionCompleteWithAgent,
34+
})
3135
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
3236
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
3337
args := []string{
@@ -51,14 +55,19 @@ func TestCreate(t *testing.T) {
5155
err := cmd.Execute()
5256
assert.NoError(t, err)
5357
}()
54-
matches := []string{
55-
"Confirm create", "yes",
58+
matches := []struct {
59+
match string
60+
write string
61+
}{
62+
{match: "compute.main"},
63+
{match: "smith (linux, i386)"},
64+
{match: "Confirm create", write: "yes"},
5665
}
57-
for i := 0; i < len(matches); i += 2 {
58-
match := matches[i]
59-
value := matches[i+1]
60-
pty.ExpectMatch(match)
61-
pty.WriteLine(value)
66+
for _, m := range matches {
67+
pty.ExpectMatch(m.match)
68+
if len(m.write) > 0 {
69+
pty.WriteLine(m.write)
70+
}
6271
}
6372
<-doneChan
6473
})

cli/show_test.go

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package cli_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
8+
"github.com/coder/coder/cli/clitest"
9+
"github.com/coder/coder/coderd/coderdtest"
10+
"github.com/coder/coder/provisioner/echo"
11+
"github.com/coder/coder/pty/ptytest"
12+
)
13+
14+
func TestShow(t *testing.T) {
15+
t.Parallel()
16+
t.Run("Exists", func(t *testing.T) {
17+
t.Parallel()
18+
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerD: true})
19+
user := coderdtest.CreateFirstUser(t, client)
20+
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
21+
Parse: echo.ParseComplete,
22+
Provision: provisionCompleteWithAgent,
23+
ProvisionDryRun: provisionCompleteWithAgent,
24+
})
25+
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
26+
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
27+
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
28+
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
29+
30+
args := []string{
31+
"show",
32+
workspace.Name,
33+
}
34+
cmd, root := clitest.New(t, args...)
35+
clitest.SetupConfig(t, client, root)
36+
doneChan := make(chan struct{})
37+
pty := ptytest.New(t)
38+
cmd.SetIn(pty.Input())
39+
cmd.SetOut(pty.Output())
40+
go func() {
41+
defer close(doneChan)
42+
err := cmd.Execute()
43+
assert.NoError(t, err)
44+
}()
45+
matches := []struct {
46+
match string
47+
write string
48+
}{
49+
{match: "compute.main"},
50+
{match: "smith (linux, i386)"},
51+
{match: "coder ssh " + workspace.Name},
52+
}
53+
for _, m := range matches {
54+
pty.ExpectMatch(m.match)
55+
if len(m.write) > 0 {
56+
pty.WriteLine(m.write)
57+
}
58+
}
59+
<-doneChan
60+
})
61+
}

cli/templatecreate.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,14 @@ func createValidTemplateVersion(cmd *cobra.Command, client *codersdk.Client, org
230230
return nil, nil, err
231231
}
232232

233-
err = cliui.WorkspaceResources(cmd.OutOrStdout(), resources, cliui.WorkspaceResourcesOptions{
233+
// Only display the resources on the start transition, to avoid listing them more than once.
234+
var startResources []codersdk.WorkspaceResource
235+
for _, r := range resources {
236+
if r.Transition == codersdk.WorkspaceTransitionStart {
237+
startResources = append(startResources, r)
238+
}
239+
}
240+
err = cliui.WorkspaceResources(cmd.OutOrStdout(), startResources, cliui.WorkspaceResourcesOptions{
234241
HideAgentState: true,
235242
HideAccess: true,
236243
Title: "Template Preview",

cli/templatecreate_test.go

+28-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,28 @@ import (
1414
"github.com/coder/coder/pty/ptytest"
1515
)
1616

17+
var provisionCompleteWithAgent = []*proto.Provision_Response{
18+
{
19+
Type: &proto.Provision_Response_Complete{
20+
Complete: &proto.Provision_Complete{
21+
Resources: []*proto.Resource{
22+
{
23+
Type: "compute",
24+
Name: "main",
25+
Agents: []*proto.Agent{
26+
{
27+
Name: "smith",
28+
OperatingSystem: "linux",
29+
Architecture: "i386",
30+
},
31+
},
32+
},
33+
},
34+
},
35+
},
36+
},
37+
}
38+
1739
func TestTemplateCreate(t *testing.T) {
1840
t.Parallel()
1941
t.Run("Create", func(t *testing.T) {
@@ -22,7 +44,7 @@ func TestTemplateCreate(t *testing.T) {
2244
coderdtest.CreateFirstUser(t, client)
2345
source := clitest.CreateTemplateVersionSource(t, &echo.Responses{
2446
Parse: echo.ParseComplete,
25-
Provision: echo.ProvisionComplete,
47+
Provision: provisionCompleteWithAgent,
2648
})
2749
args := []string{
2850
"templates",
@@ -49,11 +71,15 @@ func TestTemplateCreate(t *testing.T) {
4971
write string
5072
}{
5173
{match: "Create and upload", write: "yes"},
74+
{match: "compute.main"},
75+
{match: "smith (linux, i386)"},
5276
{match: "Confirm create?", write: "yes"},
5377
}
5478
for _, m := range matches {
5579
pty.ExpectMatch(m.match)
56-
pty.WriteLine(m.write)
80+
if len(m.write) > 0 {
81+
pty.WriteLine(m.write)
82+
}
5783
}
5884

5985
require.NoError(t, <-execDone)

0 commit comments

Comments
 (0)