github.com/kubevela/workflow@v0.6.0/pkg/webhook/v1alpha1/workflowrun/validating_handler.go (about)

     1  /*
     2  Copyright 2022 The KubeVela Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  	http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package workflowrun
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"net/http"
    23  
    24  	admissionv1 "k8s.io/api/admission/v1"
    25  	"k8s.io/apimachinery/pkg/util/validation/field"
    26  	"sigs.k8s.io/controller-runtime/pkg/client"
    27  	"sigs.k8s.io/controller-runtime/pkg/manager"
    28  	"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
    29  	"sigs.k8s.io/controller-runtime/pkg/webhook"
    30  	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
    31  
    32  	"github.com/kubevela/workflow/api/v1alpha1"
    33  	"github.com/kubevela/workflow/pkg/cue/packages"
    34  	"github.com/kubevela/workflow/pkg/types"
    35  
    36  	"github.com/kubevela/workflow/controllers"
    37  )
    38  
    39  var _ admission.Handler = &ValidatingHandler{}
    40  
    41  // ValidatingHandler handles application
    42  type ValidatingHandler struct {
    43  	pd     *packages.PackageDiscover
    44  	Client client.Client
    45  	// Decoder decodes objects
    46  	Decoder *admission.Decoder
    47  }
    48  
    49  var _ inject.Client = &ValidatingHandler{}
    50  
    51  // InjectClient injects the client into the ApplicationValidateHandler
    52  func (h *ValidatingHandler) InjectClient(c client.Client) error {
    53  	if h.Client != nil {
    54  		return nil
    55  	}
    56  	h.Client = c
    57  	return nil
    58  }
    59  
    60  var _ admission.DecoderInjector = &ValidatingHandler{}
    61  
    62  // InjectDecoder injects the decoder into the ApplicationValidateHandler
    63  func (h *ValidatingHandler) InjectDecoder(d *admission.Decoder) error {
    64  	if h.Decoder != nil {
    65  		return nil
    66  	}
    67  	h.Decoder = d
    68  	return nil
    69  }
    70  
    71  func mergeErrors(errs field.ErrorList) error {
    72  	s := ""
    73  	for _, err := range errs {
    74  		s += fmt.Sprintf("field \"%s\": %s error encountered, %s. ", err.Field, err.Type, err.Detail)
    75  	}
    76  	return fmt.Errorf(s)
    77  }
    78  
    79  // Handle validate Application Spec here
    80  func (h *ValidatingHandler) Handle(ctx context.Context, req admission.Request) admission.Response {
    81  	wr := &v1alpha1.WorkflowRun{}
    82  	if err := h.Decoder.Decode(req, wr); err != nil {
    83  		return admission.Errored(http.StatusBadRequest, err)
    84  	}
    85  	ctx = types.SetNamespaceInCtx(ctx, wr.Namespace)
    86  	switch req.Operation {
    87  	case admissionv1.Create:
    88  		if allErrs := h.ValidateWorkflow(ctx, wr); len(allErrs) > 0 {
    89  			// http.StatusUnprocessableEntity will NOT report any error descriptions
    90  			// to the client, use generic http.StatusBadRequest instead.
    91  			return admission.Errored(http.StatusBadRequest, mergeErrors(allErrs))
    92  		}
    93  	case admissionv1.Update:
    94  		if wr.ObjectMeta.DeletionTimestamp.IsZero() {
    95  			if allErrs := h.ValidateWorkflow(ctx, wr); len(allErrs) > 0 {
    96  				return admission.Errored(http.StatusBadRequest, mergeErrors(allErrs))
    97  			}
    98  		}
    99  	default:
   100  		// Do nothing for DELETE and CONNECT
   101  	}
   102  	return admission.ValidationResponse(true, "")
   103  }
   104  
   105  // RegisterValidatingHandler will register application validate handler to the webhook
   106  func RegisterValidatingHandler(mgr manager.Manager, args controllers.Args) {
   107  	server := mgr.GetWebhookServer()
   108  	server.Register("/validating-core-oam-dev-v1alpha1-workflowruns", &webhook.Admission{Handler: &ValidatingHandler{pd: args.PackageDiscover}})
   109  }