Documentation
¶
Overview ¶
Package localformat writes the uniform numbered local-chart bundle layout. Currently consumed by the helm deployer (--deployer helm). Designed to be consumable by additional deployers (e.g. helmfile per #632, argocd, Flux) without per-deployer changes to the writer; those integrations are not yet wired in this package.
Layout ¶
Each emitted folder is named NNN-<component>/ where NNN is a zero-padded 1-based index. Folders are one of two kinds, distinguished solely by the presence or absence of Chart.yaml:
KindUpstreamHelm — no Chart.yaml. The folder carries values.yaml, cluster-values.yaml, upstream.env (CHART/REPO/VERSION), and a rendered install.sh that installs the upstream chart via `helm upgrade --install`.
KindLocalHelm — Chart.yaml + templates/ present. The folder is a self-contained Helm chart; install.sh installs `./` as a local chart.
The Chart.yaml presence rule is the sole branch point for consumers. No component-kind metadata is re-read at deploy time. This is deliberate: a previous design branched deploy.sh on Helm/Kustomize/raw-manifest kinds, which bled component-type classification into every deployer. Chart.yaml presence reduces that to a single on-disk signal every deployer honors.
Classification ¶
Recipe shape determines the folder kind:
Helm repository set, no manifests → KindUpstreamHelm
Helm repository set, with raw manifests → KindUpstreamHelm primary +
KindLocalHelm "-post" injection
Helm repository empty, manifests only → KindLocalHelm (wrapped)
Kustomize (Tag/Path set) → KindLocalHelm (kustomize build
output wrapped as templates/manifest.yaml)
Mixed components and the "-post" injection ¶
When a single recipe component declares both an upstream Helm chart and raw manifests, Write emits two adjacent folders: the primary NNN-<name>/ as KindUpstreamHelm, immediately followed by (NNN+1)-<name>-post/ as KindLocalHelm wrapping the raw manifests. Subsequent components shift by one. The "mixed" concept does not appear in the recipe types, deployment order, or bundle result — it exists only in the bundle layout.
The -post folder deploys after the upstream chart, so raw manifests that reference the chart's CRDs apply against a cluster where those CRDs already exist. This is what makes the earlier pre-apply-with-retry mechanism (which applied raw manifests before the chart and retried on "CRD not found" errors) structurally unnecessary.
Base-format invariants ¶
These are load-bearing contracts. Callers and contributors should not violate them without changing the design:
localformat never writes deployer-specific files. deploy.sh, helmfile.yaml, argocd Application CRs, Flux HelmReleases, and the like are produced by the respective deployer after Write returns. Write owns per-folder content; deployers own top-level orchestration files. This separation is what makes a single folder layout consumable by every deployer without localformat growing per-deployer branches.
install.sh is never name-customized. Rendered from one of exactly two templates (upstream-helm, local-helm), parameterized only by data (name, namespace, upstream ref). Name-keyed component quirks (kai-scheduler async skip, skyhook taint cleanup, DRA restart, orphan CRD scan) stay in deploy.sh as name-matched blocks — not in install.sh. This is the structural barrier that keeps per-folder scripts from accumulating drift the way deploy.sh's branching did.
Write is deterministic and idempotent. Same Options in, same on-disk bytes and same Folder slice out. Map iteration is sorted; no timestamps or random suffixes are embedded in generated content.
Caller contract ¶
Callers pass an ordered Components slice (sorted by deployment order) and two manifest maps (name → path → rendered bytes):
- ComponentPostManifests drives both the -post injection for mixed components and the template contents for manifest-only wrapped charts. Populated from ComponentRef.ManifestFiles.
- ComponentPreManifests carries manifests intended to apply BEFORE each component's primary chart (e.g. an OS-specific namespace). Populated from ComponentRef.PreManifestFiles. The writer emits a wrapped "<name>-pre" local-helm folder ahead of the primary folder when this map has entries for the component; install.sh in the pre folder omits --create-namespace because the chart's Namespace template owns namespace creation.
Write returns a []Folder manifest so deployers can generate their own orchestration files without re-classifying or re-reading disk.
Further detail: ticket #662 carries the original design discussion and alternatives considered.
Index ¶
- Constants
- func InjectPostInstallHooks(in []byte) ([]byte, error)
- func NestUnderSubchart(values map[string]any, subchart string) map[string]any
- func RenderWrapperChartYAML(name, parent, chartName, chartVersion string) ([]byte, error)
- func ShouldVendor(c Component) bool
- func WriteProvenance(ctx context.Context, outputDir string, records []VendorRecord) (string, int64, error)
- type CLIChartPuller
- type ChartPuller
- type Component
- type Folder
- type FolderKind
- type Options
- type Upstream
- type VendorRecord
- type WriteResult
Constants ¶
const ( ProvenanceAPIVersion = "aicr.nvidia.com/v1alpha1" ProvenanceKind = "BundleProvenance" )
ProvenanceAPIVersion / ProvenanceKind identify the document shape using AICR's K8s-style convention. Bump the apiVersion when a downstream consumer would need to branch on shape (v1alpha1 → v1beta1 → v1). Additive fields do not require a bump.
const ProvenanceFileName = "provenance.yaml"
ProvenanceFileName is the on-disk filename at the bundle root. Exported so consumers (deployers, downstream tooling) reference the same name.
Variables ¶
This section is empty.
Functions ¶
func InjectPostInstallHooks ¶ added in v0.13.0
InjectPostInstallHooks rewrites a multi-document YAML stream to add post-install hook annotations. Exported for deployers that build vendored mixed-component folders outside of localformat.Write() (e.g., flux).
func NestUnderSubchart ¶ added in v0.13.0
NestUnderSubchart wraps values under a single key so Helm forwards them to the named subchart at install time. Exported for deployers that build vendored folders with a wrapper chart (e.g., flux).
func RenderWrapperChartYAML ¶ added in v0.13.0
RenderWrapperChartYAML produces the wrapper Chart.yaml content for a vendored component. Exported for deployers that build their own vendored folder layout (e.g., flux).
func ShouldVendor ¶ added in v0.13.0
ShouldVendor reports whether c should be routed through the vendor path when --vendor-charts is on. Returns false (without error) for shapes that are already local after #662 (Kustomize, manifest-only) — callers fall through to the existing classify() path for those. Exported for deployers that build their own vendored folder layout (e.g., flux) and need the same predicate without duplicating it.
func WriteProvenance ¶ added in v0.13.0
func WriteProvenance(ctx context.Context, outputDir string, records []VendorRecord) (string, int64, error)
WriteProvenance sorts records by component name and writes provenance.yaml at the root of outputDir. Returns the absolute file path, byte size, and any error. records MUST be non-empty; callers guard the call so an empty vendor set produces no file.
ctx is checked for cancellation before the filesystem write so a caller-initiated abort short-circuits the I/O. The marshaling and path-safety checks above the write are pure CPU and run regardless.
Mode 0o644: provenance is audit content meant to be read by operators and downstream tooling (yank-list scanners), not a secret.
Types ¶
type CLIChartPuller ¶ added in v0.13.0
type CLIChartPuller struct {
HelmBin string
}
CLIChartPuller shells out to `helm pull` to fetch upstream chart bytes. Used today while legal review of the in-process Helm SDK is pending; will be supplemented by an SDKChartPuller when approved.
Auth flows through helm's own conventions:
- HTTP(S): HELM_REPOSITORY_USERNAME / HELM_REPOSITORY_PASSWORD env vars.
- OCI: standard docker config (~/.docker/config.json or $DOCKER_CONFIG), exactly like `helm pull oci://...`.
HelmBin overrides the binary lookup; empty falls back to "helm" on $PATH.
func (*CLIChartPuller) Pull ¶ added in v0.13.0
func (p *CLIChartPuller) Pull(ctx context.Context, c Component) ([]byte, VendorRecord, string, error)
Pull invokes `helm pull` for c, reads the resulting .tgz from a temporary destination, computes its SHA256, and returns the bytes plus a VendorRecord. The temp directory is removed before returning even on error. ctx cancellation interrupts the helm subprocess via os.Interrupt (exec.CommandContext default).
type ChartPuller ¶ added in v0.13.0
type ChartPuller interface {
Pull(ctx context.Context, c Component) (tgz []byte, rec VendorRecord, tarball string, err error)
}
ChartPuller fetches an upstream Helm chart and returns the raw .tgz bytes plus a provenance record. The implementation choice — shelling out to the helm CLI vs the in-process Helm SDK — is hidden behind this interface so the bundle-time path is identical either way.
Implementations MUST honor ctx cancellation, MUST NOT mutate c, and SHOULD return one of the structured error codes from pkg/errors so callers can branch on intent rather than substring matching.
type Component ¶
type Component struct {
Name string
Namespace string
// Helm upstream ref (empty for manifest-only components)
Repository string
ChartName string
Version string
IsOCI bool
// Kustomize (empty for helm components)
Tag string
Path string
// Values hydrated by the component bundler
Values map[string]any
DynamicPaths []string // paths moved from values.yaml into cluster-values.yaml
}
Component is the per-component input for Write. Fields mirror the subset of pkg/bundler/deployer/helm.ComponentData that localformat needs.
type Folder ¶
type Folder struct {
Index int // 1-based; rendered as zero-padded 3-digit prefix in Dir
Dir string // e.g. "001-nfd"
Kind FolderKind
Name string // component name, or "<name>-post" for injected
Parent string // component this folder belongs to (== Name for primary)
Upstream *Upstream // set iff Kind == KindUpstreamHelm
Files []string // relative paths (to OutputDir) of files written in this folder
// CreateNamespace is true when the orchestration layer should pass
// --create-namespace to helm for this folder's release, false when
// the folder's chart ships its own Namespace resource (the Talos
// privileged-namespace pre-injection pattern). install.sh already
// honors this internally; the field exposes the same decision to
// out-of-band deployers (e.g., helmfile) that bypass install.sh.
// Helm 3 refuses to import a namespace it created out-of-band via
// --create-namespace because that namespace lacks the release's
// ownership annotations.
CreateNamespace bool
}
Folder describes one written folder. Returned by Write so callers (deployers) can generate orchestration files without re-classifying.
type FolderKind ¶
type FolderKind int
FolderKind classifies a written folder by the presence/absence of Chart.yaml.
const ( // KindUpstreamHelm: folder contains no Chart.yaml; install.sh references // an upstream Helm chart via upstream.env. KindUpstreamHelm FolderKind = iota // KindLocalHelm: folder contains a generated Chart.yaml + templates/; // install.sh installs ./ as a local chart. KindLocalHelm )
func (FolderKind) String ¶
func (k FolderKind) String() string
String returns the stable textual name for the kind. Used by logs and golden-file diagnostics so diffs show kind names rather than integers.
type Options ¶
type Options struct {
OutputDir string
Components []Component // ordered per DeploymentOrder
// ComponentPreManifests maps component name → manifest path → rendered
// bytes for manifests that should apply BEFORE each component's primary
// chart. Populated from ComponentRef.PreManifestFiles. The writer does
// not yet emit pre-phase folders — Task 4 wires the pre-injection
// branch; for now the map is threaded through but unread.
ComponentPreManifests map[string]map[string][]byte
// ComponentPostManifests maps component name → manifest path → rendered
// bytes for manifests that should apply AFTER each component's primary
// chart. Populated from ComponentRef.ManifestFiles. Drives the existing
// -post injection for mixed components and the template contents for
// manifest-only wrapped charts.
ComponentPostManifests map[string]map[string][]byte
// VendorCharts pulls upstream Helm chart bytes into each Helm-typed
// component's folder at bundle time. When set, every Helm component
// emits a single wrapped folder with charts/<chart>-<version>.tgz +
// wrapper Chart.yaml + (for mixed components) post-install-hook
// templates. Mixed components no longer split into primary + -post.
// Off by default — non-vendored bundles preserve the upstream
// CVE-yank fail-loud signal.
VendorCharts bool
// Puller fetches upstream chart bytes when VendorCharts is set. nil
// is allowed and resolves to a default *CLIChartPuller; tests can
// inject a stub here without touching package state. Ignored when
// VendorCharts is false.
Puller ChartPuller
}
Options configures Write.
type VendorRecord ¶ added in v0.13.0
type VendorRecord struct {
// Name is the recipe component name (folder NNN-<name>).
Name string `json:"name"`
// Chart is the upstream chart name as declared in the recipe.
Chart string `json:"chart"`
// Version is the chart version pulled.
Version string `json:"version"`
// Repository is the resolved upstream URL (HTTP(S) or oci://).
Repository string `json:"repository"`
// SHA256 is the hex-encoded digest of the .tgz bytes pulled.
SHA256 string `json:"sha256"`
// TarballName is the on-disk filename written under charts/.
TarballName string `json:"tarballName"`
// PullerVersion identifies the puller implementation that produced
// this record (e.g. "helm-cli v3.20.2"). Audit-only; not used by
// downstream code.
PullerVersion string `json:"pullerVersion,omitempty"`
}
VendorRecord captures one entry of the bundle-time audit log emitted when --vendor-charts is set. Together the fields let an operator reconstruct provenance for a vendored chart and run yank-list lookups after the fact.
type WriteResult ¶ added in v0.13.0
type WriteResult struct {
// Folders is one entry per emitted NNN-<name>/ directory, in
// deployment order. Files within each Folder are relative to the
// Write call's OutputDir.
Folders []Folder
// VendoredCharts is non-empty only when Options.VendorCharts was
// set; one record per upstream chart pulled into the bundle. Pass
// directly to WriteProvenance to emit the audit log.
VendoredCharts []VendorRecord
}
WriteResult is the typed return shape from Write. Callers consume Folders for per-component bookkeeping (checksums, output files) and VendoredCharts to emit provenance.yaml or other audit artifacts.
Returned as a struct (rather than (slices..., error)) so future additions — e.g., per-folder warnings, partial-failure detail — do not break the call signature for every downstream consumer.
func Write ¶
func Write(ctx context.Context, opts Options) (WriteResult, error)
Write emits the numbered folder layout. Deterministic and idempotent.
Removes any pre-existing NNN-* folders under OutputDir before writing, so reusing the same --output across recipe regenerations does not leave stale component folders that the deployer's loop would later install. Top-level orchestration files (deploy.sh, undeploy.sh, README.md, attestation/) are left intact; only files under [0-9][0-9][0-9]-* are removed.
Returns the list of emitted folders plus, when opts.VendorCharts is set, one VendorRecord per pulled upstream chart for inclusion in the bundle's provenance.yaml. The records slice is empty when VendorCharts is false.