Skip to content

Commit a24dad3

Browse files
committed
fix: do not allow scaling down controlplane to zero
Doing that is pretty pointless as it's going to destroy a cluster. Instead of doing that cluster should be deleted and recreated. And with the new approach without init nodes scaling cluster back up won't be able to succeed as bootstrap is done only a single time. Still allowing user to set replicas to zero, but block scaling in the controller with error messages when there's only a single node remaining. Signed-off-by: Artem Chernyshev <[email protected]>
1 parent 8a73e6a commit a24dad3

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed

controllers/taloscontrolplane_controller.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,14 @@ func (r *TalosControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.Re
273273
"Scaling down control plane to %d replicas (actual %d)",
274274
desiredReplicas, numMachines)
275275

276+
if numMachines == 1 {
277+
conditions.MarkFalse(tcp, controlplanev1.ResizedCondition, controlplanev1.ScalingDownReason, clusterv1.ConditionSeverityError,
278+
"Cannot scale down control plane nodes to 0",
279+
desiredReplicas, numMachines)
280+
281+
return res, nil
282+
}
283+
276284
if err := r.ensureNodesBooted(ctx, cluster, ownedMachines); err != nil {
277285
logger.Info("Waiting for all nodes to finish boot sequence", "error", err)
278286

internal/integration/integration_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,14 @@ import (
2323
"gopkg.in/yaml.v3"
2424
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2525
"k8s.io/apimachinery/pkg/labels"
26+
"k8s.io/apimachinery/pkg/runtime"
2627
"k8s.io/apimachinery/pkg/runtime/schema"
2728
clusterv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
2829
logf "sigs.k8s.io/cluster-api/cmd/clusterctl/log"
30+
"sigs.k8s.io/cluster-api/util/conditions"
2931
runtimeclient "sigs.k8s.io/controller-runtime/pkg/client"
32+
33+
controlplanev1 "github.com/talos-systems/cluster-api-control-plane-provider-talos/api/v1alpha3"
3034
)
3135

3236
var (
@@ -286,6 +290,43 @@ func (suite *IntegrationSuite) Test04ScaleControlPlaneNoWait() {
286290
suite.Require().NoError(err)
287291
}
288292

293+
// Test05ScaleControlPlaneToZero try to scale control plane to zero and check that it never does that.
294+
func (suite *IntegrationSuite) Test05ScaleControlPlaneToZero() {
295+
ctx, cancel := context.WithCancel(suite.ctx)
296+
297+
go func() {
298+
time.Sleep(time.Second * 5)
299+
300+
cancel()
301+
}()
302+
303+
suite.cluster.Scale(ctx, 0, capi.ControlPlaneNodes) //nolint:errcheck
304+
305+
err := retry.Constant(time.Second*20, retry.WithUnits(time.Second)).Retry(func() error {
306+
controlplane, err := suite.cluster.ControlPlanes(suite.ctx)
307+
if err != nil {
308+
return err
309+
}
310+
311+
var tcp controlplanev1.TalosControlPlane
312+
313+
err = runtime.DefaultUnstructuredConverter.
314+
FromUnstructured(controlplane.UnstructuredContent(), &tcp)
315+
if err != nil {
316+
return err
317+
}
318+
319+
if !conditions.Has(&tcp, controlplanev1.ResizedCondition) &&
320+
conditions.GetMessage(&tcp, controlplanev1.ResizedCondition) != "Cannot scale down control plane nodes to 0" {
321+
return retry.ExpectedErrorf("node resized conditions error status hasn't updated")
322+
}
323+
324+
return nil
325+
})
326+
327+
suite.Require().NoError(err)
328+
}
329+
289330
// TestIntegration runs integration tests.
290331
func TestIntegration(t *testing.T) {
291332
version := os.Getenv("WORKLOAD_TALOS_VERSION")

0 commit comments

Comments
 (0)