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 }