Skip to content

Commit e9d6c91

Browse files
committed
fix: support starting legacy stopped components with replicas=0
1 parent 30c8209 commit e9d6c91

4 files changed

Lines changed: 54 additions & 12 deletions

File tree

controllers/apps/component/transformer_component_validation.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ func validateCompReplicas(comp *appsv1.Component, compDef *appsv1.ComponentDefin
6666
}
6767

6868
replicas := comp.Spec.Replicas
69+
// Backward compatibility: older stop flows persisted stopped components as replicas=0.
70+
if replicas == 0 {
71+
return nil
72+
}
6973
if replicas >= replicasLimit.MinReplicas && replicas <= replicasLimit.MaxReplicas {
7074
return nil
7175
}

controllers/apps/component/transformer_component_workload.go

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,6 @@ import (
4343
intctrlutil "github.com/apecloud/kubeblocks/pkg/controllerutil"
4444
)
4545

46-
const (
47-
// TODO: use replicas status
48-
stopReplicasSnapshotKey = "apps.kubeblocks.io/stop-replicas-snapshot"
49-
)
50-
5146
// componentWorkloadTransformer handles component workload generation
5247
type componentWorkloadTransformer struct {
5348
client.Client
@@ -218,11 +213,15 @@ func (t *componentWorkloadTransformer) handleWorkloadStartNStop(transCtx *compon
218213
}
219214

220215
func isCompStopped(synthesizedComp *component.SynthesizedComponent) bool {
221-
return synthesizedComp.Stop != nil && *synthesizedComp.Stop
216+
if synthesizedComp.Stop != nil && *synthesizedComp.Stop {
217+
return true
218+
}
219+
// Backward compatibility: older stop flows persisted a stopped component as replicas=0.
220+
return synthesizedComp.Replicas == 0
222221
}
223222

224223
func isWorkloadStopped(runningITS *workloads.InstanceSet) bool {
225-
_, ok := runningITS.Annotations[stopReplicasSnapshotKey]
224+
_, ok := runningITS.Annotations[constant.StopReplicasSnapshotKey]
226225
return ok
227226
}
228227

@@ -241,7 +240,7 @@ func (t *componentWorkloadTransformer) stopWorkload(
241240
protoITS.Spec.PersistentVolumeClaimRetentionPolicy.WhenScaled = appsv1.RetainPersistentVolumeClaimRetentionPolicyType
242241

243242
// backup the replicas of runningITS
244-
snapshot, ok := runningITS.Annotations[stopReplicasSnapshotKey]
243+
snapshot, ok := runningITS.Annotations[constant.StopReplicasSnapshotKey]
245244
if !ok {
246245
replicas := map[string]int32{}
247246
if runningITS.Spec.Replicas != nil {
@@ -260,13 +259,13 @@ func (t *componentWorkloadTransformer) stopWorkload(
260259

261260
protoITS.Annotations[constant.KubeBlocksGenerationKey] = synthesizedComp.Generation
262261
}
263-
protoITS.Annotations[stopReplicasSnapshotKey] = snapshot
262+
protoITS.Annotations[constant.StopReplicasSnapshotKey] = snapshot
264263
return nil
265264
}
266265

267266
func (t *componentWorkloadTransformer) startWorkload(
268267
synthesizedComp *component.SynthesizedComponent, runningITS, protoITS *workloads.InstanceSet) error {
269-
snapshot := runningITS.Annotations[stopReplicasSnapshotKey]
268+
snapshot := runningITS.Annotations[constant.StopReplicasSnapshotKey]
270269
replicas := map[string]int32{}
271270
if err := json.Unmarshal([]byte(snapshot), &replicas); err != nil {
272271
return err
@@ -292,8 +291,8 @@ func (t *componentWorkloadTransformer) startWorkload(
292291
}
293292
}
294293

295-
delete(protoITS.Annotations, stopReplicasSnapshotKey)
296-
delete(runningITS.Annotations, stopReplicasSnapshotKey)
294+
delete(protoITS.Annotations, constant.StopReplicasSnapshotKey)
295+
delete(runningITS.Annotations, constant.StopReplicasSnapshotKey)
297296

298297
return nil
299298
}

pkg/constant/annotations.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ const (
4040
PVLastClaimPolicyAnnotationKey = "apps.kubeblocks.io/pv-last-claim-policy"
4141
LastRoleSnapshotVersionAnnotationKey = "apps.kubeblocks.io/last-role-snapshot-version"
4242
ComponentScaleInAnnotationKey = "apps.kubeblocks.io/component-scale-in" // ComponentScaleInAnnotationKey specifies whether the component is scaled in
43+
StopReplicasSnapshotKey = "apps.kubeblocks.io/stop-replicas-snapshot"
44+
SnapShotForStartAnnotationKey = "kubeblocks.io/snapshot-for-start"
4345

4446
// SkipPreTerminateAnnotationKey specifies to skip the pre-terminate action for a component.
4547
SkipPreTerminateAnnotationKey = "apps.kubeblocks.io/skip-pre-terminate"

pkg/operations/start.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
2020
package operations
2121

2222
import (
23+
"encoding/json"
2324
"time"
2425

2526
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2627
"sigs.k8s.io/controller-runtime/pkg/client"
2728

2829
appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
2930
opsv1alpha1 "github.com/apecloud/kubeblocks/apis/operations/v1alpha1"
31+
"github.com/apecloud/kubeblocks/pkg/constant"
3032
intctrlcomp "github.com/apecloud/kubeblocks/pkg/controller/component"
3133
intctrlutil "github.com/apecloud/kubeblocks/pkg/controllerutil"
3234
)
@@ -78,13 +80,20 @@ func (start StartOpsHandler) Action(reqCtx intctrlutil.RequestCtx, cli client.Cl
7880
}
7981
}
8082
compSpec.Stop = nil
83+
// Backward compatibility: older stop flows persisted stopped components as replicas=0.
84+
if compSpec.Replicas == 0 {
85+
restoreComponentReplicas(cluster, compSpec)
86+
}
8187
}
8288
for i, v := range cluster.Spec.ComponentSpecs {
8389
startComp(&cluster.Spec.ComponentSpecs[i], v.Name)
8490
}
8591
for i, v := range cluster.Spec.Shardings {
8692
startComp(&cluster.Spec.Shardings[i].Template, v.Name)
8793
}
94+
if cluster.Annotations != nil {
95+
delete(cluster.Annotations, constant.SnapShotForStartAnnotationKey)
96+
}
8897
return cli.Update(reqCtx.Ctx, cluster)
8998
}
9099

@@ -112,3 +121,31 @@ func (start StartOpsHandler) ReconcileAction(reqCtx intctrlutil.RequestCtx, cli
112121
func (start StartOpsHandler) SaveLastConfiguration(reqCtx intctrlutil.RequestCtx, cli client.Client, opsRes *OpsResource) error {
113122
return nil
114123
}
124+
125+
func restoreComponentReplicas(cluster *appsv1.Cluster, compSpec *appsv1.ClusterComponentSpec) {
126+
if cluster == nil || compSpec == nil {
127+
return
128+
}
129+
130+
snapshot := map[string]int32{}
131+
if cluster.Annotations != nil {
132+
if raw, ok := cluster.Annotations[constant.SnapShotForStartAnnotationKey]; ok && raw != "" {
133+
if err := json.Unmarshal([]byte(raw), &snapshot); err != nil {
134+
compSpec.Replicas = 1
135+
return
136+
}
137+
}
138+
}
139+
140+
if replicas, ok := snapshot[""]; ok && replicas > 0 {
141+
compSpec.Replicas = replicas
142+
} else {
143+
compSpec.Replicas = 1
144+
}
145+
146+
for i := range compSpec.Instances {
147+
if replicas, ok := snapshot[compSpec.Instances[i].Name]; ok {
148+
compSpec.Instances[i].Replicas = &replicas
149+
}
150+
}
151+
}

0 commit comments

Comments
 (0)