diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3a42b67c75f8e..9d8efa8d42f76 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -136,7 +136,7 @@ jobs: # Check for any typos - name: Check for typos - uses: crate-ci/typos@v1.16.19 + uses: crate-ci/typos@v1.16.21 with: config: .github/workflows/typos.toml diff --git a/.github/workflows/security.yaml b/.github/workflows/security.yaml index 6685ea1d2a071..0f26a126da995 100644 --- a/.github/workflows/security.yaml +++ b/.github/workflows/security.yaml @@ -122,7 +122,7 @@ jobs: image_name: ${{ steps.build.outputs.image }} - name: Run Trivy vulnerability scanner - uses: aquasecurity/trivy-action@fbd16365eb88e12433951383f5e99bd901fc618f + uses: aquasecurity/trivy-action@b77b85c0254bba6789e787844f0585cde1e56320 with: image-ref: ${{ steps.build.outputs.image }} format: sarif diff --git a/.github/workflows/stale.yaml b/.github/workflows/stale.yaml index fe348b00b484b..ed6d1d0127bc0 100644 --- a/.github/workflows/stale.yaml +++ b/.github/workflows/stale.yaml @@ -52,8 +52,8 @@ jobs: with: token: ${{ github.token }} repository: ${{ github.repository }} - retain_days: 1 - keep_minimum_runs: 1 + retain_days: 30 + keep_minimum_runs: 30 delete_workflow_pattern: pr-cleanup.yaml - name: Delete PR Deploy workflow skipped runs @@ -61,7 +61,6 @@ jobs: with: token: ${{ github.token }} repository: ${{ github.repository }} - retain_days: 0 - keep_minimum_runs: 0 - delete_run_by_conclusion_pattern: skipped + retain_days: 30 + keep_minimum_runs: 30 delete_workflow_pattern: pr-deploy.yaml diff --git a/.vscode/settings.json b/.vscode/settings.json index 0664d7e81cc75..6f726162d260a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -20,7 +20,7 @@ "codersdk", "cronstrue", "databasefake", - "dbfake", + "dbmem", "dbgen", "dbtype", "DERP", diff --git a/Makefile b/Makefile index 65e1132be0ee1..72e44308c6f03 100644 --- a/Makefile +++ b/Makefile @@ -448,13 +448,15 @@ lint/helm: DB_GEN_FILES := \ coderd/database/querier.go \ coderd/database/unique_constraint.go \ - coderd/database/dbfake/dbfake.go \ + coderd/database/dbmem/dbmem.go \ coderd/database/dbmetrics/dbmetrics.go \ coderd/database/dbauthz/dbauthz.go \ coderd/database/dbmock/dbmock.go # all gen targets should be added here and to gen/mark-fresh gen: \ + tailnet/proto/tailnet.pb.go \ + agent/proto/agent.pb.go \ provisionersdk/proto/provisioner.pb.go \ provisionerd/proto/provisionerd.pb.go \ coderd/database/dump.sql \ @@ -479,6 +481,8 @@ gen: \ # used during releases so we don't run generation scripts. gen/mark-fresh: files="\ + tailnet/proto/tailnet.pb.go \ + agent/proto/agent.pb.go \ provisionersdk/proto/provisioner.pb.go \ provisionerd/proto/provisionerd.pb.go \ coderd/database/dump.sql \ @@ -524,6 +528,22 @@ coderd/database/querier.go: coderd/database/sqlc.yaml coderd/database/dump.sql $ coderd/database/dbmock/dbmock.go: coderd/database/db.go coderd/database/querier.go go generate ./coderd/database/dbmock/ +tailnet/proto/tailnet.pb.go: tailnet/proto/tailnet.proto + protoc \ + --go_out=. \ + --go_opt=paths=source_relative \ + --go-drpc_out=. \ + --go-drpc_opt=paths=source_relative \ + ./tailnet/proto/tailnet.proto + +agent/proto/agent.pb.go: agent/proto/agent.proto + protoc \ + --go_out=. \ + --go_opt=paths=source_relative \ + --go-drpc_out=. \ + --go-drpc_opt=paths=source_relative \ + ./agent/proto/agent.proto + provisionersdk/proto/provisioner.pb.go: provisionersdk/proto/provisioner.proto protoc \ --go_out=. \ diff --git a/README.md b/README.md index 3f7d835125ff9..27634813adf34 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ curl -L https://coder.com/install.sh | sh You can run the install script with `--dry-run` to see the commands that will be used to install without executing them. You can modify the installation process by including flags. Run the install script with `--help` for reference. -> See [install](docs/install) for additional methods. +> See [install](https://coder.com/docs/v2/latest/install) for additional methods. Once installed, you can start a production deployment1 with a single command: diff --git a/agent/agent.go b/agent/agent.go index 93daba559c49e..0d2326d2ab9d3 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -536,6 +536,14 @@ func (a *agent) reportMetadataLoop(ctx context.Context) { continue case <-report: if len(updatedMetadata) > 0 { + select { + case <-reportSemaphore: + default: + // If there's already a report in flight, don't send + // another one, wait for next tick instead. + continue + } + metadata := make([]agentsdk.Metadata, 0, len(updatedMetadata)) for key, result := range updatedMetadata { metadata = append(metadata, agentsdk.Metadata{ @@ -545,14 +553,6 @@ func (a *agent) reportMetadataLoop(ctx context.Context) { delete(updatedMetadata, key) } - select { - case <-reportSemaphore: - default: - // If there's already a report in flight, don't send - // another one, wait for next tick instead. - continue - } - go func() { ctx, cancel := context.WithTimeout(ctx, reportTimeout) defer func() { @@ -743,7 +743,7 @@ func (a *agent) run(ctx context.Context) error { return script.RunOnStart }) if err != nil { - a.logger.Warn(ctx, "startup script failed", slog.Error(err)) + a.logger.Warn(ctx, "startup script(s) failed", slog.Error(err)) if errors.Is(err, agentscripts.ErrTimeout) { a.setLifecycle(ctx, codersdk.WorkspaceAgentLifecycleStartTimeout) } else { @@ -1465,6 +1465,7 @@ func (a *agent) Close() error { return script.RunOnStop }) if err != nil { + a.logger.Warn(ctx, "shutdown script(s) failed", slog.Error(err)) if errors.Is(err, agentscripts.ErrTimeout) { lifecycleState = codersdk.WorkspaceAgentLifecycleShutdownTimeout } else { diff --git a/agent/agent_test.go b/agent/agent_test.go index bf71c4f1638f9..b54f877fcdab9 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -350,8 +350,13 @@ func TestAgent_Session_TTY_MOTD(t *testing.T) { unexpected: []string{}, }, { - name: "Trim", - manifest: agentsdk.Manifest{}, + name: "Trim", + // Enable motd since it will be printed after the banner, + // this ensures that we can test for an exact mount of + // newlines. + manifest: agentsdk.Manifest{ + MOTDFile: name, + }, banner: codersdk.ServiceBannerConfig{ Enabled: true, Message: "\n\n\n\n\n\nbanner\n\n\n\n\n\n", @@ -375,6 +380,7 @@ func TestAgent_Session_TTY_MOTD(t *testing.T) { } } +//nolint:tparallel // Sub tests need to run sequentially. func TestAgent_Session_TTY_MOTD_Update(t *testing.T) { t.Parallel() if runtime.GOOS == "windows" { @@ -434,33 +440,38 @@ func TestAgent_Session_TTY_MOTD_Update(t *testing.T) { } //nolint:dogsled // Allow the blank identifiers. conn, client, _, _, _ := setupAgent(t, agentsdk.Manifest{}, 0, setSBInterval) - for _, test := range tests { + + sshClient, err := conn.SSHClient(ctx) + require.NoError(t, err) + t.Cleanup(func() { + _ = sshClient.Close() + }) + + //nolint:paralleltest // These tests need to swap the banner func. + for i, test := range tests { test := test - // Set new banner func and wait for the agent to call it to update the - // banner. - ready := make(chan struct{}, 2) - client.SetServiceBannerFunc(func() (codersdk.ServiceBannerConfig, error) { - select { - case ready <- struct{}{}: - default: - } - return test.banner, nil - }) - <-ready - <-ready // Wait for two updates to ensure the value has propagated. + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + // Set new banner func and wait for the agent to call it to update the + // banner. + ready := make(chan struct{}, 2) + client.SetServiceBannerFunc(func() (codersdk.ServiceBannerConfig, error) { + select { + case ready <- struct{}{}: + default: + } + return test.banner, nil + }) + <-ready + <-ready // Wait for two updates to ensure the value has propagated. - sshClient, err := conn.SSHClient(ctx) - require.NoError(t, err) - t.Cleanup(func() { - _ = sshClient.Close() - }) - session, err := sshClient.NewSession() - require.NoError(t, err) - t.Cleanup(func() { - _ = session.Close() - }) + session, err := sshClient.NewSession() + require.NoError(t, err) + t.Cleanup(func() { + _ = session.Close() + }) - testSessionOutput(t, session, test.expected, test.unexpected, nil) + testSessionOutput(t, session, test.expected, test.unexpected, nil) + }) } } diff --git a/agent/agentscripts/agentscripts.go b/agent/agentscripts/agentscripts.go index 98a6901ebbbc4..3acc48b0a140c 100644 --- a/agent/agentscripts/agentscripts.go +++ b/agent/agentscripts/agentscripts.go @@ -27,6 +27,14 @@ import ( var ( // ErrTimeout is returned when a script times out. ErrTimeout = xerrors.New("script timed out") + // ErrOutputPipesOpen is returned when a script exits leaving the output + // pipe(s) (stdout, stderr) open. This happens because we set WaitDelay on + // the command, which gives us two things: + // + // 1. The ability to ensure that a script exits (this is important for e.g. + // blocking login, and avoiding doing so indefinitely) + // 2. Improved command cancellation on timeout + ErrOutputPipesOpen = xerrors.New("script exited without closing output pipes") parser = cron.NewParser(cron.Second | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.DowOptional) ) @@ -97,7 +105,15 @@ func (r *Runner) Init(scripts []codersdk.WorkspaceAgentScript) error { // StartCron starts the cron scheduler. // This is done async to allow for the caller to execute scripts prior. func (r *Runner) StartCron() { - r.cron.Start() + // cron.Start() and cron.Stop() does not guarantee that the cron goroutine + // has exited by the time the `cron.Stop()` context returns, so we need to + // track it manually. + err := r.trackCommandGoroutine(func() { + r.cron.Run() + }) + if err != nil { + r.Logger.Warn(context.Background(), "start cron failed", slog.Error(err)) + } } // Execute runs a set of scripts according to a filter. @@ -240,7 +256,22 @@ func (r *Runner) run(ctx context.Context, script codersdk.WorkspaceAgentScript) err = cmdCtx.Err() case err = <-cmdDone: } - if errors.Is(err, context.DeadlineExceeded) { + switch { + case errors.Is(err, exec.ErrWaitDelay): + err = ErrOutputPipesOpen + message := fmt.Sprintf("script exited successfully, but output pipes were not closed after %s", cmd.WaitDelay) + details := fmt.Sprint( + "This usually means a child process was started with references to stdout or stderr. As a result, this " + + "process may now have been terminated. Consider redirecting the output or using a separate " + + "\"coder_script\" for the process, see " + + "https://coder.com/docs/v2/latest/templates/troubleshooting#startup-script-issues for more information.", + ) + // Inform the user by propagating the message via log writers. + _, _ = fmt.Fprintf(cmd.Stderr, "WARNING: %s. %s\n", message, details) + // Also log to agent logs for ease of debugging. + r.Logger.Warn(ctx, message, slog.F("details", details), slog.Error(err)) + + case errors.Is(err, context.DeadlineExceeded): err = ErrTimeout } return err @@ -254,7 +285,7 @@ func (r *Runner) Close() error { } close(r.closed) r.cronCtxCancel() - r.cron.Stop() + <-r.cron.Stop().Done() r.cmdCloseWait.Wait() return nil } diff --git a/agent/proto/agent.pb.go b/agent/proto/agent.pb.go new file mode 100644 index 0000000000000..fb75710f1cd56 --- /dev/null +++ b/agent/proto/agent.pb.go @@ -0,0 +1,2453 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.30.0 +// protoc v4.23.3 +// source: agent/proto/agent.proto + +package proto + +import ( + proto "github.com/coder/coder/v2/tailnet/proto" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + durationpb "google.golang.org/protobuf/types/known/durationpb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type AppHealth int32 + +const ( + AppHealth_APP_HEALTH_UNSPECIFIED AppHealth = 0 + AppHealth_DISABLED AppHealth = 1 + AppHealth_INITIALIZING AppHealth = 2 + AppHealth_HEALTHY AppHealth = 3 + AppHealth_UNHEALTHY AppHealth = 4 +) + +// Enum value maps for AppHealth. +var ( + AppHealth_name = map[int32]string{ + 0: "APP_HEALTH_UNSPECIFIED", + 1: "DISABLED", + 2: "INITIALIZING", + 3: "HEALTHY", + 4: "UNHEALTHY", + } + AppHealth_value = map[string]int32{ + "APP_HEALTH_UNSPECIFIED": 0, + "DISABLED": 1, + "INITIALIZING": 2, + "HEALTHY": 3, + "UNHEALTHY": 4, + } +) + +func (x AppHealth) Enum() *AppHealth { + p := new(AppHealth) + *p = x + return p +} + +func (x AppHealth) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AppHealth) Descriptor() protoreflect.EnumDescriptor { + return file_agent_proto_agent_proto_enumTypes[0].Descriptor() +} + +func (AppHealth) Type() protoreflect.EnumType { + return &file_agent_proto_agent_proto_enumTypes[0] +} + +func (x AppHealth) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use AppHealth.Descriptor instead. +func (AppHealth) EnumDescriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{0} +} + +type WorkspaceApp_SharingLevel int32 + +const ( + WorkspaceApp_SHARING_LEVEL_UNSPECIFIED WorkspaceApp_SharingLevel = 0 + WorkspaceApp_OWNER WorkspaceApp_SharingLevel = 1 + WorkspaceApp_AUTHENTICATED WorkspaceApp_SharingLevel = 2 + WorkspaceApp_PUBLIC WorkspaceApp_SharingLevel = 3 +) + +// Enum value maps for WorkspaceApp_SharingLevel. +var ( + WorkspaceApp_SharingLevel_name = map[int32]string{ + 0: "SHARING_LEVEL_UNSPECIFIED", + 1: "OWNER", + 2: "AUTHENTICATED", + 3: "PUBLIC", + } + WorkspaceApp_SharingLevel_value = map[string]int32{ + "SHARING_LEVEL_UNSPECIFIED": 0, + "OWNER": 1, + "AUTHENTICATED": 2, + "PUBLIC": 3, + } +) + +func (x WorkspaceApp_SharingLevel) Enum() *WorkspaceApp_SharingLevel { + p := new(WorkspaceApp_SharingLevel) + *p = x + return p +} + +func (x WorkspaceApp_SharingLevel) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (WorkspaceApp_SharingLevel) Descriptor() protoreflect.EnumDescriptor { + return file_agent_proto_agent_proto_enumTypes[1].Descriptor() +} + +func (WorkspaceApp_SharingLevel) Type() protoreflect.EnumType { + return &file_agent_proto_agent_proto_enumTypes[1] +} + +func (x WorkspaceApp_SharingLevel) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use WorkspaceApp_SharingLevel.Descriptor instead. +func (WorkspaceApp_SharingLevel) EnumDescriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{0, 0} +} + +type WorkspaceApp_Health int32 + +const ( + WorkspaceApp_HEALTH_UNSPECIFIED WorkspaceApp_Health = 0 + WorkspaceApp_DISABLED WorkspaceApp_Health = 1 + WorkspaceApp_INITIALIZING WorkspaceApp_Health = 2 + WorkspaceApp_HEALTHY WorkspaceApp_Health = 3 + WorkspaceApp_UNHEALTHY WorkspaceApp_Health = 4 +) + +// Enum value maps for WorkspaceApp_Health. +var ( + WorkspaceApp_Health_name = map[int32]string{ + 0: "HEALTH_UNSPECIFIED", + 1: "DISABLED", + 2: "INITIALIZING", + 3: "HEALTHY", + 4: "UNHEALTHY", + } + WorkspaceApp_Health_value = map[string]int32{ + "HEALTH_UNSPECIFIED": 0, + "DISABLED": 1, + "INITIALIZING": 2, + "HEALTHY": 3, + "UNHEALTHY": 4, + } +) + +func (x WorkspaceApp_Health) Enum() *WorkspaceApp_Health { + p := new(WorkspaceApp_Health) + *p = x + return p +} + +func (x WorkspaceApp_Health) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (WorkspaceApp_Health) Descriptor() protoreflect.EnumDescriptor { + return file_agent_proto_agent_proto_enumTypes[2].Descriptor() +} + +func (WorkspaceApp_Health) Type() protoreflect.EnumType { + return &file_agent_proto_agent_proto_enumTypes[2] +} + +func (x WorkspaceApp_Health) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use WorkspaceApp_Health.Descriptor instead. +func (WorkspaceApp_Health) EnumDescriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{0, 1} +} + +type Stats_Metric_Type int32 + +const ( + Stats_Metric_TYPE_UNSPECIFIED Stats_Metric_Type = 0 + Stats_Metric_COUNTER Stats_Metric_Type = 1 + Stats_Metric_GAUGE Stats_Metric_Type = 2 +) + +// Enum value maps for Stats_Metric_Type. +var ( + Stats_Metric_Type_name = map[int32]string{ + 0: "TYPE_UNSPECIFIED", + 1: "COUNTER", + 2: "GAUGE", + } + Stats_Metric_Type_value = map[string]int32{ + "TYPE_UNSPECIFIED": 0, + "COUNTER": 1, + "GAUGE": 2, + } +) + +func (x Stats_Metric_Type) Enum() *Stats_Metric_Type { + p := new(Stats_Metric_Type) + *p = x + return p +} + +func (x Stats_Metric_Type) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Stats_Metric_Type) Descriptor() protoreflect.EnumDescriptor { + return file_agent_proto_agent_proto_enumTypes[3].Descriptor() +} + +func (Stats_Metric_Type) Type() protoreflect.EnumType { + return &file_agent_proto_agent_proto_enumTypes[3] +} + +func (x Stats_Metric_Type) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Stats_Metric_Type.Descriptor instead. +func (Stats_Metric_Type) EnumDescriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{5, 1, 0} +} + +type Lifecycle_State int32 + +const ( + Lifecycle_STATE_UNSPECIFIED Lifecycle_State = 0 + Lifecycle_CREATED Lifecycle_State = 1 + Lifecycle_STARTED Lifecycle_State = 2 + Lifecycle_START_TIMEOUT Lifecycle_State = 3 + Lifecycle_START_ERROR Lifecycle_State = 4 + Lifecycle_READY Lifecycle_State = 5 + Lifecycle_SHUTTING_DOWN Lifecycle_State = 6 + Lifecycle_SHUTDOWN_TIMEOUT Lifecycle_State = 7 + Lifecycle_SHUTDOWN_ERROR Lifecycle_State = 8 + Lifecycle_OFF Lifecycle_State = 9 +) + +// Enum value maps for Lifecycle_State. +var ( + Lifecycle_State_name = map[int32]string{ + 0: "STATE_UNSPECIFIED", + 1: "CREATED", + 2: "STARTED", + 3: "START_TIMEOUT", + 4: "START_ERROR", + 5: "READY", + 6: "SHUTTING_DOWN", + 7: "SHUTDOWN_TIMEOUT", + 8: "SHUTDOWN_ERROR", + 9: "OFF", + } + Lifecycle_State_value = map[string]int32{ + "STATE_UNSPECIFIED": 0, + "CREATED": 1, + "STARTED": 2, + "START_TIMEOUT": 3, + "START_ERROR": 4, + "READY": 5, + "SHUTTING_DOWN": 6, + "SHUTDOWN_TIMEOUT": 7, + "SHUTDOWN_ERROR": 8, + "OFF": 9, + } +) + +func (x Lifecycle_State) Enum() *Lifecycle_State { + p := new(Lifecycle_State) + *p = x + return p +} + +func (x Lifecycle_State) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Lifecycle_State) Descriptor() protoreflect.EnumDescriptor { + return file_agent_proto_agent_proto_enumTypes[4].Descriptor() +} + +func (Lifecycle_State) Type() protoreflect.EnumType { + return &file_agent_proto_agent_proto_enumTypes[4] +} + +func (x Lifecycle_State) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Lifecycle_State.Descriptor instead. +func (Lifecycle_State) EnumDescriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{8, 0} +} + +type Log_Level int32 + +const ( + Log_LEVEL_UNSPECIFIED Log_Level = 0 + Log_TRACE Log_Level = 1 + Log_DEBUG Log_Level = 2 + Log_INFO Log_Level = 3 + Log_WARN Log_Level = 4 + Log_ERROR Log_Level = 5 +) + +// Enum value maps for Log_Level. +var ( + Log_Level_name = map[int32]string{ + 0: "LEVEL_UNSPECIFIED", + 1: "TRACE", + 2: "DEBUG", + 3: "INFO", + 4: "WARN", + 5: "ERROR", + } + Log_Level_value = map[string]int32{ + "LEVEL_UNSPECIFIED": 0, + "TRACE": 1, + "DEBUG": 2, + "INFO": 3, + "WARN": 4, + "ERROR": 5, + } +) + +func (x Log_Level) Enum() *Log_Level { + p := new(Log_Level) + *p = x + return p +} + +func (x Log_Level) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Log_Level) Descriptor() protoreflect.EnumDescriptor { + return file_agent_proto_agent_proto_enumTypes[5].Descriptor() +} + +func (Log_Level) Type() protoreflect.EnumType { + return &file_agent_proto_agent_proto_enumTypes[5] +} + +func (x Log_Level) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Log_Level.Descriptor instead. +func (Log_Level) EnumDescriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{17, 0} +} + +type WorkspaceApp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Uuid []byte `protobuf:"bytes,1,opt,name=uuid,proto3" json:"uuid,omitempty"` + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` + External bool `protobuf:"varint,3,opt,name=external,proto3" json:"external,omitempty"` + Slug string `protobuf:"bytes,4,opt,name=slug,proto3" json:"slug,omitempty"` + DisplayName string `protobuf:"bytes,5,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` + Command string `protobuf:"bytes,6,opt,name=command,proto3" json:"command,omitempty"` + Icon string `protobuf:"bytes,7,opt,name=icon,proto3" json:"icon,omitempty"` + Subdomain bool `protobuf:"varint,8,opt,name=subdomain,proto3" json:"subdomain,omitempty"` + SubdomainName string `protobuf:"bytes,9,opt,name=subdomain_name,json=subdomainName,proto3" json:"subdomain_name,omitempty"` + SharingLevel WorkspaceApp_SharingLevel `protobuf:"varint,10,opt,name=sharing_level,json=sharingLevel,proto3,enum=coder.agent.v2.WorkspaceApp_SharingLevel" json:"sharing_level,omitempty"` + Healthcheck *WorkspaceApp_HealthCheck `protobuf:"bytes,11,opt,name=healthcheck,proto3" json:"healthcheck,omitempty"` + Health WorkspaceApp_Health `protobuf:"varint,12,opt,name=health,proto3,enum=coder.agent.v2.WorkspaceApp_Health" json:"health,omitempty"` +} + +func (x *WorkspaceApp) Reset() { + *x = WorkspaceApp{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WorkspaceApp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WorkspaceApp) ProtoMessage() {} + +func (x *WorkspaceApp) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[0] + 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 WorkspaceApp.ProtoReflect.Descriptor instead. +func (*WorkspaceApp) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{0} +} + +func (x *WorkspaceApp) GetUuid() []byte { + if x != nil { + return x.Uuid + } + return nil +} + +func (x *WorkspaceApp) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *WorkspaceApp) GetExternal() bool { + if x != nil { + return x.External + } + return false +} + +func (x *WorkspaceApp) GetSlug() string { + if x != nil { + return x.Slug + } + return "" +} + +func (x *WorkspaceApp) GetDisplayName() string { + if x != nil { + return x.DisplayName + } + return "" +} + +func (x *WorkspaceApp) GetCommand() string { + if x != nil { + return x.Command + } + return "" +} + +func (x *WorkspaceApp) GetIcon() string { + if x != nil { + return x.Icon + } + return "" +} + +func (x *WorkspaceApp) GetSubdomain() bool { + if x != nil { + return x.Subdomain + } + return false +} + +func (x *WorkspaceApp) GetSubdomainName() string { + if x != nil { + return x.SubdomainName + } + return "" +} + +func (x *WorkspaceApp) GetSharingLevel() WorkspaceApp_SharingLevel { + if x != nil { + return x.SharingLevel + } + return WorkspaceApp_SHARING_LEVEL_UNSPECIFIED +} + +func (x *WorkspaceApp) GetHealthcheck() *WorkspaceApp_HealthCheck { + if x != nil { + return x.Healthcheck + } + return nil +} + +func (x *WorkspaceApp) GetHealth() WorkspaceApp_Health { + if x != nil { + return x.Health + } + return WorkspaceApp_HEALTH_UNSPECIFIED +} + +type Manifest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + GitAuthConfigs uint32 `protobuf:"varint,1,opt,name=git_auth_configs,json=gitAuthConfigs,proto3" json:"git_auth_configs,omitempty"` + VsCodePortProxyUri string `protobuf:"bytes,2,opt,name=vs_code_port_proxy_uri,json=vsCodePortProxyUri,proto3" json:"vs_code_port_proxy_uri,omitempty"` + Apps []*WorkspaceApp `protobuf:"bytes,3,rep,name=apps,proto3" json:"apps,omitempty"` + DerpMap *proto.DERPMap `protobuf:"bytes,4,opt,name=derp_map,json=derpMap,proto3" json:"derp_map,omitempty"` +} + +func (x *Manifest) Reset() { + *x = Manifest{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Manifest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Manifest) ProtoMessage() {} + +func (x *Manifest) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[1] + 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 Manifest.ProtoReflect.Descriptor instead. +func (*Manifest) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{1} +} + +func (x *Manifest) GetGitAuthConfigs() uint32 { + if x != nil { + return x.GitAuthConfigs + } + return 0 +} + +func (x *Manifest) GetVsCodePortProxyUri() string { + if x != nil { + return x.VsCodePortProxyUri + } + return "" +} + +func (x *Manifest) GetApps() []*WorkspaceApp { + if x != nil { + return x.Apps + } + return nil +} + +func (x *Manifest) GetDerpMap() *proto.DERPMap { + if x != nil { + return x.DerpMap + } + return nil +} + +type GetManifestRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetManifestRequest) Reset() { + *x = GetManifestRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetManifestRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetManifestRequest) ProtoMessage() {} + +func (x *GetManifestRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[2] + 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 GetManifestRequest.ProtoReflect.Descriptor instead. +func (*GetManifestRequest) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{2} +} + +type ServiceBanner struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` + Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` + BackgroundColor string `protobuf:"bytes,3,opt,name=background_color,json=backgroundColor,proto3" json:"background_color,omitempty"` +} + +func (x *ServiceBanner) Reset() { + *x = ServiceBanner{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ServiceBanner) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServiceBanner) ProtoMessage() {} + +func (x *ServiceBanner) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[3] + 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 ServiceBanner.ProtoReflect.Descriptor instead. +func (*ServiceBanner) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{3} +} + +func (x *ServiceBanner) GetEnabled() bool { + if x != nil { + return x.Enabled + } + return false +} + +func (x *ServiceBanner) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +func (x *ServiceBanner) GetBackgroundColor() string { + if x != nil { + return x.BackgroundColor + } + return "" +} + +type GetServiceBannerRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetServiceBannerRequest) Reset() { + *x = GetServiceBannerRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetServiceBannerRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetServiceBannerRequest) ProtoMessage() {} + +func (x *GetServiceBannerRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[4] + 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 GetServiceBannerRequest.ProtoReflect.Descriptor instead. +func (*GetServiceBannerRequest) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{4} +} + +type Stats struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // ConnectionsByProto is a count of connections by protocol. + ConnectionsByProto map[string]int64 `protobuf:"bytes,1,rep,name=connections_by_proto,json=connectionsByProto,proto3" json:"connections_by_proto,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + // ConnectionCount is the number of connections received by an agent. + ConnectionCount int64 `protobuf:"varint,2,opt,name=connection_count,json=connectionCount,proto3" json:"connection_count,omitempty"` + // ConnectionMedianLatencyMS is the median latency of all connections in milliseconds. + ConnectionMedianLatencyMs float64 `protobuf:"fixed64,3,opt,name=connection_median_latency_ms,json=connectionMedianLatencyMs,proto3" json:"connection_median_latency_ms,omitempty"` + // RxPackets is the number of received packets. + RxPackets int64 `protobuf:"varint,4,opt,name=rx_packets,json=rxPackets,proto3" json:"rx_packets,omitempty"` + // RxBytes is the number of received bytes. + RxBytes int64 `protobuf:"varint,5,opt,name=rx_bytes,json=rxBytes,proto3" json:"rx_bytes,omitempty"` + // TxPackets is the number of transmitted bytes. + TxPackets int64 `protobuf:"varint,6,opt,name=tx_packets,json=txPackets,proto3" json:"tx_packets,omitempty"` + // TxBytes is the number of transmitted bytes. + TxBytes int64 `protobuf:"varint,7,opt,name=tx_bytes,json=txBytes,proto3" json:"tx_bytes,omitempty"` + // SessionCountVSCode is the number of connections received by an agent + // that are from our VS Code extension. + SessionCountVscode int64 `protobuf:"varint,8,opt,name=session_count_vscode,json=sessionCountVscode,proto3" json:"session_count_vscode,omitempty"` + // SessionCountJetBrains is the number of connections received by an agent + // that are from our JetBrains extension. + SessionCountJetbrains int64 `protobuf:"varint,9,opt,name=session_count_jetbrains,json=sessionCountJetbrains,proto3" json:"session_count_jetbrains,omitempty"` + // SessionCountReconnectingPTY is the number of connections received by an agent + // that are from the reconnecting web terminal. + SessionCountReconnectingPty int64 `protobuf:"varint,10,opt,name=session_count_reconnecting_pty,json=sessionCountReconnectingPty,proto3" json:"session_count_reconnecting_pty,omitempty"` + // SessionCountSSH is the number of connections received by an agent + // that are normal, non-tagged SSH sessions. + SessionCountSsh int64 `protobuf:"varint,11,opt,name=session_count_ssh,json=sessionCountSsh,proto3" json:"session_count_ssh,omitempty"` +} + +func (x *Stats) Reset() { + *x = Stats{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Stats) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Stats) ProtoMessage() {} + +func (x *Stats) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[5] + 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 Stats.ProtoReflect.Descriptor instead. +func (*Stats) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{5} +} + +func (x *Stats) GetConnectionsByProto() map[string]int64 { + if x != nil { + return x.ConnectionsByProto + } + return nil +} + +func (x *Stats) GetConnectionCount() int64 { + if x != nil { + return x.ConnectionCount + } + return 0 +} + +func (x *Stats) GetConnectionMedianLatencyMs() float64 { + if x != nil { + return x.ConnectionMedianLatencyMs + } + return 0 +} + +func (x *Stats) GetRxPackets() int64 { + if x != nil { + return x.RxPackets + } + return 0 +} + +func (x *Stats) GetRxBytes() int64 { + if x != nil { + return x.RxBytes + } + return 0 +} + +func (x *Stats) GetTxPackets() int64 { + if x != nil { + return x.TxPackets + } + return 0 +} + +func (x *Stats) GetTxBytes() int64 { + if x != nil { + return x.TxBytes + } + return 0 +} + +func (x *Stats) GetSessionCountVscode() int64 { + if x != nil { + return x.SessionCountVscode + } + return 0 +} + +func (x *Stats) GetSessionCountJetbrains() int64 { + if x != nil { + return x.SessionCountJetbrains + } + return 0 +} + +func (x *Stats) GetSessionCountReconnectingPty() int64 { + if x != nil { + return x.SessionCountReconnectingPty + } + return 0 +} + +func (x *Stats) GetSessionCountSsh() int64 { + if x != nil { + return x.SessionCountSsh + } + return 0 +} + +type UpdateStatsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Stats *Stats `protobuf:"bytes,1,opt,name=stats,proto3" json:"stats,omitempty"` +} + +func (x *UpdateStatsRequest) Reset() { + *x = UpdateStatsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateStatsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateStatsRequest) ProtoMessage() {} + +func (x *UpdateStatsRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[6] + 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 UpdateStatsRequest.ProtoReflect.Descriptor instead. +func (*UpdateStatsRequest) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{6} +} + +func (x *UpdateStatsRequest) GetStats() *Stats { + if x != nil { + return x.Stats + } + return nil +} + +type UpdateStatsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ReportIntervalNanoseconds *durationpb.Duration `protobuf:"bytes,1,opt,name=report_interval_nanoseconds,json=reportIntervalNanoseconds,proto3" json:"report_interval_nanoseconds,omitempty"` +} + +func (x *UpdateStatsResponse) Reset() { + *x = UpdateStatsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateStatsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateStatsResponse) ProtoMessage() {} + +func (x *UpdateStatsResponse) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[7] + 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 UpdateStatsResponse.ProtoReflect.Descriptor instead. +func (*UpdateStatsResponse) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{7} +} + +func (x *UpdateStatsResponse) GetReportIntervalNanoseconds() *durationpb.Duration { + if x != nil { + return x.ReportIntervalNanoseconds + } + return nil +} + +type Lifecycle struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + State Lifecycle_State `protobuf:"varint,1,opt,name=state,proto3,enum=coder.agent.v2.Lifecycle_State" json:"state,omitempty"` +} + +func (x *Lifecycle) Reset() { + *x = Lifecycle{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Lifecycle) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Lifecycle) ProtoMessage() {} + +func (x *Lifecycle) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[8] + 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 Lifecycle.ProtoReflect.Descriptor instead. +func (*Lifecycle) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{8} +} + +func (x *Lifecycle) GetState() Lifecycle_State { + if x != nil { + return x.State + } + return Lifecycle_STATE_UNSPECIFIED +} + +type UpdateLifecycleRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Lifecycle *Lifecycle `protobuf:"bytes,1,opt,name=lifecycle,proto3" json:"lifecycle,omitempty"` +} + +func (x *UpdateLifecycleRequest) Reset() { + *x = UpdateLifecycleRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateLifecycleRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateLifecycleRequest) ProtoMessage() {} + +func (x *UpdateLifecycleRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[9] + 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 UpdateLifecycleRequest.ProtoReflect.Descriptor instead. +func (*UpdateLifecycleRequest) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{9} +} + +func (x *UpdateLifecycleRequest) GetLifecycle() *Lifecycle { + if x != nil { + return x.Lifecycle + } + return nil +} + +type BatchUpdateAppHealthRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Updates []*BatchUpdateAppHealthRequest_HealthUpdate `protobuf:"bytes,1,rep,name=updates,proto3" json:"updates,omitempty"` +} + +func (x *BatchUpdateAppHealthRequest) Reset() { + *x = BatchUpdateAppHealthRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchUpdateAppHealthRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchUpdateAppHealthRequest) ProtoMessage() {} + +func (x *BatchUpdateAppHealthRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[10] + 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 BatchUpdateAppHealthRequest.ProtoReflect.Descriptor instead. +func (*BatchUpdateAppHealthRequest) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{10} +} + +func (x *BatchUpdateAppHealthRequest) GetUpdates() []*BatchUpdateAppHealthRequest_HealthUpdate { + if x != nil { + return x.Updates + } + return nil +} + +type BatchUpdateAppHealthResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *BatchUpdateAppHealthResponse) Reset() { + *x = BatchUpdateAppHealthResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchUpdateAppHealthResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchUpdateAppHealthResponse) ProtoMessage() {} + +func (x *BatchUpdateAppHealthResponse) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[11] + 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 BatchUpdateAppHealthResponse.ProtoReflect.Descriptor instead. +func (*BatchUpdateAppHealthResponse) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{11} +} + +type Startup struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` + ExpandedDirectory string `protobuf:"bytes,2,opt,name=expanded_directory,json=expandedDirectory,proto3" json:"expanded_directory,omitempty"` + Subsystems []string `protobuf:"bytes,3,rep,name=subsystems,proto3" json:"subsystems,omitempty"` +} + +func (x *Startup) Reset() { + *x = Startup{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Startup) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Startup) ProtoMessage() {} + +func (x *Startup) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[12] + 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 Startup.ProtoReflect.Descriptor instead. +func (*Startup) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{12} +} + +func (x *Startup) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *Startup) GetExpandedDirectory() string { + if x != nil { + return x.ExpandedDirectory + } + return "" +} + +func (x *Startup) GetSubsystems() []string { + if x != nil { + return x.Subsystems + } + return nil +} + +type UpdateStartupRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Startup *Startup `protobuf:"bytes,1,opt,name=startup,proto3" json:"startup,omitempty"` +} + +func (x *UpdateStartupRequest) Reset() { + *x = UpdateStartupRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateStartupRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateStartupRequest) ProtoMessage() {} + +func (x *UpdateStartupRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[13] + 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 UpdateStartupRequest.ProtoReflect.Descriptor instead. +func (*UpdateStartupRequest) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{13} +} + +func (x *UpdateStartupRequest) GetStartup() *Startup { + if x != nil { + return x.Startup + } + return nil +} + +type Metadata struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + CollectedAt *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=collected_at,json=collectedAt,proto3" json:"collected_at,omitempty"` + Age int64 `protobuf:"varint,3,opt,name=age,proto3" json:"age,omitempty"` + Value string `protobuf:"bytes,4,opt,name=value,proto3" json:"value,omitempty"` + Error string `protobuf:"bytes,5,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *Metadata) Reset() { + *x = Metadata{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Metadata) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Metadata) ProtoMessage() {} + +func (x *Metadata) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[14] + 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 Metadata.ProtoReflect.Descriptor instead. +func (*Metadata) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{14} +} + +func (x *Metadata) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *Metadata) GetCollectedAt() *timestamppb.Timestamp { + if x != nil { + return x.CollectedAt + } + return nil +} + +func (x *Metadata) GetAge() int64 { + if x != nil { + return x.Age + } + return 0 +} + +func (x *Metadata) GetValue() string { + if x != nil { + return x.Value + } + return "" +} + +func (x *Metadata) GetError() string { + if x != nil { + return x.Error + } + return "" +} + +type BatchUpdateMetadataRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Metadata []*Metadata `protobuf:"bytes,2,rep,name=metadata,proto3" json:"metadata,omitempty"` +} + +func (x *BatchUpdateMetadataRequest) Reset() { + *x = BatchUpdateMetadataRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchUpdateMetadataRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchUpdateMetadataRequest) ProtoMessage() {} + +func (x *BatchUpdateMetadataRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[15] + 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 BatchUpdateMetadataRequest.ProtoReflect.Descriptor instead. +func (*BatchUpdateMetadataRequest) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{15} +} + +func (x *BatchUpdateMetadataRequest) GetMetadata() []*Metadata { + if x != nil { + return x.Metadata + } + return nil +} + +type BatchUpdateMetadataResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *BatchUpdateMetadataResponse) Reset() { + *x = BatchUpdateMetadataResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchUpdateMetadataResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchUpdateMetadataResponse) ProtoMessage() {} + +func (x *BatchUpdateMetadataResponse) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[16] + 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 BatchUpdateMetadataResponse.ProtoReflect.Descriptor instead. +func (*BatchUpdateMetadataResponse) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{16} +} + +type Log struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + Output string `protobuf:"bytes,2,opt,name=output,proto3" json:"output,omitempty"` + Level Log_Level `protobuf:"varint,3,opt,name=level,proto3,enum=coder.agent.v2.Log_Level" json:"level,omitempty"` +} + +func (x *Log) Reset() { + *x = Log{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Log) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Log) ProtoMessage() {} + +func (x *Log) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[17] + 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 Log.ProtoReflect.Descriptor instead. +func (*Log) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{17} +} + +func (x *Log) GetCreatedAt() *timestamppb.Timestamp { + if x != nil { + return x.CreatedAt + } + return nil +} + +func (x *Log) GetOutput() string { + if x != nil { + return x.Output + } + return "" +} + +func (x *Log) GetLevel() Log_Level { + if x != nil { + return x.Level + } + return Log_LEVEL_UNSPECIFIED +} + +type BatchCreateLogsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SourceId []byte `protobuf:"bytes,1,opt,name=source_id,json=sourceId,proto3" json:"source_id,omitempty"` + Logs []*Log `protobuf:"bytes,2,rep,name=logs,proto3" json:"logs,omitempty"` +} + +func (x *BatchCreateLogsRequest) Reset() { + *x = BatchCreateLogsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchCreateLogsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchCreateLogsRequest) ProtoMessage() {} + +func (x *BatchCreateLogsRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[18] + 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 BatchCreateLogsRequest.ProtoReflect.Descriptor instead. +func (*BatchCreateLogsRequest) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{18} +} + +func (x *BatchCreateLogsRequest) GetSourceId() []byte { + if x != nil { + return x.SourceId + } + return nil +} + +func (x *BatchCreateLogsRequest) GetLogs() []*Log { + if x != nil { + return x.Logs + } + return nil +} + +type BatchCreateLogsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *BatchCreateLogsResponse) Reset() { + *x = BatchCreateLogsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchCreateLogsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchCreateLogsResponse) ProtoMessage() {} + +func (x *BatchCreateLogsResponse) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[19] + 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 BatchCreateLogsResponse.ProtoReflect.Descriptor instead. +func (*BatchCreateLogsResponse) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{19} +} + +type WorkspaceApp_HealthCheck struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` + Interval int32 `protobuf:"varint,2,opt,name=interval,proto3" json:"interval,omitempty"` + Threshold int32 `protobuf:"varint,3,opt,name=threshold,proto3" json:"threshold,omitempty"` +} + +func (x *WorkspaceApp_HealthCheck) Reset() { + *x = WorkspaceApp_HealthCheck{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WorkspaceApp_HealthCheck) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WorkspaceApp_HealthCheck) ProtoMessage() {} + +func (x *WorkspaceApp_HealthCheck) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[20] + 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 WorkspaceApp_HealthCheck.ProtoReflect.Descriptor instead. +func (*WorkspaceApp_HealthCheck) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{0, 0} +} + +func (x *WorkspaceApp_HealthCheck) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *WorkspaceApp_HealthCheck) GetInterval() int32 { + if x != nil { + return x.Interval + } + return 0 +} + +func (x *WorkspaceApp_HealthCheck) GetThreshold() int32 { + if x != nil { + return x.Threshold + } + return 0 +} + +type Stats_Metric struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Type Stats_Metric_Type `protobuf:"varint,2,opt,name=type,proto3,enum=coder.agent.v2.Stats_Metric_Type" json:"type,omitempty"` + Value float64 `protobuf:"fixed64,3,opt,name=value,proto3" json:"value,omitempty"` + Labels map[string]string `protobuf:"bytes,4,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *Stats_Metric) Reset() { + *x = Stats_Metric{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Stats_Metric) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Stats_Metric) ProtoMessage() {} + +func (x *Stats_Metric) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[22] + 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 Stats_Metric.ProtoReflect.Descriptor instead. +func (*Stats_Metric) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{5, 1} +} + +func (x *Stats_Metric) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Stats_Metric) GetType() Stats_Metric_Type { + if x != nil { + return x.Type + } + return Stats_Metric_TYPE_UNSPECIFIED +} + +func (x *Stats_Metric) GetValue() float64 { + if x != nil { + return x.Value + } + return 0 +} + +func (x *Stats_Metric) GetLabels() map[string]string { + if x != nil { + return x.Labels + } + return nil +} + +type BatchUpdateAppHealthRequest_HealthUpdate struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Uuid []byte `protobuf:"bytes,1,opt,name=uuid,proto3" json:"uuid,omitempty"` + Health AppHealth `protobuf:"varint,2,opt,name=health,proto3,enum=coder.agent.v2.AppHealth" json:"health,omitempty"` +} + +func (x *BatchUpdateAppHealthRequest_HealthUpdate) Reset() { + *x = BatchUpdateAppHealthRequest_HealthUpdate{} + if protoimpl.UnsafeEnabled { + mi := &file_agent_proto_agent_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchUpdateAppHealthRequest_HealthUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchUpdateAppHealthRequest_HealthUpdate) ProtoMessage() {} + +func (x *BatchUpdateAppHealthRequest_HealthUpdate) ProtoReflect() protoreflect.Message { + mi := &file_agent_proto_agent_proto_msgTypes[24] + 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 BatchUpdateAppHealthRequest_HealthUpdate.ProtoReflect.Descriptor instead. +func (*BatchUpdateAppHealthRequest_HealthUpdate) Descriptor() ([]byte, []int) { + return file_agent_proto_agent_proto_rawDescGZIP(), []int{10, 0} +} + +func (x *BatchUpdateAppHealthRequest_HealthUpdate) GetUuid() []byte { + if x != nil { + return x.Uuid + } + return nil +} + +func (x *BatchUpdateAppHealthRequest_HealthUpdate) GetHealth() AppHealth { + if x != nil { + return x.Health + } + return AppHealth_APP_HEALTH_UNSPECIFIED +} + +var File_agent_proto_agent_proto protoreflect.FileDescriptor + +var file_agent_proto_agent_proto_rawDesc = []byte{ + 0x0a, 0x17, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, 0x63, 0x6f, 0x64, 0x65, 0x72, + 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x1a, 0x1b, 0x74, 0x61, 0x69, 0x6c, 0x6e, + 0x65, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe5, 0x05, 0x0a, 0x0c, 0x57, 0x6f, 0x72, 0x6b, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x41, 0x70, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, + 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x1a, + 0x0a, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x6c, + 0x75, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x12, 0x21, + 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x69, + 0x63, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x12, + 0x1c, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x09, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x25, 0x0a, + 0x0e, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x4e, 0x0a, 0x0d, 0x73, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x5f, + 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x29, 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, 0x70, 0x70, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, + 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x0c, 0x73, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4c, + 0x65, 0x76, 0x65, 0x6c, 0x12, 0x4a, 0x0a, 0x0b, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, + 0x65, 0x63, 0x6b, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 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, 0x70, 0x70, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, + 0x65, 0x63, 0x6b, 0x52, 0x0b, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, + 0x12, 0x3b, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x23, 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, 0x70, 0x70, 0x2e, 0x48, + 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x06, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x1a, 0x59, 0x0a, + 0x0b, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x10, 0x0a, 0x03, + 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x1a, + 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x68, + 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x74, + 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x22, 0x57, 0x0a, 0x0c, 0x53, 0x68, 0x61, 0x72, + 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x48, 0x41, 0x52, + 0x49, 0x4e, 0x47, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, + 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x57, 0x4e, 0x45, 0x52, + 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x41, 0x55, 0x54, 0x48, 0x45, 0x4e, 0x54, 0x49, 0x43, 0x41, + 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x10, + 0x03, 0x22, 0x5c, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x12, 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, 0x22, + 0xd0, 0x01, 0x0a, 0x08, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x10, + 0x67, 0x69, 0x74, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x67, 0x69, 0x74, 0x41, 0x75, 0x74, 0x68, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x32, 0x0a, 0x16, 0x76, 0x73, 0x5f, 0x63, 0x6f, 0x64, + 0x65, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x75, 0x72, 0x69, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x76, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x50, 0x6f, + 0x72, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x55, 0x72, 0x69, 0x12, 0x30, 0x0a, 0x04, 0x61, 0x70, + 0x70, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 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, 0x70, 0x70, 0x52, 0x04, 0x61, 0x70, 0x70, 0x73, 0x12, 0x34, 0x0a, 0x08, + 0x64, 0x65, 0x72, 0x70, 0x5f, 0x6d, 0x61, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, + 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, + 0x32, 0x2e, 0x44, 0x45, 0x52, 0x50, 0x4d, 0x61, 0x70, 0x52, 0x07, 0x64, 0x65, 0x72, 0x70, 0x4d, + 0x61, 0x70, 0x22, 0x14, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x6e, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 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, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, + 0x10, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, + 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, + 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x22, 0x19, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x22, 0x89, 0x07, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x5f, 0x0a, + 0x14, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x62, 0x79, 0x5f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x63, 0x6f, + 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x74, 0x61, + 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x79, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x12, 0x63, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x29, + 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x3f, 0x0a, 0x1c, 0x63, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x6e, 0x5f, 0x6c, + 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, + 0x19, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x64, 0x69, 0x61, + 0x6e, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x4d, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x78, + 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, + 0x72, 0x78, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x78, 0x5f, + 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x72, 0x78, 0x42, + 0x79, 0x74, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x78, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, + 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x78, 0x50, 0x61, 0x63, 0x6b, + 0x65, 0x74, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x78, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x74, 0x78, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x30, + 0x0a, 0x14, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, + 0x76, 0x73, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x73, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x56, 0x73, 0x63, 0x6f, 0x64, 0x65, + 0x12, 0x36, 0x0a, 0x17, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x5f, 0x6a, 0x65, 0x74, 0x62, 0x72, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x15, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x4a, + 0x65, 0x74, 0x62, 0x72, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x43, 0x0a, 0x1e, 0x73, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x74, 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x1b, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, + 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x74, 0x79, 0x12, 0x2a, 0x0a, + 0x11, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x73, + 0x73, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x73, 0x68, 0x1a, 0x45, 0x0a, 0x17, 0x43, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, + 0x1a, 0x9c, 0x02, 0x0a, 0x06, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x35, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x21, 0x2e, + 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x54, 0x79, 0x70, 0x65, + 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x40, 0x0a, 0x06, + 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x63, + 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x74, + 0x61, 0x74, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x1a, 0x39, + 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x34, 0x0a, 0x04, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, + 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4f, 0x55, 0x4e, 0x54, + 0x45, 0x52, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x47, 0x41, 0x55, 0x47, 0x45, 0x10, 0x02, 0x22, + 0x41, 0x0a, 0x12, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2b, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, + 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x05, 0x73, 0x74, 0x61, + 0x74, 0x73, 0x22, 0x70, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x59, 0x0a, 0x1b, 0x72, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x5f, 0x6e, 0x61, 0x6e, + 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x19, 0x72, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, + 0x6f, 0x6e, 0x64, 0x73, 0x22, 0xf2, 0x01, 0x0a, 0x09, 0x4c, 0x69, 0x66, 0x65, 0x63, 0x79, 0x63, + 0x6c, 0x65, 0x12, 0x35, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x1f, 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, 0x2e, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0xad, 0x01, 0x0a, 0x05, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, + 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x52, + 0x45, 0x41, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x54, 0x41, 0x52, 0x54, + 0x45, 0x44, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x54, 0x41, 0x52, 0x54, 0x5f, 0x54, 0x49, + 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x54, 0x41, 0x52, 0x54, + 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x45, 0x41, 0x44, + 0x59, 0x10, 0x05, 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x48, 0x55, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x5f, + 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x06, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x48, 0x55, 0x54, 0x44, 0x4f, + 0x57, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x07, 0x12, 0x12, 0x0a, 0x0e, + 0x53, 0x48, 0x55, 0x54, 0x44, 0x4f, 0x57, 0x4e, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x08, + 0x12, 0x07, 0x0a, 0x03, 0x4f, 0x46, 0x46, 0x10, 0x09, 0x22, 0x51, 0x0a, 0x16, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x4c, 0x69, 0x66, 0x65, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x37, 0x0a, 0x09, 0x6c, 0x69, 0x66, 0x65, 0x63, 0x79, 0x63, 0x6c, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 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, 0x52, 0x09, 0x6c, 0x69, 0x66, 0x65, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x22, 0xc8, 0x01, 0x0a, + 0x1b, 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, 0x12, 0x52, 0x0a, 0x07, + 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x38, 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, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, + 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, + 0x1a, 0x55, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, + 0x75, 0x75, 0x69, 0x64, 0x12, 0x31, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, + 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x41, 0x70, 0x70, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, + 0x06, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x22, 0x1e, 0x0a, 0x1c, 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, 0x22, 0x72, 0x0a, 0x07, 0x53, 0x74, 0x61, 0x72, 0x74, + 0x75, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x0a, 0x12, + 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, + 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, + 0x65, 0x64, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x73, + 0x75, 0x62, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x0a, 0x73, 0x75, 0x62, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x49, 0x0a, 0x14, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x07, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, + 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x52, 0x07, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x22, 0x99, 0x01, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x3d, 0x0a, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x41, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x03, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x14, 0x0a, 0x05, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, + 0x6f, 0x72, 0x22, 0x52, 0x0a, 0x1a, 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, + 0x12, 0x34, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, + 0x2e, 0x76, 0x32, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x1d, 0x0a, 0x1b, 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, 0x22, 0xde, 0x01, 0x0a, 0x03, 0x4c, 0x6f, 0x67, 0x12, 0x39, 0x0a, + 0x0a, 0x63, 0x72, 0x65, 0x61, 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, 0x09, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, + 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x12, 0x2f, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x19, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, + 0x2e, 0x4c, 0x6f, 0x67, 0x2e, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, + 0x6c, 0x22, 0x53, 0x0a, 0x05, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x15, 0x0a, 0x11, 0x4c, 0x45, + 0x56, 0x45, 0x4c, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, + 0x00, 0x12, 0x09, 0x0a, 0x05, 0x54, 0x52, 0x41, 0x43, 0x45, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, + 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x46, 0x4f, 0x10, + 0x03, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x41, 0x52, 0x4e, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x45, + 0x52, 0x52, 0x4f, 0x52, 0x10, 0x05, 0x22, 0x5e, 0x0a, 0x16, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x27, 0x0a, + 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, + 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x6f, 0x67, + 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x22, 0x19, 0x0a, 0x17, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x67, 0x73, 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, 0xb2, 0x07, 0x0a, 0x05, 0x41, 0x67, 0x65, 0x6e, 0x74, + 0x12, 0x4b, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x12, + 0x22, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, + 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, + 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x12, 0x5a, 0x0a, + 0x10, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x42, 0x61, 0x6e, 0x6e, 0x65, + 0x72, 0x12, 0x27, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, + 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x42, 0x61, 0x6e, + 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x63, 0x6f, 0x64, + 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x56, 0x0a, 0x0b, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x22, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, + 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x63, + 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x32, 0x2e, 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, + 0x56, 0x0a, 0x0e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x44, 0x45, 0x52, 0x50, 0x4d, 0x61, 0x70, + 0x73, 0x12, 0x27, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, + 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x44, 0x45, 0x52, 0x50, 0x4d, + 0x61, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x63, 0x6f, 0x64, + 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x45, + 0x52, 0x50, 0x4d, 0x61, 0x70, 0x30, 0x01, 0x12, 0x62, 0x0a, 0x11, 0x43, 0x6f, 0x6f, 0x72, 0x64, + 0x69, 0x6e, 0x61, 0x74, 0x65, 0x54, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x12, 0x23, 0x2e, 0x63, + 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, + 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x24, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, + 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 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 ( + file_agent_proto_agent_proto_rawDescOnce sync.Once + file_agent_proto_agent_proto_rawDescData = file_agent_proto_agent_proto_rawDesc +) + +func file_agent_proto_agent_proto_rawDescGZIP() []byte { + file_agent_proto_agent_proto_rawDescOnce.Do(func() { + file_agent_proto_agent_proto_rawDescData = protoimpl.X.CompressGZIP(file_agent_proto_agent_proto_rawDescData) + }) + return file_agent_proto_agent_proto_rawDescData +} + +var file_agent_proto_agent_proto_enumTypes = make([]protoimpl.EnumInfo, 6) +var file_agent_proto_agent_proto_msgTypes = make([]protoimpl.MessageInfo, 25) +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 + (Log_Level)(0), // 5: coder.agent.v2.Log.Level + (*WorkspaceApp)(nil), // 6: coder.agent.v2.WorkspaceApp + (*Manifest)(nil), // 7: coder.agent.v2.Manifest + (*GetManifestRequest)(nil), // 8: coder.agent.v2.GetManifestRequest + (*ServiceBanner)(nil), // 9: coder.agent.v2.ServiceBanner + (*GetServiceBannerRequest)(nil), // 10: coder.agent.v2.GetServiceBannerRequest + (*Stats)(nil), // 11: coder.agent.v2.Stats + (*UpdateStatsRequest)(nil), // 12: coder.agent.v2.UpdateStatsRequest + (*UpdateStatsResponse)(nil), // 13: coder.agent.v2.UpdateStatsResponse + (*Lifecycle)(nil), // 14: coder.agent.v2.Lifecycle + (*UpdateLifecycleRequest)(nil), // 15: coder.agent.v2.UpdateLifecycleRequest + (*BatchUpdateAppHealthRequest)(nil), // 16: coder.agent.v2.BatchUpdateAppHealthRequest + (*BatchUpdateAppHealthResponse)(nil), // 17: coder.agent.v2.BatchUpdateAppHealthResponse + (*Startup)(nil), // 18: coder.agent.v2.Startup + (*UpdateStartupRequest)(nil), // 19: coder.agent.v2.UpdateStartupRequest + (*Metadata)(nil), // 20: coder.agent.v2.Metadata + (*BatchUpdateMetadataRequest)(nil), // 21: coder.agent.v2.BatchUpdateMetadataRequest + (*BatchUpdateMetadataResponse)(nil), // 22: coder.agent.v2.BatchUpdateMetadataResponse + (*Log)(nil), // 23: coder.agent.v2.Log + (*BatchCreateLogsRequest)(nil), // 24: coder.agent.v2.BatchCreateLogsRequest + (*BatchCreateLogsResponse)(nil), // 25: coder.agent.v2.BatchCreateLogsResponse + (*WorkspaceApp_HealthCheck)(nil), // 26: coder.agent.v2.WorkspaceApp.HealthCheck + nil, // 27: coder.agent.v2.Stats.ConnectionsByProtoEntry + (*Stats_Metric)(nil), // 28: coder.agent.v2.Stats.Metric + nil, // 29: coder.agent.v2.Stats.Metric.LabelsEntry + (*BatchUpdateAppHealthRequest_HealthUpdate)(nil), // 30: coder.agent.v2.BatchUpdateAppHealthRequest.HealthUpdate + (*proto.DERPMap)(nil), // 31: coder.tailnet.v2.DERPMap + (*durationpb.Duration)(nil), // 32: google.protobuf.Duration + (*timestamppb.Timestamp)(nil), // 33: google.protobuf.Timestamp + (*proto.StreamDERPMapsRequest)(nil), // 34: coder.tailnet.v2.StreamDERPMapsRequest + (*proto.CoordinateRequest)(nil), // 35: coder.tailnet.v2.CoordinateRequest + (*proto.CoordinateResponse)(nil), // 36: coder.tailnet.v2.CoordinateResponse +} +var file_agent_proto_agent_proto_depIdxs = []int32{ + 1, // 0: coder.agent.v2.WorkspaceApp.sharing_level:type_name -> coder.agent.v2.WorkspaceApp.SharingLevel + 26, // 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 + 6, // 3: coder.agent.v2.Manifest.apps:type_name -> coder.agent.v2.WorkspaceApp + 31, // 4: coder.agent.v2.Manifest.derp_map:type_name -> coder.tailnet.v2.DERPMap + 27, // 5: coder.agent.v2.Stats.connections_by_proto:type_name -> coder.agent.v2.Stats.ConnectionsByProtoEntry + 11, // 6: coder.agent.v2.UpdateStatsRequest.stats:type_name -> coder.agent.v2.Stats + 32, // 7: coder.agent.v2.UpdateStatsResponse.report_interval_nanoseconds:type_name -> google.protobuf.Duration + 4, // 8: coder.agent.v2.Lifecycle.state:type_name -> coder.agent.v2.Lifecycle.State + 14, // 9: coder.agent.v2.UpdateLifecycleRequest.lifecycle:type_name -> coder.agent.v2.Lifecycle + 30, // 10: coder.agent.v2.BatchUpdateAppHealthRequest.updates:type_name -> coder.agent.v2.BatchUpdateAppHealthRequest.HealthUpdate + 18, // 11: coder.agent.v2.UpdateStartupRequest.startup:type_name -> coder.agent.v2.Startup + 33, // 12: coder.agent.v2.Metadata.collected_at:type_name -> google.protobuf.Timestamp + 20, // 13: coder.agent.v2.BatchUpdateMetadataRequest.metadata:type_name -> coder.agent.v2.Metadata + 33, // 14: coder.agent.v2.Log.created_at:type_name -> google.protobuf.Timestamp + 5, // 15: coder.agent.v2.Log.level:type_name -> coder.agent.v2.Log.Level + 23, // 16: coder.agent.v2.BatchCreateLogsRequest.logs:type_name -> coder.agent.v2.Log + 3, // 17: coder.agent.v2.Stats.Metric.type:type_name -> coder.agent.v2.Stats.Metric.Type + 29, // 18: coder.agent.v2.Stats.Metric.labels:type_name -> coder.agent.v2.Stats.Metric.LabelsEntry + 0, // 19: coder.agent.v2.BatchUpdateAppHealthRequest.HealthUpdate.health:type_name -> coder.agent.v2.AppHealth + 8, // 20: coder.agent.v2.Agent.GetManifest:input_type -> coder.agent.v2.GetManifestRequest + 10, // 21: coder.agent.v2.Agent.GetServiceBanner:input_type -> coder.agent.v2.GetServiceBannerRequest + 12, // 22: coder.agent.v2.Agent.UpdateStats:input_type -> coder.agent.v2.UpdateStatsRequest + 15, // 23: coder.agent.v2.Agent.UpdateLifecycle:input_type -> coder.agent.v2.UpdateLifecycleRequest + 16, // 24: coder.agent.v2.Agent.BatchUpdateAppHealths:input_type -> coder.agent.v2.BatchUpdateAppHealthRequest + 19, // 25: coder.agent.v2.Agent.UpdateStartup:input_type -> coder.agent.v2.UpdateStartupRequest + 21, // 26: coder.agent.v2.Agent.BatchUpdateMetadata:input_type -> coder.agent.v2.BatchUpdateMetadataRequest + 24, // 27: coder.agent.v2.Agent.BatchCreateLogs:input_type -> coder.agent.v2.BatchCreateLogsRequest + 34, // 28: coder.agent.v2.Agent.StreamDERPMaps:input_type -> coder.tailnet.v2.StreamDERPMapsRequest + 35, // 29: coder.agent.v2.Agent.CoordinateTailnet:input_type -> coder.tailnet.v2.CoordinateRequest + 7, // 30: coder.agent.v2.Agent.GetManifest:output_type -> coder.agent.v2.Manifest + 9, // 31: coder.agent.v2.Agent.GetServiceBanner:output_type -> coder.agent.v2.ServiceBanner + 13, // 32: coder.agent.v2.Agent.UpdateStats:output_type -> coder.agent.v2.UpdateStatsResponse + 14, // 33: coder.agent.v2.Agent.UpdateLifecycle:output_type -> coder.agent.v2.Lifecycle + 17, // 34: coder.agent.v2.Agent.BatchUpdateAppHealths:output_type -> coder.agent.v2.BatchUpdateAppHealthResponse + 18, // 35: coder.agent.v2.Agent.UpdateStartup:output_type -> coder.agent.v2.Startup + 22, // 36: coder.agent.v2.Agent.BatchUpdateMetadata:output_type -> coder.agent.v2.BatchUpdateMetadataResponse + 25, // 37: coder.agent.v2.Agent.BatchCreateLogs:output_type -> coder.agent.v2.BatchCreateLogsResponse + 31, // 38: coder.agent.v2.Agent.StreamDERPMaps:output_type -> coder.tailnet.v2.DERPMap + 36, // 39: coder.agent.v2.Agent.CoordinateTailnet:output_type -> coder.tailnet.v2.CoordinateResponse + 30, // [30:40] is the sub-list for method output_type + 20, // [20:30] is the sub-list for method input_type + 20, // [20:20] is the sub-list for extension type_name + 20, // [20:20] is the sub-list for extension extendee + 0, // [0:20] is the sub-list for field type_name +} + +func init() { file_agent_proto_agent_proto_init() } +func file_agent_proto_agent_proto_init() { + if File_agent_proto_agent_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_agent_proto_agent_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WorkspaceApp); 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[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Manifest); 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[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetManifestRequest); 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[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ServiceBanner); 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[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetServiceBannerRequest); 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[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Stats); 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[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateStatsRequest); 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[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateStatsResponse); 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[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Lifecycle); 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[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateLifecycleRequest); 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[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchUpdateAppHealthRequest); 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[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchUpdateAppHealthResponse); 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[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Startup); 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[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateStartupRequest); 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[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Metadata); 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[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchUpdateMetadataRequest); 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[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchUpdateMetadataResponse); 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[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Log); 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[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchCreateLogsRequest); 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[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchCreateLogsResponse); 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[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WorkspaceApp_HealthCheck); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_agent_proto_agent_proto_msgTypes[22].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[24].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchUpdateAppHealthRequest_HealthUpdate); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_agent_proto_agent_proto_rawDesc, + NumEnums: 6, + NumMessages: 25, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_agent_proto_agent_proto_goTypes, + DependencyIndexes: file_agent_proto_agent_proto_depIdxs, + EnumInfos: file_agent_proto_agent_proto_enumTypes, + MessageInfos: file_agent_proto_agent_proto_msgTypes, + }.Build() + File_agent_proto_agent_proto = out.File + file_agent_proto_agent_proto_rawDesc = nil + file_agent_proto_agent_proto_goTypes = nil + file_agent_proto_agent_proto_depIdxs = nil +} diff --git a/agent/proto/agent.proto b/agent/proto/agent.proto new file mode 100644 index 0000000000000..5d6c09c167db0 --- /dev/null +++ b/agent/proto/agent.proto @@ -0,0 +1,211 @@ +syntax = "proto3"; +option go_package = "github.com/coder/coder/v2/agent/proto"; + +package coder.agent.v2; + +import "tailnet/proto/tailnet.proto"; +import "google/protobuf/timestamp.proto"; +import "google/protobuf/duration.proto"; + +message WorkspaceApp { + bytes uuid = 1; + string url = 2; + bool external = 3; + string slug = 4; + string display_name = 5; + string command = 6; + string icon = 7; + bool subdomain = 8; + string subdomain_name = 9; + + enum SharingLevel { + SHARING_LEVEL_UNSPECIFIED = 0; + OWNER = 1; + AUTHENTICATED = 2; + PUBLIC = 3; + } + SharingLevel sharing_level = 10; + + message HealthCheck { + string url = 1; + int32 interval = 2; + int32 threshold = 3; + } + HealthCheck healthcheck = 11; + + enum Health { + HEALTH_UNSPECIFIED = 0; + DISABLED = 1; + INITIALIZING = 2; + HEALTHY = 3; + UNHEALTHY = 4; + } + Health health = 12; +} + +message Manifest { + uint32 git_auth_configs = 1; + string vs_code_port_proxy_uri = 2; + repeated WorkspaceApp apps = 3; + coder.tailnet.v2.DERPMap derp_map = 4; +} + +message GetManifestRequest {} + +message ServiceBanner { + bool enabled = 1; + string message = 2; + string background_color = 3; +} + +message GetServiceBannerRequest {} + +message Stats { + // ConnectionsByProto is a count of connections by protocol. + map connections_by_proto = 1; + // ConnectionCount is the number of connections received by an agent. + int64 connection_count = 2; + // ConnectionMedianLatencyMS is the median latency of all connections in milliseconds. + double connection_median_latency_ms = 3; + // RxPackets is the number of received packets. + int64 rx_packets = 4; + // RxBytes is the number of received bytes. + int64 rx_bytes = 5; + // TxPackets is the number of transmitted bytes. + int64 tx_packets = 6; + // TxBytes is the number of transmitted bytes. + int64 tx_bytes = 7; + + // SessionCountVSCode is the number of connections received by an agent + // that are from our VS Code extension. + int64 session_count_vscode = 8; + // SessionCountJetBrains is the number of connections received by an agent + // that are from our JetBrains extension. + int64 session_count_jetbrains = 9; + // SessionCountReconnectingPTY is the number of connections received by an agent + // that are from the reconnecting web terminal. + int64 session_count_reconnecting_pty = 10; + // SessionCountSSH is the number of connections received by an agent + // that are normal, non-tagged SSH sessions. + int64 session_count_ssh = 11; + + message Metric { + string name = 1; + + enum Type { + TYPE_UNSPECIFIED = 0; + COUNTER = 1; + GAUGE = 2; + } + Type type = 2; + + double value = 3; + map labels = 4; + } +} + +message UpdateStatsRequest{ + Stats stats = 1; +} + +message UpdateStatsResponse { + google.protobuf.Duration report_interval_nanoseconds = 1; +} + +message Lifecycle { + enum State { + STATE_UNSPECIFIED = 0; + CREATED = 1; + STARTED = 2; + START_TIMEOUT = 3; + START_ERROR = 4; + READY = 5; + SHUTTING_DOWN = 6; + SHUTDOWN_TIMEOUT = 7; + SHUTDOWN_ERROR = 8; + OFF = 9; + } + State state = 1; +} + +message UpdateLifecycleRequest { + Lifecycle lifecycle = 1; +} + +enum AppHealth { + APP_HEALTH_UNSPECIFIED = 0; + DISABLED = 1; + INITIALIZING = 2; + HEALTHY = 3; + UNHEALTHY = 4; +} + +message BatchUpdateAppHealthRequest { + message HealthUpdate { + bytes uuid = 1; + AppHealth health = 2; + } + repeated HealthUpdate updates = 1; +} + +message BatchUpdateAppHealthResponse {} + +message Startup { + string version = 1; + string expanded_directory = 2; + repeated string subsystems = 3; +} + +message UpdateStartupRequest{ + Startup startup = 1; +} + +message Metadata { + string key = 1; + google.protobuf.Timestamp collected_at = 2; + int64 age = 3; + string value = 4; + string error = 5; +} + +message BatchUpdateMetadataRequest { + repeated Metadata metadata = 2; +} + +message BatchUpdateMetadataResponse {} + +message Log { + google.protobuf.Timestamp created_at = 1; + string output = 2; + + enum Level { + LEVEL_UNSPECIFIED = 0; + TRACE = 1; + DEBUG = 2; + INFO = 3; + WARN = 4; + ERROR = 5; + } + Level level = 3; +} + +message BatchCreateLogsRequest { + bytes source_id = 1; + repeated Log logs = 2; +} + +message BatchCreateLogsResponse {} + +service Agent { + rpc GetManifest(GetManifestRequest) returns (Manifest); + rpc GetServiceBanner(GetServiceBannerRequest) returns (ServiceBanner); + rpc UpdateStats(UpdateStatsRequest) returns (UpdateStatsResponse); + rpc UpdateLifecycle(UpdateLifecycleRequest) returns (Lifecycle); + rpc BatchUpdateAppHealths(BatchUpdateAppHealthRequest) returns (BatchUpdateAppHealthResponse); + rpc UpdateStartup(UpdateStartupRequest) returns (Startup); + rpc BatchUpdateMetadata(BatchUpdateMetadataRequest) returns (BatchUpdateMetadataResponse); + rpc BatchCreateLogs(BatchCreateLogsRequest) returns (BatchCreateLogsResponse); + + rpc StreamDERPMaps(tailnet.v2.StreamDERPMapsRequest) returns (stream tailnet.v2.DERPMap); + rpc CoordinateTailnet(stream tailnet.v2.CoordinateRequest) returns (stream tailnet.v2.CoordinateResponse); +} diff --git a/agent/proto/agent_drpc.pb.go b/agent/proto/agent_drpc.pb.go new file mode 100644 index 0000000000000..b64ca2b4f2bc7 --- /dev/null +++ b/agent/proto/agent_drpc.pb.go @@ -0,0 +1,539 @@ +// Code generated by protoc-gen-go-drpc. DO NOT EDIT. +// protoc-gen-go-drpc version: v0.0.33 +// source: agent/proto/agent.proto + +package proto + +import ( + context "context" + errors "errors" + proto1 "github.com/coder/coder/v2/tailnet/proto" + protojson "google.golang.org/protobuf/encoding/protojson" + proto "google.golang.org/protobuf/proto" + drpc "storj.io/drpc" + drpcerr "storj.io/drpc/drpcerr" +) + +type drpcEncoding_File_agent_proto_agent_proto struct{} + +func (drpcEncoding_File_agent_proto_agent_proto) Marshal(msg drpc.Message) ([]byte, error) { + return proto.Marshal(msg.(proto.Message)) +} + +func (drpcEncoding_File_agent_proto_agent_proto) MarshalAppend(buf []byte, msg drpc.Message) ([]byte, error) { + return proto.MarshalOptions{}.MarshalAppend(buf, msg.(proto.Message)) +} + +func (drpcEncoding_File_agent_proto_agent_proto) Unmarshal(buf []byte, msg drpc.Message) error { + return proto.Unmarshal(buf, msg.(proto.Message)) +} + +func (drpcEncoding_File_agent_proto_agent_proto) JSONMarshal(msg drpc.Message) ([]byte, error) { + return protojson.Marshal(msg.(proto.Message)) +} + +func (drpcEncoding_File_agent_proto_agent_proto) JSONUnmarshal(buf []byte, msg drpc.Message) error { + return protojson.Unmarshal(buf, msg.(proto.Message)) +} + +type DRPCAgentClient interface { + DRPCConn() drpc.Conn + + GetManifest(ctx context.Context, in *GetManifestRequest) (*Manifest, error) + GetServiceBanner(ctx context.Context, in *GetServiceBannerRequest) (*ServiceBanner, error) + UpdateStats(ctx context.Context, in *UpdateStatsRequest) (*UpdateStatsResponse, error) + UpdateLifecycle(ctx context.Context, in *UpdateLifecycleRequest) (*Lifecycle, error) + BatchUpdateAppHealths(ctx context.Context, in *BatchUpdateAppHealthRequest) (*BatchUpdateAppHealthResponse, error) + UpdateStartup(ctx context.Context, in *UpdateStartupRequest) (*Startup, error) + BatchUpdateMetadata(ctx context.Context, in *BatchUpdateMetadataRequest) (*BatchUpdateMetadataResponse, error) + BatchCreateLogs(ctx context.Context, in *BatchCreateLogsRequest) (*BatchCreateLogsResponse, error) + StreamDERPMaps(ctx context.Context, in *proto1.StreamDERPMapsRequest) (DRPCAgent_StreamDERPMapsClient, error) + CoordinateTailnet(ctx context.Context) (DRPCAgent_CoordinateTailnetClient, error) +} + +type drpcAgentClient struct { + cc drpc.Conn +} + +func NewDRPCAgentClient(cc drpc.Conn) DRPCAgentClient { + return &drpcAgentClient{cc} +} + +func (c *drpcAgentClient) DRPCConn() drpc.Conn { return c.cc } + +func (c *drpcAgentClient) GetManifest(ctx context.Context, in *GetManifestRequest) (*Manifest, error) { + out := new(Manifest) + err := c.cc.Invoke(ctx, "/coder.agent.v2.Agent/GetManifest", drpcEncoding_File_agent_proto_agent_proto{}, in, out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *drpcAgentClient) GetServiceBanner(ctx context.Context, in *GetServiceBannerRequest) (*ServiceBanner, error) { + out := new(ServiceBanner) + err := c.cc.Invoke(ctx, "/coder.agent.v2.Agent/GetServiceBanner", drpcEncoding_File_agent_proto_agent_proto{}, in, out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *drpcAgentClient) UpdateStats(ctx context.Context, in *UpdateStatsRequest) (*UpdateStatsResponse, error) { + out := new(UpdateStatsResponse) + err := c.cc.Invoke(ctx, "/coder.agent.v2.Agent/UpdateStats", drpcEncoding_File_agent_proto_agent_proto{}, in, out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *drpcAgentClient) UpdateLifecycle(ctx context.Context, in *UpdateLifecycleRequest) (*Lifecycle, error) { + out := new(Lifecycle) + err := c.cc.Invoke(ctx, "/coder.agent.v2.Agent/UpdateLifecycle", drpcEncoding_File_agent_proto_agent_proto{}, in, out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *drpcAgentClient) BatchUpdateAppHealths(ctx context.Context, in *BatchUpdateAppHealthRequest) (*BatchUpdateAppHealthResponse, error) { + out := new(BatchUpdateAppHealthResponse) + err := c.cc.Invoke(ctx, "/coder.agent.v2.Agent/BatchUpdateAppHealths", drpcEncoding_File_agent_proto_agent_proto{}, in, out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *drpcAgentClient) UpdateStartup(ctx context.Context, in *UpdateStartupRequest) (*Startup, error) { + out := new(Startup) + err := c.cc.Invoke(ctx, "/coder.agent.v2.Agent/UpdateStartup", drpcEncoding_File_agent_proto_agent_proto{}, in, out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *drpcAgentClient) BatchUpdateMetadata(ctx context.Context, in *BatchUpdateMetadataRequest) (*BatchUpdateMetadataResponse, error) { + out := new(BatchUpdateMetadataResponse) + err := c.cc.Invoke(ctx, "/coder.agent.v2.Agent/BatchUpdateMetadata", drpcEncoding_File_agent_proto_agent_proto{}, in, out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *drpcAgentClient) BatchCreateLogs(ctx context.Context, in *BatchCreateLogsRequest) (*BatchCreateLogsResponse, error) { + out := new(BatchCreateLogsResponse) + err := c.cc.Invoke(ctx, "/coder.agent.v2.Agent/BatchCreateLogs", drpcEncoding_File_agent_proto_agent_proto{}, in, out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *drpcAgentClient) StreamDERPMaps(ctx context.Context, in *proto1.StreamDERPMapsRequest) (DRPCAgent_StreamDERPMapsClient, error) { + stream, err := c.cc.NewStream(ctx, "/coder.agent.v2.Agent/StreamDERPMaps", drpcEncoding_File_agent_proto_agent_proto{}) + if err != nil { + return nil, err + } + x := &drpcAgent_StreamDERPMapsClient{stream} + if err := x.MsgSend(in, drpcEncoding_File_agent_proto_agent_proto{}); err != nil { + return nil, err + } + if err := x.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type DRPCAgent_StreamDERPMapsClient interface { + drpc.Stream + Recv() (*proto1.DERPMap, error) +} + +type drpcAgent_StreamDERPMapsClient struct { + drpc.Stream +} + +func (x *drpcAgent_StreamDERPMapsClient) GetStream() drpc.Stream { + return x.Stream +} + +func (x *drpcAgent_StreamDERPMapsClient) Recv() (*proto1.DERPMap, error) { + m := new(proto1.DERPMap) + if err := x.MsgRecv(m, drpcEncoding_File_agent_proto_agent_proto{}); err != nil { + return nil, err + } + return m, nil +} + +func (x *drpcAgent_StreamDERPMapsClient) RecvMsg(m *proto1.DERPMap) error { + return x.MsgRecv(m, drpcEncoding_File_agent_proto_agent_proto{}) +} + +func (c *drpcAgentClient) CoordinateTailnet(ctx context.Context) (DRPCAgent_CoordinateTailnetClient, error) { + stream, err := c.cc.NewStream(ctx, "/coder.agent.v2.Agent/CoordinateTailnet", drpcEncoding_File_agent_proto_agent_proto{}) + if err != nil { + return nil, err + } + x := &drpcAgent_CoordinateTailnetClient{stream} + return x, nil +} + +type DRPCAgent_CoordinateTailnetClient interface { + drpc.Stream + Send(*proto1.CoordinateRequest) error + Recv() (*proto1.CoordinateResponse, error) +} + +type drpcAgent_CoordinateTailnetClient struct { + drpc.Stream +} + +func (x *drpcAgent_CoordinateTailnetClient) GetStream() drpc.Stream { + return x.Stream +} + +func (x *drpcAgent_CoordinateTailnetClient) Send(m *proto1.CoordinateRequest) error { + return x.MsgSend(m, drpcEncoding_File_agent_proto_agent_proto{}) +} + +func (x *drpcAgent_CoordinateTailnetClient) Recv() (*proto1.CoordinateResponse, error) { + m := new(proto1.CoordinateResponse) + if err := x.MsgRecv(m, drpcEncoding_File_agent_proto_agent_proto{}); err != nil { + return nil, err + } + return m, nil +} + +func (x *drpcAgent_CoordinateTailnetClient) RecvMsg(m *proto1.CoordinateResponse) error { + return x.MsgRecv(m, drpcEncoding_File_agent_proto_agent_proto{}) +} + +type DRPCAgentServer interface { + GetManifest(context.Context, *GetManifestRequest) (*Manifest, error) + GetServiceBanner(context.Context, *GetServiceBannerRequest) (*ServiceBanner, error) + UpdateStats(context.Context, *UpdateStatsRequest) (*UpdateStatsResponse, error) + UpdateLifecycle(context.Context, *UpdateLifecycleRequest) (*Lifecycle, error) + BatchUpdateAppHealths(context.Context, *BatchUpdateAppHealthRequest) (*BatchUpdateAppHealthResponse, error) + UpdateStartup(context.Context, *UpdateStartupRequest) (*Startup, error) + BatchUpdateMetadata(context.Context, *BatchUpdateMetadataRequest) (*BatchUpdateMetadataResponse, error) + BatchCreateLogs(context.Context, *BatchCreateLogsRequest) (*BatchCreateLogsResponse, error) + StreamDERPMaps(*proto1.StreamDERPMapsRequest, DRPCAgent_StreamDERPMapsStream) error + CoordinateTailnet(DRPCAgent_CoordinateTailnetStream) error +} + +type DRPCAgentUnimplementedServer struct{} + +func (s *DRPCAgentUnimplementedServer) GetManifest(context.Context, *GetManifestRequest) (*Manifest, error) { + return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) +} + +func (s *DRPCAgentUnimplementedServer) GetServiceBanner(context.Context, *GetServiceBannerRequest) (*ServiceBanner, error) { + return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) +} + +func (s *DRPCAgentUnimplementedServer) UpdateStats(context.Context, *UpdateStatsRequest) (*UpdateStatsResponse, error) { + return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) +} + +func (s *DRPCAgentUnimplementedServer) UpdateLifecycle(context.Context, *UpdateLifecycleRequest) (*Lifecycle, error) { + return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) +} + +func (s *DRPCAgentUnimplementedServer) BatchUpdateAppHealths(context.Context, *BatchUpdateAppHealthRequest) (*BatchUpdateAppHealthResponse, error) { + return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) +} + +func (s *DRPCAgentUnimplementedServer) UpdateStartup(context.Context, *UpdateStartupRequest) (*Startup, error) { + return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) +} + +func (s *DRPCAgentUnimplementedServer) BatchUpdateMetadata(context.Context, *BatchUpdateMetadataRequest) (*BatchUpdateMetadataResponse, error) { + return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) +} + +func (s *DRPCAgentUnimplementedServer) BatchCreateLogs(context.Context, *BatchCreateLogsRequest) (*BatchCreateLogsResponse, error) { + return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) +} + +func (s *DRPCAgentUnimplementedServer) StreamDERPMaps(*proto1.StreamDERPMapsRequest, DRPCAgent_StreamDERPMapsStream) error { + return drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) +} + +func (s *DRPCAgentUnimplementedServer) CoordinateTailnet(DRPCAgent_CoordinateTailnetStream) error { + return drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) +} + +type DRPCAgentDescription struct{} + +func (DRPCAgentDescription) NumMethods() int { return 10 } + +func (DRPCAgentDescription) Method(n int) (string, drpc.Encoding, drpc.Receiver, interface{}, bool) { + switch n { + case 0: + return "/coder.agent.v2.Agent/GetManifest", drpcEncoding_File_agent_proto_agent_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return srv.(DRPCAgentServer). + GetManifest( + ctx, + in1.(*GetManifestRequest), + ) + }, DRPCAgentServer.GetManifest, true + case 1: + return "/coder.agent.v2.Agent/GetServiceBanner", drpcEncoding_File_agent_proto_agent_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return srv.(DRPCAgentServer). + GetServiceBanner( + ctx, + in1.(*GetServiceBannerRequest), + ) + }, DRPCAgentServer.GetServiceBanner, true + case 2: + return "/coder.agent.v2.Agent/UpdateStats", drpcEncoding_File_agent_proto_agent_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return srv.(DRPCAgentServer). + UpdateStats( + ctx, + in1.(*UpdateStatsRequest), + ) + }, DRPCAgentServer.UpdateStats, true + case 3: + return "/coder.agent.v2.Agent/UpdateLifecycle", drpcEncoding_File_agent_proto_agent_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return srv.(DRPCAgentServer). + UpdateLifecycle( + ctx, + in1.(*UpdateLifecycleRequest), + ) + }, DRPCAgentServer.UpdateLifecycle, true + case 4: + return "/coder.agent.v2.Agent/BatchUpdateAppHealths", drpcEncoding_File_agent_proto_agent_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return srv.(DRPCAgentServer). + BatchUpdateAppHealths( + ctx, + in1.(*BatchUpdateAppHealthRequest), + ) + }, DRPCAgentServer.BatchUpdateAppHealths, true + case 5: + return "/coder.agent.v2.Agent/UpdateStartup", drpcEncoding_File_agent_proto_agent_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return srv.(DRPCAgentServer). + UpdateStartup( + ctx, + in1.(*UpdateStartupRequest), + ) + }, DRPCAgentServer.UpdateStartup, true + case 6: + return "/coder.agent.v2.Agent/BatchUpdateMetadata", drpcEncoding_File_agent_proto_agent_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return srv.(DRPCAgentServer). + BatchUpdateMetadata( + ctx, + in1.(*BatchUpdateMetadataRequest), + ) + }, DRPCAgentServer.BatchUpdateMetadata, true + case 7: + return "/coder.agent.v2.Agent/BatchCreateLogs", drpcEncoding_File_agent_proto_agent_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return srv.(DRPCAgentServer). + BatchCreateLogs( + ctx, + in1.(*BatchCreateLogsRequest), + ) + }, DRPCAgentServer.BatchCreateLogs, true + case 8: + return "/coder.agent.v2.Agent/StreamDERPMaps", drpcEncoding_File_agent_proto_agent_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return nil, srv.(DRPCAgentServer). + StreamDERPMaps( + in1.(*proto1.StreamDERPMapsRequest), + &drpcAgent_StreamDERPMapsStream{in2.(drpc.Stream)}, + ) + }, DRPCAgentServer.StreamDERPMaps, true + case 9: + return "/coder.agent.v2.Agent/CoordinateTailnet", drpcEncoding_File_agent_proto_agent_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return nil, srv.(DRPCAgentServer). + CoordinateTailnet( + &drpcAgent_CoordinateTailnetStream{in1.(drpc.Stream)}, + ) + }, DRPCAgentServer.CoordinateTailnet, true + default: + return "", nil, nil, nil, false + } +} + +func DRPCRegisterAgent(mux drpc.Mux, impl DRPCAgentServer) error { + return mux.Register(impl, DRPCAgentDescription{}) +} + +type DRPCAgent_GetManifestStream interface { + drpc.Stream + SendAndClose(*Manifest) error +} + +type drpcAgent_GetManifestStream struct { + drpc.Stream +} + +func (x *drpcAgent_GetManifestStream) SendAndClose(m *Manifest) error { + if err := x.MsgSend(m, drpcEncoding_File_agent_proto_agent_proto{}); err != nil { + return err + } + return x.CloseSend() +} + +type DRPCAgent_GetServiceBannerStream interface { + drpc.Stream + SendAndClose(*ServiceBanner) error +} + +type drpcAgent_GetServiceBannerStream struct { + drpc.Stream +} + +func (x *drpcAgent_GetServiceBannerStream) SendAndClose(m *ServiceBanner) error { + if err := x.MsgSend(m, drpcEncoding_File_agent_proto_agent_proto{}); err != nil { + return err + } + return x.CloseSend() +} + +type DRPCAgent_UpdateStatsStream interface { + drpc.Stream + SendAndClose(*UpdateStatsResponse) error +} + +type drpcAgent_UpdateStatsStream struct { + drpc.Stream +} + +func (x *drpcAgent_UpdateStatsStream) SendAndClose(m *UpdateStatsResponse) error { + if err := x.MsgSend(m, drpcEncoding_File_agent_proto_agent_proto{}); err != nil { + return err + } + return x.CloseSend() +} + +type DRPCAgent_UpdateLifecycleStream interface { + drpc.Stream + SendAndClose(*Lifecycle) error +} + +type drpcAgent_UpdateLifecycleStream struct { + drpc.Stream +} + +func (x *drpcAgent_UpdateLifecycleStream) SendAndClose(m *Lifecycle) error { + if err := x.MsgSend(m, drpcEncoding_File_agent_proto_agent_proto{}); err != nil { + return err + } + return x.CloseSend() +} + +type DRPCAgent_BatchUpdateAppHealthsStream interface { + drpc.Stream + SendAndClose(*BatchUpdateAppHealthResponse) error +} + +type drpcAgent_BatchUpdateAppHealthsStream struct { + drpc.Stream +} + +func (x *drpcAgent_BatchUpdateAppHealthsStream) SendAndClose(m *BatchUpdateAppHealthResponse) error { + if err := x.MsgSend(m, drpcEncoding_File_agent_proto_agent_proto{}); err != nil { + return err + } + return x.CloseSend() +} + +type DRPCAgent_UpdateStartupStream interface { + drpc.Stream + SendAndClose(*Startup) error +} + +type drpcAgent_UpdateStartupStream struct { + drpc.Stream +} + +func (x *drpcAgent_UpdateStartupStream) SendAndClose(m *Startup) error { + if err := x.MsgSend(m, drpcEncoding_File_agent_proto_agent_proto{}); err != nil { + return err + } + return x.CloseSend() +} + +type DRPCAgent_BatchUpdateMetadataStream interface { + drpc.Stream + SendAndClose(*BatchUpdateMetadataResponse) error +} + +type drpcAgent_BatchUpdateMetadataStream struct { + drpc.Stream +} + +func (x *drpcAgent_BatchUpdateMetadataStream) SendAndClose(m *BatchUpdateMetadataResponse) error { + if err := x.MsgSend(m, drpcEncoding_File_agent_proto_agent_proto{}); err != nil { + return err + } + return x.CloseSend() +} + +type DRPCAgent_BatchCreateLogsStream interface { + drpc.Stream + SendAndClose(*BatchCreateLogsResponse) error +} + +type drpcAgent_BatchCreateLogsStream struct { + drpc.Stream +} + +func (x *drpcAgent_BatchCreateLogsStream) SendAndClose(m *BatchCreateLogsResponse) error { + if err := x.MsgSend(m, drpcEncoding_File_agent_proto_agent_proto{}); err != nil { + return err + } + return x.CloseSend() +} + +type DRPCAgent_StreamDERPMapsStream interface { + drpc.Stream + Send(*proto1.DERPMap) error +} + +type drpcAgent_StreamDERPMapsStream struct { + drpc.Stream +} + +func (x *drpcAgent_StreamDERPMapsStream) Send(m *proto1.DERPMap) error { + return x.MsgSend(m, drpcEncoding_File_agent_proto_agent_proto{}) +} + +type DRPCAgent_CoordinateTailnetStream interface { + drpc.Stream + Send(*proto1.CoordinateResponse) error + Recv() (*proto1.CoordinateRequest, error) +} + +type drpcAgent_CoordinateTailnetStream struct { + drpc.Stream +} + +func (x *drpcAgent_CoordinateTailnetStream) Send(m *proto1.CoordinateResponse) error { + return x.MsgSend(m, drpcEncoding_File_agent_proto_agent_proto{}) +} + +func (x *drpcAgent_CoordinateTailnetStream) Recv() (*proto1.CoordinateRequest, error) { + m := new(proto1.CoordinateRequest) + if err := x.MsgRecv(m, drpcEncoding_File_agent_proto_agent_proto{}); err != nil { + return nil, err + } + return m, nil +} + +func (x *drpcAgent_CoordinateTailnetStream) RecvMsg(m *proto1.CoordinateRequest) error { + return x.MsgRecv(m, drpcEncoding_File_agent_proto_agent_proto{}) +} diff --git a/agent/reconnectingpty/reconnectingpty.go b/agent/reconnectingpty/reconnectingpty.go index 30b1f44801b9f..280cf62aaa841 100644 --- a/agent/reconnectingpty/reconnectingpty.go +++ b/agent/reconnectingpty/reconnectingpty.go @@ -196,8 +196,8 @@ func (s *ptyState) waitForStateOrContext(ctx context.Context, state State) (Stat // until EOF or an error writing to ptty or reading from conn. func readConnLoop(ctx context.Context, conn net.Conn, ptty pty.PTYCmd, metrics *prometheus.CounterVec, logger slog.Logger) { decoder := json.NewDecoder(conn) - var req codersdk.ReconnectingPTYRequest for { + var req codersdk.ReconnectingPTYRequest err := decoder.Decode(&req) if xerrors.Is(err, io.EOF) { return diff --git a/cli/cliui/agent_test.go b/cli/cliui/agent_test.go index ffb116f3a8f01..4cb10d8ec073e 100644 --- a/cli/cliui/agent_test.go +++ b/cli/cliui/agent_test.go @@ -5,12 +5,14 @@ import ( "bytes" "context" "io" + "os" "strings" "sync/atomic" "testing" "time" "github.com/google/uuid" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "golang.org/x/xerrors" @@ -25,9 +27,31 @@ import ( func TestAgent(t *testing.T) { t.Parallel() + waitLines := func(t *testing.T, output <-chan string, lines ...string) error { + t.Helper() + + var got []string + outerLoop: + for _, want := range lines { + for { + select { + case line := <-output: + got = append(got, line) + if strings.Contains(line, want) { + continue outerLoop + } + case <-time.After(testutil.WaitShort): + assert.Failf(t, "timed out waiting for line", "want: %q; got: %q", want, got) + return xerrors.Errorf("timed out waiting for line: %q; got: %q", want, got) + } + } + } + return nil + } + for _, tc := range []struct { name string - iter []func(context.Context, *codersdk.WorkspaceAgent, chan []codersdk.WorkspaceAgentLog) error + iter []func(context.Context, *testing.T, *codersdk.WorkspaceAgent, <-chan string, chan []codersdk.WorkspaceAgentLog) error logs chan []codersdk.WorkspaceAgentLog opts cliui.AgentOptions want []string @@ -38,12 +62,15 @@ func TestAgent(t *testing.T) { opts: cliui.AgentOptions{ FetchInterval: time.Millisecond, }, - iter: []func(context.Context, *codersdk.WorkspaceAgent, chan []codersdk.WorkspaceAgentLog) error{ - func(_ context.Context, agent *codersdk.WorkspaceAgent, _ chan []codersdk.WorkspaceAgentLog) error { + iter: []func(context.Context, *testing.T, *codersdk.WorkspaceAgent, <-chan string, chan []codersdk.WorkspaceAgentLog) error{ + func(_ context.Context, _ *testing.T, agent *codersdk.WorkspaceAgent, _ <-chan string, _ chan []codersdk.WorkspaceAgentLog) error { agent.Status = codersdk.WorkspaceAgentConnecting return nil }, - func(_ context.Context, agent *codersdk.WorkspaceAgent, logs chan []codersdk.WorkspaceAgentLog) error { + func(_ context.Context, t *testing.T, agent *codersdk.WorkspaceAgent, output <-chan string, _ chan []codersdk.WorkspaceAgentLog) error { + return waitLines(t, output, "â§— Waiting for the workspace agent to connect") + }, + func(_ context.Context, _ *testing.T, agent *codersdk.WorkspaceAgent, _ <-chan string, _ chan []codersdk.WorkspaceAgentLog) error { agent.Status = codersdk.WorkspaceAgentConnected agent.FirstConnectedAt = ptr.Ref(time.Now()) return nil @@ -62,12 +89,15 @@ func TestAgent(t *testing.T) { opts: cliui.AgentOptions{ FetchInterval: time.Millisecond, }, - iter: []func(context.Context, *codersdk.WorkspaceAgent, chan []codersdk.WorkspaceAgentLog) error{ - func(_ context.Context, agent *codersdk.WorkspaceAgent, _ chan []codersdk.WorkspaceAgentLog) error { + iter: []func(context.Context, *testing.T, *codersdk.WorkspaceAgent, <-chan string, chan []codersdk.WorkspaceAgentLog) error{ + func(_ context.Context, _ *testing.T, agent *codersdk.WorkspaceAgent, _ <-chan string, _ chan []codersdk.WorkspaceAgentLog) error { agent.Status = codersdk.WorkspaceAgentConnecting return nil }, - func(_ context.Context, agent *codersdk.WorkspaceAgent, logs chan []codersdk.WorkspaceAgentLog) error { + func(_ context.Context, t *testing.T, agent *codersdk.WorkspaceAgent, output <-chan string, _ chan []codersdk.WorkspaceAgentLog) error { + return waitLines(t, output, "â§— Waiting for the workspace agent to connect") + }, + func(_ context.Context, _ *testing.T, agent *codersdk.WorkspaceAgent, _ <-chan string, _ chan []codersdk.WorkspaceAgentLog) error { agent.Status = codersdk.WorkspaceAgentConnected agent.LifecycleState = codersdk.WorkspaceAgentLifecycleStartTimeout agent.FirstConnectedAt = ptr.Ref(time.Now()) @@ -87,18 +117,24 @@ func TestAgent(t *testing.T) { opts: cliui.AgentOptions{ FetchInterval: 1 * time.Millisecond, }, - iter: []func(context.Context, *codersdk.WorkspaceAgent, chan []codersdk.WorkspaceAgentLog) error{ - func(_ context.Context, agent *codersdk.WorkspaceAgent, _ chan []codersdk.WorkspaceAgentLog) error { + iter: []func(context.Context, *testing.T, *codersdk.WorkspaceAgent, <-chan string, chan []codersdk.WorkspaceAgentLog) error{ + func(_ context.Context, _ *testing.T, agent *codersdk.WorkspaceAgent, _ <-chan string, _ chan []codersdk.WorkspaceAgentLog) error { agent.Status = codersdk.WorkspaceAgentConnecting agent.LifecycleState = codersdk.WorkspaceAgentLifecycleStarting agent.StartedAt = ptr.Ref(time.Now()) return nil }, - func(_ context.Context, agent *codersdk.WorkspaceAgent, _ chan []codersdk.WorkspaceAgentLog) error { + func(_ context.Context, t *testing.T, agent *codersdk.WorkspaceAgent, output <-chan string, _ chan []codersdk.WorkspaceAgentLog) error { + return waitLines(t, output, "â§— Waiting for the workspace agent to connect") + }, + func(_ context.Context, _ *testing.T, agent *codersdk.WorkspaceAgent, _ <-chan string, _ chan []codersdk.WorkspaceAgentLog) error { agent.Status = codersdk.WorkspaceAgentTimeout return nil }, - func(_ context.Context, agent *codersdk.WorkspaceAgent, logs chan []codersdk.WorkspaceAgentLog) error { + func(_ context.Context, t *testing.T, agent *codersdk.WorkspaceAgent, output <-chan string, _ chan []codersdk.WorkspaceAgentLog) error { + return waitLines(t, output, "The workspace agent is having trouble connecting, wait for it to connect or restart your workspace.") + }, + func(_ context.Context, _ *testing.T, agent *codersdk.WorkspaceAgent, _ <-chan string, _ chan []codersdk.WorkspaceAgentLog) error { agent.Status = codersdk.WorkspaceAgentConnected agent.FirstConnectedAt = ptr.Ref(time.Now()) agent.LifecycleState = codersdk.WorkspaceAgentLifecycleReady @@ -120,8 +156,8 @@ func TestAgent(t *testing.T) { opts: cliui.AgentOptions{ FetchInterval: 1 * time.Millisecond, }, - iter: []func(context.Context, *codersdk.WorkspaceAgent, chan []codersdk.WorkspaceAgentLog) error{ - func(_ context.Context, agent *codersdk.WorkspaceAgent, _ chan []codersdk.WorkspaceAgentLog) error { + iter: []func(context.Context, *testing.T, *codersdk.WorkspaceAgent, <-chan string, chan []codersdk.WorkspaceAgentLog) error{ + func(_ context.Context, _ *testing.T, agent *codersdk.WorkspaceAgent, _ <-chan string, _ chan []codersdk.WorkspaceAgentLog) error { agent.Status = codersdk.WorkspaceAgentDisconnected agent.FirstConnectedAt = ptr.Ref(time.Now().Add(-1 * time.Minute)) agent.LastConnectedAt = ptr.Ref(time.Now().Add(-1 * time.Minute)) @@ -131,7 +167,10 @@ func TestAgent(t *testing.T) { agent.ReadyAt = ptr.Ref(time.Now()) return nil }, - func(_ context.Context, agent *codersdk.WorkspaceAgent, _ chan []codersdk.WorkspaceAgentLog) error { + func(_ context.Context, t *testing.T, agent *codersdk.WorkspaceAgent, output <-chan string, _ chan []codersdk.WorkspaceAgentLog) error { + return waitLines(t, output, "â§— The workspace agent lost connection") + }, + func(_ context.Context, _ *testing.T, agent *codersdk.WorkspaceAgent, _ <-chan string, _ chan []codersdk.WorkspaceAgentLog) error { agent.Status = codersdk.WorkspaceAgentConnected agent.DisconnectedAt = nil agent.LastConnectedAt = ptr.Ref(time.Now()) @@ -151,8 +190,8 @@ func TestAgent(t *testing.T) { FetchInterval: time.Millisecond, Wait: true, }, - iter: []func(context.Context, *codersdk.WorkspaceAgent, chan []codersdk.WorkspaceAgentLog) error{ - func(_ context.Context, agent *codersdk.WorkspaceAgent, logs chan []codersdk.WorkspaceAgentLog) error { + iter: []func(context.Context, *testing.T, *codersdk.WorkspaceAgent, <-chan string, chan []codersdk.WorkspaceAgentLog) error{ + func(_ context.Context, _ *testing.T, agent *codersdk.WorkspaceAgent, _ <-chan string, logs chan []codersdk.WorkspaceAgentLog) error { agent.Status = codersdk.WorkspaceAgentConnected agent.FirstConnectedAt = ptr.Ref(time.Now()) agent.LifecycleState = codersdk.WorkspaceAgentLifecycleStarting @@ -170,7 +209,7 @@ func TestAgent(t *testing.T) { } return nil }, - func(_ context.Context, agent *codersdk.WorkspaceAgent, logs chan []codersdk.WorkspaceAgentLog) error { + func(_ context.Context, _ *testing.T, agent *codersdk.WorkspaceAgent, _ <-chan string, logs chan []codersdk.WorkspaceAgentLog) error { agent.LifecycleState = codersdk.WorkspaceAgentLifecycleReady agent.ReadyAt = ptr.Ref(time.Now()) logs <- []codersdk.WorkspaceAgentLog{ @@ -195,8 +234,8 @@ func TestAgent(t *testing.T) { FetchInterval: time.Millisecond, Wait: true, }, - iter: []func(context.Context, *codersdk.WorkspaceAgent, chan []codersdk.WorkspaceAgentLog) error{ - func(_ context.Context, agent *codersdk.WorkspaceAgent, logs chan []codersdk.WorkspaceAgentLog) error { + iter: []func(context.Context, *testing.T, *codersdk.WorkspaceAgent, <-chan string, chan []codersdk.WorkspaceAgentLog) error{ + func(_ context.Context, _ *testing.T, agent *codersdk.WorkspaceAgent, output <-chan string, logs chan []codersdk.WorkspaceAgentLog) error { agent.Status = codersdk.WorkspaceAgentConnected agent.FirstConnectedAt = ptr.Ref(time.Now()) agent.StartedAt = ptr.Ref(time.Now()) @@ -224,8 +263,8 @@ func TestAgent(t *testing.T) { opts: cliui.AgentOptions{ FetchInterval: time.Millisecond, }, - iter: []func(context.Context, *codersdk.WorkspaceAgent, chan []codersdk.WorkspaceAgentLog) error{ - func(_ context.Context, agent *codersdk.WorkspaceAgent, logs chan []codersdk.WorkspaceAgentLog) error { + iter: []func(context.Context, *testing.T, *codersdk.WorkspaceAgent, <-chan string, chan []codersdk.WorkspaceAgentLog) error{ + func(_ context.Context, _ *testing.T, agent *codersdk.WorkspaceAgent, output <-chan string, logs chan []codersdk.WorkspaceAgentLog) error { agent.Status = codersdk.WorkspaceAgentDisconnected agent.LifecycleState = codersdk.WorkspaceAgentLifecycleOff return nil @@ -239,8 +278,8 @@ func TestAgent(t *testing.T) { FetchInterval: time.Millisecond, Wait: true, }, - iter: []func(context.Context, *codersdk.WorkspaceAgent, chan []codersdk.WorkspaceAgentLog) error{ - func(_ context.Context, agent *codersdk.WorkspaceAgent, logs chan []codersdk.WorkspaceAgentLog) error { + iter: []func(context.Context, *testing.T, *codersdk.WorkspaceAgent, <-chan string, chan []codersdk.WorkspaceAgentLog) error{ + func(_ context.Context, _ *testing.T, agent *codersdk.WorkspaceAgent, output <-chan string, logs chan []codersdk.WorkspaceAgentLog) error { agent.Status = codersdk.WorkspaceAgentConnected agent.FirstConnectedAt = ptr.Ref(time.Now()) agent.LifecycleState = codersdk.WorkspaceAgentLifecycleStarting @@ -253,7 +292,10 @@ func TestAgent(t *testing.T) { } return nil }, - func(_ context.Context, agent *codersdk.WorkspaceAgent, logs chan []codersdk.WorkspaceAgentLog) error { + func(_ context.Context, t *testing.T, agent *codersdk.WorkspaceAgent, output <-chan string, _ chan []codersdk.WorkspaceAgentLog) error { + return waitLines(t, output, "Hello world") + }, + func(_ context.Context, _ *testing.T, agent *codersdk.WorkspaceAgent, _ <-chan string, _ chan []codersdk.WorkspaceAgentLog) error { agent.ReadyAt = ptr.Ref(time.Now()) agent.LifecycleState = codersdk.WorkspaceAgentLifecycleShuttingDown return nil @@ -272,12 +314,15 @@ func TestAgent(t *testing.T) { FetchInterval: time.Millisecond, Wait: true, }, - iter: []func(context.Context, *codersdk.WorkspaceAgent, chan []codersdk.WorkspaceAgentLog) error{ - func(_ context.Context, agent *codersdk.WorkspaceAgent, _ chan []codersdk.WorkspaceAgentLog) error { + iter: []func(context.Context, *testing.T, *codersdk.WorkspaceAgent, <-chan string, chan []codersdk.WorkspaceAgentLog) error{ + func(_ context.Context, _ *testing.T, agent *codersdk.WorkspaceAgent, _ <-chan string, _ chan []codersdk.WorkspaceAgentLog) error { agent.Status = codersdk.WorkspaceAgentConnecting return nil }, - func(_ context.Context, agent *codersdk.WorkspaceAgent, _ chan []codersdk.WorkspaceAgentLog) error { + func(_ context.Context, t *testing.T, agent *codersdk.WorkspaceAgent, output <-chan string, _ chan []codersdk.WorkspaceAgentLog) error { + return waitLines(t, output, "â§— Waiting for the workspace agent to connect") + }, + func(_ context.Context, _ *testing.T, agent *codersdk.WorkspaceAgent, _ <-chan string, _ chan []codersdk.WorkspaceAgentLog) error { return xerrors.New("bad") }, }, @@ -292,13 +337,16 @@ func TestAgent(t *testing.T) { FetchInterval: time.Millisecond, Wait: true, }, - iter: []func(context.Context, *codersdk.WorkspaceAgent, chan []codersdk.WorkspaceAgentLog) error{ - func(_ context.Context, agent *codersdk.WorkspaceAgent, _ chan []codersdk.WorkspaceAgentLog) error { + iter: []func(context.Context, *testing.T, *codersdk.WorkspaceAgent, <-chan string, chan []codersdk.WorkspaceAgentLog) error{ + func(_ context.Context, _ *testing.T, agent *codersdk.WorkspaceAgent, _ <-chan string, _ chan []codersdk.WorkspaceAgentLog) error { agent.Status = codersdk.WorkspaceAgentTimeout agent.TroubleshootingURL = "https://troubleshoot" return nil }, - func(_ context.Context, agent *codersdk.WorkspaceAgent, _ chan []codersdk.WorkspaceAgentLog) error { + func(_ context.Context, t *testing.T, agent *codersdk.WorkspaceAgent, output <-chan string, _ chan []codersdk.WorkspaceAgentLog) error { + return waitLines(t, output, "The workspace agent is having trouble connecting, wait for it to connect or restart your workspace.") + }, + func(_ context.Context, _ *testing.T, agent *codersdk.WorkspaceAgent, output <-chan string, _ chan []codersdk.WorkspaceAgentLog) error { return xerrors.New("bad") }, }, @@ -317,21 +365,27 @@ func TestAgent(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort) defer cancel() - var buf bytes.Buffer + r, w, err := os.Pipe() + require.NoError(t, err, "create pipe failed") + defer r.Close() + defer w.Close() + agent := codersdk.WorkspaceAgent{ ID: uuid.New(), Status: codersdk.WorkspaceAgentConnecting, CreatedAt: time.Now(), LifecycleState: codersdk.WorkspaceAgentLifecycleCreated, } + output := make(chan string, 100) // Buffered to avoid blocking, overflow is discarded. logs := make(chan []codersdk.WorkspaceAgentLog, 1) cmd := &clibase.Cmd{ Handler: func(inv *clibase.Invocation) error { tc.opts.Fetch = func(_ context.Context, _ uuid.UUID) (codersdk.WorkspaceAgent, error) { + t.Log("iter", len(tc.iter)) var err error if len(tc.iter) > 0 { - err = tc.iter[0](ctx, &agent, logs) + err = tc.iter[0](ctx, t, &agent, output, logs) tc.iter = tc.iter[1:] } return agent, err @@ -352,27 +406,25 @@ func TestAgent(t *testing.T) { close(fetchLogs) return fetchLogs, closeFunc(func() error { return nil }), nil } - err := cliui.Agent(inv.Context(), &buf, uuid.Nil, tc.opts) + err := cliui.Agent(inv.Context(), w, uuid.Nil, tc.opts) + _ = w.Close() return err }, } inv := cmd.Invoke() - w := clitest.StartWithWaiter(t, inv) - if tc.wantErr { - w.RequireError() - } else { - w.RequireSuccess() - } + waiter := clitest.StartWithWaiter(t, inv) - s := bufio.NewScanner(&buf) + s := bufio.NewScanner(r) for s.Scan() { line := s.Text() t.Log(line) + select { + case output <- line: + default: + t.Logf("output overflow: %s", line) + } if len(tc.want) == 0 { - for i := 0; i < 5; i++ { - t.Log(line) - } require.Fail(t, "unexpected line", line) } require.Contains(t, line, tc.want[0]) @@ -382,6 +434,12 @@ func TestAgent(t *testing.T) { if len(tc.want) > 0 { require.Fail(t, "missing lines: "+strings.Join(tc.want, ", ")) } + + if tc.wantErr { + waiter.RequireError() + } else { + waiter.RequireSuccess() + } }) } diff --git a/cli/dotfiles.go b/cli/dotfiles.go index cf3b1391d5e9a..f3d15515585e3 100644 --- a/cli/dotfiles.go +++ b/cli/dotfiles.go @@ -22,6 +22,7 @@ import ( func (r *RootCmd) dotfiles() *clibase.Cmd { var symlinkDir string var gitbranch string + var dotfilesRepoDir string cmd := &clibase.Cmd{ Use: "dotfiles ", @@ -35,11 +36,10 @@ func (r *RootCmd) dotfiles() *clibase.Cmd { ), Handler: func(inv *clibase.Invocation) error { var ( - dotfilesRepoDir = "dotfiles" - gitRepo = inv.Args[0] - cfg = r.createConfig() - cfgDir = string(cfg) - dotfilesDir = filepath.Join(cfgDir, dotfilesRepoDir) + gitRepo = inv.Args[0] + cfg = r.createConfig() + cfgDir = string(cfg) + dotfilesDir = filepath.Join(cfgDir, dotfilesRepoDir) // This follows the same pattern outlined by others in the market: // https://github.com/coder/coder/pull/1696#issue-1245742312 installScriptSet = []string{ @@ -290,6 +290,13 @@ func (r *RootCmd) dotfiles() *clibase.Cmd { "If empty, will default to cloning the default branch or using the existing branch in the cloned repo on disk.", Value: clibase.StringOf(&gitbranch), }, + { + Flag: "repo-dir", + Default: "dotfiles", + Env: "CODER_DOTFILES_REPO_DIR", + Description: "Specifies the directory for the dotfiles repository, relative to global config directory.", + Value: clibase.StringOf(&dotfilesRepoDir), + }, cliui.SkipPromptOption(), } return cmd diff --git a/cli/dotfiles_test.go b/cli/dotfiles_test.go index d5511c986aecc..6726f35b785ad 100644 --- a/cli/dotfiles_test.go +++ b/cli/dotfiles_test.go @@ -50,6 +50,68 @@ func TestDotfiles(t *testing.T) { require.NoError(t, err) require.Equal(t, string(b), "wow") }) + t.Run("SwitchRepoDir", func(t *testing.T) { + t.Parallel() + _, root := clitest.New(t) + testRepo := testGitRepo(t, root) + + // nolint:gosec + err := os.WriteFile(filepath.Join(testRepo, ".bashrc"), []byte("wow"), 0o750) + require.NoError(t, err) + + c := exec.Command("git", "add", ".bashrc") + c.Dir = testRepo + err = c.Run() + require.NoError(t, err) + + c = exec.Command("git", "commit", "-m", `"add .bashrc"`) + c.Dir = testRepo + out, err := c.CombinedOutput() + require.NoError(t, err, string(out)) + + inv, _ := clitest.New(t, "dotfiles", "--global-config", string(root), "--symlink-dir", string(root), "--repo-dir", "testrepo", "-y", testRepo) + err = inv.Run() + require.NoError(t, err) + + b, err := os.ReadFile(filepath.Join(string(root), ".bashrc")) + require.NoError(t, err) + require.Equal(t, string(b), "wow") + + stat, staterr := os.Stat(filepath.Join(string(root), "testrepo")) + require.NoError(t, staterr) + require.True(t, stat.IsDir()) + }) + t.Run("SwitchRepoDirRelative", func(t *testing.T) { + t.Parallel() + _, root := clitest.New(t) + testRepo := testGitRepo(t, root) + + // nolint:gosec + err := os.WriteFile(filepath.Join(testRepo, ".bashrc"), []byte("wow"), 0o750) + require.NoError(t, err) + + c := exec.Command("git", "add", ".bashrc") + c.Dir = testRepo + err = c.Run() + require.NoError(t, err) + + c = exec.Command("git", "commit", "-m", `"add .bashrc"`) + c.Dir = testRepo + out, err := c.CombinedOutput() + require.NoError(t, err, string(out)) + + inv, _ := clitest.New(t, "dotfiles", "--global-config", string(root), "--symlink-dir", string(root), "--repo-dir", "./relrepo", "-y", testRepo) + err = inv.Run() + require.NoError(t, err) + + b, err := os.ReadFile(filepath.Join(string(root), ".bashrc")) + require.NoError(t, err) + require.Equal(t, string(b), "wow") + + stat, staterr := os.Stat(filepath.Join(string(root), "relrepo")) + require.NoError(t, staterr) + require.True(t, stat.IsDir()) + }) t.Run("InstallScript", func(t *testing.T) { t.Parallel() if runtime.GOOS == "windows" { diff --git a/cli/server.go b/cli/server.go index be855419a6052..61755840382e1 100644 --- a/cli/server.go +++ b/cli/server.go @@ -68,7 +68,7 @@ import ( "github.com/coder/coder/v2/coderd/autobuild" "github.com/coder/coder/v2/coderd/batchstats" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/dbmetrics" "github.com/coder/coder/v2/coderd/database/dbpurge" "github.com/coder/coder/v2/coderd/database/migrations" @@ -542,7 +542,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. AppHostname: appHostname, AppHostnameRegex: appHostnameRegex, Logger: logger.Named("coderd"), - Database: dbfake.New(), + Database: dbmem.New(), BaseDERPMap: derpMap, Pubsub: pubsub.NewInMemory(), CacheDir: cacheDir, @@ -633,7 +633,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. if vals.InMemoryDatabase { // This is only used for testing. - options.Database = dbfake.New() + options.Database = dbmem.New() options.Pubsub = pubsub.NewInMemory() } else { sqlDB, err := ConnectToPostgres(ctx, logger, sqlDriver, vals.PostgresURL.String()) @@ -1206,6 +1206,14 @@ func WriteConfigMW(cfg *codersdk.DeploymentValues) clibase.MiddlewareFunc { // isLocalURL returns true if the hostname of the provided URL appears to // resolve to a loopback address. func IsLocalURL(ctx context.Context, u *url.URL) (bool, error) { + // In tests, we commonly use "example.com" or "google.com", which + // are not loopback, so avoid the DNS lookup to avoid flakes. + if flag.Lookup("test.v") != nil { + if u.Hostname() == "example.com" || u.Hostname() == "google.com" { + return false, nil + } + } + resolver := &net.Resolver{} ips, err := resolver.LookupIPAddr(ctx, u.Hostname()) if err != nil { diff --git a/cli/testdata/coder_dotfiles_--help.golden b/cli/testdata/coder_dotfiles_--help.golden index a54e576b2526a..14991512127da 100644 --- a/cli/testdata/coder_dotfiles_--help.golden +++ b/cli/testdata/coder_dotfiles_--help.golden @@ -15,6 +15,10 @@ OPTIONS: default branch or using the existing branch in the cloned repo on disk. + --repo-dir string, $CODER_DOTFILES_REPO_DIR (default: dotfiles) + Specifies the directory for the dotfiles repository, relative to + global config directory. + --symlink-dir string, $CODER_SYMLINK_DIR Specifies the directory for the dotfiles symlink destinations. If empty, will use $HOME. diff --git a/coderd/awsidentity/awsidentity.go b/coderd/awsidentity/awsidentity.go index 98d0e694786c9..ff96fd2b0af1f 100644 --- a/coderd/awsidentity/awsidentity.go +++ b/coderd/awsidentity/awsidentity.go @@ -16,16 +16,23 @@ import ( type Region string const ( - Other Region = "other" - HongKong Region = "hongkong" - Bahrain Region = "bahrain" - CapeTown Region = "capetown" - Milan Region = "milan" - China Region = "china" - GovCloud Region = "govcloud" + Other Region = "other" + CapeTown Region = "capetown" + HongKong Region = "hongkong" + Hyderabad Region = "hyderabad" + Jakarta Region = "jakarta" + Melbourne Region = "melbourne" + China Region = "china" + Milan Region = "milan" + Spain Region = "spain" + Zurich Region = "zurich" + TelAviv Region = "telaviv" + Bahrain Region = "bahrain" + UAE Region = "uae" + GovCloud Region = "govcloud" ) -var All = []Region{Other, HongKong, Bahrain, CapeTown, Milan, China, GovCloud} +var All = []Region{Other, CapeTown, HongKong, Hyderabad, Jakarta, Melbourne, China, Milan, Spain, Zurich, TelAviv, Bahrain, UAE, GovCloud} // Certificates hold public keys for various AWS regions. See: type Certificates map[Region]string @@ -193,6 +200,104 @@ WtgIe3M3iwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAHzQC5XZVeuD9GTJTsbO5AyH ZQvki/jfARNrD9dgBRYZzLC/NOkWG6M9wlrmks9RtdNxc53nLxKq4I2Dd73gI0yQ wYu9YYwmM/LMgmPlI33Rg2Ohwq4DVgT3hO170PL6Fsgiq3dMvctSImJvjWktBQaT bcAgaZLHGIpXPrWSA2d+ +-----END CERTIFICATE-----`, + TelAviv: `-----BEGIN CERTIFICATE----- +MIICMzCCAZygAwIBAgIGAX0QQGVLMA0GCSqGSIb3DQEBBQUAMFwxCzAJBgNVBAYT +AlVTMRkwFwYDVQQIDBBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHDAdTZWF0dGxl +MSAwHgYDVQQKDBdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAgFw0yMTExMTExODI2 +MzVaGA8yMjAwMTExMTE4MjYzNVowXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgMEFdh +c2hpbmd0b24gU3RhdGUxEDAOBgNVBAcMB1NlYXR0bGUxIDAeBgNVBAoMF0FtYXpv +biBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDr +c24u3AgFxnoPgzxR6yFXOamcPuxYXhYKWmapb+S8vOy5hpLoRe4RkOrY0cM3bN07 +GdEMlin5mU0y1t8y3ct4YewvmkgT42kTyMM+t1K4S0xsqjXxxS716uGYh7eWtkxr +Cihj8AbXN/6pa095h+7TZyl2n83keiNUzM2KoqQVMwIDAQABMA0GCSqGSIb3DQEB +BQUAA4GBADwA6VVEIIZD2YL00F12po40xDLzIc9XvqFPS9iFaWi2ho8wLio7wA49 +VYEFZSI9CR3SGB9tL8DUib97mlxmd1AcGShMmMlhSB29vhuhrUNB/FmU7H8s62/j +D6cOR1A1cClIyZUe1yT1ZbPySCs43J+Thr8i8FSRxzDBSZZi5foW +-----END CERTIFICATE-----`, + UAE: `-----BEGIN CERTIFICATE----- +MIICMzCCAZygAwIBAgIGAXjRrnDjMA0GCSqGSIb3DQEBBQUAMFwxCzAJBgNVBAYT +AlVTMRkwFwYDVQQIDBBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHDAdTZWF0dGxl +MSAwHgYDVQQKDBdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAgFw0yMTA0MTQxODM5 +MzNaGA8yMjAwMDQxNDE4MzkzM1owXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgMEFdh +c2hpbmd0b24gU3RhdGUxEDAOBgNVBAcMB1NlYXR0bGUxIDAeBgNVBAoMF0FtYXpv +biBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDc +aTgW/KyA6zyruJQrYy00a6wqLA7eeUzk3bMiTkLsTeDQfrkaZMfBAjGaaOymRo1C +3qzE4rIenmahvUplu9ZmLwL1idWXMRX2RlSvIt+d2SeoKOKQWoc2UOFZMHYxDue7 +zkyk1CIRaBukTeY13/RIrlc6X61zJ5BBtZXlHwayjQIDAQABMA0GCSqGSIb3DQEB +BQUAA4GBABTqTy3R6RXKPW45FA+cgo7YZEj/Cnz5YaoUivRRdX2A83BHuBTvJE2+ +WX00FTEj4hRVjameE1nENoO8Z7fUVloAFDlDo69fhkJeSvn51D1WRrPnoWGgEfr1 ++OfK1bAcKTtfkkkP9r4RdwSjKzO5Zu/B+Wqm3kVEz/QNcz6npmA6 +-----END CERTIFICATE-----`, + Zurich: `-----BEGIN CERTIFICATE----- +MIICMzCCAZygAwIBAgIGAXjSGFGiMA0GCSqGSIb3DQEBBQUAMFwxCzAJBgNVBAYT +AlVTMRkwFwYDVQQIDBBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHDAdTZWF0dGxl +MSAwHgYDVQQKDBdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAgFw0yMTA0MTQyMDM1 +MTJaGA8yMjAwMDQxNDIwMzUxMlowXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgMEFdh +c2hpbmd0b24gU3RhdGUxEDAOBgNVBAcMB1NlYXR0bGUxIDAeBgNVBAoMF0FtYXpv +biBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2 +mdGdps5Rz2jzYcGNsgETTGUthJRrVqSnUWJXTlVaIbkGPLKO6Or7AfWKFp2sgRJ8 +vLsjoBVR5cESVK7cuK1wItjvJyi/opKZAUusJx2hpgU3pUHhlp9ATh/VeVD582jT +d9IY+8t5MDa6Z3fGliByEiXz0LEHdi8MBacLREu1TwIDAQABMA0GCSqGSIb3DQEB +BQUAA4GBAILlpoE3k9o7KdALAxsFJNitVS+g3RMzdbiFM+7MA63Nv5fsf+0xgcjS +NBElvPCDKFvTJl4QQhToy056llO5GvdS9RK+H8xrP2mrqngApoKTApv93vHBixgF +Sn5KrczRO0YSm3OjkqbydU7DFlmkXXR7GYE+5jbHvQHYiT1J5sMu +-----END CERTIFICATE-----`, + Spain: `-----BEGIN CERTIFICATE----- +MIICMzCCAZygAwIBAgIGAXjwLkiaMA0GCSqGSIb3DQEBBQUAMFwxCzAJBgNVBAYT +AlVTMRkwFwYDVQQIDBBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHDAdTZWF0dGxl +MSAwHgYDVQQKDBdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAgFw0yMTA0MjAxNjQ3 +NDhaGA8yMjAwMDQyMDE2NDc0OFowXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgMEFdh +c2hpbmd0b24gU3RhdGUxEDAOBgNVBAcMB1NlYXR0bGUxIDAeBgNVBAoMF0FtYXpv +biBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDB +/VvR1+45Aey5zn3vPk6xBm5o9grSDL6D2iAuprQnfVXn8CIbSDbWFhA3fi5ippjK +kh3sl8VyCvCOUXKdOaNrYBrPRkrdHdBuL2Tc84RO+3m/rxIUZ2IK1fDlC6sWAjdd +f6sBrV2w2a78H0H8EwuwiSgttURBjwJ7KPPJCqaqrQIDAQABMA0GCSqGSIb3DQEB +BQUAA4GBAKR+FzqQDzun/iMMzcFucmLMl5BxEblrFXOz7IIuOeiGkndmrqUeDCyk +ztLku45s7hxdNy4ltTuVAaE5aNBdw5J8U1mRvsKvHLy2ThH6hAWKwTqtPAJp7M21 +GDwgDDOkPSz6XVOehg+hBgiphYp84DUbWVYeP8YqLEJSqscKscWC +-----END CERTIFICATE-----`, + Melbourne: `-----BEGIN CERTIFICATE----- +MIICMzCCAZygAwIBAgIGAXjSh40SMA0GCSqGSIb3DQEBBQUAMFwxCzAJBgNVBAYT +AlVTMRkwFwYDVQQIDBBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHDAdTZWF0dGxl +MSAwHgYDVQQKDBdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAgFw0yMTA0MTQyMjM2 +NDJaGA8yMjAwMDQxNDIyMzY0MlowXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgMEFdh +c2hpbmd0b24gU3RhdGUxEDAOBgNVBAcMB1NlYXR0bGUxIDAeBgNVBAoMF0FtYXpv +biBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDH +ezwQr2VQpQSTW5TXNefiQrP+qWTGAbGsPeMX4hBMjAJUKys2NIRcRZaLM/BCew2F +IPVjNtlaj6Gwn9ipU4Mlz3zIwAMWi1AvGMSreppt+wV6MRtfOjh0Dvj/veJe88aE +ZJMozNgkJFRS+WFWsckQeL56tf6kY6QTlNo8V/0CsQIDAQABMA0GCSqGSIb3DQEB +BQUAA4GBAF7vpPghH0FRo5gu49EArRNPrIvW1egMdZHrzJNqbztLCtV/wcgkqIww +uXYj+1rhlL+/iMpQWjdVGEqIZSeXn5fLmdx50eegFCwND837r9e8XYTiQS143Sxt +9+Yi6BZ7U7YD8kK9NBWoJxFqUeHdpRCs0O7COjT3gwm7ZxvAmssh +-----END CERTIFICATE-----`, + Jakarta: `-----BEGIN CERTIFICATE----- +MIICMzCCAZygAwIBAgIGAXbVDG2yMA0GCSqGSIb3DQEBBQUAMFwxCzAJBgNVBAYT +AlVTMRkwFwYDVQQIDBBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHDAdTZWF0dGxl +MSAwHgYDVQQKDBdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAgFw0yMTAxMDYwMDE1 +MzBaGA8yMjAwMDEwNjAwMTUzMFowXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgMEFdh +c2hpbmd0b24gU3RhdGUxEDAOBgNVBAcMB1NlYXR0bGUxIDAeBgNVBAoMF0FtYXpv +biBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCn +CS/Vbt0gQ1ebWcur2hSO7PnJifE4OPxQ7RgSAlc4/spJp1sDP+ZrS0LO1ZJfKhXf +1R9S3AUwLnsc7b+IuVXdY5LK9RKqu64nyXP5dx170zoL8loEyCSuRR2fs+04i2Qs +WBVP+KFNAn7P5L1EHRjkgTO8kjNKviwRV+OkP9ab5wIDAQABMA0GCSqGSIb3DQEB +BQUAA4GBAI4WUy6+DKh0JDSzQEZNyBgNlSoSuC2owtMxCwGB6nBfzzfcekWvs6eo +fLTSGovrReX7MtVgrcJBZjmPIentw5dWUs+87w/g9lNwUnUt0ZHYyh2tuBG6hVJu +UEwDJ/z3wDd6wQviLOTF3MITawt9P8siR1hXqLJNxpjRQFZrgHqi +-----END CERTIFICATE-----`, + Hyderabad: `-----BEGIN CERTIFICATE----- +MIICMzCCAZygAwIBAgIGAXjwLj9CMA0GCSqGSIb3DQEBBQUAMFwxCzAJBgNVBAYT +AlVTMRkwFwYDVQQIDBBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHDAdTZWF0dGxl +MSAwHgYDVQQKDBdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAgFw0yMTA0MjAxNjQ3 +NDVaGA8yMjAwMDQyMDE2NDc0NVowXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgMEFdh +c2hpbmd0b24gU3RhdGUxEDAOBgNVBAcMB1NlYXR0bGUxIDAeBgNVBAoMF0FtYXpv +biBXZWIgU2VydmljZXMgTExDMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDT +wHu0ND+sFcobrjvcAYm0PNRD8f4R1jAzvoLt2+qGeOTAyO1Httj6cmsYN3AP1hN5 +iYuppFiYsl2eNPa/CD0Vg0BAfDFlV5rzjpA0j7TJabVh4kj7JvtD+xYMi6wEQA4x +6SPONY4OeZ2+8o/HS8nucpWDVdPRO6ciWUlMhjmDmwIDAQABMA0GCSqGSIb3DQEB +BQUAA4GBAAy6sgTdRkTqELHBeWj69q60xHyUmsWqHAQNXKVc9ApWGG4onzuqlMbG +ETwUZ9mTq2vxlV0KvuetCDNS5u4cJsxe/TGGbYP0yP2qfMl0cCImzRI5W0gn8gog +dervfeT7nH5ih0TWEy/QDWfkQ601L4erm4yh4YQq8vcqAPSkf04N -----END CERTIFICATE-----`, GovCloud: `-----BEGIN CERTIFICATE----- MIIDCzCCAnSgAwIBAgIJAIe9Hnq82O7UMA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNV diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index a5847839b2478..48239450ebe1a 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -16,8 +16,8 @@ import ( "github.com/coder/coder/v2/coderd/coderdtest" "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/dbauthz" - "github.com/coder/coder/v2/coderd/database/dbfake" "github.com/coder/coder/v2/coderd/database/dbgen" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/rbac" "github.com/coder/coder/v2/coderd/util/slice" @@ -62,7 +62,7 @@ func TestAsNoActor(t *testing.T) { func TestPing(t *testing.T) { t.Parallel() - q := dbauthz.New(dbfake.New(), &coderdtest.RecordingAuthorizer{}, slog.Make(), accessControlStorePointer()) + q := dbauthz.New(dbmem.New(), &coderdtest.RecordingAuthorizer{}, slog.Make(), accessControlStorePointer()) _, err := q.Ping(context.Background()) require.NoError(t, err, "must not error") } @@ -71,7 +71,7 @@ func TestPing(t *testing.T) { func TestInTX(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() q := dbauthz.New(db, &coderdtest.RecordingAuthorizer{ Wrapped: &coderdtest.FakeAuthorizer{AlwaysReturn: xerrors.New("custom error")}, }, slog.Make(), accessControlStorePointer()) @@ -99,7 +99,7 @@ func TestNew(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() exp = dbgen.Workspace(t, db, database.Workspace{}) rec = &coderdtest.RecordingAuthorizer{ Wrapped: &coderdtest.FakeAuthorizer{AlwaysReturn: nil}, @@ -126,7 +126,7 @@ func TestNew(t *testing.T) { // as only the first db call will be made. But it is better than nothing. func TestDBAuthzRecursive(t *testing.T) { t.Parallel() - q := dbauthz.New(dbfake.New(), &coderdtest.RecordingAuthorizer{ + q := dbauthz.New(dbmem.New(), &coderdtest.RecordingAuthorizer{ Wrapped: &coderdtest.FakeAuthorizer{AlwaysReturn: nil}, }, slog.Make(), accessControlStorePointer()) actor := rbac.Subject{ diff --git a/coderd/database/dbauthz/setup_test.go b/coderd/database/dbauthz/setup_test.go index 968b882f2d263..304b8673a9f8d 100644 --- a/coderd/database/dbauthz/setup_test.go +++ b/coderd/database/dbauthz/setup_test.go @@ -20,7 +20,7 @@ import ( "github.com/coder/coder/v2/coderd/coderdtest" "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/dbauthz" - "github.com/coder/coder/v2/coderd/database/dbfake" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/dbmock" "github.com/coder/coder/v2/coderd/rbac" "github.com/coder/coder/v2/coderd/rbac/regosql" @@ -104,7 +104,7 @@ func (s *MethodTestSuite) Subtest(testCaseF func(db database.Store, check *expec methodName := names[len(names)-1] s.methodAccounting[methodName]++ - db := dbfake.New() + db := dbmem.New() fakeAuthorizer := &coderdtest.FakeAuthorizer{ AlwaysReturn: nil, } diff --git a/coderd/database/dbgen/dbgen_test.go b/coderd/database/dbgen/dbgen_test.go index d7d961b1ae2fe..531c8bb25cd53 100644 --- a/coderd/database/dbgen/dbgen_test.go +++ b/coderd/database/dbgen/dbgen_test.go @@ -8,8 +8,8 @@ import ( "github.com/stretchr/testify/require" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" "github.com/coder/coder/v2/coderd/database/dbgen" + "github.com/coder/coder/v2/coderd/database/dbmem" ) func TestGenerator(t *testing.T) { @@ -17,7 +17,7 @@ func TestGenerator(t *testing.T) { t.Run("AuditLog", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() _ = dbgen.AuditLog(t, db, database.AuditLog{}) logs := must(db.GetAuditLogsOffset(context.Background(), database.GetAuditLogsOffsetParams{Limit: 1})) require.Len(t, logs, 1) @@ -25,28 +25,28 @@ func TestGenerator(t *testing.T) { t.Run("APIKey", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() exp, _ := dbgen.APIKey(t, db, database.APIKey{}) require.Equal(t, exp, must(db.GetAPIKeyByID(context.Background(), exp.ID))) }) t.Run("File", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() exp := dbgen.File(t, db, database.File{}) require.Equal(t, exp, must(db.GetFileByID(context.Background(), exp.ID))) }) t.Run("UserLink", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() exp := dbgen.UserLink(t, db, database.UserLink{}) require.Equal(t, exp, must(db.GetUserLinkByLinkedID(context.Background(), exp.LinkedID))) }) t.Run("GitAuthLink", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() exp := dbgen.ExternalAuthLink(t, db, database.ExternalAuthLink{}) require.Equal(t, exp, must(db.GetExternalAuthLink(context.Background(), database.GetExternalAuthLinkParams{ ProviderID: exp.ProviderID, @@ -56,28 +56,28 @@ func TestGenerator(t *testing.T) { t.Run("WorkspaceResource", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() exp := dbgen.WorkspaceResource(t, db, database.WorkspaceResource{}) require.Equal(t, exp, must(db.GetWorkspaceResourceByID(context.Background(), exp.ID))) }) t.Run("WorkspaceApp", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() exp := dbgen.WorkspaceApp(t, db, database.WorkspaceApp{}) require.Equal(t, exp, must(db.GetWorkspaceAppsByAgentID(context.Background(), exp.AgentID))[0]) }) t.Run("WorkspaceResourceMetadata", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() exp := dbgen.WorkspaceResourceMetadatums(t, db, database.WorkspaceResourceMetadatum{}) require.Equal(t, exp, must(db.GetWorkspaceResourceMetadataByResourceIDs(context.Background(), []uuid.UUID{exp[0].WorkspaceResourceID}))) }) t.Run("WorkspaceProxy", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() exp, secret := dbgen.WorkspaceProxy(t, db, database.WorkspaceProxy{}) require.Len(t, secret, 64) require.Equal(t, exp, must(db.GetWorkspaceProxyByID(context.Background(), exp.ID))) @@ -85,21 +85,21 @@ func TestGenerator(t *testing.T) { t.Run("Job", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() exp := dbgen.ProvisionerJob(t, db, nil, database.ProvisionerJob{}) require.Equal(t, exp, must(db.GetProvisionerJobByID(context.Background(), exp.ID))) }) t.Run("Group", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() exp := dbgen.Group(t, db, database.Group{}) require.Equal(t, exp, must(db.GetGroupByID(context.Background(), exp.ID))) }) t.Run("GroupMember", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() g := dbgen.Group(t, db, database.Group{}) u := dbgen.User(t, db, database.User{}) exp := []database.User{u} @@ -110,14 +110,14 @@ func TestGenerator(t *testing.T) { t.Run("Organization", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() exp := dbgen.Organization(t, db, database.Organization{}) require.Equal(t, exp, must(db.GetOrganizationByID(context.Background(), exp.ID))) }) t.Run("OrganizationMember", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() exp := dbgen.OrganizationMember(t, db, database.OrganizationMember{}) require.Equal(t, exp, must(db.GetOrganizationMemberByUserID(context.Background(), database.GetOrganizationMemberByUserIDParams{ OrganizationID: exp.OrganizationID, @@ -127,49 +127,49 @@ func TestGenerator(t *testing.T) { t.Run("Workspace", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() exp := dbgen.Workspace(t, db, database.Workspace{}) require.Equal(t, exp, must(db.GetWorkspaceByID(context.Background(), exp.ID))) }) t.Run("WorkspaceAgent", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() exp := dbgen.WorkspaceAgent(t, db, database.WorkspaceAgent{}) require.Equal(t, exp, must(db.GetWorkspaceAgentByID(context.Background(), exp.ID))) }) t.Run("Template", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() exp := dbgen.Template(t, db, database.Template{}) require.Equal(t, exp, must(db.GetTemplateByID(context.Background(), exp.ID))) }) t.Run("TemplateVersion", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() exp := dbgen.TemplateVersion(t, db, database.TemplateVersion{}) require.Equal(t, exp, must(db.GetTemplateVersionByID(context.Background(), exp.ID))) }) t.Run("WorkspaceBuild", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() exp := dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{}) require.Equal(t, exp, must(db.GetWorkspaceBuildByID(context.Background(), exp.ID))) }) t.Run("User", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() exp := dbgen.User(t, db, database.User{}) require.Equal(t, exp, must(db.GetUserByID(context.Background(), exp.ID))) }) t.Run("SSHKey", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() exp := dbgen.GitSSHKey(t, db, database.GitSSHKey{}) require.Equal(t, exp, must(db.GetGitSSHKey(context.Background(), exp.UserID))) }) diff --git a/coderd/database/dbfake/dbfake.go b/coderd/database/dbmem/dbmem.go similarity index 99% rename from coderd/database/dbfake/dbfake.go rename to coderd/database/dbmem/dbmem.go index e2ddde14e2d00..a0e48473602ad 100644 --- a/coderd/database/dbfake/dbfake.go +++ b/coderd/database/dbmem/dbmem.go @@ -1,4 +1,4 @@ -package dbfake +package dbmem import ( "context" @@ -705,7 +705,7 @@ func provisonerJobStatus(j database.ProvisionerJob) database.ProvisionerJobStatu return database.ProvisionerJobStatusRunning } -// isNull is only used in dbfake, so reflect is ok. Use this to make the logic +// isNull is only used in dbmem, so reflect is ok. Use this to make the logic // look more similar to the postgres. func isNull(v interface{}) bool { return !isNotNull(v) @@ -4868,7 +4868,7 @@ func (q *FakeQuerier) InsertUser(_ context.Context, arg database.InsertUserParam return database.User{}, err } - // There is a common bug when using dbfake that 2 inserted users have the + // There is a common bug when using dbmem that 2 inserted users have the // same created_at time. This causes user order to not be deterministic, // which breaks some unit tests. // To fix this, we make sure that the created_at time is always greater diff --git a/coderd/database/dbfake/dbfake_test.go b/coderd/database/dbmem/dbmem_test.go similarity index 97% rename from coderd/database/dbfake/dbfake_test.go rename to coderd/database/dbmem/dbmem_test.go index 3cbc54042f782..e7d7bd76bd132 100644 --- a/coderd/database/dbfake/dbfake_test.go +++ b/coderd/database/dbmem/dbmem_test.go @@ -1,4 +1,4 @@ -package dbfake_test +package dbmem_test import ( "context" @@ -11,8 +11,8 @@ import ( "github.com/stretchr/testify/require" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" "github.com/coder/coder/v2/coderd/database/dbgen" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/dbtime" ) @@ -20,7 +20,7 @@ import ( func TestInTx(t *testing.T) { t.Parallel() - uut := dbfake.New() + uut := dbmem.New() inTx := make(chan any) queriesDone := make(chan any) @@ -67,7 +67,7 @@ func TestInTx(t *testing.T) { func TestUserOrder(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() now := dbtime.Now() usernames := []string{"b-user", "d-user", "a-user", "c-user", "e-user"} @@ -88,7 +88,7 @@ func TestUserOrder(t *testing.T) { func TestProxyByHostname(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() // Insert a bunch of different proxies. proxies := []struct { diff --git a/coderd/database/dbpurge/dbpurge_test.go b/coderd/database/dbpurge/dbpurge_test.go index f83d1b81a1d2a..64fc74b4775ca 100644 --- a/coderd/database/dbpurge/dbpurge_test.go +++ b/coderd/database/dbpurge/dbpurge_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/require" "cdr.dev/slog/sloggers/slogtest" - "github.com/coder/coder/v2/coderd/database/dbfake" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/dbpurge" ) @@ -20,7 +20,7 @@ func TestMain(m *testing.M) { // Ensures no goroutines leak. func TestPurge(t *testing.T) { t.Parallel() - purger := dbpurge.New(context.Background(), slogtest.Make(t, nil), dbfake.New()) + purger := dbpurge.New(context.Background(), slogtest.Make(t, nil), dbmem.New()) err := purger.Close() require.NoError(t, err) } diff --git a/coderd/database/dbtestutil/db.go b/coderd/database/dbtestutil/db.go index 65e1afecc7948..c179917c0594a 100644 --- a/coderd/database/dbtestutil/db.go +++ b/coderd/database/dbtestutil/db.go @@ -18,7 +18,7 @@ import ( "golang.org/x/xerrors" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/postgres" "github.com/coder/coder/v2/coderd/database/pubsub" ) @@ -79,7 +79,7 @@ func NewDB(t testing.TB, opts ...Option) (database.Store, pubsub.Pubsub) { opt(&o) } - db := dbfake.New() + db := dbmem.New() ps := pubsub.NewInMemory() if WillUsePostgres() { connectionURL := os.Getenv("CODER_PG_CONNECTION_URL") diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index 0e79c875f93bc..dcf63c6f66f9e 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -925,6 +925,7 @@ CREATE TABLE workspace_agents ( ready_at timestamp with time zone, subsystems workspace_agent_subsystem[] DEFAULT '{}'::workspace_agent_subsystem[], display_apps display_app[] DEFAULT '{vscode,vscode_insiders,web_terminal,ssh_helper,port_forwarding_helper}'::display_app[], + api_version text DEFAULT ''::text NOT NULL, CONSTRAINT max_logs_length CHECK ((logs_length <= 1048576)), CONSTRAINT subsystems_not_none CHECK ((NOT ('none'::workspace_agent_subsystem = ANY (subsystems)))) ); diff --git a/coderd/database/migrations/000167_workspace_agent_api_version.down.sql b/coderd/database/migrations/000167_workspace_agent_api_version.down.sql new file mode 100644 index 0000000000000..53c2b3417a983 --- /dev/null +++ b/coderd/database/migrations/000167_workspace_agent_api_version.down.sql @@ -0,0 +1,3 @@ +BEGIN; +ALTER TABLE workspace_agents DROP COLUMN api_version; +COMMIT; diff --git a/coderd/database/migrations/000167_workspace_agent_api_version.up.sql b/coderd/database/migrations/000167_workspace_agent_api_version.up.sql new file mode 100644 index 0000000000000..b4187e51efa93 --- /dev/null +++ b/coderd/database/migrations/000167_workspace_agent_api_version.up.sql @@ -0,0 +1,3 @@ +BEGIN; +ALTER TABLE workspace_agents ADD COLUMN api_version TEXT DEFAULT '' NOT NULL; +COMMIT; diff --git a/coderd/database/models.go b/coderd/database/models.go index c67afa74faa9a..4d5a0193ccc7c 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -2117,6 +2117,7 @@ type WorkspaceAgent struct { ReadyAt sql.NullTime `db:"ready_at" json:"ready_at"` Subsystems []WorkspaceAgentSubsystem `db:"subsystems" json:"subsystems"` DisplayApps []DisplayApp `db:"display_apps" json:"display_apps"` + APIVersion string `db:"api_version" json:"api_version"` } type WorkspaceAgentLog struct { diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 50da65e9c74a4..b1eb3af14719e 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -7109,7 +7109,7 @@ func (q *sqlQuerier) DeleteOldWorkspaceAgentLogs(ctx context.Context) error { const getWorkspaceAgentAndOwnerByAuthToken = `-- name: GetWorkspaceAgentAndOwnerByAuthToken :one SELECT - workspace_agents.id, workspace_agents.created_at, workspace_agents.updated_at, workspace_agents.name, workspace_agents.first_connected_at, workspace_agents.last_connected_at, workspace_agents.disconnected_at, workspace_agents.resource_id, workspace_agents.auth_token, workspace_agents.auth_instance_id, workspace_agents.architecture, workspace_agents.environment_variables, workspace_agents.operating_system, workspace_agents.instance_metadata, workspace_agents.resource_metadata, workspace_agents.directory, workspace_agents.version, workspace_agents.last_connected_replica_id, workspace_agents.connection_timeout_seconds, workspace_agents.troubleshooting_url, workspace_agents.motd_file, workspace_agents.lifecycle_state, workspace_agents.expanded_directory, workspace_agents.logs_length, workspace_agents.logs_overflowed, workspace_agents.started_at, workspace_agents.ready_at, workspace_agents.subsystems, workspace_agents.display_apps, + workspace_agents.id, workspace_agents.created_at, workspace_agents.updated_at, workspace_agents.name, workspace_agents.first_connected_at, workspace_agents.last_connected_at, workspace_agents.disconnected_at, workspace_agents.resource_id, workspace_agents.auth_token, workspace_agents.auth_instance_id, workspace_agents.architecture, workspace_agents.environment_variables, workspace_agents.operating_system, workspace_agents.instance_metadata, workspace_agents.resource_metadata, workspace_agents.directory, workspace_agents.version, workspace_agents.last_connected_replica_id, workspace_agents.connection_timeout_seconds, workspace_agents.troubleshooting_url, workspace_agents.motd_file, workspace_agents.lifecycle_state, workspace_agents.expanded_directory, workspace_agents.logs_length, workspace_agents.logs_overflowed, workspace_agents.started_at, workspace_agents.ready_at, workspace_agents.subsystems, workspace_agents.display_apps, workspace_agents.api_version, workspaces.id AS workspace_id, users.id AS owner_id, users.username AS owner_name, @@ -7204,6 +7204,7 @@ func (q *sqlQuerier) GetWorkspaceAgentAndOwnerByAuthToken(ctx context.Context, a &i.WorkspaceAgent.ReadyAt, pq.Array(&i.WorkspaceAgent.Subsystems), pq.Array(&i.WorkspaceAgent.DisplayApps), + &i.WorkspaceAgent.APIVersion, &i.WorkspaceID, &i.OwnerID, &i.OwnerName, @@ -7216,7 +7217,7 @@ func (q *sqlQuerier) GetWorkspaceAgentAndOwnerByAuthToken(ctx context.Context, a const getWorkspaceAgentByID = `-- name: GetWorkspaceAgentByID :one SELECT - id, created_at, updated_at, name, first_connected_at, last_connected_at, disconnected_at, resource_id, auth_token, auth_instance_id, architecture, environment_variables, operating_system, instance_metadata, resource_metadata, directory, version, last_connected_replica_id, connection_timeout_seconds, troubleshooting_url, motd_file, lifecycle_state, expanded_directory, logs_length, logs_overflowed, started_at, ready_at, subsystems, display_apps + id, created_at, updated_at, name, first_connected_at, last_connected_at, disconnected_at, resource_id, auth_token, auth_instance_id, architecture, environment_variables, operating_system, instance_metadata, resource_metadata, directory, version, last_connected_replica_id, connection_timeout_seconds, troubleshooting_url, motd_file, lifecycle_state, expanded_directory, logs_length, logs_overflowed, started_at, ready_at, subsystems, display_apps, api_version FROM workspace_agents WHERE @@ -7256,13 +7257,14 @@ func (q *sqlQuerier) GetWorkspaceAgentByID(ctx context.Context, id uuid.UUID) (W &i.ReadyAt, pq.Array(&i.Subsystems), pq.Array(&i.DisplayApps), + &i.APIVersion, ) return i, err } const getWorkspaceAgentByInstanceID = `-- name: GetWorkspaceAgentByInstanceID :one SELECT - id, created_at, updated_at, name, first_connected_at, last_connected_at, disconnected_at, resource_id, auth_token, auth_instance_id, architecture, environment_variables, operating_system, instance_metadata, resource_metadata, directory, version, last_connected_replica_id, connection_timeout_seconds, troubleshooting_url, motd_file, lifecycle_state, expanded_directory, logs_length, logs_overflowed, started_at, ready_at, subsystems, display_apps + id, created_at, updated_at, name, first_connected_at, last_connected_at, disconnected_at, resource_id, auth_token, auth_instance_id, architecture, environment_variables, operating_system, instance_metadata, resource_metadata, directory, version, last_connected_replica_id, connection_timeout_seconds, troubleshooting_url, motd_file, lifecycle_state, expanded_directory, logs_length, logs_overflowed, started_at, ready_at, subsystems, display_apps, api_version FROM workspace_agents WHERE @@ -7304,6 +7306,7 @@ func (q *sqlQuerier) GetWorkspaceAgentByInstanceID(ctx context.Context, authInst &i.ReadyAt, pq.Array(&i.Subsystems), pq.Array(&i.DisplayApps), + &i.APIVersion, ) return i, err } @@ -7462,7 +7465,7 @@ func (q *sqlQuerier) GetWorkspaceAgentMetadata(ctx context.Context, arg GetWorks const getWorkspaceAgentsByResourceIDs = `-- name: GetWorkspaceAgentsByResourceIDs :many SELECT - id, created_at, updated_at, name, first_connected_at, last_connected_at, disconnected_at, resource_id, auth_token, auth_instance_id, architecture, environment_variables, operating_system, instance_metadata, resource_metadata, directory, version, last_connected_replica_id, connection_timeout_seconds, troubleshooting_url, motd_file, lifecycle_state, expanded_directory, logs_length, logs_overflowed, started_at, ready_at, subsystems, display_apps + id, created_at, updated_at, name, first_connected_at, last_connected_at, disconnected_at, resource_id, auth_token, auth_instance_id, architecture, environment_variables, operating_system, instance_metadata, resource_metadata, directory, version, last_connected_replica_id, connection_timeout_seconds, troubleshooting_url, motd_file, lifecycle_state, expanded_directory, logs_length, logs_overflowed, started_at, ready_at, subsystems, display_apps, api_version FROM workspace_agents WHERE @@ -7508,6 +7511,7 @@ func (q *sqlQuerier) GetWorkspaceAgentsByResourceIDs(ctx context.Context, ids [] &i.ReadyAt, pq.Array(&i.Subsystems), pq.Array(&i.DisplayApps), + &i.APIVersion, ); err != nil { return nil, err } @@ -7523,7 +7527,7 @@ func (q *sqlQuerier) GetWorkspaceAgentsByResourceIDs(ctx context.Context, ids [] } const getWorkspaceAgentsCreatedAfter = `-- name: GetWorkspaceAgentsCreatedAfter :many -SELECT id, created_at, updated_at, name, first_connected_at, last_connected_at, disconnected_at, resource_id, auth_token, auth_instance_id, architecture, environment_variables, operating_system, instance_metadata, resource_metadata, directory, version, last_connected_replica_id, connection_timeout_seconds, troubleshooting_url, motd_file, lifecycle_state, expanded_directory, logs_length, logs_overflowed, started_at, ready_at, subsystems, display_apps FROM workspace_agents WHERE created_at > $1 +SELECT id, created_at, updated_at, name, first_connected_at, last_connected_at, disconnected_at, resource_id, auth_token, auth_instance_id, architecture, environment_variables, operating_system, instance_metadata, resource_metadata, directory, version, last_connected_replica_id, connection_timeout_seconds, troubleshooting_url, motd_file, lifecycle_state, expanded_directory, logs_length, logs_overflowed, started_at, ready_at, subsystems, display_apps, api_version FROM workspace_agents WHERE created_at > $1 ` func (q *sqlQuerier) GetWorkspaceAgentsCreatedAfter(ctx context.Context, createdAt time.Time) ([]WorkspaceAgent, error) { @@ -7565,6 +7569,7 @@ func (q *sqlQuerier) GetWorkspaceAgentsCreatedAfter(ctx context.Context, created &i.ReadyAt, pq.Array(&i.Subsystems), pq.Array(&i.DisplayApps), + &i.APIVersion, ); err != nil { return nil, err } @@ -7581,7 +7586,7 @@ func (q *sqlQuerier) GetWorkspaceAgentsCreatedAfter(ctx context.Context, created const getWorkspaceAgentsInLatestBuildByWorkspaceID = `-- name: GetWorkspaceAgentsInLatestBuildByWorkspaceID :many SELECT - workspace_agents.id, workspace_agents.created_at, workspace_agents.updated_at, workspace_agents.name, workspace_agents.first_connected_at, workspace_agents.last_connected_at, workspace_agents.disconnected_at, workspace_agents.resource_id, workspace_agents.auth_token, workspace_agents.auth_instance_id, workspace_agents.architecture, workspace_agents.environment_variables, workspace_agents.operating_system, workspace_agents.instance_metadata, workspace_agents.resource_metadata, workspace_agents.directory, workspace_agents.version, workspace_agents.last_connected_replica_id, workspace_agents.connection_timeout_seconds, workspace_agents.troubleshooting_url, workspace_agents.motd_file, workspace_agents.lifecycle_state, workspace_agents.expanded_directory, workspace_agents.logs_length, workspace_agents.logs_overflowed, workspace_agents.started_at, workspace_agents.ready_at, workspace_agents.subsystems, workspace_agents.display_apps + workspace_agents.id, workspace_agents.created_at, workspace_agents.updated_at, workspace_agents.name, workspace_agents.first_connected_at, workspace_agents.last_connected_at, workspace_agents.disconnected_at, workspace_agents.resource_id, workspace_agents.auth_token, workspace_agents.auth_instance_id, workspace_agents.architecture, workspace_agents.environment_variables, workspace_agents.operating_system, workspace_agents.instance_metadata, workspace_agents.resource_metadata, workspace_agents.directory, workspace_agents.version, workspace_agents.last_connected_replica_id, workspace_agents.connection_timeout_seconds, workspace_agents.troubleshooting_url, workspace_agents.motd_file, workspace_agents.lifecycle_state, workspace_agents.expanded_directory, workspace_agents.logs_length, workspace_agents.logs_overflowed, workspace_agents.started_at, workspace_agents.ready_at, workspace_agents.subsystems, workspace_agents.display_apps, workspace_agents.api_version FROM workspace_agents JOIN @@ -7639,6 +7644,7 @@ func (q *sqlQuerier) GetWorkspaceAgentsInLatestBuildByWorkspaceID(ctx context.Co &i.ReadyAt, pq.Array(&i.Subsystems), pq.Array(&i.DisplayApps), + &i.APIVersion, ); err != nil { return nil, err } @@ -7675,7 +7681,7 @@ INSERT INTO display_apps ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17) RETURNING id, created_at, updated_at, name, first_connected_at, last_connected_at, disconnected_at, resource_id, auth_token, auth_instance_id, architecture, environment_variables, operating_system, instance_metadata, resource_metadata, directory, version, last_connected_replica_id, connection_timeout_seconds, troubleshooting_url, motd_file, lifecycle_state, expanded_directory, logs_length, logs_overflowed, started_at, ready_at, subsystems, display_apps + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17) RETURNING id, created_at, updated_at, name, first_connected_at, last_connected_at, disconnected_at, resource_id, auth_token, auth_instance_id, architecture, environment_variables, operating_system, instance_metadata, resource_metadata, directory, version, last_connected_replica_id, connection_timeout_seconds, troubleshooting_url, motd_file, lifecycle_state, expanded_directory, logs_length, logs_overflowed, started_at, ready_at, subsystems, display_apps, api_version ` type InsertWorkspaceAgentParams struct { @@ -7749,6 +7755,7 @@ func (q *sqlQuerier) InsertWorkspaceAgent(ctx context.Context, arg InsertWorkspa &i.ReadyAt, pq.Array(&i.Subsystems), pq.Array(&i.DisplayApps), + &i.APIVersion, ) return i, err } diff --git a/coderd/database/sqlc.yaml b/coderd/database/sqlc.yaml index 592b2c7b5e32e..956485311e4a1 100644 --- a/coderd/database/sqlc.yaml +++ b/coderd/database/sqlc.yaml @@ -38,6 +38,7 @@ overrides: api_key_scope: APIKeyScope api_key_scope_all: APIKeyScopeAll api_key_scope_application_connect: APIKeyScopeApplicationConnect + api_version: APIVersion avatar_url: AvatarURL created_by_avatar_url: CreatedByAvatarURL dbcrypt_key: DBCryptKey diff --git a/coderd/externalauth.go b/coderd/externalauth.go index 774a5f860397d..b1b7acc8bc449 100644 --- a/coderd/externalauth.go +++ b/coderd/externalauth.go @@ -268,8 +268,9 @@ func (api *API) externalAuthCallback(externalAuthConfig *externalauth.Config) ht redirect := state.Redirect if redirect == "" { - // This is a nicely rendered screen on the frontend - redirect = fmt.Sprintf("/external-auth/%s", externalAuthConfig.ID) + // This is a nicely rendered screen on the frontend. Passing the query param lets the + // FE know not to enter the authentication loop again, and instead display an error. + redirect = fmt.Sprintf("/external-auth/%s?redirected=true", externalAuthConfig.ID) } http.Redirect(rw, r, redirect, http.StatusTemporaryRedirect) } diff --git a/coderd/externalauth/externalauth_test.go b/coderd/externalauth/externalauth_test.go index d790c32989ea7..2108063b91f46 100644 --- a/coderd/externalauth/externalauth_test.go +++ b/coderd/externalauth/externalauth_test.go @@ -19,7 +19,7 @@ import ( "github.com/coder/coder/v2/coderd/coderdtest/oidctest" "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/dbauthz" - "github.com/coder/coder/v2/coderd/database/dbfake" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/externalauth" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/testutil" @@ -223,7 +223,7 @@ func TestRefreshToken(t *testing.T) { t.Run("Updates", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() validateCalls := 0 refreshCalls := 0 fake, config, link := setupOauth2Test(t, testConfig{ @@ -265,7 +265,7 @@ func TestRefreshToken(t *testing.T) { t.Run("WithExtra", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() fake, config, link := setupOauth2Test(t, testConfig{ FakeIDPOpts: []oidctest.FakeIDPOpt{ oidctest.WithMutateToken(func(token map[string]interface{}) { diff --git a/coderd/httpmw/actor_test.go b/coderd/httpmw/actor_test.go index fc9580166298e..ef05a8cb3a3d2 100644 --- a/coderd/httpmw/actor_test.go +++ b/coderd/httpmw/actor_test.go @@ -11,8 +11,8 @@ import ( "github.com/stretchr/testify/require" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" "github.com/coder/coder/v2/coderd/database/dbgen" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/httpmw" "github.com/coder/coder/v2/codersdk" @@ -38,7 +38,7 @@ func TestRequireAPIKeyOrWorkspaceProxyAuth(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() user = dbgen.User(t, db, database.User{}) _, token = dbgen.APIKey(t, db, database.APIKey{ UserID: user.ID, @@ -75,7 +75,7 @@ func TestRequireAPIKeyOrWorkspaceProxyAuth(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() user = dbgen.User(t, db, database.User{}) _, userToken = dbgen.APIKey(t, db, database.APIKey{ UserID: user.ID, @@ -114,7 +114,7 @@ func TestRequireAPIKeyOrWorkspaceProxyAuth(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() proxy, token = dbgen.WorkspaceProxy(t, db, database.WorkspaceProxy{}) r = httptest.NewRequest("GET", "/", nil) diff --git a/coderd/httpmw/apikey_test.go b/coderd/httpmw/apikey_test.go index f3ceba017d773..33ba90a4d728c 100644 --- a/coderd/httpmw/apikey_test.go +++ b/coderd/httpmw/apikey_test.go @@ -19,8 +19,8 @@ import ( "golang.org/x/oauth2" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" "github.com/coder/coder/v2/coderd/database/dbgen" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/httpapi" "github.com/coder/coder/v2/coderd/httpmw" @@ -48,7 +48,7 @@ func TestAPIKey(t *testing.T) { t.Run("NoCookie", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() r = httptest.NewRequest("GET", "/", nil) rw = httptest.NewRecorder() ) @@ -64,7 +64,7 @@ func TestAPIKey(t *testing.T) { t.Run("NoCookieRedirects", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() r = httptest.NewRequest("GET", "/", nil) rw = httptest.NewRecorder() ) @@ -83,7 +83,7 @@ func TestAPIKey(t *testing.T) { t.Run("InvalidFormat", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() r = httptest.NewRequest("GET", "/", nil) rw = httptest.NewRecorder() ) @@ -101,7 +101,7 @@ func TestAPIKey(t *testing.T) { t.Run("InvalidIDLength", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() r = httptest.NewRequest("GET", "/", nil) rw = httptest.NewRecorder() ) @@ -119,7 +119,7 @@ func TestAPIKey(t *testing.T) { t.Run("InvalidSecretLength", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() r = httptest.NewRequest("GET", "/", nil) rw = httptest.NewRecorder() ) @@ -137,7 +137,7 @@ func TestAPIKey(t *testing.T) { t.Run("NotFound", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() id, secret = randomAPIKeyParts() r = httptest.NewRequest("GET", "/", nil) rw = httptest.NewRecorder() @@ -156,7 +156,7 @@ func TestAPIKey(t *testing.T) { t.Run("UserLinkNotFound", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() r = httptest.NewRequest("GET", "/", nil) rw = httptest.NewRecorder() user = dbgen.User(t, db, database.User{ @@ -184,7 +184,7 @@ func TestAPIKey(t *testing.T) { t.Run("InvalidSecret", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() r = httptest.NewRequest("GET", "/", nil) rw = httptest.NewRecorder() user = dbgen.User(t, db, database.User{}) @@ -209,7 +209,7 @@ func TestAPIKey(t *testing.T) { t.Run("Expired", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() user = dbgen.User(t, db, database.User{}) _, token = dbgen.APIKey(t, db, database.APIKey{ UserID: user.ID, @@ -238,7 +238,7 @@ func TestAPIKey(t *testing.T) { t.Run("Valid", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() user = dbgen.User(t, db, database.User{}) sentAPIKey, token = dbgen.APIKey(t, db, database.APIKey{ UserID: user.ID, @@ -273,7 +273,7 @@ func TestAPIKey(t *testing.T) { t.Run("ValidWithScope", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() user = dbgen.User(t, db, database.User{}) _, token = dbgen.APIKey(t, db, database.APIKey{ UserID: user.ID, @@ -310,7 +310,7 @@ func TestAPIKey(t *testing.T) { t.Run("QueryParameter", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() user = dbgen.User(t, db, database.User{}) _, token = dbgen.APIKey(t, db, database.APIKey{ UserID: user.ID, @@ -342,7 +342,7 @@ func TestAPIKey(t *testing.T) { t.Run("ValidUpdateLastUsed", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() user = dbgen.User(t, db, database.User{}) sentAPIKey, token = dbgen.APIKey(t, db, database.APIKey{ UserID: user.ID, @@ -373,7 +373,7 @@ func TestAPIKey(t *testing.T) { t.Run("ValidUpdateExpiry", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() user = dbgen.User(t, db, database.User{}) sentAPIKey, token = dbgen.APIKey(t, db, database.APIKey{ UserID: user.ID, @@ -404,7 +404,7 @@ func TestAPIKey(t *testing.T) { t.Run("NoRefresh", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() user = dbgen.User(t, db, database.User{}) sentAPIKey, token = dbgen.APIKey(t, db, database.APIKey{ UserID: user.ID, @@ -436,7 +436,7 @@ func TestAPIKey(t *testing.T) { t.Run("OAuthNotExpired", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() user = dbgen.User(t, db, database.User{}) sentAPIKey, token = dbgen.APIKey(t, db, database.APIKey{ UserID: user.ID, @@ -472,7 +472,7 @@ func TestAPIKey(t *testing.T) { t.Run("OAuthRefresh", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() user = dbgen.User(t, db, database.User{}) sentAPIKey, token = dbgen.APIKey(t, db, database.APIKey{ UserID: user.ID, @@ -520,7 +520,7 @@ func TestAPIKey(t *testing.T) { t.Run("RemoteIPUpdates", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() user = dbgen.User(t, db, database.User{}) sentAPIKey, token = dbgen.APIKey(t, db, database.APIKey{ UserID: user.ID, @@ -551,7 +551,7 @@ func TestAPIKey(t *testing.T) { t.Run("RedirectToLogin", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() r = httptest.NewRequest("GET", "/", nil) rw = httptest.NewRecorder() ) @@ -572,7 +572,7 @@ func TestAPIKey(t *testing.T) { t.Run("Optional", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() r = httptest.NewRequest("GET", "/", nil) rw = httptest.NewRecorder() @@ -603,7 +603,7 @@ func TestAPIKey(t *testing.T) { t.Run("Tokens", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() user = dbgen.User(t, db, database.User{}) sentAPIKey, token = dbgen.APIKey(t, db, database.APIKey{ UserID: user.ID, @@ -636,7 +636,7 @@ func TestAPIKey(t *testing.T) { t.Run("MissongConfig", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() user = dbgen.User(t, db, database.User{}) _, token = dbgen.APIKey(t, db, database.APIKey{ UserID: user.ID, diff --git a/coderd/httpmw/groupparam_test.go b/coderd/httpmw/groupparam_test.go index a0c50ee0857b5..a44fbc52df38b 100644 --- a/coderd/httpmw/groupparam_test.go +++ b/coderd/httpmw/groupparam_test.go @@ -11,8 +11,8 @@ import ( "github.com/stretchr/testify/require" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" "github.com/coder/coder/v2/coderd/database/dbgen" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/httpmw" ) @@ -23,7 +23,7 @@ func TestGroupParam(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() group = dbgen.Group(t, db, database.Group{}) r = httptest.NewRequest("GET", "/", nil) w = httptest.NewRecorder() @@ -52,7 +52,7 @@ func TestGroupParam(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() group = dbgen.Group(t, db, database.Group{}) r = httptest.NewRequest("GET", "/", nil) w = httptest.NewRecorder() diff --git a/coderd/httpmw/organizationparam_test.go b/coderd/httpmw/organizationparam_test.go index 0457168132e9a..d492353e6815d 100644 --- a/coderd/httpmw/organizationparam_test.go +++ b/coderd/httpmw/organizationparam_test.go @@ -11,8 +11,8 @@ import ( "github.com/stretchr/testify/require" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" "github.com/coder/coder/v2/coderd/database/dbgen" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/httpmw" "github.com/coder/coder/v2/codersdk" @@ -38,7 +38,7 @@ func TestOrganizationParam(t *testing.T) { t.Run("None", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() rw = httptest.NewRecorder() r, _ = setupAuthentication(db) rtr = chi.NewRouter() @@ -60,7 +60,7 @@ func TestOrganizationParam(t *testing.T) { t.Run("NotFound", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() rw = httptest.NewRecorder() r, _ = setupAuthentication(db) rtr = chi.NewRouter() @@ -83,7 +83,7 @@ func TestOrganizationParam(t *testing.T) { t.Run("InvalidUUID", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() rw = httptest.NewRecorder() r, _ = setupAuthentication(db) rtr = chi.NewRouter() @@ -106,7 +106,7 @@ func TestOrganizationParam(t *testing.T) { t.Run("NotInOrganization", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() rw = httptest.NewRecorder() r, u = setupAuthentication(db) rtr = chi.NewRouter() @@ -139,7 +139,7 @@ func TestOrganizationParam(t *testing.T) { t.Run("Success", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() rw = httptest.NewRecorder() r, user = setupAuthentication(db) rtr = chi.NewRouter() diff --git a/coderd/httpmw/ratelimit_test.go b/coderd/httpmw/ratelimit_test.go index edb368829cf37..a320e05af7ffe 100644 --- a/coderd/httpmw/ratelimit_test.go +++ b/coderd/httpmw/ratelimit_test.go @@ -13,8 +13,8 @@ import ( "github.com/stretchr/testify/require" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" "github.com/coder/coder/v2/coderd/database/dbgen" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/httpmw" "github.com/coder/coder/v2/coderd/rbac" "github.com/coder/coder/v2/codersdk" @@ -71,7 +71,7 @@ func TestRateLimit(t *testing.T) { t.Run("RegularUser", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() u := dbgen.User(t, db, database.User{}) _, key := dbgen.APIKey(t, db, database.APIKey{UserID: u.ID}) @@ -114,7 +114,7 @@ func TestRateLimit(t *testing.T) { t.Run("OwnerBypass", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() u := dbgen.User(t, db, database.User{ RBACRoles: []string{rbac.RoleOwner()}, diff --git a/coderd/httpmw/templateparam_test.go b/coderd/httpmw/templateparam_test.go index d8608781905d5..18b0b2f584e5f 100644 --- a/coderd/httpmw/templateparam_test.go +++ b/coderd/httpmw/templateparam_test.go @@ -11,8 +11,8 @@ import ( "github.com/stretchr/testify/require" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" "github.com/coder/coder/v2/coderd/database/dbgen" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/httpmw" "github.com/coder/coder/v2/codersdk" ) @@ -43,7 +43,7 @@ func TestTemplateParam(t *testing.T) { t.Run("None", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() rtr := chi.NewRouter() rtr.Use(httpmw.ExtractTemplateParam(db)) rtr.Get("/", nil) @@ -58,7 +58,7 @@ func TestTemplateParam(t *testing.T) { t.Run("NotFound", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() rtr := chi.NewRouter() rtr.Use(httpmw.ExtractTemplateParam(db)) rtr.Get("/", nil) @@ -75,7 +75,7 @@ func TestTemplateParam(t *testing.T) { t.Run("BadUUID", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() rtr := chi.NewRouter() rtr.Use(httpmw.ExtractTemplateParam(db)) rtr.Get("/", nil) @@ -92,7 +92,7 @@ func TestTemplateParam(t *testing.T) { t.Run("Template", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() rtr := chi.NewRouter() rtr.Use( httpmw.ExtractAPIKeyMW(httpmw.ExtractAPIKeyConfig{ diff --git a/coderd/httpmw/templateversionparam_test.go b/coderd/httpmw/templateversionparam_test.go index 1cf4da6e832b0..3f67aafbcf191 100644 --- a/coderd/httpmw/templateversionparam_test.go +++ b/coderd/httpmw/templateversionparam_test.go @@ -11,8 +11,8 @@ import ( "github.com/stretchr/testify/require" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" "github.com/coder/coder/v2/coderd/database/dbgen" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/httpmw" "github.com/coder/coder/v2/codersdk" ) @@ -47,7 +47,7 @@ func TestTemplateVersionParam(t *testing.T) { t.Run("None", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() rtr := chi.NewRouter() rtr.Use(httpmw.ExtractTemplateVersionParam(db)) rtr.Get("/", nil) @@ -62,7 +62,7 @@ func TestTemplateVersionParam(t *testing.T) { t.Run("NotFound", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() rtr := chi.NewRouter() rtr.Use(httpmw.ExtractTemplateVersionParam(db)) rtr.Get("/", nil) @@ -79,7 +79,7 @@ func TestTemplateVersionParam(t *testing.T) { t.Run("TemplateVersion", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() rtr := chi.NewRouter() rtr.Use( httpmw.ExtractAPIKeyMW(httpmw.ExtractAPIKeyConfig{ diff --git a/coderd/httpmw/userparam_test.go b/coderd/httpmw/userparam_test.go index 040948ff60cf3..bda00193e9a24 100644 --- a/coderd/httpmw/userparam_test.go +++ b/coderd/httpmw/userparam_test.go @@ -10,8 +10,8 @@ import ( "github.com/stretchr/testify/require" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" "github.com/coder/coder/v2/coderd/database/dbgen" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/httpmw" "github.com/coder/coder/v2/codersdk" ) @@ -20,7 +20,7 @@ func TestUserParam(t *testing.T) { t.Parallel() setup := func(t *testing.T) (database.Store, *httptest.ResponseRecorder, *http.Request) { var ( - db = dbfake.New() + db = dbmem.New() r = httptest.NewRequest("GET", "/", nil) rw = httptest.NewRecorder() ) diff --git a/coderd/httpmw/workspaceagentparam_test.go b/coderd/httpmw/workspaceagentparam_test.go index 0ac2bb9eb01b9..16f81124d12d7 100644 --- a/coderd/httpmw/workspaceagentparam_test.go +++ b/coderd/httpmw/workspaceagentparam_test.go @@ -11,8 +11,8 @@ import ( "github.com/stretchr/testify/require" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" "github.com/coder/coder/v2/coderd/database/dbgen" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/httpmw" "github.com/coder/coder/v2/codersdk" ) @@ -61,7 +61,7 @@ func TestWorkspaceAgentParam(t *testing.T) { t.Run("None", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() rtr := chi.NewRouter() rtr.Use(httpmw.ExtractWorkspaceBuildParam(db)) rtr.Get("/", nil) @@ -76,7 +76,7 @@ func TestWorkspaceAgentParam(t *testing.T) { t.Run("NotFound", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() rtr := chi.NewRouter() rtr.Use(httpmw.ExtractWorkspaceAgentParam(db)) rtr.Get("/", nil) @@ -93,7 +93,7 @@ func TestWorkspaceAgentParam(t *testing.T) { t.Run("WorkspaceAgent", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() rtr := chi.NewRouter() rtr.Use( httpmw.ExtractAPIKeyMW(httpmw.ExtractAPIKeyConfig{ diff --git a/coderd/httpmw/workspacebuildparam_test.go b/coderd/httpmw/workspacebuildparam_test.go index bade2b19d8dfc..fb2d2f044f77f 100644 --- a/coderd/httpmw/workspacebuildparam_test.go +++ b/coderd/httpmw/workspacebuildparam_test.go @@ -11,8 +11,8 @@ import ( "github.com/stretchr/testify/require" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" "github.com/coder/coder/v2/coderd/database/dbgen" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/httpmw" "github.com/coder/coder/v2/codersdk" ) @@ -43,7 +43,7 @@ func TestWorkspaceBuildParam(t *testing.T) { t.Run("None", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() rtr := chi.NewRouter() rtr.Use(httpmw.ExtractWorkspaceBuildParam(db)) rtr.Get("/", nil) @@ -58,7 +58,7 @@ func TestWorkspaceBuildParam(t *testing.T) { t.Run("NotFound", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() rtr := chi.NewRouter() rtr.Use(httpmw.ExtractWorkspaceBuildParam(db)) rtr.Get("/", nil) @@ -75,7 +75,7 @@ func TestWorkspaceBuildParam(t *testing.T) { t.Run("WorkspaceBuild", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() rtr := chi.NewRouter() rtr.Use( httpmw.ExtractAPIKeyMW(httpmw.ExtractAPIKeyConfig{ diff --git a/coderd/httpmw/workspaceparam_test.go b/coderd/httpmw/workspaceparam_test.go index d65fb53f8f28d..54daf661c39c8 100644 --- a/coderd/httpmw/workspaceparam_test.go +++ b/coderd/httpmw/workspaceparam_test.go @@ -16,8 +16,8 @@ import ( "github.com/stretchr/testify/require" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" "github.com/coder/coder/v2/coderd/database/dbgen" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/httpmw" "github.com/coder/coder/v2/codersdk" @@ -75,7 +75,7 @@ func TestWorkspaceParam(t *testing.T) { t.Run("None", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() rtr := chi.NewRouter() rtr.Use(httpmw.ExtractWorkspaceParam(db)) rtr.Get("/", nil) @@ -90,7 +90,7 @@ func TestWorkspaceParam(t *testing.T) { t.Run("NotFound", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() rtr := chi.NewRouter() rtr.Use(httpmw.ExtractWorkspaceParam(db)) rtr.Get("/", nil) @@ -106,7 +106,7 @@ func TestWorkspaceParam(t *testing.T) { t.Run("Found", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() rtr := chi.NewRouter() rtr.Use( httpmw.ExtractAPIKeyMW(httpmw.ExtractAPIKeyConfig{ @@ -348,7 +348,7 @@ type setupConfig struct { func setupWorkspaceWithAgents(t testing.TB, cfg setupConfig) (database.Store, *http.Request) { t.Helper() - db := dbfake.New() + db := dbmem.New() var ( user = dbgen.User(t, db, database.User{}) diff --git a/coderd/httpmw/workspaceproxy_test.go b/coderd/httpmw/workspaceproxy_test.go index 27b85643ce43d..b0a028f3caee8 100644 --- a/coderd/httpmw/workspaceproxy_test.go +++ b/coderd/httpmw/workspaceproxy_test.go @@ -12,8 +12,8 @@ import ( "github.com/stretchr/testify/require" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" "github.com/coder/coder/v2/coderd/database/dbgen" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/httpapi" "github.com/coder/coder/v2/coderd/httpmw" "github.com/coder/coder/v2/codersdk" @@ -33,7 +33,7 @@ func TestExtractWorkspaceProxy(t *testing.T) { t.Run("NoHeader", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() r = httptest.NewRequest("GET", "/", nil) rw = httptest.NewRecorder() ) @@ -48,7 +48,7 @@ func TestExtractWorkspaceProxy(t *testing.T) { t.Run("InvalidFormat", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() r = httptest.NewRequest("GET", "/", nil) rw = httptest.NewRecorder() ) @@ -65,7 +65,7 @@ func TestExtractWorkspaceProxy(t *testing.T) { t.Run("InvalidID", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() r = httptest.NewRequest("GET", "/", nil) rw = httptest.NewRecorder() ) @@ -82,7 +82,7 @@ func TestExtractWorkspaceProxy(t *testing.T) { t.Run("InvalidSecretLength", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() r = httptest.NewRequest("GET", "/", nil) rw = httptest.NewRecorder() ) @@ -99,7 +99,7 @@ func TestExtractWorkspaceProxy(t *testing.T) { t.Run("NotFound", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() r = httptest.NewRequest("GET", "/", nil) rw = httptest.NewRecorder() ) @@ -119,7 +119,7 @@ func TestExtractWorkspaceProxy(t *testing.T) { t.Run("InvalidSecret", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() r = httptest.NewRequest("GET", "/", nil) rw = httptest.NewRecorder() @@ -142,7 +142,7 @@ func TestExtractWorkspaceProxy(t *testing.T) { t.Run("Valid", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() r = httptest.NewRequest("GET", "/", nil) rw = httptest.NewRecorder() @@ -165,7 +165,7 @@ func TestExtractWorkspaceProxy(t *testing.T) { t.Run("Deleted", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() r = httptest.NewRequest("GET", "/", nil) rw = httptest.NewRecorder() @@ -201,7 +201,7 @@ func TestExtractWorkspaceProxyParam(t *testing.T) { t.Run("OKName", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() r = httptest.NewRequest("GET", "/", nil) rw = httptest.NewRecorder() @@ -225,7 +225,7 @@ func TestExtractWorkspaceProxyParam(t *testing.T) { t.Run("OKID", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() r = httptest.NewRequest("GET", "/", nil) rw = httptest.NewRecorder() @@ -249,7 +249,7 @@ func TestExtractWorkspaceProxyParam(t *testing.T) { t.Run("NotFound", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() r = httptest.NewRequest("GET", "/", nil) rw = httptest.NewRecorder() ) @@ -267,7 +267,7 @@ func TestExtractWorkspaceProxyParam(t *testing.T) { t.Run("FetchPrimary", func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() r = httptest.NewRequest("GET", "/", nil) rw = httptest.NewRecorder() deploymentID = uuid.New() diff --git a/coderd/httpmw/workspaceresourceparam_test.go b/coderd/httpmw/workspaceresourceparam_test.go index e61e4016cb261..9549e8e6d3ecf 100644 --- a/coderd/httpmw/workspaceresourceparam_test.go +++ b/coderd/httpmw/workspaceresourceparam_test.go @@ -11,8 +11,8 @@ import ( "github.com/stretchr/testify/require" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" "github.com/coder/coder/v2/coderd/database/dbgen" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/httpmw" ) @@ -46,7 +46,7 @@ func TestWorkspaceResourceParam(t *testing.T) { t.Run("None", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() rtr := chi.NewRouter() rtr.Use(httpmw.ExtractWorkspaceResourceParam(db)) rtr.Get("/", nil) @@ -61,7 +61,7 @@ func TestWorkspaceResourceParam(t *testing.T) { t.Run("NotFound", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() rtr := chi.NewRouter() rtr.Use( httpmw.ExtractWorkspaceResourceParam(db), @@ -80,7 +80,7 @@ func TestWorkspaceResourceParam(t *testing.T) { t.Run("FoundBadJobType", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() rtr := chi.NewRouter() rtr.Use( httpmw.ExtractWorkspaceResourceParam(db), @@ -102,7 +102,7 @@ func TestWorkspaceResourceParam(t *testing.T) { t.Run("Found", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() rtr := chi.NewRouter() rtr.Use( httpmw.ExtractWorkspaceResourceParam(db), diff --git a/coderd/metricscache/metricscache_test.go b/coderd/metricscache/metricscache_test.go index 1d34668559b32..996b9940d0056 100644 --- a/coderd/metricscache/metricscache_test.go +++ b/coderd/metricscache/metricscache_test.go @@ -11,8 +11,8 @@ import ( "cdr.dev/slog/sloggers/slogtest" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" "github.com/coder/coder/v2/coderd/database/dbgen" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/metricscache" "github.com/coder/coder/v2/codersdk" @@ -210,7 +210,7 @@ func TestCache_TemplateUsers(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() var ( - db = dbfake.New() + db = dbmem.New() cache = metricscache.New(db, slogtest.Make(t, nil), metricscache.Intervals{ TemplateDAUs: testutil.IntervalFast, }) @@ -342,7 +342,7 @@ func TestCache_BuildTime(t *testing.T) { ctx := context.Background() var ( - db = dbfake.New() + db = dbmem.New() cache = metricscache.New(db, slogtest.Make(t, nil), metricscache.Intervals{ TemplateDAUs: testutil.IntervalFast, }) @@ -436,7 +436,7 @@ func TestCache_BuildTime(t *testing.T) { func TestCache_DeploymentStats(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() cache := metricscache.New(db, slogtest.Make(t, nil), metricscache.Intervals{ DeploymentStats: testutil.IntervalFast, }) diff --git a/coderd/prometheusmetrics/prometheusmetrics_test.go b/coderd/prometheusmetrics/prometheusmetrics_test.go index fb00ced6d9548..8256c2f7e2e90 100644 --- a/coderd/prometheusmetrics/prometheusmetrics_test.go +++ b/coderd/prometheusmetrics/prometheusmetrics_test.go @@ -26,8 +26,8 @@ import ( "github.com/coder/coder/v2/coderd/coderdtest" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" "github.com/coder/coder/v2/coderd/database/dbgen" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/prometheusmetrics" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/codersdk/agentsdk" @@ -48,13 +48,13 @@ func TestActiveUsers(t *testing.T) { }{{ Name: "None", Database: func(t *testing.T) database.Store { - return dbfake.New() + return dbmem.New() }, Count: 0, }, { Name: "One", Database: func(t *testing.T) database.Store { - db := dbfake.New() + db := dbmem.New() dbgen.APIKey(t, db, database.APIKey{ LastUsed: dbtime.Now(), }) @@ -64,7 +64,7 @@ func TestActiveUsers(t *testing.T) { }, { Name: "OneWithExpired", Database: func(t *testing.T) database.Store { - db := dbfake.New() + db := dbmem.New() dbgen.APIKey(t, db, database.APIKey{ LastUsed: dbtime.Now(), @@ -81,7 +81,7 @@ func TestActiveUsers(t *testing.T) { }, { Name: "Multiple", Database: func(t *testing.T) database.Store { - db := dbfake.New() + db := dbmem.New() dbgen.APIKey(t, db, database.APIKey{ LastUsed: dbtime.Now(), }) @@ -200,13 +200,13 @@ func TestWorkspaces(t *testing.T) { }{{ Name: "None", Database: func() database.Store { - return dbfake.New() + return dbmem.New() }, Total: 0, }, { Name: "Multiple", Database: func() database.Store { - db := dbfake.New() + db := dbmem.New() insertCanceled(db) insertFailed(db) insertFailed(db) diff --git a/coderd/provisionerdserver/acquirer_test.go b/coderd/provisionerdserver/acquirer_test.go index 7036df817b264..bed8eccb68aca 100644 --- a/coderd/provisionerdserver/acquirer_test.go +++ b/coderd/provisionerdserver/acquirer_test.go @@ -17,7 +17,7 @@ import ( "cdr.dev/slog" "cdr.dev/slog/sloggers/slogtest" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/provisionerjobs" "github.com/coder/coder/v2/coderd/database/pubsub" "github.com/coder/coder/v2/coderd/provisionerdserver" @@ -31,7 +31,7 @@ func TestMain(m *testing.M) { // TestAcquirer_Store tests that a database.Store is accepted as a provisionerdserver.AcquirerStore func TestAcquirer_Store(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() ps := pubsub.NewInMemory() ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort) defer cancel() diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go index 38038df49dd90..6465eab1d9fe9 100644 --- a/coderd/provisionerdserver/provisionerdserver.go +++ b/coderd/provisionerdserver/provisionerdserver.go @@ -1206,6 +1206,13 @@ func (s *server) CompleteJob(ctx context.Context, completed *proto.CompletedJob) case <-wait: // Wait for the next potential timeout to occur. if err := s.Pubsub.Publish(codersdk.WorkspaceNotifyChannel(workspaceBuild.WorkspaceID), []byte{}); err != nil { + if s.lifecycleCtx.Err() != nil { + // If the server is shutting down, we don't want to log this error, nor wait around. + s.Logger.Debug(ctx, "stopping notifications due to server shutdown", + slog.F("workspace_build_id", workspaceBuild.ID), + ) + return + } s.Logger.Error(ctx, "workspace notification after agent timeout failed", slog.F("workspace_build_id", workspaceBuild.ID), slog.Error(err), diff --git a/coderd/provisionerdserver/provisionerdserver_internal_test.go b/coderd/provisionerdserver/provisionerdserver_internal_test.go index 427a1c428b4fa..acf9508307070 100644 --- a/coderd/provisionerdserver/provisionerdserver_internal_test.go +++ b/coderd/provisionerdserver/provisionerdserver_internal_test.go @@ -10,8 +10,8 @@ import ( "golang.org/x/oauth2" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" "github.com/coder/coder/v2/coderd/database/dbgen" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/testutil" ) @@ -21,14 +21,14 @@ func TestObtainOIDCAccessToken(t *testing.T) { ctx := context.Background() t.Run("NoToken", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() _, err := obtainOIDCAccessToken(ctx, db, nil, uuid.Nil) require.NoError(t, err) }) t.Run("InvalidConfig", func(t *testing.T) { // We still want OIDC to succeed even if exchanging the token fails. t.Parallel() - db := dbfake.New() + db := dbmem.New() user := dbgen.User(t, db, database.User{}) dbgen.UserLink(t, db, database.UserLink{ UserID: user.ID, @@ -40,7 +40,7 @@ func TestObtainOIDCAccessToken(t *testing.T) { }) t.Run("Exchange", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() user := dbgen.User(t, db, database.User{}) dbgen.UserLink(t, db, database.UserLink{ UserID: user.ID, diff --git a/coderd/provisionerdserver/provisionerdserver_test.go b/coderd/provisionerdserver/provisionerdserver_test.go index db97724c72987..bc16b01c1e8cf 100644 --- a/coderd/provisionerdserver/provisionerdserver_test.go +++ b/coderd/provisionerdserver/provisionerdserver_test.go @@ -27,8 +27,8 @@ import ( "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/coderd/audit" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" "github.com/coder/coder/v2/coderd/database/dbgen" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/database/pubsub" "github.com/coder/coder/v2/coderd/externalauth" @@ -1525,7 +1525,7 @@ func TestInsertWorkspaceResource(t *testing.T) { } t.Run("NoAgents", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() job := uuid.New() err := insert(db, job, &sdkproto.Resource{ Name: "something", @@ -1538,7 +1538,7 @@ func TestInsertWorkspaceResource(t *testing.T) { }) t.Run("InvalidAgentToken", func(t *testing.T) { t.Parallel() - err := insert(dbfake.New(), uuid.New(), &sdkproto.Resource{ + err := insert(dbmem.New(), uuid.New(), &sdkproto.Resource{ Name: "something", Type: "aws_instance", Agents: []*sdkproto.Agent{{ @@ -1551,7 +1551,7 @@ func TestInsertWorkspaceResource(t *testing.T) { }) t.Run("DuplicateApps", func(t *testing.T) { t.Parallel() - err := insert(dbfake.New(), uuid.New(), &sdkproto.Resource{ + err := insert(dbmem.New(), uuid.New(), &sdkproto.Resource{ Name: "something", Type: "aws_instance", Agents: []*sdkproto.Agent{{ @@ -1566,7 +1566,7 @@ func TestInsertWorkspaceResource(t *testing.T) { }) t.Run("Success", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() job := uuid.New() err := insert(db, job, &sdkproto.Resource{ Name: "something", @@ -1623,7 +1623,7 @@ func TestInsertWorkspaceResource(t *testing.T) { t.Run("AllDisplayApps", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() job := uuid.New() err := insert(db, job, &sdkproto.Resource{ Name: "something", @@ -1651,7 +1651,7 @@ func TestInsertWorkspaceResource(t *testing.T) { t.Run("DisableDefaultApps", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() job := uuid.New() err := insert(db, job, &sdkproto.Resource{ Name: "something", @@ -1689,7 +1689,7 @@ func setup(t *testing.T, ignoreLogErrors bool, ov *overrides) (proto.DRPCProvisi ctx, cancel := context.WithCancel(context.Background()) t.Cleanup(cancel) logger := slogtest.Make(t, nil).Leveled(slog.LevelDebug) - db := dbfake.New() + db := dbmem.New() ps := pubsub.NewInMemory() deploymentValues := &codersdk.DeploymentValues{} var externalAuthConfigs []*externalauth.Config diff --git a/coderd/telemetry/telemetry_test.go b/coderd/telemetry/telemetry_test.go index cec216564b99b..5df6be77f763e 100644 --- a/coderd/telemetry/telemetry_test.go +++ b/coderd/telemetry/telemetry_test.go @@ -18,8 +18,8 @@ import ( "cdr.dev/slog/sloggers/slogtest" "github.com/coder/coder/v2/buildinfo" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" "github.com/coder/coder/v2/coderd/database/dbgen" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/telemetry" "github.com/coder/coder/v2/testutil" @@ -36,7 +36,7 @@ func TestTelemetry(t *testing.T) { var err error - db := dbfake.New() + db := dbmem.New() ctx := testutil.Context(t, testutil.WaitMedium) _, _ = dbgen.APIKey(t, db, database.APIKey{}) @@ -106,7 +106,7 @@ func TestTelemetry(t *testing.T) { }) t.Run("HashedEmail", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() _ = dbgen.User(t, db, database.User{ Email: "kyle@coder.com", }) @@ -119,7 +119,7 @@ func TestTelemetry(t *testing.T) { // nolint:paralleltest func TestTelemetryInstallSource(t *testing.T) { t.Setenv("CODER_TELEMETRY_INSTALL_SOURCE", "aws_marketplace") - db := dbfake.New() + db := dbmem.New() deployment, _ := collectSnapshot(t, db) require.Equal(t, "aws_marketplace", deployment.InstallSource) } diff --git a/coderd/updatecheck/updatecheck_test.go b/coderd/updatecheck/updatecheck_test.go index 103064eb7e6de..afc0f57cbdd41 100644 --- a/coderd/updatecheck/updatecheck_test.go +++ b/coderd/updatecheck/updatecheck_test.go @@ -14,7 +14,7 @@ import ( "cdr.dev/slog/sloggers/slogtest" - "github.com/coder/coder/v2/coderd/database/dbfake" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/updatecheck" "github.com/coder/coder/v2/testutil" ) @@ -49,7 +49,7 @@ func TestChecker_Notify(t *testing.T) { })) defer srv.Close() - db := dbfake.New() + db := dbmem.New() logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true}).Named(t.Name()) notify := make(chan updatecheck.Result, len(wantVersion)) c := updatecheck.New(db, logger, updatecheck.Options{ @@ -131,7 +131,7 @@ func TestChecker_Latest(t *testing.T) { })) defer srv.Close() - db := dbfake.New() + db := dbmem.New() logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true}).Named(t.Name()) c := updatecheck.New(db, logger, updatecheck.Options{ URL: srv.URL, diff --git a/coderd/workspacebuilds_test.go b/coderd/workspacebuilds_test.go index 1f487e6915d40..0978a1743affd 100644 --- a/coderd/workspacebuilds_test.go +++ b/coderd/workspacebuilds_test.go @@ -48,14 +48,12 @@ func TestWorkspaceBuild(t *testing.T) { coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) auditor.ResetLogs() workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) - - ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) - defer cancel() - - _, err := client.WorkspaceBuild(ctx, workspace.LatestBuild.ID) - require.NoError(t, err) - require.Len(t, auditor.AuditLogs(), 1) + _ = coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) + // Create workspace will also start a build, so we need to wait for + // it to ensure all events are recorded. + require.Len(t, auditor.AuditLogs(), 2) require.Equal(t, auditor.AuditLogs()[0].Ip.IPNet.IP.String(), "127.0.0.1") + require.Equal(t, auditor.AuditLogs()[1].Ip.IPNet.IP.String(), "127.0.0.1") } func TestWorkspaceBuildByBuildNumber(t *testing.T) { diff --git a/codersdk/deployment_test.go b/codersdk/deployment_test.go index 7cecc288512ca..d6846557cd9cc 100644 --- a/codersdk/deployment_test.go +++ b/codersdk/deployment_test.go @@ -209,25 +209,26 @@ func TestTimezoneOffsets(t *testing.T) { ExpectedOffset int }{ { - Name: "UTX", + Name: "UTC", Loc: time.UTC, ExpectedOffset: 0, }, - { - Name: "Eastern", - Loc: must(time.LoadLocation("America/New_York")), - ExpectedOffset: -4, - }, - { - Name: "Central", - Loc: must(time.LoadLocation("America/Chicago")), - ExpectedOffset: -5, - }, - { - Name: "Ireland", - Loc: must(time.LoadLocation("Europe/Dublin")), - ExpectedOffset: 1, - }, + // The following test cases are broken re: daylight savings + //{ + // Name: "Eastern", + // Loc: must(time.LoadLocation("America/New_York")), + // ExpectedOffset: -4, + //}, + //{ + // Name: "Central", + // Loc: must(time.LoadLocation("America/Chicago")), + // ExpectedOffset: -5, + //}, + //{ + // Name: "Ireland", + // Loc: must(time.LoadLocation("Europe/Dublin")), + // ExpectedOffset: 1, + //}, { Name: "HalfHourTz", // This timezone is +6:30, but the function rounds to the nearest hour. diff --git a/docs/changelogs/README.md b/docs/changelogs/README.md index 1dc1c8c5a18a6..753c7ecbd5abb 100644 --- a/docs/changelogs/README.md +++ b/docs/changelogs/README.md @@ -13,8 +13,8 @@ git checkout main; git pull; git fetch --all export CODER_IGNORE_MISSING_COMMIT_METADATA=1 export BRANCH=main ./scripts/release/generate_release_notes.sh \ - --old-version=v2.3.0 \ - --new-version=v2.3.1 \ + --old-version=v2.3.3 \ + --new-version=v2.3.4 \ --ref=$(git rev-parse --short "${ref:-origin/$BRANCH}") \ - > ./docs/changelogs/v2.3.1.md + > ./docs/changelogs/v2.3.4.md ``` diff --git a/docs/changelogs/v2.3.2.md b/docs/changelogs/v2.3.2.md new file mode 100644 index 0000000000000..373914ac0a5de --- /dev/null +++ b/docs/changelogs/v2.3.2.md @@ -0,0 +1,37 @@ +## Changelog + +### Important features + +- Moved workspace cleanup to an experimental feature (#10363) (@sreya) + +### Features + +- Add telemetry for external provisioners (#10322) (@coadler) +- Expose template insights as Prometheus metrics (#10325) (@mtojek) +- Add user groups column to users table (#10284) (@Parkreiner) +- Add cli support for `--require-active-version` (#10337) (@sreya) +- Add frontend support for mandating active template version (#10338) (@sreya) + +### Bug fixes + +- Add requester IP to workspace build audit logs (#10242) (@coadler) +- Resolve User is not unauthenticated error seen on logout (#10349) (@Kira-Pilot) +- Show dormant and suspended users in groups (#10333) (@Kira-Pilot) +- Fix additional cluster SA, role names (#10366) (@ericpaulsen) +- Update external-auth docs to use `coder_external_auth` (#10347) (@matifali) +- b8c7b56fd fix(site): fix tabs in the template layout (#10334) (@BrunoQuaresma) + +### Documentation + +- Update vscode web docs (#10327) (@matifali) +- Rework telemetry doc and add CLI warning (#10354) (@ammario) + +Compare: [`v2.3.1...v2.3.2`](https://github.com/coder/coder/compare/v2.3.1...v2.3.2) + +## Container image + +- `docker pull ghcr.io/coder/coder:v2.3.2` + +## Install/upgrade + +Refer to our docs to [install](https://coder.com/docs/v2/latest/install) or [upgrade](https://coder.com/docs/v2/latest/admin/upgrade) Coder, or use a release asset below. diff --git a/docs/changelogs/v2.3.3.md b/docs/changelogs/v2.3.3.md new file mode 100644 index 0000000000000..9460703a6df7a --- /dev/null +++ b/docs/changelogs/v2.3.3.md @@ -0,0 +1,43 @@ +## Changelog + +### Features + +- Make the dotfiles repository directory configurable for `coder dotfiles` (#10377) (@JoshVee) +- Expose template version to provisioner (#10306) (@JoshVee) + +### Bug fixes + +- Initialize terminal with correct size (#10369) (@code-asher) +- Disable tests broken by daylight savings (#10414) (@spikecurtis) +- Add new aws regions to instance identity (#10434) (@kylecarbs) +- Prevent infinite redirect oauth auth flow (#10430) (@Emyrk) +- Prevent metadata from being discarded if report is slow (#10386) (@mafredri) +- Track cron run and wait for cron stop (#10388) (@mafredri) +- Display informative error for ErrWaitDelay (#10407) (@mafredri) +- Avoid error log during shutdown (#10402) (@mafredri) +- Update installation link (#10275) (@devarshishimpi) + +### Tests + +- 8f1b4fb06 test(agent): fix service banner trim test flake (#10384) (@mafredri) +- 1286904de test(agent): improve TestAgent_Session_TTY_MOTD_Update (#10385) (@mafredri) +- eac155aec test(cli): fix TestServer flake due to DNS lookup (#10390) (@mafredri) +- 9d3785def test(cli/cliui): make agent tests more robust (#10415) (@mafredri) +- 6683ad989 test(coderd): fix TestWorkspaceBuild flake (#10387) (@mafredri) + +### Continuous integration + +- 39fbf74c7 ci: bump the github-actions group with 1 update (#10379) (@app/dependabot) +- 6b7858c51 ci: bump the github-actions group with 2 updates (#10420) (@app/dependabot) + +### Chores + +Compare: [`v2.3.2...v2.3.3`](https://github.com/coder/coder/compare/v2.3.2...v2.3.3) + +## Container image + +- `docker pull ghcr.io/coder/coder:v2.3.3` + +## Install/upgrade + +Refer to our docs to [install](https://coder.com/docs/v2/latest/install) or [upgrade](https://coder.com/docs/v2/latest/admin/upgrade) Coder, or use a release asset below. diff --git a/docs/cli/dotfiles.md b/docs/cli/dotfiles.md index 59446a8b84d77..2ed5ab1525cb0 100644 --- a/docs/cli/dotfiles.md +++ b/docs/cli/dotfiles.md @@ -28,6 +28,16 @@ coder dotfiles [flags] Specifies which branch to clone. If empty, will default to cloning the default branch or using the existing branch in the cloned repo on disk. +### --repo-dir + +| | | +| ----------- | ------------------------------------- | +| Type | string | +| Environment | $CODER_DOTFILES_REPO_DIR | +| Default | dotfiles | + +Specifies the directory for the dotfiles repository, relative to global config directory. + ### --symlink-dir | | | diff --git a/docs/templates/open-in-coder.md b/docs/templates/open-in-coder.md index a2478d233685b..936c04681a446 100644 --- a/docs/templates/open-in-coder.md +++ b/docs/templates/open-in-coder.md @@ -20,8 +20,8 @@ authentication in your Coder deployment. ### 2. Modify your template to auto-clone repos -The id in the template's `coder_git_auth` data source must match the -`CODER_GITAUTH_0_ID` in the Coder deployment configuration. +The id in the template's `coder_external_auth` data source must match the +`CODER_EXTERNAL_AUTH_X_ID` in the Coder deployment configuration. If you want the template to clone a specific git repo: diff --git a/enterprise/audit/audit_test.go b/enterprise/audit/audit_test.go index b4f5e0f2aab89..6d825306c3346 100644 --- a/enterprise/audit/audit_test.go +++ b/enterprise/audit/audit_test.go @@ -8,7 +8,7 @@ import ( "golang.org/x/xerrors" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/enterprise/audit" "github.com/coder/coder/v2/enterprise/audit/audittest" ) @@ -91,7 +91,7 @@ func TestAuditor(t *testing.T) { var ( backend = &testBackend{decision: test.backendDecision, err: test.backendError} exporter = audit.NewAuditor( - dbfake.New(), + dbmem.New(), audit.FilterFunc(func(_ context.Context, _ database.AuditLog) (audit.FilterDecision, error) { return test.filterDecision, test.filterError }), diff --git a/enterprise/audit/backends/postgres_test.go b/enterprise/audit/backends/postgres_test.go index b3fa1f31d0cbd..f566db9cb507b 100644 --- a/enterprise/audit/backends/postgres_test.go +++ b/enterprise/audit/backends/postgres_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/enterprise/audit" "github.com/coder/coder/v2/enterprise/audit/audittest" "github.com/coder/coder/v2/enterprise/audit/backends" @@ -20,7 +20,7 @@ func TestPostgresBackend(t *testing.T) { var ( ctx, cancel = context.WithCancel(context.Background()) - db = dbfake.New() + db = dbmem.New() pgb = backends.NewPostgres(db, true) alog = audittest.RandomLog() ) diff --git a/enterprise/coderd/coderd_test.go b/enterprise/coderd/coderd_test.go index 873618842b4f8..855ecef059c75 100644 --- a/enterprise/coderd/coderd_test.go +++ b/enterprise/coderd/coderd_test.go @@ -17,7 +17,7 @@ import ( "github.com/coder/coder/v2/coderd/coderdtest" "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/dbauthz" - "github.com/coder/coder/v2/coderd/database/dbfake" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/rbac" @@ -191,7 +191,7 @@ func TestAuditLogging(t *testing.T) { _, _, api, _ := coderdenttest.NewWithAPI(t, &coderdenttest.Options{ AuditLogging: true, Options: &coderdtest.Options{ - Auditor: audit.NewAuditor(dbfake.New(), audit.DefaultFilter), + Auditor: audit.NewAuditor(dbmem.New(), audit.DefaultFilter), }, LicenseOptions: &coderdenttest.LicenseOptions{ Features: license.Features{ @@ -200,7 +200,7 @@ func TestAuditLogging(t *testing.T) { }, }) auditor := *api.AGPL.Auditor.Load() - ea := audit.NewAuditor(dbfake.New(), audit.DefaultFilter) + ea := audit.NewAuditor(dbmem.New(), audit.DefaultFilter) t.Logf("%T = %T", auditor, ea) assert.EqualValues(t, reflect.ValueOf(ea).Type(), reflect.ValueOf(auditor).Type()) }) diff --git a/enterprise/coderd/coderdenttest/coderdenttest.go b/enterprise/coderd/coderdenttest/coderdenttest.go index 1c3f7c4fc83e0..26e3bfaef22d6 100644 --- a/enterprise/coderd/coderdenttest/coderdenttest.go +++ b/enterprise/coderd/coderdenttest/coderdenttest.go @@ -10,7 +10,7 @@ import ( "testing" "time" - "github.com/coder/coder/v2/coderd/database/dbfake" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/pubsub" "github.com/golang-jwt/jwt/v4" @@ -133,8 +133,8 @@ func NewWithAPI(t *testing.T, options *Options) ( // we check for the in-memory test types so that the real types don't have to exported _, ok := coderAPI.Pubsub.(*pubsub.MemoryPubsub) require.False(t, ok, "FeatureHighAvailability is incompatible with MemoryPubsub") - _, ok = coderAPI.Database.(*dbfake.FakeQuerier) - require.False(t, ok, "FeatureHighAvailability is incompatible with dbfake") + _, ok = coderAPI.Database.(*dbmem.FakeQuerier) + require.False(t, ok, "FeatureHighAvailability is incompatible with dbmem") } } _ = AddLicense(t, client, lo) diff --git a/enterprise/coderd/dormancy/dormantusersjob_test.go b/enterprise/coderd/dormancy/dormantusersjob_test.go index 4c3853cc987a3..c752e84bc1d90 100644 --- a/enterprise/coderd/dormancy/dormantusersjob_test.go +++ b/enterprise/coderd/dormancy/dormantusersjob_test.go @@ -11,7 +11,7 @@ import ( "cdr.dev/slog/sloggers/slogtest" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/enterprise/coderd/dormancy" "github.com/coder/coder/v2/testutil" ) @@ -25,7 +25,7 @@ func TestCheckInactiveUsers(t *testing.T) { // Add some dormant accounts logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true}) - db := dbfake.New() + db := dbmem.New() ctx, cancelFunc := context.WithCancel(context.Background()) t.Cleanup(cancelFunc) diff --git a/enterprise/coderd/license/license_test.go b/enterprise/coderd/license/license_test.go index 1335a89aca18e..f57dd0292d5c2 100644 --- a/enterprise/coderd/license/license_test.go +++ b/enterprise/coderd/license/license_test.go @@ -11,7 +11,7 @@ import ( "cdr.dev/slog" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/enterprise/coderd/coderdenttest" @@ -29,7 +29,7 @@ func TestEntitlements(t *testing.T) { t.Run("Defaults", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() entitlements, err := license.Entitlements(context.Background(), db, slog.Logger{}, 1, 1, coderdenttest.Keys, all) require.NoError(t, err) require.False(t, entitlements.HasLicense) @@ -41,7 +41,7 @@ func TestEntitlements(t *testing.T) { }) t.Run("Always return the current user count", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() entitlements, err := license.Entitlements(context.Background(), db, slog.Logger{}, 1, 1, coderdenttest.Keys, all) require.NoError(t, err) require.False(t, entitlements.HasLicense) @@ -50,7 +50,7 @@ func TestEntitlements(t *testing.T) { }) t.Run("SingleLicenseNothing", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() db.InsertLicense(context.Background(), database.InsertLicenseParams{ JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{}), Exp: time.Now().Add(time.Hour), @@ -66,7 +66,7 @@ func TestEntitlements(t *testing.T) { }) t.Run("SingleLicenseAll", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() db.InsertLicense(context.Background(), database.InsertLicenseParams{ JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ Features: func() license.Features { @@ -89,7 +89,7 @@ func TestEntitlements(t *testing.T) { }) t.Run("SingleLicenseGrace", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() db.InsertLicense(context.Background(), database.InsertLicenseParams{ JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ Features: license.Features{ @@ -115,7 +115,7 @@ func TestEntitlements(t *testing.T) { }) t.Run("Expiration warning", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() db.InsertLicense(context.Background(), database.InsertLicenseParams{ JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ Features: license.Features{ @@ -144,7 +144,7 @@ func TestEntitlements(t *testing.T) { t.Run("Expiration warning for license expiring in 1 day", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() db.InsertLicense(context.Background(), database.InsertLicenseParams{ JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ Features: license.Features{ @@ -173,7 +173,7 @@ func TestEntitlements(t *testing.T) { t.Run("Expiration warning for trials", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() db.InsertLicense(context.Background(), database.InsertLicenseParams{ JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ Features: license.Features{ @@ -203,7 +203,7 @@ func TestEntitlements(t *testing.T) { t.Run("Expiration warning for non trials", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() db.InsertLicense(context.Background(), database.InsertLicenseParams{ JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ Features: license.Features{ @@ -232,7 +232,7 @@ func TestEntitlements(t *testing.T) { t.Run("SingleLicenseNotEntitled", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() db.InsertLicense(context.Background(), database.InsertLicenseParams{ JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{}), Exp: time.Now().Add(time.Hour), @@ -260,7 +260,7 @@ func TestEntitlements(t *testing.T) { }) t.Run("TooManyUsers", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() activeUser1, err := db.InsertUser(context.Background(), database.InsertUserParams{ ID: uuid.New(), Username: "test1", @@ -306,7 +306,7 @@ func TestEntitlements(t *testing.T) { }) t.Run("MaximizeUserLimit", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() db.InsertUser(context.Background(), database.InsertUserParams{}) db.InsertUser(context.Background(), database.InsertUserParams{}) db.InsertLicense(context.Background(), database.InsertLicenseParams{ @@ -334,7 +334,7 @@ func TestEntitlements(t *testing.T) { }) t.Run("MultipleLicenseEnabled", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() // One trial db.InsertLicense(context.Background(), database.InsertLicenseParams{ Exp: time.Now().Add(time.Hour), @@ -358,7 +358,7 @@ func TestEntitlements(t *testing.T) { t.Run("AllFeatures", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() db.InsertLicense(context.Background(), database.InsertLicenseParams{ Exp: time.Now().Add(time.Hour), JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ @@ -380,7 +380,7 @@ func TestEntitlements(t *testing.T) { t.Run("AllFeaturesAlwaysEnable", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() db.InsertLicense(context.Background(), database.InsertLicenseParams{ Exp: dbtime.Now().Add(time.Hour), JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ @@ -403,7 +403,7 @@ func TestEntitlements(t *testing.T) { t.Run("AllFeaturesGrace", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() db.InsertLicense(context.Background(), database.InsertLicenseParams{ Exp: dbtime.Now().Add(time.Hour), JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ @@ -427,7 +427,7 @@ func TestEntitlements(t *testing.T) { t.Run("MultipleReplicasNoLicense", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() entitlements, err := license.Entitlements(context.Background(), db, slog.Logger{}, 2, 1, coderdenttest.Keys, all) require.NoError(t, err) require.False(t, entitlements.HasLicense) @@ -437,7 +437,7 @@ func TestEntitlements(t *testing.T) { t.Run("MultipleReplicasNotEntitled", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() db.InsertLicense(context.Background(), database.InsertLicenseParams{ Exp: time.Now().Add(time.Hour), JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ @@ -457,7 +457,7 @@ func TestEntitlements(t *testing.T) { t.Run("MultipleReplicasGrace", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() db.InsertLicense(context.Background(), database.InsertLicenseParams{ JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ Features: license.Features{ @@ -479,7 +479,7 @@ func TestEntitlements(t *testing.T) { t.Run("MultipleGitAuthNoLicense", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() entitlements, err := license.Entitlements(context.Background(), db, slog.Logger{}, 1, 2, coderdenttest.Keys, all) require.NoError(t, err) require.False(t, entitlements.HasLicense) @@ -489,7 +489,7 @@ func TestEntitlements(t *testing.T) { t.Run("MultipleGitAuthNotEntitled", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() db.InsertLicense(context.Background(), database.InsertLicenseParams{ Exp: time.Now().Add(time.Hour), JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ @@ -509,7 +509,7 @@ func TestEntitlements(t *testing.T) { t.Run("MultipleGitAuthGrace", func(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() db.InsertLicense(context.Background(), database.InsertLicenseParams{ JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ GraceAt: time.Now().Add(-time.Hour), diff --git a/enterprise/coderd/proxyhealth/proxyhealth_test.go b/enterprise/coderd/proxyhealth/proxyhealth_test.go index 96502fa1f56e6..6f20c1e48ebef 100644 --- a/enterprise/coderd/proxyhealth/proxyhealth_test.go +++ b/enterprise/coderd/proxyhealth/proxyhealth_test.go @@ -12,8 +12,8 @@ import ( "cdr.dev/slog/sloggers/slogtest" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" "github.com/coder/coder/v2/coderd/database/dbgen" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/httpapi" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/enterprise/coderd/proxyhealth" @@ -46,7 +46,7 @@ func TestProxyHealth_Nil(t *testing.T) { func TestProxyHealth_Unregistered(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() proxies := []database.WorkspaceProxy{ insertProxy(t, db, ""), @@ -72,7 +72,7 @@ func TestProxyHealth_Unregistered(t *testing.T) { func TestProxyHealth_Unhealthy(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() srvBadReport := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { httpapi.Write(context.Background(), w, http.StatusOK, codersdk.ProxyHealthReport{ @@ -112,7 +112,7 @@ func TestProxyHealth_Unhealthy(t *testing.T) { func TestProxyHealth_Reachable(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { httpapi.Write(context.Background(), w, http.StatusOK, codersdk.ProxyHealthReport{ @@ -147,7 +147,7 @@ func TestProxyHealth_Reachable(t *testing.T) { func TestProxyHealth_Unreachable(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() cli := &http.Client{ Transport: &http.Transport{ diff --git a/enterprise/replicasync/replicasync_test.go b/enterprise/replicasync/replicasync_test.go index 343dd940a5bd3..89ee49bec2bb6 100644 --- a/enterprise/replicasync/replicasync_test.go +++ b/enterprise/replicasync/replicasync_test.go @@ -16,7 +16,7 @@ import ( "cdr.dev/slog/sloggers/slogtest" "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbfake" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/database/pubsub" @@ -218,7 +218,7 @@ func TestReplica(t *testing.T) { // This doesn't use the database fake because creating // this many PostgreSQL connections takes some // configuration tweaking. - db := dbfake.New() + db := dbmem.New() pubsub := pubsub.NewInMemory() logger := slogtest.Make(t, nil) srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/enterprise/trialer/trialer_test.go b/enterprise/trialer/trialer_test.go index 6a160e1ab53ed..22a9eeaca31a0 100644 --- a/enterprise/trialer/trialer_test.go +++ b/enterprise/trialer/trialer_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/coder/coder/v2/coderd/database/dbfake" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/enterprise/coderd/coderdenttest" "github.com/coder/coder/v2/enterprise/trialer" ) @@ -23,7 +23,7 @@ func TestTrialer(t *testing.T) { _, _ = w.Write([]byte(license)) })) defer srv.Close() - db := dbfake.New() + db := dbmem.New() gen := trialer.New(db, srv.URL, coderdenttest.Keys) err := gen(context.Background(), "kyle@coder.com") diff --git a/examples/templates/fly-docker-image/README.md b/examples/templates/fly-docker-image/README.md deleted file mode 100644 index df79210a2f6d4..0000000000000 --- a/examples/templates/fly-docker-image/README.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -name: Develop on a Fly.io container -description: Run workspaces as Firecracker VMs on Fly.io -tags: [docker, fly.io] -icon: /icon/fly.io.svg ---- - -# Coder Fly.io Template - -This template provisions a [code-server](https://github.com/coder/code-server) instance on [fly.io](https://fly.io) using the [codercom/code-server](https://hub.docker.com/r/codercom/code-server) image. - -## Prerequisites - -- [flyctl](https://fly.io/docs/getting-started/installing-flyctl/) installed. -- [Coder](https://coder.com/) already setup and running with coder-cli installed locally. - -## Getting started - -1. Run `coder templates init` and select this template. Follow the instructions that appear. -2. cd into the directory that was created. (e.g. `cd fly-docker-image`) -3. Create the new template by running the following command from the `fly-docker-image` directory: - -```bash -coder templates create fly-docker-image \ - --var fly_api_token=$(flyctl auth token) \ - --var fly_org=personal -``` - -> If the Coder server is also running as a fly.io app, then instead of setting variable `fly_api_token` you can also set a fly.io secret with the name `FLY_API_TOKEN` -> -> ```bash -> flyctl secrets set FLY_API_TOKEN=$(flyctl auth token) --app -> ``` - -> Read our blog [post](coder.com/blog/deploying-coder-on-fly-io) to learn more about how to deploy Coder on fly.io. - -4. Navigate to the Coder dashboard and create a new workspace using the template. - -This is all. You should now have a code-server instance running on fly.io. diff --git a/examples/templates/fly-docker-image/main.tf b/examples/templates/fly-docker-image/main.tf deleted file mode 100644 index 1ef7b120c9f87..0000000000000 --- a/examples/templates/fly-docker-image/main.tf +++ /dev/null @@ -1,347 +0,0 @@ -terraform { - required_providers { - fly = { - source = "fly-apps/fly" - } - coder = { - source = "coder/coder" - } - } -} - -provider "fly" { - fly_api_token = var.fly_api_token == "" ? null : var.fly_api_token -} - -provider "coder" { -} - -resource "fly_app" "workspace" { - name = "coder-${lower(data.coder_workspace.me.owner)}-${lower(data.coder_workspace.me.name)}" - org = var.fly_org -} - -resource "fly_volume" "home-volume" { - app = fly_app.workspace.name - name = "coder_${lower(data.coder_workspace.me.owner)}_${lower(replace(data.coder_workspace.me.name, "-", "_"))}_home" - size = data.coder_parameter.volume-size.value - region = data.coder_parameter.region.value -} - -resource "fly_machine" "workspace" { - count = data.coder_workspace.me.start_count - app = fly_app.workspace.name - region = data.coder_parameter.region.value - name = data.coder_workspace.me.name - image = data.coder_parameter.docker-image.value - cpus = data.coder_parameter.cpu.value - cputype = data.coder_parameter.cputype.value - memorymb = data.coder_parameter.memory.value * 1024 - env = { - CODER_AGENT_TOKEN = "${coder_agent.main.token}" - } - entrypoint = ["sh", "-c", coder_agent.main.init_script] - services = [ - { - ports = [ - { - port = 443 - handlers = ["tls", "http"] - }, - { - port = 80 - handlers = ["http"] - } - - ] - protocol = "tcp", - "internal_port" = 80 - }, - { - ports = [ - { - port = 8080 - handlers = ["tls", "http"] - } - ] - protocol = "tcp", - "internal_port" = 8080 - } - ] - mounts = [ - { - volume = fly_volume.home-volume.id - path = "/home/coder" - } - ] -} - -variable "fly_api_token" { - type = string - description = <<-EOF -The Fly.io API token to use for deploying the workspace. You can generate one by running: - -$ flyctl auth token -EOF - sensitive = true -} - -variable "fly_org" { - type = string - description = <<-EOF -The Fly.io organization slug to deploy the workspace in. List organizations by running: - -$ flyctl orgs list -EOF -} - -data "coder_parameter" "docker-image" { - name = "docker-image" - display_name = "Docker image" - description = "The docker image to use for the workspace" - default = "codercom/code-server:latest" - icon = "https://raw.githubusercontent.com/matifali/logos/main/docker.svg" -} - -data "coder_parameter" "cpu" { - name = "cpu" - display_name = "CPU" - description = "The number of CPUs to allocate to the workspace (1-8)" - type = "number" - default = "1" - icon = "https://raw.githubusercontent.com/matifali/logos/main/cpu-3.svg" - mutable = true - validation { - min = 1 - max = 8 - } -} - -data "coder_parameter" "cputype" { - name = "cputype" - display_name = "CPU type" - description = "Which CPU type do you want?" - default = "shared" - icon = "https://raw.githubusercontent.com/matifali/logos/main/cpu-1.svg" - mutable = true - option { - name = "Shared" - value = "shared" - } - option { - name = "Performance" - value = "performance" - } -} - -data "coder_parameter" "memory" { - name = "memory" - display_name = "Memory" - description = "The amount of memory to allocate to the workspace in GB (up to 16GB)" - type = "number" - default = "2" - icon = "/icon/memory.svg" - mutable = true - validation { - min = data.coder_parameter.cputype.value == "performance" ? 2 : 1 # if the CPU type is performance, the minimum memory is 2GB - max = 16 - } -} - -data "coder_parameter" "volume-size" { - name = "volume-size" - display_name = "Home volume size" - description = "The size of the volume to create for the workspace in GB (1-20)" - type = "number" - default = "1" - icon = "https://raw.githubusercontent.com/matifali/logos/main/database.svg" - validation { - min = 1 - max = 20 - } -} - -# You can see all available regions here: https://fly.io/docs/reference/regions/ -data "coder_parameter" "region" { - name = "region" - display_name = "Region" - description = "The region to deploy the workspace in" - default = "ams" - icon = "/emojis/1f30e.png" - option { - name = "Amsterdam, Netherlands" - value = "ams" - icon = "/emojis/1f1f3-1f1f1.png" - } - option { - name = "Frankfurt, Germany" - value = "fra" - icon = "/emojis/1f1e9-1f1ea.png" - } - option { - name = "Paris, France" - value = "cdg" - icon = "/emojis/1f1eb-1f1f7.png" - } - option { - name = "Denver, Colorado (US)" - value = "den" - icon = "/emojis/1f1fa-1f1f8.png" - } - option { - name = "Dallas, Texas (US)" - value = "dfw" - icon = "/emojis/1f1fa-1f1f8.png" - } - option { - name = "Hong Kong" - value = "hkg" - icon = "/emojis/1f1ed-1f1f0.png" - } - option { - name = "Los Angeles, California (US)" - value = "lax" - icon = "/emojis/1f1fa-1f1f8.png" - } - option { - name = "London, United Kingdom" - value = "lhr" - icon = "/emojis/1f1ec-1f1e7.png" - } - option { - name = "Chennai, India" - value = "maa" - icon = "/emojis/1f1ee-1f1f3.png" - } - option { - name = "Tokyo, Japan" - value = "nrt" - icon = "/emojis/1f1ef-1f1f5.png" - } - option { - name = "Chicago, Illinois (US)" - value = "ord" - icon = "/emojis/1f1fa-1f1f8.png" - } - option { - name = "Seattle, Washington (US)" - value = "sea" - icon = "/emojis/1f1fa-1f1f8.png" - } - option { - name = "Singapore" - value = "sin" - icon = "/emojis/1f1f8-1f1ec.png" - } - option { - name = "Sydney, Australia" - value = "syd" - icon = "/emojis/1f1e6-1f1fa.png" - } - option { - name = "Toronto, Canada" - value = "yyz" - icon = "/emojis/1f1e8-1f1e6.png" - } -} - -resource "coder_app" "code-server" { - count = 1 - agent_id = coder_agent.main.id - display_name = "code-server" - slug = "code-server" - url = "http://localhost:8080?folder=/home/coder/" - icon = "/icon/code.svg" - subdomain = false - share = "owner" - - healthcheck { - url = "http://localhost:8080/healthz" - interval = 3 - threshold = 10 - } -} - -resource "coder_agent" "main" { - arch = data.coder_provisioner.me.arch - os = "linux" - startup_script_timeout = 180 - startup_script = <<-EOT - set -e - # Start code-server - code-server --auth none >/tmp/code-server.log 2>&1 & - # Set the hostname to the workspace name - sudo hostname -b "${data.coder_workspace.me.name}-fly" - echo "127.0.0.1 ${data.coder_workspace.me.name}-fly" | sudo tee -a /etc/hosts - # Install the Fly CLI and add it to the PATH - curl -L https://fly.io/install.sh | sh - echo "export PATH=$PATH:/home/coder/.fly/bin" >> /home/coder/.bashrc - source /home/coder/.bashrc - EOT - - metadata { - key = "cpu" - display_name = "CPU Usage" - interval = 5 - timeout = 5 - script = <<-EOT - #!/bin/bash - set -e - top -bn1 | grep "Cpu(s)" | awk '{print $2 + $4 "%"}' - EOT - } - metadata { - key = "memory" - display_name = "Memory Usage" - interval = 5 - timeout = 5 - script = <<-EOT - #!/bin/bash - set -e - free -m | awk 'NR==2{printf "%.2f%%\t", $3*100/$2 }' - EOT - } - metadata { - key = "disk" - display_name = "Disk Usage" - interval = 600 # every 10 minutes - timeout = 30 # df can take a while on large filesystems - script = <<-EOT - #!/bin/bash - set -e - df | awk '$NF=="/home/coder" {printf "%s", $5}' - EOT - } -} - -resource "coder_metadata" "workspace" { - count = data.coder_workspace.me.start_count - resource_id = fly_app.workspace.id - icon = data.coder_parameter.region.option[index(data.coder_parameter.region.option.*.value, data.coder_parameter.region.value)].icon - item { - key = "Region" - value = data.coder_parameter.region.option[index(data.coder_parameter.region.option.*.value, data.coder_parameter.region.value)].name - } - item { - key = "CPU Type" - value = data.coder_parameter.cputype.option[index(data.coder_parameter.cputype.option.*.value, data.coder_parameter.cputype.value)].name - } - item { - key = "CPU Count" - value = data.coder_parameter.cpu.value - } - item { - key = "Memory (GB)" - value = data.coder_parameter.memory.value - } - item { - key = "Volume Size (GB)" - value = data.coder_parameter.volume-size.value - } -} - -data "coder_provisioner" "me" { -} - -data "coder_workspace" "me" { -} diff --git a/examples/web-server/nginx/README.md b/examples/web-server/nginx/README.md index 5c822856fdb1e..3454fe190f38c 100644 --- a/examples/web-server/nginx/README.md +++ b/examples/web-server/nginx/README.md @@ -7,7 +7,7 @@ ```env CODER_HTTP_ADDRESS=127.0.0.1:3000 CODER_ACCESS_URL=https://coder.example.com - CODER_WILDCARD_ACCESS_URL=*coder.example.com + CODER_WILDCARD_ACCESS_URL=*.coder.example.com ``` Throughout the guide, be sure to replace `coder.example.com` with the domain you intend to use with Coder. diff --git a/go.mod b/go.mod index 73e8179ff3b66..8ddcf94dc1c9f 100644 --- a/go.mod +++ b/go.mod @@ -75,7 +75,7 @@ require ( github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d github.com/adrg/xdg v0.4.0 github.com/ammario/tlru v0.3.0 - github.com/andybalholm/brotli v1.0.5 + github.com/andybalholm/brotli v1.0.6 github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 github.com/awalterschulze/gographviz v2.0.3+incompatible github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 @@ -94,12 +94,12 @@ require ( github.com/coder/retry v1.4.0 github.com/coder/terraform-provider-coder v0.12.2 github.com/coder/wgtunnel v0.1.12 - github.com/coreos/go-oidc/v3 v3.6.0 + github.com/coreos/go-oidc/v3 v3.7.0 github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf github.com/creack/pty v1.1.18 github.com/dave/dst v0.27.2 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc - github.com/djherbis/times v1.5.0 + github.com/djherbis/times v1.6.0 github.com/elastic/go-sysinfo v1.11.0 github.com/fatih/color v1.15.0 github.com/fatih/structs v1.1.0 @@ -113,7 +113,7 @@ require ( github.com/go-chi/httprate v0.7.4 github.com/go-chi/render v1.0.1 github.com/go-jose/go-jose/v3 v3.0.0 - github.com/go-logr/logr v1.2.4 + github.com/go-logr/logr v1.3.0 github.com/go-ping/ping v1.1.0 github.com/go-playground/validator/v10 v10.15.1 github.com/gofrs/flock v0.8.1 @@ -138,9 +138,9 @@ require ( github.com/jmoiron/sqlx v1.3.5 github.com/justinas/nosurf v1.1.1 github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f - github.com/klauspost/compress v1.17.0 + github.com/klauspost/compress v1.17.1 github.com/lib/pq v1.10.9 - github.com/mattn/go-isatty v0.0.19 + github.com/mattn/go-isatty v0.0.20 github.com/mitchellh/go-wordwrap v1.0.1 github.com/mitchellh/mapstructure v1.5.0 github.com/moby/moby v24.0.1+incompatible @@ -153,7 +153,7 @@ require ( github.com/pkg/sftp v1.13.6-0.20221018182125-7da137aa03f0 github.com/prometheus/client_golang v1.17.0 github.com/prometheus/client_model v0.5.0 - github.com/prometheus/common v0.44.0 + github.com/prometheus/common v0.45.0 github.com/quasilyte/go-ruleguard/dsl v0.3.21 github.com/robfig/cron/v3 v3.0.1 github.com/spf13/afero v1.10.0 @@ -174,7 +174,7 @@ require ( go.opentelemetry.io/otel/sdk v1.19.0 go.opentelemetry.io/otel/trace v1.19.0 go.uber.org/atomic v1.11.0 - go.uber.org/goleak v1.2.1 + go.uber.org/goleak v1.3.0 go4.org/netipx v0.0.0-20230728180743-ad4cb58a6516 golang.org/x/crypto v0.14.0 golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b @@ -188,10 +188,10 @@ require ( golang.org/x/tools v0.14.0 golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 golang.zx2c4.com/wireguard v0.0.0-20230704135630-469159ecf7d1 - google.golang.org/api v0.147.0 - google.golang.org/grpc v1.58.2 + google.golang.org/api v0.148.0 + google.golang.org/grpc v1.59.0 google.golang.org/protobuf v1.31.0 - gopkg.in/DataDog/dd-trace-go.v1 v1.55.0 + gopkg.in/DataDog/dd-trace-go.v1 v1.56.1 gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/yaml.v3 v3.0.1 gvisor.dev/gvisor v0.0.0-20230504175454-7b0a1988a28f @@ -215,7 +215,7 @@ require ( filippo.io/edwards25519 v1.0.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/DataDog/appsec-internal-go v1.0.0 // indirect - github.com/DataDog/datadog-agent/pkg/obfuscate v0.46.0 // indirect + github.com/DataDog/datadog-agent/pkg/obfuscate v0.48.0 // indirect github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.48.0-devel.0.20230725154044-2549ba9058df // indirect github.com/DataDog/datadog-go/v5 v5.3.0 // indirect github.com/DataDog/go-libddwaf v1.5.0 // indirect @@ -332,7 +332,7 @@ require ( github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/mdlayher/genetlink v1.3.2 // indirect github.com/mdlayher/netlink v1.7.2 // indirect github.com/mdlayher/sdnotify v1.0.0 // indirect @@ -411,10 +411,10 @@ require ( golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 // indirect golang.zx2c4.com/wireguard/windows v0.5.3 // indirect - google.golang.org/appengine v1.6.7 // indirect + google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a // indirect gopkg.in/yaml.v2 v2.4.0 // indirect howett.net/plist v1.0.0 // indirect inet.af/netaddr v0.0.0-20230525184311-b8eac61e914a // indirect diff --git a/go.sum b/go.sum index 8fe52143c7a00..c4180c4191b45 100644 --- a/go.sum +++ b/go.sum @@ -58,11 +58,10 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DataDog/appsec-internal-go v1.0.0 h1:2u5IkF4DBj3KVeQn5Vg2vjPUtt513zxEYglcqnd500U= github.com/DataDog/appsec-internal-go v1.0.0/go.mod h1:+Y+4klVWKPOnZx6XESG7QHydOaUGEXyH2j/vSg9JiNM= -github.com/DataDog/datadog-agent/pkg/obfuscate v0.46.0 h1:rUNnUcHC4AlxoImuXmZeOfi6H80BDBHzeagWXWCVhnA= -github.com/DataDog/datadog-agent/pkg/obfuscate v0.46.0/go.mod h1:e933RWa4kAWuHi5jpzEuOiULlv21HcCFEVIYegmaB5c= +github.com/DataDog/datadog-agent/pkg/obfuscate v0.48.0 h1:bUMSNsw1iofWiju9yc1f+kBd33E3hMJtq9GuU602Iy8= +github.com/DataDog/datadog-agent/pkg/obfuscate v0.48.0/go.mod h1:HzySONXnAgSmIQfL6gOv9hWprKJkx8CicuXuUbmgWfo= github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.48.0-devel.0.20230725154044-2549ba9058df h1:PbzrhHhs2+RRdKKti7JBSM8ATIeiji2T2cVt/d8GT8k= github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.48.0-devel.0.20230725154044-2549ba9058df/go.mod h1:5Q39ZOIOwZMnFyRadp+5gH1bFdjmb+Pgxe+j5XOwaTg= -github.com/DataDog/datadog-go/v5 v5.1.1/go.mod h1:KhiYb2Badlv9/rofz+OznKoEF5XKTonWyhx5K83AP8E= github.com/DataDog/datadog-go/v5 v5.3.0 h1:2q2qjFOb3RwAZNU+ez27ZVDwErJv5/VpbBPprz7Z+s8= github.com/DataDog/datadog-go/v5 v5.3.0/go.mod h1:XRDJk1pTc00gm+ZDiBKsjh7oOOtJfYfglVCmFb8C2+Q= github.com/DataDog/go-libddwaf v1.5.0 h1:lrHP3VrEriy1M5uQuaOcKphf5GU40mBhihMAp6Ik55c= @@ -76,7 +75,6 @@ github.com/DataDog/sketches-go v1.4.2/go.mod h1:xJIXldczJyyjnbDop7ZZcLxJdV3+7Kra github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= @@ -105,8 +103,8 @@ github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3Uu github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/ammario/tlru v0.3.0 h1:yK8ESoFlEyz/BVVL8yZQKAUzJwFJR/j9EfxjnKxtR/Q= github.com/ammario/tlru v0.3.0/go.mod h1:aYzRFu0XLo4KavE9W8Lx7tzjkX+pAApz+NgcKYIFUBQ= -github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= -github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= +github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= @@ -249,8 +247,8 @@ github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk= github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= -github.com/coreos/go-oidc/v3 v3.6.0 h1:AKVxfYw1Gmkn/w96z0DbT/B/xFnzTd3MkZvWLjF4n/o= -github.com/coreos/go-oidc/v3 v3.6.0/go.mod h1:ZpHUsHBucTUj6WOkrP4E20UPynbLZzhTQ1XKCXkxyPc= +github.com/coreos/go-oidc/v3 v3.7.0 h1:FTdj0uexT4diYIPlF4yoFVI5MRO1r5+SEcIpEw9vC0o= +github.com/coreos/go-oidc/v3 v3.7.0/go.mod h1:yQzSCqBnK3e6Fs5l+f5i0F8Kwf0zpH9bPEsbY00KanM= github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU= github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= @@ -274,8 +272,8 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WA github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= github.com/dhui/dktest v0.3.16 h1:i6gq2YQEtcrjKbeJpBkWjE8MmLZPYllcjOFbTZuPDnw= -github.com/djherbis/times v1.5.0 h1:79myA211VwPhFTqUk8xehWrsEO+zcIZj0zT8mXPVARU= -github.com/djherbis/times v1.5.0/go.mod h1:5q7FDLvbNg1L/KaBmPcWlVR9NmoKo3+ucqUA3ijQhA0= +github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c= +github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0= github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/docker/cli v23.0.5+incompatible h1:ufWmAOuD3Vmr7JP2G5K3cyuNC4YZWiAsuDEvFVVDafE= @@ -359,8 +357,8 @@ github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxF github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.1/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jTKKwI= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= @@ -624,8 +622,8 @@ github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f/go.mod h1:4rEELDS github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= -github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.1 h1:NE3C767s2ak2bweCZo3+rdP4U/HoyVXLv/X9f2gPS5g= +github.com/klauspost/compress v1.17.1/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a h1:+RR6SqnTkDLWyICxS1xpjCi/3dhyV+TgZwA6Ww3KncQ= github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a/go.mod h1:YTtCCM3ryyfiu4F7t8HQ1mxvp1UBdWM2r6Xa+nGWvDk= @@ -673,8 +671,8 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= @@ -683,8 +681,8 @@ github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZ github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw= github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o= github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= @@ -754,7 +752,6 @@ github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhA github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= github.com/ory/dockertest/v3 v3.10.0 h1:4K3z2VMe8Woe++invjaTB7VRyQXQy5UY+loujO4aNE4= github.com/ory/dockertest/v3 v3.10.0/go.mod h1:nr57ZbRWMqfsdGdFNLHz5jjNdDb7VVFnzAeW1n5N1Lg= -github.com/outcaste-io/ristretto v0.2.1/go.mod h1:W8HywhmtlopSB1jeMg3JtdIhf+DYkLAr0VN/s4+MHac= github.com/outcaste-io/ristretto v0.2.3 h1:AK4zt/fJ76kjlYObOeNwh4T3asEuaCmp26pOvUOL9w0= github.com/outcaste-io/ristretto v0.2.3/go.mod h1:W8HywhmtlopSB1jeMg3JtdIhf+DYkLAr0VN/s4+MHac= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= @@ -788,8 +785,8 @@ github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+L github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= -github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= +github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= +github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= github.com/quasilyte/go-ruleguard/dsl v0.3.21 h1:vNkC6fC6qMLzCOGbnIHOd5ixUGgTbp3Z4fGnUgULlDA= @@ -982,11 +979,10 @@ go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmY go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go4.org/intern v0.0.0-20211027215823-ae77deb06f29/go.mod h1:cS2ma+47FKrLPdXFpr7CuxiTW3eyJbWew4qx0qtQWDA= go4.org/intern v0.0.0-20230525184215-6c62f75575cb h1:ae7kzL5Cfdmcecbh22ll7lYP3iuUdnfnhiPcSaDgH/8= go4.org/intern v0.0.0-20230525184215-6c62f75575cb/go.mod h1:Ycrt6raEcnF5FTsLiLKkhBTO6DPX3RCUCUVnks3gFJU= @@ -1188,6 +1184,7 @@ golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1220,6 +1217,7 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= @@ -1317,16 +1315,17 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.147.0 h1:Can3FaQo9LlVqxJCodNmeZW/ib3/qKAY3rFeXiHo5gc= -google.golang.org/api v0.147.0/go.mod h1:pQ/9j83DcmPd/5C9e2nFOdjjNkDZ1G+zkbK2uvdkJMs= +google.golang.org/api v0.148.0 h1:HBq4TZlN4/1pNcu0geJZ/Q50vIwIXT532UIMYoo0vOs= +google.golang.org/api v0.148.0/go.mod h1:8/TBgwaKjfqTdacOJrOv2+2Q6fBDU1uHKK06oGSkxzU= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1366,8 +1365,8 @@ google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 h1:SeZZZx0cP0fqUyA google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk= google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 h1:W18sezcAYs+3tDZX4F80yctqa12jcP1PUS2gQu1zTPU= google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97/go.mod h1:iargEX0SFPm3xcfMI0d1domjg0ZF4Aa0p2awqyxhvF0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c h1:jHkCUWkseRf+W+edG5hMzr/Uh1xkDREY4caybAq4dpY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a h1:a2MQQVoTo96JC9PMGtGBymLp7+/RzpFc2yX/9WfFg1c= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1384,8 +1383,8 @@ google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I= -google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1402,8 +1401,8 @@ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/DataDog/dd-trace-go.v1 v1.55.0 h1:ozWhUpvrDBtZKcRB5flT0waAfnqWz1f5gOf/Y+QIurg= -gopkg.in/DataDog/dd-trace-go.v1 v1.55.0/go.mod h1:1KvDrWW49v4TPaOAIjZEYdx4ZBrm9sXm5z1s+JIZiWs= +gopkg.in/DataDog/dd-trace-go.v1 v1.56.1 h1:AUe/ZF7xm6vYnigPe+TY54DmfWYJxhMRaw/TfvrbzvE= +gopkg.in/DataDog/dd-trace-go.v1 v1.56.1/go.mod h1:KDLJ3CWVOSuVVwu+0ZR5KZo2rP6c7YyBV3v387dIpUU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/provisioner/terraform/provision.go b/provisioner/terraform/provision.go index 8e22579277f80..e980a26d833fc 100644 --- a/provisioner/terraform/provision.go +++ b/provisioner/terraform/provision.go @@ -198,6 +198,7 @@ func provisionEnv( "CODER_WORKSPACE_OWNER_SESSION_TOKEN="+metadata.GetWorkspaceOwnerSessionToken(), "CODER_WORKSPACE_TEMPLATE_ID="+metadata.GetTemplateId(), "CODER_WORKSPACE_TEMPLATE_NAME="+metadata.GetTemplateName(), + "CODER_WORKSPACE_TEMPLATE_VERSION="+metadata.GetTemplateVersion(), ) for key, value := range provisionersdk.AgentScriptEnv() { env = append(env, key+"="+value) diff --git a/scripts/dbgen/main.go b/scripts/dbgen/main.go index ac946ff8a51ad..54b104d04f718 100644 --- a/scripts/dbgen/main.go +++ b/scripts/dbgen/main.go @@ -53,11 +53,11 @@ func run() error { } databasePath := filepath.Join(localPath, "..", "..", "..", "coderd", "database") - err = orderAndStubDatabaseFunctions(filepath.Join(databasePath, "dbfake", "dbfake.go"), "q", "FakeQuerier", func(params stubParams) string { + err = orderAndStubDatabaseFunctions(filepath.Join(databasePath, "dbmem", "dbmem.go"), "q", "FakeQuerier", func(params stubParams) string { return `panic("not implemented")` }) if err != nil { - return xerrors.Errorf("stub dbfake: %w", err) + return xerrors.Errorf("stub dbmem: %w", err) } err = orderAndStubDatabaseFunctions(filepath.Join(databasePath, "dbmetrics", "dbmetrics.go"), "m", "metricsStore", func(params stubParams) string { @@ -257,13 +257,13 @@ func orderAndStubDatabaseFunctions(filePath, receiver, structName string, stub f contents, err := os.ReadFile(filePath) if err != nil { - return xerrors.Errorf("read dbfake: %w", err) + return xerrors.Errorf("read dbmem: %w", err) } // Required to preserve imports! f, err := decorator.NewDecoratorWithImports(token.NewFileSet(), packageName, goast.New()).Parse(contents) if err != nil { - return xerrors.Errorf("parse dbfake: %w", err) + return xerrors.Errorf("parse dbmem: %w", err) } pointer := false @@ -298,8 +298,8 @@ func orderAndStubDatabaseFunctions(filePath, receiver, structName string, stub f for _, fn := range funcs { var bodyStmts []dst.Stmt - // Add input validation, only relevant for dbfake. - if strings.Contains(filePath, "dbfake") && len(fn.Func.Params.List) == 2 && fn.Func.Params.List[1].Names[0].Name == "arg" { + // Add input validation, only relevant for dbmem. + if strings.Contains(filePath, "dbmem") && len(fn.Func.Params.List) == 2 && fn.Func.Params.List[1].Names[0].Name == "arg" { /* err := validateDatabaseType(arg) if err != nil { diff --git a/site/site_test.go b/site/site_test.go index bf40be9b1cdcf..b240a065fea1b 100644 --- a/site/site_test.go +++ b/site/site_test.go @@ -24,8 +24,8 @@ import ( "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/db2sdk" - "github.com/coder/coder/v2/coderd/database/dbfake" "github.com/coder/coder/v2/coderd/database/dbgen" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/httpmw" "github.com/coder/coder/v2/codersdk" @@ -42,7 +42,7 @@ func TestInjection(t *testing.T) { }, } binFs := http.FS(fstest.MapFS{}) - db := dbfake.New() + db := dbmem.New() handler := site.New(&site.Options{ BinFS: binFs, Database: db, @@ -74,7 +74,7 @@ func TestInjection(t *testing.T) { func TestInjectionFailureProducesCleanHTML(t *testing.T) { t.Parallel() - db := dbfake.New() + db := dbmem.New() // Create an expired user with a refresh token, but provide no OAuth2 // configuration so that refresh is impossible, this should result in diff --git a/site/src/api/queries/appearance.ts b/site/src/api/queries/appearance.ts index 1e891deb59619..10366b4382d72 100644 --- a/site/src/api/queries/appearance.ts +++ b/site/src/api/queries/appearance.ts @@ -6,18 +6,12 @@ import { getMetadataAsJSON } from "utils/metadata"; const initialAppearanceData = getMetadataAsJSON("appearance"); const appearanceConfigKey = ["appearance"] as const; -export const appearance = (queryClient: QueryClient) => { +export const appearance = (): UseQueryOptions => { return { - queryKey: appearanceConfigKey, - queryFn: async () => { - const cachedData = queryClient.getQueryData(appearanceConfigKey); - if (cachedData === undefined && initialAppearanceData !== undefined) { - return initialAppearanceData; - } - - return API.getAppearance(); - }, - } satisfies UseQueryOptions; + queryKey: ["appearance"], + initialData: initialAppearanceData, + queryFn: () => API.getAppearance(), + }; }; export const updateAppearance = (queryClient: QueryClient) => { diff --git a/site/src/api/queries/buildInfo.ts b/site/src/api/queries/buildInfo.ts index c10b458a67fcf..58e61575ef057 100644 --- a/site/src/api/queries/buildInfo.ts +++ b/site/src/api/queries/buildInfo.ts @@ -1,4 +1,4 @@ -import { QueryClient, type UseQueryOptions } from "react-query"; +import { type UseQueryOptions } from "react-query"; import { type BuildInfoResponse } from "api/typesGenerated"; import * as API from "api/api"; import { getMetadataAsJSON } from "utils/metadata"; @@ -6,16 +6,10 @@ import { getMetadataAsJSON } from "utils/metadata"; const initialBuildInfoData = getMetadataAsJSON("build-info"); const buildInfoKey = ["buildInfo"] as const; -export const buildInfo = (queryClient: QueryClient) => { +export const buildInfo = (): UseQueryOptions => { return { queryKey: buildInfoKey, - queryFn: async () => { - const cachedData = queryClient.getQueryData(buildInfoKey); - if (cachedData === undefined && initialBuildInfoData !== undefined) { - return initialBuildInfoData; - } - - return API.getBuildInfo(); - }, - } satisfies UseQueryOptions; + initialData: initialBuildInfoData, + queryFn: () => API.getBuildInfo(), + }; }; diff --git a/site/src/api/queries/entitlements.ts b/site/src/api/queries/entitlements.ts index 271d0bbf821ee..6cb0bf9c2572e 100644 --- a/site/src/api/queries/entitlements.ts +++ b/site/src/api/queries/entitlements.ts @@ -1,15 +1,16 @@ -import { QueryClient } from "react-query"; +import { QueryClient, UseQueryOptions } from "react-query"; import * as API from "api/api"; import { Entitlements } from "api/typesGenerated"; import { getMetadataAsJSON } from "utils/metadata"; -const ENTITLEMENTS_QUERY_KEY = ["entitlements"]; +const initialEntitlementsData = getMetadataAsJSON("entitlements"); +const ENTITLEMENTS_QUERY_KEY = ["entitlements"] as const; -export const entitlements = () => { +export const entitlements = (): UseQueryOptions => { return { queryKey: ENTITLEMENTS_QUERY_KEY, - queryFn: async () => - getMetadataAsJSON("entitlements") ?? API.getEntitlements(), + queryFn: () => API.getEntitlements(), + initialData: initialEntitlementsData, }; }; diff --git a/site/src/api/queries/experiments.ts b/site/src/api/queries/experiments.ts index 3d3618819fe77..aa12d5152411b 100644 --- a/site/src/api/queries/experiments.ts +++ b/site/src/api/queries/experiments.ts @@ -1,22 +1,16 @@ import * as API from "api/api"; import { getMetadataAsJSON } from "utils/metadata"; import { type Experiments } from "api/typesGenerated"; -import { QueryClient, type UseQueryOptions } from "react-query"; +import { type UseQueryOptions } from "react-query"; const initialExperimentsData = getMetadataAsJSON("experiments"); const experimentsKey = ["experiments"] as const; -export const experiments = (queryClient: QueryClient) => { +export const experiments = (): UseQueryOptions => { return { queryKey: experimentsKey, - queryFn: async () => { - const cachedData = queryClient.getQueryData(experimentsKey); - if (cachedData === undefined && initialExperimentsData !== undefined) { - return initialExperimentsData; - } - - return API.getExperiments(); - }, + initialData: initialExperimentsData, + queryFn: () => API.getExperiments(), } satisfies UseQueryOptions; }; diff --git a/site/src/api/queries/users.ts b/site/src/api/queries/users.ts index 8f335c6525f7b..2b6900df13ac8 100644 --- a/site/src/api/queries/users.ts +++ b/site/src/api/queries/users.ts @@ -91,7 +91,9 @@ export const authMethods = () => { const initialUserData = getMetadataAsJSON("user"); -export const me = () => { +export const me = (): UseQueryOptions & { + queryKey: NonNullable["queryKey"]>; +} => { return { queryKey: ["me"], initialData: initialUserData, diff --git a/site/src/components/Dashboard/DashboardProvider.tsx b/site/src/components/Dashboard/DashboardProvider.tsx index 7e06b4a656620..ae05ff0ae7447 100644 --- a/site/src/components/Dashboard/DashboardProvider.tsx +++ b/site/src/components/Dashboard/DashboardProvider.tsx @@ -1,4 +1,4 @@ -import { useQuery, useQueryClient } from "react-query"; +import { useQuery } from "react-query"; import { buildInfo } from "api/queries/buildInfo"; import { experiments } from "api/queries/experiments"; import { entitlements } from "api/queries/entitlements"; @@ -39,11 +39,10 @@ export const DashboardProviderContext = createContext< >(undefined); export const DashboardProvider: FC = ({ children }) => { - const queryClient = useQueryClient(); - const buildInfoQuery = useQuery(buildInfo(queryClient)); + const buildInfoQuery = useQuery(buildInfo()); const entitlementsQuery = useQuery(entitlements()); - const experimentsQuery = useQuery(experiments(queryClient)); - const appearanceQuery = useQuery(appearance(queryClient)); + const experimentsQuery = useQuery(experiments()); + const appearanceQuery = useQuery(appearance()); const isLoading = !buildInfoQuery.data || diff --git a/site/src/pages/ExternalAuthPage/ExternalAuthPage.tsx b/site/src/pages/ExternalAuthPage/ExternalAuthPage.tsx index d42004b758914..8cc955b596d4c 100644 --- a/site/src/pages/ExternalAuthPage/ExternalAuthPage.tsx +++ b/site/src/pages/ExternalAuthPage/ExternalAuthPage.tsx @@ -6,16 +6,21 @@ import { } from "api/api"; import { usePermissions } from "hooks"; import { type FC } from "react"; -import { useParams } from "react-router-dom"; +import { useParams, useSearchParams } from "react-router-dom"; import ExternalAuthPageView from "./ExternalAuthPageView"; import { ApiErrorResponse } from "api/errors"; import { isAxiosError } from "axios"; +import Box from "@mui/material/Box"; +import Button from "@mui/material/Button"; +import { SignInLayout } from "components/SignInLayout/SignInLayout"; +import { Welcome } from "components/Welcome/Welcome"; const ExternalAuthPage: FC = () => { const { provider } = useParams(); if (!provider) { throw new Error("provider must exist"); } + const [searchParams] = useSearchParams(); const permissions = usePermissions(); const queryClient = useQueryClient(); const getExternalAuthProviderQuery = useQuery({ @@ -72,6 +77,35 @@ const ExternalAuthPage: FC = () => { !getExternalAuthProviderQuery.data.authenticated && !getExternalAuthProviderQuery.data.device ) { + const redirectedParam = searchParams?.get("redirected"); + if (redirectedParam && redirectedParam.toLowerCase() === "true") { + // The auth flow redirected the user here. If we redirect back to the + // callback, that resets the flow and we'll end up in an infinite loop. + // So instead, show an error, as the user expects to be authenticated at + // this point. + // TODO: Unsure what to do about the device auth flow, should we also + // show an error there? + return ( + + + + Attempted to validate the user's oauth access token from the + authentication flow. This situation may occur as a result of an + external authentication provider misconfiguration. Verify the + external authentication validation URL is accurately configured. + +
+ +
+ ); + } window.location.href = `/external-auth/${provider}/callback`; return null; } diff --git a/site/src/pages/TerminalPage/TerminalPage.tsx b/site/src/pages/TerminalPage/TerminalPage.tsx index c3844fe051cd6..7c82c82a1f5bb 100644 --- a/site/src/pages/TerminalPage/TerminalPage.tsx +++ b/site/src/pages/TerminalPage/TerminalPage.tsx @@ -54,7 +54,6 @@ const TerminalPage: FC = () => { const [terminalState, setTerminalState] = useState< "connected" | "disconnected" | "initializing" >("initializing"); - const [fitAddon, setFitAddon] = useState(null); const [searchParams] = useSearchParams(); // The reconnection token is a unique token that identifies // a terminal session. It's generated by the client to reduce @@ -125,7 +124,6 @@ const TerminalPage: FC = () => { terminal.loadAddon(new CanvasAddon()); } const fitAddon = new FitAddon(); - setFitAddon(fitAddon); terminal.loadAddon(fitAddon); terminal.loadAddon(new Unicode11Addon()); terminal.unicode.activeVersion = "11"; @@ -134,13 +132,21 @@ const TerminalPage: FC = () => { handleWebLinkRef.current(uri); }), ); - setTerminal(terminal); + terminal.open(xtermRef.current); - const listener = () => { - // This will trigger a resize event on the terminal. - fitAddon.fit(); - }; + + // We have to fit twice here. It's unknown why, but the first fit will + // overflow slightly in some scenarios. Applying a second fit resolves this. + fitAddon.fit(); + fitAddon.fit(); + + // This will trigger a resize event on the terminal. + const listener = () => fitAddon.fit(); window.addEventListener("resize", listener); + + // Terminal is correctly sized and is ready to be used. + setTerminal(terminal); + return () => { window.removeEventListener("resize", listener); terminal.dispose(); @@ -165,16 +171,10 @@ const TerminalPage: FC = () => { // Hook up the terminal through a web socket. useEffect(() => { - if (!terminal || !fitAddon) { + if (!terminal) { return; } - // We have to fit twice here. It's unknown why, but - // the first fit will overflow slightly in some - // scenarios. Applying a second fit resolves this. - fitAddon.fit(); - fitAddon.fit(); - // The terminal should be cleared on each reconnect // because all data is re-rendered from the backend. terminal.clear(); @@ -229,6 +229,8 @@ const TerminalPage: FC = () => { reconnectionToken, workspaceAgent.id, command, + terminal.rows, + terminal.cols, ) .then((url) => { if (disposed) { @@ -289,7 +291,6 @@ const TerminalPage: FC = () => { }; }, [ command, - fitAddon, proxy.preferredPathAppURL, reconnectionToken, terminal, diff --git a/site/src/utils/terminal.ts b/site/src/utils/terminal.ts index 52d46feaafcf6..d27a6efce379c 100644 --- a/site/src/utils/terminal.ts +++ b/site/src/utils/terminal.ts @@ -5,11 +5,15 @@ export const terminalWebsocketUrl = async ( reconnect: string, agentId: string, command: string | undefined, + height: number, + width: number, ): Promise => { const query = new URLSearchParams({ reconnect }); if (command) { query.set("command", command); } + query.set("height", height.toString()); + query.set("width", width.toString()); const url = new URL(baseUrl || `${location.protocol}//${location.host}`); url.protocol = url.protocol === "https:" ? "wss:" : "ws:"; diff --git a/tailnet/proto/tailnet.pb.go b/tailnet/proto/tailnet.pb.go new file mode 100644 index 0000000000000..c5318fa7df5d4 --- /dev/null +++ b/tailnet/proto/tailnet.pb.go @@ -0,0 +1,1295 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.30.0 +// protoc v4.23.3 +// source: tailnet/proto/tailnet.proto + +package proto + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type CoordinateResponse_PeerUpdate_Kind int32 + +const ( + CoordinateResponse_PeerUpdate_KIND_UNSPECIFIED CoordinateResponse_PeerUpdate_Kind = 0 + CoordinateResponse_PeerUpdate_NODE CoordinateResponse_PeerUpdate_Kind = 1 + CoordinateResponse_PeerUpdate_DISCONNECTED CoordinateResponse_PeerUpdate_Kind = 2 + CoordinateResponse_PeerUpdate_LOST CoordinateResponse_PeerUpdate_Kind = 3 +) + +// Enum value maps for CoordinateResponse_PeerUpdate_Kind. +var ( + CoordinateResponse_PeerUpdate_Kind_name = map[int32]string{ + 0: "KIND_UNSPECIFIED", + 1: "NODE", + 2: "DISCONNECTED", + 3: "LOST", + } + CoordinateResponse_PeerUpdate_Kind_value = map[string]int32{ + "KIND_UNSPECIFIED": 0, + "NODE": 1, + "DISCONNECTED": 2, + "LOST": 3, + } +) + +func (x CoordinateResponse_PeerUpdate_Kind) Enum() *CoordinateResponse_PeerUpdate_Kind { + p := new(CoordinateResponse_PeerUpdate_Kind) + *p = x + return p +} + +func (x CoordinateResponse_PeerUpdate_Kind) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CoordinateResponse_PeerUpdate_Kind) Descriptor() protoreflect.EnumDescriptor { + return file_tailnet_proto_tailnet_proto_enumTypes[0].Descriptor() +} + +func (CoordinateResponse_PeerUpdate_Kind) Type() protoreflect.EnumType { + return &file_tailnet_proto_tailnet_proto_enumTypes[0] +} + +func (x CoordinateResponse_PeerUpdate_Kind) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use CoordinateResponse_PeerUpdate_Kind.Descriptor instead. +func (CoordinateResponse_PeerUpdate_Kind) EnumDescriptor() ([]byte, []int) { + return file_tailnet_proto_tailnet_proto_rawDescGZIP(), []int{4, 0, 0} +} + +type DERPMap struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + HomeParams *DERPMap_HomeParams `protobuf:"bytes,1,opt,name=home_params,json=homeParams,proto3" json:"home_params,omitempty"` + Regions map[int32]*DERPMap_Region `protobuf:"bytes,2,rep,name=regions,proto3" json:"regions,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *DERPMap) Reset() { + *x = DERPMap{} + if protoimpl.UnsafeEnabled { + mi := &file_tailnet_proto_tailnet_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DERPMap) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DERPMap) ProtoMessage() {} + +func (x *DERPMap) ProtoReflect() protoreflect.Message { + mi := &file_tailnet_proto_tailnet_proto_msgTypes[0] + 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 DERPMap.ProtoReflect.Descriptor instead. +func (*DERPMap) Descriptor() ([]byte, []int) { + return file_tailnet_proto_tailnet_proto_rawDescGZIP(), []int{0} +} + +func (x *DERPMap) GetHomeParams() *DERPMap_HomeParams { + if x != nil { + return x.HomeParams + } + return nil +} + +func (x *DERPMap) GetRegions() map[int32]*DERPMap_Region { + if x != nil { + return x.Regions + } + return nil +} + +type StreamDERPMapsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *StreamDERPMapsRequest) Reset() { + *x = StreamDERPMapsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_tailnet_proto_tailnet_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StreamDERPMapsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StreamDERPMapsRequest) ProtoMessage() {} + +func (x *StreamDERPMapsRequest) ProtoReflect() protoreflect.Message { + mi := &file_tailnet_proto_tailnet_proto_msgTypes[1] + 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 StreamDERPMapsRequest.ProtoReflect.Descriptor instead. +func (*StreamDERPMapsRequest) Descriptor() ([]byte, []int) { + return file_tailnet_proto_tailnet_proto_rawDescGZIP(), []int{1} +} + +// defined in tailnet/coordinator.go +type Node struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + AsOf *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=as_of,json=asOf,proto3" json:"as_of,omitempty"` + Key []byte `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"` + Disco string `protobuf:"bytes,4,opt,name=disco,proto3" json:"disco,omitempty"` + PreferredDerp int32 `protobuf:"varint,5,opt,name=preferred_derp,json=preferredDerp,proto3" json:"preferred_derp,omitempty"` + DerpLatency map[string]float64 `protobuf:"bytes,6,rep,name=derp_latency,json=derpLatency,proto3" json:"derp_latency,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"fixed64,2,opt,name=value,proto3"` + DerpForcedWebsocket map[int32]string `protobuf:"bytes,7,rep,name=derp_forced_websocket,json=derpForcedWebsocket,proto3" json:"derp_forced_websocket,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Addresses []string `protobuf:"bytes,8,rep,name=addresses,proto3" json:"addresses,omitempty"` + AllowedIps []string `protobuf:"bytes,9,rep,name=allowed_ips,json=allowedIps,proto3" json:"allowed_ips,omitempty"` + Endpoints []string `protobuf:"bytes,10,rep,name=endpoints,proto3" json:"endpoints,omitempty"` +} + +func (x *Node) Reset() { + *x = Node{} + if protoimpl.UnsafeEnabled { + mi := &file_tailnet_proto_tailnet_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Node) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Node) ProtoMessage() {} + +func (x *Node) ProtoReflect() protoreflect.Message { + mi := &file_tailnet_proto_tailnet_proto_msgTypes[2] + 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 Node.ProtoReflect.Descriptor instead. +func (*Node) Descriptor() ([]byte, []int) { + return file_tailnet_proto_tailnet_proto_rawDescGZIP(), []int{2} +} + +func (x *Node) GetId() int64 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *Node) GetAsOf() *timestamppb.Timestamp { + if x != nil { + return x.AsOf + } + return nil +} + +func (x *Node) GetKey() []byte { + if x != nil { + return x.Key + } + return nil +} + +func (x *Node) GetDisco() string { + if x != nil { + return x.Disco + } + return "" +} + +func (x *Node) GetPreferredDerp() int32 { + if x != nil { + return x.PreferredDerp + } + return 0 +} + +func (x *Node) GetDerpLatency() map[string]float64 { + if x != nil { + return x.DerpLatency + } + return nil +} + +func (x *Node) GetDerpForcedWebsocket() map[int32]string { + if x != nil { + return x.DerpForcedWebsocket + } + return nil +} + +func (x *Node) GetAddresses() []string { + if x != nil { + return x.Addresses + } + return nil +} + +func (x *Node) GetAllowedIps() []string { + if x != nil { + return x.AllowedIps + } + return nil +} + +func (x *Node) GetEndpoints() []string { + if x != nil { + return x.Endpoints + } + return nil +} + +type CoordinateRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UpdateSelf *CoordinateRequest_UpdateSelf `protobuf:"bytes,1,opt,name=update_self,json=updateSelf,proto3" json:"update_self,omitempty"` + Disconnect *CoordinateRequest_Disconnect `protobuf:"bytes,2,opt,name=disconnect,proto3" json:"disconnect,omitempty"` + AddTunnel *CoordinateRequest_Tunnel `protobuf:"bytes,3,opt,name=add_tunnel,json=addTunnel,proto3" json:"add_tunnel,omitempty"` + RemoveTunnel *CoordinateRequest_Tunnel `protobuf:"bytes,4,opt,name=remove_tunnel,json=removeTunnel,proto3" json:"remove_tunnel,omitempty"` +} + +func (x *CoordinateRequest) Reset() { + *x = CoordinateRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_tailnet_proto_tailnet_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CoordinateRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CoordinateRequest) ProtoMessage() {} + +func (x *CoordinateRequest) ProtoReflect() protoreflect.Message { + mi := &file_tailnet_proto_tailnet_proto_msgTypes[3] + 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 CoordinateRequest.ProtoReflect.Descriptor instead. +func (*CoordinateRequest) Descriptor() ([]byte, []int) { + return file_tailnet_proto_tailnet_proto_rawDescGZIP(), []int{3} +} + +func (x *CoordinateRequest) GetUpdateSelf() *CoordinateRequest_UpdateSelf { + if x != nil { + return x.UpdateSelf + } + return nil +} + +func (x *CoordinateRequest) GetDisconnect() *CoordinateRequest_Disconnect { + if x != nil { + return x.Disconnect + } + return nil +} + +func (x *CoordinateRequest) GetAddTunnel() *CoordinateRequest_Tunnel { + if x != nil { + return x.AddTunnel + } + return nil +} + +func (x *CoordinateRequest) GetRemoveTunnel() *CoordinateRequest_Tunnel { + if x != nil { + return x.RemoveTunnel + } + return nil +} + +type CoordinateResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + PeerUpdates []*CoordinateResponse_PeerUpdate `protobuf:"bytes,1,rep,name=peer_updates,json=peerUpdates,proto3" json:"peer_updates,omitempty"` +} + +func (x *CoordinateResponse) Reset() { + *x = CoordinateResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_tailnet_proto_tailnet_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CoordinateResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CoordinateResponse) ProtoMessage() {} + +func (x *CoordinateResponse) ProtoReflect() protoreflect.Message { + mi := &file_tailnet_proto_tailnet_proto_msgTypes[4] + 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 CoordinateResponse.ProtoReflect.Descriptor instead. +func (*CoordinateResponse) Descriptor() ([]byte, []int) { + return file_tailnet_proto_tailnet_proto_rawDescGZIP(), []int{4} +} + +func (x *CoordinateResponse) GetPeerUpdates() []*CoordinateResponse_PeerUpdate { + if x != nil { + return x.PeerUpdates + } + return nil +} + +type DERPMap_HomeParams struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RegionScore map[int32]float64 `protobuf:"bytes,1,rep,name=region_score,json=regionScore,proto3" json:"region_score,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"fixed64,2,opt,name=value,proto3"` +} + +func (x *DERPMap_HomeParams) Reset() { + *x = DERPMap_HomeParams{} + if protoimpl.UnsafeEnabled { + mi := &file_tailnet_proto_tailnet_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DERPMap_HomeParams) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DERPMap_HomeParams) ProtoMessage() {} + +func (x *DERPMap_HomeParams) ProtoReflect() protoreflect.Message { + mi := &file_tailnet_proto_tailnet_proto_msgTypes[5] + 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 DERPMap_HomeParams.ProtoReflect.Descriptor instead. +func (*DERPMap_HomeParams) Descriptor() ([]byte, []int) { + return file_tailnet_proto_tailnet_proto_rawDescGZIP(), []int{0, 0} +} + +func (x *DERPMap_HomeParams) GetRegionScore() map[int32]float64 { + if x != nil { + return x.RegionScore + } + return nil +} + +type DERPMap_Region struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RegionId int32 `protobuf:"varint,1,opt,name=region_id,json=regionId,proto3" json:"region_id,omitempty"` + EmbeddedRelay bool `protobuf:"varint,2,opt,name=embedded_relay,json=embeddedRelay,proto3" json:"embedded_relay,omitempty"` + RegionCode string `protobuf:"bytes,3,opt,name=region_code,json=regionCode,proto3" json:"region_code,omitempty"` + RegionName string `protobuf:"bytes,4,opt,name=region_name,json=regionName,proto3" json:"region_name,omitempty"` + Avoid bool `protobuf:"varint,5,opt,name=avoid,proto3" json:"avoid,omitempty"` + Nodes []*DERPMap_Region_Node `protobuf:"bytes,6,rep,name=nodes,proto3" json:"nodes,omitempty"` +} + +func (x *DERPMap_Region) Reset() { + *x = DERPMap_Region{} + if protoimpl.UnsafeEnabled { + mi := &file_tailnet_proto_tailnet_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DERPMap_Region) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DERPMap_Region) ProtoMessage() {} + +func (x *DERPMap_Region) ProtoReflect() protoreflect.Message { + mi := &file_tailnet_proto_tailnet_proto_msgTypes[6] + 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 DERPMap_Region.ProtoReflect.Descriptor instead. +func (*DERPMap_Region) Descriptor() ([]byte, []int) { + return file_tailnet_proto_tailnet_proto_rawDescGZIP(), []int{0, 1} +} + +func (x *DERPMap_Region) GetRegionId() int32 { + if x != nil { + return x.RegionId + } + return 0 +} + +func (x *DERPMap_Region) GetEmbeddedRelay() bool { + if x != nil { + return x.EmbeddedRelay + } + return false +} + +func (x *DERPMap_Region) GetRegionCode() string { + if x != nil { + return x.RegionCode + } + return "" +} + +func (x *DERPMap_Region) GetRegionName() string { + if x != nil { + return x.RegionName + } + return "" +} + +func (x *DERPMap_Region) GetAvoid() bool { + if x != nil { + return x.Avoid + } + return false +} + +func (x *DERPMap_Region) GetNodes() []*DERPMap_Region_Node { + if x != nil { + return x.Nodes + } + return nil +} + +type DERPMap_Region_Node struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + RegionId int32 `protobuf:"varint,2,opt,name=region_id,json=regionId,proto3" json:"region_id,omitempty"` + HostName string `protobuf:"bytes,3,opt,name=host_name,json=hostName,proto3" json:"host_name,omitempty"` + CertName string `protobuf:"bytes,4,opt,name=cert_name,json=certName,proto3" json:"cert_name,omitempty"` + Ipv4 string `protobuf:"bytes,5,opt,name=ipv4,proto3" json:"ipv4,omitempty"` + Ipv6 string `protobuf:"bytes,6,opt,name=ipv6,proto3" json:"ipv6,omitempty"` + StunPort int32 `protobuf:"varint,7,opt,name=stun_port,json=stunPort,proto3" json:"stun_port,omitempty"` + StunOnly bool `protobuf:"varint,8,opt,name=stun_only,json=stunOnly,proto3" json:"stun_only,omitempty"` + DerpPort int32 `protobuf:"varint,9,opt,name=derp_port,json=derpPort,proto3" json:"derp_port,omitempty"` + InsecureForTests bool `protobuf:"varint,10,opt,name=insecure_for_tests,json=insecureForTests,proto3" json:"insecure_for_tests,omitempty"` + ForceHttp bool `protobuf:"varint,11,opt,name=force_http,json=forceHttp,proto3" json:"force_http,omitempty"` + StunTestIp string `protobuf:"bytes,12,opt,name=stun_test_ip,json=stunTestIp,proto3" json:"stun_test_ip,omitempty"` + CanPort_80 bool `protobuf:"varint,13,opt,name=can_port_80,json=canPort80,proto3" json:"can_port_80,omitempty"` +} + +func (x *DERPMap_Region_Node) Reset() { + *x = DERPMap_Region_Node{} + if protoimpl.UnsafeEnabled { + mi := &file_tailnet_proto_tailnet_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DERPMap_Region_Node) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DERPMap_Region_Node) ProtoMessage() {} + +func (x *DERPMap_Region_Node) ProtoReflect() protoreflect.Message { + mi := &file_tailnet_proto_tailnet_proto_msgTypes[9] + 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 DERPMap_Region_Node.ProtoReflect.Descriptor instead. +func (*DERPMap_Region_Node) Descriptor() ([]byte, []int) { + return file_tailnet_proto_tailnet_proto_rawDescGZIP(), []int{0, 1, 0} +} + +func (x *DERPMap_Region_Node) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *DERPMap_Region_Node) GetRegionId() int32 { + if x != nil { + return x.RegionId + } + return 0 +} + +func (x *DERPMap_Region_Node) GetHostName() string { + if x != nil { + return x.HostName + } + return "" +} + +func (x *DERPMap_Region_Node) GetCertName() string { + if x != nil { + return x.CertName + } + return "" +} + +func (x *DERPMap_Region_Node) GetIpv4() string { + if x != nil { + return x.Ipv4 + } + return "" +} + +func (x *DERPMap_Region_Node) GetIpv6() string { + if x != nil { + return x.Ipv6 + } + return "" +} + +func (x *DERPMap_Region_Node) GetStunPort() int32 { + if x != nil { + return x.StunPort + } + return 0 +} + +func (x *DERPMap_Region_Node) GetStunOnly() bool { + if x != nil { + return x.StunOnly + } + return false +} + +func (x *DERPMap_Region_Node) GetDerpPort() int32 { + if x != nil { + return x.DerpPort + } + return 0 +} + +func (x *DERPMap_Region_Node) GetInsecureForTests() bool { + if x != nil { + return x.InsecureForTests + } + return false +} + +func (x *DERPMap_Region_Node) GetForceHttp() bool { + if x != nil { + return x.ForceHttp + } + return false +} + +func (x *DERPMap_Region_Node) GetStunTestIp() string { + if x != nil { + return x.StunTestIp + } + return "" +} + +func (x *DERPMap_Region_Node) GetCanPort_80() bool { + if x != nil { + return x.CanPort_80 + } + return false +} + +type CoordinateRequest_UpdateSelf struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` +} + +func (x *CoordinateRequest_UpdateSelf) Reset() { + *x = CoordinateRequest_UpdateSelf{} + if protoimpl.UnsafeEnabled { + mi := &file_tailnet_proto_tailnet_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CoordinateRequest_UpdateSelf) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CoordinateRequest_UpdateSelf) ProtoMessage() {} + +func (x *CoordinateRequest_UpdateSelf) ProtoReflect() protoreflect.Message { + mi := &file_tailnet_proto_tailnet_proto_msgTypes[12] + 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 CoordinateRequest_UpdateSelf.ProtoReflect.Descriptor instead. +func (*CoordinateRequest_UpdateSelf) Descriptor() ([]byte, []int) { + return file_tailnet_proto_tailnet_proto_rawDescGZIP(), []int{3, 0} +} + +func (x *CoordinateRequest_UpdateSelf) GetNode() *Node { + if x != nil { + return x.Node + } + return nil +} + +type CoordinateRequest_Disconnect struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *CoordinateRequest_Disconnect) Reset() { + *x = CoordinateRequest_Disconnect{} + if protoimpl.UnsafeEnabled { + mi := &file_tailnet_proto_tailnet_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CoordinateRequest_Disconnect) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CoordinateRequest_Disconnect) ProtoMessage() {} + +func (x *CoordinateRequest_Disconnect) ProtoReflect() protoreflect.Message { + mi := &file_tailnet_proto_tailnet_proto_msgTypes[13] + 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 CoordinateRequest_Disconnect.ProtoReflect.Descriptor instead. +func (*CoordinateRequest_Disconnect) Descriptor() ([]byte, []int) { + return file_tailnet_proto_tailnet_proto_rawDescGZIP(), []int{3, 1} +} + +type CoordinateRequest_Tunnel struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Uuid []byte `protobuf:"bytes,1,opt,name=uuid,proto3" json:"uuid,omitempty"` +} + +func (x *CoordinateRequest_Tunnel) Reset() { + *x = CoordinateRequest_Tunnel{} + if protoimpl.UnsafeEnabled { + mi := &file_tailnet_proto_tailnet_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CoordinateRequest_Tunnel) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CoordinateRequest_Tunnel) ProtoMessage() {} + +func (x *CoordinateRequest_Tunnel) ProtoReflect() protoreflect.Message { + mi := &file_tailnet_proto_tailnet_proto_msgTypes[14] + 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 CoordinateRequest_Tunnel.ProtoReflect.Descriptor instead. +func (*CoordinateRequest_Tunnel) Descriptor() ([]byte, []int) { + return file_tailnet_proto_tailnet_proto_rawDescGZIP(), []int{3, 2} +} + +func (x *CoordinateRequest_Tunnel) GetUuid() []byte { + if x != nil { + return x.Uuid + } + return nil +} + +type CoordinateResponse_PeerUpdate struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Uuid []byte `protobuf:"bytes,1,opt,name=uuid,proto3" json:"uuid,omitempty"` + Node *Node `protobuf:"bytes,2,opt,name=node,proto3" json:"node,omitempty"` + Kind CoordinateResponse_PeerUpdate_Kind `protobuf:"varint,3,opt,name=kind,proto3,enum=coder.tailnet.v2.CoordinateResponse_PeerUpdate_Kind" json:"kind,omitempty"` + Reason string `protobuf:"bytes,4,opt,name=reason,proto3" json:"reason,omitempty"` +} + +func (x *CoordinateResponse_PeerUpdate) Reset() { + *x = CoordinateResponse_PeerUpdate{} + if protoimpl.UnsafeEnabled { + mi := &file_tailnet_proto_tailnet_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CoordinateResponse_PeerUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CoordinateResponse_PeerUpdate) ProtoMessage() {} + +func (x *CoordinateResponse_PeerUpdate) ProtoReflect() protoreflect.Message { + mi := &file_tailnet_proto_tailnet_proto_msgTypes[15] + 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 CoordinateResponse_PeerUpdate.ProtoReflect.Descriptor instead. +func (*CoordinateResponse_PeerUpdate) Descriptor() ([]byte, []int) { + return file_tailnet_proto_tailnet_proto_rawDescGZIP(), []int{4, 0} +} + +func (x *CoordinateResponse_PeerUpdate) GetUuid() []byte { + if x != nil { + return x.Uuid + } + return nil +} + +func (x *CoordinateResponse_PeerUpdate) GetNode() *Node { + if x != nil { + return x.Node + } + return nil +} + +func (x *CoordinateResponse_PeerUpdate) GetKind() CoordinateResponse_PeerUpdate_Kind { + if x != nil { + return x.Kind + } + return CoordinateResponse_PeerUpdate_KIND_UNSPECIFIED +} + +func (x *CoordinateResponse_PeerUpdate) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +var File_tailnet_proto_tailnet_proto protoreflect.FileDescriptor + +var file_tailnet_proto_tailnet_proto_rawDesc = []byte{ + 0x0a, 0x1b, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, + 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x63, + 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x1a, + 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x22, 0xff, 0x07, 0x0a, 0x07, 0x44, 0x45, 0x52, 0x50, 0x4d, 0x61, 0x70, 0x12, 0x45, 0x0a, 0x0b, + 0x68, 0x6f, 0x6d, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x24, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, + 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x45, 0x52, 0x50, 0x4d, 0x61, 0x70, 0x2e, 0x48, 0x6f, 0x6d, + 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x0a, 0x68, 0x6f, 0x6d, 0x65, 0x50, 0x61, 0x72, + 0x61, 0x6d, 0x73, 0x12, 0x40, 0x0a, 0x07, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, + 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x45, 0x52, 0x50, 0x4d, 0x61, 0x70, 0x2e, + 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x72, 0x65, + 0x67, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0xa6, 0x01, 0x0a, 0x0a, 0x48, 0x6f, 0x6d, 0x65, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x73, 0x12, 0x58, 0x0a, 0x0c, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x73, + 0x63, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x63, 0x6f, 0x64, + 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x45, + 0x52, 0x50, 0x4d, 0x61, 0x70, 0x2e, 0x48, 0x6f, 0x6d, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, + 0x2e, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x0b, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x1a, 0x3e, + 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0xe3, + 0x04, 0x0a, 0x06, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x67, + 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x72, 0x65, + 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x65, 0x6d, 0x62, 0x65, 0x64, 0x64, + 0x65, 0x64, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, + 0x65, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x1f, 0x0a, + 0x0b, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1f, + 0x0a, 0x0b, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x14, 0x0a, 0x05, 0x61, 0x76, 0x6f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, + 0x61, 0x76, 0x6f, 0x69, 0x64, 0x12, 0x3b, 0x0a, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x06, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, + 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x45, 0x52, 0x50, 0x4d, 0x61, 0x70, 0x2e, + 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x05, 0x6e, 0x6f, 0x64, + 0x65, 0x73, 0x1a, 0xff, 0x02, 0x0a, 0x04, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x08, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, + 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x68, 0x6f, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x65, 0x72, + 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x65, + 0x72, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x70, 0x76, 0x34, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x70, 0x76, 0x34, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x70, + 0x76, 0x36, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x70, 0x76, 0x36, 0x12, 0x1b, + 0x0a, 0x09, 0x73, 0x74, 0x75, 0x6e, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x08, 0x73, 0x74, 0x75, 0x6e, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x73, + 0x74, 0x75, 0x6e, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, + 0x73, 0x74, 0x75, 0x6e, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x72, 0x70, + 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x64, 0x65, 0x72, + 0x70, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, + 0x65, 0x5f, 0x66, 0x6f, 0x72, 0x5f, 0x74, 0x65, 0x73, 0x74, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x10, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x46, 0x6f, 0x72, 0x54, 0x65, + 0x73, 0x74, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x5f, 0x68, 0x74, 0x74, + 0x70, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x48, 0x74, + 0x74, 0x70, 0x12, 0x20, 0x0a, 0x0c, 0x73, 0x74, 0x75, 0x6e, 0x5f, 0x74, 0x65, 0x73, 0x74, 0x5f, + 0x69, 0x70, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x74, 0x75, 0x6e, 0x54, 0x65, + 0x73, 0x74, 0x49, 0x70, 0x12, 0x1e, 0x0a, 0x0b, 0x63, 0x61, 0x6e, 0x5f, 0x70, 0x6f, 0x72, 0x74, + 0x5f, 0x38, 0x30, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x63, 0x61, 0x6e, 0x50, 0x6f, + 0x72, 0x74, 0x38, 0x30, 0x1a, 0x5c, 0x0a, 0x0c, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x73, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x36, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, + 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x45, 0x52, 0x50, 0x4d, 0x61, 0x70, + 0x2e, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x22, 0x17, 0x0a, 0x15, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x44, 0x45, 0x52, 0x50, + 0x4d, 0x61, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xac, 0x04, 0x0a, 0x04, + 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x02, 0x69, 0x64, 0x12, 0x2f, 0x0a, 0x05, 0x61, 0x73, 0x5f, 0x6f, 0x66, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, + 0x04, 0x61, 0x73, 0x4f, 0x66, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x69, 0x73, 0x63, 0x6f, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x12, 0x25, 0x0a, + 0x0e, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, 0x5f, 0x64, 0x65, 0x72, 0x70, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, + 0x44, 0x65, 0x72, 0x70, 0x12, 0x4a, 0x0a, 0x0c, 0x64, 0x65, 0x72, 0x70, 0x5f, 0x6c, 0x61, 0x74, + 0x65, 0x6e, 0x63, 0x79, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x63, 0x6f, 0x64, + 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x4e, 0x6f, + 0x64, 0x65, 0x2e, 0x44, 0x65, 0x72, 0x70, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x0b, 0x64, 0x65, 0x72, 0x70, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, + 0x12, 0x63, 0x0a, 0x15, 0x64, 0x65, 0x72, 0x70, 0x5f, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x64, 0x5f, + 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x2f, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, + 0x76, 0x32, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x2e, 0x44, 0x65, 0x72, 0x70, 0x46, 0x6f, 0x72, 0x63, + 0x65, 0x64, 0x57, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x13, 0x64, 0x65, 0x72, 0x70, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x64, 0x57, 0x65, 0x62, 0x73, + 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x69, + 0x70, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, + 0x64, 0x49, 0x70, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x73, 0x1a, 0x3e, 0x0a, 0x10, 0x44, 0x65, 0x72, 0x70, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, + 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x1a, 0x46, 0x0a, 0x18, 0x44, 0x65, 0x72, 0x70, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x64, + 0x57, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xb6, 0x03, 0x0a, 0x11, 0x43, + 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x4f, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x65, 0x6c, 0x66, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, + 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x53, 0x65, 0x6c, 0x66, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x6c, + 0x66, 0x12, 0x4e, 0x0a, 0x0a, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, + 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x0a, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x12, 0x49, 0x0a, 0x0a, 0x61, 0x64, 0x64, 0x5f, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, + 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x54, 0x75, 0x6e, 0x6e, 0x65, + 0x6c, 0x52, 0x09, 0x61, 0x64, 0x64, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x4f, 0x0a, 0x0d, + 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x5f, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, + 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x52, + 0x0c, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x1a, 0x38, 0x0a, + 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x6c, 0x66, 0x12, 0x2a, 0x0a, 0x04, 0x6e, + 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x6f, 0x64, 0x65, + 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x4e, 0x6f, 0x64, + 0x65, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x1a, 0x0c, 0x0a, 0x0a, 0x44, 0x69, 0x73, 0x63, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x1a, 0x1c, 0x0a, 0x06, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x12, + 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x75, + 0x75, 0x69, 0x64, 0x22, 0xdd, 0x02, 0x0a, 0x12, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, + 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, 0x0c, 0x70, 0x65, + 0x65, 0x72, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x2f, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, + 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x52, 0x0b, 0x70, 0x65, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x1a, 0xf2, + 0x01, 0x0a, 0x0a, 0x50, 0x65, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, + 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x75, 0x75, 0x69, + 0x64, 0x12, 0x2a, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x16, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, + 0x76, 0x32, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x48, 0x0a, + 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x34, 0x2e, 0x63, 0x6f, + 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x43, + 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x4b, 0x69, 0x6e, + 0x64, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, + 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, + 0x42, 0x0a, 0x04, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x14, 0x0a, 0x10, 0x4b, 0x49, 0x4e, 0x44, 0x5f, + 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x08, 0x0a, + 0x04, 0x4e, 0x4f, 0x44, 0x45, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x49, 0x53, 0x43, 0x4f, + 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x4c, 0x4f, 0x53, + 0x54, 0x10, 0x03, 0x32, 0xc4, 0x01, 0x0a, 0x06, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x56, + 0x0a, 0x0e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x44, 0x45, 0x52, 0x50, 0x4d, 0x61, 0x70, 0x73, + 0x12, 0x27, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, + 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x44, 0x45, 0x52, 0x50, 0x4d, 0x61, + 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x63, 0x6f, 0x64, 0x65, + 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x45, 0x52, + 0x50, 0x4d, 0x61, 0x70, 0x30, 0x01, 0x12, 0x62, 0x0a, 0x11, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, + 0x6e, 0x61, 0x74, 0x65, 0x54, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x12, 0x23, 0x2e, 0x63, 0x6f, + 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x43, + 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x24, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, + 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x42, 0x29, 0x5a, 0x27, 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, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_tailnet_proto_tailnet_proto_rawDescOnce sync.Once + file_tailnet_proto_tailnet_proto_rawDescData = file_tailnet_proto_tailnet_proto_rawDesc +) + +func file_tailnet_proto_tailnet_proto_rawDescGZIP() []byte { + file_tailnet_proto_tailnet_proto_rawDescOnce.Do(func() { + file_tailnet_proto_tailnet_proto_rawDescData = protoimpl.X.CompressGZIP(file_tailnet_proto_tailnet_proto_rawDescData) + }) + return file_tailnet_proto_tailnet_proto_rawDescData +} + +var file_tailnet_proto_tailnet_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_tailnet_proto_tailnet_proto_msgTypes = make([]protoimpl.MessageInfo, 16) +var file_tailnet_proto_tailnet_proto_goTypes = []interface{}{ + (CoordinateResponse_PeerUpdate_Kind)(0), // 0: coder.tailnet.v2.CoordinateResponse.PeerUpdate.Kind + (*DERPMap)(nil), // 1: coder.tailnet.v2.DERPMap + (*StreamDERPMapsRequest)(nil), // 2: coder.tailnet.v2.StreamDERPMapsRequest + (*Node)(nil), // 3: coder.tailnet.v2.Node + (*CoordinateRequest)(nil), // 4: coder.tailnet.v2.CoordinateRequest + (*CoordinateResponse)(nil), // 5: coder.tailnet.v2.CoordinateResponse + (*DERPMap_HomeParams)(nil), // 6: coder.tailnet.v2.DERPMap.HomeParams + (*DERPMap_Region)(nil), // 7: coder.tailnet.v2.DERPMap.Region + nil, // 8: coder.tailnet.v2.DERPMap.RegionsEntry + nil, // 9: coder.tailnet.v2.DERPMap.HomeParams.RegionScoreEntry + (*DERPMap_Region_Node)(nil), // 10: coder.tailnet.v2.DERPMap.Region.Node + nil, // 11: coder.tailnet.v2.Node.DerpLatencyEntry + nil, // 12: coder.tailnet.v2.Node.DerpForcedWebsocketEntry + (*CoordinateRequest_UpdateSelf)(nil), // 13: coder.tailnet.v2.CoordinateRequest.UpdateSelf + (*CoordinateRequest_Disconnect)(nil), // 14: coder.tailnet.v2.CoordinateRequest.Disconnect + (*CoordinateRequest_Tunnel)(nil), // 15: coder.tailnet.v2.CoordinateRequest.Tunnel + (*CoordinateResponse_PeerUpdate)(nil), // 16: coder.tailnet.v2.CoordinateResponse.PeerUpdate + (*timestamppb.Timestamp)(nil), // 17: google.protobuf.Timestamp +} +var file_tailnet_proto_tailnet_proto_depIdxs = []int32{ + 6, // 0: coder.tailnet.v2.DERPMap.home_params:type_name -> coder.tailnet.v2.DERPMap.HomeParams + 8, // 1: coder.tailnet.v2.DERPMap.regions:type_name -> coder.tailnet.v2.DERPMap.RegionsEntry + 17, // 2: coder.tailnet.v2.Node.as_of:type_name -> google.protobuf.Timestamp + 11, // 3: coder.tailnet.v2.Node.derp_latency:type_name -> coder.tailnet.v2.Node.DerpLatencyEntry + 12, // 4: coder.tailnet.v2.Node.derp_forced_websocket:type_name -> coder.tailnet.v2.Node.DerpForcedWebsocketEntry + 13, // 5: coder.tailnet.v2.CoordinateRequest.update_self:type_name -> coder.tailnet.v2.CoordinateRequest.UpdateSelf + 14, // 6: coder.tailnet.v2.CoordinateRequest.disconnect:type_name -> coder.tailnet.v2.CoordinateRequest.Disconnect + 15, // 7: coder.tailnet.v2.CoordinateRequest.add_tunnel:type_name -> coder.tailnet.v2.CoordinateRequest.Tunnel + 15, // 8: coder.tailnet.v2.CoordinateRequest.remove_tunnel:type_name -> coder.tailnet.v2.CoordinateRequest.Tunnel + 16, // 9: coder.tailnet.v2.CoordinateResponse.peer_updates:type_name -> coder.tailnet.v2.CoordinateResponse.PeerUpdate + 9, // 10: coder.tailnet.v2.DERPMap.HomeParams.region_score:type_name -> coder.tailnet.v2.DERPMap.HomeParams.RegionScoreEntry + 10, // 11: coder.tailnet.v2.DERPMap.Region.nodes:type_name -> coder.tailnet.v2.DERPMap.Region.Node + 7, // 12: coder.tailnet.v2.DERPMap.RegionsEntry.value:type_name -> coder.tailnet.v2.DERPMap.Region + 3, // 13: coder.tailnet.v2.CoordinateRequest.UpdateSelf.node:type_name -> coder.tailnet.v2.Node + 3, // 14: coder.tailnet.v2.CoordinateResponse.PeerUpdate.node:type_name -> coder.tailnet.v2.Node + 0, // 15: coder.tailnet.v2.CoordinateResponse.PeerUpdate.kind:type_name -> coder.tailnet.v2.CoordinateResponse.PeerUpdate.Kind + 2, // 16: coder.tailnet.v2.Client.StreamDERPMaps:input_type -> coder.tailnet.v2.StreamDERPMapsRequest + 4, // 17: coder.tailnet.v2.Client.CoordinateTailnet:input_type -> coder.tailnet.v2.CoordinateRequest + 1, // 18: coder.tailnet.v2.Client.StreamDERPMaps:output_type -> coder.tailnet.v2.DERPMap + 5, // 19: coder.tailnet.v2.Client.CoordinateTailnet:output_type -> coder.tailnet.v2.CoordinateResponse + 18, // [18:20] is the sub-list for method output_type + 16, // [16:18] is the sub-list for method input_type + 16, // [16:16] is the sub-list for extension type_name + 16, // [16:16] is the sub-list for extension extendee + 0, // [0:16] is the sub-list for field type_name +} + +func init() { file_tailnet_proto_tailnet_proto_init() } +func file_tailnet_proto_tailnet_proto_init() { + if File_tailnet_proto_tailnet_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_tailnet_proto_tailnet_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DERPMap); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tailnet_proto_tailnet_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StreamDERPMapsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tailnet_proto_tailnet_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Node); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tailnet_proto_tailnet_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CoordinateRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tailnet_proto_tailnet_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CoordinateResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tailnet_proto_tailnet_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DERPMap_HomeParams); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tailnet_proto_tailnet_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DERPMap_Region); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tailnet_proto_tailnet_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DERPMap_Region_Node); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tailnet_proto_tailnet_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CoordinateRequest_UpdateSelf); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tailnet_proto_tailnet_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CoordinateRequest_Disconnect); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tailnet_proto_tailnet_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CoordinateRequest_Tunnel); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tailnet_proto_tailnet_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CoordinateResponse_PeerUpdate); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_tailnet_proto_tailnet_proto_rawDesc, + NumEnums: 1, + NumMessages: 16, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_tailnet_proto_tailnet_proto_goTypes, + DependencyIndexes: file_tailnet_proto_tailnet_proto_depIdxs, + EnumInfos: file_tailnet_proto_tailnet_proto_enumTypes, + MessageInfos: file_tailnet_proto_tailnet_proto_msgTypes, + }.Build() + File_tailnet_proto_tailnet_proto = out.File + file_tailnet_proto_tailnet_proto_rawDesc = nil + file_tailnet_proto_tailnet_proto_goTypes = nil + file_tailnet_proto_tailnet_proto_depIdxs = nil +} diff --git a/tailnet/proto/tailnet.proto b/tailnet/proto/tailnet.proto new file mode 100644 index 0000000000000..8c3a1e1163916 --- /dev/null +++ b/tailnet/proto/tailnet.proto @@ -0,0 +1,94 @@ +syntax = "proto3"; +option go_package = "github.com/coder/coder/v2/tailnet/proto"; + +package coder.tailnet.v2; + +import "google/protobuf/timestamp.proto"; + +message DERPMap { + message HomeParams { + map region_score = 1; + } + HomeParams home_params = 1; + + message Region { + int32 region_id = 1; + bool embedded_relay = 2; + string region_code = 3; + string region_name = 4; + bool avoid = 5; + + message Node { + string name = 1; + int32 region_id = 2; + string host_name = 3; + string cert_name = 4; + string ipv4 = 5; + string ipv6 = 6; + int32 stun_port = 7; + bool stun_only = 8; + int32 derp_port = 9; + bool insecure_for_tests = 10; + bool force_http = 11; + string stun_test_ip = 12; + bool can_port_80 = 13; + } + repeated Node nodes = 6; + } + map regions = 2; +} + +message StreamDERPMapsRequest {} + +// defined in tailnet/coordinator.go +message Node { + int64 id = 1; + google.protobuf.Timestamp as_of = 2; + bytes key = 3; + string disco = 4; + int32 preferred_derp = 5; + map derp_latency = 6; + map derp_forced_websocket = 7; + repeated string addresses = 8; + repeated string allowed_ips = 9; + repeated string endpoints = 10; +} + +message CoordinateRequest { + message UpdateSelf { + Node node = 1; + } + UpdateSelf update_self = 1; + + message Disconnect {} + Disconnect disconnect = 2; + + message Tunnel { + bytes uuid = 1; + } + Tunnel add_tunnel = 3; + Tunnel remove_tunnel = 4; +} + +message CoordinateResponse { + message PeerUpdate { + bytes uuid = 1; + Node node = 2; + + enum Kind { + KIND_UNSPECIFIED = 0; + NODE = 1; + DISCONNECTED = 2; + LOST = 3; + } + Kind kind = 3; + + string reason = 4; + } + repeated PeerUpdate peer_updates = 1; +} + +service Client { + rpc StreamDERPMaps(StreamDERPMapsRequest) returns (stream DERPMap); + rpc CoordinateTailnet(stream CoordinateRequest) returns (stream CoordinateResponse); +} diff --git a/tailnet/proto/tailnet_drpc.pb.go b/tailnet/proto/tailnet_drpc.pb.go new file mode 100644 index 0000000000000..0e0476870426e --- /dev/null +++ b/tailnet/proto/tailnet_drpc.pb.go @@ -0,0 +1,218 @@ +// Code generated by protoc-gen-go-drpc. DO NOT EDIT. +// protoc-gen-go-drpc version: v0.0.33 +// source: tailnet/proto/tailnet.proto + +package proto + +import ( + context "context" + errors "errors" + protojson "google.golang.org/protobuf/encoding/protojson" + proto "google.golang.org/protobuf/proto" + drpc "storj.io/drpc" + drpcerr "storj.io/drpc/drpcerr" +) + +type drpcEncoding_File_tailnet_proto_tailnet_proto struct{} + +func (drpcEncoding_File_tailnet_proto_tailnet_proto) Marshal(msg drpc.Message) ([]byte, error) { + return proto.Marshal(msg.(proto.Message)) +} + +func (drpcEncoding_File_tailnet_proto_tailnet_proto) MarshalAppend(buf []byte, msg drpc.Message) ([]byte, error) { + return proto.MarshalOptions{}.MarshalAppend(buf, msg.(proto.Message)) +} + +func (drpcEncoding_File_tailnet_proto_tailnet_proto) Unmarshal(buf []byte, msg drpc.Message) error { + return proto.Unmarshal(buf, msg.(proto.Message)) +} + +func (drpcEncoding_File_tailnet_proto_tailnet_proto) JSONMarshal(msg drpc.Message) ([]byte, error) { + return protojson.Marshal(msg.(proto.Message)) +} + +func (drpcEncoding_File_tailnet_proto_tailnet_proto) JSONUnmarshal(buf []byte, msg drpc.Message) error { + return protojson.Unmarshal(buf, msg.(proto.Message)) +} + +type DRPCClientClient interface { + DRPCConn() drpc.Conn + + StreamDERPMaps(ctx context.Context, in *StreamDERPMapsRequest) (DRPCClient_StreamDERPMapsClient, error) + CoordinateTailnet(ctx context.Context) (DRPCClient_CoordinateTailnetClient, error) +} + +type drpcClientClient struct { + cc drpc.Conn +} + +func NewDRPCClientClient(cc drpc.Conn) DRPCClientClient { + return &drpcClientClient{cc} +} + +func (c *drpcClientClient) DRPCConn() drpc.Conn { return c.cc } + +func (c *drpcClientClient) StreamDERPMaps(ctx context.Context, in *StreamDERPMapsRequest) (DRPCClient_StreamDERPMapsClient, error) { + stream, err := c.cc.NewStream(ctx, "/coder.tailnet.v2.Client/StreamDERPMaps", drpcEncoding_File_tailnet_proto_tailnet_proto{}) + if err != nil { + return nil, err + } + x := &drpcClient_StreamDERPMapsClient{stream} + if err := x.MsgSend(in, drpcEncoding_File_tailnet_proto_tailnet_proto{}); err != nil { + return nil, err + } + if err := x.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type DRPCClient_StreamDERPMapsClient interface { + drpc.Stream + Recv() (*DERPMap, error) +} + +type drpcClient_StreamDERPMapsClient struct { + drpc.Stream +} + +func (x *drpcClient_StreamDERPMapsClient) GetStream() drpc.Stream { + return x.Stream +} + +func (x *drpcClient_StreamDERPMapsClient) Recv() (*DERPMap, error) { + m := new(DERPMap) + if err := x.MsgRecv(m, drpcEncoding_File_tailnet_proto_tailnet_proto{}); err != nil { + return nil, err + } + return m, nil +} + +func (x *drpcClient_StreamDERPMapsClient) RecvMsg(m *DERPMap) error { + return x.MsgRecv(m, drpcEncoding_File_tailnet_proto_tailnet_proto{}) +} + +func (c *drpcClientClient) CoordinateTailnet(ctx context.Context) (DRPCClient_CoordinateTailnetClient, error) { + stream, err := c.cc.NewStream(ctx, "/coder.tailnet.v2.Client/CoordinateTailnet", drpcEncoding_File_tailnet_proto_tailnet_proto{}) + if err != nil { + return nil, err + } + x := &drpcClient_CoordinateTailnetClient{stream} + return x, nil +} + +type DRPCClient_CoordinateTailnetClient interface { + drpc.Stream + Send(*CoordinateRequest) error + Recv() (*CoordinateResponse, error) +} + +type drpcClient_CoordinateTailnetClient struct { + drpc.Stream +} + +func (x *drpcClient_CoordinateTailnetClient) GetStream() drpc.Stream { + return x.Stream +} + +func (x *drpcClient_CoordinateTailnetClient) Send(m *CoordinateRequest) error { + return x.MsgSend(m, drpcEncoding_File_tailnet_proto_tailnet_proto{}) +} + +func (x *drpcClient_CoordinateTailnetClient) Recv() (*CoordinateResponse, error) { + m := new(CoordinateResponse) + if err := x.MsgRecv(m, drpcEncoding_File_tailnet_proto_tailnet_proto{}); err != nil { + return nil, err + } + return m, nil +} + +func (x *drpcClient_CoordinateTailnetClient) RecvMsg(m *CoordinateResponse) error { + return x.MsgRecv(m, drpcEncoding_File_tailnet_proto_tailnet_proto{}) +} + +type DRPCClientServer interface { + StreamDERPMaps(*StreamDERPMapsRequest, DRPCClient_StreamDERPMapsStream) error + CoordinateTailnet(DRPCClient_CoordinateTailnetStream) error +} + +type DRPCClientUnimplementedServer struct{} + +func (s *DRPCClientUnimplementedServer) StreamDERPMaps(*StreamDERPMapsRequest, DRPCClient_StreamDERPMapsStream) error { + return drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) +} + +func (s *DRPCClientUnimplementedServer) CoordinateTailnet(DRPCClient_CoordinateTailnetStream) error { + return drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) +} + +type DRPCClientDescription struct{} + +func (DRPCClientDescription) NumMethods() int { return 2 } + +func (DRPCClientDescription) Method(n int) (string, drpc.Encoding, drpc.Receiver, interface{}, bool) { + switch n { + case 0: + return "/coder.tailnet.v2.Client/StreamDERPMaps", drpcEncoding_File_tailnet_proto_tailnet_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return nil, srv.(DRPCClientServer). + StreamDERPMaps( + in1.(*StreamDERPMapsRequest), + &drpcClient_StreamDERPMapsStream{in2.(drpc.Stream)}, + ) + }, DRPCClientServer.StreamDERPMaps, true + case 1: + return "/coder.tailnet.v2.Client/CoordinateTailnet", drpcEncoding_File_tailnet_proto_tailnet_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return nil, srv.(DRPCClientServer). + CoordinateTailnet( + &drpcClient_CoordinateTailnetStream{in1.(drpc.Stream)}, + ) + }, DRPCClientServer.CoordinateTailnet, true + default: + return "", nil, nil, nil, false + } +} + +func DRPCRegisterClient(mux drpc.Mux, impl DRPCClientServer) error { + return mux.Register(impl, DRPCClientDescription{}) +} + +type DRPCClient_StreamDERPMapsStream interface { + drpc.Stream + Send(*DERPMap) error +} + +type drpcClient_StreamDERPMapsStream struct { + drpc.Stream +} + +func (x *drpcClient_StreamDERPMapsStream) Send(m *DERPMap) error { + return x.MsgSend(m, drpcEncoding_File_tailnet_proto_tailnet_proto{}) +} + +type DRPCClient_CoordinateTailnetStream interface { + drpc.Stream + Send(*CoordinateResponse) error + Recv() (*CoordinateRequest, error) +} + +type drpcClient_CoordinateTailnetStream struct { + drpc.Stream +} + +func (x *drpcClient_CoordinateTailnetStream) Send(m *CoordinateResponse) error { + return x.MsgSend(m, drpcEncoding_File_tailnet_proto_tailnet_proto{}) +} + +func (x *drpcClient_CoordinateTailnetStream) Recv() (*CoordinateRequest, error) { + m := new(CoordinateRequest) + if err := x.MsgRecv(m, drpcEncoding_File_tailnet_proto_tailnet_proto{}); err != nil { + return nil, err + } + return m, nil +} + +func (x *drpcClient_CoordinateTailnetStream) RecvMsg(m *CoordinateRequest) error { + return x.MsgRecv(m, drpcEncoding_File_tailnet_proto_tailnet_proto{}) +}