feat: add managed agent license limit checks (#18937)

- Adds a query for counting managed agent workspace builds between two
timestamps
- The "Actual" field in the feature entitlement for managed agents is
now populated with the value read from the database
- The wsbuilder package now validates AI agent usage against the limit
when a license is installed

Closes coder/internal#777
This commit is contained in:
Dean Sheather
2025-07-22 13:39:26 +10:00
committed by GitHub
parent aa1a985381
commit 9a6dd73f68
24 changed files with 586 additions and 74 deletions
+38
View File
@@ -4286,6 +4286,44 @@ func (q *sqlQuerier) GetLicenses(ctx context.Context) ([]License, error) {
return items, nil
}
const getManagedAgentCount = `-- name: GetManagedAgentCount :one
SELECT
COUNT(DISTINCT wb.id) AS count
FROM
workspace_builds AS wb
JOIN
provisioner_jobs AS pj
ON
wb.job_id = pj.id
WHERE
wb.transition = 'start'::workspace_transition
AND wb.has_ai_task = true
-- Only count jobs that are pending, running or succeeded. Other statuses
-- like cancel(ed|ing), failed or unknown are not considered as managed
-- agent usage. These workspace builds are typically unusable anyway.
AND pj.job_status IN (
'pending'::provisioner_job_status,
'running'::provisioner_job_status,
'succeeded'::provisioner_job_status
)
-- Jobs are counted at the time they are created, not when they are
-- completed, as pending jobs haven't completed yet.
AND wb.created_at BETWEEN $1::timestamptz AND $2::timestamptz
`
type GetManagedAgentCountParams struct {
StartTime time.Time `db:"start_time" json:"start_time"`
EndTime time.Time `db:"end_time" json:"end_time"`
}
// This isn't strictly a license query, but it's related to license enforcement.
func (q *sqlQuerier) GetManagedAgentCount(ctx context.Context, arg GetManagedAgentCountParams) (int64, error) {
row := q.db.QueryRowContext(ctx, getManagedAgentCount, arg.StartTime, arg.EndTime)
var count int64
err := row.Scan(&count)
return count, err
}
const getUnexpiredLicenses = `-- name: GetUnexpiredLicenses :many
SELECT id, uploaded_at, jwt, exp, uuid
FROM licenses