Skip to content

Commit 0ebd56c

Browse files
TomerNewmank8s-ci-robot
authored andcommitted
Fix hub webhook DRA version gating to skip cluster version check
The ManagedClusterModule webhook on the hub was incorrectly using the hub cluster's Kubernetes version to gate DRA usage. Since the hub cannot know the target managed cluster's version, this could wrongly reject valid specs or accept invalid ones. Fix by passing an empty KubeVersion to the hub validator and skipping the version gate in validateDRA when the version is zero. Field format validation (driverName, deviceClasses) still runs unconditionally. The spoke cluster's own Module webhook enforces the version requirement. Also moves DiscoverKubeVersion inside the enableModule branch so that webhook modes that don't need cluster version (namespace, preflight) no longer require ClusterVersion API access.
1 parent 0feeabe commit 0ebd56c

4 files changed

Lines changed: 34 additions & 29 deletions

File tree

cmd/webhook-server/main.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -82,25 +82,25 @@ func main() {
8282
cmd.FatalError(setupLogger, err, "unable to create manager")
8383
}
8484

85-
kubeVersion, err := webhook.DiscoverKubeVersion(restCfg)
86-
if err != nil {
87-
cmd.FatalError(setupLogger, err, "unable to discover Kubernetes version")
88-
}
89-
90-
setupLogger.Info("Detected Kubernetes version", "major", kubeVersion.Major, "minor", kubeVersion.Minor)
91-
9285
if enableModule {
9386
logger.Info("Enabling Module webhook")
9487

95-
if err = webhook.NewModuleValidator(logger, kubeVersion).SetupWebhookWithManager(mgr); err != nil {
88+
kubeVersion, err := webhook.DiscoverKubeVersion(restCfg)
89+
if err != nil {
90+
cmd.FatalError(setupLogger, err, "unable to discover Kubernetes version")
91+
}
92+
93+
setupLogger.Info("Detected Kubernetes version", "major", kubeVersion.Major, "minor", kubeVersion.Minor)
94+
95+
if err = webhook.NewModuleValidator(logger, &kubeVersion).SetupWebhookWithManager(mgr); err != nil {
9696
cmd.FatalError(setupLogger, err, "unable to create webhook", "webhook", "ModuleValidator")
9797
}
9898
}
9999

100100
if enableManagedClusterModule {
101101
logger.Info("Enabling ManagedClusterModule webhook")
102102

103-
if err = hub.NewManagedClusterModuleValidator(logger, kubeVersion).SetupWebhookWithManager(mgr); err != nil {
103+
if err = hub.NewManagedClusterModuleValidator(logger, nil).SetupWebhookWithManager(mgr); err != nil {
104104
cmd.FatalError(setupLogger, err, "unable to create webhook", "webhook", "ManagedClusterModuleValidator")
105105
}
106106
}

internal/webhook/hub/managedclustermodule_webhook.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ type ManagedClusterModuleValidator struct {
3434
m admission.CustomValidator
3535
}
3636

37-
func NewManagedClusterModuleValidator(logger logr.Logger, kubeVersion webhook.KubeVersion) *ManagedClusterModuleValidator {
37+
func NewManagedClusterModuleValidator(logger logr.Logger, kubeVersion *webhook.KubeVersion) *ManagedClusterModuleValidator {
3838
return &ManagedClusterModuleValidator{
3939
logger: logger,
4040
m: webhook.NewModuleValidator(logger, kubeVersion),

internal/webhook/module.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,10 @@ type KubeVersion struct {
5151

5252
type ModuleValidator struct {
5353
logger logr.Logger
54-
kubeVersion KubeVersion
54+
kubeVersion *KubeVersion
5555
}
5656

57-
func NewModuleValidator(logger logr.Logger, kubeVersion KubeVersion) *ModuleValidator {
57+
func NewModuleValidator(logger logr.Logger, kubeVersion *KubeVersion) *ModuleValidator {
5858
return &ModuleValidator{logger: logger, kubeVersion: kubeVersion}
5959
}
6060

@@ -143,7 +143,7 @@ func (m *ModuleValidator) ValidateDelete(ctx context.Context, obj runtime.Object
143143
return nil, NotImplemented
144144
}
145145

146-
func validateModule(mod *kmmv1beta1.Module, kubeVersion KubeVersion) (admission.Warnings, error) {
146+
func validateModule(mod *kmmv1beta1.Module, kubeVersion *KubeVersion) (admission.Warnings, error) {
147147
nameLength := len(mod.Name + mod.Namespace)
148148

149149
if nameLength > maxCombinedLength {
@@ -178,16 +178,20 @@ func validateModule(mod *kmmv1beta1.Module, kubeVersion KubeVersion) (admission.
178178
return nil, validateFilesToSign(mod.Spec.ModuleLoader.Container)
179179
}
180180

181-
func validateDRA(mod *kmmv1beta1.Module, kubeVersion KubeVersion) error {
181+
func validateDRA(mod *kmmv1beta1.Module, kubeVersion *KubeVersion) error {
182182
if mod.Spec.DRA == nil {
183183
return nil
184184
}
185185

186-
if kubeVersion.Major < constants.MinKubeMajorForDRA || (kubeVersion.Major == constants.MinKubeMajorForDRA && kubeVersion.Minor < constants.MinKubeMinorForDRA) {
187-
return fmt.Errorf(
188-
"spec.dra requires Kubernetes %d.%d or later; current cluster version is %d.%d",
189-
constants.MinKubeMajorForDRA, constants.MinKubeMinorForDRA, kubeVersion.Major, kubeVersion.Minor,
190-
)
186+
// Skip version gating when kubeVersion is nil (e.g. hub webhook validating
187+
// a ManagedClusterModule — the spoke's own webhook will enforce its version).
188+
if kubeVersion != nil {
189+
if kubeVersion.Major < constants.MinKubeMajorForDRA || (kubeVersion.Major == constants.MinKubeMajorForDRA && kubeVersion.Minor < constants.MinKubeMinorForDRA) {
190+
return fmt.Errorf(
191+
"spec.dra requires Kubernetes %d.%d or later; current cluster version is %d.%d",
192+
constants.MinKubeMajorForDRA, constants.MinKubeMinorForDRA, kubeVersion.Major, kubeVersion.Minor,
193+
)
194+
}
191195
}
192196

193197
driverName := mod.Spec.DRA.DriverName

internal/webhook/module_test.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ var (
5353
},
5454
}
5555

56-
moduleWebhook = NewModuleValidator(GinkgoLogr, KubeVersion{Major: 1, Minor: 34})
56+
moduleWebhook = NewModuleValidator(GinkgoLogr, &KubeVersion{Major: 1, Minor: 34})
5757
)
5858

5959
var _ = Describe("maxCombinedLength", func() {
@@ -411,7 +411,7 @@ var _ = Describe("validateModule", func() {
411411
mod.Name = name
412412
mod.Namespace = ns
413413

414-
_, err := validateModule(&mod, KubeVersion{Major: 1, Minor: 34})
414+
_, err := validateModule(&mod, &KubeVersion{Major: 1, Minor: 34})
415415
exp := Expect(err)
416416

417417
if errExpected {
@@ -426,7 +426,7 @@ var _ = Describe("validateModule", func() {
426426
It("should pass when moduleLoader is not defined", func() {
427427
mod := validModule
428428
mod.Spec.ModuleLoader = nil
429-
_, err := validateModule(&mod, KubeVersion{Major: 1, Minor: 34})
429+
_, err := validateModule(&mod, &KubeVersion{Major: 1, Minor: 34})
430430
Expect(err).NotTo(HaveOccurred())
431431
})
432432
})
@@ -739,7 +739,7 @@ var _ = Describe("validateDRA", func() {
739739
}
740740
}
741741

742-
minValidKubeVersion := KubeVersion{Major: 1, Minor: 34}
742+
minValidKubeVersion := &KubeVersion{Major: 1, Minor: 34}
743743

744744
It("should be a no-op when spec.dra is nil", func() {
745745
mod := &kmmv1beta1.Module{}
@@ -748,7 +748,7 @@ var _ = Describe("validateDRA", func() {
748748

749749
DescribeTable(
750750
"Kubernetes version gate",
751-
func(kv KubeVersion, shouldFail bool) {
751+
func(kv *KubeVersion, shouldFail bool) {
752752
mod := &kmmv1beta1.Module{
753753
Spec: kmmv1beta1.ModuleSpec{
754754
DRA: validDRASpec(),
@@ -761,11 +761,12 @@ var _ = Describe("validateDRA", func() {
761761
Expect(err).NotTo(HaveOccurred())
762762
}
763763
},
764-
Entry("k8s 1.33 rejects", KubeVersion{Major: 1, Minor: 33}, true),
765-
Entry("k8s 1.34 accepts", KubeVersion{Major: 1, Minor: 34}, false),
766-
Entry("k8s 1.35 accepts", KubeVersion{Major: 1, Minor: 35}, false),
767-
Entry("k8s 2.0 accepts (future major)", KubeVersion{Major: 2, Minor: 0}, false),
768-
Entry("k8s 0.99 rejects (old major)", KubeVersion{Major: 0, Minor: 99}, true),
764+
Entry("k8s 1.33 rejects", &KubeVersion{Major: 1, Minor: 33}, true),
765+
Entry("k8s 1.34 accepts", &KubeVersion{Major: 1, Minor: 34}, false),
766+
Entry("k8s 1.35 accepts", &KubeVersion{Major: 1, Minor: 35}, false),
767+
Entry("k8s 2.0 accepts (future major)", &KubeVersion{Major: 2, Minor: 0}, false),
768+
Entry("k8s 0.99 rejects (old major)", &KubeVersion{Major: 0, Minor: 99}, true),
769+
Entry("nil version skips gate (hub webhook)", nil, false),
769770
)
770771

771772
It("should reject empty driverName", func() {

0 commit comments

Comments
 (0)