Skip to content

Commit 8b3d4dd

Browse files
committed
chore: merge main into branch
2 parents 923d080 + 7d63dc2 commit 8b3d4dd

File tree

180 files changed

+6226
-5997
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

180 files changed

+6226
-5997
lines changed

cli/agent_test.go

+55-101
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ import (
1616
"github.com/coder/coder/v2/agent"
1717
"github.com/coder/coder/v2/cli/clitest"
1818
"github.com/coder/coder/v2/coderd/coderdtest"
19+
"github.com/coder/coder/v2/coderd/database"
20+
"github.com/coder/coder/v2/coderd/database/dbfake"
1921
"github.com/coder/coder/v2/codersdk"
20-
"github.com/coder/coder/v2/provisioner/echo"
2122
"github.com/coder/coder/v2/provisionersdk/proto"
2223
"github.com/coder/coder/v2/pty/ptytest"
2324
)
@@ -28,20 +29,12 @@ func TestWorkspaceAgent(t *testing.T) {
2829
t.Run("LogDirectory", func(t *testing.T) {
2930
t.Parallel()
3031

31-
authToken := uuid.NewString()
32-
client := coderdtest.New(t, &coderdtest.Options{
33-
IncludeProvisionerDaemon: true,
34-
})
32+
client, db := coderdtest.NewWithDatabase(t, nil)
3533
user := coderdtest.CreateFirstUser(t, client)
36-
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
37-
Parse: echo.ParseComplete,
38-
ProvisionApply: echo.ProvisionApplyWithAgent(authToken),
34+
ws, authToken := dbfake.WorkspaceWithAgent(t, db, database.Workspace{
35+
OrganizationID: user.OrganizationID,
36+
OwnerID: user.UserID,
3937
})
40-
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
41-
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
42-
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
43-
coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID)
44-
4538
logDir := t.TempDir()
4639
inv, _ := clitest.New(t,
4740
"agent",
@@ -57,7 +50,7 @@ func TestWorkspaceAgent(t *testing.T) {
5750
ctx := inv.Context()
5851
pty.ExpectMatchContext(ctx, "agent is starting now")
5952

60-
coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID)
53+
coderdtest.AwaitWorkspaceAgents(t, client, ws.ID)
6154

6255
info, err := os.Stat(filepath.Join(logDir, "coder-agent.log"))
6356
require.NoError(t, err)
@@ -68,33 +61,23 @@ func TestWorkspaceAgent(t *testing.T) {
6861
t.Parallel()
6962
instanceID := "instanceidentifier"
7063
certificates, metadataClient := coderdtest.NewAzureInstanceIdentity(t, instanceID)
71-
client := coderdtest.New(t, &coderdtest.Options{
72-
AzureCertificates: certificates,
73-
IncludeProvisionerDaemon: true,
64+
client, db := coderdtest.NewWithDatabase(t, &coderdtest.Options{
65+
AzureCertificates: certificates,
7466
})
7567
user := coderdtest.CreateFirstUser(t, client)
76-
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
77-
Parse: echo.ParseComplete,
78-
ProvisionApply: []*proto.Response{{
79-
Type: &proto.Response_Apply{
80-
Apply: &proto.ApplyComplete{
81-
Resources: []*proto.Resource{{
82-
Name: "somename",
83-
Type: "someinstance",
84-
Agents: []*proto.Agent{{
85-
Auth: &proto.Agent_InstanceId{
86-
InstanceId: instanceID,
87-
},
88-
}},
89-
}},
90-
},
68+
ws := dbfake.Workspace(t, db, database.Workspace{
69+
OrganizationID: user.OrganizationID,
70+
OwnerID: user.UserID,
71+
})
72+
dbfake.WorkspaceBuild(t, db, ws, database.WorkspaceBuild{}, &proto.Resource{
73+
Name: "somename",
74+
Type: "someinstance",
75+
Agents: []*proto.Agent{{
76+
Auth: &proto.Agent_InstanceId{
77+
InstanceId: instanceID,
9178
},
9279
}},
9380
})
94-
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
95-
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
96-
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
97-
coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID)
9881

9982
inv, _ := clitest.New(t, "agent", "--auth", "azure-instance-identity", "--agent-url", client.URL.String())
10083
inv = inv.WithContext(
@@ -103,8 +86,8 @@ func TestWorkspaceAgent(t *testing.T) {
10386
)
10487
ctx := inv.Context()
10588
clitest.Start(t, inv)
106-
coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID)
107-
workspace, err := client.Workspace(ctx, workspace.ID)
89+
coderdtest.AwaitWorkspaceAgents(t, client, ws.ID)
90+
workspace, err := client.Workspace(ctx, ws.ID)
10891
require.NoError(t, err)
10992
resources := workspace.LatestBuild.Resources
11093
if assert.NotEmpty(t, workspace.LatestBuild.Resources) && assert.NotEmpty(t, resources[0].Agents) {
@@ -120,33 +103,23 @@ func TestWorkspaceAgent(t *testing.T) {
120103
t.Parallel()
121104
instanceID := "instanceidentifier"
122105
certificates, metadataClient := coderdtest.NewAWSInstanceIdentity(t, instanceID)
123-
client := coderdtest.New(t, &coderdtest.Options{
124-
AWSCertificates: certificates,
125-
IncludeProvisionerDaemon: true,
106+
client, db := coderdtest.NewWithDatabase(t, &coderdtest.Options{
107+
AWSCertificates: certificates,
126108
})
127109
user := coderdtest.CreateFirstUser(t, client)
128-
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
129-
Parse: echo.ParseComplete,
130-
ProvisionApply: []*proto.Response{{
131-
Type: &proto.Response_Apply{
132-
Apply: &proto.ApplyComplete{
133-
Resources: []*proto.Resource{{
134-
Name: "somename",
135-
Type: "someinstance",
136-
Agents: []*proto.Agent{{
137-
Auth: &proto.Agent_InstanceId{
138-
InstanceId: instanceID,
139-
},
140-
}},
141-
}},
142-
},
110+
ws := dbfake.Workspace(t, db, database.Workspace{
111+
OrganizationID: user.OrganizationID,
112+
OwnerID: user.UserID,
113+
})
114+
dbfake.WorkspaceBuild(t, db, ws, database.WorkspaceBuild{}, &proto.Resource{
115+
Name: "somename",
116+
Type: "someinstance",
117+
Agents: []*proto.Agent{{
118+
Auth: &proto.Agent_InstanceId{
119+
InstanceId: instanceID,
143120
},
144121
}},
145122
})
146-
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
147-
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
148-
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
149-
coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID)
150123

151124
inv, _ := clitest.New(t, "agent", "--auth", "aws-instance-identity", "--agent-url", client.URL.String())
152125
inv = inv.WithContext(
@@ -155,8 +128,8 @@ func TestWorkspaceAgent(t *testing.T) {
155128
)
156129
clitest.Start(t, inv)
157130
ctx := inv.Context()
158-
coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID)
159-
workspace, err := client.Workspace(ctx, workspace.ID)
131+
coderdtest.AwaitWorkspaceAgents(t, client, ws.ID)
132+
workspace, err := client.Workspace(ctx, ws.ID)
160133
require.NoError(t, err)
161134
resources := workspace.LatestBuild.Resources
162135
if assert.NotEmpty(t, resources) && assert.NotEmpty(t, resources[0].Agents) {
@@ -172,35 +145,24 @@ func TestWorkspaceAgent(t *testing.T) {
172145
t.Parallel()
173146
instanceID := "instanceidentifier"
174147
validator, metadataClient := coderdtest.NewGoogleInstanceIdentity(t, instanceID, false)
175-
client := coderdtest.New(t, &coderdtest.Options{
176-
GoogleTokenValidator: validator,
177-
IncludeProvisionerDaemon: true,
148+
client, db := coderdtest.NewWithDatabase(t, &coderdtest.Options{
149+
GoogleTokenValidator: validator,
178150
})
179151
owner := coderdtest.CreateFirstUser(t, client)
180-
member, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
181-
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, &echo.Responses{
182-
Parse: echo.ParseComplete,
183-
ProvisionApply: []*proto.Response{{
184-
Type: &proto.Response_Apply{
185-
Apply: &proto.ApplyComplete{
186-
Resources: []*proto.Resource{{
187-
Name: "somename",
188-
Type: "someinstance",
189-
Agents: []*proto.Agent{{
190-
Auth: &proto.Agent_InstanceId{
191-
InstanceId: instanceID,
192-
},
193-
}},
194-
}},
195-
},
152+
member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
153+
ws := dbfake.Workspace(t, db, database.Workspace{
154+
OrganizationID: owner.OrganizationID,
155+
OwnerID: memberUser.ID,
156+
})
157+
dbfake.WorkspaceBuild(t, db, ws, database.WorkspaceBuild{}, &proto.Resource{
158+
Name: "somename",
159+
Type: "someinstance",
160+
Agents: []*proto.Agent{{
161+
Auth: &proto.Agent_InstanceId{
162+
InstanceId: instanceID,
196163
},
197164
}},
198165
})
199-
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)
200-
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
201-
workspace := coderdtest.CreateWorkspace(t, member, owner.OrganizationID, template.ID)
202-
coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID)
203-
204166
inv, cfg := clitest.New(t, "agent", "--auth", "google-instance-identity", "--agent-url", client.URL.String())
205167
ptytest.New(t).Attach(inv)
206168
clitest.SetupConfig(t, member, cfg)
@@ -212,9 +174,8 @@ func TestWorkspaceAgent(t *testing.T) {
212174
)
213175

214176
ctx := inv.Context()
215-
216-
coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID)
217-
workspace, err := client.Workspace(ctx, workspace.ID)
177+
coderdtest.AwaitWorkspaceAgents(t, client, ws.ID)
178+
workspace, err := client.Workspace(ctx, ws.ID)
218179
require.NoError(t, err)
219180
resources := workspace.LatestBuild.Resources
220181
if assert.NotEmpty(t, resources) && assert.NotEmpty(t, resources[0].Agents) {
@@ -244,19 +205,12 @@ func TestWorkspaceAgent(t *testing.T) {
244205
t.Run("PostStartup", func(t *testing.T) {
245206
t.Parallel()
246207

247-
authToken := uuid.NewString()
248-
client := coderdtest.New(t, &coderdtest.Options{
249-
IncludeProvisionerDaemon: true,
250-
})
208+
client, db := coderdtest.NewWithDatabase(t, nil)
251209
user := coderdtest.CreateFirstUser(t, client)
252-
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
253-
Parse: echo.ParseComplete,
254-
ProvisionApply: echo.ProvisionApplyWithAgent(authToken),
210+
ws, authToken := dbfake.WorkspaceWithAgent(t, db, database.Workspace{
211+
OrganizationID: user.OrganizationID,
212+
OwnerID: user.UserID,
255213
})
256-
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
257-
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
258-
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
259-
coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID)
260214

261215
logDir := t.TempDir()
262216
inv, _ := clitest.New(t,
@@ -274,7 +228,7 @@ func TestWorkspaceAgent(t *testing.T) {
274228
clitest.Start(t, inv)
275229
pty.ExpectMatchContext(inv.Context(), "agent is starting now")
276230

277-
resources := coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID)
231+
resources := coderdtest.AwaitWorkspaceAgents(t, client, ws.ID)
278232
require.Len(t, resources, 1)
279233
require.Len(t, resources[0].Agents, 1)
280234
require.Len(t, resources[0].Agents[0].Subsystems, 2)

cli/autoupdate.go

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package cli
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
"golang.org/x/xerrors"
8+
9+
"github.com/coder/coder/v2/cli/clibase"
10+
"github.com/coder/coder/v2/cli/cliui"
11+
"github.com/coder/coder/v2/codersdk"
12+
)
13+
14+
func (r *RootCmd) autoupdate() *clibase.Cmd {
15+
client := new(codersdk.Client)
16+
cmd := &clibase.Cmd{
17+
Annotations: workspaceCommand,
18+
Use: "autoupdate <workspace> <always|never>",
19+
Short: "Toggle auto-update policy for a workspace",
20+
Middleware: clibase.Chain(
21+
clibase.RequireNArgs(2),
22+
r.InitClient(client),
23+
),
24+
Handler: func(inv *clibase.Invocation) error {
25+
policy := strings.ToLower(inv.Args[1])
26+
err := validateAutoUpdatePolicy(policy)
27+
if err != nil {
28+
return xerrors.Errorf("validate policy: %w", err)
29+
}
30+
31+
workspace, err := namedWorkspace(inv.Context(), client, inv.Args[0])
32+
if err != nil {
33+
return xerrors.Errorf("get workspace: %w", err)
34+
}
35+
36+
err = client.UpdateWorkspaceAutomaticUpdates(inv.Context(), workspace.ID, codersdk.UpdateWorkspaceAutomaticUpdatesRequest{
37+
AutomaticUpdates: codersdk.AutomaticUpdates(policy),
38+
})
39+
if err != nil {
40+
return xerrors.Errorf("update workspace automatic updates policy: %w", err)
41+
}
42+
_, _ = fmt.Fprintf(inv.Stdout, "Updated workspace %q auto-update policy to %q\n", workspace.Name, policy)
43+
return nil
44+
},
45+
}
46+
47+
cmd.Options = append(cmd.Options, cliui.SkipPromptOption())
48+
return cmd
49+
}
50+
51+
func validateAutoUpdatePolicy(arg string) error {
52+
switch codersdk.AutomaticUpdates(arg) {
53+
case codersdk.AutomaticUpdatesAlways, codersdk.AutomaticUpdatesNever:
54+
return nil
55+
default:
56+
return xerrors.Errorf("invalid option %q must be either of %q or %q", arg, codersdk.AutomaticUpdatesAlways, codersdk.AutomaticUpdatesNever)
57+
}
58+
}

cli/autoupdate_test.go

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package cli_test
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"testing"
7+
8+
"github.com/stretchr/testify/require"
9+
10+
"github.com/coder/coder/v2/cli/clitest"
11+
"github.com/coder/coder/v2/coderd/coderdtest"
12+
"github.com/coder/coder/v2/codersdk"
13+
)
14+
15+
func TestAutoUpdate(t *testing.T) {
16+
t.Parallel()
17+
18+
t.Run("OK", func(t *testing.T) {
19+
t.Parallel()
20+
21+
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
22+
owner := coderdtest.CreateFirstUser(t, client)
23+
member, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
24+
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil)
25+
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
26+
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)
27+
workspace := coderdtest.CreateWorkspace(t, member, owner.OrganizationID, template.ID)
28+
coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID)
29+
require.Equal(t, codersdk.AutomaticUpdatesNever, workspace.AutomaticUpdates)
30+
31+
expectedPolicy := codersdk.AutomaticUpdatesAlways
32+
inv, root := clitest.New(t, "autoupdate", workspace.Name, string(expectedPolicy))
33+
clitest.SetupConfig(t, member, root)
34+
var buf bytes.Buffer
35+
inv.Stdout = &buf
36+
err := inv.Run()
37+
require.NoError(t, err)
38+
require.Contains(t, buf.String(), fmt.Sprintf("Updated workspace %q auto-update policy to %q", workspace.Name, expectedPolicy))
39+
40+
workspace = coderdtest.MustWorkspace(t, client, workspace.ID)
41+
require.Equal(t, expectedPolicy, workspace.AutomaticUpdates)
42+
})
43+
44+
t.Run("InvalidArgs", func(t *testing.T) {
45+
type testcase struct {
46+
Name string
47+
Args []string
48+
ErrorContains string
49+
}
50+
51+
cases := []testcase{
52+
{
53+
Name: "NoPolicy",
54+
Args: []string{"autoupdate", "ws"},
55+
ErrorContains: "wanted 2 args but got 1",
56+
},
57+
{
58+
Name: "InvalidPolicy",
59+
Args: []string{"autoupdate", "ws", "sometimes"},
60+
ErrorContains: `invalid option "sometimes" must be either of`,
61+
},
62+
}
63+
64+
for _, c := range cases {
65+
c := c
66+
t.Run(c.Name, func(t *testing.T) {
67+
t.Parallel()
68+
client := coderdtest.New(t, nil)
69+
_ = coderdtest.CreateFirstUser(t, client)
70+
71+
inv, root := clitest.New(t, c.Args...)
72+
clitest.SetupConfig(t, client, root)
73+
err := inv.Run()
74+
require.Error(t, err)
75+
require.Contains(t, err.Error(), c.ErrorContains)
76+
})
77+
}
78+
})
79+
}

0 commit comments

Comments
 (0)