Documentation
¶
Overview ¶
Package values implements HelmRelease values resolution and Kustomization postBuild substitution. It is the bridge between authored manifests and rendered manifests: it consults the central Store for ConfigMap/Secret content and merges referenced data into a HelmRelease's values map or a Kustomization's postBuild substitution table.
Two key behaviors mirror flux-local:
- Deep merge follows Helm semantics: nested maps are merged, but lists are REPLACED entirely (not concatenated).
- When a valuesFrom reference is optional and the target ConfigMap / Secret (or values key) is missing, it is skipped silently so the render proceeds; a wiped Secret value (a placeholder token the manifest parser injects for SOPS-encrypted data) is treated as empty rather than failing the whole HelmRelease.
Index ¶
- func DeepMerge(base, override map[string]any) map[string]any
- func DeepMergeInto(dst, override map[string]any) map[string]any
- func ExpandPostBuildSubstituteReference(ks *manifest.Kustomization, p Provider) error
- func ExpandValueReferences(hr *manifest.HelmRelease, provider Provider, cache *Cache) error
- func UnreadableSubstituteSecrets(ks *manifest.Kustomization, p Provider) []string
- func VarsMap(in map[string]any) map[string]string
- type Cache
- type Provider
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DeepMerge ¶
DeepMerge returns a new map with override's keys merged into base. Nested maps recurse; lists and scalars from override fully replace values from base — matching Helm's merge semantics. Both inputs are read-only.
Implemented as deepMergeShared over a fresh shallow copy of base: the copy makes the top-level map owned, and deepMergeShared's copy-on-collision recursion keeps every borrowed (base) sub-tree read-only, so neither input is mutated.
func DeepMergeInto ¶
DeepMergeInto merges override's keys into dst in place. Same merge semantics as DeepMerge but mutates dst instead of allocating a new map. Callers MUST own dst and any sub-maps reachable from it — passing a map that shares sub-trees with another reachable reference will corrupt that reference. Designed for hot paths (ExpandValueReferences's per-ref loop) where the caller is building up a fresh map across N refs and the N-1 intermediate allocations DeepMerge would do are wasted.
Sub-maps coming from override are inserted by reference (not cloned) when no existing key collides — same as DeepMerge. Returns dst for fluent-style use.
func ExpandPostBuildSubstituteReference ¶
func ExpandPostBuildSubstituteReference(ks *manifest.Kustomization, p Provider) error
ExpandPostBuildSubstituteReference resolves substituteFrom references against the provider and updates ks.PostBuildSubstitute (and its raw Contents). Missing references are logged (Secrets silently) and the substitution proceeds with what's available.
func ExpandValueReferences ¶
func ExpandValueReferences(hr *manifest.HelmRelease, provider Provider, cache *Cache) error
ExpandValueReferences resolves all spec.valuesFrom references on hr, merges them with hr.Values (inline values take precedence per Helm semantics), and writes the result back to hr.Values.
Honors ValuesReference.Optional: missing resources or values keys on Optional=true refs are skipped silently; Optional=false refs fail. Matches Flux helm-controller chartutil semantics.
Hard errors from the lookup itself — unsupported kind, malformed binaryData — always bubble up; they are unrelated to whether the ref is optional.
cache may be nil — tests and embedders without an orchestrator pass nil and pay the (small) per-ref yaml.Unmarshal cost. Orchestrators supply a Cache constructed at startup so refs shared across HRs (a common pattern for platform-wide values CMs) parse exactly once.
func UnreadableSubstituteSecrets ¶ added in v0.4.7
func UnreadableSubstituteSecrets(ks *manifest.Kustomization, p Provider) []string
UnreadableSubstituteSecrets returns the names of ks.PostBuildSubstituteFrom Secret references whose data flate can't read offline — an absent Secret or an ExternalSecret-synthesized empty target, both of which yield no data so the ${VAR}s they would supply expand to the empty string. SOPS-encrypted Secrets are NOT reported: their data is wiped to placeholders, so their vars still substitute. Optional refs are skipped (the author marked them best-effort). The result is sorted and de-duplicated; nil when none.
This is a pure advisory query — it does not affect substitution. The Kustomization controller surfaces the result as a WarnUnresolvedSubstitution Warning so an unreadable secret is explained rather than silently leaving empty values behind.
func VarsMap ¶
VarsMap returns the substitution variables for use with kustomize.Substitute. Non-string scalar values are stringified; nested maps/slices and other unsupported shapes are silently dropped with a Debug log rather than rendered as Go's default `map[k:v]` / `[1 2 3]` representation, which produced literal garbage substitutions diverging from upstream kustomize-controller (whose LoadVariables only accepts flat string→string). Newline characters are stripped from every value — upstream does the same so multi-line entries can't break inline substitution into single-line YAML fields.
Types ¶
type Cache ¶
type Cache struct {
// contains filtered or unexported fields
}
Cache memoizes parsed-YAML output of valuesFrom refs across HRs. One HR with N valuesFrom refs hits each entry once; M HRs sharing the same ConfigMap/Secret/key tuple (a common pattern when a platform values CM is referenced by every app HR) re-yaml.Unmarshal'd the same bytes M times. Cache key folds the content hash so a mutation to the underlying object (re-AddObject) invalidates naturally without an explicit listener.
Stored values are TREATED AS IMMUTABLE — callers receive a deep clone before mutation so concurrent ExpandValueReferences calls can't observe a partially-modified sub-tree. The cache itself is safe for concurrent use.
Zero value is a no-op cache: NewCache or a non-nil *Cache must be supplied to opt into memoization. nil is the legacy fast path for tests / one-shot embedders.
type Provider ¶
type Provider interface {
ConfigMap(namespace, name string) *manifest.ConfigMap
Secret(namespace, name string) *manifest.Secret
}
Provider exposes the ConfigMap/Secret lookups needed for value reference expansion. The controllers implement it against the central store (see NewStoreProvider); tests use SliceProvider.
func NewStoreProvider ¶
NewStoreProvider returns a Provider backed by the central Store.