(ctx context.Context)
| 840 | } |
| 841 | |
| 842 | func (api *API) updateEntitlements(ctx context.Context) error { |
| 843 | return api.Entitlements.Update(ctx, func(ctx context.Context) (codersdk.Entitlements, error) { |
| 844 | replicas := api.replicaManager.AllPrimary() |
| 845 | agedReplicas := make([]database.Replica, 0, len(replicas)) |
| 846 | for _, replica := range replicas { |
| 847 | // If a replica is less than the update interval old, we don't |
| 848 | // want to display a warning. In the open-source version of Coder, |
| 849 | // Kubernetes Pods will start up before shutting down the other, |
| 850 | // and we don't want to display a warning in that case. |
| 851 | // |
| 852 | // Only display warnings for long-lived replicas! |
| 853 | if dbtime.Now().Sub(replica.StartedAt) < api.ReplicaErrorGracePeriod { |
| 854 | continue |
| 855 | } |
| 856 | agedReplicas = append(agedReplicas, replica) |
| 857 | } |
| 858 | |
| 859 | reloadedEntitlements, err := license.Entitlements( |
| 860 | ctx, api.Database, |
| 861 | len(agedReplicas), len(api.ExternalAuthConfigs), api.LicenseKeys, map[codersdk.FeatureName]bool{ |
| 862 | codersdk.FeatureAuditLog: api.AuditLogging, |
| 863 | codersdk.FeatureConnectionLog: api.ConnectionLogging, |
| 864 | codersdk.FeatureBrowserOnly: api.BrowserOnly, |
| 865 | codersdk.FeatureSCIM: len(api.SCIMAPIKey) != 0, |
| 866 | codersdk.FeatureMultipleExternalAuth: len(api.ExternalAuthConfigs) > 1, |
| 867 | codersdk.FeatureTemplateRBAC: api.RBAC, |
| 868 | codersdk.FeatureExternalTokenEncryption: len(api.ExternalTokenEncryption) > 0, |
| 869 | codersdk.FeatureExternalProvisionerDaemons: true, |
| 870 | codersdk.FeatureAdvancedTemplateScheduling: true, |
| 871 | codersdk.FeatureWorkspaceProxy: true, |
| 872 | codersdk.FeatureUserRoleManagement: true, |
| 873 | codersdk.FeatureAccessControl: true, |
| 874 | codersdk.FeatureControlSharedPorts: true, |
| 875 | codersdk.FeatureAIBridge: api.DeploymentValues.AI.BridgeConfig.Enabled.Value(), |
| 876 | }) |
| 877 | if err != nil { |
| 878 | return codersdk.Entitlements{}, err |
| 879 | } |
| 880 | |
| 881 | if reloadedEntitlements.RequireTelemetry && !api.DeploymentValues.Telemetry.Enable.Value() { |
| 882 | api.Logger.Error(ctx, "license requires telemetry enabled") |
| 883 | return codersdk.Entitlements{}, entitlements.ErrLicenseRequiresTelemetry |
| 884 | } |
| 885 | |
| 886 | featureChanged := func(featureName codersdk.FeatureName) (initial, changed, enabled bool) { |
| 887 | return api.Entitlements.FeatureChanged(featureName, reloadedEntitlements.Features[featureName]) |
| 888 | } |
| 889 | |
| 890 | shouldUpdate := func(initial, changed, enabled bool) bool { |
| 891 | // Avoid an initial tick on startup unless the feature is enabled. |
| 892 | return changed || (initial && enabled) |
| 893 | } |
| 894 | |
| 895 | if initial, changed, enabled := featureChanged(codersdk.FeatureAuditLog); shouldUpdate(initial, changed, enabled) { |
| 896 | auditor := agplaudit.NewNop() |
| 897 | if enabled { |
| 898 | auditor = api.AGPL.Options.Auditor |
| 899 | } |
no test coverage detected