Skip to content

Commit 7bd7223

Browse files
authored
Merge pull request #704 from anmazzotti/forbid_0_control_plane_replicas
Forbid 0 RKE2ControlPlane replicas
2 parents f40d0a6 + 80eb2ec commit 7bd7223

File tree

2 files changed

+103
-0
lines changed

2 files changed

+103
-0
lines changed

controlplane/api/v1beta1/rke2controlplane_webhook.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ func (rv *RKE2ControlPlaneCustomValidator) ValidateCreate(_ context.Context, obj
139139
allErrs = append(allErrs, rcp.validateCNI()...)
140140
allErrs = append(allErrs, rcp.validateRegistrationMethod()...)
141141
allErrs = append(allErrs, rcp.validateMachineTemplate()...)
142+
allErrs = append(allErrs, rcp.validateSpec()...)
142143

143144
if len(allErrs) == 0 {
144145
return nil, nil
@@ -166,6 +167,7 @@ func (rv *RKE2ControlPlaneCustomValidator) ValidateUpdate(_ context.Context, old
166167
allErrs = append(allErrs, bootstrapv1.ValidateRKE2ConfigSpec(newControlplane.Name, &newControlplane.Spec.RKE2ConfigSpec)...)
167168
allErrs = append(allErrs, newControlplane.validateCNI()...)
168169
allErrs = append(allErrs, newControlplane.validateMachineTemplate()...)
170+
allErrs = append(allErrs, newControlplane.validateSpec()...)
169171

170172
oldSet := oldControlplane.Spec.RegistrationMethod != ""
171173
if oldSet && newControlplane.Spec.RegistrationMethod != oldControlplane.Spec.RegistrationMethod {
@@ -279,3 +281,27 @@ func (r *RKE2ControlPlane) validateMachineTemplate() field.ErrorList {
279281

280282
return allErrs
281283
}
284+
285+
func (r *RKE2ControlPlane) validateSpec() field.ErrorList {
286+
var allErrs field.ErrorList
287+
288+
if r.Spec.Replicas == nil {
289+
allErrs = append(
290+
allErrs,
291+
field.Required(
292+
field.NewPath("spec", "replicas"),
293+
"is required",
294+
),
295+
)
296+
} else if *r.Spec.Replicas <= 0 {
297+
allErrs = append(
298+
allErrs,
299+
field.Forbidden(
300+
field.NewPath("spec", "replicas"),
301+
"cannot be less than or equal to 0",
302+
),
303+
)
304+
}
305+
306+
return allErrs
307+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
Copyright 2025 SUSE LLC.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package v1beta1
18+
19+
import (
20+
"context"
21+
22+
. "github.com/onsi/ginkgo/v2"
23+
. "github.com/onsi/gomega"
24+
v1 "k8s.io/api/core/v1"
25+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26+
"k8s.io/utils/ptr"
27+
)
28+
29+
var _ = Describe("RKE2ControlPlane webhook", func() {
30+
var (
31+
oldRcp *RKE2ControlPlane
32+
rcp *RKE2ControlPlane
33+
defaulter = &RKE2ControlPlaneCustomDefaulter{}
34+
validator = &RKE2ControlPlaneCustomValidator{}
35+
)
36+
BeforeEach(func() {
37+
rcp = &RKE2ControlPlane{
38+
ObjectMeta: metav1.ObjectMeta{
39+
Name: "test-control-plane",
40+
Namespace: "test",
41+
},
42+
Spec: RKE2ControlPlaneSpec{
43+
MachineTemplate: RKE2ControlPlaneMachineTemplate{
44+
InfrastructureRef: v1.ObjectReference{
45+
Name: "foo",
46+
Namespace: "bar",
47+
},
48+
},
49+
},
50+
}
51+
oldRcp = rcp.DeepCopy()
52+
Expect(defaulter.Default(context.TODO(), rcp)).Should(Succeed())
53+
Expect(defaulter.Default(context.TODO(), oldRcp)).Should(Succeed())
54+
})
55+
It("Should not create RKE2ControlPlane with 0 replicas", func() {
56+
rcp.Spec.Replicas = nil
57+
_, err := validator.ValidateCreate(context.TODO(), rcp)
58+
Expect(err).Should(HaveOccurred())
59+
rcp.Spec.Replicas = ptr.To(int32(0))
60+
_, err = validator.ValidateCreate(context.TODO(), rcp)
61+
Expect(err).Should(HaveOccurred())
62+
rcp.Spec.Replicas = ptr.To(int32(1))
63+
_, err = validator.ValidateCreate(context.TODO(), rcp)
64+
Expect(err).ShouldNot(HaveOccurred())
65+
})
66+
It("Should not update RKE2ControlPlane with 0 replicas", func() {
67+
rcp.Spec.Replicas = nil
68+
_, err := validator.ValidateUpdate(context.TODO(), oldRcp, rcp)
69+
Expect(err).Should(HaveOccurred())
70+
rcp.Spec.Replicas = ptr.To(int32(0))
71+
_, err = validator.ValidateUpdate(context.TODO(), oldRcp, rcp)
72+
Expect(err).Should(HaveOccurred())
73+
rcp.Spec.Replicas = ptr.To(int32(1))
74+
_, err = validator.ValidateUpdate(context.TODO(), oldRcp, rcp)
75+
Expect(err).ShouldNot(HaveOccurred())
76+
})
77+
})

0 commit comments

Comments
 (0)