Documentation
¶
Index ¶
- Constants
- Variables
- func ValidateUniqueConstraint(ents []Entitlement) error
- type Access
- type AlreadyDeletedError
- type AlreadyExistsError
- type CreateEntitlementGrantInputs
- type CreateEntitlementInputs
- type CreateEntitlementRepoInputs
- type Entitlement
- type EntitlementCreatedEventV2
- type EntitlementDeletedEventV2
- type EntitlementRepo
- type EntitlementType
- type EntitlementValue
- type EntitlementValueWithId
- type EntitlementWithCustomer
- type ForbiddenError
- type GenericProperties
- type InvalidFeatureError
- type InvalidValueError
- type ListEntitlementsOrderBy
- type ListEntitlementsParams
- type ListEntitlementsWithCustomerResult
- type ListExpiredEntitlementsParams
- type MeasureUsageFromEnum
- type MeasureUsageFromInput
- type NoAccessValue
- type NotFoundError
- type Service
- type SubTypeConnector
- type TypedEntitlement
- type UniquenessConstraintError
- type UpdateEntitlementUsagePeriodParams
- type UpsertEntitlementCurrentPeriodElement
- type UsagePeriod
- func (u UsagePeriod) Equal(other UsagePeriod) bool
- func (u UsagePeriod) GetCurrentPeriodAt(at time.Time) (timeutil.ClosedPeriod, error)
- func (u *UsagePeriod) GetOriginalValueAsUsagePeriodInput() *UsagePeriodInput
- func (u UsagePeriod) GetResetTimelineInclusive(inPeriod timeutil.ClosedPeriod) (timeutil.SimpleTimeline, error)
- func (u UsagePeriod) GetUsagePeriodInputAt(at time.Time) (UsagePeriodInput, int, error)
- func (u UsagePeriod) MarshalJSON() ([]byte, error)
- func (u *UsagePeriod) UnmarshalJSON(data []byte) error
- func (u UsagePeriod) Validate() error
- type UsagePeriodInput
- type WrongTypeError
Constants ¶
const ErrCodeEntitlementCreatePropertyMismatch models.ErrorCode = "entitlement_create_property_mismatch"
const ErrCodeEntitlementGrantsOnlySupportedForMeteredEntitlements models.ErrorCode = "entitlement_grants_only_supported_for_metered_entitlements"
const (
EventSubsystem metadata.EventSubsystem = "entitlement"
)
Variables ¶
var ErrEntitlementCreatePropertyMismatch = models.NewValidationIssue( ErrCodeEntitlementCreatePropertyMismatch, "entitlement create property mismatch", )
var ErrEntitlementGrantsOnlySupportedForMeteredEntitlements = models.NewValidationIssue( ErrCodeEntitlementGrantsOnlySupportedForMeteredEntitlements, "grants are only supported for metered entitlements", )
var MAX_SAFE_ITERATIONS = 1000000
Functions ¶
func ValidateUniqueConstraint ¶
func ValidateUniqueConstraint(ents []Entitlement) error
ValidateUniqueConstraint validates the uniqueness constraints of the entitlements The constraint is formally stated as follows:
For entitlement E 1. The ActiveFromTime is E.ActiveFrom or E.CreatedAt (if E.ActiveFrom is nil) 2. The ActiveToTime is E.ActiveTo or E.DeletedAt (if E.ActiveTo is nil). This can be nil.
Entitlement E is active at time T if and only if: 1. E.ActiveFromTime <= T and E.ActiveToTime > T 2. E.ActiveFromTime <= T and E.ActiveToTime is nil
For a set of unique entitlements S, where all E in S share the same feature (by key) and customer: 1. Let T1 be the first ActiveFromTime for any E in S sorted ascending 2. Let T2 be the last ActiveToTime for any E in S sorted ascending
The constraint:
For all E in S at any time T where T1 <= T < T2, there is at most one E that is active.
Types ¶
type Access ¶
type Access struct {
// Map of featureKey to entitlement value + ID
Entitlements map[string]EntitlementValueWithId
}
type AlreadyDeletedError ¶
type AlreadyDeletedError struct {
EntitlementID string
}
func (*AlreadyDeletedError) Error ¶
func (e *AlreadyDeletedError) Error() string
type AlreadyExistsError ¶
func (*AlreadyExistsError) Error ¶
func (e *AlreadyExistsError) Error() string
type CreateEntitlementGrantInputs ¶
type CreateEntitlementGrantInputs struct {
credit.CreateGrantInput
}
type CreateEntitlementInputs ¶
type CreateEntitlementInputs struct {
Namespace string `json:"namespace"`
FeatureID *string `json:"featureId"`
FeatureKey *string `json:"featureKey"`
UsageAttribution streaming.CustomerUsageAttribution `json:"usageAttribution"`
EntitlementType EntitlementType `json:"type"`
Metadata map[string]string `json:"metadata,omitempty"`
Annotations models.Annotations `json:"annotations,omitempty"`
// ActiveFrom allows entitlements to be scheduled for future activation.
// If not set, the entitlement is active immediately.
ActiveFrom *time.Time `json:"activeFrom,omitempty"`
// ActiveTo allows entitlements to be descheduled for future activation.
// If not set, the entitlement is active until deletion.
ActiveTo *time.Time `json:"activeTo,omitempty"`
MeasureUsageFrom *MeasureUsageFromInput `json:"measureUsageFrom,omitempty"`
IssueAfterReset *float64 `json:"issueAfterReset,omitempty"`
IssueAfterResetPriority *uint8 `json:"issueAfterResetPriority,omitempty"`
IsSoftLimit *bool `json:"isSoftLimit,omitempty"`
Config *string `json:"config,omitempty"`
UsagePeriod *UsagePeriodInput `json:"usagePeriod,omitempty"`
PreserveOverageAtReset *bool `json:"preserveOverageAtReset,omitempty"`
SubscriptionManaged bool `json:"subscriptionManaged,omitempty"`
}
func (CreateEntitlementInputs) Equal ¶
func (c CreateEntitlementInputs) Equal(other CreateEntitlementInputs) bool
func (CreateEntitlementInputs) GetType ¶
func (c CreateEntitlementInputs) GetType() EntitlementType
func (CreateEntitlementInputs) Validate ¶
func (c CreateEntitlementInputs) Validate() error
type CreateEntitlementRepoInputs ¶
type CreateEntitlementRepoInputs struct {
Namespace string `json:"namespace"`
FeatureID string `json:"featureId"`
FeatureKey string `json:"featureKey"`
UsageAttribution streaming.CustomerUsageAttribution `json:"usageAttribution"`
EntitlementType EntitlementType `json:"type"`
Metadata map[string]string `json:"metadata,omitempty"`
ActiveFrom *time.Time `json:"activeFrom,omitempty"`
ActiveTo *time.Time `json:"activeTo,omitempty"`
Annotations models.Annotations `json:"annotations,omitempty"`
MeasureUsageFrom *time.Time `json:"measureUsageFrom,omitempty"`
IssueAfterReset *float64 `json:"issueAfterReset,omitempty"`
IssueAfterResetPriority *uint8 `json:"issueAfterResetPriority,omitempty"`
IsSoftLimit *bool `json:"isSoftLimit,omitempty"`
Config *string `json:"config,omitempty"`
UsagePeriod *UsagePeriodInput `json:"usagePeriod,omitempty"`
CurrentUsagePeriod *timeutil.ClosedPeriod `json:"currentUsagePeriod,omitempty"`
PreserveOverageAtReset *bool `json:"preserveOverageAtReset,omitempty"`
}
type Entitlement ¶
type Entitlement struct {
GenericProperties
// All none-core fields are optional
// metered
MeasureUsageFrom *time.Time `json:"measureUsageFrom,omitempty"`
IssueAfterReset *float64 `json:"issueAfterReset,omitempty"`
IssueAfterResetPriority *uint8 `json:"issueAfterResetPriority,omitempty"`
IsSoftLimit *bool `json:"isSoftLimit,omitempty"`
LastReset *time.Time `json:"lastReset,omitempty"`
PreserveOverageAtReset *bool `json:"preserveOverageAtReset,omitempty"`
// static
Config *string `json:"config,omitempty"`
}
Normalized representation of an entitlement in the system
func (Entitlement) AsCreateEntitlementInputs ¶
func (e Entitlement) AsCreateEntitlementInputs(cust customer.Customer) CreateEntitlementInputs
func (Entitlement) GetCadence ¶
func (e Entitlement) GetCadence() models.CadencedModel
func (Entitlement) GetType ¶
func (e Entitlement) GetType() EntitlementType
type EntitlementCreatedEventV2 ¶
type EntitlementCreatedEventV2 entitlementEventV2
func NewEntitlementCreatedEventPayloadV2 ¶
func NewEntitlementCreatedEventPayloadV2(ent Entitlement, c *customer.Customer) EntitlementCreatedEventV2
func (EntitlementCreatedEventV2) EventMetadata ¶
func (e EntitlementCreatedEventV2) EventMetadata() metadata.EventMetadata
func (EntitlementCreatedEventV2) EventName ¶
func (e EntitlementCreatedEventV2) EventName() string
func (EntitlementCreatedEventV2) Validate ¶
func (e EntitlementCreatedEventV2) Validate() error
type EntitlementDeletedEventV2 ¶
type EntitlementDeletedEventV2 entitlementEventV2
func NewEntitlementDeletedEventPayloadV2 ¶
func NewEntitlementDeletedEventPayloadV2(ent Entitlement, c *customer.Customer) EntitlementDeletedEventV2
func (EntitlementDeletedEventV2) EventMetadata ¶
func (e EntitlementDeletedEventV2) EventMetadata() metadata.EventMetadata
func (EntitlementDeletedEventV2) EventName ¶
func (e EntitlementDeletedEventV2) EventName() string
func (EntitlementDeletedEventV2) Validate ¶
func (e EntitlementDeletedEventV2) Validate() error
type EntitlementRepo ¶
type EntitlementRepo interface {
// GetActiveEntitlementOfSubjectAt returns the active entitlement of a customer at a given time by feature key
GetActiveEntitlementOfCustomerAt(ctx context.Context, namespace string, customerID string, featureKey string, at time.Time) (*Entitlement, error)
// GetScheduledEntitlements returns all scheduled entitlements for a given customer-feature pair that become inactive after the given time, sorted by the time they become active
GetScheduledEntitlements(ctx context.Context, namespace string, customerID string, featureKey string, starting time.Time) ([]Entitlement, error)
// DeactivateEntitlement deactivates an entitlement by setting the activeTo time. If the entitlement is already deactivated, it returns an error.
DeactivateEntitlement(ctx context.Context, entitlementID models.NamespacedID, at time.Time) error
CreateEntitlement(ctx context.Context, entitlement CreateEntitlementRepoInputs) (*Entitlement, error)
GetEntitlement(ctx context.Context, entitlementID models.NamespacedID) (*Entitlement, error)
DeleteEntitlement(ctx context.Context, entitlementID models.NamespacedID, at time.Time) error
ListEntitlements(ctx context.Context, params ListEntitlementsParams) (pagination.Result[Entitlement], error)
// ListNamespacesWithActiveEntitlements returns a list of namespaces that have active entitlements
//
// Active in this context means the entitlement is active at any point between now and the given time.
// If includeDeletedAfter is before the current time, it will include namespaces that have entitlements active at that instance.
ListNamespacesWithActiveEntitlements(ctx context.Context, includeDeletedAfter time.Time) ([]string, error)
UpdateEntitlementUsagePeriod(ctx context.Context, entitlementID models.NamespacedID, params UpdateEntitlementUsagePeriodParams) error
// ListActiveEntitlementsWithExpiredUsagePeriod returns a list of active entitlements with usage period that expired before the highwatermark
// - Only entitlements active at the highwatermark are considered.
// - The list is sorted by the current usage period end, then by created at, then by id.
// - The list is paginated by the cursor & limit.
// - CurrentUsagePeriod won't be mapped to the calculated values
ListActiveEntitlementsWithExpiredUsagePeriod(ctx context.Context, params ListExpiredEntitlementsParams) ([]Entitlement, error)
// UpsertEntitlementCurrentPeriods upserts the current usage period for a list of entitlements
// - If an entitlement is found, it will be updated
// - If any update fails, the entire operation will fail
UpsertEntitlementCurrentPeriods(ctx context.Context, updates []UpsertEntitlementCurrentPeriodElement) error
LockEntitlementForTx(ctx context.Context, tx *entutils.TxDriver, entitlementID models.NamespacedID) error
entutils.TxCreator
}
type EntitlementType ¶
type EntitlementType string
const ( // EntitlementTypeMetered represents entitlements where access is determined by usage and balance calculations EntitlementTypeMetered EntitlementType = "metered" // EntitlementTypeStatic represents entitlements where access is described by a static configuration EntitlementTypeStatic EntitlementType = "static" // EntitlementTypeBoolean represents boolean access EntitlementTypeBoolean EntitlementType = "boolean" )
func (EntitlementType) StrValues ¶
func (e EntitlementType) StrValues() []string
func (EntitlementType) String ¶
func (e EntitlementType) String() string
func (EntitlementType) Values ¶
func (e EntitlementType) Values() []EntitlementType
type EntitlementValue ¶
type EntitlementValue interface {
HasAccess() bool
}
type EntitlementValueWithId ¶
type EntitlementValueWithId struct {
Type EntitlementType
Value EntitlementValue
ID string
}
type EntitlementWithCustomer ¶
type EntitlementWithCustomer struct {
Entitlement
Customer customer.Customer
}
type ForbiddenError ¶
type ForbiddenError struct {
Message string
}
func (*ForbiddenError) Error ¶
func (e *ForbiddenError) Error() string
type GenericProperties ¶
type GenericProperties struct {
models.NamespacedModel
models.ManagedModel
models.MetadataModel
models.Annotations
// ActiveFrom allows entitlements to be scheduled for future activation.
// If not set, the entitlement is active immediately.
ActiveFrom *time.Time `json:"activeFrom,omitempty"`
// ActiveTo allows entitlements to be descheduled for future activation.
// If not set, the entitlement is active until deletion.
ActiveTo *time.Time `json:"activeTo,omitempty"`
ID string `json:"id,omitempty"`
FeatureID string `json:"featureId,omitempty"`
FeatureKey string `json:"featureKey,omitempty"`
CustomerID string `json:"customerId,omitempty"`
EntitlementType EntitlementType `json:"type,omitempty"`
UsagePeriod *UsagePeriod `json:"usagePeriod,omitempty"`
CurrentUsagePeriod *timeutil.ClosedPeriod `json:"currentUsagePeriod,omitempty"`
OriginalUsagePeriodAnchor *time.Time `json:"originalUsagePeriodAnchor,omitempty"`
}
GenericProperties is the core fields of an entitlement that are always applicable regadless of type
func (GenericProperties) ActiveFromTime ¶
func (e GenericProperties) ActiveFromTime() time.Time
ActiveFromTime returns the time the entitlement is active from. Its either the ActiveFrom field or the CreatedAt field
func (GenericProperties) ActiveToTime ¶
func (e GenericProperties) ActiveToTime() *time.Time
ActiveToTime returns the time the entitlement is active to. Its either the ActiveTo field or the DeletedAt field or nil
func (GenericProperties) Validate ¶
func (e GenericProperties) Validate() error
type InvalidFeatureError ¶
func (*InvalidFeatureError) Error ¶
func (e *InvalidFeatureError) Error() string
type InvalidValueError ¶
type InvalidValueError struct {
Message string
Type EntitlementType
}
func (*InvalidValueError) Error ¶
func (e *InvalidValueError) Error() string
type ListEntitlementsOrderBy ¶
type ListEntitlementsOrderBy string
const ( ListEntitlementsOrderByCreatedAt ListEntitlementsOrderBy = "created_at" ListEntitlementsOrderByUpdatedAt ListEntitlementsOrderBy = "updated_at" )
func (ListEntitlementsOrderBy) StrValues ¶
func (o ListEntitlementsOrderBy) StrValues() []string
func (ListEntitlementsOrderBy) Values ¶
func (o ListEntitlementsOrderBy) Values() []ListEntitlementsOrderBy
type ListEntitlementsParams ¶
type ListEntitlementsParams struct {
IDs []string
Namespaces []string
SubjectKeys []string
CustomerIDs []string
CustomerKeys []string
FeatureIDs []string
FeatureKeys []string
FeatureIDsOrKeys []string
EntitlementTypes []EntitlementType
OrderBy ListEntitlementsOrderBy
Order sortx.Order
// TODO[galexi]: We should clean up how these 4 fields are used together.
IncludeDeleted bool
IncludeDeletedAfter time.Time
ExcludeInactive bool
ActiveAt *time.Time
Page pagination.Page
// will be deprecated
Limit int
// will be deprecated
Offset int
}
type ListEntitlementsWithCustomerResult ¶
type ListEntitlementsWithCustomerResult struct {
Entitlements pagination.Result[Entitlement]
CustomersByID map[models.NamespacedID]*customer.Customer
}
type MeasureUsageFromEnum ¶
type MeasureUsageFromEnum string
const ( MeasureUsageFromCurrentPeriodStart MeasureUsageFromEnum = "CURRENT_PERIOD_START" MeasureUsageFromNow MeasureUsageFromEnum = "NOW" )
func (MeasureUsageFromEnum) Validate ¶
func (e MeasureUsageFromEnum) Validate() error
func (MeasureUsageFromEnum) Values ¶
func (e MeasureUsageFromEnum) Values() []MeasureUsageFromEnum
type MeasureUsageFromInput ¶
type MeasureUsageFromInput struct {
// contains filtered or unexported fields
}
func (MeasureUsageFromInput) Equal ¶
func (m MeasureUsageFromInput) Equal(other MeasureUsageFromInput) bool
func (*MeasureUsageFromInput) FromEnum ¶
func (m *MeasureUsageFromInput) FromEnum(e MeasureUsageFromEnum, currPeriod timeutil.ClosedPeriod, now time.Time) error
func (*MeasureUsageFromInput) FromTime ¶
func (m *MeasureUsageFromInput) FromTime(t time.Time) error
func (MeasureUsageFromInput) Get ¶
func (m MeasureUsageFromInput) Get() time.Time
type NoAccessValue ¶
type NoAccessValue struct{}
func (*NoAccessValue) HasAccess ¶
func (*NoAccessValue) HasAccess() bool
type NotFoundError ¶
type NotFoundError struct {
EntitlementID models.NamespacedID
}
func (*NotFoundError) Error ¶
func (e *NotFoundError) Error() string
type Service ¶
type Service interface {
models.ServiceHooks[Entitlement]
// Meant for API use primarily
CreateEntitlement(ctx context.Context, input CreateEntitlementInputs, grants []CreateEntitlementGrantInputs) (*Entitlement, error)
// OverrideEntitlement replaces a currently active entitlement with a new one.
OverrideEntitlement(ctx context.Context, customerID string, entitlementIdOrFeatureKey string, input CreateEntitlementInputs, grants []CreateEntitlementGrantInputs) (*Entitlement, error)
ScheduleEntitlement(ctx context.Context, input CreateEntitlementInputs) (*Entitlement, error)
// SupersedeEntitlement replaces an entitlement by scheduling a new one
SupersedeEntitlement(ctx context.Context, entitlementId string, input CreateEntitlementInputs) (*Entitlement, error)
GetEntitlement(ctx context.Context, namespace string, id string) (*Entitlement, error)
GetEntitlementWithCustomer(ctx context.Context, namespace string, id string) (*EntitlementWithCustomer, error)
DeleteEntitlement(ctx context.Context, namespace string, id string, at time.Time) error
GetEntitlementValue(ctx context.Context, namespace string, customerID string, idOrFeatureKey string, at time.Time) (EntitlementValue, error)
GetEntitlementsOfCustomer(ctx context.Context, namespace string, customerId string, at time.Time) ([]Entitlement, error)
ListEntitlements(ctx context.Context, params ListEntitlementsParams) (pagination.Result[Entitlement], error)
ListEntitlementsWithCustomer(ctx context.Context, params ListEntitlementsParams) (ListEntitlementsWithCustomerResult, error)
// Attempts to get the entitlement in an ambiguous situation where it's unclear if the entitlement is referenced by ID or FeatureKey + CustomerID.
// First attempts to resolve by ID, then by FeatureKey + CustomerID.
//
// For consistency, it is forbidden for entitlements to be created for featueres the keys of which could be mistaken for entitlement IDs.
GetEntitlementOfCustomerAt(ctx context.Context, namespace string, customerID string, idOrFeatureKey string, at time.Time) (*Entitlement, error)
// GetAccess returns the access of a customer.
// It returns a map of featureKey to entitlement value + ID.
GetAccess(ctx context.Context, namespace string, customerID string) (Access, error)
}
type SubTypeConnector ¶
type SubTypeConnector interface {
GetValue(ctx context.Context, entitlement *Entitlement, at time.Time) (EntitlementValue, error)
// Runs before creating the entitlement, building the Repository inputs.
// If it returns an error the operation has to fail.
BeforeCreate(entitlement CreateEntitlementInputs, feature feature.Feature) (*CreateEntitlementRepoInputs, error)
// Runs after entitlement creation.
// If it returns an error the operation has to fail.
AfterCreate(ctx context.Context, entitlement *Entitlement) error
}
FIXME[galexi]: we can get rid of this concept due to better hierarchy
type TypedEntitlement ¶
type TypedEntitlement interface {
GetType() EntitlementType
}
type UniquenessConstraintError ¶
type UniquenessConstraintError struct {
E1, E2 Entitlement
}
func (*UniquenessConstraintError) Error ¶
func (e *UniquenessConstraintError) Error() string
type UpdateEntitlementUsagePeriodParams ¶
type UpdateEntitlementUsagePeriodParams struct {
CurrentUsagePeriod timeutil.ClosedPeriod
}
type UpsertEntitlementCurrentPeriodElement ¶
type UpsertEntitlementCurrentPeriodElement struct {
models.NamespacedID
CurrentUsagePeriod timeutil.ClosedPeriod
}
type UsagePeriod ¶
type UsagePeriod struct {
// contains filtered or unexported fields
}
func NewStartingUsagePeriod ¶
func NewStartingUsagePeriod(rec timeutil.Recurrence, start time.Time) UsagePeriod
func NewUsagePeriod ¶
func NewUsagePeriod(recs []timeutil.Timed[timeutil.Recurrence]) UsagePeriod
When providing an initial value (single element in list), for metered entitlements, timed.GetTime() should return measureUsageFrom!
func NewUsagePeriodFromRecurrence ¶
func NewUsagePeriodFromRecurrence(rec timeutil.Recurrence) UsagePeriod
Intended for testing mainly
func (UsagePeriod) Equal ¶
func (u UsagePeriod) Equal(other UsagePeriod) bool
func (UsagePeriod) GetCurrentPeriodAt ¶
func (u UsagePeriod) GetCurrentPeriodAt(at time.Time) (timeutil.ClosedPeriod, error)
func (*UsagePeriod) GetOriginalValueAsUsagePeriodInput ¶
func (u *UsagePeriod) GetOriginalValueAsUsagePeriodInput() *UsagePeriodInput
func (UsagePeriod) GetResetTimelineInclusive ¶
func (u UsagePeriod) GetResetTimelineInclusive(inPeriod timeutil.ClosedPeriod) (timeutil.SimpleTimeline, error)
func (UsagePeriod) GetUsagePeriodInputAt ¶
func (u UsagePeriod) GetUsagePeriodInputAt(at time.Time) (UsagePeriodInput, int, error)
func (UsagePeriod) MarshalJSON ¶
func (u UsagePeriod) MarshalJSON() ([]byte, error)
func (*UsagePeriod) UnmarshalJSON ¶
func (u *UsagePeriod) UnmarshalJSON(data []byte) error
func (UsagePeriod) Validate ¶
func (u UsagePeriod) Validate() error
type UsagePeriodInput ¶
type UsagePeriodInput = timeutil.Timed[timeutil.Recurrence]
func NewStartingUsagePeriodInput ¶
func NewStartingUsagePeriodInput(rec timeutil.Recurrence, start time.Time) UsagePeriodInput
func NewUsagePeriodInputFromRecurrence ¶
func NewUsagePeriodInputFromRecurrence(rec timeutil.Recurrence) UsagePeriodInput
Intended for testing mainly
type WrongTypeError ¶
type WrongTypeError struct {
Expected EntitlementType
Actual EntitlementType
}
func (*WrongTypeError) Error ¶
func (e *WrongTypeError) Error() string