Documentation
¶
Overview ¶
Package planner turns a spec plus host policy plus adapter capabilities into a bundle plan, or into a plan-time error.
Everything the planner does is side-effect-free. That boundary is what makes a plan-time failure meaningful rather than a label on a mid-deploy crash: steps 1-7 of the deployment pipeline create nothing. See design 05 §3.
Package planner turns a spec plus policy plus adapter capabilities into a plan, or into a readable plan-time error.
Everything here is side-effect-free. That boundary is what makes a plan-time failure meaningful rather than a label on a mid-deploy crash: steps 1-7 of the deployment pipeline create nothing, clone nothing, and start nothing, so the console can call Plan on every spec edit without consequence.
If a check needs a side effect to run, it belongs after the boundary and it is not a plan-time check.
Index ¶
- func ChooseDelivery(runtimeRef string, rc api.RuntimeCapabilities, builderRef string, ...) (api.ImageDelivery, error)
- type Allocation
- type Allocations
- type ImageReader
- type InstallRegistries
- type InstallRegistry
- type Inventory
- type InventoryApp
- type InventoryFilter
- type Plan
- type Planner
- func (p *Planner) Check(ctx context.Context, s *spec.AppSpec) (*Plan, error)
- func (p *Planner) Egress(ctx context.Context, s *spec.AppSpec) (policy.EffectiveEgress, error)
- func (p *Planner) PreviewPolicy(ctx context.Context, candidate policy.Document) ([]PolicyViolation, error)
- func (p *Planner) WithImages(images ImageReader) *Planner
- func (p *Planner) WithInstallRegistry(r InstallRegistries) *Planner
- func (p *Planner) WithInventory(inv Inventory) *Planner
- type PolicyViolation
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ChooseDelivery ¶
func ChooseDelivery(runtimeRef string, rc api.RuntimeCapabilities, builderRef string, bc api.BuilderCapabilities, reg InstallRegistry) (api.ImageDelivery, error)
ChooseDelivery decides how a built image reaches the runtime, from data (R-254): the runtime's ImageDelivery, the builder's SupportsPush, and whether the install has a registry.
Import when the runtime takes one and the install does not send every build through its registry; otherwise the registry, when the runtime pulls from one, one is configured and the builder can push. Anything else is a plan-time refusal that names what is missing, rather than a failure after the build has run.
Types ¶
type Allocation ¶
type Allocation struct {
CPUMillis int
MemoryBytes int64
DiskBytes int64
// LogBytes is the sum of every app's log cap on this runtime (R-224).
//
// Committed, not measured. O-16 resolved to bounding what an install
// promises rather than watching what accumulates: if every app's logs are
// capped and the caps sum under the budget, the total cannot exceed it.
// Measuring would mean acting after the disk was already filling, and the
// only remedy then is recreating containers — which the reconciler may not
// do because an unrelated app turned chatty.
LogBytes int64
}
Allocation is what other apps already hold, for the capacity check.
type Allocations ¶
type Allocations interface {
// AllocatedOn returns what is already committed on a runtime adapter,
// excluding the app being planned — replanning an app must not count its
// own current allocation against itself.
AllocatedOn(ctx context.Context, adapterRef, excludeAppID string) (Allocation, error)
}
Allocations reports current commitments per runtime adapter.
type ImageReader ¶
type ImageReader interface {
Inspect(ctx context.Context, appID, reference string, want oci.Platform) (oci.Inspection, error)
}
ImageReader reads an app's image from its registry with the app's own credential (oci.Images).
type InstallRegistries ¶
type InstallRegistries interface {
CurrentRegistry(ctx context.Context) (InstallRegistry, error)
}
InstallRegistries reads the install's registry as it is now: it can be changed from the console while Pando runs (*imageregistry.Service).
func FixedRegistry ¶
func FixedRegistry(r InstallRegistry) InstallRegistries
FixedRegistry answers InstallRegistries with r every time.
type InstallRegistry ¶
InstallRegistry is what the planner asks of the install's image registry adapter (issue #72, PR 5; R-252): whether there is one, and whether builds always go through it — its capabilities, read through *imageregistry.Registry, which satisfies this, a nil one included.
type Inventory ¶
type Inventory interface {
// LiveApps lists the live apps f admits. Every app a candidate policy
// would block must be among them; others may be too.
LiveApps(ctx context.Context, f InventoryFilter) ([]InventoryApp, error)
}
Inventory is every live app, with what a policy preview needs to judge it.
An interface because the planner does not import state (design 03 §9 keeps that boundary in one direction) and because previewing a policy against a list is the only thing this needs — not a store.
type InventoryApp ¶
type InventoryApp struct {
AppID string
Name string
// Spec is the revision the app is pinned to — what its next deploy would
// actually try to do, not its newest draft.
Spec *spec.AppSpec
// AnonymousGrant is whether anyone on the internet can reach this app
// without signing in (R-075, R-077), and AnonymousPasscode whether they
// need its passcode to (R-075a).
AnonymousGrant bool
AnonymousPasscode bool
}
InventoryApp is one running app as a policy sees it.
type InventoryFilter ¶
type InventoryFilter struct {
// Every live app with a source: a source allowlist is in force.
All bool
// Apps shared with anyone on the internet; WithoutPasscode narrows that to
// those shared without a passcode.
Anonymous bool
AnonymousWithoutPasscode bool
// EgressRuntimes are the runtimes that cannot enforce egress rules. An app
// on one is named when the candidate restricts every app's egress
// (EgressRestrictsAll), or when the app has egress settings of its own.
EgressRuntimes []string
EgressRestrictsAll bool
// OwnEgress names every app with egress settings of its own: the
// candidate forbids loosening, and only an app's own settings loosen.
OwnEgress bool
// Runtimes and Builders are adapter isolation classes. An app is named
// when its runtime's class is below the higher of its own runtime floor
// and MinRuntime, or its builder's is below the higher of its own build
// floor and MinBuild.
Runtimes map[string]spec.IsolationClass
MinRuntime spec.IsolationClass
Builders map[string]spec.IsolationClass
MinBuild spec.IsolationClass
}
InventoryFilter is which live apps a candidate policy could block, worked out from the policy and the adapters before any app is read (issue #72).
A preview runs while an administrator edits the policy form, and reading every app's pinned spec for it is twenty thousand specs a keystroke. Most of a policy cannot block most apps: no allowlist blocks no source, sharing allowed blocks no public app, a runtime that meets the floor fails no app's floor unless the app asks for more. Each field below names apps one check could fail; an app no field names passes every check, so reading only the named ones gives the same answer as reading them all. The checks themselves still run on every app read — the filter only decides which are read, never what is reported.
func (InventoryFilter) Empty ¶
func (f InventoryFilter) Empty() bool
Empty reports whether f names no app at all.
type Plan ¶
type Plan struct {
AppID string `json:"app_id"`
Bundle api.BundlePlan `json:"-"`
Notes []string `json:"notes,omitempty"`
Checks map[string]string `json:"checks"`
// Egress is the rules the app would run with, merged, with where each
// part came from and what every loosening needs (R-188).
Egress policy.EffectiveEgress `json:"egress"`
}
Plan is the result of a successful plan.
type Planner ¶
type Planner struct {
// contains filtered or unexported fields
}
Planner produces bundle plans.
func (*Planner) Check ¶
Check runs steps 1-7 and returns the plan, or the first blocking error.
The order matches design 05 §3 exactly, and it matters: the source allowlist is checked before anything would clone, capabilities before capacity, and capacity last because it is the only check whose answer depends on other apps.
func (*Planner) Egress ¶
Egress resolves an app's egress rules against host policy as it stands (R-182). The deploy runner asks this too, so what the plan showed is what the runtime is given.
func (*Planner) PreviewPolicy ¶
func (p *Planner) PreviewPolicy(ctx context.Context, candidate policy.Document) ([]PolicyViolation, error)
PreviewPolicy reports which apps a candidate policy would block (design 05 §3).
O-10 resolved this to "report now, block on next deploy": saving a policy touches no running app, and each violating app fails at step 2 the next time it deploys. That is the right behavior and a bad experience on its own — an admin tightening a policy is entitled to know it will block four apps before they save, because finding out one deploy at a time is how a policy gets rolled back in anger.
Side-effect free, and not only incidentally: this runs the same plan-time checks the deploy will run, against a policy that is not saved yet. Nothing here may write, and the checks it reuses are the pre-boundary ones for exactly that reason.
func (*Planner) WithImages ¶
func (p *Planner) WithImages(images ImageReader) *Planner
WithImages enables the plan-time checks on an image app's image: that it has a build for the runtime's platform, and which of the paths it keeps data in the spec leaves without storage (issue #41).
func (*Planner) WithInstallRegistry ¶
func (p *Planner) WithInstallRegistry(r InstallRegistries) *Planner
WithInstallRegistry tells the planner about the install's image registry. Without it the planner knows of none, and a runtime that only pulls from a registry is refused.
func (*Planner) WithInventory ¶
WithInventory enables policy preview.
type PolicyViolation ¶
type PolicyViolation struct {
AppID string `json:"app_id"`
AppName string `json:"app_name"`
// Code is the error the app's next deploy would fail with, so the console
// can show the same wording the developer will eventually see.
Code string `json:"code"`
Message string `json:"message"`
Remedy string `json:"remedy,omitempty"`
}
PolicyViolation is one app a candidate policy would block.