Documentation
¶
Overview ¶
Package helm wraps helm.sh/helm/v4 to render HelmReleases without shelling out to the `helm` binary.
The exported surface:
- Client.Template / Client.TemplateDocs render a HelmRelease to YAML documents (the equivalent of `helm template --dry-run --client-only`).
- Client.SetSourceResolver wires the canonical source-CR lookup surface — production callers pass NewStoreSourceResolver(store) so HelmRepository / OCIRepository / GitRepository / Bucket / ExternalArtifact lookups read straight from the canonical object store. Embedders rendering a single HR without an orchestrator can implement SourceResolver directly.
- Prepare(hr, charts, provider) performs the pre-render dance (Clone → ResolveChartRef → ExpandValueReferences) — call this before TemplateDocs when rendering a HelmRelease in isolation.
- Options exposes the helm CLI flags flate understands (--kube-version, --api-versions, --no-hooks, etc.).
The client is safe for concurrent use; chart downloads are cached on disk keyed by chart name + version, and parallel first-loads of the same chart coalesce through a per-path keylock.
Index ¶
- Constants
- Variables
- func Prepare(hr *manifest.HelmRelease, lookup manifest.HelmChartLookup, ...) (*manifest.HelmRelease, error)
- type ChartLoadResult
- type Client
- func (c *Client) LoadChart(ctx context.Context, hr *manifest.HelmRelease) (ChartLoadResult, error)
- func (c *Client) LocateChart(ctx context.Context, hr *manifest.HelmRelease) (string, error)
- func (c *Client) Resolver() SourceResolver
- func (c *Client) SetOCIPuller(p OCIPuller)
- func (c *Client) SetSecretGetter(g SecretGetter)
- func (c *Client) SetSourceResolver(r SourceResolver)
- func (c *Client) SetTaskYield(yield func(fn func()))
- func (c *Client) Template(ctx context.Context, hr *manifest.HelmRelease, hrValues map[string]any, ...) (string, error)
- func (c *Client) TemplateDocs(ctx context.Context, hr *manifest.HelmRelease, values map[string]any, ...) ([]map[string]any, error)
- func (c *Client) ValuesCache() *values.Cache
- type ClientOptions
- type OCIPuller
- type Options
- type SecretGetter
- type SourceResolver
Constants ¶
const DefaultRenderCacheBytes int64 = 1024 << 20
DefaultRenderCacheBytes is the default size of the persistent helm template-output cache: 1 GiB. The CLI surfaces this through the --helm-render-cache-mb flag (1024 by default; 0 disables).
const DefaultTemplateCacheBytes int64 = 256 << 20
DefaultTemplateCacheBytes is the historical default size of the helm template-output cache: 256 MiB. The CLI surfaces this through the --helm-template-cache-mb flag (256 by default; 0 disables).
Variables ¶
var BundledKubeVersion = sync.OnceValue(detectBundledKubeVersion)
BundledKubeVersion is the Kubernetes minor version associated with the k8s.io/api module flate was built against. It mirrors what the upstream helm SDK would inject if running inside a cluster of that version, and is flate's default for the `--kube-version` flag.
The mapping is well-defined: k8s.io/api v0.X.Y corresponds to Kubernetes v1.X.Y. We derive X.Y at startup from build-info; if build-info is unavailable, we fall back to a sensible default.
Functions ¶
func Prepare ¶
func Prepare(hr *manifest.HelmRelease, lookup manifest.HelmChartLookup, provider values.Provider, cache *values.Cache) (*manifest.HelmRelease, error)
Prepare runs the standard pre-render dance for a HelmRelease so it is ready to feed into Client.Template / TemplateDocs:
- Clone hr so subsequent mutations don't touch the store-canonical copy (the immutability contract every flate controller honors).
- Resolve hr.spec.chartRef via the supplied lookup. A chartRef points at a Flux HelmChart CR — typically emitted by a parent Kustomization render — and is rewritten into the concrete hr.Chart projection. Pass SourceResolver.HelmChart when an orchestrator is available, or a custom lookup otherwise.
- Expand values / valuesFrom against the supplied provider so hr.Values reflects the merged result a render would consume.
Embedders rendering a single HelmRelease without standing up the orchestrator's HR controller call Prepare then TemplateDocs. The returned *HelmRelease is the cloned, resolved one — pass it to Template / TemplateDocs and discard once rendered.
The Client's per-orchestrator values.Cache is threaded through so platform-wide valuesFrom CMs (a common pattern: one app-config CM referenced by N HRs) parse exactly once across the entire run.
Types ¶
type ChartLoadResult ¶
ChartLoadResult is the loaded chart plus the on-disk path it came from.
Fingerprint, when non-empty, is a content-addressed sha256 hex of the chart's loader.Load inputs (Metadata + Templates + Files + Schema + chart defaults + subchart contents). Computed lazily by LoadChart so the template-output cache can build a stable key without re-walking the chart on every render. Memoized per (Client, path) keyed by the same (mtime, size) fingerprint chartCacheEntry uses, so a mutable OCI re-push invalidates this digest just as it invalidates the cached *chart.Chart pointer. Empty when the template cache is disabled.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client renders HelmReleases. Construct with NewClient.
func NewClient ¶
NewClient constructs a Client backed by the supplied Layout with project-wide defaults (DefaultClientOptions). The helm-tmp/ and helm-cache/ directories are taken from the Layout — helm.Client never composes its own paths. The chart-tarball CAS is rooted at the SHARED <root>/blobs/sha256/ blob store so identical chart bytes deduplicate across HelmRepositories and across orchestrator embedders.
Disk-backed template-output cache defaults to enabled at DefaultRenderCacheBytes, rooted at layout.RenderHelmCache(). When layout.Root is empty (an embedder explicitly opted out of any persistent cache) the disk layer auto-disables so we don't write into the OS tempdir under a synthesised "flate-cache" subdir.
Embedders that need to tune cache sizing (TemplateCacheBytes, …) should call NewClientWithOptions instead.
func NewClientWithOptions ¶
func NewClientWithOptions(layout cacheroot.Layout, opts ClientOptions) (*Client, error)
NewClientWithOptions is NewClient with explicit ClientOptions. Pass DefaultClientOptions() to get historical defaults; build the struct manually to disable individual caches (e.g. TemplateCacheBytes=0 for the template-output cache).
func (*Client) LoadChart ¶
func (c *Client) LoadChart(ctx context.Context, hr *manifest.HelmRelease) (ChartLoadResult, error)
LoadChart resolves and loads the chart into helm's in-memory model. Parsed *chart.Chart values are cached by path — Helm's loader.Load reparses the tgz (and recompiles values.schema.json) on every call, which is a significant render-time hot spot when many HelmReleases share a base chart (bjw-s app-template, podinfo, common-library, …). Path is content-addressed by Helm's own cacher (name-version-digest), so this is safe across reconciles.
func (*Client) LocateChart ¶
LocateChart returns a filesystem path to the chart referenced by hr. The caller is responsible for cleanup (chart paths inside the cache are reused across calls; paths inside the tmp dir are not).
func (*Client) Resolver ¶
func (c *Client) Resolver() SourceResolver
Resolver returns the configured SourceResolver, or nil when none has been wired. Exposed so the HelmRelease controller (and embedders calling Prepare) can pass resolver.HelmChart into ResolveChartRef without holding a separate reference to the resolver.
func (*Client) SetOCIPuller ¶
SetOCIPuller installs the OCI fetcher helm.Client routes HelmRepository(type=oci) and OCIRepository chart resolution through. The orchestrator wires source/oci.Fetcher when EnableOCI=true; embedders without one (or EnableOCI=false runs) leave it nil and helm.Client falls back to its built-in registry-client pull. Safe to call before any Template call.
func (*Client) SetSecretGetter ¶
func (c *Client) SetSecretGetter(g SecretGetter)
SetSecretGetter installs a Secret lookup function so HelmRepository SecretRef credentials can be resolved at pull time. Safe to call before any Add* — typically once at orchestrator construction.
func (*Client) SetSourceResolver ¶
func (c *Client) SetSourceResolver(r SourceResolver)
SetSourceResolver installs the canonical lookup surface for HelmRepository / OCIRepository / local-artifact sources. helm.Client reads through the resolver on every Template call — there's no alternate path. Safe to call before any template call; typically once at orchestrator construction.
func (*Client) SetTaskYield ¶
func (c *Client) SetTaskYield(yield func(fn func()))
SetTaskYield installs a callback that the helm client uses to release its worker-pool slot during long-running network I/O (OCI pulls). The orchestrator wires this to task.Service.YieldSlot so concurrent helm renders don't block the pool while one of them is mid-pull. nil disables the yield (the I/O runs while still holding the slot — the legacy behavior for embedders without a task pool).
Kept as a callback rather than a direct task.Service dependency to avoid importing pkg/task into pkg/helm — the orchestrator wires the function reference and helm stays dependency-free.
func (*Client) Template ¶
func (c *Client) Template(ctx context.Context, hr *manifest.HelmRelease, hrValues map[string]any, opts Options) (string, error)
Template renders a HelmRelease and returns the rendered manifest as a single YAML string (multiple documents separated by "---" lines).
Output is cached by computeTemplateKey when c.templateCache is wired (NewClient's default, sized by ClientOptions.TemplateCacheBytes). Cache hits skip action.Install.RunWithContext — the single largest CPU + allocation consumer in the codebase (cited at ~300 MB on a 200-HR run). Each key folds in every input that affects the rendered bytes (chart content fingerprint, fully-resolved values, render Options, HR-level action.Install fields like ReleaseName, CRDs policy, hooks, post-renderers) so a stale entry never serves a different render.
func (*Client) TemplateDocs ¶
func (c *Client) TemplateDocs(ctx context.Context, hr *manifest.HelmRelease, values map[string]any, opts Options) ([]map[string]any, error)
TemplateDocs renders and returns each document parsed as a generic map.
func (*Client) ValuesCache ¶
ValuesCache returns the Client's per-orchestrator valuesFrom parse cache so callers (helm.Prepare, the HR controller) can pass it through to values.ExpandValueReferences. Always non-nil for Clients constructed via NewClient.
type ClientOptions ¶
type ClientOptions struct {
// TemplateCacheBytes caps the in-memory helm-template-output
// cache. <= 0 disables the cache. Use DefaultTemplateCacheBytes
// for the project-wide default.
TemplateCacheBytes int64
// RenderCacheBytes caps the persistent on-disk helm template-
// output cache. <= 0 disables disk caching. Disk
// caching is also disabled when RenderCacheRoot is empty even
// if RenderCacheBytes > 0 — the wiring requires both.
RenderCacheBytes int64
// RenderCacheRoot is the on-disk directory the persistent
// template-output cache writes into (typically
// layout.RenderHelmCache()). Empty disables disk caching even
// when RenderCacheBytes > 0.
RenderCacheRoot string
}
ClientOptions tunes NewClientWithOptions construction. Callers that want historical defaults pass DefaultClientOptions(); embedders that want to disable specific caches (memory-constrained CI, embedders that prefer their own caching layer) build the struct field-by-field.
func DefaultClientOptions ¶
func DefaultClientOptions() ClientOptions
DefaultClientOptions returns the ClientOptions a vanilla NewClient call uses — historical project defaults baked in. Disk caching is off by default at the constructor level: a vanilla NewClient caller hasn't provided a cache root, so we can't safely choose one for them. Callers wanting disk caching populate RenderCacheRoot explicitly (typically from layout.RenderHelmCache()).
type OCIPuller ¶
type OCIPuller = source.TypedFetcher[*manifest.OCIRepository]
OCIPuller fetches an OCI artifact into a content-addressed slot directory. Helm.Client uses it to route HelmRepository(type=oci) and OCIRepository chart resolution through the same machinery as source/oci.Fetcher — applying spec.verify / certSecretRef / proxySecretRef / insecure / layerSelector / ignore uniformly regardless of whether the chart was referenced via OCIRepository or HelmRepository(type=oci). When nil, helm.Client falls back to its built-in registry-client pull (no TLS/auth/verify surface) — matches the pre-unification behavior for EnableOCI=false runs.
source/oci.Fetcher satisfies this interface verbatim (type alias).
type Options ¶
type Options struct {
// SkipCRDs excludes CRDs from the rendered output.
SkipCRDs bool
// SkipTests excludes templates that are helm test hooks.
SkipTests bool
// SkipSecrets excludes Secret resources from the output. flate
// uses placeholder values anyway but stripping makes diffs tidier.
SkipSecrets bool
// SkipKinds is an arbitrary list of kinds to drop.
SkipKinds []string
// KubeVersion overrides Capabilities.KubeVersion (.Capabilities.KubeVersion).
KubeVersion string
// APIVersions overrides Capabilities.APIVersions
// (.Capabilities.APIVersions). Comma-separated.
APIVersions string
// IsUpgrade sets .Release.IsUpgrade instead of .Release.IsInstall.
IsUpgrade bool
// NoHooks excludes hook-annotated templates.
NoHooks bool
// ShowOnly limits output to specific template paths.
ShowOnly []string
// EnableDNS enables DNS lookups during templating.
EnableDNS bool
// SkipSchemaValidation opts out of `values.schema.json` validation
// for every HR — helm's jsonschema validator recompiles the schema
// per render and dominates allocation churn on big repos. The
// per-HR placeholder-detection path still kicks in on top of this:
// even with this flag false, schema validation is skipped when the
// HR values contain a wipe placeholder.
SkipSchemaValidation bool
}
Options collects the helm template flags flate supports.
func (Options) SkipResourceKinds ¶
SkipResourceKinds returns the union of canonical and user-specified kinds to drop from rendered output.
type SecretGetter ¶
type SecretGetter = source.SecretGetter
SecretGetter is the same shape as source.SecretGetter; aliased so the helm Client and the source Fetchers consume one canonical type. The orchestrator wires the same closure into both.
type SourceResolver ¶
type SourceResolver interface {
// HelmRepository returns the HelmRepository at the given (ns, name)
// or nil. Used for index.yaml fetch + SecretRef/CertSecretRef.
HelmRepository(namespace, name string) *manifest.HelmRepository
// OCIRepository returns the OCIRepository at the given (ns, name)
// or nil. The .url field is the chart-artifact root.
OCIRepository(namespace, name string) *manifest.OCIRepository
// LocalSourceArtifact returns the fetched on-disk artifact for a
// GitRepository / Bucket / ExternalArtifact source, or nil. Charts
// live at <artifact.LocalPath>/<hr.Chart.Name> for any of those
// three sourceRef.kind values.
LocalSourceArtifact(kind, namespace, name string) *store.SourceArtifact
// HelmChart returns the HelmChartSource at the given (ns, name) or
// nil. Used by HelmRelease.ResolveChartRef to materialize a
// spec.chartRef into a concrete chart reference.
HelmChart(namespace, name string) *manifest.HelmChartSource
}
SourceResolver is the lookup surface helm.Client needs to resolve a HelmRelease's sourceRef against the canonical object store.
The interface exists so helm.Client reads source CRs from the canonical store on every lookup rather than maintaining a parallel registry — see NewStoreSourceResolver for the production-side adapter. Embedders rendering a single HelmRelease without an Orchestrator can implement this directly.
A nil return from any method means "not found" — callers translate that into a typed manifest.ErrObjectNotFound error.
func NewStoreSourceResolver ¶
func NewStoreSourceResolver(s *store.Store) SourceResolver
NewStoreSourceResolver returns a SourceResolver backed by the canonical object store. The orchestrator wires this into helm.Client so chart-source lookups read straight from the Store.