@@ -24,6 +24,7 @@ import (
24
24
25
25
"k8s.io/apimachinery/pkg/api/equality"
26
26
"k8s.io/apimachinery/pkg/util/validation/field"
27
+ "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
27
28
28
29
appsv1alpha1 "github.com/NVIDIA/k8s-nim-operator/api/apps/v1alpha1"
29
30
)
@@ -39,22 +40,22 @@ var (
39
40
var validQoSProfiles = []string {"latency" , "throughput" }
40
41
41
42
// validateNIMSourceConfiguration validates the NIMSource configuration in the NIMCache spec.
42
- func validateNIMSourceConfiguration (source * appsv1alpha1.NIMSource , fldPath * field.Path ) field.ErrorList {
43
- errList := field.ErrorList {}
43
+ func validateNIMSourceConfiguration (source * appsv1alpha1.NIMSource , fldPath * field.Path ) (admission.Warnings , field.ErrorList ) {
44
44
// Evalutate NGCSource if it is set. NemoDataStoreSource and HuggingFaceHubSource do not require any additional validation.
45
- errList = append ( errList , validateNGCSource (source .NGC , fldPath .Child ("ngc" )) ... )
46
- return errList
45
+ warnList , errList := validateNGCSource (source .NGC , fldPath .Child ("ngc" ))
46
+ return warnList , errList
47
47
}
48
48
49
49
// ValidateNGCSource checks the NGCSource configuration.
50
- func validateNGCSource (ngcSource * appsv1alpha1.NGCSource , fldPath * field.Path ) field.ErrorList {
51
- errList := field.ErrorList {}
52
-
50
+ func validateNGCSource (ngcSource * appsv1alpha1.NGCSource , fldPath * field.Path ) (admission.Warnings , field.ErrorList ) {
53
51
// Return early if NGCSource is nil
54
52
if ngcSource == nil {
55
- return nil
53
+ return nil , nil
56
54
}
57
55
56
+ // Evaluate NGCSource.Model fields
57
+ warnList , errList := validateModel (ngcSource .Model , fldPath .Child ("model" ))
58
+
58
59
// Ensure AuthSecret is a non-empty string
59
60
if ngcSource .AuthSecret == "" {
60
61
errList = append (errList , field .Required (fldPath .Child ("authSecret" ), "must be non-empty" ))
@@ -65,14 +66,12 @@ func validateNGCSource(ngcSource *appsv1alpha1.NGCSource, fldPath *field.Path) f
65
66
errList = append (errList , field .Required (fldPath .Child ("modelPuller" ), "must be non-empty" ))
66
67
}
67
68
68
- // Evaluate NGCSource.Model fields
69
- errList = append (errList , validateModel (ngcSource .Model , fldPath .Child ("model" ))... )
70
-
71
- return errList
69
+ return warnList , errList
72
70
}
73
71
74
- func validateModel (model * appsv1alpha1.ModelSpec , fldPath * field.Path ) field.ErrorList {
72
+ func validateModel (model * appsv1alpha1.ModelSpec , fldPath * field.Path ) (admission. Warnings , field.ErrorList ) {
75
73
errList := field.ErrorList {}
74
+ warnList := admission.Warnings {}
76
75
77
76
// If Model.Profiles is not empty, ensure all other Model fields are empty. If Model.Profiles contains "all", length must be 1
78
77
if len (model .Profiles ) > 0 {
@@ -112,7 +111,7 @@ func validateModel(model *appsv1alpha1.ModelSpec, fldPath *field.Path) field.Err
112
111
errList = append (errList , field .NotSupported (fldPath .Child ("qosProfile" ), model .QoSProfile , validQoSProfiles ))
113
112
}
114
113
115
- return errList
114
+ return warnList , errList
116
115
}
117
116
118
117
func isValidQoSProfile (profile string ) bool {
@@ -124,23 +123,19 @@ func isValidQoSProfile(profile string) bool {
124
123
return false
125
124
}
126
125
127
- func validateNIMCacheStorageConfiguration (storage * appsv1alpha1.NIMCacheStorage , fldPath * field.Path ) field.ErrorList {
128
- errList := field.ErrorList {}
129
-
126
+ func validateNIMCacheStorageConfiguration (storage * appsv1alpha1.NIMCacheStorage , fldPath * field.Path ) (admission.Warnings , field.ErrorList ) {
130
127
// Spec.Storage must not be empty
131
128
if reflect .DeepEqual (storage .PVC , appsv1alpha1.PersistentVolumeClaim {}) {
132
- errList = append (errList , field .Required (fldPath , "must not be empty" ))
133
129
// Don't validate PVC configuration if storage is completely empty
134
- return errList
130
+ return admission. Warnings {}, field. ErrorList { field . Required ( fldPath , "must not be empty" )}
135
131
}
136
132
137
- errList = append (errList , validatePVCConfiguration (& storage .PVC , fldPath .Child ("pvc" ))... )
138
-
139
- return errList
133
+ return validatePVCConfiguration (& storage .PVC , fldPath .Child ("pvc" ))
140
134
}
141
135
142
- func validatePVCConfiguration (pvc * appsv1alpha1.PersistentVolumeClaim , fldPath * field.Path ) field.ErrorList {
136
+ func validatePVCConfiguration (pvc * appsv1alpha1.PersistentVolumeClaim , fldPath * field.Path ) (admission. Warnings , field.ErrorList ) {
143
137
errList := field.ErrorList {}
138
+ warnList := admission.Warnings {}
144
139
145
140
// If PVC.Create is False, PVC.Name cannot be empty
146
141
if (pvc .Create == nil || ! * pvc .Create ) && pvc .Name == "" {
@@ -162,13 +157,14 @@ func validatePVCConfiguration(pvc *appsv1alpha1.PersistentVolumeClaim, fldPath *
162
157
}
163
158
}
164
159
165
- return errList
160
+ return warnList , errList
166
161
}
167
162
168
- func validateProxyConfiguration (proxy * appsv1alpha1.ProxySpec , fldPath * field.Path ) field.ErrorList {
163
+ func validateProxyConfiguration (proxy * appsv1alpha1.ProxySpec , fldPath * field.Path ) (admission.Warnings , field.ErrorList ) {
164
+ warnList := admission.Warnings {}
169
165
errList := field.ErrorList {}
170
166
if proxy == nil {
171
- return nil
167
+ return nil , nil
172
168
}
173
169
174
170
// If Proxy is not nil, ensure Proxy.NoProxy is a valid proxy string
@@ -194,7 +190,7 @@ func validateProxyConfiguration(proxy *appsv1alpha1.ProxySpec, fldPath *field.Pa
194
190
errList = append (errList , field .Invalid (fldPath .Child ("httpProxy" ), proxy .HttpProxy , "must start with http:// or https://" ))
195
191
}
196
192
197
- return errList
193
+ return warnList , errList
198
194
}
199
195
200
196
// validateNIMCacheSpec aggregates all structural validation rules for a NIMCache
@@ -209,23 +205,27 @@ func validateProxyConfiguration(proxy *appsv1alpha1.ProxySpec, fldPath *field.Pa
209
205
// field.NewPath("nimcache").Child("spec")).
210
206
//
211
207
// Returns a field.ErrorList with any validation errors encountered.
212
- func validateNIMCacheSpec (spec * appsv1alpha1.NIMCacheSpec , fldPath * field.Path ) field.ErrorList {
213
- errList := field. ErrorList {}
208
+ func validateNIMCacheSpec (spec * appsv1alpha1.NIMCacheSpec , fldPath * field.Path ) (admission. Warnings , field.ErrorList ) {
209
+ warningList , errList := validateNIMSourceConfiguration ( & spec . Source , fldPath . Child ( "source" ))
214
210
215
211
// Delegate to existing granular validators.
216
- errList = append (errList , validateNIMSourceConfiguration (& spec .Source , fldPath .Child ("source" ))... )
217
- errList = append (errList , validateNIMCacheStorageConfiguration (& spec .Storage , fldPath .Child ("storage" ))... )
218
- errList = append (errList , validateProxyConfiguration (spec .Proxy , fldPath .Child ("proxy" ))... )
212
+ wList , eList := validateNIMCacheStorageConfiguration (& spec .Storage , fldPath .Child ("storage" ))
213
+ warningList = append (warningList , wList ... )
214
+ errList = append (errList , eList ... )
215
+
216
+ wList , eList = validateProxyConfiguration (spec .Proxy , fldPath .Child ("proxy" ))
217
+ warningList = append (warningList , wList ... )
218
+ errList = append (errList , eList ... )
219
219
220
- return errList
220
+ return warningList , errList
221
221
}
222
222
223
- func validateImmutableNIMCacheSpec (oldNIMCache , newNIMCache * appsv1alpha1.NIMCache , fldPath * field.Path ) field.ErrorList {
223
+ func validateImmutableNIMCacheSpec (oldNIMCache , newNIMCache * appsv1alpha1.NIMCache , fldPath * field.Path ) (admission. Warnings , field.ErrorList ) {
224
224
errList := field.ErrorList {}
225
-
225
+ warningList := admission. Warnings {}
226
226
if ! equality .Semantic .DeepEqual (oldNIMCache .Spec , newNIMCache .Spec ) {
227
227
errList = append (errList , field .Forbidden (fldPath .Child ("spec" ), "is immutable once the object is created" ))
228
228
}
229
229
230
- return errList
230
+ return warningList , errList
231
231
}
0 commit comments