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

k8snetworkplumbingwg / sriov-network-operator / 20939602361

13 Jan 2026 12:12AM UTC coverage: 63.219% (+0.007%) from 63.212%
20939602361

Pull #1014

github

web-flow
build(deps): bump the general-dependencies group with 5 updates

Bumps the general-dependencies group with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [github.com/google/renameio/v2](https://github.com/google/renameio) | `2.0.1` | `2.0.2` |
| [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) | `2.27.3` | `2.27.5` |
| [github.com/onsi/gomega](https://github.com/onsi/gomega) | `1.38.3` | `1.39.0` |
| [github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring](https://github.com/prometheus-operator/prometheus-operator) | `0.87.1` | `0.88.0` |
| [github.com/prometheus-operator/prometheus-operator/pkg/client](https://github.com/prometheus-operator/prometheus-operator) | `0.87.1` | `0.88.0` |


Updates `github.com/google/renameio/v2` from 2.0.1 to 2.0.2
- [Commits](https://github.com/google/renameio/compare/v2.0.1...v2.0.2)

Updates `github.com/onsi/ginkgo/v2` from 2.27.3 to 2.27.5
- [Release notes](https://github.com/onsi/ginkgo/releases)
- [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/ginkgo/compare/v2.27.3...v2.27.5)

Updates `github.com/onsi/gomega` from 1.38.3 to 1.39.0
- [Release notes](https://github.com/onsi/gomega/releases)
- [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/gomega/compare/v1.38.3...v1.39.0)

Updates `github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring` from 0.87.1 to 0.88.0
- [Release notes](https://github.com/prometheus-operator/prometheus-operator/releases)
- [Changelog](https://github.com/prometheus-operator/prometheus-operator/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus-operator/prometheus-operator/compare/v0.87.1...v0.88.0)

Updates `github.com/prometheus-operator/prometheus-operator/pkg/client` from 0.87.1 to 0.88.0
- [Release notes](https://github.com/prometheus-operator/prometheus-operator/releases)
- [Changelog](https://github.com/pr... (continued)
Pull Request #1014: build(deps): bump the general-dependencies group with 5 updates

9156 of 14483 relevant lines covered (63.22%)

0.7 hits per line

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

80.31
/controllers/drain_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
        "sync"
23

24
        "github.com/go-logr/logr"
25
        corev1 "k8s.io/api/core/v1"
26
        "k8s.io/apimachinery/pkg/api/errors"
27
        "k8s.io/apimachinery/pkg/runtime"
28
        "k8s.io/apimachinery/pkg/types"
29
        "k8s.io/client-go/tools/record"
30
        "k8s.io/client-go/util/workqueue"
31
        ctrl "sigs.k8s.io/controller-runtime"
32
        "sigs.k8s.io/controller-runtime/pkg/builder"
33
        "sigs.k8s.io/controller-runtime/pkg/client"
34
        "sigs.k8s.io/controller-runtime/pkg/controller"
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
        constants "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/consts"
42
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/drain"
43
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/orchestrator"
44
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/utils"
45
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/vars"
46
)
47

48
type DrainReconcile struct {
49
        client.Client
50
        Scheme   *runtime.Scheme
51
        recorder record.EventRecorder
52
        drainer  drain.DrainInterface
53

54
        drainCheckMutex sync.Mutex
55
}
56

57
func NewDrainReconcileController(client client.Client, Scheme *runtime.Scheme, recorder record.EventRecorder, orchestrator orchestrator.Interface) (*DrainReconcile, error) {
1✔
58
        drainer, err := drain.NewDrainer(orchestrator)
1✔
59
        if err != nil {
1✔
60
                return nil, err
×
61
        }
×
62

63
        return &DrainReconcile{
1✔
64
                client,
1✔
65
                Scheme,
1✔
66
                recorder,
1✔
67
                drainer,
1✔
68
                sync.Mutex{}}, nil
1✔
69
}
70

71
//+kubebuilder:rbac:groups="",resources=nodes,verbs=get;list;watch;update;patch
72
//+kubebuilder:rbac:groups=sriovnetwork.openshift.io,resources=sriovnodestates,verbs=get;list;watch
73
//+kubebuilder:rbac:groups=core,resources=events,verbs=create;patch
74

75
// Reconcile is part of the main kubernetes reconciliation loop which aims to
76
// move the current state of the cluster closer to the desired state.
77
// For more details, check Reconcile and its Result here:
78
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.8.3/pkg/reconcile
79
func (dr *DrainReconcile) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
1✔
80
        ctx = context.WithValue(ctx, constants.LoggerContextKey, log.FromContext(ctx))
1✔
81
        reqLogger := log.FromContext(ctx).WithName("Drain Reconcile")
1✔
82

1✔
83
        req.Namespace = vars.Namespace
1✔
84

1✔
85
        // get node object
1✔
86
        node := &corev1.Node{}
1✔
87
        found, err := dr.getObject(ctx, req, node)
1✔
88
        if err != nil {
2✔
89
                reqLogger.Error(err, "failed to get node object")
1✔
90
                return ctrl.Result{}, err
1✔
91
        }
1✔
92
        if !found {
2✔
93
                reqLogger.Info("node not found don't, requeue the request")
1✔
94
                return ctrl.Result{}, nil
1✔
95
        }
1✔
96

97
        // get sriovNodeNodeState object
98
        nodeNetworkState := &sriovnetworkv1.SriovNetworkNodeState{}
1✔
99
        found, err = dr.getObject(ctx, req, nodeNetworkState)
1✔
100
        if err != nil {
1✔
101
                reqLogger.Error(err, "failed to get sriovNetworkNodeState object")
×
102
                return ctrl.Result{}, err
×
103
        }
×
104
        if !found {
1✔
105
                reqLogger.Info("sriovNetworkNodeState not found, don't requeue the request")
×
106
                return ctrl.Result{}, nil
×
107
        }
×
108

109
        // check if use-external-drainer is set for a specific node state
110
        if utils.ObjectHasAnnotation(nodeNetworkState, constants.NodeStateExternalDrainerAnnotation, "true") {
1✔
111
                reqLogger.Info(`nodestate is set with external drainer annotation, don't requeue the request. 
×
112
                Draining will be done externally`, "nodeState", req.Name)
×
113
                return ctrl.Result{}, nil
×
114
        }
×
115

116
        // create the drain state annotation if it doesn't exist in the sriovNetworkNodeState object
117
        nodeStateDrainAnnotationCurrent, currentNodeStateExist, err := dr.ensureAnnotationExists(ctx, nodeNetworkState, constants.NodeStateDrainAnnotationCurrent)
1✔
118
        if err != nil {
1✔
119
                reqLogger.Error(err, "failed to ensure nodeStateDrainAnnotationCurrent")
×
120
                return ctrl.Result{}, err
×
121
        }
×
122
        _, desireNodeStateExist, err := dr.ensureAnnotationExists(ctx, nodeNetworkState, constants.NodeStateDrainAnnotation)
1✔
123
        if err != nil {
1✔
124
                reqLogger.Error(err, "failed to ensure nodeStateDrainAnnotation")
×
125
                return ctrl.Result{}, err
×
126
        }
×
127

128
        // create the drain state annotation if it doesn't exist in the node object
129
        nodeDrainAnnotation, nodeExist, err := dr.ensureAnnotationExists(ctx, node, constants.NodeDrainAnnotation)
1✔
130
        if err != nil {
1✔
131
                reqLogger.Error(err, "failed to ensure nodeStateDrainAnnotation")
×
132
                return ctrl.Result{}, err
×
133
        }
×
134

135
        // requeue the request if we needed to add any of the annotations
136
        if !nodeExist || !currentNodeStateExist || !desireNodeStateExist {
2✔
137
                return ctrl.Result{Requeue: true}, nil
1✔
138
        }
1✔
139
        reqLogger.V(2).Info("Drain annotations", "nodeAnnotation", nodeDrainAnnotation, "nodeStateAnnotation", nodeStateDrainAnnotationCurrent)
1✔
140

1✔
141
        // Check the node request
1✔
142
        if nodeDrainAnnotation == constants.DrainIdle {
2✔
143
                // this cover the case the node is on idle
1✔
144

1✔
145
                // node request to be on idle and the currect state is idle
1✔
146
                // we don't do anything
1✔
147
                if nodeStateDrainAnnotationCurrent == constants.DrainIdle {
2✔
148
                        reqLogger.Info("node and nodeState are on idle nothing todo")
1✔
149
                        return reconcile.Result{}, nil
1✔
150
                }
1✔
151

152
                // we have two options here:
153
                // 1. node request idle and the current status is drain complete
154
                // this means the daemon finish is work, so we need to clean the drain
155
                //
156
                // 2. the operator is still draining the node but maybe the sriov policy changed and the daemon
157
                //  doesn't need to drain anymore, so we can stop the drain
158
                if nodeStateDrainAnnotationCurrent == constants.DrainComplete ||
1✔
159
                        nodeStateDrainAnnotationCurrent == constants.Draining {
2✔
160
                        return dr.handleNodeIdleNodeStateDrainingOrCompleted(ctx, node, nodeNetworkState)
1✔
161
                }
1✔
162
        }
163

164
        // this cover the case a node request to drain or reboot
165
        if nodeDrainAnnotation == constants.DrainRequired ||
1✔
166
                nodeDrainAnnotation == constants.RebootRequired {
2✔
167
                return dr.handleNodeDrainOrReboot(ctx, node, nodeNetworkState, nodeDrainAnnotation, nodeStateDrainAnnotationCurrent)
1✔
168
        }
1✔
169

170
        reqLogger.Error(nil, "unexpected node drain annotation")
×
171
        return reconcile.Result{}, fmt.Errorf("unexpected node drain annotation")
×
172
}
173

174
func (dr *DrainReconcile) getObject(ctx context.Context, req ctrl.Request, object client.Object) (bool, error) {
1✔
175
        err := dr.Get(ctx, req.NamespacedName, object)
1✔
176
        if err != nil {
2✔
177
                if errors.IsNotFound(err) {
2✔
178
                        return false, nil
1✔
179
                }
1✔
180
                return false, err
1✔
181
        }
182
        return true, nil
1✔
183
}
184

185
func (dr *DrainReconcile) ensureAnnotationExists(ctx context.Context, object client.Object, key string) (string, bool, error) {
1✔
186
        value, exist := object.GetAnnotations()[key]
1✔
187
        if !exist {
2✔
188
                err := utils.AnnotateObject(ctx, object, key, constants.DrainIdle, dr.Client)
1✔
189
                if err != nil {
1✔
190
                        return "", false, err
×
191
                }
×
192
                return constants.DrainIdle, false, nil
1✔
193
        }
194

195
        return value, true, nil
1✔
196
}
197

198
// SetupWithManager sets up the controller with the Manager.
199
func (dr *DrainReconcile) SetupWithManager(mgr ctrl.Manager) error {
1✔
200
        createUpdateEnqueue := handler.Funcs{
1✔
201
                CreateFunc: func(c context.Context, e event.TypedCreateEvent[client.Object], w workqueue.TypedRateLimitingInterface[reconcile.Request]) {
2✔
202
                        w.Add(reconcile.Request{NamespacedName: types.NamespacedName{
1✔
203
                                Namespace: vars.Namespace,
1✔
204
                                Name:      e.Object.GetName(),
1✔
205
                        }})
1✔
206
                },
1✔
207
                UpdateFunc: func(ctx context.Context, e event.TypedUpdateEvent[client.Object], w workqueue.TypedRateLimitingInterface[reconcile.Request]) {
1✔
208
                        w.Add(reconcile.Request{NamespacedName: types.NamespacedName{
1✔
209
                                Namespace: vars.Namespace,
1✔
210
                                Name:      e.ObjectNew.GetName(),
1✔
211
                        }})
1✔
212
                },
1✔
213
        }
214

215
        // Watch for spec and annotation changes
216
        nodePredicates := builder.WithPredicates(DrainAnnotationPredicate{})
1✔
217
        nodeStatePredicates := builder.WithPredicates(DrainStateAnnotationPredicate{})
1✔
218

1✔
219
        return ctrl.NewControllerManagedBy(mgr).
1✔
220
                WithOptions(controller.Options{
1✔
221
                        MaxConcurrentReconciles: 50,
1✔
222
                        LogConstructor: func(request *reconcile.Request) logr.Logger {
2✔
223
                                logger := mgr.GetLogger().WithValues("Function", "Drain")
1✔
224
                                // Inspired by https://github.com/kubernetes-sigs/controller-runtime/blob/52b17917caa97ec546423867d9637f1787830f3e/pkg/builder/controller.go#L447
1✔
225
                                if req, ok := any(request).(*reconcile.Request); ok && req != nil {
2✔
226
                                        logger = logger.WithValues("node", request.Name)
1✔
227
                                }
1✔
228
                                return logger
1✔
229
                        },
230
                }).
231
                For(&corev1.Node{}, nodePredicates).
232
                Watches(&sriovnetworkv1.SriovNetworkNodeState{}, createUpdateEnqueue, nodeStatePredicates).
233
                Complete(dr)
234
}
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