Skip to content

Commit 6098765

Browse files
authored
feat(bundler): route registry/manifest reads through recipe-bound provider (#1016)
1 parent 4e6cd9c commit 6098765

10 files changed

Lines changed: 342 additions & 49 deletions

File tree

pkg/bundler/bundler.go

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ func (b *DefaultBundler) Make(ctx context.Context, recipeResult *recipe.RecipeRe
224224
enabledRefs := make([]recipe.ComponentRef, 0, len(recipeResult.ComponentRefs))
225225
enabledSet := make(map[string]struct{})
226226
for _, ref := range recipeResult.ComponentRefs {
227-
setEnabled, ok, overrideErr := b.getSetEnabledOverride(ref.Name)
227+
setEnabled, ok, overrideErr := b.getSetEnabledOverride(ref.Name, recipeResult.DataProvider())
228228
if overrideErr != nil {
229229
return nil, overrideErr
230230
}
@@ -297,7 +297,7 @@ func (b *DefaultBundler) Make(ctx context.Context, recipeResult *recipe.RecipeRe
297297
// Copy external data files before deployer construction so the file list
298298
// is available for both the deployer (checksum tracking) and post-generation
299299
// attestation. This is a no-op when --data is not set.
300-
dataFiles, err := b.copyDataFiles(dir)
300+
dataFiles, err := b.copyDataFiles(dir, recipeResult.DataProvider())
301301
if err != nil {
302302
if _, ok := stderrors.AsType[*errors.StructuredError](err); ok {
303303
return nil, err
@@ -317,7 +317,7 @@ func (b *DefaultBundler) Make(ctx context.Context, recipeResult *recipe.RecipeRe
317317
// buildDeployer constructs the appropriate deployer.Deployer based on config.
318318
// It handles deployer-specific pre-flight validation and data collection.
319319
func (b *DefaultBundler) buildDeployer(ctx context.Context, recipeResult *recipe.RecipeResult, componentValues map[string]map[string]any, dataFiles []string) (deployer.Deployer, error) {
320-
dynamicValues, err := b.buildDynamicValuesMap()
320+
dynamicValues, err := b.buildDynamicValuesMap(recipeResult.DataProvider())
321321
if err != nil {
322322
return nil, err
323323
}
@@ -572,6 +572,7 @@ func deployerResultNames(dt config.DeployerType) (types.BundleType, string) {
572572
// It loads base values from the recipe, applies user overrides, and applies node selectors.
573573
func (b *DefaultBundler) extractComponentValues(ctx context.Context, recipeResult *recipe.RecipeResult) (map[string]map[string]any, error) {
574574
componentValues := make(map[string]map[string]any)
575+
provider := recipeResult.DataProvider()
575576

576577
for _, ref := range recipeResult.ComponentRefs {
577578
if err := ctx.Err(); err != nil {
@@ -590,7 +591,7 @@ func (b *DefaultBundler) extractComponentValues(ctx context.Context, recipeResul
590591

591592
// Apply user value overrides from --set flags.
592593
// Strip "enabled" key — it controls component inclusion, not Helm chart values.
593-
if overrides := b.getValueOverridesForComponent(ref.Name); len(overrides) > 0 {
594+
if overrides := b.getValueOverridesForComponent(ref.Name, provider); len(overrides) > 0 {
594595
if _, has := overrides["enabled"]; has {
595596
filtered := make(map[string]string, len(overrides)-1)
596597
for k, v := range overrides {
@@ -614,7 +615,7 @@ func (b *DefaultBundler) extractComponentValues(ctx context.Context, recipeResul
614615
}
615616

616617
// Apply node selectors, tolerations, workload selector, and taints based on component type
617-
b.applyNodeSchedulingOverrides(ref.Name, values)
618+
b.applyNodeSchedulingOverrides(ref.Name, values, provider)
618619

619620
componentValues[ref.Name] = values
620621
}
@@ -624,7 +625,9 @@ func (b *DefaultBundler) extractComponentValues(ctx context.Context, recipeResul
624625

625626
// getValueOverridesForComponent returns value overrides for a specific component.
626627
// Uses the component registry to match both exact names and alternative override keys.
627-
func (b *DefaultBundler) getValueOverridesForComponent(componentName string) map[string]string {
628+
// The provider argument scopes the registry lookup to the recipe's bound DataProvider;
629+
// a nil provider falls back to the package-global registry via GetComponentRegistryFor.
630+
func (b *DefaultBundler) getValueOverridesForComponent(componentName string, provider recipe.DataProvider) map[string]string {
628631
if b.Config == nil {
629632
return nil
630633
}
@@ -640,7 +643,7 @@ func (b *DefaultBundler) getValueOverridesForComponent(componentName string) map
640643
}
641644

642645
// Use component registry to find component by any override key
643-
registry, err := recipe.GetComponentRegistry()
646+
registry, err := recipe.GetComponentRegistryFor(provider)
644647
if err != nil {
645648
// Fall back to non-hyphenated check if registry fails
646649
nonHyphenated := removeHyphens(componentName)
@@ -675,8 +678,9 @@ func (b *DefaultBundler) getValueOverridesForComponent(componentName string) map
675678
// bundle whose enable/disable state doesn't match the operator's intent, which
676679
// is the canonical misconfigured-artifact scenario the project rule targets.
677680
// This allows --set awsebscsidriver:enabled=false to disable a component at bundle time.
678-
func (b *DefaultBundler) getSetEnabledOverride(componentName string) (bool, bool, error) {
679-
overrides := b.getValueOverridesForComponent(componentName)
681+
// The provider argument scopes the registry lookup to the recipe's bound DataProvider.
682+
func (b *DefaultBundler) getSetEnabledOverride(componentName string, provider recipe.DataProvider) (bool, bool, error) {
683+
overrides := b.getValueOverridesForComponent(componentName, provider)
680684
if overrides == nil {
681685
return false, false, nil
682686
}
@@ -695,13 +699,15 @@ func (b *DefaultBundler) getSetEnabledOverride(componentName string) (bool, bool
695699

696700
// applyNodeSchedulingOverrides applies node selectors and tolerations to component values.
697701
// Uses the component registry to determine the correct paths for each component.
698-
func (b *DefaultBundler) applyNodeSchedulingOverrides(componentName string, values map[string]any) {
702+
// The provider argument scopes the registry lookup to the recipe's bound DataProvider;
703+
// a nil provider falls back to the package-global registry via GetComponentRegistryFor.
704+
func (b *DefaultBundler) applyNodeSchedulingOverrides(componentName string, values map[string]any, provider recipe.DataProvider) {
699705
if b.Config == nil {
700706
return
701707
}
702708

703709
// Get component configuration from registry
704-
registry, err := recipe.GetComponentRegistry()
710+
registry, err := recipe.GetComponentRegistryFor(provider)
705711
if err != nil {
706712
slog.Debug("failed to load component registry for node scheduling",
707713
"error", err,
@@ -791,7 +797,7 @@ func (b *DefaultBundler) applyNodeSchedulingOverrides(componentName string, valu
791797
// values map must not block injection; only CLI --set inputs take precedence.
792798
if sc := b.Config.StorageClass(); sc != "" {
793799
if paths := comp.GetStorageClassPaths(); len(paths) > 0 {
794-
explicitOverrides := b.getValueOverridesForComponent(componentName)
800+
explicitOverrides := b.getValueOverridesForComponent(componentName, provider)
795801
overrides := make(map[string]string, len(paths))
796802
for _, path := range paths {
797803
if _, isExplicit := explicitOverrides[path]; !isExplicit {
@@ -818,7 +824,7 @@ func (b *DefaultBundler) warnMissingStorageClassForPVCs(ctx context.Context, rec
818824
return nil
819825
}
820826

821-
registry, err := recipe.GetComponentRegistry()
827+
registry, err := recipe.GetComponentRegistryFor(recipeResult.DataProvider())
822828
if err != nil {
823829
return errors.Wrap(errors.ErrCodeInternal,
824830
"failed to load component registry for storage class warnings", err)
@@ -914,7 +920,7 @@ func (b *DefaultBundler) runComponentValidations(ctx context.Context, recipeResu
914920
// Get component registry — required to know which validations to run.
915921
// A registry-load failure produces an unvalidated bundle, which is the
916922
// opposite of what this tool promises; surface the failure to the user.
917-
registry, err := recipe.GetComponentRegistry()
923+
registry, err := recipe.GetComponentRegistryFor(recipeResult.DataProvider())
918924
if err != nil {
919925
return errors.Wrap(errors.ErrCodeInternal,
920926
"failed to load component registry for validations", err)
@@ -963,11 +969,14 @@ func (b *DefaultBundler) runComponentValidations(ctx context.Context, recipeResu
963969

964970
// copyDataFiles copies external data files from the --data directory into the bundle.
965971
// Returns a list of relative paths to the copied files (e.g., "data/overrides.yaml").
966-
func (b *DefaultBundler) copyDataFiles(dir string) ([]string, error) {
967-
provider := recipe.GetDataProvider() //nolint:staticcheck // tracked by #983 Stage 2
968-
969-
// Check if the provider is a LayeredDataProvider with external files
970-
layered, ok := provider.(*recipe.LayeredDataProvider)
972+
// The provider argument supplies the LayeredDataProvider whose external directory is
973+
// the source of truth; a nil provider falls back to the package-global provider so
974+
// pre-WithDataProvider callers (legacy CLI path) still emit the same bundles.
975+
func (b *DefaultBundler) copyDataFiles(dir string, provider recipe.DataProvider) ([]string, error) {
976+
// Check if the provider is a LayeredDataProvider with external files.
977+
// EffectiveDataProvider falls back to the package-global provider when the
978+
// caller did not bind one (pre-WithDataProvider CLI path).
979+
layered, ok := recipe.EffectiveDataProvider(provider).(*recipe.LayeredDataProvider)
971980
if !ok {
972981
return nil, nil // No external data
973982
}
@@ -1206,12 +1215,14 @@ func (b *DefaultBundler) writeRecipeFile(recipeResult *recipe.RecipeResult, dir
12061215

12071216
// buildDynamicValuesMap re-keys the config's dynamic values from user override keys
12081217
// (e.g., "gpuoperator") to component names (e.g., "gpu-operator") using the registry.
1209-
func (b *DefaultBundler) buildDynamicValuesMap() (map[string][]string, error) {
1218+
// The provider argument scopes the registry lookup to the recipe's bound DataProvider;
1219+
// a nil provider falls back to the package-global registry via GetComponentRegistryFor.
1220+
func (b *DefaultBundler) buildDynamicValuesMap(provider recipe.DataProvider) (map[string][]string, error) {
12101221
if !b.Config.HasDynamicValues() {
12111222
return make(map[string][]string), nil
12121223
}
12131224

1214-
registry, err := recipe.GetComponentRegistry()
1225+
registry, err := recipe.GetComponentRegistryFor(provider)
12151226
if err != nil {
12161227
return nil, errors.Wrap(errors.ErrCodeInternal, "failed to load component registry for dynamic resolution", err)
12171228
}
@@ -1277,6 +1288,7 @@ func (b *DefaultBundler) collectComponentManifestsByPhase(
12771288
) (map[string]map[string][]byte, error) {
12781289

12791290
result := make(map[string]map[string][]byte)
1291+
provider := recipeResult.DataProvider()
12801292

12811293
for _, ref := range recipeResult.ComponentRefs {
12821294
if err := ctx.Err(); err != nil {
@@ -1300,10 +1312,14 @@ func (b *DefaultBundler) collectComponentManifestsByPhase(
13001312

13011313
componentManifests := make(map[string][]byte, len(paths))
13021314
for _, manifestPath := range paths {
1303-
content, err := recipe.GetManifestContent(manifestPath)
1315+
content, err := recipe.GetManifestContentWithProvider(provider, manifestPath)
13041316
if err != nil {
13051317
if stderrors.Is(err, fs.ErrNotExist) {
1306-
_, hasExternalData := recipe.GetDataProvider().(*recipe.LayeredDataProvider) //nolint:staticcheck // tracked by #983 Stage 2
1318+
// Honor bound provider for the type assertion when
1319+
// available; EffectiveDataProvider falls back to the
1320+
// package-global provider when no provider is bound
1321+
// (CLI today).
1322+
_, hasExternalData := recipe.EffectiveDataProvider(provider).(*recipe.LayeredDataProvider)
13071323
return nil, errors.New(errors.ErrCodeInvalidRequest,
13081324
missingManifestMessage(manifestPath, ref.Name, hasExternalData))
13091325
}
@@ -1393,7 +1409,7 @@ func (b *DefaultBundler) injectGKECriticalPriorityQuotas(
13931409
return pre, nil
13941410
}
13951411

1396-
registry, err := recipe.GetComponentRegistry()
1412+
registry, err := recipe.GetComponentRegistryFor(recipeResult.DataProvider())
13971413
if err != nil {
13981414
return nil, errors.Wrap(errors.ErrCodeInternal,
13991415
"failed to load component registry for GKE quota synthesis", err)

0 commit comments

Comments
 (0)