diff --git a/agent/agent.go b/agent/agent.go index 2194e04dd1820..3a01605639a35 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -941,7 +941,7 @@ func (a *agent) handleManifest(manifestOK *checkpoint) func(ctx context.Context, } } - err = a.scriptRunner.Init(manifest.Scripts) + err = a.scriptRunner.Init(manifest.Scripts, aAPI.ScriptCompleted) if err != nil { return xerrors.Errorf("init script runner: %w", err) } @@ -949,9 +949,7 @@ func (a *agent) handleManifest(manifestOK *checkpoint) func(ctx context.Context, start := time.Now() // here we use the graceful context because the script runner is not directly tied // to the agent API. - err := a.scriptRunner.Execute(a.gracefulCtx, func(script codersdk.WorkspaceAgentScript) bool { - return script.RunOnStart - }) + err := a.scriptRunner.Execute(a.gracefulCtx, agentscripts.ExecuteStartScripts) // Measure the time immediately after the script has finished dur := time.Since(start).Seconds() if err != nil { @@ -1844,9 +1842,7 @@ func (a *agent) Close() error { a.gracefulCancel() lifecycleState := codersdk.WorkspaceAgentLifecycleOff - err = a.scriptRunner.Execute(a.hardCtx, func(script codersdk.WorkspaceAgentScript) bool { - return script.RunOnStop - }) + err = a.scriptRunner.Execute(a.hardCtx, agentscripts.ExecuteStopScripts) if err != nil { a.logger.Warn(a.hardCtx, "shutdown script(s) failed", slog.Error(err)) if errors.Is(err, agentscripts.ErrTimeout) { diff --git a/agent/agent_test.go b/agent/agent_test.go index 91e7c1c34e0c0..5ef7afdb0e920 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -1517,10 +1517,12 @@ func TestAgent_Lifecycle(t *testing.T) { agentsdk.Manifest{ DERPMap: derpMap, Scripts: []codersdk.WorkspaceAgentScript{{ + ID: uuid.New(), LogPath: "coder-startup-script.log", Script: "echo 1", RunOnStart: true, }, { + ID: uuid.New(), LogPath: "coder-shutdown-script.log", Script: "echo " + expected, RunOnStop: true, diff --git a/agent/agentscripts/agentscripts.go b/agent/agentscripts/agentscripts.go index 2df1bc0ca0418..b4def315fab50 100644 --- a/agent/agentscripts/agentscripts.go +++ b/agent/agentscripts/agentscripts.go @@ -19,10 +19,13 @@ import ( "github.com/spf13/afero" "golang.org/x/sync/errgroup" "golang.org/x/xerrors" + "google.golang.org/protobuf/types/known/timestamppb" "cdr.dev/slog" "github.com/coder/coder/v2/agent/agentssh" + "github.com/coder/coder/v2/agent/proto" + "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/codersdk/agentsdk" ) @@ -75,18 +78,21 @@ func New(opts Options) *Runner { } } +type ScriptCompletedFunc func(context.Context, *proto.WorkspaceAgentScriptCompletedRequest) (*proto.WorkspaceAgentScriptCompletedResponse, error) + type Runner struct { Options - cronCtx context.Context - cronCtxCancel context.CancelFunc - cmdCloseWait sync.WaitGroup - closed chan struct{} - closeMutex sync.Mutex - cron *cron.Cron - initialized atomic.Bool - scripts []codersdk.WorkspaceAgentScript - dataDir string + cronCtx context.Context + cronCtxCancel context.CancelFunc + cmdCloseWait sync.WaitGroup + closed chan struct{} + closeMutex sync.Mutex + cron *cron.Cron + initialized atomic.Bool + scripts []codersdk.WorkspaceAgentScript + dataDir string + scriptCompleted ScriptCompletedFunc // scriptsExecuted includes all scripts executed by the workspace agent. Agents // execute startup scripts, and scripts on a cron schedule. Both will increment @@ -116,12 +122,13 @@ func (r *Runner) RegisterMetrics(reg prometheus.Registerer) { // Init initializes the runner with the provided scripts. // It also schedules any scripts that have a schedule. // This function must be called before Execute. -func (r *Runner) Init(scripts []codersdk.WorkspaceAgentScript) error { +func (r *Runner) Init(scripts []codersdk.WorkspaceAgentScript, scriptCompleted ScriptCompletedFunc) error { if r.initialized.Load() { return xerrors.New("init: already initialized") } r.initialized.Store(true) r.scripts = scripts + r.scriptCompleted = scriptCompleted r.Logger.Info(r.cronCtx, "initializing agent scripts", slog.F("script_count", len(scripts)), slog.F("log_dir", r.LogDir)) err := r.Filesystem.MkdirAll(r.ScriptBinDir(), 0o700) @@ -135,7 +142,7 @@ func (r *Runner) Init(scripts []codersdk.WorkspaceAgentScript) error { } script := script _, err := r.cron.AddFunc(script.Cron, func() { - err := r.trackRun(r.cronCtx, script) + err := r.trackRun(r.cronCtx, script, ExecuteCronScripts) if err != nil { r.Logger.Warn(context.Background(), "run agent script on schedule", slog.Error(err)) } @@ -172,22 +179,33 @@ func (r *Runner) StartCron() { } } +// ExecuteOption describes what scripts we want to execute. +type ExecuteOption int + +// ExecuteOption enums. +const ( + ExecuteAllScripts ExecuteOption = iota + ExecuteStartScripts + ExecuteStopScripts + ExecuteCronScripts +) + // Execute runs a set of scripts according to a filter. -func (r *Runner) Execute(ctx context.Context, filter func(script codersdk.WorkspaceAgentScript) bool) error { - if filter == nil { - // Execute em' all! - filter = func(script codersdk.WorkspaceAgentScript) bool { - return true - } - } +func (r *Runner) Execute(ctx context.Context, option ExecuteOption) error { var eg errgroup.Group for _, script := range r.scripts { - if !filter(script) { + runScript := (option == ExecuteStartScripts && script.RunOnStart) || + (option == ExecuteStopScripts && script.RunOnStop) || + (option == ExecuteCronScripts && script.Cron != "") || + option == ExecuteAllScripts + + if !runScript { continue } + script := script eg.Go(func() error { - err := r.trackRun(ctx, script) + err := r.trackRun(ctx, script, option) if err != nil { return xerrors.Errorf("run agent script %q: %w", script.LogSourceID, err) } @@ -198,8 +216,8 @@ func (r *Runner) Execute(ctx context.Context, filter func(script codersdk.Worksp } // trackRun wraps "run" with metrics. -func (r *Runner) trackRun(ctx context.Context, script codersdk.WorkspaceAgentScript) error { - err := r.run(ctx, script) +func (r *Runner) trackRun(ctx context.Context, script codersdk.WorkspaceAgentScript, option ExecuteOption) error { + err := r.run(ctx, script, option) if err != nil { r.scriptsExecuted.WithLabelValues("false").Add(1) } else { @@ -212,7 +230,7 @@ func (r *Runner) trackRun(ctx context.Context, script codersdk.WorkspaceAgentScr // If the timeout is exceeded, the process is sent an interrupt signal. // If the process does not exit after a few seconds, it is forcefully killed. // This function immediately returns after a timeout, and does not wait for the process to exit. -func (r *Runner) run(ctx context.Context, script codersdk.WorkspaceAgentScript) error { +func (r *Runner) run(ctx context.Context, script codersdk.WorkspaceAgentScript, option ExecuteOption) error { logPath := script.LogPath if logPath == "" { logPath = fmt.Sprintf("coder-script-%s.log", script.LogSourceID) @@ -299,9 +317,9 @@ func (r *Runner) run(ctx context.Context, script codersdk.WorkspaceAgentScript) cmd.Stdout = io.MultiWriter(fileWriter, infoW) cmd.Stderr = io.MultiWriter(fileWriter, errW) - start := time.Now() + start := dbtime.Now() defer func() { - end := time.Now() + end := dbtime.Now() execTime := end.Sub(start) exitCode := 0 if err != nil { @@ -314,6 +332,60 @@ func (r *Runner) run(ctx context.Context, script codersdk.WorkspaceAgentScript) } else { logger.Info(ctx, fmt.Sprintf("%s script completed", logPath), slog.F("execution_time", execTime), slog.F("exit_code", exitCode)) } + + if r.scriptCompleted == nil { + logger.Debug(ctx, "r.scriptCompleted unexpectedly nil") + return + } + + // We want to check this outside of the goroutine to avoid a race condition + timedOut := errors.Is(err, ErrTimeout) + pipesLeftOpen := errors.Is(err, ErrOutputPipesOpen) + + err = r.trackCommandGoroutine(func() { + var stage proto.Timing_Stage + switch option { + case ExecuteStartScripts: + stage = proto.Timing_START + case ExecuteStopScripts: + stage = proto.Timing_STOP + case ExecuteCronScripts: + stage = proto.Timing_CRON + } + + var status proto.Timing_Status + switch { + case timedOut: + status = proto.Timing_TIMED_OUT + case pipesLeftOpen: + status = proto.Timing_PIPES_LEFT_OPEN + case exitCode != 0: + status = proto.Timing_EXIT_FAILURE + default: + status = proto.Timing_OK + } + + reportTimeout := 30 * time.Second + reportCtx, cancel := context.WithTimeout(context.Background(), reportTimeout) + defer cancel() + + _, err := r.scriptCompleted(reportCtx, &proto.WorkspaceAgentScriptCompletedRequest{ + Timing: &proto.Timing{ + ScriptId: script.ID[:], + Start: timestamppb.New(start), + End: timestamppb.New(end), + ExitCode: int32(exitCode), + Stage: stage, + Status: status, + }, + }) + if err != nil { + logger.Error(ctx, fmt.Sprintf("reporting script completed: %s", err.Error())) + } + }) + if err != nil { + logger.Error(ctx, fmt.Sprintf("reporting script completed: track command goroutine: %s", err.Error())) + } }() err = cmd.Start() diff --git a/agent/agentscripts/agentscripts_test.go b/agent/agentscripts/agentscripts_test.go index 2be7e76c54f6a..e47fdbae8f87e 100644 --- a/agent/agentscripts/agentscripts_test.go +++ b/agent/agentscripts/agentscripts_test.go @@ -17,6 +17,7 @@ import ( "cdr.dev/slog/sloggers/slogtest" "github.com/coder/coder/v2/agent/agentscripts" "github.com/coder/coder/v2/agent/agentssh" + "github.com/coder/coder/v2/agent/agenttest" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/codersdk/agentsdk" "github.com/coder/coder/v2/testutil" @@ -34,14 +35,13 @@ func TestExecuteBasic(t *testing.T) { return fLogger }) defer runner.Close() + aAPI := agenttest.NewFakeAgentAPI(t, slogtest.Make(t, nil), nil, nil) err := runner.Init([]codersdk.WorkspaceAgentScript{{ LogSourceID: uuid.New(), Script: "echo hello", - }}) + }}, aAPI.ScriptCompleted) require.NoError(t, err) - require.NoError(t, runner.Execute(context.Background(), func(script codersdk.WorkspaceAgentScript) bool { - return true - })) + require.NoError(t, runner.Execute(context.Background(), agentscripts.ExecuteAllScripts)) log := testutil.RequireRecvCtx(ctx, t, fLogger.logs) require.Equal(t, "hello", log.Output) } @@ -61,18 +61,17 @@ func TestEnv(t *testing.T) { cmd.exe /c echo %CODER_SCRIPT_BIN_DIR% ` } + aAPI := agenttest.NewFakeAgentAPI(t, slogtest.Make(t, nil), nil, nil) err := runner.Init([]codersdk.WorkspaceAgentScript{{ LogSourceID: id, Script: script, - }}) + }}, aAPI.ScriptCompleted) require.NoError(t, err) ctx := testutil.Context(t, testutil.WaitLong) done := testutil.Go(t, func() { - err := runner.Execute(ctx, func(script codersdk.WorkspaceAgentScript) bool { - return true - }) + err := runner.Execute(ctx, agentscripts.ExecuteAllScripts) assert.NoError(t, err) }) defer func() { @@ -103,13 +102,44 @@ func TestTimeout(t *testing.T) { t.Parallel() runner := setup(t, nil) defer runner.Close() + aAPI := agenttest.NewFakeAgentAPI(t, slogtest.Make(t, nil), nil, nil) err := runner.Init([]codersdk.WorkspaceAgentScript{{ LogSourceID: uuid.New(), Script: "sleep infinity", Timeout: time.Millisecond, - }}) + }}, aAPI.ScriptCompleted) require.NoError(t, err) - require.ErrorIs(t, runner.Execute(context.Background(), nil), agentscripts.ErrTimeout) + require.ErrorIs(t, runner.Execute(context.Background(), agentscripts.ExecuteAllScripts), agentscripts.ErrTimeout) +} + +func TestScriptReportsTiming(t *testing.T) { + t.Parallel() + + ctx := testutil.Context(t, testutil.WaitShort) + fLogger := newFakeScriptLogger() + runner := setup(t, func(uuid2 uuid.UUID) agentscripts.ScriptLogger { + return fLogger + }) + + aAPI := agenttest.NewFakeAgentAPI(t, slogtest.Make(t, nil), nil, nil) + err := runner.Init([]codersdk.WorkspaceAgentScript{{ + DisplayName: "say-hello", + LogSourceID: uuid.New(), + Script: "echo hello", + }}, aAPI.ScriptCompleted) + require.NoError(t, err) + require.NoError(t, runner.Execute(ctx, agentscripts.ExecuteAllScripts)) + runner.Close() + + log := testutil.RequireRecvCtx(ctx, t, fLogger.logs) + require.Equal(t, "hello", log.Output) + + timings := aAPI.GetTimings() + require.Equal(t, 1, len(timings)) + + timing := timings[0] + require.Equal(t, int32(0), timing.ExitCode) + require.GreaterOrEqual(t, timing.End.AsTime(), timing.Start.AsTime()) } // TestCronClose exists because cron.Run() can happen after cron.Close(). diff --git a/agent/agenttest/client.go b/agent/agenttest/client.go index decb43ae9d05a..a17f9200a9b87 100644 --- a/agent/agenttest/client.go +++ b/agent/agenttest/client.go @@ -170,6 +170,7 @@ type FakeAgentAPI struct { logsCh chan<- *agentproto.BatchCreateLogsRequest lifecycleStates []codersdk.WorkspaceAgentLifecycle metadata map[string]agentsdk.Metadata + timings []*agentproto.Timing getAnnouncementBannersFunc func() ([]codersdk.BannerConfig, error) } @@ -182,6 +183,12 @@ func (*FakeAgentAPI) GetServiceBanner(context.Context, *agentproto.GetServiceBan return &agentproto.ServiceBanner{}, nil } +func (f *FakeAgentAPI) GetTimings() []*agentproto.Timing { + f.Lock() + defer f.Unlock() + return slices.Clone(f.timings) +} + func (f *FakeAgentAPI) SetAnnouncementBannersFunc(fn func() ([]codersdk.BannerConfig, error)) { f.Lock() defer f.Unlock() @@ -301,6 +308,14 @@ func (f *FakeAgentAPI) BatchCreateLogs(ctx context.Context, req *agentproto.Batc return &agentproto.BatchCreateLogsResponse{}, nil } +func (f *FakeAgentAPI) ScriptCompleted(_ context.Context, req *agentproto.WorkspaceAgentScriptCompletedRequest) (*agentproto.WorkspaceAgentScriptCompletedResponse, error) { + f.Lock() + f.timings = append(f.timings, req.Timing) + f.Unlock() + + return &agentproto.WorkspaceAgentScriptCompletedResponse{}, nil +} + func NewFakeAgentAPI(t testing.TB, logger slog.Logger, manifest *agentproto.Manifest, statsCh chan *agentproto.Stats) *FakeAgentAPI { return &FakeAgentAPI{ t: t, diff --git a/agent/proto/agent.pb.go b/agent/proto/agent.pb.go index 5c973815b00be..8063b42f3b622 100644 --- a/agent/proto/agent.pb.go +++ b/agent/proto/agent.pb.go @@ -414,6 +414,107 @@ func (Log_Level) EnumDescriptor() ([]byte, []int) { return file_agent_proto_agent_proto_rawDescGZIP(), []int{19, 0} } +type Timing_Stage int32 + +const ( + Timing_START Timing_Stage = 0 + Timing_STOP Timing_Stage = 1 + Timing_CRON Timing_Stage = 2 +) + +// Enum value maps for Timing_Stage. +var ( + Timing_Stage_name = map[int32]string{ + 0: "START", + 1: "STOP", + 2: "CRON", + } + Timing_Stage_value = map[string]int32{ + "START": 0, + "STOP": 1, + "CRON": 2, + } +) + +func (x Timing_Stage) Enum() *Timing_Stage { + p := new(Timing_Stage) + *p = x + return p +} + +func (x Timing_Stage) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Timing_Stage) Descriptor() protoreflect.EnumDescriptor { + return file_agent_proto_agent_proto_enumTypes[7].Descriptor() +} + +func (Timing_Stage) Type() protoreflect.EnumType { + return &file_agent_proto_agent_proto_enumTypes[7] +} + +func (x Timing_Stage) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Timing_Stage.Descriptor instead. +func (Timing_Stage) EnumDescriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{27, 0} +} + +type Timing_Status int32 + +const ( + Timing_OK Timing_Status = 0 + Timing_EXIT_FAILURE Timing_Status = 1 + Timing_TIMED_OUT Timing_Status = 2 + Timing_PIPES_LEFT_OPEN Timing_Status = 3 +) + +// Enum value maps for Timing_Status. +var ( + Timing_Status_name = map[int32]string{ + 0: "OK", + 1: "EXIT_FAILURE", + 2: "TIMED_OUT", + 3: "PIPES_LEFT_OPEN", + } + Timing_Status_value = map[string]int32{ + "OK": 0, + "EXIT_FAILURE": 1, + "TIMED_OUT": 2, + "PIPES_LEFT_OPEN": 3, + } +) + +func (x Timing_Status) Enum() *Timing_Status { + p := new(Timing_Status) + *p = x + return p +} + +func (x Timing_Status) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Timing_Status) Descriptor() protoreflect.EnumDescriptor { + return file_agent_proto_agent_proto_enumTypes[8].Descriptor() +} + +func (Timing_Status) Type() protoreflect.EnumType { + return &file_agent_proto_agent_proto_enumTypes[8] +} + +func (x Timing_Status) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Timing_Status.Descriptor instead. +func (Timing_Status) EnumDescriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{27, 1} +} + type WorkspaceApp struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -571,6 +672,7 @@ type WorkspaceAgentScript struct { StartBlocksLogin bool `protobuf:"varint,7,opt,name=start_blocks_login,json=startBlocksLogin,proto3" json:"start_blocks_login,omitempty"` Timeout *durationpb.Duration `protobuf:"bytes,8,opt,name=timeout,proto3" json:"timeout,omitempty"` DisplayName string `protobuf:"bytes,9,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` + Id []byte `protobuf:"bytes,10,opt,name=id,proto3" json:"id,omitempty"` } func (x *WorkspaceAgentScript) Reset() { @@ -668,6 +770,13 @@ func (x *WorkspaceAgentScript) GetDisplayName() string { return "" } +func (x *WorkspaceAgentScript) GetId() []byte { + if x != nil { + return x.Id + } + return nil +} + type WorkspaceAgentMetadata struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2023,6 +2132,178 @@ func (x *BannerConfig) GetBackgroundColor() string { return "" } +type WorkspaceAgentScriptCompletedRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Timing *Timing `protobuf:"bytes,1,opt,name=timing,proto3" json:"timing,omitempty"` +} + +func (x *WorkspaceAgentScriptCompletedRequest) Reset() { + *x = WorkspaceAgentScriptCompletedRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WorkspaceAgentScriptCompletedRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WorkspaceAgentScriptCompletedRequest) ProtoMessage() {} + +func (x *WorkspaceAgentScriptCompletedRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[25] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WorkspaceAgentScriptCompletedRequest.ProtoReflect.Descriptor instead. +func (*WorkspaceAgentScriptCompletedRequest) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{25} +} + +func (x *WorkspaceAgentScriptCompletedRequest) GetTiming() *Timing { + if x != nil { + return x.Timing + } + return nil +} + +type WorkspaceAgentScriptCompletedResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *WorkspaceAgentScriptCompletedResponse) Reset() { + *x = WorkspaceAgentScriptCompletedResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WorkspaceAgentScriptCompletedResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WorkspaceAgentScriptCompletedResponse) ProtoMessage() {} + +func (x *WorkspaceAgentScriptCompletedResponse) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[26] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WorkspaceAgentScriptCompletedResponse.ProtoReflect.Descriptor instead. +func (*WorkspaceAgentScriptCompletedResponse) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{26} +} + +type Timing struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ScriptId []byte `protobuf:"bytes,1,opt,name=script_id,json=scriptId,proto3" json:"script_id,omitempty"` + Start *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=start,proto3" json:"start,omitempty"` + End *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=end,proto3" json:"end,omitempty"` + ExitCode int32 `protobuf:"varint,4,opt,name=exit_code,json=exitCode,proto3" json:"exit_code,omitempty"` + Stage Timing_Stage `protobuf:"varint,5,opt,name=stage,proto3,enum=coder.agent.v2.Timing_Stage" json:"stage,omitempty"` + Status Timing_Status `protobuf:"varint,6,opt,name=status,proto3,enum=coder.agent.v2.Timing_Status" json:"status,omitempty"` +} + +func (x *Timing) Reset() { + *x = Timing{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Timing) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Timing) ProtoMessage() {} + +func (x *Timing) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[27] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Timing.ProtoReflect.Descriptor instead. +func (*Timing) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{27} +} + +func (x *Timing) GetScriptId() []byte { + if x != nil { + return x.ScriptId + } + return nil +} + +func (x *Timing) GetStart() *timestamppb.Timestamp { + if x != nil { + return x.Start + } + return nil +} + +func (x *Timing) GetEnd() *timestamppb.Timestamp { + if x != nil { + return x.End + } + return nil +} + +func (x *Timing) GetExitCode() int32 { + if x != nil { + return x.ExitCode + } + return 0 +} + +func (x *Timing) GetStage() Timing_Stage { + if x != nil { + return x.Stage + } + return Timing_START +} + +func (x *Timing) GetStatus() Timing_Status { + if x != nil { + return x.Status + } + return Timing_OK +} + type WorkspaceApp_Healthcheck struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2036,7 +2317,7 @@ type WorkspaceApp_Healthcheck struct { func (x *WorkspaceApp_Healthcheck) Reset() { *x = WorkspaceApp_Healthcheck{} if protoimpl.UnsafeEnabled { - mi := &file_agent_proto_agent_proto_msgTypes[25] + mi := &file_agent_proto_agent_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2049,7 +2330,7 @@ func (x *WorkspaceApp_Healthcheck) String() string { func (*WorkspaceApp_Healthcheck) ProtoMessage() {} func (x *WorkspaceApp_Healthcheck) ProtoReflect() protoreflect.Message { - mi := &file_agent_proto_agent_proto_msgTypes[25] + mi := &file_agent_proto_agent_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2100,7 +2381,7 @@ type WorkspaceAgentMetadata_Result struct { func (x *WorkspaceAgentMetadata_Result) Reset() { *x = WorkspaceAgentMetadata_Result{} if protoimpl.UnsafeEnabled { - mi := &file_agent_proto_agent_proto_msgTypes[26] + mi := &file_agent_proto_agent_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2113,7 +2394,7 @@ func (x *WorkspaceAgentMetadata_Result) String() string { func (*WorkspaceAgentMetadata_Result) ProtoMessage() {} func (x *WorkspaceAgentMetadata_Result) ProtoReflect() protoreflect.Message { - mi := &file_agent_proto_agent_proto_msgTypes[26] + mi := &file_agent_proto_agent_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2172,7 +2453,7 @@ type WorkspaceAgentMetadata_Description struct { func (x *WorkspaceAgentMetadata_Description) Reset() { *x = WorkspaceAgentMetadata_Description{} if protoimpl.UnsafeEnabled { - mi := &file_agent_proto_agent_proto_msgTypes[27] + mi := &file_agent_proto_agent_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2185,7 +2466,7 @@ func (x *WorkspaceAgentMetadata_Description) String() string { func (*WorkspaceAgentMetadata_Description) ProtoMessage() {} func (x *WorkspaceAgentMetadata_Description) ProtoReflect() protoreflect.Message { - mi := &file_agent_proto_agent_proto_msgTypes[27] + mi := &file_agent_proto_agent_proto_msgTypes[30] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2250,7 +2531,7 @@ type Stats_Metric struct { func (x *Stats_Metric) Reset() { *x = Stats_Metric{} if protoimpl.UnsafeEnabled { - mi := &file_agent_proto_agent_proto_msgTypes[30] + mi := &file_agent_proto_agent_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2263,7 +2544,7 @@ func (x *Stats_Metric) String() string { func (*Stats_Metric) ProtoMessage() {} func (x *Stats_Metric) ProtoReflect() protoreflect.Message { - mi := &file_agent_proto_agent_proto_msgTypes[30] + mi := &file_agent_proto_agent_proto_msgTypes[33] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2319,7 +2600,7 @@ type Stats_Metric_Label struct { func (x *Stats_Metric_Label) Reset() { *x = Stats_Metric_Label{} if protoimpl.UnsafeEnabled { - mi := &file_agent_proto_agent_proto_msgTypes[31] + mi := &file_agent_proto_agent_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2332,7 +2613,7 @@ func (x *Stats_Metric_Label) String() string { func (*Stats_Metric_Label) ProtoMessage() {} func (x *Stats_Metric_Label) ProtoReflect() protoreflect.Message { - mi := &file_agent_proto_agent_proto_msgTypes[31] + mi := &file_agent_proto_agent_proto_msgTypes[34] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2374,7 +2655,7 @@ type BatchUpdateAppHealthRequest_HealthUpdate struct { func (x *BatchUpdateAppHealthRequest_HealthUpdate) Reset() { *x = BatchUpdateAppHealthRequest_HealthUpdate{} if protoimpl.UnsafeEnabled { - mi := &file_agent_proto_agent_proto_msgTypes[32] + mi := &file_agent_proto_agent_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2387,7 +2668,7 @@ func (x *BatchUpdateAppHealthRequest_HealthUpdate) String() string { func (*BatchUpdateAppHealthRequest_HealthUpdate) ProtoMessage() {} func (x *BatchUpdateAppHealthRequest_HealthUpdate) ProtoReflect() protoreflect.Message { - mi := &file_agent_proto_agent_proto_msgTypes[32] + mi := &file_agent_proto_agent_proto_msgTypes[35] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2477,7 +2758,7 @@ var file_agent_proto_agent_proto_rawDesc = []byte{ 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x49, 0x53, 0x41, 0x42, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x49, 0x5a, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x48, 0x45, 0x41, 0x4c, 0x54, 0x48, 0x59, 0x10, 0x03, 0x12, - 0x0d, 0x0a, 0x09, 0x55, 0x4e, 0x48, 0x45, 0x41, 0x4c, 0x54, 0x48, 0x59, 0x10, 0x04, 0x22, 0xc9, + 0x0d, 0x0a, 0x09, 0x55, 0x4e, 0x48, 0x45, 0x41, 0x4c, 0x54, 0x48, 0x59, 0x10, 0x04, 0x22, 0xd9, 0x02, 0x0a, 0x14, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x22, 0x0a, 0x0d, 0x6c, 0x6f, 0x67, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, @@ -2498,7 +2779,8 @@ var file_agent_proto_agent_proto_rawDesc = []byte{ 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, - 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x86, 0x04, 0x0a, 0x16, 0x57, + 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x22, 0x86, 0x04, 0x0a, 0x16, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x45, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, @@ -2778,71 +3060,111 @@ var file_agent_proto_agent_proto_rawDesc = []byte{ 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6c, - 0x6f, 0x72, 0x2a, 0x63, 0x0a, 0x09, 0x41, 0x70, 0x70, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x12, - 0x1a, 0x0a, 0x16, 0x41, 0x50, 0x50, 0x5f, 0x48, 0x45, 0x41, 0x4c, 0x54, 0x48, 0x5f, 0x55, 0x4e, - 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x44, - 0x49, 0x53, 0x41, 0x42, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x49, 0x4e, 0x49, - 0x54, 0x49, 0x41, 0x4c, 0x49, 0x5a, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x48, - 0x45, 0x41, 0x4c, 0x54, 0x48, 0x59, 0x10, 0x03, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x4e, 0x48, 0x45, - 0x41, 0x4c, 0x54, 0x48, 0x59, 0x10, 0x04, 0x32, 0xef, 0x06, 0x0a, 0x05, 0x41, 0x67, 0x65, 0x6e, - 0x74, 0x12, 0x4b, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, - 0x12, 0x22, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, - 0x32, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, - 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x12, 0x5a, - 0x0a, 0x10, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x42, 0x61, 0x6e, 0x6e, - 0x65, 0x72, 0x12, 0x27, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, - 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x42, 0x61, - 0x6e, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x63, 0x6f, - 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x56, 0x0a, 0x0b, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x22, 0x2e, 0x63, 0x6f, 0x64, 0x65, - 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, - 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x54, 0x0a, 0x0f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x66, 0x65, - 0x63, 0x79, 0x63, 0x6c, 0x65, 0x12, 0x26, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x66, - 0x65, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, - 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x4c, - 0x69, 0x66, 0x65, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x12, 0x72, 0x0a, 0x15, 0x42, 0x61, 0x74, 0x63, - 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, - 0x73, 0x12, 0x2b, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, - 0x76, 0x32, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, - 0x70, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, + 0x6f, 0x72, 0x22, 0x56, 0x0a, 0x24, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x41, + 0x67, 0x65, 0x6e, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, + 0x74, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x06, 0x74, 0x69, + 0x6d, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x6f, 0x64, + 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x54, 0x69, 0x6d, 0x69, + 0x6e, 0x67, 0x52, 0x06, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x22, 0x27, 0x0a, 0x25, 0x57, 0x6f, + 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x53, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0xfd, 0x02, 0x0a, 0x06, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x12, 0x1b, + 0x0a, 0x09, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x08, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x05, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x2c, 0x0a, + 0x03, 0x65, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x65, + 0x78, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, + 0x65, 0x78, 0x69, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x32, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x67, + 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, + 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x2e, + 0x53, 0x74, 0x61, 0x67, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x12, 0x35, 0x0a, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x63, + 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x54, 0x69, + 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x22, 0x26, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x67, 0x65, 0x12, 0x09, 0x0a, 0x05, + 0x53, 0x54, 0x41, 0x52, 0x54, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x53, 0x54, 0x4f, 0x50, 0x10, + 0x01, 0x12, 0x08, 0x0a, 0x04, 0x43, 0x52, 0x4f, 0x4e, 0x10, 0x02, 0x22, 0x46, 0x0a, 0x06, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x06, 0x0a, 0x02, 0x4f, 0x4b, 0x10, 0x00, 0x12, 0x10, 0x0a, + 0x0c, 0x45, 0x58, 0x49, 0x54, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x10, 0x01, 0x12, + 0x0d, 0x0a, 0x09, 0x54, 0x49, 0x4d, 0x45, 0x44, 0x5f, 0x4f, 0x55, 0x54, 0x10, 0x02, 0x12, 0x13, + 0x0a, 0x0f, 0x50, 0x49, 0x50, 0x45, 0x53, 0x5f, 0x4c, 0x45, 0x46, 0x54, 0x5f, 0x4f, 0x50, 0x45, + 0x4e, 0x10, 0x03, 0x2a, 0x63, 0x0a, 0x09, 0x41, 0x70, 0x70, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, + 0x12, 0x1a, 0x0a, 0x16, 0x41, 0x50, 0x50, 0x5f, 0x48, 0x45, 0x41, 0x4c, 0x54, 0x48, 0x5f, 0x55, + 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, + 0x44, 0x49, 0x53, 0x41, 0x42, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x49, 0x4e, + 0x49, 0x54, 0x49, 0x41, 0x4c, 0x49, 0x5a, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, + 0x48, 0x45, 0x41, 0x4c, 0x54, 0x48, 0x59, 0x10, 0x03, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x4e, 0x48, + 0x45, 0x41, 0x4c, 0x54, 0x48, 0x59, 0x10, 0x04, 0x32, 0xef, 0x07, 0x0a, 0x05, 0x41, 0x67, 0x65, + 0x6e, 0x74, 0x12, 0x4b, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, + 0x74, 0x12, 0x22, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, + 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x12, + 0x5a, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x42, 0x61, 0x6e, + 0x6e, 0x65, 0x72, 0x12, 0x27, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, + 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x42, + 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x63, + 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x56, 0x0a, 0x0b, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x22, 0x2e, 0x63, 0x6f, 0x64, + 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, - 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x48, 0x65, - 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x0d, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x12, 0x24, 0x2e, - 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, - 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x12, 0x6e, 0x0a, 0x13, - 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x12, 0x2a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, - 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x2b, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, - 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x62, 0x0a, 0x0f, - 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x67, 0x73, 0x12, - 0x26, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, - 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x67, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, - 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x77, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x41, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x6d, - 0x65, 0x6e, 0x74, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x12, 0x2d, 0x2e, 0x63, 0x6f, 0x64, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x0f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x66, + 0x65, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x12, 0x26, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, + 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4c, 0x69, + 0x66, 0x65, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, + 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, + 0x4c, 0x69, 0x66, 0x65, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x12, 0x72, 0x0a, 0x15, 0x42, 0x61, 0x74, + 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x48, 0x65, 0x61, 0x6c, 0x74, + 0x68, 0x73, 0x12, 0x2b, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, + 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, + 0x70, 0x70, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x2c, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, + 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x48, + 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, + 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x12, 0x24, + 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, + 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x12, 0x6e, 0x0a, + 0x13, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x12, 0x2a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, + 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x2b, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, + 0x32, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x62, 0x0a, + 0x0f, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x67, 0x73, + 0x12, 0x26, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, + 0x32, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x67, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, + 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x77, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x41, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x12, 0x2d, 0x2e, 0x63, 0x6f, + 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, + 0x41, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x61, 0x6e, 0x6e, + 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x61, 0x6e, 0x6e, 0x65, - 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x63, 0x6f, 0x64, 0x65, - 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6e, - 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, - 0x64, 0x65, 0x72, 0x2f, 0x76, 0x32, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7e, 0x0a, 0x0f, 0x53, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x34, 0x2e, + 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x57, + 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x53, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, + 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x41, 0x67, + 0x65, 0x6e, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, + 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, + 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x76, 0x32, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2857,111 +3179,123 @@ func file_agent_proto_agent_proto_rawDescGZIP() []byte { return file_agent_proto_agent_proto_rawDescData } -var file_agent_proto_agent_proto_enumTypes = make([]protoimpl.EnumInfo, 7) -var file_agent_proto_agent_proto_msgTypes = make([]protoimpl.MessageInfo, 33) +var file_agent_proto_agent_proto_enumTypes = make([]protoimpl.EnumInfo, 9) +var file_agent_proto_agent_proto_msgTypes = make([]protoimpl.MessageInfo, 36) var file_agent_proto_agent_proto_goTypes = []interface{}{ - (AppHealth)(0), // 0: coder.agent.v2.AppHealth - (WorkspaceApp_SharingLevel)(0), // 1: coder.agent.v2.WorkspaceApp.SharingLevel - (WorkspaceApp_Health)(0), // 2: coder.agent.v2.WorkspaceApp.Health - (Stats_Metric_Type)(0), // 3: coder.agent.v2.Stats.Metric.Type - (Lifecycle_State)(0), // 4: coder.agent.v2.Lifecycle.State - (Startup_Subsystem)(0), // 5: coder.agent.v2.Startup.Subsystem - (Log_Level)(0), // 6: coder.agent.v2.Log.Level - (*WorkspaceApp)(nil), // 7: coder.agent.v2.WorkspaceApp - (*WorkspaceAgentScript)(nil), // 8: coder.agent.v2.WorkspaceAgentScript - (*WorkspaceAgentMetadata)(nil), // 9: coder.agent.v2.WorkspaceAgentMetadata - (*Manifest)(nil), // 10: coder.agent.v2.Manifest - (*GetManifestRequest)(nil), // 11: coder.agent.v2.GetManifestRequest - (*ServiceBanner)(nil), // 12: coder.agent.v2.ServiceBanner - (*GetServiceBannerRequest)(nil), // 13: coder.agent.v2.GetServiceBannerRequest - (*Stats)(nil), // 14: coder.agent.v2.Stats - (*UpdateStatsRequest)(nil), // 15: coder.agent.v2.UpdateStatsRequest - (*UpdateStatsResponse)(nil), // 16: coder.agent.v2.UpdateStatsResponse - (*Lifecycle)(nil), // 17: coder.agent.v2.Lifecycle - (*UpdateLifecycleRequest)(nil), // 18: coder.agent.v2.UpdateLifecycleRequest - (*BatchUpdateAppHealthRequest)(nil), // 19: coder.agent.v2.BatchUpdateAppHealthRequest - (*BatchUpdateAppHealthResponse)(nil), // 20: coder.agent.v2.BatchUpdateAppHealthResponse - (*Startup)(nil), // 21: coder.agent.v2.Startup - (*UpdateStartupRequest)(nil), // 22: coder.agent.v2.UpdateStartupRequest - (*Metadata)(nil), // 23: coder.agent.v2.Metadata - (*BatchUpdateMetadataRequest)(nil), // 24: coder.agent.v2.BatchUpdateMetadataRequest - (*BatchUpdateMetadataResponse)(nil), // 25: coder.agent.v2.BatchUpdateMetadataResponse - (*Log)(nil), // 26: coder.agent.v2.Log - (*BatchCreateLogsRequest)(nil), // 27: coder.agent.v2.BatchCreateLogsRequest - (*BatchCreateLogsResponse)(nil), // 28: coder.agent.v2.BatchCreateLogsResponse - (*GetAnnouncementBannersRequest)(nil), // 29: coder.agent.v2.GetAnnouncementBannersRequest - (*GetAnnouncementBannersResponse)(nil), // 30: coder.agent.v2.GetAnnouncementBannersResponse - (*BannerConfig)(nil), // 31: coder.agent.v2.BannerConfig - (*WorkspaceApp_Healthcheck)(nil), // 32: coder.agent.v2.WorkspaceApp.Healthcheck - (*WorkspaceAgentMetadata_Result)(nil), // 33: coder.agent.v2.WorkspaceAgentMetadata.Result - (*WorkspaceAgentMetadata_Description)(nil), // 34: coder.agent.v2.WorkspaceAgentMetadata.Description - nil, // 35: coder.agent.v2.Manifest.EnvironmentVariablesEntry - nil, // 36: coder.agent.v2.Stats.ConnectionsByProtoEntry - (*Stats_Metric)(nil), // 37: coder.agent.v2.Stats.Metric - (*Stats_Metric_Label)(nil), // 38: coder.agent.v2.Stats.Metric.Label - (*BatchUpdateAppHealthRequest_HealthUpdate)(nil), // 39: coder.agent.v2.BatchUpdateAppHealthRequest.HealthUpdate - (*durationpb.Duration)(nil), // 40: google.protobuf.Duration - (*proto.DERPMap)(nil), // 41: coder.tailnet.v2.DERPMap - (*timestamppb.Timestamp)(nil), // 42: google.protobuf.Timestamp + (AppHealth)(0), // 0: coder.agent.v2.AppHealth + (WorkspaceApp_SharingLevel)(0), // 1: coder.agent.v2.WorkspaceApp.SharingLevel + (WorkspaceApp_Health)(0), // 2: coder.agent.v2.WorkspaceApp.Health + (Stats_Metric_Type)(0), // 3: coder.agent.v2.Stats.Metric.Type + (Lifecycle_State)(0), // 4: coder.agent.v2.Lifecycle.State + (Startup_Subsystem)(0), // 5: coder.agent.v2.Startup.Subsystem + (Log_Level)(0), // 6: coder.agent.v2.Log.Level + (Timing_Stage)(0), // 7: coder.agent.v2.Timing.Stage + (Timing_Status)(0), // 8: coder.agent.v2.Timing.Status + (*WorkspaceApp)(nil), // 9: coder.agent.v2.WorkspaceApp + (*WorkspaceAgentScript)(nil), // 10: coder.agent.v2.WorkspaceAgentScript + (*WorkspaceAgentMetadata)(nil), // 11: coder.agent.v2.WorkspaceAgentMetadata + (*Manifest)(nil), // 12: coder.agent.v2.Manifest + (*GetManifestRequest)(nil), // 13: coder.agent.v2.GetManifestRequest + (*ServiceBanner)(nil), // 14: coder.agent.v2.ServiceBanner + (*GetServiceBannerRequest)(nil), // 15: coder.agent.v2.GetServiceBannerRequest + (*Stats)(nil), // 16: coder.agent.v2.Stats + (*UpdateStatsRequest)(nil), // 17: coder.agent.v2.UpdateStatsRequest + (*UpdateStatsResponse)(nil), // 18: coder.agent.v2.UpdateStatsResponse + (*Lifecycle)(nil), // 19: coder.agent.v2.Lifecycle + (*UpdateLifecycleRequest)(nil), // 20: coder.agent.v2.UpdateLifecycleRequest + (*BatchUpdateAppHealthRequest)(nil), // 21: coder.agent.v2.BatchUpdateAppHealthRequest + (*BatchUpdateAppHealthResponse)(nil), // 22: coder.agent.v2.BatchUpdateAppHealthResponse + (*Startup)(nil), // 23: coder.agent.v2.Startup + (*UpdateStartupRequest)(nil), // 24: coder.agent.v2.UpdateStartupRequest + (*Metadata)(nil), // 25: coder.agent.v2.Metadata + (*BatchUpdateMetadataRequest)(nil), // 26: coder.agent.v2.BatchUpdateMetadataRequest + (*BatchUpdateMetadataResponse)(nil), // 27: coder.agent.v2.BatchUpdateMetadataResponse + (*Log)(nil), // 28: coder.agent.v2.Log + (*BatchCreateLogsRequest)(nil), // 29: coder.agent.v2.BatchCreateLogsRequest + (*BatchCreateLogsResponse)(nil), // 30: coder.agent.v2.BatchCreateLogsResponse + (*GetAnnouncementBannersRequest)(nil), // 31: coder.agent.v2.GetAnnouncementBannersRequest + (*GetAnnouncementBannersResponse)(nil), // 32: coder.agent.v2.GetAnnouncementBannersResponse + (*BannerConfig)(nil), // 33: coder.agent.v2.BannerConfig + (*WorkspaceAgentScriptCompletedRequest)(nil), // 34: coder.agent.v2.WorkspaceAgentScriptCompletedRequest + (*WorkspaceAgentScriptCompletedResponse)(nil), // 35: coder.agent.v2.WorkspaceAgentScriptCompletedResponse + (*Timing)(nil), // 36: coder.agent.v2.Timing + (*WorkspaceApp_Healthcheck)(nil), // 37: coder.agent.v2.WorkspaceApp.Healthcheck + (*WorkspaceAgentMetadata_Result)(nil), // 38: coder.agent.v2.WorkspaceAgentMetadata.Result + (*WorkspaceAgentMetadata_Description)(nil), // 39: coder.agent.v2.WorkspaceAgentMetadata.Description + nil, // 40: coder.agent.v2.Manifest.EnvironmentVariablesEntry + nil, // 41: coder.agent.v2.Stats.ConnectionsByProtoEntry + (*Stats_Metric)(nil), // 42: coder.agent.v2.Stats.Metric + (*Stats_Metric_Label)(nil), // 43: coder.agent.v2.Stats.Metric.Label + (*BatchUpdateAppHealthRequest_HealthUpdate)(nil), // 44: coder.agent.v2.BatchUpdateAppHealthRequest.HealthUpdate + (*durationpb.Duration)(nil), // 45: google.protobuf.Duration + (*proto.DERPMap)(nil), // 46: coder.tailnet.v2.DERPMap + (*timestamppb.Timestamp)(nil), // 47: google.protobuf.Timestamp } var file_agent_proto_agent_proto_depIdxs = []int32{ 1, // 0: coder.agent.v2.WorkspaceApp.sharing_level:type_name -> coder.agent.v2.WorkspaceApp.SharingLevel - 32, // 1: coder.agent.v2.WorkspaceApp.healthcheck:type_name -> coder.agent.v2.WorkspaceApp.Healthcheck + 37, // 1: coder.agent.v2.WorkspaceApp.healthcheck:type_name -> coder.agent.v2.WorkspaceApp.Healthcheck 2, // 2: coder.agent.v2.WorkspaceApp.health:type_name -> coder.agent.v2.WorkspaceApp.Health - 40, // 3: coder.agent.v2.WorkspaceAgentScript.timeout:type_name -> google.protobuf.Duration - 33, // 4: coder.agent.v2.WorkspaceAgentMetadata.result:type_name -> coder.agent.v2.WorkspaceAgentMetadata.Result - 34, // 5: coder.agent.v2.WorkspaceAgentMetadata.description:type_name -> coder.agent.v2.WorkspaceAgentMetadata.Description - 35, // 6: coder.agent.v2.Manifest.environment_variables:type_name -> coder.agent.v2.Manifest.EnvironmentVariablesEntry - 41, // 7: coder.agent.v2.Manifest.derp_map:type_name -> coder.tailnet.v2.DERPMap - 8, // 8: coder.agent.v2.Manifest.scripts:type_name -> coder.agent.v2.WorkspaceAgentScript - 7, // 9: coder.agent.v2.Manifest.apps:type_name -> coder.agent.v2.WorkspaceApp - 34, // 10: coder.agent.v2.Manifest.metadata:type_name -> coder.agent.v2.WorkspaceAgentMetadata.Description - 36, // 11: coder.agent.v2.Stats.connections_by_proto:type_name -> coder.agent.v2.Stats.ConnectionsByProtoEntry - 37, // 12: coder.agent.v2.Stats.metrics:type_name -> coder.agent.v2.Stats.Metric - 14, // 13: coder.agent.v2.UpdateStatsRequest.stats:type_name -> coder.agent.v2.Stats - 40, // 14: coder.agent.v2.UpdateStatsResponse.report_interval:type_name -> google.protobuf.Duration + 45, // 3: coder.agent.v2.WorkspaceAgentScript.timeout:type_name -> google.protobuf.Duration + 38, // 4: coder.agent.v2.WorkspaceAgentMetadata.result:type_name -> coder.agent.v2.WorkspaceAgentMetadata.Result + 39, // 5: coder.agent.v2.WorkspaceAgentMetadata.description:type_name -> coder.agent.v2.WorkspaceAgentMetadata.Description + 40, // 6: coder.agent.v2.Manifest.environment_variables:type_name -> coder.agent.v2.Manifest.EnvironmentVariablesEntry + 46, // 7: coder.agent.v2.Manifest.derp_map:type_name -> coder.tailnet.v2.DERPMap + 10, // 8: coder.agent.v2.Manifest.scripts:type_name -> coder.agent.v2.WorkspaceAgentScript + 9, // 9: coder.agent.v2.Manifest.apps:type_name -> coder.agent.v2.WorkspaceApp + 39, // 10: coder.agent.v2.Manifest.metadata:type_name -> coder.agent.v2.WorkspaceAgentMetadata.Description + 41, // 11: coder.agent.v2.Stats.connections_by_proto:type_name -> coder.agent.v2.Stats.ConnectionsByProtoEntry + 42, // 12: coder.agent.v2.Stats.metrics:type_name -> coder.agent.v2.Stats.Metric + 16, // 13: coder.agent.v2.UpdateStatsRequest.stats:type_name -> coder.agent.v2.Stats + 45, // 14: coder.agent.v2.UpdateStatsResponse.report_interval:type_name -> google.protobuf.Duration 4, // 15: coder.agent.v2.Lifecycle.state:type_name -> coder.agent.v2.Lifecycle.State - 42, // 16: coder.agent.v2.Lifecycle.changed_at:type_name -> google.protobuf.Timestamp - 17, // 17: coder.agent.v2.UpdateLifecycleRequest.lifecycle:type_name -> coder.agent.v2.Lifecycle - 39, // 18: coder.agent.v2.BatchUpdateAppHealthRequest.updates:type_name -> coder.agent.v2.BatchUpdateAppHealthRequest.HealthUpdate + 47, // 16: coder.agent.v2.Lifecycle.changed_at:type_name -> google.protobuf.Timestamp + 19, // 17: coder.agent.v2.UpdateLifecycleRequest.lifecycle:type_name -> coder.agent.v2.Lifecycle + 44, // 18: coder.agent.v2.BatchUpdateAppHealthRequest.updates:type_name -> coder.agent.v2.BatchUpdateAppHealthRequest.HealthUpdate 5, // 19: coder.agent.v2.Startup.subsystems:type_name -> coder.agent.v2.Startup.Subsystem - 21, // 20: coder.agent.v2.UpdateStartupRequest.startup:type_name -> coder.agent.v2.Startup - 33, // 21: coder.agent.v2.Metadata.result:type_name -> coder.agent.v2.WorkspaceAgentMetadata.Result - 23, // 22: coder.agent.v2.BatchUpdateMetadataRequest.metadata:type_name -> coder.agent.v2.Metadata - 42, // 23: coder.agent.v2.Log.created_at:type_name -> google.protobuf.Timestamp + 23, // 20: coder.agent.v2.UpdateStartupRequest.startup:type_name -> coder.agent.v2.Startup + 38, // 21: coder.agent.v2.Metadata.result:type_name -> coder.agent.v2.WorkspaceAgentMetadata.Result + 25, // 22: coder.agent.v2.BatchUpdateMetadataRequest.metadata:type_name -> coder.agent.v2.Metadata + 47, // 23: coder.agent.v2.Log.created_at:type_name -> google.protobuf.Timestamp 6, // 24: coder.agent.v2.Log.level:type_name -> coder.agent.v2.Log.Level - 26, // 25: coder.agent.v2.BatchCreateLogsRequest.logs:type_name -> coder.agent.v2.Log - 31, // 26: coder.agent.v2.GetAnnouncementBannersResponse.announcement_banners:type_name -> coder.agent.v2.BannerConfig - 40, // 27: coder.agent.v2.WorkspaceApp.Healthcheck.interval:type_name -> google.protobuf.Duration - 42, // 28: coder.agent.v2.WorkspaceAgentMetadata.Result.collected_at:type_name -> google.protobuf.Timestamp - 40, // 29: coder.agent.v2.WorkspaceAgentMetadata.Description.interval:type_name -> google.protobuf.Duration - 40, // 30: coder.agent.v2.WorkspaceAgentMetadata.Description.timeout:type_name -> google.protobuf.Duration - 3, // 31: coder.agent.v2.Stats.Metric.type:type_name -> coder.agent.v2.Stats.Metric.Type - 38, // 32: coder.agent.v2.Stats.Metric.labels:type_name -> coder.agent.v2.Stats.Metric.Label - 0, // 33: coder.agent.v2.BatchUpdateAppHealthRequest.HealthUpdate.health:type_name -> coder.agent.v2.AppHealth - 11, // 34: coder.agent.v2.Agent.GetManifest:input_type -> coder.agent.v2.GetManifestRequest - 13, // 35: coder.agent.v2.Agent.GetServiceBanner:input_type -> coder.agent.v2.GetServiceBannerRequest - 15, // 36: coder.agent.v2.Agent.UpdateStats:input_type -> coder.agent.v2.UpdateStatsRequest - 18, // 37: coder.agent.v2.Agent.UpdateLifecycle:input_type -> coder.agent.v2.UpdateLifecycleRequest - 19, // 38: coder.agent.v2.Agent.BatchUpdateAppHealths:input_type -> coder.agent.v2.BatchUpdateAppHealthRequest - 22, // 39: coder.agent.v2.Agent.UpdateStartup:input_type -> coder.agent.v2.UpdateStartupRequest - 24, // 40: coder.agent.v2.Agent.BatchUpdateMetadata:input_type -> coder.agent.v2.BatchUpdateMetadataRequest - 27, // 41: coder.agent.v2.Agent.BatchCreateLogs:input_type -> coder.agent.v2.BatchCreateLogsRequest - 29, // 42: coder.agent.v2.Agent.GetAnnouncementBanners:input_type -> coder.agent.v2.GetAnnouncementBannersRequest - 10, // 43: coder.agent.v2.Agent.GetManifest:output_type -> coder.agent.v2.Manifest - 12, // 44: coder.agent.v2.Agent.GetServiceBanner:output_type -> coder.agent.v2.ServiceBanner - 16, // 45: coder.agent.v2.Agent.UpdateStats:output_type -> coder.agent.v2.UpdateStatsResponse - 17, // 46: coder.agent.v2.Agent.UpdateLifecycle:output_type -> coder.agent.v2.Lifecycle - 20, // 47: coder.agent.v2.Agent.BatchUpdateAppHealths:output_type -> coder.agent.v2.BatchUpdateAppHealthResponse - 21, // 48: coder.agent.v2.Agent.UpdateStartup:output_type -> coder.agent.v2.Startup - 25, // 49: coder.agent.v2.Agent.BatchUpdateMetadata:output_type -> coder.agent.v2.BatchUpdateMetadataResponse - 28, // 50: coder.agent.v2.Agent.BatchCreateLogs:output_type -> coder.agent.v2.BatchCreateLogsResponse - 30, // 51: coder.agent.v2.Agent.GetAnnouncementBanners:output_type -> coder.agent.v2.GetAnnouncementBannersResponse - 43, // [43:52] is the sub-list for method output_type - 34, // [34:43] is the sub-list for method input_type - 34, // [34:34] is the sub-list for extension type_name - 34, // [34:34] is the sub-list for extension extendee - 0, // [0:34] is the sub-list for field type_name + 28, // 25: coder.agent.v2.BatchCreateLogsRequest.logs:type_name -> coder.agent.v2.Log + 33, // 26: coder.agent.v2.GetAnnouncementBannersResponse.announcement_banners:type_name -> coder.agent.v2.BannerConfig + 36, // 27: coder.agent.v2.WorkspaceAgentScriptCompletedRequest.timing:type_name -> coder.agent.v2.Timing + 47, // 28: coder.agent.v2.Timing.start:type_name -> google.protobuf.Timestamp + 47, // 29: coder.agent.v2.Timing.end:type_name -> google.protobuf.Timestamp + 7, // 30: coder.agent.v2.Timing.stage:type_name -> coder.agent.v2.Timing.Stage + 8, // 31: coder.agent.v2.Timing.status:type_name -> coder.agent.v2.Timing.Status + 45, // 32: coder.agent.v2.WorkspaceApp.Healthcheck.interval:type_name -> google.protobuf.Duration + 47, // 33: coder.agent.v2.WorkspaceAgentMetadata.Result.collected_at:type_name -> google.protobuf.Timestamp + 45, // 34: coder.agent.v2.WorkspaceAgentMetadata.Description.interval:type_name -> google.protobuf.Duration + 45, // 35: coder.agent.v2.WorkspaceAgentMetadata.Description.timeout:type_name -> google.protobuf.Duration + 3, // 36: coder.agent.v2.Stats.Metric.type:type_name -> coder.agent.v2.Stats.Metric.Type + 43, // 37: coder.agent.v2.Stats.Metric.labels:type_name -> coder.agent.v2.Stats.Metric.Label + 0, // 38: coder.agent.v2.BatchUpdateAppHealthRequest.HealthUpdate.health:type_name -> coder.agent.v2.AppHealth + 13, // 39: coder.agent.v2.Agent.GetManifest:input_type -> coder.agent.v2.GetManifestRequest + 15, // 40: coder.agent.v2.Agent.GetServiceBanner:input_type -> coder.agent.v2.GetServiceBannerRequest + 17, // 41: coder.agent.v2.Agent.UpdateStats:input_type -> coder.agent.v2.UpdateStatsRequest + 20, // 42: coder.agent.v2.Agent.UpdateLifecycle:input_type -> coder.agent.v2.UpdateLifecycleRequest + 21, // 43: coder.agent.v2.Agent.BatchUpdateAppHealths:input_type -> coder.agent.v2.BatchUpdateAppHealthRequest + 24, // 44: coder.agent.v2.Agent.UpdateStartup:input_type -> coder.agent.v2.UpdateStartupRequest + 26, // 45: coder.agent.v2.Agent.BatchUpdateMetadata:input_type -> coder.agent.v2.BatchUpdateMetadataRequest + 29, // 46: coder.agent.v2.Agent.BatchCreateLogs:input_type -> coder.agent.v2.BatchCreateLogsRequest + 31, // 47: coder.agent.v2.Agent.GetAnnouncementBanners:input_type -> coder.agent.v2.GetAnnouncementBannersRequest + 34, // 48: coder.agent.v2.Agent.ScriptCompleted:input_type -> coder.agent.v2.WorkspaceAgentScriptCompletedRequest + 12, // 49: coder.agent.v2.Agent.GetManifest:output_type -> coder.agent.v2.Manifest + 14, // 50: coder.agent.v2.Agent.GetServiceBanner:output_type -> coder.agent.v2.ServiceBanner + 18, // 51: coder.agent.v2.Agent.UpdateStats:output_type -> coder.agent.v2.UpdateStatsResponse + 19, // 52: coder.agent.v2.Agent.UpdateLifecycle:output_type -> coder.agent.v2.Lifecycle + 22, // 53: coder.agent.v2.Agent.BatchUpdateAppHealths:output_type -> coder.agent.v2.BatchUpdateAppHealthResponse + 23, // 54: coder.agent.v2.Agent.UpdateStartup:output_type -> coder.agent.v2.Startup + 27, // 55: coder.agent.v2.Agent.BatchUpdateMetadata:output_type -> coder.agent.v2.BatchUpdateMetadataResponse + 30, // 56: coder.agent.v2.Agent.BatchCreateLogs:output_type -> coder.agent.v2.BatchCreateLogsResponse + 32, // 57: coder.agent.v2.Agent.GetAnnouncementBanners:output_type -> coder.agent.v2.GetAnnouncementBannersResponse + 35, // 58: coder.agent.v2.Agent.ScriptCompleted:output_type -> coder.agent.v2.WorkspaceAgentScriptCompletedResponse + 49, // [49:59] is the sub-list for method output_type + 39, // [39:49] is the sub-list for method input_type + 39, // [39:39] is the sub-list for extension type_name + 39, // [39:39] is the sub-list for extension extendee + 0, // [0:39] is the sub-list for field type_name } func init() { file_agent_proto_agent_proto_init() } @@ -3271,7 +3605,7 @@ func file_agent_proto_agent_proto_init() { } } file_agent_proto_agent_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*WorkspaceApp_Healthcheck); i { + switch v := v.(*WorkspaceAgentScriptCompletedRequest); i { case 0: return &v.state case 1: @@ -3283,7 +3617,7 @@ func file_agent_proto_agent_proto_init() { } } file_agent_proto_agent_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*WorkspaceAgentMetadata_Result); i { + switch v := v.(*WorkspaceAgentScriptCompletedResponse); i { case 0: return &v.state case 1: @@ -3295,7 +3629,31 @@ func file_agent_proto_agent_proto_init() { } } file_agent_proto_agent_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*WorkspaceAgentMetadata_Description); i { + switch v := v.(*Timing); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_agent_proto_agent_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WorkspaceApp_Healthcheck); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_agent_proto_agent_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WorkspaceAgentMetadata_Result); i { case 0: return &v.state case 1: @@ -3307,6 +3665,18 @@ func file_agent_proto_agent_proto_init() { } } file_agent_proto_agent_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WorkspaceAgentMetadata_Description); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_agent_proto_agent_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Stats_Metric); i { case 0: return &v.state @@ -3318,7 +3688,7 @@ func file_agent_proto_agent_proto_init() { return nil } } - file_agent_proto_agent_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + file_agent_proto_agent_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Stats_Metric_Label); i { case 0: return &v.state @@ -3330,7 +3700,7 @@ func file_agent_proto_agent_proto_init() { return nil } } - file_agent_proto_agent_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + file_agent_proto_agent_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BatchUpdateAppHealthRequest_HealthUpdate); i { case 0: return &v.state @@ -3348,8 +3718,8 @@ func file_agent_proto_agent_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_agent_proto_agent_proto_rawDesc, - NumEnums: 7, - NumMessages: 33, + NumEnums: 9, + NumMessages: 36, NumExtensions: 0, NumServices: 1, }, diff --git a/agent/proto/agent.proto b/agent/proto/agent.proto index 001544b6d88da..f307066fcbfdf 100644 --- a/agent/proto/agent.proto +++ b/agent/proto/agent.proto @@ -54,6 +54,7 @@ message WorkspaceAgentScript { bool start_blocks_login = 7; google.protobuf.Duration timeout = 8; string display_name = 9; + bytes id = 10; } message WorkspaceAgentMetadata { @@ -265,6 +266,35 @@ message BannerConfig { string background_color = 3; } +message WorkspaceAgentScriptCompletedRequest { + Timing timing = 1; +} + +message WorkspaceAgentScriptCompletedResponse { +} + +message Timing { + bytes script_id = 1; + google.protobuf.Timestamp start = 2; + google.protobuf.Timestamp end = 3; + int32 exit_code = 4; + + enum Stage { + START = 0; + STOP = 1; + CRON = 2; + } + Stage stage = 5; + + enum Status { + OK = 0; + EXIT_FAILURE = 1; + TIMED_OUT = 2; + PIPES_LEFT_OPEN = 3; + } + Status status = 6; +} + service Agent { rpc GetManifest(GetManifestRequest) returns (Manifest); rpc GetServiceBanner(GetServiceBannerRequest) returns (ServiceBanner); @@ -275,4 +305,5 @@ service Agent { rpc BatchUpdateMetadata(BatchUpdateMetadataRequest) returns (BatchUpdateMetadataResponse); rpc BatchCreateLogs(BatchCreateLogsRequest) returns (BatchCreateLogsResponse); rpc GetAnnouncementBanners(GetAnnouncementBannersRequest) returns (GetAnnouncementBannersResponse); + rpc ScriptCompleted(WorkspaceAgentScriptCompletedRequest) returns (WorkspaceAgentScriptCompletedResponse); } diff --git a/agent/proto/agent_drpc.pb.go b/agent/proto/agent_drpc.pb.go index 09b3c972c2ce6..7bb1957230d76 100644 --- a/agent/proto/agent_drpc.pb.go +++ b/agent/proto/agent_drpc.pb.go @@ -47,6 +47,7 @@ type DRPCAgentClient interface { BatchUpdateMetadata(ctx context.Context, in *BatchUpdateMetadataRequest) (*BatchUpdateMetadataResponse, error) BatchCreateLogs(ctx context.Context, in *BatchCreateLogsRequest) (*BatchCreateLogsResponse, error) GetAnnouncementBanners(ctx context.Context, in *GetAnnouncementBannersRequest) (*GetAnnouncementBannersResponse, error) + ScriptCompleted(ctx context.Context, in *WorkspaceAgentScriptCompletedRequest) (*WorkspaceAgentScriptCompletedResponse, error) } type drpcAgentClient struct { @@ -140,6 +141,15 @@ func (c *drpcAgentClient) GetAnnouncementBanners(ctx context.Context, in *GetAnn return out, nil } +func (c *drpcAgentClient) ScriptCompleted(ctx context.Context, in *WorkspaceAgentScriptCompletedRequest) (*WorkspaceAgentScriptCompletedResponse, error) { + out := new(WorkspaceAgentScriptCompletedResponse) + err := c.cc.Invoke(ctx, "/coder.agent.v2.Agent/ScriptCompleted", drpcEncoding_File_agent_proto_agent_proto{}, in, out) + if err != nil { + return nil, err + } + return out, nil +} + type DRPCAgentServer interface { GetManifest(context.Context, *GetManifestRequest) (*Manifest, error) GetServiceBanner(context.Context, *GetServiceBannerRequest) (*ServiceBanner, error) @@ -150,6 +160,7 @@ type DRPCAgentServer interface { BatchUpdateMetadata(context.Context, *BatchUpdateMetadataRequest) (*BatchUpdateMetadataResponse, error) BatchCreateLogs(context.Context, *BatchCreateLogsRequest) (*BatchCreateLogsResponse, error) GetAnnouncementBanners(context.Context, *GetAnnouncementBannersRequest) (*GetAnnouncementBannersResponse, error) + ScriptCompleted(context.Context, *WorkspaceAgentScriptCompletedRequest) (*WorkspaceAgentScriptCompletedResponse, error) } type DRPCAgentUnimplementedServer struct{} @@ -190,9 +201,13 @@ func (s *DRPCAgentUnimplementedServer) GetAnnouncementBanners(context.Context, * return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) } +func (s *DRPCAgentUnimplementedServer) ScriptCompleted(context.Context, *WorkspaceAgentScriptCompletedRequest) (*WorkspaceAgentScriptCompletedResponse, error) { + return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) +} + type DRPCAgentDescription struct{} -func (DRPCAgentDescription) NumMethods() int { return 9 } +func (DRPCAgentDescription) NumMethods() int { return 10 } func (DRPCAgentDescription) Method(n int) (string, drpc.Encoding, drpc.Receiver, interface{}, bool) { switch n { @@ -277,6 +292,15 @@ func (DRPCAgentDescription) Method(n int) (string, drpc.Encoding, drpc.Receiver, in1.(*GetAnnouncementBannersRequest), ) }, DRPCAgentServer.GetAnnouncementBanners, true + case 9: + return "/coder.agent.v2.Agent/ScriptCompleted", drpcEncoding_File_agent_proto_agent_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return srv.(DRPCAgentServer). + ScriptCompleted( + ctx, + in1.(*WorkspaceAgentScriptCompletedRequest), + ) + }, DRPCAgentServer.ScriptCompleted, true default: return "", nil, nil, nil, false } @@ -429,3 +453,19 @@ func (x *drpcAgent_GetAnnouncementBannersStream) SendAndClose(m *GetAnnouncement } return x.CloseSend() } + +type DRPCAgent_ScriptCompletedStream interface { + drpc.Stream + SendAndClose(*WorkspaceAgentScriptCompletedResponse) error +} + +type drpcAgent_ScriptCompletedStream struct { + drpc.Stream +} + +func (x *drpcAgent_ScriptCompletedStream) SendAndClose(m *WorkspaceAgentScriptCompletedResponse) error { + if err := x.MsgSend(m, drpcEncoding_File_agent_proto_agent_proto{}); err != nil { + return err + } + return x.CloseSend() +} diff --git a/coderd/agentapi/api.go b/coderd/agentapi/api.go index 7aeb3a7de9d78..bea1fa5d881a3 100644 --- a/coderd/agentapi/api.go +++ b/coderd/agentapi/api.go @@ -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, diff --git a/coderd/agentapi/manifest.go b/coderd/agentapi/manifest.go index 6791fe168b4f5..a58bf6941cb04 100644 --- a/coderd/agentapi/manifest.go +++ b/coderd/agentapi/manifest.go @@ -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, diff --git a/coderd/agentapi/manifest_test.go b/coderd/agentapi/manifest_test.go index 546c70e16fc18..e7a36081f64b4 100644 --- a/coderd/agentapi/manifest_test.go +++ b/coderd/agentapi/manifest_test.go @@ -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, diff --git a/coderd/agentapi/scripts.go b/coderd/agentapi/scripts.go new file mode 100644 index 0000000000000..3aa085ade8a03 --- /dev/null +++ b/coderd/agentapi/scripts.go @@ -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 +} diff --git a/coderd/agentapi/scripts_test.go b/coderd/agentapi/scripts_test.go new file mode 100644 index 0000000000000..44c1841be3396 --- /dev/null +++ b/coderd/agentapi/scripts_test.go @@ -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 +} diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 37afc0ec80653..ebf9bf8ae075d 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -14263,6 +14263,10 @@ const docTemplate = `{ "display_name": { "type": "string" }, + "id": { + "type": "string", + "format": "uuid" + }, "log_path": { "type": "string" }, diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 9c511d9f07068..3a162713ed489 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -12989,6 +12989,10 @@ "display_name": { "type": "string" }, + "id": { + "type": "string", + "format": "uuid" + }, "log_path": { "type": "string" }, diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index 568b988e054c8..83ad60bb8351e 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -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 diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index 85bd179a95f44..10d5a32323a5f 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -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) })) diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index 7a85fa4143a01..dbf8e5514ea2e 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -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], diff --git a/coderd/database/dbmetrics/dbmetrics.go b/coderd/database/dbmetrics/dbmetrics.go index f982c1db51686..afdd6e35a14a2 100644 --- a/coderd/database/dbmetrics/dbmetrics.go +++ b/coderd/database/dbmetrics/dbmetrics.go @@ -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) diff --git a/coderd/database/dbmock/dbmock.go b/coderd/database/dbmock/dbmock.go index 470e9cb491c47..d85f29e154f17 100644 --- a/coderd/database/dbmock/dbmock.go +++ b/coderd/database/dbmock/dbmock.go @@ -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() diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index b1aa3cc24691a..27c384e794239 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -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; diff --git a/coderd/database/foreign_key_constraint.go b/coderd/database/foreign_key_constraint.go index 907cebed6d8e0..f142e729b2f38 100644 --- a/coderd/database/foreign_key_constraint.go +++ b/coderd/database/foreign_key_constraint.go @@ -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; diff --git a/coderd/database/migrations/000257_workspace_agent_script_timings.down.sql b/coderd/database/migrations/000257_workspace_agent_script_timings.down.sql new file mode 100644 index 0000000000000..2d31e89383ca6 --- /dev/null +++ b/coderd/database/migrations/000257_workspace_agent_script_timings.down.sql @@ -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; diff --git a/coderd/database/migrations/000257_workspace_agent_script_timings.up.sql b/coderd/database/migrations/000257_workspace_agent_script_timings.up.sql new file mode 100644 index 0000000000000..1eb28f99b5d87 --- /dev/null +++ b/coderd/database/migrations/000257_workspace_agent_script_timings.up.sql @@ -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.'; diff --git a/coderd/database/migrations/testdata/fixtures/000257_workspace_agent_script_timings.up.sql b/coderd/database/migrations/testdata/fixtures/000257_workspace_agent_script_timings.up.sql new file mode 100644 index 0000000000000..d38b7e8c5d4ed --- /dev/null +++ b/coderd/database/migrations/testdata/fixtures/000257_workspace_agent_script_timings.up.sql @@ -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'); diff --git a/coderd/database/models.go b/coderd/database/models.go index a5a1679b5b55c..87ef020e8be5e 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -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 { diff --git a/coderd/database/querier.go b/coderd/database/querier.go index cad3df1cd6834..46086fa72d072 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -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) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 74990ab1103bd..a8ea40a395cf1 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -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 } diff --git a/coderd/database/queries/workspaceagents.sql b/coderd/database/queries/workspaceagents.sql index 9c5860bf494a6..1020aba219920 100644 --- a/coderd/database/queries/workspaceagents.sql +++ b/coderd/database/queries/workspaceagents.sql @@ -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); diff --git a/coderd/database/queries/workspacescripts.sql b/coderd/database/queries/workspacescripts.sql index 796627c62ad1f..aa1407647bd0c 100644 --- a/coderd/database/queries/workspacescripts.sql +++ b/coderd/database/queries/workspacescripts.sql @@ -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 diff --git a/coderd/database/unique_constraint.go b/coderd/database/unique_constraint.go index 92e1515475420..f4470c6546698 100644 --- a/coderd/database/unique_constraint.go +++ b/coderd/database/unique_constraint.go @@ -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); diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go index 84739ac9cd78a..2db5bbd1062b1 100644 --- a/coderd/provisionerdserver/provisionerdserver.go +++ b/coderd/provisionerdserver/provisionerdserver.go @@ -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) diff --git a/coderd/workspaceagents.go b/coderd/workspaceagents.go index 109010444ae56..4b1af869cc007 100644 --- a/coderd/workspaceagents.go +++ b/coderd/workspaceagents.go @@ -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, diff --git a/codersdk/agentsdk/convert.go b/codersdk/agentsdk/convert.go index 10462f293378e..002d96a50a017 100644 --- a/codersdk/agentsdk/convert.go +++ b/codersdk/agentsdk/convert.go @@ -158,13 +158,19 @@ func ProtoFromScripts(scripts []codersdk.WorkspaceAgentScript) []*proto.Workspac } func AgentScriptFromProto(protoScript *proto.WorkspaceAgentScript) (codersdk.WorkspaceAgentScript, error) { - id, err := uuid.FromBytes(protoScript.LogSourceId) + id, err := uuid.FromBytes(protoScript.Id) if err != nil { return codersdk.WorkspaceAgentScript{}, xerrors.Errorf("parse id: %w", err) } + logSourceID, err := uuid.FromBytes(protoScript.LogSourceId) + if err != nil { + return codersdk.WorkspaceAgentScript{}, xerrors.Errorf("parse log source id: %w", err) + } + return codersdk.WorkspaceAgentScript{ - LogSourceID: id, + ID: id, + LogSourceID: logSourceID, LogPath: protoScript.LogPath, Script: protoScript.Script, Cron: protoScript.Cron, @@ -178,6 +184,7 @@ func AgentScriptFromProto(protoScript *proto.WorkspaceAgentScript) (codersdk.Wor func ProtoFromScript(s codersdk.WorkspaceAgentScript) *proto.WorkspaceAgentScript { return &proto.WorkspaceAgentScript{ + Id: s.ID[:], LogSourceId: s.LogSourceID[:], LogPath: s.LogPath, Script: s.Script, diff --git a/codersdk/agentsdk/convert_test.go b/codersdk/agentsdk/convert_test.go index b302d3c0c1a07..6e42c0e1ce420 100644 --- a/codersdk/agentsdk/convert_test.go +++ b/codersdk/agentsdk/convert_test.go @@ -106,6 +106,7 @@ func TestManifest(t *testing.T) { }, Scripts: []codersdk.WorkspaceAgentScript{ { + ID: uuid.New(), LogSourceID: uuid.New(), LogPath: "/var/log/script.log", Script: "script", @@ -117,6 +118,7 @@ func TestManifest(t *testing.T) { DisplayName: "foo", }, { + ID: uuid.New(), LogSourceID: uuid.New(), LogPath: "/var/log/script2.log", Script: "script2", diff --git a/codersdk/workspaceagents.go b/codersdk/workspaceagents.go index 4d1df36361039..eeb335b130cdd 100644 --- a/codersdk/workspaceagents.go +++ b/codersdk/workspaceagents.go @@ -185,6 +185,7 @@ type WorkspaceAgentLogSource struct { } type WorkspaceAgentScript struct { + ID uuid.UUID `json:"id" format:"uuid"` LogSourceID uuid.UUID `json:"log_source_id" format:"uuid"` LogPath string `json:"log_path"` Script string `json:"script"` diff --git a/docs/reference/api/agents.md b/docs/reference/api/agents.md index ee15d88b2b3be..8e7f46bc7d366 100644 --- a/docs/reference/api/agents.md +++ b/docs/reference/api/agents.md @@ -488,6 +488,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaceagents/{workspaceagent} \ { "cron": "string", "display_name": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "log_path": "string", "log_source_id": "4197ab25-95cf-4b91-9c78-f7f2af5d353a", "run_on_start": true, diff --git a/docs/reference/api/builds.md b/docs/reference/api/builds.md index c40e5171ddb52..c0f1658e8ec8a 100644 --- a/docs/reference/api/builds.md +++ b/docs/reference/api/builds.md @@ -129,6 +129,7 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/workspace/{workspacenam { "cron": "string", "display_name": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "log_path": "string", "log_source_id": "4197ab25-95cf-4b91-9c78-f7f2af5d353a", "run_on_start": true, @@ -313,6 +314,7 @@ curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild} \ { "cron": "string", "display_name": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "log_path": "string", "log_source_id": "4197ab25-95cf-4b91-9c78-f7f2af5d353a", "run_on_start": true, @@ -636,6 +638,7 @@ curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild}/res { "cron": "string", "display_name": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "log_path": "string", "log_source_id": "4197ab25-95cf-4b91-9c78-f7f2af5d353a", "run_on_start": true, @@ -742,6 +745,7 @@ Status Code **200** | `»» scripts` | array | false | | | | `»»» cron` | string | false | | | | `»»» display_name` | string | false | | | +| `»»» id` | string(uuid) | false | | | | `»»» log_path` | string | false | | | | `»»» log_source_id` | string(uuid) | false | | | | `»»» run_on_start` | boolean | false | | | @@ -929,6 +933,7 @@ curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild}/sta { "cron": "string", "display_name": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "log_path": "string", "log_source_id": "4197ab25-95cf-4b91-9c78-f7f2af5d353a", "run_on_start": true, @@ -1118,6 +1123,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace}/builds \ { "cron": "string", "display_name": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "log_path": "string", "log_source_id": "4197ab25-95cf-4b91-9c78-f7f2af5d353a", "run_on_start": true, @@ -1261,6 +1267,7 @@ Status Code **200** | `»»» scripts` | array | false | | | | `»»»» cron` | string | false | | | | `»»»» display_name` | string | false | | | +| `»»»» id` | string(uuid) | false | | | | `»»»» log_path` | string | false | | | | `»»»» log_source_id` | string(uuid) | false | | | | `»»»» run_on_start` | boolean | false | | | @@ -1502,6 +1509,7 @@ curl -X POST http://coder-server:8080/api/v2/workspaces/{workspace}/builds \ { "cron": "string", "display_name": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "log_path": "string", "log_source_id": "4197ab25-95cf-4b91-9c78-f7f2af5d353a", "run_on_start": true, diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md index 7e440d977da7e..c8f58d591170b 100644 --- a/docs/reference/api/schemas.md +++ b/docs/reference/api/schemas.md @@ -6455,6 +6455,7 @@ If the schedule is empty, the user will be updated to use the default schedule.| { "cron": "string", "display_name": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "log_path": "string", "log_source_id": "4197ab25-95cf-4b91-9c78-f7f2af5d353a", "run_on_start": true, @@ -6635,6 +6636,7 @@ If the schedule is empty, the user will be updated to use the default schedule.| { "cron": "string", "display_name": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "log_path": "string", "log_source_id": "4197ab25-95cf-4b91-9c78-f7f2af5d353a", "run_on_start": true, @@ -6904,6 +6906,7 @@ If the schedule is empty, the user will be updated to use the default schedule.| { "cron": "string", "display_name": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "log_path": "string", "log_source_id": "4197ab25-95cf-4b91-9c78-f7f2af5d353a", "run_on_start": true, @@ -6920,6 +6923,7 @@ If the schedule is empty, the user will be updated to use the default schedule.| | -------------------- | ------- | -------- | ------------ | ----------- | | `cron` | string | false | | | | `display_name` | string | false | | | +| `id` | string | false | | | | `log_path` | string | false | | | | `log_source_id` | string | false | | | | `run_on_start` | boolean | false | | | @@ -7149,6 +7153,7 @@ If the schedule is empty, the user will be updated to use the default schedule.| { "cron": "string", "display_name": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "log_path": "string", "log_source_id": "4197ab25-95cf-4b91-9c78-f7f2af5d353a", "run_on_start": true, @@ -7485,6 +7490,7 @@ If the schedule is empty, the user will be updated to use the default schedule.| { "cron": "string", "display_name": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "log_path": "string", "log_source_id": "4197ab25-95cf-4b91-9c78-f7f2af5d353a", "run_on_start": true, @@ -7746,6 +7752,7 @@ If the schedule is empty, the user will be updated to use the default schedule.| { "cron": "string", "display_name": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "log_path": "string", "log_source_id": "4197ab25-95cf-4b91-9c78-f7f2af5d353a", "run_on_start": true, diff --git a/docs/reference/api/templates.md b/docs/reference/api/templates.md index bd346e5b5a542..ceda61533ef5b 100644 --- a/docs/reference/api/templates.md +++ b/docs/reference/api/templates.md @@ -2001,6 +2001,7 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/d { "cron": "string", "display_name": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "log_path": "string", "log_source_id": "4197ab25-95cf-4b91-9c78-f7f2af5d353a", "run_on_start": true, @@ -2107,6 +2108,7 @@ Status Code **200** | `»» scripts` | array | false | | | | `»»» cron` | string | false | | | | `»»» display_name` | string | false | | | +| `»»» id` | string(uuid) | false | | | | `»»» log_path` | string | false | | | | `»»» log_source_id` | string(uuid) | false | | | | `»»» run_on_start` | boolean | false | | | @@ -2425,6 +2427,7 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/r { "cron": "string", "display_name": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "log_path": "string", "log_source_id": "4197ab25-95cf-4b91-9c78-f7f2af5d353a", "run_on_start": true, @@ -2531,6 +2534,7 @@ Status Code **200** | `»» scripts` | array | false | | | | `»»» cron` | string | false | | | | `»»» display_name` | string | false | | | +| `»»» id` | string(uuid) | false | | | | `»»» log_path` | string | false | | | | `»»» log_source_id` | string(uuid) | false | | | | `»»» run_on_start` | boolean | false | | | diff --git a/docs/reference/api/workspaces.md b/docs/reference/api/workspaces.md index 387c221639401..2987cf65159e4 100644 --- a/docs/reference/api/workspaces.md +++ b/docs/reference/api/workspaces.md @@ -168,6 +168,7 @@ of the template will be used. { "cron": "string", "display_name": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "log_path": "string", "log_source_id": "4197ab25-95cf-4b91-9c78-f7f2af5d353a", "run_on_start": true, @@ -385,6 +386,7 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/workspace/{workspacenam { "cron": "string", "display_name": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "log_path": "string", "log_source_id": "4197ab25-95cf-4b91-9c78-f7f2af5d353a", "run_on_start": true, @@ -626,6 +628,7 @@ of the template will be used. { "cron": "string", "display_name": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "log_path": "string", "log_source_id": "4197ab25-95cf-4b91-9c78-f7f2af5d353a", "run_on_start": true, @@ -842,6 +845,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces \ { "cron": "string", "display_name": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "log_path": "string", "log_source_id": "4197ab25-95cf-4b91-9c78-f7f2af5d353a", "run_on_start": true, @@ -1060,6 +1064,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace} \ { "cron": "string", "display_name": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "log_path": "string", "log_source_id": "4197ab25-95cf-4b91-9c78-f7f2af5d353a", "run_on_start": true, @@ -1393,6 +1398,7 @@ curl -X PUT http://coder-server:8080/api/v2/workspaces/{workspace}/dormant \ { "cron": "string", "display_name": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "log_path": "string", "log_source_id": "4197ab25-95cf-4b91-9c78-f7f2af5d353a", "run_on_start": true, diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index b943f7b40ba10..35f393e567f1e 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -1887,6 +1887,7 @@ export interface WorkspaceAgentPortShares { // From codersdk/workspaceagents.go export interface WorkspaceAgentScript { + readonly id: string; readonly log_source_id: string; readonly log_path: string; readonly script: string; diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index 0bf829bb1e876..9bd865b127c42 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -886,6 +886,7 @@ export const MockWorkspaceAgentLogSource: TypesGen.WorkspaceAgentLogSource = { }; export const MockWorkspaceAgentScript: TypesGen.WorkspaceAgentScript = { + id: "08eaca83-1221-4fad-b882-d1136981f54d", log_source_id: MockWorkspaceAgentLogSource.id, cron: "", log_path: "", pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy