@@ -21,26 +21,33 @@ import (
2121 rayv1 "github.com/ray-project/kuberay/ray-operator/apis/ray/v1"
2222 corev1 "k8s.io/api/core/v1"
2323 "k8s.io/apimachinery/pkg/runtime"
24+ "k8s.io/apimachinery/pkg/util/validation/field"
2425 ctrl "sigs.k8s.io/controller-runtime"
2526 logf "sigs.k8s.io/controller-runtime/pkg/log"
2627 "sigs.k8s.io/controller-runtime/pkg/webhook"
28+ "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
2729)
2830
2931// log is for logging in this package.
3032var rayclusterlog = logf .Log .WithName ("raycluster-resource" )
3133
32- func (r * RayClusterDefaulter ) SetupWebhookWithManager (mgr ctrl.Manager ) error {
34+ type RayClusterWebhook struct {}
35+ type RayClusterDefaulter struct {}
36+ type RayClusterValidator struct {}
37+
38+ func (w * RayClusterWebhook ) SetupWebhookWithManager (mgr ctrl.Manager ) error {
3339 return ctrl .NewWebhookManagedBy (mgr ).
3440 For (& rayv1.RayCluster {}).
35- WithDefaulter (r ).
41+ WithDefaulter (& RayClusterDefaulter {}).
42+ WithValidator (& RayClusterValidator {}).
3643 Complete ()
3744}
3845
3946//+kubebuilder:webhook:path=/mutate-ray-io-v1-raycluster,mutating=true,failurePolicy=fail,sideEffects=None,groups=ray.io,resources=rayclusters,verbs=create;update,versions=v1,name=mraycluster.kb.io,admissionReviewVersions=v1
40-
41- type RayClusterDefaulter struct {}
47+ //+kubebuilder:webhook:path=/validate-ray-io-v1-raycluster,mutating=false,failurePolicy=fail,sideEffects=None,groups=ray.io,resources=rayclusters,verbs=create;update,versions=v1,name=vraycluster.kb.io,admissionReviewVersions=v1
4248
4349var _ webhook.CustomDefaulter = & RayClusterDefaulter {}
50+ var _ webhook.CustomValidator = & RayClusterValidator {}
4451
4552// Default implements webhook.Defaulter so a webhook will be registered for the type
4653func (r * RayClusterDefaulter ) Default (ctx context.Context , obj runtime.Object ) error {
@@ -120,3 +127,32 @@ func (r *RayClusterDefaulter) Default(ctx context.Context, obj runtime.Object) e
120127 }
121128 return nil
122129}
130+
131+ func (v * RayClusterValidator ) ValidateCreate (ctx context.Context , obj runtime.Object ) (admission.Warnings , error ) {
132+ raycluster := obj .(* rayv1.RayCluster )
133+ var warnings admission.Warnings
134+ var allErrors field.ErrorList
135+ specPath := field .NewPath ("spec" )
136+
137+ if raycluster .Spec .HeadGroupSpec .EnableIngress == nil || * raycluster .Spec .HeadGroupSpec .EnableIngress {
138+ rayclusterlog .Info ("Creating RayCluster resources with EnableIngress set to true or unspecified is not allowed" )
139+ allErrors = append (allErrors , field .Invalid (specPath .Child ("headGroupSpec" ).Child ("enableIngress" ), raycluster .Spec .HeadGroupSpec .EnableIngress , "creating RayCluster resources with EnableIngress set to true or unspecified is not allowed" ))
140+ }
141+
142+ return warnings , allErrors .ToAggregate ()
143+ }
144+
145+ func (v * RayClusterValidator ) ValidateUpdate (ctx context.Context , oldObj , newObj runtime.Object ) (admission.Warnings , error ) {
146+ newRayCluster := newObj .(* rayv1.RayCluster )
147+ if ! newRayCluster .DeletionTimestamp .IsZero () {
148+ // Object is being deleted, skip validations
149+ return nil , nil
150+ }
151+ warnings , err := v .ValidateCreate (ctx , newRayCluster )
152+ return warnings , err
153+ }
154+
155+ func (v * RayClusterValidator ) ValidateDelete (ctx context.Context , obj runtime.Object ) (admission.Warnings , error ) {
156+ // Optional: Add delete validation logic here
157+ return nil , nil
158+ }
0 commit comments