From 40e9c87726f08d143165e17b4a13c7ae760d485d Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Thu, 19 Jan 2023 09:21:00 +0000 Subject: [PATCH 01/23] feat: Add new migrations --- .../migrations/000090_add_workspace_agent_state.down.sql | 3 +++ .../migrations/000090_add_workspace_agent_state.up.sql | 5 +++++ 2 files changed, 8 insertions(+) create mode 100644 coderd/database/migrations/000090_add_workspace_agent_state.down.sql create mode 100644 coderd/database/migrations/000090_add_workspace_agent_state.up.sql diff --git a/coderd/database/migrations/000090_add_workspace_agent_state.down.sql b/coderd/database/migrations/000090_add_workspace_agent_state.down.sql new file mode 100644 index 0000000000000..760610d3f8137 --- /dev/null +++ b/coderd/database/migrations/000090_add_workspace_agent_state.down.sql @@ -0,0 +1,3 @@ +ALTER TABLE workspace_agent DROP COLUMN state; + +DROP TYPE workspace_agent_state; diff --git a/coderd/database/migrations/000090_add_workspace_agent_state.up.sql b/coderd/database/migrations/000090_add_workspace_agent_state.up.sql new file mode 100644 index 0000000000000..e31095d774a91 --- /dev/null +++ b/coderd/database/migrations/000090_add_workspace_agent_state.up.sql @@ -0,0 +1,5 @@ +CREATE TYPE workspace_agent_state AS ENUM ('starting', 'start_timeout', 'start_error', 'ready'); + +ALTER TABLE workspace_agents ADD COLUMN state workspace_agent_state NULL DEFAULT NULL; + +COMMENT ON COLUMN workspace_agents.state IS 'The current state of the workspace agent.'; From 5abf55553eb43e6ffb7038b7fc76425518c01129 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Thu, 19 Jan 2023 09:28:00 +0000 Subject: [PATCH 02/23] Generate database changes --- coderd/database/databasefake/databasefake.go | 13 ++++ coderd/database/dump.sql | 12 +++- ...000091_add_workspace_agent_state.down.sql} | 0 ...> 000091_add_workspace_agent_state.up.sql} | 0 coderd/database/models.go | 66 +++++++++++++++++++ coderd/database/querier.go | 1 + coderd/database/queries.sql.go | 37 +++++++++-- coderd/database/queries/workspaceagents.sql | 8 +++ site/src/api/typesGenerated.ts | 14 ++++ 9 files changed, 144 insertions(+), 7 deletions(-) rename coderd/database/migrations/{000090_add_workspace_agent_state.down.sql => 000091_add_workspace_agent_state.down.sql} (100%) rename coderd/database/migrations/{000090_add_workspace_agent_state.up.sql => 000091_add_workspace_agent_state.up.sql} (100%) diff --git a/coderd/database/databasefake/databasefake.go b/coderd/database/databasefake/databasefake.go index 51a7134ab1d33..7f5583ff4d699 100644 --- a/coderd/database/databasefake/databasefake.go +++ b/coderd/database/databasefake/databasefake.go @@ -4294,3 +4294,16 @@ func (q *fakeQuerier) GetQuotaConsumedForUser(_ context.Context, userID uuid.UUI } return sum, nil } + +func (q *fakeQuerier) UpdateWorkspaceAgentStateByID(_ context.Context, id uuid.UUID, state database.AgentState) error { + q.mutex.Lock() + defer q.mutex.Unlock() + for i, agent := range q.workspaceAgents { + if agent.ID == id { + agent.State = state + q.workspaceAgents[i] = agent + return nil + } + } + return sql.ErrNoRows +} diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index 5f32d13f904c7..d688e5e0dc9ce 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -99,6 +99,13 @@ CREATE TYPE user_status AS ENUM ( 'suspended' ); +CREATE TYPE workspace_agent_state AS ENUM ( + 'starting', + 'start_timeout', + 'start_error', + 'ready' +); + CREATE TYPE workspace_app_health AS ENUM ( 'disabled', 'initializing', @@ -448,7 +455,8 @@ 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, + state workspace_agent_state ); 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 +467,8 @@ 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.state IS 'The current state of the workspace agent.'; + CREATE TABLE workspace_apps ( id uuid NOT NULL, created_at timestamp with time zone NOT NULL, diff --git a/coderd/database/migrations/000090_add_workspace_agent_state.down.sql b/coderd/database/migrations/000091_add_workspace_agent_state.down.sql similarity index 100% rename from coderd/database/migrations/000090_add_workspace_agent_state.down.sql rename to coderd/database/migrations/000091_add_workspace_agent_state.down.sql diff --git a/coderd/database/migrations/000090_add_workspace_agent_state.up.sql b/coderd/database/migrations/000091_add_workspace_agent_state.up.sql similarity index 100% rename from coderd/database/migrations/000090_add_workspace_agent_state.up.sql rename to coderd/database/migrations/000091_add_workspace_agent_state.up.sql diff --git a/coderd/database/models.go b/coderd/database/models.go index e2a9cf2c31845..8090843e9df44 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -1002,6 +1002,70 @@ func AllUserStatusValues() []UserStatus { } } +type WorkspaceAgentState string + +const ( + WorkspaceAgentStateStarting WorkspaceAgentState = "starting" + WorkspaceAgentStateStartTimeout WorkspaceAgentState = "start_timeout" + WorkspaceAgentStateStartError WorkspaceAgentState = "start_error" + WorkspaceAgentStateReady WorkspaceAgentState = "ready" +) + +func (e *WorkspaceAgentState) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = WorkspaceAgentState(s) + case string: + *e = WorkspaceAgentState(s) + default: + return fmt.Errorf("unsupported scan type for WorkspaceAgentState: %T", src) + } + return nil +} + +type NullWorkspaceAgentState struct { + WorkspaceAgentState WorkspaceAgentState + Valid bool // Valid is true if WorkspaceAgentState is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullWorkspaceAgentState) Scan(value interface{}) error { + if value == nil { + ns.WorkspaceAgentState, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.WorkspaceAgentState.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullWorkspaceAgentState) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return ns.WorkspaceAgentState, nil +} + +func (e WorkspaceAgentState) Valid() bool { + switch e { + case WorkspaceAgentStateStarting, + WorkspaceAgentStateStartTimeout, + WorkspaceAgentStateStartError, + WorkspaceAgentStateReady: + return true + } + return false +} + +func AllWorkspaceAgentStateValues() []WorkspaceAgentState { + return []WorkspaceAgentState{ + WorkspaceAgentStateStarting, + WorkspaceAgentStateStartTimeout, + WorkspaceAgentStateStartError, + WorkspaceAgentStateReady, + } +} + type WorkspaceAppHealth string const ( @@ -1448,6 +1512,8 @@ 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 state of the workspace agent. + State NullWorkspaceAgentState `db:"state" json:"state"` } type WorkspaceApp struct { diff --git a/coderd/database/querier.go b/coderd/database/querier.go index 6a11205739c87..812af45541102 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -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 + UpdateWorkspaceAgentStateByID(ctx context.Context, arg UpdateWorkspaceAgentStateByIDParams) error UpdateWorkspaceAgentVersionByID(ctx context.Context, arg UpdateWorkspaceAgentVersionByIDParams) error UpdateWorkspaceAppHealthByID(ctx context.Context, arg UpdateWorkspaceAppHealthByIDParams) error UpdateWorkspaceAutostart(ctx context.Context, arg UpdateWorkspaceAutostartParams) error diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 198ed29bd15a6..2ddfe6e3715d6 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -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, state FROM workspace_agents WHERE @@ -4904,13 +4904,14 @@ func (q *sqlQuerier) GetWorkspaceAgentByAuthToken(ctx context.Context, authToken &i.ConnectionTimeoutSeconds, &i.TroubleshootingURL, &i.MOTDFile, + &i.State, ) 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, state FROM workspace_agents WHERE @@ -4943,13 +4944,14 @@ func (q *sqlQuerier) GetWorkspaceAgentByID(ctx context.Context, id uuid.UUID) (W &i.ConnectionTimeoutSeconds, &i.TroubleshootingURL, &i.MOTDFile, + &i.State, ) 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, state FROM workspace_agents WHERE @@ -4984,13 +4986,14 @@ func (q *sqlQuerier) GetWorkspaceAgentByInstanceID(ctx context.Context, authInst &i.ConnectionTimeoutSeconds, &i.TroubleshootingURL, &i.MOTDFile, + &i.State, ) 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, state FROM workspace_agents WHERE @@ -5029,6 +5032,7 @@ func (q *sqlQuerier) GetWorkspaceAgentsByResourceIDs(ctx context.Context, ids [] &i.ConnectionTimeoutSeconds, &i.TroubleshootingURL, &i.MOTDFile, + &i.State, ); err != nil { return nil, err } @@ -5044,7 +5048,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, state FROM workspace_agents WHERE created_at > $1 ` func (q *sqlQuerier) GetWorkspaceAgentsCreatedAfter(ctx context.Context, createdAt time.Time) ([]WorkspaceAgent, error) { @@ -5079,6 +5083,7 @@ func (q *sqlQuerier) GetWorkspaceAgentsCreatedAfter(ctx context.Context, created &i.ConnectionTimeoutSeconds, &i.TroubleshootingURL, &i.MOTDFile, + &i.State, ); err != nil { return nil, err } @@ -5115,7 +5120,7 @@ INSERT INTO motd_file ) 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) 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, state ` type InsertWorkspaceAgentParams struct { @@ -5182,6 +5187,7 @@ func (q *sqlQuerier) InsertWorkspaceAgent(ctx context.Context, arg InsertWorkspa &i.ConnectionTimeoutSeconds, &i.TroubleshootingURL, &i.MOTDFile, + &i.State, ) return i, err } @@ -5220,6 +5226,25 @@ func (q *sqlQuerier) UpdateWorkspaceAgentConnectionByID(ctx context.Context, arg return err } +const updateWorkspaceAgentStateByID = `-- name: UpdateWorkspaceAgentStateByID :exec +UPDATE + workspace_agents +SET + state = $2 +WHERE + id = $1 +` + +type UpdateWorkspaceAgentStateByIDParams struct { + ID uuid.UUID `db:"id" json:"id"` + State NullWorkspaceAgentState `db:"state" json:"state"` +} + +func (q *sqlQuerier) UpdateWorkspaceAgentStateByID(ctx context.Context, arg UpdateWorkspaceAgentStateByIDParams) error { + _, err := q.db.ExecContext(ctx, updateWorkspaceAgentStateByID, arg.ID, arg.State) + return err +} + const updateWorkspaceAgentVersionByID = `-- name: UpdateWorkspaceAgentVersionByID :exec UPDATE workspace_agents diff --git a/coderd/database/queries/workspaceagents.sql b/coderd/database/queries/workspaceagents.sql index 12193013cec8d..2b5b6e138a2b2 100644 --- a/coderd/database/queries/workspaceagents.sql +++ b/coderd/database/queries/workspaceagents.sql @@ -80,3 +80,11 @@ SET version = $2 WHERE id = $1; + +-- name: UpdateWorkspaceAgentStateByID :exec +UPDATE + workspace_agents +SET + state = $2 +WHERE + id = $1; diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 26bf9a9de44c1..3bf0568adb7aa 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -918,6 +918,7 @@ export interface WorkspaceAgent { readonly last_connected_at?: string readonly disconnected_at?: string readonly status: WorkspaceAgentStatus + readonly state: WorkspaceAgentState readonly name: string readonly resource_id: string readonly instance_id?: string @@ -1225,6 +1226,19 @@ export const TemplateRoles: TemplateRole[] = ["", "admin", "use"] export type UserStatus = "active" | "suspended" export const UserStatuses: UserStatus[] = ["active", "suspended"] +// From codersdk/workspaceagents.go +export type WorkspaceAgentState = + | "ready" + | "start_error" + | "start_timeout" + | "starting" +export const WorkspaceAgentStates: WorkspaceAgentState[] = [ + "ready", + "start_error", + "start_timeout", + "starting", +] + // From codersdk/workspaceagents.go export type WorkspaceAgentStatus = | "connected" From a84e46725456d3e368db121e605374ca49ca5898 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Thu, 19 Jan 2023 09:25:43 +0000 Subject: [PATCH 03/23] feat: Add agent state reporting --- agent/agent.go | 79 +++++++++++++++++--- agent/agent_test.go | 4 + coderd/coderd.go | 1 + coderd/database/databasefake/databasefake.go | 6 +- coderd/workspaceagents.go | 44 +++++++++++ coderd/wsconncache/wsconncache_test.go | 4 + codersdk/workspaceagents.go | 30 ++++++++ 7 files changed, 156 insertions(+), 12 deletions(-) diff --git a/agent/agent.go b/agent/agent.go index 47d9c394a86b9..f3d6860fa499c 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -71,6 +71,7 @@ type Client interface { WorkspaceAgentMetadata(ctx context.Context) (codersdk.WorkspaceAgentMetadata, error) ListenWorkspaceAgent(ctx context.Context) (net.Conn, error) AgentReportStats(ctx context.Context, log slog.Logger, stats func() *codersdk.AgentStats) (io.Closer, error) + PostWorkspaceAgentState(ctx context.Context, state codersdk.PostWorkspaceAgentStateRequest) error PostWorkspaceAgentAppHealth(ctx context.Context, req codersdk.PostWorkspaceAppHealthsRequest) error PostWorkspaceAgentVersion(ctx context.Context, version string) error } @@ -127,6 +128,9 @@ type agent struct { sessionToken atomic.Pointer[string] sshServer *ssh.Server + stateMu sync.Mutex // Protects following. + state codersdk.WorkspaceAgentState + network *tailnet.Conn } @@ -156,6 +160,30 @@ func (a *agent) runLoop(ctx context.Context) { } } +func (a *agent) setState(ctx context.Context, state codersdk.WorkspaceAgentState) { + a.stateMu.Lock() + defer a.stateMu.Unlock() + + a.state = state + + var err error + for r := retry.New(time.Second, 30*time.Second); r.Wait(ctx); { + err = a.client.PostWorkspaceAgentState(ctx, codersdk.PostWorkspaceAgentStateRequest{ + State: state, + }) + if err == nil { + return + } + } + if xerrors.Is(err, context.Canceled) || xerrors.Is(err, context.DeadlineExceeded) || a.isClosed() { + return + } + if err != nil { + // If we fail to report the state we probably shouldn't exit, log only. + a.logger.Error(ctx, "post state", slog.Error(err)) + } +} + func (a *agent) run(ctx context.Context) error { // This allows the agent to refresh it's token if necessary. // For instance identity this is required, since the instance @@ -180,22 +208,55 @@ func (a *agent) run(ctx context.Context) error { // The startup script should only execute on the first run! if oldMetadata == nil { + scriptDone := make(chan error, 1) + scriptStart := time.Now() + go func() { + defer close(scriptDone) + scriptDone <- a.runStartupScript(ctx, metadata.StartupScript) + }() go func() { - err := a.runStartupScript(ctx, metadata.StartupScript) + var timeout <-chan time.Time + // If timeout is zero, an older version of the coder + // provider was used. Otherwise a timeout is always > 0. + if metadata.StartupScriptTimeout > 0 { + t := time.NewTimer(metadata.StartupScriptTimeout) + defer t.Stop() + timeout = t.C + } + + a.setState(ctx, codersdk.WorkspaceAgentStateStarting) + + var err error + select { + case err = <-scriptDone: + case <-timeout: + a.logger.Warn(ctx, "startup script timed out") + a.setState(ctx, codersdk.WorkspaceAgentStateStartTimeout) + err = <-scriptDone // The script can still complete after a timeout. + } if errors.Is(err, context.Canceled) { return } + execTime := time.Since(scriptStart) if err != nil { - a.logger.Warn(ctx, "agent script failed", slog.Error(err)) + a.logger.Warn(ctx, "startup script failed", slog.F("execution_time", execTime), slog.Error(err)) + a.setState(ctx, codersdk.WorkspaceAgentStateStartError) + return } - }() - } + a.logger.Info(ctx, "startup script completed", slog.F("execution_time", execTime)) - if metadata.GitAuthConfigs > 0 { - err = gitauth.OverrideVSCodeConfigs(a.filesystem) - if err != nil { - return xerrors.Errorf("override vscode configuration for git auth: %w", err) - } + // Perform overrides after startup script has completed to ensure + // there is no conflict with the user's scripts. We also want to + // ensure this is done before the workspace is marked as ready. + if metadata.GitAuthConfigs > 0 { + err = gitauth.OverrideVSCodeConfigs(a.filesystem) + if err != nil { + a.logger.Warn(ctx, "failed to override vscode git auth configs", slog.Error(err)) + } + } + + a.setState(ctx, codersdk.WorkspaceAgentStateReady) + }() } // This automatically closes when the context ends! diff --git a/agent/agent_test.go b/agent/agent_test.go index 44b1ff7bf93ae..f9a551c811ba4 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -1130,6 +1130,10 @@ func (c *client) AgentReportStats(ctx context.Context, _ slog.Logger, stats func }), nil } +func (*client) PostWorkspaceAgentState(_ context.Context, _ codersdk.PostWorkspaceAgentStateRequest) error { + return nil +} + func (*client) PostWorkspaceAgentAppHealth(_ context.Context, _ codersdk.PostWorkspaceAppHealthsRequest) error { return nil } diff --git a/coderd/coderd.go b/coderd/coderd.go index 5429eeee9cad9..1db6838898845 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -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-state", api.workspaceAgentReportState) }) r.Route("/{workspaceagent}", func(r chi.Router) { r.Use( diff --git a/coderd/database/databasefake/databasefake.go b/coderd/database/databasefake/databasefake.go index 7f5583ff4d699..16fb158505606 100644 --- a/coderd/database/databasefake/databasefake.go +++ b/coderd/database/databasefake/databasefake.go @@ -4295,12 +4295,12 @@ func (q *fakeQuerier) GetQuotaConsumedForUser(_ context.Context, userID uuid.UUI return sum, nil } -func (q *fakeQuerier) UpdateWorkspaceAgentStateByID(_ context.Context, id uuid.UUID, state database.AgentState) error { +func (q *fakeQuerier) UpdateWorkspaceAgentStateByID(_ context.Context, arg database.UpdateWorkspaceAgentStateByIDParams) error { q.mutex.Lock() defer q.mutex.Unlock() for i, agent := range q.workspaceAgents { - if agent.ID == id { - agent.State = state + if agent.ID == arg.ID { + agent.State = arg.State q.workspaceAgents[i] = agent return nil } diff --git a/coderd/workspaceagents.go b/coderd/workspaceagents.go index 6c2f6f970c3cc..8b9c565638165 100644 --- a/coderd/workspaceagents.go +++ b/coderd/workspaceagents.go @@ -900,6 +900,50 @@ func (api *API) workspaceAgentReportStats(rw http.ResponseWriter, r *http.Reques }) } +// @Summary Submit workspace agent state +// @ID submit-workspace-agent-state +// @Security CoderSessionToken +// @Accept json +// @Tags Agents +// @Param request body codersdk.PostWorkspaceAgentStateRequest true "Workspace agent state request" +// @Success 204 "Success" +// @Router /workspaceagents/me/report-state [post] +func (api *API) workspaceAgentReportState(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.PostWorkspaceAgentStateRequest + 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), + ) + + err = api.Database.UpdateWorkspaceAgentStateByID(ctx, database.UpdateWorkspaceAgentStateByIDParams{ + ID: workspaceAgent.ID, + State: database.WorkspaceAgentState(req.State), + }) + if err != nil { + httpapi.InternalServerError(rw, err) + return + } + + httpapi.Write(ctx, rw, http.StatusNoContent, nil) +} + // @Summary Submit workspace agent application health // @ID submit-workspace-agent-application-health // @Security CoderSessionToken diff --git a/coderd/wsconncache/wsconncache_test.go b/coderd/wsconncache/wsconncache_test.go index edb58891f1178..c0bc915763b21 100644 --- a/coderd/wsconncache/wsconncache_test.go +++ b/coderd/wsconncache/wsconncache_test.go @@ -217,6 +217,10 @@ func (*client) AgentReportStats(_ context.Context, _ slog.Logger, _ func() *code return io.NopCloser(strings.NewReader("")), nil } +func (*client) PostWorkspaceAgentState(_ context.Context, _ codersdk.PostWorkspaceAgentStateRequest) error { + return nil +} + func (*client) PostWorkspaceAgentAppHealth(_ context.Context, _ codersdk.PostWorkspaceAppHealthsRequest) error { return nil } diff --git a/codersdk/workspaceagents.go b/codersdk/workspaceagents.go index 93ac907ab445e..d49bab8345bb9 100644 --- a/codersdk/workspaceagents.go +++ b/codersdk/workspaceagents.go @@ -34,6 +34,16 @@ const ( WorkspaceAgentTimeout WorkspaceAgentStatus = "timeout" ) +// WorkspaceAgentState represents the lifecycle state of a workspace agent. +type WorkspaceAgentState string + +const ( + WorkspaceAgentStateStarting WorkspaceAgentState = "starting" + WorkspaceAgentStateStartTimeout WorkspaceAgentState = "start_timeout" + WorkspaceAgentStateStartError WorkspaceAgentState = "start_error" + WorkspaceAgentStateReady WorkspaceAgentState = "ready" +) + type WorkspaceAgent struct { ID uuid.UUID `json:"id" format:"uuid"` CreatedAt time.Time `json:"created_at" format:"date-time"` @@ -42,6 +52,7 @@ type WorkspaceAgent struct { LastConnectedAt *time.Time `json:"last_connected_at,omitempty" format:"date-time"` DisconnectedAt *time.Time `json:"disconnected_at,omitempty" format:"date-time"` Status WorkspaceAgentStatus `json:"status" enums:"connecting,connected,disconnected,timeout"` + State WorkspaceAgentState `json:"state" enums:"starting,start_timeout,start_error,ready"` Name string `json:"name"` ResourceID uuid.UUID `json:"resource_id" format:"uuid"` InstanceID string `json:"instance_id,omitempty"` @@ -131,6 +142,7 @@ type WorkspaceAgentMetadata struct { DERPMap *tailcfg.DERPMap `json:"derpmap"` EnvironmentVariables map[string]string `json:"environment_variables"` StartupScript string `json:"startup_script"` + StartupScriptTimeout time.Duration `json:"startup_script_timeout" format:"duration"` Directory string `json:"directory"` MOTDFile string `json:"motd_file"` } @@ -681,3 +693,21 @@ func (c *Client) WorkspaceAgentGitAuth(ctx context.Context, gitURL string, liste var authResp WorkspaceAgentGitAuthResponse return authResp, json.NewDecoder(res.Body).Decode(&authResp) } + +// @typescript-ignore PostWorkspaceAgentStateRequest +type PostWorkspaceAgentStateRequest struct { + State WorkspaceAgentState `json:"state"` +} + +func (c *Client) PostWorkspaceAgentState(ctx context.Context, req PostWorkspaceAgentStateRequest) error { + res, err := c.Request(ctx, http.MethodPost, "/api/v2/workspaceagents/me/report-state", req) + if err != nil { + return xerrors.Errorf("agent state post request: %w", err) + } + defer res.Body.Close() + if res.StatusCode != http.StatusOK { + return readBodyAsError(res) + } + + return nil +} From 8119e71c37e9a73f9f1e2ba1d93284391032945f Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Thu, 19 Jan 2023 09:29:28 +0000 Subject: [PATCH 04/23] Generate docs --- coderd/apidoc/docs.go | 72 ++++++++++++++++++++++++++++++++++ coderd/apidoc/swagger.json | 58 ++++++++++++++++++++++++++++ codersdk/workspaceagents.go | 2 +- docs/api/agents.md | 37 ++++++++++++++++++ docs/api/builds.md | 16 ++++++++ docs/api/schemas.md | 77 +++++++++++++++++++++++++++++-------- docs/api/templates.md | 12 ++++++ docs/api/workspaces.md | 4 ++ 8 files changed, 260 insertions(+), 18 deletions(-) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 1ec2452a6da59..d81f0db6dbefd 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -3973,6 +3973,39 @@ const docTemplate = `{ } } }, + "/workspaceagents/me/report-state": { + "post": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "consumes": [ + "application/json" + ], + "tags": [ + "Agents" + ], + "summary": "Submit workspace agent state", + "operationId": "submit-workspace-agent-state", + "parameters": [ + { + "description": "Workspace agent state request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.PostWorkspaceAgentStateRequest" + } + } + ], + "responses": { + "204": { + "description": "Success" + } + } + } + }, "/workspaceagents/me/report-stats": { "post": { "security": [ @@ -6717,6 +6750,14 @@ const docTemplate = `{ "ParameterSourceSchemeData" ] }, + "codersdk.PostWorkspaceAgentStateRequest": { + "type": "object", + "properties": { + "state": { + "$ref": "#/definitions/codersdk.WorkspaceAgentState" + } + } + }, "codersdk.PostWorkspaceAgentVersionRequest": { "description": "x-apidocgen:skip", "type": "object", @@ -7693,6 +7734,19 @@ const docTemplate = `{ "startup_script": { "type": "string" }, + "state": { + "enum": [ + "starting", + "start_timeout", + "start_error", + "ready" + ], + "allOf": [ + { + "$ref": "#/definitions/codersdk.WorkspaceAgentState" + } + ] + }, "status": { "enum": [ "connecting", @@ -7779,11 +7833,29 @@ const docTemplate = `{ "startup_script": { "type": "string" }, + "startup_script_timeout": { + "type": "integer" + }, "vscode_port_proxy_uri": { "type": "string" } } }, + "codersdk.WorkspaceAgentState": { + "type": "string", + "enum": [ + "starting", + "start_timeout", + "start_error", + "ready" + ], + "x-enum-varnames": [ + "WorkspaceAgentStateStarting", + "WorkspaceAgentStateStartTimeout", + "WorkspaceAgentStateStartError", + "WorkspaceAgentStateReady" + ] + }, "codersdk.WorkspaceAgentStatus": { "type": "string", "enum": [ diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 33dfd90093f52..fed588df6d83e 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -3493,6 +3493,35 @@ } } }, + "/workspaceagents/me/report-state": { + "post": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "consumes": ["application/json"], + "tags": ["Agents"], + "summary": "Submit workspace agent state", + "operationId": "submit-workspace-agent-state", + "parameters": [ + { + "description": "Workspace agent state request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.PostWorkspaceAgentStateRequest" + } + } + ], + "responses": { + "204": { + "description": "Success" + } + } + } + }, "/workspaceagents/me/report-stats": { "post": { "security": [ @@ -6000,6 +6029,14 @@ "ParameterSourceSchemeData" ] }, + "codersdk.PostWorkspaceAgentStateRequest": { + "type": "object", + "properties": { + "state": { + "$ref": "#/definitions/codersdk.WorkspaceAgentState" + } + } + }, "codersdk.PostWorkspaceAgentVersionRequest": { "description": "x-apidocgen:skip", "type": "object", @@ -6928,6 +6965,14 @@ "startup_script": { "type": "string" }, + "state": { + "enum": ["starting", "start_timeout", "start_error", "ready"], + "allOf": [ + { + "$ref": "#/definitions/codersdk.WorkspaceAgentState" + } + ] + }, "status": { "enum": ["connecting", "connected", "disconnected", "timeout"], "allOf": [ @@ -7009,11 +7054,24 @@ "startup_script": { "type": "string" }, + "startup_script_timeout": { + "type": "integer" + }, "vscode_port_proxy_uri": { "type": "string" } } }, + "codersdk.WorkspaceAgentState": { + "type": "string", + "enum": ["starting", "start_timeout", "start_error", "ready"], + "x-enum-varnames": [ + "WorkspaceAgentStateStarting", + "WorkspaceAgentStateStartTimeout", + "WorkspaceAgentStateStartError", + "WorkspaceAgentStateReady" + ] + }, "codersdk.WorkspaceAgentStatus": { "type": "string", "enum": ["connecting", "connected", "disconnected", "timeout"], diff --git a/codersdk/workspaceagents.go b/codersdk/workspaceagents.go index d49bab8345bb9..ef5a4279f482c 100644 --- a/codersdk/workspaceagents.go +++ b/codersdk/workspaceagents.go @@ -142,7 +142,7 @@ type WorkspaceAgentMetadata struct { DERPMap *tailcfg.DERPMap `json:"derpmap"` EnvironmentVariables map[string]string `json:"environment_variables"` StartupScript string `json:"startup_script"` - StartupScriptTimeout time.Duration `json:"startup_script_timeout" format:"duration"` + StartupScriptTimeout time.Duration `json:"startup_script_timeout"` Directory string `json:"directory"` MOTDFile string `json:"motd_file"` } diff --git a/docs/api/agents.md b/docs/api/agents.md index b43626f5c94bd..fefb1e0e91390 100644 --- a/docs/api/agents.md +++ b/docs/api/agents.md @@ -370,6 +370,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaceagents/me/metadata \ "git_auth_configs": 0, "motd_file": "string", "startup_script": "string", + "startup_script_timeout": 0, "vscode_port_proxy_uri": "string" } ``` @@ -382,6 +383,41 @@ curl -X GET http://coder-server:8080/api/v2/workspaceagents/me/metadata \ To perform this operation, you must be authenticated. [Learn more](authentication.md). +## Submit workspace agent state + +### Code samples + +```shell +# Example request using curl +curl -X POST http://coder-server:8080/api/v2/workspaceagents/me/report-state \ + -H 'Content-Type: application/json' \ + -H 'Coder-Session-Token: API_KEY' +``` + +`POST /workspaceagents/me/report-state` + +> Body parameter + +```json +{ + "state": "starting" +} +``` + +### Parameters + +| Name | In | Type | Required | Description | +| ------ | ---- | -------------------------------------------------------------------------------------------- | -------- | ----------------------------- | +| `body` | body | [codersdk.PostWorkspaceAgentStateRequest](schemas.md#codersdkpostworkspaceagentstaterequest) | true | Workspace agent state request | + +### Responses + +| Status | Meaning | Description | Schema | +| ------ | --------------------------------------------------------------- | ----------- | ------ | +| 204 | [No Content](https://tools.ietf.org/html/rfc7231#section-6.3.5) | Success | | + +To perform this operation, you must be authenticated. [Learn more](authentication.md). + ## Submit workspace agent stats ### Code samples @@ -507,6 +543,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaceagents/{workspaceagent} \ "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", diff --git a/docs/api/builds.md b/docs/api/builds.md index 89b30d46d6d48..87e51ffeb5536 100644 --- a/docs/api/builds.md +++ b/docs/api/builds.md @@ -100,6 +100,7 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/workspace/{workspacenam "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -242,6 +243,7 @@ curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild} \ "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -527,6 +529,7 @@ curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild}/res "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -601,6 +604,7 @@ Status Code **200** | `»» operating_system` | string | false | | | | `»» resource_id` | string(uuid) | false | | | | `»» startup_script` | string | false | | | +| `»» state` | [codersdk.WorkspaceAgentState](schemas.md#codersdkworkspaceagentstate) | false | | | | `»» status` | [codersdk.WorkspaceAgentStatus](schemas.md#codersdkworkspaceagentstatus) | false | | | | `»» troubleshooting_url` | string | false | | | | `»» updated_at` | string(date-time) | false | | | @@ -630,6 +634,10 @@ Status Code **200** | `sharing_level` | `owner` | | `sharing_level` | `authenticated` | | `sharing_level` | `public` | +| `state` | `starting` | +| `state` | `start_timeout` | +| `state` | `start_error` | +| `state` | `ready` | | `status` | `connecting` | | `status` | `connected` | | `status` | `disconnected` | @@ -738,6 +746,7 @@ curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild}/sta "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -885,6 +894,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace}/builds \ "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -991,6 +1001,7 @@ Status Code **200** | `»»» operating_system` | string | false | | | | `»»» resource_id` | string(uuid) | false | | | | `»»» startup_script` | string | false | | | +| `»»» state` | [codersdk.WorkspaceAgentState](schemas.md#codersdkworkspaceagentstate) | false | | | | `»»» status` | [codersdk.WorkspaceAgentStatus](schemas.md#codersdkworkspaceagentstatus) | false | | | | `»»» troubleshooting_url` | string | false | | | | `»»» updated_at` | string(date-time) | false | | | @@ -1038,6 +1049,10 @@ Status Code **200** | `sharing_level` | `owner` | | `sharing_level` | `authenticated` | | `sharing_level` | `public` | +| `state` | `starting` | +| `state` | `start_timeout` | +| `state` | `start_error` | +| `state` | `ready` | | `status` | `connecting` | | `status` | `connected` | | `status` | `disconnected` | @@ -1188,6 +1203,7 @@ curl -X POST http://coder-server:8080/api/v2/workspaces/{workspace}/builds \ "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", diff --git a/docs/api/schemas.md b/docs/api/schemas.md index d242e8bd22fae..b66a1e92ea8bf 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -3320,6 +3320,20 @@ Parameter represents a set value for the scope. | `none` | | `data` | +## codersdk.PostWorkspaceAgentStateRequest + +```json +{ + "state": "starting" +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +| ------- | ------------------------------------------------------------ | -------- | ------------ | ----------- | +| `state` | [codersdk.WorkspaceAgentState](#codersdkworkspaceagentstate) | false | | | + ## codersdk.PostWorkspaceAppHealthsRequest ```json @@ -4583,6 +4597,7 @@ Parameter represents a set value for the scope. "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -4702,6 +4717,7 @@ Parameter represents a set value for the scope. "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -4731,6 +4747,7 @@ Parameter represents a set value for the scope. | `operating_system` | string | false | | | | `resource_id` | string | false | | | | `startup_script` | string | false | | | +| `state` | [codersdk.WorkspaceAgentState](#codersdkworkspaceagentstate) | false | | | | `status` | [codersdk.WorkspaceAgentStatus](#codersdkworkspaceagentstatus) | false | | | | `troubleshooting_url` | string | false | | | | `updated_at` | string | false | | | @@ -4738,12 +4755,16 @@ Parameter represents a set value for the scope. #### Enumerated Values -| Property | Value | -| -------- | -------------- | -| `status` | `connecting` | -| `status` | `connected` | -| `status` | `disconnected` | -| `status` | `timeout` | +| Property | Value | +| -------- | --------------- | +| `state` | `starting` | +| `state` | `start_timeout` | +| `state` | `start_error` | +| `state` | `ready` | +| `status` | `connecting` | +| `status` | `connected` | +| `status` | `disconnected` | +| `status` | `timeout` | ## codersdk.WorkspaceAgentAuthenticateResponse @@ -4923,23 +4944,42 @@ Parameter represents a set value for the scope. "git_auth_configs": 0, "motd_file": "string", "startup_script": "string", + "startup_script_timeout": 0, "vscode_port_proxy_uri": "string" } ``` ### Properties -| Name | Type | Required | Restrictions | Description | -| ----------------------- | ------------------------------------------------------- | -------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `apps` | array of [codersdk.WorkspaceApp](#codersdkworkspaceapp) | false | | | -| `derpmap` | [tailcfg.DERPMap](#tailcfgderpmap) | false | | | -| `directory` | string | false | | | -| `environment_variables` | object | false | | | -| » `[any property]` | string | false | | | -| `git_auth_configs` | integer | false | | Git auth configs stores the number of Git configurations the Coder deployment has. If this number is >0, we set up special configuration in the workspace. | -| `motd_file` | string | false | | | -| `startup_script` | string | false | | | -| `vscode_port_proxy_uri` | string | false | | | +| Name | Type | Required | Restrictions | Description | +| ------------------------ | ------------------------------------------------------- | -------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `apps` | array of [codersdk.WorkspaceApp](#codersdkworkspaceapp) | false | | | +| `derpmap` | [tailcfg.DERPMap](#tailcfgderpmap) | false | | | +| `directory` | string | false | | | +| `environment_variables` | object | false | | | +| » `[any property]` | string | false | | | +| `git_auth_configs` | integer | false | | Git auth configs stores the number of Git configurations the Coder deployment has. If this number is >0, we set up special configuration in the workspace. | +| `motd_file` | string | false | | | +| `startup_script` | string | false | | | +| `startup_script_timeout` | integer | false | | | +| `vscode_port_proxy_uri` | string | false | | | + +## codersdk.WorkspaceAgentState + +```json +"starting" +``` + +### Properties + +#### Enumerated Values + +| Value | +| --------------- | +| `starting` | +| `start_timeout` | +| `start_error` | +| `ready` | ## codersdk.WorkspaceAgentStatus @@ -5114,6 +5154,7 @@ Parameter represents a set value for the scope. "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -5279,6 +5320,7 @@ Parameter represents a set value for the scope. "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -5466,6 +5508,7 @@ Parameter represents a set value for the scope. "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", diff --git a/docs/api/templates.md b/docs/api/templates.md index 6a2b81d49b973..62487489939d1 100644 --- a/docs/api/templates.md +++ b/docs/api/templates.md @@ -1576,6 +1576,7 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/d "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -1650,6 +1651,7 @@ Status Code **200** | `»» operating_system` | string | false | | | | `»» resource_id` | string(uuid) | false | | | | `»» startup_script` | string | false | | | +| `»» state` | [codersdk.WorkspaceAgentState](schemas.md#codersdkworkspaceagentstate) | false | | | | `»» status` | [codersdk.WorkspaceAgentStatus](schemas.md#codersdkworkspaceagentstatus) | false | | | | `»» troubleshooting_url` | string | false | | | | `»» updated_at` | string(date-time) | false | | | @@ -1679,6 +1681,10 @@ Status Code **200** | `sharing_level` | `owner` | | `sharing_level` | `authenticated` | | `sharing_level` | `public` | +| `state` | `starting` | +| `state` | `start_timeout` | +| `state` | `start_error` | +| `state` | `ready` | | `status` | `connecting` | | `status` | `connected` | | `status` | `disconnected` | @@ -1917,6 +1923,7 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/r "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -1991,6 +1998,7 @@ Status Code **200** | `»» operating_system` | string | false | | | | `»» resource_id` | string(uuid) | false | | | | `»» startup_script` | string | false | | | +| `»» state` | [codersdk.WorkspaceAgentState](schemas.md#codersdkworkspaceagentstate) | false | | | | `»» status` | [codersdk.WorkspaceAgentStatus](schemas.md#codersdkworkspaceagentstatus) | false | | | | `»» troubleshooting_url` | string | false | | | | `»» updated_at` | string(date-time) | false | | | @@ -2020,6 +2028,10 @@ Status Code **200** | `sharing_level` | `owner` | | `sharing_level` | `authenticated` | | `sharing_level` | `public` | +| `state` | `starting` | +| `state` | `start_timeout` | +| `state` | `start_error` | +| `state` | `ready` | | `status` | `connecting` | | `status` | `connected` | | `status` | `disconnected` | diff --git a/docs/api/workspaces.md b/docs/api/workspaces.md index e552bc6b4236c..6f97bf5661253 100644 --- a/docs/api/workspaces.md +++ b/docs/api/workspaces.md @@ -104,6 +104,7 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/member "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -265,6 +266,7 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/workspace/{workspacenam "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -445,6 +447,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces \ "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -607,6 +610,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace} \ "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", From 515e342ac3b5d573c249ae989bbcc1b770107e5b Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Thu, 19 Jan 2023 12:54:50 +0000 Subject: [PATCH 05/23] WIP --- coderd/coderdtest/authorize.go | 1 + .../migrations/000091_add_workspace_agent_state.down.sql | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/coderd/coderdtest/authorize.go b/coderd/coderdtest/authorize.go index 1924ca2e41b9d..e1b0e7fcd4fb8 100644 --- a/coderd/coderdtest/authorize.go +++ b/coderd/coderdtest/authorize.go @@ -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-state": {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)}, diff --git a/coderd/database/migrations/000091_add_workspace_agent_state.down.sql b/coderd/database/migrations/000091_add_workspace_agent_state.down.sql index 760610d3f8137..7fa324957d981 100644 --- a/coderd/database/migrations/000091_add_workspace_agent_state.down.sql +++ b/coderd/database/migrations/000091_add_workspace_agent_state.down.sql @@ -1,3 +1,3 @@ -ALTER TABLE workspace_agent DROP COLUMN state; +ALTER TABLE workspace_agents DROP COLUMN state; DROP TYPE workspace_agent_state; From 1e53635ca6ae5ff72e37c7df6f4831e5a1d13425 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Thu, 19 Jan 2023 13:46:40 +0000 Subject: [PATCH 06/23] Rename state -> lifecycle state --- agent/agent.go | 24 ++-- agent/agent_test.go | 2 +- coderd/apidoc/docs.go | 74 +++++------ coderd/apidoc/swagger.json | 53 ++++---- coderd/coderd.go | 2 +- coderd/coderdtest/authorize.go | 8 +- coderd/database/databasefake/databasefake.go | 4 +- coderd/database/dump.sql | 7 +- .../000091_add_workspace_agent_state.down.sql | 4 +- .../000091_add_workspace_agent_state.up.sql | 6 +- coderd/database/models.go | 63 +++++----- coderd/database/querier.go | 2 +- coderd/database/queries.sql.go | 38 +++--- coderd/database/queries/workspaceagents.sql | 4 +- coderd/workspaceagents.go | 18 +-- coderd/wsconncache/wsconncache_test.go | 2 +- codersdk/workspaceagents.go | 68 +++++----- docs/api/agents.md | 16 +-- docs/api/builds.md | 34 ++--- docs/api/schemas.md | 118 ++++++++---------- docs/api/templates.md | 26 ++-- docs/api/workspaces.md | 8 +- site/src/api/typesGenerated.ts | 8 +- 23 files changed, 286 insertions(+), 303 deletions(-) diff --git a/agent/agent.go b/agent/agent.go index f3d6860fa499c..5638bab2052a2 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -71,7 +71,7 @@ type Client interface { WorkspaceAgentMetadata(ctx context.Context) (codersdk.WorkspaceAgentMetadata, error) ListenWorkspaceAgent(ctx context.Context) (net.Conn, error) AgentReportStats(ctx context.Context, log slog.Logger, stats func() *codersdk.AgentStats) (io.Closer, error) - PostWorkspaceAgentState(ctx context.Context, state codersdk.PostWorkspaceAgentStateRequest) error + PostWorkspaceAgentLifecycle(ctx context.Context, state codersdk.PostWorkspaceAgentLifecycleRequest) error PostWorkspaceAgentAppHealth(ctx context.Context, req codersdk.PostWorkspaceAppHealthsRequest) error PostWorkspaceAgentVersion(ctx context.Context, version string) error } @@ -128,8 +128,8 @@ type agent struct { sessionToken atomic.Pointer[string] sshServer *ssh.Server - stateMu sync.Mutex // Protects following. - state codersdk.WorkspaceAgentState + lifecycleMu sync.Mutex // Protects following. + lifecycleState codersdk.WorkspaceAgentLifecycle network *tailnet.Conn } @@ -160,15 +160,15 @@ func (a *agent) runLoop(ctx context.Context) { } } -func (a *agent) setState(ctx context.Context, state codersdk.WorkspaceAgentState) { - a.stateMu.Lock() - defer a.stateMu.Unlock() +func (a *agent) setLifecycle(ctx context.Context, state codersdk.WorkspaceAgentLifecycle) { + a.lifecycleMu.Lock() + defer a.lifecycleMu.Unlock() - a.state = state + a.lifecycleState = state var err error for r := retry.New(time.Second, 30*time.Second); r.Wait(ctx); { - err = a.client.PostWorkspaceAgentState(ctx, codersdk.PostWorkspaceAgentStateRequest{ + err = a.client.PostWorkspaceAgentLifecycle(ctx, codersdk.PostWorkspaceAgentLifecycleRequest{ State: state, }) if err == nil { @@ -224,14 +224,14 @@ func (a *agent) run(ctx context.Context) error { timeout = t.C } - a.setState(ctx, codersdk.WorkspaceAgentStateStarting) + a.setLifecycle(ctx, codersdk.WorkspaceAgentLifecycleStarting) var err error select { case err = <-scriptDone: case <-timeout: a.logger.Warn(ctx, "startup script timed out") - a.setState(ctx, codersdk.WorkspaceAgentStateStartTimeout) + a.setLifecycle(ctx, codersdk.WorkspaceAgentLifecycleStartTimeout) err = <-scriptDone // The script can still complete after a timeout. } if errors.Is(err, context.Canceled) { @@ -240,7 +240,7 @@ func (a *agent) run(ctx context.Context) error { execTime := time.Since(scriptStart) if err != nil { a.logger.Warn(ctx, "startup script failed", slog.F("execution_time", execTime), slog.Error(err)) - a.setState(ctx, codersdk.WorkspaceAgentStateStartError) + a.setLifecycle(ctx, codersdk.WorkspaceAgentLifecycleStartError) return } a.logger.Info(ctx, "startup script completed", slog.F("execution_time", execTime)) @@ -255,7 +255,7 @@ func (a *agent) run(ctx context.Context) error { } } - a.setState(ctx, codersdk.WorkspaceAgentStateReady) + a.setLifecycle(ctx, codersdk.WorkspaceAgentLifecycleReady) }() } diff --git a/agent/agent_test.go b/agent/agent_test.go index f9a551c811ba4..29b13eebce241 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -1130,7 +1130,7 @@ func (c *client) AgentReportStats(ctx context.Context, _ slog.Logger, stats func }), nil } -func (*client) PostWorkspaceAgentState(_ context.Context, _ codersdk.PostWorkspaceAgentStateRequest) error { +func (*client) PostWorkspaceAgentLifecycle(_ context.Context, _ codersdk.PostWorkspaceAgentLifecycleRequest) error { return nil } diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index d81f0db6dbefd..98ec0e769646a 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -3973,7 +3973,7 @@ const docTemplate = `{ } } }, - "/workspaceagents/me/report-state": { + "/workspaceagents/me/report-lifecycle": { "post": { "security": [ { @@ -3986,16 +3986,16 @@ const docTemplate = `{ "tags": [ "Agents" ], - "summary": "Submit workspace agent state", - "operationId": "submit-workspace-agent-state", + "summary": "Submit workspace agent lifecycle state", + "operationId": "submit-workspace-agent-lifecycle-state", "parameters": [ { - "description": "Workspace agent state request", + "description": "Workspace agent lifecycle request", "name": "request", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/codersdk.PostWorkspaceAgentStateRequest" + "$ref": "#/definitions/codersdk.PostWorkspaceAgentLifecycleRequest" } } ], @@ -6750,11 +6750,11 @@ const docTemplate = `{ "ParameterSourceSchemeData" ] }, - "codersdk.PostWorkspaceAgentStateRequest": { + "codersdk.PostWorkspaceAgentLifecycleRequest": { "type": "object", "properties": { "state": { - "$ref": "#/definitions/codersdk.WorkspaceAgentState" + "$ref": "#/definitions/codersdk.WorkspaceAgentLifecycle" } } }, @@ -7721,6 +7721,9 @@ const docTemplate = `{ "$ref": "#/definitions/codersdk.DERPRegion" } }, + "lifecycle_state": { + "$ref": "#/definitions/codersdk.WorkspaceAgentLifecycle" + }, "name": { "type": "string" }, @@ -7734,31 +7737,8 @@ const docTemplate = `{ "startup_script": { "type": "string" }, - "state": { - "enum": [ - "starting", - "start_timeout", - "start_error", - "ready" - ], - "allOf": [ - { - "$ref": "#/definitions/codersdk.WorkspaceAgentState" - } - ] - }, "status": { - "enum": [ - "connecting", - "connected", - "disconnected", - "timeout" - ], - "allOf": [ - { - "$ref": "#/definitions/codersdk.WorkspaceAgentStatus" - } - ] + "$ref": "#/definitions/codersdk.WorkspaceAgentStatus" }, "troubleshooting_url": { "type": "string" @@ -7802,6 +7782,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": { @@ -7841,21 +7838,6 @@ const docTemplate = `{ } } }, - "codersdk.WorkspaceAgentState": { - "type": "string", - "enum": [ - "starting", - "start_timeout", - "start_error", - "ready" - ], - "x-enum-varnames": [ - "WorkspaceAgentStateStarting", - "WorkspaceAgentStateStartTimeout", - "WorkspaceAgentStateStartError", - "WorkspaceAgentStateReady" - ] - }, "codersdk.WorkspaceAgentStatus": { "type": "string", "enum": [ diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index fed588df6d83e..991b3e3caff4f 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -3493,7 +3493,7 @@ } } }, - "/workspaceagents/me/report-state": { + "/workspaceagents/me/report-lifecycle": { "post": { "security": [ { @@ -3502,16 +3502,16 @@ ], "consumes": ["application/json"], "tags": ["Agents"], - "summary": "Submit workspace agent state", - "operationId": "submit-workspace-agent-state", + "summary": "Submit workspace agent lifecycle state", + "operationId": "submit-workspace-agent-lifecycle-state", "parameters": [ { - "description": "Workspace agent state request", + "description": "Workspace agent lifecycle request", "name": "request", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/codersdk.PostWorkspaceAgentStateRequest" + "$ref": "#/definitions/codersdk.PostWorkspaceAgentLifecycleRequest" } } ], @@ -6029,11 +6029,11 @@ "ParameterSourceSchemeData" ] }, - "codersdk.PostWorkspaceAgentStateRequest": { + "codersdk.PostWorkspaceAgentLifecycleRequest": { "type": "object", "properties": { "state": { - "$ref": "#/definitions/codersdk.WorkspaceAgentState" + "$ref": "#/definitions/codersdk.WorkspaceAgentLifecycle" } } }, @@ -6952,6 +6952,9 @@ "$ref": "#/definitions/codersdk.DERPRegion" } }, + "lifecycle_state": { + "$ref": "#/definitions/codersdk.WorkspaceAgentLifecycle" + }, "name": { "type": "string" }, @@ -6965,21 +6968,8 @@ "startup_script": { "type": "string" }, - "state": { - "enum": ["starting", "start_timeout", "start_error", "ready"], - "allOf": [ - { - "$ref": "#/definitions/codersdk.WorkspaceAgentState" - } - ] - }, "status": { - "enum": ["connecting", "connected", "disconnected", "timeout"], - "allOf": [ - { - "$ref": "#/definitions/codersdk.WorkspaceAgentStatus" - } - ] + "$ref": "#/definitions/codersdk.WorkspaceAgentStatus" }, "troubleshooting_url": { "type": "string" @@ -7023,6 +7013,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": { @@ -7062,16 +7063,6 @@ } } }, - "codersdk.WorkspaceAgentState": { - "type": "string", - "enum": ["starting", "start_timeout", "start_error", "ready"], - "x-enum-varnames": [ - "WorkspaceAgentStateStarting", - "WorkspaceAgentStateStartTimeout", - "WorkspaceAgentStateStartError", - "WorkspaceAgentStateReady" - ] - }, "codersdk.WorkspaceAgentStatus": { "type": "string", "enum": ["connecting", "connected", "disconnected", "timeout"], diff --git a/coderd/coderd.go b/coderd/coderd.go index 1db6838898845..6119497796354 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -541,7 +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-state", api.workspaceAgentReportState) + r.Post("/report-lifecycle", api.workspaceAgentReportLifecycle) }) r.Route("/{workspaceagent}", func(r chi.Router) { r.Use( diff --git a/coderd/coderdtest/authorize.go b/coderd/coderdtest/authorize.go index e1b0e7fcd4fb8..462dcc644f56f 100644 --- a/coderd/coderdtest/authorize.go +++ b/coderd/coderdtest/authorize.go @@ -75,7 +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-state": {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)}, @@ -277,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 diff --git a/coderd/database/databasefake/databasefake.go b/coderd/database/databasefake/databasefake.go index 16fb158505606..829f7d5071938 100644 --- a/coderd/database/databasefake/databasefake.go +++ b/coderd/database/databasefake/databasefake.go @@ -4295,12 +4295,12 @@ func (q *fakeQuerier) GetQuotaConsumedForUser(_ context.Context, userID uuid.UUI return sum, nil } -func (q *fakeQuerier) UpdateWorkspaceAgentStateByID(_ context.Context, arg database.UpdateWorkspaceAgentStateByIDParams) error { +func (q *fakeQuerier) UpdateWorkspaceAgentLifecycleStateByID(_ context.Context, arg database.UpdateWorkspaceAgentLifecycleStateByIDParams) error { q.mutex.Lock() defer q.mutex.Unlock() for i, agent := range q.workspaceAgents { if agent.ID == arg.ID { - agent.State = arg.State + agent.LifecycleState = arg.LifecycleState q.workspaceAgents[i] = agent return nil } diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index d688e5e0dc9ce..2a93ec2f4c77c 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -99,7 +99,8 @@ CREATE TYPE user_status AS ENUM ( 'suspended' ); -CREATE TYPE workspace_agent_state AS ENUM ( +CREATE TYPE workspace_agent_lifecycle_state AS ENUM ( + 'created', 'starting', 'start_timeout', 'start_error', @@ -456,7 +457,7 @@ CREATE TABLE workspace_agents ( connection_timeout_seconds integer DEFAULT 0 NOT NULL, troubleshooting_url text DEFAULT ''::text NOT NULL, motd_file text DEFAULT ''::text NOT NULL, - state workspace_agent_state + lifecycle_state workspace_agent_lifecycle_state DEFAULT 'created'::workspace_agent_lifecycle_state 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.'; @@ -467,7 +468,7 @@ 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.state IS 'The current state of the workspace agent.'; +COMMENT ON COLUMN workspace_agents.lifecycle_state IS 'The current lifecycle state of the workspace agent.'; CREATE TABLE workspace_apps ( id uuid NOT NULL, diff --git a/coderd/database/migrations/000091_add_workspace_agent_state.down.sql b/coderd/database/migrations/000091_add_workspace_agent_state.down.sql index 7fa324957d981..fec6cec86818c 100644 --- a/coderd/database/migrations/000091_add_workspace_agent_state.down.sql +++ b/coderd/database/migrations/000091_add_workspace_agent_state.down.sql @@ -1,3 +1,3 @@ -ALTER TABLE workspace_agents DROP COLUMN state; +ALTER TABLE workspace_agents DROP COLUMN lifecycle_state; -DROP TYPE workspace_agent_state; +DROP TYPE workspace_agent_lifecycle_state; diff --git a/coderd/database/migrations/000091_add_workspace_agent_state.up.sql b/coderd/database/migrations/000091_add_workspace_agent_state.up.sql index e31095d774a91..4057f3bc8b206 100644 --- a/coderd/database/migrations/000091_add_workspace_agent_state.up.sql +++ b/coderd/database/migrations/000091_add_workspace_agent_state.up.sql @@ -1,5 +1,5 @@ -CREATE TYPE workspace_agent_state AS ENUM ('starting', 'start_timeout', 'start_error', 'ready'); +CREATE TYPE workspace_agent_lifecycle_state AS ENUM ('created', 'starting', 'start_timeout', 'start_error', 'ready'); -ALTER TABLE workspace_agents ADD COLUMN state workspace_agent_state NULL DEFAULT NULL; +ALTER TABLE workspace_agents ADD COLUMN lifecycle_state workspace_agent_lifecycle_state NOT NULL DEFAULT 'created'; -COMMENT ON COLUMN workspace_agents.state IS 'The current state of the workspace agent.'; +COMMENT ON COLUMN workspace_agents.lifecycle_state IS 'The current lifecycle state of the workspace agent.'; diff --git a/coderd/database/models.go b/coderd/database/models.go index 8090843e9df44..05f5b613f7a65 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -1002,67 +1002,70 @@ func AllUserStatusValues() []UserStatus { } } -type WorkspaceAgentState string +type WorkspaceAgentLifecycleState string const ( - WorkspaceAgentStateStarting WorkspaceAgentState = "starting" - WorkspaceAgentStateStartTimeout WorkspaceAgentState = "start_timeout" - WorkspaceAgentStateStartError WorkspaceAgentState = "start_error" - WorkspaceAgentStateReady WorkspaceAgentState = "ready" + WorkspaceAgentLifecycleStateCreated WorkspaceAgentLifecycleState = "created" + WorkspaceAgentLifecycleStateStarting WorkspaceAgentLifecycleState = "starting" + WorkspaceAgentLifecycleStateStartTimeout WorkspaceAgentLifecycleState = "start_timeout" + WorkspaceAgentLifecycleStateStartError WorkspaceAgentLifecycleState = "start_error" + WorkspaceAgentLifecycleStateReady WorkspaceAgentLifecycleState = "ready" ) -func (e *WorkspaceAgentState) Scan(src interface{}) error { +func (e *WorkspaceAgentLifecycleState) Scan(src interface{}) error { switch s := src.(type) { case []byte: - *e = WorkspaceAgentState(s) + *e = WorkspaceAgentLifecycleState(s) case string: - *e = WorkspaceAgentState(s) + *e = WorkspaceAgentLifecycleState(s) default: - return fmt.Errorf("unsupported scan type for WorkspaceAgentState: %T", src) + return fmt.Errorf("unsupported scan type for WorkspaceAgentLifecycleState: %T", src) } return nil } -type NullWorkspaceAgentState struct { - WorkspaceAgentState WorkspaceAgentState - Valid bool // Valid is true if WorkspaceAgentState is not NULL +type NullWorkspaceAgentLifecycleState struct { + WorkspaceAgentLifecycleState WorkspaceAgentLifecycleState + Valid bool // Valid is true if WorkspaceAgentLifecycleState is not NULL } // Scan implements the Scanner interface. -func (ns *NullWorkspaceAgentState) Scan(value interface{}) error { +func (ns *NullWorkspaceAgentLifecycleState) Scan(value interface{}) error { if value == nil { - ns.WorkspaceAgentState, ns.Valid = "", false + ns.WorkspaceAgentLifecycleState, ns.Valid = "", false return nil } ns.Valid = true - return ns.WorkspaceAgentState.Scan(value) + return ns.WorkspaceAgentLifecycleState.Scan(value) } // Value implements the driver Valuer interface. -func (ns NullWorkspaceAgentState) Value() (driver.Value, error) { +func (ns NullWorkspaceAgentLifecycleState) Value() (driver.Value, error) { if !ns.Valid { return nil, nil } - return ns.WorkspaceAgentState, nil + return ns.WorkspaceAgentLifecycleState, nil } -func (e WorkspaceAgentState) Valid() bool { +func (e WorkspaceAgentLifecycleState) Valid() bool { switch e { - case WorkspaceAgentStateStarting, - WorkspaceAgentStateStartTimeout, - WorkspaceAgentStateStartError, - WorkspaceAgentStateReady: + case WorkspaceAgentLifecycleStateCreated, + WorkspaceAgentLifecycleStateStarting, + WorkspaceAgentLifecycleStateStartTimeout, + WorkspaceAgentLifecycleStateStartError, + WorkspaceAgentLifecycleStateReady: return true } return false } -func AllWorkspaceAgentStateValues() []WorkspaceAgentState { - return []WorkspaceAgentState{ - WorkspaceAgentStateStarting, - WorkspaceAgentStateStartTimeout, - WorkspaceAgentStateStartError, - WorkspaceAgentStateReady, +func AllWorkspaceAgentLifecycleStateValues() []WorkspaceAgentLifecycleState { + return []WorkspaceAgentLifecycleState{ + WorkspaceAgentLifecycleStateCreated, + WorkspaceAgentLifecycleStateStarting, + WorkspaceAgentLifecycleStateStartTimeout, + WorkspaceAgentLifecycleStateStartError, + WorkspaceAgentLifecycleStateReady, } } @@ -1512,8 +1515,8 @@ 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 state of the workspace agent. - State NullWorkspaceAgentState `db:"state" json:"state"` + // The current lifecycle state of the workspace agent. + LifecycleState WorkspaceAgentLifecycleState `db:"lifecycle_state" json:"lifecycle_state"` } type WorkspaceApp struct { diff --git a/coderd/database/querier.go b/coderd/database/querier.go index 812af45541102..7e9ddecea7c56 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -199,7 +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 - UpdateWorkspaceAgentStateByID(ctx context.Context, arg UpdateWorkspaceAgentStateByIDParams) 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 diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 2ddfe6e3715d6..4668f95d3ac17 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -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, state + 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 FROM workspace_agents WHERE @@ -4904,14 +4904,14 @@ func (q *sqlQuerier) GetWorkspaceAgentByAuthToken(ctx context.Context, authToken &i.ConnectionTimeoutSeconds, &i.TroubleshootingURL, &i.MOTDFile, - &i.State, + &i.LifecycleState, ) 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, state + 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 FROM workspace_agents WHERE @@ -4944,14 +4944,14 @@ func (q *sqlQuerier) GetWorkspaceAgentByID(ctx context.Context, id uuid.UUID) (W &i.ConnectionTimeoutSeconds, &i.TroubleshootingURL, &i.MOTDFile, - &i.State, + &i.LifecycleState, ) 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, state + 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 FROM workspace_agents WHERE @@ -4986,14 +4986,14 @@ func (q *sqlQuerier) GetWorkspaceAgentByInstanceID(ctx context.Context, authInst &i.ConnectionTimeoutSeconds, &i.TroubleshootingURL, &i.MOTDFile, - &i.State, + &i.LifecycleState, ) 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, state + 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 FROM workspace_agents WHERE @@ -5032,7 +5032,7 @@ func (q *sqlQuerier) GetWorkspaceAgentsByResourceIDs(ctx context.Context, ids [] &i.ConnectionTimeoutSeconds, &i.TroubleshootingURL, &i.MOTDFile, - &i.State, + &i.LifecycleState, ); err != nil { return nil, err } @@ -5048,7 +5048,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, state 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 FROM workspace_agents WHERE created_at > $1 ` func (q *sqlQuerier) GetWorkspaceAgentsCreatedAfter(ctx context.Context, createdAt time.Time) ([]WorkspaceAgent, error) { @@ -5083,7 +5083,7 @@ func (q *sqlQuerier) GetWorkspaceAgentsCreatedAfter(ctx context.Context, created &i.ConnectionTimeoutSeconds, &i.TroubleshootingURL, &i.MOTDFile, - &i.State, + &i.LifecycleState, ); err != nil { return nil, err } @@ -5120,7 +5120,7 @@ INSERT INTO motd_file ) 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, state + ($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, lifecycle_state ` type InsertWorkspaceAgentParams struct { @@ -5187,7 +5187,7 @@ func (q *sqlQuerier) InsertWorkspaceAgent(ctx context.Context, arg InsertWorkspa &i.ConnectionTimeoutSeconds, &i.TroubleshootingURL, &i.MOTDFile, - &i.State, + &i.LifecycleState, ) return i, err } @@ -5226,22 +5226,22 @@ func (q *sqlQuerier) UpdateWorkspaceAgentConnectionByID(ctx context.Context, arg return err } -const updateWorkspaceAgentStateByID = `-- name: UpdateWorkspaceAgentStateByID :exec +const updateWorkspaceAgentLifecycleStateByID = `-- name: UpdateWorkspaceAgentLifecycleStateByID :exec UPDATE workspace_agents SET - state = $2 + lifecycle_state = $2 WHERE id = $1 ` -type UpdateWorkspaceAgentStateByIDParams struct { - ID uuid.UUID `db:"id" json:"id"` - State NullWorkspaceAgentState `db:"state" json:"state"` +type UpdateWorkspaceAgentLifecycleStateByIDParams struct { + ID uuid.UUID `db:"id" json:"id"` + LifecycleState WorkspaceAgentLifecycleState `db:"lifecycle_state" json:"lifecycle_state"` } -func (q *sqlQuerier) UpdateWorkspaceAgentStateByID(ctx context.Context, arg UpdateWorkspaceAgentStateByIDParams) error { - _, err := q.db.ExecContext(ctx, updateWorkspaceAgentStateByID, arg.ID, arg.State) +func (q *sqlQuerier) UpdateWorkspaceAgentLifecycleStateByID(ctx context.Context, arg UpdateWorkspaceAgentLifecycleStateByIDParams) error { + _, err := q.db.ExecContext(ctx, updateWorkspaceAgentLifecycleStateByID, arg.ID, arg.LifecycleState) return err } diff --git a/coderd/database/queries/workspaceagents.sql b/coderd/database/queries/workspaceagents.sql index 2b5b6e138a2b2..0bee46f91cb14 100644 --- a/coderd/database/queries/workspaceagents.sql +++ b/coderd/database/queries/workspaceagents.sql @@ -81,10 +81,10 @@ SET WHERE id = $1; --- name: UpdateWorkspaceAgentStateByID :exec +-- name: UpdateWorkspaceAgentLifecycleStateByID :exec UPDATE workspace_agents SET - state = $2 + lifecycle_state = $2 WHERE id = $1; diff --git a/coderd/workspaceagents.go b/coderd/workspaceagents.go index 8b9c565638165..3b9cf42cb07e6 100644 --- a/coderd/workspaceagents.go +++ b/coderd/workspaceagents.go @@ -900,15 +900,15 @@ func (api *API) workspaceAgentReportStats(rw http.ResponseWriter, r *http.Reques }) } -// @Summary Submit workspace agent state -// @ID submit-workspace-agent-state +// @Summary Submit workspace agent lifecycle state +// @ID submit-workspace-agent-lifecycle-state // @Security CoderSessionToken // @Accept json // @Tags Agents -// @Param request body codersdk.PostWorkspaceAgentStateRequest true "Workspace agent state request" +// @Param request body codersdk.PostWorkspaceAgentLifecycleRequest true "Workspace agent lifecycle request" // @Success 204 "Success" -// @Router /workspaceagents/me/report-state [post] -func (api *API) workspaceAgentReportState(rw http.ResponseWriter, r *http.Request) { +// @Router /workspaceagents/me/report-lifecycle [post] +func (api *API) workspaceAgentReportLifecycle(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() workspaceAgent := httpmw.WorkspaceAgent(r) @@ -921,7 +921,7 @@ func (api *API) workspaceAgentReportState(rw http.ResponseWriter, r *http.Reques return } - var req codersdk.PostWorkspaceAgentStateRequest + var req codersdk.PostWorkspaceAgentLifecycleRequest if !httpapi.Read(ctx, rw, r, &req) { return } @@ -932,9 +932,9 @@ func (api *API) workspaceAgentReportState(rw http.ResponseWriter, r *http.Reques slog.F("payload", req), ) - err = api.Database.UpdateWorkspaceAgentStateByID(ctx, database.UpdateWorkspaceAgentStateByIDParams{ - ID: workspaceAgent.ID, - State: database.WorkspaceAgentState(req.State), + err = api.Database.UpdateWorkspaceAgentLifecycleStateByID(ctx, database.UpdateWorkspaceAgentLifecycleStateByIDParams{ + ID: workspaceAgent.ID, + LifecycleState: database.WorkspaceAgentLifecycleState(req.State), }) if err != nil { httpapi.InternalServerError(rw, err) diff --git a/coderd/wsconncache/wsconncache_test.go b/coderd/wsconncache/wsconncache_test.go index c0bc915763b21..a73e95e98947c 100644 --- a/coderd/wsconncache/wsconncache_test.go +++ b/coderd/wsconncache/wsconncache_test.go @@ -217,7 +217,7 @@ func (*client) AgentReportStats(_ context.Context, _ slog.Logger, _ func() *code return io.NopCloser(strings.NewReader("")), nil } -func (*client) PostWorkspaceAgentState(_ context.Context, _ codersdk.PostWorkspaceAgentStateRequest) error { +func (*client) PostWorkspaceAgentLifecycle(_ context.Context, _ codersdk.PostWorkspaceAgentLifecycleRequest) error { return nil } diff --git a/codersdk/workspaceagents.go b/codersdk/workspaceagents.go index ef5a4279f482c..589ee3040f424 100644 --- a/codersdk/workspaceagents.go +++ b/codersdk/workspaceagents.go @@ -34,35 +34,45 @@ const ( WorkspaceAgentTimeout WorkspaceAgentStatus = "timeout" ) -// WorkspaceAgentState represents the lifecycle state of a workspace agent. -type WorkspaceAgentState string +// WorkspaceAgentLifecycle represents the lifecycle state of a workspace agent. +// +// The agent lifecycle starts in the "created" state, and transitions to +// "starting" when the agent reports it has begun preparing (e.g. started +// executing the startup script). +// +// Note that states are not guaranteed to be reported, for instance the agent +// may go from "created" to "ready" without reporting "starting", if it had +// trouble connecting on startup. +type WorkspaceAgentLifecycle string +// WorkspaceAgentLifecycle enums. const ( - WorkspaceAgentStateStarting WorkspaceAgentState = "starting" - WorkspaceAgentStateStartTimeout WorkspaceAgentState = "start_timeout" - WorkspaceAgentStateStartError WorkspaceAgentState = "start_error" - WorkspaceAgentStateReady WorkspaceAgentState = "ready" + WorkspaceAgentLifecycleCreated WorkspaceAgentLifecycle = "created" + WorkspaceAgentLifecycleStarting WorkspaceAgentLifecycle = "starting" + WorkspaceAgentLifecycleStartTimeout WorkspaceAgentLifecycle = "start_timeout" + WorkspaceAgentLifecycleStartError WorkspaceAgentLifecycle = "start_error" + WorkspaceAgentLifecycleReady WorkspaceAgentLifecycle = "ready" ) type WorkspaceAgent struct { - ID uuid.UUID `json:"id" format:"uuid"` - CreatedAt time.Time `json:"created_at" format:"date-time"` - UpdatedAt time.Time `json:"updated_at" format:"date-time"` - FirstConnectedAt *time.Time `json:"first_connected_at,omitempty" format:"date-time"` - LastConnectedAt *time.Time `json:"last_connected_at,omitempty" format:"date-time"` - DisconnectedAt *time.Time `json:"disconnected_at,omitempty" format:"date-time"` - Status WorkspaceAgentStatus `json:"status" enums:"connecting,connected,disconnected,timeout"` - State WorkspaceAgentState `json:"state" enums:"starting,start_timeout,start_error,ready"` - Name string `json:"name"` - ResourceID uuid.UUID `json:"resource_id" format:"uuid"` - InstanceID string `json:"instance_id,omitempty"` - Architecture string `json:"architecture"` - EnvironmentVariables map[string]string `json:"environment_variables"` - OperatingSystem string `json:"operating_system"` - StartupScript string `json:"startup_script,omitempty"` - Directory string `json:"directory,omitempty"` - Version string `json:"version"` - Apps []WorkspaceApp `json:"apps"` + ID uuid.UUID `json:"id" format:"uuid"` + CreatedAt time.Time `json:"created_at" format:"date-time"` + UpdatedAt time.Time `json:"updated_at" format:"date-time"` + FirstConnectedAt *time.Time `json:"first_connected_at,omitempty" format:"date-time"` + LastConnectedAt *time.Time `json:"last_connected_at,omitempty" format:"date-time"` + DisconnectedAt *time.Time `json:"disconnected_at,omitempty" format:"date-time"` + Status WorkspaceAgentStatus `json:"status"` + LifecycleState WorkspaceAgentLifecycle `json:"lifecycle_state"` + Name string `json:"name"` + ResourceID uuid.UUID `json:"resource_id" format:"uuid"` + InstanceID string `json:"instance_id,omitempty"` + Architecture string `json:"architecture"` + EnvironmentVariables map[string]string `json:"environment_variables"` + OperatingSystem string `json:"operating_system"` + StartupScript string `json:"startup_script,omitempty"` + Directory string `json:"directory,omitempty"` + Version string `json:"version"` + Apps []WorkspaceApp `json:"apps"` // DERPLatency is mapped by region name (e.g. "New York City", "Seattle"). DERPLatency map[string]DERPRegion `json:"latency,omitempty"` ConnectionTimeoutSeconds int32 `json:"connection_timeout_seconds"` @@ -694,13 +704,13 @@ func (c *Client) WorkspaceAgentGitAuth(ctx context.Context, gitURL string, liste return authResp, json.NewDecoder(res.Body).Decode(&authResp) } -// @typescript-ignore PostWorkspaceAgentStateRequest -type PostWorkspaceAgentStateRequest struct { - State WorkspaceAgentState `json:"state"` +// @typescript-ignore PostWorkspaceAgentLifecycleRequest +type PostWorkspaceAgentLifecycleRequest struct { + State WorkspaceAgentLifecycle `json:"state"` } -func (c *Client) PostWorkspaceAgentState(ctx context.Context, req PostWorkspaceAgentStateRequest) error { - res, err := c.Request(ctx, http.MethodPost, "/api/v2/workspaceagents/me/report-state", req) +func (c *Client) PostWorkspaceAgentLifecycle(ctx context.Context, req PostWorkspaceAgentLifecycleRequest) error { + res, err := c.Request(ctx, http.MethodPost, "/api/v2/workspaceagents/me/report-lifecycle", req) if err != nil { return xerrors.Errorf("agent state post request: %w", err) } diff --git a/docs/api/agents.md b/docs/api/agents.md index fefb1e0e91390..87143b696d41f 100644 --- a/docs/api/agents.md +++ b/docs/api/agents.md @@ -383,32 +383,32 @@ curl -X GET http://coder-server:8080/api/v2/workspaceagents/me/metadata \ To perform this operation, you must be authenticated. [Learn more](authentication.md). -## Submit workspace agent state +## Submit workspace agent lifecycle state ### Code samples ```shell # Example request using curl -curl -X POST http://coder-server:8080/api/v2/workspaceagents/me/report-state \ +curl -X POST http://coder-server:8080/api/v2/workspaceagents/me/report-lifecycle \ -H 'Content-Type: application/json' \ -H 'Coder-Session-Token: API_KEY' ``` -`POST /workspaceagents/me/report-state` +`POST /workspaceagents/me/report-lifecycle` > Body parameter ```json { - "state": "starting" + "state": "created" } ``` ### Parameters -| Name | In | Type | Required | Description | -| ------ | ---- | -------------------------------------------------------------------------------------------- | -------- | ----------------------------- | -| `body` | body | [codersdk.PostWorkspaceAgentStateRequest](schemas.md#codersdkpostworkspaceagentstaterequest) | true | Workspace agent state request | +| Name | In | Type | Required | Description | +| ------ | ---- | ---------------------------------------------------------------------------------------------------- | -------- | --------------------------------- | +| `body` | body | [codersdk.PostWorkspaceAgentLifecycleRequest](schemas.md#codersdkpostworkspaceagentlifecyclerequest) | true | Workspace agent lifecycle request | ### Responses @@ -539,11 +539,11 @@ curl -X GET http://coder-server:8080/api/v2/workspaceagents/{workspaceagent} \ "preferred": true } }, + "lifecycle_state": "created", "name": "string", "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", - "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", diff --git a/docs/api/builds.md b/docs/api/builds.md index 87e51ffeb5536..87a8cbdec1640 100644 --- a/docs/api/builds.md +++ b/docs/api/builds.md @@ -96,11 +96,11 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/workspace/{workspacenam "preferred": true } }, + "lifecycle_state": "created", "name": "string", "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", - "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -239,11 +239,11 @@ curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild} \ "preferred": true } }, + "lifecycle_state": "created", "name": "string", "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", - "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -525,11 +525,11 @@ curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild}/res "preferred": true } }, + "lifecycle_state": "created", "name": "string", "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", - "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -600,11 +600,11 @@ Status Code **200** | `»»» [any property]` | [codersdk.DERPRegion](schemas.md#codersdkderpregion) | false | | | | `»»»» latency_ms` | number | false | | | | `»»»» preferred` | boolean | false | | | +| `»» lifecycle_state` | [codersdk.WorkspaceAgentLifecycle](schemas.md#codersdkworkspaceagentlifecycle) | false | | | | `»» name` | string | false | | | | `»» operating_system` | string | false | | | | `»» resource_id` | string(uuid) | false | | | | `»» startup_script` | string | false | | | -| `»» state` | [codersdk.WorkspaceAgentState](schemas.md#codersdkworkspaceagentstate) | false | | | | `»» status` | [codersdk.WorkspaceAgentStatus](schemas.md#codersdkworkspaceagentstatus) | false | | | | `»» troubleshooting_url` | string | false | | | | `»» updated_at` | string(date-time) | false | | | @@ -634,10 +634,11 @@ Status Code **200** | `sharing_level` | `owner` | | `sharing_level` | `authenticated` | | `sharing_level` | `public` | -| `state` | `starting` | -| `state` | `start_timeout` | -| `state` | `start_error` | -| `state` | `ready` | +| `lifecycle_state` | `created` | +| `lifecycle_state` | `starting` | +| `lifecycle_state` | `start_timeout` | +| `lifecycle_state` | `start_error` | +| `lifecycle_state` | `ready` | | `status` | `connecting` | | `status` | `connected` | | `status` | `disconnected` | @@ -742,11 +743,11 @@ curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild}/sta "preferred": true } }, + "lifecycle_state": "created", "name": "string", "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", - "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -890,11 +891,11 @@ curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace}/builds \ "preferred": true } }, + "lifecycle_state": "created", "name": "string", "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", - "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -997,11 +998,11 @@ Status Code **200** | `»»»» [any property]` | [codersdk.DERPRegion](schemas.md#codersdkderpregion) | false | | | | `»»»»» latency_ms` | number | false | | | | `»»»»» preferred` | boolean | false | | | +| `»»» lifecycle_state` | [codersdk.WorkspaceAgentLifecycle](schemas.md#codersdkworkspaceagentlifecycle) | false | | | | `»»» name` | string | false | | | | `»»» operating_system` | string | false | | | | `»»» resource_id` | string(uuid) | false | | | | `»»» startup_script` | string | false | | | -| `»»» state` | [codersdk.WorkspaceAgentState](schemas.md#codersdkworkspaceagentstate) | false | | | | `»»» status` | [codersdk.WorkspaceAgentStatus](schemas.md#codersdkworkspaceagentstatus) | false | | | | `»»» troubleshooting_url` | string | false | | | | `»»» updated_at` | string(date-time) | false | | | @@ -1049,10 +1050,11 @@ Status Code **200** | `sharing_level` | `owner` | | `sharing_level` | `authenticated` | | `sharing_level` | `public` | -| `state` | `starting` | -| `state` | `start_timeout` | -| `state` | `start_error` | -| `state` | `ready` | +| `lifecycle_state` | `created` | +| `lifecycle_state` | `starting` | +| `lifecycle_state` | `start_timeout` | +| `lifecycle_state` | `start_error` | +| `lifecycle_state` | `ready` | | `status` | `connecting` | | `status` | `connected` | | `status` | `disconnected` | @@ -1199,11 +1201,11 @@ curl -X POST http://coder-server:8080/api/v2/workspaces/{workspace}/builds \ "preferred": true } }, + "lifecycle_state": "created", "name": "string", "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", - "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", diff --git a/docs/api/schemas.md b/docs/api/schemas.md index b66a1e92ea8bf..8e7eeb727f931 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -3320,19 +3320,19 @@ Parameter represents a set value for the scope. | `none` | | `data` | -## codersdk.PostWorkspaceAgentStateRequest +## codersdk.PostWorkspaceAgentLifecycleRequest ```json { - "state": "starting" + "state": "created" } ``` ### Properties -| Name | Type | Required | Restrictions | Description | -| ------- | ------------------------------------------------------------ | -------- | ------------ | ----------- | -| `state` | [codersdk.WorkspaceAgentState](#codersdkworkspaceagentstate) | false | | | +| Name | Type | Required | Restrictions | Description | +| ------- | -------------------------------------------------------------------- | -------- | ------------ | ----------- | +| `state` | [codersdk.WorkspaceAgentLifecycle](#codersdkworkspaceagentlifecycle) | false | | | ## codersdk.PostWorkspaceAppHealthsRequest @@ -4593,11 +4593,11 @@ Parameter represents a set value for the scope. "preferred": true } }, + "lifecycle_state": "created", "name": "string", "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", - "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -4713,11 +4713,11 @@ Parameter represents a set value for the scope. "preferred": true } }, + "lifecycle_state": "created", "name": "string", "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", - "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -4727,44 +4727,31 @@ Parameter represents a set value for the scope. ### Properties -| Name | Type | Required | Restrictions | Description | -| ---------------------------- | -------------------------------------------------------------- | -------- | ------------ | ------------------------------------------------------------------- | -| `apps` | array of [codersdk.WorkspaceApp](#codersdkworkspaceapp) | false | | | -| `architecture` | string | false | | | -| `connection_timeout_seconds` | integer | false | | | -| `created_at` | string | false | | | -| `directory` | string | false | | | -| `disconnected_at` | string | false | | | -| `environment_variables` | object | false | | | -| » `[any property]` | string | false | | | -| `first_connected_at` | string | false | | | -| `id` | string | false | | | -| `instance_id` | string | false | | | -| `last_connected_at` | string | false | | | -| `latency` | object | false | | Latency is mapped by region name (e.g. "New York City", "Seattle"). | -| » `[any property]` | [codersdk.DERPRegion](#codersdkderpregion) | false | | | -| `name` | string | false | | | -| `operating_system` | string | false | | | -| `resource_id` | string | false | | | -| `startup_script` | string | false | | | -| `state` | [codersdk.WorkspaceAgentState](#codersdkworkspaceagentstate) | false | | | -| `status` | [codersdk.WorkspaceAgentStatus](#codersdkworkspaceagentstatus) | false | | | -| `troubleshooting_url` | string | false | | | -| `updated_at` | string | false | | | -| `version` | string | false | | | - -#### Enumerated Values - -| Property | Value | -| -------- | --------------- | -| `state` | `starting` | -| `state` | `start_timeout` | -| `state` | `start_error` | -| `state` | `ready` | -| `status` | `connecting` | -| `status` | `connected` | -| `status` | `disconnected` | -| `status` | `timeout` | +| Name | Type | Required | Restrictions | Description | +| ---------------------------- | -------------------------------------------------------------------- | -------- | ------------ | ------------------------------------------------------------------- | +| `apps` | array of [codersdk.WorkspaceApp](#codersdkworkspaceapp) | false | | | +| `architecture` | string | false | | | +| `connection_timeout_seconds` | integer | false | | | +| `created_at` | string | false | | | +| `directory` | string | false | | | +| `disconnected_at` | string | false | | | +| `environment_variables` | object | false | | | +| » `[any property]` | string | false | | | +| `first_connected_at` | string | false | | | +| `id` | string | false | | | +| `instance_id` | string | false | | | +| `last_connected_at` | string | false | | | +| `latency` | object | false | | Latency is mapped by region name (e.g. "New York City", "Seattle"). | +| » `[any property]` | [codersdk.DERPRegion](#codersdkderpregion) | false | | | +| `lifecycle_state` | [codersdk.WorkspaceAgentLifecycle](#codersdkworkspaceagentlifecycle) | false | | | +| `name` | string | false | | | +| `operating_system` | string | false | | | +| `resource_id` | string | false | | | +| `startup_script` | string | false | | | +| `status` | [codersdk.WorkspaceAgentStatus](#codersdkworkspaceagentstatus) | false | | | +| `troubleshooting_url` | string | false | | | +| `updated_at` | string | false | | | +| `version` | string | false | | | ## codersdk.WorkspaceAgentAuthenticateResponse @@ -4862,6 +4849,24 @@ Parameter represents a set value for the scope. | `url` | string | false | | | | `username` | string | false | | | +## codersdk.WorkspaceAgentLifecycle + +```json +"created" +``` + +### Properties + +#### Enumerated Values + +| Value | +| --------------- | +| `created` | +| `starting` | +| `start_timeout` | +| `start_error` | +| `ready` | + ## codersdk.WorkspaceAgentMetadata ```json @@ -4964,23 +4969,6 @@ Parameter represents a set value for the scope. | `startup_script_timeout` | integer | false | | | | `vscode_port_proxy_uri` | string | false | | | -## codersdk.WorkspaceAgentState - -```json -"starting" -``` - -### Properties - -#### Enumerated Values - -| Value | -| --------------- | -| `starting` | -| `start_timeout` | -| `start_error` | -| `ready` | - ## codersdk.WorkspaceAgentStatus ```json @@ -5150,11 +5138,11 @@ Parameter represents a set value for the scope. "preferred": true } }, + "lifecycle_state": "created", "name": "string", "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", - "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -5316,11 +5304,11 @@ Parameter represents a set value for the scope. "preferred": true } }, + "lifecycle_state": "created", "name": "string", "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", - "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -5504,11 +5492,11 @@ Parameter represents a set value for the scope. "preferred": true } }, + "lifecycle_state": "created", "name": "string", "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", - "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", diff --git a/docs/api/templates.md b/docs/api/templates.md index 62487489939d1..0f20877893bb9 100644 --- a/docs/api/templates.md +++ b/docs/api/templates.md @@ -1572,11 +1572,11 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/d "preferred": true } }, + "lifecycle_state": "created", "name": "string", "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", - "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -1647,11 +1647,11 @@ Status Code **200** | `»»» [any property]` | [codersdk.DERPRegion](schemas.md#codersdkderpregion) | false | | | | `»»»» latency_ms` | number | false | | | | `»»»» preferred` | boolean | false | | | +| `»» lifecycle_state` | [codersdk.WorkspaceAgentLifecycle](schemas.md#codersdkworkspaceagentlifecycle) | false | | | | `»» name` | string | false | | | | `»» operating_system` | string | false | | | | `»» resource_id` | string(uuid) | false | | | | `»» startup_script` | string | false | | | -| `»» state` | [codersdk.WorkspaceAgentState](schemas.md#codersdkworkspaceagentstate) | false | | | | `»» status` | [codersdk.WorkspaceAgentStatus](schemas.md#codersdkworkspaceagentstatus) | false | | | | `»» troubleshooting_url` | string | false | | | | `»» updated_at` | string(date-time) | false | | | @@ -1681,10 +1681,11 @@ Status Code **200** | `sharing_level` | `owner` | | `sharing_level` | `authenticated` | | `sharing_level` | `public` | -| `state` | `starting` | -| `state` | `start_timeout` | -| `state` | `start_error` | -| `state` | `ready` | +| `lifecycle_state` | `created` | +| `lifecycle_state` | `starting` | +| `lifecycle_state` | `start_timeout` | +| `lifecycle_state` | `start_error` | +| `lifecycle_state` | `ready` | | `status` | `connecting` | | `status` | `connected` | | `status` | `disconnected` | @@ -1919,11 +1920,11 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/r "preferred": true } }, + "lifecycle_state": "created", "name": "string", "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", - "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -1994,11 +1995,11 @@ Status Code **200** | `»»» [any property]` | [codersdk.DERPRegion](schemas.md#codersdkderpregion) | false | | | | `»»»» latency_ms` | number | false | | | | `»»»» preferred` | boolean | false | | | +| `»» lifecycle_state` | [codersdk.WorkspaceAgentLifecycle](schemas.md#codersdkworkspaceagentlifecycle) | false | | | | `»» name` | string | false | | | | `»» operating_system` | string | false | | | | `»» resource_id` | string(uuid) | false | | | | `»» startup_script` | string | false | | | -| `»» state` | [codersdk.WorkspaceAgentState](schemas.md#codersdkworkspaceagentstate) | false | | | | `»» status` | [codersdk.WorkspaceAgentStatus](schemas.md#codersdkworkspaceagentstatus) | false | | | | `»» troubleshooting_url` | string | false | | | | `»» updated_at` | string(date-time) | false | | | @@ -2028,10 +2029,11 @@ Status Code **200** | `sharing_level` | `owner` | | `sharing_level` | `authenticated` | | `sharing_level` | `public` | -| `state` | `starting` | -| `state` | `start_timeout` | -| `state` | `start_error` | -| `state` | `ready` | +| `lifecycle_state` | `created` | +| `lifecycle_state` | `starting` | +| `lifecycle_state` | `start_timeout` | +| `lifecycle_state` | `start_error` | +| `lifecycle_state` | `ready` | | `status` | `connecting` | | `status` | `connected` | | `status` | `disconnected` | diff --git a/docs/api/workspaces.md b/docs/api/workspaces.md index 6f97bf5661253..b363b773ce953 100644 --- a/docs/api/workspaces.md +++ b/docs/api/workspaces.md @@ -100,11 +100,11 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/member "preferred": true } }, + "lifecycle_state": "created", "name": "string", "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", - "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -262,11 +262,11 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/workspace/{workspacenam "preferred": true } }, + "lifecycle_state": "created", "name": "string", "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", - "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -443,11 +443,11 @@ curl -X GET http://coder-server:8080/api/v2/workspaces \ "preferred": true } }, + "lifecycle_state": "created", "name": "string", "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", - "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -606,11 +606,11 @@ curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace} \ "preferred": true } }, + "lifecycle_state": "created", "name": "string", "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", - "state": "starting", "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 3bf0568adb7aa..35010f93a7194 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -918,7 +918,7 @@ export interface WorkspaceAgent { readonly last_connected_at?: string readonly disconnected_at?: string readonly status: WorkspaceAgentStatus - readonly state: WorkspaceAgentState + readonly lifecycle_state: WorkspaceAgentLifecycle readonly name: string readonly resource_id: string readonly instance_id?: string @@ -1227,12 +1227,14 @@ export type UserStatus = "active" | "suspended" export const UserStatuses: UserStatus[] = ["active", "suspended"] // From codersdk/workspaceagents.go -export type WorkspaceAgentState = +export type WorkspaceAgentLifecycle = + | "created" | "ready" | "start_error" | "start_timeout" | "starting" -export const WorkspaceAgentStates: WorkspaceAgentState[] = [ +export const WorkspaceAgentLifecycles: WorkspaceAgentLifecycle[] = [ + "created", "ready", "start_error", "start_timeout", From 534f9546e33b4827da337d06473a1f10c865bae2 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Mon, 23 Jan 2023 13:08:21 +0000 Subject: [PATCH 07/23] Add tests, improve lifecycle reporting --- agent/agent.go | 74 +++++++--- agent/agent_test.go | 143 ++++++++++++++++--- coderd/database/databasefake/databasefake.go | 5 + coderd/workspaceagents.go | 12 +- coderd/workspaceagents_test.go | 85 +++++++++++ codersdk/workspaceagents.go | 2 +- 6 files changed, 277 insertions(+), 44 deletions(-) diff --git a/agent/agent.go b/agent/agent.go index 5638bab2052a2..174255763cf82 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -102,6 +102,7 @@ func New(options Options) io.Closer { exchangeToken: options.ExchangeToken, filesystem: options.Filesystem, tempDir: options.TempDir, + lifecycleUpdate: make(chan struct{}, 1), } a.init(ctx) return a @@ -128,8 +129,9 @@ type agent struct { sessionToken atomic.Pointer[string] sshServer *ssh.Server - lifecycleMu sync.Mutex // Protects following. - lifecycleState codersdk.WorkspaceAgentLifecycle + lifecycleUpdate chan struct{} + lifecycleMu sync.Mutex // Protects following. + lifecycleState codersdk.WorkspaceAgentLifecycle network *tailnet.Conn } @@ -139,6 +141,8 @@ type agent struct { // may be happening, but regardless after the intermittent // failure, you'll want the agent to reconnect. func (a *agent) runLoop(ctx context.Context) { + go a.reportLifecycleLoop(ctx) + for retrier := retry.New(100*time.Millisecond, 10*time.Second); retrier.Wait(ctx); { a.logger.Info(ctx, "running loop") err := a.run(ctx) @@ -160,27 +164,51 @@ func (a *agent) runLoop(ctx context.Context) { } } -func (a *agent) setLifecycle(ctx context.Context, state codersdk.WorkspaceAgentLifecycle) { - a.lifecycleMu.Lock() - defer a.lifecycleMu.Unlock() +// reportLifecycleLoop reports the current lifecycle state once. +// Only the latest state is reported, intermediate states may be +// lost if the agent can't communicate with the API. +func (a *agent) reportLifecycleLoop(ctx context.Context) { + var lastReported codersdk.WorkspaceAgentLifecycle + for { + select { + case <-a.lifecycleUpdate: + case <-ctx.Done(): + return + } - a.lifecycleState = state + for r := retry.New(time.Second, 15*time.Second); r.Wait(ctx); { + a.lifecycleMu.Lock() + state := a.lifecycleState + a.lifecycleMu.Unlock() - var err error - for r := retry.New(time.Second, 30*time.Second); r.Wait(ctx); { - err = a.client.PostWorkspaceAgentLifecycle(ctx, codersdk.PostWorkspaceAgentLifecycleRequest{ - State: state, - }) - if err == nil { - return + if state == lastReported { + continue + } + + err := a.client.PostWorkspaceAgentLifecycle(ctx, codersdk.PostWorkspaceAgentLifecycleRequest{ + State: state, + }) + if err == nil { + lastReported = state + break + } + if xerrors.Is(err, context.Canceled) || xerrors.Is(err, context.DeadlineExceeded) { + return + } + // If we fail to report the state we probably shouldn't exit, log only. + a.logger.Error(ctx, "post state", slog.Error(err)) } } - if xerrors.Is(err, context.Canceled) || xerrors.Is(err, context.DeadlineExceeded) || a.isClosed() { - return - } - if err != nil { - // If we fail to report the state we probably shouldn't exit, log only. - a.logger.Error(ctx, "post state", slog.Error(err)) +} + +func (a *agent) setLifecycle(state codersdk.WorkspaceAgentLifecycle) { + a.lifecycleMu.Lock() + defer a.lifecycleMu.Unlock() + + a.lifecycleState = state + select { + case a.lifecycleUpdate <- struct{}{}: + default: } } @@ -224,14 +252,14 @@ func (a *agent) run(ctx context.Context) error { timeout = t.C } - a.setLifecycle(ctx, codersdk.WorkspaceAgentLifecycleStarting) + a.setLifecycle(codersdk.WorkspaceAgentLifecycleStarting) var err error select { case err = <-scriptDone: case <-timeout: a.logger.Warn(ctx, "startup script timed out") - a.setLifecycle(ctx, codersdk.WorkspaceAgentLifecycleStartTimeout) + a.setLifecycle(codersdk.WorkspaceAgentLifecycleStartTimeout) err = <-scriptDone // The script can still complete after a timeout. } if errors.Is(err, context.Canceled) { @@ -240,7 +268,7 @@ func (a *agent) run(ctx context.Context) error { execTime := time.Since(scriptStart) if err != nil { a.logger.Warn(ctx, "startup script failed", slog.F("execution_time", execTime), slog.Error(err)) - a.setLifecycle(ctx, codersdk.WorkspaceAgentLifecycleStartError) + a.setLifecycle(codersdk.WorkspaceAgentLifecycleStartError) return } a.logger.Info(ctx, "startup script completed", slog.F("execution_time", execTime)) @@ -255,7 +283,7 @@ func (a *agent) run(ctx context.Context) error { } } - a.setLifecycle(ctx, codersdk.WorkspaceAgentLifecycleReady) + a.setLifecycle(codersdk.WorkspaceAgentLifecycleReady) }() } diff --git a/agent/agent_test.go b/agent/agent_test.go index 29b13eebce241..82a5bec8e6452 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -57,7 +57,7 @@ func TestAgent_Stats_SSH(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() - conn, stats, _ := setupAgent(t, codersdk.WorkspaceAgentMetadata{}, 0) + conn, _, stats, _ := setupAgent(t, codersdk.WorkspaceAgentMetadata{}, 0) sshClient, err := conn.SSHClient(ctx) require.NoError(t, err) @@ -83,7 +83,7 @@ func TestAgent_Stats_ReconnectingPTY(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() - conn, stats, _ := setupAgent(t, codersdk.WorkspaceAgentMetadata{}, 0) + conn, _, stats, _ := setupAgent(t, codersdk.WorkspaceAgentMetadata{}, 0) ptyConn, err := conn.ReconnectingPTY(ctx, uuid.New(), 128, 128, "/bin/bash") require.NoError(t, err) @@ -531,7 +531,7 @@ func TestAgent_SFTP(t *testing.T) { if runtime.GOOS == "windows" { home = "/" + strings.ReplaceAll(home, "\\", "/") } - conn, _, _ := setupAgent(t, codersdk.WorkspaceAgentMetadata{}, 0) + conn, _, _, _ := setupAgent(t, codersdk.WorkspaceAgentMetadata{}, 0) sshClient, err := conn.SSHClient(ctx) require.NoError(t, err) defer sshClient.Close() @@ -562,7 +562,7 @@ func TestAgent_SCP(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() - conn, _, _ := setupAgent(t, codersdk.WorkspaceAgentMetadata{}, 0) + conn, _, _, _ := setupAgent(t, codersdk.WorkspaceAgentMetadata{}, 0) sshClient, err := conn.SSHClient(ctx) require.NoError(t, err) defer sshClient.Close() @@ -666,7 +666,7 @@ func TestAgent_StartupScript(t *testing.T) { t.Skip("This test doesn't work on Windows for some reason...") } content := "output" - _, _, fs := setupAgent(t, codersdk.WorkspaceAgentMetadata{ + _, _, _, fs := setupAgent(t, codersdk.WorkspaceAgentMetadata{ StartupScript: "echo " + content, }, 0) var gotContent string @@ -694,6 +694,97 @@ func TestAgent_StartupScript(t *testing.T) { require.Equal(t, content, strings.TrimSpace(gotContent)) } +func TestAgent_Lifecycle(t *testing.T) { + t.Parallel() + + t.Run("Timeout", func(t *testing.T) { + t.Parallel() + + _, client, _, _ := setupAgent(t, codersdk.WorkspaceAgentMetadata{ + StartupScript: "sleep 10", + StartupScriptTimeout: time.Nanosecond, + }, 0) + + want := []codersdk.WorkspaceAgentLifecycle{ + codersdk.WorkspaceAgentLifecycleStarting, + codersdk.WorkspaceAgentLifecycleStartTimeout, + } + + var got []codersdk.WorkspaceAgentLifecycle + assert.Eventually(t, func() bool { + got = client.getLifecycleStates() + return len(got) > 0 && got[len(got)-1] == want[len(want)-1] + }, testutil.WaitShort, testutil.IntervalMedium) + switch len(got) { + case 1: + // This can happen if lifecycle states are too + // fast, only the latest on is reported. + require.Equal(t, want[1:], got) + default: + // This is the expected case. + require.Equal(t, want, got) + } + }) + + t.Run("Error", func(t *testing.T) { + t.Parallel() + + _, client, _, _ := setupAgent(t, codersdk.WorkspaceAgentMetadata{ + StartupScript: "false", + StartupScriptTimeout: 30 * time.Second, + }, 0) + + want := []codersdk.WorkspaceAgentLifecycle{ + codersdk.WorkspaceAgentLifecycleStarting, + codersdk.WorkspaceAgentLifecycleStartError, + } + + var got []codersdk.WorkspaceAgentLifecycle + assert.Eventually(t, func() bool { + got = client.getLifecycleStates() + return len(got) > 0 && got[len(got)-1] == want[len(want)-1] + }, testutil.WaitShort, testutil.IntervalMedium) + switch len(got) { + case 1: + // This can happen if lifecycle states are too + // fast, only the latest on is reported. + require.Equal(t, want[1:], got) + default: + // This is the expected case. + require.Equal(t, want, got) + } + }) + + t.Run("Ready", func(t *testing.T) { + t.Parallel() + + _, client, _, _ := setupAgent(t, codersdk.WorkspaceAgentMetadata{ + StartupScript: "true", + StartupScriptTimeout: 30 * time.Second, + }, 0) + + want := []codersdk.WorkspaceAgentLifecycle{ + codersdk.WorkspaceAgentLifecycleStarting, + codersdk.WorkspaceAgentLifecycleReady, + } + + var got []codersdk.WorkspaceAgentLifecycle + assert.Eventually(t, func() bool { + got = client.getLifecycleStates() + return len(got) > 0 && got[len(got)-1] == want[len(want)-1] + }, testutil.WaitShort, testutil.IntervalMedium) + switch len(got) { + case 1: + // This can happen if lifecycle states are too + // fast, only the latest on is reported. + require.Equal(t, want[1:], got) + default: + // This is the expected case. + require.Equal(t, want, got) + } + }) +} + func TestAgent_ReconnectingPTY(t *testing.T) { t.Parallel() if runtime.GOOS == "windows" { @@ -706,7 +797,7 @@ func TestAgent_ReconnectingPTY(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() - conn, _, _ := setupAgent(t, codersdk.WorkspaceAgentMetadata{}, 0) + conn, _, _, _ := setupAgent(t, codersdk.WorkspaceAgentMetadata{}, 0) id := uuid.New() netConn, err := conn.ReconnectingPTY(ctx, id, 100, 100, "/bin/bash") require.NoError(t, err) @@ -807,7 +898,7 @@ func TestAgent_Dial(t *testing.T) { } }() - conn, _, _ := setupAgent(t, codersdk.WorkspaceAgentMetadata{}, 0) + conn, _, _, _ := setupAgent(t, codersdk.WorkspaceAgentMetadata{}, 0) require.True(t, conn.AwaitReachable(context.Background())) conn1, err := conn.DialContext(context.Background(), l.Addr().Network(), l.Addr().String()) require.NoError(t, err) @@ -828,7 +919,7 @@ func TestAgent_Speedtest(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() derpMap := tailnettest.RunDERPAndSTUN(t) - conn, _, _ := setupAgent(t, codersdk.WorkspaceAgentMetadata{ + conn, _, _, _ := setupAgent(t, codersdk.WorkspaceAgentMetadata{ DERPMap: derpMap, }, 0) defer conn.Close() @@ -913,7 +1004,7 @@ func TestAgent_WriteVSCodeConfigs(t *testing.T) { } func setupSSHCommand(t *testing.T, beforeArgs []string, afterArgs []string) *exec.Cmd { - agentConn, _, _ := setupAgent(t, codersdk.WorkspaceAgentMetadata{}, 0) + agentConn, _, _, _ := setupAgent(t, codersdk.WorkspaceAgentMetadata{}, 0) listener, err := net.Listen("tcp", "127.0.0.1:0") require.NoError(t, err) waitGroup := sync.WaitGroup{} @@ -959,7 +1050,7 @@ func setupSSHCommand(t *testing.T, beforeArgs []string, afterArgs []string) *exe func setupSSHSession(t *testing.T, options codersdk.WorkspaceAgentMetadata) *ssh.Session { ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() - conn, _, _ := setupAgent(t, options, 0) + conn, _, _, _ := setupAgent(t, options, 0) sshClient, err := conn.SSHClient(ctx) require.NoError(t, err) t.Cleanup(func() { @@ -981,6 +1072,7 @@ func (c closeFunc) Close() error { func setupAgent(t *testing.T, metadata codersdk.WorkspaceAgentMetadata, ptyTimeout time.Duration) ( *codersdk.AgentConn, + *client, <-chan *codersdk.AgentStats, afero.Fs, ) { @@ -994,14 +1086,15 @@ func setupAgent(t *testing.T, metadata codersdk.WorkspaceAgentMetadata, ptyTimeo agentID := uuid.New() statsCh := make(chan *codersdk.AgentStats, 50) fs := afero.NewMemMapFs() + c := &client{ + t: t, + agentID: agentID, + metadata: metadata, + statsChan: statsCh, + coordinator: coordinator, + } closer := agent.New(agent.Options{ - Client: &client{ - t: t, - agentID: agentID, - metadata: metadata, - statsChan: statsCh, - coordinator: coordinator, - }, + Client: c, Filesystem: fs, Logger: slogtest.Make(t, nil).Leveled(slog.LevelDebug), ReconnectingPTYTimeout: ptyTimeout, @@ -1034,7 +1127,7 @@ func setupAgent(t *testing.T, metadata codersdk.WorkspaceAgentMetadata, ptyTimeo conn.SetNodeCallback(sendNode) return &codersdk.AgentConn{ Conn: conn, - }, statsCh, fs + }, c, statsCh, fs } var dialTestPayload = []byte("dean-was-here123") @@ -1075,6 +1168,9 @@ type client struct { statsChan chan *codersdk.AgentStats coordinator tailnet.Coordinator lastWorkspaceAgent func() + + mu sync.Mutex // Protects following. + lifecycleStates []codersdk.WorkspaceAgentLifecycle } func (c *client) WorkspaceAgentMetadata(_ context.Context) (codersdk.WorkspaceAgentMetadata, error) { @@ -1130,7 +1226,16 @@ func (c *client) AgentReportStats(ctx context.Context, _ slog.Logger, stats func }), nil } -func (*client) PostWorkspaceAgentLifecycle(_ context.Context, _ codersdk.PostWorkspaceAgentLifecycleRequest) error { +func (c *client) getLifecycleStates() []codersdk.WorkspaceAgentLifecycle { + c.mu.Lock() + defer c.mu.Unlock() + return c.lifecycleStates +} + +func (c *client) PostWorkspaceAgentLifecycle(_ context.Context, req codersdk.PostWorkspaceAgentLifecycleRequest) error { + c.mu.Lock() + defer c.mu.Unlock() + c.lifecycleStates = append(c.lifecycleStates, req.State) return nil } diff --git a/coderd/database/databasefake/databasefake.go b/coderd/database/databasefake/databasefake.go index 829f7d5071938..42aca99b1d00d 100644 --- a/coderd/database/databasefake/databasefake.go +++ b/coderd/database/databasefake/databasefake.go @@ -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) @@ -4296,6 +4297,10 @@ func (q *fakeQuerier) GetQuotaConsumedForUser(_ context.Context, userID uuid.UUI } 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 { diff --git a/coderd/workspaceagents.go b/coderd/workspaceagents.go index 3b9cf42cb07e6..3bef6c97fcf24 100644 --- a/coderd/workspaceagents.go +++ b/coderd/workspaceagents.go @@ -754,6 +754,7 @@ func convertWorkspaceAgent(derpMap *tailcfg.DERPMap, coordinator tailnet.Coordin Apps: apps, ConnectionTimeoutSeconds: dbAgent.ConnectionTimeoutSeconds, TroubleshootingURL: troubleshootingURL, + LifecycleState: codersdk.WorkspaceAgentLifecycle(dbAgent.LifecycleState), } node := coordinator.Node(dbAgent.ID) if node != nil { @@ -932,9 +933,18 @@ func (api *API) workspaceAgentReportLifecycle(rw http.ResponseWriter, r *http.Re 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: database.WorkspaceAgentLifecycleState(req.State), + LifecycleState: lifecycleState, }) if err != nil { httpapi.InternalServerError(rw, err) diff --git a/coderd/workspaceagents_test.go b/coderd/workspaceagents_test.go index 15927730bd915..0882a4afe2ef2 100644 --- a/coderd/workspaceagents_test.go +++ b/coderd/workspaceagents_test.go @@ -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 state", 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) + } + } + }) + } + }) +} diff --git a/codersdk/workspaceagents.go b/codersdk/workspaceagents.go index 589ee3040f424..f9465a35d2e6c 100644 --- a/codersdk/workspaceagents.go +++ b/codersdk/workspaceagents.go @@ -715,7 +715,7 @@ func (c *Client) PostWorkspaceAgentLifecycle(ctx context.Context, req PostWorksp return xerrors.Errorf("agent state post request: %w", err) } defer res.Body.Close() - if res.StatusCode != http.StatusOK { + if res.StatusCode != http.StatusNoContent { return readBodyAsError(res) } From 90192e5f37551e8e91ecce4609b969be6da3df06 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Mon, 23 Jan 2023 13:16:52 +0000 Subject: [PATCH 08/23] Fix lint --- agent/agent_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/agent/agent_test.go b/agent/agent_test.go index 82a5bec8e6452..8ad6106fccad8 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -531,6 +531,7 @@ func TestAgent_SFTP(t *testing.T) { if runtime.GOOS == "windows" { home = "/" + strings.ReplaceAll(home, "\\", "/") } + //nolint:dogsled conn, _, _, _ := setupAgent(t, codersdk.WorkspaceAgentMetadata{}, 0) sshClient, err := conn.SSHClient(ctx) require.NoError(t, err) @@ -562,6 +563,7 @@ func TestAgent_SCP(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() + //nolint:dogsled conn, _, _, _ := setupAgent(t, codersdk.WorkspaceAgentMetadata{}, 0) sshClient, err := conn.SSHClient(ctx) require.NoError(t, err) @@ -666,6 +668,7 @@ func TestAgent_StartupScript(t *testing.T) { t.Skip("This test doesn't work on Windows for some reason...") } content := "output" + //nolint:dogsled _, _, _, fs := setupAgent(t, codersdk.WorkspaceAgentMetadata{ StartupScript: "echo " + content, }, 0) @@ -797,6 +800,7 @@ func TestAgent_ReconnectingPTY(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() + //nolint:dogsled conn, _, _, _ := setupAgent(t, codersdk.WorkspaceAgentMetadata{}, 0) id := uuid.New() netConn, err := conn.ReconnectingPTY(ctx, id, 100, 100, "/bin/bash") @@ -898,6 +902,7 @@ func TestAgent_Dial(t *testing.T) { } }() + //nolint:dogsled conn, _, _, _ := setupAgent(t, codersdk.WorkspaceAgentMetadata{}, 0) require.True(t, conn.AwaitReachable(context.Background())) conn1, err := conn.DialContext(context.Background(), l.Addr().Network(), l.Addr().String()) @@ -919,6 +924,7 @@ func TestAgent_Speedtest(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() derpMap := tailnettest.RunDERPAndSTUN(t) + //nolint:dogsled conn, _, _, _ := setupAgent(t, codersdk.WorkspaceAgentMetadata{ DERPMap: derpMap, }, 0) @@ -1004,6 +1010,7 @@ func TestAgent_WriteVSCodeConfigs(t *testing.T) { } func setupSSHCommand(t *testing.T, beforeArgs []string, afterArgs []string) *exec.Cmd { + //nolint:dogsled agentConn, _, _, _ := setupAgent(t, codersdk.WorkspaceAgentMetadata{}, 0) listener, err := net.Listen("tcp", "127.0.0.1:0") require.NoError(t, err) @@ -1050,6 +1057,7 @@ func setupSSHCommand(t *testing.T, beforeArgs []string, afterArgs []string) *exe func setupSSHSession(t *testing.T, options codersdk.WorkspaceAgentMetadata) *ssh.Session { ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() + //nolint:dogsled conn, _, _, _ := setupAgent(t, options, 0) sshClient, err := conn.SSHClient(ctx) require.NoError(t, err) From aaf19bcb00ee608e945d5b2f64950f0abb34531e Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Mon, 23 Jan 2023 13:47:52 +0000 Subject: [PATCH 09/23] test: Update terraform tests for provider v0.6.7 --- provisioner/terraform/resources.go | 4 + provisioner/terraform/resources_test.go | 9 +- provisioner/terraform/testdata/generate.sh | 1 + .../multiple-agents/multiple-agents.tf | 19 +- .../multiple-agents.tfplan.json | 31 +- .../multiple-agents.tfstate.json | 25 +- provisionersdk/proto/provisioner.pb.go | 365 ++++++++++-------- provisionersdk/proto/provisioner.proto | 2 + 8 files changed, 266 insertions(+), 190 deletions(-) diff --git a/provisioner/terraform/resources.go b/provisioner/terraform/resources.go index 7e701cc82749e..043ecfe47f5cd 100644 --- a/provisioner/terraform/resources.go +++ b/provisioner/terraform/resources.go @@ -27,6 +27,8 @@ type agentAttributes struct { ConnectionTimeoutSeconds int32 `mapstructure:"connection_timeout"` TroubleshootingURL string `mapstructure:"troubleshooting_url"` MOTDFile string `mapstructure:"motd_file"` + DelayLoginUntilReady bool `mapstructure:"delay_login_until_ready"` + StartupScriptTimeout int32 `mapstructure:"startup_script_timeout"` } // A mapping of attributes on the "coder_app" resource. @@ -132,6 +134,8 @@ func ConvertResourcesAndParameters(modules []*tfjson.StateModule, rawGraph strin ConnectionTimeoutSeconds: attrs.ConnectionTimeoutSeconds, TroubleshootingUrl: attrs.TroubleshootingURL, MotdFile: attrs.MOTDFile, + DelayLoginUntilReady: attrs.DelayLoginUntilReady, + StartupScriptTimeout: attrs.StartupScriptTimeout, } switch attrs.Auth { case "token": diff --git a/provisioner/terraform/resources_test.go b/provisioner/terraform/resources_test.go index f299e64a8ed3b..2b1d73b8ffeb7 100644 --- a/provisioner/terraform/resources_test.go +++ b/provisioner/terraform/resources_test.go @@ -105,6 +105,8 @@ func TestConvertResources(t *testing.T) { Architecture: "amd64", Auth: &proto.Agent_Token{}, ConnectionTimeoutSeconds: 120, + DelayLoginUntilReady: false, + StartupScriptTimeout: 300, }, { Name: "dev2", OperatingSystem: "darwin", @@ -112,6 +114,8 @@ func TestConvertResources(t *testing.T) { Auth: &proto.Agent_Token{}, ConnectionTimeoutSeconds: 1, MotdFile: "/etc/motd", + DelayLoginUntilReady: false, + StartupScriptTimeout: 30, }, { Name: "dev3", OperatingSystem: "windows", @@ -119,6 +123,8 @@ func TestConvertResources(t *testing.T) { Auth: &proto.Agent_Token{}, ConnectionTimeoutSeconds: 120, TroubleshootingUrl: "https://coder.com/troubleshoot", + DelayLoginUntilReady: true, + StartupScriptTimeout: 300, }}, }}, }, @@ -231,7 +237,8 @@ func TestConvertResources(t *testing.T) { ConnectionTimeoutSeconds: 120, }}, }, - }}, + }, + }, "rich-parameters": { resources: []*proto.Resource{{ Name: "dev", diff --git a/provisioner/terraform/testdata/generate.sh b/provisioner/terraform/testdata/generate.sh index 9e6b7ccdc0587..29e26a310c522 100755 --- a/provisioner/terraform/testdata/generate.sh +++ b/provisioner/terraform/testdata/generate.sh @@ -9,6 +9,7 @@ for d in */; do # This needs care to update correctly. if [[ $name == "kubernetes-metadata" ]]; then + popd continue fi diff --git a/provisioner/terraform/testdata/multiple-agents/multiple-agents.tf b/provisioner/terraform/testdata/multiple-agents/multiple-agents.tf index ca40d81479532..3db1113f2dd3b 100644 --- a/provisioner/terraform/testdata/multiple-agents/multiple-agents.tf +++ b/provisioner/terraform/testdata/multiple-agents/multiple-agents.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = "0.6.4" + version = "0.6.7" } } } @@ -13,16 +13,19 @@ resource "coder_agent" "dev1" { } resource "coder_agent" "dev2" { - os = "darwin" - arch = "amd64" - connection_timeout = 1 - motd_file = "/etc/motd" + os = "darwin" + arch = "amd64" + connection_timeout = 1 + motd_file = "/etc/motd" + startup_script_timeout = 30 + delay_login_until_ready = false } resource "coder_agent" "dev3" { - os = "windows" - arch = "arm64" - troubleshooting_url = "https://coder.com/troubleshoot" + os = "windows" + arch = "arm64" + troubleshooting_url = "https://coder.com/troubleshoot" + delay_login_until_ready = true } resource "null_resource" "dev" { diff --git a/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfplan.json b/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfplan.json index 66ec6c3d868b2..ef9f6e331b9a6 100644 --- a/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfplan.json +++ b/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.1", - "terraform_version": "1.3.3", + "terraform_version": "1.3.7", "planned_values": { "root_module": { "resources": [ @@ -15,11 +15,14 @@ "arch": "amd64", "auth": "token", "connection_timeout": 120, + "delay_login_until_ready": false, "dir": null, "env": null, "motd_file": null, "os": "linux", + "shutdown_script": null, "startup_script": null, + "startup_script_timeout": 300, "troubleshooting_url": null }, "sensitive_values": {} @@ -35,11 +38,14 @@ "arch": "amd64", "auth": "token", "connection_timeout": 1, + "delay_login_until_ready": false, "dir": null, "env": null, "motd_file": "/etc/motd", "os": "darwin", + "shutdown_script": null, "startup_script": null, + "startup_script_timeout": 30, "troubleshooting_url": null }, "sensitive_values": {} @@ -55,11 +61,14 @@ "arch": "arm64", "auth": "token", "connection_timeout": 120, + "delay_login_until_ready": true, "dir": null, "env": null, "motd_file": null, "os": "windows", + "shutdown_script": null, "startup_script": null, + "startup_script_timeout": 300, "troubleshooting_url": "https://coder.com/troubleshoot" }, "sensitive_values": {} @@ -95,11 +104,14 @@ "arch": "amd64", "auth": "token", "connection_timeout": 120, + "delay_login_until_ready": false, "dir": null, "env": null, "motd_file": null, "os": "linux", + "shutdown_script": null, "startup_script": null, + "startup_script_timeout": 300, "troubleshooting_url": null }, "after_unknown": { @@ -128,11 +140,14 @@ "arch": "amd64", "auth": "token", "connection_timeout": 1, + "delay_login_until_ready": false, "dir": null, "env": null, "motd_file": "/etc/motd", "os": "darwin", + "shutdown_script": null, "startup_script": null, + "startup_script_timeout": 30, "troubleshooting_url": null }, "after_unknown": { @@ -161,11 +176,14 @@ "arch": "arm64", "auth": "token", "connection_timeout": 120, + "delay_login_until_ready": true, "dir": null, "env": null, "motd_file": null, "os": "windows", + "shutdown_script": null, "startup_script": null, + "startup_script_timeout": 300, "troubleshooting_url": "https://coder.com/troubleshoot" }, "after_unknown": { @@ -206,7 +224,7 @@ "coder": { "name": "coder", "full_name": "registry.terraform.io/coder/coder", - "version_constraint": "0.6.4" + "version_constraint": "0.6.7" }, "null": { "name": "null", @@ -244,11 +262,17 @@ "connection_timeout": { "constant_value": 1 }, + "delay_login_until_ready": { + "constant_value": false + }, "motd_file": { "constant_value": "/etc/motd" }, "os": { "constant_value": "darwin" + }, + "startup_script_timeout": { + "constant_value": 30 } }, "schema_version": 0 @@ -263,6 +287,9 @@ "arch": { "constant_value": "arm64" }, + "delay_login_until_ready": { + "constant_value": true + }, "os": { "constant_value": "windows" }, diff --git a/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfstate.json b/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfstate.json index 68db0a20abf8d..b4f0d1594bdf5 100644 --- a/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfstate.json +++ b/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.3.3", + "terraform_version": "1.3.7", "values": { "root_module": { "resources": [ @@ -15,14 +15,17 @@ "arch": "amd64", "auth": "token", "connection_timeout": 120, + "delay_login_until_ready": false, "dir": null, "env": null, - "id": "e545d734-f852-4fda-ac8f-39e3ff094e58", + "id": "8ba856b4-4aa9-4fbe-aa04-9af53dc93f08", "init_script": "", "motd_file": null, "os": "linux", + "shutdown_script": null, "startup_script": null, - "token": "c2c47266-af7a-467c-9ffc-30c3270ffecb", + "startup_script_timeout": 300, + "token": "c7f72bfa-c84c-4b52-898c-1c056a42141e", "troubleshooting_url": null }, "sensitive_values": {} @@ -38,14 +41,17 @@ "arch": "amd64", "auth": "token", "connection_timeout": 1, + "delay_login_until_ready": false, "dir": null, "env": null, - "id": "b5e18556-d202-478f-80d9-76f34a4cb105", + "id": "3e79acd5-88f4-4de6-8145-a8e0e2b1129b", "init_script": "", "motd_file": "/etc/motd", "os": "darwin", + "shutdown_script": null, "startup_script": null, - "token": "795082f9-642a-4647-a595-6539edaa74a3", + "startup_script_timeout": 30, + "token": "0e2fa4e7-df44-41c4-a6e4-9e46c6f5e441", "troubleshooting_url": null }, "sensitive_values": {} @@ -61,14 +67,17 @@ "arch": "arm64", "auth": "token", "connection_timeout": 120, + "delay_login_until_ready": true, "dir": null, "env": null, - "id": "27e1114a-bc92-4e35-ab57-1680f3b7658f", + "id": "c9df6531-41f4-4005-b1a7-b4c4712b117f", "init_script": "", "motd_file": null, "os": "windows", + "shutdown_script": null, "startup_script": null, - "token": "c4fc1679-eb42-4d9f-bca8-fcf9641a7256", + "startup_script_timeout": 300, + "token": "68f0e144-22ce-455f-be00-edef913f34a6", "troubleshooting_url": "https://coder.com/troubleshoot" }, "sensitive_values": {} @@ -81,7 +90,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "5577006791947779410", + "id": "5895060021397476995", "triggers": null }, "sensitive_values": {}, diff --git a/provisionersdk/proto/provisioner.pb.go b/provisionersdk/proto/provisioner.pb.go index 1355451e5c57e..b47a77b6f9efa 100644 --- a/provisionersdk/proto/provisioner.pb.go +++ b/provisionersdk/proto/provisioner.pb.go @@ -1017,6 +1017,8 @@ type Agent struct { ConnectionTimeoutSeconds int32 `protobuf:"varint,11,opt,name=connection_timeout_seconds,json=connectionTimeoutSeconds,proto3" json:"connection_timeout_seconds,omitempty"` TroubleshootingUrl string `protobuf:"bytes,12,opt,name=troubleshooting_url,json=troubleshootingUrl,proto3" json:"troubleshooting_url,omitempty"` MotdFile string `protobuf:"bytes,13,opt,name=motd_file,json=motdFile,proto3" json:"motd_file,omitempty"` + DelayLoginUntilReady bool `protobuf:"varint,14,opt,name=delay_login_until_ready,json=delayLoginUntilReady,proto3" json:"delay_login_until_ready,omitempty"` + StartupScriptTimeout int32 `protobuf:"varint,15,opt,name=startup_script_timeout,json=startupScriptTimeout,proto3" json:"startup_script_timeout,omitempty"` } func (x *Agent) Reset() { @@ -1149,6 +1151,20 @@ func (x *Agent) GetMotdFile() string { return "" } +func (x *Agent) GetDelayLoginUntilReady() bool { + if x != nil { + return x.DelayLoginUntilReady + } + return false +} + +func (x *Agent) GetStartupScriptTimeout() int32 { + if x != nil { + return x.StartupScriptTimeout + } + return 0 +} + type isAgent_Auth interface { isAgent_Auth() } @@ -2459,7 +2475,7 @@ var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{ 0x0a, 0x14, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x41, 0x75, 0x74, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, - 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x22, 0x9b, 0x04, 0x0a, 0x05, 0x41, 0x67, 0x65, 0x6e, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x22, 0x88, 0x05, 0x0a, 0x05, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x03, 0x65, 0x6e, 0x76, 0x18, 0x03, 0x20, 0x03, @@ -2489,181 +2505,188 @@ var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{ 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x74, 0x72, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x73, 0x68, 0x6f, 0x6f, 0x74, 0x69, 0x6e, 0x67, 0x55, 0x72, 0x6c, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x6f, 0x74, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x6f, 0x74, - 0x64, 0x46, 0x69, 0x6c, 0x65, 0x1a, 0x36, 0x0a, 0x08, 0x45, 0x6e, 0x76, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x06, 0x0a, - 0x04, 0x61, 0x75, 0x74, 0x68, 0x22, 0xb5, 0x02, 0x0a, 0x03, 0x41, 0x70, 0x70, 0x12, 0x12, 0x0a, - 0x04, 0x73, 0x6c, 0x75, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x73, 0x6c, 0x75, - 0x67, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, - 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x10, - 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, - 0x12, 0x12, 0x0a, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x69, 0x63, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, - 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, - 0x69, 0x6e, 0x12, 0x3a, 0x0a, 0x0b, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, - 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, - 0x6b, 0x52, 0x0b, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x41, - 0x0a, 0x0d, 0x73, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x65, - 0x76, 0x65, 0x6c, 0x52, 0x0c, 0x73, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, - 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x18, 0x09, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x22, 0x59, 0x0a, - 0x0b, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x10, 0x0a, 0x03, - 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x1a, - 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x68, - 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x74, - 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x22, 0xf1, 0x02, 0x0a, 0x08, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2a, 0x0a, - 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x67, 0x65, 0x6e, - 0x74, 0x52, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x3a, 0x0a, 0x08, 0x6d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x69, 0x64, 0x65, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x04, 0x68, 0x69, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x63, 0x6f, - 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x12, 0x23, 0x0a, - 0x0d, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x5f, 0x63, 0x6f, 0x73, 0x74, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x43, 0x6f, 0x73, - 0x74, 0x1a, 0x69, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, - 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, - 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, - 0x69, 0x76, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x73, 0x5f, 0x6e, 0x75, 0x6c, 0x6c, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x73, 0x4e, 0x75, 0x6c, 0x6c, 0x22, 0xfc, 0x01, 0x0a, - 0x05, 0x50, 0x61, 0x72, 0x73, 0x65, 0x1a, 0x27, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x1a, - 0x55, 0x0a, 0x08, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x49, 0x0a, 0x11, 0x70, - 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x53, 0x63, - 0x68, 0x65, 0x6d, 0x61, 0x52, 0x10, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x53, - 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x1a, 0x73, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x24, 0x0a, 0x03, 0x6c, 0x6f, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4c, 0x6f, - 0x67, 0x48, 0x00, 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x12, 0x39, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x70, - 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x2e, 0x43, - 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, - 0x65, 0x74, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x82, 0x0a, 0x0a, 0x09, - 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0xd1, 0x02, 0x0a, 0x08, 0x4d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x5f, - 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x64, 0x65, 0x72, - 0x55, 0x72, 0x6c, 0x12, 0x53, 0x0a, 0x14, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, - 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x77, 0x6f, 0x72, 0x6b, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, - 0x27, 0x0a, 0x0f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, - 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x77, 0x6f, 0x72, 0x6b, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, - 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x77, - 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, - 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x15, 0x77, 0x6f, 0x72, - 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x65, 0x6d, 0x61, - 0x69, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x1a, 0x79, 0x0a, - 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, - 0x74, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, - 0x63, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3b, 0x0a, 0x08, 0x6d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, - 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0xda, 0x01, 0x0a, 0x04, 0x50, 0x6c, 0x61, - 0x6e, 0x12, 0x35, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, - 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x46, 0x0a, 0x10, 0x70, 0x61, 0x72, 0x61, - 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, - 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, - 0x0f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, - 0x12, 0x53, 0x0a, 0x15, 0x72, 0x69, 0x63, 0x68, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, - 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, - 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x52, 0x13, 0x72, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x73, 0x1a, 0x52, 0x0a, 0x05, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x12, 0x35, + 0x64, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x35, 0x0a, 0x17, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x6c, + 0x6f, 0x67, 0x69, 0x6e, 0x5f, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x79, + 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x4c, 0x6f, 0x67, + 0x69, 0x6e, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x52, 0x65, 0x61, 0x64, 0x79, 0x12, 0x34, 0x0a, 0x16, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x5f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x5f, 0x74, + 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x14, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x75, 0x70, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, + 0x75, 0x74, 0x1a, 0x36, 0x0a, 0x08, 0x45, 0x6e, 0x76, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x06, 0x0a, 0x04, 0x61, 0x75, + 0x74, 0x68, 0x22, 0xb5, 0x02, 0x0a, 0x03, 0x41, 0x70, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x6c, + 0x75, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x12, 0x21, + 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, + 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x12, 0x0a, + 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x63, 0x6f, + 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, + 0x3a, 0x0a, 0x0b, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x65, 0x72, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x0b, + 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x41, 0x0a, 0x0d, 0x73, + 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x2e, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, + 0x52, 0x0c, 0x73, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1a, + 0x0a, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x22, 0x59, 0x0a, 0x0b, 0x48, 0x65, + 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x68, 0x72, 0x65, 0x73, + 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x74, 0x68, 0x72, 0x65, + 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x22, 0xf1, 0x02, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2a, 0x0a, 0x06, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x06, + 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x3a, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x69, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x04, 0x68, 0x69, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0c, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, + 0x1d, 0x0a, 0x0a, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x5f, 0x63, 0x6f, 0x73, 0x74, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x09, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x43, 0x6f, 0x73, 0x74, 0x1a, 0x69, + 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, + 0x12, 0x17, 0x0a, 0x07, 0x69, 0x73, 0x5f, 0x6e, 0x75, 0x6c, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x06, 0x69, 0x73, 0x4e, 0x75, 0x6c, 0x6c, 0x22, 0xfc, 0x01, 0x0a, 0x05, 0x50, 0x61, + 0x72, 0x73, 0x65, 0x1a, 0x27, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, + 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x1a, 0x55, 0x0a, 0x08, + 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x49, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x61, + 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x72, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, + 0x61, 0x52, 0x10, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, + 0x6d, 0x61, 0x73, 0x1a, 0x73, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x24, 0x0a, 0x03, 0x6c, 0x6f, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x48, 0x00, + 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x12, 0x39, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x70, + 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, + 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x82, 0x0a, 0x0a, 0x09, 0x50, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0xd1, 0x02, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x55, 0x72, 0x6c, + 0x12, 0x53, 0x0a, 0x14, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, + 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x57, 0x6f, 0x72, + 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x77, + 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x0f, + 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x77, 0x6f, 0x72, + 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x77, 0x6f, 0x72, 0x6b, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, + 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x15, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x1a, 0x79, 0x0a, 0x06, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, + 0x72, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3b, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0xda, 0x01, 0x0a, 0x04, 0x50, 0x6c, 0x61, 0x6e, 0x12, 0x35, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x1a, 0x08, 0x0a, 0x06, 0x43, 0x61, 0x6e, - 0x63, 0x65, 0x6c, 0x1a, 0xb3, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x31, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x48, 0x00, 0x52, 0x04, 0x70, 0x6c, - 0x61, 0x6e, 0x12, 0x34, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, - 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x48, - 0x00, 0x52, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x12, 0x37, 0x0a, 0x06, 0x63, 0x61, 0x6e, 0x63, - 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x48, 0x00, 0x52, 0x06, 0x63, 0x61, 0x6e, 0x63, 0x65, - 0x6c, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x1a, 0xbb, 0x01, 0x0a, 0x08, 0x43, 0x6f, - 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, - 0x6f, 0x72, 0x12, 0x33, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, - 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x3a, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, - 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, - 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, - 0x65, 0x72, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x1a, 0x77, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x24, 0x0a, 0x03, 0x6c, 0x6f, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4c, - 0x6f, 0x67, 0x48, 0x00, 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x12, 0x3d, 0x0a, 0x08, 0x63, 0x6f, 0x6d, - 0x70, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x46, 0x0a, 0x10, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, + 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0f, 0x70, 0x61, + 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x53, 0x0a, + 0x15, 0x72, 0x69, 0x63, 0x68, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, + 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x13, 0x72, + 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x73, 0x1a, 0x52, 0x0a, 0x05, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x12, 0x35, 0x0a, 0x06, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x08, - 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, - 0x2a, 0x3f, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x09, 0x0a, 0x05, - 0x54, 0x52, 0x41, 0x43, 0x45, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x45, 0x42, 0x55, 0x47, - 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, - 0x57, 0x41, 0x52, 0x4e, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, - 0x04, 0x2a, 0x3b, 0x0a, 0x0f, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4c, - 0x65, 0x76, 0x65, 0x6c, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x57, 0x4e, 0x45, 0x52, 0x10, 0x00, 0x12, - 0x11, 0x0a, 0x0d, 0x41, 0x55, 0x54, 0x48, 0x45, 0x4e, 0x54, 0x49, 0x43, 0x41, 0x54, 0x45, 0x44, - 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x10, 0x02, 0x2a, 0x37, - 0x0a, 0x13, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x54, 0x41, 0x52, 0x54, 0x10, 0x00, - 0x12, 0x08, 0x0a, 0x04, 0x53, 0x54, 0x4f, 0x50, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, - 0x53, 0x54, 0x52, 0x4f, 0x59, 0x10, 0x02, 0x32, 0xa3, 0x01, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x12, 0x42, 0x0a, 0x05, 0x50, 0x61, 0x72, 0x73, 0x65, - 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, - 0x61, 0x72, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, - 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, - 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x50, 0x0a, 0x09, 0x50, - 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x1a, 0x08, 0x0a, 0x06, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, + 0x1a, 0xb3, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x04, + 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x48, 0x00, 0x52, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x12, + 0x34, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, + 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x48, 0x00, 0x52, 0x05, + 0x61, 0x70, 0x70, 0x6c, 0x79, 0x12, 0x37, 0x0a, 0x06, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x61, + 0x6e, 0x63, 0x65, 0x6c, 0x48, 0x00, 0x52, 0x06, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x42, 0x06, + 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x1a, 0xbb, 0x01, 0x0a, 0x08, 0x43, 0x6f, 0x6d, 0x70, 0x6c, + 0x65, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, + 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, + 0x33, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x12, 0x3a, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, + 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, + 0x65, 0x74, 0x65, 0x72, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, + 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, + 0x70, 0x6c, 0x61, 0x6e, 0x1a, 0x77, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x24, 0x0a, 0x03, 0x6c, 0x6f, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x48, + 0x00, 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x12, 0x3d, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, + 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x42, 0x2d, 0x5a, - 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, - 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x73, 0x64, 0x6b, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x08, 0x63, 0x6f, 0x6d, + 0x70, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x2a, 0x3f, 0x0a, + 0x08, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x09, 0x0a, 0x05, 0x54, 0x52, 0x41, + 0x43, 0x45, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x01, 0x12, + 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x41, 0x52, + 0x4e, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x04, 0x2a, 0x3b, + 0x0a, 0x0f, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, + 0x6c, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x57, 0x4e, 0x45, 0x52, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, + 0x41, 0x55, 0x54, 0x48, 0x45, 0x4e, 0x54, 0x49, 0x43, 0x41, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, + 0x0a, 0x0a, 0x06, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x10, 0x02, 0x2a, 0x37, 0x0a, 0x13, 0x57, + 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x54, 0x41, 0x52, 0x54, 0x10, 0x00, 0x12, 0x08, 0x0a, + 0x04, 0x53, 0x54, 0x4f, 0x50, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x53, 0x54, 0x52, + 0x4f, 0x59, 0x10, 0x02, 0x32, 0xa3, 0x01, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x65, 0x72, 0x12, 0x42, 0x0a, 0x05, 0x50, 0x61, 0x72, 0x73, 0x65, 0x12, 0x1a, 0x2e, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, + 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x2e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x50, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x42, 0x2d, 0x5a, 0x2b, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, + 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x73, 0x64, 0x6b, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( diff --git a/provisionersdk/proto/provisioner.proto b/provisionersdk/proto/provisioner.proto index c1dcb09fcee8e..d0707f1e2f604 100644 --- a/provisionersdk/proto/provisioner.proto +++ b/provisionersdk/proto/provisioner.proto @@ -116,6 +116,8 @@ message Agent { int32 connection_timeout_seconds = 11; string troubleshooting_url = 12; string motd_file = 13; + bool delay_login_until_ready = 14; + int32 startup_script_timeout = 15; } enum AppSharingLevel { From bd1a87f584c8340a905da1bfdeab562eda396473 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Mon, 23 Jan 2023 14:32:11 +0000 Subject: [PATCH 10/23] test(site): Update agent mocks --- site/src/testHelpers/entities.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index b588d51314a05..6ac7d92b066e6 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -301,6 +301,7 @@ export const MockWorkspaceAgent: TypesGen.WorkspaceAgent = { }, connection_timeout_seconds: 120, troubleshooting_url: "https://coder.com/troubleshoot", + lifecycle_state: "starting", } export const MockWorkspaceAgentDisconnected: TypesGen.WorkspaceAgent = { @@ -310,6 +311,7 @@ export const MockWorkspaceAgentDisconnected: TypesGen.WorkspaceAgent = { status: "disconnected", version: "", latency: {}, + lifecycle_state: "ready", } export const MockWorkspaceAgentOutdated: TypesGen.WorkspaceAgent = { @@ -333,6 +335,7 @@ export const MockWorkspaceAgentOutdated: TypesGen.WorkspaceAgent = { latency_ms: 221.66, }, }, + lifecycle_state: "ready", } export const MockWorkspaceAgentConnecting: TypesGen.WorkspaceAgent = { @@ -342,6 +345,7 @@ export const MockWorkspaceAgentConnecting: TypesGen.WorkspaceAgent = { status: "connecting", version: "", latency: {}, + lifecycle_state: "created", } export const MockWorkspaceAgentTimeout: TypesGen.WorkspaceAgent = { @@ -351,6 +355,28 @@ export const MockWorkspaceAgentTimeout: TypesGen.WorkspaceAgent = { status: "timeout", version: "", latency: {}, + lifecycle_state: "created", +} + +export const MockWorkspaceAgentStarting: TypesGen.WorkspaceAgent = { + ...MockWorkspaceAgent, + id: "test-workspace-agent-starting", + name: "a-starting-workspace-agent", + lifecycle_state: "starting", +} + +export const MockWorkspaceAgentStartTimeout: TypesGen.WorkspaceAgent = { + ...MockWorkspaceAgent, + id: "test-workspace-agent-start-timeout", + name: "a-workspace-agent-timed-out-while-running-startup-script", + lifecycle_state: "start_timeout", +} + +export const MockWorkspaceAgentStartError: TypesGen.WorkspaceAgent = { + ...MockWorkspaceAgent, + id: "test-workspace-agent-start-error", + name: "a-workspace-agent-errored-while-running-startup-script", + lifecycle_state: "start_error", } export const MockWorkspaceResource: TypesGen.WorkspaceResource = { From df9944e3b0b2ec92991ea2b21237d8223622407d Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Mon, 23 Jan 2023 15:08:28 +0000 Subject: [PATCH 11/23] Add new columns to workspace agent table --- coderd/database/dump.sql | 8 +- .../000091_add_workspace_agent_state.down.sql | 3 + .../000091_add_workspace_agent_state.up.sql | 10 +- coderd/database/models.go | 4 + coderd/database/queries.sql.go | 66 ++-- coderd/database/queries/workspaceagents.sql | 6 +- .../provisionerdserver/provisionerdserver.go | 8 +- provisionersdk/proto/provisioner.pb.go | 370 +++++++++--------- provisionersdk/proto/provisioner.proto | 2 +- 9 files changed, 260 insertions(+), 217 deletions(-) diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index 2a93ec2f4c77c..74ab801f8131d 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -457,7 +457,9 @@ CREATE TABLE workspace_agents ( connection_timeout_seconds integer DEFAULT 0 NOT NULL, troubleshooting_url 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 + 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.'; @@ -470,6 +472,10 @@ COMMENT ON COLUMN workspace_agents.motd_file IS 'Path to file inside workspace c COMMENT ON COLUMN workspace_agents.lifecycle_state IS 'The current lifecycle state of 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, diff --git a/coderd/database/migrations/000091_add_workspace_agent_state.down.sql b/coderd/database/migrations/000091_add_workspace_agent_state.down.sql index fec6cec86818c..b8c0a33a32a3d 100644 --- a/coderd/database/migrations/000091_add_workspace_agent_state.down.sql +++ b/coderd/database/migrations/000091_add_workspace_agent_state.down.sql @@ -1,3 +1,6 @@ +ALTER TABLE workspace_agents DROP COLUMN startup_script_timeout; +ALTER TABLE workspace_agents DROP COLUMN delay_login_until_ready; + ALTER TABLE workspace_agents DROP COLUMN lifecycle_state; DROP TYPE workspace_agent_lifecycle_state; diff --git a/coderd/database/migrations/000091_add_workspace_agent_state.up.sql b/coderd/database/migrations/000091_add_workspace_agent_state.up.sql index 4057f3bc8b206..0c3b198712607 100644 --- a/coderd/database/migrations/000091_add_workspace_agent_state.up.sql +++ b/coderd/database/migrations/000091_add_workspace_agent_state.up.sql @@ -1,5 +1,13 @@ CREATE TYPE workspace_agent_lifecycle_state AS ENUM ('created', 'starting', 'start_timeout', 'start_error', 'ready'); ALTER TABLE workspace_agents ADD COLUMN lifecycle_state workspace_agent_lifecycle_state NOT NULL DEFAULT 'created'; - COMMENT ON COLUMN workspace_agents.lifecycle_state IS 'The current lifecycle state of 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.'; diff --git a/coderd/database/models.go b/coderd/database/models.go index 05f5b613f7a65..a0314a0b603f8 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -1517,6 +1517,10 @@ type WorkspaceAgent struct { MOTDFile string `db:"motd_file" json:"motd_file"` // The current lifecycle state of 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 { diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 4668f95d3ac17..4eff98612623b 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -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, lifecycle_state + 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 @@ -4905,13 +4905,15 @@ func (q *sqlQuerier) GetWorkspaceAgentByAuthToken(ctx context.Context, authToken &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, lifecycle_state + 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 @@ -4945,13 +4947,15 @@ func (q *sqlQuerier) GetWorkspaceAgentByID(ctx context.Context, id uuid.UUID) (W &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, lifecycle_state + 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 @@ -4987,13 +4991,15 @@ func (q *sqlQuerier) GetWorkspaceAgentByInstanceID(ctx context.Context, authInst &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, lifecycle_state + 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 @@ -5033,6 +5039,8 @@ func (q *sqlQuerier) GetWorkspaceAgentsByResourceIDs(ctx context.Context, ids [] &i.TroubleshootingURL, &i.MOTDFile, &i.LifecycleState, + &i.DelayLoginUntilReady, + &i.StartupScriptTimeoutSeconds, ); err != nil { return nil, err } @@ -5048,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, lifecycle_state 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) { @@ -5084,6 +5092,8 @@ func (q *sqlQuerier) GetWorkspaceAgentsCreatedAfter(ctx context.Context, created &i.TroubleshootingURL, &i.MOTDFile, &i.LifecycleState, + &i.DelayLoginUntilReady, + &i.StartupScriptTimeoutSeconds, ); err != nil { return nil, err } @@ -5117,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, lifecycle_state + ($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) { @@ -5162,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( @@ -5188,6 +5204,8 @@ func (q *sqlQuerier) InsertWorkspaceAgent(ctx context.Context, arg InsertWorkspa &i.TroubleshootingURL, &i.MOTDFile, &i.LifecycleState, + &i.DelayLoginUntilReady, + &i.StartupScriptTimeoutSeconds, ) return i, err } diff --git a/coderd/database/queries/workspaceagents.sql b/coderd/database/queries/workspaceagents.sql index 0bee46f91cb14..25e7de2863459 100644 --- a/coderd/database/queries/workspaceagents.sql +++ b/coderd/database/queries/workspaceagents.sql @@ -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 diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go index 30a73fd7aa4cd..04f3a42876963 100644 --- a/coderd/provisionerdserver/provisionerdserver.go +++ b/coderd/provisionerdserver/provisionerdserver.go @@ -946,9 +946,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) diff --git a/provisionersdk/proto/provisioner.pb.go b/provisionersdk/proto/provisioner.pb.go index b47a77b6f9efa..ce29977d21542 100644 --- a/provisionersdk/proto/provisioner.pb.go +++ b/provisionersdk/proto/provisioner.pb.go @@ -1013,12 +1013,12 @@ type Agent struct { // // *Agent_Token // *Agent_InstanceId - Auth isAgent_Auth `protobuf_oneof:"auth"` - ConnectionTimeoutSeconds int32 `protobuf:"varint,11,opt,name=connection_timeout_seconds,json=connectionTimeoutSeconds,proto3" json:"connection_timeout_seconds,omitempty"` - TroubleshootingUrl string `protobuf:"bytes,12,opt,name=troubleshooting_url,json=troubleshootingUrl,proto3" json:"troubleshooting_url,omitempty"` - MotdFile string `protobuf:"bytes,13,opt,name=motd_file,json=motdFile,proto3" json:"motd_file,omitempty"` - DelayLoginUntilReady bool `protobuf:"varint,14,opt,name=delay_login_until_ready,json=delayLoginUntilReady,proto3" json:"delay_login_until_ready,omitempty"` - StartupScriptTimeout int32 `protobuf:"varint,15,opt,name=startup_script_timeout,json=startupScriptTimeout,proto3" json:"startup_script_timeout,omitempty"` + Auth isAgent_Auth `protobuf_oneof:"auth"` + ConnectionTimeoutSeconds int32 `protobuf:"varint,11,opt,name=connection_timeout_seconds,json=connectionTimeoutSeconds,proto3" json:"connection_timeout_seconds,omitempty"` + TroubleshootingUrl string `protobuf:"bytes,12,opt,name=troubleshooting_url,json=troubleshootingUrl,proto3" json:"troubleshooting_url,omitempty"` + MotdFile string `protobuf:"bytes,13,opt,name=motd_file,json=motdFile,proto3" json:"motd_file,omitempty"` + DelayLoginUntilReady bool `protobuf:"varint,14,opt,name=delay_login_until_ready,json=delayLoginUntilReady,proto3" json:"delay_login_until_ready,omitempty"` + StartupScriptTimeoutSeconds int32 `protobuf:"varint,15,opt,name=startup_script_timeout_seconds,json=startupScriptTimeoutSeconds,proto3" json:"startup_script_timeout_seconds,omitempty"` } func (x *Agent) Reset() { @@ -1158,9 +1158,9 @@ func (x *Agent) GetDelayLoginUntilReady() bool { return false } -func (x *Agent) GetStartupScriptTimeout() int32 { +func (x *Agent) GetStartupScriptTimeoutSeconds() int32 { if x != nil { - return x.StartupScriptTimeout + return x.StartupScriptTimeoutSeconds } return 0 } @@ -2475,7 +2475,7 @@ var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{ 0x0a, 0x14, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x41, 0x75, 0x74, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, - 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x22, 0x88, 0x05, 0x0a, 0x05, 0x41, 0x67, 0x65, 0x6e, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x22, 0x97, 0x05, 0x0a, 0x05, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x03, 0x65, 0x6e, 0x76, 0x18, 0x03, 0x20, 0x03, @@ -2508,185 +2508,185 @@ var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{ 0x64, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x35, 0x0a, 0x17, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x5f, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x79, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x4c, 0x6f, 0x67, - 0x69, 0x6e, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x52, 0x65, 0x61, 0x64, 0x79, 0x12, 0x34, 0x0a, 0x16, + 0x69, 0x6e, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x52, 0x65, 0x61, 0x64, 0x79, 0x12, 0x43, 0x0a, 0x1e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x5f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x5f, 0x74, - 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x14, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x75, 0x70, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, - 0x75, 0x74, 0x1a, 0x36, 0x0a, 0x08, 0x45, 0x6e, 0x76, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, - 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, - 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x06, 0x0a, 0x04, 0x61, 0x75, - 0x74, 0x68, 0x22, 0xb5, 0x02, 0x0a, 0x03, 0x41, 0x70, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x6c, - 0x75, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x12, 0x21, - 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, - 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x12, 0x0a, - 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x63, 0x6f, - 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, - 0x3a, 0x0a, 0x0b, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x65, 0x72, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x0b, - 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x41, 0x0a, 0x0d, 0x73, - 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, - 0x2e, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, - 0x52, 0x0c, 0x73, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1a, - 0x0a, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x22, 0x59, 0x0a, 0x0b, 0x48, 0x65, - 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x68, 0x72, 0x65, 0x73, - 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x74, 0x68, 0x72, 0x65, - 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x22, 0xf1, 0x02, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2a, 0x0a, 0x06, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x06, - 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x3a, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x69, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x04, 0x68, 0x69, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, - 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0c, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, - 0x1d, 0x0a, 0x0a, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x5f, 0x63, 0x6f, 0x73, 0x74, 0x18, 0x08, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x09, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x43, 0x6f, 0x73, 0x74, 0x1a, 0x69, - 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, - 0x12, 0x17, 0x0a, 0x07, 0x69, 0x73, 0x5f, 0x6e, 0x75, 0x6c, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x06, 0x69, 0x73, 0x4e, 0x75, 0x6c, 0x6c, 0x22, 0xfc, 0x01, 0x0a, 0x05, 0x50, 0x61, - 0x72, 0x73, 0x65, 0x1a, 0x27, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, - 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x1a, 0x55, 0x0a, 0x08, - 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x49, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x61, - 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, - 0x72, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, - 0x61, 0x52, 0x10, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, - 0x6d, 0x61, 0x73, 0x1a, 0x73, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x0f, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x1b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x53, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, + 0x73, 0x1a, 0x36, 0x0a, 0x08, 0x45, 0x6e, 0x76, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x06, 0x0a, 0x04, 0x61, 0x75, 0x74, + 0x68, 0x22, 0xb5, 0x02, 0x0a, 0x03, 0x41, 0x70, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x6c, 0x75, + 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x12, 0x21, 0x0a, + 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, + 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, + 0x69, 0x63, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x63, 0x6f, 0x6e, + 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x3a, + 0x0a, 0x0b, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x72, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x0b, 0x68, + 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x41, 0x0a, 0x0d, 0x73, 0x68, + 0x61, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, + 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, + 0x0c, 0x73, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1a, 0x0a, + 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x22, 0x59, 0x0a, 0x0b, 0x48, 0x65, 0x61, + 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, + 0x6f, 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x74, 0x68, 0x72, 0x65, 0x73, + 0x68, 0x6f, 0x6c, 0x64, 0x22, 0xf1, 0x02, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2a, 0x0a, 0x06, 0x61, 0x67, 0x65, + 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x61, + 0x67, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x3a, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x69, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x04, 0x68, 0x69, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0c, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, + 0x0a, 0x0a, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x5f, 0x63, 0x6f, 0x73, 0x74, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x09, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x43, 0x6f, 0x73, 0x74, 0x1a, 0x69, 0x0a, + 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x12, + 0x17, 0x0a, 0x07, 0x69, 0x73, 0x5f, 0x6e, 0x75, 0x6c, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x06, 0x69, 0x73, 0x4e, 0x75, 0x6c, 0x6c, 0x22, 0xfc, 0x01, 0x0a, 0x05, 0x50, 0x61, 0x72, + 0x73, 0x65, 0x1a, 0x27, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, + 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x1a, 0x55, 0x0a, 0x08, 0x43, + 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x49, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x61, 0x6d, + 0x65, 0x74, 0x65, 0x72, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, + 0x52, 0x10, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, + 0x61, 0x73, 0x1a, 0x73, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, + 0x0a, 0x03, 0x6c, 0x6f, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x48, 0x00, 0x52, + 0x03, 0x6c, 0x6f, 0x67, 0x12, 0x39, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, + 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x42, + 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x82, 0x0a, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0xd1, 0x02, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x55, 0x72, 0x6c, 0x12, + 0x53, 0x0a, 0x14, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x57, 0x6f, 0x72, 0x6b, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x77, 0x6f, + 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x77, + 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, + 0x77, 0x6e, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x77, 0x6f, 0x72, 0x6b, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x77, 0x6f, 0x72, 0x6b, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x10, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, + 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x15, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, + 0x77, 0x6e, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x1a, 0x79, 0x0a, 0x06, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, + 0x79, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3b, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x1a, 0xda, 0x01, 0x0a, 0x04, 0x50, 0x6c, 0x61, 0x6e, 0x12, 0x35, 0x0a, + 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x12, 0x46, 0x0a, 0x10, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, + 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, + 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, + 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0f, 0x70, 0x61, 0x72, + 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x53, 0x0a, 0x15, + 0x72, 0x69, 0x63, 0x68, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x13, 0x72, 0x69, + 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x73, 0x1a, 0x52, 0x0a, 0x05, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x12, 0x35, 0x0a, 0x06, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x1a, 0x08, 0x0a, 0x06, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x1a, + 0xb3, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x04, 0x70, + 0x6c, 0x61, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x48, 0x00, 0x52, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x12, 0x34, + 0x0a, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x48, 0x00, 0x52, 0x05, 0x61, + 0x70, 0x70, 0x6c, 0x79, 0x12, 0x37, 0x0a, 0x06, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x61, 0x6e, + 0x63, 0x65, 0x6c, 0x48, 0x00, 0x52, 0x06, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x42, 0x06, 0x0a, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x1a, 0xbb, 0x01, 0x0a, 0x08, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, + 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x33, + 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x12, 0x3a, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, + 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, + 0x74, 0x65, 0x72, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, + 0x12, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x70, + 0x6c, 0x61, 0x6e, 0x1a, 0x77, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, 0x0a, 0x03, 0x6c, 0x6f, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x48, 0x00, - 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x12, 0x39, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x70, - 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, - 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x82, 0x0a, 0x0a, 0x09, 0x50, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0xd1, 0x02, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x55, 0x72, 0x6c, - 0x12, 0x53, 0x0a, 0x14, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, - 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x57, 0x6f, 0x72, - 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x77, - 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x0f, - 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x77, 0x6f, 0x72, - 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x77, 0x6f, 0x72, 0x6b, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, - 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x15, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x1a, 0x79, 0x0a, 0x06, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3b, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0xda, 0x01, 0x0a, 0x04, 0x50, 0x6c, 0x61, 0x6e, 0x12, 0x35, - 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, - 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x46, 0x0a, 0x10, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, - 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, - 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0f, 0x70, 0x61, - 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x53, 0x0a, - 0x15, 0x72, 0x69, 0x63, 0x68, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, - 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, - 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x13, 0x72, - 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x73, 0x1a, 0x52, 0x0a, 0x05, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x12, 0x35, 0x0a, 0x06, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x1a, 0x08, 0x0a, 0x06, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, - 0x1a, 0xb3, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x04, - 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x48, 0x00, 0x52, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x12, - 0x34, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, - 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x48, 0x00, 0x52, 0x05, - 0x61, 0x70, 0x70, 0x6c, 0x79, 0x12, 0x37, 0x0a, 0x06, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x61, - 0x6e, 0x63, 0x65, 0x6c, 0x48, 0x00, 0x52, 0x06, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x42, 0x06, - 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x1a, 0xbb, 0x01, 0x0a, 0x08, 0x43, 0x6f, 0x6d, 0x70, 0x6c, - 0x65, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, - 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, - 0x33, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, - 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x73, 0x12, 0x3a, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, - 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, - 0x65, 0x74, 0x65, 0x72, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, - 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, - 0x70, 0x6c, 0x61, 0x6e, 0x1a, 0x77, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x24, 0x0a, 0x03, 0x6c, 0x6f, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x48, - 0x00, 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x12, 0x3d, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, - 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x08, 0x63, 0x6f, 0x6d, - 0x70, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x2a, 0x3f, 0x0a, - 0x08, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x09, 0x0a, 0x05, 0x54, 0x52, 0x41, - 0x43, 0x45, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x01, 0x12, - 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x41, 0x52, - 0x4e, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x04, 0x2a, 0x3b, - 0x0a, 0x0f, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, - 0x6c, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x57, 0x4e, 0x45, 0x52, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, - 0x41, 0x55, 0x54, 0x48, 0x45, 0x4e, 0x54, 0x49, 0x43, 0x41, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, - 0x0a, 0x0a, 0x06, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x10, 0x02, 0x2a, 0x37, 0x0a, 0x13, 0x57, - 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x54, 0x41, 0x52, 0x54, 0x10, 0x00, 0x12, 0x08, 0x0a, - 0x04, 0x53, 0x54, 0x4f, 0x50, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x53, 0x54, 0x52, - 0x4f, 0x59, 0x10, 0x02, 0x32, 0xa3, 0x01, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x65, 0x72, 0x12, 0x42, 0x0a, 0x05, 0x50, 0x61, 0x72, 0x73, 0x65, 0x12, 0x1a, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, - 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x2e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x50, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x42, 0x2d, 0x5a, 0x2b, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, - 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, - 0x73, 0x64, 0x6b, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x12, 0x3d, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, + 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x70, + 0x6c, 0x65, 0x74, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x2a, 0x3f, 0x0a, 0x08, + 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x09, 0x0a, 0x05, 0x54, 0x52, 0x41, 0x43, + 0x45, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x01, 0x12, 0x08, + 0x0a, 0x04, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x41, 0x52, 0x4e, + 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x04, 0x2a, 0x3b, 0x0a, + 0x0f, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, + 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x57, 0x4e, 0x45, 0x52, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x41, + 0x55, 0x54, 0x48, 0x45, 0x4e, 0x54, 0x49, 0x43, 0x41, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0a, + 0x0a, 0x06, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x10, 0x02, 0x2a, 0x37, 0x0a, 0x13, 0x57, 0x6f, + 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x54, 0x41, 0x52, 0x54, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, + 0x53, 0x54, 0x4f, 0x50, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x53, 0x54, 0x52, 0x4f, + 0x59, 0x10, 0x02, 0x32, 0xa3, 0x01, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x72, 0x12, 0x42, 0x0a, 0x05, 0x50, 0x61, 0x72, 0x73, 0x65, 0x12, 0x1a, 0x2e, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, + 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x50, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x42, 0x2d, 0x5a, 0x2b, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, + 0x64, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x73, + 0x64, 0x6b, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/provisionersdk/proto/provisioner.proto b/provisionersdk/proto/provisioner.proto index d0707f1e2f604..dd8a49a6a60bd 100644 --- a/provisionersdk/proto/provisioner.proto +++ b/provisionersdk/proto/provisioner.proto @@ -117,7 +117,7 @@ message Agent { string troubleshooting_url = 12; string motd_file = 13; bool delay_login_until_ready = 14; - int32 startup_script_timeout = 15; + int32 startup_script_timeout_seconds = 15; } enum AppSharingLevel { From 60f414fbd2847532dd3e742029fe9b26375a28b6 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Mon, 23 Jan 2023 15:47:43 +0000 Subject: [PATCH 12/23] Fix plumbing --- coderd/apidoc/docs.go | 8 + coderd/apidoc/swagger.json | 8 + .../000091_add_workspace_agent_state.down.sql | 2 +- coderd/workspaceagents.go | 35 +- codersdk/workspaceagents.go | 4 + docs/api/agents.md | 2 + docs/api/builds.md | 300 +++++++++--------- docs/api/schemas.md | 62 ++-- docs/api/templates.md | 232 +++++++------- docs/api/workspaces.md | 8 + provisioner/terraform/resources.go | 24 +- provisioner/terraform/resources_test.go | 46 +-- site/src/api/typesGenerated.ts | 2 + site/src/testHelpers/entities.ts | 2 + 14 files changed, 404 insertions(+), 331 deletions(-) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 98ec0e769646a..4d78aeec69524 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -7686,6 +7686,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" }, @@ -7737,6 +7741,10 @@ 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": { "$ref": "#/definitions/codersdk.WorkspaceAgentStatus" }, diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 991b3e3caff4f..630b08dc83002 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -6917,6 +6917,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" }, @@ -6968,6 +6972,10 @@ "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": { "$ref": "#/definitions/codersdk.WorkspaceAgentStatus" }, diff --git a/coderd/database/migrations/000091_add_workspace_agent_state.down.sql b/coderd/database/migrations/000091_add_workspace_agent_state.down.sql index b8c0a33a32a3d..ecd39183ad044 100644 --- a/coderd/database/migrations/000091_add_workspace_agent_state.down.sql +++ b/coderd/database/migrations/000091_add_workspace_agent_state.down.sql @@ -1,4 +1,4 @@ -ALTER TABLE workspace_agents DROP COLUMN startup_script_timeout; +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; diff --git a/coderd/workspaceagents.go b/coderd/workspaceagents.go index 3bef6c97fcf24..31862316b74c9 100644 --- a/coderd/workspaceagents.go +++ b/coderd/workspaceagents.go @@ -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,22 +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, - LifecycleState: codersdk.WorkspaceAgentLifecycle(dbAgent.LifecycleState), + 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 { diff --git a/codersdk/workspaceagents.go b/codersdk/workspaceagents.go index f9465a35d2e6c..2bc3f0db83316 100644 --- a/codersdk/workspaceagents.go +++ b/codersdk/workspaceagents.go @@ -77,6 +77,10 @@ type WorkspaceAgent struct { DERPLatency map[string]DERPRegion `json:"latency,omitempty"` ConnectionTimeoutSeconds int32 `json:"connection_timeout_seconds"` TroubleshootingURL string `json:"troubleshooting_url"` + // DelayLoginUntilReady 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"` + // 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. + StartupScriptTimeoutSeconds int32 `db:"startup_script_timeout_seconds" json:"startup_script_timeout_seconds"` } type WorkspaceAgentResourceMetadata struct { diff --git a/docs/api/agents.md b/docs/api/agents.md index 87143b696d41f..900c7820b4fcb 100644 --- a/docs/api/agents.md +++ b/docs/api/agents.md @@ -519,6 +519,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaceagents/{workspaceagent} \ "architecture": "string", "connection_timeout_seconds": 0, "created_at": "2019-08-24T14:15:22Z", + "delay_login_until_ready": true, "directory": "string", "disconnected_at": "2019-08-24T14:15:22Z", "environment_variables": { @@ -544,6 +545,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaceagents/{workspaceagent} \ "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "startup_script_timeout_seconds": 0, "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", diff --git a/docs/api/builds.md b/docs/api/builds.md index 87a8cbdec1640..ee5d3392b5122 100644 --- a/docs/api/builds.md +++ b/docs/api/builds.md @@ -76,6 +76,7 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/workspace/{workspacenam "architecture": "string", "connection_timeout_seconds": 0, "created_at": "2019-08-24T14:15:22Z", + "delay_login_until_ready": true, "directory": "string", "disconnected_at": "2019-08-24T14:15:22Z", "environment_variables": { @@ -101,6 +102,7 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/workspace/{workspacenam "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "startup_script_timeout_seconds": 0, "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -219,6 +221,7 @@ curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild} \ "architecture": "string", "connection_timeout_seconds": 0, "created_at": "2019-08-24T14:15:22Z", + "delay_login_until_ready": true, "directory": "string", "disconnected_at": "2019-08-24T14:15:22Z", "environment_variables": { @@ -244,6 +247,7 @@ curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild} \ "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "startup_script_timeout_seconds": 0, "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -505,6 +509,7 @@ curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild}/res "architecture": "string", "connection_timeout_seconds": 0, "created_at": "2019-08-24T14:15:22Z", + "delay_login_until_ready": true, "directory": "string", "disconnected_at": "2019-08-24T14:15:22Z", "environment_variables": { @@ -530,6 +535,7 @@ curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild}/res "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "startup_script_timeout_seconds": 0, "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -566,62 +572,64 @@ curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild}/res Status Code **200** -| Name | Type | Required | Restrictions | Description | -| ------------------------------- | -------------------------------------------------------------------------------- | -------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `[array item]` | array | false | | | -| `» agents` | array | false | | | -| `»» apps` | array | false | | | -| `»»» command` | string | false | | | -| `»»» display_name` | string | false | | »»display name is a friendly name for the app. | -| `»»» external` | boolean | false | | External specifies whether the URL should be opened externally on the client or not. | -| `»»» health` | [codersdk.WorkspaceAppHealth](schemas.md#codersdkworkspaceapphealth) | false | | | -| `»»» healthcheck` | [codersdk.Healthcheck](schemas.md#codersdkhealthcheck) | false | | Healthcheck specifies the configuration for checking app health. | -| `»»»» interval` | integer | false | | Interval specifies the seconds between each health check. | -| `»»»» threshold` | integer | false | | Threshold specifies the number of consecutive failed health checks before returning "unhealthy". | -| `»»»» url` | string | false | | »»»url specifies the endpoint to check for the app health. | -| `»»» icon` | string | false | | Icon is a relative path or external URL that specifies an icon to be displayed in the dashboard. | -| `»»» id` | string(uuid) | false | | | -| `»»» sharing_level` | [codersdk.WorkspaceAppSharingLevel](schemas.md#codersdkworkspaceappsharinglevel) | false | | | -| `»»» slug` | string | false | | Slug is a unique identifier within the agent. | -| `»»» subdomain` | boolean | false | | Subdomain denotes whether the app should be accessed via a path on the `coder server` or via a hostname-based dev URL. If this is set to true and there is no app wildcard configured on the server, the app will not be accessible in the UI. | -| `»»» url` | string | false | | »»url is the address being proxied to inside the workspace. If external is specified, this will be opened on the client. | -| `»» architecture` | string | false | | | -| `»» connection_timeout_seconds` | integer | false | | | -| `»» created_at` | string(date-time) | false | | | -| `»» directory` | string | false | | | -| `»» disconnected_at` | string(date-time) | false | | | -| `»» environment_variables` | object | false | | | -| `»»» [any property]` | string | false | | | -| `»» first_connected_at` | string(date-time) | false | | | -| `»» id` | string(uuid) | false | | | -| `»» instance_id` | string | false | | | -| `»» last_connected_at` | string(date-time) | false | | | -| `»» latency` | object | false | | »latency is mapped by region name (e.g. "New York City", "Seattle"). | -| `»»» [any property]` | [codersdk.DERPRegion](schemas.md#codersdkderpregion) | false | | | -| `»»»» latency_ms` | number | false | | | -| `»»»» preferred` | boolean | false | | | -| `»» lifecycle_state` | [codersdk.WorkspaceAgentLifecycle](schemas.md#codersdkworkspaceagentlifecycle) | false | | | -| `»» name` | string | false | | | -| `»» operating_system` | string | false | | | -| `»» resource_id` | string(uuid) | false | | | -| `»» startup_script` | string | false | | | -| `»» status` | [codersdk.WorkspaceAgentStatus](schemas.md#codersdkworkspaceagentstatus) | false | | | -| `»» troubleshooting_url` | string | false | | | -| `»» updated_at` | string(date-time) | false | | | -| `»» version` | string | false | | | -| `» created_at` | string(date-time) | false | | | -| `» daily_cost` | integer | false | | | -| `» hide` | boolean | false | | | -| `» icon` | string | false | | | -| `» id` | string(uuid) | false | | | -| `» job_id` | string(uuid) | false | | | -| `» metadata` | array | false | | | -| `»» key` | string | false | | | -| `»» sensitive` | boolean | false | | | -| `»» value` | string | false | | | -| `» name` | string | false | | | -| `» type` | string | false | | | -| `» workspace_transition` | [codersdk.WorkspaceTransition](schemas.md#codersdkworkspacetransition) | false | | | +| Name | Type | Required | Restrictions | Description | +| ----------------------------------- | -------------------------------------------------------------------------------- | -------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `[array item]` | array | false | | | +| `» agents` | array | false | | | +| `»» apps` | array | false | | | +| `»»» command` | string | false | | | +| `»»» display_name` | string | false | | »»display name is a friendly name for the app. | +| `»»» external` | boolean | false | | External specifies whether the URL should be opened externally on the client or not. | +| `»»» health` | [codersdk.WorkspaceAppHealth](schemas.md#codersdkworkspaceapphealth) | false | | | +| `»»» healthcheck` | [codersdk.Healthcheck](schemas.md#codersdkhealthcheck) | false | | Healthcheck specifies the configuration for checking app health. | +| `»»»» interval` | integer | false | | Interval specifies the seconds between each health check. | +| `»»»» threshold` | integer | false | | Threshold specifies the number of consecutive failed health checks before returning "unhealthy". | +| `»»»» url` | string | false | | »»»url specifies the endpoint to check for the app health. | +| `»»» icon` | string | false | | Icon is a relative path or external URL that specifies an icon to be displayed in the dashboard. | +| `»»» id` | string(uuid) | false | | | +| `»»» sharing_level` | [codersdk.WorkspaceAppSharingLevel](schemas.md#codersdkworkspaceappsharinglevel) | false | | | +| `»»» slug` | string | false | | Slug is a unique identifier within the agent. | +| `»»» subdomain` | boolean | false | | Subdomain denotes whether the app should be accessed via a path on the `coder server` or via a hostname-based dev URL. If this is set to true and there is no app wildcard configured on the server, the app will not be accessible in the UI. | +| `»»» url` | string | false | | »»url is the address being proxied to inside the workspace. If external is specified, this will be opened on the client. | +| `»» architecture` | string | false | | | +| `»» connection_timeout_seconds` | integer | false | | | +| `»» created_at` | string(date-time) | false | | | +| `»» delay_login_until_ready` | boolean | false | | »delay login until ready if true, the agent will delay logins until it is ready (e.g. executing startup script has ended). | +| `»» directory` | string | false | | | +| `»» disconnected_at` | string(date-time) | false | | | +| `»» environment_variables` | object | false | | | +| `»»» [any property]` | string | false | | | +| `»» first_connected_at` | string(date-time) | false | | | +| `»» id` | string(uuid) | false | | | +| `»» instance_id` | string | false | | | +| `»» last_connected_at` | string(date-time) | false | | | +| `»» latency` | object | false | | »latency is mapped by region name (e.g. "New York City", "Seattle"). | +| `»»» [any property]` | [codersdk.DERPRegion](schemas.md#codersdkderpregion) | false | | | +| `»»»» latency_ms` | number | false | | | +| `»»»» preferred` | boolean | false | | | +| `»» lifecycle_state` | [codersdk.WorkspaceAgentLifecycle](schemas.md#codersdkworkspaceagentlifecycle) | false | | | +| `»» name` | string | false | | | +| `»» operating_system` | string | false | | | +| `»» resource_id` | string(uuid) | false | | | +| `»» startup_script` | string | false | | | +| `»» startup_script_timeout_seconds` | integer | false | | »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. | +| `»» status` | [codersdk.WorkspaceAgentStatus](schemas.md#codersdkworkspaceagentstatus) | false | | | +| `»» troubleshooting_url` | string | false | | | +| `»» updated_at` | string(date-time) | false | | | +| `»» version` | string | false | | | +| `» created_at` | string(date-time) | false | | | +| `» daily_cost` | integer | false | | | +| `» hide` | boolean | false | | | +| `» icon` | string | false | | | +| `» id` | string(uuid) | false | | | +| `» job_id` | string(uuid) | false | | | +| `» metadata` | array | false | | | +| `»» key` | string | false | | | +| `»» sensitive` | boolean | false | | | +| `»» value` | string | false | | | +| `» name` | string | false | | | +| `» type` | string | false | | | +| `» workspace_transition` | [codersdk.WorkspaceTransition](schemas.md#codersdkworkspacetransition) | false | | | #### Enumerated Values @@ -723,6 +731,7 @@ curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild}/sta "architecture": "string", "connection_timeout_seconds": 0, "created_at": "2019-08-24T14:15:22Z", + "delay_login_until_ready": true, "directory": "string", "disconnected_at": "2019-08-24T14:15:22Z", "environment_variables": { @@ -748,6 +757,7 @@ curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild}/sta "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "startup_script_timeout_seconds": 0, "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -871,6 +881,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace}/builds \ "architecture": "string", "connection_timeout_seconds": 0, "created_at": "2019-08-24T14:15:22Z", + "delay_login_until_ready": true, "directory": "string", "disconnected_at": "2019-08-24T14:15:22Z", "environment_variables": { @@ -896,6 +907,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace}/builds \ "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "startup_script_timeout_seconds": 0, "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -943,92 +955,94 @@ curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace}/builds \ Status Code **200** -| Name | Type | Required | Restrictions | Description | -| -------------------------------- | -------------------------------------------------------------------------------- | -------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `[array item]` | array | false | | | -| `» build_number` | integer | false | | | -| `» created_at` | string(date-time) | false | | | -| `» daily_cost` | integer | false | | | -| `» deadline` | string(date-time) | false | | | -| `» id` | string(uuid) | false | | | -| `» initiator_id` | string(uuid) | false | | | -| `» initiator_name` | string | false | | | -| `» job` | [codersdk.ProvisionerJob](schemas.md#codersdkprovisionerjob) | false | | | -| `»» canceled_at` | string(date-time) | false | | | -| `»» completed_at` | string(date-time) | false | | | -| `»» created_at` | string(date-time) | false | | | -| `»» error` | string | false | | | -| `»» file_id` | string(uuid) | false | | | -| `»» id` | string(uuid) | false | | | -| `»» started_at` | string(date-time) | false | | | -| `»» status` | [codersdk.ProvisionerJobStatus](schemas.md#codersdkprovisionerjobstatus) | false | | | -| `»» tags` | object | false | | | -| `»»» [any property]` | string | false | | | -| `»» worker_id` | string(uuid) | false | | | -| `» reason` | [codersdk.BuildReason](schemas.md#codersdkbuildreason) | false | | | -| `» resources` | array | false | | | -| `»» agents` | array | false | | | -| `»»» apps` | array | false | | | -| `»»»» command` | string | false | | | -| `»»»» display_name` | string | false | | »»»display name is a friendly name for the app. | -| `»»»» external` | boolean | false | | External specifies whether the URL should be opened externally on the client or not. | -| `»»»» health` | [codersdk.WorkspaceAppHealth](schemas.md#codersdkworkspaceapphealth) | false | | | -| `»»»» healthcheck` | [codersdk.Healthcheck](schemas.md#codersdkhealthcheck) | false | | Healthcheck specifies the configuration for checking app health. | -| `»»»»» interval` | integer | false | | Interval specifies the seconds between each health check. | -| `»»»»» threshold` | integer | false | | Threshold specifies the number of consecutive failed health checks before returning "unhealthy". | -| `»»»»» url` | string | false | | »»»»url specifies the endpoint to check for the app health. | -| `»»»» icon` | string | false | | Icon is a relative path or external URL that specifies an icon to be displayed in the dashboard. | -| `»»»» id` | string(uuid) | false | | | -| `»»»» sharing_level` | [codersdk.WorkspaceAppSharingLevel](schemas.md#codersdkworkspaceappsharinglevel) | false | | | -| `»»»» slug` | string | false | | Slug is a unique identifier within the agent. | -| `»»»» subdomain` | boolean | false | | Subdomain denotes whether the app should be accessed via a path on the `coder server` or via a hostname-based dev URL. If this is set to true and there is no app wildcard configured on the server, the app will not be accessible in the UI. | -| `»»»» url` | string | false | | »»»url is the address being proxied to inside the workspace. If external is specified, this will be opened on the client. | -| `»»» architecture` | string | false | | | -| `»»» connection_timeout_seconds` | integer | false | | | -| `»»» created_at` | string(date-time) | false | | | -| `»»» directory` | string | false | | | -| `»»» disconnected_at` | string(date-time) | false | | | -| `»»» environment_variables` | object | false | | | -| `»»»» [any property]` | string | false | | | -| `»»» first_connected_at` | string(date-time) | false | | | -| `»»» id` | string(uuid) | false | | | -| `»»» instance_id` | string | false | | | -| `»»» last_connected_at` | string(date-time) | false | | | -| `»»» latency` | object | false | | »»latency is mapped by region name (e.g. "New York City", "Seattle"). | -| `»»»» [any property]` | [codersdk.DERPRegion](schemas.md#codersdkderpregion) | false | | | -| `»»»»» latency_ms` | number | false | | | -| `»»»»» preferred` | boolean | false | | | -| `»»» lifecycle_state` | [codersdk.WorkspaceAgentLifecycle](schemas.md#codersdkworkspaceagentlifecycle) | false | | | -| `»»» name` | string | false | | | -| `»»» operating_system` | string | false | | | -| `»»» resource_id` | string(uuid) | false | | | -| `»»» startup_script` | string | false | | | -| `»»» status` | [codersdk.WorkspaceAgentStatus](schemas.md#codersdkworkspaceagentstatus) | false | | | -| `»»» troubleshooting_url` | string | false | | | -| `»»» updated_at` | string(date-time) | false | | | -| `»»» version` | string | false | | | -| `»» created_at` | string(date-time) | false | | | -| `»» daily_cost` | integer | false | | | -| `»» hide` | boolean | false | | | -| `»» icon` | string | false | | | -| `»» id` | string(uuid) | false | | | -| `»» job_id` | string(uuid) | false | | | -| `»» metadata` | array | false | | | -| `»»» key` | string | false | | | -| `»»» sensitive` | boolean | false | | | -| `»»» value` | string | false | | | -| `»» name` | string | false | | | -| `»» type` | string | false | | | -| `»» workspace_transition` | [codersdk.WorkspaceTransition](schemas.md#codersdkworkspacetransition) | false | | | -| `» status` | [codersdk.WorkspaceStatus](schemas.md#codersdkworkspacestatus) | false | | | -| `» template_version_id` | string(uuid) | false | | | -| `» template_version_name` | string | false | | | -| `» transition` | [codersdk.WorkspaceTransition](schemas.md#codersdkworkspacetransition) | false | | | -| `» updated_at` | string(date-time) | false | | | -| `» workspace_id` | string(uuid) | false | | | -| `» workspace_name` | string | false | | | -| `» workspace_owner_id` | string(uuid) | false | | | -| `» workspace_owner_name` | string | false | | | +| Name | Type | Required | Restrictions | Description | +| ------------------------------------ | -------------------------------------------------------------------------------- | -------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `[array item]` | array | false | | | +| `» build_number` | integer | false | | | +| `» created_at` | string(date-time) | false | | | +| `» daily_cost` | integer | false | | | +| `» deadline` | string(date-time) | false | | | +| `» id` | string(uuid) | false | | | +| `» initiator_id` | string(uuid) | false | | | +| `» initiator_name` | string | false | | | +| `» job` | [codersdk.ProvisionerJob](schemas.md#codersdkprovisionerjob) | false | | | +| `»» canceled_at` | string(date-time) | false | | | +| `»» completed_at` | string(date-time) | false | | | +| `»» created_at` | string(date-time) | false | | | +| `»» error` | string | false | | | +| `»» file_id` | string(uuid) | false | | | +| `»» id` | string(uuid) | false | | | +| `»» started_at` | string(date-time) | false | | | +| `»» status` | [codersdk.ProvisionerJobStatus](schemas.md#codersdkprovisionerjobstatus) | false | | | +| `»» tags` | object | false | | | +| `»»» [any property]` | string | false | | | +| `»» worker_id` | string(uuid) | false | | | +| `» reason` | [codersdk.BuildReason](schemas.md#codersdkbuildreason) | false | | | +| `» resources` | array | false | | | +| `»» agents` | array | false | | | +| `»»» apps` | array | false | | | +| `»»»» command` | string | false | | | +| `»»»» display_name` | string | false | | »»»display name is a friendly name for the app. | +| `»»»» external` | boolean | false | | External specifies whether the URL should be opened externally on the client or not. | +| `»»»» health` | [codersdk.WorkspaceAppHealth](schemas.md#codersdkworkspaceapphealth) | false | | | +| `»»»» healthcheck` | [codersdk.Healthcheck](schemas.md#codersdkhealthcheck) | false | | Healthcheck specifies the configuration for checking app health. | +| `»»»»» interval` | integer | false | | Interval specifies the seconds between each health check. | +| `»»»»» threshold` | integer | false | | Threshold specifies the number of consecutive failed health checks before returning "unhealthy". | +| `»»»»» url` | string | false | | »»»»url specifies the endpoint to check for the app health. | +| `»»»» icon` | string | false | | Icon is a relative path or external URL that specifies an icon to be displayed in the dashboard. | +| `»»»» id` | string(uuid) | false | | | +| `»»»» sharing_level` | [codersdk.WorkspaceAppSharingLevel](schemas.md#codersdkworkspaceappsharinglevel) | false | | | +| `»»»» slug` | string | false | | Slug is a unique identifier within the agent. | +| `»»»» subdomain` | boolean | false | | Subdomain denotes whether the app should be accessed via a path on the `coder server` or via a hostname-based dev URL. If this is set to true and there is no app wildcard configured on the server, the app will not be accessible in the UI. | +| `»»»» url` | string | false | | »»»url is the address being proxied to inside the workspace. If external is specified, this will be opened on the client. | +| `»»» architecture` | string | false | | | +| `»»» connection_timeout_seconds` | integer | false | | | +| `»»» created_at` | string(date-time) | false | | | +| `»»» delay_login_until_ready` | boolean | false | | »»delay login until ready if true, the agent will delay logins until it is ready (e.g. executing startup script has ended). | +| `»»» directory` | string | false | | | +| `»»» disconnected_at` | string(date-time) | false | | | +| `»»» environment_variables` | object | false | | | +| `»»»» [any property]` | string | false | | | +| `»»» first_connected_at` | string(date-time) | false | | | +| `»»» id` | string(uuid) | false | | | +| `»»» instance_id` | string | false | | | +| `»»» last_connected_at` | string(date-time) | false | | | +| `»»» latency` | object | false | | »»latency is mapped by region name (e.g. "New York City", "Seattle"). | +| `»»»» [any property]` | [codersdk.DERPRegion](schemas.md#codersdkderpregion) | false | | | +| `»»»»» latency_ms` | number | false | | | +| `»»»»» preferred` | boolean | false | | | +| `»»» lifecycle_state` | [codersdk.WorkspaceAgentLifecycle](schemas.md#codersdkworkspaceagentlifecycle) | false | | | +| `»»» name` | string | false | | | +| `»»» operating_system` | string | false | | | +| `»»» resource_id` | string(uuid) | false | | | +| `»»» startup_script` | string | false | | | +| `»»» startup_script_timeout_seconds` | integer | false | | »»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. | +| `»»» status` | [codersdk.WorkspaceAgentStatus](schemas.md#codersdkworkspaceagentstatus) | false | | | +| `»»» troubleshooting_url` | string | false | | | +| `»»» updated_at` | string(date-time) | false | | | +| `»»» version` | string | false | | | +| `»» created_at` | string(date-time) | false | | | +| `»» daily_cost` | integer | false | | | +| `»» hide` | boolean | false | | | +| `»» icon` | string | false | | | +| `»» id` | string(uuid) | false | | | +| `»» job_id` | string(uuid) | false | | | +| `»» metadata` | array | false | | | +| `»»» key` | string | false | | | +| `»»» sensitive` | boolean | false | | | +| `»»» value` | string | false | | | +| `»» name` | string | false | | | +| `»» type` | string | false | | | +| `»» workspace_transition` | [codersdk.WorkspaceTransition](schemas.md#codersdkworkspacetransition) | false | | | +| `» status` | [codersdk.WorkspaceStatus](schemas.md#codersdkworkspacestatus) | false | | | +| `» template_version_id` | string(uuid) | false | | | +| `» template_version_name` | string | false | | | +| `» transition` | [codersdk.WorkspaceTransition](schemas.md#codersdkworkspacetransition) | false | | | +| `» updated_at` | string(date-time) | false | | | +| `» workspace_id` | string(uuid) | false | | | +| `» workspace_name` | string | false | | | +| `» workspace_owner_id` | string(uuid) | false | | | +| `» workspace_owner_name` | string | false | | | #### Enumerated Values @@ -1181,6 +1195,7 @@ curl -X POST http://coder-server:8080/api/v2/workspaces/{workspace}/builds \ "architecture": "string", "connection_timeout_seconds": 0, "created_at": "2019-08-24T14:15:22Z", + "delay_login_until_ready": true, "directory": "string", "disconnected_at": "2019-08-24T14:15:22Z", "environment_variables": { @@ -1206,6 +1221,7 @@ curl -X POST http://coder-server:8080/api/v2/workspaces/{workspace}/builds \ "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "startup_script_timeout_seconds": 0, "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", diff --git a/docs/api/schemas.md b/docs/api/schemas.md index 8e7eeb727f931..1f1f218228d2d 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -4573,6 +4573,7 @@ Parameter represents a set value for the scope. "architecture": "string", "connection_timeout_seconds": 0, "created_at": "2019-08-24T14:15:22Z", + "delay_login_until_ready": true, "directory": "string", "disconnected_at": "2019-08-24T14:15:22Z", "environment_variables": { @@ -4598,6 +4599,7 @@ Parameter represents a set value for the scope. "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "startup_script_timeout_seconds": 0, "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -4693,6 +4695,7 @@ Parameter represents a set value for the scope. "architecture": "string", "connection_timeout_seconds": 0, "created_at": "2019-08-24T14:15:22Z", + "delay_login_until_ready": true, "directory": "string", "disconnected_at": "2019-08-24T14:15:22Z", "environment_variables": { @@ -4718,6 +4721,7 @@ Parameter represents a set value for the scope. "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "startup_script_timeout_seconds": 0, "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -4727,31 +4731,33 @@ Parameter represents a set value for the scope. ### Properties -| Name | Type | Required | Restrictions | Description | -| ---------------------------- | -------------------------------------------------------------------- | -------- | ------------ | ------------------------------------------------------------------- | -| `apps` | array of [codersdk.WorkspaceApp](#codersdkworkspaceapp) | false | | | -| `architecture` | string | false | | | -| `connection_timeout_seconds` | integer | false | | | -| `created_at` | string | false | | | -| `directory` | string | false | | | -| `disconnected_at` | string | false | | | -| `environment_variables` | object | false | | | -| » `[any property]` | string | false | | | -| `first_connected_at` | string | false | | | -| `id` | string | false | | | -| `instance_id` | string | false | | | -| `last_connected_at` | string | false | | | -| `latency` | object | false | | Latency is mapped by region name (e.g. "New York City", "Seattle"). | -| » `[any property]` | [codersdk.DERPRegion](#codersdkderpregion) | false | | | -| `lifecycle_state` | [codersdk.WorkspaceAgentLifecycle](#codersdkworkspaceagentlifecycle) | false | | | -| `name` | string | false | | | -| `operating_system` | string | false | | | -| `resource_id` | string | false | | | -| `startup_script` | string | false | | | -| `status` | [codersdk.WorkspaceAgentStatus](#codersdkworkspaceagentstatus) | false | | | -| `troubleshooting_url` | string | false | | | -| `updated_at` | string | false | | | -| `version` | string | false | | | +| Name | Type | Required | Restrictions | Description | +| -------------------------------- | -------------------------------------------------------------------- | -------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `apps` | array of [codersdk.WorkspaceApp](#codersdkworkspaceapp) | false | | | +| `architecture` | string | false | | | +| `connection_timeout_seconds` | integer | false | | | +| `created_at` | string | false | | | +| `delay_login_until_ready` | boolean | false | | Delay login until ready if true, the agent will delay logins until it is ready (e.g. executing startup script has ended). | +| `directory` | string | false | | | +| `disconnected_at` | string | false | | | +| `environment_variables` | object | false | | | +| » `[any property]` | string | false | | | +| `first_connected_at` | string | false | | | +| `id` | string | false | | | +| `instance_id` | string | false | | | +| `last_connected_at` | string | false | | | +| `latency` | object | false | | Latency is mapped by region name (e.g. "New York City", "Seattle"). | +| » `[any property]` | [codersdk.DERPRegion](#codersdkderpregion) | false | | | +| `lifecycle_state` | [codersdk.WorkspaceAgentLifecycle](#codersdkworkspaceagentlifecycle) | false | | | +| `name` | string | false | | | +| `operating_system` | string | false | | | +| `resource_id` | string | false | | | +| `startup_script` | string | false | | | +| `startup_script_timeout_seconds` | integer | false | | 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. | +| `status` | [codersdk.WorkspaceAgentStatus](#codersdkworkspaceagentstatus) | false | | | +| `troubleshooting_url` | string | false | | | +| `updated_at` | string | false | | | +| `version` | string | false | | | ## codersdk.WorkspaceAgentAuthenticateResponse @@ -5118,6 +5124,7 @@ Parameter represents a set value for the scope. "architecture": "string", "connection_timeout_seconds": 0, "created_at": "2019-08-24T14:15:22Z", + "delay_login_until_ready": true, "directory": "string", "disconnected_at": "2019-08-24T14:15:22Z", "environment_variables": { @@ -5143,6 +5150,7 @@ Parameter represents a set value for the scope. "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "startup_script_timeout_seconds": 0, "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -5284,6 +5292,7 @@ Parameter represents a set value for the scope. "architecture": "string", "connection_timeout_seconds": 0, "created_at": "2019-08-24T14:15:22Z", + "delay_login_until_ready": true, "directory": "string", "disconnected_at": "2019-08-24T14:15:22Z", "environment_variables": { @@ -5309,6 +5318,7 @@ Parameter represents a set value for the scope. "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "startup_script_timeout_seconds": 0, "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -5472,6 +5482,7 @@ Parameter represents a set value for the scope. "architecture": "string", "connection_timeout_seconds": 0, "created_at": "2019-08-24T14:15:22Z", + "delay_login_until_ready": true, "directory": "string", "disconnected_at": "2019-08-24T14:15:22Z", "environment_variables": { @@ -5497,6 +5508,7 @@ Parameter represents a set value for the scope. "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "startup_script_timeout_seconds": 0, "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", diff --git a/docs/api/templates.md b/docs/api/templates.md index 0f20877893bb9..06ffeb6ef0547 100644 --- a/docs/api/templates.md +++ b/docs/api/templates.md @@ -1552,6 +1552,7 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/d "architecture": "string", "connection_timeout_seconds": 0, "created_at": "2019-08-24T14:15:22Z", + "delay_login_until_ready": true, "directory": "string", "disconnected_at": "2019-08-24T14:15:22Z", "environment_variables": { @@ -1577,6 +1578,7 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/d "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "startup_script_timeout_seconds": 0, "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -1613,62 +1615,64 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/d Status Code **200** -| Name | Type | Required | Restrictions | Description | -| ------------------------------- | -------------------------------------------------------------------------------- | -------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `[array item]` | array | false | | | -| `» agents` | array | false | | | -| `»» apps` | array | false | | | -| `»»» command` | string | false | | | -| `»»» display_name` | string | false | | »»display name is a friendly name for the app. | -| `»»» external` | boolean | false | | External specifies whether the URL should be opened externally on the client or not. | -| `»»» health` | [codersdk.WorkspaceAppHealth](schemas.md#codersdkworkspaceapphealth) | false | | | -| `»»» healthcheck` | [codersdk.Healthcheck](schemas.md#codersdkhealthcheck) | false | | Healthcheck specifies the configuration for checking app health. | -| `»»»» interval` | integer | false | | Interval specifies the seconds between each health check. | -| `»»»» threshold` | integer | false | | Threshold specifies the number of consecutive failed health checks before returning "unhealthy". | -| `»»»» url` | string | false | | »»»url specifies the endpoint to check for the app health. | -| `»»» icon` | string | false | | Icon is a relative path or external URL that specifies an icon to be displayed in the dashboard. | -| `»»» id` | string(uuid) | false | | | -| `»»» sharing_level` | [codersdk.WorkspaceAppSharingLevel](schemas.md#codersdkworkspaceappsharinglevel) | false | | | -| `»»» slug` | string | false | | Slug is a unique identifier within the agent. | -| `»»» subdomain` | boolean | false | | Subdomain denotes whether the app should be accessed via a path on the `coder server` or via a hostname-based dev URL. If this is set to true and there is no app wildcard configured on the server, the app will not be accessible in the UI. | -| `»»» url` | string | false | | »»url is the address being proxied to inside the workspace. If external is specified, this will be opened on the client. | -| `»» architecture` | string | false | | | -| `»» connection_timeout_seconds` | integer | false | | | -| `»» created_at` | string(date-time) | false | | | -| `»» directory` | string | false | | | -| `»» disconnected_at` | string(date-time) | false | | | -| `»» environment_variables` | object | false | | | -| `»»» [any property]` | string | false | | | -| `»» first_connected_at` | string(date-time) | false | | | -| `»» id` | string(uuid) | false | | | -| `»» instance_id` | string | false | | | -| `»» last_connected_at` | string(date-time) | false | | | -| `»» latency` | object | false | | »latency is mapped by region name (e.g. "New York City", "Seattle"). | -| `»»» [any property]` | [codersdk.DERPRegion](schemas.md#codersdkderpregion) | false | | | -| `»»»» latency_ms` | number | false | | | -| `»»»» preferred` | boolean | false | | | -| `»» lifecycle_state` | [codersdk.WorkspaceAgentLifecycle](schemas.md#codersdkworkspaceagentlifecycle) | false | | | -| `»» name` | string | false | | | -| `»» operating_system` | string | false | | | -| `»» resource_id` | string(uuid) | false | | | -| `»» startup_script` | string | false | | | -| `»» status` | [codersdk.WorkspaceAgentStatus](schemas.md#codersdkworkspaceagentstatus) | false | | | -| `»» troubleshooting_url` | string | false | | | -| `»» updated_at` | string(date-time) | false | | | -| `»» version` | string | false | | | -| `» created_at` | string(date-time) | false | | | -| `» daily_cost` | integer | false | | | -| `» hide` | boolean | false | | | -| `» icon` | string | false | | | -| `» id` | string(uuid) | false | | | -| `» job_id` | string(uuid) | false | | | -| `» metadata` | array | false | | | -| `»» key` | string | false | | | -| `»» sensitive` | boolean | false | | | -| `»» value` | string | false | | | -| `» name` | string | false | | | -| `» type` | string | false | | | -| `» workspace_transition` | [codersdk.WorkspaceTransition](schemas.md#codersdkworkspacetransition) | false | | | +| Name | Type | Required | Restrictions | Description | +| ----------------------------------- | -------------------------------------------------------------------------------- | -------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `[array item]` | array | false | | | +| `» agents` | array | false | | | +| `»» apps` | array | false | | | +| `»»» command` | string | false | | | +| `»»» display_name` | string | false | | »»display name is a friendly name for the app. | +| `»»» external` | boolean | false | | External specifies whether the URL should be opened externally on the client or not. | +| `»»» health` | [codersdk.WorkspaceAppHealth](schemas.md#codersdkworkspaceapphealth) | false | | | +| `»»» healthcheck` | [codersdk.Healthcheck](schemas.md#codersdkhealthcheck) | false | | Healthcheck specifies the configuration for checking app health. | +| `»»»» interval` | integer | false | | Interval specifies the seconds between each health check. | +| `»»»» threshold` | integer | false | | Threshold specifies the number of consecutive failed health checks before returning "unhealthy". | +| `»»»» url` | string | false | | »»»url specifies the endpoint to check for the app health. | +| `»»» icon` | string | false | | Icon is a relative path or external URL that specifies an icon to be displayed in the dashboard. | +| `»»» id` | string(uuid) | false | | | +| `»»» sharing_level` | [codersdk.WorkspaceAppSharingLevel](schemas.md#codersdkworkspaceappsharinglevel) | false | | | +| `»»» slug` | string | false | | Slug is a unique identifier within the agent. | +| `»»» subdomain` | boolean | false | | Subdomain denotes whether the app should be accessed via a path on the `coder server` or via a hostname-based dev URL. If this is set to true and there is no app wildcard configured on the server, the app will not be accessible in the UI. | +| `»»» url` | string | false | | »»url is the address being proxied to inside the workspace. If external is specified, this will be opened on the client. | +| `»» architecture` | string | false | | | +| `»» connection_timeout_seconds` | integer | false | | | +| `»» created_at` | string(date-time) | false | | | +| `»» delay_login_until_ready` | boolean | false | | »delay login until ready if true, the agent will delay logins until it is ready (e.g. executing startup script has ended). | +| `»» directory` | string | false | | | +| `»» disconnected_at` | string(date-time) | false | | | +| `»» environment_variables` | object | false | | | +| `»»» [any property]` | string | false | | | +| `»» first_connected_at` | string(date-time) | false | | | +| `»» id` | string(uuid) | false | | | +| `»» instance_id` | string | false | | | +| `»» last_connected_at` | string(date-time) | false | | | +| `»» latency` | object | false | | »latency is mapped by region name (e.g. "New York City", "Seattle"). | +| `»»» [any property]` | [codersdk.DERPRegion](schemas.md#codersdkderpregion) | false | | | +| `»»»» latency_ms` | number | false | | | +| `»»»» preferred` | boolean | false | | | +| `»» lifecycle_state` | [codersdk.WorkspaceAgentLifecycle](schemas.md#codersdkworkspaceagentlifecycle) | false | | | +| `»» name` | string | false | | | +| `»» operating_system` | string | false | | | +| `»» resource_id` | string(uuid) | false | | | +| `»» startup_script` | string | false | | | +| `»» startup_script_timeout_seconds` | integer | false | | »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. | +| `»» status` | [codersdk.WorkspaceAgentStatus](schemas.md#codersdkworkspaceagentstatus) | false | | | +| `»» troubleshooting_url` | string | false | | | +| `»» updated_at` | string(date-time) | false | | | +| `»» version` | string | false | | | +| `» created_at` | string(date-time) | false | | | +| `» daily_cost` | integer | false | | | +| `» hide` | boolean | false | | | +| `» icon` | string | false | | | +| `» id` | string(uuid) | false | | | +| `» job_id` | string(uuid) | false | | | +| `» metadata` | array | false | | | +| `»» key` | string | false | | | +| `»» sensitive` | boolean | false | | | +| `»» value` | string | false | | | +| `» name` | string | false | | | +| `» type` | string | false | | | +| `» workspace_transition` | [codersdk.WorkspaceTransition](schemas.md#codersdkworkspacetransition) | false | | | #### Enumerated Values @@ -1900,6 +1904,7 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/r "architecture": "string", "connection_timeout_seconds": 0, "created_at": "2019-08-24T14:15:22Z", + "delay_login_until_ready": true, "directory": "string", "disconnected_at": "2019-08-24T14:15:22Z", "environment_variables": { @@ -1925,6 +1930,7 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/r "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "startup_script_timeout_seconds": 0, "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -1961,62 +1967,64 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/r Status Code **200** -| Name | Type | Required | Restrictions | Description | -| ------------------------------- | -------------------------------------------------------------------------------- | -------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `[array item]` | array | false | | | -| `» agents` | array | false | | | -| `»» apps` | array | false | | | -| `»»» command` | string | false | | | -| `»»» display_name` | string | false | | »»display name is a friendly name for the app. | -| `»»» external` | boolean | false | | External specifies whether the URL should be opened externally on the client or not. | -| `»»» health` | [codersdk.WorkspaceAppHealth](schemas.md#codersdkworkspaceapphealth) | false | | | -| `»»» healthcheck` | [codersdk.Healthcheck](schemas.md#codersdkhealthcheck) | false | | Healthcheck specifies the configuration for checking app health. | -| `»»»» interval` | integer | false | | Interval specifies the seconds between each health check. | -| `»»»» threshold` | integer | false | | Threshold specifies the number of consecutive failed health checks before returning "unhealthy". | -| `»»»» url` | string | false | | »»»url specifies the endpoint to check for the app health. | -| `»»» icon` | string | false | | Icon is a relative path or external URL that specifies an icon to be displayed in the dashboard. | -| `»»» id` | string(uuid) | false | | | -| `»»» sharing_level` | [codersdk.WorkspaceAppSharingLevel](schemas.md#codersdkworkspaceappsharinglevel) | false | | | -| `»»» slug` | string | false | | Slug is a unique identifier within the agent. | -| `»»» subdomain` | boolean | false | | Subdomain denotes whether the app should be accessed via a path on the `coder server` or via a hostname-based dev URL. If this is set to true and there is no app wildcard configured on the server, the app will not be accessible in the UI. | -| `»»» url` | string | false | | »»url is the address being proxied to inside the workspace. If external is specified, this will be opened on the client. | -| `»» architecture` | string | false | | | -| `»» connection_timeout_seconds` | integer | false | | | -| `»» created_at` | string(date-time) | false | | | -| `»» directory` | string | false | | | -| `»» disconnected_at` | string(date-time) | false | | | -| `»» environment_variables` | object | false | | | -| `»»» [any property]` | string | false | | | -| `»» first_connected_at` | string(date-time) | false | | | -| `»» id` | string(uuid) | false | | | -| `»» instance_id` | string | false | | | -| `»» last_connected_at` | string(date-time) | false | | | -| `»» latency` | object | false | | »latency is mapped by region name (e.g. "New York City", "Seattle"). | -| `»»» [any property]` | [codersdk.DERPRegion](schemas.md#codersdkderpregion) | false | | | -| `»»»» latency_ms` | number | false | | | -| `»»»» preferred` | boolean | false | | | -| `»» lifecycle_state` | [codersdk.WorkspaceAgentLifecycle](schemas.md#codersdkworkspaceagentlifecycle) | false | | | -| `»» name` | string | false | | | -| `»» operating_system` | string | false | | | -| `»» resource_id` | string(uuid) | false | | | -| `»» startup_script` | string | false | | | -| `»» status` | [codersdk.WorkspaceAgentStatus](schemas.md#codersdkworkspaceagentstatus) | false | | | -| `»» troubleshooting_url` | string | false | | | -| `»» updated_at` | string(date-time) | false | | | -| `»» version` | string | false | | | -| `» created_at` | string(date-time) | false | | | -| `» daily_cost` | integer | false | | | -| `» hide` | boolean | false | | | -| `» icon` | string | false | | | -| `» id` | string(uuid) | false | | | -| `» job_id` | string(uuid) | false | | | -| `» metadata` | array | false | | | -| `»» key` | string | false | | | -| `»» sensitive` | boolean | false | | | -| `»» value` | string | false | | | -| `» name` | string | false | | | -| `» type` | string | false | | | -| `» workspace_transition` | [codersdk.WorkspaceTransition](schemas.md#codersdkworkspacetransition) | false | | | +| Name | Type | Required | Restrictions | Description | +| ----------------------------------- | -------------------------------------------------------------------------------- | -------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `[array item]` | array | false | | | +| `» agents` | array | false | | | +| `»» apps` | array | false | | | +| `»»» command` | string | false | | | +| `»»» display_name` | string | false | | »»display name is a friendly name for the app. | +| `»»» external` | boolean | false | | External specifies whether the URL should be opened externally on the client or not. | +| `»»» health` | [codersdk.WorkspaceAppHealth](schemas.md#codersdkworkspaceapphealth) | false | | | +| `»»» healthcheck` | [codersdk.Healthcheck](schemas.md#codersdkhealthcheck) | false | | Healthcheck specifies the configuration for checking app health. | +| `»»»» interval` | integer | false | | Interval specifies the seconds between each health check. | +| `»»»» threshold` | integer | false | | Threshold specifies the number of consecutive failed health checks before returning "unhealthy". | +| `»»»» url` | string | false | | »»»url specifies the endpoint to check for the app health. | +| `»»» icon` | string | false | | Icon is a relative path or external URL that specifies an icon to be displayed in the dashboard. | +| `»»» id` | string(uuid) | false | | | +| `»»» sharing_level` | [codersdk.WorkspaceAppSharingLevel](schemas.md#codersdkworkspaceappsharinglevel) | false | | | +| `»»» slug` | string | false | | Slug is a unique identifier within the agent. | +| `»»» subdomain` | boolean | false | | Subdomain denotes whether the app should be accessed via a path on the `coder server` or via a hostname-based dev URL. If this is set to true and there is no app wildcard configured on the server, the app will not be accessible in the UI. | +| `»»» url` | string | false | | »»url is the address being proxied to inside the workspace. If external is specified, this will be opened on the client. | +| `»» architecture` | string | false | | | +| `»» connection_timeout_seconds` | integer | false | | | +| `»» created_at` | string(date-time) | false | | | +| `»» delay_login_until_ready` | boolean | false | | »delay login until ready if true, the agent will delay logins until it is ready (e.g. executing startup script has ended). | +| `»» directory` | string | false | | | +| `»» disconnected_at` | string(date-time) | false | | | +| `»» environment_variables` | object | false | | | +| `»»» [any property]` | string | false | | | +| `»» first_connected_at` | string(date-time) | false | | | +| `»» id` | string(uuid) | false | | | +| `»» instance_id` | string | false | | | +| `»» last_connected_at` | string(date-time) | false | | | +| `»» latency` | object | false | | »latency is mapped by region name (e.g. "New York City", "Seattle"). | +| `»»» [any property]` | [codersdk.DERPRegion](schemas.md#codersdkderpregion) | false | | | +| `»»»» latency_ms` | number | false | | | +| `»»»» preferred` | boolean | false | | | +| `»» lifecycle_state` | [codersdk.WorkspaceAgentLifecycle](schemas.md#codersdkworkspaceagentlifecycle) | false | | | +| `»» name` | string | false | | | +| `»» operating_system` | string | false | | | +| `»» resource_id` | string(uuid) | false | | | +| `»» startup_script` | string | false | | | +| `»» startup_script_timeout_seconds` | integer | false | | »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. | +| `»» status` | [codersdk.WorkspaceAgentStatus](schemas.md#codersdkworkspaceagentstatus) | false | | | +| `»» troubleshooting_url` | string | false | | | +| `»» updated_at` | string(date-time) | false | | | +| `»» version` | string | false | | | +| `» created_at` | string(date-time) | false | | | +| `» daily_cost` | integer | false | | | +| `» hide` | boolean | false | | | +| `» icon` | string | false | | | +| `» id` | string(uuid) | false | | | +| `» job_id` | string(uuid) | false | | | +| `» metadata` | array | false | | | +| `»» key` | string | false | | | +| `»» sensitive` | boolean | false | | | +| `»» value` | string | false | | | +| `» name` | string | false | | | +| `» type` | string | false | | | +| `» workspace_transition` | [codersdk.WorkspaceTransition](schemas.md#codersdkworkspacetransition) | false | | | #### Enumerated Values diff --git a/docs/api/workspaces.md b/docs/api/workspaces.md index b363b773ce953..f51d33d76dbd8 100644 --- a/docs/api/workspaces.md +++ b/docs/api/workspaces.md @@ -80,6 +80,7 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/member "architecture": "string", "connection_timeout_seconds": 0, "created_at": "2019-08-24T14:15:22Z", + "delay_login_until_ready": true, "directory": "string", "disconnected_at": "2019-08-24T14:15:22Z", "environment_variables": { @@ -105,6 +106,7 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/member "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "startup_script_timeout_seconds": 0, "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -242,6 +244,7 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/workspace/{workspacenam "architecture": "string", "connection_timeout_seconds": 0, "created_at": "2019-08-24T14:15:22Z", + "delay_login_until_ready": true, "directory": "string", "disconnected_at": "2019-08-24T14:15:22Z", "environment_variables": { @@ -267,6 +270,7 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/workspace/{workspacenam "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "startup_script_timeout_seconds": 0, "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -423,6 +427,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces \ "architecture": "string", "connection_timeout_seconds": 0, "created_at": "2019-08-24T14:15:22Z", + "delay_login_until_ready": true, "directory": "string", "disconnected_at": "2019-08-24T14:15:22Z", "environment_variables": { @@ -448,6 +453,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces \ "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "startup_script_timeout_seconds": 0, "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", @@ -586,6 +592,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace} \ "architecture": "string", "connection_timeout_seconds": 0, "created_at": "2019-08-24T14:15:22Z", + "delay_login_until_ready": true, "directory": "string", "disconnected_at": "2019-08-24T14:15:22Z", "environment_variables": { @@ -611,6 +618,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace} \ "operating_system": "string", "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", "startup_script": "string", + "startup_script_timeout_seconds": 0, "status": "connecting", "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", diff --git a/provisioner/terraform/resources.go b/provisioner/terraform/resources.go index 043ecfe47f5cd..c0ced8e3fcc52 100644 --- a/provisioner/terraform/resources.go +++ b/provisioner/terraform/resources.go @@ -124,18 +124,18 @@ func ConvertResourcesAndParameters(modules []*tfjson.StateModule, rawGraph strin agentNames[tfResource.Name] = struct{}{} agent := &proto.Agent{ - Name: tfResource.Name, - Id: attrs.ID, - Env: attrs.Env, - StartupScript: attrs.StartupScript, - OperatingSystem: attrs.OperatingSystem, - Architecture: attrs.Architecture, - Directory: attrs.Directory, - ConnectionTimeoutSeconds: attrs.ConnectionTimeoutSeconds, - TroubleshootingUrl: attrs.TroubleshootingURL, - MotdFile: attrs.MOTDFile, - DelayLoginUntilReady: attrs.DelayLoginUntilReady, - StartupScriptTimeout: attrs.StartupScriptTimeout, + Name: tfResource.Name, + Id: attrs.ID, + Env: attrs.Env, + StartupScript: attrs.StartupScript, + OperatingSystem: attrs.OperatingSystem, + Architecture: attrs.Architecture, + Directory: attrs.Directory, + ConnectionTimeoutSeconds: attrs.ConnectionTimeoutSeconds, + TroubleshootingUrl: attrs.TroubleshootingURL, + MotdFile: attrs.MOTDFile, + DelayLoginUntilReady: attrs.DelayLoginUntilReady, + StartupScriptTimeoutSeconds: attrs.StartupScriptTimeout, } switch attrs.Auth { case "token": diff --git a/provisioner/terraform/resources_test.go b/provisioner/terraform/resources_test.go index 2b1d73b8ffeb7..95d81b7540317 100644 --- a/provisioner/terraform/resources_test.go +++ b/provisioner/terraform/resources_test.go @@ -100,31 +100,31 @@ func TestConvertResources(t *testing.T) { Name: "dev", Type: "null_resource", Agents: []*proto.Agent{{ - Name: "dev1", - OperatingSystem: "linux", - Architecture: "amd64", - Auth: &proto.Agent_Token{}, - ConnectionTimeoutSeconds: 120, - DelayLoginUntilReady: false, - StartupScriptTimeout: 300, + Name: "dev1", + OperatingSystem: "linux", + Architecture: "amd64", + Auth: &proto.Agent_Token{}, + ConnectionTimeoutSeconds: 120, + DelayLoginUntilReady: false, + StartupScriptTimeoutSeconds: 300, }, { - Name: "dev2", - OperatingSystem: "darwin", - Architecture: "amd64", - Auth: &proto.Agent_Token{}, - ConnectionTimeoutSeconds: 1, - MotdFile: "/etc/motd", - DelayLoginUntilReady: false, - StartupScriptTimeout: 30, + Name: "dev2", + OperatingSystem: "darwin", + Architecture: "amd64", + Auth: &proto.Agent_Token{}, + ConnectionTimeoutSeconds: 1, + MotdFile: "/etc/motd", + DelayLoginUntilReady: false, + StartupScriptTimeoutSeconds: 30, }, { - Name: "dev3", - OperatingSystem: "windows", - Architecture: "arm64", - Auth: &proto.Agent_Token{}, - ConnectionTimeoutSeconds: 120, - TroubleshootingUrl: "https://coder.com/troubleshoot", - DelayLoginUntilReady: true, - StartupScriptTimeout: 300, + Name: "dev3", + OperatingSystem: "windows", + Architecture: "arm64", + Auth: &proto.Agent_Token{}, + ConnectionTimeoutSeconds: 120, + TroubleshootingUrl: "https://coder.com/troubleshoot", + DelayLoginUntilReady: true, + StartupScriptTimeoutSeconds: 300, }}, }}, }, diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 35010f93a7194..8c52c5da260f6 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -932,6 +932,8 @@ export interface WorkspaceAgent { readonly latency?: Record readonly connection_timeout_seconds: number readonly troubleshooting_url: string + readonly delay_login_until_ready: boolean + readonly startup_script_timeout_seconds: number } // From codersdk/workspaceagents.go diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index 6ac7d92b066e6..027357a4653f9 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -302,6 +302,8 @@ export const MockWorkspaceAgent: TypesGen.WorkspaceAgent = { connection_timeout_seconds: 120, troubleshooting_url: "https://coder.com/troubleshoot", lifecycle_state: "starting", + delay_login_until_ready: true, + startup_script_timeout_seconds: 120, } export const MockWorkspaceAgentDisconnected: TypesGen.WorkspaceAgent = { From 087070e8b35278ea94c37ca89b2d60472899d6f9 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Mon, 23 Jan 2023 16:29:30 +0000 Subject: [PATCH 13/23] Run OverrideVSCodeConfigs even on error --- agent/agent.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/agent/agent.go b/agent/agent.go index 174255763cf82..a84e1173da9a2 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -266,24 +266,26 @@ func (a *agent) run(ctx context.Context) error { return } execTime := time.Since(scriptStart) + lifecycleStatus := codersdk.WorkspaceAgentLifecycleReady if err != nil { a.logger.Warn(ctx, "startup script failed", slog.F("execution_time", execTime), slog.Error(err)) - a.setLifecycle(codersdk.WorkspaceAgentLifecycleStartError) - return + lifecycleStatus = codersdk.WorkspaceAgentLifecycleStartError + } else { + a.logger.Info(ctx, "startup script completed", slog.F("execution_time", execTime)) } - a.logger.Info(ctx, "startup script completed", slog.F("execution_time", execTime)) // Perform overrides after startup script has completed to ensure // there is no conflict with the user's scripts. We also want to // ensure this is done before the workspace is marked as ready. + // Note, this is done even in the even that startup script failed. if metadata.GitAuthConfigs > 0 { - err = gitauth.OverrideVSCodeConfigs(a.filesystem) + err := gitauth.OverrideVSCodeConfigs(a.filesystem) if err != nil { a.logger.Warn(ctx, "failed to override vscode git auth configs", slog.Error(err)) } } - a.setLifecycle(codersdk.WorkspaceAgentLifecycleReady) + a.setLifecycle(lifecycleStatus) }() } From c6928e92f3e78320ab3aa4c845bdcd84c682342e Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Mon, 23 Jan 2023 16:53:40 +0000 Subject: [PATCH 14/23] Use consistent Seconds terminology --- provisioner/terraform/resources.go | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/provisioner/terraform/resources.go b/provisioner/terraform/resources.go index c0ced8e3fcc52..385ae2cc9be34 100644 --- a/provisioner/terraform/resources.go +++ b/provisioner/terraform/resources.go @@ -16,19 +16,19 @@ import ( // A mapping of attributes on the "coder_agent" resource. type agentAttributes struct { - Auth string `mapstructure:"auth"` - OperatingSystem string `mapstructure:"os"` - Architecture string `mapstructure:"arch"` - Directory string `mapstructure:"dir"` - ID string `mapstructure:"id"` - Token string `mapstructure:"token"` - Env map[string]string `mapstructure:"env"` - StartupScript string `mapstructure:"startup_script"` - ConnectionTimeoutSeconds int32 `mapstructure:"connection_timeout"` - TroubleshootingURL string `mapstructure:"troubleshooting_url"` - MOTDFile string `mapstructure:"motd_file"` - DelayLoginUntilReady bool `mapstructure:"delay_login_until_ready"` - StartupScriptTimeout int32 `mapstructure:"startup_script_timeout"` + Auth string `mapstructure:"auth"` + OperatingSystem string `mapstructure:"os"` + Architecture string `mapstructure:"arch"` + Directory string `mapstructure:"dir"` + ID string `mapstructure:"id"` + Token string `mapstructure:"token"` + Env map[string]string `mapstructure:"env"` + StartupScript string `mapstructure:"startup_script"` + ConnectionTimeoutSeconds int32 `mapstructure:"connection_timeout"` + TroubleshootingURL string `mapstructure:"troubleshooting_url"` + MOTDFile string `mapstructure:"motd_file"` + DelayLoginUntilReady bool `mapstructure:"delay_login_until_ready"` + StartupScriptTimeoutSeconds int32 `mapstructure:"startup_script_timeout"` } // A mapping of attributes on the "coder_app" resource. @@ -135,7 +135,7 @@ func ConvertResourcesAndParameters(modules []*tfjson.StateModule, rawGraph strin TroubleshootingUrl: attrs.TroubleshootingURL, MotdFile: attrs.MOTDFile, DelayLoginUntilReady: attrs.DelayLoginUntilReady, - StartupScriptTimeoutSeconds: attrs.StartupScriptTimeout, + StartupScriptTimeoutSeconds: attrs.StartupScriptTimeoutSeconds, } switch attrs.Auth { case "token": From c132d4eb6eb4a5c12cef4177c068a9516470f5d7 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Mon, 23 Jan 2023 17:01:40 +0000 Subject: [PATCH 15/23] Fix s/continue/break/ --- agent/agent.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent/agent.go b/agent/agent.go index a84e1173da9a2..af6411e173c5c 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -182,7 +182,7 @@ func (a *agent) reportLifecycleLoop(ctx context.Context) { a.lifecycleMu.Unlock() if state == lastReported { - continue + break } err := a.client.PostWorkspaceAgentLifecycle(ctx, codersdk.PostWorkspaceAgentLifecycleRequest{ From 903e850c02b94b6e01d98112bf281751a3d5b5a8 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Mon, 23 Jan 2023 17:06:29 +0000 Subject: [PATCH 16/23] Fix git auth override order --- agent/agent.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/agent/agent.go b/agent/agent.go index af6411e173c5c..7f7601b94a22b 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -236,6 +236,19 @@ func (a *agent) run(ctx context.Context) error { // The startup script should only execute on the first run! if oldMetadata == nil { + a.setLifecycle(codersdk.WorkspaceAgentLifecycleStarting) + + // Perform overrides early so that Git auth can work even if users + // connect to a workspace that is not yet ready. We don't run this + // concurrently with the startup script to avoid conflicts between + // them. + if metadata.GitAuthConfigs > 0 { + err := gitauth.OverrideVSCodeConfigs(a.filesystem) + if err != nil { + a.logger.Warn(ctx, "failed to override vscode git auth configs", slog.Error(err)) + } + } + scriptDone := make(chan error, 1) scriptStart := time.Now() go func() { @@ -252,8 +265,6 @@ func (a *agent) run(ctx context.Context) error { timeout = t.C } - a.setLifecycle(codersdk.WorkspaceAgentLifecycleStarting) - var err error select { case err = <-scriptDone: @@ -274,17 +285,6 @@ func (a *agent) run(ctx context.Context) error { a.logger.Info(ctx, "startup script completed", slog.F("execution_time", execTime)) } - // Perform overrides after startup script has completed to ensure - // there is no conflict with the user's scripts. We also want to - // ensure this is done before the workspace is marked as ready. - // Note, this is done even in the even that startup script failed. - if metadata.GitAuthConfigs > 0 { - err := gitauth.OverrideVSCodeConfigs(a.filesystem) - if err != nil { - a.logger.Warn(ctx, "failed to override vscode git auth configs", slog.Error(err)) - } - } - a.setLifecycle(lifecycleStatus) }() } From 034a8507944479cd804e0e8c24f08309f38bce0d Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Mon, 23 Jan 2023 17:08:23 +0000 Subject: [PATCH 17/23] Fix nit --- coderd/workspaceagents_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coderd/workspaceagents_test.go b/coderd/workspaceagents_test.go index 0882a4afe2ef2..b5974b6f5d35f 100644 --- a/coderd/workspaceagents_test.go +++ b/coderd/workspaceagents_test.go @@ -1224,7 +1224,7 @@ func gitAuthCallback(t *testing.T, id string, client *codersdk.Client) *http.Res func TestWorkspaceAgent_LifecycleState(t *testing.T) { t.Parallel() - t.Run("Set state", func(t *testing.T) { + t.Run("Set", func(t *testing.T) { t.Parallel() client := coderdtest.New(t, &coderdtest.Options{ From f76247f29cb67420dd93c900e581fd345471aab8 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Mon, 23 Jan 2023 17:24:45 +0000 Subject: [PATCH 18/23] Publish workspace update --- coderd/workspaceagents.go | 1 + 1 file changed, 1 insertion(+) diff --git a/coderd/workspaceagents.go b/coderd/workspaceagents.go index 31862316b74c9..aceefbbcdf0ad 100644 --- a/coderd/workspaceagents.go +++ b/coderd/workspaceagents.go @@ -953,6 +953,7 @@ func (api *API) workspaceAgentReportLifecycle(rw http.ResponseWriter, r *http.Re httpapi.InternalServerError(rw, err) return } + api.publishWorkspaceUpdate(ctx, workspace.ID) httpapi.Write(ctx, rw, http.StatusNoContent, nil) } From 2ccdcacc8ffca45d99b88e7182081fc1d3cad6ee Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Tue, 24 Jan 2023 10:43:58 +0000 Subject: [PATCH 19/23] Hide report lifecycle endpoint from apidocs --- coderd/apidoc/docs.go | 3 +++ coderd/apidoc/swagger.json | 3 +++ coderd/workspaceagents.go | 1 + docs/api/agents.md | 35 ----------------------------------- 4 files changed, 7 insertions(+), 35 deletions(-) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 4d78aeec69524..2205b0fb6f578 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -4003,6 +4003,9 @@ const docTemplate = `{ "204": { "description": "Success" } + }, + "x-apidocgen": { + "skip": true } } }, diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 630b08dc83002..cba572c89a154 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -3519,6 +3519,9 @@ "204": { "description": "Success" } + }, + "x-apidocgen": { + "skip": true } } }, diff --git a/coderd/workspaceagents.go b/coderd/workspaceagents.go index aceefbbcdf0ad..69d056f66da9c 100644 --- a/coderd/workspaceagents.go +++ b/coderd/workspaceagents.go @@ -912,6 +912,7 @@ func (api *API) workspaceAgentReportStats(rw http.ResponseWriter, r *http.Reques // @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() diff --git a/docs/api/agents.md b/docs/api/agents.md index 900c7820b4fcb..3359c66e32628 100644 --- a/docs/api/agents.md +++ b/docs/api/agents.md @@ -383,41 +383,6 @@ curl -X GET http://coder-server:8080/api/v2/workspaceagents/me/metadata \ To perform this operation, you must be authenticated. [Learn more](authentication.md). -## Submit workspace agent lifecycle state - -### Code samples - -```shell -# Example request using curl -curl -X POST http://coder-server:8080/api/v2/workspaceagents/me/report-lifecycle \ - -H 'Content-Type: application/json' \ - -H 'Coder-Session-Token: API_KEY' -``` - -`POST /workspaceagents/me/report-lifecycle` - -> Body parameter - -```json -{ - "state": "created" -} -``` - -### Parameters - -| Name | In | Type | Required | Description | -| ------ | ---- | ---------------------------------------------------------------------------------------------------- | -------- | --------------------------------- | -| `body` | body | [codersdk.PostWorkspaceAgentLifecycleRequest](schemas.md#codersdkpostworkspaceagentlifecyclerequest) | true | Workspace agent lifecycle request | - -### Responses - -| Status | Meaning | Description | Schema | -| ------ | --------------------------------------------------------------- | ----------- | ------ | -| 204 | [No Content](https://tools.ietf.org/html/rfc7231#section-6.3.5) | Success | | - -To perform this operation, you must be authenticated. [Learn more](authentication.md). - ## Submit workspace agent stats ### Code samples From 830f9f1439f6abb04a34928e20be3193c29947d0 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Tue, 24 Jan 2023 11:11:17 +0000 Subject: [PATCH 20/23] Set all existing agents to ready --- coderd/database/dump.sql | 2 +- .../000091_add_workspace_agent_state.up.sql | 16 +++++++++++----- coderd/database/models.go | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index 74ab801f8131d..76881e579022e 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -470,7 +470,7 @@ 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 of the workspace agent.'; +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).'; diff --git a/coderd/database/migrations/000091_add_workspace_agent_state.up.sql b/coderd/database/migrations/000091_add_workspace_agent_state.up.sql index 0c3b198712607..c2c1f4da3fa80 100644 --- a/coderd/database/migrations/000091_add_workspace_agent_state.up.sql +++ b/coderd/database/migrations/000091_add_workspace_agent_state.up.sql @@ -1,13 +1,19 @@ CREATE TYPE workspace_agent_lifecycle_state AS ENUM ('created', 'starting', 'start_timeout', 'start_error', 'ready'); -ALTER TABLE workspace_agents ADD COLUMN lifecycle_state workspace_agent_lifecycle_state NOT NULL DEFAULT 'created'; -COMMENT ON COLUMN workspace_agents.lifecycle_state IS 'The current lifecycle state of the workspace agent.'; +-- 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'; -/* Set default values that conform to current behavior */ -/* Allow logins immediately after agent connect */ +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 */ +-- 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.'; diff --git a/coderd/database/models.go b/coderd/database/models.go index a0314a0b603f8..9337610a23c4b 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -1515,7 +1515,7 @@ 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 of the workspace agent. + // 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"` From 2b1569f2619b5f63b254564fb3ef57d923352bf9 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Tue, 24 Jan 2023 11:14:14 +0000 Subject: [PATCH 21/23] Add debug logging to lifecycle states --- agent/agent.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/agent/agent.go b/agent/agent.go index 7f7601b94a22b..6a38ad562c95a 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -185,6 +185,8 @@ func (a *agent) reportLifecycleLoop(ctx context.Context) { break } + a.logger.Debug(ctx, "post lifecycle state", slog.F("state", state)) + err := a.client.PostWorkspaceAgentLifecycle(ctx, codersdk.PostWorkspaceAgentLifecycleRequest{ State: state, }) @@ -201,10 +203,12 @@ func (a *agent) reportLifecycleLoop(ctx context.Context) { } } -func (a *agent) setLifecycle(state codersdk.WorkspaceAgentLifecycle) { +func (a *agent) setLifecycle(ctx context.Context, state codersdk.WorkspaceAgentLifecycle) { a.lifecycleMu.Lock() defer a.lifecycleMu.Unlock() + a.logger.Debug(ctx, "set lifecycle state", slog.F("state", state), slog.F("previous", a.lifecycleState)) + a.lifecycleState = state select { case a.lifecycleUpdate <- struct{}{}: @@ -236,7 +240,7 @@ func (a *agent) run(ctx context.Context) error { // The startup script should only execute on the first run! if oldMetadata == nil { - a.setLifecycle(codersdk.WorkspaceAgentLifecycleStarting) + a.setLifecycle(ctx, codersdk.WorkspaceAgentLifecycleStarting) // Perform overrides early so that Git auth can work even if users // connect to a workspace that is not yet ready. We don't run this @@ -270,7 +274,7 @@ func (a *agent) run(ctx context.Context) error { case err = <-scriptDone: case <-timeout: a.logger.Warn(ctx, "startup script timed out") - a.setLifecycle(codersdk.WorkspaceAgentLifecycleStartTimeout) + a.setLifecycle(ctx, codersdk.WorkspaceAgentLifecycleStartTimeout) err = <-scriptDone // The script can still complete after a timeout. } if errors.Is(err, context.Canceled) { @@ -285,7 +289,7 @@ func (a *agent) run(ctx context.Context) error { a.logger.Info(ctx, "startup script completed", slog.F("execution_time", execTime)) } - a.setLifecycle(lifecycleStatus) + a.setLifecycle(ctx, lifecycleStatus) }() } From 71706e0e170bfe41c338f91a7e281c961a4ed67e Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Tue, 24 Jan 2023 11:38:25 +0000 Subject: [PATCH 22/23] Add note about error during vscode git auth override --- agent/agent.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/agent/agent.go b/agent/agent.go index 6a38ad562c95a..7c4b0d9e3fa77 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -247,6 +247,9 @@ func (a *agent) run(ctx context.Context) error { // concurrently with the startup script to avoid conflicts between // them. if metadata.GitAuthConfigs > 0 { + // If this fails, we should consider surfacing the error in the + // startup log and setting the lifecycle state to be "start_error" + // (after startup script completion), but for now we'll just log it. err := gitauth.OverrideVSCodeConfigs(a.filesystem) if err != nil { a.logger.Warn(ctx, "failed to override vscode git auth configs", slog.Error(err)) From 21a9d28ca1015a6a853cbdf2ecf5e5924ce47bb7 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Tue, 24 Jan 2023 11:41:43 +0000 Subject: [PATCH 23/23] Fix typo in tests --- agent/agent_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/agent/agent_test.go b/agent/agent_test.go index 8ad6106fccad8..d152974843bb7 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -720,8 +720,8 @@ func TestAgent_Lifecycle(t *testing.T) { }, testutil.WaitShort, testutil.IntervalMedium) switch len(got) { case 1: - // This can happen if lifecycle states are too - // fast, only the latest on is reported. + // This can happen if lifecycle state updates are + // too fast, only the latest one is reported. require.Equal(t, want[1:], got) default: // This is the expected case. @@ -749,8 +749,8 @@ func TestAgent_Lifecycle(t *testing.T) { }, testutil.WaitShort, testutil.IntervalMedium) switch len(got) { case 1: - // This can happen if lifecycle states are too - // fast, only the latest on is reported. + // This can happen if lifecycle state updates are + // too fast, only the latest one is reported. require.Equal(t, want[1:], got) default: // This is the expected case. @@ -778,8 +778,8 @@ func TestAgent_Lifecycle(t *testing.T) { }, testutil.WaitShort, testutil.IntervalMedium) switch len(got) { case 1: - // This can happen if lifecycle states are too - // fast, only the latest on is reported. + // This can happen if lifecycle state updates are + // too fast, only the latest one is reported. require.Equal(t, want[1:], got) default: // This is the expected case.