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

k8snetworkplumbingwg / sriov-network-operator / 11775513002

11 Nov 2024 09:12AM UTC coverage: 47.024% (+1.4%) from 45.603%
11775513002

Pull #747

github

web-flow
Merge baa41c97a into 92fee7bec
Pull Request #747: Redesign device plugin reset

86 of 118 new or added lines in 4 files covered. (72.88%)

9 existing lines in 2 files now uncovered.

7103 of 15105 relevant lines covered (47.02%)

0.52 hits per line

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

57.33
/controllers/sriovnetworknodepolicy_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
        "encoding/json"
22
        "fmt"
23
        "reflect"
24
        "sort"
25
        "strings"
26
        "time"
27

28
        corev1 "k8s.io/api/core/v1"
29
        "k8s.io/apimachinery/pkg/api/equality"
30
        "k8s.io/apimachinery/pkg/api/errors"
31
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32
        "k8s.io/apimachinery/pkg/runtime"
33
        "k8s.io/apimachinery/pkg/types"
34
        "k8s.io/client-go/util/workqueue"
35
        ctrl "sigs.k8s.io/controller-runtime"
36
        "sigs.k8s.io/controller-runtime/pkg/client"
37
        "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
38
        "sigs.k8s.io/controller-runtime/pkg/event"
39
        "sigs.k8s.io/controller-runtime/pkg/handler"
40
        "sigs.k8s.io/controller-runtime/pkg/log"
41
        "sigs.k8s.io/controller-runtime/pkg/reconcile"
42
        "sigs.k8s.io/controller-runtime/pkg/source"
43

44
        dptypes "github.com/k8snetworkplumbingwg/sriov-network-device-plugin/pkg/types"
45

46
        sriovnetworkv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1"
47
        constants "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/consts"
48
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/featuregate"
49
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/utils"
50
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/vars"
51
)
52

53
const nodePolicySyncEventName = "node-policy-sync-event"
54

55
// SriovNetworkNodePolicyReconciler reconciles a SriovNetworkNodePolicy object
56
type SriovNetworkNodePolicyReconciler struct {
57
        client.Client
58
        Scheme      *runtime.Scheme
59
        FeatureGate featuregate.FeatureGate
60
}
61

62
//+kubebuilder:rbac:groups=sriovnetwork.openshift.io,resources=sriovnetworknodepolicies,verbs=get;list;watch;create;update;patch;delete
63
//+kubebuilder:rbac:groups=sriovnetwork.openshift.io,resources=sriovnetworknodepolicies/status,verbs=get;update;patch
64
//+kubebuilder:rbac:groups=sriovnetwork.openshift.io,resources=sriovnetworknodepolicies/finalizers,verbs=update
65

66
// Reconcile is part of the main kubernetes reconciliation loop which aims to
67
// move the current state of the cluster closer to the desired state.
68
// TODO(user): Modify the Reconcile function to compare the state specified by
69
// the SriovNetworkNodePolicy object against the actual cluster state, and then
70
// perform operations to make the cluster state reflect the state specified by
71
// the user.
72
//
73
// For more details, check Reconcile and its Result here:
74
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.8.3/pkg/reconcile
75
func (r *SriovNetworkNodePolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
1✔
76
        // Only handle node-policy-sync-event
1✔
77
        if req.Name != nodePolicySyncEventName || req.Namespace != "" {
2✔
78
                return reconcile.Result{}, nil
1✔
79
        }
1✔
80

81
        reqLogger := log.FromContext(ctx)
1✔
82
        reqLogger.Info("Reconciling")
1✔
83

1✔
84
        // Fetch the default SriovOperatorConfig
1✔
85
        defaultOpConf := &sriovnetworkv1.SriovOperatorConfig{}
1✔
86
        if err := r.Get(ctx, types.NamespacedName{Namespace: vars.Namespace, Name: constants.DefaultConfigName}, defaultOpConf); err != nil {
1✔
87
                if errors.IsNotFound(err) {
×
88
                        reqLogger.Info("default SriovOperatorConfig object not found, cannot reconcile SriovNetworkNodePolicies. Requeue.")
×
89
                        return reconcile.Result{RequeueAfter: 5 * time.Second}, nil
×
90
                }
×
91
                return reconcile.Result{}, err
×
92
        }
93

94
        // Fetch the SriovNetworkNodePolicyList
95
        policyList := &sriovnetworkv1.SriovNetworkNodePolicyList{}
1✔
96
        err := r.List(ctx, policyList, &client.ListOptions{})
1✔
97
        if err != nil {
1✔
98
                if errors.IsNotFound(err) {
×
99
                        // Request object not found, could have been deleted after reconcile request.
×
100
                        // Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
×
101
                        // Return and don't requeue
×
102
                        return reconcile.Result{}, nil
×
103
                }
×
104
                // Error reading the object - requeue the request.
105
                return reconcile.Result{}, err
×
106
        }
107
        // Fetch the Nodes
108
        nodeList := &corev1.NodeList{}
1✔
109
        lo := &client.MatchingLabels{
1✔
110
                "node-role.kubernetes.io/worker": "",
1✔
111
                "kubernetes.io/os":               "linux",
1✔
112
        }
1✔
113
        if len(defaultOpConf.Spec.ConfigDaemonNodeSelector) > 0 {
1✔
114
                labels := client.MatchingLabels(defaultOpConf.Spec.ConfigDaemonNodeSelector)
×
115
                lo = &labels
×
116
        }
×
117
        err = r.List(ctx, nodeList, lo)
1✔
118
        if err != nil {
1✔
119
                // Error reading the object - requeue the request.
×
120
                reqLogger.Error(err, "Fail to list nodes")
×
121
                return reconcile.Result{}, err
×
122
        }
×
123

124
        // Sort the policies with priority, higher priority ones is applied later
125
        // We need to use the sort so we always get the policies in the same order
126
        // That is needed so when we create the node Affinity for the sriov-device plugin
127
        // it will remain in the same order and not trigger a pod recreation
128
        sort.Sort(sriovnetworkv1.ByPriority(policyList.Items))
1✔
129
        // Sync SriovNetworkNodeState objects
1✔
130
        if err = r.syncAllSriovNetworkNodeStates(ctx, defaultOpConf, policyList, nodeList); err != nil {
1✔
131
                return reconcile.Result{}, err
×
132
        }
×
133
        // Sync Sriov device plugin ConfigMap object
134
        if err = r.syncDevicePluginConfigMap(ctx, defaultOpConf, policyList, nodeList); err != nil {
1✔
135
                return reconcile.Result{}, err
×
136
        }
×
137

138
        // All was successful. Request that this be re-triggered after ResyncPeriod,
139
        // so we can reconcile state again.
140
        return reconcile.Result{RequeueAfter: constants.ResyncPeriod}, nil
1✔
141
}
142

143
// SetupWithManager sets up the controller with the Manager.
144
func (r *SriovNetworkNodePolicyReconciler) SetupWithManager(mgr ctrl.Manager) error {
1✔
145
        qHandler := func(q workqueue.RateLimitingInterface) {
2✔
146
                q.AddAfter(reconcile.Request{NamespacedName: types.NamespacedName{
1✔
147
                        Namespace: "",
1✔
148
                        Name:      nodePolicySyncEventName,
1✔
149
                }}, time.Second)
1✔
150
        }
1✔
151

152
        delayedEventHandler := handler.Funcs{
1✔
153
                CreateFunc: func(ctx context.Context, e event.CreateEvent, q workqueue.RateLimitingInterface) {
2✔
154
                        log.Log.WithName("SriovNetworkNodePolicy").
1✔
155
                                Info("Enqueuing sync for create event", "resource", e.Object.GetName(), "type", e.Object.GetObjectKind().GroupVersionKind().String())
1✔
156
                        qHandler(q)
1✔
157
                },
1✔
158
                UpdateFunc: func(ctx context.Context, e event.UpdateEvent, q workqueue.RateLimitingInterface) {
×
159
                        log.Log.WithName("SriovNetworkNodePolicy").
×
160
                                Info("Enqueuing sync for update event", "resource", e.ObjectNew.GetName(), "type", e.ObjectNew.GetObjectKind().GroupVersionKind().String())
×
161
                        qHandler(q)
×
162
                },
×
163
                DeleteFunc: func(ctx context.Context, e event.DeleteEvent, q workqueue.RateLimitingInterface) {
1✔
164
                        log.Log.WithName("SriovNetworkNodePolicy").
1✔
165
                                Info("Enqueuing sync for delete event", "resource", e.Object.GetName(), "type", e.Object.GetObjectKind().GroupVersionKind().String())
1✔
166
                        qHandler(q)
1✔
167
                },
1✔
168
                GenericFunc: func(ctx context.Context, e event.GenericEvent, q workqueue.RateLimitingInterface) {
1✔
169
                        log.Log.WithName("SriovNetworkNodePolicy").
1✔
170
                                Info("Enqueuing sync for generic event", "resource", e.Object.GetName(), "type", e.Object.GetObjectKind().GroupVersionKind().String())
1✔
171
                        qHandler(q)
1✔
172
                },
1✔
173
        }
174

175
        // we want to act fast on new or deleted nodes
176
        nodeEvenHandler := handler.Funcs{
1✔
177
                CreateFunc: func(ctx context.Context, e event.CreateEvent, q workqueue.RateLimitingInterface) {
2✔
178
                        log.Log.WithName("SriovNetworkNodePolicy").
1✔
179
                                Info("Enqueuing sync for create event", "resource", e.Object.GetName())
1✔
180
                        qHandler(q)
1✔
181
                },
1✔
182
                UpdateFunc: func(ctx context.Context, e event.UpdateEvent, q workqueue.RateLimitingInterface) {
1✔
183
                        reflect.DeepEqual(e.ObjectOld.GetLabels(), e.ObjectNew.GetLabels())
1✔
184
                        log.Log.WithName("SriovNetworkNodePolicy").
1✔
185
                                Info("Enqueuing sync for create event", "resource", e.ObjectNew.GetName())
1✔
186
                        qHandler(q)
1✔
187
                },
1✔
188
                DeleteFunc: func(ctx context.Context, e event.DeleteEvent, q workqueue.RateLimitingInterface) {
1✔
189
                        log.Log.WithName("SriovNetworkNodePolicy").
1✔
190
                                Info("Enqueuing sync for delete event", "resource", e.Object.GetName())
1✔
191
                        qHandler(q)
1✔
192
                },
1✔
193
        }
194

195
        // send initial sync event to trigger reconcile when controller is started
196
        var eventChan = make(chan event.GenericEvent, 1)
1✔
197
        eventChan <- event.GenericEvent{Object: &sriovnetworkv1.SriovNetworkNodePolicy{
1✔
198
                ObjectMeta: metav1.ObjectMeta{Name: nodePolicySyncEventName, Namespace: ""}}}
1✔
199
        close(eventChan)
1✔
200

1✔
201
        return ctrl.NewControllerManagedBy(mgr).
1✔
202
                For(&sriovnetworkv1.SriovNetworkNodePolicy{}).
1✔
203
                Watches(&corev1.Node{}, nodeEvenHandler).
1✔
204
                Watches(&sriovnetworkv1.SriovNetworkNodePolicy{}, delayedEventHandler).
1✔
205
                Watches(&sriovnetworkv1.SriovNetworkPoolConfig{}, delayedEventHandler).
1✔
206
                WatchesRawSource(&source.Channel{Source: eventChan}, delayedEventHandler).
1✔
207
                Complete(r)
1✔
208
}
209

210
func (r *SriovNetworkNodePolicyReconciler) syncDevicePluginConfigMap(ctx context.Context, dc *sriovnetworkv1.SriovOperatorConfig,
211
        pl *sriovnetworkv1.SriovNetworkNodePolicyList, nl *corev1.NodeList) error {
1✔
212
        logger := log.Log.WithName("syncDevicePluginConfigMap")
1✔
213
        logger.V(1).Info("Start to sync device plugin ConfigMap")
1✔
214

1✔
215
        configData := make(map[string]string)
1✔
216
        for _, node := range nl.Items {
2✔
217
                data, err := r.renderDevicePluginConfigData(ctx, pl, &node)
1✔
218
                if err != nil {
1✔
219
                        return err
×
220
                }
×
221
                config, err := json.Marshal(data)
1✔
222
                if err != nil {
1✔
223
                        return err
×
224
                }
×
225
                configData[node.Name] = string(config)
1✔
226

1✔
227
                if data.ResourceList == nil || len(data.ResourceList) == 0 {
2✔
228
                        // if we don't have policies we should add the disabled label for the device plugin
1✔
229
                        err = utils.LabelNode(ctx, node.Name, constants.SriovDevicePluginLabel, constants.SriovDevicePluginLabelDisabled, r.Client)
1✔
230
                        if err != nil {
1✔
NEW
231
                                logger.Error(err, "failed to label node for device plugin label",
×
NEW
232
                                        "labelKey",
×
NEW
233
                                        constants.SriovDevicePluginLabel,
×
NEW
234
                                        "labelValue",
×
NEW
235
                                        constants.SriovDevicePluginLabelDisabled)
×
NEW
236
                                return err
×
NEW
237
                        }
×
238
                } else {
1✔
239
                        // if we have policies we should add the enabled label for the device plugin
1✔
240
                        err = utils.LabelNode(ctx, node.Name, constants.SriovDevicePluginLabel, constants.SriovDevicePluginLabelEnabled, r.Client)
1✔
241
                        if err != nil {
1✔
NEW
242
                                logger.Error(err, "failed to label node for device plugin label",
×
NEW
243
                                        "labelKey",
×
NEW
244
                                        constants.SriovDevicePluginLabel,
×
NEW
245
                                        "labelValue",
×
NEW
246
                                        constants.SriovDevicePluginLabelEnabled)
×
NEW
247
                                return err
×
NEW
248
                        }
×
249
                }
250
        }
251

252
        cm := &corev1.ConfigMap{
1✔
253
                TypeMeta: metav1.TypeMeta{
1✔
254
                        APIVersion: "v1",
1✔
255
                        Kind:       "ConfigMap",
1✔
256
                },
1✔
257
                ObjectMeta: metav1.ObjectMeta{
1✔
258
                        Name:      constants.ConfigMapName,
1✔
259
                        Namespace: vars.Namespace,
1✔
260
                },
1✔
261
                Data: configData,
1✔
262
        }
1✔
263

1✔
264
        if err := controllerutil.SetControllerReference(dc, cm, r.Scheme); err != nil {
1✔
265
                return err
×
266
        }
×
267

268
        found := &corev1.ConfigMap{}
1✔
269
        err := r.Get(ctx, types.NamespacedName{Namespace: cm.Namespace, Name: cm.Name}, found)
1✔
270
        if err != nil {
2✔
271
                if errors.IsNotFound(err) {
2✔
272
                        err = r.Create(ctx, cm)
1✔
273
                        if err != nil {
1✔
274
                                return fmt.Errorf("couldn't create ConfigMap: %v", err)
×
275
                        }
×
276
                        logger.V(1).Info("Created ConfigMap for", cm.Namespace, cm.Name)
1✔
277
                } else {
×
278
                        return fmt.Errorf("failed to get ConfigMap: %v", err)
×
279
                }
×
280
        } else {
1✔
281
                logger.V(1).Info("ConfigMap already exists, updating")
1✔
282
                err = r.Update(ctx, cm)
1✔
283
                if err != nil {
1✔
284
                        return fmt.Errorf("couldn't update ConfigMap: %v", err)
×
285
                }
×
286
        }
287
        return nil
1✔
288
}
289

290
func (r *SriovNetworkNodePolicyReconciler) syncAllSriovNetworkNodeStates(ctx context.Context, dc *sriovnetworkv1.SriovOperatorConfig, npl *sriovnetworkv1.SriovNetworkNodePolicyList, nl *corev1.NodeList) error {
1✔
291
        logger := log.Log.WithName("syncAllSriovNetworkNodeStates")
1✔
292
        logger.V(1).Info("Start to sync all SriovNetworkNodeState custom resource")
1✔
293
        found := &corev1.ConfigMap{}
1✔
294
        if err := r.Get(ctx, types.NamespacedName{Namespace: vars.Namespace, Name: constants.ConfigMapName}, found); err != nil {
2✔
295
                logger.V(1).Info("Fail to get", "ConfigMap", constants.ConfigMapName)
1✔
296
        }
1✔
297
        for _, node := range nl.Items {
2✔
298
                logger.V(1).Info("Sync SriovNetworkNodeState CR", "name", node.Name)
1✔
299
                ns := &sriovnetworkv1.SriovNetworkNodeState{}
1✔
300
                ns.Name = node.Name
1✔
301
                ns.Namespace = vars.Namespace
1✔
302
                netPoolConfig, _, err := findNodePoolConfig(ctx, &node, r.Client)
1✔
303
                if err != nil {
1✔
304
                        logger.Error(err, "failed to get SriovNetworkPoolConfig for the current node")
×
305
                }
×
306
                if netPoolConfig != nil {
2✔
307
                        ns.Spec.System.RdmaMode = netPoolConfig.Spec.RdmaMode
1✔
308
                }
1✔
309
                j, _ := json.Marshal(ns)
1✔
310
                logger.V(2).Info("SriovNetworkNodeState CR", "content", j)
1✔
311
                if err := r.syncSriovNetworkNodeState(ctx, dc, npl, ns, &node); err != nil {
1✔
312
                        logger.Error(err, "Fail to sync", "SriovNetworkNodeState", ns.Name)
×
313
                        return err
×
314
                }
×
315
        }
316
        logger.V(1).Info("Remove SriovNetworkNodeState custom resource for unselected node")
1✔
317
        nsList := &sriovnetworkv1.SriovNetworkNodeStateList{}
1✔
318
        err := r.List(ctx, nsList, &client.ListOptions{})
1✔
319
        if err != nil {
1✔
320
                if !errors.IsNotFound(err) {
×
321
                        logger.Error(err, "Fail to list SriovNetworkNodeState CRs")
×
322
                        return err
×
323
                }
×
324
        } else {
1✔
325
                for _, ns := range nsList.Items {
2✔
326
                        found := false
1✔
327
                        for _, node := range nl.Items {
2✔
328
                                if ns.GetName() == node.GetName() {
2✔
329
                                        found = true
1✔
330
                                        break
1✔
331
                                }
332
                        }
333
                        if !found {
2✔
334
                                // remove device plugin labels
1✔
335
                                logger.Info("removing device plugin label from node as SriovNetworkNodeState doesn't exist", "nodeStateName", ns.Name)
1✔
336
                                err = utils.RemoveLabelFromNode(ctx, ns.Name, constants.SriovDevicePluginLabel, r.Client)
1✔
337
                                if err != nil {
1✔
NEW
338
                                        logger.Error(err, "Fail to remove device plugin label from node", "node", ns.Name)
×
NEW
339
                                        return err
×
NEW
340
                                }
×
341
                                logger.Info("Deleting SriovNetworkNodeState as node with that name doesn't exist", "nodeStateName", ns.Name)
1✔
342
                                err = r.Delete(ctx, &ns, &client.DeleteOptions{})
1✔
343
                                if err != nil {
1✔
344
                                        logger.Error(err, "Fail to Delete", "SriovNetworkNodeState CR:", ns.GetName())
×
345
                                        return err
×
346
                                }
×
347
                        }
348
                }
349
        }
350
        return nil
1✔
351
}
352

353
func (r *SriovNetworkNodePolicyReconciler) syncSriovNetworkNodeState(ctx context.Context,
354
        dc *sriovnetworkv1.SriovOperatorConfig,
355
        npl *sriovnetworkv1.SriovNetworkNodePolicyList,
356
        ns *sriovnetworkv1.SriovNetworkNodeState,
357
        node *corev1.Node) error {
1✔
358
        logger := log.Log.WithName("syncSriovNetworkNodeState")
1✔
359
        logger.V(1).Info("Start to sync SriovNetworkNodeState", "Name", ns.Name)
1✔
360

1✔
361
        if err := controllerutil.SetControllerReference(dc, ns, r.Scheme); err != nil {
1✔
362
                return err
×
363
        }
×
364
        found := &sriovnetworkv1.SriovNetworkNodeState{}
1✔
365
        err := r.Get(ctx, types.NamespacedName{Namespace: ns.Namespace, Name: ns.Name}, found)
1✔
366
        if err != nil {
2✔
367
                logger.Error(err, "Fail to get SriovNetworkNodeState", "namespace", ns.Namespace, "name", ns.Name)
1✔
368
                if errors.IsNotFound(err) {
2✔
369
                        err = r.Create(ctx, ns)
1✔
370
                        if err != nil {
1✔
371
                                return fmt.Errorf("couldn't create SriovNetworkNodeState: %v", err)
×
372
                        }
×
373
                        logger.Info("Created SriovNetworkNodeState for", ns.Namespace, ns.Name)
1✔
374
                } else {
×
375
                        return fmt.Errorf("failed to get SriovNetworkNodeState: %v", err)
×
376
                }
×
377
        } else {
1✔
378
                if len(found.Status.Interfaces) == 0 {
1✔
379
                        logger.Info("SriovNetworkNodeState Status Interfaces are empty. Skip update of policies in spec",
×
380
                                "namespace", ns.Namespace, "name", ns.Name)
×
381
                        return nil
×
382
                }
×
383

384
                logger.V(1).Info("SriovNetworkNodeState already exists, updating")
1✔
385
                newVersion := found.DeepCopy()
1✔
386
                newVersion.Spec = ns.Spec
1✔
387
                newVersion.OwnerReferences = ns.OwnerReferences
1✔
388

1✔
389
                // Previous Policy Priority(ppp) records the priority of previous evaluated policy in node policy list.
1✔
390
                // Since node policy list is already sorted with priority number, comparing current priority with ppp shall
1✔
391
                // be sufficient.
1✔
392
                // ppp is set to 100 as initial value to avoid matching with the first policy in policy list, although
1✔
393
                // it should not matter since the flag used in p.Apply() will only be applied when VF partition is detected.
1✔
394
                ppp := 100
1✔
395
                for _, p := range npl.Items {
2✔
396
                        // Note(adrianc): default policy is deprecated and ignored.
1✔
397
                        if p.Name == constants.DefaultPolicyName {
1✔
398
                                continue
×
399
                        }
400
                        if p.Selected(node) {
2✔
401
                                logger.Info("apply", "policy", p.Name, "node", node.Name)
1✔
402
                                // Merging only for policies with the same priority (ppp == p.Spec.Priority)
1✔
403
                                // This boolean flag controls merging of PF configuration (e.g. mtu, numvfs etc)
1✔
404
                                // when VF partition is configured.
1✔
405
                                err = p.Apply(newVersion, ppp == p.Spec.Priority)
1✔
406
                                if err != nil {
1✔
407
                                        return err
×
408
                                }
×
409
                                if r.FeatureGate.IsEnabled(constants.ManageSoftwareBridgesFeatureGate) {
1✔
410
                                        err = p.ApplyBridgeConfig(newVersion)
×
411
                                        if err != nil {
×
412
                                                return err
×
413
                                        }
×
414
                                }
415
                                // record the evaluated policy priority for next loop
416
                                ppp = p.Spec.Priority
1✔
417
                        }
418
                }
419

420
                // Note(adrianc): we check same ownerReferences since SriovNetworkNodeState
421
                // was owned by a default SriovNetworkNodePolicy. if we encounter a descripancy
422
                // we need to update.
423
                if reflect.DeepEqual(newVersion.OwnerReferences, found.OwnerReferences) &&
1✔
424
                        equality.Semantic.DeepEqual(newVersion.Spec, found.Spec) {
1✔
425
                        logger.V(1).Info("SriovNetworkNodeState did not change, not updating")
×
426
                        return nil
×
427
                }
×
428
                err = r.Update(ctx, newVersion)
1✔
429
                if err != nil {
1✔
430
                        return fmt.Errorf("couldn't update SriovNetworkNodeState: %v", err)
×
431
                }
×
432
        }
433
        return nil
1✔
434
}
435

436
func (r *SriovNetworkNodePolicyReconciler) renderDevicePluginConfigData(ctx context.Context, pl *sriovnetworkv1.SriovNetworkNodePolicyList, node *corev1.Node) (dptypes.ResourceConfList, error) {
1✔
437
        logger := log.Log.WithName("renderDevicePluginConfigData")
1✔
438
        logger.V(1).Info("Start to render device plugin config data", "node", node.Name)
1✔
439
        rcl := dptypes.ResourceConfList{}
1✔
440
        for _, p := range pl.Items {
2✔
441
                // Note(adrianc): default policy is deprecated and ignored.
1✔
442
                if p.Name == constants.DefaultPolicyName {
1✔
443
                        continue
×
444
                }
445

446
                // render node specific data for device plugin config
447
                if !p.Selected(node) {
1✔
448
                        continue
×
449
                }
450

451
                nodeState := &sriovnetworkv1.SriovNetworkNodeState{}
1✔
452
                err := r.Get(ctx, types.NamespacedName{Namespace: vars.Namespace, Name: node.Name}, nodeState)
1✔
453
                if err != nil {
1✔
454
                        return rcl, err
×
455
                }
×
456

457
                found, i := resourceNameInList(p.Spec.ResourceName, &rcl)
1✔
458

1✔
459
                if found {
1✔
NEW
460
                        err := updateDevicePluginResource(&rcl.ResourceList[i], &p, nodeState)
×
461
                        if err != nil {
×
462
                                return rcl, err
×
463
                        }
×
464
                        logger.V(1).Info("Update resource", "Resource", rcl.ResourceList[i])
×
465
                } else {
1✔
466
                        rc, err := createDevicePluginResource(&p, nodeState)
1✔
467
                        if err != nil {
1✔
468
                                return rcl, err
×
469
                        }
×
470
                        rcl.ResourceList = append(rcl.ResourceList, *rc)
1✔
471
                        logger.V(1).Info("Add resource", "Resource", *rc)
1✔
472
                }
473
        }
474
        return rcl, nil
1✔
475
}
476

477
func resourceNameInList(name string, rcl *dptypes.ResourceConfList) (bool, int) {
1✔
478
        for i, rc := range rcl.ResourceList {
1✔
479
                if rc.ResourceName == name {
×
480
                        return true, i
×
481
                }
×
482
        }
483
        return false, 0
1✔
484
}
485

486
func createDevicePluginResource(
487
        p *sriovnetworkv1.SriovNetworkNodePolicy,
488
        nodeState *sriovnetworkv1.SriovNetworkNodeState) (*dptypes.ResourceConfig, error) {
1✔
489
        netDeviceSelectors := dptypes.NetDeviceSelectors{}
1✔
490

1✔
491
        rc := &dptypes.ResourceConfig{
1✔
492
                ResourceName: p.Spec.ResourceName,
1✔
493
        }
1✔
494
        netDeviceSelectors.IsRdma = p.Spec.IsRdma
1✔
495
        netDeviceSelectors.NeedVhostNet = p.Spec.NeedVhostNet
1✔
496
        netDeviceSelectors.VdpaType = dptypes.VdpaType(p.Spec.VdpaType)
1✔
497

1✔
498
        if p.Spec.NicSelector.Vendor != "" {
2✔
499
                netDeviceSelectors.Vendors = append(netDeviceSelectors.Vendors, p.Spec.NicSelector.Vendor)
1✔
500
        }
1✔
501
        if p.Spec.NicSelector.DeviceID != "" {
1✔
502
                var deviceID string
×
503
                if p.Spec.NumVfs == 0 {
×
504
                        deviceID = p.Spec.NicSelector.DeviceID
×
505
                } else {
×
506
                        deviceID = sriovnetworkv1.GetVfDeviceID(p.Spec.NicSelector.DeviceID)
×
507
                }
×
508

509
                if !sriovnetworkv1.StringInArray(deviceID, netDeviceSelectors.Devices) && deviceID != "" {
×
510
                        netDeviceSelectors.Devices = append(netDeviceSelectors.Devices, deviceID)
×
511
                }
×
512
        }
513
        if len(p.Spec.NicSelector.PfNames) > 0 {
1✔
514
                netDeviceSelectors.PfNames = append(netDeviceSelectors.PfNames, p.Spec.NicSelector.PfNames...)
×
515
        }
×
516
        // vfio-pci device link type is not detectable
517
        if p.Spec.DeviceType != constants.DeviceTypeVfioPci {
2✔
518
                if p.Spec.LinkType != "" {
1✔
519
                        linkType := constants.LinkTypeEthernet
×
520
                        if strings.EqualFold(p.Spec.LinkType, constants.LinkTypeIB) {
×
521
                                linkType = constants.LinkTypeInfiniband
×
522
                        }
×
523
                        netDeviceSelectors.LinkTypes = sriovnetworkv1.UniqueAppend(netDeviceSelectors.LinkTypes, linkType)
×
524
                }
525
        }
526
        if len(p.Spec.NicSelector.RootDevices) > 0 {
1✔
527
                netDeviceSelectors.RootDevices = append(netDeviceSelectors.RootDevices, p.Spec.NicSelector.RootDevices...)
×
528
        }
×
529
        // Removed driver constraint for "netdevice" DeviceType
530
        if p.Spec.DeviceType == constants.DeviceTypeVfioPci {
1✔
531
                netDeviceSelectors.Drivers = append(netDeviceSelectors.Drivers, p.Spec.DeviceType)
×
532
        }
×
533
        // Enable the selection of devices using NetFilter
534
        if p.Spec.NicSelector.NetFilter != "" {
1✔
535
                // Loop through interfaces status to find a match for NetworkID or NetworkTag
×
536
                if len(nodeState.Status.Interfaces) == 0 {
×
537
                        return nil, fmt.Errorf("node state %s doesn't contain interfaces data", nodeState.Name)
×
538
                }
×
539
                for _, intf := range nodeState.Status.Interfaces {
×
540
                        if sriovnetworkv1.NetFilterMatch(p.Spec.NicSelector.NetFilter, intf.NetFilter) {
×
541
                                // Found a match add the Interfaces PciAddress
×
542
                                netDeviceSelectors.PciAddresses = sriovnetworkv1.UniqueAppend(netDeviceSelectors.PciAddresses, intf.PciAddress)
×
543
                        }
×
544
                }
545
        }
546

547
        netDeviceSelectorsMarshal, err := json.Marshal(netDeviceSelectors)
1✔
548
        if err != nil {
1✔
549
                return nil, err
×
550
        }
×
551
        rawNetDeviceSelectors := json.RawMessage(netDeviceSelectorsMarshal)
1✔
552
        rc.Selectors = &rawNetDeviceSelectors
1✔
553

1✔
554
        rc.ExcludeTopology = p.Spec.ExcludeTopology
1✔
555

1✔
556
        return rc, nil
1✔
557
}
558

559
func updateDevicePluginResource(
560
        rc *dptypes.ResourceConfig,
561
        p *sriovnetworkv1.SriovNetworkNodePolicy,
562
        nodeState *sriovnetworkv1.SriovNetworkNodeState) error {
×
563
        netDeviceSelectors := dptypes.NetDeviceSelectors{}
×
564

×
565
        if err := json.Unmarshal(*rc.Selectors, &netDeviceSelectors); err != nil {
×
566
                return err
×
567
        }
×
568

569
        if p.Spec.NicSelector.Vendor != "" && !sriovnetworkv1.StringInArray(p.Spec.NicSelector.Vendor, netDeviceSelectors.Vendors) {
×
570
                netDeviceSelectors.Vendors = append(netDeviceSelectors.Vendors, p.Spec.NicSelector.Vendor)
×
571
        }
×
572
        if p.Spec.NicSelector.DeviceID != "" {
×
573
                var deviceID string
×
574
                if p.Spec.NumVfs == 0 {
×
575
                        deviceID = p.Spec.NicSelector.DeviceID
×
576
                } else {
×
577
                        deviceID = sriovnetworkv1.GetVfDeviceID(p.Spec.NicSelector.DeviceID)
×
578
                }
×
579

580
                if !sriovnetworkv1.StringInArray(deviceID, netDeviceSelectors.Devices) && deviceID != "" {
×
581
                        netDeviceSelectors.Devices = append(netDeviceSelectors.Devices, deviceID)
×
582
                }
×
583
        }
584
        if len(p.Spec.NicSelector.PfNames) > 0 {
×
585
                netDeviceSelectors.PfNames = sriovnetworkv1.UniqueAppend(netDeviceSelectors.PfNames, p.Spec.NicSelector.PfNames...)
×
586
        }
×
587
        // vfio-pci device link type is not detectable
588
        if p.Spec.DeviceType != constants.DeviceTypeVfioPci {
×
589
                if p.Spec.LinkType != "" {
×
590
                        linkType := constants.LinkTypeEthernet
×
591
                        if strings.EqualFold(p.Spec.LinkType, constants.LinkTypeIB) {
×
592
                                linkType = constants.LinkTypeInfiniband
×
593
                        }
×
594
                        if !sriovnetworkv1.StringInArray(linkType, netDeviceSelectors.LinkTypes) {
×
595
                                netDeviceSelectors.LinkTypes = sriovnetworkv1.UniqueAppend(netDeviceSelectors.LinkTypes, linkType)
×
596
                        }
×
597
                }
598
        }
599
        if len(p.Spec.NicSelector.RootDevices) > 0 {
×
600
                netDeviceSelectors.RootDevices = sriovnetworkv1.UniqueAppend(netDeviceSelectors.RootDevices, p.Spec.NicSelector.RootDevices...)
×
601
        }
×
602
        // Removed driver constraint for "netdevice" DeviceType
603
        if p.Spec.DeviceType == constants.DeviceTypeVfioPci {
×
604
                netDeviceSelectors.Drivers = sriovnetworkv1.UniqueAppend(netDeviceSelectors.Drivers, p.Spec.DeviceType)
×
605
        }
×
606
        // Enable the selection of devices using NetFilter
607
        if p.Spec.NicSelector.NetFilter != "" {
×
608
                // Loop through interfaces status to find a match for NetworkID or NetworkTag
×
609
                for _, intf := range nodeState.Status.Interfaces {
×
610
                        if sriovnetworkv1.NetFilterMatch(p.Spec.NicSelector.NetFilter, intf.NetFilter) {
×
611
                                // Found a match add the Interfaces PciAddress
×
612
                                netDeviceSelectors.PciAddresses = sriovnetworkv1.UniqueAppend(netDeviceSelectors.PciAddresses, intf.PciAddress)
×
613
                        }
×
614
                }
615
        }
616

617
        netDeviceSelectorsMarshal, err := json.Marshal(netDeviceSelectors)
×
618
        if err != nil {
×
619
                return err
×
620
        }
×
621
        rawNetDeviceSelectors := json.RawMessage(netDeviceSelectorsMarshal)
×
622
        rc.Selectors = &rawNetDeviceSelectors
×
623

×
624
        rc.ExcludeTopology = p.Spec.ExcludeTopology
×
625

×
626
        return nil
×
627
}
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