mirror of
https://github.com/coder/coder.git
synced 2025-07-08 11:39:50 +00:00
feat: Add workspace agent lifecycle state reporting (#5785)
This commit is contained in:
committed by
GitHub
parent
dbfeb5630c
commit
138887de7e
87
coderd/apidoc/docs.go
generated
87
coderd/apidoc/docs.go
generated
@ -3973,6 +3973,42 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/workspaceagents/me/report-lifecycle": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Agents"
|
||||
],
|
||||
"summary": "Submit workspace agent lifecycle state",
|
||||
"operationId": "submit-workspace-agent-lifecycle-state",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Workspace agent lifecycle request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/codersdk.PostWorkspaceAgentLifecycleRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "Success"
|
||||
}
|
||||
},
|
||||
"x-apidocgen": {
|
||||
"skip": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/workspaceagents/me/report-stats": {
|
||||
"post": {
|
||||
"security": [
|
||||
@ -6723,6 +6759,14 @@ const docTemplate = `{
|
||||
"ParameterSourceSchemeData"
|
||||
]
|
||||
},
|
||||
"codersdk.PostWorkspaceAgentLifecycleRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"state": {
|
||||
"$ref": "#/definitions/codersdk.WorkspaceAgentLifecycle"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.PostWorkspaceAgentVersionRequest": {
|
||||
"description": "x-apidocgen:skip",
|
||||
"type": "object",
|
||||
@ -7651,6 +7695,10 @@ const docTemplate = `{
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"delay_login_until_ready": {
|
||||
"description": "DelayLoginUntilReady if true, the agent will delay logins until it is ready (e.g. executing startup script has ended).",
|
||||
"type": "boolean"
|
||||
},
|
||||
"directory": {
|
||||
"type": "string"
|
||||
},
|
||||
@ -7686,6 +7734,9 @@ const docTemplate = `{
|
||||
"$ref": "#/definitions/codersdk.DERPRegion"
|
||||
}
|
||||
},
|
||||
"lifecycle_state": {
|
||||
"$ref": "#/definitions/codersdk.WorkspaceAgentLifecycle"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
@ -7699,18 +7750,12 @@ const docTemplate = `{
|
||||
"startup_script": {
|
||||
"type": "string"
|
||||
},
|
||||
"startup_script_timeout_seconds": {
|
||||
"description": "StartupScriptTimeoutSeconds is the number of seconds to wait for the startup script to complete. If the script does not complete within this time, the agent lifecycle will be marked as start_timeout.",
|
||||
"type": "integer"
|
||||
},
|
||||
"status": {
|
||||
"enum": [
|
||||
"connecting",
|
||||
"connected",
|
||||
"disconnected",
|
||||
"timeout"
|
||||
],
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/codersdk.WorkspaceAgentStatus"
|
||||
}
|
||||
]
|
||||
"$ref": "#/definitions/codersdk.WorkspaceAgentStatus"
|
||||
},
|
||||
"troubleshooting_url": {
|
||||
"type": "string"
|
||||
@ -7754,6 +7799,23 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.WorkspaceAgentLifecycle": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"created",
|
||||
"starting",
|
||||
"start_timeout",
|
||||
"start_error",
|
||||
"ready"
|
||||
],
|
||||
"x-enum-varnames": [
|
||||
"WorkspaceAgentLifecycleCreated",
|
||||
"WorkspaceAgentLifecycleStarting",
|
||||
"WorkspaceAgentLifecycleStartTimeout",
|
||||
"WorkspaceAgentLifecycleStartError",
|
||||
"WorkspaceAgentLifecycleReady"
|
||||
]
|
||||
},
|
||||
"codersdk.WorkspaceAgentMetadata": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@ -7785,6 +7847,9 @@ const docTemplate = `{
|
||||
"startup_script": {
|
||||
"type": "string"
|
||||
},
|
||||
"startup_script_timeout": {
|
||||
"type": "integer"
|
||||
},
|
||||
"vscode_port_proxy_uri": {
|
||||
"type": "string"
|
||||
}
|
||||
|
72
coderd/apidoc/swagger.json
generated
72
coderd/apidoc/swagger.json
generated
@ -3493,6 +3493,38 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/workspaceagents/me/report-lifecycle": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"consumes": ["application/json"],
|
||||
"tags": ["Agents"],
|
||||
"summary": "Submit workspace agent lifecycle state",
|
||||
"operationId": "submit-workspace-agent-lifecycle-state",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Workspace agent lifecycle request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/codersdk.PostWorkspaceAgentLifecycleRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "Success"
|
||||
}
|
||||
},
|
||||
"x-apidocgen": {
|
||||
"skip": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/workspaceagents/me/report-stats": {
|
||||
"post": {
|
||||
"security": [
|
||||
@ -6006,6 +6038,14 @@
|
||||
"ParameterSourceSchemeData"
|
||||
]
|
||||
},
|
||||
"codersdk.PostWorkspaceAgentLifecycleRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"state": {
|
||||
"$ref": "#/definitions/codersdk.WorkspaceAgentLifecycle"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.PostWorkspaceAgentVersionRequest": {
|
||||
"description": "x-apidocgen:skip",
|
||||
"type": "object",
|
||||
@ -6886,6 +6926,10 @@
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"delay_login_until_ready": {
|
||||
"description": "DelayLoginUntilReady if true, the agent will delay logins until it is ready (e.g. executing startup script has ended).",
|
||||
"type": "boolean"
|
||||
},
|
||||
"directory": {
|
||||
"type": "string"
|
||||
},
|
||||
@ -6921,6 +6965,9 @@
|
||||
"$ref": "#/definitions/codersdk.DERPRegion"
|
||||
}
|
||||
},
|
||||
"lifecycle_state": {
|
||||
"$ref": "#/definitions/codersdk.WorkspaceAgentLifecycle"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
@ -6934,13 +6981,12 @@
|
||||
"startup_script": {
|
||||
"type": "string"
|
||||
},
|
||||
"startup_script_timeout_seconds": {
|
||||
"description": "StartupScriptTimeoutSeconds is the number of seconds to wait for the startup script to complete. If the script does not complete within this time, the agent lifecycle will be marked as start_timeout.",
|
||||
"type": "integer"
|
||||
},
|
||||
"status": {
|
||||
"enum": ["connecting", "connected", "disconnected", "timeout"],
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/codersdk.WorkspaceAgentStatus"
|
||||
}
|
||||
]
|
||||
"$ref": "#/definitions/codersdk.WorkspaceAgentStatus"
|
||||
},
|
||||
"troubleshooting_url": {
|
||||
"type": "string"
|
||||
@ -6984,6 +7030,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.WorkspaceAgentLifecycle": {
|
||||
"type": "string",
|
||||
"enum": ["created", "starting", "start_timeout", "start_error", "ready"],
|
||||
"x-enum-varnames": [
|
||||
"WorkspaceAgentLifecycleCreated",
|
||||
"WorkspaceAgentLifecycleStarting",
|
||||
"WorkspaceAgentLifecycleStartTimeout",
|
||||
"WorkspaceAgentLifecycleStartError",
|
||||
"WorkspaceAgentLifecycleReady"
|
||||
]
|
||||
},
|
||||
"codersdk.WorkspaceAgentMetadata": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@ -7015,6 +7072,9 @@
|
||||
"startup_script": {
|
||||
"type": "string"
|
||||
},
|
||||
"startup_script_timeout": {
|
||||
"type": "integer"
|
||||
},
|
||||
"vscode_port_proxy_uri": {
|
||||
"type": "string"
|
||||
}
|
||||
|
@ -541,6 +541,7 @@ func New(options *Options) *API {
|
||||
r.Get("/gitsshkey", api.agentGitSSHKey)
|
||||
r.Get("/coordinate", api.workspaceAgentCoordinate)
|
||||
r.Post("/report-stats", api.workspaceAgentReportStats)
|
||||
r.Post("/report-lifecycle", api.workspaceAgentReportLifecycle)
|
||||
})
|
||||
r.Route("/{workspaceagent}", func(r chi.Router) {
|
||||
r.Use(
|
||||
|
@ -75,6 +75,7 @@ func AGPLRoutes(a *AuthTester) (map[string]string, map[string]RouteCheck) {
|
||||
"POST:/api/v2/workspaceagents/me/version": {NoAuthorize: true},
|
||||
"POST:/api/v2/workspaceagents/me/app-health": {NoAuthorize: true},
|
||||
"POST:/api/v2/workspaceagents/me/report-stats": {NoAuthorize: true},
|
||||
"POST:/api/v2/workspaceagents/me/report-lifecycle": {NoAuthorize: true},
|
||||
|
||||
// These endpoints have more assertions. This is good, add more endpoints to assert if you can!
|
||||
"GET:/api/v2/organizations/{organization}": {AssertObject: rbac.ResourceOrganization.WithID(a.Admin.OrganizationID).InOrg(a.Admin.OrganizationID)},
|
||||
@ -276,9 +277,11 @@ func AGPLRoutes(a *AuthTester) (map[string]string, map[string]RouteCheck) {
|
||||
// Routes like proxy routes support all HTTP methods. A helper func to expand
|
||||
// 1 url to all http methods.
|
||||
assertAllHTTPMethods := func(url string, check RouteCheck) {
|
||||
methods := []string{http.MethodGet, http.MethodHead, http.MethodPost,
|
||||
methods := []string{
|
||||
http.MethodGet, http.MethodHead, http.MethodPost,
|
||||
http.MethodPut, http.MethodPatch, http.MethodDelete,
|
||||
http.MethodConnect, http.MethodOptions, http.MethodTrace}
|
||||
http.MethodConnect, http.MethodOptions, http.MethodTrace,
|
||||
}
|
||||
|
||||
for _, method := range methods {
|
||||
route := method + ":" + url
|
||||
|
@ -2789,6 +2789,7 @@ func (q *fakeQuerier) InsertWorkspaceAgent(_ context.Context, arg database.Inser
|
||||
ConnectionTimeoutSeconds: arg.ConnectionTimeoutSeconds,
|
||||
TroubleshootingURL: arg.TroubleshootingURL,
|
||||
MOTDFile: arg.MOTDFile,
|
||||
LifecycleState: database.WorkspaceAgentLifecycleStateCreated,
|
||||
}
|
||||
|
||||
q.workspaceAgents = append(q.workspaceAgents, agent)
|
||||
@ -4294,3 +4295,20 @@ func (q *fakeQuerier) GetQuotaConsumedForUser(_ context.Context, userID uuid.UUI
|
||||
}
|
||||
return sum, nil
|
||||
}
|
||||
|
||||
func (q *fakeQuerier) UpdateWorkspaceAgentLifecycleStateByID(_ context.Context, arg database.UpdateWorkspaceAgentLifecycleStateByIDParams) error {
|
||||
if err := validateDatabaseType(arg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
for i, agent := range q.workspaceAgents {
|
||||
if agent.ID == arg.ID {
|
||||
agent.LifecycleState = arg.LifecycleState
|
||||
q.workspaceAgents[i] = agent
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
|
19
coderd/database/dump.sql
generated
19
coderd/database/dump.sql
generated
@ -99,6 +99,14 @@ CREATE TYPE user_status AS ENUM (
|
||||
'suspended'
|
||||
);
|
||||
|
||||
CREATE TYPE workspace_agent_lifecycle_state AS ENUM (
|
||||
'created',
|
||||
'starting',
|
||||
'start_timeout',
|
||||
'start_error',
|
||||
'ready'
|
||||
);
|
||||
|
||||
CREATE TYPE workspace_app_health AS ENUM (
|
||||
'disabled',
|
||||
'initializing',
|
||||
@ -448,7 +456,10 @@ CREATE TABLE workspace_agents (
|
||||
last_connected_replica_id uuid,
|
||||
connection_timeout_seconds integer DEFAULT 0 NOT NULL,
|
||||
troubleshooting_url text DEFAULT ''::text NOT NULL,
|
||||
motd_file text DEFAULT ''::text NOT NULL
|
||||
motd_file text DEFAULT ''::text NOT NULL,
|
||||
lifecycle_state workspace_agent_lifecycle_state DEFAULT 'created'::workspace_agent_lifecycle_state NOT NULL,
|
||||
delay_login_until_ready boolean DEFAULT false NOT NULL,
|
||||
startup_script_timeout_seconds integer DEFAULT 0 NOT NULL
|
||||
);
|
||||
|
||||
COMMENT ON COLUMN workspace_agents.version IS 'Version tracks the version of the currently running workspace agent. Workspace agents register their version upon start.';
|
||||
@ -459,6 +470,12 @@ COMMENT ON COLUMN workspace_agents.troubleshooting_url IS 'URL for troubleshooti
|
||||
|
||||
COMMENT ON COLUMN workspace_agents.motd_file IS 'Path to file inside workspace containing the message of the day (MOTD) to show to the user when logging in via SSH.';
|
||||
|
||||
COMMENT ON COLUMN workspace_agents.lifecycle_state IS 'The current lifecycle state reported by the workspace agent.';
|
||||
|
||||
COMMENT ON COLUMN workspace_agents.delay_login_until_ready IS 'If true, the agent will delay logins until it is ready (e.g. executing startup script has ended).';
|
||||
|
||||
COMMENT ON COLUMN workspace_agents.startup_script_timeout_seconds IS 'The number of seconds to wait for the startup script to complete. If the script does not complete within this time, the agent lifecycle will be marked as start_timeout.';
|
||||
|
||||
CREATE TABLE workspace_apps (
|
||||
id uuid NOT NULL,
|
||||
created_at timestamp with time zone NOT NULL,
|
||||
|
@ -0,0 +1,6 @@
|
||||
ALTER TABLE workspace_agents DROP COLUMN startup_script_timeout_seconds;
|
||||
ALTER TABLE workspace_agents DROP COLUMN delay_login_until_ready;
|
||||
|
||||
ALTER TABLE workspace_agents DROP COLUMN lifecycle_state;
|
||||
|
||||
DROP TYPE workspace_agent_lifecycle_state;
|
@ -0,0 +1,19 @@
|
||||
CREATE TYPE workspace_agent_lifecycle_state AS ENUM ('created', 'starting', 'start_timeout', 'start_error', 'ready');
|
||||
|
||||
-- Set all existing workspace agents to 'ready' so that only newly created agents will be in the 'created' state.
|
||||
ALTER TABLE workspace_agents ADD COLUMN lifecycle_state workspace_agent_lifecycle_state NOT NULL DEFAULT 'ready';
|
||||
-- Change the default for newly created agents.
|
||||
ALTER TABLE workspace_agents ALTER COLUMN lifecycle_state SET DEFAULT 'created';
|
||||
|
||||
COMMENT ON COLUMN workspace_agents.lifecycle_state IS 'The current lifecycle state reported by the workspace agent.';
|
||||
|
||||
-- Set default values that conform to current behavior.
|
||||
-- Allow logins immediately after agent connect.
|
||||
ALTER TABLE workspace_agents ADD COLUMN delay_login_until_ready boolean NOT NULL DEFAULT false;
|
||||
|
||||
COMMENT ON COLUMN workspace_agents.delay_login_until_ready IS 'If true, the agent will delay logins until it is ready (e.g. executing startup script has ended).';
|
||||
|
||||
-- Disable startup script timeouts by default.
|
||||
ALTER TABLE workspace_agents ADD COLUMN startup_script_timeout_seconds int4 NOT NULL DEFAULT 0;
|
||||
|
||||
COMMENT ON COLUMN workspace_agents.startup_script_timeout_seconds IS 'The number of seconds to wait for the startup script to complete. If the script does not complete within this time, the agent lifecycle will be marked as start_timeout.';
|
@ -1002,6 +1002,73 @@ func AllUserStatusValues() []UserStatus {
|
||||
}
|
||||
}
|
||||
|
||||
type WorkspaceAgentLifecycleState string
|
||||
|
||||
const (
|
||||
WorkspaceAgentLifecycleStateCreated WorkspaceAgentLifecycleState = "created"
|
||||
WorkspaceAgentLifecycleStateStarting WorkspaceAgentLifecycleState = "starting"
|
||||
WorkspaceAgentLifecycleStateStartTimeout WorkspaceAgentLifecycleState = "start_timeout"
|
||||
WorkspaceAgentLifecycleStateStartError WorkspaceAgentLifecycleState = "start_error"
|
||||
WorkspaceAgentLifecycleStateReady WorkspaceAgentLifecycleState = "ready"
|
||||
)
|
||||
|
||||
func (e *WorkspaceAgentLifecycleState) Scan(src interface{}) error {
|
||||
switch s := src.(type) {
|
||||
case []byte:
|
||||
*e = WorkspaceAgentLifecycleState(s)
|
||||
case string:
|
||||
*e = WorkspaceAgentLifecycleState(s)
|
||||
default:
|
||||
return fmt.Errorf("unsupported scan type for WorkspaceAgentLifecycleState: %T", src)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type NullWorkspaceAgentLifecycleState struct {
|
||||
WorkspaceAgentLifecycleState WorkspaceAgentLifecycleState
|
||||
Valid bool // Valid is true if WorkspaceAgentLifecycleState is not NULL
|
||||
}
|
||||
|
||||
// Scan implements the Scanner interface.
|
||||
func (ns *NullWorkspaceAgentLifecycleState) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
ns.WorkspaceAgentLifecycleState, ns.Valid = "", false
|
||||
return nil
|
||||
}
|
||||
ns.Valid = true
|
||||
return ns.WorkspaceAgentLifecycleState.Scan(value)
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (ns NullWorkspaceAgentLifecycleState) Value() (driver.Value, error) {
|
||||
if !ns.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return ns.WorkspaceAgentLifecycleState, nil
|
||||
}
|
||||
|
||||
func (e WorkspaceAgentLifecycleState) Valid() bool {
|
||||
switch e {
|
||||
case WorkspaceAgentLifecycleStateCreated,
|
||||
WorkspaceAgentLifecycleStateStarting,
|
||||
WorkspaceAgentLifecycleStateStartTimeout,
|
||||
WorkspaceAgentLifecycleStateStartError,
|
||||
WorkspaceAgentLifecycleStateReady:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func AllWorkspaceAgentLifecycleStateValues() []WorkspaceAgentLifecycleState {
|
||||
return []WorkspaceAgentLifecycleState{
|
||||
WorkspaceAgentLifecycleStateCreated,
|
||||
WorkspaceAgentLifecycleStateStarting,
|
||||
WorkspaceAgentLifecycleStateStartTimeout,
|
||||
WorkspaceAgentLifecycleStateStartError,
|
||||
WorkspaceAgentLifecycleStateReady,
|
||||
}
|
||||
}
|
||||
|
||||
type WorkspaceAppHealth string
|
||||
|
||||
const (
|
||||
@ -1448,6 +1515,12 @@ type WorkspaceAgent struct {
|
||||
TroubleshootingURL string `db:"troubleshooting_url" json:"troubleshooting_url"`
|
||||
// Path to file inside workspace containing the message of the day (MOTD) to show to the user when logging in via SSH.
|
||||
MOTDFile string `db:"motd_file" json:"motd_file"`
|
||||
// The current lifecycle state reported by the workspace agent.
|
||||
LifecycleState WorkspaceAgentLifecycleState `db:"lifecycle_state" json:"lifecycle_state"`
|
||||
// If true, the agent will delay logins until it is ready (e.g. executing startup script has ended).
|
||||
DelayLoginUntilReady bool `db:"delay_login_until_ready" json:"delay_login_until_ready"`
|
||||
// The number of seconds to wait for the startup script to complete. If the script does not complete within this time, the agent lifecycle will be marked as start_timeout.
|
||||
StartupScriptTimeoutSeconds int32 `db:"startup_script_timeout_seconds" json:"startup_script_timeout_seconds"`
|
||||
}
|
||||
|
||||
type WorkspaceApp struct {
|
||||
|
@ -199,6 +199,7 @@ type sqlcQuerier interface {
|
||||
UpdateUserStatus(ctx context.Context, arg UpdateUserStatusParams) (User, error)
|
||||
UpdateWorkspace(ctx context.Context, arg UpdateWorkspaceParams) (Workspace, error)
|
||||
UpdateWorkspaceAgentConnectionByID(ctx context.Context, arg UpdateWorkspaceAgentConnectionByIDParams) error
|
||||
UpdateWorkspaceAgentLifecycleStateByID(ctx context.Context, arg UpdateWorkspaceAgentLifecycleStateByIDParams) error
|
||||
UpdateWorkspaceAgentVersionByID(ctx context.Context, arg UpdateWorkspaceAgentVersionByIDParams) error
|
||||
UpdateWorkspaceAppHealthByID(ctx context.Context, arg UpdateWorkspaceAppHealthByIDParams) error
|
||||
UpdateWorkspaceAutostart(ctx context.Context, arg UpdateWorkspaceAutostartParams) error
|
||||
|
@ -4869,7 +4869,7 @@ func (q *sqlQuerier) UpdateUserStatus(ctx context.Context, arg UpdateUserStatusP
|
||||
|
||||
const getWorkspaceAgentByAuthToken = `-- name: GetWorkspaceAgentByAuthToken :one
|
||||
SELECT
|
||||
id, created_at, updated_at, name, first_connected_at, last_connected_at, disconnected_at, resource_id, auth_token, auth_instance_id, architecture, environment_variables, operating_system, startup_script, instance_metadata, resource_metadata, directory, version, last_connected_replica_id, connection_timeout_seconds, troubleshooting_url, motd_file
|
||||
id, created_at, updated_at, name, first_connected_at, last_connected_at, disconnected_at, resource_id, auth_token, auth_instance_id, architecture, environment_variables, operating_system, startup_script, instance_metadata, resource_metadata, directory, version, last_connected_replica_id, connection_timeout_seconds, troubleshooting_url, motd_file, lifecycle_state, delay_login_until_ready, startup_script_timeout_seconds
|
||||
FROM
|
||||
workspace_agents
|
||||
WHERE
|
||||
@ -4904,13 +4904,16 @@ func (q *sqlQuerier) GetWorkspaceAgentByAuthToken(ctx context.Context, authToken
|
||||
&i.ConnectionTimeoutSeconds,
|
||||
&i.TroubleshootingURL,
|
||||
&i.MOTDFile,
|
||||
&i.LifecycleState,
|
||||
&i.DelayLoginUntilReady,
|
||||
&i.StartupScriptTimeoutSeconds,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getWorkspaceAgentByID = `-- name: GetWorkspaceAgentByID :one
|
||||
SELECT
|
||||
id, created_at, updated_at, name, first_connected_at, last_connected_at, disconnected_at, resource_id, auth_token, auth_instance_id, architecture, environment_variables, operating_system, startup_script, instance_metadata, resource_metadata, directory, version, last_connected_replica_id, connection_timeout_seconds, troubleshooting_url, motd_file
|
||||
id, created_at, updated_at, name, first_connected_at, last_connected_at, disconnected_at, resource_id, auth_token, auth_instance_id, architecture, environment_variables, operating_system, startup_script, instance_metadata, resource_metadata, directory, version, last_connected_replica_id, connection_timeout_seconds, troubleshooting_url, motd_file, lifecycle_state, delay_login_until_ready, startup_script_timeout_seconds
|
||||
FROM
|
||||
workspace_agents
|
||||
WHERE
|
||||
@ -4943,13 +4946,16 @@ func (q *sqlQuerier) GetWorkspaceAgentByID(ctx context.Context, id uuid.UUID) (W
|
||||
&i.ConnectionTimeoutSeconds,
|
||||
&i.TroubleshootingURL,
|
||||
&i.MOTDFile,
|
||||
&i.LifecycleState,
|
||||
&i.DelayLoginUntilReady,
|
||||
&i.StartupScriptTimeoutSeconds,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getWorkspaceAgentByInstanceID = `-- name: GetWorkspaceAgentByInstanceID :one
|
||||
SELECT
|
||||
id, created_at, updated_at, name, first_connected_at, last_connected_at, disconnected_at, resource_id, auth_token, auth_instance_id, architecture, environment_variables, operating_system, startup_script, instance_metadata, resource_metadata, directory, version, last_connected_replica_id, connection_timeout_seconds, troubleshooting_url, motd_file
|
||||
id, created_at, updated_at, name, first_connected_at, last_connected_at, disconnected_at, resource_id, auth_token, auth_instance_id, architecture, environment_variables, operating_system, startup_script, instance_metadata, resource_metadata, directory, version, last_connected_replica_id, connection_timeout_seconds, troubleshooting_url, motd_file, lifecycle_state, delay_login_until_ready, startup_script_timeout_seconds
|
||||
FROM
|
||||
workspace_agents
|
||||
WHERE
|
||||
@ -4984,13 +4990,16 @@ func (q *sqlQuerier) GetWorkspaceAgentByInstanceID(ctx context.Context, authInst
|
||||
&i.ConnectionTimeoutSeconds,
|
||||
&i.TroubleshootingURL,
|
||||
&i.MOTDFile,
|
||||
&i.LifecycleState,
|
||||
&i.DelayLoginUntilReady,
|
||||
&i.StartupScriptTimeoutSeconds,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getWorkspaceAgentsByResourceIDs = `-- name: GetWorkspaceAgentsByResourceIDs :many
|
||||
SELECT
|
||||
id, created_at, updated_at, name, first_connected_at, last_connected_at, disconnected_at, resource_id, auth_token, auth_instance_id, architecture, environment_variables, operating_system, startup_script, instance_metadata, resource_metadata, directory, version, last_connected_replica_id, connection_timeout_seconds, troubleshooting_url, motd_file
|
||||
id, created_at, updated_at, name, first_connected_at, last_connected_at, disconnected_at, resource_id, auth_token, auth_instance_id, architecture, environment_variables, operating_system, startup_script, instance_metadata, resource_metadata, directory, version, last_connected_replica_id, connection_timeout_seconds, troubleshooting_url, motd_file, lifecycle_state, delay_login_until_ready, startup_script_timeout_seconds
|
||||
FROM
|
||||
workspace_agents
|
||||
WHERE
|
||||
@ -5029,6 +5038,9 @@ func (q *sqlQuerier) GetWorkspaceAgentsByResourceIDs(ctx context.Context, ids []
|
||||
&i.ConnectionTimeoutSeconds,
|
||||
&i.TroubleshootingURL,
|
||||
&i.MOTDFile,
|
||||
&i.LifecycleState,
|
||||
&i.DelayLoginUntilReady,
|
||||
&i.StartupScriptTimeoutSeconds,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -5044,7 +5056,7 @@ func (q *sqlQuerier) GetWorkspaceAgentsByResourceIDs(ctx context.Context, ids []
|
||||
}
|
||||
|
||||
const getWorkspaceAgentsCreatedAfter = `-- name: GetWorkspaceAgentsCreatedAfter :many
|
||||
SELECT id, created_at, updated_at, name, first_connected_at, last_connected_at, disconnected_at, resource_id, auth_token, auth_instance_id, architecture, environment_variables, operating_system, startup_script, instance_metadata, resource_metadata, directory, version, last_connected_replica_id, connection_timeout_seconds, troubleshooting_url, motd_file FROM workspace_agents WHERE created_at > $1
|
||||
SELECT id, created_at, updated_at, name, first_connected_at, last_connected_at, disconnected_at, resource_id, auth_token, auth_instance_id, architecture, environment_variables, operating_system, startup_script, instance_metadata, resource_metadata, directory, version, last_connected_replica_id, connection_timeout_seconds, troubleshooting_url, motd_file, lifecycle_state, delay_login_until_ready, startup_script_timeout_seconds FROM workspace_agents WHERE created_at > $1
|
||||
`
|
||||
|
||||
func (q *sqlQuerier) GetWorkspaceAgentsCreatedAfter(ctx context.Context, createdAt time.Time) ([]WorkspaceAgent, error) {
|
||||
@ -5079,6 +5091,9 @@ func (q *sqlQuerier) GetWorkspaceAgentsCreatedAfter(ctx context.Context, created
|
||||
&i.ConnectionTimeoutSeconds,
|
||||
&i.TroubleshootingURL,
|
||||
&i.MOTDFile,
|
||||
&i.LifecycleState,
|
||||
&i.DelayLoginUntilReady,
|
||||
&i.StartupScriptTimeoutSeconds,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -5112,30 +5127,34 @@ INSERT INTO
|
||||
resource_metadata,
|
||||
connection_timeout_seconds,
|
||||
troubleshooting_url,
|
||||
motd_file
|
||||
motd_file,
|
||||
delay_login_until_ready,
|
||||
startup_script_timeout_seconds
|
||||
)
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17) RETURNING id, created_at, updated_at, name, first_connected_at, last_connected_at, disconnected_at, resource_id, auth_token, auth_instance_id, architecture, environment_variables, operating_system, startup_script, instance_metadata, resource_metadata, directory, version, last_connected_replica_id, connection_timeout_seconds, troubleshooting_url, motd_file
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19) RETURNING id, created_at, updated_at, name, first_connected_at, last_connected_at, disconnected_at, resource_id, auth_token, auth_instance_id, architecture, environment_variables, operating_system, startup_script, instance_metadata, resource_metadata, directory, version, last_connected_replica_id, connection_timeout_seconds, troubleshooting_url, motd_file, lifecycle_state, delay_login_until_ready, startup_script_timeout_seconds
|
||||
`
|
||||
|
||||
type InsertWorkspaceAgentParams struct {
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
||||
Name string `db:"name" json:"name"`
|
||||
ResourceID uuid.UUID `db:"resource_id" json:"resource_id"`
|
||||
AuthToken uuid.UUID `db:"auth_token" json:"auth_token"`
|
||||
AuthInstanceID sql.NullString `db:"auth_instance_id" json:"auth_instance_id"`
|
||||
Architecture string `db:"architecture" json:"architecture"`
|
||||
EnvironmentVariables pqtype.NullRawMessage `db:"environment_variables" json:"environment_variables"`
|
||||
OperatingSystem string `db:"operating_system" json:"operating_system"`
|
||||
StartupScript sql.NullString `db:"startup_script" json:"startup_script"`
|
||||
Directory string `db:"directory" json:"directory"`
|
||||
InstanceMetadata pqtype.NullRawMessage `db:"instance_metadata" json:"instance_metadata"`
|
||||
ResourceMetadata pqtype.NullRawMessage `db:"resource_metadata" json:"resource_metadata"`
|
||||
ConnectionTimeoutSeconds int32 `db:"connection_timeout_seconds" json:"connection_timeout_seconds"`
|
||||
TroubleshootingURL string `db:"troubleshooting_url" json:"troubleshooting_url"`
|
||||
MOTDFile string `db:"motd_file" json:"motd_file"`
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
||||
Name string `db:"name" json:"name"`
|
||||
ResourceID uuid.UUID `db:"resource_id" json:"resource_id"`
|
||||
AuthToken uuid.UUID `db:"auth_token" json:"auth_token"`
|
||||
AuthInstanceID sql.NullString `db:"auth_instance_id" json:"auth_instance_id"`
|
||||
Architecture string `db:"architecture" json:"architecture"`
|
||||
EnvironmentVariables pqtype.NullRawMessage `db:"environment_variables" json:"environment_variables"`
|
||||
OperatingSystem string `db:"operating_system" json:"operating_system"`
|
||||
StartupScript sql.NullString `db:"startup_script" json:"startup_script"`
|
||||
Directory string `db:"directory" json:"directory"`
|
||||
InstanceMetadata pqtype.NullRawMessage `db:"instance_metadata" json:"instance_metadata"`
|
||||
ResourceMetadata pqtype.NullRawMessage `db:"resource_metadata" json:"resource_metadata"`
|
||||
ConnectionTimeoutSeconds int32 `db:"connection_timeout_seconds" json:"connection_timeout_seconds"`
|
||||
TroubleshootingURL string `db:"troubleshooting_url" json:"troubleshooting_url"`
|
||||
MOTDFile string `db:"motd_file" json:"motd_file"`
|
||||
DelayLoginUntilReady bool `db:"delay_login_until_ready" json:"delay_login_until_ready"`
|
||||
StartupScriptTimeoutSeconds int32 `db:"startup_script_timeout_seconds" json:"startup_script_timeout_seconds"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) InsertWorkspaceAgent(ctx context.Context, arg InsertWorkspaceAgentParams) (WorkspaceAgent, error) {
|
||||
@ -5157,6 +5176,8 @@ func (q *sqlQuerier) InsertWorkspaceAgent(ctx context.Context, arg InsertWorkspa
|
||||
arg.ConnectionTimeoutSeconds,
|
||||
arg.TroubleshootingURL,
|
||||
arg.MOTDFile,
|
||||
arg.DelayLoginUntilReady,
|
||||
arg.StartupScriptTimeoutSeconds,
|
||||
)
|
||||
var i WorkspaceAgent
|
||||
err := row.Scan(
|
||||
@ -5182,6 +5203,9 @@ func (q *sqlQuerier) InsertWorkspaceAgent(ctx context.Context, arg InsertWorkspa
|
||||
&i.ConnectionTimeoutSeconds,
|
||||
&i.TroubleshootingURL,
|
||||
&i.MOTDFile,
|
||||
&i.LifecycleState,
|
||||
&i.DelayLoginUntilReady,
|
||||
&i.StartupScriptTimeoutSeconds,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
@ -5220,6 +5244,25 @@ func (q *sqlQuerier) UpdateWorkspaceAgentConnectionByID(ctx context.Context, arg
|
||||
return err
|
||||
}
|
||||
|
||||
const updateWorkspaceAgentLifecycleStateByID = `-- name: UpdateWorkspaceAgentLifecycleStateByID :exec
|
||||
UPDATE
|
||||
workspace_agents
|
||||
SET
|
||||
lifecycle_state = $2
|
||||
WHERE
|
||||
id = $1
|
||||
`
|
||||
|
||||
type UpdateWorkspaceAgentLifecycleStateByIDParams struct {
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
LifecycleState WorkspaceAgentLifecycleState `db:"lifecycle_state" json:"lifecycle_state"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) UpdateWorkspaceAgentLifecycleStateByID(ctx context.Context, arg UpdateWorkspaceAgentLifecycleStateByIDParams) error {
|
||||
_, err := q.db.ExecContext(ctx, updateWorkspaceAgentLifecycleStateByID, arg.ID, arg.LifecycleState)
|
||||
return err
|
||||
}
|
||||
|
||||
const updateWorkspaceAgentVersionByID = `-- name: UpdateWorkspaceAgentVersionByID :exec
|
||||
UPDATE
|
||||
workspace_agents
|
||||
|
@ -56,10 +56,12 @@ INSERT INTO
|
||||
resource_metadata,
|
||||
connection_timeout_seconds,
|
||||
troubleshooting_url,
|
||||
motd_file
|
||||
motd_file,
|
||||
delay_login_until_ready,
|
||||
startup_script_timeout_seconds
|
||||
)
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17) RETURNING *;
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19) RETURNING *;
|
||||
|
||||
-- name: UpdateWorkspaceAgentConnectionByID :exec
|
||||
UPDATE
|
||||
@ -80,3 +82,11 @@ SET
|
||||
version = $2
|
||||
WHERE
|
||||
id = $1;
|
||||
|
||||
-- name: UpdateWorkspaceAgentLifecycleStateByID :exec
|
||||
UPDATE
|
||||
workspace_agents
|
||||
SET
|
||||
lifecycle_state = $2
|
||||
WHERE
|
||||
id = $1;
|
||||
|
@ -949,9 +949,11 @@ func InsertWorkspaceResource(ctx context.Context, db database.Store, jobID uuid.
|
||||
String: prAgent.StartupScript,
|
||||
Valid: prAgent.StartupScript != "",
|
||||
},
|
||||
ConnectionTimeoutSeconds: prAgent.GetConnectionTimeoutSeconds(),
|
||||
TroubleshootingURL: prAgent.GetTroubleshootingUrl(),
|
||||
MOTDFile: prAgent.GetMotdFile(),
|
||||
ConnectionTimeoutSeconds: prAgent.GetConnectionTimeoutSeconds(),
|
||||
TroubleshootingURL: prAgent.GetTroubleshootingUrl(),
|
||||
MOTDFile: prAgent.GetMotdFile(),
|
||||
DelayLoginUntilReady: prAgent.GetDelayLoginUntilReady(),
|
||||
StartupScriptTimeoutSeconds: prAgent.GetStartupScriptTimeoutSeconds(),
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("insert agent: %w", err)
|
||||
|
@ -150,6 +150,7 @@ func (api *API) workspaceAgentMetadata(rw http.ResponseWriter, r *http.Request)
|
||||
Directory: apiAgent.Directory,
|
||||
VSCodePortProxyURI: vscodeProxyURI,
|
||||
MOTDFile: workspaceAgent.MOTDFile,
|
||||
StartupScriptTimeout: time.Duration(apiAgent.StartupScriptTimeoutSeconds) * time.Second,
|
||||
})
|
||||
}
|
||||
|
||||
@ -739,21 +740,24 @@ func convertWorkspaceAgent(derpMap *tailcfg.DERPMap, coordinator tailnet.Coordin
|
||||
troubleshootingURL = dbAgent.TroubleshootingURL
|
||||
}
|
||||
workspaceAgent := codersdk.WorkspaceAgent{
|
||||
ID: dbAgent.ID,
|
||||
CreatedAt: dbAgent.CreatedAt,
|
||||
UpdatedAt: dbAgent.UpdatedAt,
|
||||
ResourceID: dbAgent.ResourceID,
|
||||
InstanceID: dbAgent.AuthInstanceID.String,
|
||||
Name: dbAgent.Name,
|
||||
Architecture: dbAgent.Architecture,
|
||||
OperatingSystem: dbAgent.OperatingSystem,
|
||||
StartupScript: dbAgent.StartupScript.String,
|
||||
Version: dbAgent.Version,
|
||||
EnvironmentVariables: envs,
|
||||
Directory: dbAgent.Directory,
|
||||
Apps: apps,
|
||||
ConnectionTimeoutSeconds: dbAgent.ConnectionTimeoutSeconds,
|
||||
TroubleshootingURL: troubleshootingURL,
|
||||
ID: dbAgent.ID,
|
||||
CreatedAt: dbAgent.CreatedAt,
|
||||
UpdatedAt: dbAgent.UpdatedAt,
|
||||
ResourceID: dbAgent.ResourceID,
|
||||
InstanceID: dbAgent.AuthInstanceID.String,
|
||||
Name: dbAgent.Name,
|
||||
Architecture: dbAgent.Architecture,
|
||||
OperatingSystem: dbAgent.OperatingSystem,
|
||||
StartupScript: dbAgent.StartupScript.String,
|
||||
Version: dbAgent.Version,
|
||||
EnvironmentVariables: envs,
|
||||
Directory: dbAgent.Directory,
|
||||
Apps: apps,
|
||||
ConnectionTimeoutSeconds: dbAgent.ConnectionTimeoutSeconds,
|
||||
TroubleshootingURL: troubleshootingURL,
|
||||
LifecycleState: codersdk.WorkspaceAgentLifecycle(dbAgent.LifecycleState),
|
||||
DelayLoginUntilReady: dbAgent.DelayLoginUntilReady,
|
||||
StartupScriptTimeoutSeconds: dbAgent.StartupScriptTimeoutSeconds,
|
||||
}
|
||||
node := coordinator.Node(dbAgent.ID)
|
||||
if node != nil {
|
||||
@ -900,6 +904,61 @@ func (api *API) workspaceAgentReportStats(rw http.ResponseWriter, r *http.Reques
|
||||
})
|
||||
}
|
||||
|
||||
// @Summary Submit workspace agent lifecycle state
|
||||
// @ID submit-workspace-agent-lifecycle-state
|
||||
// @Security CoderSessionToken
|
||||
// @Accept json
|
||||
// @Tags Agents
|
||||
// @Param request body codersdk.PostWorkspaceAgentLifecycleRequest true "Workspace agent lifecycle request"
|
||||
// @Success 204 "Success"
|
||||
// @Router /workspaceagents/me/report-lifecycle [post]
|
||||
// @x-apidocgen {"skip": true}
|
||||
func (api *API) workspaceAgentReportLifecycle(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
workspaceAgent := httpmw.WorkspaceAgent(r)
|
||||
workspace, err := api.Database.GetWorkspaceByAgentID(ctx, workspaceAgent.ID)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "Failed to get workspace.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var req codersdk.PostWorkspaceAgentLifecycleRequest
|
||||
if !httpapi.Read(ctx, rw, r, &req) {
|
||||
return
|
||||
}
|
||||
|
||||
api.Logger.Debug(ctx, "workspace agent state report",
|
||||
slog.F("agent", workspaceAgent.ID),
|
||||
slog.F("workspace", workspace.ID),
|
||||
slog.F("payload", req),
|
||||
)
|
||||
|
||||
lifecycleState := database.WorkspaceAgentLifecycleState(req.State)
|
||||
if !lifecycleState.Valid() {
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "Invalid lifecycle state.",
|
||||
Detail: fmt.Sprintf("Invalid lifecycle state %q, must be be one of %q.", req.State, database.AllWorkspaceAgentLifecycleStateValues()),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
err = api.Database.UpdateWorkspaceAgentLifecycleStateByID(ctx, database.UpdateWorkspaceAgentLifecycleStateByIDParams{
|
||||
ID: workspaceAgent.ID,
|
||||
LifecycleState: lifecycleState,
|
||||
})
|
||||
if err != nil {
|
||||
httpapi.InternalServerError(rw, err)
|
||||
return
|
||||
}
|
||||
api.publishWorkspaceUpdate(ctx, workspace.ID)
|
||||
|
||||
httpapi.Write(ctx, rw, http.StatusNoContent, nil)
|
||||
}
|
||||
|
||||
// @Summary Submit workspace agent application health
|
||||
// @ID submit-workspace-agent-application-health
|
||||
// @Security CoderSessionToken
|
||||
|
@ -1220,3 +1220,88 @@ func gitAuthCallback(t *testing.T, id string, client *codersdk.Client) *http.Res
|
||||
})
|
||||
return res
|
||||
}
|
||||
|
||||
func TestWorkspaceAgent_LifecycleState(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("Set", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
IncludeProvisionerDaemon: true,
|
||||
})
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
authToken := uuid.NewString()
|
||||
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
|
||||
Parse: echo.ParseComplete,
|
||||
ProvisionPlan: echo.ProvisionComplete,
|
||||
ProvisionApply: []*proto.Provision_Response{{
|
||||
Type: &proto.Provision_Response_Complete{
|
||||
Complete: &proto.Provision_Complete{
|
||||
Resources: []*proto.Resource{{
|
||||
Name: "example",
|
||||
Type: "aws_instance",
|
||||
Agents: []*proto.Agent{{
|
||||
Id: uuid.NewString(),
|
||||
Auth: &proto.Agent_Token{
|
||||
Token: authToken,
|
||||
},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}},
|
||||
})
|
||||
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
|
||||
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
|
||||
|
||||
for _, res := range workspace.LatestBuild.Resources {
|
||||
for _, a := range res.Agents {
|
||||
require.Equal(t, codersdk.WorkspaceAgentLifecycleCreated, a.LifecycleState)
|
||||
}
|
||||
}
|
||||
|
||||
agentClient := codersdk.New(client.URL)
|
||||
agentClient.SetSessionToken(authToken)
|
||||
|
||||
tests := []struct {
|
||||
state codersdk.WorkspaceAgentLifecycle
|
||||
wantErr bool
|
||||
}{
|
||||
{codersdk.WorkspaceAgentLifecycleCreated, false},
|
||||
{codersdk.WorkspaceAgentLifecycleStarting, false},
|
||||
{codersdk.WorkspaceAgentLifecycleStartTimeout, false},
|
||||
{codersdk.WorkspaceAgentLifecycleStartError, false},
|
||||
{codersdk.WorkspaceAgentLifecycleReady, false},
|
||||
{codersdk.WorkspaceAgentLifecycle("nonexistent_state"), true},
|
||||
{codersdk.WorkspaceAgentLifecycle(""), true},
|
||||
}
|
||||
//nolint:paralleltest // No race between setting the state and getting the workspace.
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(string(tt.state), func(t *testing.T) {
|
||||
ctx, _ := testutil.Context(t)
|
||||
|
||||
err := agentClient.PostWorkspaceAgentLifecycle(ctx, codersdk.PostWorkspaceAgentLifecycleRequest{
|
||||
State: tt.state,
|
||||
})
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err, "post lifecycle state %q", tt.state)
|
||||
|
||||
workspace, err = client.Workspace(ctx, workspace.ID)
|
||||
require.NoError(t, err, "get workspace")
|
||||
|
||||
for _, res := range workspace.LatestBuild.Resources {
|
||||
for _, agent := range res.Agents {
|
||||
require.Equal(t, tt.state, agent.LifecycleState)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -217,6 +217,10 @@ func (*client) AgentReportStats(_ context.Context, _ slog.Logger, _ func() *code
|
||||
return io.NopCloser(strings.NewReader("")), nil
|
||||
}
|
||||
|
||||
func (*client) PostWorkspaceAgentLifecycle(_ context.Context, _ codersdk.PostWorkspaceAgentLifecycleRequest) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*client) PostWorkspaceAgentAppHealth(_ context.Context, _ codersdk.PostWorkspaceAppHealthsRequest) error {
|
||||
return nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user