@@ -22,21 +22,17 @@ import (
2222 "fmt"
2323 "path/filepath"
2424 "regexp"
25- "strconv"
2625 "strings"
2726
2827 corev1 "k8s.io/api/core/v1"
2928 "k8s.io/apimachinery/pkg/util/validation"
3029
3130 "github.com/go-logr/logr"
32- configv1 "github.com/openshift/api/config/v1"
3331 kmmv1beta1 "github.com/rh-ecosystem-edge/kernel-module-management/api/v1beta1"
3432 "github.com/rh-ecosystem-edge/kernel-module-management/internal/constants"
33+ "github.com/rh-ecosystem-edge/kernel-module-management/internal/version"
3534 "k8s.io/apimachinery/pkg/runtime"
36- "k8s.io/apimachinery/pkg/runtime/schema"
37- "k8s.io/apimachinery/pkg/runtime/serializer"
3835 "k8s.io/apimachinery/pkg/util/sets"
39- "k8s.io/client-go/rest"
4036 ctrl "sigs.k8s.io/controller-runtime"
4137 "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
4238)
@@ -45,66 +41,15 @@ import (
4541// 63 (max label key length after slash) - len("version-schedule-plugin.") = 38
4642const maxCombinedLength = 38
4743
48- var ocpVersionRe = regexp .MustCompile (`^v?(\d+)\.(\d+)` )
49-
50- // OCPVersion holds the parsed major and minor version of an OpenShift cluster.
51- type OCPVersion struct {
52- Major int
53- Minor int
54- }
55-
5644type ModuleValidator struct {
5745 logger logr.Logger
58- ocpVersion * OCPVersion
46+ ocpVersion * version. OCPVersion
5947}
6048
61- func NewModuleValidator (logger logr.Logger , ocpVersion * OCPVersion ) * ModuleValidator {
49+ func NewModuleValidator (logger logr.Logger , ocpVersion * version. OCPVersion ) * ModuleValidator {
6250 return & ModuleValidator {logger : logger , ocpVersion : ocpVersion }
6351}
6452
65- // DiscoverOCPVersion queries the OpenShift ClusterVersion resource and returns the cluster version.
66- func DiscoverOCPVersion (cfg * rest.Config ) (OCPVersion , error ) {
67- ocpScheme := runtime .NewScheme ()
68- if err := configv1 .Install (ocpScheme ); err != nil {
69- return OCPVersion {}, fmt .Errorf ("failed to register OpenShift config scheme: %v" , err )
70- }
71-
72- cfgCopy := * cfg
73- cfgCopy .GroupVersion = & schema.GroupVersion {Group : "config.openshift.io" , Version : "v1" }
74- cfgCopy .APIPath = "/apis"
75- cfgCopy .NegotiatedSerializer = serializer .NewCodecFactory (ocpScheme )
76-
77- client , err := rest .RESTClientFor (& cfgCopy )
78- if err != nil {
79- return OCPVersion {}, fmt .Errorf ("failed to create REST client for OpenShift config API: %v" , err )
80- }
81-
82- cv := & configv1.ClusterVersion {}
83- if err = client .Get ().Resource ("clusterversions" ).Name ("version" ).Do (context .Background ()).Into (cv ); err != nil {
84- return OCPVersion {}, fmt .Errorf ("failed to get ClusterVersion: %v" , err )
85- }
86-
87- return parseOCPVersion (cv .Status .Desired .Version )
88- }
89-
90- // parseOCPVersion extracts the major and minor version from an OpenShift
91- // version string such as "4.21.0" or "4.21.0-rc.1".
92- func parseOCPVersion (version string ) (OCPVersion , error ) {
93- m := ocpVersionRe .FindStringSubmatch (version )
94- if m == nil {
95- return OCPVersion {}, fmt .Errorf ("cannot parse OpenShift version from %q" , version )
96- }
97- major , err := strconv .Atoi (m [1 ])
98- if err != nil {
99- return OCPVersion {}, fmt .Errorf ("cannot parse OpenShift major version from %q: %v" , version , err )
100- }
101- minor , err := strconv .Atoi (m [2 ])
102- if err != nil {
103- return OCPVersion {}, fmt .Errorf ("cannot parse OpenShift minor version from %q: %v" , version , err )
104- }
105- return OCPVersion {Major : major , Minor : minor }, nil
106- }
107-
10853func (m * ModuleValidator ) SetupWebhookWithManager (mgr ctrl.Manager ) error {
10954 // controller-runtime will set the path to `validate-<group>-<version>-<resource> so we
11055 // need to make sure it is set correctly in the +kubebuilder annotation below.
@@ -157,7 +102,7 @@ func (m *ModuleValidator) ValidateDelete(ctx context.Context, obj runtime.Object
157102 return nil , NotImplemented
158103}
159104
160- func validateModule (mod * kmmv1beta1.Module , ocpVersion * OCPVersion ) (admission.Warnings , error ) {
105+ func validateModule (mod * kmmv1beta1.Module , ocpVersion * version. OCPVersion ) (admission.Warnings , error ) {
161106 nameLength := len (mod .Name + mod .Namespace )
162107
163108 if nameLength > maxCombinedLength {
@@ -204,18 +149,18 @@ func validateModule(mod *kmmv1beta1.Module, ocpVersion *OCPVersion) (admission.W
204149 return nil , validateFilesToSign (mod .Spec .ModuleLoader .Container )
205150}
206151
207- func validateDRA (mod * kmmv1beta1.Module , ocpVersion * OCPVersion ) error {
152+ func validateDRA (mod * kmmv1beta1.Module , ocpVersion * version. OCPVersion ) error {
208153 if mod .Spec .DRA == nil {
209154 return nil
210155 }
211156
212- if ocpVersion != nil {
213- if ocpVersion . Major < constants . MinOCPMajorForDRA || ( ocpVersion . Major == constants . MinOCPMajorForDRA && ocpVersion . Minor < constants . MinOCPMinorForDRA ) {
214- return fmt . Errorf (
215- "spec.dra requires OpenShift %d.%d or later; current cluster version is %d.%d" ,
216- constants . MinOCPMajorForDRA , constants . MinOCPMinorForDRA , ocpVersion . Major , ocpVersion . Minor ,
217- )
218- }
157+ // Skip version gating when ocpVersion is nil (e.g. hub webhook validating
158+ // a ManagedClusterModule — the spoke's own webhook will enforce its version).
159+ if ocpVersion != nil && ! ocpVersion . AtLeast ( constants . MinOCPMajorForDRA , constants . MinOCPMinorForDRA ) {
160+ return fmt . Errorf (
161+ "spec.dra requires OpenShift %d.%d or later; current cluster version is %d.%d" ,
162+ constants . MinOCPMajorForDRA , constants . MinOCPMinorForDRA , ocpVersion . Major , ocpVersion . Minor ,
163+ )
219164 }
220165 driverName := mod .Spec .DRA .DriverName
221166 if driverName == "" {
@@ -261,7 +206,7 @@ func validateHostPathVolumes(fieldPath string, volumes []corev1.Volume) error {
261206 for i , vol := range volumes {
262207 if vol .HostPath != nil && ! isAllowedHostPath (vol .HostPath .Path ) {
263208 return fmt .Errorf (
264- "%s.volumes[%d]: hostPath %q is not allowed; only /dev, /sys, /var and /opt paths are permitted" ,
209+ "%s.volumes[%d]: hostPath %q is not allowed; only /dev, /sys, /var, /opt and /run paths are permitted" ,
265210 fieldPath , i , vol .HostPath .Path ,
266211 )
267212 }
0 commit comments