Skip to content

Commit af2feb1

Browse files
authored
Merge pull request #5406 from spectrocloud/machineset-version
🐛 normalize MachineSet version validation
2 parents 0caa40d + 929728c commit af2feb1

File tree

2 files changed

+80
-1
lines changed

2 files changed

+80
-1
lines changed

api/v1beta1/machineset_webhook.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@ package v1beta1
1818

1919
import (
2020
"fmt"
21+
"strings"
2122

2223
apierrors "k8s.io/apimachinery/pkg/api/errors"
2324
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2425
"k8s.io/apimachinery/pkg/labels"
2526
runtime "k8s.io/apimachinery/pkg/runtime"
2627
"k8s.io/apimachinery/pkg/util/validation/field"
28+
"sigs.k8s.io/cluster-api/util/version"
2729
ctrl "sigs.k8s.io/controller-runtime"
2830
"sigs.k8s.io/controller-runtime/pkg/webhook"
2931
)
@@ -64,6 +66,11 @@ func (m *MachineSet) Default() {
6466
m.Spec.Selector.MatchLabels[MachineSetLabelName] = m.Name
6567
m.Spec.Template.Labels[MachineSetLabelName] = m.Name
6668
}
69+
70+
if m.Spec.Template.Spec.Version != nil && !strings.HasPrefix(*m.Spec.Template.Spec.Version, "v") {
71+
normalizedVersion := "v" + *m.Spec.Template.Spec.Version
72+
m.Spec.Template.Spec.Version = &normalizedVersion
73+
}
6774
}
6875

6976
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type.
@@ -111,6 +118,12 @@ func (m *MachineSet) validate(old *MachineSet) error {
111118
)
112119
}
113120

121+
if m.Spec.Template.Spec.Version != nil {
122+
if !version.KubeSemver.MatchString(*m.Spec.Template.Spec.Version) {
123+
allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "template", "spec", "version"), *m.Spec.Template.Spec.Version, "must be a valid semantic version"))
124+
}
125+
}
126+
114127
if len(allErrs) == 0 {
115128
return nil
116129
}

api/v1beta1/machineset_webhook_test.go

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ import (
2020
"testing"
2121

2222
. "github.com/onsi/gomega"
23-
2423
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24+
"k8s.io/utils/pointer"
2525
utildefaulting "sigs.k8s.io/cluster-api/util/defaulting"
2626
)
2727

@@ -31,6 +31,13 @@ func TestMachineSetDefault(t *testing.T) {
3131
ObjectMeta: metav1.ObjectMeta{
3232
Name: "test-ms",
3333
},
34+
Spec: MachineSetSpec{
35+
Template: MachineTemplateSpec{
36+
Spec: MachineSpec{
37+
Version: pointer.String("1.19.10"),
38+
},
39+
},
40+
},
3441
}
3542
t.Run("for MachineSet", utildefaulting.DefaultValidateTest(ms))
3643
ms.Default()
@@ -39,6 +46,7 @@ func TestMachineSetDefault(t *testing.T) {
3946
g.Expect(ms.Spec.DeletePolicy).To(Equal(string(RandomMachineSetDeletePolicy)))
4047
g.Expect(ms.Spec.Selector.MatchLabels).To(HaveKeyWithValue(MachineSetLabelName, "test-ms"))
4148
g.Expect(ms.Spec.Template.Labels).To(HaveKeyWithValue(MachineSetLabelName, "test-ms"))
49+
g.Expect(*ms.Spec.Template.Spec.Version).To(Equal("v1.19.10"))
4250
}
4351

4452
func TestMachineSetLabelSelectorMatchValidation(t *testing.T) {
@@ -151,3 +159,61 @@ func TestMachineSetClusterNameImmutable(t *testing.T) {
151159
})
152160
}
153161
}
162+
163+
func TestMachineSetVersionValidation(t *testing.T) {
164+
tests := []struct {
165+
name string
166+
version string
167+
expectErr bool
168+
}{
169+
{
170+
name: "should succeed when given a valid semantic version with prepended 'v'",
171+
version: "v1.19.2",
172+
expectErr: false,
173+
},
174+
{
175+
name: "should return error when given a valid semantic version without 'v'",
176+
version: "1.19.2",
177+
expectErr: true,
178+
},
179+
{
180+
name: "should return error when given an invalid semantic version",
181+
version: "1",
182+
expectErr: true,
183+
},
184+
{
185+
name: "should return error when given an invalid semantic version",
186+
version: "v1",
187+
expectErr: true,
188+
},
189+
{
190+
name: "should return error when given an invalid semantic version",
191+
version: "wrong_version",
192+
expectErr: true,
193+
},
194+
}
195+
196+
for _, tt := range tests {
197+
t.Run(tt.name, func(t *testing.T) {
198+
g := NewWithT(t)
199+
200+
md := &MachineSet{
201+
Spec: MachineSetSpec{
202+
Template: MachineTemplateSpec{
203+
Spec: MachineSpec{
204+
Version: pointer.String(tt.version),
205+
},
206+
},
207+
},
208+
}
209+
210+
if tt.expectErr {
211+
g.Expect(md.ValidateCreate()).NotTo(Succeed())
212+
g.Expect(md.ValidateUpdate(md)).NotTo(Succeed())
213+
} else {
214+
g.Expect(md.ValidateCreate()).To(Succeed())
215+
g.Expect(md.ValidateUpdate(md)).To(Succeed())
216+
}
217+
})
218+
}
219+
}

0 commit comments

Comments
 (0)