diff --git a/.github/workflows/docs-ci.yaml b/.github/workflows/docs-ci.yaml index ef7114a8e2..37e8c56268 100644 --- a/.github/workflows/docs-ci.yaml +++ b/.github/workflows/docs-ci.yaml @@ -15,6 +15,9 @@ on: - "**.md" - ".github/workflows/docs-ci.yaml" +permissions: + contents: read + jobs: docs: runs-on: ubuntu-latest diff --git a/agent/agent.go b/agent/agent.go index b05648c9c8..65ca33a962 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -41,8 +41,10 @@ import ( "github.com/coder/coder/v2/agent/agentscripts" "github.com/coder/coder/v2/agent/agentssh" "github.com/coder/coder/v2/agent/proto" + "github.com/coder/coder/v2/agent/proto/resourcesmonitor" "github.com/coder/coder/v2/agent/reconnectingpty" "github.com/coder/coder/v2/buildinfo" + "github.com/coder/coder/v2/cli/clistat" "github.com/coder/coder/v2/cli/gitauth" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/codersdk" @@ -50,6 +52,7 @@ import ( "github.com/coder/coder/v2/codersdk/workspacesdk" "github.com/coder/coder/v2/tailnet" tailnetproto "github.com/coder/coder/v2/tailnet/proto" + "github.com/coder/quartz" ) const ( @@ -89,8 +92,8 @@ type Options struct { } type Client interface { - ConnectRPC23(ctx context.Context) ( - proto.DRPCAgentClient23, tailnetproto.DRPCTailnetClient23, error, + ConnectRPC24(ctx context.Context) ( + proto.DRPCAgentClient24, tailnetproto.DRPCTailnetClient24, error, ) RewriteDERPMap(derpMap *tailcfg.DERPMap) } @@ -410,7 +413,7 @@ func (t *trySingleflight) Do(key string, fn func()) { fn() } -func (a *agent) reportMetadata(ctx context.Context, aAPI proto.DRPCAgentClient23) error { +func (a *agent) reportMetadata(ctx context.Context, aAPI proto.DRPCAgentClient24) error { tickerDone := make(chan struct{}) collectDone := make(chan struct{}) ctx, cancel := context.WithCancel(ctx) @@ -626,7 +629,7 @@ func (a *agent) reportMetadata(ctx context.Context, aAPI proto.DRPCAgentClient23 // reportLifecycle reports the current lifecycle state once. All state // changes are reported in order. -func (a *agent) reportLifecycle(ctx context.Context, aAPI proto.DRPCAgentClient23) error { +func (a *agent) reportLifecycle(ctx context.Context, aAPI proto.DRPCAgentClient24) error { for { select { case <-a.lifecycleUpdate: @@ -708,7 +711,7 @@ func (a *agent) setLifecycle(state codersdk.WorkspaceAgentLifecycle) { // fetchServiceBannerLoop fetches the service banner on an interval. It will // not be fetched immediately; the expectation is that it is primed elsewhere // (and must be done before the session actually starts). -func (a *agent) fetchServiceBannerLoop(ctx context.Context, aAPI proto.DRPCAgentClient23) error { +func (a *agent) fetchServiceBannerLoop(ctx context.Context, aAPI proto.DRPCAgentClient24) error { ticker := time.NewTicker(a.announcementBannersRefreshInterval) defer ticker.Stop() for { @@ -744,7 +747,7 @@ func (a *agent) run() (retErr error) { a.sessionToken.Store(&sessionToken) // ConnectRPC returns the dRPC connection we use for the Agent and Tailnet v2+ APIs - aAPI, tAPI, err := a.client.ConnectRPC23(a.hardCtx) + aAPI, tAPI, err := a.client.ConnectRPC24(a.hardCtx) if err != nil { return err } @@ -761,7 +764,7 @@ func (a *agent) run() (retErr error) { connMan := newAPIConnRoutineManager(a.gracefulCtx, a.hardCtx, a.logger, aAPI, tAPI) connMan.startAgentAPI("init notification banners", gracefulShutdownBehaviorStop, - func(ctx context.Context, aAPI proto.DRPCAgentClient23) error { + func(ctx context.Context, aAPI proto.DRPCAgentClient24) error { bannersProto, err := aAPI.GetAnnouncementBanners(ctx, &proto.GetAnnouncementBannersRequest{}) if err != nil { return xerrors.Errorf("fetch service banner: %w", err) @@ -778,7 +781,7 @@ func (a *agent) run() (retErr error) { // sending logs gets gracefulShutdownBehaviorRemain because we want to send logs generated by // shutdown scripts. connMan.startAgentAPI("send logs", gracefulShutdownBehaviorRemain, - func(ctx context.Context, aAPI proto.DRPCAgentClient23) error { + func(ctx context.Context, aAPI proto.DRPCAgentClient24) error { err := a.logSender.SendLoop(ctx, aAPI) if xerrors.Is(err, agentsdk.LogLimitExceededError) { // we don't want this error to tear down the API connection and propagate to the @@ -796,6 +799,25 @@ func (a *agent) run() (retErr error) { // metadata reporting can cease as soon as we start gracefully shutting down connMan.startAgentAPI("report metadata", gracefulShutdownBehaviorStop, a.reportMetadata) + // resources monitor can cease as soon as we start gracefully shutting down. + connMan.startAgentAPI("resources monitor", gracefulShutdownBehaviorStop, func(ctx context.Context, aAPI proto.DRPCAgentClient24) error { + logger := a.logger.Named("resources_monitor") + clk := quartz.NewReal() + config, err := aAPI.GetResourcesMonitoringConfiguration(ctx, &proto.GetResourcesMonitoringConfigurationRequest{}) + if err != nil { + return xerrors.Errorf("failed to get resources monitoring configuration: %w", err) + } + + statfetcher, err := clistat.New() + if err != nil { + return xerrors.Errorf("failed to create resources fetcher: %w", err) + } + resourcesFetcher := resourcesmonitor.NewFetcher(statfetcher) + + resourcesmonitor := resourcesmonitor.NewResourcesMonitor(logger, clk, config, resourcesFetcher, aAPI) + return resourcesmonitor.Start(ctx) + }) + // channels to sync goroutines below // handle manifest // | @@ -818,7 +840,7 @@ func (a *agent) run() (retErr error) { connMan.startAgentAPI("handle manifest", gracefulShutdownBehaviorStop, a.handleManifest(manifestOK)) connMan.startAgentAPI("app health reporter", gracefulShutdownBehaviorStop, - func(ctx context.Context, aAPI proto.DRPCAgentClient23) error { + func(ctx context.Context, aAPI proto.DRPCAgentClient24) error { if err := manifestOK.wait(ctx); err != nil { return xerrors.Errorf("no manifest: %w", err) } @@ -833,7 +855,7 @@ func (a *agent) run() (retErr error) { a.createOrUpdateNetwork(manifestOK, networkOK)) connMan.startTailnetAPI("coordination", gracefulShutdownBehaviorStop, - func(ctx context.Context, tAPI tailnetproto.DRPCTailnetClient23) error { + func(ctx context.Context, tAPI tailnetproto.DRPCTailnetClient24) error { if err := networkOK.wait(ctx); err != nil { return xerrors.Errorf("no network: %w", err) } @@ -842,7 +864,7 @@ func (a *agent) run() (retErr error) { ) connMan.startTailnetAPI("derp map subscriber", gracefulShutdownBehaviorStop, - func(ctx context.Context, tAPI tailnetproto.DRPCTailnetClient23) error { + func(ctx context.Context, tAPI tailnetproto.DRPCTailnetClient24) error { if err := networkOK.wait(ctx); err != nil { return xerrors.Errorf("no network: %w", err) } @@ -851,7 +873,7 @@ func (a *agent) run() (retErr error) { connMan.startAgentAPI("fetch service banner loop", gracefulShutdownBehaviorStop, a.fetchServiceBannerLoop) - connMan.startAgentAPI("stats report loop", gracefulShutdownBehaviorStop, func(ctx context.Context, aAPI proto.DRPCAgentClient23) error { + connMan.startAgentAPI("stats report loop", gracefulShutdownBehaviorStop, func(ctx context.Context, aAPI proto.DRPCAgentClient24) error { if err := networkOK.wait(ctx); err != nil { return xerrors.Errorf("no network: %w", err) } @@ -864,8 +886,8 @@ func (a *agent) run() (retErr error) { } // handleManifest returns a function that fetches and processes the manifest -func (a *agent) handleManifest(manifestOK *checkpoint) func(ctx context.Context, aAPI proto.DRPCAgentClient23) error { - return func(ctx context.Context, aAPI proto.DRPCAgentClient23) error { +func (a *agent) handleManifest(manifestOK *checkpoint) func(ctx context.Context, aAPI proto.DRPCAgentClient24) error { + return func(ctx context.Context, aAPI proto.DRPCAgentClient24) error { var ( sentResult = false err error @@ -974,8 +996,8 @@ func (a *agent) handleManifest(manifestOK *checkpoint) func(ctx context.Context, // createOrUpdateNetwork waits for the manifest to be set using manifestOK, then creates or updates // the tailnet using the information in the manifest -func (a *agent) createOrUpdateNetwork(manifestOK, networkOK *checkpoint) func(context.Context, proto.DRPCAgentClient23) error { - return func(ctx context.Context, _ proto.DRPCAgentClient23) (retErr error) { +func (a *agent) createOrUpdateNetwork(manifestOK, networkOK *checkpoint) func(context.Context, proto.DRPCAgentClient24) error { + return func(ctx context.Context, _ proto.DRPCAgentClient24) (retErr error) { if err := manifestOK.wait(ctx); err != nil { return xerrors.Errorf("no manifest: %w", err) } @@ -1279,7 +1301,7 @@ func (a *agent) createTailnet(ctx context.Context, agentID uuid.UUID, derpMap *t // runCoordinator runs a coordinator and returns whether a reconnect // should occur. -func (a *agent) runCoordinator(ctx context.Context, tClient tailnetproto.DRPCTailnetClient23, network *tailnet.Conn) error { +func (a *agent) runCoordinator(ctx context.Context, tClient tailnetproto.DRPCTailnetClient24, network *tailnet.Conn) error { defer a.logger.Debug(ctx, "disconnected from coordination RPC") // we run the RPC on the hardCtx so that we have a chance to send the disconnect message if we // gracefully shut down. @@ -1326,7 +1348,7 @@ func (a *agent) runCoordinator(ctx context.Context, tClient tailnetproto.DRPCTai } // runDERPMapSubscriber runs a coordinator and returns if a reconnect should occur. -func (a *agent) runDERPMapSubscriber(ctx context.Context, tClient tailnetproto.DRPCTailnetClient23, network *tailnet.Conn) error { +func (a *agent) runDERPMapSubscriber(ctx context.Context, tClient tailnetproto.DRPCTailnetClient24, network *tailnet.Conn) error { defer a.logger.Debug(ctx, "disconnected from derp map RPC") ctx, cancel := context.WithCancel(ctx) defer cancel() @@ -1696,8 +1718,8 @@ const ( type apiConnRoutineManager struct { logger slog.Logger - aAPI proto.DRPCAgentClient23 - tAPI tailnetproto.DRPCTailnetClient23 + aAPI proto.DRPCAgentClient24 + tAPI tailnetproto.DRPCTailnetClient24 eg *errgroup.Group stopCtx context.Context remainCtx context.Context @@ -1705,7 +1727,7 @@ type apiConnRoutineManager struct { func newAPIConnRoutineManager( gracefulCtx, hardCtx context.Context, logger slog.Logger, - aAPI proto.DRPCAgentClient23, tAPI tailnetproto.DRPCTailnetClient23, + aAPI proto.DRPCAgentClient24, tAPI tailnetproto.DRPCTailnetClient24, ) *apiConnRoutineManager { // routines that remain in operation during graceful shutdown use the remainCtx. They'll still // exit if the errgroup hits an error, which usually means a problem with the conn. @@ -1738,7 +1760,7 @@ func newAPIConnRoutineManager( // but for Tailnet. func (a *apiConnRoutineManager) startAgentAPI( name string, behavior gracefulShutdownBehavior, - f func(context.Context, proto.DRPCAgentClient23) error, + f func(context.Context, proto.DRPCAgentClient24) error, ) { logger := a.logger.With(slog.F("name", name)) var ctx context.Context @@ -1775,7 +1797,7 @@ func (a *apiConnRoutineManager) startAgentAPI( // but for the Agent API. func (a *apiConnRoutineManager) startTailnetAPI( name string, behavior gracefulShutdownBehavior, - f func(context.Context, tailnetproto.DRPCTailnetClient23) error, + f func(context.Context, tailnetproto.DRPCTailnetClient24) error, ) { logger := a.logger.With(slog.F("name", name)) var ctx context.Context diff --git a/agent/agenttest/client.go b/agent/agenttest/client.go index fbd1ce7060..ea53ae9a67 100644 --- a/agent/agenttest/client.go +++ b/agent/agenttest/client.go @@ -97,8 +97,8 @@ func (c *Client) Close() { c.derpMapOnce.Do(func() { close(c.derpMapUpdates) }) } -func (c *Client) ConnectRPC23(ctx context.Context) ( - agentproto.DRPCAgentClient23, proto.DRPCTailnetClient23, error, +func (c *Client) ConnectRPC24(ctx context.Context) ( + agentproto.DRPCAgentClient24, proto.DRPCTailnetClient24, error, ) { conn, lis := drpcsdk.MemTransportPipe() c.LastWorkspaceAgent = func() { @@ -172,7 +172,9 @@ type FakeAgentAPI struct { metadata map[string]agentsdk.Metadata timings []*agentproto.Timing - getAnnouncementBannersFunc func() ([]codersdk.BannerConfig, error) + getAnnouncementBannersFunc func() ([]codersdk.BannerConfig, error) + getResourcesMonitoringConfigurationFunc func() (*agentproto.GetResourcesMonitoringConfigurationResponse, error) + pushResourcesMonitoringUsageFunc func(*agentproto.PushResourcesMonitoringUsageRequest) (*agentproto.PushResourcesMonitoringUsageResponse, error) } func (f *FakeAgentAPI) GetManifest(context.Context, *agentproto.GetManifestRequest) (*agentproto.Manifest, error) { @@ -213,6 +215,33 @@ func (f *FakeAgentAPI) GetAnnouncementBanners(context.Context, *agentproto.GetAn return &agentproto.GetAnnouncementBannersResponse{AnnouncementBanners: bannersProto}, nil } +func (f *FakeAgentAPI) GetResourcesMonitoringConfiguration(_ context.Context, _ *agentproto.GetResourcesMonitoringConfigurationRequest) (*agentproto.GetResourcesMonitoringConfigurationResponse, error) { + f.Lock() + defer f.Unlock() + + if f.getResourcesMonitoringConfigurationFunc == nil { + return &agentproto.GetResourcesMonitoringConfigurationResponse{ + Config: &agentproto.GetResourcesMonitoringConfigurationResponse_Config{ + CollectionIntervalSeconds: 10, + NumDatapoints: 20, + }, + }, nil + } + + return f.getResourcesMonitoringConfigurationFunc() +} + +func (f *FakeAgentAPI) PushResourcesMonitoringUsage(_ context.Context, req *agentproto.PushResourcesMonitoringUsageRequest) (*agentproto.PushResourcesMonitoringUsageResponse, error) { + f.Lock() + defer f.Unlock() + + if f.pushResourcesMonitoringUsageFunc == nil { + return &agentproto.PushResourcesMonitoringUsageResponse{}, nil + } + + return f.pushResourcesMonitoringUsageFunc(req) +} + func (f *FakeAgentAPI) UpdateStats(ctx context.Context, req *agentproto.UpdateStatsRequest) (*agentproto.UpdateStatsResponse, error) { f.logger.Debug(ctx, "update stats called", slog.F("req", req)) // empty request is sent to get the interval; but our tests don't want empty stats requests diff --git a/agent/proto/agent.pb.go b/agent/proto/agent.pb.go index 4b90e0cf60..613ce3d2d6 100644 --- a/agent/proto/agent.pb.go +++ b/agent/proto/agent.pb.go @@ -2304,6 +2304,192 @@ func (x *Timing) GetStatus() Timing_Status { return Timing_OK } +type GetResourcesMonitoringConfigurationRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetResourcesMonitoringConfigurationRequest) Reset() { + *x = GetResourcesMonitoringConfigurationRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetResourcesMonitoringConfigurationRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetResourcesMonitoringConfigurationRequest) ProtoMessage() {} + +func (x *GetResourcesMonitoringConfigurationRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[28] + 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 GetResourcesMonitoringConfigurationRequest.ProtoReflect.Descriptor instead. +func (*GetResourcesMonitoringConfigurationRequest) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{28} +} + +type GetResourcesMonitoringConfigurationResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Config *GetResourcesMonitoringConfigurationResponse_Config `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"` + Memory *GetResourcesMonitoringConfigurationResponse_Memory `protobuf:"bytes,2,opt,name=memory,proto3,oneof" json:"memory,omitempty"` + Volumes []*GetResourcesMonitoringConfigurationResponse_Volume `protobuf:"bytes,3,rep,name=volumes,proto3" json:"volumes,omitempty"` +} + +func (x *GetResourcesMonitoringConfigurationResponse) Reset() { + *x = GetResourcesMonitoringConfigurationResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetResourcesMonitoringConfigurationResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetResourcesMonitoringConfigurationResponse) ProtoMessage() {} + +func (x *GetResourcesMonitoringConfigurationResponse) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[29] + 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 GetResourcesMonitoringConfigurationResponse.ProtoReflect.Descriptor instead. +func (*GetResourcesMonitoringConfigurationResponse) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{29} +} + +func (x *GetResourcesMonitoringConfigurationResponse) GetConfig() *GetResourcesMonitoringConfigurationResponse_Config { + if x != nil { + return x.Config + } + return nil +} + +func (x *GetResourcesMonitoringConfigurationResponse) GetMemory() *GetResourcesMonitoringConfigurationResponse_Memory { + if x != nil { + return x.Memory + } + return nil +} + +func (x *GetResourcesMonitoringConfigurationResponse) GetVolumes() []*GetResourcesMonitoringConfigurationResponse_Volume { + if x != nil { + return x.Volumes + } + return nil +} + +type PushResourcesMonitoringUsageRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Datapoints []*PushResourcesMonitoringUsageRequest_Datapoint `protobuf:"bytes,1,rep,name=datapoints,proto3" json:"datapoints,omitempty"` +} + +func (x *PushResourcesMonitoringUsageRequest) Reset() { + *x = PushResourcesMonitoringUsageRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PushResourcesMonitoringUsageRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PushResourcesMonitoringUsageRequest) ProtoMessage() {} + +func (x *PushResourcesMonitoringUsageRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[30] + 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 PushResourcesMonitoringUsageRequest.ProtoReflect.Descriptor instead. +func (*PushResourcesMonitoringUsageRequest) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{30} +} + +func (x *PushResourcesMonitoringUsageRequest) GetDatapoints() []*PushResourcesMonitoringUsageRequest_Datapoint { + if x != nil { + return x.Datapoints + } + return nil +} + +type PushResourcesMonitoringUsageResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *PushResourcesMonitoringUsageResponse) Reset() { + *x = PushResourcesMonitoringUsageResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PushResourcesMonitoringUsageResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PushResourcesMonitoringUsageResponse) ProtoMessage() {} + +func (x *PushResourcesMonitoringUsageResponse) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[31] + 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 PushResourcesMonitoringUsageResponse.ProtoReflect.Descriptor instead. +func (*PushResourcesMonitoringUsageResponse) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{31} +} + type WorkspaceApp_Healthcheck struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2317,7 +2503,7 @@ type WorkspaceApp_Healthcheck struct { func (x *WorkspaceApp_Healthcheck) Reset() { *x = WorkspaceApp_Healthcheck{} if protoimpl.UnsafeEnabled { - mi := &file_agent_proto_agent_proto_msgTypes[28] + mi := &file_agent_proto_agent_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2330,7 +2516,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[28] + mi := &file_agent_proto_agent_proto_msgTypes[32] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2381,7 +2567,7 @@ type WorkspaceAgentMetadata_Result struct { func (x *WorkspaceAgentMetadata_Result) Reset() { *x = WorkspaceAgentMetadata_Result{} if protoimpl.UnsafeEnabled { - mi := &file_agent_proto_agent_proto_msgTypes[29] + mi := &file_agent_proto_agent_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2394,7 +2580,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[29] + mi := &file_agent_proto_agent_proto_msgTypes[33] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2453,7 +2639,7 @@ type WorkspaceAgentMetadata_Description struct { func (x *WorkspaceAgentMetadata_Description) Reset() { *x = WorkspaceAgentMetadata_Description{} if protoimpl.UnsafeEnabled { - mi := &file_agent_proto_agent_proto_msgTypes[30] + mi := &file_agent_proto_agent_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2466,7 +2652,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[30] + mi := &file_agent_proto_agent_proto_msgTypes[34] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2531,7 +2717,7 @@ type Stats_Metric struct { func (x *Stats_Metric) Reset() { *x = Stats_Metric{} if protoimpl.UnsafeEnabled { - mi := &file_agent_proto_agent_proto_msgTypes[33] + mi := &file_agent_proto_agent_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2544,7 +2730,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[33] + mi := &file_agent_proto_agent_proto_msgTypes[37] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2600,7 +2786,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[34] + mi := &file_agent_proto_agent_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2613,7 +2799,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[34] + mi := &file_agent_proto_agent_proto_msgTypes[38] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2655,7 +2841,7 @@ type BatchUpdateAppHealthRequest_HealthUpdate struct { func (x *BatchUpdateAppHealthRequest_HealthUpdate) Reset() { *x = BatchUpdateAppHealthRequest_HealthUpdate{} if protoimpl.UnsafeEnabled { - mi := &file_agent_proto_agent_proto_msgTypes[35] + mi := &file_agent_proto_agent_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2668,7 +2854,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[35] + mi := &file_agent_proto_agent_proto_msgTypes[39] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2698,6 +2884,344 @@ func (x *BatchUpdateAppHealthRequest_HealthUpdate) GetHealth() AppHealth { return AppHealth_APP_HEALTH_UNSPECIFIED } +type GetResourcesMonitoringConfigurationResponse_Config struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + NumDatapoints int32 `protobuf:"varint,1,opt,name=num_datapoints,json=numDatapoints,proto3" json:"num_datapoints,omitempty"` + CollectionIntervalSeconds int32 `protobuf:"varint,2,opt,name=collection_interval_seconds,json=collectionIntervalSeconds,proto3" json:"collection_interval_seconds,omitempty"` +} + +func (x *GetResourcesMonitoringConfigurationResponse_Config) Reset() { + *x = GetResourcesMonitoringConfigurationResponse_Config{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[40] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetResourcesMonitoringConfigurationResponse_Config) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetResourcesMonitoringConfigurationResponse_Config) ProtoMessage() {} + +func (x *GetResourcesMonitoringConfigurationResponse_Config) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[40] + 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 GetResourcesMonitoringConfigurationResponse_Config.ProtoReflect.Descriptor instead. +func (*GetResourcesMonitoringConfigurationResponse_Config) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{29, 0} +} + +func (x *GetResourcesMonitoringConfigurationResponse_Config) GetNumDatapoints() int32 { + if x != nil { + return x.NumDatapoints + } + return 0 +} + +func (x *GetResourcesMonitoringConfigurationResponse_Config) GetCollectionIntervalSeconds() int32 { + if x != nil { + return x.CollectionIntervalSeconds + } + return 0 +} + +type GetResourcesMonitoringConfigurationResponse_Memory struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` +} + +func (x *GetResourcesMonitoringConfigurationResponse_Memory) Reset() { + *x = GetResourcesMonitoringConfigurationResponse_Memory{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[41] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetResourcesMonitoringConfigurationResponse_Memory) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetResourcesMonitoringConfigurationResponse_Memory) ProtoMessage() {} + +func (x *GetResourcesMonitoringConfigurationResponse_Memory) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[41] + 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 GetResourcesMonitoringConfigurationResponse_Memory.ProtoReflect.Descriptor instead. +func (*GetResourcesMonitoringConfigurationResponse_Memory) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{29, 1} +} + +func (x *GetResourcesMonitoringConfigurationResponse_Memory) GetEnabled() bool { + if x != nil { + return x.Enabled + } + return false +} + +type GetResourcesMonitoringConfigurationResponse_Volume struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` + Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` +} + +func (x *GetResourcesMonitoringConfigurationResponse_Volume) Reset() { + *x = GetResourcesMonitoringConfigurationResponse_Volume{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[42] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetResourcesMonitoringConfigurationResponse_Volume) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetResourcesMonitoringConfigurationResponse_Volume) ProtoMessage() {} + +func (x *GetResourcesMonitoringConfigurationResponse_Volume) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[42] + 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 GetResourcesMonitoringConfigurationResponse_Volume.ProtoReflect.Descriptor instead. +func (*GetResourcesMonitoringConfigurationResponse_Volume) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{29, 2} +} + +func (x *GetResourcesMonitoringConfigurationResponse_Volume) GetEnabled() bool { + if x != nil { + return x.Enabled + } + return false +} + +func (x *GetResourcesMonitoringConfigurationResponse_Volume) GetPath() string { + if x != nil { + return x.Path + } + return "" +} + +type PushResourcesMonitoringUsageRequest_Datapoint struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + CollectedAt *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=collected_at,json=collectedAt,proto3" json:"collected_at,omitempty"` + Memory *PushResourcesMonitoringUsageRequest_Datapoint_MemoryUsage `protobuf:"bytes,2,opt,name=memory,proto3,oneof" json:"memory,omitempty"` + Volumes []*PushResourcesMonitoringUsageRequest_Datapoint_VolumeUsage `protobuf:"bytes,3,rep,name=volumes,proto3" json:"volumes,omitempty"` +} + +func (x *PushResourcesMonitoringUsageRequest_Datapoint) Reset() { + *x = PushResourcesMonitoringUsageRequest_Datapoint{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[43] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PushResourcesMonitoringUsageRequest_Datapoint) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PushResourcesMonitoringUsageRequest_Datapoint) ProtoMessage() {} + +func (x *PushResourcesMonitoringUsageRequest_Datapoint) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[43] + 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 PushResourcesMonitoringUsageRequest_Datapoint.ProtoReflect.Descriptor instead. +func (*PushResourcesMonitoringUsageRequest_Datapoint) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{30, 0} +} + +func (x *PushResourcesMonitoringUsageRequest_Datapoint) GetCollectedAt() *timestamppb.Timestamp { + if x != nil { + return x.CollectedAt + } + return nil +} + +func (x *PushResourcesMonitoringUsageRequest_Datapoint) GetMemory() *PushResourcesMonitoringUsageRequest_Datapoint_MemoryUsage { + if x != nil { + return x.Memory + } + return nil +} + +func (x *PushResourcesMonitoringUsageRequest_Datapoint) GetVolumes() []*PushResourcesMonitoringUsageRequest_Datapoint_VolumeUsage { + if x != nil { + return x.Volumes + } + return nil +} + +type PushResourcesMonitoringUsageRequest_Datapoint_MemoryUsage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Used int64 `protobuf:"varint,1,opt,name=used,proto3" json:"used,omitempty"` + Total int64 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"` +} + +func (x *PushResourcesMonitoringUsageRequest_Datapoint_MemoryUsage) Reset() { + *x = PushResourcesMonitoringUsageRequest_Datapoint_MemoryUsage{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[44] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PushResourcesMonitoringUsageRequest_Datapoint_MemoryUsage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PushResourcesMonitoringUsageRequest_Datapoint_MemoryUsage) ProtoMessage() {} + +func (x *PushResourcesMonitoringUsageRequest_Datapoint_MemoryUsage) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[44] + 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 PushResourcesMonitoringUsageRequest_Datapoint_MemoryUsage.ProtoReflect.Descriptor instead. +func (*PushResourcesMonitoringUsageRequest_Datapoint_MemoryUsage) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{30, 0, 0} +} + +func (x *PushResourcesMonitoringUsageRequest_Datapoint_MemoryUsage) GetUsed() int64 { + if x != nil { + return x.Used + } + return 0 +} + +func (x *PushResourcesMonitoringUsageRequest_Datapoint_MemoryUsage) GetTotal() int64 { + if x != nil { + return x.Total + } + return 0 +} + +type PushResourcesMonitoringUsageRequest_Datapoint_VolumeUsage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Volume string `protobuf:"bytes,1,opt,name=volume,proto3" json:"volume,omitempty"` + Used int64 `protobuf:"varint,2,opt,name=used,proto3" json:"used,omitempty"` + Total int64 `protobuf:"varint,3,opt,name=total,proto3" json:"total,omitempty"` +} + +func (x *PushResourcesMonitoringUsageRequest_Datapoint_VolumeUsage) Reset() { + *x = PushResourcesMonitoringUsageRequest_Datapoint_VolumeUsage{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[45] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PushResourcesMonitoringUsageRequest_Datapoint_VolumeUsage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PushResourcesMonitoringUsageRequest_Datapoint_VolumeUsage) ProtoMessage() {} + +func (x *PushResourcesMonitoringUsageRequest_Datapoint_VolumeUsage) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[45] + 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 PushResourcesMonitoringUsageRequest_Datapoint_VolumeUsage.ProtoReflect.Descriptor instead. +func (*PushResourcesMonitoringUsageRequest_Datapoint_VolumeUsage) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{30, 0, 1} +} + +func (x *PushResourcesMonitoringUsageRequest_Datapoint_VolumeUsage) GetVolume() string { + if x != nil { + return x.Volume + } + return "" +} + +func (x *PushResourcesMonitoringUsageRequest_Datapoint_VolumeUsage) GetUsed() int64 { + if x != nil { + return x.Used + } + return 0 +} + +func (x *PushResourcesMonitoringUsageRequest_Datapoint_VolumeUsage) GetTotal() int64 { + if x != nil { + return x.Total + } + return 0 +} + var File_agent_proto_agent_proto protoreflect.FileDescriptor var file_agent_proto_agent_proto_rawDesc = []byte{ @@ -3092,79 +3616,173 @@ var file_agent_proto_agent_proto_rawDesc = []byte{ 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, + 0x4e, 0x10, 0x03, 0x22, 0x2c, 0x0a, 0x2a, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x22, 0xa0, 0x04, 0x0a, 0x2b, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x5a, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x42, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, + 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x4d, + 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x5f, 0x0a, + 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x42, 0x2e, + 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x47, + 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, + 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x6f, 0x72, + 0x79, 0x48, 0x00, 0x52, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x88, 0x01, 0x01, 0x12, 0x5c, + 0x0a, 0x07, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x42, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, + 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x4d, 0x6f, 0x6e, + 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x56, 0x6f, 0x6c, + 0x75, 0x6d, 0x65, 0x52, 0x07, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x1a, 0x6f, 0x0a, 0x06, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x25, 0x0a, 0x0e, 0x6e, 0x75, 0x6d, 0x5f, 0x64, 0x61, + 0x74, 0x61, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, + 0x6e, 0x75, 0x6d, 0x44, 0x61, 0x74, 0x61, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x3e, 0x0a, + 0x1b, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x76, 0x61, 0x6c, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x19, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x1a, 0x22, 0x0a, + 0x06, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, + 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, + 0x64, 0x1a, 0x36, 0x0a, 0x06, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x65, + 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, + 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x6d, 0x65, + 0x6d, 0x6f, 0x72, 0x79, 0x22, 0xb3, 0x04, 0x0a, 0x23, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, + 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x5d, 0x0a, 0x0a, + 0x64, 0x61, 0x74, 0x61, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x3d, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, + 0x32, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x4d, + 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, + 0x0a, 0x64, 0x61, 0x74, 0x61, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x1a, 0xac, 0x03, 0x0a, 0x09, + 0x44, 0x61, 0x74, 0x61, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x3d, 0x0a, 0x0c, 0x63, 0x6f, 0x6c, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 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, 0x0b, 0x63, 0x6f, 0x6c, + 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x66, 0x0a, 0x06, 0x6d, 0x65, 0x6d, 0x6f, + 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x49, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, + 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, + 0x67, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x44, 0x61, + 0x74, 0x61, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2e, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x55, 0x73, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x88, 0x01, 0x01, + 0x12, 0x63, 0x0a, 0x07, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x49, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, + 0x76, 0x32, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, + 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x2e, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x07, 0x76, 0x6f, + 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x1a, 0x37, 0x0a, 0x0b, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x55, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x04, 0x75, 0x73, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, + 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x1a, 0x4f, + 0x0a, 0x0b, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, + 0x06, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x76, + 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x04, 0x75, 0x73, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, + 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, + 0x09, 0x0a, 0x07, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x22, 0x26, 0x0a, 0x24, 0x50, 0x75, + 0x73, 0x68, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, + 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 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, 0x9c, 0x0a, 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, 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, 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, + 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, 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, + 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, 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, 0x12, 0x9e, 0x01, 0x0a, 0x23, 0x47, 0x65, + 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, + 0x72, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x3a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, + 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x4d, + 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3b, 0x2e, + 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x47, + 0x65, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, + 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x89, 0x01, 0x0a, 0x1c, 0x50, + 0x75, 0x73, 0x68, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x4d, 0x6f, 0x6e, 0x69, + 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x33, 0x2e, 0x63, 0x6f, + 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x75, 0x73, + 0x68, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, + 0x72, 0x69, 0x6e, 0x67, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x34, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, + 0x32, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x4d, + 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x55, 0x73, 0x61, 0x67, 0x65, 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 ( @@ -3180,122 +3798,143 @@ func file_agent_proto_agent_proto_rawDescGZIP() []byte { } 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_msgTypes = make([]protoimpl.MessageInfo, 46) 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 - (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 + (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 + (*GetResourcesMonitoringConfigurationRequest)(nil), // 37: coder.agent.v2.GetResourcesMonitoringConfigurationRequest + (*GetResourcesMonitoringConfigurationResponse)(nil), // 38: coder.agent.v2.GetResourcesMonitoringConfigurationResponse + (*PushResourcesMonitoringUsageRequest)(nil), // 39: coder.agent.v2.PushResourcesMonitoringUsageRequest + (*PushResourcesMonitoringUsageResponse)(nil), // 40: coder.agent.v2.PushResourcesMonitoringUsageResponse + (*WorkspaceApp_Healthcheck)(nil), // 41: coder.agent.v2.WorkspaceApp.Healthcheck + (*WorkspaceAgentMetadata_Result)(nil), // 42: coder.agent.v2.WorkspaceAgentMetadata.Result + (*WorkspaceAgentMetadata_Description)(nil), // 43: coder.agent.v2.WorkspaceAgentMetadata.Description + nil, // 44: coder.agent.v2.Manifest.EnvironmentVariablesEntry + nil, // 45: coder.agent.v2.Stats.ConnectionsByProtoEntry + (*Stats_Metric)(nil), // 46: coder.agent.v2.Stats.Metric + (*Stats_Metric_Label)(nil), // 47: coder.agent.v2.Stats.Metric.Label + (*BatchUpdateAppHealthRequest_HealthUpdate)(nil), // 48: coder.agent.v2.BatchUpdateAppHealthRequest.HealthUpdate + (*GetResourcesMonitoringConfigurationResponse_Config)(nil), // 49: coder.agent.v2.GetResourcesMonitoringConfigurationResponse.Config + (*GetResourcesMonitoringConfigurationResponse_Memory)(nil), // 50: coder.agent.v2.GetResourcesMonitoringConfigurationResponse.Memory + (*GetResourcesMonitoringConfigurationResponse_Volume)(nil), // 51: coder.agent.v2.GetResourcesMonitoringConfigurationResponse.Volume + (*PushResourcesMonitoringUsageRequest_Datapoint)(nil), // 52: coder.agent.v2.PushResourcesMonitoringUsageRequest.Datapoint + (*PushResourcesMonitoringUsageRequest_Datapoint_MemoryUsage)(nil), // 53: coder.agent.v2.PushResourcesMonitoringUsageRequest.Datapoint.MemoryUsage + (*PushResourcesMonitoringUsageRequest_Datapoint_VolumeUsage)(nil), // 54: coder.agent.v2.PushResourcesMonitoringUsageRequest.Datapoint.VolumeUsage + (*durationpb.Duration)(nil), // 55: google.protobuf.Duration + (*proto.DERPMap)(nil), // 56: coder.tailnet.v2.DERPMap + (*timestamppb.Timestamp)(nil), // 57: 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 - 37, // 1: coder.agent.v2.WorkspaceApp.healthcheck:type_name -> coder.agent.v2.WorkspaceApp.Healthcheck + 41, // 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 - 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 + 55, // 3: coder.agent.v2.WorkspaceAgentScript.timeout:type_name -> google.protobuf.Duration + 42, // 4: coder.agent.v2.WorkspaceAgentMetadata.result:type_name -> coder.agent.v2.WorkspaceAgentMetadata.Result + 43, // 5: coder.agent.v2.WorkspaceAgentMetadata.description:type_name -> coder.agent.v2.WorkspaceAgentMetadata.Description + 44, // 6: coder.agent.v2.Manifest.environment_variables:type_name -> coder.agent.v2.Manifest.EnvironmentVariablesEntry + 56, // 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 + 43, // 10: coder.agent.v2.Manifest.metadata:type_name -> coder.agent.v2.WorkspaceAgentMetadata.Description + 45, // 11: coder.agent.v2.Stats.connections_by_proto:type_name -> coder.agent.v2.Stats.ConnectionsByProtoEntry + 46, // 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 + 55, // 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 - 47, // 16: coder.agent.v2.Lifecycle.changed_at:type_name -> google.protobuf.Timestamp + 57, // 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 + 48, // 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 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 + 42, // 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 + 57, // 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 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 + 57, // 28: coder.agent.v2.Timing.start:type_name -> google.protobuf.Timestamp + 57, // 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 + 49, // 32: coder.agent.v2.GetResourcesMonitoringConfigurationResponse.config:type_name -> coder.agent.v2.GetResourcesMonitoringConfigurationResponse.Config + 50, // 33: coder.agent.v2.GetResourcesMonitoringConfigurationResponse.memory:type_name -> coder.agent.v2.GetResourcesMonitoringConfigurationResponse.Memory + 51, // 34: coder.agent.v2.GetResourcesMonitoringConfigurationResponse.volumes:type_name -> coder.agent.v2.GetResourcesMonitoringConfigurationResponse.Volume + 52, // 35: coder.agent.v2.PushResourcesMonitoringUsageRequest.datapoints:type_name -> coder.agent.v2.PushResourcesMonitoringUsageRequest.Datapoint + 55, // 36: coder.agent.v2.WorkspaceApp.Healthcheck.interval:type_name -> google.protobuf.Duration + 57, // 37: coder.agent.v2.WorkspaceAgentMetadata.Result.collected_at:type_name -> google.protobuf.Timestamp + 55, // 38: coder.agent.v2.WorkspaceAgentMetadata.Description.interval:type_name -> google.protobuf.Duration + 55, // 39: coder.agent.v2.WorkspaceAgentMetadata.Description.timeout:type_name -> google.protobuf.Duration + 3, // 40: coder.agent.v2.Stats.Metric.type:type_name -> coder.agent.v2.Stats.Metric.Type + 47, // 41: coder.agent.v2.Stats.Metric.labels:type_name -> coder.agent.v2.Stats.Metric.Label + 0, // 42: coder.agent.v2.BatchUpdateAppHealthRequest.HealthUpdate.health:type_name -> coder.agent.v2.AppHealth + 57, // 43: coder.agent.v2.PushResourcesMonitoringUsageRequest.Datapoint.collected_at:type_name -> google.protobuf.Timestamp + 53, // 44: coder.agent.v2.PushResourcesMonitoringUsageRequest.Datapoint.memory:type_name -> coder.agent.v2.PushResourcesMonitoringUsageRequest.Datapoint.MemoryUsage + 54, // 45: coder.agent.v2.PushResourcesMonitoringUsageRequest.Datapoint.volumes:type_name -> coder.agent.v2.PushResourcesMonitoringUsageRequest.Datapoint.VolumeUsage + 13, // 46: coder.agent.v2.Agent.GetManifest:input_type -> coder.agent.v2.GetManifestRequest + 15, // 47: coder.agent.v2.Agent.GetServiceBanner:input_type -> coder.agent.v2.GetServiceBannerRequest + 17, // 48: coder.agent.v2.Agent.UpdateStats:input_type -> coder.agent.v2.UpdateStatsRequest + 20, // 49: coder.agent.v2.Agent.UpdateLifecycle:input_type -> coder.agent.v2.UpdateLifecycleRequest + 21, // 50: coder.agent.v2.Agent.BatchUpdateAppHealths:input_type -> coder.agent.v2.BatchUpdateAppHealthRequest + 24, // 51: coder.agent.v2.Agent.UpdateStartup:input_type -> coder.agent.v2.UpdateStartupRequest + 26, // 52: coder.agent.v2.Agent.BatchUpdateMetadata:input_type -> coder.agent.v2.BatchUpdateMetadataRequest + 29, // 53: coder.agent.v2.Agent.BatchCreateLogs:input_type -> coder.agent.v2.BatchCreateLogsRequest + 31, // 54: coder.agent.v2.Agent.GetAnnouncementBanners:input_type -> coder.agent.v2.GetAnnouncementBannersRequest + 34, // 55: coder.agent.v2.Agent.ScriptCompleted:input_type -> coder.agent.v2.WorkspaceAgentScriptCompletedRequest + 37, // 56: coder.agent.v2.Agent.GetResourcesMonitoringConfiguration:input_type -> coder.agent.v2.GetResourcesMonitoringConfigurationRequest + 39, // 57: coder.agent.v2.Agent.PushResourcesMonitoringUsage:input_type -> coder.agent.v2.PushResourcesMonitoringUsageRequest + 12, // 58: coder.agent.v2.Agent.GetManifest:output_type -> coder.agent.v2.Manifest + 14, // 59: coder.agent.v2.Agent.GetServiceBanner:output_type -> coder.agent.v2.ServiceBanner + 18, // 60: coder.agent.v2.Agent.UpdateStats:output_type -> coder.agent.v2.UpdateStatsResponse + 19, // 61: coder.agent.v2.Agent.UpdateLifecycle:output_type -> coder.agent.v2.Lifecycle + 22, // 62: coder.agent.v2.Agent.BatchUpdateAppHealths:output_type -> coder.agent.v2.BatchUpdateAppHealthResponse + 23, // 63: coder.agent.v2.Agent.UpdateStartup:output_type -> coder.agent.v2.Startup + 27, // 64: coder.agent.v2.Agent.BatchUpdateMetadata:output_type -> coder.agent.v2.BatchUpdateMetadataResponse + 30, // 65: coder.agent.v2.Agent.BatchCreateLogs:output_type -> coder.agent.v2.BatchCreateLogsResponse + 32, // 66: coder.agent.v2.Agent.GetAnnouncementBanners:output_type -> coder.agent.v2.GetAnnouncementBannersResponse + 35, // 67: coder.agent.v2.Agent.ScriptCompleted:output_type -> coder.agent.v2.WorkspaceAgentScriptCompletedResponse + 38, // 68: coder.agent.v2.Agent.GetResourcesMonitoringConfiguration:output_type -> coder.agent.v2.GetResourcesMonitoringConfigurationResponse + 40, // 69: coder.agent.v2.Agent.PushResourcesMonitoringUsage:output_type -> coder.agent.v2.PushResourcesMonitoringUsageResponse + 58, // [58:70] is the sub-list for method output_type + 46, // [46:58] is the sub-list for method input_type + 46, // [46:46] is the sub-list for extension type_name + 46, // [46:46] is the sub-list for extension extendee + 0, // [0:46] is the sub-list for field type_name } func init() { file_agent_proto_agent_proto_init() } @@ -3641,7 +4280,7 @@ func file_agent_proto_agent_proto_init() { } } file_agent_proto_agent_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*WorkspaceApp_Healthcheck); i { + switch v := v.(*GetResourcesMonitoringConfigurationRequest); i { case 0: return &v.state case 1: @@ -3653,7 +4292,7 @@ func file_agent_proto_agent_proto_init() { } } file_agent_proto_agent_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*WorkspaceAgentMetadata_Result); i { + switch v := v.(*GetResourcesMonitoringConfigurationResponse); i { case 0: return &v.state case 1: @@ -3665,7 +4304,31 @@ 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 { + switch v := v.(*PushResourcesMonitoringUsageRequest); 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[31].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PushResourcesMonitoringUsageResponse); 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[32].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WorkspaceApp_Healthcheck); i { case 0: return &v.state case 1: @@ -3677,7 +4340,7 @@ func file_agent_proto_agent_proto_init() { } } file_agent_proto_agent_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Stats_Metric); i { + switch v := v.(*WorkspaceAgentMetadata_Result); i { case 0: return &v.state case 1: @@ -3689,6 +4352,30 @@ func file_agent_proto_agent_proto_init() { } } file_agent_proto_agent_proto_msgTypes[34].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[37].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Stats_Metric); 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[38].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Stats_Metric_Label); i { case 0: return &v.state @@ -3700,7 +4387,7 @@ func file_agent_proto_agent_proto_init() { return nil } } - file_agent_proto_agent_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { + file_agent_proto_agent_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BatchUpdateAppHealthRequest_HealthUpdate); i { case 0: return &v.state @@ -3712,14 +4399,88 @@ func file_agent_proto_agent_proto_init() { return nil } } + file_agent_proto_agent_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetResourcesMonitoringConfigurationResponse_Config); 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[41].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetResourcesMonitoringConfigurationResponse_Memory); 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[42].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetResourcesMonitoringConfigurationResponse_Volume); 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[43].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PushResourcesMonitoringUsageRequest_Datapoint); 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[44].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PushResourcesMonitoringUsageRequest_Datapoint_MemoryUsage); 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[45].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PushResourcesMonitoringUsageRequest_Datapoint_VolumeUsage); 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].OneofWrappers = []interface{}{} + file_agent_proto_agent_proto_msgTypes[43].OneofWrappers = []interface{}{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_agent_proto_agent_proto_rawDesc, NumEnums: 9, - NumMessages: 36, + NumMessages: 46, NumExtensions: 0, NumServices: 1, }, diff --git a/agent/proto/agent.proto b/agent/proto/agent.proto index f307066fcb..6bb802d966 100644 --- a/agent/proto/agent.proto +++ b/agent/proto/agent.proto @@ -295,6 +295,51 @@ message Timing { Status status = 6; } +message GetResourcesMonitoringConfigurationRequest { +} + +message GetResourcesMonitoringConfigurationResponse { + message Config { + int32 num_datapoints = 1; + int32 collection_interval_seconds = 2; + } + Config config = 1; + + message Memory { + bool enabled = 1; + } + optional Memory memory = 2; + + message Volume { + bool enabled = 1; + string path = 2; + } + repeated Volume volumes = 3; +} + +message PushResourcesMonitoringUsageRequest { + message Datapoint { + message MemoryUsage { + int64 used = 1; + int64 total = 2; + } + message VolumeUsage { + string volume = 1; + int64 used = 2; + int64 total = 3; + } + + google.protobuf.Timestamp collected_at = 1; + optional MemoryUsage memory = 2; + repeated VolumeUsage volumes = 3; + + } + repeated Datapoint datapoints = 1; +} + +message PushResourcesMonitoringUsageResponse { +} + service Agent { rpc GetManifest(GetManifestRequest) returns (Manifest); rpc GetServiceBanner(GetServiceBannerRequest) returns (ServiceBanner); @@ -306,4 +351,6 @@ service Agent { rpc BatchCreateLogs(BatchCreateLogsRequest) returns (BatchCreateLogsResponse); rpc GetAnnouncementBanners(GetAnnouncementBannersRequest) returns (GetAnnouncementBannersResponse); rpc ScriptCompleted(WorkspaceAgentScriptCompletedRequest) returns (WorkspaceAgentScriptCompletedResponse); + rpc GetResourcesMonitoringConfiguration(GetResourcesMonitoringConfigurationRequest) returns (GetResourcesMonitoringConfigurationResponse); + rpc PushResourcesMonitoringUsage(PushResourcesMonitoringUsageRequest) returns (PushResourcesMonitoringUsageResponse); } diff --git a/agent/proto/agent_drpc.pb.go b/agent/proto/agent_drpc.pb.go index 9f7e21c962..2a90380185 100644 --- a/agent/proto/agent_drpc.pb.go +++ b/agent/proto/agent_drpc.pb.go @@ -48,6 +48,8 @@ type DRPCAgentClient interface { BatchCreateLogs(ctx context.Context, in *BatchCreateLogsRequest) (*BatchCreateLogsResponse, error) GetAnnouncementBanners(ctx context.Context, in *GetAnnouncementBannersRequest) (*GetAnnouncementBannersResponse, error) ScriptCompleted(ctx context.Context, in *WorkspaceAgentScriptCompletedRequest) (*WorkspaceAgentScriptCompletedResponse, error) + GetResourcesMonitoringConfiguration(ctx context.Context, in *GetResourcesMonitoringConfigurationRequest) (*GetResourcesMonitoringConfigurationResponse, error) + PushResourcesMonitoringUsage(ctx context.Context, in *PushResourcesMonitoringUsageRequest) (*PushResourcesMonitoringUsageResponse, error) } type drpcAgentClient struct { @@ -150,6 +152,24 @@ func (c *drpcAgentClient) ScriptCompleted(ctx context.Context, in *WorkspaceAgen return out, nil } +func (c *drpcAgentClient) GetResourcesMonitoringConfiguration(ctx context.Context, in *GetResourcesMonitoringConfigurationRequest) (*GetResourcesMonitoringConfigurationResponse, error) { + out := new(GetResourcesMonitoringConfigurationResponse) + err := c.cc.Invoke(ctx, "/coder.agent.v2.Agent/GetResourcesMonitoringConfiguration", drpcEncoding_File_agent_proto_agent_proto{}, in, out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *drpcAgentClient) PushResourcesMonitoringUsage(ctx context.Context, in *PushResourcesMonitoringUsageRequest) (*PushResourcesMonitoringUsageResponse, error) { + out := new(PushResourcesMonitoringUsageResponse) + err := c.cc.Invoke(ctx, "/coder.agent.v2.Agent/PushResourcesMonitoringUsage", 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) @@ -161,6 +181,8 @@ type DRPCAgentServer interface { BatchCreateLogs(context.Context, *BatchCreateLogsRequest) (*BatchCreateLogsResponse, error) GetAnnouncementBanners(context.Context, *GetAnnouncementBannersRequest) (*GetAnnouncementBannersResponse, error) ScriptCompleted(context.Context, *WorkspaceAgentScriptCompletedRequest) (*WorkspaceAgentScriptCompletedResponse, error) + GetResourcesMonitoringConfiguration(context.Context, *GetResourcesMonitoringConfigurationRequest) (*GetResourcesMonitoringConfigurationResponse, error) + PushResourcesMonitoringUsage(context.Context, *PushResourcesMonitoringUsageRequest) (*PushResourcesMonitoringUsageResponse, error) } type DRPCAgentUnimplementedServer struct{} @@ -205,9 +227,17 @@ func (s *DRPCAgentUnimplementedServer) ScriptCompleted(context.Context, *Workspa return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) } +func (s *DRPCAgentUnimplementedServer) GetResourcesMonitoringConfiguration(context.Context, *GetResourcesMonitoringConfigurationRequest) (*GetResourcesMonitoringConfigurationResponse, error) { + return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) +} + +func (s *DRPCAgentUnimplementedServer) PushResourcesMonitoringUsage(context.Context, *PushResourcesMonitoringUsageRequest) (*PushResourcesMonitoringUsageResponse, error) { + return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) +} + type DRPCAgentDescription struct{} -func (DRPCAgentDescription) NumMethods() int { return 10 } +func (DRPCAgentDescription) NumMethods() int { return 12 } func (DRPCAgentDescription) Method(n int) (string, drpc.Encoding, drpc.Receiver, interface{}, bool) { switch n { @@ -301,6 +331,24 @@ func (DRPCAgentDescription) Method(n int) (string, drpc.Encoding, drpc.Receiver, in1.(*WorkspaceAgentScriptCompletedRequest), ) }, DRPCAgentServer.ScriptCompleted, true + case 10: + return "/coder.agent.v2.Agent/GetResourcesMonitoringConfiguration", drpcEncoding_File_agent_proto_agent_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return srv.(DRPCAgentServer). + GetResourcesMonitoringConfiguration( + ctx, + in1.(*GetResourcesMonitoringConfigurationRequest), + ) + }, DRPCAgentServer.GetResourcesMonitoringConfiguration, true + case 11: + return "/coder.agent.v2.Agent/PushResourcesMonitoringUsage", drpcEncoding_File_agent_proto_agent_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return srv.(DRPCAgentServer). + PushResourcesMonitoringUsage( + ctx, + in1.(*PushResourcesMonitoringUsageRequest), + ) + }, DRPCAgentServer.PushResourcesMonitoringUsage, true default: return "", nil, nil, nil, false } @@ -469,3 +517,35 @@ func (x *drpcAgent_ScriptCompletedStream) SendAndClose(m *WorkspaceAgentScriptCo } return x.CloseSend() } + +type DRPCAgent_GetResourcesMonitoringConfigurationStream interface { + drpc.Stream + SendAndClose(*GetResourcesMonitoringConfigurationResponse) error +} + +type drpcAgent_GetResourcesMonitoringConfigurationStream struct { + drpc.Stream +} + +func (x *drpcAgent_GetResourcesMonitoringConfigurationStream) SendAndClose(m *GetResourcesMonitoringConfigurationResponse) error { + if err := x.MsgSend(m, drpcEncoding_File_agent_proto_agent_proto{}); err != nil { + return err + } + return x.CloseSend() +} + +type DRPCAgent_PushResourcesMonitoringUsageStream interface { + drpc.Stream + SendAndClose(*PushResourcesMonitoringUsageResponse) error +} + +type drpcAgent_PushResourcesMonitoringUsageStream struct { + drpc.Stream +} + +func (x *drpcAgent_PushResourcesMonitoringUsageStream) SendAndClose(m *PushResourcesMonitoringUsageResponse) error { + if err := x.MsgSend(m, drpcEncoding_File_agent_proto_agent_proto{}); err != nil { + return err + } + return x.CloseSend() +} diff --git a/agent/proto/agent_drpc_old.go b/agent/proto/agent_drpc_old.go index f46afaba42..f1db351428 100644 --- a/agent/proto/agent_drpc_old.go +++ b/agent/proto/agent_drpc_old.go @@ -40,3 +40,11 @@ type DRPCAgentClient23 interface { DRPCAgentClient22 ScriptCompleted(ctx context.Context, in *WorkspaceAgentScriptCompletedRequest) (*WorkspaceAgentScriptCompletedResponse, error) } + +// DRPCAgentClient24 is the Agent API at v2.4. It adds the GetResourcesMonitoringConfiguration and +// PushResourcesMonitoringUsage RPCs. Compatible with Coder v2.19+ +type DRPCAgentClient24 interface { + DRPCAgentClient23 + GetResourcesMonitoringConfiguration(ctx context.Context, in *GetResourcesMonitoringConfigurationRequest) (*GetResourcesMonitoringConfigurationResponse, error) + PushResourcesMonitoringUsage(ctx context.Context, in *PushResourcesMonitoringUsageRequest) (*PushResourcesMonitoringUsageResponse, error) +} diff --git a/agent/proto/resourcesmonitor/fetcher.go b/agent/proto/resourcesmonitor/fetcher.go new file mode 100644 index 0000000000..495a249fe9 --- /dev/null +++ b/agent/proto/resourcesmonitor/fetcher.go @@ -0,0 +1,49 @@ +package resourcesmonitor + +import ( + "golang.org/x/xerrors" + + "github.com/coder/coder/v2/cli/clistat" +) + +type Fetcher interface { + FetchMemory() (total int64, used int64, err error) + FetchVolume(volume string) (total int64, used int64, err error) +} + +type fetcher struct { + *clistat.Statter +} + +//nolint:revive +func NewFetcher(f *clistat.Statter) *fetcher { + return &fetcher{ + f, + } +} + +func (f *fetcher) FetchMemory() (total int64, used int64, err error) { + mem, err := f.HostMemory(clistat.PrefixDefault) + if err != nil { + return 0, 0, xerrors.Errorf("failed to fetch memory: %w", err) + } + + if mem.Total == nil { + return 0, 0, xerrors.New("memory total is nil - can not fetch memory") + } + + return int64(*mem.Total), int64(mem.Used), nil +} + +func (f *fetcher) FetchVolume(volume string) (total int64, used int64, err error) { + vol, err := f.Disk(clistat.PrefixDefault, volume) + if err != nil { + return 0, 0, err + } + + if vol.Total == nil { + return 0, 0, xerrors.New("volume total is nil - can not fetch volume") + } + + return int64(*vol.Total), int64(vol.Used), nil +} diff --git a/agent/proto/resourcesmonitor/queue.go b/agent/proto/resourcesmonitor/queue.go new file mode 100644 index 0000000000..9f463509f2 --- /dev/null +++ b/agent/proto/resourcesmonitor/queue.go @@ -0,0 +1,85 @@ +package resourcesmonitor + +import ( + "time" + + "google.golang.org/protobuf/types/known/timestamppb" + + "github.com/coder/coder/v2/agent/proto" +) + +type Datapoint struct { + CollectedAt time.Time + Memory *MemoryDatapoint + Volumes []*VolumeDatapoint +} + +type MemoryDatapoint struct { + Total int64 + Used int64 +} + +type VolumeDatapoint struct { + Path string + Total int64 + Used int64 +} + +// Queue represents a FIFO queue with a fixed size +type Queue struct { + items []Datapoint + size int +} + +// newQueue creates a new Queue with the given size +func NewQueue(size int) *Queue { + return &Queue{ + items: make([]Datapoint, 0, size), + size: size, + } +} + +// Push adds a new item to the queue +func (q *Queue) Push(item Datapoint) { + if len(q.items) >= q.size { + // Remove the first item (FIFO) + q.items = q.items[1:] + } + q.items = append(q.items, item) +} + +func (q *Queue) IsFull() bool { + return len(q.items) == q.size +} + +func (q *Queue) Items() []Datapoint { + return q.items +} + +func (q *Queue) ItemsAsProto() []*proto.PushResourcesMonitoringUsageRequest_Datapoint { + items := make([]*proto.PushResourcesMonitoringUsageRequest_Datapoint, 0, len(q.items)) + + for _, item := range q.items { + protoItem := &proto.PushResourcesMonitoringUsageRequest_Datapoint{ + CollectedAt: timestamppb.New(item.CollectedAt), + } + if item.Memory != nil { + protoItem.Memory = &proto.PushResourcesMonitoringUsageRequest_Datapoint_MemoryUsage{ + Total: item.Memory.Total, + Used: item.Memory.Used, + } + } + + for _, volume := range item.Volumes { + protoItem.Volumes = append(protoItem.Volumes, &proto.PushResourcesMonitoringUsageRequest_Datapoint_VolumeUsage{ + Volume: volume.Path, + Total: volume.Total, + Used: volume.Used, + }) + } + + items = append(items, protoItem) + } + + return items +} diff --git a/agent/proto/resourcesmonitor/queue_test.go b/agent/proto/resourcesmonitor/queue_test.go new file mode 100644 index 0000000000..a3a8fbc0d0 --- /dev/null +++ b/agent/proto/resourcesmonitor/queue_test.go @@ -0,0 +1,92 @@ +package resourcesmonitor_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/coder/coder/v2/agent/proto/resourcesmonitor" +) + +func TestResourceMonitorQueue(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + pushCount int + expected []resourcesmonitor.Datapoint + }{ + { + name: "Push zero", + pushCount: 0, + expected: []resourcesmonitor.Datapoint{}, + }, + { + name: "Push less than capacity", + pushCount: 3, + expected: []resourcesmonitor.Datapoint{ + {Memory: &resourcesmonitor.MemoryDatapoint{Total: 1, Used: 1}}, + {Memory: &resourcesmonitor.MemoryDatapoint{Total: 2, Used: 2}}, + {Memory: &resourcesmonitor.MemoryDatapoint{Total: 3, Used: 3}}, + }, + }, + { + name: "Push exactly capacity", + pushCount: 20, + expected: func() []resourcesmonitor.Datapoint { + var result []resourcesmonitor.Datapoint + for i := 1; i <= 20; i++ { + result = append(result, resourcesmonitor.Datapoint{ + Memory: &resourcesmonitor.MemoryDatapoint{ + Total: int64(i), + Used: int64(i), + }, + }) + } + return result + }(), + }, + { + name: "Push more than capacity", + pushCount: 25, + expected: func() []resourcesmonitor.Datapoint { + var result []resourcesmonitor.Datapoint + for i := 6; i <= 25; i++ { + result = append(result, resourcesmonitor.Datapoint{ + Memory: &resourcesmonitor.MemoryDatapoint{ + Total: int64(i), + Used: int64(i), + }, + }) + } + return result + }(), + }, + } + + for _, tt := range tests { + tt := tt + + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + queue := resourcesmonitor.NewQueue(20) + for i := 1; i <= tt.pushCount; i++ { + queue.Push(resourcesmonitor.Datapoint{ + Memory: &resourcesmonitor.MemoryDatapoint{ + Total: int64(i), + Used: int64(i), + }, + }) + } + + if tt.pushCount < 20 { + require.False(t, queue.IsFull()) + } else { + require.True(t, queue.IsFull()) + require.Equal(t, 20, len(queue.Items())) + } + + require.EqualValues(t, tt.expected, queue.Items()) + }) + } +} diff --git a/agent/proto/resourcesmonitor/resources_monitor.go b/agent/proto/resourcesmonitor/resources_monitor.go new file mode 100644 index 0000000000..7dea49614c --- /dev/null +++ b/agent/proto/resourcesmonitor/resources_monitor.go @@ -0,0 +1,93 @@ +package resourcesmonitor + +import ( + "context" + "time" + + "cdr.dev/slog" + "github.com/coder/coder/v2/agent/proto" + "github.com/coder/quartz" +) + +type monitor struct { + logger slog.Logger + clock quartz.Clock + config *proto.GetResourcesMonitoringConfigurationResponse + resourcesFetcher Fetcher + datapointsPusher datapointsPusher + queue *Queue +} + +//nolint:revive +func NewResourcesMonitor(logger slog.Logger, clock quartz.Clock, config *proto.GetResourcesMonitoringConfigurationResponse, resourcesFetcher Fetcher, datapointsPusher datapointsPusher) *monitor { + return &monitor{ + logger: logger, + clock: clock, + config: config, + resourcesFetcher: resourcesFetcher, + datapointsPusher: datapointsPusher, + queue: NewQueue(int(config.Config.NumDatapoints)), + } +} + +type datapointsPusher interface { + PushResourcesMonitoringUsage(ctx context.Context, req *proto.PushResourcesMonitoringUsageRequest) (*proto.PushResourcesMonitoringUsageResponse, error) +} + +func (m *monitor) Start(ctx context.Context) error { + m.clock.TickerFunc(ctx, time.Duration(m.config.Config.CollectionIntervalSeconds)*time.Second, func() error { + datapoint := Datapoint{ + CollectedAt: m.clock.Now(), + Volumes: make([]*VolumeDatapoint, 0, len(m.config.Volumes)), + } + + if m.config.Memory != nil && m.config.Memory.Enabled { + memTotal, memUsed, err := m.resourcesFetcher.FetchMemory() + if err != nil { + m.logger.Error(ctx, "failed to fetch memory", slog.Error(err)) + } else { + datapoint.Memory = &MemoryDatapoint{ + Total: memTotal, + Used: memUsed, + } + } + } + + for _, volume := range m.config.Volumes { + if !volume.Enabled { + continue + } + + volTotal, volUsed, err := m.resourcesFetcher.FetchVolume(volume.Path) + if err != nil { + m.logger.Error(ctx, "failed to fetch volume", slog.Error(err)) + continue + } + + datapoint.Volumes = append(datapoint.Volumes, &VolumeDatapoint{ + Path: volume.Path, + Total: volTotal, + Used: volUsed, + }) + } + + m.queue.Push(datapoint) + + if m.queue.IsFull() { + _, err := m.datapointsPusher.PushResourcesMonitoringUsage(ctx, &proto.PushResourcesMonitoringUsageRequest{ + Datapoints: m.queue.ItemsAsProto(), + }) + if err != nil { + // We don't want to stop the monitoring if we fail to push the datapoints + // to the server. We just log the error and continue. + // The queue will anyway remove the oldest datapoint and add the new one. + m.logger.Error(ctx, "failed to push resources monitoring usage", slog.Error(err)) + return nil + } + } + + return nil + }, "resources_monitor") + + return nil +} diff --git a/agent/proto/resourcesmonitor/resources_monitor_test.go b/agent/proto/resourcesmonitor/resources_monitor_test.go new file mode 100644 index 0000000000..ddf3522ece --- /dev/null +++ b/agent/proto/resourcesmonitor/resources_monitor_test.go @@ -0,0 +1,235 @@ +package resourcesmonitor_test + +import ( + "context" + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "cdr.dev/slog" + "cdr.dev/slog/sloggers/sloghuman" + "github.com/coder/coder/v2/agent/proto" + "github.com/coder/coder/v2/agent/proto/resourcesmonitor" + "github.com/coder/quartz" +) + +type datapointsPusherMock struct { + PushResourcesMonitoringUsageFunc func(ctx context.Context, req *proto.PushResourcesMonitoringUsageRequest) (*proto.PushResourcesMonitoringUsageResponse, error) +} + +func (d *datapointsPusherMock) PushResourcesMonitoringUsage(ctx context.Context, req *proto.PushResourcesMonitoringUsageRequest) (*proto.PushResourcesMonitoringUsageResponse, error) { + return d.PushResourcesMonitoringUsageFunc(ctx, req) +} + +type fetcher struct { + totalMemory int64 + usedMemory int64 + totalVolume int64 + usedVolume int64 + + errMemory error + errVolume error +} + +func (r *fetcher) FetchMemory() (total int64, used int64, err error) { + return r.totalMemory, r.usedMemory, r.errMemory +} + +func (r *fetcher) FetchVolume(_ string) (total int64, used int64, err error) { + return r.totalVolume, r.usedVolume, r.errVolume +} + +func TestPushResourcesMonitoringWithConfig(t *testing.T) { + t.Parallel() + tests := []struct { + name string + config *proto.GetResourcesMonitoringConfigurationResponse + datapointsPusher func(ctx context.Context, req *proto.PushResourcesMonitoringUsageRequest) (*proto.PushResourcesMonitoringUsageResponse, error) + fetcher resourcesmonitor.Fetcher + numTicks int + }{ + { + name: "SuccessfulMonitoring", + config: &proto.GetResourcesMonitoringConfigurationResponse{ + Config: &proto.GetResourcesMonitoringConfigurationResponse_Config{ + NumDatapoints: 20, + CollectionIntervalSeconds: 1, + }, + Volumes: []*proto.GetResourcesMonitoringConfigurationResponse_Volume{ + { + Enabled: true, + Path: "/", + }, + }, + }, + datapointsPusher: func(_ context.Context, _ *proto.PushResourcesMonitoringUsageRequest) (*proto.PushResourcesMonitoringUsageResponse, error) { + return &proto.PushResourcesMonitoringUsageResponse{}, nil + }, + fetcher: &fetcher{ + totalMemory: 16000, + usedMemory: 8000, + totalVolume: 100000, + usedVolume: 50000, + }, + numTicks: 20, + }, + { + name: "SuccessfulMonitoringLongRun", + config: &proto.GetResourcesMonitoringConfigurationResponse{ + Config: &proto.GetResourcesMonitoringConfigurationResponse_Config{ + NumDatapoints: 20, + CollectionIntervalSeconds: 1, + }, + Volumes: []*proto.GetResourcesMonitoringConfigurationResponse_Volume{ + { + Enabled: true, + Path: "/", + }, + }, + }, + datapointsPusher: func(_ context.Context, _ *proto.PushResourcesMonitoringUsageRequest) (*proto.PushResourcesMonitoringUsageResponse, error) { + return &proto.PushResourcesMonitoringUsageResponse{}, nil + }, + fetcher: &fetcher{ + totalMemory: 16000, + usedMemory: 8000, + totalVolume: 100000, + usedVolume: 50000, + }, + numTicks: 60, + }, + { + // We want to make sure that even if the datapointsPusher fails, the monitoring continues. + name: "ErrorPushingDatapoints", + config: &proto.GetResourcesMonitoringConfigurationResponse{ + Config: &proto.GetResourcesMonitoringConfigurationResponse_Config{ + NumDatapoints: 20, + CollectionIntervalSeconds: 1, + }, + Volumes: []*proto.GetResourcesMonitoringConfigurationResponse_Volume{ + { + Enabled: true, + Path: "/", + }, + }, + }, + datapointsPusher: func(_ context.Context, _ *proto.PushResourcesMonitoringUsageRequest) (*proto.PushResourcesMonitoringUsageResponse, error) { + return nil, assert.AnError + }, + fetcher: &fetcher{ + totalMemory: 16000, + usedMemory: 8000, + totalVolume: 100000, + usedVolume: 50000, + }, + numTicks: 60, + }, + { + // If one of the resources fails to be fetched, the datapoints still should be pushed with the other resources. + name: "ErrorFetchingMemory", + config: &proto.GetResourcesMonitoringConfigurationResponse{ + Config: &proto.GetResourcesMonitoringConfigurationResponse_Config{ + NumDatapoints: 20, + CollectionIntervalSeconds: 1, + }, + Volumes: []*proto.GetResourcesMonitoringConfigurationResponse_Volume{ + { + Enabled: true, + Path: "/", + }, + }, + }, + datapointsPusher: func(_ context.Context, req *proto.PushResourcesMonitoringUsageRequest) (*proto.PushResourcesMonitoringUsageResponse, error) { + require.Len(t, req.Datapoints, 20) + require.Nil(t, req.Datapoints[0].Memory) + require.NotNil(t, req.Datapoints[0].Volumes) + require.Equal(t, &proto.PushResourcesMonitoringUsageRequest_Datapoint_VolumeUsage{ + Volume: "/", + Total: 100000, + Used: 50000, + }, req.Datapoints[0].Volumes[0]) + + return &proto.PushResourcesMonitoringUsageResponse{}, nil + }, + fetcher: &fetcher{ + totalMemory: 0, + usedMemory: 0, + errMemory: assert.AnError, + totalVolume: 100000, + usedVolume: 50000, + }, + numTicks: 20, + }, + { + // If one of the resources fails to be fetched, the datapoints still should be pushed with the other resources. + name: "ErrorFetchingVolume", + config: &proto.GetResourcesMonitoringConfigurationResponse{ + Config: &proto.GetResourcesMonitoringConfigurationResponse_Config{ + NumDatapoints: 20, + CollectionIntervalSeconds: 1, + }, + Volumes: []*proto.GetResourcesMonitoringConfigurationResponse_Volume{ + { + Enabled: true, + Path: "/", + }, + }, + }, + datapointsPusher: func(_ context.Context, req *proto.PushResourcesMonitoringUsageRequest) (*proto.PushResourcesMonitoringUsageResponse, error) { + require.Len(t, req.Datapoints, 20) + require.Len(t, req.Datapoints[0].Volumes, 0) + + return &proto.PushResourcesMonitoringUsageResponse{}, nil + }, + fetcher: &fetcher{ + totalMemory: 16000, + usedMemory: 8000, + totalVolume: 0, + usedVolume: 0, + errVolume: assert.AnError, + }, + numTicks: 20, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + var ( + logger = slog.Make(sloghuman.Sink(os.Stdout)) + clk = quartz.NewMock(t) + counterCalls = 0 + ) + + datapointsPusher := func(ctx context.Context, req *proto.PushResourcesMonitoringUsageRequest) (*proto.PushResourcesMonitoringUsageResponse, error) { + counterCalls++ + return tt.datapointsPusher(ctx, req) + } + + pusher := &datapointsPusherMock{ + PushResourcesMonitoringUsageFunc: datapointsPusher, + } + + monitor := resourcesmonitor.NewResourcesMonitor(logger, clk, tt.config, tt.fetcher, pusher) + require.NoError(t, monitor.Start(ctx)) + + for i := 0; i < tt.numTicks; i++ { + _, waiter := clk.AdvanceNext() + require.NoError(t, waiter.Wait(ctx)) + } + + // expectedCalls is computed with the following logic : + // We have one call per tick, once reached the ${config.NumDatapoints}. + expectedCalls := tt.numTicks - int(tt.config.Config.NumDatapoints) + 1 + require.Equal(t, expectedCalls, counterCalls) + cancel() + }) + } +} diff --git a/cli/testdata/coder_provisioner_list_--output_json.golden b/cli/testdata/coder_provisioner_list_--output_json.golden index d6983d11e5..168e690f0b 100644 --- a/cli/testdata/coder_provisioner_list_--output_json.golden +++ b/cli/testdata/coder_provisioner_list_--output_json.golden @@ -21,7 +21,7 @@ "previous_job": { "id": "======[workspace build job ID]======", "status": "succeeded", - "template_name": "", + "template_name": "test-template", "template_icon": "", "template_display_name": "" }, diff --git a/coderd/agentapi/api.go b/coderd/agentapi/api.go index c48fd17f8a..a4f02de82b 100644 --- a/coderd/agentapi/api.go +++ b/coderd/agentapi/api.go @@ -42,6 +42,7 @@ type API struct { *LifecycleAPI *AppsAPI *MetadataAPI + *ResourcesMonitoringAPI *LogsAPI *ScriptsAPI *tailnet.DRPCService @@ -104,6 +105,12 @@ func New(opts Options) *API { appearanceFetcher: opts.AppearanceFetcher, } + api.ResourcesMonitoringAPI = &ResourcesMonitoringAPI{ + Log: opts.Log, + AgentID: opts.AgentID, + Database: opts.Database, + } + api.StatsAPI = &StatsAPI{ AgentFn: api.agent, Database: opts.Database, diff --git a/coderd/agentapi/resources_monitoring.go b/coderd/agentapi/resources_monitoring.go new file mode 100644 index 0000000000..0bce9b5104 --- /dev/null +++ b/coderd/agentapi/resources_monitoring.go @@ -0,0 +1,67 @@ +package agentapi + +import ( + "context" + "database/sql" + "errors" + + "golang.org/x/xerrors" + + "github.com/google/uuid" + + "cdr.dev/slog" + "github.com/coder/coder/v2/agent/proto" + "github.com/coder/coder/v2/coderd/database" +) + +type ResourcesMonitoringAPI struct { + AgentID uuid.UUID + Database database.Store + Log slog.Logger +} + +func (a *ResourcesMonitoringAPI) GetResourcesMonitoringConfiguration(ctx context.Context, _ *proto.GetResourcesMonitoringConfigurationRequest) (*proto.GetResourcesMonitoringConfigurationResponse, error) { + memoryMonitor, memoryErr := a.Database.FetchMemoryResourceMonitorsByAgentID(ctx, a.AgentID) + if memoryErr != nil && !errors.Is(memoryErr, sql.ErrNoRows) { + return nil, xerrors.Errorf("failed to fetch memory resource monitor: %w", memoryErr) + } + + volumeMonitors, err := a.Database.FetchVolumesResourceMonitorsByAgentID(ctx, a.AgentID) + if err != nil { + return nil, xerrors.Errorf("failed to fetch volume resource monitors: %w", err) + } + + return &proto.GetResourcesMonitoringConfigurationResponse{ + Config: &proto.GetResourcesMonitoringConfigurationResponse_Config{ + CollectionIntervalSeconds: 10, + NumDatapoints: 20, + }, + Memory: func() *proto.GetResourcesMonitoringConfigurationResponse_Memory { + if memoryErr != nil { + return nil + } + + return &proto.GetResourcesMonitoringConfigurationResponse_Memory{ + Enabled: memoryMonitor.Enabled, + } + }(), + Volumes: func() []*proto.GetResourcesMonitoringConfigurationResponse_Volume { + volumes := make([]*proto.GetResourcesMonitoringConfigurationResponse_Volume, 0, len(volumeMonitors)) + for _, monitor := range volumeMonitors { + volumes = append(volumes, &proto.GetResourcesMonitoringConfigurationResponse_Volume{ + Enabled: monitor.Enabled, + Path: monitor.Path, + }) + } + + return volumes + }(), + }, nil +} + +func (a *ResourcesMonitoringAPI) PushResourcesMonitoringUsage(ctx context.Context, req *proto.PushResourcesMonitoringUsageRequest) (*proto.PushResourcesMonitoringUsageResponse, error) { + a.Log.Info(ctx, "resources monitoring usage received", + slog.F("request", req)) + + return &proto.PushResourcesMonitoringUsageResponse{}, nil +} diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 828904416b..7a54ee80dc 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -2976,6 +2976,43 @@ const docTemplate = `{ "in": "path", "required": true }, + { + "type": "integer", + "description": "Page limit", + "name": "limit", + "in": "query" + }, + { + "type": "array", + "format": "uuid", + "items": { + "type": "string" + }, + "description": "Filter results by job IDs", + "name": "ids", + "in": "query" + }, + { + "enum": [ + "pending", + "running", + "succeeded", + "canceling", + "canceled", + "failed", + "unknown", + "pending", + "running", + "succeeded", + "canceling", + "canceled", + "failed" + ], + "type": "string", + "description": "Filter results by status", + "name": "status", + "in": "query" + }, { "type": "object", "description": "Provisioner tags to filter by (JSON of the form {'tag1':'value1','tag2':'value2'})", diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 64d8617736..aa24368d37 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -2610,6 +2610,43 @@ "in": "path", "required": true }, + { + "type": "integer", + "description": "Page limit", + "name": "limit", + "in": "query" + }, + { + "type": "array", + "format": "uuid", + "items": { + "type": "string" + }, + "description": "Filter results by job IDs", + "name": "ids", + "in": "query" + }, + { + "enum": [ + "pending", + "running", + "succeeded", + "canceling", + "canceled", + "failed", + "unknown", + "pending", + "running", + "succeeded", + "canceling", + "canceled", + "failed" + ], + "type": "string", + "description": "Filter results by status", + "name": "status", + "in": "query" + }, { "type": "object", "description": "Provisioner tags to filter by (JSON of the form {'tag1':'value1','tag2':'value2'})", diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index 23ff52f014..9a985a779b 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -184,6 +184,8 @@ var ( rbac.ResourceGroup.Type: {policy.ActionRead}, // Provisionerd creates notification messages rbac.ResourceNotificationMessage.Type: {policy.ActionCreate, policy.ActionRead}, + // Provisionerd creates workspaces resources monitor + rbac.ResourceWorkspaceAgentResourceMonitor.Type: {policy.ActionCreate}, }), Org: map[string][]rbac.Permission{}, User: []rbac.Permission{}, @@ -1401,7 +1403,13 @@ func (q *querier) FavoriteWorkspace(ctx context.Context, id uuid.UUID) error { } func (q *querier) FetchMemoryResourceMonitorsByAgentID(ctx context.Context, agentID uuid.UUID) (database.WorkspaceAgentMemoryResourceMonitor, error) { - if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceWorkspaceAgentResourceMonitor); err != nil { + workspace, err := q.db.GetWorkspaceByAgentID(ctx, agentID) + if err != nil { + return database.WorkspaceAgentMemoryResourceMonitor{}, err + } + + err = q.authorizeContext(ctx, policy.ActionRead, workspace) + if err != nil { return database.WorkspaceAgentMemoryResourceMonitor{}, err } @@ -1416,7 +1424,13 @@ func (q *querier) FetchNewMessageMetadata(ctx context.Context, arg database.Fetc } func (q *querier) FetchVolumesResourceMonitorsByAgentID(ctx context.Context, agentID uuid.UUID) ([]database.WorkspaceAgentVolumeResourceMonitor, error) { - if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceWorkspaceAgentResourceMonitor); err != nil { + workspace, err := q.db.GetWorkspaceByAgentID(ctx, agentID) + if err != nil { + return nil, err + } + + err = q.authorizeContext(ctx, policy.ActionRead, workspace) + if err != nil { return nil, err } diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index 46aa96bf1f..1291c27236 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -4772,7 +4772,7 @@ func (s *MethodTestSuite) TestResourcesMonitor() { monitor, err := db.FetchMemoryResourceMonitorsByAgentID(context.Background(), agt.ID) require.NoError(s.T(), err) - check.Args(agt.ID).Asserts(rbac.ResourceWorkspaceAgentResourceMonitor, policy.ActionRead).Returns(monitor) + check.Args(agt.ID).Asserts(w, policy.ActionRead).Returns(monitor) })) s.Run("FetchVolumesResourceMonitorsByAgentID", s.Subtest(func(db database.Store, check *expects) { @@ -4813,6 +4813,6 @@ func (s *MethodTestSuite) TestResourcesMonitor() { monitors, err := db.FetchVolumesResourceMonitorsByAgentID(context.Background(), agt.ID) require.NoError(s.T(), err) - check.Args(agt.ID).Asserts(rbac.ResourceWorkspaceAgentResourceMonitor, policy.ActionRead).Returns(monitors) + check.Args(agt.ID).Asserts(w, policy.ActionRead).Returns(monitors) })) } diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index fc8708ce32..83ca261cd3 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -3935,7 +3935,7 @@ func (q *FakeQuerier) GetProvisionerDaemonsByOrganization(_ context.Context, arg return daemons, nil } -func (q *FakeQuerier) GetProvisionerDaemonsWithStatusByOrganization(_ context.Context, arg database.GetProvisionerDaemonsWithStatusByOrganizationParams) ([]database.GetProvisionerDaemonsWithStatusByOrganizationRow, error) { +func (q *FakeQuerier) GetProvisionerDaemonsWithStatusByOrganization(ctx context.Context, arg database.GetProvisionerDaemonsWithStatusByOrganizationParams) ([]database.GetProvisionerDaemonsWithStatusByOrganizationRow, error) { err := validateDatabaseType(arg) if err != nil { return nil, err @@ -3985,6 +3985,31 @@ func (q *FakeQuerier) GetProvisionerDaemonsWithStatusByOrganization(_ context.Co status = database.ProvisionerDaemonStatusIdle } } + var currentTemplate database.Template + if currentJob.ID != uuid.Nil { + var input codersdk.ProvisionerJobInput + err := json.Unmarshal(currentJob.Input, &input) + if err != nil { + return nil, err + } + if input.WorkspaceBuildID != nil { + b, err := q.getWorkspaceBuildByIDNoLock(ctx, *input.WorkspaceBuildID) + if err != nil { + return nil, err + } + input.TemplateVersionID = &b.TemplateVersionID + } + if input.TemplateVersionID != nil { + v, err := q.getTemplateVersionByIDNoLock(ctx, *input.TemplateVersionID) + if err != nil { + return nil, err + } + currentTemplate, err = q.getTemplateByIDNoLock(ctx, v.TemplateID.UUID) + if err != nil { + return nil, err + } + } + } var previousJob database.ProvisionerJob for _, job := range q.provisionerJobs { @@ -4001,6 +4026,31 @@ func (q *FakeQuerier) GetProvisionerDaemonsWithStatusByOrganization(_ context.Co } } } + var previousTemplate database.Template + if previousJob.ID != uuid.Nil { + var input codersdk.ProvisionerJobInput + err := json.Unmarshal(previousJob.Input, &input) + if err != nil { + return nil, err + } + if input.WorkspaceBuildID != nil { + b, err := q.getWorkspaceBuildByIDNoLock(ctx, *input.WorkspaceBuildID) + if err != nil { + return nil, err + } + input.TemplateVersionID = &b.TemplateVersionID + } + if input.TemplateVersionID != nil { + v, err := q.getTemplateVersionByIDNoLock(ctx, *input.TemplateVersionID) + if err != nil { + return nil, err + } + previousTemplate, err = q.getTemplateByIDNoLock(ctx, v.TemplateID.UUID) + if err != nil { + return nil, err + } + } + } // Get the provisioner key name var keyName string @@ -4012,13 +4062,19 @@ func (q *FakeQuerier) GetProvisionerDaemonsWithStatusByOrganization(_ context.Co } rows = append(rows, database.GetProvisionerDaemonsWithStatusByOrganizationRow{ - ProvisionerDaemon: daemon, - Status: status, - KeyName: keyName, - CurrentJobID: uuid.NullUUID{UUID: currentJob.ID, Valid: currentJob.ID != uuid.Nil}, - CurrentJobStatus: database.NullProvisionerJobStatus{ProvisionerJobStatus: currentJob.JobStatus, Valid: currentJob.ID != uuid.Nil}, - PreviousJobID: uuid.NullUUID{UUID: previousJob.ID, Valid: previousJob.ID != uuid.Nil}, - PreviousJobStatus: database.NullProvisionerJobStatus{ProvisionerJobStatus: previousJob.JobStatus, Valid: previousJob.ID != uuid.Nil}, + ProvisionerDaemon: daemon, + Status: status, + KeyName: keyName, + CurrentJobID: uuid.NullUUID{UUID: currentJob.ID, Valid: currentJob.ID != uuid.Nil}, + CurrentJobStatus: database.NullProvisionerJobStatus{ProvisionerJobStatus: currentJob.JobStatus, Valid: currentJob.ID != uuid.Nil}, + CurrentJobTemplateName: currentTemplate.Name, + CurrentJobTemplateDisplayName: currentTemplate.DisplayName, + CurrentJobTemplateIcon: currentTemplate.Icon, + PreviousJobID: uuid.NullUUID{UUID: previousJob.ID, Valid: previousJob.ID != uuid.Nil}, + PreviousJobStatus: database.NullProvisionerJobStatus{ProvisionerJobStatus: previousJob.JobStatus, Valid: previousJob.ID != uuid.Nil}, + PreviousJobTemplateName: previousTemplate.Name, + PreviousJobTemplateDisplayName: previousTemplate.DisplayName, + PreviousJobTemplateIcon: previousTemplate.Icon, }) } @@ -4026,6 +4082,10 @@ func (q *FakeQuerier) GetProvisionerDaemonsWithStatusByOrganization(_ context.Co return a.ProvisionerDaemon.CreatedAt.Compare(b.ProvisionerDaemon.CreatedAt) }) + if arg.Limit.Valid && arg.Limit.Int32 > 0 && len(rows) > int(arg.Limit.Int32) { + rows = rows[:arg.Limit.Int32] + } + return rows, nil } diff --git a/coderd/database/querier.go b/coderd/database/querier.go index 2b6679a869..56e110f0f7 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -210,6 +210,8 @@ type sqlcQuerier interface { GetPreviousTemplateVersion(ctx context.Context, arg GetPreviousTemplateVersionParams) (TemplateVersion, error) GetProvisionerDaemons(ctx context.Context) ([]ProvisionerDaemon, error) GetProvisionerDaemonsByOrganization(ctx context.Context, arg GetProvisionerDaemonsByOrganizationParams) ([]ProvisionerDaemon, error) + // Current job information. + // Previous job information. GetProvisionerDaemonsWithStatusByOrganization(ctx context.Context, arg GetProvisionerDaemonsWithStatusByOrganizationParams) ([]GetProvisionerDaemonsWithStatusByOrganizationRow, error) GetProvisionerJobByID(ctx context.Context, id uuid.UUID) (ProvisionerJob, error) GetProvisionerJobTimingsByJobID(ctx context.Context, jobID uuid.UUID) ([]ProvisionerJobTiming, error) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 49ecffbe51..4816e57142 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -5960,9 +5960,12 @@ SELECT current_job.job_status AS current_job_status, previous_job.id AS previous_job_id, previous_job.job_status AS previous_job_status, - COALESCE(tmpl.name, ''::text) AS current_job_template_name, - COALESCE(tmpl.display_name, ''::text) AS current_job_template_display_name, - COALESCE(tmpl.icon, ''::text) AS current_job_template_icon + COALESCE(current_template.name, ''::text) AS current_job_template_name, + COALESCE(current_template.display_name, ''::text) AS current_job_template_display_name, + COALESCE(current_template.icon, ''::text) AS current_job_template_icon, + COALESCE(previous_template.name, ''::text) AS previous_job_template_name, + COALESCE(previous_template.display_name, ''::text) AS previous_job_template_display_name, + COALESCE(previous_template.icon, ''::text) AS previous_job_template_icon FROM provisioner_daemons pd JOIN @@ -5988,43 +5991,62 @@ LEFT JOIN ) ) LEFT JOIN - template_versions version ON version.id = (current_job.input->>'template_version_id')::uuid + workspace_builds current_build ON current_build.id = CASE WHEN current_job.input ? 'workspace_build_id' THEN (current_job.input->>'workspace_build_id')::uuid END LEFT JOIN - templates tmpl ON tmpl.id = version.template_id + -- We should always have a template version, either explicitly or implicitly via workspace build. + template_versions current_version ON current_version.id = CASE WHEN current_job.input ? 'template_version_id' THEN (current_job.input->>'template_version_id')::uuid ELSE current_build.template_version_id END +LEFT JOIN + templates current_template ON current_template.id = current_version.template_id +LEFT JOIN + workspace_builds previous_build ON previous_build.id = CASE WHEN previous_job.input ? 'workspace_build_id' THEN (previous_job.input->>'workspace_build_id')::uuid END +LEFT JOIN + -- We should always have a template version, either explicitly or implicitly via workspace build. + template_versions previous_version ON previous_version.id = CASE WHEN previous_job.input ? 'template_version_id' THEN (previous_job.input->>'template_version_id')::uuid ELSE previous_build.template_version_id END +LEFT JOIN + templates previous_template ON previous_template.id = previous_version.template_id WHERE pd.organization_id = $2::uuid AND (COALESCE(array_length($3::uuid[], 1), 0) = 0 OR pd.id = ANY($3::uuid[])) AND ($4::tagset = 'null'::tagset OR provisioner_tagset_contains(pd.tags::tagset, $4::tagset)) ORDER BY pd.created_at ASC +LIMIT + $5::int ` type GetProvisionerDaemonsWithStatusByOrganizationParams struct { - StaleIntervalMS int64 `db:"stale_interval_ms" json:"stale_interval_ms"` - OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"` - IDs []uuid.UUID `db:"ids" json:"ids"` - Tags StringMap `db:"tags" json:"tags"` + StaleIntervalMS int64 `db:"stale_interval_ms" json:"stale_interval_ms"` + OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"` + IDs []uuid.UUID `db:"ids" json:"ids"` + Tags StringMap `db:"tags" json:"tags"` + Limit sql.NullInt32 `db:"limit" json:"limit"` } type GetProvisionerDaemonsWithStatusByOrganizationRow struct { - ProvisionerDaemon ProvisionerDaemon `db:"provisioner_daemon" json:"provisioner_daemon"` - Status ProvisionerDaemonStatus `db:"status" json:"status"` - KeyName string `db:"key_name" json:"key_name"` - CurrentJobID uuid.NullUUID `db:"current_job_id" json:"current_job_id"` - CurrentJobStatus NullProvisionerJobStatus `db:"current_job_status" json:"current_job_status"` - PreviousJobID uuid.NullUUID `db:"previous_job_id" json:"previous_job_id"` - PreviousJobStatus NullProvisionerJobStatus `db:"previous_job_status" json:"previous_job_status"` - CurrentJobTemplateName string `db:"current_job_template_name" json:"current_job_template_name"` - CurrentJobTemplateDisplayName string `db:"current_job_template_display_name" json:"current_job_template_display_name"` - CurrentJobTemplateIcon string `db:"current_job_template_icon" json:"current_job_template_icon"` + ProvisionerDaemon ProvisionerDaemon `db:"provisioner_daemon" json:"provisioner_daemon"` + Status ProvisionerDaemonStatus `db:"status" json:"status"` + KeyName string `db:"key_name" json:"key_name"` + CurrentJobID uuid.NullUUID `db:"current_job_id" json:"current_job_id"` + CurrentJobStatus NullProvisionerJobStatus `db:"current_job_status" json:"current_job_status"` + PreviousJobID uuid.NullUUID `db:"previous_job_id" json:"previous_job_id"` + PreviousJobStatus NullProvisionerJobStatus `db:"previous_job_status" json:"previous_job_status"` + CurrentJobTemplateName string `db:"current_job_template_name" json:"current_job_template_name"` + CurrentJobTemplateDisplayName string `db:"current_job_template_display_name" json:"current_job_template_display_name"` + CurrentJobTemplateIcon string `db:"current_job_template_icon" json:"current_job_template_icon"` + PreviousJobTemplateName string `db:"previous_job_template_name" json:"previous_job_template_name"` + PreviousJobTemplateDisplayName string `db:"previous_job_template_display_name" json:"previous_job_template_display_name"` + PreviousJobTemplateIcon string `db:"previous_job_template_icon" json:"previous_job_template_icon"` } +// Current job information. +// Previous job information. func (q *sqlQuerier) GetProvisionerDaemonsWithStatusByOrganization(ctx context.Context, arg GetProvisionerDaemonsWithStatusByOrganizationParams) ([]GetProvisionerDaemonsWithStatusByOrganizationRow, error) { rows, err := q.db.QueryContext(ctx, getProvisionerDaemonsWithStatusByOrganization, arg.StaleIntervalMS, arg.OrganizationID, pq.Array(arg.IDs), arg.Tags, + arg.Limit, ) if err != nil { return nil, err @@ -6054,6 +6076,9 @@ func (q *sqlQuerier) GetProvisionerDaemonsWithStatusByOrganization(ctx context.C &i.CurrentJobTemplateName, &i.CurrentJobTemplateDisplayName, &i.CurrentJobTemplateIcon, + &i.PreviousJobTemplateName, + &i.PreviousJobTemplateDisplayName, + &i.PreviousJobTemplateIcon, ); err != nil { return nil, err } diff --git a/coderd/database/queries/provisionerdaemons.sql b/coderd/database/queries/provisionerdaemons.sql index b003153ee9..2aaf23ec0d 100644 --- a/coderd/database/queries/provisionerdaemons.sql +++ b/coderd/database/queries/provisionerdaemons.sql @@ -45,9 +45,12 @@ SELECT current_job.job_status AS current_job_status, previous_job.id AS previous_job_id, previous_job.job_status AS previous_job_status, - COALESCE(tmpl.name, ''::text) AS current_job_template_name, - COALESCE(tmpl.display_name, ''::text) AS current_job_template_display_name, - COALESCE(tmpl.icon, ''::text) AS current_job_template_icon + COALESCE(current_template.name, ''::text) AS current_job_template_name, + COALESCE(current_template.display_name, ''::text) AS current_job_template_display_name, + COALESCE(current_template.icon, ''::text) AS current_job_template_icon, + COALESCE(previous_template.name, ''::text) AS previous_job_template_name, + COALESCE(previous_template.display_name, ''::text) AS previous_job_template_display_name, + COALESCE(previous_template.icon, ''::text) AS previous_job_template_icon FROM provisioner_daemons pd JOIN @@ -72,16 +75,30 @@ LEFT JOIN LIMIT 1 ) ) +-- Current job information. LEFT JOIN - template_versions version ON version.id = (current_job.input->>'template_version_id')::uuid + workspace_builds current_build ON current_build.id = CASE WHEN current_job.input ? 'workspace_build_id' THEN (current_job.input->>'workspace_build_id')::uuid END LEFT JOIN - templates tmpl ON tmpl.id = version.template_id + -- We should always have a template version, either explicitly or implicitly via workspace build. + template_versions current_version ON current_version.id = CASE WHEN current_job.input ? 'template_version_id' THEN (current_job.input->>'template_version_id')::uuid ELSE current_build.template_version_id END +LEFT JOIN + templates current_template ON current_template.id = current_version.template_id +-- Previous job information. +LEFT JOIN + workspace_builds previous_build ON previous_build.id = CASE WHEN previous_job.input ? 'workspace_build_id' THEN (previous_job.input->>'workspace_build_id')::uuid END +LEFT JOIN + -- We should always have a template version, either explicitly or implicitly via workspace build. + template_versions previous_version ON previous_version.id = CASE WHEN previous_job.input ? 'template_version_id' THEN (previous_job.input->>'template_version_id')::uuid ELSE previous_build.template_version_id END +LEFT JOIN + templates previous_template ON previous_template.id = previous_version.template_id WHERE pd.organization_id = @organization_id::uuid AND (COALESCE(array_length(@ids::uuid[], 1), 0) = 0 OR pd.id = ANY(@ids::uuid[])) AND (@tags::tagset = 'null'::tagset OR provisioner_tagset_contains(pd.tags::tagset, @tags::tagset)) ORDER BY - pd.created_at ASC; + pd.created_at ASC +LIMIT + sqlc.narg('limit')::int; -- name: DeleteOldProvisionerDaemons :exec -- Delete provisioner daemons that have been created at least a week ago diff --git a/coderd/provisionerdaemons.go b/coderd/provisionerdaemons.go index bf4dfb6c4d..e701771770 100644 --- a/coderd/provisionerdaemons.go +++ b/coderd/provisionerdaemons.go @@ -1,6 +1,7 @@ package coderd import ( + "database/sql" "net/http" "github.com/coder/coder/v2/coderd/database" @@ -18,31 +19,50 @@ import ( // @Produce json // @Tags Provisioning // @Param organization path string true "Organization ID" format(uuid) +// @Param limit query int false "Page limit" +// @Param ids query []string false "Filter results by job IDs" format(uuid) +// @Param status query codersdk.ProvisionerJobStatus false "Filter results by status" enums(pending,running,succeeded,canceling,canceled,failed) // @Param tags query object false "Provisioner tags to filter by (JSON of the form {'tag1':'value1','tag2':'value2'})" // @Success 200 {array} codersdk.ProvisionerDaemon // @Router /organizations/{organization}/provisionerdaemons [get] func (api *API) provisionerDaemons(rw http.ResponseWriter, r *http.Request) { var ( - ctx = r.Context() - org = httpmw.OrganizationParam(r) - tagParam = r.URL.Query().Get("tags") - tags = database.StringMap{} - err = tags.Scan([]byte(tagParam)) + ctx = r.Context() + org = httpmw.OrganizationParam(r) ) - if tagParam != "" && err != nil { + qp := r.URL.Query() + p := httpapi.NewQueryParamParser() + limit := p.PositiveInt32(qp, 50, "limit") + ids := p.UUIDs(qp, nil, "ids") + tagsRaw := p.String(qp, "", "tags") + p.ErrorExcessParams(qp) + if len(p.Errors) > 0 { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ - Message: "Invalid tags query parameter", - Detail: err.Error(), + Message: "Invalid query parameters.", + Validations: p.Errors, }) return } + tags := database.StringMap{} + if tagsRaw != "" { + if err := tags.Scan([]byte(tagsRaw)); err != nil { + httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ + Message: "Invalid tags query parameter", + Detail: err.Error(), + }) + return + } + } + daemons, err := api.Database.GetProvisionerDaemonsWithStatusByOrganization( ctx, database.GetProvisionerDaemonsWithStatusByOrganizationParams{ OrganizationID: org.ID, StaleIntervalMS: provisionerdserver.StaleInterval.Milliseconds(), + Limit: sql.NullInt32{Int32: limit, Valid: limit > 0}, + IDs: ids, Tags: tags, }, ) @@ -68,8 +88,11 @@ func (api *API) provisionerDaemons(rw http.ResponseWriter, r *http.Request) { } if dbDaemon.PreviousJobID.Valid { previousJob = &codersdk.ProvisionerDaemonJob{ - ID: dbDaemon.PreviousJobID.UUID, - Status: codersdk.ProvisionerJobStatus(dbDaemon.PreviousJobStatus.ProvisionerJobStatus), + ID: dbDaemon.PreviousJobID.UUID, + Status: codersdk.ProvisionerJobStatus(dbDaemon.PreviousJobStatus.ProvisionerJobStatus), + TemplateName: dbDaemon.PreviousJobTemplateName, + TemplateIcon: dbDaemon.PreviousJobTemplateIcon, + TemplateDisplayName: dbDaemon.PreviousJobTemplateDisplayName, } } diff --git a/coderd/provisionerdaemons_test.go b/coderd/provisionerdaemons_test.go index 243a24add0..6496b4dd57 100644 --- a/coderd/provisionerdaemons_test.go +++ b/coderd/provisionerdaemons_test.go @@ -1,27 +1,251 @@ package coderd_test import ( + "database/sql" + "encoding/json" + "strconv" "testing" + "time" + "github.com/google/uuid" "github.com/stretchr/testify/require" "github.com/coder/coder/v2/coderd/coderdtest" + "github.com/coder/coder/v2/coderd/database" + "github.com/coder/coder/v2/coderd/database/dbgen" + "github.com/coder/coder/v2/coderd/database/dbtestutil" + "github.com/coder/coder/v2/coderd/database/dbtime" + "github.com/coder/coder/v2/coderd/rbac" + "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/testutil" ) -func TestGetProvisionerDaemons(t *testing.T) { +func TestProvisionerDaemons(t *testing.T) { t.Parallel() - t.Run("OK", func(t *testing.T) { + db, ps := dbtestutil.NewDB(t, + dbtestutil.WithDumpOnFailure(), + //nolint:gocritic // Use UTC for consistent timestamp length in golden files. + dbtestutil.WithTimezone("UTC"), + ) + client, _, coderdAPI := coderdtest.NewWithAPI(t, &coderdtest.Options{ + IncludeProvisionerDaemon: false, + Database: db, + Pubsub: ps, + }) + owner := coderdtest.CreateFirstUser(t, client) + templateAdminClient, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.ScopedRoleOrgTemplateAdmin(owner.OrganizationID)) + memberClient, member := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) + + // Create initial resources with a running provisioner. + firstProvisioner := coderdtest.NewTaggedProvisionerDaemon(t, coderdAPI, "default-provisioner", map[string]string{"owner": "", "scope": "organization"}) + t.Cleanup(func() { _ = firstProvisioner.Close() }) + version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil) + coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) + template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) + + workspace := coderdtest.CreateWorkspace(t, client, template.ID) + coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) + + // Stop the provisioner so it doesn't grab any more jobs. + firstProvisioner.Close() + + // Create a provisioner that's working on a job. + pd1 := dbgen.ProvisionerDaemon(t, coderdAPI.Database, database.ProvisionerDaemon{ + Name: "provisioner-1", + CreatedAt: dbtime.Now().Add(1 * time.Second), + LastSeenAt: sql.NullTime{Time: coderdAPI.Clock.Now().Add(time.Hour), Valid: true}, // Stale interval can't be adjusted, keep online. + KeyID: codersdk.ProvisionerKeyUUIDBuiltIn, + Tags: database.StringMap{"owner": "", "scope": "organization", "foo": "bar"}, + }) + w1 := dbgen.Workspace(t, coderdAPI.Database, database.WorkspaceTable{ + OwnerID: member.ID, + TemplateID: template.ID, + }) + wb1ID := uuid.MustParse("00000000-0000-0000-dddd-000000000001") + job1 := dbgen.ProvisionerJob(t, db, coderdAPI.Pubsub, database.ProvisionerJob{ + WorkerID: uuid.NullUUID{UUID: pd1.ID, Valid: true}, + Input: json.RawMessage(`{"workspace_build_id":"` + wb1ID.String() + `"}`), + CreatedAt: dbtime.Now().Add(2 * time.Second), + StartedAt: sql.NullTime{Time: coderdAPI.Clock.Now(), Valid: true}, + Tags: database.StringMap{"owner": "", "scope": "organization", "foo": "bar"}, + }) + dbgen.WorkspaceBuild(t, coderdAPI.Database, database.WorkspaceBuild{ + ID: wb1ID, + JobID: job1.ID, + WorkspaceID: w1.ID, + TemplateVersionID: version.ID, + }) + + // Create a provisioner that completed a job previously and is offline. + pd2 := dbgen.ProvisionerDaemon(t, coderdAPI.Database, database.ProvisionerDaemon{ + Name: "provisioner-2", + CreatedAt: dbtime.Now().Add(2 * time.Second), + LastSeenAt: sql.NullTime{Time: coderdAPI.Clock.Now().Add(-time.Hour), Valid: true}, + KeyID: codersdk.ProvisionerKeyUUIDBuiltIn, + Tags: database.StringMap{"owner": "", "scope": "organization"}, + }) + w2 := dbgen.Workspace(t, coderdAPI.Database, database.WorkspaceTable{ + OwnerID: member.ID, + TemplateID: template.ID, + }) + wb2ID := uuid.MustParse("00000000-0000-0000-dddd-000000000002") + job2 := dbgen.ProvisionerJob(t, db, coderdAPI.Pubsub, database.ProvisionerJob{ + WorkerID: uuid.NullUUID{UUID: pd2.ID, Valid: true}, + Input: json.RawMessage(`{"workspace_build_id":"` + wb2ID.String() + `"}`), + CreatedAt: dbtime.Now().Add(3 * time.Second), + StartedAt: sql.NullTime{Time: coderdAPI.Clock.Now().Add(-2 * time.Hour), Valid: true}, + CompletedAt: sql.NullTime{Time: coderdAPI.Clock.Now().Add(-time.Hour), Valid: true}, + Tags: database.StringMap{"owner": "", "scope": "organization"}, + }) + dbgen.WorkspaceBuild(t, coderdAPI.Database, database.WorkspaceBuild{ + ID: wb2ID, + JobID: job2.ID, + WorkspaceID: w2.ID, + TemplateVersionID: version.ID, + }) + + // Create a pending job. + w3 := dbgen.Workspace(t, coderdAPI.Database, database.WorkspaceTable{ + OwnerID: member.ID, + TemplateID: template.ID, + }) + wb3ID := uuid.MustParse("00000000-0000-0000-dddd-000000000003") + job3 := dbgen.ProvisionerJob(t, db, coderdAPI.Pubsub, database.ProvisionerJob{ + Input: json.RawMessage(`{"workspace_build_id":"` + wb3ID.String() + `"}`), + CreatedAt: dbtime.Now().Add(4 * time.Second), + Tags: database.StringMap{"owner": "", "scope": "organization"}, + }) + dbgen.WorkspaceBuild(t, coderdAPI.Database, database.WorkspaceBuild{ + ID: wb3ID, + JobID: job3.ID, + WorkspaceID: w3.ID, + TemplateVersionID: version.ID, + }) + + // Create a provisioner that is idle. + pd3 := dbgen.ProvisionerDaemon(t, coderdAPI.Database, database.ProvisionerDaemon{ + Name: "provisioner-3", + CreatedAt: dbtime.Now().Add(3 * time.Second), + LastSeenAt: sql.NullTime{Time: coderdAPI.Clock.Now().Add(time.Hour), Valid: true}, + KeyID: codersdk.ProvisionerKeyUUIDBuiltIn, + Tags: database.StringMap{"owner": "", "scope": "organization"}, + }) + + // Add more provisioners than the default limit. + var userDaemons []database.ProvisionerDaemon + for i := range 50 { + userDaemons = append(userDaemons, dbgen.ProvisionerDaemon(t, coderdAPI.Database, database.ProvisionerDaemon{ + Name: "user-provisioner-" + strconv.Itoa(i), + CreatedAt: dbtime.Now().Add(3 * time.Second), + KeyID: codersdk.ProvisionerKeyUUIDUserAuth, + Tags: database.StringMap{"count": strconv.Itoa(i)}, + })) + } + + t.Run("Default limit", func(t *testing.T) { t.Parallel() - client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) - owner := coderdtest.CreateFirstUser(t, client) - memberClient, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) - ctx := testutil.Context(t, testutil.WaitMedium) + daemons, err := templateAdminClient.OrganizationProvisionerDaemons(ctx, owner.OrganizationID, nil) + require.NoError(t, err) + require.Len(t, daemons, 50) + }) - daemons, err := memberClient.ProvisionerDaemons(ctx) + t.Run("IDs", func(t *testing.T) { + t.Parallel() + ctx := testutil.Context(t, testutil.WaitMedium) + daemons, err := templateAdminClient.OrganizationProvisionerDaemons(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerDaemonsOptions{ + IDs: []uuid.UUID{pd1.ID, pd2.ID}, + }) + require.NoError(t, err) + require.Len(t, daemons, 2) + require.Equal(t, pd1.ID, daemons[0].ID) + require.Equal(t, pd2.ID, daemons[1].ID) + }) + + t.Run("Tags", func(t *testing.T) { + t.Parallel() + ctx := testutil.Context(t, testutil.WaitMedium) + daemons, err := templateAdminClient.OrganizationProvisionerDaemons(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerDaemonsOptions{ + Tags: map[string]string{"count": "1"}, + }) + require.NoError(t, err) + require.Len(t, daemons, 1) + require.Equal(t, userDaemons[1].ID, daemons[0].ID) + }) + + t.Run("Limit", func(t *testing.T) { + t.Parallel() + ctx := testutil.Context(t, testutil.WaitMedium) + daemons, err := templateAdminClient.OrganizationProvisionerDaemons(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerDaemonsOptions{ + Limit: 1, + }) require.NoError(t, err) require.Len(t, daemons, 1) }) + + t.Run("Busy", func(t *testing.T) { + t.Parallel() + ctx := testutil.Context(t, testutil.WaitMedium) + daemons, err := templateAdminClient.OrganizationProvisionerDaemons(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerDaemonsOptions{ + IDs: []uuid.UUID{pd1.ID}, + }) + require.NoError(t, err) + require.Len(t, daemons, 1) + // Verify status. + require.NotNil(t, daemons[0].Status) + require.Equal(t, codersdk.ProvisionerDaemonBusy, *daemons[0].Status) + require.NotNil(t, daemons[0].CurrentJob) + require.Nil(t, daemons[0].PreviousJob) + // Verify job. + require.Equal(t, job1.ID, daemons[0].CurrentJob.ID) + require.Equal(t, codersdk.ProvisionerJobRunning, daemons[0].CurrentJob.Status) + require.Equal(t, template.Name, daemons[0].CurrentJob.TemplateName) + require.Equal(t, template.DisplayName, daemons[0].CurrentJob.TemplateDisplayName) + require.Equal(t, template.Icon, daemons[0].CurrentJob.TemplateIcon) + }) + + t.Run("Offline", func(t *testing.T) { + t.Parallel() + ctx := testutil.Context(t, testutil.WaitMedium) + daemons, err := templateAdminClient.OrganizationProvisionerDaemons(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerDaemonsOptions{ + IDs: []uuid.UUID{pd2.ID}, + }) + require.NoError(t, err) + require.Len(t, daemons, 1) + // Verify status. + require.NotNil(t, daemons[0].Status) + require.Equal(t, codersdk.ProvisionerDaemonOffline, *daemons[0].Status) + require.Nil(t, daemons[0].CurrentJob) + require.NotNil(t, daemons[0].PreviousJob) + // Verify job. + require.Equal(t, job2.ID, daemons[0].PreviousJob.ID) + require.Equal(t, codersdk.ProvisionerJobSucceeded, daemons[0].PreviousJob.Status) + require.Equal(t, template.Name, daemons[0].PreviousJob.TemplateName) + require.Equal(t, template.DisplayName, daemons[0].PreviousJob.TemplateDisplayName) + require.Equal(t, template.Icon, daemons[0].PreviousJob.TemplateIcon) + }) + + t.Run("Idle", func(t *testing.T) { + t.Parallel() + ctx := testutil.Context(t, testutil.WaitMedium) + daemons, err := templateAdminClient.OrganizationProvisionerDaemons(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerDaemonsOptions{ + IDs: []uuid.UUID{pd3.ID}, + }) + require.NoError(t, err) + require.Len(t, daemons, 1) + // Verify status. + require.NotNil(t, daemons[0].Status) + require.Equal(t, codersdk.ProvisionerDaemonIdle, *daemons[0].Status) + require.Nil(t, daemons[0].CurrentJob) + require.Nil(t, daemons[0].PreviousJob) + }) + + t.Run("MemberAllowed", func(t *testing.T) { + t.Parallel() + ctx := testutil.Context(t, testutil.WaitMedium) + daemons, err := memberClient.OrganizationProvisionerDaemons(ctx, owner.OrganizationID, nil) + require.NoError(t, err) + require.Len(t, daemons, 50) + }) } diff --git a/coderd/provisionerdserver/provisionerdserver_test.go b/coderd/provisionerdserver/provisionerdserver_test.go index f10fa8e569..21ba8c6fad 100644 --- a/coderd/provisionerdserver/provisionerdserver_test.go +++ b/coderd/provisionerdserver/provisionerdserver_test.go @@ -1785,7 +1785,7 @@ func TestInsertWorkspacePresetsAndParameters(t *testing.T) { t.Run(c.name, func(t *testing.T) { t.Parallel() - ctx := context.Background() + ctx := testutil.Context(t, testutil.WaitLong) logger := testutil.Logger(t) db, ps := dbtestutil.NewDB(t) org := dbgen.Organization(t, db, database.Organization{}) diff --git a/coderd/workspaceagents_test.go b/coderd/workspaceagents_test.go index 7a051ef233..cdb33e08a5 100644 --- a/coderd/workspaceagents_test.go +++ b/coderd/workspaceagents_test.go @@ -2234,7 +2234,7 @@ func requireGetManifest(ctx context.Context, t testing.TB, aAPI agentproto.DRPCA } func postStartup(ctx context.Context, t testing.TB, client agent.Client, startup *agentproto.Startup) error { - aAPI, _, err := client.ConnectRPC23(ctx) + aAPI, _, err := client.ConnectRPC24(ctx) require.NoError(t, err) defer func() { cErr := aAPI.DRPCConn().Close() diff --git a/codersdk/agentsdk/agentsdk.go b/codersdk/agentsdk/agentsdk.go index 13f2fff43d..b5f86c2220 100644 --- a/codersdk/agentsdk/agentsdk.go +++ b/codersdk/agentsdk/agentsdk.go @@ -231,9 +231,9 @@ func (c *Client) ConnectRPC23(ctx context.Context) ( } // ConnectRPC24 returns a dRPC client to the Agent API v2.4. It is useful when you want to be -// maximally compatible with Coderd Release Versions from 2.18+ // TODO update release +// maximally compatible with Coderd Release Versions from 2.xx+ // TODO @vincent: define version func (c *Client) ConnectRPC24(ctx context.Context) ( - proto.DRPCAgentClient23, tailnetproto.DRPCTailnetClient23, error, + proto.DRPCAgentClient24, tailnetproto.DRPCTailnetClient24, error, ) { conn, err := c.connectRPCVersion(ctx, apiversion.New(2, 4)) if err != nil { diff --git a/codersdk/organizations.go b/codersdk/organizations.go index 59d2d6822f..3fafc72b80 100644 --- a/codersdk/organizations.go +++ b/codersdk/organizations.go @@ -318,21 +318,34 @@ func (c *Client) ProvisionerDaemons(ctx context.Context) ([]ProvisionerDaemon, e return daemons, json.NewDecoder(res.Body).Decode(&daemons) } -func (c *Client) OrganizationProvisionerDaemons(ctx context.Context, organizationID uuid.UUID, tags map[string]string) ([]ProvisionerDaemon, error) { - baseURL := fmt.Sprintf("/api/v2/organizations/%s/provisionerdaemons", organizationID.String()) +type OrganizationProvisionerDaemonsOptions struct { + Limit int + IDs []uuid.UUID + Tags map[string]string +} - queryParams := url.Values{} - tagsJSON, err := json.Marshal(tags) - if err != nil { - return nil, xerrors.Errorf("marshal tags: %w", err) +func (c *Client) OrganizationProvisionerDaemons(ctx context.Context, organizationID uuid.UUID, opts *OrganizationProvisionerDaemonsOptions) ([]ProvisionerDaemon, error) { + qp := url.Values{} + if opts != nil { + if opts.Limit > 0 { + qp.Add("limit", strconv.Itoa(opts.Limit)) + } + if len(opts.IDs) > 0 { + qp.Add("ids", joinSliceStringer(opts.IDs)) + } + if len(opts.Tags) > 0 { + tagsRaw, err := json.Marshal(opts.Tags) + if err != nil { + return nil, xerrors.Errorf("marshal tags: %w", err) + } + qp.Add("tags", string(tagsRaw)) + } } - queryParams.Add("tags", string(tagsJSON)) - if len(queryParams) > 0 { - baseURL = fmt.Sprintf("%s?%s", baseURL, queryParams.Encode()) - } - - res, err := c.Request(ctx, http.MethodGet, baseURL, nil) + res, err := c.Request(ctx, http.MethodGet, + fmt.Sprintf("/api/v2/organizations/%s/provisionerdaemons?%s", organizationID.String(), qp.Encode()), + nil, + ) if err != nil { return nil, xerrors.Errorf("execute request: %w", err) } diff --git a/codersdk/richparameters.go b/codersdk/richparameters.go index a0848d3cdf..6fd082d5fa 100644 --- a/codersdk/richparameters.go +++ b/codersdk/richparameters.go @@ -5,7 +5,7 @@ import ( "golang.org/x/xerrors" - "github.com/coder/terraform-provider-coder/provider" + "github.com/coder/terraform-provider-coder/v2/provider" ) func ValidateNewWorkspaceParameters(richParameters []TemplateVersionParameter, buildParameters []WorkspaceBuildParameter) error { diff --git a/docs/admin/users/sessions-tokens.md b/docs/admin/users/sessions-tokens.md index dbbcfb82df..6332b8182f 100644 --- a/docs/admin/users/sessions-tokens.md +++ b/docs/admin/users/sessions-tokens.md @@ -51,10 +51,28 @@ See the help docs for ### Generate a long-lived API token on behalf of another user -Today, you must use the REST API to generate a token on behalf of another user. -You must have the `Owner` role to do this. Use our API reference for more -information: -[Create token API key](https://coder.com/docs/reference/api/users#create-token-api-key) +You must have the `Owner` role to generate a token for another user. + +As of Coder v2.17+, you can use the CLI or API to create long-lived tokens on +behalf of other users. Use the API for earlier versions of Coder. + +
+ +#### CLI + +```sh +coder tokens create my-token --user +``` + +See the full CLI reference for +[`coder tokens create`](../../reference/cli/tokens_create.md) + +#### API + +Use our API reference for more information on how to +[create token API key](../../reference/api/users.md#create-token-api-key) + +
### Set max token length diff --git a/docs/reference/api/provisioning.md b/docs/reference/api/provisioning.md index a8f7fd7e83..1d910e4bc0 100644 --- a/docs/reference/api/provisioning.md +++ b/docs/reference/api/provisioning.md @@ -18,8 +18,29 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/provisi | Name | In | Type | Required | Description | |----------------|-------|--------------|----------|------------------------------------------------------------------------------------| | `organization` | path | string(uuid) | true | Organization ID | +| `limit` | query | integer | false | Page limit | +| `ids` | query | array(uuid) | false | Filter results by job IDs | +| `status` | query | string | false | Filter results by status | | `tags` | query | object | false | Provisioner tags to filter by (JSON of the form {'tag1':'value1','tag2':'value2'}) | +#### Enumerated Values + +| Parameter | Value | +|-----------|-------------| +| `status` | `pending` | +| `status` | `running` | +| `status` | `succeeded` | +| `status` | `canceling` | +| `status` | `canceled` | +| `status` | `failed` | +| `status` | `unknown` | +| `status` | `pending` | +| `status` | `running` | +| `status` | `succeeded` | +| `status` | `canceling` | +| `status` | `canceled` | +| `status` | `failed` | + ### Example responses > 200 Response diff --git a/enterprise/coderd/provisionerdaemons_test.go b/enterprise/coderd/provisionerdaemons_test.go index bcdb75c6a5..20d7844675 100644 --- a/enterprise/coderd/provisionerdaemons_test.go +++ b/enterprise/coderd/provisionerdaemons_test.go @@ -990,7 +990,9 @@ func TestGetProvisionerDaemons(t *testing.T) { require.NoError(t, err) require.Len(t, allDaemons, 1) - daemonsAsFound, err := orgAdmin.OrganizationProvisionerDaemons(ctx, org.ID, tt.tagsToFilterBy) + daemonsAsFound, err := orgAdmin.OrganizationProvisionerDaemons(ctx, org.ID, &codersdk.OrganizationProvisionerDaemonsOptions{ + Tags: tt.tagsToFilterBy, + }) if tt.expectToGetDaemon { require.NoError(t, err) require.Len(t, daemonsAsFound, 1) diff --git a/go.mod b/go.mod index 94052d9067..0254d964d3 100644 --- a/go.mod +++ b/go.mod @@ -94,7 +94,7 @@ require ( github.com/coder/quartz v0.1.2 github.com/coder/retry v1.5.1 github.com/coder/serpent v0.10.0 - github.com/coder/terraform-provider-coder v1.0.5-0.20250131073245-5b9a30ca496b + github.com/coder/terraform-provider-coder/v2 v2.1.3 github.com/coder/websocket v1.8.12 github.com/coder/wgtunnel v0.1.13-0.20240522110300-ade90dfb2da0 github.com/coreos/go-oidc/v3 v3.12.0 @@ -468,6 +468,4 @@ require ( sigs.k8s.io/yaml v1.4.0 // indirect ) -require github.com/coder/terraform-provider-coder/v2 v2.1.3 // indirect - -replace github.com/coder/terraform-provider-coder => github.com/coder/terraform-provider-coder/v2 v2.1.4-0.20250211100915-129c295afed8 +replace github.com/coder/terraform-provider-coder/v2 => github.com/coder/terraform-provider-coder/v2 v2.1.4-0.20250211100915-129c295afed8 diff --git a/go.sum b/go.sum index 1cbafcd160..34058615f8 100644 --- a/go.sum +++ b/go.sum @@ -240,8 +240,6 @@ github.com/coder/tailscale v1.1.1-0.20250129014916-8086c871eae6 h1:prDIwUcsSEKbs github.com/coder/tailscale v1.1.1-0.20250129014916-8086c871eae6/go.mod h1:1ggFFdHTRjPRu9Yc1yA7nVHBYB50w9Ce7VIXNqcW6Ko= github.com/coder/terraform-config-inspect v0.0.0-20250107175719-6d06d90c630e h1:JNLPDi2P73laR1oAclY6jWzAbucf70ASAvf5mh2cME0= github.com/coder/terraform-config-inspect v0.0.0-20250107175719-6d06d90c630e/go.mod h1:Gz/z9Hbn+4KSp8A2FBtNszfLSdT2Tn/uAKGuVqqWmDI= -github.com/coder/terraform-provider-coder/v2 v2.1.3 h1:zB7ObGsiOGBHcJUUMmcSauEPlTWRIYmMYieF05LxHSc= -github.com/coder/terraform-provider-coder/v2 v2.1.3/go.mod h1:RHGyb+ghiy8UpDAMJM8duRFuzd+1VqA3AtkRLh2P3Ug= github.com/coder/terraform-provider-coder/v2 v2.1.4-0.20250211100915-129c295afed8 h1:qslh7kQytybvJHlqTI3XKUuFRnZWgvEjzZKq6e1aQ2M= github.com/coder/terraform-provider-coder/v2 v2.1.4-0.20250211100915-129c295afed8/go.mod h1:RHGyb+ghiy8UpDAMJM8duRFuzd+1VqA3AtkRLh2P3Ug= github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo= diff --git a/provisioner/terraform/executor.go b/provisioner/terraform/executor.go index 99ec99856c..4d08f24cac 100644 --- a/provisioner/terraform/executor.go +++ b/provisioner/terraform/executor.go @@ -15,7 +15,7 @@ import ( "sync" "time" - "github.com/coder/terraform-provider-coder/provider" + "github.com/coder/terraform-provider-coder/v2/provider" "github.com/hashicorp/go-version" tfjson "github.com/hashicorp/terraform-json" diff --git a/provisioner/terraform/provision.go b/provisioner/terraform/provision.go index c31773b67b..33aa3556a4 100644 --- a/provisioner/terraform/provision.go +++ b/provisioner/terraform/provision.go @@ -16,7 +16,7 @@ import ( "golang.org/x/xerrors" "cdr.dev/slog" - "github.com/coder/terraform-provider-coder/provider" + "github.com/coder/terraform-provider-coder/v2/provider" "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/tracing" @@ -274,7 +274,7 @@ func provisionEnv( env = append(env, provider.ParameterEnvironmentVariable(param.Name)+"="+param.Value) } for _, extAuth := range externalAuth { - // env = append(env, provider.GitAuthAccessTokenEnvironmentVariable(extAuth.Id)+"="+extAuth.AccessToken) + // env = append(env, gitAuthAccessTokenEnvironmentVariable(extAuth.Id)+"="+extAuth.AccessToken) env = append(env, provider.ExternalAuthAccessTokenEnvironmentVariable(extAuth.Id)+"="+extAuth.AccessToken) } @@ -356,3 +356,12 @@ func tryGettingCoderProviderStacktrace(sess *provisionersdk.Session) string { } return string(stacktraces) } + +// gitAuthAccessTokenEnvironmentVariable is copied from +// github.com/coder/terraform-provider-coder/provider.GitAuthAccessTokenEnvironmentVariable@v1.0.4. +// While removed in v2 of the provider, we keep this to support customers using older templates that +// depend on this environment variable. Once we are certain that no customers are still using v1 of +// the provider, we can remove this function. +func gitAuthAccessTokenEnvironmentVariable(id string) string { + return fmt.Sprintf("CODER_GIT_AUTH_ACCESS_TOKEN_%s", id) +} diff --git a/provisioner/terraform/resources.go b/provisioner/terraform/resources.go index a9ebf39ad6..5c96863728 100644 --- a/provisioner/terraform/resources.go +++ b/provisioner/terraform/resources.go @@ -12,7 +12,7 @@ import ( "cdr.dev/slog" - "github.com/coder/terraform-provider-coder/provider" + "github.com/coder/terraform-provider-coder/v2/provider" tfaddr "github.com/hashicorp/go-terraform-address" @@ -824,7 +824,6 @@ func ConvertState(ctx context.Context, modules []*tfjson.StateModule, rawGraph s } if len(nonExistentParameters) > 0 { - // TODO (sasswart): should this be an error? Or should we just log it? logger.Warn( ctx, "coder_workspace_preset defines preset values for at least one parameter that is not defined by the template", diff --git a/provisioner/terraform/resources_test.go b/provisioner/terraform/resources_test.go index d589b9a966..1c6859a880 100644 --- a/provisioner/terraform/resources_test.go +++ b/provisioner/terraform/resources_test.go @@ -827,38 +827,9 @@ func TestConvertResources(t *testing.T) { Parameters: []*proto.PresetParameter{{ Name: "Sample", Value: "A1B2C3", - // Advice from Danny: - // This is Terraform functionality. We don't have to test it explicitly. - // Sas: We still at some point need to document it. - // TODO (sasswart): Decide how to support presetting coder parameters from external modules - // Options are: - // * Set outputs with the parameter names and refer to those in the preset - // * set presets in the child module (won't work because we don't support merging presets) - // * hard coder parameter names - // }, { - // Name: "First parameter from module", - // Value: "A1B2C3", - // }, { - // Name: "First parameter from child module", - // Value: "A1B2C3", }}, }}, }, - // TODO (sasswart): Decide how to test sad paths. - // Do we just introduce an expectedErr in the testcase? - // Methinks yes - // "presets-without-parameters": { - // resources: []*proto.Resource{{ - // Name: "dev", - // Type: "null_resource", - // }}, - // }, - // "presets-with-invalid-parameters": { - // resources: []*proto.Resource{{ - // Name: "dev", - // Type: "null_resource", - // }}, - // }, } { folderName := folderName expected := expected diff --git a/provisioner/terraform/testdata/calling-module/calling-module.tfplan.json b/provisioner/terraform/testdata/calling-module/calling-module.tfplan.json index e3237c2a8c..6be5318da7 100644 --- a/provisioner/terraform/testdata/calling-module/calling-module.tfplan.json +++ b/provisioner/terraform/testdata/calling-module/calling-module.tfplan.json @@ -21,6 +21,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -29,6 +30,7 @@ "sensitive_values": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } } @@ -91,6 +93,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -101,12 +104,14 @@ "id": true, "init_script": true, "metadata": [], + "resources_monitoring": [], "token": true }, "before_sensitive": false, "after_sensitive": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } } @@ -254,7 +259,7 @@ ] } ], - "timestamp": "2025-02-06T07:28:26Z", + "timestamp": "2025-01-29T22:47:46Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/calling-module/calling-module.tfstate.json b/provisioner/terraform/testdata/calling-module/calling-module.tfstate.json index 0ad2ea5f83..73aeed2d3a 100644 --- a/provisioner/terraform/testdata/calling-module/calling-module.tfstate.json +++ b/provisioner/terraform/testdata/calling-module/calling-module.tfstate.json @@ -26,16 +26,17 @@ } ], "env": null, - "id": "64433843-18f6-4f77-8f4f-f4f0eeaa67e2", + "id": "14f0eb08-1bdb-4d48-ab20-e06584ee5b68", "init_script": "", "metadata": [], "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "d109220e-5f54-4971-90d6-0761a77c653e", + "token": "454fffe5-3c59-4a9e-80a0-0d1644ce3b24", "troubleshooting_url": null }, "sensitive_values": { @@ -43,6 +44,7 @@ {} ], "metadata": [], + "resources_monitoring": [], "token": true } } @@ -66,7 +68,7 @@ "outputs": { "script": "" }, - "random": "1425989887898282436" + "random": "8389680299908922676" }, "sensitive_values": { "inputs": {}, @@ -81,7 +83,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "7833850527819665042", + "id": "8124127383117450432", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfplan.json b/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfplan.json index b5aa139dc1..9f2b1d3736 100644 --- a/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfplan.json +++ b/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfplan.json @@ -21,6 +21,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -29,6 +30,7 @@ "sensitive_values": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -81,6 +83,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -91,12 +94,14 @@ "id": true, "init_script": true, "metadata": [], + "resources_monitoring": [], "token": true }, "before_sensitive": false, "after_sensitive": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } } @@ -199,7 +204,7 @@ ] } }, - "timestamp": "2025-02-06T07:28:26Z", + "timestamp": "2025-01-29T22:47:48Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfstate.json b/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfstate.json index 2c8a2ddb67..fc6241b86e 100644 --- a/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfstate.json +++ b/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfstate.json @@ -26,16 +26,17 @@ } ], "env": null, - "id": "8092bd1c-099b-4ca8-8dc1-03e1c8687300", + "id": "038d5038-be85-4609-bde3-56b7452e4386", "init_script": "", "metadata": [], "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "1492d9de-d682-4966-b98e-d3e387823458", + "token": "e570d762-5584-4192-a474-be9e137b2f09", "troubleshooting_url": null }, "sensitive_values": { @@ -43,6 +44,7 @@ {} ], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -54,7 +56,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "8792052167088454384", + "id": "690495753077748083", "triggers": null }, "sensitive_values": {}, @@ -71,7 +73,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "8664046372417778228", + "id": "3238567980725122951", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfplan.json b/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfplan.json index 1d18f36a91..f5218d0c65 100644 --- a/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfplan.json +++ b/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfplan.json @@ -21,6 +21,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -29,6 +30,7 @@ "sensitive_values": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -81,6 +83,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -91,12 +94,14 @@ "id": true, "init_script": true, "metadata": [], + "resources_monitoring": [], "token": true }, "before_sensitive": false, "after_sensitive": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } } @@ -199,7 +204,7 @@ ] } }, - "timestamp": "2025-02-06T07:28:26Z", + "timestamp": "2025-01-29T22:47:50Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfstate.json b/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfstate.json index c2bbebdc80..44bca5b6ab 100644 --- a/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfstate.json +++ b/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfstate.json @@ -26,16 +26,17 @@ } ], "env": null, - "id": "f2f20308-2d37-4f79-b773-26427b2d6b88", + "id": "be15a1b3-f041-4471-9dec-9784c68edb26", "init_script": "", "metadata": [], "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "7c634c45-9a0c-494c-9469-d78253487973", + "token": "df2580ad-59cc-48fb-bb21-40a8be5a5a66", "troubleshooting_url": null }, "sensitive_values": { @@ -43,6 +44,7 @@ {} ], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -54,7 +56,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "5416219352181334882", + "id": "9103672483967127580", "triggers": null }, "sensitive_values": {}, @@ -70,7 +72,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "5511965030506979192", + "id": "4372402015997897970", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tfplan.json b/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tfplan.json index d9317007be..826ba9da95 100644 --- a/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tfplan.json +++ b/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tfplan.json @@ -30,6 +30,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -40,6 +41,7 @@ {} ], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -89,6 +91,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -101,6 +104,7 @@ "id": true, "init_script": true, "metadata": [], + "resources_monitoring": [], "token": true }, "before_sensitive": false, @@ -109,6 +113,7 @@ {} ], "metadata": [], + "resources_monitoring": [], "token": true } } @@ -198,7 +203,7 @@ ] } }, - "timestamp": "2025-02-06T07:28:26Z", + "timestamp": "2025-01-29T22:47:53Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tfstate.json b/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tfstate.json index 6a36c31a23..1948baf713 100644 --- a/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tfstate.json +++ b/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tfstate.json @@ -26,16 +26,17 @@ } ], "env": null, - "id": "5a27b716-6b53-46ad-94fb-6ff0a7fb5028", + "id": "398e27d3-10cc-4522-9144-34658eedad0e", "init_script": "", "metadata": [], "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "ce7268ac-92f8-4889-8341-64aa6c411844", + "token": "33068dbe-54d7-45eb-bfe5-87a9756802e2", "troubleshooting_url": null }, "sensitive_values": { @@ -43,6 +44,7 @@ {} ], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -54,7 +56,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "682773674388598502", + "id": "5682617535476100233", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/display-apps/display-apps.tfplan.json b/provisioner/terraform/testdata/display-apps/display-apps.tfplan.json index 490c0c01ae..9172849c34 100644 --- a/provisioner/terraform/testdata/display-apps/display-apps.tfplan.json +++ b/provisioner/terraform/testdata/display-apps/display-apps.tfplan.json @@ -30,6 +30,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -40,6 +41,7 @@ {} ], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -89,6 +91,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -101,6 +104,7 @@ "id": true, "init_script": true, "metadata": [], + "resources_monitoring": [], "token": true }, "before_sensitive": false, @@ -109,6 +113,7 @@ {} ], "metadata": [], + "resources_monitoring": [], "token": true } } @@ -198,7 +203,7 @@ ] } }, - "timestamp": "2025-02-06T07:28:26Z", + "timestamp": "2025-01-29T22:47:52Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/display-apps/display-apps.tfstate.json b/provisioner/terraform/testdata/display-apps/display-apps.tfstate.json index de4ad59e80..88e4d0f768 100644 --- a/provisioner/terraform/testdata/display-apps/display-apps.tfstate.json +++ b/provisioner/terraform/testdata/display-apps/display-apps.tfstate.json @@ -26,16 +26,17 @@ } ], "env": null, - "id": "52c95fc8-4d53-479c-8368-87f329b84bf7", + "id": "810cdd01-a27d-442f-9e69-bdaecced8a59", "init_script": "", "metadata": [], "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "326a8bd5-1673-4bdf-beee-66c644b45088", + "token": "fade1b71-d52b-4ef2-bb05-961f7795bab9", "troubleshooting_url": null }, "sensitive_values": { @@ -43,6 +44,7 @@ {} ], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -54,7 +56,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "2940668912954669921", + "id": "5174735461860530782", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tfplan.json b/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tfplan.json index 0a0902576e..654ce7464a 100644 --- a/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tfplan.json +++ b/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tfplan.json @@ -21,6 +21,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -29,6 +30,7 @@ "sensitive_values": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -69,6 +71,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -79,12 +82,14 @@ "id": true, "init_script": true, "metadata": [], + "resources_monitoring": [], "token": true }, "before_sensitive": false, "after_sensitive": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } } @@ -222,7 +227,7 @@ ] } }, - "timestamp": "2025-02-06T07:28:26Z", + "timestamp": "2025-01-29T22:47:55Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tfstate.json b/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tfstate.json index f232546ce6..733c9dd3ac 100644 --- a/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tfstate.json +++ b/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tfstate.json @@ -54,16 +54,17 @@ } ], "env": null, - "id": "0be614e7-c8c1-4821-97c2-1cc3dec6744b", + "id": "7ead336b-d366-4991-b38d-bdb8b9333ae9", "init_script": "", "metadata": [], "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "de9d4b55-2735-47b4-b091-260dcb1be4cb", + "token": "a3d2c620-f065-4b29-ae58-370292e787d4", "troubleshooting_url": null }, "sensitive_values": { @@ -71,6 +72,7 @@ {} ], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -82,7 +84,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "6479999379045576610", + "id": "3060850815800759131", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/instance-id/instance-id.tfplan.json b/provisioner/terraform/testdata/instance-id/instance-id.tfplan.json index b0a45acab9..04e6c6f009 100644 --- a/provisioner/terraform/testdata/instance-id/instance-id.tfplan.json +++ b/provisioner/terraform/testdata/instance-id/instance-id.tfplan.json @@ -21,6 +21,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -29,6 +30,7 @@ "sensitive_values": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -81,6 +83,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -91,12 +94,14 @@ "id": true, "init_script": true, "metadata": [], + "resources_monitoring": [], "token": true }, "before_sensitive": false, "after_sensitive": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } } @@ -219,7 +224,7 @@ ] } ], - "timestamp": "2025-02-06T07:28:26Z", + "timestamp": "2025-01-29T22:47:57Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/instance-id/instance-id.tfstate.json b/provisioner/terraform/testdata/instance-id/instance-id.tfstate.json index bda8532f11..e884830606 100644 --- a/provisioner/terraform/testdata/instance-id/instance-id.tfstate.json +++ b/provisioner/terraform/testdata/instance-id/instance-id.tfstate.json @@ -26,16 +26,17 @@ } ], "env": null, - "id": "c4dfe556-bda2-4c46-921d-877a9f6362a5", + "id": "c6e99a38-f10b-4242-a7c6-bd9186008b9d", "init_script": "", "metadata": [], "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "0cd5fb29-059b-490d-a8d9-d2b6daa86dfe", + "token": "ecddacca-df83-4dd2-b6cb-71f439e9e5f5", "troubleshooting_url": null }, "sensitive_values": { @@ -43,6 +44,7 @@ {} ], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -54,8 +56,8 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 0, "values": { - "agent_id": "c4dfe556-bda2-4c46-921d-877a9f6362a5", - "id": "6d9e9e65-c9ff-47de-a733-541a36d9d039", + "agent_id": "c6e99a38-f10b-4242-a7c6-bd9186008b9d", + "id": "0ed215f9-07b0-455f-828d-faee5f63ea93", "instance_id": "example" }, "sensitive_values": {}, @@ -71,7 +73,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "1151295831746427704", + "id": "1340003819945612525", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/mapped-apps/mapped-apps.tfplan.json b/provisioner/terraform/testdata/mapped-apps/mapped-apps.tfplan.json index 90a6d64eca..7dd1dc173f 100644 --- a/provisioner/terraform/testdata/mapped-apps/mapped-apps.tfplan.json +++ b/provisioner/terraform/testdata/mapped-apps/mapped-apps.tfplan.json @@ -21,6 +21,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -29,6 +30,7 @@ "sensitive_values": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -121,6 +123,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -131,12 +134,14 @@ "id": true, "init_script": true, "metadata": [], + "resources_monitoring": [], "token": true }, "before_sensitive": false, "after_sensitive": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } } @@ -321,7 +326,7 @@ ] } ], - "timestamp": "2025-02-06T07:28:26Z", + "timestamp": "2025-01-29T22:47:59Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/mapped-apps/mapped-apps.tfstate.json b/provisioner/terraform/testdata/mapped-apps/mapped-apps.tfstate.json index 8108f3b038..fb32d22e2c 100644 --- a/provisioner/terraform/testdata/mapped-apps/mapped-apps.tfstate.json +++ b/provisioner/terraform/testdata/mapped-apps/mapped-apps.tfstate.json @@ -26,16 +26,17 @@ } ], "env": null, - "id": "81df047e-38db-4717-a08d-79822c7f9631", + "id": "18098e15-2e8b-4c83-9362-0823834ae628", "init_script": "", "metadata": [], "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "9aa50425-529d-4948-b301-47d00140bbf2", + "token": "59691c9e-bf9e-4c93-9768-ba3582c68727", "troubleshooting_url": null }, "sensitive_values": { @@ -43,6 +44,7 @@ {} ], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -55,14 +57,14 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "81df047e-38db-4717-a08d-79822c7f9631", + "agent_id": "18098e15-2e8b-4c83-9362-0823834ae628", "command": null, "display_name": "app1", "external": false, "healthcheck": [], "hidden": false, "icon": null, - "id": "701538ed-7f91-4fa7-b55f-a2389bfc7b0b", + "id": "8f031ab5-e051-4eff-9f7e-233f5825c3fd", "open_in": "slim-window", "order": null, "share": "owner", @@ -86,14 +88,14 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "81df047e-38db-4717-a08d-79822c7f9631", + "agent_id": "18098e15-2e8b-4c83-9362-0823834ae628", "command": null, "display_name": "app2", "external": false, "healthcheck": [], "hidden": false, "icon": null, - "id": "df262f25-b224-4598-8f2e-e7d1ddb252d4", + "id": "5462894e-7fdc-4fd0-8715-7829e53efea2", "open_in": "slim-window", "order": null, "share": "owner", @@ -116,7 +118,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "3545091168208360820", + "id": "2699316377754222096", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tfplan.json b/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tfplan.json index 997caf079e..69600fed24 100644 --- a/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tfplan.json +++ b/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tfplan.json @@ -21,6 +21,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -29,6 +30,7 @@ "sensitive_values": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -49,6 +51,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -57,6 +60,7 @@ "sensitive_values": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -192,6 +196,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -202,12 +207,14 @@ "id": true, "init_script": true, "metadata": [], + "resources_monitoring": [], "token": true }, "before_sensitive": false, "after_sensitive": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } } @@ -233,6 +240,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -243,12 +251,14 @@ "id": true, "init_script": true, "metadata": [], + "resources_monitoring": [], "token": true }, "before_sensitive": false, "after_sensitive": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } } @@ -563,19 +573,19 @@ }, "relevant_attributes": [ { - "resource": "coder_agent.dev2", + "resource": "coder_agent.dev1", "attribute": [ "id" ] }, { - "resource": "coder_agent.dev1", + "resource": "coder_agent.dev2", "attribute": [ "id" ] } ], - "timestamp": "2025-02-06T07:28:26Z", + "timestamp": "2025-01-29T22:48:03Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tfstate.json b/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tfstate.json index 99580bd9d5..db2617701b 100644 --- a/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tfstate.json +++ b/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tfstate.json @@ -26,16 +26,17 @@ } ], "env": null, - "id": "358f434c-9056-4c2a-96cf-dd273e62a2f4", + "id": "00794e64-40d3-43df-885a-4b1cc5f5b965", "init_script": "", "metadata": [], "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "c3f886c0-c942-46f2-807f-1e6c38524191", + "token": "7c0a6e5e-dd2c-46e4-a5f5-f71aae7515c3", "troubleshooting_url": null }, "sensitive_values": { @@ -43,6 +44,7 @@ {} ], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -68,16 +70,17 @@ } ], "env": null, - "id": "decbcebe-ce0f-46ed-81cd-366651275bdc", + "id": "1b8ddc14-25c2-4eab-b282-71b12d45de73", "init_script": "", "metadata": [], "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "51f8f7fc-ec89-4500-b292-29386cf85245", + "token": "39497aa1-11a1-40c0-854d-554c2e27ef77", "troubleshooting_url": null }, "sensitive_values": { @@ -85,6 +88,7 @@ {} ], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -96,14 +100,14 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "358f434c-9056-4c2a-96cf-dd273e62a2f4", + "agent_id": "00794e64-40d3-43df-885a-4b1cc5f5b965", "command": null, "display_name": null, "external": false, "healthcheck": [], "hidden": false, "icon": null, - "id": "07e9147a-8ef2-4160-afbc-f3f7d1c06fad", + "id": "c9cf036f-5fd9-408a-8c28-90cde4c5b0cf", "open_in": "slim-window", "order": null, "share": "owner", @@ -126,7 +130,7 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "358f434c-9056-4c2a-96cf-dd273e62a2f4", + "agent_id": "00794e64-40d3-43df-885a-4b1cc5f5b965", "command": null, "display_name": null, "external": false, @@ -139,7 +143,7 @@ ], "hidden": false, "icon": null, - "id": "47b6572e-4ce6-4b8c-b2bc-5b1bfaa6c6c3", + "id": "e40999b2-8ceb-4e35-962b-c0b7b95c8bc8", "open_in": "slim-window", "order": null, "share": "owner", @@ -164,14 +168,14 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "decbcebe-ce0f-46ed-81cd-366651275bdc", + "agent_id": "1b8ddc14-25c2-4eab-b282-71b12d45de73", "command": null, "display_name": null, "external": false, "healthcheck": [], "hidden": false, "icon": null, - "id": "3218f83a-486c-4d32-9dff-bcc502a06057", + "id": "4e61c245-271a-41e1-9a37-2badf68bf5cd", "open_in": "slim-window", "order": null, "share": "owner", @@ -194,7 +198,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "6789549112713389367", + "id": "7796235346668423309", "triggers": null }, "sensitive_values": {}, @@ -210,7 +214,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "4753479913925883652", + "id": "8353198974918613541", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tfplan.json b/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tfplan.json index 2356e902bb..da3f19c548 100644 --- a/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tfplan.json +++ b/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tfplan.json @@ -21,6 +21,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -29,6 +30,7 @@ "sensitive_values": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -49,6 +51,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -57,6 +60,7 @@ "sensitive_values": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -148,6 +152,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -158,12 +163,14 @@ "id": true, "init_script": true, "metadata": [], + "resources_monitoring": [], "token": true }, "before_sensitive": false, "after_sensitive": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } } @@ -189,6 +196,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -199,12 +207,14 @@ "id": true, "init_script": true, "metadata": [], + "resources_monitoring": [], "token": true }, "before_sensitive": false, "after_sensitive": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } } @@ -472,7 +482,7 @@ ] } ], - "timestamp": "2025-02-06T07:28:26Z", + "timestamp": "2025-01-29T22:48:05Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tfstate.json b/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tfstate.json index 160f263e1f..6b2f13b3e8 100644 --- a/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tfstate.json +++ b/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tfstate.json @@ -26,16 +26,17 @@ } ], "env": null, - "id": "cd64c74f-5861-4733-b7dc-a01fbe892431", + "id": "f1398cbc-4e67-4a0e-92b7-15dc33221872", "init_script": "", "metadata": [], "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "98f0d5fc-182e-49c3-8e20-7fb228f63a3e", + "token": "acbbabee-e370-4aba-b876-843fb10201e8", "troubleshooting_url": null }, "sensitive_values": { @@ -43,6 +44,7 @@ {} ], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -68,16 +70,17 @@ } ], "env": null, - "id": "a3e3ec9b-0695-4b8b-a32b-fb55021ee96a", + "id": "ea44429d-fc3c-4ea6-ba23-a997dc66cad8", "init_script": "", "metadata": [], "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "6892aa3e-0411-4b59-9bee-785b905fdba2", + "token": "51fea695-82dd-4ccd-bf25-2c55a82b4851", "troubleshooting_url": null }, "sensitive_values": { @@ -85,6 +88,7 @@ {} ], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -96,8 +100,8 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "cd64c74f-5861-4733-b7dc-a01fbe892431", - "id": "911d7e12-7c8e-436f-abc3-ee53df6422b1", + "agent_id": "f1398cbc-4e67-4a0e-92b7-15dc33221872", + "id": "f8f7b3f7-5c4b-47b9-959e-32d2044329e3", "name": "ENV_1", "value": "Env 1" }, @@ -114,8 +118,8 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "cd64c74f-5861-4733-b7dc-a01fbe892431", - "id": "68417a79-e829-4577-86a5-2a282a420fd9", + "agent_id": "f1398cbc-4e67-4a0e-92b7-15dc33221872", + "id": "b7171d98-09c9-4bc4-899d-4b7343cd86ca", "name": "ENV_2", "value": "Env 2" }, @@ -132,8 +136,8 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "a3e3ec9b-0695-4b8b-a32b-fb55021ee96a", - "id": "32a80778-1c3c-444a-947a-6eef729de65e", + "agent_id": "ea44429d-fc3c-4ea6-ba23-a997dc66cad8", + "id": "84021f25-1736-4884-8e5c-553e9c1f6fa6", "name": "ENV_3", "value": "Env 3" }, @@ -150,7 +154,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "7492908688673175566", + "id": "4901314428677246063", "triggers": null }, "sensitive_values": {}, @@ -166,7 +170,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "1959061390178382235", + "id": "3203010350140581146", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tfplan.json b/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tfplan.json index 4e7bc71746..7724005431 100644 --- a/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tfplan.json +++ b/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tfplan.json @@ -21,6 +21,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -29,6 +30,7 @@ "sensitive_values": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -49,6 +51,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -57,6 +60,7 @@ "sensitive_values": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -169,6 +173,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -179,12 +184,14 @@ "id": true, "init_script": true, "metadata": [], + "resources_monitoring": [], "token": true }, "before_sensitive": false, "after_sensitive": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } } @@ -210,6 +217,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -220,12 +228,14 @@ "id": true, "init_script": true, "metadata": [], + "resources_monitoring": [], "token": true }, "before_sensitive": false, "after_sensitive": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } } @@ -511,19 +521,19 @@ }, "relevant_attributes": [ { - "resource": "coder_agent.dev1", + "resource": "coder_agent.dev2", "attribute": [ "id" ] }, { - "resource": "coder_agent.dev2", + "resource": "coder_agent.dev1", "attribute": [ "id" ] } ], - "timestamp": "2025-02-06T07:28:26Z", + "timestamp": "2025-01-29T22:48:08Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tfstate.json b/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tfstate.json index 6c91cd73a6..c5db3c24d2 100644 --- a/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tfstate.json +++ b/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tfstate.json @@ -26,16 +26,17 @@ } ], "env": null, - "id": "ee4b0276-a97b-4b6b-8cd3-2819c6a67aa6", + "id": "bd762939-8952-4ac7-a9e5-618ec420b518", "init_script": "", "metadata": [], "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "6a41a636-d2d2-44cf-9c3e-548478f06e19", + "token": "f86127e8-2852-4c02-9f07-c376ec04318f", "troubleshooting_url": null }, "sensitive_values": { @@ -43,6 +44,7 @@ {} ], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -68,16 +70,17 @@ } ], "env": null, - "id": "bd327d5e-3632-4d42-af81-cadf99aad2b5", + "id": "60244093-3c9d-4655-b34f-c4713f7001c1", "init_script": "", "metadata": [], "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "4ce115b1-7bab-440a-9136-025321a4b0c8", + "token": "cad61f70-873f-440c-ad1c-9d34be2e19c4", "troubleshooting_url": null }, "sensitive_values": { @@ -85,6 +88,7 @@ {} ], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -96,11 +100,11 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "ee4b0276-a97b-4b6b-8cd3-2819c6a67aa6", + "agent_id": "bd762939-8952-4ac7-a9e5-618ec420b518", "cron": null, "display_name": "Foobar Script 1", "icon": null, - "id": "de8c8a6c-e85f-41fb-afa2-d5ac623a4fae", + "id": "b34b6cd5-e85d-41c8-ad92-eaaceb2404cb", "log_path": null, "run_on_start": true, "run_on_stop": false, @@ -121,11 +125,11 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "ee4b0276-a97b-4b6b-8cd3-2819c6a67aa6", + "agent_id": "bd762939-8952-4ac7-a9e5-618ec420b518", "cron": null, "display_name": "Foobar Script 2", "icon": null, - "id": "3cb68229-11fd-4828-951c-e18d3c20a81d", + "id": "d6f4e24c-3023-417d-b9be-4c83dbdf4802", "log_path": null, "run_on_start": true, "run_on_stop": false, @@ -146,11 +150,11 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "bd327d5e-3632-4d42-af81-cadf99aad2b5", + "agent_id": "60244093-3c9d-4655-b34f-c4713f7001c1", "cron": null, "display_name": "Foobar Script 3", "icon": null, - "id": "54976735-7900-4be8-9cfa-4b1bbd2dd0b6", + "id": "a19e9106-5eb5-4941-b6ae-72a7724efdf0", "log_path": null, "run_on_start": true, "run_on_stop": false, @@ -171,7 +175,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "1999609760128298126", + "id": "8576645433635584827", "triggers": null }, "sensitive_values": {}, @@ -187,7 +191,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "1520359202312470236", + "id": "1280398780322015606", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfplan.json b/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfplan.json index 4091204d51..201e09ad76 100644 --- a/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfplan.json +++ b/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfplan.json @@ -21,6 +21,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -29,6 +30,7 @@ "sensitive_values": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -49,6 +51,7 @@ "motd_file": "/etc/motd", "order": null, "os": "darwin", + "resources_monitoring": [], "shutdown_script": "echo bye bye", "startup_script": null, "startup_script_behavior": "non-blocking", @@ -57,6 +60,7 @@ "sensitive_values": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -77,6 +81,7 @@ "motd_file": null, "order": null, "os": "windows", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "blocking", @@ -85,6 +90,7 @@ "sensitive_values": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -105,6 +111,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -113,6 +120,7 @@ "sensitive_values": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -153,6 +161,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -163,12 +172,14 @@ "id": true, "init_script": true, "metadata": [], + "resources_monitoring": [], "token": true }, "before_sensitive": false, "after_sensitive": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } } @@ -194,6 +205,7 @@ "motd_file": "/etc/motd", "order": null, "os": "darwin", + "resources_monitoring": [], "shutdown_script": "echo bye bye", "startup_script": null, "startup_script_behavior": "non-blocking", @@ -204,12 +216,14 @@ "id": true, "init_script": true, "metadata": [], + "resources_monitoring": [], "token": true }, "before_sensitive": false, "after_sensitive": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } } @@ -235,6 +249,7 @@ "motd_file": null, "order": null, "os": "windows", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "blocking", @@ -245,12 +260,14 @@ "id": true, "init_script": true, "metadata": [], + "resources_monitoring": [], "token": true }, "before_sensitive": false, "after_sensitive": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } } @@ -276,6 +293,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -286,12 +304,14 @@ "id": true, "init_script": true, "metadata": [], + "resources_monitoring": [], "token": true }, "before_sensitive": false, "after_sensitive": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } } @@ -431,7 +451,7 @@ ] } }, - "timestamp": "2025-02-06T07:28:26Z", + "timestamp": "2025-01-29T22:48:01Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfstate.json b/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfstate.json index 9e2ddad560..53335cffd6 100644 --- a/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfstate.json +++ b/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfstate.json @@ -26,16 +26,17 @@ } ], "env": null, - "id": "c063caac-e0f7-40eb-8b1e-e9b653d5753d", + "id": "215a9369-35c9-4abe-b1c0-3eb3ab1c1922", "init_script": "", "metadata": [], "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "3e420343-27a9-49da-9851-d434d34a6d53", + "token": "3fdd733c-b02e-4d81-a032-7c8d7ee3dcd8", "troubleshooting_url": null }, "sensitive_values": { @@ -43,6 +44,7 @@ {} ], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -68,16 +70,17 @@ } ], "env": null, - "id": "952eddec-f95e-4401-aee6-ba7b9f1f4f40", + "id": "b79acfba-d148-4940-80aa-0c72c037a3ed", "init_script": "", "metadata": [], "motd_file": "/etc/motd", "order": null, "os": "darwin", + "resources_monitoring": [], "shutdown_script": "echo bye bye", "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "23253e29-9acc-4602-a8b9-e66b2a75af61", + "token": "e841a152-a794-4b05-9818-95e7440d402d", "troubleshooting_url": null }, "sensitive_values": { @@ -85,6 +88,7 @@ {} ], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -110,16 +114,17 @@ } ], "env": null, - "id": "24e9cc27-7115-4ad5-a3e8-77b143be2d30", + "id": "4e863395-523b-443a-83c2-ab27e42a06b2", "init_script": "", "metadata": [], "motd_file": null, "order": null, "os": "windows", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "blocking", - "token": "13a353ce-da86-4015-a6d0-c5926cd0374c", + "token": "ee0a5e1d-879e-4bff-888e-6cf94533f0bd", "troubleshooting_url": "https://coder.com/troubleshoot" }, "sensitive_values": { @@ -127,6 +132,7 @@ {} ], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -152,16 +158,17 @@ } ], "env": null, - "id": "3d83fed1-7aed-4240-9c0b-3afbbcfb6fa2", + "id": "611c43f5-fa8f-4641-9b5c-a58a8945caa1", "init_script": "", "metadata": [], "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "9a31e16d-9c15-4dba-accf-a037d17741be", + "token": "2d2669c7-6385-4ce8-8948-e4b24db45132", "troubleshooting_url": null }, "sensitive_values": { @@ -169,6 +176,7 @@ {} ], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -180,7 +188,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "1754313482916802938", + "id": "5237006672454822031", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfplan.json b/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfplan.json index 16d2119977..d5d555e057 100644 --- a/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfplan.json +++ b/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfplan.json @@ -21,6 +21,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -29,6 +30,7 @@ "sensitive_values": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -152,6 +154,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -162,12 +165,14 @@ "id": true, "init_script": true, "metadata": [], + "resources_monitoring": [], "token": true }, "before_sensitive": false, "after_sensitive": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } } @@ -440,7 +445,7 @@ ] } ], - "timestamp": "2025-02-06T07:28:26Z", + "timestamp": "2025-01-29T22:48:10Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfstate.json b/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfstate.json index 6dd5ae33d3..9bad983044 100644 --- a/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfstate.json +++ b/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfstate.json @@ -26,16 +26,17 @@ } ], "env": null, - "id": "054b161e-afd2-4783-a5b3-e926149361f3", + "id": "cae4d590-8332-45b6-9453-e0151ca4f219", "init_script": "", "metadata": [], "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "4d658a7b-6bdb-4b8d-a689-cbe3d5a3d95e", + "token": "6db086ba-440b-4e66-8803-80e021cda61a", "troubleshooting_url": null }, "sensitive_values": { @@ -43,6 +44,7 @@ {} ], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -54,14 +56,14 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "054b161e-afd2-4783-a5b3-e926149361f3", + "agent_id": "cae4d590-8332-45b6-9453-e0151ca4f219", "command": null, "display_name": null, "external": false, "healthcheck": [], "hidden": false, "icon": null, - "id": "15a4a26b-a880-4bdd-aa1a-1c023dc699c3", + "id": "64803468-4ec4-49fe-beb7-e65eaf8e01ca", "open_in": "slim-window", "order": null, "share": "owner", @@ -84,7 +86,7 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "054b161e-afd2-4783-a5b3-e926149361f3", + "agent_id": "cae4d590-8332-45b6-9453-e0151ca4f219", "command": null, "display_name": null, "external": false, @@ -97,7 +99,7 @@ ], "hidden": false, "icon": null, - "id": "13804972-c155-47bf-9fc2-81421523eebf", + "id": "df3f07ab-1796-41c9-8e7d-b957dca031d4", "open_in": "slim-window", "order": null, "share": "owner", @@ -122,14 +124,14 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 1, "values": { - "agent_id": "054b161e-afd2-4783-a5b3-e926149361f3", + "agent_id": "cae4d590-8332-45b6-9453-e0151ca4f219", "command": null, "display_name": null, "external": false, "healthcheck": [], "hidden": false, "icon": null, - "id": "2744abcb-51db-43cf-a2e3-61dcbd8d896a", + "id": "fdb06774-4140-42ef-989b-12b98254b27c", "open_in": "slim-window", "order": null, "share": "owner", @@ -152,7 +154,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "4930273725392327631", + "id": "8206837964247342986", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tfplan.json b/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tfplan.json index 05b7ec2cf5..6354226c4c 100644 --- a/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tfplan.json +++ b/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tfplan.json @@ -30,6 +30,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -40,6 +41,7 @@ "metadata": [ {} ], + "resources_monitoring": [], "token": true } }, @@ -145,6 +147,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -157,6 +160,7 @@ "metadata": [ {} ], + "resources_monitoring": [], "token": true }, "before_sensitive": false, @@ -165,6 +169,7 @@ "metadata": [ {} ], + "resources_monitoring": [], "token": true } } @@ -426,7 +431,7 @@ ] } ], - "timestamp": "2025-02-06T07:28:26Z", + "timestamp": "2025-01-29T22:48:14Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tfstate.json b/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tfstate.json index 32e8bcbdcc..82eed92f36 100644 --- a/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tfstate.json +++ b/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tfstate.json @@ -26,7 +26,7 @@ } ], "env": null, - "id": "233e324a-4c1b-490b-9439-ed996b476cf5", + "id": "b3257d67-247c-4fc6-92a8-fc997501a0e1", "init_script": "", "metadata": [ { @@ -41,10 +41,11 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "1f12022b-bcef-4bfd-b07d-d3ad488da0a2", + "token": "ac3563fb-3069-4919-b076-6687c765772b", "troubleshooting_url": null }, "sensitive_values": { @@ -54,6 +55,7 @@ "metadata": [ {} ], + "resources_monitoring": [], "token": true } }, @@ -68,7 +70,7 @@ "daily_cost": 29, "hide": true, "icon": "/icon/server.svg", - "id": "63496838-bc47-449a-b1fe-0135ad8e1759", + "id": "fcd81afa-64ad-45e3-b000-31d1b19df922", "item": [ { "is_null": false, @@ -83,7 +85,7 @@ "value": "" } ], - "resource_id": "1166169950293623087" + "resource_id": "8033209281634385030" }, "sensitive_values": { "item": [ @@ -107,7 +109,7 @@ "daily_cost": 20, "hide": true, "icon": "/icon/server.svg", - "id": "fc15b16c-6a70-4875-8a21-cca3aa9ec21a", + "id": "186819f3-a92f-4785-9ee4-d79f57711f63", "item": [ { "is_null": false, @@ -116,7 +118,7 @@ "value": "world" } ], - "resource_id": "1166169950293623087" + "resource_id": "8033209281634385030" }, "sensitive_values": { "item": [ @@ -136,7 +138,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "1166169950293623087", + "id": "8033209281634385030", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/resource-metadata/resource-metadata.tfplan.json b/provisioner/terraform/testdata/resource-metadata/resource-metadata.tfplan.json index 6377191478..fd252c9adb 100644 --- a/provisioner/terraform/testdata/resource-metadata/resource-metadata.tfplan.json +++ b/provisioner/terraform/testdata/resource-metadata/resource-metadata.tfplan.json @@ -30,6 +30,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -40,6 +41,7 @@ "metadata": [ {} ], + "resources_monitoring": [], "token": true } }, @@ -132,6 +134,7 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -144,6 +147,7 @@ "metadata": [ {} ], + "resources_monitoring": [], "token": true }, "before_sensitive": false, @@ -152,6 +156,7 @@ "metadata": [ {} ], + "resources_monitoring": [], "token": true } } @@ -378,7 +383,7 @@ ] } ], - "timestamp": "2025-02-06T07:28:26Z", + "timestamp": "2025-01-29T22:48:12Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/resource-metadata/resource-metadata.tfstate.json b/provisioner/terraform/testdata/resource-metadata/resource-metadata.tfstate.json index 96667cb142..a0838cc561 100644 --- a/provisioner/terraform/testdata/resource-metadata/resource-metadata.tfstate.json +++ b/provisioner/terraform/testdata/resource-metadata/resource-metadata.tfstate.json @@ -26,7 +26,7 @@ } ], "env": null, - "id": "9ca8533d-2f72-497c-8ecc-b4ce7ed7c00e", + "id": "066d91d2-860a-4a44-9443-9eaf9315729b", "init_script": "", "metadata": [ { @@ -41,10 +41,11 @@ "motd_file": null, "order": null, "os": "linux", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "d86a54a7-bd70-4d8d-90b1-10fde02f5bcf", + "token": "9b6cc6dd-0e02-489f-b651-7a01804c406f", "troubleshooting_url": null }, "sensitive_values": { @@ -54,6 +55,7 @@ "metadata": [ {} ], + "resources_monitoring": [], "token": true } }, @@ -68,7 +70,7 @@ "daily_cost": 29, "hide": true, "icon": "/icon/server.svg", - "id": "5dfed2fe-d39c-4bf1-9234-d153d43c205f", + "id": "fa791d91-9718-420e-9fa8-7a02e7af1563", "item": [ { "is_null": false, @@ -95,7 +97,7 @@ "value": "squirrel" } ], - "resource_id": "3677336873960413975" + "resource_id": "2710066198333857753" }, "sensitive_values": { "item": [ @@ -118,7 +120,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "3677336873960413975", + "id": "2710066198333857753", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tfplan.json b/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tfplan.json index 06fb504fb5..95fb198c1e 100644 --- a/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tfplan.json +++ b/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tfplan.json @@ -21,6 +21,7 @@ "motd_file": null, "order": null, "os": "windows", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -29,6 +30,7 @@ "sensitive_values": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -69,6 +71,7 @@ "motd_file": null, "order": null, "os": "windows", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -79,12 +82,14 @@ "id": true, "init_script": true, "metadata": [], + "resources_monitoring": [], "token": true }, "before_sensitive": false, "after_sensitive": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } } @@ -130,7 +135,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "678e4104-cd99-40d4-86e0-5244028860de", + "id": "e8485920-025a-4c2c-b018-722f61b64347", "mutable": false, "name": "Example", "option": null, @@ -157,7 +162,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "22b1d84d-7c1d-47d0-b789-6a8d07ea926d", + "id": "6156655b-f893-4eba-914e-e87414f4bf7e", "mutable": false, "name": "Sample", "option": null, @@ -263,7 +268,7 @@ ] } }, - "timestamp": "2025-02-06T07:28:26Z", + "timestamp": "2025-01-29T22:48:18Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tfstate.json b/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tfstate.json index 9c68c8d660..2cc48c837a 100644 --- a/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tfstate.json +++ b/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tfstate.json @@ -17,7 +17,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "b8460866-87f5-4e31-824e-6d0c48dbcc79", + "id": "4b774ce8-1e9f-4721-8a14-05efd3eb2dab", "mutable": false, "name": "Example", "option": null, @@ -44,7 +44,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "61920fa1-8186-40a6-9e0f-8cbca91985a9", + "id": "447ae720-c046-452e-8d2c-1b5d4060b798", "mutable": false, "name": "Sample", "option": null, @@ -80,16 +80,17 @@ } ], "env": null, - "id": "adb01e5b-ebc5-488a-ae46-79d99bd6310f", + "id": "b8d637c2-a19c-479c-b3e2-374f15ce37c3", "init_script": "", "metadata": [], "motd_file": null, "order": null, "os": "windows", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "ca3400c8-5759-4ffe-b335-368737690d93", + "token": "52ce8a0d-12c9-40b5-9f86-dc6240b98d5f", "troubleshooting_url": null }, "sensitive_values": { @@ -97,6 +98,7 @@ {} ], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -108,7 +110,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "7469573159164897550", + "id": "769369130050936586", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tfplan.json b/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tfplan.json index 6d98cba649..691c168418 100644 --- a/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tfplan.json +++ b/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tfplan.json @@ -21,6 +21,7 @@ "motd_file": null, "order": null, "os": "windows", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -29,6 +30,7 @@ "sensitive_values": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -69,6 +71,7 @@ "motd_file": null, "order": null, "os": "windows", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -79,12 +82,14 @@ "id": true, "init_script": true, "metadata": [], + "resources_monitoring": [], "token": true }, "before_sensitive": false, "after_sensitive": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } } @@ -130,7 +135,7 @@ "display_name": null, "ephemeral": true, "icon": null, - "id": "0db9ef7c-02fe-43cf-8654-1bedc26f9fcb", + "id": "30116bcb-f109-4807-be06-666a60b6cbb2", "mutable": true, "name": "number_example", "option": null, @@ -157,7 +162,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "ef93145f-722a-4c24-8e7f-f94fc8327188", + "id": "755395f4-d163-4b90-a8f4-e7ae24e17dd0", "mutable": false, "name": "number_example_max", "option": null, @@ -196,7 +201,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "4561c132-1925-4612-8456-7ddbc8d1a1a8", + "id": "dec9fa47-a252-4eb7-868b-10d0fe7bad57", "mutable": false, "name": "number_example_max_zero", "option": null, @@ -235,7 +240,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "b102d78f-a86b-4457-a643-505a59710008", + "id": "57107f82-107b-484d-8491-0787f051dca7", "mutable": false, "name": "number_example_min", "option": null, @@ -274,7 +279,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "ad756fd0-ac71-4be8-87a3-ca7462d44a6b", + "id": "c21a61f4-26e0-49bb-99c8-56240433c21b", "mutable": false, "name": "number_example_min_max", "option": null, @@ -313,7 +318,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "918bb8b5-ef2f-4bf6-9c65-bee901131d5d", + "id": "4894f5cc-f4e6-4a86-bdfa-36c9d3f8f1a3", "mutable": false, "name": "number_example_min_zero", "option": null, @@ -545,7 +550,7 @@ ] } }, - "timestamp": "2025-02-06T07:28:26Z", + "timestamp": "2025-01-29T22:48:20Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tfstate.json b/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tfstate.json index f127b8e73b..1ad55291de 100644 --- a/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tfstate.json +++ b/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tfstate.json @@ -17,7 +17,7 @@ "display_name": null, "ephemeral": true, "icon": null, - "id": "56a3b2a7-479b-41f5-a99b-f51a850ac8c2", + "id": "9b5bb411-bfe5-471a-8f2d-9fcc8c17b616", "mutable": true, "name": "number_example", "option": null, @@ -44,7 +44,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "bf19a33e-4b16-4b86-bbf8-cb76c952ce71", + "id": "2ebaf3ec-9272-48f4-981d-09485ae7960e", "mutable": false, "name": "number_example_max", "option": null, @@ -83,7 +83,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "d25e4b3a-f630-4da0-840f-1b823e336155", + "id": "d05a833c-d0ca-4f22-8b80-40851c111b61", "mutable": false, "name": "number_example_max_zero", "option": null, @@ -122,7 +122,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "6fde8249-13f5-4c8e-b9cb-2a1db8d3ff11", + "id": "de0cd614-72b3-4404-80a1-e3c780823fc9", "mutable": false, "name": "number_example_min", "option": null, @@ -161,7 +161,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "8a21c092-2d4a-412a-a0bb-61f20b67b9b0", + "id": "66eae3e1-9bb5-44f8-8f15-2b400628d0e7", "mutable": false, "name": "number_example_min_max", "option": null, @@ -200,7 +200,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "916a9318-6082-4ace-a196-20d78621aa9a", + "id": "d24d37f9-5a91-4c7f-9915-bfc10f6d353d", "mutable": false, "name": "number_example_min_zero", "option": null, @@ -248,16 +248,17 @@ } ], "env": null, - "id": "327d3049-be5e-4a37-98f1-b6591fb86104", + "id": "81170f06-8f49-43fb-998f-dc505a29632c", "init_script": "", "metadata": [], "motd_file": null, "order": null, "os": "windows", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "0de65cf4-bb12-4daa-b75b-422eb9c6f3b1", + "token": "f8433068-1acc-4225-94c0-725f86cdc002", "troubleshooting_url": null }, "sensitive_values": { @@ -265,6 +266,7 @@ {} ], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -276,7 +278,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "4847948730203176710", + "id": "3641782836917385715", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/rich-parameters/rich-parameters.tfplan.json b/provisioner/terraform/testdata/rich-parameters/rich-parameters.tfplan.json index 068cc549a7..387be7249d 100644 --- a/provisioner/terraform/testdata/rich-parameters/rich-parameters.tfplan.json +++ b/provisioner/terraform/testdata/rich-parameters/rich-parameters.tfplan.json @@ -21,6 +21,7 @@ "motd_file": null, "order": null, "os": "windows", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -29,6 +30,7 @@ "sensitive_values": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -69,6 +71,7 @@ "motd_file": null, "order": null, "os": "windows", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", @@ -79,12 +82,14 @@ "id": true, "init_script": true, "metadata": [], + "resources_monitoring": [], "token": true }, "before_sensitive": false, "after_sensitive": { "display_apps": [], "metadata": [], + "resources_monitoring": [], "token": true } } @@ -130,7 +135,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "18a679bf-c1f9-4056-b5ec-1401587efcaf", + "id": "72f11f9b-8c7f-4e4a-a207-f080b114862b", "mutable": false, "name": "Example", "option": [ @@ -174,7 +179,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "a15920af-2f38-4cba-a26f-97492b58d853", + "id": "b154b8a7-d31f-46f7-b876-e5bfdf50950c", "mutable": false, "name": "number_example", "option": null, @@ -201,7 +206,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "7fdb781f-ad42-4cbf-88f2-b8014a4f1b9e", + "id": "8199f88e-8b73-4385-bbb2-315182f753ef", "mutable": false, "name": "number_example_max_zero", "option": null, @@ -240,7 +245,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "b1284628-4b51-4fb5-9bd6-d4b46895e73a", + "id": "110c995d-46d7-4277-8f57-a3d3d42733c3", "mutable": false, "name": "number_example_min_max", "option": null, @@ -279,7 +284,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "24062c56-f326-4bab-893f-eb6bd99d9d0e", + "id": "e7a1f991-48a8-44c5-8a5c-597db8539cb7", "mutable": false, "name": "number_example_min_zero", "option": null, @@ -318,7 +323,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "ea1e26d1-dd66-41af-b1f9-b50220db3dc6", + "id": "27d12cdf-da7e-466b-907a-4824920305da", "mutable": false, "name": "Sample", "option": null, @@ -349,7 +354,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "91236b71-4966-4cdc-8d3c-39d706180779", + "id": "1242389a-5061-482a-8274-410174fb3fc0", "mutable": true, "name": "First parameter from module", "option": null, @@ -376,7 +381,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "6ae5570d-ef16-4bdf-a46b-0025b197f2fa", + "id": "72418f70-4e3c-400f-9a7d-bf3467598deb", "mutable": true, "name": "Second parameter from module", "option": null, @@ -408,7 +413,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "7b0cbc7c-c11b-4902-98d4-4b4354978e05", + "id": "9b4b60d8-21bb-4d52-910a-536355e9a85f", "mutable": true, "name": "First parameter from child module", "option": null, @@ -435,7 +440,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "2b4e1132-77ef-4871-9ffe-f51d188d9821", + "id": "4edca123-07bf-4409-ad40-ed26f93beb5f", "mutable": true, "name": "Second parameter from child module", "option": null, @@ -788,7 +793,7 @@ } } }, - "timestamp": "2025-02-06T07:28:26Z", + "timestamp": "2025-01-29T22:48:16Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/rich-parameters/rich-parameters.tfstate.json b/provisioner/terraform/testdata/rich-parameters/rich-parameters.tfstate.json index 688552edfd..0c8abfa386 100644 --- a/provisioner/terraform/testdata/rich-parameters/rich-parameters.tfstate.json +++ b/provisioner/terraform/testdata/rich-parameters/rich-parameters.tfstate.json @@ -17,7 +17,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "4d2ee311-d55d-4222-b78c-8573531f141a", + "id": "7298c15e-11c8-4a9e-a2ef-044dbc44d519", "mutable": false, "name": "Example", "option": [ @@ -61,7 +61,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "558025fd-1456-4f1f-b876-f4466e1df6a6", + "id": "a0dda000-20cb-42a7-9f83-1a1de0876e48", "mutable": false, "name": "number_example", "option": null, @@ -88,7 +88,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "0b65aa73-27c7-47d9-9281-7604545c3f6d", + "id": "82a297b9-bbcb-4807-9de3-7217953dc6b0", "mutable": false, "name": "number_example_max_zero", "option": null, @@ -127,7 +127,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "4d817bbd-d8d7-413b-b7d9-5bffdb3b6f15", + "id": "ae1c376b-e28b-456a-b36e-125b3bc6d938", "mutable": false, "name": "number_example_min_max", "option": null, @@ -166,7 +166,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "654efe81-8678-4425-b19e-0436cc4a460e", + "id": "57573ac3-5610-4887-b269-376071867eb5", "mutable": false, "name": "number_example_min_zero", "option": null, @@ -205,7 +205,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "8e6d963f-186c-4eea-863e-e6f492d09b98", + "id": "0e08645d-0105-49ef-b278-26cdc30a826c", "mutable": false, "name": "Sample", "option": null, @@ -241,16 +241,17 @@ } ], "env": null, - "id": "0832e1d0-6ee5-4f00-89c2-ead6d781734d", + "id": "c5c402bd-215b-487f-862f-eca25fe88a72", "init_script": "", "metadata": [], "motd_file": null, "order": null, "os": "windows", + "resources_monitoring": [], "shutdown_script": null, "startup_script": null, "startup_script_behavior": "non-blocking", - "token": "e51c05f1-e69c-4489-951a-b18cc28dfc8e", + "token": "b70d10f3-90bc-4abd-8cd9-b11da843954a", "troubleshooting_url": null }, "sensitive_values": { @@ -258,6 +259,7 @@ {} ], "metadata": [], + "resources_monitoring": [], "token": true } }, @@ -269,7 +271,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "7215235512764323226", + "id": "8544034527967282476", "triggers": null }, "sensitive_values": {}, @@ -294,7 +296,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "c3ae0239-9c8d-4d71-b7cf-858f7f93da00", + "id": "68ae438d-7194-4f5b-adeb-9c74059d9888", "mutable": true, "name": "First parameter from module", "option": null, @@ -321,7 +323,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "5fdf8d8d-b4b3-4703-9d37-e235a337b0f6", + "id": "32f0f7f3-26a5-4023-a4e6-d9436cfe8cb4", "mutable": true, "name": "Second parameter from module", "option": null, @@ -353,7 +355,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "3903f4a3-89e8-47be-ad6d-7d1953f73e9d", + "id": "5235636a-3319-47ae-8879-b62f9ee9c5aa", "mutable": true, "name": "First parameter from child module", "option": null, @@ -380,7 +382,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "06e55c81-1797-4240-9887-a0ad9fee1ee3", + "id": "54fa94ff-3048-457d-8de2-c182f6287c8d", "mutable": true, "name": "Second parameter from child module", "option": null, diff --git a/provisionerd/proto/provisionerd.proto b/provisionerd/proto/provisionerd.proto index 0960ffd8cb..301cd06987 100644 --- a/provisionerd/proto/provisionerd.proto +++ b/provisionerd/proto/provisionerd.proto @@ -84,7 +84,7 @@ message CompletedJob { repeated provisioner.ExternalAuthProviderResource external_auth_providers = 5; repeated provisioner.Module start_modules = 6; repeated provisioner.Module stop_modules = 7; - repeated provisioner.Preset presets = 8; + repeated provisioner.Preset presets = 8; } message TemplateDryRun { repeated provisioner.Resource resources = 1; diff --git a/provisionersdk/proto/provisioner.proto b/provisionersdk/proto/provisioner.proto index 56bf90c524..1db08ef835 100644 --- a/provisionersdk/proto/provisioner.proto +++ b/provisionersdk/proto/provisioner.proto @@ -321,7 +321,7 @@ message PlanComplete { repeated ExternalAuthProviderResource external_auth_providers = 4; repeated Timing timings = 6; repeated Module modules = 7; - repeated Preset presets = 8; + repeated Preset presets = 8; } // ApplyRequest asks the provisioner to apply the changes. Apply MUST be preceded by a successful plan request/response diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index da66061ac7..3ff85a4804 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -1441,6 +1441,13 @@ export interface OrganizationMemberWithUserData extends OrganizationMember { readonly global_roles: readonly SlimRole[]; } +// From codersdk/organizations.go +export interface OrganizationProvisionerDaemonsOptions { + readonly Limit: number; + readonly IDs: readonly string[]; + readonly Tags: Record; +} + // From codersdk/organizations.go export interface OrganizationProvisionerJobsOptions { readonly Limit: number; diff --git a/site/src/modules/dashboard/Navbar/MobileMenu.test.tsx b/site/src/modules/dashboard/Navbar/MobileMenu.test.tsx new file mode 100644 index 0000000000..ce8a29df78 --- /dev/null +++ b/site/src/modules/dashboard/Navbar/MobileMenu.test.tsx @@ -0,0 +1,22 @@ +import { includeOrigin } from "./MobileMenu"; + +const mockOrigin = "https://example.com"; + +describe("support link", () => { + it("should include origin if target starts with '/'", () => { + (window as unknown as { location: Partial }).location = { + origin: mockOrigin, + }; // Mock the location origin + + expect(includeOrigin("/test")).toBe(`${mockOrigin}/test`); + expect(includeOrigin("/path/to/resource")).toBe( + `${mockOrigin}/path/to/resource`, + ); + }); + + it("should return the target unchanged if it does not start with '/'", () => { + expect(includeOrigin(`${mockOrigin}/page`)).toBe(`${mockOrigin}/page`); + expect(includeOrigin("../relative/path")).toBe("../relative/path"); + expect(includeOrigin("relative/path")).toBe("relative/path"); + }); +}); diff --git a/site/src/modules/dashboard/Navbar/MobileMenu.tsx b/site/src/modules/dashboard/Navbar/MobileMenu.tsx index f24755a5c4..20058335eb 100644 --- a/site/src/modules/dashboard/Navbar/MobileMenu.tsx +++ b/site/src/modules/dashboard/Navbar/MobileMenu.tsx @@ -307,7 +307,11 @@ const UserSettingsSub: FC = ({ asChild className={cn(itemStyles.default, itemStyles.sub)} > - + {l.name} @@ -318,3 +322,11 @@ const UserSettingsSub: FC = ({ ); }; + +export const includeOrigin = (target: string): string => { + if (target.startsWith("/")) { + const baseUrl = window.location.origin; + return `${baseUrl}${target}`; + } + return target; +}; diff --git a/site/src/pages/DeploymentSettingsPage/GeneralSettingsPage/UserEngagementChart.stories.tsx b/site/src/pages/DeploymentSettingsPage/GeneralSettingsPage/UserEngagementChart.stories.tsx index 2c019d2a99..e2e2a99111 100644 --- a/site/src/pages/DeploymentSettingsPage/GeneralSettingsPage/UserEngagementChart.stories.tsx +++ b/site/src/pages/DeploymentSettingsPage/GeneralSettingsPage/UserEngagementChart.stories.tsx @@ -6,12 +6,12 @@ const meta: Meta = { component: UserEngagementChart, args: { data: [ - { date: "1/1/2024", users: 150 }, - { date: "1/2/2024", users: 165 }, - { date: "1/3/2024", users: 180 }, - { date: "1/4/2024", users: 155 }, - { date: "1/5/2024", users: 190 }, - { date: "1/6/2024", users: 200 }, + { date: "1/1/2024", users: 140 }, + { date: "1/2/2024", users: 175 }, + { date: "1/3/2024", users: 120 }, + { date: "1/4/2024", users: 195 }, + { date: "1/5/2024", users: 230 }, + { date: "1/6/2024", users: 130 }, { date: "1/7/2024", users: 210 }, ], }, diff --git a/site/src/pages/DeploymentSettingsPage/GeneralSettingsPage/UserEngagementChart.tsx b/site/src/pages/DeploymentSettingsPage/GeneralSettingsPage/UserEngagementChart.tsx index 431141a148..585088f02d 100644 --- a/site/src/pages/DeploymentSettingsPage/GeneralSettingsPage/UserEngagementChart.tsx +++ b/site/src/pages/DeploymentSettingsPage/GeneralSettingsPage/UserEngagementChart.tsx @@ -157,7 +157,7 @@ export const UserEngagementChart: FC = ({ data }) => { {!organization.is_default && ( - + -
+
Deleting an organization is irreversible. -
@@ -151,45 +155,3 @@ export const OrganizationSettingsPageView: FC<
); }; - -const styles = { - dangerSettings: (theme) => ({ - display: "flex", - backgroundColor: theme.roles.danger.background, - alignItems: "center", - justifyContent: "space-between", - border: `1px solid ${theme.roles.danger.outline}`, - borderRadius: 8, - padding: 12, - paddingLeft: 18, - gap: 8, - lineHeight: "18px", - flexGrow: 1, - - "& .option": { - color: theme.roles.danger.fill.solid, - "&.Mui-checked": { - color: theme.roles.danger.fill.solid, - }, - }, - - "& .info": { - fontSize: 14, - fontWeight: 600, - color: theme.roles.danger.text, - }, - }), - dangerButton: (theme) => ({ - borderColor: theme.roles.danger.outline, - color: theme.roles.danger.text, - - "&.MuiLoadingButton-loading": { - color: theme.roles.danger.disabled.text, - }, - - "&:hover:not(:disabled)": { - backgroundColor: theme.roles.danger.hover.background, - borderColor: theme.roles.danger.hover.fill.outline, - }, - }), -} satisfies Record>; diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index a607df6bb8..c866c64f15 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -246,6 +246,11 @@ export const MockSupportLinks: TypesGen.LinkConfig[] = [ "https://github.com/coder/coder/issues/new?labels=needs+grooming&body={CODER_BUILD_INFO}", icon: "", }, + { + name: "Fourth link", + target: "/icons", + icon: "", + }, ]; export const MockUpdateCheck: TypesGen.UpdateCheckResponse = { diff --git a/site/src/theme/icons.json b/site/src/theme/icons.json index 3d63b9ac81..3639d73f2f 100644 --- a/site/src/theme/icons.json +++ b/site/src/theme/icons.json @@ -59,6 +59,7 @@ "jupyter.svg", "k8s.png", "kasmvnc.svg", + "keycloak.svg", "kotlin.svg", "lxc.svg", "matlab.svg", diff --git a/site/static/icon/keycloak.svg b/site/static/icon/keycloak.svg new file mode 100644 index 0000000000..44798d21c8 --- /dev/null +++ b/site/static/icon/keycloak.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tailnet/proto/tailnet_drpc_old.go b/tailnet/proto/tailnet_drpc_old.go index 64be85d875..dfe902bdd5 100644 --- a/tailnet/proto/tailnet_drpc_old.go +++ b/tailnet/proto/tailnet_drpc_old.go @@ -34,3 +34,9 @@ type DRPCTailnetClient23 interface { RefreshResumeToken(ctx context.Context, in *RefreshResumeTokenRequest) (*RefreshResumeTokenResponse, error) WorkspaceUpdates(ctx context.Context, in *WorkspaceUpdatesRequest) (DRPCTailnet_WorkspaceUpdatesClient, error) } + +// DRPCTailnetClient24 is the Tailnet API at v2.4. It is functionally identical to 2.3, because the +// change was to the Agent API (ResourcesMonitoring methods). +type DRPCTailnetClient24 interface { + DRPCTailnetClient23 +} diff --git a/tailnet/proto/version.go b/tailnet/proto/version.go index f86711171d..ea38518033 100644 --- a/tailnet/proto/version.go +++ b/tailnet/proto/version.go @@ -38,6 +38,11 @@ import ( // shipped in Coder v2.16.0, but we forgot to increment the API version. If // you dial for API v2.2, you MAY be connected to a server that supports // ScriptCompleted, but be prepared to process "unsupported" errors.) +// +// API v2.4: +// - Shipped in Coder v2.{{placeholder}} // TODO Vincent: Replace with the correct version +// - Added support for GetResourcesMonitoringConfiguration and +// PushResourcesMonitoringUsage RPCs on the Agent API. const ( CurrentMajor = 2 CurrentMinor = 4