@@ -3,6 +3,7 @@ package containerruntimeconfig
33import (
44 "context"
55 "fmt"
6+ "path/filepath"
67 "reflect"
78 "strconv"
89 "strings"
@@ -17,7 +18,9 @@ import (
1718 configclientset "github.com/openshift/client-go/config/clientset/versioned"
1819 configinformers "github.com/openshift/client-go/config/informers/externalversions"
1920 cligoinformersv1 "github.com/openshift/client-go/config/informers/externalversions/config/v1"
21+ cligoinformersv1alpha1 "github.com/openshift/client-go/config/informers/externalversions/config/v1alpha1"
2022 cligolistersv1 "github.com/openshift/client-go/config/listers/config/v1"
23+ cligolistersv1alpha1 "github.com/openshift/client-go/config/listers/config/v1alpha1"
2124 runtimeutils "github.com/openshift/runtime-utils/pkg/registries"
2225
2326 operatorinformersv1alpha1 "github.com/openshift/client-go/operator/informers/externalversions/operator/v1alpha1"
@@ -84,6 +87,7 @@ type Controller struct {
8487
8588 syncHandler func (mcp string ) error
8689 syncImgHandler func (mcp string ) error
90+ syncCRIOCPHandler func (key string ) error
8791 enqueueContainerRuntimeConfig func (* mcfgv1.ContainerRuntimeConfig )
8892
8993 ccLister mcfglistersv1.ControllerConfigLister
@@ -104,6 +108,10 @@ type Controller struct {
104108 itmsLister cligolistersv1.ImageTagMirrorSetLister
105109 itmsListerSynced cache.InformerSynced
106110
111+ criocpLister cligolistersv1alpha1.CRIOCredentialProviderConfigLister
112+ criocpListerSynced cache.InformerSynced
113+ addedCRIOCPObservers bool
114+
107115 configInformerFactory configinformers.SharedInformerFactory
108116 clusterImagePolicyLister cligolistersv1.ClusterImagePolicyLister
109117 clusterImagePolicyListerSynced cache.InformerSynced
@@ -120,8 +128,9 @@ type Controller struct {
120128
121129 fgHandler ctrlcommon.FeatureGatesHandler
122130
123- queue workqueue.TypedRateLimitingInterface [string ]
124- imgQueue workqueue.TypedRateLimitingInterface [string ]
131+ queue workqueue.TypedRateLimitingInterface [string ]
132+ imgQueue workqueue.TypedRateLimitingInterface [string ]
133+ criocpQueue workqueue.TypedRateLimitingInterface [string ]
125134}
126135
127136// New returns a new container runtime config controller
@@ -133,6 +142,7 @@ func New(
133142 imgInformer cligoinformersv1.ImageInformer ,
134143 idmsInformer cligoinformersv1.ImageDigestMirrorSetInformer ,
135144 itmsInformer cligoinformersv1.ImageTagMirrorSetInformer ,
145+ criocpInformer cligoinformersv1alpha1.CRIOCredentialProviderConfigInformer ,
136146 configInformerFactory configinformers.SharedInformerFactory ,
137147 icspInformer operatorinformersv1alpha1.ImageContentSourcePolicyInformer ,
138148 clusterVersionInformer cligoinformersv1.ClusterVersionInformer ,
@@ -186,8 +196,15 @@ func New(
186196 DeleteFunc : ctrl .itmsConfDeleted ,
187197 })
188198
199+ criocpInformer .Informer ().AddEventHandler (cache.ResourceEventHandlerFuncs {
200+ AddFunc : ctrl .criocpConfAdded ,
201+ UpdateFunc : ctrl .criocpConfUpdated ,
202+ DeleteFunc : ctrl .criocpConfDeleted ,
203+ })
204+
189205 ctrl .syncHandler = ctrl .syncContainerRuntimeConfig
190206 ctrl .syncImgHandler = ctrl .syncImageConfig
207+ ctrl .syncCRIOCPHandler = ctrl .syncCRIOCredentialProviderConfig
191208 ctrl .enqueueContainerRuntimeConfig = ctrl .enqueue
192209
193210 ctrl .mcpLister = mcpInformer .Lister ()
@@ -211,6 +228,9 @@ func New(
211228 ctrl .itmsLister = itmsInformer .Lister ()
212229 ctrl .itmsListerSynced = itmsInformer .Informer ().HasSynced
213230
231+ ctrl .criocpLister = criocpInformer .Lister ()
232+ ctrl .criocpListerSynced = criocpInformer .Informer ().HasSynced
233+
214234 ctrl .clusterVersionLister = clusterVersionInformer .Lister ()
215235 ctrl .clusterVersionListerSynced = clusterVersionInformer .Informer ().HasSynced
216236
@@ -226,6 +246,7 @@ func (ctrl *Controller) Run(workers int, stopCh <-chan struct{}) {
226246 defer utilruntime .HandleCrash ()
227247 defer ctrl .queue .ShutDown ()
228248 defer ctrl .imgQueue .ShutDown ()
249+ defer ctrl .criocpQueue .ShutDown ()
229250 listerCaches := []cache.InformerSynced {ctrl .mcpListerSynced , ctrl .mccrListerSynced , ctrl .ccListerSynced ,
230251 ctrl .imgListerSynced , ctrl .icspListerSynced , ctrl .idmsListerSynced , ctrl .itmsListerSynced , ctrl .clusterVersionListerSynced }
231252
@@ -237,6 +258,14 @@ func (ctrl *Controller) Run(workers int, stopCh <-chan struct{}) {
237258 ctrl .addedPolicyObservers = true
238259 }
239260
261+ if ctrl .criocpEnabled () {
262+ ctrl .addCRIOCPObservers ()
263+ klog .Info ("added CRIOCredentialProviderConfig observers with CRIOCredentialProviderConfig featuregate enabled" )
264+ ctrl .configInformerFactory .Start (stopCh )
265+ listerCaches = append (listerCaches , ctrl .criocpListerSynced )
266+ ctrl .addedCRIOCPObservers = true
267+ }
268+
240269 if ! cache .WaitForCacheSync (stopCh , listerCaches ... ) {
241270 return
242271 }
@@ -251,6 +280,9 @@ func (ctrl *Controller) Run(workers int, stopCh <-chan struct{}) {
251280 // Just need one worker for the image config
252281 go wait .Until (ctrl .imgWorker , time .Second , stopCh )
253282
283+ // Just need one worker for the CRIOCredentialProviderConfig
284+ go wait .Until (ctrl .criocpWorker , time .Second , stopCh )
285+
254286 <- stopCh
255287}
256288
@@ -312,6 +344,28 @@ func (ctrl *Controller) itmsConfDeleted(_ interface{}) {
312344 ctrl .imgQueue .Add ("openshift-config" )
313345}
314346
347+ func (ctrl * Controller ) addCRIOCPObservers () {
348+ ctrl .configInformerFactory .Config ().V1alpha1 ().CRIOCredentialProviderConfigs ().Informer ().AddEventHandler (cache.ResourceEventHandlerFuncs {
349+ AddFunc : ctrl .criocpConfAdded ,
350+ UpdateFunc : ctrl .criocpConfUpdated ,
351+ DeleteFunc : ctrl .criocpConfDeleted ,
352+ })
353+ ctrl .criocpLister = ctrl .configInformerFactory .Config ().V1alpha1 ().CRIOCredentialProviderConfigs ().Lister ()
354+ ctrl .criocpListerSynced = ctrl .configInformerFactory .Config ().V1alpha1 ().CRIOCredentialProviderConfigs ().Informer ().HasSynced
355+ }
356+
357+ func (ctrl * Controller ) criocpConfAdded (_ interface {}) {
358+ ctrl .criocpQueue .Add ("openshift-config" )
359+ }
360+
361+ func (ctrl * Controller ) criocpConfUpdated (_ , _ interface {}) {
362+ ctrl .criocpQueue .Add ("openshift-config" )
363+ }
364+
365+ func (ctrl * Controller ) criocpConfDeleted (_ interface {}) {
366+ ctrl .criocpQueue .Add ("openshift-config" )
367+ }
368+
315369func (ctrl * Controller ) addImagePolicyObservers () {
316370 ctrl .configInformerFactory .Config ().V1 ().ClusterImagePolicies ().Informer ().AddEventHandler (cache.ResourceEventHandlerFuncs {
317371 AddFunc : ctrl .clusterImagePolicyAdded ,
@@ -358,6 +412,10 @@ func (ctrl *Controller) sigstoreAPIEnabled() bool {
358412 return ctrl .fgHandler .Enabled (features .FeatureGateSigstoreImageVerification )
359413}
360414
415+ func (ctrl * Controller ) criocpEnabled () bool {
416+ return ctrl .fgHandler .Enabled (features .FeatureGateCRIOCredentialProviderConfig )
417+ }
418+
361419func (ctrl * Controller ) updateContainerRuntimeConfig (oldObj , newObj interface {}) {
362420 oldCtrCfg := oldObj .(* mcfgv1.ContainerRuntimeConfig )
363421 newCtrCfg := newObj .(* mcfgv1.ContainerRuntimeConfig )
@@ -437,6 +495,11 @@ func (ctrl *Controller) imgWorker() {
437495 }
438496}
439497
498+ func (ctrl * Controller ) criocpWorker () {
499+ for ctrl .processNextCRIOCPWorkItem () {
500+ }
501+ }
502+
440503func (ctrl * Controller ) processNextWorkItem () bool {
441504 key , quit := ctrl .queue .Get ()
442505 if quit {
@@ -463,6 +526,19 @@ func (ctrl *Controller) processNextImgWorkItem() bool {
463526 return true
464527}
465528
529+ func (ctrl * Controller ) processNextCRIOCPWorkItem () bool {
530+ key , quit := ctrl .criocpQueue .Get ()
531+ if quit {
532+ return false
533+ }
534+ defer ctrl .criocpQueue .Done (key )
535+
536+ err := ctrl .syncCRIOCPHandler (key )
537+ ctrl .handleCRIOCPErr (err , key )
538+
539+ return true
540+ }
541+
466542func (ctrl * Controller ) handleErr (err error , key string ) {
467543 if err == nil {
468544 ctrl .queue .Forget (key )
@@ -499,6 +575,24 @@ func (ctrl *Controller) handleImgErr(err error, key string) {
499575 ctrl .imgQueue .AddAfter (key , 1 * time .Minute )
500576}
501577
578+ func (ctrl * Controller ) handleCRIOCPErr (err error , key string ) {
579+ if err == nil {
580+ ctrl .criocpQueue .Forget (key )
581+ return
582+ }
583+
584+ if ctrl .criocpQueue .NumRequeues (key ) < maxRetries {
585+ klog .V (2 ).Infof ("Error syncing CRIOCredentialProviderConfig %v: %v" , key , err )
586+ ctrl .criocpQueue .AddRateLimited (key )
587+ return
588+ }
589+
590+ utilruntime .HandleError (err )
591+ klog .V (2 ).Infof ("Dropping CRIOCredentialProviderConfig %q out of the queue: %v" , key , err )
592+ ctrl .criocpQueue .Forget (key )
593+ ctrl .criocpQueue .AddAfter (key , 1 * time .Minute )
594+ }
595+
502596// generateOriginalContainerRuntimeConfigs returns rendered default storage, registries and policy config files
503597func generateOriginalContainerRuntimeConfigs (templateDir string , cc * mcfgv1.ControllerConfig , role string ) (* ign3types.File , * ign3types.File , * ign3types.File , error ) {
504598 // Render the default templates
@@ -546,6 +640,53 @@ func generateOriginalContainerRuntimeConfigs(templateDir string, cc *mcfgv1.Cont
546640 return gmcStorageConfig , gmcRegistriesConfig , gmcPolicyJSON , nil
547641}
548642
643+ func generateOriginalCredentialProviderConfig (templateDir string , cc * mcfgv1.ControllerConfig , role string ) (* ign3types.File , error ) {
644+
645+ // Render the default templates
646+ rc := & mtmpl.RenderConfig {
647+ ControllerConfigSpec : & cc .Spec ,
648+ }
649+ generatedConfigs , err := mtmpl .GenerateMachineConfigsForRole (rc , role , templateDir )
650+ if err != nil {
651+ return nil , fmt .Errorf ("generateMachineConfigsforRole failed with error %w" , err )
652+ }
653+ // Find generated provider.yaml
654+ var (
655+ config , gmcCredProviderConfig * ign3types.File
656+ errCredProvider error
657+ credProviderConfigPath string
658+ )
659+
660+ // Determine credential provider config path based on platform
661+ // staying consistent with path used in pkg/controller/template/render.go
662+ credProviderConfigPathFormat := filepath .FromSlash ("/etc/kubernetes/credential-providers/%s-credential-provider.yaml" )
663+ switch cc .Spec .Infra .Status .PlatformStatus .Type {
664+ case apicfgv1 .AWSPlatformType :
665+ credProviderConfigPath = fmt .Sprintf (credProviderConfigPathFormat , "ecr" )
666+ case apicfgv1 .GCPPlatformType :
667+ credProviderConfigPath = fmt .Sprintf (credProviderConfigPathFormat , "gcr" )
668+ case apicfgv1 .AzurePlatformType :
669+ credProviderConfigPath = fmt .Sprintf (credProviderConfigPathFormat , "acr" )
670+ default :
671+ return nil , fmt .Errorf ("unsupported platform type: %s" , cc .Spec .Infra .Status .PlatformStatus .Type )
672+ }
673+ klog .Infof ("credential provider config path set to: %s" , credProviderConfigPath )
674+
675+ // Find credential provider config
676+ for _ , gmc := range generatedConfigs {
677+ config , errCredProvider = findCredProviderConfig (gmc , credProviderConfigPath )
678+ if errCredProvider != nil {
679+ klog .V (4 ).Infof ("could not find credential provider config in generated config %s: %v" , gmc .Name , errCredProvider )
680+ return nil , fmt .Errorf ("could not generate original credential provider configs: %w" , errCredProvider )
681+ }
682+
683+ gmcCredProviderConfig = config
684+
685+ }
686+
687+ return gmcCredProviderConfig , nil
688+ }
689+
549690func (ctrl * Controller ) syncStatusOnly (cfg * mcfgv1.ContainerRuntimeConfig , err error , args ... interface {}) error {
550691 statusUpdateErr := retry .RetryOnConflict (updateBackoff , func () error {
551692 newcfg , getErr := ctrl .mccrLister .Get (cfg .Name )
@@ -958,6 +1099,45 @@ func (ctrl *Controller) syncImageConfig(key string) error {
9581099 return nil
9591100}
9601101
1102+ func (ctrl * Controller ) syncCRIOCredentialProviderConfig (key string ) error {
1103+ startTime := time .Now ()
1104+ klog .V (4 ).Infof ("Started syncing CRIOCredentialProvider config %q (%v)" , key , startTime )
1105+ defer func () {
1106+ klog .V (4 ).Infof ("Finished syncing CRIOCredentialProvider config %q (%v)" , key , time .Since (startTime ))
1107+ }()
1108+
1109+ // Get ControllerConfig
1110+ controllerConfig , err := ctrl .ccLister .Get (ctrlcommon .ControllerConfigName )
1111+ if err != nil {
1112+ return fmt .Errorf ("could not get ControllerConfig %w" , err )
1113+ }
1114+
1115+ sel , err := metav1 .LabelSelectorAsSelector (metav1 .AddLabelToSelector (& metav1.LabelSelector {}, builtInLabelKey , "" ))
1116+ if err != nil {
1117+ return err
1118+ }
1119+ // Find all the MCO built in MachineConfigPools
1120+ mcpPools , err := ctrl .mcpLister .List (sel )
1121+ if err != nil {
1122+ return err
1123+ }
1124+
1125+ for _ , pool := range mcpPools {
1126+ role := pool .Name
1127+ credProviderConfigIgn , err := generateOriginalCredentialProviderConfig (ctrl .templatesDir , controllerConfig , role )
1128+ if err != nil {
1129+ return fmt .Errorf ("could not generate original CRIO credential provider config for role %s: %w" , role , err )
1130+ }
1131+ contents , err := ctrlcommon .DecodeIgnitionFileContents (credProviderConfigIgn .Contents .Source , credProviderConfigIgn .Contents .Compression )
1132+ if err != nil {
1133+ return fmt .Errorf ("could not decode CRIO credential provider config for role %s: %w" , role , err )
1134+ }
1135+ klog .Infof ("Decoded CRIO credential provider config contents successfully for role %s: %s" , role , string (contents ))
1136+ }
1137+
1138+ return nil
1139+ }
1140+
9611141func (ctrl * Controller ) syncIgnitionConfig (managedKey string , ignFile * ign3types.Config , pool * mcfgv1.MachineConfigPool , ownerRef metav1.OwnerReference ) (bool , error ) {
9621142 rawIgn , err := json .Marshal (ignFile )
9631143 if err != nil {
0 commit comments