mirror of
https://github.com/coder/coder.git
synced 2025-07-18 14:17:22 +00:00
feat: add health check monitoring to workspace apps (#4114)
This commit is contained in:
@ -2019,19 +2019,38 @@ func (q *fakeQuerier) InsertWorkspaceApp(_ context.Context, arg database.InsertW
|
||||
|
||||
// nolint:gosimple
|
||||
workspaceApp := database.WorkspaceApp{
|
||||
ID: arg.ID,
|
||||
AgentID: arg.AgentID,
|
||||
CreatedAt: arg.CreatedAt,
|
||||
Name: arg.Name,
|
||||
Icon: arg.Icon,
|
||||
Command: arg.Command,
|
||||
Url: arg.Url,
|
||||
RelativePath: arg.RelativePath,
|
||||
ID: arg.ID,
|
||||
AgentID: arg.AgentID,
|
||||
CreatedAt: arg.CreatedAt,
|
||||
Name: arg.Name,
|
||||
Icon: arg.Icon,
|
||||
Command: arg.Command,
|
||||
Url: arg.Url,
|
||||
RelativePath: arg.RelativePath,
|
||||
HealthcheckUrl: arg.HealthcheckUrl,
|
||||
HealthcheckInterval: arg.HealthcheckInterval,
|
||||
HealthcheckThreshold: arg.HealthcheckThreshold,
|
||||
Health: arg.Health,
|
||||
}
|
||||
q.workspaceApps = append(q.workspaceApps, workspaceApp)
|
||||
return workspaceApp, nil
|
||||
}
|
||||
|
||||
func (q *fakeQuerier) UpdateWorkspaceAppHealthByID(_ context.Context, arg database.UpdateWorkspaceAppHealthByIDParams) error {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
|
||||
for index, app := range q.workspaceApps {
|
||||
if app.ID != arg.ID {
|
||||
continue
|
||||
}
|
||||
app.Health = arg.Health
|
||||
q.workspaceApps[index] = app
|
||||
return nil
|
||||
}
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
|
||||
func (q *fakeQuerier) UpdateAPIKeyByID(_ context.Context, arg database.UpdateAPIKeyByIDParams) error {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
|
13
coderd/database/dump.sql
generated
13
coderd/database/dump.sql
generated
@ -88,6 +88,13 @@ CREATE TYPE user_status AS ENUM (
|
||||
'suspended'
|
||||
);
|
||||
|
||||
CREATE TYPE workspace_app_health AS ENUM (
|
||||
'disabled',
|
||||
'initializing',
|
||||
'healthy',
|
||||
'unhealthy'
|
||||
);
|
||||
|
||||
CREATE TYPE workspace_transition AS ENUM (
|
||||
'start',
|
||||
'stop',
|
||||
@ -344,7 +351,11 @@ CREATE TABLE workspace_apps (
|
||||
icon character varying(256) NOT NULL,
|
||||
command character varying(65534),
|
||||
url character varying(65534),
|
||||
relative_path boolean DEFAULT false NOT NULL
|
||||
relative_path boolean DEFAULT false NOT NULL,
|
||||
healthcheck_url text DEFAULT ''::text NOT NULL,
|
||||
healthcheck_interval integer DEFAULT 0 NOT NULL,
|
||||
healthcheck_threshold integer DEFAULT 0 NOT NULL,
|
||||
health workspace_app_health DEFAULT 'disabled'::public.workspace_app_health NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE workspace_builds (
|
||||
|
@ -0,0 +1,7 @@
|
||||
ALTER TABLE ONLY workspace_apps
|
||||
DROP COLUMN IF EXISTS healthcheck_url,
|
||||
DROP COLUMN IF EXISTS healthcheck_interval,
|
||||
DROP COLUMN IF EXISTS healthcheck_threshold,
|
||||
DROP COLUMN IF EXISTS health;
|
||||
|
||||
DROP TYPE workspace_app_health;
|
@ -0,0 +1,7 @@
|
||||
CREATE TYPE workspace_app_health AS ENUM ('disabled', 'initializing', 'healthy', 'unhealthy');
|
||||
|
||||
ALTER TABLE ONLY workspace_apps
|
||||
ADD COLUMN IF NOT EXISTS healthcheck_url text NOT NULL DEFAULT '',
|
||||
ADD COLUMN IF NOT EXISTS healthcheck_interval int NOT NULL DEFAULT 0,
|
||||
ADD COLUMN IF NOT EXISTS healthcheck_threshold int NOT NULL DEFAULT 0,
|
||||
ADD COLUMN IF NOT EXISTS health workspace_app_health NOT NULL DEFAULT 'disabled';
|
@ -312,6 +312,27 @@ func (e *UserStatus) Scan(src interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type WorkspaceAppHealth string
|
||||
|
||||
const (
|
||||
WorkspaceAppHealthDisabled WorkspaceAppHealth = "disabled"
|
||||
WorkspaceAppHealthInitializing WorkspaceAppHealth = "initializing"
|
||||
WorkspaceAppHealthHealthy WorkspaceAppHealth = "healthy"
|
||||
WorkspaceAppHealthUnhealthy WorkspaceAppHealth = "unhealthy"
|
||||
)
|
||||
|
||||
func (e *WorkspaceAppHealth) Scan(src interface{}) error {
|
||||
switch s := src.(type) {
|
||||
case []byte:
|
||||
*e = WorkspaceAppHealth(s)
|
||||
case string:
|
||||
*e = WorkspaceAppHealth(s)
|
||||
default:
|
||||
return fmt.Errorf("unsupported scan type for WorkspaceAppHealth: %T", src)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type WorkspaceTransition string
|
||||
|
||||
const (
|
||||
@ -576,14 +597,18 @@ type WorkspaceAgent struct {
|
||||
}
|
||||
|
||||
type WorkspaceApp struct {
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
||||
AgentID uuid.UUID `db:"agent_id" json:"agent_id"`
|
||||
Name string `db:"name" json:"name"`
|
||||
Icon string `db:"icon" json:"icon"`
|
||||
Command sql.NullString `db:"command" json:"command"`
|
||||
Url sql.NullString `db:"url" json:"url"`
|
||||
RelativePath bool `db:"relative_path" json:"relative_path"`
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
||||
AgentID uuid.UUID `db:"agent_id" json:"agent_id"`
|
||||
Name string `db:"name" json:"name"`
|
||||
Icon string `db:"icon" json:"icon"`
|
||||
Command sql.NullString `db:"command" json:"command"`
|
||||
Url sql.NullString `db:"url" json:"url"`
|
||||
RelativePath bool `db:"relative_path" json:"relative_path"`
|
||||
HealthcheckUrl string `db:"healthcheck_url" json:"healthcheck_url"`
|
||||
HealthcheckInterval int32 `db:"healthcheck_interval" json:"healthcheck_interval"`
|
||||
HealthcheckThreshold int32 `db:"healthcheck_threshold" json:"healthcheck_threshold"`
|
||||
Health WorkspaceAppHealth `db:"health" json:"health"`
|
||||
}
|
||||
|
||||
type WorkspaceBuild struct {
|
||||
|
@ -149,6 +149,7 @@ type querier interface {
|
||||
UpdateWorkspace(ctx context.Context, arg UpdateWorkspaceParams) (Workspace, error)
|
||||
UpdateWorkspaceAgentConnectionByID(ctx context.Context, arg UpdateWorkspaceAgentConnectionByIDParams) error
|
||||
UpdateWorkspaceAgentVersionByID(ctx context.Context, arg UpdateWorkspaceAgentVersionByIDParams) error
|
||||
UpdateWorkspaceAppHealthByID(ctx context.Context, arg UpdateWorkspaceAppHealthByIDParams) error
|
||||
UpdateWorkspaceAutostart(ctx context.Context, arg UpdateWorkspaceAutostartParams) error
|
||||
UpdateWorkspaceBuildByID(ctx context.Context, arg UpdateWorkspaceBuildByIDParams) error
|
||||
UpdateWorkspaceDeletedByID(ctx context.Context, arg UpdateWorkspaceDeletedByIDParams) error
|
||||
|
@ -3849,7 +3849,7 @@ func (q *sqlQuerier) UpdateWorkspaceAgentVersionByID(ctx context.Context, arg Up
|
||||
}
|
||||
|
||||
const getWorkspaceAppByAgentIDAndName = `-- name: GetWorkspaceAppByAgentIDAndName :one
|
||||
SELECT id, created_at, agent_id, name, icon, command, url, relative_path FROM workspace_apps WHERE agent_id = $1 AND name = $2
|
||||
SELECT id, created_at, agent_id, name, icon, command, url, relative_path, healthcheck_url, healthcheck_interval, healthcheck_threshold, health FROM workspace_apps WHERE agent_id = $1 AND name = $2
|
||||
`
|
||||
|
||||
type GetWorkspaceAppByAgentIDAndNameParams struct {
|
||||
@ -3869,12 +3869,16 @@ func (q *sqlQuerier) GetWorkspaceAppByAgentIDAndName(ctx context.Context, arg Ge
|
||||
&i.Command,
|
||||
&i.Url,
|
||||
&i.RelativePath,
|
||||
&i.HealthcheckUrl,
|
||||
&i.HealthcheckInterval,
|
||||
&i.HealthcheckThreshold,
|
||||
&i.Health,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getWorkspaceAppsByAgentID = `-- name: GetWorkspaceAppsByAgentID :many
|
||||
SELECT id, created_at, agent_id, name, icon, command, url, relative_path FROM workspace_apps WHERE agent_id = $1 ORDER BY name ASC
|
||||
SELECT id, created_at, agent_id, name, icon, command, url, relative_path, healthcheck_url, healthcheck_interval, healthcheck_threshold, health FROM workspace_apps WHERE agent_id = $1 ORDER BY name ASC
|
||||
`
|
||||
|
||||
func (q *sqlQuerier) GetWorkspaceAppsByAgentID(ctx context.Context, agentID uuid.UUID) ([]WorkspaceApp, error) {
|
||||
@ -3895,6 +3899,10 @@ func (q *sqlQuerier) GetWorkspaceAppsByAgentID(ctx context.Context, agentID uuid
|
||||
&i.Command,
|
||||
&i.Url,
|
||||
&i.RelativePath,
|
||||
&i.HealthcheckUrl,
|
||||
&i.HealthcheckInterval,
|
||||
&i.HealthcheckThreshold,
|
||||
&i.Health,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -3910,7 +3918,7 @@ func (q *sqlQuerier) GetWorkspaceAppsByAgentID(ctx context.Context, agentID uuid
|
||||
}
|
||||
|
||||
const getWorkspaceAppsByAgentIDs = `-- name: GetWorkspaceAppsByAgentIDs :many
|
||||
SELECT id, created_at, agent_id, name, icon, command, url, relative_path FROM workspace_apps WHERE agent_id = ANY($1 :: uuid [ ]) ORDER BY name ASC
|
||||
SELECT id, created_at, agent_id, name, icon, command, url, relative_path, healthcheck_url, healthcheck_interval, healthcheck_threshold, health FROM workspace_apps WHERE agent_id = ANY($1 :: uuid [ ]) ORDER BY name ASC
|
||||
`
|
||||
|
||||
func (q *sqlQuerier) GetWorkspaceAppsByAgentIDs(ctx context.Context, ids []uuid.UUID) ([]WorkspaceApp, error) {
|
||||
@ -3931,6 +3939,10 @@ func (q *sqlQuerier) GetWorkspaceAppsByAgentIDs(ctx context.Context, ids []uuid.
|
||||
&i.Command,
|
||||
&i.Url,
|
||||
&i.RelativePath,
|
||||
&i.HealthcheckUrl,
|
||||
&i.HealthcheckInterval,
|
||||
&i.HealthcheckThreshold,
|
||||
&i.Health,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -3946,7 +3958,7 @@ func (q *sqlQuerier) GetWorkspaceAppsByAgentIDs(ctx context.Context, ids []uuid.
|
||||
}
|
||||
|
||||
const getWorkspaceAppsCreatedAfter = `-- name: GetWorkspaceAppsCreatedAfter :many
|
||||
SELECT id, created_at, agent_id, name, icon, command, url, relative_path FROM workspace_apps WHERE created_at > $1 ORDER BY name ASC
|
||||
SELECT id, created_at, agent_id, name, icon, command, url, relative_path, healthcheck_url, healthcheck_interval, healthcheck_threshold, health FROM workspace_apps WHERE created_at > $1 ORDER BY name ASC
|
||||
`
|
||||
|
||||
func (q *sqlQuerier) GetWorkspaceAppsCreatedAfter(ctx context.Context, createdAt time.Time) ([]WorkspaceApp, error) {
|
||||
@ -3967,6 +3979,10 @@ func (q *sqlQuerier) GetWorkspaceAppsCreatedAfter(ctx context.Context, createdAt
|
||||
&i.Command,
|
||||
&i.Url,
|
||||
&i.RelativePath,
|
||||
&i.HealthcheckUrl,
|
||||
&i.HealthcheckInterval,
|
||||
&i.HealthcheckThreshold,
|
||||
&i.Health,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -3991,21 +4007,29 @@ INSERT INTO
|
||||
icon,
|
||||
command,
|
||||
url,
|
||||
relative_path
|
||||
relative_path,
|
||||
healthcheck_url,
|
||||
healthcheck_interval,
|
||||
healthcheck_threshold,
|
||||
health
|
||||
)
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5, $6, $7, $8) RETURNING id, created_at, agent_id, name, icon, command, url, relative_path
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) RETURNING id, created_at, agent_id, name, icon, command, url, relative_path, healthcheck_url, healthcheck_interval, healthcheck_threshold, health
|
||||
`
|
||||
|
||||
type InsertWorkspaceAppParams struct {
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
||||
AgentID uuid.UUID `db:"agent_id" json:"agent_id"`
|
||||
Name string `db:"name" json:"name"`
|
||||
Icon string `db:"icon" json:"icon"`
|
||||
Command sql.NullString `db:"command" json:"command"`
|
||||
Url sql.NullString `db:"url" json:"url"`
|
||||
RelativePath bool `db:"relative_path" json:"relative_path"`
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
||||
AgentID uuid.UUID `db:"agent_id" json:"agent_id"`
|
||||
Name string `db:"name" json:"name"`
|
||||
Icon string `db:"icon" json:"icon"`
|
||||
Command sql.NullString `db:"command" json:"command"`
|
||||
Url sql.NullString `db:"url" json:"url"`
|
||||
RelativePath bool `db:"relative_path" json:"relative_path"`
|
||||
HealthcheckUrl string `db:"healthcheck_url" json:"healthcheck_url"`
|
||||
HealthcheckInterval int32 `db:"healthcheck_interval" json:"healthcheck_interval"`
|
||||
HealthcheckThreshold int32 `db:"healthcheck_threshold" json:"healthcheck_threshold"`
|
||||
Health WorkspaceAppHealth `db:"health" json:"health"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) InsertWorkspaceApp(ctx context.Context, arg InsertWorkspaceAppParams) (WorkspaceApp, error) {
|
||||
@ -4018,6 +4042,10 @@ func (q *sqlQuerier) InsertWorkspaceApp(ctx context.Context, arg InsertWorkspace
|
||||
arg.Command,
|
||||
arg.Url,
|
||||
arg.RelativePath,
|
||||
arg.HealthcheckUrl,
|
||||
arg.HealthcheckInterval,
|
||||
arg.HealthcheckThreshold,
|
||||
arg.Health,
|
||||
)
|
||||
var i WorkspaceApp
|
||||
err := row.Scan(
|
||||
@ -4029,10 +4057,33 @@ func (q *sqlQuerier) InsertWorkspaceApp(ctx context.Context, arg InsertWorkspace
|
||||
&i.Command,
|
||||
&i.Url,
|
||||
&i.RelativePath,
|
||||
&i.HealthcheckUrl,
|
||||
&i.HealthcheckInterval,
|
||||
&i.HealthcheckThreshold,
|
||||
&i.Health,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateWorkspaceAppHealthByID = `-- name: UpdateWorkspaceAppHealthByID :exec
|
||||
UPDATE
|
||||
workspace_apps
|
||||
SET
|
||||
health = $2
|
||||
WHERE
|
||||
id = $1
|
||||
`
|
||||
|
||||
type UpdateWorkspaceAppHealthByIDParams struct {
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
Health WorkspaceAppHealth `db:"health" json:"health"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) UpdateWorkspaceAppHealthByID(ctx context.Context, arg UpdateWorkspaceAppHealthByIDParams) error {
|
||||
_, err := q.db.ExecContext(ctx, updateWorkspaceAppHealthByID, arg.ID, arg.Health)
|
||||
return err
|
||||
}
|
||||
|
||||
const getLatestWorkspaceBuildByWorkspaceID = `-- name: GetLatestWorkspaceBuildByWorkspaceID :one
|
||||
SELECT
|
||||
id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason
|
||||
|
@ -20,7 +20,19 @@ INSERT INTO
|
||||
icon,
|
||||
command,
|
||||
url,
|
||||
relative_path
|
||||
relative_path,
|
||||
healthcheck_url,
|
||||
healthcheck_interval,
|
||||
healthcheck_threshold,
|
||||
health
|
||||
)
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5, $6, $7, $8) RETURNING *;
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) RETURNING *;
|
||||
|
||||
-- name: UpdateWorkspaceAppHealthByID :exec
|
||||
UPDATE
|
||||
workspace_apps
|
||||
SET
|
||||
health = $2
|
||||
WHERE
|
||||
id = $1;
|
||||
|
Reference in New Issue
Block a user