@@ -23,10 +23,12 @@ import (
2323
2424	corev1 "k8s.io/api/core/v1" 
2525	"k8s.io/apimachinery/pkg/runtime" 
26+ 	"k8s.io/apimachinery/pkg/util/validation/field" 
2627	"k8s.io/utils/pointer" 
2728	ctrl "sigs.k8s.io/controller-runtime" 
2829	logf "sigs.k8s.io/controller-runtime/pkg/log" 
2930	"sigs.k8s.io/controller-runtime/pkg/webhook" 
31+ 	"sigs.k8s.io/controller-runtime/pkg/webhook/admission" 
3032
3133	"github.com/project-codeflare/codeflare-operator/pkg/config" 
3234)
@@ -40,16 +42,24 @@ func SetupRayClusterWebhookWithManager(mgr ctrl.Manager, cfg *config.KubeRayConf
4042		WithDefaulter (& rayClusterDefaulter {
4143			Config : cfg ,
4244		}).
45+ 		WithValidator (& rayClusterWebhook {
46+ 			Config : cfg ,
47+ 		}).
4348		Complete ()
4449}
4550
4651// +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 
52+ // +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 
4753
4854type  rayClusterDefaulter  struct  {
4955	Config  * config.KubeRayConfiguration 
5056}
57+ type  rayClusterWebhook  struct  {
58+ 	Config  * config.KubeRayConfiguration 
59+ }
5160
5261var  _  webhook.CustomDefaulter  =  & rayClusterDefaulter {}
62+ var  _  webhook.CustomValidator  =  & rayClusterWebhook {}
5363
5464// Default implements webhook.Defaulter so a webhook will be registered for the type 
5565func  (r  * rayClusterDefaulter ) Default (ctx  context.Context , obj  runtime.Object ) error  {
@@ -132,3 +142,32 @@ func (r *rayClusterDefaulter) Default(ctx context.Context, obj runtime.Object) e
132142
133143	return  nil 
134144}
145+ 
146+ func  (v  * rayClusterWebhook ) ValidateCreate (ctx  context.Context , obj  runtime.Object ) (admission.Warnings , error ) {
147+ 	raycluster  :=  obj .(* rayv1.RayCluster )
148+ 	var  warnings  admission.Warnings 
149+ 	var  allErrors  field.ErrorList 
150+ 	specPath  :=  field .NewPath ("spec" )
151+ 
152+ 	if  pointer .BoolDeref (raycluster .Spec .HeadGroupSpec .EnableIngress , false ) {
153+ 		rayclusterlog .Info ("Creating RayCluster resources with EnableIngress set to true or unspecified is not allowed" )
154+ 		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" ))
155+ 	}
156+ 
157+ 	return  warnings , allErrors .ToAggregate ()
158+ }
159+ 
160+ func  (v  * rayClusterWebhook ) ValidateUpdate (ctx  context.Context , oldObj , newObj  runtime.Object ) (admission.Warnings , error ) {
161+ 	newRayCluster  :=  newObj .(* rayv1.RayCluster )
162+ 	if  ! newRayCluster .DeletionTimestamp .IsZero () {
163+ 		// Object is being deleted, skip validations 
164+ 		return  nil , nil 
165+ 	}
166+ 	warnings , err  :=  v .ValidateCreate (ctx , newRayCluster )
167+ 	return  warnings , err 
168+ }
169+ 
170+ func  (v  * rayClusterWebhook ) ValidateDelete (ctx  context.Context , obj  runtime.Object ) (admission.Warnings , error ) {
171+ 	// Optional: Add delete validation logic here 
172+ 	return  nil , nil 
173+ }
0 commit comments