Skip to content

Commit 9b77b42

Browse files
committed
feat(coderd/database): update AcquireProvisionerJob query to allow specifying exact tag match behaviour
1 parent 91c3df7 commit 9b77b42

File tree

8 files changed

+59
-30
lines changed

8 files changed

+59
-30
lines changed

coderd/database/dbfake/dbfake.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,9 @@ func (b WorkspaceBuildBuilder) Do() WorkspaceResponse {
192192
UUID: uuid.New(),
193193
Valid: true,
194194
},
195-
Types: []database.ProvisionerType{database.ProvisionerTypeEcho},
196-
Tags: []byte(`{"scope": "organization"}`),
195+
Types: []database.ProvisionerType{database.ProvisionerTypeEcho},
196+
Tags: []byte(`{"scope": "organization", "owner": ""}`),
197+
ExactTagMatch: false,
197198
})
198199
require.NoError(b.t, err, "acquire starting job")
199200
if j.ID == job.ID {

coderd/database/dbgen/dbgen.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -417,10 +417,11 @@ func ProvisionerJob(t testing.TB, db database.Store, ps pubsub.Pubsub, orig data
417417
}
418418
if !orig.StartedAt.Time.IsZero() {
419419
job, err = db.AcquireProvisionerJob(genCtx, database.AcquireProvisionerJobParams{
420-
StartedAt: orig.StartedAt,
421-
Types: []database.ProvisionerType{database.ProvisionerTypeEcho},
422-
Tags: must(json.Marshal(orig.Tags)),
423-
WorkerID: uuid.NullUUID{},
420+
StartedAt: orig.StartedAt,
421+
Types: []database.ProvisionerType{database.ProvisionerTypeEcho},
422+
Tags: must(json.Marshal(orig.Tags)),
423+
WorkerID: uuid.NullUUID{},
424+
ExactTagMatch: false,
424425
})
425426
require.NoError(t, err)
426427
// There is no easy way to make sure we acquire the correct job.

coderd/database/dbmem/dbmem.go

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,19 @@ var deletedUserLinkError = &pq.Error{
748748
Routine: "exec_stmt_raise",
749749
}
750750

751+
func tagsEqual(m1, m2 map[string]string) bool {
752+
return tagsSubset(m1, m2) && tagsSubset(m2, m1)
753+
}
754+
755+
func tagsSubset(needle, haystack map[string]string) bool {
756+
for k := range needle {
757+
if needle[k] != haystack[k] {
758+
return false
759+
}
760+
}
761+
return true
762+
}
763+
751764
func (*FakeQuerier) AcquireLock(_ context.Context, _ int64) error {
752765
return xerrors.New("AcquireLock must only be called within a transaction")
753766
}
@@ -783,19 +796,11 @@ func (q *FakeQuerier) AcquireProvisionerJob(_ context.Context, arg database.Acqu
783796
}
784797
}
785798

786-
missing := false
787-
for key, value := range provisionerJob.Tags {
788-
provided, found := tags[key]
789-
if !found {
790-
missing = true
791-
break
792-
}
793-
if provided != value {
794-
missing = true
795-
break
796-
}
799+
matchFunc := tagsSubset
800+
if arg.ExactTagMatch {
801+
matchFunc = tagsEqual
797802
}
798-
if missing {
803+
if !matchFunc(tags, provisionerJob.Tags) {
799804
continue
800805
}
801806
provisionerJob.StartedAt = arg.StartedAt

coderd/database/queries.sql.go

Lines changed: 12 additions & 6 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: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,12 @@ WHERE
2121
nested.started_at IS NULL
2222
-- Ensure the caller has the correct provisioner.
2323
AND nested.provisioner = ANY(@types :: provisioner_type [ ])
24-
-- Ensure the caller satisfies all job tags.
25-
AND nested.tags <@ @tags :: jsonb
24+
-- Ensure the caller satisfies all job tags according to the operator
25+
AND CASE
26+
WHEN @exact_tag_match :: boolean THEN nested.tags = @tags :: jsonb
27+
ELSE
28+
nested.tags = @tags :: jsonb
29+
END
2630
ORDER BY
2731
nested.created_at
2832
FOR UPDATE

coderd/provisionerdserver/acquirer.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ type Acquirer struct {
4949
mu sync.Mutex
5050
q map[dKey]domain
5151

52+
exactTagMatch bool
53+
5254
// testing only
5355
backupPollDuration time.Duration
5456
}
@@ -61,6 +63,12 @@ func TestingBackupPollDuration(dur time.Duration) AcquirerOption {
6163
}
6264
}
6365

66+
func WithExactTagMatch() AcquirerOption {
67+
return func(a *Acquirer) {
68+
a.exactTagMatch = true
69+
}
70+
}
71+
6472
// AcquirerStore is the subset of database.Store that the Acquirer needs
6573
type AcquirerStore interface {
6674
AcquireProvisionerJob(context.Context, database.AcquireProvisionerJobParams) (database.ProvisionerJob, error)
@@ -76,6 +84,7 @@ func NewAcquirer(ctx context.Context, logger slog.Logger, store AcquirerStore, p
7684
ps: ps,
7785
q: make(map[dKey]domain),
7886
backupPollDuration: backupPollDuration,
87+
exactTagMatch: false,
7988
}
8089
for _, opt := range opts {
8190
opt(a)
@@ -96,7 +105,8 @@ func (a *Acquirer) AcquireJob(
96105
logger := a.logger.With(
97106
slog.F("worker_id", worker),
98107
slog.F("provisioner_types", pt),
99-
slog.F("tags", tags))
108+
slog.F("tags", tags),
109+
slog.F("exact_tag_match", a.exactTagMatch))
100110
logger.Debug(ctx, "acquiring job")
101111
dk := domainKey(pt, tags)
102112
dbTags, err := tags.ToJSON()

coderd/provisionerdserver/provisionerdserver_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,8 @@ func TestUpdateJob(t *testing.T) {
573573
UUID: srvID,
574574
Valid: true,
575575
},
576-
Types: []database.ProvisionerType{database.ProvisionerTypeEcho},
576+
Types: []database.ProvisionerType{database.ProvisionerTypeEcho},
577+
ExactTagMatch: false,
577578
})
578579
require.NoError(t, err)
579580
return job.ID

enterprise/coderd/schedule/template_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,9 @@ func TestTemplateUpdateBuildDeadlines(t *testing.T) {
181181
UUID: uuid.New(),
182182
Valid: true,
183183
},
184-
Types: []database.ProvisionerType{database.ProvisionerTypeEcho},
185-
Tags: json.RawMessage(fmt.Sprintf(`{%q: "yeah"}`, c.name)),
184+
Types: []database.ProvisionerType{database.ProvisionerTypeEcho},
185+
Tags: json.RawMessage(fmt.Sprintf(`{%q: "yeah"}`, c.name)),
186+
ExactTagMatch: false,
186187
})
187188
require.NoError(t, err)
188189
require.Equal(t, job.ID, acquiredJob.ID)

0 commit comments

Comments
 (0)