• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

k8snetworkplumbingwg / sriov-network-operator / 26533894142

27 May 2026 07:30PM UTC coverage: 63.627% (+0.2%) from 63.396%
26533894142

Pull #1010

github

web-flow
Merge e50e887e9 into ff8603a91
Pull Request #1010: Conditions/network crds

196 of 247 new or added lines in 10 files covered. (79.35%)

18 existing lines in 1 file now uncovered.

9649 of 15165 relevant lines covered (63.63%)

0.71 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

72.95
/controllers/generic_network_controller.go
1
/*
2
Copyright 2021.
3

4
Licensed under the Apache License, Version 2.0 (the "License");
5
you may not use this file except in compliance with the License.
6
You may obtain a copy of the License at
7

8
    http://www.apache.org/licenses/LICENSE-2.0
9

10
Unless required by applicable law or agreed to in writing, software
11
distributed under the License is distributed on an "AS IS" BASIS,
12
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
See the License for the specific language governing permissions and
14
limitations under the License.
15
*/
16

17
package controllers
18

19
import (
20
        "context"
21
        "fmt"
22

23
        netattdefv1 "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1"
24
        corev1 "k8s.io/api/core/v1"
25
        "k8s.io/apimachinery/pkg/api/equality"
26
        "k8s.io/apimachinery/pkg/api/errors"
27
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28
        uns "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
29
        "k8s.io/apimachinery/pkg/runtime"
30
        "k8s.io/apimachinery/pkg/types"
31
        "k8s.io/client-go/util/workqueue"
32
        ctrl "sigs.k8s.io/controller-runtime"
33
        "sigs.k8s.io/controller-runtime/pkg/client"
34
        "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
35
        "sigs.k8s.io/controller-runtime/pkg/event"
36
        "sigs.k8s.io/controller-runtime/pkg/handler"
37
        "sigs.k8s.io/controller-runtime/pkg/log"
38
        "sigs.k8s.io/controller-runtime/pkg/reconcile"
39

40
        sriovnetworkv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1"
41
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/consts"
42
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/status"
43
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/utils"
44
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/vars"
45
)
46

47
type NetworkCRInstance interface {
48
        client.Object
49
        // renders NetAttDef from the network instance
50
        RenderNetAttDef() (*uns.Unstructured, error)
51
        // return name of the target namespace for the network
52
        NetworkNamespace() string
53
}
54

55
// interface which controller should implement to be compatible with genericNetworkReconciler
56
type networkController interface {
57
        reconcile.Reconciler
58
        // GetObject should return CR type which implements networkCRInstance
59
        // interface
60
        GetObject() NetworkCRInstance
61
        // should return CR list type
62
        GetObjectList() client.ObjectList
63
        // should return name of the controller
64
        Name() string
65
}
66

67
func newGenericNetworkReconciler(c client.Client, s *runtime.Scheme, controller networkController, statusPatcher status.Interface) *genericNetworkReconciler {
1✔
68
        return &genericNetworkReconciler{
1✔
69
                Client:        c,
1✔
70
                Scheme:        s,
1✔
71
                controller:    controller,
1✔
72
                statusPatcher: statusPatcher,
1✔
73
        }
1✔
74
}
1✔
75

76
// genericNetworkReconciler provide common code for all network controllers
77
type genericNetworkReconciler struct {
78
        client.Client
79
        Scheme        *runtime.Scheme
80
        controller    networkController
81
        statusPatcher status.Interface
82
}
83

84
func (r *genericNetworkReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
1✔
85
        reqLogger := log.FromContext(ctx).WithValues(r.controller.Name(), req.NamespacedName)
1✔
86

1✔
87
        reqLogger.Info("Reconciling " + r.controller.Name())
1✔
88
        var err error
1✔
89

1✔
90
        // Fetch instance of the network object
1✔
91
        instance := r.controller.GetObject()
1✔
92
        err = r.Get(ctx, req.NamespacedName, instance)
1✔
93
        if err != nil {
2✔
94
                if errors.IsNotFound(err) {
2✔
95
                        // Request object not found, could have been deleted after reconcile request.
1✔
96
                        // Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
1✔
97
                        // Return and don't requeue
1✔
98
                        return reconcile.Result{}, nil
1✔
99
                }
1✔
100
                // Error reading the object - requeue the request.
101
                return reconcile.Result{}, err
×
102
        }
103

104
        if instance == nil {
1✔
105
                // Request object not found, could have been deleted after reconcile request.
×
106
                // Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
×
107
                // Return and don't requeue
×
108
                return reconcile.Result{}, nil
×
109
        }
×
110

111
        if instance.NetworkNamespace() != "" && instance.GetNamespace() != vars.Namespace {
2✔
112
                errMsg := fmt.Errorf("spec.networkNamespace cannot be set when the resource is not in the operator namespace (%s)", vars.Namespace)
1✔
113
                reqLogger.Error(
1✔
114
                        errMsg,
1✔
115
                        ".spec.networkNamespace can't be specified if the resource belongs to a namespace other than the operator's",
1✔
116
                        "operatorNamespace", vars.Namespace,
1✔
117
                        ".metadata.namespace", instance.GetNamespace(),
1✔
118
                        ".spec.networkNamespace", instance.NetworkNamespace(),
1✔
119
                )
1✔
120
                err = r.statusPatcher.ApplyCondition(ctx, instance,
1✔
121
                        status.NewCondition(sriovnetworkv1.ConditionReady, metav1.ConditionFalse,
1✔
122
                                sriovnetworkv1.ReasonNetworkAttachmentDefInvalid, errMsg.Error(), instance.GetGeneration()))
1✔
123
                if err != nil {
1✔
NEW
124
                        reqLogger.Error(err, "Failed to apply status conditions")
×
NEW
125
                }
×
126
                return reconcile.Result{}, err
1✔
127
        }
128

129
        // examine DeletionTimestamp to determine if object is under deletion
130
        if instance.GetDeletionTimestamp().IsZero() {
2✔
131
                // The object is not being deleted, so if it does not have our finalizer,
1✔
132
                // then lets add the finalizer and update the object. This is equivalent
1✔
133
                // registering our finalizer.
1✔
134
                err = r.updateFinalizers(ctx, instance)
1✔
135
                if err != nil {
1✔
UNCOV
136
                        return reconcile.Result{}, err
×
UNCOV
137
                }
×
138
        } else {
1✔
139
                // The object is being deleted
1✔
140
                err = r.cleanResourcesAndFinalizers(ctx, instance)
1✔
141
                return reconcile.Result{}, err
1✔
142
        }
1✔
143
        raw, err := instance.RenderNetAttDef()
1✔
144
        if err != nil {
1✔
NEW
145
                if updateErr := r.statusPatcher.ApplyCondition(ctx, instance,
×
NEW
146
                        status.NewCondition(sriovnetworkv1.ConditionReady, metav1.ConditionFalse,
×
NEW
147
                                sriovnetworkv1.ReasonNetworkAttachmentDefInvalid, err.Error(), instance.GetGeneration())); updateErr != nil {
×
NEW
148
                        reqLogger.Error(updateErr, "Failed to apply status conditions")
×
NEW
149
                }
×
150
                return reconcile.Result{}, err
×
151
        }
152
        netAttDef := &netattdefv1.NetworkAttachmentDefinition{}
1✔
153
        err = r.Scheme.Convert(raw, netAttDef, nil)
1✔
154
        if err != nil {
1✔
155
                return reconcile.Result{}, err
×
156
        }
×
157
        // format CNI config json in CR for easier readability
158
        netAttDef.Spec.Config, err = formatJSON(netAttDef.Spec.Config)
1✔
159
        if err != nil {
1✔
160
                reqLogger.Error(err, "Couldn't process rendered NetworkAttachmentDefinition config", "Namespace", netAttDef.Namespace, "Name", netAttDef.Name)
×
161
                return reconcile.Result{}, err
×
162
        }
×
163
        if lnns, ok := instance.GetAnnotations()[sriovnetworkv1.LASTNETWORKNAMESPACE]; ok && netAttDef.GetNamespace() != lnns {
2✔
164
                err = r.Delete(ctx, &netattdefv1.NetworkAttachmentDefinition{
1✔
165
                        ObjectMeta: metav1.ObjectMeta{
1✔
166
                                Name:      instance.GetName(),
1✔
167
                                Namespace: lnns,
1✔
168
                        },
1✔
169
                })
1✔
170
                if err != nil {
2✔
171
                        if !errors.IsNotFound(err) {
1✔
172
                                reqLogger.Error(err, "Couldn't delete NetworkAttachmentDefinition CR", "Namespace", lnns, "Name", instance.GetName())
×
173
                                return reconcile.Result{}, err
×
174
                        }
×
175
                        reqLogger.Info("Old NetworkAttachmentDefinition not found, skipping deletion", "Namespace", lnns, "Name", instance.GetName())
1✔
176
                }
177
                // Clear the stale annotation so we don't retry deletion.
178
                // It will be re-set at creation time (L192).
179
                if err := utils.AnnotateObject(ctx, instance, sriovnetworkv1.LASTNETWORKNAMESPACE, "", r.Client); err != nil {
1✔
180
                        reqLogger.Error(err, "Couldn't clear LASTNETWORKNAMESPACE annotation", "Name", instance.GetName())
×
181
                        return reconcile.Result{}, err
×
182
                }
×
183
        }
184

185
        if instance.GetNamespace() == netAttDef.Namespace {
2✔
186
                // If the NetAttachDef is in the same namespace of the resource, then we can leverage the OwnerReference field for garbage collector
1✔
187
                if err := controllerutil.SetOwnerReference(instance, netAttDef, r.Scheme); err != nil {
1✔
188
                        return reconcile.Result{}, err
×
189
                }
×
190
        }
191

192
        // Check if this NetworkAttachmentDefinition already exists
193
        found := &netattdefv1.NetworkAttachmentDefinition{}
1✔
194
        err = r.Get(ctx, types.NamespacedName{Name: netAttDef.Name, Namespace: netAttDef.Namespace}, found)
1✔
195
        if err != nil {
2✔
196
                if errors.IsNotFound(err) {
2✔
197
                        targetNamespace := &corev1.Namespace{}
1✔
198
                        err = r.Get(ctx, types.NamespacedName{Name: netAttDef.Namespace}, targetNamespace)
1✔
199
                        if errors.IsNotFound(err) {
2✔
200
                                reqLogger.Info("Target namespace doesn't exist, NetworkAttachmentDefinition will be created when namespace is available", "Namespace", netAttDef.Namespace, "Name", netAttDef.Name)
1✔
201
                                if updateErr := r.statusPatcher.ApplyCondition(ctx, instance,
1✔
202
                                        status.NewCondition(sriovnetworkv1.ConditionReady, metav1.ConditionFalse,
1✔
203
                                                sriovnetworkv1.ReasonNamespaceNotFound, fmt.Sprintf("target namespace %q does not exist", netAttDef.Namespace), instance.GetGeneration())); updateErr != nil {
1✔
UNCOV
204
                                        reqLogger.Error(updateErr, "Failed to apply status conditions")
×
NEW
205
                                        return reconcile.Result{}, updateErr
×
NEW
206
                                }
×
207
                                return reconcile.Result{}, nil
1✔
208
                        }
209

210
                        reqLogger.Info("NetworkAttachmentDefinition CR not exist, creating")
1✔
211
                        err = r.Create(ctx, netAttDef)
1✔
212
                        if err != nil {
1✔
UNCOV
213
                                reqLogger.Error(err, "Couldn't create NetworkAttachmentDefinition CR", "Namespace", netAttDef.Namespace, "Name", netAttDef.Name)
×
UNCOV
214
                                if updateErr := r.statusPatcher.ApplyCondition(ctx, instance,
×
UNCOV
215
                                        status.NewCondition(sriovnetworkv1.ConditionReady, metav1.ConditionFalse,
×
UNCOV
216
                                                sriovnetworkv1.ReasonNetworkAttachmentDefInvalid, err.Error(), instance.GetGeneration())); updateErr != nil {
×
UNCOV
217
                                        reqLogger.Error(updateErr, "Failed to apply status conditions")
×
NEW
218
                                        return reconcile.Result{}, updateErr
×
NEW
219
                                }
×
NEW
220
                                return reconcile.Result{}, err
×
221
                        }
222

223
                        err = utils.AnnotateObject(ctx, instance, sriovnetworkv1.LASTNETWORKNAMESPACE, netAttDef.Namespace, r.Client)
1✔
224
                        if err != nil {
1✔
225
                                return reconcile.Result{}, err
×
226
                        }
×
227

228
                        if updateErr := r.statusPatcher.ApplyCondition(ctx, instance,
1✔
229
                                status.NewCondition(sriovnetworkv1.ConditionReady, metav1.ConditionTrue,
1✔
230
                                        sriovnetworkv1.ReasonNetworkReady, "NetworkAttachmentDefinition is provisioned and ready", instance.GetGeneration())); updateErr != nil {
1✔
NEW
231
                                reqLogger.Error(updateErr, "Failed to apply status conditions")
×
232
                                return reconcile.Result{}, updateErr
×
233
                        }
×
UNCOV
234
                } else {
×
UNCOV
235
                        reqLogger.Error(err, "Couldn't get NetworkAttachmentDefinition CR", "Namespace", netAttDef.Namespace, "Name", netAttDef.Name)
×
UNCOV
236
                        if updateErr := r.statusPatcher.ApplyCondition(ctx, instance,
×
237
                                status.NewCondition(sriovnetworkv1.ConditionReady, metav1.ConditionFalse,
×
238
                                        sriovnetworkv1.ReasonNetworkAttachmentDefNotFound, err.Error(), instance.GetGeneration())); updateErr != nil {
×
239
                                reqLogger.Error(updateErr, "Failed to apply status conditions")
×
240
                        }
×
241
                        return reconcile.Result{}, err
×
242
                }
243
        } else {
1✔
244
                reqLogger.Info("NetworkAttachmentDefinition CR already exist")
1✔
245

1✔
246
                foundOwner := found.GetAnnotations()[consts.OwnerRefAnnotation]
1✔
247
                expectedOwner := netAttDef.GetAnnotations()[consts.OwnerRefAnnotation]
1✔
248

1✔
249
                // Note for the future: the `foundOwner != ""` condition can be removed to make the operator not touching the NetworkAttachmentDefinition created
1✔
250
                // by the user.
1✔
251
                if foundOwner != "" && foundOwner != expectedOwner {
2✔
252
                        reqLogger.Info("A NetworkAttachmentDefinition with the same name already exists and it does not belong to this resource",
1✔
253
                                "Namespace", netAttDef.Namespace, "Name", netAttDef.Name,
1✔
254
                                "CurrentOwner", foundOwner, "ExpectedOwner", expectedOwner,
1✔
255
                        )
1✔
256
                        if updateErr := r.statusPatcher.ApplyCondition(ctx, instance,
1✔
257
                                status.NewCondition(sriovnetworkv1.ConditionReady, metav1.ConditionFalse,
1✔
258
                                        sriovnetworkv1.ReasonNetworkAttachmentDefInvalid,
1✔
259
                                        fmt.Sprintf("NetworkAttachmentDefinition '%s/%s' already exists and is owned by %s", netAttDef.Namespace, netAttDef.Name, foundOwner),
1✔
260
                                        instance.GetGeneration())); updateErr != nil {
1✔
UNCOV
261
                                reqLogger.Error(updateErr, "Failed to apply status conditions")
×
UNCOV
262
                                return reconcile.Result{}, updateErr
×
UNCOV
263
                        }
×
264
                        return reconcile.Result{}, nil
1✔
265
                }
266

267
                if !equality.Semantic.DeepEqual(found.Spec, netAttDef.Spec) || !equality.Semantic.DeepEqual(found.GetAnnotations(), netAttDef.GetAnnotations()) {
2✔
268
                        reqLogger.Info("Update NetworkAttachmentDefinition CR", "Namespace", netAttDef.Namespace, "Name", netAttDef.Name)
1✔
269
                        netAttDef.SetResourceVersion(found.GetResourceVersion())
1✔
270

1✔
271
                        err = r.Update(ctx, netAttDef)
1✔
272
                        if err != nil {
1✔
NEW
273
                                reqLogger.Error(err, "Couldn't update NetworkAttachmentDefinition CR", "Namespace", netAttDef.Namespace, "Name", netAttDef.Name)
×
NEW
274
                                if updateErr := r.statusPatcher.ApplyCondition(ctx, instance,
×
NEW
275
                                        status.NewCondition(sriovnetworkv1.ConditionReady, metav1.ConditionFalse,
×
NEW
276
                                                sriovnetworkv1.ReasonNetworkAttachmentDefInvalid, err.Error(), instance.GetGeneration())); updateErr != nil {
×
NEW
277
                                        reqLogger.Error(updateErr, "Failed to apply status conditions")
×
NEW
278
                                }
×
NEW
279
                                return reconcile.Result{}, err
×
280
                        }
281
                }
282

283
                if err := r.statusPatcher.ApplyCondition(ctx, instance,
1✔
284
                        status.NewCondition(sriovnetworkv1.ConditionReady, metav1.ConditionTrue,
1✔
285
                                sriovnetworkv1.ReasonNetworkReady, "NetworkAttachmentDefinition is provisioned and ready", instance.GetGeneration())); err != nil {
1✔
286
                        reqLogger.Error(err, "Failed to apply status conditions")
×
287
                        return reconcile.Result{}, err
×
UNCOV
288
                }
×
289
        }
290

291
        return ctrl.Result{}, nil
1✔
292
}
293

294
// SetupWithManager sets up the controller with the Manager.
295
func (r *genericNetworkReconciler) SetupWithManager(mgr ctrl.Manager) error {
1✔
296
        // Reconcile when the target namespace is created after the network object.
1✔
297
        namespaceHandler := handler.Funcs{
1✔
298
                CreateFunc: r.namespaceHandlerCreate,
1✔
299
        }
1✔
300
        return ctrl.NewControllerManagedBy(mgr).
1✔
301
                For(r.controller.GetObject()).
1✔
302
                Watches(&netattdefv1.NetworkAttachmentDefinition{}, handler.EnqueueRequestsFromMapFunc(r.handleNetAttDef)).
1✔
303
                Watches(&corev1.Namespace{}, &namespaceHandler).
1✔
304
                Complete(r.controller)
1✔
305
}
1✔
306

307
func (r *genericNetworkReconciler) handleNetAttDef(ctx context.Context, obj client.Object) []reconcile.Request {
1✔
308
        ret := []reconcile.Request{}
1✔
309
        instance := r.controller.GetObject()
1✔
310
        nadNamespacedName := types.NamespacedName{Namespace: obj.GetNamespace(), Name: obj.GetName()}
1✔
311

1✔
312
        err := r.Get(ctx, nadNamespacedName, instance)
1✔
313
        if err == nil {
2✔
314
                // Found a NetworkObject in the same namespace as the NetworkAttachmentDefinition, reconcile it
1✔
315
                ret = append(ret, reconcile.Request{NamespacedName: nadNamespacedName})
1✔
316
        } else if !errors.IsNotFound(err) {
2✔
317
                log.Log.WithName(r.controller.Name()+" handleNetAttDef").Error(err, "can't get object", "object", nadNamespacedName)
×
318
        }
×
319

320
        // Not found, try to find the NetworkObject in the operator's namespace
321
        operatorNamespacedName := types.NamespacedName{Namespace: vars.Namespace, Name: obj.GetName()}
1✔
322
        err = r.Get(ctx, operatorNamespacedName, instance)
1✔
323
        if err == nil {
2✔
324
                // Found a NetworkObject in the operator's namespace, reconcile it
1✔
325
                ret = append(ret, reconcile.Request{NamespacedName: operatorNamespacedName})
1✔
326
        } else if !errors.IsNotFound(err) {
2✔
327
                log.Log.WithName(r.controller.Name()+" handleNetAttDef").Error(err, "can't get object", "object", operatorNamespacedName)
×
328
        }
×
329

330
        return ret
1✔
331
}
332

333
func (r *genericNetworkReconciler) namespaceHandlerCreate(ctx context.Context, e event.TypedCreateEvent[client.Object], w workqueue.TypedRateLimitingInterface[reconcile.Request]) {
1✔
334
        networkList := r.controller.GetObjectList()
1✔
335
        err := r.List(ctx,
1✔
336
                networkList,
1✔
337
                client.MatchingFields{"spec.networkNamespace": e.Object.GetName()},
1✔
338
        )
1✔
339
        logger := log.Log.WithName(r.controller.Name() + " reconciler")
1✔
340
        if err != nil {
1✔
341
                logger.Info("Can't list networks for namespace", "resource", e.Object.GetName(), "error", err)
×
342
                return
×
343
        }
×
344
        unsContent, err := runtime.DefaultUnstructuredConverter.ToUnstructured(networkList)
1✔
345
        if err != nil {
1✔
346
                logger.Info("Can't convert network list to unstructured object", "resource", e.Object.GetName(), "error", err)
×
347
                return
×
348
        }
×
349
        unsList := &uns.Unstructured{}
1✔
350
        unsList.SetUnstructuredContent(unsContent)
1✔
351
        _ = unsList.EachListItem(func(o runtime.Object) error {
2✔
352
                unsObj := o.(*uns.Unstructured)
1✔
353
                w.Add(reconcile.Request{NamespacedName: types.NamespacedName{
1✔
354
                        Namespace: unsObj.GetNamespace(),
1✔
355
                        Name:      unsObj.GetName(),
1✔
356
                }})
1✔
357
                return nil
1✔
358
        })
1✔
359
}
360

361
// deleteNetAttDef deletes the generated net-att-def CR
362
func (r *genericNetworkReconciler) deleteNetAttDef(ctx context.Context, cr NetworkCRInstance) error {
1✔
363
        // Fetch the NetworkAttachmentDefinition instance
1✔
364
        namespace := cr.NetworkNamespace()
1✔
365
        if namespace == "" {
2✔
366
                namespace = cr.GetNamespace()
1✔
367
        }
1✔
368
        instance := &netattdefv1.NetworkAttachmentDefinition{ObjectMeta: metav1.ObjectMeta{Name: cr.GetName(), Namespace: namespace}}
1✔
369
        err := r.Delete(ctx, instance)
1✔
370
        if err != nil {
2✔
371
                if errors.IsNotFound(err) {
2✔
372
                        return nil
1✔
373
                }
1✔
374
                return err
1✔
375
        }
376
        return nil
1✔
377
}
378

379
func (r *genericNetworkReconciler) updateFinalizers(ctx context.Context, instance NetworkCRInstance) error {
1✔
380
        if instance.GetNamespace() != vars.Namespace {
2✔
381
                // If the resource is in a namespace different than the operator one, then the NetworkAttachmentDefinition will
1✔
382
                // be created in the same namespace and its deletion can be handled by OwnerReferences. There is no need for finalizers
1✔
383
                return nil
1✔
384
        }
1✔
385

386
        instanceFinalizers := instance.GetFinalizers()
1✔
387
        if !sriovnetworkv1.StringInArray(sriovnetworkv1.NETATTDEFFINALIZERNAME, instanceFinalizers) {
2✔
388
                instance.SetFinalizers(append(instanceFinalizers, sriovnetworkv1.NETATTDEFFINALIZERNAME))
1✔
389
                if err := r.Update(ctx, instance); err != nil {
1✔
UNCOV
390
                        return err
×
UNCOV
391
                }
×
392
        }
393

394
        return nil
1✔
395
}
396

397
func (r *genericNetworkReconciler) cleanResourcesAndFinalizers(ctx context.Context, instance NetworkCRInstance) error {
1✔
398
        instanceFinalizers := instance.GetFinalizers()
1✔
399

1✔
400
        if sriovnetworkv1.StringInArray(sriovnetworkv1.NETATTDEFFINALIZERNAME, instanceFinalizers) {
2✔
401
                // our finalizer is present, so lets handle any external dependency
1✔
402
                log.FromContext(ctx).Info("delete NetworkAttachmentDefinition CR", "Namespace", instance.NetworkNamespace(), "Name", instance.GetName())
1✔
403
                if err := r.deleteNetAttDef(ctx, instance); err != nil {
2✔
404
                        // if fail to delete the external dependency here, return with error
1✔
405
                        // so that it can be retried
1✔
406
                        return err
1✔
407
                }
1✔
408
                // remove our finalizer from the list and update it.
409
                newFinalizers, found := sriovnetworkv1.RemoveString(sriovnetworkv1.NETATTDEFFINALIZERNAME, instanceFinalizers)
1✔
410
                if found {
2✔
411
                        instance.SetFinalizers(newFinalizers)
1✔
412
                        if err := r.Update(ctx, instance); err != nil {
2✔
413
                                // If the object is not found, it's already been deleted
1✔
414
                                if errors.IsNotFound(err) {
2✔
415
                                        return nil
1✔
416
                                }
1✔
UNCOV
417
                                return err
×
418
                        }
419
                }
420
        }
421
        return nil
1✔
422
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc