@@ -18,6 +18,7 @@ package controllers
1818
1919import (
2020 "context"
21+ "fmt"
2122
2223 netattdefv1 "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1"
2324 corev1 "k8s.io/api/core/v1"
@@ -30,6 +31,7 @@ import (
3031 "k8s.io/client-go/util/workqueue"
3132 ctrl "sigs.k8s.io/controller-runtime"
3233 "sigs.k8s.io/controller-runtime/pkg/client"
34+ "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
3335 "sigs.k8s.io/controller-runtime/pkg/event"
3436 "sigs.k8s.io/controller-runtime/pkg/handler"
3537 "sigs.k8s.io/controller-runtime/pkg/log"
@@ -72,7 +74,6 @@ type genericNetworkReconciler struct {
7274}
7375
7476func (r * genericNetworkReconciler ) Reconcile (ctx context.Context , req ctrl.Request ) (ctrl.Result , error ) {
75- req .Namespace = vars .Namespace
7677 reqLogger := log .FromContext (ctx ).WithValues (r .controller .Name (), req .NamespacedName )
7778
7879 reqLogger .Info ("Reconciling " + r .controller .Name ())
@@ -91,37 +92,37 @@ func (r *genericNetworkReconciler) Reconcile(ctx context.Context, req ctrl.Reque
9192 // Error reading the object - requeue the request.
9293 return reconcile.Result {}, err
9394 }
94- instanceFinalizers := instance .GetFinalizers ()
95+
96+ if instance == nil {
97+ // Request object not found, could have been deleted after reconcile request.
98+ // Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
99+ // Return and don't requeue
100+ return reconcile.Result {}, nil
101+ }
102+
103+ if instance .NetworkNamespace () != "" && instance .GetNamespace () != vars .Namespace {
104+ reqLogger .Error (
105+ fmt .Errorf ("bad value for NetworkNamespace" ),
106+ ".spec.networkNamespace can't be specified if the resource belongs to a namespace other than the operator's" ,
107+ "operatorNamespace" , vars .Namespace ,
108+ ".metadata.namespace" , instance .GetNamespace (),
109+ ".spec.networkNamespace" , instance .NetworkNamespace (),
110+ )
111+ return reconcile.Result {}, nil
112+ }
113+
95114 // examine DeletionTimestamp to determine if object is under deletion
96115 if instance .GetDeletionTimestamp ().IsZero () {
97116 // The object is not being deleted, so if it does not have our finalizer,
98117 // then lets add the finalizer and update the object. This is equivalent
99118 // registering our finalizer.
100- if ! sriovnetworkv1 .StringInArray (sriovnetworkv1 .NETATTDEFFINALIZERNAME , instanceFinalizers ) {
101- instance .SetFinalizers (append (instanceFinalizers , sriovnetworkv1 .NETATTDEFFINALIZERNAME ))
102- if err := r .Update (ctx , instance ); err != nil {
103- return reconcile.Result {}, err
104- }
119+ err = r .updateFinalizers (ctx , instance )
120+ if err != nil {
121+ return reconcile.Result {}, err
105122 }
106123 } else {
107124 // The object is being deleted
108- if sriovnetworkv1 .StringInArray (sriovnetworkv1 .NETATTDEFFINALIZERNAME , instanceFinalizers ) {
109- // our finalizer is present, so lets handle any external dependency
110- reqLogger .Info ("delete NetworkAttachmentDefinition CR" , "Namespace" , instance .NetworkNamespace (), "Name" , instance .GetName ())
111- if err := r .deleteNetAttDef (ctx , instance ); err != nil {
112- // if fail to delete the external dependency here, return with error
113- // so that it can be retried
114- return reconcile.Result {}, err
115- }
116- // remove our finalizer from the list and update it.
117- newFinalizers , found := sriovnetworkv1 .RemoveString (sriovnetworkv1 .NETATTDEFFINALIZERNAME , instanceFinalizers )
118- if found {
119- instance .SetFinalizers (newFinalizers )
120- if err := r .Update (ctx , instance ); err != nil {
121- return reconcile.Result {}, err
122- }
123- }
124- }
125+ err = r .cleanResourcesAndFinalizers (ctx , instance )
125126 return reconcile.Result {}, err
126127 }
127128 raw , err := instance .RenderNetAttDef ()
@@ -151,6 +152,14 @@ func (r *genericNetworkReconciler) Reconcile(ctx context.Context, req ctrl.Reque
151152 return reconcile.Result {}, err
152153 }
153154 }
155+
156+ if instance .GetNamespace () == netAttDef .Namespace {
157+ // If the NetAttachDef is in the same namespace of the resource, then we can leverage the OwnerReference field for garbage collector
158+ if err := controllerutil .SetOwnerReference (instance , netAttDef , r .Scheme ); err != nil {
159+ return reconcile.Result {}, err
160+ }
161+ }
162+
154163 // Check if this NetworkAttachmentDefinition already exists
155164 found := & netattdefv1.NetworkAttachmentDefinition {}
156165 err = r .Get (ctx , types.NamespacedName {Name : netAttDef .Name , Namespace : netAttDef .Namespace }, found )
@@ -183,6 +192,7 @@ func (r *genericNetworkReconciler) Reconcile(ctx context.Context, req ctrl.Reque
183192 if ! equality .Semantic .DeepEqual (found .Spec , netAttDef .Spec ) || ! equality .Semantic .DeepEqual (found .GetAnnotations (), netAttDef .GetAnnotations ()) {
184193 reqLogger .Info ("Update NetworkAttachmentDefinition CR" , "Namespace" , netAttDef .Namespace , "Name" , netAttDef .Name )
185194 netAttDef .SetResourceVersion (found .GetResourceVersion ())
195+
186196 err = r .Update (ctx , netAttDef )
187197 if err != nil {
188198 reqLogger .Error (err , "Couldn't update NetworkAttachmentDefinition CR" , "Namespace" , netAttDef .Namespace , "Name" , netAttDef .Name )
@@ -202,11 +212,37 @@ func (r *genericNetworkReconciler) SetupWithManager(mgr ctrl.Manager) error {
202212 }
203213 return ctrl .NewControllerManagedBy (mgr ).
204214 For (r .controller .GetObject ()).
205- Watches (& netattdefv1.NetworkAttachmentDefinition {}, & handler.EnqueueRequestForObject {} ).
215+ Watches (& netattdefv1.NetworkAttachmentDefinition {}, handler .EnqueueRequestsFromMapFunc ( r . handleNetAttDef ) ).
206216 Watches (& corev1.Namespace {}, & namespaceHandler ).
207217 Complete (r .controller )
208218}
209219
220+ func (r * genericNetworkReconciler ) handleNetAttDef (ctx context.Context , obj client.Object ) []reconcile.Request {
221+ ret := []reconcile.Request {}
222+ instance := r .controller .GetObject ()
223+ nadNamespacedName := types.NamespacedName {Namespace : obj .GetNamespace (), Name : obj .GetName ()}
224+
225+ err := r .Get (ctx , nadNamespacedName , instance )
226+ if err == nil {
227+ // Found a NetworkObject in the same namespace as the NetworkAttachmentDefinition, reconcile it
228+ ret = append (ret , reconcile.Request {NamespacedName : nadNamespacedName })
229+ } else if ! errors .IsNotFound (err ) {
230+ log .Log .WithName (r .controller .Name ()+ " handleNetAttDef" ).Error (err , "can't get object" , "object" , nadNamespacedName )
231+ }
232+
233+ // Not found, try to find the NetworkObject in the operator's namespace
234+ operatorNamespacedName := types.NamespacedName {Namespace : vars .Namespace , Name : obj .GetName ()}
235+ err = r .Get (ctx , operatorNamespacedName , instance )
236+ if err == nil {
237+ // Found a NetworkObject in the operator's namespace, reconcile it
238+ ret = append (ret , reconcile.Request {NamespacedName : operatorNamespacedName })
239+ } else if ! errors .IsNotFound (err ) {
240+ log .Log .WithName (r .controller .Name ()+ " handleNetAttDef" ).Error (err , "can't get object" , "object" , operatorNamespacedName )
241+ }
242+
243+ return ret
244+ }
245+
210246func (r * genericNetworkReconciler ) namespaceHandlerCreate (ctx context.Context , e event.TypedCreateEvent [client.Object ], w workqueue.TypedRateLimitingInterface [reconcile.Request ]) {
211247 networkList := r .controller .GetObjectList ()
212248 err := r .List (ctx ,
@@ -252,3 +288,44 @@ func (r *genericNetworkReconciler) deleteNetAttDef(ctx context.Context, cr Netwo
252288 }
253289 return nil
254290}
291+
292+ func (r * genericNetworkReconciler ) updateFinalizers (ctx context.Context , instance NetworkCRInstance ) error {
293+ if instance .GetNamespace () != vars .Namespace {
294+ // If the resource is in a namespace different than the operator one, then the NetworkAttachmentDefinition will
295+ // be created in the same namespace and its deletion can be handled by OwnerReferences. There is no need for finalizers
296+ return nil
297+ }
298+
299+ instanceFinalizers := instance .GetFinalizers ()
300+ if ! sriovnetworkv1 .StringInArray (sriovnetworkv1 .NETATTDEFFINALIZERNAME , instanceFinalizers ) {
301+ instance .SetFinalizers (append (instanceFinalizers , sriovnetworkv1 .NETATTDEFFINALIZERNAME ))
302+ if err := r .Update (ctx , instance ); err != nil {
303+ return err
304+ }
305+ }
306+
307+ return nil
308+ }
309+
310+ func (r * genericNetworkReconciler ) cleanResourcesAndFinalizers (ctx context.Context , instance NetworkCRInstance ) error {
311+ instanceFinalizers := instance .GetFinalizers ()
312+
313+ if sriovnetworkv1 .StringInArray (sriovnetworkv1 .NETATTDEFFINALIZERNAME , instanceFinalizers ) {
314+ // our finalizer is present, so lets handle any external dependency
315+ log .FromContext (ctx ).Info ("delete NetworkAttachmentDefinition CR" , "Namespace" , instance .NetworkNamespace (), "Name" , instance .GetName ())
316+ if err := r .deleteNetAttDef (ctx , instance ); err != nil {
317+ // if fail to delete the external dependency here, return with error
318+ // so that it can be retried
319+ return err
320+ }
321+ // remove our finalizer from the list and update it.
322+ newFinalizers , found := sriovnetworkv1 .RemoveString (sriovnetworkv1 .NETATTDEFFINALIZERNAME , instanceFinalizers )
323+ if found {
324+ instance .SetFinalizers (newFinalizers )
325+ if err := r .Update (ctx , instance ); err != nil {
326+ return err
327+ }
328+ }
329+ }
330+ return nil
331+ }
0 commit comments