Skip to content

Commit 914739d

Browse files
committed
setting nodestate annotation with 'sriovnetwork.openshift.io/use-external-drainer=true' in case exteranl drainer is enabled
The motivation is for external drainer verification, that SRIOV operator is set with external drainer Signed-off-by: Ido Heyvi <[email protected]>
1 parent bbbff6b commit 914739d

File tree

9 files changed

+190
-61
lines changed

9 files changed

+190
-61
lines changed

bindata/manifests/daemon/daemonset.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,10 @@ spec:
169169
value: "{{.ClusterType}}"
170170
- name: DEV_MODE
171171
value: "{{.DevMode}}"
172+
{{- if .UseExternalDrainer }}
173+
- name: USE_EXTERNAL_DRAINER
174+
value: "{{.UseExternalDrainer}}"
175+
{{- end }}
172176
resources:
173177
requests:
174178
cpu: 100m

controllers/drain_controller.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,13 @@ func (dr *DrainReconcile) Reconcile(ctx context.Context, req ctrl.Request) (ctrl
106106
return ctrl.Result{}, nil
107107
}
108108

109+
// check if use-external-drainer is set for a specific node state
110+
if utils.ObjectHasAnnotation(nodeNetworkState, constants.NodeStateExternalDrainerAnnotation, "true") {
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+
109116
// create the drain state annotation if it doesn't exist in the sriovNetworkNodeState object
110117
nodeStateDrainAnnotationCurrent, currentNodeStateExist, err := dr.ensureAnnotationExists(ctx, nodeNetworkState, constants.NodeStateDrainAnnotationCurrent)
111118
if err != nil {

controllers/drain_controller_test.go

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,19 @@ var _ = Describe("Drain Controller", Ordered, func() {
113113
})
114114

115115
Context("when there is only one node", func() {
116+
It("should not drain node on drain require while use-external-drainer annotation is set",
117+
func(ctx context.Context) {
118+
node, nodeState := createNode(ctx, "node1", true)
119+
120+
simulateDaemonSetAnnotation(node, constants.DrainRequired)
121+
122+
expectNodeStateAnnotation(nodeState, constants.DrainIdle)
123+
expectNodeIsSchedulable(node)
124+
125+
})
116126

117127
It("should drain single node on drain require", func(ctx context.Context) {
118-
node, nodeState := createNode(ctx, "node1")
128+
node, nodeState := createNode(ctx, "node1", false)
119129

120130
simulateDaemonSetAnnotation(node, constants.DrainRequired)
121131

@@ -129,7 +139,7 @@ var _ = Describe("Drain Controller", Ordered, func() {
129139
})
130140

131141
It("should not drain on reboot for single node", func(ctx context.Context) {
132-
node, nodeState := createNode(ctx, "node1")
142+
node, nodeState := createNode(ctx, "node1", false)
133143

134144
simulateDaemonSetAnnotation(node, constants.RebootRequired)
135145

@@ -142,8 +152,8 @@ var _ = Describe("Drain Controller", Ordered, func() {
142152
})
143153

144154
It("should drain on reboot for multiple node", func(ctx context.Context) {
145-
node, nodeState := createNode(ctx, "node1")
146-
createNode(ctx, "node2")
155+
node, nodeState := createNode(ctx, "node1", false)
156+
createNode(ctx, "node2", false)
147157

148158
simulateDaemonSetAnnotation(node, constants.RebootRequired)
149159

@@ -159,9 +169,9 @@ var _ = Describe("Drain Controller", Ordered, func() {
159169
Context("when there are multiple nodes", func() {
160170

161171
It("should drain nodes serially with default pool selector", func(ctx context.Context) {
162-
node1, nodeState1 := createNode(ctx, "node1")
163-
node2, nodeState2 := createNode(ctx, "node2")
164-
node3, nodeState3 := createNode(ctx, "node3")
172+
node1, nodeState1 := createNode(ctx, "node1", false)
173+
node2, nodeState2 := createNode(ctx, "node2", false)
174+
node3, nodeState3 := createNode(ctx, "node3", false)
165175

166176
// Two nodes require to drain at the same time
167177
simulateDaemonSetAnnotation(node1, constants.DrainRequired)
@@ -199,9 +209,9 @@ var _ = Describe("Drain Controller", Ordered, func() {
199209
})
200210

201211
It("should drain nodes in parallel with a custom pool selector", func(ctx context.Context) {
202-
node1, nodeState1 := createNode(ctx, "node1")
203-
node2, nodeState2 := createNode(ctx, "node2")
204-
node3, nodeState3 := createNode(ctx, "node3")
212+
node1, nodeState1 := createNode(ctx, "node1", false)
213+
node2, nodeState2 := createNode(ctx, "node2", false)
214+
node3, nodeState3 := createNode(ctx, "node3", false)
205215

206216
maxun := intstr.Parse("2")
207217
poolConfig := &sriovnetworkv1.SriovNetworkPoolConfig{}
@@ -250,9 +260,9 @@ var _ = Describe("Drain Controller", Ordered, func() {
250260
})
251261

252262
It("should drain nodes in parallel with a custom pool selector and honor MaxUnavailable", func(ctx context.Context) {
253-
node1, nodeState1 := createNode(ctx, "node1")
254-
node2, nodeState2 := createNode(ctx, "node2")
255-
node3, nodeState3 := createNode(ctx, "node3")
263+
node1, nodeState1 := createNode(ctx, "node1", false)
264+
node2, nodeState2 := createNode(ctx, "node2", false)
265+
node3, nodeState3 := createNode(ctx, "node3", false)
256266

257267
maxun := intstr.Parse("2")
258268
poolConfig := &sriovnetworkv1.SriovNetworkPoolConfig{}
@@ -275,9 +285,9 @@ var _ = Describe("Drain Controller", Ordered, func() {
275285
})
276286

277287
It("should drain all nodes in parallel with a custom pool using nil in max unavailable", func(ctx context.Context) {
278-
node1, nodeState1 := createNode(ctx, "node1")
279-
node2, nodeState2 := createNode(ctx, "node2")
280-
node3, nodeState3 := createNode(ctx, "node3")
288+
node1, nodeState1 := createNode(ctx, "node1", false)
289+
node2, nodeState2 := createNode(ctx, "node2", false)
290+
node3, nodeState3 := createNode(ctx, "node3", false)
281291

282292
poolConfig := &sriovnetworkv1.SriovNetworkPoolConfig{}
283293
poolConfig.SetNamespace(testNamespace)
@@ -303,7 +313,7 @@ var _ = Describe("Drain Controller", Ordered, func() {
303313
})
304314

305315
It("should drain in parallel nodes from two different pools, one custom and one default", func() {
306-
node1, nodeState1 := createNode(ctx, "node1")
316+
node1, nodeState1 := createNode(ctx, "node1", false)
307317
node2, nodeState2 := createNodeWithLabel(ctx, "node2", "pool")
308318
createPodOnNode(ctx, "test-node-2", "node2")
309319

@@ -326,7 +336,7 @@ var _ = Describe("Drain Controller", Ordered, func() {
326336
})
327337

328338
It("should select all the nodes to drain in parallel when the selector is empty", func() {
329-
node1, nodeState1 := createNode(ctx, "node3")
339+
node1, nodeState1 := createNode(ctx, "node3", false)
330340
node2, nodeState2 := createNodeWithLabel(ctx, "node4", "pool")
331341
createPodOnNode(ctx, "test-empty-1", "node3")
332342
createPodOnNode(ctx, "test-empty-2", "node4")
@@ -408,7 +418,7 @@ func simulateDaemonSetAnnotation(node *corev1.Node, drainAnnotationValue string)
408418
ToNot(HaveOccurred())
409419
}
410420

411-
func createNode(ctx context.Context, nodeName string) (*corev1.Node, *sriovnetworkv1.SriovNetworkNodeState) {
421+
func createNode(ctx context.Context, nodeName string, useExternalDrainer bool) (*corev1.Node, *sriovnetworkv1.SriovNetworkNodeState) {
412422
node := corev1.Node{
413423
ObjectMeta: metav1.ObjectMeta{
414424
Name: nodeName,
@@ -426,12 +436,16 @@ func createNode(ctx context.Context, nodeName string) (*corev1.Node, *sriovnetwo
426436
ObjectMeta: metav1.ObjectMeta{
427437
Name: nodeName,
428438
Namespace: vars.Namespace,
429-
Labels: map[string]string{
439+
Annotations: map[string]string{
430440
constants.NodeStateDrainAnnotationCurrent: constants.DrainIdle,
431441
},
432442
},
433443
}
434444

445+
if useExternalDrainer {
446+
nodeState.Annotations[constants.NodeStateExternalDrainerAnnotation] = "true"
447+
}
448+
435449
Expect(k8sClient.Create(ctx, &node)).ToNot(HaveOccurred())
436450
Expect(k8sClient.Create(ctx, &nodeState)).ToNot(HaveOccurred())
437451

controllers/sriovoperatorconfig_controller.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ func (r *SriovOperatorConfigReconciler) syncConfigDaemonSet(ctx context.Context,
196196
data.Data["ReleaseVersion"] = os.Getenv("RELEASEVERSION")
197197
data.Data["ClusterType"] = vars.ClusterType
198198
data.Data["DevMode"] = os.Getenv("DEV_MODE")
199+
data.Data["UseExternalDrainer"] = vars.UseExternalDrainer
199200
data.Data["ImagePullSecrets"] = GetImagePullSecrets()
200201
if dc.Spec.ConfigurationMode == sriovnetworkv1.SystemdConfigurationMode {
201202
data.Data["UsedSystemdMode"] = true

deployment/sriov-network-operator-chart/templates/operator.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,10 @@ spec:
7878
value: {{ .Values.operator.metricsExporter.certificates.secretName }}
7979
- name: METRICS_EXPORTER_KUBE_RBAC_PROXY_IMAGE
8080
value: {{ .Values.images.metricsExporterKubeRbacProxy }}
81+
{{- if .Values.operator.externalDrainer.enabled }}
8182
- name: USE_EXTERNAL_DRAINER
8283
value: {{ .Values.operator.externalDrainer.enabled | quote }}
84+
{{- end }}
8385
{{- if .Values.operator.metricsExporter.prometheusOperator.enabled }}
8486
- name: METRICS_EXPORTER_PROMETHEUS_OPERATOR_ENABLED
8587
value: {{ .Values.operator.metricsExporter.prometheusOperator.enabled | quote}}

main.go

Lines changed: 3 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -208,33 +208,8 @@ func main() {
208208
os.Exit(1)
209209
}
210210

211-
// we need a client that doesn't use the local cache for the objects
212-
drainKClient, err := client.New(restConfig, client.Options{
213-
Scheme: scheme,
214-
Cache: &client.CacheOptions{
215-
DisableFor: []client.Object{
216-
&sriovnetworkv1.SriovNetworkNodeState{},
217-
&corev1.Node{},
218-
&mcfgv1.MachineConfigPool{},
219-
},
220-
},
221-
})
222-
if err != nil {
223-
setupLog.Error(err, "unable to create drain kubernetes client")
224-
os.Exit(1)
225-
}
226-
227-
drainController, err := controllers.NewDrainReconcileController(drainKClient,
228-
mgr.GetScheme(),
229-
mgr.GetEventRecorderFor("SR-IOV operator"),
230-
platformsHelper)
231-
if err != nil {
232-
setupLog.Error(err, "unable to create controller", "controller", "DrainReconcile")
233-
os.Exit(1)
234-
}
235-
236-
if err = drainController.SetupWithManager(mgr); err != nil {
237-
setupLog.Error(err, "unable to setup controller with manager", "controller", "DrainReconcile")
211+
if err := setupDrainController(mgr, restConfig, platformsHelper, mgr.GetScheme()); err != nil {
212+
setupLog.Error(err, "unable to setup drain controller")
238213
os.Exit(1)
239214
}
240215
// +kubebuilder:scaffold:builder
@@ -299,8 +274,7 @@ func main() {
299274
func setupDrainController(mgr ctrl.Manager, restConfig *rest.Config,
300275
platformsHelper platforms.Interface, scheme *runtime.Scheme) error {
301276
if vars.UseExternalDrainer {
302-
setupLog.Info("internal drain controller is disabled, draining will be done externally by the maintenance operator")
303-
return nil
277+
setupLog.Info("'UseExternalDrainer' is set, draining will be done externally")
304278
}
305279

306280
// we need a client that doesn't use the local cache for the objects

pkg/consts/constants.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,15 @@ const (
7676
SriovDevicePluginLabelEnabled = "Enabled"
7777
SriovDevicePluginLabelDisabled = "Disabled"
7878

79-
NodeDrainAnnotation = "sriovnetwork.openshift.io/state"
80-
NodeStateDrainAnnotation = "sriovnetwork.openshift.io/desired-state"
81-
NodeStateDrainAnnotationCurrent = "sriovnetwork.openshift.io/current-state"
82-
DrainIdle = "Idle"
83-
DrainRequired = "Drain_Required"
84-
RebootRequired = "Reboot_Required"
85-
Draining = "Draining"
86-
DrainComplete = "DrainComplete"
79+
NodeDrainAnnotation = "sriovnetwork.openshift.io/state"
80+
NodeStateDrainAnnotation = "sriovnetwork.openshift.io/desired-state"
81+
NodeStateDrainAnnotationCurrent = "sriovnetwork.openshift.io/current-state"
82+
NodeStateExternalDrainerAnnotation = "sriovnetwork.openshift.io/use-external-drainer"
83+
DrainIdle = "Idle"
84+
DrainRequired = "Drain_Required"
85+
RebootRequired = "Reboot_Required"
86+
Draining = "Draining"
87+
DrainComplete = "DrainComplete"
8788

8889
SyncStatusSucceeded = "Succeeded"
8990
SyncStatusFailed = "Failed"

pkg/daemon/daemon.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,19 @@ func (dn *NodeReconciler) apply(ctx context.Context, desiredNodeState *sriovnetw
408408
return ctrl.Result{}, err
409409
}
410410

411+
// remove external drainer nodestate annotation if exists
412+
annotations := desiredNodeState.GetAnnotations()
413+
if _, ok := annotations[consts.NodeStateExternalDrainerAnnotation]; ok {
414+
reqLogger.Info("remove external drainer nodestate annotation", "annotation", consts.NodeStateExternalDrainerAnnotation)
415+
original := desiredNodeState.DeepCopy()
416+
delete(annotations, consts.NodeStateExternalDrainerAnnotation)
417+
// Patch only the annotations
418+
if err := dn.client.Patch(ctx, desiredNodeState, client.MergeFrom(original)); err != nil {
419+
reqLogger.Error(err, "failed to patch nodestate after removing external drainer annotation")
420+
return ctrl.Result{}, err
421+
}
422+
}
423+
411424
reqLogger.Info("sync succeeded")
412425
syncStatus := consts.SyncStatusSucceeded
413426
lastSyncError := ""
@@ -532,6 +545,16 @@ func (dn *NodeReconciler) handleDrain(ctx context.Context, desiredNodeState *sri
532545
return false, nil
533546
}
534547

548+
// add external drainer nodestate annotation if flag is enabled
549+
if vars.UseExternalDrainer {
550+
err := utils.AnnotateObject(ctx, desiredNodeState,
551+
consts.NodeStateExternalDrainerAnnotation, "true", dn.client)
552+
if err != nil {
553+
funcLog.Error(err, "failed to add nodestate external drainer annotation")
554+
return false, err
555+
}
556+
}
557+
535558
// annotate both node and node state with drain or reboot
536559
annotation := consts.DrainRequired
537560
if reqReboot {

0 commit comments

Comments
 (0)