Skip to content

Commit 5b01c5a

Browse files
fix(preflight): sanitize kubernetes version for image name preflight check (#1198)
kubernetes version can include extraneous values other than major.minor.patch. e.g. "1.33.1+fips.0". While our image builder conventions include kubernetes major, minor, and patch versions in the image name, they don't include extraneous info as part of kubernetes version. To ensure our check only matches the right parts of the image name, we sanitize the kubernetes version before doing a substring match.
1 parent 8a2f7d7 commit 5b01c5a

File tree

2 files changed

+67
-1
lines changed

2 files changed

+67
-1
lines changed

pkg/webhook/preflight/nutanix/imagekubernetesversioncheck.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"fmt"
99
"strings"
1010

11+
"github.com/blang/semver/v4"
1112
vmmv4 "github.com/nutanix/ntnx-api-golang-clients/vmm-go-client/v4/models/vmm/v4/content"
1213

1314
carenv1 "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/v1alpha1"
@@ -81,7 +82,15 @@ func (c *imageKubernetesVersionCheck) checkKubernetesVersion(image *vmmv4.Image)
8182
return fmt.Errorf("VM image name is empty")
8283
}
8384

84-
if !strings.Contains(imageName, c.clusterK8sVersion) {
85+
parsedVersion, err := semver.Parse(c.clusterK8sVersion)
86+
if err != nil {
87+
return fmt.Errorf("failed to parse kubernetes version '%s': %v", c.clusterK8sVersion, err)
88+
}
89+
90+
// For example, "1.33.1+fips.0" becomes "1.33.1".
91+
k8sVersion := parsedVersion.FinalizeVersion()
92+
93+
if !strings.Contains(imageName, k8sVersion) {
8594
return fmt.Errorf(
8695
"cluster kubernetes version '%s' is not part of image name '%s'",
8796
c.clusterK8sVersion,

pkg/webhook/preflight/nutanix/imagekubernetesversioncheck_test.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,31 @@ func TestVMImageCheckWithKubernetesVersion(t *testing.T) {
8585
},
8686
},
8787
},
88+
{
89+
name: "kubernetes version with build metadata matches",
90+
nclient: &mocknclient{
91+
getImageByIdFunc: func(uuid *string) (*vmmv4.GetImageApiResponse, error) {
92+
resp := &vmmv4.GetImageApiResponse{}
93+
err := resp.SetData(vmmv4.Image{
94+
ObjectType_: ptr.To("vmm.v4.content.Image"),
95+
ExtId: ptr.To("test-uuid"),
96+
Name: ptr.To("kubedistro-rhel-8.10-release-fips-1.33.1-20250704023459"),
97+
})
98+
require.NoError(t, err)
99+
return resp, nil
100+
},
101+
},
102+
machineDetails: &carenv1.NutanixMachineDetails{
103+
Image: &capxv1.NutanixResourceIdentifier{
104+
Type: capxv1.NutanixIdentifierUUID,
105+
UUID: ptr.To("test-uuid"),
106+
},
107+
},
108+
clusterK8sVersion: "1.33.1+fips.0",
109+
want: preflight.CheckResult{
110+
Allowed: true,
111+
},
112+
},
88113
{
89114
name: "custom image name - extraction fails",
90115
nclient: &mocknclient{
@@ -117,6 +142,38 @@ func TestVMImageCheckWithKubernetesVersion(t *testing.T) {
117142
},
118143
},
119144
},
145+
{
146+
name: "invalid kubernetes version",
147+
nclient: &mocknclient{
148+
getImageByIdFunc: func(uuid *string) (*vmmv4.GetImageApiResponse, error) {
149+
resp := &vmmv4.GetImageApiResponse{}
150+
err := resp.SetData(vmmv4.Image{
151+
ObjectType_: ptr.To("vmm.v4.content.Image"),
152+
ExtId: ptr.To("test-uuid"),
153+
Name: ptr.To("kubedistro-rhel-8.10-release-fips-1.33.1-20250704023459"),
154+
})
155+
require.NoError(t, err)
156+
return resp, nil
157+
},
158+
},
159+
machineDetails: &carenv1.NutanixMachineDetails{
160+
Image: &capxv1.NutanixResourceIdentifier{
161+
Type: capxv1.NutanixIdentifierUUID,
162+
UUID: ptr.To("test-uuid"),
163+
},
164+
},
165+
clusterK8sVersion: "invalid.version",
166+
want: preflight.CheckResult{
167+
Allowed: false,
168+
InternalError: false,
169+
Causes: []preflight.Cause{
170+
{
171+
Message: "failed to parse kubernetes version 'invalid.version': No Major.Minor.Patch elements found",
172+
Field: "test-field",
173+
},
174+
},
175+
},
176+
},
120177
{
121178
name: "empty image name",
122179
nclient: &mocknclient{

0 commit comments

Comments
 (0)