@@ -192,6 +192,14 @@ func (ctrl *Controller) updateMachineConfigPool(old, cur interface{}) {
192192
193193 klog .V (4 ).Infof ("Updating MachineConfigPool %s" , oldPool .Name )
194194 ctrl .enqueueMachineConfigPool (curPool )
195+
196+ // If the worker pool's osImageStream changed, enqueue all custom pools that might inherit from it
197+ if curPool .Name == ctrlcommon .MachineConfigPoolWorker &&
198+ oldPool .Spec .OSImageStream .Name != curPool .Spec .OSImageStream .Name {
199+ klog .V (4 ).Infof ("Worker pool osImageStream changed from %q to %q, enqueuing custom pools" ,
200+ oldPool .Spec .OSImageStream .Name , curPool .Spec .OSImageStream .Name )
201+ ctrl .enqueueCustomPools ()
202+ }
195203}
196204
197205func (ctrl * Controller ) deleteMachineConfigPool (obj interface {}) {
@@ -398,6 +406,23 @@ func (ctrl *Controller) enqueueDefault(pool *mcfgv1.MachineConfigPool) {
398406 ctrl .enqueueAfter (pool , renderDelay )
399407}
400408
409+ // enqueueCustomPools enqueues all custom pools (pools that are not master, worker, or arbiter).
410+ // This is used when the worker pool changes in a way that might affect custom pools that inherit from it.
411+ func (ctrl * Controller ) enqueueCustomPools () {
412+ pools , err := ctrl .mcpLister .List (labels .Everything ())
413+ if err != nil {
414+ klog .Warningf ("Failed to list pools when enqueuing custom pools: %v" , err )
415+ return
416+ }
417+
418+ for _ , pool := range pools {
419+ if ctrlcommon .IsCustomPool (pool ) {
420+ klog .V (4 ).Infof ("Enqueuing custom pool %s due to worker pool change" , pool .Name )
421+ ctrl .enqueueMachineConfigPool (pool )
422+ }
423+ }
424+ }
425+
401426// worker runs a worker thread that just dequeues items, processes them, and marks them done.
402427// It enforces that the syncHandler is never invoked concurrently with the same key.
403428func (ctrl * Controller ) worker () {
@@ -565,17 +590,51 @@ func (ctrl *Controller) getRenderedMachineConfig(pool *mcfgv1.MachineConfigPool,
565590 return generateAndValidateRenderedMachineConfig (currentMC , pool , configs , cc , & mcop .Spec .IrreconcilableValidationOverrides , osImageStreamSet )
566591}
567592
593+ // getOSImageStreamNameForPool determines the OS image stream name for a pool,
594+ // implementing inheritance from the worker pool for custom pools.
595+ // Returns:
596+ // - The pool's explicit osImageStream.Name if set
597+ // - For custom pools: the worker pool's osImageStream.Name if the custom pool has none
598+ // - Empty string (which will resolve to the default stream)
599+ func (ctrl * Controller ) getOSImageStreamNameForPool (pool * mcfgv1.MachineConfigPool ) string {
600+ streamName , err := ctrlcommon .GetEffectiveOSImageStreamName (pool , ctrl .mcpLister )
601+ if err != nil {
602+ klog .V (2 ).Infof ("Failed to get effective osImageStream for pool %s: %v; using default stream" , pool .Name , err )
603+ return ""
604+ }
605+
606+ // Log what stream is being used
607+ if streamName != "" {
608+ if pool .Spec .OSImageStream .Name != "" {
609+ klog .V (4 ).Infof ("Pool %s using explicit osImageStream: %s" , pool .Name , streamName )
610+ } else {
611+ klog .V (4 ).Infof ("Custom pool %s inheriting osImageStream from worker: %s" , pool .Name , streamName )
612+ }
613+ } else {
614+ if ctrlcommon .IsCustomPool (pool ) {
615+ klog .V (4 ).Infof ("Custom pool %s using default osImageStream (worker also uses default)" , pool .Name )
616+ } else {
617+ klog .V (4 ).Infof ("Standard pool %s using default osImageStream" , pool .Name )
618+ }
619+ }
620+
621+ return streamName
622+ }
623+
568624func (ctrl * Controller ) getOSImageStreamForPool (pool * mcfgv1.MachineConfigPool ) (* v1alpha1.OSImageStreamSet , error ) {
569625 if ! osimagestream .IsFeatureEnabled (ctrl .fgHandler ) || ctrl .osImageStreamLister == nil {
570626 return nil , nil
571627 }
572628
629+ // Determine which stream name to use based on inheritance logic
630+ streamName := ctrl .getOSImageStreamNameForPool (pool )
631+
573632 imageStream , err := ctrl .osImageStreamLister .Get (ctrlcommon .ClusterInstanceNameOSImageStream )
574633 if err != nil {
575634 return nil , fmt .Errorf ("could not get OSImageStream for pool %s: %w" , pool .Name , err )
576635 }
577636
578- imageStreamSet , err := osimagestream .GetOSImageStreamSetByName (imageStream , pool . Spec . OSImageStream . Name )
637+ imageStreamSet , err := osimagestream .GetOSImageStreamSetByName (imageStream , streamName )
579638 if err != nil {
580639 return nil , fmt .Errorf ("could not get OSImageStreamSet for pool %s: %w" , pool .Name , err )
581640 }
@@ -778,6 +837,31 @@ func generateAndValidateRenderedMachineConfig(
778837 return generated , nil
779838}
780839
840+ // getOSImageStreamNameForPoolBootstrap implements the same inheritance logic as
841+ // getOSImageStreamNameForPool but for the bootstrap scenario where we only have
842+ // a slice of pools, not a lister.
843+ func getOSImageStreamNameForPoolBootstrap (pool * mcfgv1.MachineConfigPool , pools []* mcfgv1.MachineConfigPool ) string {
844+ // If the pool explicitly sets an osImageStream, use it
845+ if pool .Spec .OSImageStream .Name != "" {
846+ return pool .Spec .OSImageStream .Name
847+ }
848+
849+ // Only custom pools inherit from worker
850+ if ! ctrlcommon .IsCustomPool (pool ) {
851+ return ""
852+ }
853+
854+ // Find worker pool in the provided slice
855+ for _ , p := range pools {
856+ if p .Name == ctrlcommon .MachineConfigPoolWorker {
857+ return p .Spec .OSImageStream .Name
858+ }
859+ }
860+
861+ // Worker not found, use default
862+ return ""
863+ }
864+
781865// RunBootstrap runs the render controller in bootstrap mode.
782866// For each pool, it matches the machineconfigs based on label selector and
783867// returns the generated machineconfigs and pool with CurrentMachineConfig status field set.
@@ -793,7 +877,9 @@ func RunBootstrap(pools []*mcfgv1.MachineConfigPool, configs []*mcfgv1.MachineCo
793877 }
794878 var osImageStreamSet * v1alpha1.OSImageStreamSet
795879 if osImageStream != nil {
796- osImageStreamSet , err = osimagestream .GetOSImageStreamSetByName (osImageStream , pool .Spec .OSImageStream .Name )
880+ // Determine which stream name to use based on inheritance logic
881+ streamName := getOSImageStreamNameForPoolBootstrap (pool , pools )
882+ osImageStreamSet , err = osimagestream .GetOSImageStreamSetByName (osImageStream , streamName )
797883 if err != nil {
798884 return nil , nil , fmt .Errorf ("couldn't get the OSImageStream for pool %s %w" , pool .Name , err )
799885 }
0 commit comments