Skip to content

Commit 72e1e5b

Browse files
committed
Merge branch 'main' into rafrdz/offline-provisioners
2 parents 0b86c21 + c70a786 commit 72e1e5b

File tree

156 files changed

+4984
-913
lines changed

Some content is hidden

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

156 files changed

+4984
-913
lines changed

agent/agent_test.go

Lines changed: 69 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -2668,19 +2668,19 @@ func TestAgent_Dial(t *testing.T) {
26682668

26692669
cases := []struct {
26702670
name string
2671-
setup func(t *testing.T) net.Listener
2671+
setup func(t testing.TB) net.Listener
26722672
}{
26732673
{
26742674
name: "TCP",
2675-
setup: func(t *testing.T) net.Listener {
2675+
setup: func(t testing.TB) net.Listener {
26762676
l, err := net.Listen("tcp", "127.0.0.1:0")
26772677
require.NoError(t, err, "create TCP listener")
26782678
return l
26792679
},
26802680
},
26812681
{
26822682
name: "UDP",
2683-
setup: func(t *testing.T) net.Listener {
2683+
setup: func(t testing.TB) net.Listener {
26842684
addr := net.UDPAddr{
26852685
IP: net.ParseIP("127.0.0.1"),
26862686
Port: 0,
@@ -2698,57 +2698,69 @@ func TestAgent_Dial(t *testing.T) {
26982698

26992699
// The purpose of this test is to ensure that a client can dial a
27002700
// listener in the workspace over tailnet.
2701-
l := c.setup(t)
2702-
done := make(chan struct{})
2703-
defer func() {
2704-
l.Close()
2705-
<-done
2706-
}()
2707-
2708-
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
2709-
defer cancel()
2710-
2711-
go func() {
2712-
defer close(done)
2713-
for range 2 {
2714-
c, err := l.Accept()
2715-
if assert.NoError(t, err, "accept connection") {
2716-
testAccept(ctx, t, c)
2717-
_ = c.Close()
2701+
//
2702+
// The OS sometimes drops packets if the system can't keep up with
2703+
// them. For TCP packets, it's typically fine due to
2704+
// retransmissions, but for UDP packets, it can fail this test.
2705+
//
2706+
// The OS gets involved for the Wireguard traffic (either via DERP
2707+
// or direct UDP), and also for the traffic between the agent and
2708+
// the listener in the "workspace".
2709+
//
2710+
// To avoid this, we'll retry this test up to 3 times.
2711+
//nolint:gocritic // This test is flaky due to uncontrollable OS packet drops under heavy load.
2712+
testutil.RunRetry(t, 3, func(t testing.TB) {
2713+
ctx := testutil.Context(t, testutil.WaitLong)
2714+
2715+
l := c.setup(t)
2716+
done := make(chan struct{})
2717+
defer func() {
2718+
l.Close()
2719+
<-done
2720+
}()
2721+
2722+
go func() {
2723+
defer close(done)
2724+
for range 2 {
2725+
c, err := l.Accept()
2726+
if assert.NoError(t, err, "accept connection") {
2727+
testAccept(ctx, t, c)
2728+
_ = c.Close()
2729+
}
27182730
}
2719-
}
2720-
}()
2731+
}()
27212732

2722-
agentID := uuid.UUID{0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8}
2723-
//nolint:dogsled
2724-
agentConn, _, _, _, _ := setupAgent(t, agentsdk.Manifest{
2725-
AgentID: agentID,
2726-
}, 0)
2727-
require.True(t, agentConn.AwaitReachable(ctx))
2728-
conn, err := agentConn.DialContext(ctx, l.Addr().Network(), l.Addr().String())
2729-
require.NoError(t, err)
2730-
testDial(ctx, t, conn)
2731-
err = conn.Close()
2732-
require.NoError(t, err)
2733+
agentID := uuid.UUID{0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8}
2734+
//nolint:dogsled
2735+
agentConn, _, _, _, _ := setupAgent(t, agentsdk.Manifest{
2736+
AgentID: agentID,
2737+
}, 0)
2738+
require.True(t, agentConn.AwaitReachable(ctx))
2739+
conn, err := agentConn.DialContext(ctx, l.Addr().Network(), l.Addr().String())
2740+
require.NoError(t, err)
2741+
testDial(ctx, t, conn)
2742+
err = conn.Close()
2743+
require.NoError(t, err)
27332744

2734-
// also connect via the CoderServicePrefix, to test that we can reach the agent on this
2735-
// IP. This will be required for CoderVPN.
2736-
_, rawPort, _ := net.SplitHostPort(l.Addr().String())
2737-
port, _ := strconv.ParseUint(rawPort, 10, 16)
2738-
ipp := netip.AddrPortFrom(tailnet.CoderServicePrefix.AddrFromUUID(agentID), uint16(port))
2739-
2740-
switch l.Addr().Network() {
2741-
case "tcp":
2742-
conn, err = agentConn.Conn.DialContextTCP(ctx, ipp)
2743-
case "udp":
2744-
conn, err = agentConn.Conn.DialContextUDP(ctx, ipp)
2745-
default:
2746-
t.Fatalf("unknown network: %s", l.Addr().Network())
2747-
}
2748-
require.NoError(t, err)
2749-
testDial(ctx, t, conn)
2750-
err = conn.Close()
2751-
require.NoError(t, err)
2745+
// also connect via the CoderServicePrefix, to test that we can reach the agent on this
2746+
// IP. This will be required for CoderVPN.
2747+
_, rawPort, _ := net.SplitHostPort(l.Addr().String())
2748+
port, _ := strconv.ParseUint(rawPort, 10, 16)
2749+
ipp := netip.AddrPortFrom(tailnet.CoderServicePrefix.AddrFromUUID(agentID), uint16(port))
2750+
2751+
switch l.Addr().Network() {
2752+
case "tcp":
2753+
conn, err = agentConn.Conn.DialContextTCP(ctx, ipp)
2754+
case "udp":
2755+
conn, err = agentConn.Conn.DialContextUDP(ctx, ipp)
2756+
default:
2757+
t.Fatalf("unknown network: %s", l.Addr().Network())
2758+
}
2759+
require.NoError(t, err)
2760+
testDial(ctx, t, conn)
2761+
err = conn.Close()
2762+
require.NoError(t, err)
2763+
})
27522764
})
27532765
}
27542766
}
@@ -3251,7 +3263,7 @@ func setupSSHSessionOnPort(
32513263
return session
32523264
}
32533265

3254-
func setupAgent(t *testing.T, metadata agentsdk.Manifest, ptyTimeout time.Duration, opts ...func(*agenttest.Client, *agent.Options)) (
3266+
func setupAgent(t testing.TB, metadata agentsdk.Manifest, ptyTimeout time.Duration, opts ...func(*agenttest.Client, *agent.Options)) (
32553267
*workspacesdk.AgentConn,
32563268
*agenttest.Client,
32573269
<-chan *proto.Stats,
@@ -3349,7 +3361,7 @@ func setupAgent(t *testing.T, metadata agentsdk.Manifest, ptyTimeout time.Durati
33493361

33503362
var dialTestPayload = []byte("dean-was-here123")
33513363

3352-
func testDial(ctx context.Context, t *testing.T, c net.Conn) {
3364+
func testDial(ctx context.Context, t testing.TB, c net.Conn) {
33533365
t.Helper()
33543366

33553367
if deadline, ok := ctx.Deadline(); ok {
@@ -3365,7 +3377,7 @@ func testDial(ctx context.Context, t *testing.T, c net.Conn) {
33653377
assertReadPayload(t, c, dialTestPayload)
33663378
}
33673379

3368-
func testAccept(ctx context.Context, t *testing.T, c net.Conn) {
3380+
func testAccept(ctx context.Context, t testing.TB, c net.Conn) {
33693381
t.Helper()
33703382
defer c.Close()
33713383

@@ -3382,7 +3394,7 @@ func testAccept(ctx context.Context, t *testing.T, c net.Conn) {
33823394
assertWritePayload(t, c, dialTestPayload)
33833395
}
33843396

3385-
func assertReadPayload(t *testing.T, r io.Reader, payload []byte) {
3397+
func assertReadPayload(t testing.TB, r io.Reader, payload []byte) {
33863398
t.Helper()
33873399
b := make([]byte, len(payload)+16)
33883400
n, err := r.Read(b)
@@ -3391,11 +3403,11 @@ func assertReadPayload(t *testing.T, r io.Reader, payload []byte) {
33913403
assert.Equal(t, payload, b[:n])
33923404
}
33933405

3394-
func assertWritePayload(t *testing.T, w io.Writer, payload []byte) {
3406+
func assertWritePayload(t testing.TB, w io.Writer, payload []byte) {
33953407
t.Helper()
33963408
n, err := w.Write(payload)
33973409
assert.NoError(t, err, "write payload")
3398-
assert.Equal(t, len(payload), n, "payload length does not match")
3410+
assert.Equal(t, len(payload), n, "written payload length does not match")
33993411
}
34003412

34013413
func testSessionOutput(t *testing.T, session *ssh.Session, expected, unexpected []string, expectedRe *regexp.Regexp) {

agent/agentcontainers/api_test.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2096,9 +2096,6 @@ func TestAPI(t *testing.T) {
20962096
}
20972097
)
20982098

2099-
coderBin, err := os.Executable()
2100-
require.NoError(t, err)
2101-
21022099
// Mock the `List` function to always return the test container.
21032100
mCCLI.EXPECT().List(gomock.Any()).Return(codersdk.WorkspaceAgentListContainersResponse{
21042101
Containers: []codersdk.WorkspaceAgentContainer{testContainer},
@@ -2139,7 +2136,7 @@ func TestAPI(t *testing.T) {
21392136
require.Equal(t, http.StatusOK, rec.Code)
21402137

21412138
var response codersdk.WorkspaceAgentListContainersResponse
2142-
err = json.NewDecoder(rec.Body).Decode(&response)
2139+
err := json.NewDecoder(rec.Body).Decode(&response)
21432140
require.NoError(t, err)
21442141

21452142
// Then: We expect that there will be an error associated with the devcontainer.
@@ -2149,16 +2146,16 @@ func TestAPI(t *testing.T) {
21492146
gomock.InOrder(
21502147
mCCLI.EXPECT().DetectArchitecture(gomock.Any(), testContainer.ID).Return(runtime.GOARCH, nil),
21512148
mCCLI.EXPECT().ExecAs(gomock.Any(), testContainer.ID, "root", "mkdir", "-p", "/.coder-agent").Return(nil, nil),
2152-
mCCLI.EXPECT().Copy(gomock.Any(), testContainer.ID, coderBin, "/.coder-agent/coder").Return(nil),
2149+
mCCLI.EXPECT().Copy(gomock.Any(), testContainer.ID, gomock.Any(), "/.coder-agent/coder").Return(nil),
21532150
mCCLI.EXPECT().ExecAs(gomock.Any(), testContainer.ID, "root", "chmod", "0755", "/.coder-agent", "/.coder-agent/coder").Return(nil, nil),
21542151
mCCLI.EXPECT().ExecAs(gomock.Any(), testContainer.ID, "root", "/bin/sh", "-c", "chown $(id -u):$(id -g) /.coder-agent/coder").Return(nil, nil),
21552152
)
21562153

21572154
// Given: We allow creation to succeed.
21582155
testutil.RequireSend(ctx, t, fSAC.createErrC, nil)
21592156

2160-
_, aw := mClock.AdvanceNext()
2161-
aw.MustWait(ctx)
2157+
err = api.RefreshContainers(ctx)
2158+
require.NoError(t, err)
21622159

21632160
req = httptest.NewRequest(http.MethodGet, "/", nil)
21642161
rec = httptest.NewRecorder()

cli/create.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,12 @@ const PresetNone = "none"
2929

3030
var ErrNoPresetFound = xerrors.New("no preset found")
3131

32-
func (r *RootCmd) create() *serpent.Command {
32+
type CreateOptions struct {
33+
BeforeCreate func(ctx context.Context, client *codersdk.Client, template codersdk.Template, templateVersionID uuid.UUID) error
34+
AfterCreate func(ctx context.Context, inv *serpent.Invocation, client *codersdk.Client, workspace codersdk.Workspace) error
35+
}
36+
37+
func (r *RootCmd) Create(opts CreateOptions) *serpent.Command {
3338
var (
3439
templateName string
3540
templateVersion string
@@ -305,6 +310,13 @@ func (r *RootCmd) create() *serpent.Command {
305310
_, _ = fmt.Fprintf(inv.Stdout, "%s", cliui.Bold("No preset applied."))
306311
}
307312

313+
if opts.BeforeCreate != nil {
314+
err = opts.BeforeCreate(inv.Context(), client, template, templateVersionID)
315+
if err != nil {
316+
return xerrors.Errorf("before create: %w", err)
317+
}
318+
}
319+
308320
richParameters, err := prepWorkspaceBuild(inv, client, prepWorkspaceBuildArgs{
309321
Action: WorkspaceCreate,
310322
TemplateVersionID: templateVersionID,
@@ -366,6 +378,14 @@ func (r *RootCmd) create() *serpent.Command {
366378
cliui.Keyword(workspace.Name),
367379
cliui.Timestamp(time.Now()),
368380
)
381+
382+
if opts.AfterCreate != nil {
383+
err = opts.AfterCreate(inv.Context(), inv, client, workspace)
384+
if err != nil {
385+
return err
386+
}
387+
}
388+
369389
return nil
370390
},
371391
}

cli/exp_rpty.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ func handleRPTY(inv *serpent.Invocation, client *codersdk.Client, args handleRPT
9797
reconnectID = uuid.New()
9898
}
9999

100-
ws, agt, _, err := getWorkspaceAndAgent(ctx, inv, client, true, args.NamedWorkspace)
100+
ws, agt, _, err := GetWorkspaceAndAgent(ctx, inv, client, true, args.NamedWorkspace)
101101
if err != nil {
102102
return err
103103
}

cli/list.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import (
1818
// workspaceListRow is the type provided to the OutputFormatter. This is a bit
1919
// dodgy but it's the only way to do complex display code for one format vs. the
2020
// other.
21-
type workspaceListRow struct {
21+
type WorkspaceListRow struct {
2222
// For JSON format:
2323
codersdk.Workspace `table:"-"`
2424

@@ -40,7 +40,7 @@ type workspaceListRow struct {
4040
DailyCost string `json:"-" table:"daily cost"`
4141
}
4242

43-
func workspaceListRowFromWorkspace(now time.Time, workspace codersdk.Workspace) workspaceListRow {
43+
func WorkspaceListRowFromWorkspace(now time.Time, workspace codersdk.Workspace) WorkspaceListRow {
4444
status := codersdk.WorkspaceDisplayStatus(workspace.LatestBuild.Job.Status, workspace.LatestBuild.Transition)
4545

4646
lastBuilt := now.UTC().Sub(workspace.LatestBuild.Job.CreatedAt).Truncate(time.Second)
@@ -55,7 +55,7 @@ func workspaceListRowFromWorkspace(now time.Time, workspace codersdk.Workspace)
5555
favIco = "★"
5656
}
5757
workspaceName := favIco + " " + workspace.OwnerName + "/" + workspace.Name
58-
return workspaceListRow{
58+
return WorkspaceListRow{
5959
Favorite: workspace.Favorite,
6060
Workspace: workspace,
6161
WorkspaceName: workspaceName,
@@ -80,7 +80,7 @@ func (r *RootCmd) list() *serpent.Command {
8080
filter cliui.WorkspaceFilter
8181
formatter = cliui.NewOutputFormatter(
8282
cliui.TableFormat(
83-
[]workspaceListRow{},
83+
[]WorkspaceListRow{},
8484
[]string{
8585
"workspace",
8686
"template",
@@ -107,7 +107,7 @@ func (r *RootCmd) list() *serpent.Command {
107107
r.InitClient(client),
108108
),
109109
Handler: func(inv *serpent.Invocation) error {
110-
res, err := queryConvertWorkspaces(inv.Context(), client, filter.Filter(), workspaceListRowFromWorkspace)
110+
res, err := QueryConvertWorkspaces(inv.Context(), client, filter.Filter(), WorkspaceListRowFromWorkspace)
111111
if err != nil {
112112
return err
113113
}
@@ -137,9 +137,9 @@ func (r *RootCmd) list() *serpent.Command {
137137
// queryConvertWorkspaces is a helper function for converting
138138
// codersdk.Workspaces to a different type.
139139
// It's used by the list command to convert workspaces to
140-
// workspaceListRow, and by the schedule command to
140+
// WorkspaceListRow, and by the schedule command to
141141
// convert workspaces to scheduleListRow.
142-
func queryConvertWorkspaces[T any](ctx context.Context, client *codersdk.Client, filter codersdk.WorkspaceFilter, convertF func(time.Time, codersdk.Workspace) T) ([]T, error) {
142+
func QueryConvertWorkspaces[T any](ctx context.Context, client *codersdk.Client, filter codersdk.WorkspaceFilter, convertF func(time.Time, codersdk.Workspace) T) ([]T, error) {
143143
var empty []T
144144
workspaces, err := client.Workspaces(ctx, filter)
145145
if err != nil {

cli/open.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func (r *RootCmd) openVSCode() *serpent.Command {
7272
// need to wait for the agent to start.
7373
workspaceQuery := inv.Args[0]
7474
autostart := true
75-
workspace, workspaceAgent, otherWorkspaceAgents, err := getWorkspaceAndAgent(ctx, inv, client, autostart, workspaceQuery)
75+
workspace, workspaceAgent, otherWorkspaceAgents, err := GetWorkspaceAndAgent(ctx, inv, client, autostart, workspaceQuery)
7676
if err != nil {
7777
return xerrors.Errorf("get workspace and agent: %w", err)
7878
}
@@ -316,7 +316,7 @@ func (r *RootCmd) openApp() *serpent.Command {
316316
}
317317

318318
workspaceName := inv.Args[0]
319-
ws, agt, _, err := getWorkspaceAndAgent(ctx, inv, client, false, workspaceName)
319+
ws, agt, _, err := GetWorkspaceAndAgent(ctx, inv, client, false, workspaceName)
320320
if err != nil {
321321
var sdkErr *codersdk.Error
322322
if errors.As(err, &sdkErr) && sdkErr.StatusCode() == http.StatusNotFound {

cli/ping.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ func (r *RootCmd) ping() *serpent.Command {
110110
defer notifyCancel()
111111

112112
workspaceName := inv.Args[0]
113-
_, workspaceAgent, _, err := getWorkspaceAndAgent(
113+
_, workspaceAgent, _, err := GetWorkspaceAndAgent(
114114
ctx, inv, client,
115115
false, // Do not autostart for a ping.
116116
workspaceName,

cli/portforward.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func (r *RootCmd) portForward() *serpent.Command {
8484
return xerrors.New("no port-forwards requested")
8585
}
8686

87-
workspace, workspaceAgent, _, err := getWorkspaceAndAgent(ctx, inv, client, !disableAutostart, inv.Args[0])
87+
workspace, workspaceAgent, _, err := GetWorkspaceAndAgent(ctx, inv, client, !disableAutostart, inv.Args[0])
8888
if err != nil {
8989
return err
9090
}

cli/root.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ func (r *RootCmd) CoreSubcommands() []*serpent.Command {
108108
// Workspace Commands
109109
r.autoupdate(),
110110
r.configSSH(),
111-
r.create(),
111+
r.Create(CreateOptions{}),
112112
r.deleteWorkspace(),
113113
r.favorite(),
114114
r.list(),

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy