diff --git a/agent/agent.go b/agent/agent.go index e435b795d5..3d9b8947b1 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -64,7 +64,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 @@ -145,7 +145,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, @@ -167,7 +167,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 @@ -609,7 +609,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 1d9a2ba02d..a217c9b0ac 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 462ef3c204..34f04b7070 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 f930bf74f4..e83cf37d32 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" @@ -6903,10 +6906,14 @@ const docTemplate = `{ "codersdk.AgentSubsystem": { "type": "string", "enum": [ - "envbox" + "envbox", + "envbuilder", + "exectrace" ], "x-enum-varnames": [ - "AgentSubsystemEnvbox" + "AgentSubsystemEnvbox", + "AgentSubsystemEnvbuilder", + "AgentSubsystemExectrace" ] }, "codersdk.AppHostResponse": { @@ -10556,8 +10563,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 0d691b237b..0206c57062 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" @@ -6130,8 +6133,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", @@ -9571,8 +9578,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 f3313c7680..d6ad41f514 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 c7ce32c794..156fe957d6 100644 --- a/coderd/database/dbfake/dbfake.go +++ b/coderd/database/dbfake/dbfake.go @@ -5203,6 +5203,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() @@ -5213,7 +5230,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 9dfb9ded10..95a1e3534a 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -148,7 +148,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 ( @@ -775,11 +776,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 0000000000..05bea6c620 --- /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 0000000000..9ebb71d5bd --- /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 d3b7700b56..0c1b4a7002 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -1307,6 +1307,7 @@ const ( WorkspaceAgentSubsystemEnvbuilder WorkspaceAgentSubsystem = "envbuilder" WorkspaceAgentSubsystemEnvbox WorkspaceAgentSubsystem = "envbox" WorkspaceAgentSubsystemNone WorkspaceAgentSubsystem = "none" + WorkspaceAgentSubsystemExectrace WorkspaceAgentSubsystem = "exectrace" ) func (e *WorkspaceAgentSubsystem) Scan(src interface{}) error { @@ -1348,7 +1349,8 @@ func (e WorkspaceAgentSubsystem) Valid() bool { switch e { case WorkspaceAgentSubsystemEnvbuilder, WorkspaceAgentSubsystemEnvbox, - WorkspaceAgentSubsystemNone: + WorkspaceAgentSubsystemNone, + WorkspaceAgentSubsystemExectrace: return true } return false @@ -1359,6 +1361,7 @@ func AllWorkspaceAgentSubsystemValues() []WorkspaceAgentSubsystem { WorkspaceAgentSubsystemEnvbuilder, WorkspaceAgentSubsystemEnvbox, WorkspaceAgentSubsystemNone, + WorkspaceAgentSubsystemExectrace, } } @@ -1944,14 +1947,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 95efcc4369..c3c9552266 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -6239,7 +6239,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 @@ -6281,17 +6281,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 @@ -6331,17 +6331,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 @@ -6383,10 +6383,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 } @@ -6506,7 +6506,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 @@ -6552,10 +6552,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 } @@ -6571,7 +6571,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) { @@ -6613,10 +6613,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 } @@ -6633,7 +6633,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 @@ -6691,10 +6691,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 } @@ -6735,7 +6735,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 { @@ -6817,10 +6817,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 } @@ -7040,16 +7040,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 { @@ -7057,7 +7057,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 4025ac7e59..dcc1508161 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 834118a0d8..615be6949d 100644 --- a/coderd/telemetry/telemetry.go +++ b/coderd/telemetry/telemetry.go @@ -544,6 +544,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, @@ -556,7 +561,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 @@ -792,7 +797,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 28569f1ca9..5592bda5db 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) @@ -98,7 +99,9 @@ func TestTelemetry(t *testing.T) { require.Len(t, snapshot.WorkspaceProxies, 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 545f3e7c6e..3fa5baf231 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 12cb19efac..b85dd9d355 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 e2189e1cc5..d5e038bdf6 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 e9aad8421e..71153a0e89 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 2316fdaafd..8bf6f10619 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 daf7958de3..782e41a6f6 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 7aed5d4f60..048eff66ad 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 @@ -913,9 +913,11 @@ _None_ #### Enumerated Values -| Value | -| -------- | -| `envbox` | +| Value | +| ------------ | +| `envbox` | +| `envbuilder` | +| `exectrace` | ## codersdk.AppHostResponse @@ -5402,7 +5404,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" @@ -5543,7 +5545,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" @@ -5585,7 +5587,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 | | | @@ -6001,7 +6003,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" @@ -6312,7 +6314,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" @@ -6524,7 +6526,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 f8a1612161..14ce5dec7d 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 6cfb468f6a..f5c4aadd72 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 3e5acc5671..c1aa96d872 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -1340,7 +1340,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 } @@ -1545,8 +1545,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 94eaa3add0..d8ed5bbe20 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, },