@@ -39,6 +39,7 @@ import (
3939 k8serrors "k8s.io/apimachinery/pkg/api/errors"
4040 "k8s.io/apimachinery/pkg/api/meta"
4141 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
42+ "k8s.io/client-go/tools/record"
4243 "sigs.k8s.io/cluster-api/util/conditions"
4344 ctrl "sigs.k8s.io/controller-runtime"
4445 "sigs.k8s.io/controller-runtime/pkg/builder"
@@ -66,6 +67,7 @@ type BareMetalHostReconciler struct {
6667 Log logr.Logger
6768 ProvisionerFactory provisioner.Factory
6869 APIReader client.Reader
70+ Recorder record.EventRecorder
6971}
7072
7173// Instead of passing a zillion arguments to the action of a phase,
@@ -1321,13 +1323,20 @@ func (r *BareMetalHostReconciler) actionProvisioning(ctx context.Context, prov p
13211323 image = * info .host .Spec .Image .DeepCopy ()
13221324 }
13231325
1326+ // Extract OCI auth secret credentials if needed
1327+ authSecret , err := r .getImageAuthSecret (ctx , info .host , & image )
1328+ if err != nil {
1329+ return recordActionFailure (info , metal3api .ProvisioningError , err .Error ())
1330+ }
1331+
13241332 provResult , err := prov .Provision (ctx , provisioner.ProvisionData {
13251333 Image : image ,
13261334 CustomDeploy : info .host .Spec .CustomDeploy .DeepCopy (),
13271335 HostConfig : hostConf ,
13281336 BootMode : info .host .Status .Provisioning .BootMode ,
13291337 HardwareProfile : hwProf ,
13301338 RootDeviceHints : info .host .Status .Provisioning .RootDeviceHints .DeepCopy (),
1339+ ImagePullSecret : authSecret ,
13311340 }, forceReboot )
13321341 if err != nil {
13331342 return actionError {fmt .Errorf ("failed to provision: %w" , err )}
@@ -2407,6 +2416,23 @@ func (r *BareMetalHostReconciler) getBMCSecretAndSetOwner(ctx context.Context, r
24072416 return bmcCredsSecret , nil
24082417}
24092418
2419+ // getImageAuthSecret validates and extracts the OCI registry credentials for the image.
2420+ // It returns the base64-encoded credentials in the format expected by Ironic, or an empty
2421+ // string if no auth secret is configured.
2422+ func (r * BareMetalHostReconciler ) getImageAuthSecret (ctx context.Context , host * metal3api.BareMetalHost , image * metal3api.Image ) (string , error ) {
2423+ if image == nil || ! image .IsOCI () {
2424+ return "" , nil
2425+ }
2426+
2427+ if image .OCIAuthSecretName == nil || * image .OCIAuthSecretName == "" {
2428+ return "" , nil
2429+ }
2430+
2431+ secretManager := r .secretManager (ctx , r .Log )
2432+ validator := NewImageAuthValidator (r .Recorder )
2433+ return validator .Validate (ctx , host , secretManager )
2434+ }
2435+
24102436func credentialsFromSecret (bmcCredsSecret * corev1.Secret ) * bmc.Credentials {
24112437 // We trim surrounding whitespace because those characters are
24122438 // unlikely to be part of the username or password and it is
@@ -2492,6 +2518,8 @@ func (r *BareMetalHostReconciler) updateEventHandler(e event.UpdateEvent) bool {
24922518
24932519// SetupWithManager registers the reconciler to be run by the manager.
24942520func (r * BareMetalHostReconciler ) SetupWithManager (mgr ctrl.Manager , preprovImgEnable bool , maxConcurrentReconcile int ) error {
2521+ r .Recorder = mgr .GetEventRecorderFor ("baremetalhost-controller" )
2522+
24952523 controller := ctrl .NewControllerManagedBy (mgr ).
24962524 For (& metal3api.BareMetalHost {}).
24972525 WithEventFilter (
0 commit comments