@@ -20,11 +20,13 @@ import (
2020 "context"
2121 "errors"
2222 "fmt"
23+ "os"
2324 "time"
2425
2526 "github.com/go-logr/logr"
2627 "github.com/openmcp-project/controller-utils/pkg/clusters"
2728 "github.com/openmcp-project/controller-utils/pkg/controller/smartrequeue"
29+ openmcpconsts "github.com/openmcp-project/openmcp-operator/api/constants"
2830 corev1 "k8s.io/api/core/v1"
2931 rbac "k8s.io/api/rbac/v1"
3032 apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -100,8 +102,14 @@ func (r *CrossplaneReconciler) Reconcile(ctx context.Context, req ctrl.Request)
100102
101103 log .Info ("Reconciling Crossplane" , "name" , crossplane .Name , "namespace" , crossplane .Namespace )
102104
105+ // Get ProviderConfig from Platform cluster
106+ pc := & v1alpha1.ProviderConfig {}
107+ if err := r .PlatformCluster .Client ().Get (ctx , types.NamespacedName {Name : "default" }, pc ); err != nil {
108+ return requeueEntry .Error (err )
109+ }
110+
103111 // Setup reconciliation context
104- ctx , err := r .setupReconciliationContext (ctx , req )
112+ ctx , err := r .setupReconciliationContext (ctx , req , pc )
105113 if err != nil {
106114 return requeueEntry .Error (err )
107115 }
@@ -126,7 +134,7 @@ func (r *CrossplaneReconciler) Reconcile(ctx context.Context, req ctrl.Request)
126134 return requeueEntry .Error (err )
127135 }
128136
129- return r .reconcileCrossplaneInstance (ctx , crossplane , mcpCluster .Client ())
137+ return r .reconcileCrossplaneInstance (ctx , mcpCluster .Client (), crossplane , pc )
130138}
131139
132140func (r * CrossplaneReconciler ) updateStatus (ctx context.Context , crossplane * v1alpha1.Crossplane , newConditions * []metav1.Condition ) {
@@ -140,13 +148,7 @@ func (r *CrossplaneReconciler) updateStatus(ctx context.Context, crossplane *v1a
140148 }
141149}
142150
143- func (r * CrossplaneReconciler ) setupReconciliationContext (ctx context.Context , req ctrl.Request ) (context.Context , error ) {
144- // Get ProviderConfig from Platform cluster
145- providerConfig := & v1alpha1.ProviderConfig {}
146- if err := r .PlatformCluster .Client ().Get (ctx , types.NamespacedName {Name : "default" }, providerConfig ); err != nil {
147- return ctx , fmt .Errorf ("unable to fetch ProviderConfig 'default': %w" , err )
148- }
149-
151+ func (r * CrossplaneReconciler ) setupReconciliationContext (ctx context.Context , req ctrl.Request , providerConfig * v1alpha1.ProviderConfig ) (context.Context , error ) {
150152 // Handle ProviderConfig as ReleaseChannel
151153 resolverFn := r .GetResolverFunc (providerConfig )
152154 ctx = rcontext .WithVersionResolver (ctx , resolverFn )
@@ -210,16 +212,16 @@ func (r *CrossplaneReconciler) setupFluxKubeconfig(ctx context.Context, req ctrl
210212 return ctx , nil
211213}
212214
213- func (r * CrossplaneReconciler ) reconcileCrossplaneInstance (ctx context.Context , crossplane * v1alpha1.Crossplane , mcpClient client. Client ) (ctrl.Result , error ) {
215+ func (r * CrossplaneReconciler ) reconcileCrossplaneInstance (ctx context.Context , mcpClient client. Client , xp * v1alpha1.Crossplane , pc * v1alpha1. ProviderConfig ) (ctrl.Result , error ) {
214216 log := log .FromContext (ctx )
215217 requeueEntry := smartrequeue .FromContext (ctx )
216218
217219 // Handle deletion
218- if ! crossplane .DeletionTimestamp .IsZero () {
219- return r .deleteCrossplaneInstance (ctx , crossplane , mcpClient )
220+ if ! xp .DeletionTimestamp .IsZero () {
221+ return r .deleteCrossplaneInstance (ctx , mcpClient , xp , pc )
220222 }
221223
222- conditions , err := r .createOrUpdateCrossplaneInstance (ctx , crossplane , mcpClient )
224+ conditions , err := r .createOrUpdateCrossplaneInstance (ctx , mcpClient , xp , pc )
223225 if err != nil {
224226 log .Error (err , "failed to create or update Crossplane instance" )
225227 return requeueEntry .Error (err )
@@ -231,13 +233,13 @@ func (r *CrossplaneReconciler) reconcileCrossplaneInstance(ctx context.Context,
231233 condApi .SetStatusCondition (& newConditions , c )
232234 }
233235
234- r .updateStatus (ctx , crossplane , & newConditions )
236+ r .updateStatus (ctx , xp , & newConditions )
235237
236238 // Successfully reconciled - reset the requeue backoff
237239 return requeueEntry .Reset ()
238240}
239241
240- func (r * CrossplaneReconciler ) deleteCrossplaneInstance (ctx context.Context , xp * v1alpha1.Crossplane , mcpClient client. Client ) (ctrl.Result , error ) {
242+ func (r * CrossplaneReconciler ) deleteCrossplaneInstance (ctx context.Context , mcpClient client. Client , xp * v1alpha1.Crossplane , pc * v1alpha1. ProviderConfig ) (ctrl.Result , error ) {
241243 requeueEntry := smartrequeue .FromContext (ctx )
242244
243245 if ! r .hasFinalizer (xp ) {
@@ -247,7 +249,7 @@ func (r *CrossplaneReconciler) deleteCrossplaneInstance(ctx context.Context, xp
247249
248250 log := log .FromContext (ctx )
249251
250- conditions , err := r .deleteControlPlaneComponents (ctx , xp , mcpClient )
252+ conditions , err := r .deleteControlPlaneComponents (ctx , mcpClient , xp , pc )
251253
252254 // Update status with current conditions
253255 newConditions := []metav1.Condition {}
@@ -272,12 +274,15 @@ func (r *CrossplaneReconciler) deleteCrossplaneInstance(ctx context.Context, xp
272274 return requeueEntry .Never ()
273275}
274276
275- func (r * CrossplaneReconciler ) deleteControlPlaneComponents (ctx context.Context , xp * v1alpha1.Crossplane , mcpClient client. Client ) ([]metav1.Condition , error ) {
277+ func (r * CrossplaneReconciler ) deleteControlPlaneComponents (ctx context.Context , mcpClient client. Client , xp * v1alpha1.Crossplane , pc * v1alpha1. ProviderConfig ) ([]metav1.Condition , error ) {
276278 // disable all components
277279 xpCopy := xp .DeepCopy ()
278280 xpCopy .Spec = v1alpha1.CrossplaneSpec {}
281+ // disable imagePullSecrets from ProviderConfig
282+ pcCopy := pc .DeepCopy ()
283+ pcCopy .Spec = v1alpha1.ProviderConfigSpec {}
279284
280- j , err := r .newJuggler (ctx , xpCopy , mcpClient )
285+ j , err := r .newJuggler (ctx , mcpClient , xpCopy , pcCopy )
281286 if err != nil {
282287 return nil , err
283288 }
@@ -307,8 +312,8 @@ func (r *CrossplaneReconciler) deleteControlPlaneComponents(ctx context.Context,
307312 return conditions , nil
308313}
309314
310- func (r * CrossplaneReconciler ) createOrUpdateCrossplaneInstance (ctx context.Context , crossplane * v1alpha1.Crossplane , mcpClient client. Client ) ([]metav1.Condition , error ) {
311- j , err := r .newJuggler (ctx , crossplane , mcpClient )
315+ func (r * CrossplaneReconciler ) createOrUpdateCrossplaneInstance (ctx context.Context , mcpClient client. Client , xp * v1alpha1.Crossplane , pc * v1alpha1. ProviderConfig ) ([]metav1.Condition , error ) {
316+ j , err := r .newJuggler (ctx , mcpClient , xp , pc )
312317 if err != nil {
313318 return nil , err
314319 }
@@ -327,15 +332,45 @@ func (r *CrossplaneReconciler) createOrUpdateCrossplaneInstance(ctx context.Cont
327332 return conditions , nil
328333}
329334
330- func (r * CrossplaneReconciler ) newJuggler (ctx context.Context , xp * v1alpha1.Crossplane , mcpClient client. Client ) (* juggler.Juggler , error ) {
335+ func (r * CrossplaneReconciler ) newJuggler (ctx context.Context , mcpClient client. Client , xp * v1alpha1.Crossplane , pc * v1alpha1. ProviderConfig ) (* juggler.Juggler , error ) {
331336 logger := log .FromContext (ctx )
332- comps := []juggler.Component {}
337+ var comps []juggler.Component
333338 jug := juggler .NewJuggler (logger , juggler .NewEventRecorder (r .Recorder , xp ))
334339
335340 xpComp := & component.Crossplane {
336341 Config : & xp .Spec ,
337342 }
338343 comps = append (comps , xpComp )
344+
345+ // Add image pull secrets as components to be managed by the juggler.
346+ // Target secret namespace is crossplane-system
347+ if pc .Spec .ImagePullSecrets != nil {
348+ podNs := os .Getenv (openmcpconsts .EnvVariablePodNamespace )
349+ if podNs == "" {
350+ return nil , errors .New ("environment variable POD_NAMESPACE not set" )
351+ }
352+ for _ , ps := range pc .Spec .ImagePullSecrets {
353+ if ps .Name == "" {
354+ continue
355+ }
356+ sec := & component.Secret {
357+ SourceClient : r .PlatformCluster .Client (),
358+ Source : types.NamespacedName {
359+ Name : ps .Name ,
360+ Namespace : podNs ,
361+ },
362+ Target : types.NamespacedName {
363+ Name : ps .Name ,
364+ Namespace : component .CrossplaneNamespace ,
365+ },
366+ Enabled : xpComp .IsEnabled (),
367+ }
368+ comps = append (comps , sec )
369+ // Set image pull secret reference in Crossplane component so it can be added to the PodSpec
370+ xpComp .ImagePullSecretNames = append (xpComp .ImagePullSecretNames , sec .Target .Name )
371+ }
372+ }
373+
339374 if xp .Spec .Providers != nil {
340375 for _ , provider := range xp .Spec .Providers {
341376 xpp := & component.CrossplaneProvider {
@@ -366,6 +401,7 @@ func (r *CrossplaneReconciler) registerReconcilers(juggler *juggler.Juggler, log
366401
367402 or := object .NewReconciler (logger , mcpClient , sputils .LabelComponentName )
368403 or .RegisterType (
404+ & component.Secret {},
369405 & component.CrossplaneProvider {},
370406 )
371407 juggler .RegisterReconciler (or )
0 commit comments