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:
Steven Masley 2024-03-06 12:04:50 -06:00 committed by GitHub
parent 46a2ff1061
commit b5f866c1cb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 91 additions and 44 deletions

View File

@ -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,
},

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -0,0 +1,2 @@
ALTER TABLE provisioner_daemons
DROP COLUMN organization_id;

View File

@ -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;

View File

@ -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 {

View File

@ -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
}

View File

@ -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

View File

@ -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) {