mirror of
https://github.com/coder/coder.git
synced 2026-09-21 12:44:32 +08:00
fix: write server config to telemetry (#13590)
* fix: add external auth configs to telemetry * Refactor telemetry to send the entire config * gen * Fix linting
This commit is contained in:
+10
-23
@@ -796,31 +796,18 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
||||
cliui.Infof(inv.Stdout, "\n==> Logs will stream in below (press ctrl+c to gracefully exit):")
|
||||
|
||||
if vals.Telemetry.Enable {
|
||||
gitAuth := make([]telemetry.GitAuth, 0)
|
||||
// TODO:
|
||||
gitAuthConfigs := make([]codersdk.ExternalAuthConfig, 0)
|
||||
for _, cfg := range gitAuthConfigs {
|
||||
gitAuth = append(gitAuth, telemetry.GitAuth{
|
||||
Type: cfg.Type,
|
||||
})
|
||||
vals, err := vals.WithoutSecrets()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("remove secrets from deployment values: %w", err)
|
||||
}
|
||||
|
||||
options.Telemetry, err = telemetry.New(telemetry.Options{
|
||||
BuiltinPostgres: builtinPostgres,
|
||||
DeploymentID: deploymentID,
|
||||
Database: options.Database,
|
||||
Logger: logger.Named("telemetry"),
|
||||
URL: vals.Telemetry.URL.Value(),
|
||||
Wildcard: vals.WildcardAccessURL.String() != "",
|
||||
DERPServerRelayURL: vals.DERP.Server.RelayURL.String(),
|
||||
GitAuth: gitAuth,
|
||||
GitHubOAuth: vals.OAuth2.Github.ClientID != "",
|
||||
OIDCAuth: vals.OIDC.ClientID != "",
|
||||
OIDCIssuerURL: vals.OIDC.IssuerURL.String(),
|
||||
Prometheus: vals.Prometheus.Enable.Value(),
|
||||
STUN: len(vals.DERP.Server.STUNAddresses) != 0,
|
||||
Tunnel: tunnel != nil,
|
||||
Experiments: vals.Experiments.Value(),
|
||||
BuiltinPostgres: builtinPostgres,
|
||||
DeploymentID: deploymentID,
|
||||
Database: options.Database,
|
||||
Logger: logger.Named("telemetry"),
|
||||
URL: vals.Telemetry.URL.Value(),
|
||||
Tunnel: tunnel != nil,
|
||||
DeploymentConfig: vals,
|
||||
ParseLicenseJWT: func(lic *telemetry.License) error {
|
||||
// This will be nil when running in AGPL-only mode.
|
||||
if options.ParseLicenseClaims == nil {
|
||||
|
||||
Generated
-6
@@ -9349,12 +9349,6 @@ const docTemplate = `{
|
||||
"description": "DisplayName is shown in the UI to identify the auth config.",
|
||||
"type": "string"
|
||||
},
|
||||
"extra_token_keys": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"id": {
|
||||
"description": "ID is a unique identifier for the auth config.\nIt defaults to ` + "`" + `type` + "`" + ` when not provided.",
|
||||
"type": "string"
|
||||
|
||||
Generated
-6
@@ -8379,12 +8379,6 @@
|
||||
"description": "DisplayName is shown in the UI to identify the auth config.",
|
||||
"type": "string"
|
||||
},
|
||||
"extra_token_keys": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"id": {
|
||||
"description": "ID is a unique identifier for the auth config.\nIt defaults to `type` when not provided.",
|
||||
"type": "string"
|
||||
|
||||
@@ -41,20 +41,13 @@ type Options struct {
|
||||
// URL is an endpoint to direct telemetry towards!
|
||||
URL *url.URL
|
||||
|
||||
BuiltinPostgres bool
|
||||
DeploymentID string
|
||||
GitHubOAuth bool
|
||||
OIDCAuth bool
|
||||
OIDCIssuerURL string
|
||||
Wildcard bool
|
||||
DERPServerRelayURL string
|
||||
GitAuth []GitAuth
|
||||
Prometheus bool
|
||||
STUN bool
|
||||
SnapshotFrequency time.Duration
|
||||
Tunnel bool
|
||||
ParseLicenseJWT func(lic *License) error
|
||||
Experiments []string
|
||||
DeploymentID string
|
||||
DeploymentConfig *codersdk.DeploymentValues
|
||||
BuiltinPostgres bool
|
||||
Tunnel bool
|
||||
|
||||
SnapshotFrequency time.Duration
|
||||
ParseLicenseJWT func(lic *License) error
|
||||
}
|
||||
|
||||
// New constructs a reporter for telemetry data.
|
||||
@@ -242,31 +235,24 @@ func (r *remoteReporter) deployment() error {
|
||||
}
|
||||
|
||||
data, err := json.Marshal(&Deployment{
|
||||
ID: r.options.DeploymentID,
|
||||
Architecture: sysInfo.Architecture,
|
||||
BuiltinPostgres: r.options.BuiltinPostgres,
|
||||
Containerized: containerized,
|
||||
Wildcard: r.options.Wildcard,
|
||||
DERPServerRelayURL: r.options.DERPServerRelayURL,
|
||||
GitAuth: r.options.GitAuth,
|
||||
Kubernetes: os.Getenv("KUBERNETES_SERVICE_HOST") != "",
|
||||
GitHubOAuth: r.options.GitHubOAuth,
|
||||
OIDCAuth: r.options.OIDCAuth,
|
||||
OIDCIssuerURL: r.options.OIDCIssuerURL,
|
||||
Prometheus: r.options.Prometheus,
|
||||
InstallSource: installSource,
|
||||
STUN: r.options.STUN,
|
||||
Tunnel: r.options.Tunnel,
|
||||
OSType: sysInfo.OS.Type,
|
||||
OSFamily: sysInfo.OS.Family,
|
||||
OSPlatform: sysInfo.OS.Platform,
|
||||
OSName: sysInfo.OS.Name,
|
||||
OSVersion: sysInfo.OS.Version,
|
||||
CPUCores: runtime.NumCPU(),
|
||||
MemoryTotal: mem.Total,
|
||||
MachineID: sysInfo.UniqueID,
|
||||
StartedAt: r.startedAt,
|
||||
ShutdownAt: r.shutdownAt,
|
||||
ID: r.options.DeploymentID,
|
||||
Architecture: sysInfo.Architecture,
|
||||
BuiltinPostgres: r.options.BuiltinPostgres,
|
||||
Containerized: containerized,
|
||||
Config: r.options.DeploymentConfig,
|
||||
Kubernetes: os.Getenv("KUBERNETES_SERVICE_HOST") != "",
|
||||
InstallSource: installSource,
|
||||
Tunnel: r.options.Tunnel,
|
||||
OSType: sysInfo.OS.Type,
|
||||
OSFamily: sysInfo.OS.Family,
|
||||
OSPlatform: sysInfo.OS.Platform,
|
||||
OSName: sysInfo.OS.Name,
|
||||
OSVersion: sysInfo.OS.Version,
|
||||
CPUCores: runtime.NumCPU(),
|
||||
MemoryTotal: mem.Total,
|
||||
MachineID: sysInfo.UniqueID,
|
||||
StartedAt: r.startedAt,
|
||||
ShutdownAt: r.shutdownAt,
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("marshal deployment: %w", err)
|
||||
@@ -481,10 +467,6 @@ func (r *remoteReporter) createSnapshot() (*Snapshot, error) {
|
||||
}
|
||||
return nil
|
||||
})
|
||||
eg.Go(func() error {
|
||||
snapshot.Experiments = ConvertExperiments(r.options.Experiments)
|
||||
return nil
|
||||
})
|
||||
|
||||
err := eg.Wait()
|
||||
if err != nil {
|
||||
@@ -745,16 +727,6 @@ func ConvertExternalProvisioner(id uuid.UUID, tags map[string]string, provisione
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertExperiments(experiments []string) []Experiment {
|
||||
var out []Experiment
|
||||
|
||||
for _, exp := range experiments {
|
||||
out = append(out, Experiment{Name: exp})
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// 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.
|
||||
@@ -777,40 +749,28 @@ type Snapshot struct {
|
||||
WorkspaceResourceMetadata []WorkspaceResourceMetadata `json:"workspace_resource_metadata"`
|
||||
WorkspaceResources []WorkspaceResource `json:"workspace_resources"`
|
||||
Workspaces []Workspace `json:"workspaces"`
|
||||
Experiments []Experiment `json:"experiments"`
|
||||
}
|
||||
|
||||
// Deployment contains information about the host running Coder.
|
||||
type Deployment struct {
|
||||
ID string `json:"id"`
|
||||
Architecture string `json:"architecture"`
|
||||
BuiltinPostgres bool `json:"builtin_postgres"`
|
||||
Containerized bool `json:"containerized"`
|
||||
Kubernetes bool `json:"kubernetes"`
|
||||
Tunnel bool `json:"tunnel"`
|
||||
Wildcard bool `json:"wildcard"`
|
||||
DERPServerRelayURL string `json:"derp_server_relay_url"`
|
||||
GitAuth []GitAuth `json:"git_auth"`
|
||||
GitHubOAuth bool `json:"github_oauth"`
|
||||
OIDCAuth bool `json:"oidc_auth"`
|
||||
OIDCIssuerURL string `json:"oidc_issuer_url"`
|
||||
Prometheus bool `json:"prometheus"`
|
||||
InstallSource string `json:"install_source"`
|
||||
STUN bool `json:"stun"`
|
||||
OSType string `json:"os_type"`
|
||||
OSFamily string `json:"os_family"`
|
||||
OSPlatform string `json:"os_platform"`
|
||||
OSName string `json:"os_name"`
|
||||
OSVersion string `json:"os_version"`
|
||||
CPUCores int `json:"cpu_cores"`
|
||||
MemoryTotal uint64 `json:"memory_total"`
|
||||
MachineID string `json:"machine_id"`
|
||||
StartedAt time.Time `json:"started_at"`
|
||||
ShutdownAt *time.Time `json:"shutdown_at"`
|
||||
}
|
||||
|
||||
type GitAuth struct {
|
||||
Type string `json:"type"`
|
||||
ID string `json:"id"`
|
||||
Architecture string `json:"architecture"`
|
||||
BuiltinPostgres bool `json:"builtin_postgres"`
|
||||
Containerized bool `json:"containerized"`
|
||||
Kubernetes bool `json:"kubernetes"`
|
||||
Config *codersdk.DeploymentValues `json:"config"`
|
||||
Tunnel bool `json:"tunnel"`
|
||||
InstallSource string `json:"install_source"`
|
||||
OSType string `json:"os_type"`
|
||||
OSFamily string `json:"os_family"`
|
||||
OSPlatform string `json:"os_platform"`
|
||||
OSName string `json:"os_name"`
|
||||
OSVersion string `json:"os_version"`
|
||||
CPUCores int `json:"cpu_cores"`
|
||||
MemoryTotal uint64 `json:"memory_total"`
|
||||
MachineID string `json:"machine_id"`
|
||||
StartedAt time.Time `json:"started_at"`
|
||||
ShutdownAt *time.Time `json:"shutdown_at"`
|
||||
}
|
||||
|
||||
type APIKey struct {
|
||||
@@ -985,10 +945,6 @@ type ExternalProvisioner struct {
|
||||
ShutdownAt *time.Time `json:"shutdown_at"`
|
||||
}
|
||||
|
||||
type Experiment struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type noopReporter struct{}
|
||||
|
||||
func (*noopReporter) Report(_ *Snapshot) {}
|
||||
|
||||
@@ -114,17 +114,6 @@ func TestTelemetry(t *testing.T) {
|
||||
require.Len(t, snapshot.Users, 1)
|
||||
require.Equal(t, snapshot.Users[0].EmailHashed, "bb44bf07cf9a2db0554bba63a03d822c927deae77df101874496df5a6a3e896d@coder.com")
|
||||
})
|
||||
t.Run("Experiments", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const expName = "my-experiment"
|
||||
exps := []string{expName}
|
||||
_, snapshot := collectSnapshot(t, dbmem.New(), func(opts telemetry.Options) telemetry.Options {
|
||||
opts.Experiments = exps
|
||||
return opts
|
||||
})
|
||||
require.Equal(t, []telemetry.Experiment{{Name: expName}}, snapshot.Experiments)
|
||||
})
|
||||
}
|
||||
|
||||
// nolint:paralleltest
|
||||
|
||||
@@ -393,7 +393,7 @@ type ExternalAuthConfig struct {
|
||||
AppInstallationsURL string `json:"app_installations_url" yaml:"app_installations_url"`
|
||||
NoRefresh bool `json:"no_refresh" yaml:"no_refresh"`
|
||||
Scopes []string `json:"scopes" yaml:"scopes"`
|
||||
ExtraTokenKeys []string `json:"extra_token_keys" yaml:"extra_token_keys"`
|
||||
ExtraTokenKeys []string `json:"-" yaml:"extra_token_keys"`
|
||||
DeviceFlow bool `json:"device_flow" yaml:"device_flow"`
|
||||
DeviceCodeURL string `json:"device_code_url" yaml:"device_code_url"`
|
||||
// Regex allows API requesters to match an auth config by
|
||||
|
||||
Generated
-1
@@ -227,7 +227,6 @@ curl -X GET http://coder-server:8080/api/v2/deployment/config \
|
||||
"device_flow": true,
|
||||
"display_icon": "string",
|
||||
"display_name": "string",
|
||||
"extra_token_keys": ["string"],
|
||||
"id": "string",
|
||||
"no_refresh": true,
|
||||
"regex": "string",
|
||||
|
||||
Generated
-5
@@ -1646,7 +1646,6 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
|
||||
"device_flow": true,
|
||||
"display_icon": "string",
|
||||
"display_name": "string",
|
||||
"extra_token_keys": ["string"],
|
||||
"id": "string",
|
||||
"no_refresh": true,
|
||||
"regex": "string",
|
||||
@@ -2020,7 +2019,6 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
|
||||
"device_flow": true,
|
||||
"display_icon": "string",
|
||||
"display_name": "string",
|
||||
"extra_token_keys": ["string"],
|
||||
"id": "string",
|
||||
"no_refresh": true,
|
||||
"regex": "string",
|
||||
@@ -2441,7 +2439,6 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
|
||||
"device_flow": true,
|
||||
"display_icon": "string",
|
||||
"display_name": "string",
|
||||
"extra_token_keys": ["string"],
|
||||
"id": "string",
|
||||
"no_refresh": true,
|
||||
"regex": "string",
|
||||
@@ -2464,7 +2461,6 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
|
||||
| `device_flow` | boolean | false | | |
|
||||
| `display_icon` | string | false | | Display icon is a URL to an icon to display in the UI. |
|
||||
| `display_name` | string | false | | Display name is shown in the UI to identify the auth config. |
|
||||
| `extra_token_keys` | array of string | false | | |
|
||||
| `id` | string | false | | ID is a unique identifier for the auth config. It defaults to `type` when not provided. |
|
||||
| `no_refresh` | boolean | false | | |
|
||||
| `regex` | string | false | | Regex allows API requesters to match an auth config by a string (e.g. coder.com) instead of by it's type. |
|
||||
@@ -8546,7 +8542,6 @@ _None_
|
||||
"device_flow": true,
|
||||
"display_icon": "string",
|
||||
"display_name": "string",
|
||||
"extra_token_keys": ["string"],
|
||||
"id": "string",
|
||||
"no_refresh": true,
|
||||
"regex": "string",
|
||||
|
||||
Generated
-1
@@ -509,7 +509,6 @@ export interface ExternalAuthConfig {
|
||||
readonly app_installations_url: string;
|
||||
readonly no_refresh: boolean;
|
||||
readonly scopes: readonly string[];
|
||||
readonly extra_token_keys: readonly string[];
|
||||
readonly device_flow: boolean;
|
||||
readonly device_code_url: string;
|
||||
readonly regex: string;
|
||||
|
||||
-1
@@ -19,7 +19,6 @@ const meta: Meta<typeof ExternalAuthSettingsPageView> = {
|
||||
app_installations_url: "",
|
||||
no_refresh: false,
|
||||
scopes: [],
|
||||
extra_token_keys: [],
|
||||
device_flow: true,
|
||||
device_code_url: "",
|
||||
display_icon: "",
|
||||
|
||||
Reference in New Issue
Block a user