Skip to content

Commit 984d3e1

Browse files
committed
Merge branch 'main' into 9754-severity
2 parents 3d17eb5 + a9c0c01 commit 984d3e1

File tree

82 files changed

+2104
-1983
lines changed

Some content is hidden

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

82 files changed

+2104
-1983
lines changed

agent/agent.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ type Options struct {
6868
EnvironmentVariables map[string]string
6969
Logger slog.Logger
7070
IgnorePorts map[int]string
71+
PortCacheDuration time.Duration
7172
SSHMaxTimeout time.Duration
7273
TailnetListenPort uint16
7374
Subsystems []codersdk.AgentSubsystem
@@ -126,6 +127,9 @@ func New(options Options) Agent {
126127
if options.ServiceBannerRefreshInterval == 0 {
127128
options.ServiceBannerRefreshInterval = 2 * time.Minute
128129
}
130+
if options.PortCacheDuration == 0 {
131+
options.PortCacheDuration = 1 * time.Second
132+
}
129133

130134
prometheusRegistry := options.PrometheusRegistry
131135
if prometheusRegistry == nil {
@@ -153,6 +157,7 @@ func New(options Options) Agent {
153157
lifecycleReported: make(chan codersdk.WorkspaceAgentLifecycle, 1),
154158
lifecycleStates: []agentsdk.PostLifecycleRequest{{State: codersdk.WorkspaceAgentLifecycleCreated}},
155159
ignorePorts: options.IgnorePorts,
160+
portCacheDuration: options.PortCacheDuration,
156161
connStatsChan: make(chan *agentsdk.Stats, 1),
157162
reportMetadataInterval: options.ReportMetadataInterval,
158163
serviceBannerRefreshInterval: options.ServiceBannerRefreshInterval,
@@ -181,8 +186,9 @@ type agent struct {
181186
// ignorePorts tells the api handler which ports to ignore when
182187
// listing all listening ports. This is helpful to hide ports that
183188
// are used by the agent, that the user does not care about.
184-
ignorePorts map[int]string
185-
subsystems []codersdk.AgentSubsystem
189+
ignorePorts map[int]string
190+
portCacheDuration time.Duration
191+
subsystems []codersdk.AgentSubsystem
186192

187193
reconnectingPTYs sync.Map
188194
reconnectingPTYTimeout time.Duration

agent/api.go

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,27 @@ func (a *agent) apiHandler() http.Handler {
2626
cpy[k] = b
2727
}
2828

29-
lp := &listeningPortsHandler{ignorePorts: cpy}
29+
cacheDuration := 1 * time.Second
30+
if a.portCacheDuration > 0 {
31+
cacheDuration = a.portCacheDuration
32+
}
33+
34+
lp := &listeningPortsHandler{
35+
ignorePorts: cpy,
36+
cacheDuration: cacheDuration,
37+
}
3038
r.Get("/api/v0/listening-ports", lp.handler)
3139

3240
return r
3341
}
3442

3543
type listeningPortsHandler struct {
36-
mut sync.Mutex
37-
ports []codersdk.WorkspaceAgentListeningPort
38-
mtime time.Time
39-
ignorePorts map[int]string
44+
ignorePorts map[int]string
45+
cacheDuration time.Duration
46+
47+
mut sync.Mutex
48+
ports []codersdk.WorkspaceAgentListeningPort
49+
mtime time.Time
4050
}
4151

4252
// handler returns a list of listening ports. This is tested by coderd's

agent/ports_supported.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ func (lp *listeningPortsHandler) getListeningPorts() ([]codersdk.WorkspaceAgentL
1515
lp.mut.Lock()
1616
defer lp.mut.Unlock()
1717

18-
if time.Since(lp.mtime) < time.Second {
18+
if time.Since(lp.mtime) < lp.cacheDuration {
1919
// copy
2020
ports := make([]codersdk.WorkspaceAgentListeningPort, len(lp.ports))
2121
copy(ports, lp.ports)

cli/agent_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,15 @@ func TestWorkspaceAgent(t *testing.T) {
6969
OrganizationID: user.OrganizationID,
7070
OwnerID: user.UserID,
7171
})
72-
dbfake.WorkspaceBuild(t, db, ws, database.WorkspaceBuild{}, &proto.Resource{
72+
dbfake.NewWorkspaceBuildBuilder(t, db, ws).Resource(&proto.Resource{
7373
Name: "somename",
7474
Type: "someinstance",
7575
Agents: []*proto.Agent{{
7676
Auth: &proto.Agent_InstanceId{
7777
InstanceId: instanceID,
7878
},
7979
}},
80-
})
80+
}).Do()
8181

8282
inv, _ := clitest.New(t, "agent", "--auth", "azure-instance-identity", "--agent-url", client.URL.String())
8383
inv = inv.WithContext(
@@ -112,15 +112,15 @@ func TestWorkspaceAgent(t *testing.T) {
112112
OrganizationID: user.OrganizationID,
113113
OwnerID: user.UserID,
114114
})
115-
dbfake.WorkspaceBuild(t, db, ws, database.WorkspaceBuild{}, &proto.Resource{
115+
dbfake.NewWorkspaceBuildBuilder(t, db, ws).Resource(&proto.Resource{
116116
Name: "somename",
117117
Type: "someinstance",
118118
Agents: []*proto.Agent{{
119119
Auth: &proto.Agent_InstanceId{
120120
InstanceId: instanceID,
121121
},
122122
}},
123-
})
123+
}).Do()
124124

125125
inv, _ := clitest.New(t, "agent", "--auth", "aws-instance-identity", "--agent-url", client.URL.String())
126126
inv = inv.WithContext(
@@ -156,15 +156,15 @@ func TestWorkspaceAgent(t *testing.T) {
156156
OrganizationID: owner.OrganizationID,
157157
OwnerID: memberUser.ID,
158158
})
159-
dbfake.WorkspaceBuild(t, db, ws, database.WorkspaceBuild{}, &proto.Resource{
159+
dbfake.NewWorkspaceBuildBuilder(t, db, ws).Resource(&proto.Resource{
160160
Name: "somename",
161161
Type: "someinstance",
162162
Agents: []*proto.Agent{{
163163
Auth: &proto.Agent_InstanceId{
164164
InstanceId: instanceID,
165165
},
166166
}},
167-
})
167+
}).Do()
168168
inv, cfg := clitest.New(t, "agent", "--auth", "google-instance-identity", "--agent-url", client.URL.String())
169169
clitest.SetupConfig(t, member, cfg)
170170

cli/configssh_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -696,7 +696,7 @@ func TestConfigSSH_Hostnames(t *testing.T) {
696696
OrganizationID: owner.OrganizationID,
697697
OwnerID: memberUser.ID,
698698
})
699-
dbfake.WorkspaceBuild(t, db, ws, database.WorkspaceBuild{}, resources...)
699+
dbfake.NewWorkspaceBuildBuilder(t, db, ws).Resource(resources...).Do()
700700
sshConfigFile := sshConfigFileName(t)
701701

702702
inv, root := clitest.New(t, "config-ssh", "--ssh-config-file", sshConfigFile)

cli/ssh.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ func (r *RootCmd) ssh() *clibase.Cmd {
228228
if err != nil {
229229
return xerrors.Errorf("connect SSH: %w", err)
230230
}
231-
copier := &rawSSHCopier{conn: rawSSH, r: inv.Stdin, w: inv.Stdout}
231+
copier := newRawSSHCopier(logger, rawSSH, inv.Stdin, inv.Stdout)
232232
if err = stack.push("rawSSHCopier", copier); err != nil {
233233
return err
234234
}
@@ -853,9 +853,16 @@ type rawSSHCopier struct {
853853
logger slog.Logger
854854
r io.Reader
855855
w io.Writer
856+
857+
done chan struct{}
858+
}
859+
860+
func newRawSSHCopier(logger slog.Logger, conn *gonet.TCPConn, r io.Reader, w io.Writer) *rawSSHCopier {
861+
return &rawSSHCopier{conn: conn, logger: logger, r: r, w: w, done: make(chan struct{})}
856862
}
857863

858864
func (c *rawSSHCopier) copy(wg *sync.WaitGroup) {
865+
defer close(c.done)
859866
logCtx := context.Background()
860867
wg.Add(1)
861868
go func() {
@@ -890,5 +897,16 @@ func (c *rawSSHCopier) copy(wg *sync.WaitGroup) {
890897
}
891898

892899
func (c *rawSSHCopier) Close() error {
893-
return c.conn.CloseWrite()
900+
err := c.conn.CloseWrite()
901+
902+
// give the copy() call a chance to return on a timeout, so that we don't
903+
// continue tearing down and close the underlying netstack before the SSH
904+
// session has a chance to gracefully shut down.
905+
t := time.NewTimer(5 * time.Second)
906+
defer t.Stop()
907+
select {
908+
case <-c.done:
909+
case <-t.C:
910+
}
911+
return err
894912
}

cli/ssh_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ func TestSSH(t *testing.T) {
151151
pty.WriteLine("echo hell'o'")
152152
pty.ExpectMatchContext(ctx, "hello")
153153

154-
_ = dbfake.WorkspaceBuildBuilder(t, store, workspace).
154+
_ = dbfake.NewWorkspaceBuildBuilder(t, store, workspace).
155155
Seed(database.WorkspaceBuild{
156156
Transition: database.WorkspaceTransitionStop,
157157
BuildNumber: 2,
@@ -520,7 +520,7 @@ func TestSSH(t *testing.T) {
520520
err = session.Shell()
521521
require.NoError(t, err)
522522

523-
_ = dbfake.WorkspaceBuildBuilder(t, store, workspace).
523+
_ = dbfake.NewWorkspaceBuildBuilder(t, store, workspace).
524524
Seed(database.WorkspaceBuild{
525525
Transition: database.WorkspaceTransitionStop,
526526
BuildNumber: 2,

cli/templatecreate.go

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,11 @@ func (r *RootCmd) templateCreate() *clibase.Cmd {
3131
disableEveryone bool
3232
requireActiveVersion bool
3333

34-
defaultTTL time.Duration
35-
failureTTL time.Duration
36-
inactivityTTL time.Duration
37-
maxTTL time.Duration
34+
defaultTTL time.Duration
35+
failureTTL time.Duration
36+
dormancyThreshold time.Duration
37+
dormancyAutoDeletion time.Duration
38+
maxTTL time.Duration
3839

3940
uploadFlags templateUploadFlags
4041
)
@@ -47,18 +48,18 @@ func (r *RootCmd) templateCreate() *clibase.Cmd {
4748
r.InitClient(client),
4849
),
4950
Handler: func(inv *clibase.Invocation) error {
50-
isTemplateSchedulingOptionsSet := failureTTL != 0 || inactivityTTL != 0 || maxTTL != 0
51+
isTemplateSchedulingOptionsSet := failureTTL != 0 || dormancyThreshold != 0 || dormancyAutoDeletion != 0 || maxTTL != 0
5152

5253
if isTemplateSchedulingOptionsSet || requireActiveVersion {
53-
if failureTTL != 0 || inactivityTTL != 0 {
54+
if failureTTL != 0 || dormancyThreshold != 0 || dormancyAutoDeletion != 0 {
5455
// This call can be removed when workspace_actions is no longer experimental
5556
experiments, exErr := client.Experiments(inv.Context())
5657
if exErr != nil {
5758
return xerrors.Errorf("get experiments: %w", exErr)
5859
}
5960

6061
if !experiments.Enabled(codersdk.ExperimentWorkspaceActions) {
61-
return xerrors.Errorf("--failure-ttl and --inactivity-ttl are experimental features. Use the workspace_actions CODER_EXPERIMENTS flag to set these configuration values.")
62+
return xerrors.Errorf("--failure-ttl, --dormancy-threshold, and --dormancy-auto-deletion are experimental features. Use the workspace_actions CODER_EXPERIMENTS flag to set these configuration values.")
6263
}
6364
}
6465

@@ -153,14 +154,15 @@ func (r *RootCmd) templateCreate() *clibase.Cmd {
153154
}
154155

155156
createReq := codersdk.CreateTemplateRequest{
156-
Name: templateName,
157-
VersionID: job.ID,
158-
DefaultTTLMillis: ptr.Ref(defaultTTL.Milliseconds()),
159-
FailureTTLMillis: ptr.Ref(failureTTL.Milliseconds()),
160-
MaxTTLMillis: ptr.Ref(maxTTL.Milliseconds()),
161-
TimeTilDormantMillis: ptr.Ref(inactivityTTL.Milliseconds()),
162-
DisableEveryoneGroupAccess: disableEveryone,
163-
RequireActiveVersion: requireActiveVersion,
157+
Name: templateName,
158+
VersionID: job.ID,
159+
DefaultTTLMillis: ptr.Ref(defaultTTL.Milliseconds()),
160+
FailureTTLMillis: ptr.Ref(failureTTL.Milliseconds()),
161+
MaxTTLMillis: ptr.Ref(maxTTL.Milliseconds()),
162+
TimeTilDormantMillis: ptr.Ref(dormancyThreshold.Milliseconds()),
163+
TimeTilDormantAutoDeleteMillis: ptr.Ref(dormancyAutoDeletion.Milliseconds()),
164+
DisableEveryoneGroupAccess: disableEveryone,
165+
RequireActiveVersion: requireActiveVersion,
164166
}
165167

166168
_, err = client.CreateTemplate(inv.Context(), organization.ID, createReq)
@@ -220,11 +222,18 @@ func (r *RootCmd) templateCreate() *clibase.Cmd {
220222
Value: clibase.DurationOf(&failureTTL),
221223
},
222224
{
223-
Flag: "inactivity-ttl",
224-
Description: "Specify an inactivity TTL for workspaces created from this template. It is the amount of time the workspace is not used before it is be stopped and auto-locked. This includes across multiple builds (e.g. auto-starts and stops). This licensed feature's default is 0h (off). Maps to \"Dormancy threshold\" in the UI.",
225+
Flag: "dormancy-threshold",
226+
Description: "Specify a duration workspaces may be inactive prior to being moved to the dormant state. This licensed feature's default is 0h (off). Maps to \"Dormancy threshold\" in the UI.",
225227
Default: "0h",
226-
Value: clibase.DurationOf(&inactivityTTL),
228+
Value: clibase.DurationOf(&dormancyThreshold),
227229
},
230+
{
231+
Flag: "dormancy-auto-deletion",
232+
Description: "Specify a duration workspaces may be in the dormant state prior to being deleted. This licensed feature's default is 0h (off). Maps to \"Dormancy Auto-Deletion\" in the UI.",
233+
Default: "0h",
234+
Value: clibase.DurationOf(&dormancyAutoDeletion),
235+
},
236+
228237
{
229238
Flag: "max-ttl",
230239
Description: "Edit the template maximum time before shutdown - workspaces created from this template must shutdown within the given duration after starting. This is an enterprise-only feature.",

cli/templateedit.go

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
2828
autostopRequirementWeeks int64
2929
autostartRequirementDaysOfWeek []string
3030
failureTTL time.Duration
31-
inactivityTTL time.Duration
31+
dormancyThreshold time.Duration
32+
dormancyAutoDeletion time.Duration
3233
allowUserCancelWorkspaceJobs bool
3334
allowUserAutostart bool
3435
allowUserAutostop bool
@@ -46,14 +47,14 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
4647
Short: "Edit the metadata of a template by name.",
4748
Handler: func(inv *clibase.Invocation) error {
4849
// This clause can be removed when workspace_actions is no longer experimental
49-
if failureTTL != 0 || inactivityTTL != 0 {
50+
if failureTTL != 0 || dormancyThreshold != 0 || dormancyAutoDeletion != 0 {
5051
experiments, exErr := client.Experiments(inv.Context())
5152
if exErr != nil {
5253
return xerrors.Errorf("get experiments: %w", exErr)
5354
}
5455

5556
if !experiments.Enabled(codersdk.ExperimentWorkspaceActions) {
56-
return xerrors.Errorf("--failure-ttl and --inactivity-ttl are experimental features. Use the workspace_actions CODER_EXPERIMENTS flag to set these configuration values.")
57+
return xerrors.Errorf("--failure-ttl, --dormancy-threshold, and --dormancy-auto-deletion are experimental features. Use the workspace_actions CODER_EXPERIMENTS flag to set these configuration values.")
5758
}
5859
}
5960

@@ -64,7 +65,8 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
6465
!allowUserAutostop ||
6566
maxTTL != 0 ||
6667
failureTTL != 0 ||
67-
inactivityTTL != 0 ||
68+
dormancyThreshold != 0 ||
69+
dormancyAutoDeletion != 0 ||
6870
len(autostartRequirementDaysOfWeek) > 0
6971

7072
requiresEntitlement := requiresScheduling || requireActiveVersion
@@ -119,6 +121,15 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
119121
if unsetAutostopRequirementDaysOfWeek {
120122
autostopRequirementDaysOfWeek = []string{}
121123
}
124+
if failureTTL == 0 {
125+
failureTTL = time.Duration(template.FailureTTLMillis) * time.Millisecond
126+
}
127+
if dormancyThreshold == 0 {
128+
dormancyThreshold = time.Duration(template.TimeTilDormantMillis) * time.Millisecond
129+
}
130+
if dormancyAutoDeletion == 0 {
131+
dormancyAutoDeletion = time.Duration(template.TimeTilDormantAutoDeleteMillis) * time.Millisecond
132+
}
122133

123134
// Default values
124135
if !userSetOption(inv, "description") {
@@ -152,13 +163,14 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
152163
AutostartRequirement: &codersdk.TemplateAutostartRequirement{
153164
DaysOfWeek: autostartRequirementDaysOfWeek,
154165
},
155-
FailureTTLMillis: failureTTL.Milliseconds(),
156-
TimeTilDormantMillis: inactivityTTL.Milliseconds(),
157-
AllowUserCancelWorkspaceJobs: allowUserCancelWorkspaceJobs,
158-
AllowUserAutostart: allowUserAutostart,
159-
AllowUserAutostop: allowUserAutostop,
160-
RequireActiveVersion: requireActiveVersion,
161-
DeprecationMessage: deprecated,
166+
FailureTTLMillis: failureTTL.Milliseconds(),
167+
TimeTilDormantMillis: dormancyThreshold.Milliseconds(),
168+
TimeTilDormantAutoDeleteMillis: dormancyAutoDeletion.Milliseconds(),
169+
AllowUserCancelWorkspaceJobs: allowUserCancelWorkspaceJobs,
170+
AllowUserAutostart: allowUserAutostart,
171+
AllowUserAutostop: allowUserAutostop,
172+
RequireActiveVersion: requireActiveVersion,
173+
DeprecationMessage: deprecated,
162174
}
163175

164176
_, err = client.UpdateTemplateMeta(inv.Context(), template.ID, req)
@@ -254,10 +266,16 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
254266
Value: clibase.DurationOf(&failureTTL),
255267
},
256268
{
257-
Flag: "inactivity-ttl",
258-
Description: "Specify an inactivity TTL for workspaces created from this template. It is the amount of time the workspace is not used before it is be stopped and auto-locked. This includes across multiple builds (e.g. auto-starts and stops). This licensed feature's default is 0h (off). Maps to \"Dormancy threshold\" in the UI.",
269+
Flag: "dormancy-threshold",
270+
Description: "Specify a duration workspaces may be inactive prior to being moved to the dormant state. This licensed feature's default is 0h (off). Maps to \"Dormancy threshold\" in the UI.",
271+
Default: "0h",
272+
Value: clibase.DurationOf(&dormancyThreshold),
273+
},
274+
{
275+
Flag: "dormancy-auto-deletion",
276+
Description: "Specify a duration workspaces may be in the dormant state prior to being deleted. This licensed feature's default is 0h (off). Maps to \"Dormancy Auto-Deletion\" in the UI.",
259277
Default: "0h",
260-
Value: clibase.DurationOf(&inactivityTTL),
278+
Value: clibase.DurationOf(&dormancyAutoDeletion),
261279
},
262280
{
263281
Flag: "allow-user-cancel-workspace-jobs",

0 commit comments

Comments
 (0)