Documentation
¶
Overview ¶
Package component provides shared bundler utilities used by pkg/bundler and its deployers.
Component configuration is defined declaratively in recipes/registry.yaml. This package provides reusable building blocks for bundle generation. With the declarative registry, no separate Go packages are required per component — adding a registry.yaml entry is sufficient.
Historically AICR had one Go bundler package per component. Those per-component packages have been replaced by the registry-driven pkg/bundler.DefaultBundler; the legacy BaseBundler / MakeBundle entry points described below remain exported for external integrations and the component test harness.
Generic Bundler Framework ¶
The framework provides a declarative approach to bundle generation using:
ComponentConfig: Defines all component-specific settings in one struct:
- Name and DisplayName for identification
- ValueOverrideKeys for CLI --set flag mapping
- Node selector and toleration paths for workload placement
- DefaultHelmRepository, DefaultHelmChart, DefaultHelmChartVersion for Helm deployment
- TemplateGetter function for embedded templates
- Optional CustomManifestFunc for generating additional manifests
- Optional MetadataExtensions map for custom README template data (preferred over MetadataFunc)
MakeBundle: Generic function that handles all common bundling steps:
- Extracting component values from recipe input
- Applying user value overrides from CLI flags
- Applying node selectors and tolerations to Helm paths
- Creating directory structure
- Writing values.yaml with proper YAML headers
- Calling optional CustomManifestFunc for additional files
- Generating README from templates
- Computing checksums
Minimal Bundler Example ¶
Most bundlers can be implemented in ~50 lines using the framework:
var componentConfig = component.ComponentConfig{
Name: "my-operator",
DisplayName: "My Operator",
ValueOverrideKeys: []string{"myoperator"},
DefaultHelmRepository: "https://charts.example.com",
DefaultHelmChart: "example/my-operator",
TemplateGetter: GetTemplate,
}
type Bundler struct {
*component.BaseBundler
}
func NewBundler(cfg *config.Config) *Bundler {
return &Bundler{
BaseBundler: component.NewBaseBundler(cfg, types.BundleTypeMyOperator),
}
}
func (b *Bundler) Make(ctx context.Context, input recipe.RecipeInput, dir string, provider recipe.DataProvider) (*result.Result, error) {
return component.MakeBundle(ctx, b.BaseBundler, input, dir, componentConfig, provider)
}
Custom Metadata ¶
Components that need additional template data beyond the default BundleMetadata can provide a MetadataExtensions map in ComponentConfig:
var componentConfig = component.ComponentConfig{
// ... other fields ...
MetadataExtensions: map[string]any{
"InstallCRDs": true,
"CustomField": "custom-value",
},
}
These extensions are merged into the BundleMetadata.Extensions map and can be accessed in templates via {{ .Script.Extensions.InstallCRDs }}.
For more complex metadata requirements, MetadataFunc is still supported but MetadataExtensions is preferred for simple key-value additions.
Custom Manifest Generation ¶
Components that need to generate additional manifests can provide a CustomManifestFunc:
var componentConfig = component.ComponentConfig{
// ... other fields ...
CustomManifestFunc: func(ctx context.Context, b *component.BaseBundler,
values map[string]any, configMap map[string]string, dir string) ([]string, error) {
// Generate manifests using b.WriteFile() or b.GenerateFileFromTemplate()
return []string{"manifests/custom.yaml"}, nil
},
}
BaseBundler Helper Methods ¶
BaseBundler provides common functionality for file operations:
- CreateBundleDir: Creates directory structure with proper permissions
- WriteFile: Writes content with automatic directory creation
- WriteFileString: Convenience wrapper for string content
- RenderTemplate: Renders Go templates with error handling
- GenerateFileFromTemplate: One-step template rendering and file writing
- GenerateChecksums: Creates checksums.txt with SHA256 hashes
- CheckContext: Periodic context cancellation checking
- Finalize: Records timing and result metadata
- BuildConfigMapFromInput: Creates baseline config map from recipe input
Helper Functions ¶
Utility functions for common operations:
- GetConfigValue: Safely extracts config map values with defaults
- GetBundlerVersion: Returns bundler version from config
- GetRecipeBundlerVersion: Returns recipe version from config
- MarshalYAMLWithHeader: Serializes values with component header
- ApplyMapOverrides: Applies dot-notation overrides to nested maps
- ApplyNodeSelectorOverrides: Applies node selectors to Helm paths
- ApplyTolerationsOverrides: Applies tolerations to Helm paths
- GenerateDefaultBundleMetadata: Creates default BundleMetadata struct
Default BundleMetadata ¶
Components using the default metadata get:
- Namespace, HelmRepository, HelmChart, HelmChartVersion
- Version (bundler version), RecipeVersion
Access in templates via {{ .Script.Namespace }}, {{ .Script.Version }}, etc.
Internal Test Harness ¶
A TestHarness and RecipeBuilder live in this package's _test.go files for reuse by the package's own tests. They are intentionally not exported as production API — bundler tests in other packages should construct their own fixtures rather than depend on this package's test scaffolding.
Index ¶
- Constants
- func AppendTolerationsOverrides(values map[string]any, tolerations []corev1.Toleration, paths ...string)
- func ApplyMapOverrides(target map[string]any, overrides map[string]string) error
- func ApplyNodeSelectorOverrides(values map[string]any, nodeSelector map[string]string, paths ...string)
- func ApplyTolerationsOverrides(values map[string]any, tolerations []corev1.Toleration, paths ...string)
- func ConvertMapValue(value string) any
- func DeepCopyMap(m map[string]any) map[string]any
- func GetBundlerVersion(m map[string]string) string
- func GetConfigValue(config map[string]string, key, defaultValue string) string
- func GetRecipeBundlerVersion(m map[string]string) string
- func GetValueByPath(target map[string]any, path string) (any, bool)
- func MakeBundle(ctx context.Context, b *BaseBundler, input recipe.RecipeInput, ...) (*result.Result, error)deprecated
- func MarshalYAML(v any) ([]byte, error)
- func MarshalYAMLWithHeader(v any, header ValuesHeader) ([]byte, error)
- func RemoveValueByPath(target map[string]any, path string) bool
- func SetValueByPath(target map[string]any, path string, value any)
- func TolerationsToPodSpec(tolerations []corev1.Toleration) []map[string]any
- type BaseBundler
- func (b *BaseBundler) AddError(err error)
- func (b *BaseBundler) BuildConfigMapFromInput(input interface{ ... }) map[string]string
- func (b *BaseBundler) CheckContext(ctx context.Context) error
- func (b *BaseBundler) CreateBundleDir(outputDir, bundleName string) (BundleDirectories, error)
- func (b *BaseBundler) Finalize(start time.Time)
- func (b *BaseBundler) GenerateChecksums(ctx context.Context, bundleDir string) error
- func (b *BaseBundler) GenerateFileFromTemplate(ctx context.Context, getTemplate TemplateFunc, templateName, outputPath string, ...) error
- func (b *BaseBundler) MakeExecutable(path string) error
- func (b *BaseBundler) RenderAndWriteTemplate(tmplContent, name, outputPath string, data any, perm os.FileMode) error
- func (b *BaseBundler) RenderTemplate(tmplContent, name string, data any) (string, error)
- func (b *BaseBundler) WriteFile(path string, content []byte, perm os.FileMode) error
- func (b *BaseBundler) WriteFileString(path, content string, perm os.FileMode) error
- type BundleDirectories
- type BundleMetadata
- type ComponentConfigdeprecated
- type CustomManifestFunc
- type MetadataFunc
- type TemplateFunc
- type ValuesHeader
Constants ¶
const ( StrTrue = "true" StrFalse = "false" )
Common string constants for boolean values in Helm templates.
Variables ¶
This section is empty.
Functions ¶
func AppendTolerationsOverrides ¶ added in v0.14.0
func AppendTolerationsOverrides(values map[string]any, tolerations []corev1.Toleration, paths ...string)
AppendTolerationsOverrides appends CLI tolerations to whatever list is already at each path, instead of replacing it. Used when a recipe overlay has populated the path with a non-empty list (e.g., bcm.yaml's BCM-master `controller.tolerations`): the overlay's intent is "ALSO tolerate these", not "use only these", so the CLI flag's tolerations must augment the overlay list rather than clobber it.
If the path is absent or holds an empty/non-slice value, the behavior is identical to ApplyTolerationsOverrides (CLI tolerations become the full list at the path).
func ApplyMapOverrides ¶
ApplyMapOverrides applies overrides to a map[string]any using dot-notation paths. Handles nested maps by traversing the path segments and creating nested maps as needed. Useful for applying --set flag overrides to values.yaml content.
func ApplyNodeSelectorOverrides ¶
func ApplyNodeSelectorOverrides(values map[string]any, nodeSelector map[string]string, paths ...string)
ApplyNodeSelectorOverrides applies node selector overrides to a values map. If nodeSelector is non-empty, it sets or merges with the existing nodeSelector field. The function applies to the specified paths in the values map (e.g., "nodeSelector", "webhook.nodeSelector").
func ApplyTolerationsOverrides ¶
func ApplyTolerationsOverrides(values map[string]any, tolerations []corev1.Toleration, paths ...string)
ApplyTolerationsOverrides applies toleration overrides to a values map. If tolerations is non-empty, it sets or replaces the existing tolerations field. The function applies to the specified paths in the values map (e.g., "tolerations", "webhook.tolerations").
func ConvertMapValue ¶ added in v0.14.0
ConvertMapValue converts a string value to an appropriate Go type. Handles bools ("true"/"false") and numbers (int64, float64). Returns the original string if no conversion applies.
func DeepCopyMap ¶ added in v0.12.0
DeepCopyMap returns a deep copy of a map[string]any by recursively copying nested maps and slices. Preserves original types (no serialization roundtrip). Delegates to serializer.DeepCopyAnyMap so the recipe and bundler packages share a single implementation.
func GetBundlerVersion ¶
GetBundlerVersion retrieves the bundler version from the config map.
func GetConfigValue ¶
GetConfigValue gets a value from config map with a default fallback.
func GetRecipeBundlerVersion ¶
GetRecipeBundlerVersion retrieves the bundler version from the recipe config map.
func GetValueByPath ¶ added in v0.12.0
GetValueByPath retrieves a value from a nested map using dot-notation path. Returns the value and true if found, or nil and false if any path segment is missing.
func MakeBundle
deprecated
func MakeBundle(ctx context.Context, b *BaseBundler, input recipe.RecipeInput, outputDir string, cfg ComponentConfig, provider recipe.DataProvider) (*result.Result, error)
Deprecated: MakeBundle is unused in production code. Bundle generation is now handled by DefaultBundler.Make with deployer generators. MakeBundle generates a bundle using the generic bundling logic. This function handles the common steps: creating directories, applying overrides, writing values.yaml, generating README, generating checksums, and finalizing. Configuration is enriched from the component registry when values are not explicitly set in the ComponentConfig.
The provider parameter routes registry lookups through the supplied DataProvider for per-tenant isolation. Pass nil to fall back to the package-global registry.
func MarshalYAML ¶
MarshalYAML serializes a value to YAML format with mapping keys sorted so the output is byte-stable across runs (matters for OCI manifest digests, fingerprints, and attestations).
func MarshalYAMLWithHeader ¶
func MarshalYAMLWithHeader(v any, header ValuesHeader) ([]byte, error)
MarshalYAMLWithHeader serializes a value to YAML format with a metadata header. Mapping keys are sorted so the output is byte-stable across runs.
func RemoveValueByPath ¶ added in v0.12.0
RemoveValueByPath removes a value from a nested map at the given dot-notation path. Returns true if the value existed and was removed, false otherwise.
func SetValueByPath ¶ added in v0.12.0
SetValueByPath sets a value in a nested map at the given dot-notation path, creating intermediate maps as needed. Non-map intermediate segments are replaced with new maps (permissive mode).
func TolerationsToPodSpec ¶
func TolerationsToPodSpec(tolerations []corev1.Toleration) []map[string]any
TolerationsToPodSpec converts a slice of corev1.Toleration to a YAML-friendly format. This format matches what Kubernetes expects in pod specs and Helm values.
Types ¶
type BaseBundler ¶
BaseBundler provides common functionality for bundler implementations. Bundlers can use this to reuse standard operations and reduce boilerplate.
Thread-safety: BaseBundler is safe for use by a single bundler instance. Do not share BaseBundler instances between concurrent bundler executions.
func NewBaseBundler ¶
func NewBaseBundler(cfg *config.Config, bundlerType types.BundleType) *BaseBundler
NewBaseBundler creates a new base bundler helper.
func (*BaseBundler) AddError ¶
func (b *BaseBundler) AddError(err error)
AddError adds a non-fatal error to the result. These errors are collected but do not stop bundle generation.
func (*BaseBundler) BuildConfigMapFromInput ¶
func (b *BaseBundler) BuildConfigMapFromInput(input interface{ GetVersion() string }) map[string]string
BuildConfigMapFromInput creates a configuration map from a RecipeInput. This includes base config from bundler settings plus recipe version. Use this when working with RecipeResult (new format) instead of Recipe.
func (*BaseBundler) CheckContext ¶
func (b *BaseBundler) CheckContext(ctx context.Context) error
CheckContext checks if the context has been canceled. This should be called periodically during long-running operations to allow for graceful cancellation.
func (*BaseBundler) CreateBundleDir ¶
func (b *BaseBundler) CreateBundleDir(outputDir, bundleName string) (BundleDirectories, error)
CreateBundleDir creates the root bundle directory. Subdirectories (scripts, manifests) are created on-demand when files are written. Returns the bundle directories for easy access to each subdirectory path.
func (*BaseBundler) Finalize ¶
func (b *BaseBundler) Finalize(start time.Time)
Finalize marks the bundler as successful and updates metrics. This should be called at the end of a successful bundle generation. It updates the result duration and marks success. Note: Bundlers should record their own Prometheus metrics after calling this.
func (*BaseBundler) GenerateChecksums ¶
func (b *BaseBundler) GenerateChecksums(ctx context.Context, bundleDir string) error
GenerateChecksums creates a checksums.txt file for all generated files. The checksum file contains SHA256 hashes for verification of bundle integrity. Each line follows the format: "<hash> <relative-path>"
func (*BaseBundler) GenerateFileFromTemplate ¶
func (b *BaseBundler) GenerateFileFromTemplate(ctx context.Context, getTemplate TemplateFunc, templateName, outputPath string, data any, perm os.FileMode) error
GenerateFileFromTemplate is a convenience method that combines template retrieval, rendering, and file writing in one call. This reduces boilerplate in bundler implementations by handling the common pattern of: 1. Get template by name 2. Check if template exists 3. Render template with data 4. Write rendered content to file
Example usage:
err := b.GenerateFileFromTemplate(ctx, GetTemplate, "values.yaml",
filepath.Join(dir, "values.yaml"), data, 0644)
func (*BaseBundler) MakeExecutable ¶
func (b *BaseBundler) MakeExecutable(path string) error
MakeExecutable changes file permissions to make a file executable. This is typically used for shell scripts after writing them.
func (*BaseBundler) RenderAndWriteTemplate ¶
func (b *BaseBundler) RenderAndWriteTemplate(tmplContent, name, outputPath string, data any, perm os.FileMode) error
RenderAndWriteTemplate renders a template and writes it to a file. This combines RenderTemplate and WriteFile for convenience.
func (*BaseBundler) RenderTemplate ¶
func (b *BaseBundler) RenderTemplate(tmplContent, name string, data any) (string, error)
RenderTemplate renders a template with the given data. The template is parsed and executed with the provided data structure. Returns the rendered content as a string.
func (*BaseBundler) WriteFile ¶
WriteFile writes content to a file and tracks it in the result. The file is created with the specified permissions and automatically added to the result's file list with its size. Parent directories are created automatically if they don't exist.
func (*BaseBundler) WriteFileString ¶
func (b *BaseBundler) WriteFileString(path, content string, perm os.FileMode) error
WriteFileString writes string content to a file. This is a convenience wrapper around WriteFile for string content.
type BundleDirectories ¶
BundleDirectories holds the standard bundle directory structure.
type BundleMetadata ¶
type BundleMetadata struct {
// Common fields used by all components
Namespace string
HelmRepository string
HelmChart string
HelmChartVersion string
HelmReleaseName string
Version string
RecipeVersion string
// Extensions holds component-specific fields.
// Templates can access these via {{ .Script.Extensions.FieldName }}
Extensions map[string]any
}
BundleMetadata contains common metadata used for README and manifest template rendering. This is the default metadata structure used when MetadataFunc is not provided. The Extensions map allows component-specific fields without custom structs.
func GenerateBundleMetadataWithExtensions ¶
func GenerateBundleMetadataWithExtensions(config map[string]string, cfg ComponentConfig) *BundleMetadata
GenerateBundleMetadataWithExtensions creates bundle metadata with custom extensions. This is used when components need additional fields beyond the standard ones.
func GenerateDefaultBundleMetadata ¶
func GenerateDefaultBundleMetadata(config map[string]string, name string, defaultHelmRepo string, defaultHelmChart string) *BundleMetadata
GenerateDefaultBundleMetadata creates default bundle metadata from config map.
type ComponentConfig
deprecated
type ComponentConfig struct {
// Name is the component identifier used in recipes (e.g., "gpu-operator").
Name string
// DisplayName is the human-readable name used in templates (e.g., "GPU Operator").
DisplayName string
// ValueOverrideKeys are alternative keys to check for value overrides.
// The Name is always checked first, then these alternatives (e.g., ["gpuoperator"]).
ValueOverrideKeys []string
// SystemNodeSelectorPaths are Helm value paths for system component node selectors.
// Example: ["operator.nodeSelector", "nfd.nodeSelector"]
SystemNodeSelectorPaths []string
// SystemTolerationPaths are Helm value paths for system component tolerations.
// Example: ["operator.tolerations"]
SystemTolerationPaths []string
// AcceleratedNodeSelectorPaths are Helm value paths for GPU node selectors.
// Example: ["daemonsets.nodeSelector"]
AcceleratedNodeSelectorPaths []string
// AcceleratedTolerationPaths are Helm value paths for GPU node tolerations.
// Example: ["daemonsets.tolerations"]
AcceleratedTolerationPaths []string
// DefaultHelmRepository is the default Helm repository URL.
DefaultHelmRepository string
// DefaultHelmChart is the chart name (e.g., "nvidia/gpu-operator").
DefaultHelmChart string
// DefaultHelmChartVersion is the default chart version if not specified in recipe.
DefaultHelmChartVersion string
// TemplateGetter is the function that retrieves templates by name.
// If nil, TemplateNames will be used with the embedded TemplatesFS.
TemplateGetter TemplateFunc
// TemplateNames lists the template files to embed (e.g., ["README.md"]).
// Used with auto-generated template getter when TemplateGetter is nil.
TemplateNames []string
// CustomManifestFunc is an optional function to generate additional manifests.
// It receives the values map, config map, and output directory.
// It should return the list of generated file paths, or nil if no manifests were generated.
CustomManifestFunc CustomManifestFunc
// MetadataFunc creates component-specific metadata for templates.
// If nil, the default BundleMetadata is used.
MetadataFunc MetadataFunc
// MetadataExtensions provides additional fields for BundleMetadata.
// These are merged into the Extensions map of the generated metadata.
// Use this instead of MetadataFunc for simple extensions.
MetadataExtensions map[string]any
}
Deprecated: ComponentConfig is unused in production code. The declarative registry in recipes/registry.yaml replaced per-component Go bundlers. ComponentConfig defines the configuration for a bundler component.
type CustomManifestFunc ¶
type CustomManifestFunc func(ctx context.Context, b *BaseBundler, values map[string]any, configMap map[string]string, dir string) ([]string, error)
CustomManifestFunc is a function type for generating custom manifests. It receives context, base bundler, values map, config map, and output directory. Returns slice of generated file paths (may be nil/empty if no manifests needed).
type MetadataFunc ¶
MetadataFunc is a function type for creating component-specific metadata.
type TemplateFunc ¶
TemplateFunc is a function that retrieves templates by name. Returns the template content and whether it was found.
func NewTemplateGetter ¶
func NewTemplateGetter(templates map[string]string) TemplateFunc
NewTemplateGetter creates a TemplateFunc from a map of template names to content. This is used to simplify template handling in bundlers by converting embedded templates into a standard lookup function.
Example usage:
//go:embed templates/README.md.tmpl
var readmeTemplate string
var GetTemplate = NewTemplateGetter(map[string]string{
"README.md": readmeTemplate,
})
func StandardTemplates ¶
func StandardTemplates(readmeTemplate string) TemplateFunc
StandardTemplates returns a TemplateFunc for components that only have a README template. This is the most common case and reduces boilerplate further.
Example usage:
//go:embed templates/README.md.tmpl var readmeTemplate string var GetTemplate = StandardTemplates(readmeTemplate)
type ValuesHeader ¶
ValuesHeader contains metadata for values.yaml file headers.