mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add agent timings (#14713)
* feat: begin impl of agent script timings * feat: add job_id and display_name to script timings * fix: increment migration number * fix: rename migrations from 251 to 254 * test: get tests compiling * fix: appease the linter * fix: get tests passing again * fix: drop column from correct table * test: add fixture for agent script timings * fix: typo * fix: use job id used in provisioner job timings * fix: increment migration number * test: behaviour of script runner * test: rewrite test * test: does exit 1 script break things? * test: rewrite test again * fix: revert change Not sure how this came to be, I do not recall manually changing these files. * fix: let code breathe * fix: wrap errors * fix: justify nolint * fix: swap require.Equal argument order * fix: add mutex operations * feat: add 'ran_on_start' and 'blocked_login' fields * fix: update testdata fixture * fix: refer to agent_id instead of job_id in timings * fix: JobID -> AgentID in dbauthz_test * fix: add 'id' to scripts, make timing refer to script id * fix: fix broken tests and convert bug * fix: update testdata fixtures * fix: update testdata fixtures again * feat: capture stage and if script timed out * fix: update migration number * test: add test for script api * fix: fake db query * fix: use UTC time * fix: ensure r.scriptComplete is not nil * fix: move err check to right after call * fix: uppercase sql * fix: use dbtime.Now() * fix: debug log on r.scriptCompleted being nil * fix: ensure correct rbac permissions * chore: remove DisplayName * fix: get tests passing * fix: remove space in sql up * docs: document ExecuteOption * fix: drop 'RETURNING' from sql * chore: remove 'display_name' from timing table * fix: testdata fixture * fix: put r.scriptCompleted call in goroutine * fix: track goroutine for test + use separate context for reporting * fix: appease linter, handle trackCommandGoroutine error * fix: resolve race condition * feat: replace timed_out column with status column * test: update testdata fixture * fix: apply suggestions from review * revert: linter changes
This commit is contained in:
@@ -42,6 +42,7 @@ type API struct {
|
||||
*AppsAPI
|
||||
*MetadataAPI
|
||||
*LogsAPI
|
||||
*ScriptsAPI
|
||||
*tailnet.DRPCService
|
||||
|
||||
mu sync.Mutex
|
||||
@@ -152,6 +153,10 @@ func New(opts Options) *API {
|
||||
PublishWorkspaceAgentLogsUpdateFn: opts.PublishWorkspaceAgentLogsUpdateFn,
|
||||
}
|
||||
|
||||
api.ScriptsAPI = &ScriptsAPI{
|
||||
Database: opts.Database,
|
||||
}
|
||||
|
||||
api.DRPCService = &tailnet.DRPCService{
|
||||
CoordPtr: opts.TailnetCoordinator,
|
||||
Logger: opts.Log,
|
||||
|
||||
@@ -178,6 +178,7 @@ func dbAgentScriptsToProto(scripts []database.WorkspaceAgentScript) []*agentprot
|
||||
|
||||
func dbAgentScriptToProto(script database.WorkspaceAgentScript) *agentproto.WorkspaceAgentScript {
|
||||
return &agentproto.WorkspaceAgentScript{
|
||||
Id: script.ID[:],
|
||||
LogSourceId: script.LogSourceID[:],
|
||||
LogPath: script.LogPath,
|
||||
Script: script.Script,
|
||||
|
||||
@@ -108,6 +108,7 @@ func TestGetManifest(t *testing.T) {
|
||||
}
|
||||
scripts = []database.WorkspaceAgentScript{
|
||||
{
|
||||
ID: uuid.New(),
|
||||
WorkspaceAgentID: agent.ID,
|
||||
LogSourceID: uuid.New(),
|
||||
LogPath: "/cool/log/path/1",
|
||||
@@ -119,6 +120,7 @@ func TestGetManifest(t *testing.T) {
|
||||
TimeoutSeconds: 60,
|
||||
},
|
||||
{
|
||||
ID: uuid.New(),
|
||||
WorkspaceAgentID: agent.ID,
|
||||
LogSourceID: uuid.New(),
|
||||
LogPath: "/cool/log/path/2",
|
||||
@@ -227,6 +229,7 @@ func TestGetManifest(t *testing.T) {
|
||||
}
|
||||
protoScripts = []*agentproto.WorkspaceAgentScript{
|
||||
{
|
||||
Id: scripts[0].ID[:],
|
||||
LogSourceId: scripts[0].LogSourceID[:],
|
||||
LogPath: scripts[0].LogPath,
|
||||
Script: scripts[0].Script,
|
||||
@@ -237,6 +240,7 @@ func TestGetManifest(t *testing.T) {
|
||||
Timeout: durationpb.New(time.Duration(scripts[0].TimeoutSeconds) * time.Second),
|
||||
},
|
||||
{
|
||||
Id: scripts[1].ID[:],
|
||||
LogSourceId: scripts[1].LogSourceID[:],
|
||||
LogPath: scripts[1].LogPath,
|
||||
Script: scripts[1].Script,
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package agentapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
agentproto "github.com/coder/coder/v2/agent/proto"
|
||||
"github.com/coder/coder/v2/coderd/database"
|
||||
"github.com/coder/coder/v2/coderd/database/dbauthz"
|
||||
)
|
||||
|
||||
type ScriptsAPI struct {
|
||||
Database database.Store
|
||||
}
|
||||
|
||||
func (s *ScriptsAPI) ScriptCompleted(ctx context.Context, req *agentproto.WorkspaceAgentScriptCompletedRequest) (*agentproto.WorkspaceAgentScriptCompletedResponse, error) {
|
||||
res := &agentproto.WorkspaceAgentScriptCompletedResponse{}
|
||||
|
||||
scriptID, err := uuid.FromBytes(req.Timing.ScriptId)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("script id from bytes: %w", err)
|
||||
}
|
||||
|
||||
var stage database.WorkspaceAgentScriptTimingStage
|
||||
switch req.Timing.Stage {
|
||||
case agentproto.Timing_START:
|
||||
stage = database.WorkspaceAgentScriptTimingStageStart
|
||||
case agentproto.Timing_STOP:
|
||||
stage = database.WorkspaceAgentScriptTimingStageStop
|
||||
case agentproto.Timing_CRON:
|
||||
stage = database.WorkspaceAgentScriptTimingStageCron
|
||||
}
|
||||
|
||||
var status database.WorkspaceAgentScriptTimingStatus
|
||||
switch req.Timing.Status {
|
||||
case agentproto.Timing_OK:
|
||||
status = database.WorkspaceAgentScriptTimingStatusOk
|
||||
case agentproto.Timing_EXIT_FAILURE:
|
||||
status = database.WorkspaceAgentScriptTimingStatusExitFailure
|
||||
case agentproto.Timing_TIMED_OUT:
|
||||
status = database.WorkspaceAgentScriptTimingStatusTimedOut
|
||||
case agentproto.Timing_PIPES_LEFT_OPEN:
|
||||
status = database.WorkspaceAgentScriptTimingStatusPipesLeftOpen
|
||||
}
|
||||
|
||||
//nolint:gocritic // We need permissions to write to the DB here and we are in the context of the agent.
|
||||
ctx = dbauthz.AsProvisionerd(ctx)
|
||||
err = s.Database.InsertWorkspaceAgentScriptTimings(ctx, database.InsertWorkspaceAgentScriptTimingsParams{
|
||||
ScriptID: scriptID,
|
||||
Stage: stage,
|
||||
Status: status,
|
||||
StartedAt: req.Timing.Start.AsTime(),
|
||||
EndedAt: req.Timing.End.AsTime(),
|
||||
ExitCode: req.Timing.ExitCode,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("insert workspace agent script timings into database: %w", err)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package agentapi_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"go.uber.org/mock/gomock"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
agentproto "github.com/coder/coder/v2/agent/proto"
|
||||
"github.com/coder/coder/v2/coderd/agentapi"
|
||||
"github.com/coder/coder/v2/coderd/database"
|
||||
"github.com/coder/coder/v2/coderd/database/dbmock"
|
||||
"github.com/coder/coder/v2/coderd/database/dbtime"
|
||||
)
|
||||
|
||||
func TestScriptCompleted(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
scriptID uuid.UUID
|
||||
timing *agentproto.Timing
|
||||
}{
|
||||
{
|
||||
scriptID: uuid.New(),
|
||||
timing: &agentproto.Timing{
|
||||
Stage: agentproto.Timing_START,
|
||||
Start: timestamppb.New(dbtime.Now()),
|
||||
End: timestamppb.New(dbtime.Now().Add(time.Second)),
|
||||
Status: agentproto.Timing_OK,
|
||||
ExitCode: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
scriptID: uuid.New(),
|
||||
timing: &agentproto.Timing{
|
||||
Stage: agentproto.Timing_STOP,
|
||||
Start: timestamppb.New(dbtime.Now()),
|
||||
End: timestamppb.New(dbtime.Now().Add(time.Second)),
|
||||
Status: agentproto.Timing_OK,
|
||||
ExitCode: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
scriptID: uuid.New(),
|
||||
timing: &agentproto.Timing{
|
||||
Stage: agentproto.Timing_CRON,
|
||||
Start: timestamppb.New(dbtime.Now()),
|
||||
End: timestamppb.New(dbtime.Now().Add(time.Second)),
|
||||
Status: agentproto.Timing_OK,
|
||||
ExitCode: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
scriptID: uuid.New(),
|
||||
timing: &agentproto.Timing{
|
||||
Stage: agentproto.Timing_START,
|
||||
Start: timestamppb.New(dbtime.Now()),
|
||||
End: timestamppb.New(dbtime.Now().Add(time.Second)),
|
||||
Status: agentproto.Timing_TIMED_OUT,
|
||||
ExitCode: 255,
|
||||
},
|
||||
},
|
||||
{
|
||||
scriptID: uuid.New(),
|
||||
timing: &agentproto.Timing{
|
||||
Stage: agentproto.Timing_START,
|
||||
Start: timestamppb.New(dbtime.Now()),
|
||||
End: timestamppb.New(dbtime.Now().Add(time.Second)),
|
||||
Status: agentproto.Timing_EXIT_FAILURE,
|
||||
ExitCode: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
// Setup the script ID
|
||||
tt.timing.ScriptId = tt.scriptID[:]
|
||||
|
||||
mDB := dbmock.NewMockStore(gomock.NewController(t))
|
||||
mDB.EXPECT().InsertWorkspaceAgentScriptTimings(gomock.Any(), database.InsertWorkspaceAgentScriptTimingsParams{
|
||||
ScriptID: tt.scriptID,
|
||||
Stage: protoScriptTimingStageToDatabase(tt.timing.Stage),
|
||||
Status: protoScriptTimingStatusToDatabase(tt.timing.Status),
|
||||
StartedAt: tt.timing.Start.AsTime(),
|
||||
EndedAt: tt.timing.End.AsTime(),
|
||||
ExitCode: tt.timing.ExitCode,
|
||||
})
|
||||
|
||||
api := &agentapi.ScriptsAPI{Database: mDB}
|
||||
api.ScriptCompleted(context.Background(), &agentproto.WorkspaceAgentScriptCompletedRequest{
|
||||
Timing: tt.timing,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func protoScriptTimingStageToDatabase(stage agentproto.Timing_Stage) database.WorkspaceAgentScriptTimingStage {
|
||||
var dbStage database.WorkspaceAgentScriptTimingStage
|
||||
switch stage {
|
||||
case agentproto.Timing_START:
|
||||
dbStage = database.WorkspaceAgentScriptTimingStageStart
|
||||
case agentproto.Timing_STOP:
|
||||
dbStage = database.WorkspaceAgentScriptTimingStageStop
|
||||
case agentproto.Timing_CRON:
|
||||
dbStage = database.WorkspaceAgentScriptTimingStageCron
|
||||
}
|
||||
return dbStage
|
||||
}
|
||||
|
||||
func protoScriptTimingStatusToDatabase(stage agentproto.Timing_Status) database.WorkspaceAgentScriptTimingStatus {
|
||||
var dbStatus database.WorkspaceAgentScriptTimingStatus
|
||||
switch stage {
|
||||
case agentproto.Timing_OK:
|
||||
dbStatus = database.WorkspaceAgentScriptTimingStatusOk
|
||||
case agentproto.Timing_EXIT_FAILURE:
|
||||
dbStatus = database.WorkspaceAgentScriptTimingStatusExitFailure
|
||||
case agentproto.Timing_TIMED_OUT:
|
||||
dbStatus = database.WorkspaceAgentScriptTimingStatusTimedOut
|
||||
case agentproto.Timing_PIPES_LEFT_OPEN:
|
||||
dbStatus = database.WorkspaceAgentScriptTimingStatusPipesLeftOpen
|
||||
}
|
||||
return dbStatus
|
||||
}
|
||||
Generated
+4
@@ -14263,6 +14263,10 @@ const docTemplate = `{
|
||||
"display_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"log_path": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
Generated
+4
@@ -12989,6 +12989,10 @@
|
||||
"display_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"log_path": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -3027,6 +3027,13 @@ func (q *querier) InsertWorkspaceAgentMetadata(ctx context.Context, arg database
|
||||
return q.db.InsertWorkspaceAgentMetadata(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) InsertWorkspaceAgentScriptTimings(ctx context.Context, arg database.InsertWorkspaceAgentScriptTimingsParams) error {
|
||||
if err := q.authorizeContext(ctx, policy.ActionCreate, rbac.ResourceSystem); err != nil {
|
||||
return err
|
||||
}
|
||||
return q.db.InsertWorkspaceAgentScriptTimings(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) InsertWorkspaceAgentScripts(ctx context.Context, arg database.InsertWorkspaceAgentScriptsParams) ([]database.WorkspaceAgentScript, error) {
|
||||
if err := q.authorizeContext(ctx, policy.ActionCreate, rbac.ResourceSystem); err != nil {
|
||||
return []database.WorkspaceAgentScript{}, err
|
||||
|
||||
@@ -2632,6 +2632,13 @@ func (s *MethodTestSuite) TestSystemFunctions() {
|
||||
s.Run("InsertWorkspaceAppStats", s.Subtest(func(db database.Store, check *expects) {
|
||||
check.Args(database.InsertWorkspaceAppStatsParams{}).Asserts(rbac.ResourceSystem, policy.ActionCreate)
|
||||
}))
|
||||
s.Run("InsertWorkspaceAgentScriptTimings", s.Subtest(func(db database.Store, check *expects) {
|
||||
check.Args(database.InsertWorkspaceAgentScriptTimingsParams{
|
||||
ScriptID: uuid.New(),
|
||||
Stage: database.WorkspaceAgentScriptTimingStageStart,
|
||||
Status: database.WorkspaceAgentScriptTimingStatusOk,
|
||||
}).Asserts(rbac.ResourceSystem, policy.ActionCreate)
|
||||
}))
|
||||
s.Run("InsertWorkspaceAgentScripts", s.Subtest(func(db database.Store, check *expects) {
|
||||
check.Args(database.InsertWorkspaceAgentScriptsParams{}).Asserts(rbac.ResourceSystem, policy.ActionCreate)
|
||||
}))
|
||||
|
||||
@@ -222,6 +222,7 @@ type data struct {
|
||||
workspaceAgentLogs []database.WorkspaceAgentLog
|
||||
workspaceAgentLogSources []database.WorkspaceAgentLogSource
|
||||
workspaceAgentPortShares []database.WorkspaceAgentPortShare
|
||||
workspaceAgentScriptTimings []database.WorkspaceAgentScriptTiming
|
||||
workspaceAgentScripts []database.WorkspaceAgentScript
|
||||
workspaceAgentStats []database.WorkspaceAgentStat
|
||||
workspaceApps []database.WorkspaceApp
|
||||
@@ -7826,6 +7827,30 @@ func (q *FakeQuerier) InsertWorkspaceAgentMetadata(_ context.Context, arg databa
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) InsertWorkspaceAgentScriptTimings(_ context.Context, arg database.InsertWorkspaceAgentScriptTimingsParams) error {
|
||||
err := validateDatabaseType(arg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
|
||||
q.workspaceAgentScriptTimings = append(q.workspaceAgentScriptTimings,
|
||||
//nolint:gosimple // Stop the linter complaining about changing the type of `arg`.
|
||||
database.WorkspaceAgentScriptTiming{
|
||||
ScriptID: arg.ScriptID,
|
||||
StartedAt: arg.StartedAt,
|
||||
EndedAt: arg.EndedAt,
|
||||
ExitCode: arg.ExitCode,
|
||||
Stage: arg.Stage,
|
||||
Status: arg.Status,
|
||||
},
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) InsertWorkspaceAgentScripts(_ context.Context, arg database.InsertWorkspaceAgentScriptsParams) ([]database.WorkspaceAgentScript, error) {
|
||||
err := validateDatabaseType(arg)
|
||||
if err != nil {
|
||||
@@ -7840,6 +7865,7 @@ func (q *FakeQuerier) InsertWorkspaceAgentScripts(_ context.Context, arg databas
|
||||
script := database.WorkspaceAgentScript{
|
||||
LogSourceID: source,
|
||||
WorkspaceAgentID: arg.WorkspaceAgentID,
|
||||
ID: arg.ID[index],
|
||||
LogPath: arg.LogPath[index],
|
||||
Script: arg.Script[index],
|
||||
Cron: arg.Cron[index],
|
||||
|
||||
@@ -1929,6 +1929,13 @@ func (m metricsStore) InsertWorkspaceAgentMetadata(ctx context.Context, arg data
|
||||
return err
|
||||
}
|
||||
|
||||
func (m metricsStore) InsertWorkspaceAgentScriptTimings(ctx context.Context, arg database.InsertWorkspaceAgentScriptTimingsParams) error {
|
||||
start := time.Now()
|
||||
err := m.s.InsertWorkspaceAgentScriptTimings(ctx, arg)
|
||||
m.queryLatencies.WithLabelValues("InsertWorkspaceAgentScriptTimings").Observe(time.Since(start).Seconds())
|
||||
return err
|
||||
}
|
||||
|
||||
func (m metricsStore) InsertWorkspaceAgentScripts(ctx context.Context, arg database.InsertWorkspaceAgentScriptsParams) ([]database.WorkspaceAgentScript, error) {
|
||||
start := time.Now()
|
||||
r0, r1 := m.s.InsertWorkspaceAgentScripts(ctx, arg)
|
||||
|
||||
@@ -4064,6 +4064,20 @@ func (mr *MockStoreMockRecorder) InsertWorkspaceAgentMetadata(arg0, arg1 any) *g
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertWorkspaceAgentMetadata", reflect.TypeOf((*MockStore)(nil).InsertWorkspaceAgentMetadata), arg0, arg1)
|
||||
}
|
||||
|
||||
// InsertWorkspaceAgentScriptTimings mocks base method.
|
||||
func (m *MockStore) InsertWorkspaceAgentScriptTimings(arg0 context.Context, arg1 database.InsertWorkspaceAgentScriptTimingsParams) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "InsertWorkspaceAgentScriptTimings", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// InsertWorkspaceAgentScriptTimings indicates an expected call of InsertWorkspaceAgentScriptTimings.
|
||||
func (mr *MockStoreMockRecorder) InsertWorkspaceAgentScriptTimings(arg0, arg1 any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertWorkspaceAgentScriptTimings", reflect.TypeOf((*MockStore)(nil).InsertWorkspaceAgentScriptTimings), arg0, arg1)
|
||||
}
|
||||
|
||||
// InsertWorkspaceAgentScripts mocks base method.
|
||||
func (m *MockStore) InsertWorkspaceAgentScripts(arg0 context.Context, arg1 database.InsertWorkspaceAgentScriptsParams) ([]database.WorkspaceAgentScript, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
Generated
+37
-1
@@ -216,6 +216,23 @@ CREATE TYPE workspace_agent_lifecycle_state AS ENUM (
|
||||
'off'
|
||||
);
|
||||
|
||||
CREATE TYPE workspace_agent_script_timing_stage AS ENUM (
|
||||
'start',
|
||||
'stop',
|
||||
'cron'
|
||||
);
|
||||
|
||||
COMMENT ON TYPE workspace_agent_script_timing_stage IS 'What stage the script was ran in.';
|
||||
|
||||
CREATE TYPE workspace_agent_script_timing_status AS ENUM (
|
||||
'ok',
|
||||
'exit_failure',
|
||||
'timed_out',
|
||||
'pipes_left_open'
|
||||
);
|
||||
|
||||
COMMENT ON TYPE workspace_agent_script_timing_status IS 'What the exit status of the script is.';
|
||||
|
||||
CREATE TYPE workspace_agent_subsystem AS ENUM (
|
||||
'envbuilder',
|
||||
'envbox',
|
||||
@@ -1355,6 +1372,15 @@ CREATE TABLE workspace_agent_port_share (
|
||||
protocol port_share_protocol DEFAULT 'http'::port_share_protocol NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE workspace_agent_script_timings (
|
||||
script_id uuid NOT NULL,
|
||||
started_at timestamp with time zone NOT NULL,
|
||||
ended_at timestamp with time zone NOT NULL,
|
||||
exit_code integer NOT NULL,
|
||||
stage workspace_agent_script_timing_stage NOT NULL,
|
||||
status workspace_agent_script_timing_status NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE workspace_agent_scripts (
|
||||
workspace_agent_id uuid NOT NULL,
|
||||
log_source_id uuid NOT NULL,
|
||||
@@ -1366,7 +1392,8 @@ CREATE TABLE workspace_agent_scripts (
|
||||
run_on_start boolean NOT NULL,
|
||||
run_on_stop boolean NOT NULL,
|
||||
timeout_seconds integer NOT NULL,
|
||||
display_name text NOT NULL
|
||||
display_name text NOT NULL,
|
||||
id uuid DEFAULT gen_random_uuid() NOT NULL
|
||||
);
|
||||
|
||||
CREATE SEQUENCE workspace_agent_startup_logs_id_seq
|
||||
@@ -1858,6 +1885,12 @@ ALTER TABLE ONLY workspace_agent_metadata
|
||||
ALTER TABLE ONLY workspace_agent_port_share
|
||||
ADD CONSTRAINT workspace_agent_port_share_pkey PRIMARY KEY (workspace_id, agent_name, port);
|
||||
|
||||
ALTER TABLE ONLY workspace_agent_script_timings
|
||||
ADD CONSTRAINT workspace_agent_script_timings_script_id_started_at_key UNIQUE (script_id, started_at);
|
||||
|
||||
ALTER TABLE ONLY workspace_agent_scripts
|
||||
ADD CONSTRAINT workspace_agent_scripts_id_key UNIQUE (id);
|
||||
|
||||
ALTER TABLE ONLY workspace_agent_logs
|
||||
ADD CONSTRAINT workspace_agent_startup_logs_pkey PRIMARY KEY (id);
|
||||
|
||||
@@ -2225,6 +2258,9 @@ ALTER TABLE ONLY workspace_agent_metadata
|
||||
ALTER TABLE ONLY workspace_agent_port_share
|
||||
ADD CONSTRAINT workspace_agent_port_share_workspace_id_fkey FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY workspace_agent_script_timings
|
||||
ADD CONSTRAINT workspace_agent_script_timings_script_id_fkey FOREIGN KEY (script_id) REFERENCES workspace_agent_scripts(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY workspace_agent_scripts
|
||||
ADD CONSTRAINT workspace_agent_scripts_workspace_agent_id_fkey FOREIGN KEY (workspace_agent_id) REFERENCES workspace_agents(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ const (
|
||||
ForeignKeyWorkspaceAgentLogSourcesWorkspaceAgentID ForeignKeyConstraint = "workspace_agent_log_sources_workspace_agent_id_fkey" // ALTER TABLE ONLY workspace_agent_log_sources ADD CONSTRAINT workspace_agent_log_sources_workspace_agent_id_fkey FOREIGN KEY (workspace_agent_id) REFERENCES workspace_agents(id) ON DELETE CASCADE;
|
||||
ForeignKeyWorkspaceAgentMetadataWorkspaceAgentID ForeignKeyConstraint = "workspace_agent_metadata_workspace_agent_id_fkey" // ALTER TABLE ONLY workspace_agent_metadata ADD CONSTRAINT workspace_agent_metadata_workspace_agent_id_fkey FOREIGN KEY (workspace_agent_id) REFERENCES workspace_agents(id) ON DELETE CASCADE;
|
||||
ForeignKeyWorkspaceAgentPortShareWorkspaceID ForeignKeyConstraint = "workspace_agent_port_share_workspace_id_fkey" // ALTER TABLE ONLY workspace_agent_port_share ADD CONSTRAINT workspace_agent_port_share_workspace_id_fkey FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE CASCADE;
|
||||
ForeignKeyWorkspaceAgentScriptTimingsScriptID ForeignKeyConstraint = "workspace_agent_script_timings_script_id_fkey" // ALTER TABLE ONLY workspace_agent_script_timings ADD CONSTRAINT workspace_agent_script_timings_script_id_fkey FOREIGN KEY (script_id) REFERENCES workspace_agent_scripts(id) ON DELETE CASCADE;
|
||||
ForeignKeyWorkspaceAgentScriptsWorkspaceAgentID ForeignKeyConstraint = "workspace_agent_scripts_workspace_agent_id_fkey" // ALTER TABLE ONLY workspace_agent_scripts ADD CONSTRAINT workspace_agent_scripts_workspace_agent_id_fkey FOREIGN KEY (workspace_agent_id) REFERENCES workspace_agents(id) ON DELETE CASCADE;
|
||||
ForeignKeyWorkspaceAgentStartupLogsAgentID ForeignKeyConstraint = "workspace_agent_startup_logs_agent_id_fkey" // ALTER TABLE ONLY workspace_agent_logs ADD CONSTRAINT workspace_agent_startup_logs_agent_id_fkey FOREIGN KEY (agent_id) REFERENCES workspace_agents(id) ON DELETE CASCADE;
|
||||
ForeignKeyWorkspaceAgentsResourceID ForeignKeyConstraint = "workspace_agents_resource_id_fkey" // ALTER TABLE ONLY workspace_agents ADD CONSTRAINT workspace_agents_resource_id_fkey FOREIGN KEY (resource_id) REFERENCES workspace_resources(id) ON DELETE CASCADE;
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
DROP TYPE IF EXISTS workspace_agent_script_timing_status CASCADE;
|
||||
DROP TYPE IF EXISTS workspace_agent_script_timing_stage CASCADE;
|
||||
DROP TABLE IF EXISTS workspace_agent_script_timings;
|
||||
|
||||
ALTER TABLE workspace_agent_scripts DROP COLUMN id;
|
||||
@@ -0,0 +1,31 @@
|
||||
ALTER TABLE workspace_agent_scripts ADD COLUMN id uuid UNIQUE NOT NULL DEFAULT gen_random_uuid();
|
||||
|
||||
CREATE TYPE workspace_agent_script_timing_stage AS ENUM (
|
||||
'start',
|
||||
'stop',
|
||||
'cron'
|
||||
);
|
||||
|
||||
COMMENT ON TYPE workspace_agent_script_timing_stage IS 'What stage the script was ran in.';
|
||||
|
||||
CREATE TYPE workspace_agent_script_timing_status AS ENUM (
|
||||
'ok',
|
||||
'exit_failure',
|
||||
'timed_out',
|
||||
'pipes_left_open'
|
||||
);
|
||||
|
||||
COMMENT ON TYPE workspace_agent_script_timing_status IS 'What the exit status of the script is.';
|
||||
|
||||
CREATE TABLE workspace_agent_script_timings
|
||||
(
|
||||
script_id uuid NOT NULL REFERENCES workspace_agent_scripts (id) ON DELETE CASCADE,
|
||||
started_at timestamp with time zone NOT NULL,
|
||||
ended_at timestamp with time zone NOT NULL,
|
||||
exit_code int NOT NULL,
|
||||
stage workspace_agent_script_timing_stage NOT NULL,
|
||||
status workspace_agent_script_timing_status NOT NULL,
|
||||
UNIQUE (script_id, started_at)
|
||||
);
|
||||
|
||||
COMMENT ON TYPE workspace_agent_script_timings IS 'Timing and execution information about a script run.';
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
INSERT INTO workspace_agent_script_timings (script_id, started_at, ended_at, exit_code, stage, status)
|
||||
VALUES
|
||||
((SELECT id FROM workspace_agent_scripts LIMIT 1), NOW() - INTERVAL '1 hour 55 minutes', NOW() - INTERVAL '1 hour 50 minutes', 0, 'start', 'ok');
|
||||
@@ -1881,6 +1881,133 @@ func AllWorkspaceAgentLifecycleStateValues() []WorkspaceAgentLifecycleState {
|
||||
}
|
||||
}
|
||||
|
||||
// What stage the script was ran in.
|
||||
type WorkspaceAgentScriptTimingStage string
|
||||
|
||||
const (
|
||||
WorkspaceAgentScriptTimingStageStart WorkspaceAgentScriptTimingStage = "start"
|
||||
WorkspaceAgentScriptTimingStageStop WorkspaceAgentScriptTimingStage = "stop"
|
||||
WorkspaceAgentScriptTimingStageCron WorkspaceAgentScriptTimingStage = "cron"
|
||||
)
|
||||
|
||||
func (e *WorkspaceAgentScriptTimingStage) Scan(src interface{}) error {
|
||||
switch s := src.(type) {
|
||||
case []byte:
|
||||
*e = WorkspaceAgentScriptTimingStage(s)
|
||||
case string:
|
||||
*e = WorkspaceAgentScriptTimingStage(s)
|
||||
default:
|
||||
return fmt.Errorf("unsupported scan type for WorkspaceAgentScriptTimingStage: %T", src)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type NullWorkspaceAgentScriptTimingStage struct {
|
||||
WorkspaceAgentScriptTimingStage WorkspaceAgentScriptTimingStage `json:"workspace_agent_script_timing_stage"`
|
||||
Valid bool `json:"valid"` // Valid is true if WorkspaceAgentScriptTimingStage is not NULL
|
||||
}
|
||||
|
||||
// Scan implements the Scanner interface.
|
||||
func (ns *NullWorkspaceAgentScriptTimingStage) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
ns.WorkspaceAgentScriptTimingStage, ns.Valid = "", false
|
||||
return nil
|
||||
}
|
||||
ns.Valid = true
|
||||
return ns.WorkspaceAgentScriptTimingStage.Scan(value)
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (ns NullWorkspaceAgentScriptTimingStage) Value() (driver.Value, error) {
|
||||
if !ns.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return string(ns.WorkspaceAgentScriptTimingStage), nil
|
||||
}
|
||||
|
||||
func (e WorkspaceAgentScriptTimingStage) Valid() bool {
|
||||
switch e {
|
||||
case WorkspaceAgentScriptTimingStageStart,
|
||||
WorkspaceAgentScriptTimingStageStop,
|
||||
WorkspaceAgentScriptTimingStageCron:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func AllWorkspaceAgentScriptTimingStageValues() []WorkspaceAgentScriptTimingStage {
|
||||
return []WorkspaceAgentScriptTimingStage{
|
||||
WorkspaceAgentScriptTimingStageStart,
|
||||
WorkspaceAgentScriptTimingStageStop,
|
||||
WorkspaceAgentScriptTimingStageCron,
|
||||
}
|
||||
}
|
||||
|
||||
// What the exit status of the script is.
|
||||
type WorkspaceAgentScriptTimingStatus string
|
||||
|
||||
const (
|
||||
WorkspaceAgentScriptTimingStatusOk WorkspaceAgentScriptTimingStatus = "ok"
|
||||
WorkspaceAgentScriptTimingStatusExitFailure WorkspaceAgentScriptTimingStatus = "exit_failure"
|
||||
WorkspaceAgentScriptTimingStatusTimedOut WorkspaceAgentScriptTimingStatus = "timed_out"
|
||||
WorkspaceAgentScriptTimingStatusPipesLeftOpen WorkspaceAgentScriptTimingStatus = "pipes_left_open"
|
||||
)
|
||||
|
||||
func (e *WorkspaceAgentScriptTimingStatus) Scan(src interface{}) error {
|
||||
switch s := src.(type) {
|
||||
case []byte:
|
||||
*e = WorkspaceAgentScriptTimingStatus(s)
|
||||
case string:
|
||||
*e = WorkspaceAgentScriptTimingStatus(s)
|
||||
default:
|
||||
return fmt.Errorf("unsupported scan type for WorkspaceAgentScriptTimingStatus: %T", src)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type NullWorkspaceAgentScriptTimingStatus struct {
|
||||
WorkspaceAgentScriptTimingStatus WorkspaceAgentScriptTimingStatus `json:"workspace_agent_script_timing_status"`
|
||||
Valid bool `json:"valid"` // Valid is true if WorkspaceAgentScriptTimingStatus is not NULL
|
||||
}
|
||||
|
||||
// Scan implements the Scanner interface.
|
||||
func (ns *NullWorkspaceAgentScriptTimingStatus) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
ns.WorkspaceAgentScriptTimingStatus, ns.Valid = "", false
|
||||
return nil
|
||||
}
|
||||
ns.Valid = true
|
||||
return ns.WorkspaceAgentScriptTimingStatus.Scan(value)
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (ns NullWorkspaceAgentScriptTimingStatus) Value() (driver.Value, error) {
|
||||
if !ns.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return string(ns.WorkspaceAgentScriptTimingStatus), nil
|
||||
}
|
||||
|
||||
func (e WorkspaceAgentScriptTimingStatus) Valid() bool {
|
||||
switch e {
|
||||
case WorkspaceAgentScriptTimingStatusOk,
|
||||
WorkspaceAgentScriptTimingStatusExitFailure,
|
||||
WorkspaceAgentScriptTimingStatusTimedOut,
|
||||
WorkspaceAgentScriptTimingStatusPipesLeftOpen:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func AllWorkspaceAgentScriptTimingStatusValues() []WorkspaceAgentScriptTimingStatus {
|
||||
return []WorkspaceAgentScriptTimingStatus{
|
||||
WorkspaceAgentScriptTimingStatusOk,
|
||||
WorkspaceAgentScriptTimingStatusExitFailure,
|
||||
WorkspaceAgentScriptTimingStatusTimedOut,
|
||||
WorkspaceAgentScriptTimingStatusPipesLeftOpen,
|
||||
}
|
||||
}
|
||||
|
||||
type WorkspaceAgentSubsystem string
|
||||
|
||||
const (
|
||||
@@ -2881,6 +3008,16 @@ type WorkspaceAgentScript struct {
|
||||
RunOnStop bool `db:"run_on_stop" json:"run_on_stop"`
|
||||
TimeoutSeconds int32 `db:"timeout_seconds" json:"timeout_seconds"`
|
||||
DisplayName string `db:"display_name" json:"display_name"`
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
}
|
||||
|
||||
type WorkspaceAgentScriptTiming struct {
|
||||
ScriptID uuid.UUID `db:"script_id" json:"script_id"`
|
||||
StartedAt time.Time `db:"started_at" json:"started_at"`
|
||||
EndedAt time.Time `db:"ended_at" json:"ended_at"`
|
||||
ExitCode int32 `db:"exit_code" json:"exit_code"`
|
||||
Stage WorkspaceAgentScriptTimingStage `db:"stage" json:"stage"`
|
||||
Status WorkspaceAgentScriptTimingStatus `db:"status" json:"status"`
|
||||
}
|
||||
|
||||
type WorkspaceAgentStat struct {
|
||||
|
||||
@@ -394,6 +394,7 @@ type sqlcQuerier interface {
|
||||
InsertWorkspaceAgentLogSources(ctx context.Context, arg InsertWorkspaceAgentLogSourcesParams) ([]WorkspaceAgentLogSource, error)
|
||||
InsertWorkspaceAgentLogs(ctx context.Context, arg InsertWorkspaceAgentLogsParams) ([]WorkspaceAgentLog, error)
|
||||
InsertWorkspaceAgentMetadata(ctx context.Context, arg InsertWorkspaceAgentMetadataParams) error
|
||||
InsertWorkspaceAgentScriptTimings(ctx context.Context, arg InsertWorkspaceAgentScriptTimingsParams) error
|
||||
InsertWorkspaceAgentScripts(ctx context.Context, arg InsertWorkspaceAgentScriptsParams) ([]WorkspaceAgentScript, error)
|
||||
InsertWorkspaceAgentStats(ctx context.Context, arg InsertWorkspaceAgentStatsParams) error
|
||||
InsertWorkspaceApp(ctx context.Context, arg InsertWorkspaceAppParams) (WorkspaceApp, error)
|
||||
|
||||
@@ -11802,6 +11802,41 @@ func (q *sqlQuerier) InsertWorkspaceAgentMetadata(ctx context.Context, arg Inser
|
||||
return err
|
||||
}
|
||||
|
||||
const insertWorkspaceAgentScriptTimings = `-- name: InsertWorkspaceAgentScriptTimings :exec
|
||||
INSERT INTO
|
||||
workspace_agent_script_timings (
|
||||
script_id,
|
||||
started_at,
|
||||
ended_at,
|
||||
exit_code,
|
||||
stage,
|
||||
status
|
||||
)
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5, $6)
|
||||
`
|
||||
|
||||
type InsertWorkspaceAgentScriptTimingsParams struct {
|
||||
ScriptID uuid.UUID `db:"script_id" json:"script_id"`
|
||||
StartedAt time.Time `db:"started_at" json:"started_at"`
|
||||
EndedAt time.Time `db:"ended_at" json:"ended_at"`
|
||||
ExitCode int32 `db:"exit_code" json:"exit_code"`
|
||||
Stage WorkspaceAgentScriptTimingStage `db:"stage" json:"stage"`
|
||||
Status WorkspaceAgentScriptTimingStatus `db:"status" json:"status"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) InsertWorkspaceAgentScriptTimings(ctx context.Context, arg InsertWorkspaceAgentScriptTimingsParams) error {
|
||||
_, err := q.db.ExecContext(ctx, insertWorkspaceAgentScriptTimings,
|
||||
arg.ScriptID,
|
||||
arg.StartedAt,
|
||||
arg.EndedAt,
|
||||
arg.ExitCode,
|
||||
arg.Stage,
|
||||
arg.Status,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
const updateWorkspaceAgentConnectionByID = `-- name: UpdateWorkspaceAgentConnectionByID :exec
|
||||
UPDATE
|
||||
workspace_agents
|
||||
@@ -15492,7 +15527,7 @@ func (q *sqlQuerier) UpdateWorkspacesDormantDeletingAtByTemplateID(ctx context.C
|
||||
}
|
||||
|
||||
const getWorkspaceAgentScriptsByAgentIDs = `-- name: GetWorkspaceAgentScriptsByAgentIDs :many
|
||||
SELECT workspace_agent_id, log_source_id, log_path, created_at, script, cron, start_blocks_login, run_on_start, run_on_stop, timeout_seconds, display_name FROM workspace_agent_scripts WHERE workspace_agent_id = ANY($1 :: uuid [ ])
|
||||
SELECT workspace_agent_id, log_source_id, log_path, created_at, script, cron, start_blocks_login, run_on_start, run_on_stop, timeout_seconds, display_name, id FROM workspace_agent_scripts WHERE workspace_agent_id = ANY($1 :: uuid [ ])
|
||||
`
|
||||
|
||||
func (q *sqlQuerier) GetWorkspaceAgentScriptsByAgentIDs(ctx context.Context, ids []uuid.UUID) ([]WorkspaceAgentScript, error) {
|
||||
@@ -15516,6 +15551,7 @@ func (q *sqlQuerier) GetWorkspaceAgentScriptsByAgentIDs(ctx context.Context, ids
|
||||
&i.RunOnStop,
|
||||
&i.TimeoutSeconds,
|
||||
&i.DisplayName,
|
||||
&i.ID,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -15532,7 +15568,7 @@ func (q *sqlQuerier) GetWorkspaceAgentScriptsByAgentIDs(ctx context.Context, ids
|
||||
|
||||
const insertWorkspaceAgentScripts = `-- name: InsertWorkspaceAgentScripts :many
|
||||
INSERT INTO
|
||||
workspace_agent_scripts (workspace_agent_id, created_at, log_source_id, log_path, script, cron, start_blocks_login, run_on_start, run_on_stop, timeout_seconds, display_name)
|
||||
workspace_agent_scripts (workspace_agent_id, created_at, log_source_id, log_path, script, cron, start_blocks_login, run_on_start, run_on_stop, timeout_seconds, display_name, id)
|
||||
SELECT
|
||||
$1 :: uuid AS workspace_agent_id,
|
||||
$2 :: timestamptz AS created_at,
|
||||
@@ -15544,8 +15580,9 @@ SELECT
|
||||
unnest($8 :: boolean [ ]) AS run_on_start,
|
||||
unnest($9 :: boolean [ ]) AS run_on_stop,
|
||||
unnest($10 :: integer [ ]) AS timeout_seconds,
|
||||
unnest($11 :: text [ ]) AS display_name
|
||||
RETURNING workspace_agent_scripts.workspace_agent_id, workspace_agent_scripts.log_source_id, workspace_agent_scripts.log_path, workspace_agent_scripts.created_at, workspace_agent_scripts.script, workspace_agent_scripts.cron, workspace_agent_scripts.start_blocks_login, workspace_agent_scripts.run_on_start, workspace_agent_scripts.run_on_stop, workspace_agent_scripts.timeout_seconds, workspace_agent_scripts.display_name
|
||||
unnest($11 :: text [ ]) AS display_name,
|
||||
unnest($12 :: uuid [ ]) AS id
|
||||
RETURNING workspace_agent_scripts.workspace_agent_id, workspace_agent_scripts.log_source_id, workspace_agent_scripts.log_path, workspace_agent_scripts.created_at, workspace_agent_scripts.script, workspace_agent_scripts.cron, workspace_agent_scripts.start_blocks_login, workspace_agent_scripts.run_on_start, workspace_agent_scripts.run_on_stop, workspace_agent_scripts.timeout_seconds, workspace_agent_scripts.display_name, workspace_agent_scripts.id
|
||||
`
|
||||
|
||||
type InsertWorkspaceAgentScriptsParams struct {
|
||||
@@ -15560,6 +15597,7 @@ type InsertWorkspaceAgentScriptsParams struct {
|
||||
RunOnStop []bool `db:"run_on_stop" json:"run_on_stop"`
|
||||
TimeoutSeconds []int32 `db:"timeout_seconds" json:"timeout_seconds"`
|
||||
DisplayName []string `db:"display_name" json:"display_name"`
|
||||
ID []uuid.UUID `db:"id" json:"id"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) InsertWorkspaceAgentScripts(ctx context.Context, arg InsertWorkspaceAgentScriptsParams) ([]WorkspaceAgentScript, error) {
|
||||
@@ -15575,6 +15613,7 @@ func (q *sqlQuerier) InsertWorkspaceAgentScripts(ctx context.Context, arg Insert
|
||||
pq.Array(arg.RunOnStop),
|
||||
pq.Array(arg.TimeoutSeconds),
|
||||
pq.Array(arg.DisplayName),
|
||||
pq.Array(arg.ID),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -15595,6 +15634,7 @@ func (q *sqlQuerier) InsertWorkspaceAgentScripts(ctx context.Context, arg Insert
|
||||
&i.RunOnStop,
|
||||
&i.TimeoutSeconds,
|
||||
&i.DisplayName,
|
||||
&i.ID,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -287,3 +287,16 @@ WHERE
|
||||
workspace_id = workspace_build_with_user.workspace_id
|
||||
)
|
||||
;
|
||||
|
||||
-- name: InsertWorkspaceAgentScriptTimings :exec
|
||||
INSERT INTO
|
||||
workspace_agent_script_timings (
|
||||
script_id,
|
||||
started_at,
|
||||
ended_at,
|
||||
exit_code,
|
||||
stage,
|
||||
status
|
||||
)
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5, $6);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
-- name: InsertWorkspaceAgentScripts :many
|
||||
INSERT INTO
|
||||
workspace_agent_scripts (workspace_agent_id, created_at, log_source_id, log_path, script, cron, start_blocks_login, run_on_start, run_on_stop, timeout_seconds, display_name)
|
||||
workspace_agent_scripts (workspace_agent_id, created_at, log_source_id, log_path, script, cron, start_blocks_login, run_on_start, run_on_stop, timeout_seconds, display_name, id)
|
||||
SELECT
|
||||
@workspace_agent_id :: uuid AS workspace_agent_id,
|
||||
@created_at :: timestamptz AS created_at,
|
||||
@@ -12,7 +12,8 @@ SELECT
|
||||
unnest(@run_on_start :: boolean [ ]) AS run_on_start,
|
||||
unnest(@run_on_stop :: boolean [ ]) AS run_on_stop,
|
||||
unnest(@timeout_seconds :: integer [ ]) AS timeout_seconds,
|
||||
unnest(@display_name :: text [ ]) AS display_name
|
||||
unnest(@display_name :: text [ ]) AS display_name,
|
||||
unnest(@id :: uuid [ ]) AS id
|
||||
RETURNING workspace_agent_scripts.*;
|
||||
|
||||
-- name: GetWorkspaceAgentScriptsByAgentIDs :many
|
||||
|
||||
@@ -67,6 +67,8 @@ const (
|
||||
UniqueWorkspaceAgentLogSourcesPkey UniqueConstraint = "workspace_agent_log_sources_pkey" // ALTER TABLE ONLY workspace_agent_log_sources ADD CONSTRAINT workspace_agent_log_sources_pkey PRIMARY KEY (workspace_agent_id, id);
|
||||
UniqueWorkspaceAgentMetadataPkey UniqueConstraint = "workspace_agent_metadata_pkey" // ALTER TABLE ONLY workspace_agent_metadata ADD CONSTRAINT workspace_agent_metadata_pkey PRIMARY KEY (workspace_agent_id, key);
|
||||
UniqueWorkspaceAgentPortSharePkey UniqueConstraint = "workspace_agent_port_share_pkey" // ALTER TABLE ONLY workspace_agent_port_share ADD CONSTRAINT workspace_agent_port_share_pkey PRIMARY KEY (workspace_id, agent_name, port);
|
||||
UniqueWorkspaceAgentScriptTimingsScriptIDStartedAtKey UniqueConstraint = "workspace_agent_script_timings_script_id_started_at_key" // ALTER TABLE ONLY workspace_agent_script_timings ADD CONSTRAINT workspace_agent_script_timings_script_id_started_at_key UNIQUE (script_id, started_at);
|
||||
UniqueWorkspaceAgentScriptsIDKey UniqueConstraint = "workspace_agent_scripts_id_key" // ALTER TABLE ONLY workspace_agent_scripts ADD CONSTRAINT workspace_agent_scripts_id_key UNIQUE (id);
|
||||
UniqueWorkspaceAgentStartupLogsPkey UniqueConstraint = "workspace_agent_startup_logs_pkey" // ALTER TABLE ONLY workspace_agent_logs ADD CONSTRAINT workspace_agent_startup_logs_pkey PRIMARY KEY (id);
|
||||
UniqueWorkspaceAgentsPkey UniqueConstraint = "workspace_agents_pkey" // ALTER TABLE ONLY workspace_agents ADD CONSTRAINT workspace_agents_pkey PRIMARY KEY (id);
|
||||
UniqueWorkspaceAppStatsPkey UniqueConstraint = "workspace_app_stats_pkey" // ALTER TABLE ONLY workspace_app_stats ADD CONSTRAINT workspace_app_stats_pkey PRIMARY KEY (id);
|
||||
|
||||
@@ -1818,6 +1818,7 @@ func InsertWorkspaceResource(ctx context.Context, db database.Store, jobID uuid.
|
||||
logSourceIDs := make([]uuid.UUID, 0, len(prAgent.Scripts))
|
||||
logSourceDisplayNames := make([]string, 0, len(prAgent.Scripts))
|
||||
logSourceIcons := make([]string, 0, len(prAgent.Scripts))
|
||||
scriptIDs := make([]uuid.UUID, 0, len(prAgent.Scripts))
|
||||
scriptDisplayName := make([]string, 0, len(prAgent.Scripts))
|
||||
scriptLogPaths := make([]string, 0, len(prAgent.Scripts))
|
||||
scriptSources := make([]string, 0, len(prAgent.Scripts))
|
||||
@@ -1831,6 +1832,7 @@ func InsertWorkspaceResource(ctx context.Context, db database.Store, jobID uuid.
|
||||
logSourceIDs = append(logSourceIDs, uuid.New())
|
||||
logSourceDisplayNames = append(logSourceDisplayNames, script.DisplayName)
|
||||
logSourceIcons = append(logSourceIcons, script.Icon)
|
||||
scriptIDs = append(scriptIDs, uuid.New())
|
||||
scriptDisplayName = append(scriptDisplayName, script.DisplayName)
|
||||
scriptLogPaths = append(scriptLogPaths, script.LogPath)
|
||||
scriptSources = append(scriptSources, script.Script)
|
||||
@@ -1864,6 +1866,7 @@ func InsertWorkspaceResource(ctx context.Context, db database.Store, jobID uuid.
|
||||
RunOnStart: scriptRunOnStart,
|
||||
RunOnStop: scriptRunOnStop,
|
||||
DisplayName: scriptDisplayName,
|
||||
ID: scriptIDs,
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("insert agent scripts: %w", err)
|
||||
|
||||
@@ -969,6 +969,7 @@ func convertScripts(dbScripts []database.WorkspaceAgentScript) []codersdk.Worksp
|
||||
scripts := make([]codersdk.WorkspaceAgentScript, 0)
|
||||
for _, dbScript := range dbScripts {
|
||||
scripts = append(scripts, codersdk.WorkspaceAgentScript{
|
||||
ID: dbScript.ID,
|
||||
LogPath: dbScript.LogPath,
|
||||
LogSourceID: dbScript.LogSourceID,
|
||||
Script: dbScript.Script,
|
||||
|
||||
Reference in New Issue
Block a user