From f8eeeec6c2e42e35d7122dad006b3028ccdc3952 Mon Sep 17 00:00:00 2001 From: Yauheni Kaliuta Date: Thu, 9 Nov 2023 17:06:54 +0200 Subject: [PATCH] webhook: implement one instance enforcing The webhook is written with the idea to handle both Create and Update requests (configured in config/webhook/manifests.yaml), but at the moment only duplication check on Create is implemented. Implements the logic which is done now on reconcile time [1] (same for DSCI). It checks for 0 instances, not 1, since when the webhook is running the object has not been created yet. Means if it's 1 then it handles request to create a second one. It could be probably possible to use generics but does not make a lot of sense for such a simple case. Closes: #693 [1] https://github.com/opendatahub-io/opendatahub-operator/blob/incubation/controllers/datasciencecluster/datasciencecluster_controller.go#L98 Signed-off-by: Yauheni Kaliuta --- controllers/webhook/webhook.go | 55 +++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/controllers/webhook/webhook.go b/controllers/webhook/webhook.go index 07b6d63c2ad..f730dc78703 100644 --- a/controllers/webhook/webhook.go +++ b/controllers/webhook/webhook.go @@ -22,13 +22,12 @@ import ( "net/http" admissionv1 "k8s.io/api/admission/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - - dsc "github.com/opendatahub-io/opendatahub-operator/v2/apis/datasciencecluster/v1" - dsci "github.com/opendatahub-io/opendatahub-operator/v2/apis/dscinitialization/v1" ) var log = ctrl.Log.WithName("odh-controller-webhook") @@ -59,6 +58,54 @@ func (w *OpenDataHubWebhook) InjectClient(c client.Client) error { return nil } +func (w *OpenDataHubWebhook) checkDupCreation(ctx context.Context, req admission.Request) admission.Response { + if req.Operation != admissionv1.Create { + return admission.Allowed(fmt.Sprintf("duplication check: skipping %v request", req.Operation)) + } + + switch req.Kind.Kind { + case "DataScienceCluster": + case "DSCInitialization": + default: + log.Info("Got wrong kind", "kind", req.Kind.Kind) + return admission.Errored(http.StatusBadRequest, nil) + } + + gvk := schema.GroupVersionKind{ + Group: req.Kind.Group, + Version: req.Kind.Version, + Kind: req.Kind.Kind, + } + + list := &unstructured.UnstructuredList{} + list.SetGroupVersionKind(gvk) + + if err := w.client.List(ctx, list); err != nil { + return admission.Errored(http.StatusBadRequest, err) + } + + // if len == 1 now creation of #2 is being handled + if len(list.Items) > 0 { + return admission.Denied(fmt.Sprintf("Only one instance of %s object is allowed", req.Kind.Kind)) + } + + return admission.Allowed(fmt.Sprintf("%s duplication check passed", req.Kind.Kind)) +} + func (w *OpenDataHubWebhook) Handle(ctx context.Context, req admission.Request) admission.Response { - return admission.ValidationResponse(true, "") + var resp admission.Response + + // Handle only Create and Update + if req.Operation == admissionv1.Delete || req.Operation == admissionv1.Connect { + msg := fmt.Sprintf("ODH skipping %v request", req.Operation) + log.Info(msg) + return admission.Allowed(msg) + } + + resp = w.checkDupCreation(ctx, req) + if !resp.Allowed { + return resp + } + + return admission.Allowed(fmt.Sprintf("%s allowed", req.Kind.Kind)) }