@@ -29,17 +29,22 @@ import (
2929 rbacv1 "k8s.io/api/rbac/v1"
3030 k8s_errors "k8s.io/apimachinery/pkg/api/errors"
3131 v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
3233 "k8s.io/apimachinery/pkg/fields"
3334 "k8s.io/apimachinery/pkg/runtime"
35+ "k8s.io/apimachinery/pkg/runtime/schema"
3436 "k8s.io/apimachinery/pkg/types"
3537 "k8s.io/client-go/kubernetes"
3638 ctrl "sigs.k8s.io/controller-runtime"
3739 "sigs.k8s.io/controller-runtime/pkg/builder"
40+ "sigs.k8s.io/controller-runtime/pkg/cache"
3841 "sigs.k8s.io/controller-runtime/pkg/client"
42+ "sigs.k8s.io/controller-runtime/pkg/controller"
3943 "sigs.k8s.io/controller-runtime/pkg/handler"
4044 "sigs.k8s.io/controller-runtime/pkg/log"
4145 "sigs.k8s.io/controller-runtime/pkg/predicate"
4246 "sigs.k8s.io/controller-runtime/pkg/reconcile"
47+ "sigs.k8s.io/controller-runtime/pkg/source"
4348
4449 "github.com/go-logr/logr"
4550 infranetworkv1 "github.com/openstack-k8s-operators/infra-operator/apis/network/v1beta1"
@@ -68,8 +73,11 @@ const (
6873// OpenStackDataPlaneNodeSetReconciler reconciles a OpenStackDataPlaneNodeSet object
6974type OpenStackDataPlaneNodeSetReconciler struct {
7075 client.Client
71- Kclient kubernetes.Interface
72- Scheme * runtime.Scheme
76+ Kclient kubernetes.Interface
77+ Scheme * runtime.Scheme
78+ Controller controller.Controller
79+ Cache cache.Cache
80+ Watching map [string ]bool
7381}
7482
7583// GetLogger returns a logger object with a prefix of "controller.name" and additional controller context fields
@@ -141,6 +149,10 @@ func (r *OpenStackDataPlaneNodeSetReconciler) Reconcile(ctx context.Context, req
141149 Log := r .GetLogger (ctx )
142150 Log .Info ("Reconciling NodeSet" )
143151
152+ // Try to set up MachineConfig watch if not already done
153+ // This is done conditionally because MachineConfig CRD may not exist on all clusters
154+ r .ensureMachineConfigWatch (ctx )
155+
144156 validate := validator .New ()
145157
146158 // Fetch the OpenStackDataPlaneNodeSet instance
@@ -669,7 +681,12 @@ func (r *OpenStackDataPlaneNodeSetReconciler) SetupWithManager(
669681 }); err != nil {
670682 return err
671683 }
672- return ctrl .NewControllerManagedBy (mgr ).
684+ // Initialize the Watching map for conditional CRD watches
685+ r .Watching = make (map [string ]bool )
686+ r .Cache = mgr .GetCache ()
687+
688+ // Build the controller without MachineConfig watch (added conditionally later)
689+ c , err := ctrl .NewControllerManagedBy (mgr ).
673690 For (& dataplanev1.OpenStackDataPlaneNodeSet {},
674691 builder .WithPredicates (predicate .Or (
675692 predicate.GenerationChangedPredicate {},
@@ -692,10 +709,15 @@ func (r *OpenStackDataPlaneNodeSetReconciler) SetupWithManager(
692709 builder .WithPredicates (predicate.ResourceVersionChangedPredicate {})).
693710 Watches (& openstackv1.OpenStackVersion {},
694711 handler .EnqueueRequestsFromMapFunc (r .genericWatcherFn )).
695- Watches (& machineconfig.MachineConfig {},
696- handler .EnqueueRequestsFromMapFunc (r .machineConfigWatcherFn ),
697- builder .WithPredicates (predicate.ResourceVersionChangedPredicate {})).
698- Complete (r )
712+ // NOTE: MachineConfig watch is added conditionally during reconciliation
713+ // to avoid failures when the MachineConfig CRD doesn't exist
714+ Build (r )
715+
716+ if err != nil {
717+ return err
718+ }
719+ r .Controller = c
720+ return nil
699721}
700722
701723// machineConfigWatcherFn - watches for changes to the registries MachineConfig resource and queues
@@ -734,6 +756,70 @@ func (r *OpenStackDataPlaneNodeSetReconciler) machineConfigWatcherFn(
734756 return requests
735757}
736758
759+ // machineConfigWatcherFnTyped - typed version of machineConfigWatcherFn for use with source.Kind
760+ func (r * OpenStackDataPlaneNodeSetReconciler ) machineConfigWatcherFnTyped (
761+ ctx context.Context , obj * machineconfig.MachineConfig ,
762+ ) []reconcile.Request {
763+ return r .machineConfigWatcherFn (ctx , obj )
764+ }
765+
766+ const machineConfigCRDName = "machineconfigs.machineconfiguration.openshift.io"
767+
768+ // ensureMachineConfigWatch attempts to set up a watch for MachineConfig resources.
769+ // This is done conditionally because the MachineConfig CRD may not exist on all clusters
770+ // (e.g., non-OpenShift Kubernetes clusters or clusters without the Machine Config Operator).
771+ // Returns true if the CRD is available (watch was set up or already exists), false otherwise.
772+ func (r * OpenStackDataPlaneNodeSetReconciler ) ensureMachineConfigWatch (ctx context.Context ) bool {
773+ Log := r .GetLogger (ctx )
774+
775+ // Check if we're already watching
776+ if r .Watching [machineConfigCRDName ] {
777+ return true
778+ }
779+
780+ // Check if the MachineConfig CRD exists
781+ crd := & unstructured.Unstructured {}
782+ crd .SetGroupVersionKind (schema.GroupVersionKind {
783+ Group : "apiextensions.k8s.io" ,
784+ Kind : "CustomResourceDefinition" ,
785+ Version : "v1" ,
786+ })
787+
788+ err := r .Get (ctx , client.ObjectKey {Name : machineConfigCRDName }, crd )
789+ if err != nil {
790+ if k8s_errors .IsNotFound (err ) {
791+ Log .Info ("MachineConfig CRD not found, disconnected environment features disabled" )
792+ } else {
793+ Log .Error (err , "Error checking for MachineConfig CRD" )
794+ }
795+ return false
796+ }
797+
798+ // CRD exists, set up the watch
799+ Log .Info ("MachineConfig CRD found, enabling watch for disconnected environment support" )
800+ err = r .Controller .Watch (
801+ source .Kind (
802+ r .Cache ,
803+ & machineconfig.MachineConfig {},
804+ handler .TypedEnqueueRequestsFromMapFunc (r .machineConfigWatcherFnTyped ),
805+ predicate.TypedResourceVersionChangedPredicate [* machineconfig.MachineConfig ]{},
806+ ),
807+ )
808+ if err != nil {
809+ Log .Error (err , "Failed to set up MachineConfig watch" )
810+ return false
811+ }
812+
813+ r .Watching [machineConfigCRDName ] = true
814+ Log .Info ("Successfully set up MachineConfig watch" )
815+ return true
816+ }
817+
818+ // IsMachineConfigAvailable returns true if the MachineConfig CRD is available and being watched
819+ func (r * OpenStackDataPlaneNodeSetReconciler ) IsMachineConfigAvailable () bool {
820+ return r .Watching [machineConfigCRDName ]
821+ }
822+
737823func (r * OpenStackDataPlaneNodeSetReconciler ) secretWatcherFn (
738824 ctx context.Context , obj client.Object ,
739825) []reconcile.Request {
0 commit comments