diff --git a/agent/agent.go b/agent/agent.go index 52c423787fb44..6a248bf37085d 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -63,7 +63,7 @@ type Options struct { IgnorePorts map[int]string SSHMaxTimeout time.Duration TailnetListenPort uint16 - Subsystem codersdk.AgentSubsystem + Subsystems []codersdk.AgentSubsystem Addresses []netip.Prefix PrometheusRegistry *prometheus.Registry ReportMetadataInterval time.Duration @@ -144,7 +144,7 @@ func New(options Options) Agent { reportMetadataInterval: options.ReportMetadataInterval, serviceBannerRefreshInterval: options.ServiceBannerRefreshInterval, sshMaxTimeout: options.SSHMaxTimeout, - subsystem: options.Subsystem, + subsystems: options.Subsystems, addresses: options.Addresses, prometheusRegistry: prometheusRegistry, @@ -166,7 +166,7 @@ type agent struct { // listing all listening ports. This is helpful to hide ports that // are used by the agent, that the user does not care about. ignorePorts map[int]string - subsystem codersdk.AgentSubsystem + subsystems []codersdk.AgentSubsystem reconnectingPTYs sync.Map reconnectingPTYTimeout time.Duration @@ -608,7 +608,7 @@ func (a *agent) run(ctx context.Context) error { err = a.client.PostStartup(ctx, agentsdk.PostStartupRequest{ Version: buildinfo.Version(), ExpandedDirectory: manifest.Directory, - Subsystem: a.subsystem, + Subsystems: a.subsystems, }) if err != nil { return xerrors.Errorf("update workspace agent version: %w", err) diff --git a/cli/agent.go b/cli/agent.go index 1d9a2ba02d51c..a217c9b0acc67 100644 --- a/cli/agent.go +++ b/cli/agent.go @@ -12,6 +12,7 @@ import ( "path/filepath" "runtime" "strconv" + "strings" "sync" "time" @@ -253,7 +254,19 @@ func (r *RootCmd) workspaceAgent() *clibase.Cmd { } prometheusRegistry := prometheus.NewRegistry() - subsystem := inv.Environ.Get(agent.EnvAgentSubsystem) + subsystemsRaw := inv.Environ.Get(agent.EnvAgentSubsystem) + subsystems := []codersdk.AgentSubsystem{} + for _, s := range strings.Split(subsystemsRaw, ",") { + subsystem := codersdk.AgentSubsystem(strings.TrimSpace(s)) + if subsystem == "" { + continue + } + if !subsystem.Valid() { + return xerrors.Errorf("invalid subsystem %q", subsystem) + } + subsystems = append(subsystems, subsystem) + } + agnt := agent.New(agent.Options{ Client: client, Logger: logger, @@ -275,7 +288,7 @@ func (r *RootCmd) workspaceAgent() *clibase.Cmd { }, IgnorePorts: ignorePorts, SSHMaxTimeout: sshMaxTimeout, - Subsystem: codersdk.AgentSubsystem(subsystem), + Subsystems: subsystems, PrometheusRegistry: prometheusRegistry, }) diff --git a/cli/agent_test.go b/cli/agent_test.go index 462ef3c204541..34f04b70705b2 100644 --- a/cli/agent_test.go +++ b/cli/agent_test.go @@ -2,6 +2,7 @@ package cli_test import ( "context" + "fmt" "os" "path/filepath" "runtime" @@ -264,8 +265,8 @@ func TestWorkspaceAgent(t *testing.T) { "--agent-url", client.URL.String(), "--log-dir", logDir, ) - // Set the subsystem for the agent. - inv.Environ.Set(agent.EnvAgentSubsystem, string(codersdk.AgentSubsystemEnvbox)) + // Set the subsystems for the agent. + inv.Environ.Set(agent.EnvAgentSubsystem, fmt.Sprintf("%s,%s", codersdk.AgentSubsystemExectrace, codersdk.AgentSubsystemEnvbox)) pty := ptytest.New(t).Attach(inv) @@ -275,6 +276,9 @@ func TestWorkspaceAgent(t *testing.T) { resources := coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) require.Len(t, resources, 1) require.Len(t, resources[0].Agents, 1) - require.Equal(t, codersdk.AgentSubsystemEnvbox, resources[0].Agents[0].Subsystem) + require.Len(t, resources[0].Agents[0].Subsystems, 2) + // Sorted + require.Equal(t, codersdk.AgentSubsystemEnvbox, resources[0].Agents[0].Subsystems[0]) + require.Equal(t, codersdk.AgentSubsystemExectrace, resources[0].Agents[0].Subsystems[1]) }) } diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 8d7920c2d2e8d..2e9132cb812b5 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -6447,8 +6447,11 @@ const docTemplate = `{ "expanded_directory": { "type": "string" }, - "subsystem": { - "$ref": "#/definitions/codersdk.AgentSubsystem" + "subsystems": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.AgentSubsystem" + } }, "version": { "type": "string" @@ -6900,10 +6903,14 @@ const docTemplate = `{ "codersdk.AgentSubsystem": { "type": "string", "enum": [ - "envbox" + "envbox", + "envbuilder", + "exectrace" ], "x-enum-varnames": [ - "AgentSubsystemEnvbox" + "AgentSubsystemEnvbox", + "AgentSubsystemEnvbuilder", + "AgentSubsystemExectrace" ] }, "codersdk.AppHostResponse": { @@ -10525,8 +10532,11 @@ const docTemplate = `{ "status": { "$ref": "#/definitions/codersdk.WorkspaceAgentStatus" }, - "subsystem": { - "$ref": "#/definitions/codersdk.AgentSubsystem" + "subsystems": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.AgentSubsystem" + } }, "troubleshooting_url": { "type": "string" diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index bc4c0e7b8a958..634c2594befee 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -5697,8 +5697,11 @@ "expanded_directory": { "type": "string" }, - "subsystem": { - "$ref": "#/definitions/codersdk.AgentSubsystem" + "subsystems": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.AgentSubsystem" + } }, "version": { "type": "string" @@ -6127,8 +6130,12 @@ }, "codersdk.AgentSubsystem": { "type": "string", - "enum": ["envbox"], - "x-enum-varnames": ["AgentSubsystemEnvbox"] + "enum": ["envbox", "envbuilder", "exectrace"], + "x-enum-varnames": [ + "AgentSubsystemEnvbox", + "AgentSubsystemEnvbuilder", + "AgentSubsystemExectrace" + ] }, "codersdk.AppHostResponse": { "type": "object", @@ -9546,8 +9553,11 @@ "status": { "$ref": "#/definitions/codersdk.WorkspaceAgentStatus" }, - "subsystem": { - "$ref": "#/definitions/codersdk.AgentSubsystem" + "subsystems": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.AgentSubsystem" + } }, "troubleshooting_url": { "type": "string" diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index f3313c768053f..d6ad41f51408a 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -1064,8 +1064,10 @@ func (s *MethodTestSuite) TestWorkspace() { res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) agt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID}) check.Args(database.UpdateWorkspaceAgentStartupByIDParams{ - ID: agt.ID, - Subsystem: database.WorkspaceAgentSubsystemNone, + ID: agt.ID, + Subsystems: []database.WorkspaceAgentSubsystem{ + database.WorkspaceAgentSubsystemEnvbox, + }, }).Asserts(ws, rbac.ActionUpdate).Returns() })) s.Run("GetWorkspaceAgentLogsAfter", s.Subtest(func(db database.Store, check *expects) { diff --git a/coderd/database/dbfake/dbfake.go b/coderd/database/dbfake/dbfake.go index cc0d05aaee9c3..dfb57c6b91a5b 100644 --- a/coderd/database/dbfake/dbfake.go +++ b/coderd/database/dbfake/dbfake.go @@ -5161,6 +5161,23 @@ func (q *FakeQuerier) UpdateWorkspaceAgentStartupByID(_ context.Context, arg dat return err } + if len(arg.Subsystems) > 0 { + seen := map[database.WorkspaceAgentSubsystem]struct{}{ + arg.Subsystems[0]: {}, + } + for i := 1; i < len(arg.Subsystems); i++ { + s := arg.Subsystems[i] + if _, ok := seen[s]; ok { + return xerrors.Errorf("duplicate subsystem %q", s) + } + seen[s] = struct{}{} + + if arg.Subsystems[i-1] > arg.Subsystems[i] { + return xerrors.Errorf("subsystems not sorted: %q > %q", arg.Subsystems[i-1], arg.Subsystems[i]) + } + } + } + q.mutex.Lock() defer q.mutex.Unlock() @@ -5171,7 +5188,7 @@ func (q *FakeQuerier) UpdateWorkspaceAgentStartupByID(_ context.Context, arg dat agent.Version = arg.Version agent.ExpandedDirectory = arg.ExpandedDirectory - agent.Subsystem = arg.Subsystem + agent.Subsystems = arg.Subsystems q.workspaceAgents[index] = agent return nil } diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index f121fccf8cebb..ed1c2e165ffac 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -143,7 +143,8 @@ CREATE TYPE workspace_agent_log_source AS ENUM ( CREATE TYPE workspace_agent_subsystem AS ENUM ( 'envbuilder', 'envbox', - 'none' + 'none', + 'exectrace' ); CREATE TYPE workspace_app_health AS ENUM ( @@ -767,11 +768,12 @@ CREATE TABLE workspace_agents ( shutdown_script_timeout_seconds integer DEFAULT 0 NOT NULL, logs_length integer DEFAULT 0 NOT NULL, logs_overflowed boolean DEFAULT false NOT NULL, - subsystem workspace_agent_subsystem DEFAULT 'none'::workspace_agent_subsystem NOT NULL, startup_script_behavior startup_script_behavior DEFAULT 'non-blocking'::startup_script_behavior NOT NULL, started_at timestamp with time zone, ready_at timestamp with time zone, - CONSTRAINT max_logs_length CHECK ((logs_length <= 1048576)) + subsystems workspace_agent_subsystem[] DEFAULT '{}'::workspace_agent_subsystem[], + CONSTRAINT max_logs_length CHECK ((logs_length <= 1048576)), + CONSTRAINT subsystems_not_none CHECK ((NOT ('none'::workspace_agent_subsystem = ANY (subsystems)))) ); COMMENT ON COLUMN workspace_agents.version IS 'Version tracks the version of the currently running workspace agent. Workspace agents register their version upon start.'; diff --git a/coderd/database/migrations/000148_agent_multiple_subsystems.down.sql b/coderd/database/migrations/000148_agent_multiple_subsystems.down.sql new file mode 100644 index 0000000000000..05bea6c620502 --- /dev/null +++ b/coderd/database/migrations/000148_agent_multiple_subsystems.down.sql @@ -0,0 +1,17 @@ +BEGIN; + +-- Bring back the subsystem column. +ALTER TABLE workspace_agents ADD COLUMN subsystem workspace_agent_subsystem NOT NULL DEFAULT 'none'; + +-- Update all existing workspace_agents to have subsystem = subsystems[0] unless +-- subsystems is empty. +UPDATE workspace_agents SET subsystem = subsystems[1] WHERE cardinality(subsystems) > 0; + +-- Drop the subsystems column from workspace_agents. +ALTER TABLE workspace_agents DROP COLUMN subsystems; + +-- We cannot drop the "exectrace" value from the workspace_agent_subsystem type +-- because you cannot drop values from an enum type. +UPDATE workspace_agents SET subsystem = 'none' WHERE subsystem = 'exectrace'; + +COMMIT; diff --git a/coderd/database/migrations/000148_agent_multiple_subsystems.up.sql b/coderd/database/migrations/000148_agent_multiple_subsystems.up.sql new file mode 100644 index 0000000000000..9ebb71d5bdf5e --- /dev/null +++ b/coderd/database/migrations/000148_agent_multiple_subsystems.up.sql @@ -0,0 +1,21 @@ +BEGIN; + +-- Add "exectrace" to workspace_agent_subsystem type. +ALTER TYPE workspace_agent_subsystem ADD VALUE 'exectrace'; + +-- Create column subsystems in workspace_agents table, with default value being +-- an empty array. +ALTER TABLE workspace_agents ADD COLUMN subsystems workspace_agent_subsystem[] DEFAULT '{}'; + +-- Add a constraint that the subsystems cannot contain the deprecated value +-- 'none'. +ALTER TABLE workspace_agents ADD CONSTRAINT subsystems_not_none CHECK (NOT ('none' = ANY (subsystems))); + +-- Update all existing workspace_agents to have subsystems = [subsystem] unless +-- the subsystem is 'none'. +UPDATE workspace_agents SET subsystems = ARRAY[subsystem] WHERE subsystem != 'none'; + +-- Drop the subsystem column from workspace_agents. +ALTER TABLE workspace_agents DROP COLUMN subsystem; + +COMMIT; diff --git a/coderd/database/models.go b/coderd/database/models.go index 4e34989b09ae9..2d22980214f59 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -1249,6 +1249,7 @@ const ( WorkspaceAgentSubsystemEnvbuilder WorkspaceAgentSubsystem = "envbuilder" WorkspaceAgentSubsystemEnvbox WorkspaceAgentSubsystem = "envbox" WorkspaceAgentSubsystemNone WorkspaceAgentSubsystem = "none" + WorkspaceAgentSubsystemExectrace WorkspaceAgentSubsystem = "exectrace" ) func (e *WorkspaceAgentSubsystem) Scan(src interface{}) error { @@ -1290,7 +1291,8 @@ func (e WorkspaceAgentSubsystem) Valid() bool { switch e { case WorkspaceAgentSubsystemEnvbuilder, WorkspaceAgentSubsystemEnvbox, - WorkspaceAgentSubsystemNone: + WorkspaceAgentSubsystemNone, + WorkspaceAgentSubsystemExectrace: return true } return false @@ -1301,6 +1303,7 @@ func AllWorkspaceAgentSubsystemValues() []WorkspaceAgentSubsystem { WorkspaceAgentSubsystemEnvbuilder, WorkspaceAgentSubsystemEnvbox, WorkspaceAgentSubsystemNone, + WorkspaceAgentSubsystemExectrace, } } @@ -1884,14 +1887,14 @@ type WorkspaceAgent struct { // Total length of startup logs LogsLength int32 `db:"logs_length" json:"logs_length"` // Whether the startup logs overflowed in length - LogsOverflowed bool `db:"logs_overflowed" json:"logs_overflowed"` - Subsystem WorkspaceAgentSubsystem `db:"subsystem" json:"subsystem"` + LogsOverflowed bool `db:"logs_overflowed" json:"logs_overflowed"` // When startup script behavior is non-blocking, the workspace will be ready and accessible upon agent connection, when it is blocking, workspace will wait for the startup script to complete before becoming ready and accessible. StartupScriptBehavior StartupScriptBehavior `db:"startup_script_behavior" json:"startup_script_behavior"` // The time the agent entered the starting lifecycle state StartedAt sql.NullTime `db:"started_at" json:"started_at"` // The time the agent entered the ready or start_error lifecycle state - ReadyAt sql.NullTime `db:"ready_at" json:"ready_at"` + ReadyAt sql.NullTime `db:"ready_at" json:"ready_at"` + Subsystems []WorkspaceAgentSubsystem `db:"subsystems" json:"subsystems"` } type WorkspaceAgentLog struct { diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 3e07fc22f1aa3..7f1265805baf4 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -6170,7 +6170,7 @@ func (q *sqlQuerier) DeleteOldWorkspaceAgentLogs(ctx context.Context) error { 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, startup_script_timeout_seconds, expanded_directory, shutdown_script, shutdown_script_timeout_seconds, logs_length, logs_overflowed, subsystem, startup_script_behavior, started_at, ready_at + 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, startup_script_timeout_seconds, expanded_directory, shutdown_script, shutdown_script_timeout_seconds, logs_length, logs_overflowed, startup_script_behavior, started_at, ready_at, subsystems FROM workspace_agents WHERE @@ -6212,17 +6212,17 @@ func (q *sqlQuerier) GetWorkspaceAgentByAuthToken(ctx context.Context, authToken &i.ShutdownScriptTimeoutSeconds, &i.LogsLength, &i.LogsOverflowed, - &i.Subsystem, &i.StartupScriptBehavior, &i.StartedAt, &i.ReadyAt, + pq.Array(&i.Subsystems), ) 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, startup_script_timeout_seconds, expanded_directory, shutdown_script, shutdown_script_timeout_seconds, logs_length, logs_overflowed, subsystem, startup_script_behavior, started_at, ready_at + 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, startup_script_timeout_seconds, expanded_directory, shutdown_script, shutdown_script_timeout_seconds, logs_length, logs_overflowed, startup_script_behavior, started_at, ready_at, subsystems FROM workspace_agents WHERE @@ -6262,17 +6262,17 @@ func (q *sqlQuerier) GetWorkspaceAgentByID(ctx context.Context, id uuid.UUID) (W &i.ShutdownScriptTimeoutSeconds, &i.LogsLength, &i.LogsOverflowed, - &i.Subsystem, &i.StartupScriptBehavior, &i.StartedAt, &i.ReadyAt, + pq.Array(&i.Subsystems), ) 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, startup_script_timeout_seconds, expanded_directory, shutdown_script, shutdown_script_timeout_seconds, logs_length, logs_overflowed, subsystem, startup_script_behavior, started_at, ready_at + 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, startup_script_timeout_seconds, expanded_directory, shutdown_script, shutdown_script_timeout_seconds, logs_length, logs_overflowed, startup_script_behavior, started_at, ready_at, subsystems FROM workspace_agents WHERE @@ -6314,10 +6314,10 @@ func (q *sqlQuerier) GetWorkspaceAgentByInstanceID(ctx context.Context, authInst &i.ShutdownScriptTimeoutSeconds, &i.LogsLength, &i.LogsOverflowed, - &i.Subsystem, &i.StartupScriptBehavior, &i.StartedAt, &i.ReadyAt, + pq.Array(&i.Subsystems), ) return i, err } @@ -6437,7 +6437,7 @@ func (q *sqlQuerier) GetWorkspaceAgentMetadata(ctx context.Context, workspaceAge 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, startup_script_timeout_seconds, expanded_directory, shutdown_script, shutdown_script_timeout_seconds, logs_length, logs_overflowed, subsystem, startup_script_behavior, started_at, ready_at + 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, startup_script_timeout_seconds, expanded_directory, shutdown_script, shutdown_script_timeout_seconds, logs_length, logs_overflowed, startup_script_behavior, started_at, ready_at, subsystems FROM workspace_agents WHERE @@ -6483,10 +6483,10 @@ func (q *sqlQuerier) GetWorkspaceAgentsByResourceIDs(ctx context.Context, ids [] &i.ShutdownScriptTimeoutSeconds, &i.LogsLength, &i.LogsOverflowed, - &i.Subsystem, &i.StartupScriptBehavior, &i.StartedAt, &i.ReadyAt, + pq.Array(&i.Subsystems), ); err != nil { return nil, err } @@ -6502,7 +6502,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, startup_script_timeout_seconds, expanded_directory, shutdown_script, shutdown_script_timeout_seconds, logs_length, logs_overflowed, subsystem, startup_script_behavior, started_at, ready_at 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, startup_script_timeout_seconds, expanded_directory, shutdown_script, shutdown_script_timeout_seconds, logs_length, logs_overflowed, startup_script_behavior, started_at, ready_at, subsystems FROM workspace_agents WHERE created_at > $1 ` func (q *sqlQuerier) GetWorkspaceAgentsCreatedAfter(ctx context.Context, createdAt time.Time) ([]WorkspaceAgent, error) { @@ -6544,10 +6544,10 @@ func (q *sqlQuerier) GetWorkspaceAgentsCreatedAfter(ctx context.Context, created &i.ShutdownScriptTimeoutSeconds, &i.LogsLength, &i.LogsOverflowed, - &i.Subsystem, &i.StartupScriptBehavior, &i.StartedAt, &i.ReadyAt, + pq.Array(&i.Subsystems), ); err != nil { return nil, err } @@ -6564,7 +6564,7 @@ func (q *sqlQuerier) GetWorkspaceAgentsCreatedAfter(ctx context.Context, created const getWorkspaceAgentsInLatestBuildByWorkspaceID = `-- name: GetWorkspaceAgentsInLatestBuildByWorkspaceID :many SELECT - workspace_agents.id, workspace_agents.created_at, workspace_agents.updated_at, workspace_agents.name, workspace_agents.first_connected_at, workspace_agents.last_connected_at, workspace_agents.disconnected_at, workspace_agents.resource_id, workspace_agents.auth_token, workspace_agents.auth_instance_id, workspace_agents.architecture, workspace_agents.environment_variables, workspace_agents.operating_system, workspace_agents.startup_script, workspace_agents.instance_metadata, workspace_agents.resource_metadata, workspace_agents.directory, workspace_agents.version, workspace_agents.last_connected_replica_id, workspace_agents.connection_timeout_seconds, workspace_agents.troubleshooting_url, workspace_agents.motd_file, workspace_agents.lifecycle_state, workspace_agents.startup_script_timeout_seconds, workspace_agents.expanded_directory, workspace_agents.shutdown_script, workspace_agents.shutdown_script_timeout_seconds, workspace_agents.logs_length, workspace_agents.logs_overflowed, workspace_agents.subsystem, workspace_agents.startup_script_behavior, workspace_agents.started_at, workspace_agents.ready_at + workspace_agents.id, workspace_agents.created_at, workspace_agents.updated_at, workspace_agents.name, workspace_agents.first_connected_at, workspace_agents.last_connected_at, workspace_agents.disconnected_at, workspace_agents.resource_id, workspace_agents.auth_token, workspace_agents.auth_instance_id, workspace_agents.architecture, workspace_agents.environment_variables, workspace_agents.operating_system, workspace_agents.startup_script, workspace_agents.instance_metadata, workspace_agents.resource_metadata, workspace_agents.directory, workspace_agents.version, workspace_agents.last_connected_replica_id, workspace_agents.connection_timeout_seconds, workspace_agents.troubleshooting_url, workspace_agents.motd_file, workspace_agents.lifecycle_state, workspace_agents.startup_script_timeout_seconds, workspace_agents.expanded_directory, workspace_agents.shutdown_script, workspace_agents.shutdown_script_timeout_seconds, workspace_agents.logs_length, workspace_agents.logs_overflowed, workspace_agents.startup_script_behavior, workspace_agents.started_at, workspace_agents.ready_at, workspace_agents.subsystems FROM workspace_agents JOIN @@ -6622,10 +6622,10 @@ func (q *sqlQuerier) GetWorkspaceAgentsInLatestBuildByWorkspaceID(ctx context.Co &i.ShutdownScriptTimeoutSeconds, &i.LogsLength, &i.LogsOverflowed, - &i.Subsystem, &i.StartupScriptBehavior, &i.StartedAt, &i.ReadyAt, + pq.Array(&i.Subsystems), ); err != nil { return nil, err } @@ -6666,7 +6666,7 @@ INSERT INTO shutdown_script_timeout_seconds ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21) 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, startup_script_timeout_seconds, expanded_directory, shutdown_script, shutdown_script_timeout_seconds, logs_length, logs_overflowed, subsystem, startup_script_behavior, started_at, ready_at + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21) 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, startup_script_timeout_seconds, expanded_directory, shutdown_script, shutdown_script_timeout_seconds, logs_length, logs_overflowed, startup_script_behavior, started_at, ready_at, subsystems ` type InsertWorkspaceAgentParams struct { @@ -6748,10 +6748,10 @@ func (q *sqlQuerier) InsertWorkspaceAgent(ctx context.Context, arg InsertWorkspa &i.ShutdownScriptTimeoutSeconds, &i.LogsLength, &i.LogsOverflowed, - &i.Subsystem, &i.StartupScriptBehavior, &i.StartedAt, &i.ReadyAt, + pq.Array(&i.Subsystems), ) return i, err } @@ -6971,16 +6971,16 @@ UPDATE SET version = $2, expanded_directory = $3, - subsystem = $4 + subsystems = $4 WHERE id = $1 ` type UpdateWorkspaceAgentStartupByIDParams struct { - ID uuid.UUID `db:"id" json:"id"` - Version string `db:"version" json:"version"` - ExpandedDirectory string `db:"expanded_directory" json:"expanded_directory"` - Subsystem WorkspaceAgentSubsystem `db:"subsystem" json:"subsystem"` + ID uuid.UUID `db:"id" json:"id"` + Version string `db:"version" json:"version"` + ExpandedDirectory string `db:"expanded_directory" json:"expanded_directory"` + Subsystems []WorkspaceAgentSubsystem `db:"subsystems" json:"subsystems"` } func (q *sqlQuerier) UpdateWorkspaceAgentStartupByID(ctx context.Context, arg UpdateWorkspaceAgentStartupByIDParams) error { @@ -6988,7 +6988,7 @@ func (q *sqlQuerier) UpdateWorkspaceAgentStartupByID(ctx context.Context, arg Up arg.ID, arg.Version, arg.ExpandedDirectory, - arg.Subsystem, + pq.Array(arg.Subsystems), ) return err } diff --git a/coderd/database/queries/workspaceagents.sql b/coderd/database/queries/workspaceagents.sql index 4025ac7e59a1b..dcc15081615e2 100644 --- a/coderd/database/queries/workspaceagents.sql +++ b/coderd/database/queries/workspaceagents.sql @@ -83,7 +83,7 @@ UPDATE SET version = $2, expanded_directory = $3, - subsystem = $4 + subsystems = $4 WHERE id = $1; diff --git a/coderd/telemetry/telemetry.go b/coderd/telemetry/telemetry.go index ced52a58fd273..69156564bbbd3 100644 --- a/coderd/telemetry/telemetry.go +++ b/coderd/telemetry/telemetry.go @@ -534,6 +534,11 @@ func ConvertProvisionerJob(job database.ProvisionerJob) ProvisionerJob { // ConvertWorkspaceAgent anonymizes a workspace agent. func ConvertWorkspaceAgent(agent database.WorkspaceAgent) WorkspaceAgent { + subsystems := []string{} + for _, subsystem := range agent.Subsystems { + subsystems = append(subsystems, string(subsystem)) + } + snapAgent := WorkspaceAgent{ ID: agent.ID, CreatedAt: agent.CreatedAt, @@ -546,7 +551,7 @@ func ConvertWorkspaceAgent(agent database.WorkspaceAgent) WorkspaceAgent { Directory: agent.Directory != "", ConnectionTimeoutSeconds: agent.ConnectionTimeoutSeconds, ShutdownScript: agent.ShutdownScript.Valid, - Subsystem: string(agent.Subsystem), + Subsystems: subsystems, } if agent.FirstConnectedAt.Valid { snapAgent.FirstConnectedAt = &agent.FirstConnectedAt.Time @@ -768,7 +773,7 @@ type WorkspaceAgent struct { DisconnectedAt *time.Time `json:"disconnected_at"` ConnectionTimeoutSeconds int32 `json:"connection_timeout_seconds"` ShutdownScript bool `json:"shutdown_script"` - Subsystem string `json:"subsystem"` + Subsystems []string `json:"subsystems"` } type WorkspaceAgentStat struct { diff --git a/coderd/telemetry/telemetry_test.go b/coderd/telemetry/telemetry_test.go index 93e1a5295475b..dcf3daa120c16 100644 --- a/coderd/telemetry/telemetry_test.go +++ b/coderd/telemetry/telemetry_test.go @@ -54,15 +54,16 @@ func TestTelemetry(t *testing.T) { SharingLevel: database.AppSharingLevelOwner, Health: database.WorkspaceAppHealthDisabled, }) - wsagent := dbgen.WorkspaceAgent(t, db, database.WorkspaceAgent{ - Subsystem: database.WorkspaceAgentSubsystemEnvbox, - }) + wsagent := dbgen.WorkspaceAgent(t, db, database.WorkspaceAgent{}) // Update the workspace agent to have a valid subsystem. err = db.UpdateWorkspaceAgentStartupByID(ctx, database.UpdateWorkspaceAgentStartupByIDParams{ ID: wsagent.ID, Version: wsagent.Version, ExpandedDirectory: wsagent.ExpandedDirectory, - Subsystem: database.WorkspaceAgentSubsystemEnvbox, + Subsystems: []database.WorkspaceAgentSubsystem{ + database.WorkspaceAgentSubsystemEnvbox, + database.WorkspaceAgentSubsystemExectrace, + }, }) require.NoError(t, err) @@ -95,7 +96,9 @@ func TestTelemetry(t *testing.T) { require.Len(t, snapshot.WorkspaceAgentStats, 1) wsa := snapshot.WorkspaceAgents[0] - require.Equal(t, string(database.WorkspaceAgentSubsystemEnvbox), wsa.Subsystem) + require.Len(t, wsa.Subsystems, 2) + require.Equal(t, string(database.WorkspaceAgentSubsystemEnvbox), wsa.Subsystems[0]) + require.Equal(t, string(database.WorkspaceAgentSubsystemExectrace), wsa.Subsystems[1]) }) t.Run("HashedEmail", func(t *testing.T) { t.Parallel() diff --git a/coderd/workspaceagents.go b/coderd/workspaceagents.go index 0f5607db73436..0dfe76a660018 100644 --- a/coderd/workspaceagents.go +++ b/coderd/workspaceagents.go @@ -14,6 +14,7 @@ import ( "net/netip" "net/url" "runtime/pprof" + "sort" "strconv" "strings" "sync" @@ -219,11 +220,31 @@ func (api *API) postWorkspaceAgentStartup(rw http.ResponseWriter, r *http.Reques return } + // Validate subsystems. + seen := make(map[codersdk.AgentSubsystem]bool) + for _, s := range req.Subsystems { + if !s.Valid() { + httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ + Message: "Invalid workspace agent subsystem provided.", + Detail: fmt.Sprintf("invalid subsystem: %q", s), + }) + return + } + if seen[s] { + httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ + Message: "Invalid workspace agent subsystem provided.", + Detail: fmt.Sprintf("duplicate subsystem: %q", s), + }) + return + } + seen[s] = true + } + if err := api.Database.UpdateWorkspaceAgentStartupByID(ctx, database.UpdateWorkspaceAgentStartupByIDParams{ ID: apiAgent.ID, Version: req.Version, ExpandedDirectory: req.ExpandedDirectory, - Subsystem: convertWorkspaceAgentSubsystem(req.Subsystem), + Subsystems: convertWorkspaceAgentSubsystems(req.Subsystems), }); err != nil { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ Message: "Error setting agent version", @@ -1277,6 +1298,11 @@ func convertWorkspaceAgent(derpMap *tailcfg.DERPMap, coordinator tailnet.Coordin if dbAgent.TroubleshootingURL != "" { troubleshootingURL = dbAgent.TroubleshootingURL } + subsystems := make([]codersdk.AgentSubsystem, len(dbAgent.Subsystems)) + for i, subsystem := range dbAgent.Subsystems { + subsystems[i] = codersdk.AgentSubsystem(subsystem) + } + workspaceAgent := codersdk.WorkspaceAgent{ ID: dbAgent.ID, CreatedAt: dbAgent.CreatedAt, @@ -1302,7 +1328,7 @@ func convertWorkspaceAgent(derpMap *tailcfg.DERPMap, coordinator tailnet.Coordin LoginBeforeReady: dbAgent.StartupScriptBehavior != database.StartupScriptBehaviorBlocking, ShutdownScript: dbAgent.ShutdownScript.String, ShutdownScriptTimeoutSeconds: dbAgent.ShutdownScriptTimeoutSeconds, - Subsystem: codersdk.AgentSubsystem(dbAgent.Subsystem), + Subsystems: subsystems, } node := coordinator.Node(dbAgent.ID) if node != nil { @@ -2114,11 +2140,23 @@ func convertWorkspaceAgentLog(logEntry database.WorkspaceAgentLog) codersdk.Work } } -func convertWorkspaceAgentSubsystem(ss codersdk.AgentSubsystem) database.WorkspaceAgentSubsystem { - switch ss { - case codersdk.AgentSubsystemEnvbox: - return database.WorkspaceAgentSubsystemEnvbox - default: - return database.WorkspaceAgentSubsystemNone +func convertWorkspaceAgentSubsystems(ss []codersdk.AgentSubsystem) []database.WorkspaceAgentSubsystem { + out := make([]database.WorkspaceAgentSubsystem, 0, len(ss)) + for _, s := range ss { + switch s { + case codersdk.AgentSubsystemEnvbox: + out = append(out, database.WorkspaceAgentSubsystemEnvbox) + case codersdk.AgentSubsystemEnvbuilder: + out = append(out, database.WorkspaceAgentSubsystemEnvbuilder) + case codersdk.AgentSubsystemExectrace: + out = append(out, database.WorkspaceAgentSubsystemExectrace) + default: + // Invalid, drop it. + } } + + sort.Slice(out, func(i, j int) bool { + return out[i] < out[j] + }) + return out } diff --git a/coderd/workspaceagents_test.go b/coderd/workspaceagents_test.go index 12cb19efac012..b85dd9d3550d9 100644 --- a/coderd/workspaceagents_test.go +++ b/coderd/workspaceagents_test.go @@ -1195,16 +1195,23 @@ func TestWorkspaceAgent_Startup(t *testing.T) { ctx := testutil.Context(t, testutil.WaitMedium) - const ( - expectedVersion = "v1.2.3" - expectedDir = "/home/coder" - expectedSubsystem = codersdk.AgentSubsystemEnvbox + var ( + expectedVersion = "v1.2.3" + expectedDir = "/home/coder" + expectedSubsystems = []codersdk.AgentSubsystem{ + codersdk.AgentSubsystemEnvbox, + codersdk.AgentSubsystemExectrace, + } ) err := agentClient.PostStartup(ctx, agentsdk.PostStartupRequest{ Version: expectedVersion, ExpandedDirectory: expectedDir, - Subsystem: expectedSubsystem, + Subsystems: []codersdk.AgentSubsystem{ + // Not sorted. + expectedSubsystems[1], + expectedSubsystems[0], + }, }) require.NoError(t, err) @@ -1215,7 +1222,8 @@ func TestWorkspaceAgent_Startup(t *testing.T) { require.NoError(t, err) require.Equal(t, expectedVersion, wsagent.Version) require.Equal(t, expectedDir, wsagent.ExpandedDirectory) - require.Equal(t, expectedSubsystem, wsagent.Subsystem) + // Sorted + require.Equal(t, expectedSubsystems, wsagent.Subsystems) }) t.Run("InvalidSemver", func(t *testing.T) { diff --git a/codersdk/agentsdk/agentsdk.go b/codersdk/agentsdk/agentsdk.go index e2189e1cc53d2..d5e038bdf6b39 100644 --- a/codersdk/agentsdk/agentsdk.go +++ b/codersdk/agentsdk/agentsdk.go @@ -612,9 +612,9 @@ func (c *Client) PostLifecycle(ctx context.Context, req PostLifecycleRequest) er } type PostStartupRequest struct { - Version string `json:"version"` - ExpandedDirectory string `json:"expanded_directory"` - Subsystem codersdk.AgentSubsystem `json:"subsystem"` + Version string `json:"version"` + ExpandedDirectory string `json:"expanded_directory"` + Subsystems []codersdk.AgentSubsystem `json:"subsystems"` } func (c *Client) PostStartup(ctx context.Context, req PostStartupRequest) error { diff --git a/codersdk/workspaceagents.go b/codersdk/workspaceagents.go index e9aad8421e36a..71153a0e89b8a 100644 --- a/codersdk/workspaceagents.go +++ b/codersdk/workspaceagents.go @@ -167,7 +167,7 @@ type WorkspaceAgent struct { LoginBeforeReady bool `json:"login_before_ready"` ShutdownScript string `json:"shutdown_script,omitempty"` ShutdownScriptTimeoutSeconds int32 `json:"shutdown_script_timeout_seconds"` - Subsystem AgentSubsystem `json:"subsystem"` + Subsystems []AgentSubsystem `json:"subsystems"` Health WorkspaceAgentHealth `json:"health"` // Health reports the health of the agent. } @@ -754,9 +754,20 @@ type WorkspaceAgentLog struct { type AgentSubsystem string const ( - AgentSubsystemEnvbox AgentSubsystem = "envbox" + AgentSubsystemEnvbox AgentSubsystem = "envbox" + AgentSubsystemEnvbuilder AgentSubsystem = "envbuilder" + AgentSubsystemExectrace AgentSubsystem = "exectrace" ) +func (s AgentSubsystem) Valid() bool { + switch s { + case AgentSubsystemEnvbox, AgentSubsystemEnvbuilder, AgentSubsystemExectrace: + return true + default: + return false + } +} + type WorkspaceAgentLogSource string const ( diff --git a/docs/api/agents.md b/docs/api/agents.md index 2316fdaafde51..8bf6f10619e50 100644 --- a/docs/api/agents.md +++ b/docs/api/agents.md @@ -695,7 +695,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaceagents/{workspaceagent} \ "startup_script_behavior": "blocking", "startup_script_timeout_seconds": 0, "status": "connecting", - "subsystem": "envbox", + "subsystems": ["envbox"], "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", "version": "string" diff --git a/docs/api/builds.md b/docs/api/builds.md index daf7958de387f..782e41a6f61aa 100644 --- a/docs/api/builds.md +++ b/docs/api/builds.md @@ -120,7 +120,7 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/workspace/{workspacenam "startup_script_behavior": "blocking", "startup_script_timeout_seconds": 0, "status": "connecting", - "subsystem": "envbox", + "subsystems": ["envbox"], "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", "version": "string" @@ -282,7 +282,7 @@ curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild} \ "startup_script_behavior": "blocking", "startup_script_timeout_seconds": 0, "status": "connecting", - "subsystem": "envbox", + "subsystems": ["envbox"], "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", "version": "string" @@ -583,7 +583,7 @@ curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild}/res "startup_script_behavior": "blocking", "startup_script_timeout_seconds": 0, "status": "connecting", - "subsystem": "envbox", + "subsystems": ["envbox"], "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", "version": "string" @@ -672,7 +672,7 @@ Status Code **200** | `»» startup_script_behavior` | [codersdk.WorkspaceAgentStartupScriptBehavior](schemas.md#codersdkworkspaceagentstartupscriptbehavior) | 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 | | | -| `»» subsystem` | [codersdk.AgentSubsystem](schemas.md#codersdkagentsubsystem) | false | | | +| `»» subsystems` | array | false | | | | `»» troubleshooting_url` | string | false | | | | `»» updated_at` | string(date-time) | false | | | | `»» version` | string | false | | | @@ -716,7 +716,6 @@ Status Code **200** | `status` | `connected` | | `status` | `disconnected` | | `status` | `timeout` | -| `subsystem` | `envbox` | | `workspace_transition` | `start` | | `workspace_transition` | `stop` | | `workspace_transition` | `delete` | @@ -841,7 +840,7 @@ curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild}/sta "startup_script_behavior": "blocking", "startup_script_timeout_seconds": 0, "status": "connecting", - "subsystem": "envbox", + "subsystems": ["envbox"], "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", "version": "string" @@ -1008,7 +1007,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace}/builds \ "startup_script_behavior": "blocking", "startup_script_timeout_seconds": 0, "status": "connecting", - "subsystem": "envbox", + "subsystems": ["envbox"], "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", "version": "string" @@ -1133,7 +1132,7 @@ Status Code **200** | `»»» startup_script_behavior` | [codersdk.WorkspaceAgentStartupScriptBehavior](schemas.md#codersdkworkspaceagentstartupscriptbehavior) | 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 | | | -| `»»» subsystem` | [codersdk.AgentSubsystem](schemas.md#codersdkagentsubsystem) | false | | | +| `»»» subsystems` | array | false | | | | `»»» troubleshooting_url` | string | false | | | | `»»» updated_at` | string(date-time) | false | | | | `»»» version` | string | false | | | @@ -1197,7 +1196,6 @@ Status Code **200** | `status` | `connected` | | `status` | `disconnected` | | `status` | `timeout` | -| `subsystem` | `envbox` | | `workspace_transition` | `start` | | `workspace_transition` | `stop` | | `workspace_transition` | `delete` | @@ -1356,7 +1354,7 @@ curl -X POST http://coder-server:8080/api/v2/workspaces/{workspace}/builds \ "startup_script_behavior": "blocking", "startup_script_timeout_seconds": 0, "status": "connecting", - "subsystem": "envbox", + "subsystems": ["envbox"], "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", "version": "string" diff --git a/docs/api/schemas.md b/docs/api/schemas.md index 192cc9625eddd..38b9e4b73aca0 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -377,18 +377,18 @@ ```json { "expanded_directory": "string", - "subsystem": "envbox", + "subsystems": ["envbox"], "version": "string" } ``` ### Properties -| Name | Type | Required | Restrictions | Description | -| -------------------- | -------------------------------------------------- | -------- | ------------ | ----------- | -| `expanded_directory` | string | false | | | -| `subsystem` | [codersdk.AgentSubsystem](#codersdkagentsubsystem) | false | | | -| `version` | string | false | | | +| Name | Type | Required | Restrictions | Description | +| -------------------- | ----------------------------------------------------------- | -------- | ------------ | ----------- | +| `expanded_directory` | string | false | | | +| `subsystems` | array of [codersdk.AgentSubsystem](#codersdkagentsubsystem) | false | | | +| `version` | string | false | | | ## agentsdk.Stats @@ -902,9 +902,11 @@ #### Enumerated Values -| Value | -| -------- | -| `envbox` | +| Value | +| ------------ | +| `envbox` | +| `envbuilder` | +| `exectrace` | ## codersdk.AppHostResponse @@ -5357,7 +5359,7 @@ If the schedule is empty, the user will be updated to use the default schedule.| "startup_script_behavior": "blocking", "startup_script_timeout_seconds": 0, "status": "connecting", - "subsystem": "envbox", + "subsystems": ["envbox"], "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", "version": "string" @@ -5498,7 +5500,7 @@ If the schedule is empty, the user will be updated to use the default schedule.| "startup_script_behavior": "blocking", "startup_script_timeout_seconds": 0, "status": "connecting", - "subsystem": "envbox", + "subsystems": ["envbox"], "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", "version": "string" @@ -5540,7 +5542,7 @@ If the schedule is empty, the user will be updated to use the default schedule.| | `startup_script_behavior` | [codersdk.WorkspaceAgentStartupScriptBehavior](#codersdkworkspaceagentstartupscriptbehavior) | 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 | | | -| `subsystem` | [codersdk.AgentSubsystem](#codersdkagentsubsystem) | false | | | +| `subsystems` | array of [codersdk.AgentSubsystem](#codersdkagentsubsystem) | false | | | | `troubleshooting_url` | string | false | | | | `updated_at` | string | false | | | | `version` | string | false | | | @@ -5956,7 +5958,7 @@ If the schedule is empty, the user will be updated to use the default schedule.| "startup_script_behavior": "blocking", "startup_script_timeout_seconds": 0, "status": "connecting", - "subsystem": "envbox", + "subsystems": ["envbox"], "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", "version": "string" @@ -6267,7 +6269,7 @@ If the schedule is empty, the user will be updated to use the default schedule.| "startup_script_behavior": "blocking", "startup_script_timeout_seconds": 0, "status": "connecting", - "subsystem": "envbox", + "subsystems": ["envbox"], "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", "version": "string" @@ -6479,7 +6481,7 @@ If the schedule is empty, the user will be updated to use the default schedule.| "startup_script_behavior": "blocking", "startup_script_timeout_seconds": 0, "status": "connecting", - "subsystem": "envbox", + "subsystems": ["envbox"], "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", "version": "string" diff --git a/docs/api/templates.md b/docs/api/templates.md index f8a1612161f81..14ce5dec7d29f 100644 --- a/docs/api/templates.md +++ b/docs/api/templates.md @@ -1633,7 +1633,7 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/d "startup_script_behavior": "blocking", "startup_script_timeout_seconds": 0, "status": "connecting", - "subsystem": "envbox", + "subsystems": ["envbox"], "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", "version": "string" @@ -1722,7 +1722,7 @@ Status Code **200** | `»» startup_script_behavior` | [codersdk.WorkspaceAgentStartupScriptBehavior](schemas.md#codersdkworkspaceagentstartupscriptbehavior) | 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 | | | -| `»» subsystem` | [codersdk.AgentSubsystem](schemas.md#codersdkagentsubsystem) | false | | | +| `»» subsystems` | array | false | | | | `»» troubleshooting_url` | string | false | | | | `»» updated_at` | string(date-time) | false | | | | `»» version` | string | false | | | @@ -1766,7 +1766,6 @@ Status Code **200** | `status` | `connected` | | `status` | `disconnected` | | `status` | `timeout` | -| `subsystem` | `envbox` | | `workspace_transition` | `start` | | `workspace_transition` | `stop` | | `workspace_transition` | `delete` | @@ -2025,7 +2024,7 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/r "startup_script_behavior": "blocking", "startup_script_timeout_seconds": 0, "status": "connecting", - "subsystem": "envbox", + "subsystems": ["envbox"], "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", "version": "string" @@ -2114,7 +2113,7 @@ Status Code **200** | `»» startup_script_behavior` | [codersdk.WorkspaceAgentStartupScriptBehavior](schemas.md#codersdkworkspaceagentstartupscriptbehavior) | 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 | | | -| `»» subsystem` | [codersdk.AgentSubsystem](schemas.md#codersdkagentsubsystem) | false | | | +| `»» subsystems` | array | false | | | | `»» troubleshooting_url` | string | false | | | | `»» updated_at` | string(date-time) | false | | | | `»» version` | string | false | | | @@ -2158,7 +2157,6 @@ Status Code **200** | `status` | `connected` | | `status` | `disconnected` | | `status` | `timeout` | -| `subsystem` | `envbox` | | `workspace_transition` | `start` | | `workspace_transition` | `stop` | | `workspace_transition` | `delete` | diff --git a/docs/api/workspaces.md b/docs/api/workspaces.md index 6cfb468f6af50..f5c4aadd729c5 100644 --- a/docs/api/workspaces.md +++ b/docs/api/workspaces.md @@ -148,7 +148,7 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/member "startup_script_behavior": "blocking", "startup_script_timeout_seconds": 0, "status": "connecting", - "subsystem": "envbox", + "subsystems": ["envbox"], "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", "version": "string" @@ -336,7 +336,7 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/workspace/{workspacenam "startup_script_behavior": "blocking", "startup_script_timeout_seconds": 0, "status": "connecting", - "subsystem": "envbox", + "subsystems": ["envbox"], "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", "version": "string" @@ -523,7 +523,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces \ "startup_script_behavior": "blocking", "startup_script_timeout_seconds": 0, "status": "connecting", - "subsystem": "envbox", + "subsystems": ["envbox"], "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", "version": "string" @@ -712,7 +712,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace} \ "startup_script_behavior": "blocking", "startup_script_timeout_seconds": 0, "status": "connecting", - "subsystem": "envbox", + "subsystems": ["envbox"], "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", "version": "string" @@ -1034,7 +1034,7 @@ curl -X PUT http://coder-server:8080/api/v2/workspaces/{workspace}/lock \ "startup_script_behavior": "blocking", "startup_script_timeout_seconds": 0, "status": "connecting", - "subsystem": "envbox", + "subsystems": ["envbox"], "troubleshooting_url": "string", "updated_at": "2019-08-24T14:15:22Z", "version": "string" diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index f8b91abb925b6..34052933a9945 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -1333,7 +1333,7 @@ export interface WorkspaceAgent { readonly login_before_ready: boolean readonly shutdown_script?: string readonly shutdown_script_timeout_seconds: number - readonly subsystem: AgentSubsystem + readonly subsystems: AgentSubsystem[] readonly health: WorkspaceAgentHealth } @@ -1538,8 +1538,12 @@ export type APIKeyScope = "all" | "application_connect" export const APIKeyScopes: APIKeyScope[] = ["all", "application_connect"] // From codersdk/workspaceagents.go -export type AgentSubsystem = "envbox" -export const AgentSubsystems: AgentSubsystem[] = ["envbox"] +export type AgentSubsystem = "envbox" | "envbuilder" | "exectrace" +export const AgentSubsystems: AgentSubsystem[] = [ + "envbox", + "envbuilder", + "exectrace", +] // From codersdk/audit.go export type AuditAction = diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index 3d28ae7ad1ffb..08e5f6fb44cfa 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -563,7 +563,7 @@ export const MockWorkspaceAgent: TypesGen.WorkspaceAgent = { logs_overflowed: false, startup_script_timeout_seconds: 120, shutdown_script_timeout_seconds: 120, - subsystem: "envbox", + subsystems: ["envbox", "exectrace"], health: { healthy: true, },