Skip to content

Commit 491f9b3

Browse files
fix: requeue reconcillation after replica update (#189)
1 parent fe80214 commit 491f9b3

3 files changed

Lines changed: 91 additions & 0 deletions

File tree

internal/controller/clickhouse/sync.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,8 @@ func (r *clickhouseReconciler) reconcileReplicaResources(ctx context.Context, lo
659659
}
660660

661661
log.Info(fmt.Sprintf("updating chosen replica %v with priority %s: %v", chosenReplica, highestStage.String(), replicasInStatus))
662+
663+
requeueAfter = chctrl.RequeueOnRefreshTimeout
662664
replicasInStatus = []v1.ClickHouseReplicaID{chosenReplica}
663665

664666
case chctrl.StageNotExists, chctrl.StageError:

internal/controller/keeper/sync.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,8 @@ func (r *keeperReconciler) reconcileReplicaResources(ctx context.Context, log ct
527527
}
528528

529529
log.Info(fmt.Sprintf("updating chosen replica %d with priority %s: %v", chosenReplica, highestStage.String(), replicasInStatus))
530+
531+
requeueAfter = chctrl.RequeueOnRefreshTimeout
530532
replicasInStatus = []v1.KeeperReplicaID{chosenReplica}
531533

532534
case chctrl.StageNotExists, chctrl.StageError:

test/e2e/clickhouse_e2e_test.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ import (
1616
. "github.com/onsi/ginkgo/v2"
1717
. "github.com/onsi/gomega"
1818
corev1 "k8s.io/api/core/v1"
19+
storagev1 "k8s.io/api/storage/v1"
1920
"k8s.io/apimachinery/pkg/api/meta"
21+
"k8s.io/apimachinery/pkg/api/resource"
2022
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2123
"k8s.io/apimachinery/pkg/labels"
2224
"k8s.io/apimachinery/pkg/runtime"
@@ -254,6 +256,91 @@ var _ = Describe("ClickHouse controller", Label("clickhouse"), func() {
254256
ClickHouseRWChecks(ctx, &cr, new(0))
255257
})
256258

259+
It("should resize PVCs on every replica", func(ctx context.Context) {
260+
By("creating an expandable StorageClass")
261+
262+
sc := &storagev1.StorageClass{
263+
ObjectMeta: metav1.ObjectMeta{
264+
Name: fmt.Sprintf("expandable-%d", rand.Uint32()), //nolint:gosec
265+
},
266+
Provisioner: "rancher.io/local-path",
267+
VolumeBindingMode: new(storagev1.VolumeBindingWaitForFirstConsumer),
268+
AllowVolumeExpansion: new(true),
269+
ReclaimPolicy: new(corev1.PersistentVolumeReclaimDelete),
270+
}
271+
Expect(k8sClient.Create(ctx, sc)).To(Succeed())
272+
DeferCleanup(func(ctx context.Context) {
273+
Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, sc))).To(Succeed())
274+
})
275+
276+
cr := v1.ClickHouseCluster{
277+
ObjectMeta: metav1.ObjectMeta{
278+
Namespace: ns,
279+
Name: fmt.Sprintf("pvc-resize-%d", rand.Uint32()), //nolint:gosec
280+
},
281+
Spec: v1.ClickHouseClusterSpec{
282+
Replicas: new(int32(3)),
283+
ContainerTemplate: v1.ContainerTemplateSpec{
284+
Image: v1.ContainerImage{Tag: BaseVersion},
285+
},
286+
KeeperClusterRef: v1.KeeperClusterReference{
287+
Name: keeper.Name,
288+
},
289+
DataVolumeClaimSpec: &corev1.PersistentVolumeClaimSpec{
290+
AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce},
291+
StorageClassName: &sc.Name,
292+
Resources: corev1.VolumeResourceRequirements{
293+
Requests: corev1.ResourceList{
294+
corev1.ResourceStorage: resource.MustParse("1Gi"),
295+
},
296+
},
297+
},
298+
},
299+
}
300+
301+
By("creating cluster CR with 3 replicas")
302+
Expect(k8sClient.Create(ctx, &cr)).To(Succeed())
303+
DeferCleanup(func(ctx context.Context) {
304+
By("deleting cluster CR")
305+
Expect(k8sClient.Delete(ctx, &cr)).To(Succeed())
306+
})
307+
308+
WaitClickHouseUpdatedAndReady(ctx, &cr, 3*time.Minute, false)
309+
310+
By("recording initial PVC sizes")
311+
312+
listOpts := []client.ListOption{
313+
client.InNamespace(ns),
314+
client.MatchingLabels{controllerutil.LabelAppKey: cr.SpecificName()},
315+
}
316+
317+
var pvcs corev1.PersistentVolumeClaimList
318+
Expect(k8sClient.List(ctx, &pvcs, listOpts...)).To(Succeed())
319+
Expect(pvcs.Items).To(HaveLen(int(cr.Replicas())), "expected one PVC per replica")
320+
321+
for _, pvc := range pvcs.Items {
322+
Expect(pvc.Spec.Resources.Requests.Storage().Cmp(
323+
*cr.Spec.DataVolumeClaimSpec.Resources.Requests.Storage())).To(Equal(0),
324+
"actual: %v, spec: %v", pvc.Spec.Resources, cr.Spec.DataVolumeClaimSpec.Resources)
325+
}
326+
327+
By("upgrading storage request from 1Gi to 2Gi")
328+
329+
Expect(k8sClient.Get(ctx, cr.NamespacedName(), &cr)).To(Succeed())
330+
cr.Spec.DataVolumeClaimSpec.Resources.Requests[corev1.ResourceStorage] = resource.MustParse("2Gi")
331+
Expect(k8sClient.Update(ctx, &cr)).To(Succeed())
332+
WaitClickHouseUpdatedAndReady(ctx, &cr, 3*time.Minute, false)
333+
334+
Expect(k8sClient.List(ctx, &pvcs, listOpts...)).To(Succeed())
335+
Expect(pvcs.Items).To(HaveLen(int(cr.Replicas())), "expected one PVC per replica")
336+
337+
for _, pvc := range pvcs.Items {
338+
Expect(pvc.Spec.Resources.Requests.Storage().Cmp(
339+
*cr.Spec.DataVolumeClaimSpec.Resources.Requests.Storage())).To(Equal(0),
340+
"actual: %v, spec: %v", pvc.Spec.Resources, cr.Spec.DataVolumeClaimSpec.Resources)
341+
}
342+
})
343+
257344
It("should correctly configure access", func(ctx context.Context) {
258345
var (
259346
password = fmt.Sprintf("test-password-%d", rand.Uint32()) //nolint:gosec

0 commit comments

Comments
 (0)