Skip to content

Commit 765effe

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

File tree

2 files changed

+92
-22
lines changed

2 files changed

+92
-22
lines changed

pkg/controller/logstorage/initializer/initializing_controller.go

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -168,25 +168,35 @@ 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 {
185189
return fmt.Errorf("LogStorage spec.indices.replicas (%d) must be less than spec.nodes.count (%d); "+
186190
"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)
191+
"For a single-node Elasticsearch cluster, set spec.indices.replicas to 0", replicas, nodeCount), ""
188192
}
189-
return nil
193+
if replicas > 0 && nodeCount == replicas+1 {
194+
return nil, fmt.Sprintf("LogStorage spec.nodes.count (%d) is only 1 more than spec.indices.replicas (%d); "+
195+
"this may prevent voluntary pod evictions (e.g., node repaving) due to PodDisruptionBudget constraints. "+
196+
"If this is expected for your environment, no action is needed. "+
197+
"Otherwise, consider setting spec.nodes.count to at least %d", nodeCount, replicas, replicas+2)
198+
}
199+
return nil, ""
190200
}
191201

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

254264
// Default and validate the object.
255265
FillDefaults(ls)
256-
err = validateLogStorage(&ls.Spec)
266+
err, warning := validateLogStorage(&ls.Spec)
257267
if err != nil {
258268
// Invalid - mark it as such and return.
259269
r.setConditionDegraded(ctx, ls, reqLogger)
260270
r.status.SetDegraded(operatorv1.ResourceValidationError, "An error occurred while validating LogStorage", err, reqLogger)
261271
return reconcile.Result{}, err
262272
}
273+
if warning != "" {
274+
reqLogger.Info(warning)
275+
}
263276

264277
pullSecrets, err := utils.GetNetworkingPullSecrets(install, r.client)
265278
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)