mirror of https://github.com/coder/coder.git
chore: add organization_id column to provisioner daemons (#12356)
* chore: add organization_id column to provisioner daemons * Update upsert to include organization id on set
This commit is contained in:
parent
46a2ff1061
commit
b5f866c1cb
|
@ -1239,10 +1239,18 @@ func (api *API) CreateInMemoryProvisionerDaemon(dialCtx context.Context, name st
|
|||
}
|
||||
}()
|
||||
|
||||
// All in memory provisioners will be part of the default org for now.
|
||||
//nolint:gocritic // in-memory provisioners are owned by system
|
||||
defaultOrg, err := api.Database.GetDefaultOrganization(dbauthz.AsSystemRestricted(dialCtx))
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("unable to fetch default org for in memory provisioner: %w", err)
|
||||
}
|
||||
|
||||
//nolint:gocritic // in-memory provisioners are owned by system
|
||||
daemon, err := api.Database.UpsertProvisionerDaemon(dbauthz.AsSystemRestricted(dialCtx), database.UpsertProvisionerDaemonParams{
|
||||
Name: name,
|
||||
CreatedAt: dbtime.Now(),
|
||||
Name: name,
|
||||
OrganizationID: defaultOrg.ID,
|
||||
CreatedAt: dbtime.Now(),
|
||||
Provisioners: []database.ProvisionerType{
|
||||
database.ProvisionerTypeEcho, database.ProvisionerTypeTerraform,
|
||||
},
|
||||
|
|
|
@ -203,6 +203,7 @@ func TestDeleteOldProvisionerDaemons(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
db, _ := dbtestutil.NewDB(t)
|
||||
defaultOrg := dbgen.Organization(t, db, database.Organization{})
|
||||
logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true})
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
|
||||
|
@ -213,24 +214,26 @@ func TestDeleteOldProvisionerDaemons(t *testing.T) {
|
|||
// given
|
||||
_, err := db.UpsertProvisionerDaemon(ctx, database.UpsertProvisionerDaemonParams{
|
||||
// Provisioner daemon created 14 days ago, and checked in just before 7 days deadline.
|
||||
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)},
|
||||
Version: "1.0.0",
|
||||
APIVersion: proto.CurrentVersion.String(),
|
||||
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)},
|
||||
Version: "1.0.0",
|
||||
APIVersion: proto.CurrentVersion.String(),
|
||||
OrganizationID: defaultOrg.ID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
_, err = db.UpsertProvisionerDaemon(ctx, database.UpsertProvisionerDaemonParams{
|
||||
// Provisioner daemon created 8 days ago, and checked in last time an hour after creation.
|
||||
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)},
|
||||
Version: "1.0.0",
|
||||
APIVersion: proto.CurrentVersion.String(),
|
||||
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)},
|
||||
Version: "1.0.0",
|
||||
APIVersion: proto.CurrentVersion.String(),
|
||||
OrganizationID: defaultOrg.ID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
_, err = db.UpsertProvisionerDaemon(ctx, database.UpsertProvisionerDaemonParams{
|
||||
|
@ -241,9 +244,10 @@ func TestDeleteOldProvisionerDaemons(t *testing.T) {
|
|||
provisionersdk.TagScope: provisionersdk.ScopeUser,
|
||||
provisionersdk.TagOwner: uuid.NewString(),
|
||||
},
|
||||
CreatedAt: now.Add(-9 * 24 * time.Hour),
|
||||
Version: "1.0.0",
|
||||
APIVersion: proto.CurrentVersion.String(),
|
||||
CreatedAt: now.Add(-9 * 24 * time.Hour),
|
||||
Version: "1.0.0",
|
||||
APIVersion: proto.CurrentVersion.String(),
|
||||
OrganizationID: defaultOrg.ID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
_, err = db.UpsertProvisionerDaemon(ctx, database.UpsertProvisionerDaemonParams{
|
||||
|
@ -254,10 +258,11 @@ func TestDeleteOldProvisionerDaemons(t *testing.T) {
|
|||
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)},
|
||||
Version: "1.0.0",
|
||||
APIVersion: proto.CurrentVersion.String(),
|
||||
CreatedAt: now.Add(-6 * 24 * time.Hour),
|
||||
LastSeenAt: sql.NullTime{Valid: true, Time: now.Add(-6 * 24 * time.Hour)},
|
||||
Version: "1.0.0",
|
||||
APIVersion: proto.CurrentVersion.String(),
|
||||
OrganizationID: defaultOrg.ID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
|
|
|
@ -614,7 +614,8 @@ CREATE TABLE provisioner_daemons (
|
|||
tags jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
last_seen_at timestamp with time zone,
|
||||
version text DEFAULT ''::text NOT NULL,
|
||||
api_version text DEFAULT '1.0'::text NOT NULL
|
||||
api_version text DEFAULT '1.0'::text NOT NULL,
|
||||
organization_id uuid NOT NULL
|
||||
);
|
||||
|
||||
COMMENT ON COLUMN provisioner_daemons.api_version IS 'The API version of the provisioner daemon';
|
||||
|
@ -1688,6 +1689,9 @@ ALTER TABLE ONLY organization_members
|
|||
ALTER TABLE ONLY parameter_schemas
|
||||
ADD CONSTRAINT parameter_schemas_job_id_fkey FOREIGN KEY (job_id) REFERENCES provisioner_jobs(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY provisioner_daemons
|
||||
ADD CONSTRAINT provisioner_daemons_organization_id_fkey FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY provisioner_job_logs
|
||||
ADD CONSTRAINT provisioner_job_logs_job_id_fkey FOREIGN KEY (job_id) REFERENCES provisioner_jobs(id) ON DELETE CASCADE;
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ const (
|
|||
ForeignKeyOrganizationMembersOrganizationIDUUID ForeignKeyConstraint = "organization_members_organization_id_uuid_fkey" // ALTER TABLE ONLY organization_members ADD CONSTRAINT organization_members_organization_id_uuid_fkey FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE;
|
||||
ForeignKeyOrganizationMembersUserIDUUID ForeignKeyConstraint = "organization_members_user_id_uuid_fkey" // ALTER TABLE ONLY organization_members ADD CONSTRAINT organization_members_user_id_uuid_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
|
||||
ForeignKeyParameterSchemasJobID ForeignKeyConstraint = "parameter_schemas_job_id_fkey" // ALTER TABLE ONLY parameter_schemas ADD CONSTRAINT parameter_schemas_job_id_fkey FOREIGN KEY (job_id) REFERENCES provisioner_jobs(id) ON DELETE CASCADE;
|
||||
ForeignKeyProvisionerDaemonsOrganizationID ForeignKeyConstraint = "provisioner_daemons_organization_id_fkey" // ALTER TABLE ONLY provisioner_daemons ADD CONSTRAINT provisioner_daemons_organization_id_fkey FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE;
|
||||
ForeignKeyProvisionerJobLogsJobID ForeignKeyConstraint = "provisioner_job_logs_job_id_fkey" // ALTER TABLE ONLY provisioner_job_logs ADD CONSTRAINT provisioner_job_logs_job_id_fkey FOREIGN KEY (job_id) REFERENCES provisioner_jobs(id) ON DELETE CASCADE;
|
||||
ForeignKeyProvisionerJobsOrganizationID ForeignKeyConstraint = "provisioner_jobs_organization_id_fkey" // ALTER TABLE ONLY provisioner_jobs ADD CONSTRAINT provisioner_jobs_organization_id_fkey FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE;
|
||||
ForeignKeyTailnetAgentsCoordinatorID ForeignKeyConstraint = "tailnet_agents_coordinator_id_fkey" // ALTER TABLE ONLY tailnet_agents ADD CONSTRAINT tailnet_agents_coordinator_id_fkey FOREIGN KEY (coordinator_id) REFERENCES tailnet_coordinators(id) ON DELETE CASCADE;
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE provisioner_daemons
|
||||
DROP COLUMN organization_id;
|
|
@ -0,0 +1,14 @@
|
|||
-- At the time of this migration, only 1 org is expected in a deployment.
|
||||
-- In the future when multi-org is more common, there might be a use case
|
||||
-- to allow a provisioner to be associated with multiple orgs.
|
||||
ALTER TABLE provisioner_daemons
|
||||
ADD COLUMN organization_id UUID REFERENCES organizations(id) ON DELETE CASCADE;
|
||||
|
||||
UPDATE
|
||||
provisioner_daemons
|
||||
SET
|
||||
-- Default to the first org
|
||||
organization_id = (SELECT id FROM organizations WHERE is_default = true LIMIT 1 );
|
||||
|
||||
ALTER TABLE provisioner_daemons
|
||||
ALTER COLUMN organization_id SET NOT NULL;
|
|
@ -1966,7 +1966,8 @@ type ProvisionerDaemon struct {
|
|||
LastSeenAt sql.NullTime `db:"last_seen_at" json:"last_seen_at"`
|
||||
Version string `db:"version" json:"version"`
|
||||
// The API version of the provisioner daemon
|
||||
APIVersion string `db:"api_version" json:"api_version"`
|
||||
APIVersion string `db:"api_version" json:"api_version"`
|
||||
OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"`
|
||||
}
|
||||
|
||||
type ProvisionerJob struct {
|
||||
|
|
|
@ -3686,7 +3686,7 @@ func (q *sqlQuerier) DeleteOldProvisionerDaemons(ctx context.Context) error {
|
|||
|
||||
const getProvisionerDaemons = `-- name: GetProvisionerDaemons :many
|
||||
SELECT
|
||||
id, created_at, name, provisioners, replica_id, tags, last_seen_at, version, api_version
|
||||
id, created_at, name, provisioners, replica_id, tags, last_seen_at, version, api_version, organization_id
|
||||
FROM
|
||||
provisioner_daemons
|
||||
`
|
||||
|
@ -3710,6 +3710,7 @@ func (q *sqlQuerier) GetProvisionerDaemons(ctx context.Context) ([]ProvisionerDa
|
|||
&i.LastSeenAt,
|
||||
&i.Version,
|
||||
&i.APIVersion,
|
||||
&i.OrganizationID,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -3754,6 +3755,7 @@ INSERT INTO
|
|||
tags,
|
||||
last_seen_at,
|
||||
"version",
|
||||
organization_id,
|
||||
api_version
|
||||
)
|
||||
VALUES (
|
||||
|
@ -3764,27 +3766,30 @@ VALUES (
|
|||
$4,
|
||||
$5,
|
||||
$6,
|
||||
$7
|
||||
$7,
|
||||
$8
|
||||
) ON CONFLICT("name", LOWER(COALESCE(tags ->> 'owner'::text, ''::text))) DO UPDATE SET
|
||||
provisioners = $3,
|
||||
tags = $4,
|
||||
last_seen_at = $5,
|
||||
"version" = $6,
|
||||
api_version = $7
|
||||
api_version = $8,
|
||||
organization_id = $7
|
||||
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, api_version
|
||||
RETURNING id, created_at, name, provisioners, replica_id, tags, last_seen_at, version, api_version, organization_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"`
|
||||
APIVersion string `db:"api_version" json:"api_version"`
|
||||
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"`
|
||||
OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"`
|
||||
APIVersion string `db:"api_version" json:"api_version"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) UpsertProvisionerDaemon(ctx context.Context, arg UpsertProvisionerDaemonParams) (ProvisionerDaemon, error) {
|
||||
|
@ -3795,6 +3800,7 @@ func (q *sqlQuerier) UpsertProvisionerDaemon(ctx context.Context, arg UpsertProv
|
|||
arg.Tags,
|
||||
arg.LastSeenAt,
|
||||
arg.Version,
|
||||
arg.OrganizationID,
|
||||
arg.APIVersion,
|
||||
)
|
||||
var i ProvisionerDaemon
|
||||
|
@ -3808,6 +3814,7 @@ func (q *sqlQuerier) UpsertProvisionerDaemon(ctx context.Context, arg UpsertProv
|
|||
&i.LastSeenAt,
|
||||
&i.Version,
|
||||
&i.APIVersion,
|
||||
&i.OrganizationID,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ INSERT INTO
|
|||
tags,
|
||||
last_seen_at,
|
||||
"version",
|
||||
organization_id,
|
||||
api_version
|
||||
)
|
||||
VALUES (
|
||||
|
@ -34,13 +35,15 @@ VALUES (
|
|||
@tags,
|
||||
@last_seen_at,
|
||||
@version,
|
||||
@organization_id,
|
||||
@api_version
|
||||
) ON CONFLICT("name", LOWER(COALESCE(tags ->> 'owner'::text, ''::text))) DO UPDATE SET
|
||||
provisioners = @provisioners,
|
||||
tags = @tags,
|
||||
last_seen_at = @last_seen_at,
|
||||
"version" = @version,
|
||||
api_version = @api_version
|
||||
api_version = @api_version,
|
||||
organization_id = @organization_id
|
||||
WHERE
|
||||
-- Only ones with the same tags are allowed clobber
|
||||
provisioner_daemons.tags <@ @tags :: jsonb
|
||||
|
|
|
@ -134,6 +134,7 @@ func (p *provisionerDaemonAuth) authorize(r *http.Request, tags map[string]strin
|
|||
// @Router /organizations/{organization}/provisionerdaemons/serve [get]
|
||||
func (api *API) provisionerDaemonServe(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
organization := httpmw.OrganizationParam(r)
|
||||
|
||||
tags := map[string]string{}
|
||||
if r.URL.Query().Has("tag") {
|
||||
|
@ -246,13 +247,14 @@ func (api *API) provisionerDaemonServe(rw http.ResponseWriter, r *http.Request)
|
|||
// Create the daemon in the database.
|
||||
now := dbtime.Now()
|
||||
daemon, err := api.Database.UpsertProvisionerDaemon(authCtx, database.UpsertProvisionerDaemonParams{
|
||||
Name: name,
|
||||
Provisioners: provisioners,
|
||||
Tags: tags,
|
||||
CreatedAt: now,
|
||||
LastSeenAt: sql.NullTime{Time: now, Valid: true},
|
||||
Version: versionHdrVal,
|
||||
APIVersion: apiVersion,
|
||||
Name: name,
|
||||
Provisioners: provisioners,
|
||||
Tags: tags,
|
||||
CreatedAt: now,
|
||||
LastSeenAt: sql.NullTime{Time: now, Valid: true},
|
||||
Version: versionHdrVal,
|
||||
APIVersion: apiVersion,
|
||||
OrganizationID: organization.ID,
|
||||
})
|
||||
if err != nil {
|
||||
if !xerrors.Is(err, context.Canceled) {
|
||||
|
|
Loading…
Reference in New Issue