diff --git a/coderd/telemetry/telemetry.go b/coderd/telemetry/telemetry.go index ced52a58fd273..834118a0d8a98 100644 --- a/coderd/telemetry/telemetry.go +++ b/coderd/telemetry/telemetry.go @@ -22,7 +22,6 @@ import ( "golang.org/x/xerrors" "cdr.dev/slog" - "github.com/coder/coder/buildinfo" "github.com/coder/coder/coderd/database" ) @@ -460,6 +459,17 @@ func (r *remoteReporter) createSnapshot() (*Snapshot, error) { } return nil }) + eg.Go(func() error { + proxies, err := r.options.Database.GetWorkspaceProxies(ctx) + if err != nil { + return xerrors.Errorf("get workspace proxies: %w", err) + } + snapshot.WorkspaceProxies = make([]WorkspaceProxy, 0, len(proxies)) + for _, proxy := range proxies { + snapshot.WorkspaceProxies = append(snapshot.WorkspaceProxies, ConvertWorkspaceProxy(proxy)) + } + return nil + }) err := eg.Wait() if err != nil { @@ -665,6 +675,19 @@ func ConvertLicense(license database.License) License { } } +// ConvertWorkspaceProxy anonymizes a workspace proxy. +func ConvertWorkspaceProxy(proxy database.WorkspaceProxy) WorkspaceProxy { + return WorkspaceProxy{ + ID: proxy.ID, + Name: proxy.Name, + DisplayName: proxy.DisplayName, + DerpEnabled: proxy.DerpEnabled, + DerpOnly: proxy.DerpOnly, + CreatedAt: proxy.CreatedAt, + UpdatedAt: proxy.UpdatedAt, + } +} + // Snapshot represents a point-in-time anonymized database dump. // Data is aggregated by latest on the server-side, so partial data // can be sent without issue. @@ -684,6 +707,7 @@ type Snapshot struct { WorkspaceBuilds []WorkspaceBuild `json:"workspace_build"` WorkspaceResources []WorkspaceResource `json:"workspace_resources"` WorkspaceResourceMetadata []WorkspaceResourceMetadata `json:"workspace_resource_metadata"` + WorkspaceProxies []WorkspaceProxy `json:"workspace_proxies"` CLIInvocations []CLIInvocation `json:"cli_invocations"` } @@ -872,6 +896,18 @@ type CLIInvocation struct { InvokedAt time.Time `json:"invoked_at"` } +type WorkspaceProxy struct { + ID uuid.UUID `json:"id"` + Name string `json:"name"` + DisplayName string `json:"display_name"` + // No URLs since we don't send deployment URL. + DerpEnabled bool `json:"derp_enabled"` + DerpOnly bool `json:"derp_only"` + // No Status since it may contain sensitive information. + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + type noopReporter struct{} func (*noopReporter) Report(_ *Snapshot) {} diff --git a/coderd/telemetry/telemetry_test.go b/coderd/telemetry/telemetry_test.go index 93e1a5295475b..28569f1ca98e4 100644 --- a/coderd/telemetry/telemetry_test.go +++ b/coderd/telemetry/telemetry_test.go @@ -81,6 +81,8 @@ func TestTelemetry(t *testing.T) { UUID: uuid.New(), }) assert.NoError(t, err) + _, _ = dbgen.WorkspaceProxy(t, db, database.WorkspaceProxy{}) + _, snapshot := collectSnapshot(t, db) require.Len(t, snapshot.ProvisionerJobs, 1) require.Len(t, snapshot.Licenses, 1) @@ -93,6 +95,7 @@ func TestTelemetry(t *testing.T) { require.Len(t, snapshot.WorkspaceBuilds, 1) require.Len(t, snapshot.WorkspaceResources, 1) require.Len(t, snapshot.WorkspaceAgentStats, 1) + require.Len(t, snapshot.WorkspaceProxies, 1) wsa := snapshot.WorkspaceAgents[0] require.Equal(t, string(database.WorkspaceAgentSubsystemEnvbox), wsa.Subsystem) diff --git a/enterprise/coderd/workspaceproxy.go b/enterprise/coderd/workspaceproxy.go index 591f2fa33374f..54279953920de 100644 --- a/enterprise/coderd/workspaceproxy.go +++ b/enterprise/coderd/workspaceproxy.go @@ -23,6 +23,7 @@ import ( "github.com/coder/coder/coderd/httpapi" "github.com/coder/coder/coderd/httpmw" "github.com/coder/coder/coderd/rbac" + "github.com/coder/coder/coderd/telemetry" "github.com/coder/coder/coderd/workspaceapps" "github.com/coder/coder/codersdk" "github.com/coder/coder/cryptorand" @@ -369,6 +370,10 @@ func (api *API) postWorkspaceProxy(rw http.ResponseWriter, r *http.Request) { return } + api.Telemetry.Report(&telemetry.Snapshot{ + WorkspaceProxies: []telemetry.WorkspaceProxy{telemetry.ConvertWorkspaceProxy(proxy)}, + }) + aReq.New = proxy httpapi.Write(ctx, rw, http.StatusCreated, codersdk.UpdateWorkspaceProxyResponse{ Proxy: convertProxy(proxy, proxyhealth.ProxyStatus{