Documentation
¶
Overview ¶
Package compiler renders the authored policy model plus registry state into each workload's concrete WorkloadPolicy and decides which versions advance (ADR-0018).
Rendering is a pure function of its inputs: label selectors resolve to the workloads that match them, and those workloads' current addresses become host routes; address groups expand to their CIDRs; service references and inline entries expand to one resolved rule per protocol. Versioning is a pure function too: the previously persisted policy is diffed against the freshly rendered one and the version advances only when the rendered output changed. The Engine runs both inside one store transaction that holds the render lock, so renders are serialized across processes (ADR-0017) and every persisted change is announced to the replica holding the workload's stream.
Version 1 re-renders every workload on any change and recovers per-workload version semantics by diffing. Compilation is inbound-only (ADR-0010): admission never lets an outbound rule reach this package, and the renderer emits only inbound rules regardless.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Render ¶
func Render(in *Inputs) map[identity.WorkloadID]*innerwallv1.WorkloadPolicy
Render produces the policy of every active workload in the inputs. Versions are left at zero: assigning them is Plan's job, because a version is a statement about change and rendering knows nothing about the past. A retired workload is no input to policy (ADR-0023): it is not rendered, so its persisted policy and version stay as the record of what it last held, and it resolves as nobody's peer.
func StateVersion ¶
StateVersion is the version of the state a render reads: a digest over everything in the inputs that can change a rendered policy (each active workload's labels, addresses, and mode, and which workloads are retired; each authored object's id and version). A caller that authored against one state version can tell from another that the persisted state has moved since, and a dry run reports the version it computed against so that staleness is detectable rather than silent. It is derived, never stored.
Types ¶
type Announcement ¶
type Announcement struct {
ID identity.WorkloadID
Version uint64
}
Announcement is what a render publishes for each workload whose version advanced: the store delivers it over the database's notification channel to every replica, and the replica holding the workload's stream pushes.
type Change ¶
type Change struct {
ID identity.WorkloadID
Version uint64
Changes int
}
Change is one workload whose version advanced in a render.
type Directive ¶ added in v0.5.0
type Directive struct {
ID identity.WorkloadID
Kind DirectiveKind
}
Directive is a request addressed to one workload's live stream, carried over the same notification channel as announcements to every replica; the one holding that stream acts on it and the others drop it. Delivery is best-effort by design: it is a request, not state.
type DirectiveKind ¶ added in v0.5.0
type DirectiveKind int
DirectiveKind is what a directive asks of the stream it names.
const ( // DirectiveReconnect asks the replica holding the stream to send its // agent a Reconnect directive (ADR-0018 as amended). DirectiveReconnect DirectiveKind = iota + 1 // DirectiveEnd asks the replica holding the stream of a retired // workload to end it with the refusal every door gives a retired // identity (ADR-0023). DirectiveEnd )
Directive kinds.
type Engine ¶
type Engine struct {
Store Store
Log *slog.Logger
// Now is the clock; time.Now if nil.
Now func() time.Time
}
Engine renders on demand. Callers invoke Render after every change that can affect a rendered policy: authored mutations, enrollment, label and mode changes, inventory reports that changed a workload's addresses, and a workload's retirement.
func (*Engine) Render ¶
Render re-renders every workload and persists the ones whose output changed. It is synchronous: when it returns, every changed version is durable and announced.
type Inputs ¶
type Inputs struct {
Workloads []registry.Workload
Rulesets []policy.Ruleset
Services []policy.Service
AddressGroups []policy.AddressGroup
}
Inputs is everything a render reads, loaded in one transaction so that every workload's policy is rendered against the same state.
type ModeChange ¶
type ModeChange struct {
From innerwallv1.EnforcementMode
To innerwallv1.EnforcementMode
}
ModeChange is a mode the dry run would change.
type Outcome ¶
type Outcome struct {
ID identity.WorkloadID
// Policy is the rendered policy carrying the version it should be
// persisted at: the previous version when nothing changed, one more
// when something did.
Policy *innerwallv1.WorkloadPolicy
// Changes is the delta from the previously persisted policy. Empty
// exactly when Changed is false.
Changes []*innerwallv1.DeltaChange
// Changed reports whether the version advanced: the rendered output
// differs from what was persisted, or nothing was persisted yet.
Changed bool
}
Outcome is Plan's verdict for one workload.
func Plan ¶
func Plan(previous, current map[identity.WorkloadID]*innerwallv1.WorkloadPolicy) []Outcome
Plan diffs each freshly rendered policy against the previously persisted one and assigns versions: unchanged output keeps its version, changed output takes the next. This is the whole of the versioning rule (ADR-0018): a version advances if and only if the rendered bytes differ, so a re-render of an unchanged estate is a no-op and an authored change that does not affect a workload leaves that workload's version alone. A workload with no persisted policy is planned against the empty policy at version 0 and always persisted at version 1, even when its rendered policy is itself empty, so that every registered workload has a durable snapshot from its first render on. Outcomes are sorted by workload id.
type Report ¶
type Report struct {
// Workloads is how many workloads were rendered: every active one.
Workloads int
// Changed lists the workloads whose rendered output changed, and
// therefore whose version advanced and whose stream is pushed.
Changed []Change
}
Report summarizes one render.
type RuleChange ¶
type RuleChange struct {
Before *innerwallv1.ResolvedRule
After *innerwallv1.ResolvedRule
}
RuleChange is one rendered rule the dry run would change: what the workload holds now and what it would hold.
type Store ¶
type Store interface {
// RenderTx runs fn in one transaction holding the render lock, so two
// renders in any two processes never interleave. It commits when fn
// returns nil and rolls back otherwise.
RenderTx(ctx context.Context, fn func(ctx context.Context, tx Tx) error) error
}
Store runs render transactions.
type Tx ¶
type Tx interface {
LoadInputs(ctx context.Context) (*Inputs, error)
// LoadPolicies returns the persisted policy of every workload that has
// one, with its version.
LoadPolicies(ctx context.Context) (map[identity.WorkloadID]*innerwallv1.WorkloadPolicy, error)
// SavePolicy persists a changed policy at the version it carries and
// announces the change so the stream holding the workload pushes it
// once the transaction commits.
SavePolicy(ctx context.Context, id identity.WorkloadID, policy *innerwallv1.WorkloadPolicy, now time.Time) error
}
Tx is the store's side of one render: everything is read and written inside a single transaction that holds the render lock.
type WorkloadDiff ¶
type WorkloadDiff struct {
ID identity.WorkloadID
// Version is the persisted version the diff is against; zero when no
// policy has been rendered yet.
Version uint64
Mode *ModeChange
Added []*innerwallv1.ResolvedRule
Removed []*innerwallv1.ResolvedRule
Changed []RuleChange
}
WorkloadDiff is what a dry run would change on one workload. Only workloads whose rendered policy would differ are reported; a workload with no persisted policy is diffed against the empty one, as a first render would.
func DryRun ¶
func DryRun(previous, current map[identity.WorkloadID]*innerwallv1.WorkloadPolicy) []WorkloadDiff
DryRun diffs the freshly rendered policies (current) against the persisted ones (previous), classifying the wire contract's delta of each workload, computed by the one shared implementation (ADR-0018), into added, removed, and changed rules and a mode change. A rendered rule counts as changed when the delta upserts it over an existing one or adds or removes its peers. Workloads are reported in id order.