From eb21e6c16a9fc208fa70b871b3480d68c40765b7 Mon Sep 17 00:00:00 2001 From: ChristianZaccaria Date: Wed, 17 Apr 2024 18:01:35 +0100 Subject: [PATCH 1/2] Create RayCluster ValidatingWebhook --- PROJECT | 1 + config/webhook/manifests.yaml | 27 ++++++++++++++++++++ pkg/controllers/raycluster_webhook.go | 36 +++++++++++++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/PROJECT b/PROJECT index 0fc5562e2..6a659e10e 100644 --- a/PROJECT +++ b/PROJECT @@ -19,5 +19,6 @@ resources: version: v1 webhooks: defaulting: true + validating: true # or might be validation: true webhookVersion: v1 version: "3" diff --git a/config/webhook/manifests.yaml b/config/webhook/manifests.yaml index faf91696b..c14976cfe 100644 --- a/config/webhook/manifests.yaml +++ b/config/webhook/manifests.yaml @@ -25,3 +25,30 @@ webhooks: resources: - rayclusters sideEffects: None +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + creationTimestamp: null + name: validating-webhook-configuration +webhooks: +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-ray-io-v1-raycluster + failurePolicy: Fail + name: vraycluster.kb.io + rules: + - apiGroups: + - ray.io + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - rayclusters + sideEffects: None diff --git a/pkg/controllers/raycluster_webhook.go b/pkg/controllers/raycluster_webhook.go index 0cd635040..1badaf182 100644 --- a/pkg/controllers/raycluster_webhook.go +++ b/pkg/controllers/raycluster_webhook.go @@ -29,6 +29,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/webhook" "github.com/project-codeflare/codeflare-operator/pkg/config" + "k8s.io/apimachinery/pkg/util/validation/field" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" ) // log is for logging in this package. @@ -40,16 +42,21 @@ func SetupRayClusterWebhookWithManager(mgr ctrl.Manager, cfg *config.KubeRayConf WithDefaulter(&rayClusterDefaulter{ Config: cfg, }). + WithValidator(&rayClusterValidator{}). Complete() } // +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 +//+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 type rayClusterDefaulter struct { Config *config.KubeRayConfiguration } +type rayClusterValidator struct{} var _ webhook.CustomDefaulter = &rayClusterDefaulter{} +var _ webhook.CustomValidator = &rayClusterValidator{} + // Default implements webhook.Defaulter so a webhook will be registered for the type func (r *rayClusterDefaulter) Default(ctx context.Context, obj runtime.Object) error { @@ -132,3 +139,32 @@ func (r *rayClusterDefaulter) Default(ctx context.Context, obj runtime.Object) e return nil } + +func (v *rayClusterValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { + raycluster := obj.(*rayv1.RayCluster) + var warnings admission.Warnings + var allErrors field.ErrorList + specPath := field.NewPath("spec") + + if raycluster.Spec.HeadGroupSpec.EnableIngress == nil || *raycluster.Spec.HeadGroupSpec.EnableIngress { + rayclusterlog.Info("Creating RayCluster resources with EnableIngress set to true or unspecified is not allowed") + 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")) + } + + return warnings, allErrors.ToAggregate() +} + +func (v *rayClusterValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) { + newRayCluster := newObj.(*rayv1.RayCluster) + if !newRayCluster.DeletionTimestamp.IsZero() { + // Object is being deleted, skip validations + return nil, nil + } + warnings, err := v.ValidateCreate(ctx, newRayCluster) + return warnings, err +} + +func (v *rayClusterValidator) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { + // Optional: Add delete validation logic here + return nil, nil +} From 1acc0167949700b7a7f6c8bada994bd085d0d96d Mon Sep 17 00:00:00 2001 From: ChristianZaccaria Date: Thu, 18 Apr 2024 08:15:13 +0100 Subject: [PATCH 2/2] Rebased --- config/openshift/kustomization.yaml | 3 ++- ...atch.yaml => webhookcainjection_mpatch.yaml} | 0 config/openshift/webhookcainjection_vpatch.yaml | 7 +++++++ pkg/controllers/raycluster_webhook.go | 17 ++++++++++------- 4 files changed, 19 insertions(+), 8 deletions(-) rename config/openshift/{webhookcainjection_patch.yaml => webhookcainjection_mpatch.yaml} (100%) create mode 100644 config/openshift/webhookcainjection_vpatch.yaml diff --git a/config/openshift/kustomization.yaml b/config/openshift/kustomization.yaml index 22e168162..dd9471671 100644 --- a/config/openshift/kustomization.yaml +++ b/config/openshift/kustomization.yaml @@ -19,4 +19,5 @@ bases: patches: - path: manager_webhook_patch.yaml -- path: webhookcainjection_patch.yaml +- path: webhookcainjection_mpatch.yaml +- path: webhookcainjection_vpatch.yaml diff --git a/config/openshift/webhookcainjection_patch.yaml b/config/openshift/webhookcainjection_mpatch.yaml similarity index 100% rename from config/openshift/webhookcainjection_patch.yaml rename to config/openshift/webhookcainjection_mpatch.yaml diff --git a/config/openshift/webhookcainjection_vpatch.yaml b/config/openshift/webhookcainjection_vpatch.yaml new file mode 100644 index 000000000..91f741a05 --- /dev/null +++ b/config/openshift/webhookcainjection_vpatch.yaml @@ -0,0 +1,7 @@ +# This patch add annotation to admission webhook config +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: validating-webhook-configuration + annotations: + service.beta.openshift.io/inject-cabundle: "true" diff --git a/pkg/controllers/raycluster_webhook.go b/pkg/controllers/raycluster_webhook.go index 1badaf182..5536aab20 100644 --- a/pkg/controllers/raycluster_webhook.go +++ b/pkg/controllers/raycluster_webhook.go @@ -23,14 +23,14 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/utils/pointer" ctrl "sigs.k8s.io/controller-runtime" logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/webhook" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" "github.com/project-codeflare/codeflare-operator/pkg/config" - "k8s.io/apimachinery/pkg/util/validation/field" - "sigs.k8s.io/controller-runtime/pkg/webhook/admission" ) // log is for logging in this package. @@ -42,22 +42,25 @@ func SetupRayClusterWebhookWithManager(mgr ctrl.Manager, cfg *config.KubeRayConf WithDefaulter(&rayClusterDefaulter{ Config: cfg, }). - WithValidator(&rayClusterValidator{}). + WithValidator(&rayClusterValidator{ + Config: cfg, + }). Complete() } // +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 -//+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 +// +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 type rayClusterDefaulter struct { Config *config.KubeRayConfiguration } -type rayClusterValidator struct{} +type rayClusterValidator struct { + Config *config.KubeRayConfiguration +} var _ webhook.CustomDefaulter = &rayClusterDefaulter{} var _ webhook.CustomValidator = &rayClusterValidator{} - // Default implements webhook.Defaulter so a webhook will be registered for the type func (r *rayClusterDefaulter) Default(ctx context.Context, obj runtime.Object) error { raycluster := obj.(*rayv1.RayCluster) @@ -157,7 +160,7 @@ func (v *rayClusterValidator) ValidateCreate(ctx context.Context, obj runtime.Ob func (v *rayClusterValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) { newRayCluster := newObj.(*rayv1.RayCluster) if !newRayCluster.DeletionTimestamp.IsZero() { - // Object is being deleted, skip validations + // Object is being deleted, skip validations return nil, nil } warnings, err := v.ValidateCreate(ctx, newRayCluster)