Skip to content

Commit 8a2be3d

Browse files
committed
Enable warning messages for nimservice and nimcache webhook
Signed-off-by: Sheng Lin <[email protected]>
1 parent 0bf59f5 commit 8a2be3d

6 files changed

+584
-517
lines changed

internal/webhook/apps/v1alpha1/nimcache_webhook.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,13 @@ func (v *NIMCacheCustomValidator) ValidateCreate(_ context.Context, obj runtime.
7070

7171
fldPath := field.NewPath("nimcache").Child("spec")
7272
// Perform structural validation via helper.
73-
errList := validateNIMCacheSpec(&nimcache.Spec, fldPath)
73+
warningList, errList := validateNIMCacheSpec(&nimcache.Spec, fldPath)
7474

7575
if len(errList) > 0 {
76-
return nil, errList.ToAggregate()
76+
return warningList, errList.ToAggregate()
7777
}
7878

79-
return nil, nil
79+
return warningList, nil
8080
}
8181

8282
// ValidateUpdate implements webhook.CustomValidator so a webhook will be registered for the type NIMCache.
@@ -91,7 +91,7 @@ func (v *NIMCacheCustomValidator) ValidateUpdate(_ context.Context, oldObj, newO
9191
fldPath := field.NewPath("nimcache").Child("spec")
9292

9393
// Begin by validating the new spec structurally.
94-
errList := validateNIMCacheSpec(&nimcache.Spec, fldPath)
94+
warningList, errList := validateNIMCacheSpec(&nimcache.Spec, fldPath)
9595

9696
oldNIMCache, ok := oldObj.(*appsv1alpha1.NIMCache)
9797
if !ok {
@@ -103,13 +103,15 @@ func (v *NIMCacheCustomValidator) ValidateUpdate(_ context.Context, oldObj, newO
103103
}
104104

105105
// Append immutability errors after structural checks.
106-
errList = append(errList, validateImmutableNIMCacheSpec(oldNIMCache, newNIMCache, field.NewPath("nimcache"))...)
106+
wList, eList := validateImmutableNIMCacheSpec(oldNIMCache, newNIMCache, field.NewPath("nimcache"))
107+
warningList = append(warningList, wList...)
108+
errList = append(errList, eList...)
107109

108110
if len(errList) > 0 {
109-
return nil, errList.ToAggregate()
111+
return warningList, errList.ToAggregate()
110112
}
111113

112-
return nil, nil
114+
return warningList, nil
113115
}
114116

115117
// ValidateDelete implements webhook.CustomValidator so a webhook will be registered for the type NIMCache.

internal/webhook/apps/v1alpha1/nimcache_webhook_validation_helper.go

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424

2525
"k8s.io/apimachinery/pkg/api/equality"
2626
"k8s.io/apimachinery/pkg/util/validation/field"
27+
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
2728

2829
appsv1alpha1 "github.com/NVIDIA/k8s-nim-operator/api/apps/v1alpha1"
2930
)
@@ -39,22 +40,22 @@ var (
3940
var validQoSProfiles = []string{"latency", "throughput"}
4041

4142
// 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) {
4444
// 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
4747
}
4848

4949
// 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) {
5351
// Return early if NGCSource is nil
5452
if ngcSource == nil {
55-
return nil
53+
return nil, nil
5654
}
5755

56+
// Evaluate NGCSource.Model fields
57+
warnList, errList := validateModel(ngcSource.Model, fldPath.Child("model"))
58+
5859
// Ensure AuthSecret is a non-empty string
5960
if ngcSource.AuthSecret == "" {
6061
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
6566
errList = append(errList, field.Required(fldPath.Child("modelPuller"), "must be non-empty"))
6667
}
6768

68-
// Evaluate NGCSource.Model fields
69-
errList = append(errList, validateModel(ngcSource.Model, fldPath.Child("model"))...)
70-
71-
return errList
69+
return warnList, errList
7270
}
7371

74-
func validateModel(model *appsv1alpha1.ModelSpec, fldPath *field.Path) field.ErrorList {
72+
func validateModel(model *appsv1alpha1.ModelSpec, fldPath *field.Path) (admission.Warnings, field.ErrorList) {
7573
errList := field.ErrorList{}
74+
warnList := admission.Warnings{}
7675

7776
// If Model.Profiles is not empty, ensure all other Model fields are empty. If Model.Profiles contains "all", length must be 1
7877
if len(model.Profiles) > 0 {
@@ -112,7 +111,7 @@ func validateModel(model *appsv1alpha1.ModelSpec, fldPath *field.Path) field.Err
112111
errList = append(errList, field.NotSupported(fldPath.Child("qosProfile"), model.QoSProfile, validQoSProfiles))
113112
}
114113

115-
return errList
114+
return warnList, errList
116115
}
117116

118117
func isValidQoSProfile(profile string) bool {
@@ -124,23 +123,19 @@ func isValidQoSProfile(profile string) bool {
124123
return false
125124
}
126125

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) {
130127
// Spec.Storage must not be empty
131128
if reflect.DeepEqual(storage.PVC, appsv1alpha1.PersistentVolumeClaim{}) {
132-
errList = append(errList, field.Required(fldPath, "must not be empty"))
133129
// 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")}
135131
}
136132

137-
errList = append(errList, validatePVCConfiguration(&storage.PVC, fldPath.Child("pvc"))...)
138-
139-
return errList
133+
return validatePVCConfiguration(&storage.PVC, fldPath.Child("pvc"))
140134
}
141135

142-
func validatePVCConfiguration(pvc *appsv1alpha1.PersistentVolumeClaim, fldPath *field.Path) field.ErrorList {
136+
func validatePVCConfiguration(pvc *appsv1alpha1.PersistentVolumeClaim, fldPath *field.Path) (admission.Warnings, field.ErrorList) {
143137
errList := field.ErrorList{}
138+
warnList := admission.Warnings{}
144139

145140
// If PVC.Create is False, PVC.Name cannot be empty
146141
if (pvc.Create == nil || !*pvc.Create) && pvc.Name == "" {
@@ -162,13 +157,14 @@ func validatePVCConfiguration(pvc *appsv1alpha1.PersistentVolumeClaim, fldPath *
162157
}
163158
}
164159

165-
return errList
160+
return warnList, errList
166161
}
167162

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{}
169165
errList := field.ErrorList{}
170166
if proxy == nil {
171-
return nil
167+
return nil, nil
172168
}
173169

174170
// 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
194190
errList = append(errList, field.Invalid(fldPath.Child("httpProxy"), proxy.HttpProxy, "must start with http:// or https://"))
195191
}
196192

197-
return errList
193+
return warnList, errList
198194
}
199195

200196
// validateNIMCacheSpec aggregates all structural validation rules for a NIMCache
@@ -209,23 +205,27 @@ func validateProxyConfiguration(proxy *appsv1alpha1.ProxySpec, fldPath *field.Pa
209205
// field.NewPath("nimcache").Child("spec")).
210206
//
211207
// 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"))
214210

215211
// 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...)
219219

220-
return errList
220+
return warningList, errList
221221
}
222222

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) {
224224
errList := field.ErrorList{}
225-
225+
warningList := admission.Warnings{}
226226
if !equality.Semantic.DeepEqual(oldNIMCache.Spec, newNIMCache.Spec) {
227227
errList = append(errList, field.Forbidden(fldPath.Child("spec"), "is immutable once the object is created"))
228228
}
229229

230-
return errList
230+
return warningList, errList
231231
}

0 commit comments

Comments
 (0)