mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
chore: add additional fields to license telemetry (#11173)
This sends the email the license was issued to, and whether or not it's a trial in the telemetry payload. It's a bit janky since the license parsing is all enterprise licensed.
This commit is contained in:
@@ -788,6 +788,22 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
||||
Prometheus: vals.Prometheus.Enable.Value(),
|
||||
STUN: len(vals.DERP.Server.STUNAddresses) != 0,
|
||||
Tunnel: tunnel != nil,
|
||||
ParseLicenseJWT: func(lic *telemetry.License) error {
|
||||
// This will be nil when running in AGPL-only mode.
|
||||
if options.ParseLicenseClaims == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
email, trial, err := options.ParseLicenseClaims(lic.JWT)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if email != "" {
|
||||
lic.Email = &email
|
||||
}
|
||||
lic.Trial = &trial
|
||||
return nil
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("create telemetry reporter: %w", err)
|
||||
|
||||
@@ -174,6 +174,11 @@ type Options struct {
|
||||
StatsBatcher *batchstats.Batcher
|
||||
|
||||
WorkspaceAppsStatsCollectorOptions workspaceapps.StatsCollectorOptions
|
||||
|
||||
// This janky function is used in telemetry to parse fields out of the raw
|
||||
// JWT. It needs to be passed through like this because license parsing is
|
||||
// under the enterprise license, and can't be imported into AGPL.
|
||||
ParseLicenseClaims func(rawJWT string) (email string, trial bool, err error)
|
||||
}
|
||||
|
||||
// @title Coder API
|
||||
|
||||
@@ -52,6 +52,7 @@ type Options struct {
|
||||
STUN bool
|
||||
SnapshotFrequency time.Duration
|
||||
Tunnel bool
|
||||
ParseLicenseJWT func(lic *License) error
|
||||
}
|
||||
|
||||
// New constructs a reporter for telemetry data.
|
||||
@@ -446,7 +447,13 @@ func (r *remoteReporter) createSnapshot() (*Snapshot, error) {
|
||||
}
|
||||
snapshot.Licenses = make([]License, 0, len(licenses))
|
||||
for _, license := range licenses {
|
||||
snapshot.Licenses = append(snapshot.Licenses, ConvertLicense(license))
|
||||
tl := ConvertLicense(license)
|
||||
if r.options.ParseLicenseJWT != nil {
|
||||
if err := r.options.ParseLicenseJWT(&tl); err != nil {
|
||||
r.options.Logger.Warn(ctx, "parse license JWT", slog.Error(err))
|
||||
}
|
||||
}
|
||||
snapshot.Licenses = append(snapshot.Licenses, tl)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@@ -904,6 +911,10 @@ type License struct {
|
||||
UploadedAt time.Time `json:"uploaded_at"`
|
||||
Exp time.Time `json:"exp"`
|
||||
UUID uuid.UUID `json:"uuid"`
|
||||
// These two fields are set by decoding the JWT. If the signing keys aren't
|
||||
// passed in, these will always be nil.
|
||||
Email *string `json:"email"`
|
||||
Trial *bool `json:"trial"`
|
||||
}
|
||||
|
||||
type WorkspaceProxy struct {
|
||||
|
||||
@@ -109,6 +109,13 @@ func New(ctx context.Context, options *Options) (_ *API, err error) {
|
||||
}
|
||||
}()
|
||||
|
||||
api.AGPL.Options.ParseLicenseClaims = func(rawJWT string) (email string, trial bool, err error) {
|
||||
c, err := license.ParseClaims(rawJWT, Keys)
|
||||
if err != nil {
|
||||
return "", false, err
|
||||
}
|
||||
return c.Subject, c.Trial, nil
|
||||
}
|
||||
api.AGPL.Options.SetUserGroups = api.setUserGroups
|
||||
api.AGPL.Options.SetUserSiteRoles = api.setUserSiteRoles
|
||||
api.AGPL.SiteHandler.AppearanceFetcher = api.fetchAppearanceConfig
|
||||
|
||||
@@ -9,9 +9,8 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/coder/coder/v2/coderd/database"
|
||||
"github.com/coder/coder/v2/coderd/database/dbtime"
|
||||
|
||||
Reference in New Issue
Block a user