Skip to content

Commit 4f7ae64

Browse files
johnstcnmtojek
andauthored
feat(coderd/database): add UpsertProvisionerDaemons query (#11178)
Co-authored-by: Marcin Tojek <marcin@coder.com>
1 parent ef4d1b6 commit 4f7ae64

15 files changed

+213
-101
lines changed

coderd/database/dbauthz/dbauthz.go

+12-8
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/coder/coder/v2/coderd/httpapi/httpapiconstraints"
2323
"github.com/coder/coder/v2/coderd/rbac"
2424
"github.com/coder/coder/v2/coderd/util/slice"
25+
"github.com/coder/coder/v2/provisionersdk"
2526
)
2627

2728
var _ database.Store = (*querier)(nil)
@@ -2155,14 +2156,6 @@ func (q *querier) InsertOrganizationMember(ctx context.Context, arg database.Ins
21552156
return insert(q.log, q.auth, obj, q.db.InsertOrganizationMember)(ctx, arg)
21562157
}
21572158

2158-
// TODO: We need to create a ProvisionerDaemon resource type
2159-
func (q *querier) InsertProvisionerDaemon(ctx context.Context, arg database.InsertProvisionerDaemonParams) (database.ProvisionerDaemon, error) {
2160-
// if err := q.authorizeContext(ctx, rbac.ActionCreate, rbac.ResourceSystem); err != nil {
2161-
// return database.ProvisionerDaemon{}, err
2162-
// }
2163-
return q.db.InsertProvisionerDaemon(ctx, arg)
2164-
}
2165-
21662159
// TODO: We need to create a ProvisionerJob resource type
21672160
func (q *querier) InsertProvisionerJob(ctx context.Context, arg database.InsertProvisionerJobParams) (database.ProvisionerJob, error) {
21682161
// if err := q.authorizeContext(ctx, rbac.ActionCreate, rbac.ResourceSystem); err != nil {
@@ -3063,6 +3056,17 @@ func (q *querier) UpsertOAuthSigningKey(ctx context.Context, value string) error
30633056
return q.db.UpsertOAuthSigningKey(ctx, value)
30643057
}
30653058

3059+
func (q *querier) UpsertProvisionerDaemon(ctx context.Context, arg database.UpsertProvisionerDaemonParams) (database.ProvisionerDaemon, error) {
3060+
res := rbac.ResourceProvisionerDaemon.All()
3061+
if arg.Tags[provisionersdk.TagScope] == provisionersdk.ScopeUser {
3062+
res.Owner = arg.Tags[provisionersdk.TagOwner]
3063+
}
3064+
if err := q.authorizeContext(ctx, rbac.ActionCreate, res); err != nil {
3065+
return database.ProvisionerDaemon{}, err
3066+
}
3067+
return q.db.UpsertProvisionerDaemon(ctx, arg)
3068+
}
3069+
30663070
func (q *querier) UpsertServiceBanner(ctx context.Context, value string) error {
30673071
if err := q.authorizeContext(ctx, rbac.ActionCreate, rbac.ResourceDeploymentValues); err != nil {
30683072
return err

coderd/database/dbauthz/dbauthz_test.go

+18-7
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/coder/coder/v2/coderd/database/dbtime"
2323
"github.com/coder/coder/v2/coderd/rbac"
2424
"github.com/coder/coder/v2/coderd/util/slice"
25+
"github.com/coder/coder/v2/provisionersdk"
2526
"github.com/coder/coder/v2/testutil"
2627
)
2728

@@ -1370,8 +1371,10 @@ func (s *MethodTestSuite) TestWorkspace() {
13701371

13711372
func (s *MethodTestSuite) TestExtraMethods() {
13721373
s.Run("GetProvisionerDaemons", s.Subtest(func(db database.Store, check *expects) {
1373-
d, err := db.InsertProvisionerDaemon(context.Background(), database.InsertProvisionerDaemonParams{
1374-
ID: uuid.New(),
1374+
d, err := db.UpsertProvisionerDaemon(context.Background(), database.UpsertProvisionerDaemonParams{
1375+
Tags: database.StringMap(map[string]string{
1376+
provisionersdk.TagScope: provisionersdk.ScopeOrganization,
1377+
}),
13751378
})
13761379
s.NoError(err, "insert provisioner daemon")
13771380
check.Args().Asserts(d, rbac.ActionRead)
@@ -1650,11 +1653,19 @@ func (s *MethodTestSuite) TestSystemFunctions() {
16501653
JobID: j.ID,
16511654
}).Asserts( /*rbac.ResourceSystem, rbac.ActionCreate*/ )
16521655
}))
1653-
s.Run("InsertProvisionerDaemon", s.Subtest(func(db database.Store, check *expects) {
1654-
// TODO: we need to create a ProvisionerDaemon resource
1655-
check.Args(database.InsertProvisionerDaemonParams{
1656-
ID: uuid.New(),
1657-
}).Asserts( /*rbac.ResourceSystem, rbac.ActionCreate*/ )
1656+
s.Run("UpsertProvisionerDaemon", s.Subtest(func(db database.Store, check *expects) {
1657+
pd := rbac.ResourceProvisionerDaemon.All()
1658+
check.Args(database.UpsertProvisionerDaemonParams{
1659+
Tags: database.StringMap(map[string]string{
1660+
provisionersdk.TagScope: provisionersdk.ScopeOrganization,
1661+
}),
1662+
}).Asserts(pd, rbac.ActionCreate)
1663+
check.Args(database.UpsertProvisionerDaemonParams{
1664+
Tags: database.StringMap(map[string]string{
1665+
provisionersdk.TagScope: provisionersdk.ScopeUser,
1666+
provisionersdk.TagOwner: "11111111-1111-1111-1111-111111111111",
1667+
}),
1668+
}).Asserts(pd.WithOwner("11111111-1111-1111-1111-111111111111"), rbac.ActionCreate)
16581669
}))
16591670
s.Run("InsertTemplateVersionParameter", s.Subtest(func(db database.Store, check *expects) {
16601671
v := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{})

coderd/database/dbmem/dbmem.go

+38-19
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"github.com/coder/coder/v2/coderd/rbac/regosql"
2727
"github.com/coder/coder/v2/coderd/util/slice"
2828
"github.com/coder/coder/v2/codersdk"
29+
"github.com/coder/coder/v2/provisionersdk"
2930
)
3031

3132
var validProxyByHostnameRegex = regexp.MustCompile(`^[a-zA-Z0-9._-]+$`)
@@ -4936,25 +4937,6 @@ func (q *FakeQuerier) InsertOrganizationMember(_ context.Context, arg database.I
49364937
return organizationMember, nil
49374938
}
49384939

4939-
func (q *FakeQuerier) InsertProvisionerDaemon(_ context.Context, arg database.InsertProvisionerDaemonParams) (database.ProvisionerDaemon, error) {
4940-
if err := validateDatabaseType(arg); err != nil {
4941-
return database.ProvisionerDaemon{}, err
4942-
}
4943-
4944-
q.mutex.Lock()
4945-
defer q.mutex.Unlock()
4946-
4947-
daemon := database.ProvisionerDaemon{
4948-
ID: arg.ID,
4949-
Name: arg.Name,
4950-
Provisioners: arg.Provisioners,
4951-
Tags: arg.Tags,
4952-
LastSeenAt: arg.LastSeenAt,
4953-
}
4954-
q.provisionerDaemons = append(q.provisionerDaemons, daemon)
4955-
return daemon, nil
4956-
}
4957-
49584940
func (q *FakeQuerier) InsertProvisionerJob(_ context.Context, arg database.InsertProvisionerJobParams) (database.ProvisionerJob, error) {
49594941
if err := validateDatabaseType(arg); err != nil {
49604942
return database.ProvisionerJob{}, err
@@ -6961,6 +6943,43 @@ func (q *FakeQuerier) UpsertOAuthSigningKey(_ context.Context, value string) err
69616943
return nil
69626944
}
69636945

6946+
func (q *FakeQuerier) UpsertProvisionerDaemon(_ context.Context, arg database.UpsertProvisionerDaemonParams) (database.ProvisionerDaemon, error) {
6947+
err := validateDatabaseType(arg)
6948+
if err != nil {
6949+
return database.ProvisionerDaemon{}, err
6950+
}
6951+
6952+
q.mutex.Lock()
6953+
defer q.mutex.Unlock()
6954+
for _, d := range q.provisionerDaemons {
6955+
if d.Name == arg.Name {
6956+
if d.Tags[provisionersdk.TagScope] == provisionersdk.ScopeOrganization && arg.Tags[provisionersdk.TagOwner] != "" {
6957+
continue
6958+
}
6959+
if d.Tags[provisionersdk.TagScope] == provisionersdk.ScopeUser && arg.Tags[provisionersdk.TagOwner] != d.Tags[provisionersdk.TagOwner] {
6960+
continue
6961+
}
6962+
d.Provisioners = arg.Provisioners
6963+
d.Tags = arg.Tags
6964+
d.Version = arg.Version
6965+
d.LastSeenAt = arg.LastSeenAt
6966+
return d, nil
6967+
}
6968+
}
6969+
d := database.ProvisionerDaemon{
6970+
ID: uuid.New(),
6971+
CreatedAt: arg.CreatedAt,
6972+
Name: arg.Name,
6973+
Provisioners: arg.Provisioners,
6974+
Tags: arg.Tags,
6975+
ReplicaID: uuid.NullUUID{},
6976+
LastSeenAt: arg.LastSeenAt,
6977+
Version: arg.Version,
6978+
}
6979+
q.provisionerDaemons = append(q.provisionerDaemons, d)
6980+
return d, nil
6981+
}
6982+
69646983
func (q *FakeQuerier) UpsertServiceBanner(_ context.Context, data string) error {
69656984
q.mutex.RLock()
69666985
defer q.mutex.RUnlock()

coderd/database/dbmetrics/dbmetrics.go

+7-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/dbmock/dbmock.go

+15-15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/dbpurge/dbpurge_test.go

+22-15
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"github.com/coder/coder/v2/coderd/database/dbpurge"
2020
"github.com/coder/coder/v2/coderd/database/dbtestutil"
2121
"github.com/coder/coder/v2/coderd/database/dbtime"
22+
"github.com/coder/coder/v2/provisionersdk"
2223
"github.com/coder/coder/v2/testutil"
2324
)
2425

@@ -209,39 +210,45 @@ func TestDeleteOldProvisionerDaemons(t *testing.T) {
209210
now := dbtime.Now()
210211

211212
// given
212-
_, err := db.InsertProvisionerDaemon(ctx, database.InsertProvisionerDaemonParams{
213+
_, err := db.UpsertProvisionerDaemon(ctx, database.UpsertProvisionerDaemonParams{
213214
// Provisioner daemon created 14 days ago, and checked in just before 7 days deadline.
214-
ID: uuid.New(),
215215
Name: "external-0",
216216
Provisioners: []database.ProvisionerType{"echo"},
217+
Tags: database.StringMap{provisionersdk.TagScope: provisionersdk.ScopeOrganization},
217218
CreatedAt: now.Add(-14 * 24 * time.Hour),
218219
LastSeenAt: sql.NullTime{Valid: true, Time: now.Add(-7 * 24 * time.Hour).Add(time.Minute)},
219220
})
220221
require.NoError(t, err)
221-
_, err = db.InsertProvisionerDaemon(ctx, database.InsertProvisionerDaemonParams{
222+
_, err = db.UpsertProvisionerDaemon(ctx, database.UpsertProvisionerDaemonParams{
222223
// Provisioner daemon created 8 days ago, and checked in last time an hour after creation.
223-
ID: uuid.New(),
224224
Name: "external-1",
225225
Provisioners: []database.ProvisionerType{"echo"},
226+
Tags: database.StringMap{provisionersdk.TagScope: provisionersdk.ScopeOrganization},
226227
CreatedAt: now.Add(-8 * 24 * time.Hour),
227228
LastSeenAt: sql.NullTime{Valid: true, Time: now.Add(-8 * 24 * time.Hour).Add(time.Hour)},
228229
})
229230
require.NoError(t, err)
230-
_, err = db.InsertProvisionerDaemon(ctx, database.InsertProvisionerDaemonParams{
231+
_, err = db.UpsertProvisionerDaemon(ctx, database.UpsertProvisionerDaemonParams{
231232
// Provisioner daemon created 9 days ago, and never checked in.
232-
ID: uuid.New(),
233-
Name: "external-2",
233+
Name: "alice-provisioner",
234234
Provisioners: []database.ProvisionerType{"echo"},
235-
CreatedAt: now.Add(-9 * 24 * time.Hour),
235+
Tags: database.StringMap{
236+
provisionersdk.TagScope: provisionersdk.ScopeUser,
237+
provisionersdk.TagOwner: uuid.NewString(),
238+
},
239+
CreatedAt: now.Add(-9 * 24 * time.Hour),
236240
})
237241
require.NoError(t, err)
238-
_, err = db.InsertProvisionerDaemon(ctx, database.InsertProvisionerDaemonParams{
242+
_, err = db.UpsertProvisionerDaemon(ctx, database.UpsertProvisionerDaemonParams{
239243
// Provisioner daemon created 6 days ago, and never checked in.
240-
ID: uuid.New(),
241-
Name: "external-3",
244+
Name: "bob-provisioner",
242245
Provisioners: []database.ProvisionerType{"echo"},
243-
CreatedAt: now.Add(-6 * 24 * time.Hour),
244-
LastSeenAt: sql.NullTime{Valid: true, Time: now.Add(-6 * 24 * time.Hour)},
246+
Tags: database.StringMap{
247+
provisionersdk.TagScope: provisionersdk.ScopeUser,
248+
provisionersdk.TagOwner: uuid.NewString(),
249+
},
250+
CreatedAt: now.Add(-6 * 24 * time.Hour),
251+
LastSeenAt: sql.NullTime{Valid: true, Time: now.Add(-6 * 24 * time.Hour)},
245252
})
246253
require.NoError(t, err)
247254

@@ -257,8 +264,8 @@ func TestDeleteOldProvisionerDaemons(t *testing.T) {
257264
}
258265
return containsProvisionerDaemon(daemons, "external-0") &&
259266
!containsProvisionerDaemon(daemons, "external-1") &&
260-
!containsProvisionerDaemon(daemons, "external-2") &&
261-
containsProvisionerDaemon(daemons, "external-3")
267+
!containsProvisionerDaemon(daemons, "alice-provisioner") &&
268+
containsProvisionerDaemon(daemons, "bob-provisioner")
262269
}, testutil.WaitShort, testutil.IntervalFast)
263270
}
264271

coderd/database/dump.sql

+4-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
DROP INDEX IF EXISTS idx_provisioner_daemons_name_owner_key;
2+
3+
ALTER TABLE ONLY provisioner_daemons
4+
ADD CONSTRAINT provisioner_daemons_name_key UNIQUE (name);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
ALTER TABLE ONLY provisioner_daemons
2+
DROP CONSTRAINT IF EXISTS provisioner_daemons_name_key;
3+
4+
CREATE UNIQUE INDEX IF NOT EXISTS idx_provisioner_daemons_name_owner_key
5+
ON provisioner_daemons
6+
USING btree (name, lower((tags->>'owner')::text));
7+
8+
COMMENT ON INDEX idx_provisioner_daemons_name_owner_key
9+
IS 'Relax uniqueness constraint for provisioner daemon names';
10+

coderd/database/querier.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)