@@ -3,6 +3,7 @@ package license
33import (
44"context"
55"crypto/ed25519"
6+ "database/sql"
67"fmt"
78"math"
89"time"
@@ -94,10 +95,34 @@ func Entitlements(
9495return codersdk.Entitlements {},xerrors .Errorf ("query active user count: %w" ,err )
9596}
9697
98+ // nolint:gocritic // Getting external workspaces is a system function.
99+ externalWorkspaces ,err := db .GetWorkspaces (dbauthz .AsSystemRestricted (ctx ), database.GetWorkspacesParams {
100+ HasExternalAgent : sql.NullBool {
101+ Bool :true ,
102+ Valid :true ,
103+ },
104+ })
105+ if err != nil {
106+ return codersdk.Entitlements {},xerrors .Errorf ("query external workspaces: %w" ,err )
107+ }
108+
109+ // nolint:gocritic // Getting external templates is a system function.
110+ externalTemplates ,err := db .GetTemplatesWithFilter (dbauthz .AsSystemRestricted (ctx ), database.GetTemplatesWithFilterParams {
111+ HasExternalAgent : sql.NullBool {
112+ Bool :true ,
113+ Valid :true ,
114+ },
115+ })
116+ if err != nil {
117+ return codersdk.Entitlements {},xerrors .Errorf ("query external templates: %w" ,err )
118+ }
119+
97120entitlements ,err := LicensesEntitlements (ctx ,now ,licenses ,enablements ,keys ,FeatureArguments {
98- ActiveUserCount :activeUserCount ,
99- ReplicaCount :replicaCount ,
100- ExternalAuthCount :externalAuthCount ,
121+ ActiveUserCount :activeUserCount ,
122+ ReplicaCount :replicaCount ,
123+ ExternalAuthCount :externalAuthCount ,
124+ ExternalWorkspaceCount :int64 (len (externalWorkspaces )),
125+ ExternalTemplateCount :int64 (len (externalTemplates )),
101126ManagedAgentCountFn :func (ctx context.Context ,startTime time.Time ,endTime time.Time ) (int64 ,error ) {
102127// nolint:gocritic // Requires permission to read all workspaces to read managed agent count.
103128return db .GetManagedAgentCount (dbauthz .AsSystemRestricted (ctx ), database.GetManagedAgentCountParams {
@@ -114,9 +139,11 @@ func Entitlements(
114139}
115140
116141type FeatureArguments struct {
117- ActiveUserCount int64
118- ReplicaCount int
119- ExternalAuthCount int
142+ ActiveUserCount int64
143+ ReplicaCount int
144+ ExternalAuthCount int
145+ ExternalWorkspaceCount int64
146+ ExternalTemplateCount int64
120147// Unfortunately, managed agent count is not a simple count of the current
121148// state of the world, but a count between two points in time determined by
122149// the licenses.
@@ -418,6 +445,30 @@ func LicensesEntitlements(
418445}
419446}
420447
448+ if featureArguments .ExternalWorkspaceCount > 0 {
449+ feature := entitlements .Features [codersdk .FeatureWorkspaceExternalAgent ]
450+ switch feature .Entitlement {
451+ case codersdk .EntitlementNotEntitled :
452+ entitlements .Errors = append (entitlements .Errors ,
453+ "You have external workspaces but your license is not entitled to this feature." )
454+ case codersdk .EntitlementGracePeriod :
455+ entitlements .Warnings = append (entitlements .Warnings ,
456+ "You have external workspaces but your license is expired." )
457+ }
458+ }
459+
460+ if featureArguments .ExternalTemplateCount > 0 {
461+ feature := entitlements .Features [codersdk .FeatureWorkspaceExternalAgent ]
462+ switch feature .Entitlement {
463+ case codersdk .EntitlementNotEntitled :
464+ entitlements .Errors = append (entitlements .Errors ,
465+ "You have templates which use external agents but your license is not entitled to this feature." )
466+ case codersdk .EntitlementGracePeriod :
467+ entitlements .Warnings = append (entitlements .Warnings ,
468+ "You have templates which use external agents but your license is expired." )
469+ }
470+ }
471+
421472// Managed agent warnings are applied based on usage period. We only
422473// generate a warning if the license actually has managed agents.
423474// Note that agents are free when unlicensed.