mirror of https://github.com/coder/coder.git
feat(coderd/database): add UpsertProvisionerDaemons query (#11178)
Co-authored-by: Marcin Tojek <marcin@coder.com>
This commit is contained in:
parent
ef4d1b68e1
commit
4f7ae6461b
|
@ -22,6 +22,7 @@ import (
|
|||
"github.com/coder/coder/v2/coderd/httpapi/httpapiconstraints"
|
||||
"github.com/coder/coder/v2/coderd/rbac"
|
||||
"github.com/coder/coder/v2/coderd/util/slice"
|
||||
"github.com/coder/coder/v2/provisionersdk"
|
||||
)
|
||||
|
||||
var _ database.Store = (*querier)(nil)
|
||||
|
@ -2155,14 +2156,6 @@ func (q *querier) InsertOrganizationMember(ctx context.Context, arg database.Ins
|
|||
return insert(q.log, q.auth, obj, q.db.InsertOrganizationMember)(ctx, arg)
|
||||
}
|
||||
|
||||
// TODO: We need to create a ProvisionerDaemon resource type
|
||||
func (q *querier) InsertProvisionerDaemon(ctx context.Context, arg database.InsertProvisionerDaemonParams) (database.ProvisionerDaemon, error) {
|
||||
// if err := q.authorizeContext(ctx, rbac.ActionCreate, rbac.ResourceSystem); err != nil {
|
||||
// return database.ProvisionerDaemon{}, err
|
||||
// }
|
||||
return q.db.InsertProvisionerDaemon(ctx, arg)
|
||||
}
|
||||
|
||||
// TODO: We need to create a ProvisionerJob resource type
|
||||
func (q *querier) InsertProvisionerJob(ctx context.Context, arg database.InsertProvisionerJobParams) (database.ProvisionerJob, error) {
|
||||
// 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
|
|||
return q.db.UpsertOAuthSigningKey(ctx, value)
|
||||
}
|
||||
|
||||
func (q *querier) UpsertProvisionerDaemon(ctx context.Context, arg database.UpsertProvisionerDaemonParams) (database.ProvisionerDaemon, error) {
|
||||
res := rbac.ResourceProvisionerDaemon.All()
|
||||
if arg.Tags[provisionersdk.TagScope] == provisionersdk.ScopeUser {
|
||||
res.Owner = arg.Tags[provisionersdk.TagOwner]
|
||||
}
|
||||
if err := q.authorizeContext(ctx, rbac.ActionCreate, res); err != nil {
|
||||
return database.ProvisionerDaemon{}, err
|
||||
}
|
||||
return q.db.UpsertProvisionerDaemon(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) UpsertServiceBanner(ctx context.Context, value string) error {
|
||||
if err := q.authorizeContext(ctx, rbac.ActionCreate, rbac.ResourceDeploymentValues); err != nil {
|
||||
return err
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
"github.com/coder/coder/v2/coderd/database/dbtime"
|
||||
"github.com/coder/coder/v2/coderd/rbac"
|
||||
"github.com/coder/coder/v2/coderd/util/slice"
|
||||
"github.com/coder/coder/v2/provisionersdk"
|
||||
"github.com/coder/coder/v2/testutil"
|
||||
)
|
||||
|
||||
|
@ -1370,8 +1371,10 @@ func (s *MethodTestSuite) TestWorkspace() {
|
|||
|
||||
func (s *MethodTestSuite) TestExtraMethods() {
|
||||
s.Run("GetProvisionerDaemons", s.Subtest(func(db database.Store, check *expects) {
|
||||
d, err := db.InsertProvisionerDaemon(context.Background(), database.InsertProvisionerDaemonParams{
|
||||
ID: uuid.New(),
|
||||
d, err := db.UpsertProvisionerDaemon(context.Background(), database.UpsertProvisionerDaemonParams{
|
||||
Tags: database.StringMap(map[string]string{
|
||||
provisionersdk.TagScope: provisionersdk.ScopeOrganization,
|
||||
}),
|
||||
})
|
||||
s.NoError(err, "insert provisioner daemon")
|
||||
check.Args().Asserts(d, rbac.ActionRead)
|
||||
|
@ -1650,11 +1653,19 @@ func (s *MethodTestSuite) TestSystemFunctions() {
|
|||
JobID: j.ID,
|
||||
}).Asserts( /*rbac.ResourceSystem, rbac.ActionCreate*/ )
|
||||
}))
|
||||
s.Run("InsertProvisionerDaemon", s.Subtest(func(db database.Store, check *expects) {
|
||||
// TODO: we need to create a ProvisionerDaemon resource
|
||||
check.Args(database.InsertProvisionerDaemonParams{
|
||||
ID: uuid.New(),
|
||||
}).Asserts( /*rbac.ResourceSystem, rbac.ActionCreate*/ )
|
||||
s.Run("UpsertProvisionerDaemon", s.Subtest(func(db database.Store, check *expects) {
|
||||
pd := rbac.ResourceProvisionerDaemon.All()
|
||||
check.Args(database.UpsertProvisionerDaemonParams{
|
||||
Tags: database.StringMap(map[string]string{
|
||||
provisionersdk.TagScope: provisionersdk.ScopeOrganization,
|
||||
}),
|
||||
}).Asserts(pd, rbac.ActionCreate)
|
||||
check.Args(database.UpsertProvisionerDaemonParams{
|
||||
Tags: database.StringMap(map[string]string{
|
||||
provisionersdk.TagScope: provisionersdk.ScopeUser,
|
||||
provisionersdk.TagOwner: "11111111-1111-1111-1111-111111111111",
|
||||
}),
|
||||
}).Asserts(pd.WithOwner("11111111-1111-1111-1111-111111111111"), rbac.ActionCreate)
|
||||
}))
|
||||
s.Run("InsertTemplateVersionParameter", s.Subtest(func(db database.Store, check *expects) {
|
||||
v := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{})
|
||||
|
|
|
@ -26,6 +26,7 @@ import (
|
|||
"github.com/coder/coder/v2/coderd/rbac/regosql"
|
||||
"github.com/coder/coder/v2/coderd/util/slice"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
"github.com/coder/coder/v2/provisionersdk"
|
||||
)
|
||||
|
||||
var validProxyByHostnameRegex = regexp.MustCompile(`^[a-zA-Z0-9._-]+$`)
|
||||
|
@ -4936,25 +4937,6 @@ func (q *FakeQuerier) InsertOrganizationMember(_ context.Context, arg database.I
|
|||
return organizationMember, nil
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) InsertProvisionerDaemon(_ context.Context, arg database.InsertProvisionerDaemonParams) (database.ProvisionerDaemon, error) {
|
||||
if err := validateDatabaseType(arg); err != nil {
|
||||
return database.ProvisionerDaemon{}, err
|
||||
}
|
||||
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
|
||||
daemon := database.ProvisionerDaemon{
|
||||
ID: arg.ID,
|
||||
Name: arg.Name,
|
||||
Provisioners: arg.Provisioners,
|
||||
Tags: arg.Tags,
|
||||
LastSeenAt: arg.LastSeenAt,
|
||||
}
|
||||
q.provisionerDaemons = append(q.provisionerDaemons, daemon)
|
||||
return daemon, nil
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) InsertProvisionerJob(_ context.Context, arg database.InsertProvisionerJobParams) (database.ProvisionerJob, error) {
|
||||
if err := validateDatabaseType(arg); err != nil {
|
||||
return database.ProvisionerJob{}, err
|
||||
|
@ -6961,6 +6943,43 @@ func (q *FakeQuerier) UpsertOAuthSigningKey(_ context.Context, value string) err
|
|||
return nil
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) UpsertProvisionerDaemon(_ context.Context, arg database.UpsertProvisionerDaemonParams) (database.ProvisionerDaemon, error) {
|
||||
err := validateDatabaseType(arg)
|
||||
if err != nil {
|
||||
return database.ProvisionerDaemon{}, err
|
||||
}
|
||||
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
for _, d := range q.provisionerDaemons {
|
||||
if d.Name == arg.Name {
|
||||
if d.Tags[provisionersdk.TagScope] == provisionersdk.ScopeOrganization && arg.Tags[provisionersdk.TagOwner] != "" {
|
||||
continue
|
||||
}
|
||||
if d.Tags[provisionersdk.TagScope] == provisionersdk.ScopeUser && arg.Tags[provisionersdk.TagOwner] != d.Tags[provisionersdk.TagOwner] {
|
||||
continue
|
||||
}
|
||||
d.Provisioners = arg.Provisioners
|
||||
d.Tags = arg.Tags
|
||||
d.Version = arg.Version
|
||||
d.LastSeenAt = arg.LastSeenAt
|
||||
return d, nil
|
||||
}
|
||||
}
|
||||
d := database.ProvisionerDaemon{
|
||||
ID: uuid.New(),
|
||||
CreatedAt: arg.CreatedAt,
|
||||
Name: arg.Name,
|
||||
Provisioners: arg.Provisioners,
|
||||
Tags: arg.Tags,
|
||||
ReplicaID: uuid.NullUUID{},
|
||||
LastSeenAt: arg.LastSeenAt,
|
||||
Version: arg.Version,
|
||||
}
|
||||
q.provisionerDaemons = append(q.provisionerDaemons, d)
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) UpsertServiceBanner(_ context.Context, data string) error {
|
||||
q.mutex.RLock()
|
||||
defer q.mutex.RUnlock()
|
||||
|
|
|
@ -1348,13 +1348,6 @@ func (m metricsStore) InsertOrganizationMember(ctx context.Context, arg database
|
|||
return member, err
|
||||
}
|
||||
|
||||
func (m metricsStore) InsertProvisionerDaemon(ctx context.Context, arg database.InsertProvisionerDaemonParams) (database.ProvisionerDaemon, error) {
|
||||
start := time.Now()
|
||||
daemon, err := m.s.InsertProvisionerDaemon(ctx, arg)
|
||||
m.queryLatencies.WithLabelValues("InsertProvisionerDaemon").Observe(time.Since(start).Seconds())
|
||||
return daemon, err
|
||||
}
|
||||
|
||||
func (m metricsStore) InsertProvisionerJob(ctx context.Context, arg database.InsertProvisionerJobParams) (database.ProvisionerJob, error) {
|
||||
start := time.Now()
|
||||
job, err := m.s.InsertProvisionerJob(ctx, arg)
|
||||
|
@ -1950,6 +1943,13 @@ func (m metricsStore) UpsertOAuthSigningKey(ctx context.Context, value string) e
|
|||
return r0
|
||||
}
|
||||
|
||||
func (m metricsStore) UpsertProvisionerDaemon(ctx context.Context, arg database.UpsertProvisionerDaemonParams) (database.ProvisionerDaemon, error) {
|
||||
start := time.Now()
|
||||
r0, r1 := m.s.UpsertProvisionerDaemon(ctx, arg)
|
||||
m.queryLatencies.WithLabelValues("UpsertProvisionerDaemon").Observe(time.Since(start).Seconds())
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
func (m metricsStore) UpsertServiceBanner(ctx context.Context, value string) error {
|
||||
start := time.Now()
|
||||
r0 := m.s.UpsertServiceBanner(ctx, value)
|
||||
|
|
|
@ -2833,21 +2833,6 @@ func (mr *MockStoreMockRecorder) InsertOrganizationMember(arg0, arg1 interface{}
|
|||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertOrganizationMember", reflect.TypeOf((*MockStore)(nil).InsertOrganizationMember), arg0, arg1)
|
||||
}
|
||||
|
||||
// InsertProvisionerDaemon mocks base method.
|
||||
func (m *MockStore) InsertProvisionerDaemon(arg0 context.Context, arg1 database.InsertProvisionerDaemonParams) (database.ProvisionerDaemon, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "InsertProvisionerDaemon", arg0, arg1)
|
||||
ret0, _ := ret[0].(database.ProvisionerDaemon)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// InsertProvisionerDaemon indicates an expected call of InsertProvisionerDaemon.
|
||||
func (mr *MockStoreMockRecorder) InsertProvisionerDaemon(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertProvisionerDaemon", reflect.TypeOf((*MockStore)(nil).InsertProvisionerDaemon), arg0, arg1)
|
||||
}
|
||||
|
||||
// InsertProvisionerJob mocks base method.
|
||||
func (m *MockStore) InsertProvisionerJob(arg0 context.Context, arg1 database.InsertProvisionerJobParams) (database.ProvisionerJob, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
@ -4089,6 +4074,21 @@ func (mr *MockStoreMockRecorder) UpsertOAuthSigningKey(arg0, arg1 interface{}) *
|
|||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpsertOAuthSigningKey", reflect.TypeOf((*MockStore)(nil).UpsertOAuthSigningKey), arg0, arg1)
|
||||
}
|
||||
|
||||
// UpsertProvisionerDaemon mocks base method.
|
||||
func (m *MockStore) UpsertProvisionerDaemon(arg0 context.Context, arg1 database.UpsertProvisionerDaemonParams) (database.ProvisionerDaemon, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UpsertProvisionerDaemon", arg0, arg1)
|
||||
ret0, _ := ret[0].(database.ProvisionerDaemon)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// UpsertProvisionerDaemon indicates an expected call of UpsertProvisionerDaemon.
|
||||
func (mr *MockStoreMockRecorder) UpsertProvisionerDaemon(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpsertProvisionerDaemon", reflect.TypeOf((*MockStore)(nil).UpsertProvisionerDaemon), arg0, arg1)
|
||||
}
|
||||
|
||||
// UpsertServiceBanner mocks base method.
|
||||
func (m *MockStore) UpsertServiceBanner(arg0 context.Context, arg1 string) error {
|
||||
m.ctrl.T.Helper()
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
"github.com/coder/coder/v2/coderd/database/dbpurge"
|
||||
"github.com/coder/coder/v2/coderd/database/dbtestutil"
|
||||
"github.com/coder/coder/v2/coderd/database/dbtime"
|
||||
"github.com/coder/coder/v2/provisionersdk"
|
||||
"github.com/coder/coder/v2/testutil"
|
||||
)
|
||||
|
||||
|
@ -209,39 +210,45 @@ func TestDeleteOldProvisionerDaemons(t *testing.T) {
|
|||
now := dbtime.Now()
|
||||
|
||||
// given
|
||||
_, err := db.InsertProvisionerDaemon(ctx, database.InsertProvisionerDaemonParams{
|
||||
_, err := db.UpsertProvisionerDaemon(ctx, database.UpsertProvisionerDaemonParams{
|
||||
// Provisioner daemon created 14 days ago, and checked in just before 7 days deadline.
|
||||
ID: uuid.New(),
|
||||
Name: "external-0",
|
||||
Provisioners: []database.ProvisionerType{"echo"},
|
||||
Tags: database.StringMap{provisionersdk.TagScope: provisionersdk.ScopeOrganization},
|
||||
CreatedAt: now.Add(-14 * 24 * time.Hour),
|
||||
LastSeenAt: sql.NullTime{Valid: true, Time: now.Add(-7 * 24 * time.Hour).Add(time.Minute)},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
_, err = db.InsertProvisionerDaemon(ctx, database.InsertProvisionerDaemonParams{
|
||||
_, err = db.UpsertProvisionerDaemon(ctx, database.UpsertProvisionerDaemonParams{
|
||||
// Provisioner daemon created 8 days ago, and checked in last time an hour after creation.
|
||||
ID: uuid.New(),
|
||||
Name: "external-1",
|
||||
Provisioners: []database.ProvisionerType{"echo"},
|
||||
Tags: database.StringMap{provisionersdk.TagScope: provisionersdk.ScopeOrganization},
|
||||
CreatedAt: now.Add(-8 * 24 * time.Hour),
|
||||
LastSeenAt: sql.NullTime{Valid: true, Time: now.Add(-8 * 24 * time.Hour).Add(time.Hour)},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
_, err = db.InsertProvisionerDaemon(ctx, database.InsertProvisionerDaemonParams{
|
||||
_, err = db.UpsertProvisionerDaemon(ctx, database.UpsertProvisionerDaemonParams{
|
||||
// Provisioner daemon created 9 days ago, and never checked in.
|
||||
ID: uuid.New(),
|
||||
Name: "external-2",
|
||||
Name: "alice-provisioner",
|
||||
Provisioners: []database.ProvisionerType{"echo"},
|
||||
CreatedAt: now.Add(-9 * 24 * time.Hour),
|
||||
Tags: database.StringMap{
|
||||
provisionersdk.TagScope: provisionersdk.ScopeUser,
|
||||
provisionersdk.TagOwner: uuid.NewString(),
|
||||
},
|
||||
CreatedAt: now.Add(-9 * 24 * time.Hour),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
_, err = db.InsertProvisionerDaemon(ctx, database.InsertProvisionerDaemonParams{
|
||||
_, err = db.UpsertProvisionerDaemon(ctx, database.UpsertProvisionerDaemonParams{
|
||||
// Provisioner daemon created 6 days ago, and never checked in.
|
||||
ID: uuid.New(),
|
||||
Name: "external-3",
|
||||
Name: "bob-provisioner",
|
||||
Provisioners: []database.ProvisionerType{"echo"},
|
||||
CreatedAt: now.Add(-6 * 24 * time.Hour),
|
||||
LastSeenAt: sql.NullTime{Valid: true, Time: now.Add(-6 * 24 * time.Hour)},
|
||||
Tags: database.StringMap{
|
||||
provisionersdk.TagScope: provisionersdk.ScopeUser,
|
||||
provisionersdk.TagOwner: uuid.NewString(),
|
||||
},
|
||||
CreatedAt: now.Add(-6 * 24 * time.Hour),
|
||||
LastSeenAt: sql.NullTime{Valid: true, Time: now.Add(-6 * 24 * time.Hour)},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
|
@ -257,8 +264,8 @@ func TestDeleteOldProvisionerDaemons(t *testing.T) {
|
|||
}
|
||||
return containsProvisionerDaemon(daemons, "external-0") &&
|
||||
!containsProvisionerDaemon(daemons, "external-1") &&
|
||||
!containsProvisionerDaemon(daemons, "external-2") &&
|
||||
containsProvisionerDaemon(daemons, "external-3")
|
||||
!containsProvisionerDaemon(daemons, "alice-provisioner") &&
|
||||
containsProvisionerDaemon(daemons, "bob-provisioner")
|
||||
}, testutil.WaitShort, testutil.IntervalFast)
|
||||
}
|
||||
|
||||
|
|
|
@ -1283,9 +1283,6 @@ ALTER TABLE ONLY parameter_values
|
|||
ALTER TABLE ONLY parameter_values
|
||||
ADD CONSTRAINT parameter_values_scope_id_name_key UNIQUE (scope_id, name);
|
||||
|
||||
ALTER TABLE ONLY provisioner_daemons
|
||||
ADD CONSTRAINT provisioner_daemons_name_key UNIQUE (name);
|
||||
|
||||
ALTER TABLE ONLY provisioner_daemons
|
||||
ADD CONSTRAINT provisioner_daemons_pkey PRIMARY KEY (id);
|
||||
|
||||
|
@ -1415,6 +1412,10 @@ CREATE UNIQUE INDEX idx_organization_name ON organizations USING btree (name);
|
|||
|
||||
CREATE UNIQUE INDEX idx_organization_name_lower ON organizations USING btree (lower(name));
|
||||
|
||||
CREATE UNIQUE INDEX idx_provisioner_daemons_name_owner_key ON provisioner_daemons USING btree (name, lower((tags ->> 'owner'::text)));
|
||||
|
||||
COMMENT ON INDEX idx_provisioner_daemons_name_owner_key IS 'Relax uniqueness constraint for provisioner daemon names';
|
||||
|
||||
CREATE INDEX idx_tailnet_agents_coordinator ON tailnet_agents USING btree (coordinator_id);
|
||||
|
||||
CREATE INDEX idx_tailnet_clients_coordinator ON tailnet_clients USING btree (coordinator_id);
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
DROP INDEX IF EXISTS idx_provisioner_daemons_name_owner_key;
|
||||
|
||||
ALTER TABLE ONLY provisioner_daemons
|
||||
ADD CONSTRAINT provisioner_daemons_name_key UNIQUE (name);
|
|
@ -0,0 +1,10 @@
|
|||
ALTER TABLE ONLY provisioner_daemons
|
||||
DROP CONSTRAINT IF EXISTS provisioner_daemons_name_key;
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_provisioner_daemons_name_owner_key
|
||||
ON provisioner_daemons
|
||||
USING btree (name, lower((tags->>'owner')::text));
|
||||
|
||||
COMMENT ON INDEX idx_provisioner_daemons_name_owner_key
|
||||
IS 'Relax uniqueness constraint for provisioner daemon names';
|
||||
|
|
@ -277,7 +277,6 @@ type sqlcQuerier interface {
|
|||
InsertMissingGroups(ctx context.Context, arg InsertMissingGroupsParams) ([]Group, error)
|
||||
InsertOrganization(ctx context.Context, arg InsertOrganizationParams) (Organization, error)
|
||||
InsertOrganizationMember(ctx context.Context, arg InsertOrganizationMemberParams) (OrganizationMember, error)
|
||||
InsertProvisionerDaemon(ctx context.Context, arg InsertProvisionerDaemonParams) (ProvisionerDaemon, error)
|
||||
InsertProvisionerJob(ctx context.Context, arg InsertProvisionerJobParams) (ProvisionerJob, error)
|
||||
InsertProvisionerJobLogs(ctx context.Context, arg InsertProvisionerJobLogsParams) ([]ProvisionerJobLog, error)
|
||||
InsertReplica(ctx context.Context, arg InsertReplicaParams) (Replica, error)
|
||||
|
@ -373,6 +372,7 @@ type sqlcQuerier interface {
|
|||
UpsertLastUpdateCheck(ctx context.Context, value string) error
|
||||
UpsertLogoURL(ctx context.Context, value string) error
|
||||
UpsertOAuthSigningKey(ctx context.Context, value string) error
|
||||
UpsertProvisionerDaemon(ctx context.Context, arg UpsertProvisionerDaemonParams) (ProvisionerDaemon, error)
|
||||
UpsertServiceBanner(ctx context.Context, value string) error
|
||||
UpsertTailnetAgent(ctx context.Context, arg UpsertTailnetAgentParams) (TailnetAgent, error)
|
||||
UpsertTailnetClient(ctx context.Context, arg UpsertTailnetClientParams) (TailnetClient, error)
|
||||
|
|
|
@ -3056,7 +3056,7 @@ func (q *sqlQuerier) GetProvisionerDaemons(ctx context.Context) ([]ProvisionerDa
|
|||
return items, nil
|
||||
}
|
||||
|
||||
const insertProvisionerDaemon = `-- name: InsertProvisionerDaemon :one
|
||||
const upsertProvisionerDaemon = `-- name: UpsertProvisionerDaemon :one
|
||||
INSERT INTO
|
||||
provisioner_daemons (
|
||||
id,
|
||||
|
@ -3064,29 +3064,45 @@ INSERT INTO
|
|||
"name",
|
||||
provisioners,
|
||||
tags,
|
||||
last_seen_at
|
||||
last_seen_at,
|
||||
"version"
|
||||
)
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5, $6) RETURNING id, created_at, name, provisioners, replica_id, tags, last_seen_at, version
|
||||
VALUES (
|
||||
gen_random_uuid(),
|
||||
$1,
|
||||
$2,
|
||||
$3,
|
||||
$4,
|
||||
$5,
|
||||
$6
|
||||
) ON CONFLICT("name", lower((tags ->> 'owner'::text))) DO UPDATE SET
|
||||
provisioners = $3,
|
||||
tags = $4,
|
||||
last_seen_at = $5,
|
||||
"version" = $6
|
||||
WHERE
|
||||
-- Only ones with the same tags are allowed clobber
|
||||
provisioner_daemons.tags <@ $4 :: jsonb
|
||||
RETURNING id, created_at, name, provisioners, replica_id, tags, last_seen_at, version
|
||||
`
|
||||
|
||||
type InsertProvisionerDaemonParams struct {
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
type UpsertProvisionerDaemonParams struct {
|
||||
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
||||
Name string `db:"name" json:"name"`
|
||||
Provisioners []ProvisionerType `db:"provisioners" json:"provisioners"`
|
||||
Tags StringMap `db:"tags" json:"tags"`
|
||||
LastSeenAt sql.NullTime `db:"last_seen_at" json:"last_seen_at"`
|
||||
Version string `db:"version" json:"version"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) InsertProvisionerDaemon(ctx context.Context, arg InsertProvisionerDaemonParams) (ProvisionerDaemon, error) {
|
||||
row := q.db.QueryRowContext(ctx, insertProvisionerDaemon,
|
||||
arg.ID,
|
||||
func (q *sqlQuerier) UpsertProvisionerDaemon(ctx context.Context, arg UpsertProvisionerDaemonParams) (ProvisionerDaemon, error) {
|
||||
row := q.db.QueryRowContext(ctx, upsertProvisionerDaemon,
|
||||
arg.CreatedAt,
|
||||
arg.Name,
|
||||
pq.Array(arg.Provisioners),
|
||||
arg.Tags,
|
||||
arg.LastSeenAt,
|
||||
arg.Version,
|
||||
)
|
||||
var i ProvisionerDaemon
|
||||
err := row.Scan(
|
||||
|
|
|
@ -4,19 +4,6 @@ SELECT
|
|||
FROM
|
||||
provisioner_daemons;
|
||||
|
||||
-- name: InsertProvisionerDaemon :one
|
||||
INSERT INTO
|
||||
provisioner_daemons (
|
||||
id,
|
||||
created_at,
|
||||
"name",
|
||||
provisioners,
|
||||
tags,
|
||||
last_seen_at
|
||||
)
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5, $6) RETURNING *;
|
||||
|
||||
-- name: DeleteOldProvisionerDaemons :exec
|
||||
-- Delete provisioner daemons that have been created at least a week ago
|
||||
-- and have not connected to coderd since a week.
|
||||
|
@ -26,3 +13,32 @@ DELETE FROM provisioner_daemons WHERE (
|
|||
(created_at < (NOW() - INTERVAL '7 days') AND last_seen_at IS NULL) OR
|
||||
(last_seen_at IS NOT NULL AND last_seen_at < (NOW() - INTERVAL '7 days'))
|
||||
);
|
||||
|
||||
-- name: UpsertProvisionerDaemon :one
|
||||
INSERT INTO
|
||||
provisioner_daemons (
|
||||
id,
|
||||
created_at,
|
||||
"name",
|
||||
provisioners,
|
||||
tags,
|
||||
last_seen_at,
|
||||
"version"
|
||||
)
|
||||
VALUES (
|
||||
gen_random_uuid(),
|
||||
@created_at,
|
||||
@name,
|
||||
@provisioners,
|
||||
@tags,
|
||||
@last_seen_at,
|
||||
@version
|
||||
) ON CONFLICT("name", lower((tags ->> 'owner'::text))) DO UPDATE SET
|
||||
provisioners = @provisioners,
|
||||
tags = @tags,
|
||||
last_seen_at = @last_seen_at,
|
||||
"version" = @version
|
||||
WHERE
|
||||
-- Only ones with the same tags are allowed clobber
|
||||
provisioner_daemons.tags <@ @tags :: jsonb
|
||||
RETURNING *;
|
||||
|
|
|
@ -27,7 +27,6 @@ const (
|
|||
UniqueParameterSchemasPkey UniqueConstraint = "parameter_schemas_pkey" // ALTER TABLE ONLY parameter_schemas ADD CONSTRAINT parameter_schemas_pkey PRIMARY KEY (id);
|
||||
UniqueParameterValuesPkey UniqueConstraint = "parameter_values_pkey" // ALTER TABLE ONLY parameter_values ADD CONSTRAINT parameter_values_pkey PRIMARY KEY (id);
|
||||
UniqueParameterValuesScopeIDNameKey UniqueConstraint = "parameter_values_scope_id_name_key" // ALTER TABLE ONLY parameter_values ADD CONSTRAINT parameter_values_scope_id_name_key UNIQUE (scope_id, name);
|
||||
UniqueProvisionerDaemonsNameKey UniqueConstraint = "provisioner_daemons_name_key" // ALTER TABLE ONLY provisioner_daemons ADD CONSTRAINT provisioner_daemons_name_key UNIQUE (name);
|
||||
UniqueProvisionerDaemonsPkey UniqueConstraint = "provisioner_daemons_pkey" // ALTER TABLE ONLY provisioner_daemons ADD CONSTRAINT provisioner_daemons_pkey PRIMARY KEY (id);
|
||||
UniqueProvisionerJobLogsPkey UniqueConstraint = "provisioner_job_logs_pkey" // ALTER TABLE ONLY provisioner_job_logs ADD CONSTRAINT provisioner_job_logs_pkey PRIMARY KEY (id);
|
||||
UniqueProvisionerJobsPkey UniqueConstraint = "provisioner_jobs_pkey" // ALTER TABLE ONLY provisioner_jobs ADD CONSTRAINT provisioner_jobs_pkey PRIMARY KEY (id);
|
||||
|
@ -66,6 +65,7 @@ const (
|
|||
UniqueIndexAPIKeyName UniqueConstraint = "idx_api_key_name" // CREATE UNIQUE INDEX idx_api_key_name ON api_keys USING btree (user_id, token_name) WHERE (login_type = 'token'::login_type);
|
||||
UniqueIndexOrganizationName UniqueConstraint = "idx_organization_name" // CREATE UNIQUE INDEX idx_organization_name ON organizations USING btree (name);
|
||||
UniqueIndexOrganizationNameLower UniqueConstraint = "idx_organization_name_lower" // CREATE UNIQUE INDEX idx_organization_name_lower ON organizations USING btree (lower(name));
|
||||
UniqueIndexProvisionerDaemonsNameOwnerKey UniqueConstraint = "idx_provisioner_daemons_name_owner_key" // CREATE UNIQUE INDEX idx_provisioner_daemons_name_owner_key ON provisioner_daemons USING btree (name, lower((tags ->> 'owner'::text)));
|
||||
UniqueIndexUsersEmail UniqueConstraint = "idx_users_email" // CREATE UNIQUE INDEX idx_users_email ON users USING btree (email) WHERE (deleted = false);
|
||||
UniqueIndexUsersUsername UniqueConstraint = "idx_users_username" // CREATE UNIQUE INDEX idx_users_username ON users USING btree (username) WHERE (deleted = false);
|
||||
UniqueTemplatesOrganizationIDNameIndex UniqueConstraint = "templates_organization_id_name_idx" // CREATE UNIQUE INDEX templates_organization_id_name_idx ON templates USING btree (organization_id, lower((name)::text)) WHERE (deleted = false);
|
||||
|
|
|
@ -14,6 +14,7 @@ const (
|
|||
// If the scope is "user", the "owner" is changed to the user ID.
|
||||
// This is for user-scoped provisioner daemons, where users should
|
||||
// own their own operations.
|
||||
// Otherwise, the "owner" tag is always empty.
|
||||
func MutateTags(userID uuid.UUID, tags map[string]string) map[string]string {
|
||||
if tags == nil {
|
||||
tags = map[string]string{}
|
||||
|
@ -21,11 +22,13 @@ func MutateTags(userID uuid.UUID, tags map[string]string) map[string]string {
|
|||
_, ok := tags[TagScope]
|
||||
if !ok {
|
||||
tags[TagScope] = ScopeOrganization
|
||||
delete(tags, TagOwner)
|
||||
}
|
||||
switch tags[TagScope] {
|
||||
case ScopeUser:
|
||||
tags[TagOwner] = userID.String()
|
||||
case ScopeOrganization:
|
||||
delete(tags, TagOwner)
|
||||
default:
|
||||
tags[TagScope] = ScopeOrganization
|
||||
}
|
||||
|
|
|
@ -54,6 +54,27 @@ func TestMutateTags(t *testing.T) {
|
|||
provisionersdk.TagScope: provisionersdk.ScopeOrganization,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "organization scope with owner",
|
||||
tags: map[string]string{
|
||||
provisionersdk.TagScope: provisionersdk.ScopeOrganization,
|
||||
provisionersdk.TagOwner: testUserID.String(),
|
||||
},
|
||||
userID: uuid.Nil,
|
||||
want: map[string]string{
|
||||
provisionersdk.TagScope: provisionersdk.ScopeOrganization,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "owner tag with no other context",
|
||||
tags: map[string]string{
|
||||
provisionersdk.TagOwner: testUserID.String(),
|
||||
},
|
||||
userID: uuid.Nil,
|
||||
want: map[string]string{
|
||||
provisionersdk.TagScope: provisionersdk.ScopeOrganization,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid scope",
|
||||
tags: map[string]string{provisionersdk.TagScope: "360noscope"},
|
||||
|
|
Loading…
Reference in New Issue