Skip to content

Commit 0e6fd84

Browse files
committed
fix(logstorage): warn when node count only exceeds replicas by 1
1 parent 2138da0 commit 0e6fd84

File tree

2 files changed

+90
-24
lines changed

2 files changed

+90
-24
lines changed

pkg/controller/logstorage/initializer/initializing_controller.go

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -168,25 +168,31 @@ func FillDefaults(opr *operatorv1.LogStorage) {
168168
}
169169
}
170170

171-
func validateLogStorage(spec *operatorv1.LogStorageSpec) error {
172-
if err := validateReplicasForNodeCount(spec); err != nil {
173-
return err
171+
func validateLogStorage(spec *operatorv1.LogStorageSpec) (error, string) {
172+
err, warning := validateReplicasForNodeCount(spec)
173+
if err != nil {
174+
return err, ""
174175
}
175-
return validateComponentResources(spec)
176+
if err := validateComponentResources(spec); err != nil {
177+
return err, ""
178+
}
179+
return nil, warning
176180
}
177181

178-
func validateReplicasForNodeCount(spec *operatorv1.LogStorageSpec) error {
182+
func validateReplicasForNodeCount(spec *operatorv1.LogStorageSpec) (error, string) {
179183
if spec.Nodes == nil || spec.Indices == nil || spec.Indices.Replicas == nil {
180-
return nil
184+
return nil, ""
181185
}
182186
replicas := int(*spec.Indices.Replicas)
183187
nodeCount := int(spec.Nodes.Count)
184188
if replicas > 0 && nodeCount <= replicas {
185-
return fmt.Errorf("LogStorage spec.indices.replicas (%d) must be less than spec.nodes.count (%d); "+
186-
"replica shards cannot be allocated when there are not enough nodes. "+
187-
"For a single-node Elasticsearch cluster, set spec.indices.replicas to 0", replicas, nodeCount)
189+
return fmt.Errorf("LogStorage spec.indices.replicas (%d) must be less than spec.nodes.count (%d); replica shards cannot be allocated when there are not enough nodes. For a single-node Elasticsearch cluster, set spec.indices.replicas to 0", replicas, nodeCount), ""
188190
}
189-
return nil
191+
192+
if replicas > 0 && nodeCount == replicas+1 {
193+
return nil, fmt.Sprintf("LogStorage spec.nodes.count (%d) is only 1 more than spec.indices.replicas (%d); this may prevent voluntary pod evictions (e.g., node repaving) due to PodDisruptionBudget constraints. If this is expected for your environment, no action is needed. Otherwise, consider setting spec.nodes.count to at least %d", nodeCount, replicas, replicas+2)
194+
}
195+
return nil, ""
190196
}
191197

192198
func validateComponentResources(spec *operatorv1.LogStorageSpec) error {
@@ -253,13 +259,16 @@ func (r *LogStorageInitializer) Reconcile(ctx context.Context, request reconcile
253259

254260
// Default and validate the object.
255261
FillDefaults(ls)
256-
err = validateLogStorage(&ls.Spec)
262+
err, warning := validateLogStorage(&ls.Spec)
257263
if err != nil {
258264
// Invalid - mark it as such and return.
259265
r.setConditionDegraded(ctx, ls, reqLogger)
260266
r.status.SetDegraded(operatorv1.ResourceValidationError, "An error occurred while validating LogStorage", err, reqLogger)
261267
return reconcile.Result{}, err
262268
}
269+
if warning != "" {
270+
reqLogger.Info(warning)
271+
}
263272

264273
pullSecrets, err := utils.GetNetworkingPullSecrets(install, r.client)
265274
if err != nil {

pkg/controller/logstorage/initializer/initializing_controller_test.go

Lines changed: 70 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ var _ = Describe("LogStorage Initializing controller", func() {
128128
mockStatus.On("ClearDegraded")
129129
mockStatus.On("SetDegraded", mock.Anything, mock.Anything, mock.Anything, mock.Anything)
130130
mockStatus.On("OnCRNotFound")
131+
mockStatus.On("SetWarning", mock.Anything, mock.Anything)
132+
mockStatus.On("ClearWarning", mock.Anything)
131133
})
132134

133135
It("fills defaults on an empty LogStorage", func() {
@@ -204,6 +206,27 @@ var _ = Describe("LogStorage Initializing controller", func() {
204206
Expect(ls.Status.State).Should(Equal(operatorv1.TigeraStatusDegraded))
205207
})
206208

209+
It("sets a warning when node count only exceeds replicas by 1", func() {
210+
var replicas int32 = 1
211+
ls := &operatorv1.LogStorage{}
212+
ls.Name = "tigera-secure"
213+
FillDefaults(ls)
214+
ls.Spec.Indices.Replicas = &replicas
215+
ls.Spec.Nodes.Count = 2
216+
Expect(cli.Create(ctx, ls)).ShouldNot(HaveOccurred())
217+
218+
r, err := NewTestInitializer(cli, scheme, mockStatus, operatorv1.ProviderNone, dns.DefaultClusterDomain)
219+
Expect(err).ShouldNot(HaveOccurred())
220+
_, err = r.Reconcile(ctx, reconcile.Request{})
221+
Expect(err).ShouldNot(HaveOccurred())
222+
Expect(mockStatus.AssertNumberOfCalls(GinkgoT(), "SetDegraded", 0)).Should(BeTrue())
223+
mockStatus.AssertCalled(GinkgoT(), "SetWarning", "replicaNodeCount", mock.Anything)
224+
225+
ls = &operatorv1.LogStorage{}
226+
Expect(cli.Get(ctx, client.ObjectKey{Name: "tigera-secure"}, ls)).ShouldNot(HaveOccurred())
227+
Expect(ls.Status.State).Should(Equal(operatorv1.TigeraStatusReady))
228+
})
229+
207230
It("handles LogStorage deletion", func() {
208231
// Create a LogStorage instance.
209232
ls := &operatorv1.LogStorage{}
@@ -379,7 +402,9 @@ var _ = Describe("LogStorage Initializing controller", func() {
379402
Nodes: &operatorv1.Nodes{Count: 1},
380403
Indices: &operatorv1.Indices{Replicas: &replicas},
381404
}
382-
Expect(validateReplicasForNodeCount(spec)).NotTo(BeNil())
405+
err, warning := validateReplicasForNodeCount(spec)
406+
Expect(err).NotTo(BeNil())
407+
Expect(warning).To(BeEmpty())
383408
})
384409

385410
It("should return an error when replicas equals node count", func() {
@@ -388,40 +413,72 @@ var _ = Describe("LogStorage Initializing controller", func() {
388413
Nodes: &operatorv1.Nodes{Count: 2},
389414
Indices: &operatorv1.Indices{Replicas: &replicas},
390415
}
391-
Expect(validateReplicasForNodeCount(spec)).NotTo(BeNil())
416+
err, warning := validateReplicasForNodeCount(spec)
417+
Expect(err).NotTo(BeNil())
418+
Expect(warning).To(BeEmpty())
392419
})
393420

394-
It("should return nil when replicas is 0 and node count is 1", func() {
395-
var replicas int32 = 0
421+
It("should return a warning when node count is only 1 more than replicas", func() {
422+
var replicas int32 = 1
396423
spec := &operatorv1.LogStorageSpec{
397-
Nodes: &operatorv1.Nodes{Count: 1},
424+
Nodes: &operatorv1.Nodes{Count: 2},
425+
Indices: &operatorv1.Indices{Replicas: &replicas},
426+
}
427+
err, warning := validateReplicasForNodeCount(spec)
428+
Expect(err).To(BeNil())
429+
Expect(warning).To(ContainSubstring("only 1 more than"))
430+
})
431+
432+
It("should return a warning when node count is 3 and replicas is 2", func() {
433+
var replicas int32 = 2
434+
spec := &operatorv1.LogStorageSpec{
435+
Nodes: &operatorv1.Nodes{Count: 3},
398436
Indices: &operatorv1.Indices{Replicas: &replicas},
399437
}
400-
Expect(validateReplicasForNodeCount(spec)).To(BeNil())
438+
err, warning := validateReplicasForNodeCount(spec)
439+
Expect(err).To(BeNil())
440+
Expect(warning).To(ContainSubstring("only 1 more than"))
401441
})
402442

403-
It("should return nil when replicas is 1 and node count is 2", func() {
443+
It("should return no error or warning when node count exceeds replicas by 2 or more", func() {
404444
var replicas int32 = 1
405445
spec := &operatorv1.LogStorageSpec{
406-
Nodes: &operatorv1.Nodes{Count: 2},
446+
Nodes: &operatorv1.Nodes{Count: 3},
447+
Indices: &operatorv1.Indices{Replicas: &replicas},
448+
}
449+
err, warning := validateReplicasForNodeCount(spec)
450+
Expect(err).To(BeNil())
451+
Expect(warning).To(BeEmpty())
452+
})
453+
454+
It("should return no error or warning when replicas is 0 and node count is 1", func() {
455+
var replicas int32 = 0
456+
spec := &operatorv1.LogStorageSpec{
457+
Nodes: &operatorv1.Nodes{Count: 1},
407458
Indices: &operatorv1.Indices{Replicas: &replicas},
408459
}
409-
Expect(validateReplicasForNodeCount(spec)).To(BeNil())
460+
err, warning := validateReplicasForNodeCount(spec)
461+
Expect(err).To(BeNil())
462+
Expect(warning).To(BeEmpty())
410463
})
411464

412-
It("should return nil when indices is nil", func() {
465+
It("should return no error or warning when indices is nil", func() {
413466
spec := &operatorv1.LogStorageSpec{
414467
Nodes: &operatorv1.Nodes{Count: 1},
415468
}
416-
Expect(validateReplicasForNodeCount(spec)).To(BeNil())
469+
err, warning := validateReplicasForNodeCount(spec)
470+
Expect(err).To(BeNil())
471+
Expect(warning).To(BeEmpty())
417472
})
418473

419-
It("should return nil when nodes is nil", func() {
474+
It("should return no error or warning when nodes is nil", func() {
420475
var replicas int32 = 1
421476
spec := &operatorv1.LogStorageSpec{
422477
Indices: &operatorv1.Indices{Replicas: &replicas},
423478
}
424-
Expect(validateReplicasForNodeCount(spec)).To(BeNil())
479+
err, warning := validateReplicasForNodeCount(spec)
480+
Expect(err).To(BeNil())
481+
Expect(warning).To(BeEmpty())
425482
})
426483
})
427484

0 commit comments

Comments
 (0)