Documentation
¶
Overview ¶
Package fluxdelivery is the Go half of kcl/lib/flux_delivery.k: gitless Flux delivery through a flux-operator ResourceSet.
A ledger decides which bundle digest a delivery unit runs. Its writer turns that decision into one [Input], checks it with Validate, and writes it into a ResourceSet whose template (Template) flux-operator renders into the unit's OCIRepository and one Kustomization per applier. The control-plane hub writes inline inputs (ResourceSet); self-hosted forge writes a ResourceSetInputProvider whose values are the same map ([Input.Map]).
What lives here, and why in forge ¶
- The TEMPLATE, as a generated constant (template_gen.go) of the one string in kcl/lib/flux_delivery.k, so a hub writer in Go and a self-hosted render in KCL emit the same objects. TestTemplateMatchesKCL pins the pair.
- The INPUT, typed. Nobody writes the input map by hand: [Input.Map] is its JSON form, field names fixed by tags.
- The NAMES of the rendered objects ([BundleObjectName] and friends), moved from control-plane's fluxtenant. The observer reads these objects back by name, so a name composed twice is a name that can disagree, and the template does not derive them: they are inputs, computed here.
- VALIDATION (Validate): the structural refusals that make a bad input unwritable rather than a green environment over nothing. These are facts about the Flux objects the template emits, so they sit beside it.
- An in-process RENDERER (Render) that reproduces flux-operator's ResourceSet builder, for a writer's pre-write check and for tests. It never applies anything, and it does not import flux-operator (whose builder is internal/, and whose module is AGPL). The real engine is held to it by an oracle test that runs the pinned `flux-operator build resourceset`.
The safety properties ¶
Every rendered object carries `fluxcd.controlplane.io/prune: disabled` unless its input retires it, and every Kustomization carries `spec.deletionPolicy: Orphan` unless the input says teardown. So deleting the ResourceSet, emptying its inputs or a render that drops an applier orphans Flux objects and never deletes a workload. CheckRendered asserts these properties on a render; a writer runs it before every write.
Index ¶
- Constants
- Variables
- func BoundLabelValue(name string) string
- func CheckRendered(in BindingInput, objs []*unstructured.Unstructured) error
- func CheckRenderedSelfHosted(in BindingInput, objs []*unstructured.Unstructured, mode SelfHosted) error
- func CheckTransition(live *BindingInput, next BindingInput) error
- func HealthAPIVersion(kind string) (string, bool)
- func InputProvider(in BindingInput) (map[string]any, error)
- func InputProviderName(env, binding string) string
- func KustomizationName(org, env, binding, cluster string) string
- func LabelValue(s string) string
- func LowerDNS(s string) string
- func Render(rs map[string]any, providers ...Provider) ([]*unstructured.Unstructured, error)
- func ResourceSet(in BindingInput) (map[string]any, error)
- func ResourceSetName(env, binding string) string
- func Rules() []rbacv1.PolicyRule
- func SelfHostedNamespace(project, env string) string
- func SelfHostedServiceAccount(phase release.Phase) string
- func SourceName(org, env, binding string) string
- func TreeKustomizationName(org, env, binding, cluster, unit string, phase release.Phase) string
- func Validate(in BindingInput) error
- func ValidateSelfHosted(in BindingInput, mode SelfHosted) error
- type Applier
- type BindingInput
- type HealthCheck
- type HealthCheckExpr
- type OIDCIdentity
- type Patch
- type PatchTarget
- type Provider
- type SelfHosted
- type Source
- type Verify
Constants ¶
const ( // APIVersion is flux-operator's API group/version for ResourceSet and // ResourceSetInputProvider (FLUX_DELIVERY_API_VERSION). APIVersion = "fluxcd.controlplane.io/v1" // KindResourceSet is the ResourceSet kind. KindResourceSet = "ResourceSet" // ServiceAccount is the identity a delivery ResourceSet runs as, and the // name of its Role and RoleBinding (FLUX_DELIVERY_SA). ServiceAccount = "flux-delivery" // PruneAnnotation / PruneDisabled are flux-operator's per-object // garbage-collection opt-out (FLUX_DELIVERY_PRUNE_ANNOTATION / // FLUX_DELIVERY_PRUNE_DISABLED). flux-operator checks it against the LIVE // object, on garbage collection and on ResourceSet deletion alike. PruneAnnotation = "fluxcd.controlplane.io/prune" PruneDisabled = "disabled" // RetireOrphan / RetireTeardown are the retire states an input may carry // (FLUX_DELIVERY_RETIRE_ORPHAN / FLUX_DELIVERY_RETIRE_TEARDOWN). See // [Input.Retire]. RetireOrphan = "orphan" RetireTeardown = "teardown" // InputLabel is the label a self-hosted ResourceSetInputProvider carries // so the delivery ResourceSet's inputsFrom selector finds it // (FLUX_DELIVERY_INPUT_LABEL). InputLabel = "forge.dev/delivery" )
The strings shared with kcl/lib/flux_delivery.k. TestKCLConstantsAgree pins every one against the KCL declaration of the same value.
const ( SourceAPIVersion = "source.toolkit.fluxcd.io/v1" KustomizeAPIVersion = "kustomize.toolkit.fluxcd.io/v1" KindOCIRepository = "OCIRepository" KindKustomization = "Kustomization" // KubeConfigKey is the key inside every destination kubeconfig Secret the // template names. control-plane's fluxhub writes the Secret with the same // key; a disagreement reads to kustomize-controller as a missing // kubeconfig. KubeConfigKey = "value" // ShardLabel and its two values. The template derives the value from // whether the applier names a kubeconfig, so the connected shard and the // kubeConfig field cannot disagree. Same spellings as forge/pkg/flux. ShardLabel = "sharding.fluxcd.io/key" ShardMain = "shard0" ShardConnected = "connected" )
The Flux identities the template renders, pinned to Flux v2.9.5 (source- and kustomize-controller v1.9.5) by the CRD-schema test.
const ( VerifyOff = "off" VerifyAudit = "audit" VerifyEnforce = "enforce" )
The verification modes (Verify.Mode): the effective delivery policy's `flux_verify`. Only enforce renders `spec.verify`; audit is the writer's business (it records the publisher's verdict) and renders nothing.
const ( ForgeTierInProgress = `has(status.conditions) && status.conditions.exists(c, c.type == 'Reconciling' && c.status == 'True')` ForgeTierFailed = `has(status.conditions) && status.conditions.exists(c, c.type == 'Stalled' && c.status == 'True')` ForgeTierCurrent = `` /* 340-byte string literal not displayed */ )
A STOPPED TIER IS SETTLED, NOT STILL ROLLING OUT.
A forge.dev tier whose compute was stopped on purpose (its owner suspended it, or a billing lapse did) carries Suspended=True and Ready=False. kstatus reads a custom resource's Ready=False as InProgress, so an applier waiting on a suspended tier timed out its health check and its tree read failed (control-plane prod's egresscanary env, 2026-11-01: FluxTreeNotReady for an environment exactly as its owner left it).
These judge the tier kinds as kstatus would, plus one arm: Suspended=True at the current generation is Current. Reconciling=True is InProgress, Stalled=True is Failed (a controller's fail-fast), and Ready=True is Current. Current also requires status.observedGeneration to equal metadata.generation itself: Flux holds a stale observedGeneration InProgress before any expression runs, but the expression does not lean on that, so a Ready=True left over from a previous spec never reads settled for a newer one.
const ( // KindInputProvider is flux-operator's ResourceSetInputProvider. KindInputProvider = "ResourceSetInputProvider" // InputProviderStatic is the provider type whose one exported input is // its `spec.defaultValues`. InputProviderStatic = "Static" // PointerFenceAnnotation carries the writer's fence on the pointer, as // decimal digits: the live pointer's fence plus one, allocated by the // write that is conditional on that pointer, so the sequence is the // cluster's and shared by every deployer. A write that would move it // backwards is refused ([ErrStaleFence]); the self-hosted writer also // refuses one that reuses it for another promotion. PointerFenceAnnotation = "forge.dev/delivery-fence" // PointerPromotionAnnotation names the ledger promotion the pointer // projects. PointerPromotionAnnotation = "forge.dev/delivery-promotion" // GrantsRecord is the ConfigMap in a self-hosted delivery namespace that // records what the bootstrap granted the apply identities, so a deploy // can compare a release's needs with it before it writes anything. GrantsRecord = "forge-delivery-grants" )
The self-hosted pointer's kind and the annotations a writer reads back.
const ( // ChartName is the bootstrap platform chart's name, the `--target` that // installs it (FLUX_DELIVERY_CHART_NAME). ChartName = "flux-delivery" // PreServiceAccount, ApplyServiceAccount and NoneServiceAccount are the // apply identities in an env's delivery namespace (FLUX_DELIVERY_PRE_SA, // FLUX_DELIVERY_APPLY_SA, FLUX_DELIVERY_NONE_SA). PreServiceAccount = "forge-delivery-pre" ApplyServiceAccount = "forge-delivery-apply" NoneServiceAccount = "forge-delivery-none" // SelfHostedPullSecret is the copy of the registry pull Secret the // bootstrap writes into the delivery namespace; an input names it as // source.pullSecret (FLUX_DELIVERY_PULL_SECRET). SelfHostedPullSecret = "forge-delivery-pull" // EnvLabel carries the env on every self-hosted delivery object // (FLUX_DELIVERY_ENV_LABEL). EnvLabel = "forge.dev/delivery-env" )
The names a self-hosted bootstrap and its writer share with kcl/lib/flux_delivery.k. TestKCLConstantsAgree pins each one.
const ( ProviderGeneric = "generic" ProviderAWS = "aws" ProviderAzure = "azure" ProviderGCP = "gcp" )
The pull providers Flux's OCIRepository accepts.
const ExternalSecretCurrent = `` /* 296-byte string literal not displayed */
ExternalSecretCurrent is the health expression for an ExternalSecret (moved from control-plane's fluxtenant). ESO leaves Ready=True from the preceding sync while reconciling a pin bump; its syncedResourceVersion is "<generation>-<metadata hash>" and advances only after the target Secret is written. The delimiter is part of the match (generation 1 must not accept generation 10). A missing status field is not current, and an absent variable is a CEL error, which Flux also treats as not current.
const FenceAnnotation = "deploy.reliant.dev/generation"
FenceAnnotation is stamped on the OCIRepository with BindingInput.Fence: the annotation the hub's converger already writes there (control-plane's deployconverge.GenerationAnnotation), which its observer and fence reader read back. Kept under the same key so adopting a live object is a no-op.
const Schema = "forge.dev/flux-delivery/v1"
Schema is the version of the input shape. The template's first action is to refuse (sprig `fail`) any other value, so an input written by a newer writer stalls the ResourceSet instead of misrendering. Any change to the input's shape bumps it — and with it the template.
const Template = `` /* 3502-byte string literal not displayed */
Template is kcl/lib/flux_delivery.k's FLUX_DELIVERY_TEMPLATE: the ResourceSet resourcesTemplate. Regenerate with `go generate ./pkg/fluxdelivery`.
Variables ¶
var ( // ErrUnretiredApplierDropped is a write that drops an applier the live // input holds without having retired it first. The dropped // Kustomization would leave the ResourceSet's inventory still live and // still reading the shared source, and when the source moves to a digest // without its path, Flux prunes everything it applied. ErrUnretiredApplierDropped = errors.New("fluxdelivery: the write drops an applier that was never retired") // ErrPathChanged is a write that keeps an applier's name and changes its // path. The name is a function of the same coordinates the path is, so // this can only be a bug, and a Kustomization whose path moves prunes // everything the old path applied. ErrPathChanged = errors.New("fluxdelivery: an applier kept its name and changed its path") // ErrStaleFence is a write whose fence is older than the live one: a // writer that lost a race would move the environment backwards. ErrStaleFence = errors.New("fluxdelivery: the write's fence is older than the live input's") )
The writer's refusals on a transition from the live input to the next.
var ( // ErrInvalidInput is an input whose shape is wrong: schema, a required // field, a retire value, a duration. ErrInvalidInput = errors.New("fluxdelivery: invalid input") // ErrBindingUnsupported is a non-empty binding: the ledger has no // per-binding promotion yet, so nothing may write one. ErrBindingUnsupported = errors.New("fluxdelivery: the ledger has no per-binding promotion yet; binding must be \"\"") // ErrInvalidName is a name, label or annotation Kubernetes would refuse, // or one that disagrees with the function that composes it. ErrInvalidName = errors.New("fluxdelivery: invalid name") // ErrNotDigestPinned is a source not pinned by a sha256 manifest digest. ErrNotDigestPinned = errors.New("fluxdelivery: the source must be pinned by its sha256 manifest digest, never a tag") // ErrUnknownProvider is a pull provider outside Flux's enum. ErrUnknownProvider = errors.New("fluxdelivery: source provider must be one of generic, aws, azure, gcp") // ErrNoAppliers is an input with no applier. A source alone fetches // bytes, applies nothing and reports Ready: an environment built that // way looks healthy forever and never deploys. ErrNoAppliers = errors.New("fluxdelivery: the input has no applier, so nothing would apply the bundle") // ErrPathMismatch is an applier whose path is not release's answer for // its coordinates — the green-over-nothing guard: Flux reconciles a path // the artifact does not hold as "no resources" and reports Ready. ErrPathMismatch = errors.New("fluxdelivery: applier path disagrees with release.BundleTreePath / BundleClusterPath") // ErrNoClusterCredential is an applier with neither a kubeconfig nor an // explicit in-cluster identity, or with both. An absent kubeConfig makes // kustomize-controller apply to its OWN cluster. ErrNoClusterCredential = errors.New("fluxdelivery: an applier needs exactly one of kubeConfigSecret and inCluster") // ErrServiceAccountOnConnected is a serviceAccountName beside a // kubeconfig. The connected shard applies as the kubeconfig's identity // and never as a service account; the hub's admission policy refuses it. ErrServiceAccountOnConnected = errors.New("fluxdelivery: a kubeconfig applier must not name a serviceAccountName") // ErrDuplicateApplier is two appliers with one cluster or one name: the // second Kustomization would overwrite the first. ErrDuplicateApplier = errors.New("fluxdelivery: two appliers collide") // ErrInvalidTree is a dependency outside the input, an unknown health // kind, a flat cluster given tree coordinates or the reverse. ErrInvalidTree = errors.New("fluxdelivery: invalid applier tree") // ErrInvalidVerify is a verify block enforce mode cannot render. ErrInvalidVerify = errors.New("fluxdelivery: invalid verify settings") )
The refusals, moved from control-plane's fluxtenant.BuildBundle and validateBundleTrees. Each is a fact about the Flux objects the template emits, so a writer refuses before it writes anything — a refusal never leaves a half-applied environment.
var ErrUnsafeRender = errors.New("fluxdelivery: unsafe render")
ErrUnsafeRender is a render that breaks one of the template's safety properties. Reaching it means the template or the renderer is wrong, never the input: Validate has already accepted the input.
Functions ¶
func BoundLabelValue ¶
BoundLabelValue fits a composed name into a label value (63 characters) WITHOUT merging distinct inputs.
A name that fits is returned unchanged. A longer one becomes a readable prefix, a dot, and the first 12 hex characters of the SHA-256 of the WHOLE name. Plain truncation would merge two inputs that differ past the cut into one object, and the second would overwrite the first; the hash covers every byte. The separator is a dot for the collision proof above, and trimming the cut's trailing `-`/`.` keeps the result a legal subdomain and label value.
func CheckRendered ¶
func CheckRendered(in BindingInput, objs []*unstructured.Unstructured) error
CheckRendered asserts the safety properties on objs, the render of in (Render). A writer runs it on the would-be ResourceSet before every write, so a template or renderer bug is caught in the writer, attributed to the binding, before flux-operator ever sees it. Every golden in this package is held to it.
The properties:
- exactly one OCIRepository (the input's source) and one Kustomization per applier, in order, and nothing else — no Secret, no RBAC, no Namespace: the template renders only objects one binding owns;
- every object in the input's namespace, carrying the input's labels;
- the prune opt-out on every object the input does not retire;
- deletionPolicy Orphan on every Kustomization unless the binding is torn down (then Delete), and suspend exactly when retired as orphan or carried suspended;
- the shard label and kubeConfig agree, every Kustomization applies as the input's ServiceAccount, and one without a kubeConfig impersonates a named one;
- the source is digest-pinned to the input's digest, selects the manifests layer, carries the fence, and verifies exactly when the input enforces;
- every Kustomization reads the input's source at the applier's path.
func CheckRenderedSelfHosted ¶
func CheckRenderedSelfHosted(in BindingInput, objs []*unstructured.Unstructured, mode SelfHosted) error
CheckRenderedSelfHosted is CheckRendered for a self-hosted binding (ValidateSelfHosted): a delivery without identities names no ServiceAccount, because kustomize-controller applies as itself there.
func CheckTransition ¶
func CheckTransition(live *BindingInput, next BindingInput) error
CheckTransition refuses a write of next over live (nil: nothing is live, a first write). The three rules, each the writer's alone to enforce:
- the fence never moves backwards (ErrStaleFence);
- every applier the live input holds is in next, unless the live input had already retired it (that applier, or the whole binding) — the first of the two writes that drop one (ErrUnretiredApplierDropped);
- an applier present in both keeps its path (ErrPathChanged).
It does not check that a live retire has been APPLIED before the drop: that is an observation of the renderer, which the caller makes.
func HealthAPIVersion ¶
HealthAPIVersion is the apiVersion of a kind an applier may be judged on, and whether the kind is known. The set the hub's trees use; a kind outside it has no apiVersion to name, and an unknown health check never reports.
func InputProvider ¶
func InputProvider(in BindingInput) (map[string]any, error)
InputProvider is the pointer object for in: a Static ResourceSetInputProvider in in.Namespace, labelled so the delivery ResourceSet selects it, with in as its `defaultValues` and the fence and promotion as annotations.
It validates nothing: call ValidateSelfHosted first. It refuses only an input it cannot encode.
func InputProviderName ¶
InputProviderName is the name of a binding's pointer: the same as its ResourceSet's, in its own kind.
func KustomizationName ¶
KustomizationName is the name of a FLAT (layout v1) cluster's Kustomization (control-plane's fluxtenant.BundleKustomizationName).
The cluster is sanitized through release.BundlePathSegment — the function the path uses, so the name and the path agree about what a cluster's identity reduces to — then folded to the subdomain alphabet (LowerDNS) and bounded as a label value (BoundLabelValue): kustomize-controller stamps `kustomize.toolkit.fluxcd.io/name: <this>` on every object it applies, and an over-long name fails every apply naming the APPLIED object.
func LabelValue ¶
LabelValue is the label value for a cluster or unit name, the way the hub labels an applier with its cluster (`reliant.dev/cluster`) and unit.
func LowerDNS ¶
LowerDNS folds a path segment into the RFC-1123 subdomain alphabet: lower case, and `_` (legal in a path, illegal in a name) to `-`.
A DOT IS LEFT ALONE: folding it would collapse two genuinely different contexts (`a.b` and `a-b`) onto one object name, the silent overwrite Validate refuses. Leaving it means the only collisions are ones the refusal catches.
func Render ¶
func Render(rs map[string]any, providers ...Provider) ([]*unstructured.Unstructured, error)
Render builds the objects flux-operator would apply for rs, a ResourceSet object (as ResourceSet or kcl's flux_delivery_resourceset returns it), with providers standing in for the ResourceSetInputProviders its inputsFrom selects. The objects carry the owner labels and commonMetadata flux-operator stamps before it applies.
func ResourceSet ¶
func ResourceSet(in BindingInput) (map[string]any, error)
ResourceSet is the ResourceSet that renders one binding, with the binding's input inline — the hub's shape, where the writer owns the object. It is the object kcl's `flux_delivery_resourceset(ResourceSetName(env, binding), namespace, inputs = [in.Map()])` returns; the KCL agreement test pins the two.
It validates nothing: call Validate first. It refuses only an input it cannot encode.
func ResourceSetName ¶
ResourceSetName is the name of the ResourceSet that renders a binding, in the org's hub namespace: `delivery.<env>`, or `delivery.<env>.<binding>`. Bounded as a label value because flux-operator stamps it on every object it applies (`resourceset.fluxcd.controlplane.io/name`).
func Rules ¶
func Rules() []rbacv1.PolicyRule
Rules are the verbs the delivery ServiceAccount holds in its own namespace: the two Flux kinds the template renders, and nothing else. No Secret verb at all — `create` cannot be bounded by resourceNames, and a Secret `create` in a hub namespace mints a token for any ServiceAccount there. `delete` is the retire protocol and ResourceSet uninstall; the prune opt-out bounds it.
kcl/lib/flux_delivery.k's flux_delivery_rbac() declares the same rules for a self-hosted bootstrap; the KCL agreement test pins the pair.
func SelfHostedNamespace ¶
SelfHostedNamespace is an env's default delivery namespace: forge-delivery-<project>-<env>, the same composition as KCL's flux_delivery_namespace. A Bundle may name its own (FluxDelivery.namespace); the render reports the one in effect, and a writer reads that rather than recomposing it.
func SelfHostedServiceAccount ¶
SelfHostedServiceAccount is the identity a self-hosted tree (with identities) of phase applies as: PreServiceAccount for `pre`, ApplyServiceAccount for rollout and post.
func SourceName ¶
SourceName is the name of a binding's OCIRepository: `<org>.env.<env>` (control-plane's fluxtenant.BundleObjectName) for the environment's binding.
func TreeKustomizationName ¶
TreeKustomizationName is the name of one layout-v2 tree's Kustomization (control-plane's fluxtenant.BundleTreeKustomizationName). The unit sits between cluster and phase exactly as it does in the path.
func Validate ¶
func Validate(in BindingInput) error
Validate refuses an input the template must not render. It is pure, and it runs before anything is written: the hub converger and `forge env deploy` call the same function.
It does NOT judge the input against the LIVE ResourceSet (the shrink, path-invariance and fence refusals): those compare two inputs of one binding and belong to the writer.
func ValidateSelfHosted ¶
func ValidateSelfHosted(in BindingInput, mode SelfHosted) error
ValidateSelfHosted is Validate for a self-hosted binding: every structural refusal of the hub, except that an in-cluster TREE is the norm here rather than a breach, plus the identity rules above. A self-hosted input that names a kubeconfig is refused: there is no other cluster to reach.
Types ¶
type Applier ¶
type Applier struct {
// Name is [TreeKustomizationName] for a tree, [KustomizationName] for a
// flat cluster.
Name string `json:"name"`
// Source is the OCIRepository the applier reads, and must equal
// Source.Name: one input, one source.
Source string `json:"source"`
// Cluster, Unit and Phase are the applier's coordinates in the bundle:
// the rendered cluster name as the bundle's paths index it (a kube
// context, not necessarily a DNS label), the delivery unit and the phase
// of a tree. Unit and Phase are "" for a flat cluster. [Validate] derives
// Name and Path from them; the template reads neither.
Cluster string `json:"cluster"`
Unit string `json:"unit"`
Phase release.Phase `json:"phase"`
// Path is release.BundleTreePath (tree) or release.BundleClusterPath
// (flat) of the coordinates — CHECKED, because a Kustomization at a path
// the artifact does not hold reconciles as "no resources" and reports
// Ready.
Path string `json:"path"`
// Retire retires this applier alone: "" or [RetireOrphan]. The first of
// the two writes that drop an applier.
Retire string `json:"retire"`
// Labels are stamped on this Kustomization beside BindingInput.Labels
// (the hub: cluster, delivery unit, phase — [LabelValue] of each).
Labels map[string]string `json:"labels"`
// KubeConfigSecret names the destination kubeconfig Secret in Namespace
// (key [KubeConfigKey]). Exactly one of KubeConfigSecret and InCluster.
KubeConfigSecret string `json:"kubeConfigSecret"`
// InCluster applies to the namespace's own cluster with the controller's
// in-cluster identity, impersonating ServiceAccountName. Explicit rather
// than inferred from an empty KubeConfigSecret: an absent kubeConfig is
// a destination breach when it happens by omission.
InCluster bool `json:"inCluster"`
// ServiceAccountName is the identity an in-cluster apply impersonates.
// Required with InCluster, refused beside a kubeconfig (the connected
// shard applies as the kubeconfig's identity and nothing else). Rendered
// even when empty, as the hub's objects already carry it.
ServiceAccountName string `json:"serviceAccountName"`
// TargetNamespace forces every applied object into one namespace (a
// hosted destination); "" leaves the bundle's own namespaces.
TargetNamespace string `json:"targetNamespace"`
// DependsOn are applier names IN THIS INPUT that must be Ready first.
DependsOn []string `json:"dependsOn"`
// ExternalDependsOn are Kustomization names OUTSIDE this binding, in the
// same namespace. Not resolved here; empty today.
ExternalDependsOn []string `json:"externalDependsOn"`
// Health is what the applier is judged on (instead of Wait).
Health []HealthCheck `json:"health"`
// HealthExprs override kstatus for kinds whose Ready alone does not prove
// the current spec reconciled.
HealthExprs []HealthCheckExpr `json:"healthExprs"`
// Wait judges every applied object; a tree waits on Health instead.
Wait bool `json:"wait"`
// Timeout and RetryInterval are canonical Go durations ("1m30s");
// RetryInterval "" leaves Flux's default.
Timeout string `json:"timeout"`
RetryInterval string `json:"retryInterval"`
// Suspended carries a live suspend into the input (adoption, or a tree
// added suspended).
Suspended bool `json:"suspended"`
// CommonLabels are stamped on every object the applier applies (a hosted
// destination's identity).
CommonLabels map[string]string `json:"commonLabels"`
// Patches are kustomize patches on the applied objects (a hosted
// destination's deployment ids), in a stable order.
Patches []Patch `json:"patches"`
}
Applier is one Kustomization.
type BindingInput ¶
type BindingInput struct {
// Schema is [Schema].
Schema string `json:"schema"`
// Org is the owning organization. RFC-1123 label.
Org string `json:"org"`
// Env is the environment id. RFC-1123 label. (Not `id`: flux-operator
// reserves inputs.id and inputs.provider.)
Env string `json:"env"`
// Binding is the ledger binding within the environment. "" — the whole
// environment — is the only value [Validate] accepts until the ledger has
// per-binding promotion; the key exists so nothing re-shapes later.
Binding string `json:"binding"`
// Namespace is where the ResourceSet and everything it renders live
// (`flux-<org>` on the hub, `flux-system` self-hosted).
Namespace string `json:"namespace"`
// Fence is the writer's lease fence at the last write that moved
// something, as decimal digits (inputs are JSON). Stamped on the
// OCIRepository as [FenceAnnotation].
Fence string `json:"fence"`
// Promotion is the ledger row this input projects.
Promotion string `json:"promotion"`
// Retire is "", [RetireOrphan] or [RetireTeardown], and only ever from a
// ledger-recorded intent. Binding-wide; an applier may also be retired
// alone ([Applier.Retire]).
Retire string `json:"retire"`
// Labels are stamped on EVERY rendered object. Computed by the writer
// (the hub: managed-by, org, environment; a binding label only for a
// non-empty binding); the template adds only the shard label.
Labels map[string]string `json:"labels"`
// Source is the binding's ONE OCIRepository.
Source Source `json:"source"`
// Appliers are one Kustomization each: a layout-v2 tree, or a flat
// (layout v1) cluster.
Appliers []Applier `json:"appliers"`
}
BindingInput is ONE ResourceSet input: everything one ledger binding — one promotion-row stream — decides. Today a binding is one environment (Binding == "").
Every field is computed by the ledger's writer; the template derives nothing but the safety stamps (see the package doc). Field names are fixed by the JSON tags, and BindingInput.Map is the only way to produce the map a ResourceSet carries.
func LiveInput ¶
func LiveInput(pointer *unstructured.Unstructured) (BindingInput, error)
LiveInput reads the input a live pointer carries back into a BindingInput. A pointer whose defaultValues does not decode as one (an older schema, a hand edit) is an error: a writer must not compare against an input it cannot read.
func (BindingInput) Map ¶
func (in BindingInput) Map() (map[string]any, error)
Map is the input as a ResourceSet carries it: `spec.inputs[i]`, or a ResourceSetInputProvider's `defaultValues`.
Every key is present, with empty maps and lists rather than null: the template runs with missingkey=error, so an absent key is a stalled render, and a writer comparing the live input with the next one must not see a difference between null and empty.
type HealthCheck ¶
type HealthCheck struct {
APIVersion string `json:"apiVersion"`
Kind string `json:"kind"`
Name string `json:"name"`
Namespace string `json:"namespace,omitempty"`
}
HealthCheck is one entry of Kustomization.spec.healthChecks.
type HealthCheckExpr ¶
type HealthCheckExpr struct {
APIVersion string `json:"apiVersion"`
Kind string `json:"kind"`
// InProgress and Failed are evaluated before Current, in that order
// (Flux RFC 0009). omitempty keeps an expression that sets only Current
// rendering exactly as before.
InProgress string `json:"inProgress,omitempty"`
Failed string `json:"failed,omitempty"`
Current string `json:"current"`
}
HealthCheckExpr is one entry of Kustomization.spec.healthCheckExprs.
func ForgeTierHealthExprs ¶ added in v1.0.15
func ForgeTierHealthExprs() []HealthCheckExpr
ForgeTierHealthExprs is one expression per forge.dev tier kind, for an applier that waits on every object it applies (Wait).
type OIDCIdentity ¶
OIDCIdentity is one keyless signer identity, as Flux's matchOIDCIdentity.
type Patch ¶
type Patch struct {
Patch string `json:"patch"`
Target PatchTarget `json:"target"`
}
Patch is one entry of Kustomization.spec.patches.
type PatchTarget ¶
type PatchTarget struct {
Group string `json:"group,omitempty"`
Version string `json:"version,omitempty"`
Kind string `json:"kind"`
Name string `json:"name"`
}
PatchTarget selects the object a Patch applies to.
type Provider ¶
Provider is the exported inputs of one ResourceSetInputProvider the ResourceSet selects (the self-hosted shape). flux-operator adds the provider reference to each input; an `id` is the provider's own business and, if wanted, belongs in Inputs.
type SelfHosted ¶
type SelfHosted struct {
// ApplyIdentities is FluxDelivery.apply_identities: every tree names its derived
// identity. False: no tree names one.
ApplyIdentities bool
}
SelfHosted is how a self-hosted delivery applies, for ValidateSelfHosted.
type Source ¶
type Source struct {
// Name is [SourceName](org, env, binding).
Name string `json:"name"`
// URL is the bundle repository, `oci://` scheme included, without a tag:
// the digest pins it.
URL string `json:"url"`
// Digest is the bundle's OCI MANIFEST digest ("sha256:" + 64 hex), the
// value Flux reports as the revision.
Digest string `json:"digest"`
// Interval is the reconcile interval of the source and of every applier,
// as a canonical Go duration ("5m0s"): the form the API server stores, so
// a render equals the live object byte for byte.
Interval string `json:"interval"`
// Insecure allows the pull over plain HTTP. The digest still pins the
// content; this weakens transport, not integrity.
Insecure bool `json:"insecure"`
// Provider is Flux's pull auth provider ("" for Flux's generic default).
Provider string `json:"provider"`
// PullSecret names the registry pull Secret in Namespace, written by the
// writer (or the self-hosted bootstrap), never by the template. "" for
// an anonymous pull.
PullSecret string `json:"pullSecret"`
// Verify is the signature verification the source enforces.
Verify Verify `json:"verify"`
}
Source is the binding's OCIRepository.
type Verify ¶
type Verify struct {
// Mode is [VerifyOff], [VerifyAudit] or [VerifyEnforce].
Mode string `json:"mode"`
// Provider is Flux's verification provider, "cosign" or "notation".
// Required in enforce mode.
Provider string `json:"provider"`
// SecretRef names the Secret of trusted public keys in Namespace, written
// by the writer before an enforcing input. Key-based verification;
// exclusive with OIDC.
SecretRef string `json:"secretRef"`
// OIDC are the keyless identities a signature may carry; exclusive with
// SecretRef.
OIDC []OIDCIdentity `json:"oidc"`
}
Verify is the source's signature verification.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
internal
|
|
|
gentemplate
command
Command gentemplate writes pkg/fluxdelivery/template_gen.go: the Go constant of kcl/lib/flux_delivery.k's FLUX_DELIVERY_TEMPLATE, evaluated through forge's own KCL seam.
|
Command gentemplate writes pkg/fluxdelivery/template_gen.go: the Go constant of kcl/lib/flux_delivery.k's FLUX_DELIVERY_TEMPLATE, evaluated through forge's own KCL seam. |
|
kcleval
Package kcleval evaluates a KCL program against the forge module embedded in this binary — the module a released forge renders with — for fluxdelivery's generator and its Go/KCL agreement tests.
|
Package kcleval evaluates a KCL program against the forge module embedded in this binary — the module a released forge renders with — for fluxdelivery's generator and its Go/KCL agreement tests. |