mirror of
https://github.com/coder/coder.git
synced 2025-07-15 22:20:27 +00:00
feat: add agent metadata (#6614)
This commit is contained in:
@ -1564,6 +1564,44 @@ func (q *querier) InsertWorkspaceAgentStat(ctx context.Context, arg database.Ins
|
||||
return q.db.InsertWorkspaceAgentStat(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) InsertWorkspaceAgentMetadata(ctx context.Context, arg database.InsertWorkspaceAgentMetadataParams) error {
|
||||
// We don't check for workspace ownership here since the agent metadata may
|
||||
// be associated with an orphaned agent used by a dry run build.
|
||||
if err := q.authorizeContext(ctx, rbac.ActionCreate, rbac.ResourceSystem); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return q.db.InsertWorkspaceAgentMetadata(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) UpdateWorkspaceAgentMetadata(ctx context.Context, arg database.UpdateWorkspaceAgentMetadataParams) error {
|
||||
workspace, err := q.db.GetWorkspaceByAgentID(ctx, arg.WorkspaceAgentID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = q.authorizeContext(ctx, rbac.ActionUpdate, workspace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return q.db.UpdateWorkspaceAgentMetadata(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) GetWorkspaceAgentMetadata(ctx context.Context, workspaceAgentID uuid.UUID) ([]database.WorkspaceAgentMetadatum, error) {
|
||||
workspace, err := q.db.GetWorkspaceByAgentID(ctx, workspaceAgentID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = q.authorizeContext(ctx, rbac.ActionRead, workspace)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return q.db.GetWorkspaceAgentMetadata(ctx, workspaceAgentID)
|
||||
}
|
||||
|
||||
func (q *querier) UpdateWorkspaceAppHealthByID(ctx context.Context, arg database.UpdateWorkspaceAppHealthByIDParams) error {
|
||||
// TODO: This is a workspace agent operation. Should users be able to query this?
|
||||
workspace, err := q.db.GetWorkspaceByWorkspaceAppID(ctx, arg.ID)
|
||||
|
@ -124,6 +124,7 @@ type data struct {
|
||||
templateVersionVariables []database.TemplateVersionVariable
|
||||
templates []database.Template
|
||||
workspaceAgents []database.WorkspaceAgent
|
||||
workspaceAgentMetadata []database.WorkspaceAgentMetadatum
|
||||
workspaceAgentLogs []database.WorkspaceAgentStartupLog
|
||||
workspaceApps []database.WorkspaceApp
|
||||
workspaceBuilds []database.WorkspaceBuild
|
||||
@ -2741,6 +2742,60 @@ func (q *fakeQuerier) InsertAPIKey(_ context.Context, arg database.InsertAPIKeyP
|
||||
return key, nil
|
||||
}
|
||||
|
||||
func (q *fakeQuerier) UpdateWorkspaceAgentMetadata(_ context.Context, arg database.UpdateWorkspaceAgentMetadataParams) error {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
|
||||
//nolint:gosimple
|
||||
updated := database.WorkspaceAgentMetadatum{
|
||||
WorkspaceAgentID: arg.WorkspaceAgentID,
|
||||
Key: arg.Key,
|
||||
Value: arg.Value,
|
||||
Error: arg.Error,
|
||||
CollectedAt: arg.CollectedAt,
|
||||
}
|
||||
|
||||
for i, m := range q.workspaceAgentMetadata {
|
||||
if m.WorkspaceAgentID == arg.WorkspaceAgentID && m.Key == arg.Key {
|
||||
q.workspaceAgentMetadata[i] = updated
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *fakeQuerier) InsertWorkspaceAgentMetadata(_ context.Context, arg database.InsertWorkspaceAgentMetadataParams) error {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
|
||||
//nolint:gosimple
|
||||
metadatum := database.WorkspaceAgentMetadatum{
|
||||
WorkspaceAgentID: arg.WorkspaceAgentID,
|
||||
Script: arg.Script,
|
||||
DisplayName: arg.DisplayName,
|
||||
Key: arg.Key,
|
||||
Timeout: arg.Timeout,
|
||||
Interval: arg.Interval,
|
||||
}
|
||||
|
||||
q.workspaceAgentMetadata = append(q.workspaceAgentMetadata, metadatum)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *fakeQuerier) GetWorkspaceAgentMetadata(_ context.Context, workspaceAgentID uuid.UUID) ([]database.WorkspaceAgentMetadatum, error) {
|
||||
q.mutex.RLock()
|
||||
defer q.mutex.RUnlock()
|
||||
|
||||
metadata := make([]database.WorkspaceAgentMetadatum, 0)
|
||||
for _, m := range q.workspaceAgentMetadata {
|
||||
if m.WorkspaceAgentID == workspaceAgentID {
|
||||
metadata = append(metadata, m)
|
||||
}
|
||||
}
|
||||
return metadata, nil
|
||||
}
|
||||
|
||||
func (q *fakeQuerier) InsertFile(_ context.Context, arg database.InsertFileParams) (database.File, error) {
|
||||
if err := validateDatabaseType(arg); err != nil {
|
||||
return database.File{}, err
|
||||
|
18
coderd/database/dump.sql
generated
18
coderd/database/dump.sql
generated
@ -475,6 +475,18 @@ CREATE TABLE users (
|
||||
last_seen_at timestamp without time zone DEFAULT '0001-01-01 00:00:00'::timestamp without time zone NOT NULL
|
||||
);
|
||||
|
||||
CREATE UNLOGGED TABLE workspace_agent_metadata (
|
||||
workspace_agent_id uuid NOT NULL,
|
||||
display_name character varying(127) NOT NULL,
|
||||
key character varying(127) NOT NULL,
|
||||
script character varying(65535) NOT NULL,
|
||||
value character varying(65535) DEFAULT ''::character varying NOT NULL,
|
||||
error character varying(65535) DEFAULT ''::character varying NOT NULL,
|
||||
timeout bigint NOT NULL,
|
||||
"interval" bigint NOT NULL,
|
||||
collected_at timestamp with time zone DEFAULT '0001-01-01 00:00:00+00'::timestamp with time zone NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE workspace_agent_startup_logs (
|
||||
agent_id uuid NOT NULL,
|
||||
created_at timestamp with time zone NOT NULL,
|
||||
@ -756,6 +768,9 @@ ALTER TABLE ONLY user_links
|
||||
ALTER TABLE ONLY users
|
||||
ADD CONSTRAINT users_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY workspace_agent_metadata
|
||||
ADD CONSTRAINT workspace_agent_metadata_pkey PRIMARY KEY (workspace_agent_id, key);
|
||||
|
||||
ALTER TABLE ONLY workspace_agent_startup_logs
|
||||
ADD CONSTRAINT workspace_agent_startup_logs_pkey PRIMARY KEY (id);
|
||||
|
||||
@ -894,6 +909,9 @@ ALTER TABLE ONLY templates
|
||||
ALTER TABLE ONLY user_links
|
||||
ADD CONSTRAINT user_links_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY workspace_agent_metadata
|
||||
ADD CONSTRAINT workspace_agent_metadata_workspace_agent_id_fkey FOREIGN KEY (workspace_agent_id) REFERENCES workspace_agents(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY workspace_agent_startup_logs
|
||||
ADD CONSTRAINT workspace_agent_startup_logs_agent_id_fkey FOREIGN KEY (agent_id) REFERENCES workspace_agents(id) ON DELETE CASCADE;
|
||||
|
||||
|
@ -0,0 +1 @@
|
||||
DROP TABLE workspace_agent_metadata;
|
@ -0,0 +1,16 @@
|
||||
-- This table is UNLOGGED because it is very update-heavy and the the data
|
||||
-- is not valuable enough to justify the overhead of WAL logging. This should
|
||||
-- give us a ~70% improvement in write throughput.
|
||||
CREATE UNLOGGED TABLE workspace_agent_metadata (
|
||||
workspace_agent_id uuid NOT NULL,
|
||||
display_name varchar(127) NOT NULL,
|
||||
key varchar(127) NOT NULL,
|
||||
script varchar(65535) NOT NULL,
|
||||
value varchar(65535) NOT NULL DEFAULT '',
|
||||
error varchar(65535) NOT NULL DEFAULT '',
|
||||
timeout bigint NOT NULL,
|
||||
interval bigint NOT NULL,
|
||||
collected_at timestamp with time zone NOT NULL DEFAULT '0001-01-01 00:00:00+00',
|
||||
PRIMARY KEY (workspace_agent_id, key),
|
||||
FOREIGN KEY (workspace_agent_id) REFERENCES workspace_agents(id) ON DELETE CASCADE
|
||||
);
|
18
coderd/database/migrations/testdata/fixtures/000111_workspace_agent_metadata.up.sql
vendored
Normal file
18
coderd/database/migrations/testdata/fixtures/000111_workspace_agent_metadata.up.sql
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
INSERT INTO
|
||||
workspace_agent_metadata (
|
||||
workspace_agent_id,
|
||||
display_name,
|
||||
key,
|
||||
script,
|
||||
timeout,
|
||||
interval
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
'45e89705-e09d-4850-bcec-f9a937f5d78d',
|
||||
'a h e m',
|
||||
'ahem',
|
||||
'rm -rf',
|
||||
3,
|
||||
1
|
||||
);
|
@ -1575,6 +1575,18 @@ type WorkspaceAgent struct {
|
||||
StartupLogsOverflowed bool `db:"startup_logs_overflowed" json:"startup_logs_overflowed"`
|
||||
}
|
||||
|
||||
type WorkspaceAgentMetadatum struct {
|
||||
WorkspaceAgentID uuid.UUID `db:"workspace_agent_id" json:"workspace_agent_id"`
|
||||
DisplayName string `db:"display_name" json:"display_name"`
|
||||
Key string `db:"key" json:"key"`
|
||||
Script string `db:"script" json:"script"`
|
||||
Value string `db:"value" json:"value"`
|
||||
Error string `db:"error" json:"error"`
|
||||
Timeout int64 `db:"timeout" json:"timeout"`
|
||||
Interval int64 `db:"interval" json:"interval"`
|
||||
CollectedAt time.Time `db:"collected_at" json:"collected_at"`
|
||||
}
|
||||
|
||||
type WorkspaceAgentStartupLog struct {
|
||||
AgentID uuid.UUID `db:"agent_id" json:"agent_id"`
|
||||
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
||||
|
@ -126,6 +126,7 @@ type sqlcQuerier interface {
|
||||
GetWorkspaceAgentByAuthToken(ctx context.Context, authToken uuid.UUID) (WorkspaceAgent, error)
|
||||
GetWorkspaceAgentByID(ctx context.Context, id uuid.UUID) (WorkspaceAgent, error)
|
||||
GetWorkspaceAgentByInstanceID(ctx context.Context, authInstanceID string) (WorkspaceAgent, error)
|
||||
GetWorkspaceAgentMetadata(ctx context.Context, workspaceAgentID uuid.UUID) ([]WorkspaceAgentMetadatum, error)
|
||||
GetWorkspaceAgentStartupLogsAfter(ctx context.Context, arg GetWorkspaceAgentStartupLogsAfterParams) ([]WorkspaceAgentStartupLog, error)
|
||||
GetWorkspaceAgentStats(ctx context.Context, createdAt time.Time) ([]GetWorkspaceAgentStatsRow, error)
|
||||
GetWorkspaceAgentsByResourceIDs(ctx context.Context, ids []uuid.UUID) ([]WorkspaceAgent, error)
|
||||
@ -185,6 +186,7 @@ type sqlcQuerier interface {
|
||||
InsertUserLink(ctx context.Context, arg InsertUserLinkParams) (UserLink, error)
|
||||
InsertWorkspace(ctx context.Context, arg InsertWorkspaceParams) (Workspace, error)
|
||||
InsertWorkspaceAgent(ctx context.Context, arg InsertWorkspaceAgentParams) (WorkspaceAgent, error)
|
||||
InsertWorkspaceAgentMetadata(ctx context.Context, arg InsertWorkspaceAgentMetadataParams) error
|
||||
InsertWorkspaceAgentStartupLogs(ctx context.Context, arg InsertWorkspaceAgentStartupLogsParams) ([]WorkspaceAgentStartupLog, error)
|
||||
InsertWorkspaceAgentStat(ctx context.Context, arg InsertWorkspaceAgentStatParams) (WorkspaceAgentStat, error)
|
||||
InsertWorkspaceApp(ctx context.Context, arg InsertWorkspaceAppParams) (WorkspaceApp, error)
|
||||
@ -229,6 +231,7 @@ type sqlcQuerier interface {
|
||||
UpdateWorkspace(ctx context.Context, arg UpdateWorkspaceParams) (Workspace, error)
|
||||
UpdateWorkspaceAgentConnectionByID(ctx context.Context, arg UpdateWorkspaceAgentConnectionByIDParams) error
|
||||
UpdateWorkspaceAgentLifecycleStateByID(ctx context.Context, arg UpdateWorkspaceAgentLifecycleStateByIDParams) error
|
||||
UpdateWorkspaceAgentMetadata(ctx context.Context, arg UpdateWorkspaceAgentMetadataParams) error
|
||||
UpdateWorkspaceAgentStartupByID(ctx context.Context, arg UpdateWorkspaceAgentStartupByIDParams) error
|
||||
UpdateWorkspaceAgentStartupLogOverflowByID(ctx context.Context, arg UpdateWorkspaceAgentStartupLogOverflowByIDParams) error
|
||||
UpdateWorkspaceAppHealthByID(ctx context.Context, arg UpdateWorkspaceAppHealthByIDParams) error
|
||||
|
@ -5297,6 +5297,48 @@ func (q *sqlQuerier) GetWorkspaceAgentByInstanceID(ctx context.Context, authInst
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getWorkspaceAgentMetadata = `-- name: GetWorkspaceAgentMetadata :many
|
||||
SELECT
|
||||
workspace_agent_id, display_name, key, script, value, error, timeout, interval, collected_at
|
||||
FROM
|
||||
workspace_agent_metadata
|
||||
WHERE
|
||||
workspace_agent_id = $1
|
||||
`
|
||||
|
||||
func (q *sqlQuerier) GetWorkspaceAgentMetadata(ctx context.Context, workspaceAgentID uuid.UUID) ([]WorkspaceAgentMetadatum, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getWorkspaceAgentMetadata, workspaceAgentID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []WorkspaceAgentMetadatum
|
||||
for rows.Next() {
|
||||
var i WorkspaceAgentMetadatum
|
||||
if err := rows.Scan(
|
||||
&i.WorkspaceAgentID,
|
||||
&i.DisplayName,
|
||||
&i.Key,
|
||||
&i.Script,
|
||||
&i.Value,
|
||||
&i.Error,
|
||||
&i.Timeout,
|
||||
&i.Interval,
|
||||
&i.CollectedAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getWorkspaceAgentStartupLogsAfter = `-- name: GetWorkspaceAgentStartupLogsAfter :many
|
||||
SELECT
|
||||
agent_id, created_at, output, id
|
||||
@ -5651,6 +5693,41 @@ func (q *sqlQuerier) InsertWorkspaceAgent(ctx context.Context, arg InsertWorkspa
|
||||
return i, err
|
||||
}
|
||||
|
||||
const insertWorkspaceAgentMetadata = `-- name: InsertWorkspaceAgentMetadata :exec
|
||||
INSERT INTO
|
||||
workspace_agent_metadata (
|
||||
workspace_agent_id,
|
||||
display_name,
|
||||
key,
|
||||
script,
|
||||
timeout,
|
||||
interval
|
||||
)
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5, $6)
|
||||
`
|
||||
|
||||
type InsertWorkspaceAgentMetadataParams struct {
|
||||
WorkspaceAgentID uuid.UUID `db:"workspace_agent_id" json:"workspace_agent_id"`
|
||||
DisplayName string `db:"display_name" json:"display_name"`
|
||||
Key string `db:"key" json:"key"`
|
||||
Script string `db:"script" json:"script"`
|
||||
Timeout int64 `db:"timeout" json:"timeout"`
|
||||
Interval int64 `db:"interval" json:"interval"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) InsertWorkspaceAgentMetadata(ctx context.Context, arg InsertWorkspaceAgentMetadataParams) error {
|
||||
_, err := q.db.ExecContext(ctx, insertWorkspaceAgentMetadata,
|
||||
arg.WorkspaceAgentID,
|
||||
arg.DisplayName,
|
||||
arg.Key,
|
||||
arg.Script,
|
||||
arg.Timeout,
|
||||
arg.Interval,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
const insertWorkspaceAgentStartupLogs = `-- name: InsertWorkspaceAgentStartupLogs :many
|
||||
WITH new_length AS (
|
||||
UPDATE workspace_agents SET
|
||||
@ -5758,6 +5835,37 @@ func (q *sqlQuerier) UpdateWorkspaceAgentLifecycleStateByID(ctx context.Context,
|
||||
return err
|
||||
}
|
||||
|
||||
const updateWorkspaceAgentMetadata = `-- name: UpdateWorkspaceAgentMetadata :exec
|
||||
UPDATE
|
||||
workspace_agent_metadata
|
||||
SET
|
||||
value = $3,
|
||||
error = $4,
|
||||
collected_at = $5
|
||||
WHERE
|
||||
workspace_agent_id = $1
|
||||
AND key = $2
|
||||
`
|
||||
|
||||
type UpdateWorkspaceAgentMetadataParams struct {
|
||||
WorkspaceAgentID uuid.UUID `db:"workspace_agent_id" json:"workspace_agent_id"`
|
||||
Key string `db:"key" json:"key"`
|
||||
Value string `db:"value" json:"value"`
|
||||
Error string `db:"error" json:"error"`
|
||||
CollectedAt time.Time `db:"collected_at" json:"collected_at"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) UpdateWorkspaceAgentMetadata(ctx context.Context, arg UpdateWorkspaceAgentMetadataParams) error {
|
||||
_, err := q.db.ExecContext(ctx, updateWorkspaceAgentMetadata,
|
||||
arg.WorkspaceAgentID,
|
||||
arg.Key,
|
||||
arg.Value,
|
||||
arg.Error,
|
||||
arg.CollectedAt,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
const updateWorkspaceAgentStartupByID = `-- name: UpdateWorkspaceAgentStartupByID :exec
|
||||
UPDATE
|
||||
workspace_agents
|
||||
|
@ -94,6 +94,38 @@ SET
|
||||
WHERE
|
||||
id = $1;
|
||||
|
||||
-- name: InsertWorkspaceAgentMetadata :exec
|
||||
INSERT INTO
|
||||
workspace_agent_metadata (
|
||||
workspace_agent_id,
|
||||
display_name,
|
||||
key,
|
||||
script,
|
||||
timeout,
|
||||
interval
|
||||
)
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5, $6);
|
||||
|
||||
-- name: UpdateWorkspaceAgentMetadata :exec
|
||||
UPDATE
|
||||
workspace_agent_metadata
|
||||
SET
|
||||
value = $3,
|
||||
error = $4,
|
||||
collected_at = $5
|
||||
WHERE
|
||||
workspace_agent_id = $1
|
||||
AND key = $2;
|
||||
|
||||
-- name: GetWorkspaceAgentMetadata :many
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
workspace_agent_metadata
|
||||
WHERE
|
||||
workspace_agent_id = $1;
|
||||
|
||||
-- name: UpdateWorkspaceAgentStartupLogOverflowByID :exec
|
||||
UPDATE
|
||||
workspace_agents
|
||||
|
Reference in New Issue
Block a user