Documentation
¶
Overview ¶
Package metering folds each candidate resource's event history into the usage drafts of one billing period: the intervals the fold implies, clipped to the period, carrying the quantities every later number is derived from. It persists nothing. Writing the usage rows and the run's stats belongs to a later package, so a period can be metered without a handle on the database it will be written to.
Every draft of a resource is held against internal/engine/invariants before it is handed out. A breach fails the whole resource set with a report of every violating resource rather than letting one wrong resource through.
The normative specification is roadmap/03-phase-3-metering-rating.md, WP 3.3.
Index ¶
Constants ¶
const InvariantReservedUsageField = "reserved_usage_field"
InvariantReservedUsageField is what a resource whose size carries one of those names is reported as. It stands beside the invariants package's own codes in a run's violation report rather than in that package: such a resource has no drafts to hold against an invariant, so the breach is found here, one step before invariants.Check runs.
const WarningCandidateWithoutHistory = "candidate_without_history"
WarningCandidateWithoutHistory marks a candidate the projection lists whose events are missing or all lie at or after the period end. It is metered as nothing, because there is no history to bill it from.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type ResourceUsage ¶
type ResourceUsage struct {
Resource source.Resource
Drafts []UsageDraft
}
ResourceUsage is one resource and the drafts the period bills it as.
type ResourceViolations ¶
type ResourceViolations struct {
Cloud string `json:"cloud"`
ResourceType string `json:"resource_type"`
ResourceID string `json:"resource_id"`
Violations []invariants.Violation `json:"violations"`
}
ResourceViolations is one resource and the metering rules it breached: the invariants its drafts failed, or the reserved usage field that stopped the drafts from being built at all.
type Result ¶
type Result struct {
// Candidates counts every candidate examined, including those that yielded
// no drafts.
Candidates int
Resources []ResourceUsage
Warnings []Warning
}
Result is what one metering pass produced.
func Meter ¶
func Meter(ctx context.Context, src Source, periodFrom, periodTo time.Time, clouds []string) (*Result, error)
Meter folds every candidate of the period into its drafts. The candidates of the named clouds are read from src, and each one's history is loaded, folded, and checked on its own: the loop runs sequentially over the one connection the snapshot holds and holds a single resource's events at a time, which is what lets a resource with years of history be metered at all. The drafts are the other half of the footprint, and they are all kept until Meter returns: the pass hands out every resource's usage or none of it, so there is nothing it could hand on early.
A resource whose drafts breach an invariant is collected rather than returned on, so that the error names every violating resource of the period. Any violation fails the whole pass: the error is a *ViolationError and no drafts come back with it.
The errors of src are returned unchanged, so a caller reads a canceled context or a failed query as the source reported it. A resource whose size carries one of the reserved usage fields is collected the same way a breached invariant is: it is a resource nothing can bill correctly, and one such size persists in the events table and reaches every later period, so a run that named one of them and stopped would have an operator fix the period's resources one run at a time.
type Source ¶
type Source interface {
Candidates(ctx context.Context, clouds []string, periodFrom, periodTo time.Time) ([]source.Resource, error)
History(ctx context.Context, r source.Resource, periodTo time.Time) ([]event.Stored, error)
}
Source is what metering reads a period from, implemented by *source.Snapshot. The interface lives here rather than next to that type so the loop below can be exercised without a database.
type UsageDraft ¶
type UsageDraft struct {
State, ProjectID string
FromTS, ToTS time.Time
Seconds int64
Usage map[string]any
}
UsageDraft is one interval of a resource clipped to the billing period. Seconds is the whole seconds of [FromTS, ToTS), a sub-second remainder truncated (D2), and Usage is decision D9's object: every size field of the interval verbatim, plus the minutes those seconds are worth and the count of one that prices a resource by its existence.
func MeterResource ¶
MeterResource folds one resource's history into the drafts the period [periodFrom, periodTo) bills it as. It is the whole of what metering computes; Meter is this over a source's candidate list.
A history that is empty, or a period with no length, bills nothing and yields an empty slice. An interval whose size carries one of the reserved usage fields is an error rather than a draft.
type ViolationError ¶
type ViolationError struct {
Resources []ResourceViolations
}
ViolationError is what Meter fails a period with: every resource the period cannot be billed from, and nothing else. No drafts come back with it, because a run that found one wrong resource keeps no partial output.
func (*ViolationError) Error ¶
func (e *ViolationError) Error() string
Error reports how many resources breached an invariant. The breaches themselves are in Resources, which the run writes to its stats.
type Warning ¶
type Warning struct {
Cloud string `json:"cloud"`
ResourceType string `json:"resource_type"`
ResourceID string `json:"resource_id"`
Code string `json:"code"`
}
Warning names a resource that was metered on incomplete data. Code is WarningCandidateWithoutHistory or timeline.WarningHistoryStartsWithoutCreate. A warning does not fail the run: it reaches an operator through the run's stats.