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

k8snetworkplumbingwg / sriov-network-operator / 12744720588

13 Jan 2025 09:57AM UTC coverage: 47.404% (-0.002%) from 47.406%
12744720588

Pull #830

github

web-flow
Merge 84d0a6d3e into 0860d5383
Pull Request #830: ovs: add internal interface

6 of 9 new or added lines in 1 file covered. (66.67%)

5 existing lines in 1 file now uncovered.

7267 of 15330 relevant lines covered (47.4%)

0.52 hits per line

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

74.38
/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
        "reflect"
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/errors"
26
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27
        uns "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
28
        "k8s.io/apimachinery/pkg/runtime"
29
        "k8s.io/apimachinery/pkg/types"
30
        "k8s.io/client-go/util/workqueue"
31
        ctrl "sigs.k8s.io/controller-runtime"
32
        "sigs.k8s.io/controller-runtime/pkg/client"
33
        "sigs.k8s.io/controller-runtime/pkg/event"
34
        "sigs.k8s.io/controller-runtime/pkg/handler"
35
        "sigs.k8s.io/controller-runtime/pkg/log"
36
        "sigs.k8s.io/controller-runtime/pkg/reconcile"
37

38
        sriovnetworkv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1"
39
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/utils"
40
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/vars"
41
)
42

43
type networkCRInstance interface {
44
        client.Object
45
        // renders NetAttDef from the network instance
46
        RenderNetAttDef() (*uns.Unstructured, error)
47
        // return name of the target namespace for the network
48
        NetworkNamespace() string
49
}
50

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

63
func newGenericNetworkReconciler(c client.Client, s *runtime.Scheme, controller networkController) *genericNetworkReconciler {
1✔
64
        return &genericNetworkReconciler{Client: c, Scheme: s, controller: controller}
1✔
65
}
1✔
66

67
// genericNetworkReconciler provide common code for all network controllers
68
type genericNetworkReconciler struct {
69
        client.Client
70
        Scheme     *runtime.Scheme
71
        controller networkController
72
}
73

74
func (r *genericNetworkReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
1✔
75
        req.Namespace = vars.Namespace
1✔
76
        reqLogger := log.FromContext(ctx).WithValues(r.controller.Name(), req.NamespacedName)
1✔
77

1✔
78
        reqLogger.Info("Reconciling " + r.controller.Name())
1✔
79
        var err error
1✔
80

1✔
81
        // Fetch instance of the network object
1✔
82
        instance := r.controller.GetObject()
1✔
83
        err = r.Get(ctx, req.NamespacedName, instance)
1✔
84
        if err != nil {
2✔
85
                if errors.IsNotFound(err) {
2✔
86
                        // Request object not found, could have been deleted after reconcile request.
1✔
87
                        // Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
1✔
88
                        // Return and don't requeue
1✔
89
                        return reconcile.Result{}, nil
1✔
90
                }
1✔
91
                // Error reading the object - requeue the request.
92
                return reconcile.Result{}, err
×
93
        }
94
        instanceFinalizers := instance.GetFinalizers()
1✔
95
        // examine DeletionTimestamp to determine if object is under deletion
1✔
96
        if instance.GetDeletionTimestamp().IsZero() {
2✔
97
                // The object is not being deleted, so if it does not have our finalizer,
1✔
98
                // then lets add the finalizer and update the object. This is equivalent
1✔
99
                // registering our finalizer.
1✔
100
                if !sriovnetworkv1.StringInArray(sriovnetworkv1.NETATTDEFFINALIZERNAME, instanceFinalizers) {
2✔
101
                        instance.SetFinalizers(append(instanceFinalizers, sriovnetworkv1.NETATTDEFFINALIZERNAME))
1✔
102
                        if err := r.Update(ctx, instance); err != nil {
2✔
103
                                return reconcile.Result{}, err
1✔
104
                        }
1✔
105
                }
106
        } else {
1✔
107
                // The object is being deleted
1✔
108
                if sriovnetworkv1.StringInArray(sriovnetworkv1.NETATTDEFFINALIZERNAME, instanceFinalizers) {
2✔
109
                        // our finalizer is present, so lets handle any external dependency
1✔
110
                        reqLogger.Info("delete NetworkAttachmentDefinition CR", "Namespace", instance.NetworkNamespace(), "Name", instance.GetName())
1✔
111
                        if err := r.deleteNetAttDef(ctx, instance); err != nil {
1✔
UNCOV
112
                                // if fail to delete the external dependency here, return with error
×
UNCOV
113
                                // so that it can be retried
×
UNCOV
114
                                return reconcile.Result{}, err
×
UNCOV
115
                        }
×
116
                        // remove our finalizer from the list and update it.
117
                        newFinalizers, found := sriovnetworkv1.RemoveString(sriovnetworkv1.NETATTDEFFINALIZERNAME, instanceFinalizers)
1✔
118
                        if found {
2✔
119
                                instance.SetFinalizers(newFinalizers)
1✔
120
                                if err := r.Update(ctx, instance); err != nil {
2✔
121
                                        return reconcile.Result{}, err
1✔
122
                                }
1✔
123
                        }
124
                }
125
                return reconcile.Result{}, err
1✔
126
        }
127
        raw, err := instance.RenderNetAttDef()
1✔
128
        if err != nil {
1✔
129
                return reconcile.Result{}, err
×
130
        }
×
131
        netAttDef := &netattdefv1.NetworkAttachmentDefinition{}
1✔
132
        err = r.Scheme.Convert(raw, netAttDef, nil)
1✔
133
        if err != nil {
1✔
134
                return reconcile.Result{}, err
×
135
        }
×
136
        // format CNI config json in CR for easier readability
137
        netAttDef.Spec.Config, err = formatJSON(netAttDef.Spec.Config)
1✔
138
        if err != nil {
1✔
139
                reqLogger.Error(err, "Couldn't process rendered NetworkAttachmentDefinition config", "Namespace", netAttDef.Namespace, "Name", netAttDef.Name)
×
140
                return reconcile.Result{}, err
×
141
        }
×
142
        if lnns, ok := instance.GetAnnotations()[sriovnetworkv1.LASTNETWORKNAMESPACE]; ok && netAttDef.GetNamespace() != lnns {
1✔
143
                err = r.Delete(ctx, &netattdefv1.NetworkAttachmentDefinition{
×
144
                        ObjectMeta: metav1.ObjectMeta{
×
145
                                Name:      instance.GetName(),
×
146
                                Namespace: lnns,
×
147
                        },
×
148
                })
×
149
                if err != nil {
×
150
                        reqLogger.Error(err, "Couldn't delete NetworkAttachmentDefinition CR", "Namespace", instance.GetName(), "Name", lnns)
×
151
                        return reconcile.Result{}, err
×
152
                }
×
153
        }
154
        // Check if this NetworkAttachmentDefinition already exists
155
        found := &netattdefv1.NetworkAttachmentDefinition{}
1✔
156
        err = r.Get(ctx, types.NamespacedName{Name: netAttDef.Name, Namespace: netAttDef.Namespace}, found)
1✔
157
        if err != nil {
2✔
158
                if errors.IsNotFound(err) {
2✔
159
                        targetNamespace := &corev1.Namespace{}
1✔
160
                        err = r.Get(ctx, types.NamespacedName{Name: netAttDef.Namespace}, targetNamespace)
1✔
161
                        if errors.IsNotFound(err) {
2✔
162
                                reqLogger.Info("Target namespace doesn't exist, NetworkAttachmentDefinition will be created when namespace is available", "Namespace", netAttDef.Namespace, "Name", netAttDef.Name)
1✔
163
                                return reconcile.Result{}, nil
1✔
164
                        }
1✔
165

166
                        reqLogger.Info("NetworkAttachmentDefinition CR not exist, creating")
1✔
167
                        err = r.Create(ctx, netAttDef)
1✔
168
                        if err != nil {
1✔
169
                                reqLogger.Error(err, "Couldn't create NetworkAttachmentDefinition CR", "Namespace", netAttDef.Namespace, "Name", netAttDef.Name)
×
170
                                return reconcile.Result{}, err
×
171
                        }
×
172

173
                        err = utils.AnnotateObject(ctx, instance, sriovnetworkv1.LASTNETWORKNAMESPACE, netAttDef.Namespace, r.Client)
1✔
174
                        if err != nil {
1✔
175
                                return reconcile.Result{}, err
×
176
                        }
×
177
                } else {
×
178
                        reqLogger.Error(err, "Couldn't get NetworkAttachmentDefinition CR", "Namespace", netAttDef.Namespace, "Name", netAttDef.Name)
×
179
                        return reconcile.Result{}, err
×
180
                }
×
181
        } else {
1✔
182
                reqLogger.Info("NetworkAttachmentDefinition CR already exist")
1✔
183
                if !reflect.DeepEqual(found.Spec, netAttDef.Spec) || !reflect.DeepEqual(found.GetAnnotations(), netAttDef.GetAnnotations()) {
2✔
184
                        reqLogger.Info("Update NetworkAttachmentDefinition CR", "Namespace", netAttDef.Namespace, "Name", netAttDef.Name)
1✔
185
                        netAttDef.SetResourceVersion(found.GetResourceVersion())
1✔
186
                        err = r.Update(ctx, netAttDef)
1✔
187
                        if err != nil {
1✔
188
                                reqLogger.Error(err, "Couldn't update NetworkAttachmentDefinition CR", "Namespace", netAttDef.Namespace, "Name", netAttDef.Name)
×
189
                                return reconcile.Result{}, err
×
190
                        }
×
191
                }
192
        }
193

194
        return ctrl.Result{}, nil
1✔
195
}
196

197
// SetupWithManager sets up the controller with the Manager.
198
func (r *genericNetworkReconciler) SetupWithManager(mgr ctrl.Manager) error {
1✔
199
        // Reconcile when the target namespace is created after the network object.
1✔
200
        namespaceHandler := handler.Funcs{
1✔
201
                CreateFunc: r.namespaceHandlerCreate,
1✔
202
        }
1✔
203
        return ctrl.NewControllerManagedBy(mgr).
1✔
204
                For(r.controller.GetObject()).
1✔
205
                Watches(&netattdefv1.NetworkAttachmentDefinition{}, &handler.EnqueueRequestForObject{}).
1✔
206
                Watches(&corev1.Namespace{}, &namespaceHandler).
1✔
207
                Complete(r.controller)
1✔
208
}
1✔
209

210
func (r *genericNetworkReconciler) namespaceHandlerCreate(ctx context.Context, e event.CreateEvent, q workqueue.RateLimitingInterface) {
1✔
211
        networkList := r.controller.GetObjectList()
1✔
212
        err := r.List(ctx,
1✔
213
                networkList,
1✔
214
                client.MatchingFields{"spec.networkNamespace": e.Object.GetName()},
1✔
215
        )
1✔
216
        logger := log.Log.WithName(r.controller.Name() + " reconciler")
1✔
217
        if err != nil {
1✔
218
                logger.Info("Can't list networks for namespace", "resource", e.Object.GetName(), "error", err)
×
219
                return
×
220
        }
×
221
        unsContent, err := runtime.DefaultUnstructuredConverter.ToUnstructured(networkList)
1✔
222
        if err != nil {
1✔
223
                logger.Info("Can't convert network list to unstructured object", "resource", e.Object.GetName(), "error", err)
×
224
                return
×
225
        }
×
226
        unsList := &uns.Unstructured{}
1✔
227
        unsList.SetUnstructuredContent(unsContent)
1✔
228
        _ = unsList.EachListItem(func(o runtime.Object) error {
2✔
229
                unsObj := o.(*uns.Unstructured)
1✔
230
                q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
1✔
231
                        Namespace: unsObj.GetNamespace(),
1✔
232
                        Name:      unsObj.GetName(),
1✔
233
                }})
1✔
234
                return nil
1✔
235
        })
1✔
236
}
237

238
// deleteNetAttDef deletes the generated net-att-def CR
239
func (r *genericNetworkReconciler) deleteNetAttDef(ctx context.Context, cr networkCRInstance) error {
1✔
240
        // Fetch the NetworkAttachmentDefinition instance
1✔
241
        namespace := cr.NetworkNamespace()
1✔
242
        if namespace == "" {
2✔
243
                namespace = cr.GetNamespace()
1✔
244
        }
1✔
245
        instance := &netattdefv1.NetworkAttachmentDefinition{ObjectMeta: metav1.ObjectMeta{Name: cr.GetName(), Namespace: namespace}}
1✔
246
        err := r.Delete(ctx, instance)
1✔
247
        if err != nil {
2✔
248
                if errors.IsNotFound(err) {
2✔
249
                        return nil
1✔
250
                }
1✔
UNCOV
251
                return err
×
252
        }
253
        return nil
1✔
254
}
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

© 2025 Coveralls, Inc