component

package
v0.15.0-rc2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 15, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

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

View Source
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

func ApplyMapOverrides(target map[string]any, overrides map[string]string) error

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 ApplyTypedOverrides added in v0.15.0

func ApplyTypedOverrides(target map[string]any, overrides map[string]any) error

ApplyTypedOverrides applies structured (--set-json / --set-file) overrides to target using dot-notation paths. For each path, a map value is deep-merged into any existing map at that path (so partial object overrides compose with recipe/base values); every other value kind — scalar or list — replaces what is at the path. Values are deep-copied so the override source is never aliased into target. Intermediate path segments that exist but are not maps are an error (strict mode), matching ApplyMapOverrides.

Paths are applied shallowest-first (by segment count, then lexicographically) rather than in Go's randomized map-iteration order. This makes the result deterministic when two paths overlap by prefix — e.g. "driver.env" (an object) and "driver.env.HTTPS_PROXY" (a scalar): the parent object is merged first, then the deeper, more-specific override lands last and wins. Without the sort, the apply order — and thus the bundle output — would vary run to run, violating the project's "same inputs -> same outputs" guarantee.

func ConvertMapValue added in v0.14.0

func ConvertMapValue(value string) any

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

func DeepCopyMap(m map[string]any) map[string]any

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

func GetBundlerVersion(m map[string]string) string

GetBundlerVersion retrieves the bundler version from the config map.

func GetConfigValue

func GetConfigValue(config map[string]string, key, defaultValue string) string

GetConfigValue gets a value from config map with a default fallback.

func GetRecipeBundlerVersion

func GetRecipeBundlerVersion(m map[string]string) string

GetRecipeBundlerVersion retrieves the bundler version from the recipe config map.

func GetValueByPath added in v0.12.0

func GetValueByPath(target map[string]any, path string) (any, bool)

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

func MarshalYAML(v any) ([]byte, error)

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

func RemoveValueByPath(target map[string]any, path string) bool

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

func SetValueByPath(target map[string]any, path string, value any)

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

type BaseBundler struct {
	Config *config.Config
	Result *result.Result
}

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

func (b *BaseBundler) WriteFile(path string, content []byte, perm os.FileMode) error

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

type BundleDirectories struct {
	Root      string
	Scripts   string
	Manifests string
}

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

type MetadataFunc func(configMap map[string]string) any

MetadataFunc is a function type for creating component-specific metadata.

type TemplateFunc

type TemplateFunc func(name string) (string, bool)

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

type ValuesHeader struct {
	ComponentName  string
	BundlerVersion string
	RecipeVersion  string
}

ValuesHeader contains metadata for values.yaml file headers.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL