Skip to content

Commit d5d8788

Browse files
committed
Merge branch 'main' of https://github.com/coder/coder into bq/upgrade-msw
2 parents 538f1e2 + 9cfd5ba commit d5d8788

28 files changed

+397
-161
lines changed

cli/cliui/provisionerjob_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ import (
1111
"testing"
1212
"time"
1313

14-
"github.com/coder/coder/v2/testutil"
1514
"github.com/stretchr/testify/assert"
1615

16+
"github.com/coder/coder/v2/testutil"
17+
1718
"github.com/coder/coder/v2/cli/cliui"
1819
"github.com/coder/coder/v2/coderd/database/dbtime"
1920
"github.com/coder/coder/v2/codersdk"

cli/server.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ func enablePrometheus(
258258
), nil
259259
}
260260

261+
//nolint:gocognit // TODO(dannyk): reduce complexity of this function
261262
func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.API, io.Closer, error)) *serpent.Command {
262263
if newAPI == nil {
263264
newAPI = func(_ context.Context, o *coderd.Options) (*coderd.API, io.Closer, error) {
@@ -819,6 +820,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
819820
Prometheus: vals.Prometheus.Enable.Value(),
820821
STUN: len(vals.DERP.Server.STUNAddresses) != 0,
821822
Tunnel: tunnel != nil,
823+
Experiments: vals.Experiments.Value(),
822824
ParseLicenseJWT: func(lic *telemetry.License) error {
823825
// This will be nil when running in AGPL-only mode.
824826
if options.ParseLicenseClaims == nil {
@@ -892,6 +894,15 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
892894
return xerrors.Errorf("register agents prometheus metric: %w", err)
893895
}
894896
defer closeAgentsFunc()
897+
898+
var active codersdk.Experiments
899+
for _, exp := range options.DeploymentValues.Experiments.Value() {
900+
active = append(active, codersdk.Experiment(exp))
901+
}
902+
903+
if err = prometheusmetrics.Experiments(options.PrometheusRegistry, active); err != nil {
904+
return xerrors.Errorf("register experiments metric: %w", err)
905+
}
895906
}
896907

897908
client := codersdk.New(localURL)

coderd/coderd.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1271,6 +1271,7 @@ func (api *API) CreateInMemoryProvisionerDaemon(dialCtx context.Context, name st
12711271
api.ctx, // use the same ctx as the API
12721272
api.AccessURL,
12731273
daemon.ID,
1274+
defaultOrg.ID,
12741275
logger,
12751276
daemon.Provisioners,
12761277
provisionerdserver.Tags(daemon.Tags),

coderd/database/dbauthz/dbauthz_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2093,7 +2093,7 @@ func (s *MethodTestSuite) TestSystemFunctions() {
20932093
j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{
20942094
StartedAt: sql.NullTime{Valid: false},
20952095
})
2096-
check.Args(database.AcquireProvisionerJobParams{Types: []database.ProvisionerType{j.Provisioner}, Tags: must(json.Marshal(j.Tags))}).
2096+
check.Args(database.AcquireProvisionerJobParams{OrganizationID: j.OrganizationID, Types: []database.ProvisionerType{j.Provisioner}, Tags: must(json.Marshal(j.Tags))}).
20972097
Asserts( /*rbac.ResourceSystem, rbac.ActionUpdate*/ )
20982098
}))
20992099
s.Run("UpdateProvisionerJobWithCompleteByID", s.Subtest(func(db database.Store, check *expects) {

coderd/database/dbfake/dbfake.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ func (b WorkspaceBuildBuilder) Do() WorkspaceResponse {
187187
// import job as well
188188
for {
189189
j, err := b.db.AcquireProvisionerJob(ownerCtx, database.AcquireProvisionerJobParams{
190+
OrganizationID: job.OrganizationID,
190191
StartedAt: sql.NullTime{
191192
Time: dbtime.Now(),
192193
Valid: true,

coderd/database/dbgen/dbgen.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,12 @@ func GroupMember(t testing.TB, db database.Store, orig database.GroupMember) dat
387387
func ProvisionerJob(t testing.TB, db database.Store, ps pubsub.Pubsub, orig database.ProvisionerJob) database.ProvisionerJob {
388388
t.Helper()
389389

390+
var defOrgID uuid.UUID
391+
if orig.OrganizationID == uuid.Nil {
392+
defOrg, _ := db.GetDefaultOrganization(genCtx)
393+
defOrgID = defOrg.ID
394+
}
395+
390396
jobID := takeFirst(orig.ID, uuid.New())
391397
// Always set some tags to prevent Acquire from grabbing jobs it should not.
392398
if !orig.StartedAt.Time.IsZero() {
@@ -401,7 +407,7 @@ func ProvisionerJob(t testing.TB, db database.Store, ps pubsub.Pubsub, orig data
401407
ID: jobID,
402408
CreatedAt: takeFirst(orig.CreatedAt, dbtime.Now()),
403409
UpdatedAt: takeFirst(orig.UpdatedAt, dbtime.Now()),
404-
OrganizationID: takeFirst(orig.OrganizationID, uuid.New()),
410+
OrganizationID: takeFirst(orig.OrganizationID, defOrgID, uuid.New()),
405411
InitiatorID: takeFirst(orig.InitiatorID, uuid.New()),
406412
Provisioner: takeFirst(orig.Provisioner, database.ProvisionerTypeEcho),
407413
StorageMethod: takeFirst(orig.StorageMethod, database.ProvisionerStorageMethodFile),
@@ -418,10 +424,11 @@ func ProvisionerJob(t testing.TB, db database.Store, ps pubsub.Pubsub, orig data
418424
}
419425
if !orig.StartedAt.Time.IsZero() {
420426
job, err = db.AcquireProvisionerJob(genCtx, database.AcquireProvisionerJobParams{
421-
StartedAt: orig.StartedAt,
422-
Types: []database.ProvisionerType{database.ProvisionerTypeEcho},
423-
Tags: must(json.Marshal(orig.Tags)),
424-
WorkerID: uuid.NullUUID{},
427+
StartedAt: orig.StartedAt,
428+
OrganizationID: job.OrganizationID,
429+
Types: []database.ProvisionerType{database.ProvisionerTypeEcho},
430+
Tags: must(json.Marshal(orig.Tags)),
431+
WorkerID: uuid.NullUUID{},
425432
})
426433
require.NoError(t, err)
427434
// There is no easy way to make sure we acquire the correct job.

coderd/database/dbmem/dbmem.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,9 @@ func (q *FakeQuerier) AcquireProvisionerJob(_ context.Context, arg database.Acqu
803803
defer q.mutex.Unlock()
804804

805805
for index, provisionerJob := range q.provisionerJobs {
806+
if provisionerJob.OrganizationID != arg.OrganizationID {
807+
continue
808+
}
806809
if provisionerJob.StartedAt.Valid {
807810
continue
808811
}
@@ -7861,15 +7864,16 @@ func (q *FakeQuerier) UpsertProvisionerDaemon(_ context.Context, arg database.Up
78617864
}
78627865
}
78637866
d := database.ProvisionerDaemon{
7864-
ID: uuid.New(),
7865-
CreatedAt: arg.CreatedAt,
7866-
Name: arg.Name,
7867-
Provisioners: arg.Provisioners,
7868-
Tags: maps.Clone(arg.Tags),
7869-
ReplicaID: uuid.NullUUID{},
7870-
LastSeenAt: arg.LastSeenAt,
7871-
Version: arg.Version,
7872-
APIVersion: arg.APIVersion,
7867+
ID: uuid.New(),
7868+
CreatedAt: arg.CreatedAt,
7869+
Name: arg.Name,
7870+
Provisioners: arg.Provisioners,
7871+
Tags: maps.Clone(arg.Tags),
7872+
ReplicaID: uuid.NullUUID{},
7873+
LastSeenAt: arg.LastSeenAt,
7874+
Version: arg.Version,
7875+
APIVersion: arg.APIVersion,
7876+
OrganizationID: arg.OrganizationID,
78737877
}
78747878
q.provisionerDaemons = append(q.provisionerDaemons, d)
78757879
return d, nil

coderd/database/dump.sql

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

coderd/database/gen/dump/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ func main() {
9191
"s/ public\\./ /g",
9292
"s/::public\\./::/g",
9393
"s/'public\\./'/g",
94+
"s/(public\\./(/g",
9495
// Remove database settings.
9596
"s/SET .* = .*;//g",
9697
// Remove select statements. These aren't useful

coderd/database/querier_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,7 @@ func TestQueuePosition(t *testing.T) {
363363
}
364364

365365
job, err := db.AcquireProvisionerJob(ctx, database.AcquireProvisionerJobParams{
366+
OrganizationID: org.ID,
366367
StartedAt: sql.NullTime{
367368
Time: dbtime.Now(),
368369
Valid: true,

coderd/database/queries.sql.go

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

coderd/database/queries/provisionerjobs.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ WHERE
1919
provisioner_jobs AS nested
2020
WHERE
2121
nested.started_at IS NULL
22+
AND nested.organization_id = @organization_id
2223
-- Ensure the caller has the correct provisioner.
2324
AND nested.provisioner = ANY(@types :: provisioner_type [ ])
2425
AND CASE

coderd/prometheusmetrics/prometheusmetrics.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,32 @@ func AgentStats(ctx context.Context, logger slog.Logger, registerer prometheus.R
516516
}, nil
517517
}
518518

519+
// Experiments registers a metric which indicates whether each experiment is enabled or not.
520+
func Experiments(registerer prometheus.Registerer, active codersdk.Experiments) error {
521+
experimentsGauge := prometheus.NewGaugeVec(prometheus.GaugeOpts{
522+
Namespace: "coderd",
523+
Name: "experiments",
524+
Help: "Indicates whether each experiment is enabled (1) or not (0)",
525+
}, []string{"experiment"})
526+
if err := registerer.Register(experimentsGauge); err != nil {
527+
return err
528+
}
529+
530+
for _, exp := range codersdk.ExperimentsAll {
531+
var val float64
532+
for _, enabled := range active {
533+
if exp == enabled {
534+
val = 1
535+
break
536+
}
537+
}
538+
539+
experimentsGauge.WithLabelValues(string(exp)).Set(val)
540+
}
541+
542+
return nil
543+
}
544+
519545
// filterAcceptableAgentLabels handles a slightly messy situation whereby `prometheus-aggregate-agent-stats-by` can control on
520546
// which labels agent stats are aggregated, but for these specific metrics in this file there is no `template` label value,
521547
// and therefore we have to exclude it from the list of acceptable labels.

coderd/prometheusmetrics/prometheusmetrics_test.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ func TestWorkspaces(t *testing.T) {
134134
require.NoError(t, err)
135135
// This marks the job as started.
136136
_, err = db.AcquireProvisionerJob(context.Background(), database.AcquireProvisionerJobParams{
137+
OrganizationID: job.OrganizationID,
137138
StartedAt: sql.NullTime{
138139
Time: dbtime.Now(),
139140
Valid: true,
@@ -499,6 +500,88 @@ func TestAgentStats(t *testing.T) {
499500
assert.EqualValues(t, golden, collected)
500501
}
501502

503+
func TestExperimentsMetric(t *testing.T) {
504+
t.Parallel()
505+
506+
tests := []struct {
507+
name string
508+
experiments codersdk.Experiments
509+
expected map[codersdk.Experiment]float64
510+
}{
511+
{
512+
name: "Enabled experiment is exported in metrics",
513+
experiments: codersdk.Experiments{codersdk.ExperimentSharedPorts},
514+
expected: map[codersdk.Experiment]float64{
515+
codersdk.ExperimentSharedPorts: 1,
516+
},
517+
},
518+
{
519+
name: "Disabled experiment is exported in metrics",
520+
experiments: codersdk.Experiments{},
521+
expected: map[codersdk.Experiment]float64{
522+
codersdk.ExperimentSharedPorts: 0,
523+
},
524+
},
525+
{
526+
name: "Unknown experiment is not exported in metrics",
527+
experiments: codersdk.Experiments{codersdk.Experiment("bob")},
528+
expected: map[codersdk.Experiment]float64{},
529+
},
530+
}
531+
532+
for _, tc := range tests {
533+
tc := tc
534+
535+
t.Run(tc.name, func(t *testing.T) {
536+
t.Parallel()
537+
reg := prometheus.NewRegistry()
538+
539+
require.NoError(t, prometheusmetrics.Experiments(reg, tc.experiments))
540+
541+
out, err := reg.Gather()
542+
require.NoError(t, err)
543+
require.Lenf(t, out, 1, "unexpected number of registered metrics")
544+
545+
seen := make(map[codersdk.Experiment]float64)
546+
547+
for _, metric := range out[0].GetMetric() {
548+
require.Equal(t, "coderd_experiments", out[0].GetName())
549+
550+
labels := metric.GetLabel()
551+
require.Lenf(t, labels, 1, "unexpected number of labels")
552+
553+
experiment := codersdk.Experiment(labels[0].GetValue())
554+
value := metric.GetGauge().GetValue()
555+
556+
seen[experiment] = value
557+
558+
expectedValue := 0
559+
560+
// Find experiment we expect to be enabled.
561+
for _, exp := range tc.experiments {
562+
if experiment == exp {
563+
expectedValue = 1
564+
break
565+
}
566+
}
567+
568+
require.EqualValuesf(t, expectedValue, value, "expected %d value for experiment %q", expectedValue, experiment)
569+
}
570+
571+
// We don't want to define the state of all experiments because codersdk.ExperimentAll will change at some
572+
// point and break these tests; so we only validate the experiments we know about.
573+
for exp, val := range seen {
574+
expectedVal, found := tc.expected[exp]
575+
if !found {
576+
t.Logf("ignoring experiment %q; it is not listed in expectations", exp)
577+
continue
578+
}
579+
require.Equalf(t, expectedVal, val, "experiment %q did not match expected value %v", exp, expectedVal)
580+
}
581+
})
582+
}
583+
}
584+
502585
func prepareWorkspaceAndAgent(t *testing.T, client *codersdk.Client, user codersdk.CreateFirstUserResponse, workspaceNum int) *agentsdk.Client {
503586
authToken := uuid.NewString()
504587

0 commit comments

Comments
 (0)