Skip to content

Commit b8a73f5

Browse files
committed
Merge branch 'main' into mes/table-user-groups
2 parents 2e2bf08 + 492da15 commit b8a73f5

File tree

155 files changed

+3854
-2552
lines changed

Some content is hidden

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

155 files changed

+3854
-2552
lines changed

.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ jobs:
223223
go-version: 1.20.10
224224

225225
- name: Install shfmt
226-
run: go install mvdan.cc/sh/v3/cmd/shfmt@v3.5.0
226+
run: go install mvdan.cc/sh/v3/cmd/shfmt@v3.7.0
227227

228228
- name: make fmt
229229
run: |

cli/exp_scaletest.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,7 +1241,7 @@ func (r *runnableTraceWrapper) Run(ctx context.Context, id string, logs io.Write
12411241
return r.runner.Run(ctx2, id, logs)
12421242
}
12431243

1244-
func (r *runnableTraceWrapper) Cleanup(ctx context.Context, id string) error {
1244+
func (r *runnableTraceWrapper) Cleanup(ctx context.Context, id string, logs io.Writer) error {
12451245
c, ok := r.runner.(harness.Cleanable)
12461246
if !ok {
12471247
return nil
@@ -1253,7 +1253,7 @@ func (r *runnableTraceWrapper) Cleanup(ctx context.Context, id string) error {
12531253
ctx, span := r.tracer.Start(ctx, r.spanName+" cleanup")
12541254
defer span.End()
12551255

1256-
return c.Cleanup(ctx, id)
1256+
return c.Cleanup(ctx, id, logs)
12571257
}
12581258

12591259
// newScaleTestUser returns a random username and email address that can be used

coderd/apidoc/docs.go

Lines changed: 30 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

Lines changed: 26 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/coderd.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,7 @@ func New(options *Options) *API {
597597
})
598598
r.Route("/experiments", func(r chi.Router) {
599599
r.Use(apiKeyMiddleware)
600+
r.Get("/available", handleExperimentsSafe)
600601
r.Get("/", api.handleExperimentsGet)
601602
})
602603
r.Get("/updatecheck", api.updateCheck)
@@ -1108,6 +1109,7 @@ func (api *API) CreateInMemoryProvisionerDaemon(ctx context.Context) (client pro
11081109
logger := api.Logger.Named(fmt.Sprintf("inmem-provisionerd-%s", name))
11091110
logger.Info(ctx, "starting in-memory provisioner daemon")
11101111
srv, err := provisionerdserver.NewServer(
1112+
api.ctx,
11111113
api.AccessURL,
11121114
uuid.New(),
11131115
logger,

coderd/experiments.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ import (
44
"net/http"
55

66
"github.com/coder/coder/v2/coderd/httpapi"
7+
"github.com/coder/coder/v2/codersdk"
78
)
89

9-
// @Summary Get experiments
10-
// @ID get-experiments
10+
// @Summary Get enabled experiments
11+
// @ID get-enabled-experiments
1112
// @Security CoderSessionToken
1213
// @Produce json
1314
// @Tags General
@@ -17,3 +18,17 @@ func (api *API) handleExperimentsGet(rw http.ResponseWriter, r *http.Request) {
1718
ctx := r.Context()
1819
httpapi.Write(ctx, rw, http.StatusOK, api.Experiments)
1920
}
21+
22+
// @Summary Get safe experiments
23+
// @ID get-safe-experiments
24+
// @Security CoderSessionToken
25+
// @Produce json
26+
// @Tags General
27+
// @Success 200 {array} codersdk.Experiment
28+
// @Router /experiments/available [get]
29+
func handleExperimentsSafe(rw http.ResponseWriter, r *http.Request) {
30+
ctx := r.Context()
31+
httpapi.Write(ctx, rw, http.StatusOK, codersdk.AvailableExperiments{
32+
Safe: codersdk.ExperimentsAll,
33+
})
34+
}

coderd/experiments_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,4 +116,21 @@ func Test_Experiments(t *testing.T) {
116116
require.Error(t, err)
117117
require.ErrorContains(t, err, httpmw.SignedOutErrorMessage)
118118
})
119+
120+
t.Run("available experiments", func(t *testing.T) {
121+
t.Parallel()
122+
cfg := coderdtest.DeploymentValues(t)
123+
client := coderdtest.New(t, &coderdtest.Options{
124+
DeploymentValues: cfg,
125+
})
126+
_ = coderdtest.CreateFirstUser(t, client)
127+
128+
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
129+
defer cancel()
130+
131+
experiments, err := client.SafeExperiments(ctx)
132+
require.NoError(t, err)
133+
require.NotNil(t, experiments)
134+
require.ElementsMatch(t, codersdk.ExperimentsAll, experiments.Safe)
135+
})
119136
}

coderd/provisionerdserver/provisionerdserver.go

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ type Options struct {
5858
}
5959

6060
type server struct {
61+
// lifecycleCtx must be tied to the API server's lifecycle
62+
// as when the API server shuts down, we want to cancel any
63+
// long-running operations.
64+
lifecycleCtx context.Context
6165
AccessURL *url.URL
6266
ID uuid.UUID
6367
Logger slog.Logger
@@ -107,6 +111,7 @@ func (t Tags) Valid() error {
107111
}
108112

109113
func NewServer(
114+
lifecycleCtx context.Context,
110115
accessURL *url.URL,
111116
id uuid.UUID,
112117
logger slog.Logger,
@@ -124,7 +129,10 @@ func NewServer(
124129
deploymentValues *codersdk.DeploymentValues,
125130
options Options,
126131
) (proto.DRPCProvisionerDaemonServer, error) {
127-
// Panic early if pointers are nil
132+
// Fail-fast if pointers are nil
133+
if lifecycleCtx == nil {
134+
return nil, xerrors.New("ctx is nil")
135+
}
128136
if quotaCommitter == nil {
129137
return nil, xerrors.New("quotaCommitter is nil")
130138
}
@@ -153,6 +161,7 @@ func NewServer(
153161
options.AcquireJobLongPollDur = DefaultAcquireJobLongPollDur
154162
}
155163
return &server{
164+
lifecycleCtx: lifecycleCtx,
156165
AccessURL: accessURL,
157166
ID: id,
158167
Logger: logger,
@@ -1184,16 +1193,21 @@ func (s *server) CompleteJob(ctx context.Context, completed *proto.CompletedJob)
11841193
}
11851194
go func() {
11861195
for _, wait := range updates {
1187-
// Wait for the next potential timeout to occur. Note that we
1188-
// can't listen on the context here because we will hang around
1189-
// after this function has returned. The s also doesn't
1190-
// have a shutdown signal we can listen to.
1191-
<-wait
1192-
if err := s.Pubsub.Publish(codersdk.WorkspaceNotifyChannel(workspaceBuild.WorkspaceID), []byte{}); err != nil {
1193-
s.Logger.Error(ctx, "workspace notification after agent timeout failed",
1196+
select {
1197+
case <-s.lifecycleCtx.Done():
1198+
// If the server is shutting down, we don't want to wait around.
1199+
s.Logger.Debug(ctx, "stopping notifications due to server shutdown",
11941200
slog.F("workspace_build_id", workspaceBuild.ID),
1195-
slog.Error(err),
11961201
)
1202+
return
1203+
case <-wait:
1204+
// Wait for the next potential timeout to occur.
1205+
if err := s.Pubsub.Publish(codersdk.WorkspaceNotifyChannel(workspaceBuild.WorkspaceID), []byte{}); err != nil {
1206+
s.Logger.Error(ctx, "workspace notification after agent timeout failed",
1207+
slog.F("workspace_build_id", workspaceBuild.ID),
1208+
slog.Error(err),
1209+
)
1210+
}
11971211
}
11981212
}
11991213
}()

coderd/provisionerdserver/provisionerdserver_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1733,6 +1733,7 @@ func setup(t *testing.T, ignoreLogErrors bool, ov *overrides) (proto.DRPCProvisi
17331733
}
17341734

17351735
srv, err := provisionerdserver.NewServer(
1736+
ctx,
17361737
&url.URL{},
17371738
srvID,
17381739
slogtest.Make(t, &slogtest.Options{IgnoreErrors: ignoreLogErrors}),

coderd/templates.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,7 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
610610
req.DefaultTTLMillis == time.Duration(template.DefaultTTL).Milliseconds() &&
611611
req.MaxTTLMillis == time.Duration(template.MaxTTL).Milliseconds() &&
612612
autostopRequirementDaysOfWeekParsed == scheduleOpts.AutostopRequirement.DaysOfWeek &&
613+
autostartRequirementDaysOfWeekParsed == scheduleOpts.AutostartRequirement.DaysOfWeek &&
613614
req.AutostopRequirement.Weeks == scheduleOpts.AutostopRequirement.Weeks &&
614615
req.FailureTTLMillis == time.Duration(template.FailureTTL).Milliseconds() &&
615616
req.TimeTilDormantMillis == time.Duration(template.TimeTilDormant).Milliseconds() &&

codersdk/deployment.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2013,12 +2013,13 @@ var ExperimentsAll = Experiments{
20132013
ExperimentSingleTailnet,
20142014
}
20152015

2016-
// Experiments is a list of experiments that are enabled for the deployment.
2016+
// Experiments is a list of experiments.
20172017
// Multiple experiments may be enabled at the same time.
20182018
// Experiments are not safe for production use, and are not guaranteed to
20192019
// be backwards compatible. They may be removed or renamed at any time.
20202020
type Experiments []Experiment
20212021

2022+
// Returns a list of experiments that are enabled for the deployment.
20222023
func (e Experiments) Enabled(ex Experiment) bool {
20232024
for _, v := range e {
20242025
if v == ex {
@@ -2041,6 +2042,25 @@ func (c *Client) Experiments(ctx context.Context) (Experiments, error) {
20412042
return exp, json.NewDecoder(res.Body).Decode(&exp)
20422043
}
20432044

2045+
// AvailableExperiments is an expandable type that returns all safe experiments
2046+
// available to be used with a deployment.
2047+
type AvailableExperiments struct {
2048+
Safe []Experiment `json:"safe"`
2049+
}
2050+
2051+
func (c *Client) SafeExperiments(ctx context.Context) (AvailableExperiments, error) {
2052+
res, err := c.Request(ctx, http.MethodGet, "/api/v2/experiments/available", nil)
2053+
if err != nil {
2054+
return AvailableExperiments{}, err
2055+
}
2056+
defer res.Body.Close()
2057+
if res.StatusCode != http.StatusOK {
2058+
return AvailableExperiments{}, ReadBodyAsError(res)
2059+
}
2060+
var exp AvailableExperiments
2061+
return exp, json.NewDecoder(res.Body).Decode(&exp)
2062+
}
2063+
20442064
type DAUsResponse struct {
20452065
Entries []DAUEntry `json:"entries"`
20462066
TZHourOffset int `json:"tz_hour_offset"`

docs/admin/provisioners.md

Lines changed: 1 addition & 1 deletion

docs/api/general.md

Lines changed: 39 additions & 2 deletions

docs/changelogs/v2.3.0.md

Lines changed: 1 addition & 1 deletion

docs/images/autostart.png

-30.4 KB

docs/images/autostop.png

-10.2 KB

docs/images/creating-workspace-ui.png

69.7 KB

docs/images/schedule.png

-12.3 KB

docs/images/template-variables.png

89.9 KB
54.2 KB
46.9 KB
55.9 KB
93.4 KB
75.6 KB

docs/images/templates/edit-files.png

50.1 KB
32.8 KB
63.6 KB

docs/images/templates/publish.png

79.1 KB
45 KB

docs/images/templates/source-code.png

59.3 KB
140 KB
39.6 KB
61.5 KB
226 KB

docs/images/templates/update.png

171 KB
67.5 KB
497 KB
110 KB

docs/images/workspace-update.png

33.6 KB

0 commit comments

Comments
 (0)